Merge branch 'ext-boltcards_keys' of https://github.com/iWarpBTC/lnbits-legend into ext-boltcards_keys

This commit is contained in:
Gene Takavic 2022-09-22 11:22:09 +02:00
commit 30e0537270
16 changed files with 112 additions and 106 deletions

View file

@ -1,6 +1,7 @@
FROM python:3.9-slim
RUN apt-get clean
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y curl pkg-config build-essential
RUN curl -sSL https://install.python-poetry.org | python3 -
ENV PATH="/root/.local/bin:$PATH"
WORKDIR /app

View file

@ -12,6 +12,8 @@ By default, LNbits will use SQLite as its database. You can also use PostgreSQL
## Option 1 (recommended): poetry
If you have problems installing LNbits using these instructions, please have a look at the [Troubleshooting](#troubleshooting) section.
```sh
git clone https://github.com/lnbits/lnbits-legend.git
cd lnbits-legend/
@ -26,12 +28,11 @@ curl -sSL https://install.python-poetry.org | python3 -
export PATH="/home/ubuntu/.local/bin:$PATH" # or whatever is suggested in the poetry install notes printed to terminal
poetry env use python3.9
poetry install --no-dev
poetry run python build.py
mkdir data
cp .env.example .env
sudo nano .env # set funding source
nano .env # set funding source
```
#### Running the server
@ -176,13 +177,15 @@ Problems installing? These commands have helped us install LNbits.
```sh
sudo apt install pkg-config libffi-dev libpq-dev
# build essentials for debian/ubuntu
sudo apt install python3.9-dev gcc build-essential
# if the secp256k1 build fails:
# if you used venv
./venv/bin/pip install setuptools wheel
# if you used poetry
poetry add setuptools wheel
# build essentials for debian/ubuntu
sudo apt install python3-dev gcc build-essential
# if you used venv
./venv/bin/pip install setuptools wheel
```
### Optional: PostgreSQL database

View file

@ -452,6 +452,15 @@ async def delete_payment(checking_id: str, conn: Optional[Connection] = None) ->
)
async def delete_wallet_payment(
checking_id: str, wallet_id: str, conn: Optional[Connection] = None
) -> None:
await (conn or db).execute(
"DELETE FROM apipayments WHERE checking_id = ? AND wallet = ?",
(checking_id, wallet_id),
)
async def check_internal(
payment_hash: str, conn: Optional[Connection] = None
) -> Optional[str]:

View file

@ -9,6 +9,7 @@ from lnurl import encode as lnurl_encode # type: ignore
from loguru import logger
from pydantic import BaseModel
from lnbits.db import Connection
from lnbits.helpers import url_for
from lnbits.settings import WALLET
from lnbits.wallets.base import PaymentStatus
@ -131,7 +132,11 @@ class Payment(BaseModel):
def is_uncheckable(self) -> bool:
return self.checking_id.startswith("internal_")
async def update_status(self, status: PaymentStatus) -> None:
async def update_status(
self,
status: PaymentStatus,
conn: Optional[Connection] = None,
) -> None:
from .crud import update_payment_details
await update_payment_details(
@ -139,6 +144,7 @@ class Payment(BaseModel):
pending=status.pending,
fee=status.fee_msat,
preimage=status.preimage,
conn=conn,
)
async def set_pending(self, pending: bool) -> None:
@ -146,7 +152,10 @@ class Payment(BaseModel):
await update_payment_status(self.checking_id, pending)
async def check_status(self) -> PaymentStatus:
async def check_status(
self,
conn: Optional[Connection] = None,
) -> PaymentStatus:
if self.is_uncheckable:
return PaymentStatus(None)
@ -165,18 +174,18 @@ class Payment(BaseModel):
logger.warning(
f"Deleting outgoing failed payment {self.checking_id}: {status}"
)
await self.delete()
await self.delete(conn)
elif not status.pending:
logger.info(
f"Marking '{'in' if self.is_in else 'out'}' {self.checking_id} as not pending anymore: {status}"
)
await self.update_status(status)
await self.update_status(status, conn=conn)
return status
async def delete(self) -> None:
async def delete(self, conn: Optional[Connection] = None) -> None:
from .crud import delete_payment
await delete_payment(self.checking_id)
await delete_payment(self.checking_id, conn=conn)
class BalanceCheck(BaseModel):

View file

@ -28,7 +28,7 @@ from . import db
from .crud import (
check_internal,
create_payment,
delete_payment,
delete_wallet_payment,
get_wallet,
get_wallet_payment,
update_payment_details,
@ -221,7 +221,7 @@ async def pay_invoice(
logger.warning(f"backend sent payment failure")
async with db.connect() as conn:
logger.debug(f"deleting temporary payment {temp_id}")
await delete_payment(temp_id, conn=conn)
await delete_wallet_payment(temp_id, wallet_id, conn=conn)
raise PaymentFailure(
f"payment failed: {payment.error_message}"
or "payment failed, but backend didn't give us an error message"

View file

@ -369,9 +369,9 @@ new Vue({
decodeRequest: function () {
this.parse.show = true
let req = this.parse.data.request.toLowerCase()
if (this.parse.data.request.startsWith('lightning:')) {
if (this.parse.data.request.toLowerCase().startsWith('lightning:')) {
this.parse.data.request = this.parse.data.request.slice(10)
} else if (this.parse.data.request.startsWith('lnurl:')) {
} else if (this.parse.data.request.toLowerCase().startsWith('lnurl:')) {
this.parse.data.request = this.parse.data.request.slice(6)
} else if (req.indexOf('lightning=lnurl1') !== -1) {
this.parse.data.request = this.parse.data.request

View file

@ -711,7 +711,7 @@
<q-card class="q-pa-lg">
<h6 class="q-my-md text-primary">Warning</h6>
<p>
Login functionality to be released in v0.2, for now,
Login functionality to be released in a future update, for now,
<strong
>make sure you bookmark this page for future access to your
wallet</strong

View file

@ -402,10 +402,6 @@ async def subscribe(request: Request, wallet: Wallet):
async def api_payments_sse(
request: Request, wallet: WalletTypeInfo = Depends(get_key_type)
):
if wallet is None or wallet.wallet is None:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist."
)
return EventSourceResponse(
subscribe(request, wallet.wallet), ping=20, media_type="text/event-stream"
)

View file

@ -138,44 +138,38 @@ async def get_key_type(
detail="Invoice (or Admin) key required.",
)
try:
admin_checker = WalletAdminKeyChecker(api_key=token)
await admin_checker.__call__(r)
wallet = WalletTypeInfo(0, admin_checker.wallet) # type: ignore
if (LNBITS_ADMIN_USERS and wallet.wallet.user not in LNBITS_ADMIN_USERS) and (
LNBITS_ADMIN_EXTENSIONS and pathname in LNBITS_ADMIN_EXTENSIONS
for typenr, WalletChecker in zip(
[0, 1], [WalletAdminKeyChecker, WalletInvoiceKeyChecker]
):
try:
checker = WalletChecker(api_key=token)
await checker.__call__(r)
wallet = WalletTypeInfo(typenr, checker.wallet) # type: ignore
if wallet is None or wallet.wallet is None:
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist."
)
if (
LNBITS_ADMIN_USERS and wallet.wallet.user not in LNBITS_ADMIN_USERS
) and (LNBITS_ADMIN_EXTENSIONS and pathname in LNBITS_ADMIN_EXTENSIONS):
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN,
detail="User not authorized for this extension.",
)
return wallet
except HTTPException as e:
if e.status_code == HTTPStatus.BAD_REQUEST:
raise
if e.status_code == HTTPStatus.UNAUTHORIZED:
elif e.status_code == HTTPStatus.UNAUTHORIZED:
# we pass this in case it is not an invoice key, nor an admin key, and then return NOT_FOUND at the end of this block
pass
else:
raise
except:
raise
try:
invoice_checker = WalletInvoiceKeyChecker(api_key=token)
await invoice_checker.__call__(r)
wallet = WalletTypeInfo(1, invoice_checker.wallet) # type: ignore
if (LNBITS_ADMIN_USERS and wallet.wallet.user not in LNBITS_ADMIN_USERS) and (
LNBITS_ADMIN_EXTENSIONS and pathname in LNBITS_ADMIN_EXTENSIONS
):
raise HTTPException(
status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist."
)
return wallet
except HTTPException as e:
if e.status_code == HTTPStatus.BAD_REQUEST:
raise
if e.status_code == HTTPStatus.UNAUTHORIZED:
return WalletTypeInfo(2, None) # type: ignore
except:
raise
return wallet
async def require_admin_key(

View file

@ -19,26 +19,9 @@ async def create_ticket(
(payment_hash, wallet, event, name, email, False, True),
)
ticket = await get_ticket(payment_hash)
assert ticket, "Newly created ticket couldn't be retrieved"
return ticket
async def set_ticket_paid(payment_hash: str) -> Tickets:
row = await db.fetchone("SELECT * FROM events.ticket WHERE id = ?", (payment_hash,))
if row[6] != True:
await db.execute(
"""
UPDATE events.ticket
SET paid = true
WHERE id = ?
""",
(payment_hash,),
)
eventdata = await get_event(row[2])
# UPDATE EVENT DATA ON SOLD TICKET
eventdata = await get_event(event)
assert eventdata, "Couldn't get event from ticket being paid"
sold = eventdata.sold + 1
amount_tickets = eventdata.amount_tickets - 1
await db.execute(
@ -47,11 +30,11 @@ async def set_ticket_paid(payment_hash: str) -> Tickets:
SET sold = ?, amount_tickets = ?
WHERE id = ?
""",
(sold, amount_tickets, row[2]),
(sold, amount_tickets, event),
)
ticket = await get_ticket(payment_hash)
assert ticket, "Newly updated ticket couldn't be retrieved"
assert ticket, "Newly created ticket couldn't be retrieved"
return ticket

View file

@ -24,7 +24,6 @@ from .crud import (
get_ticket,
get_tickets,
reg_ticket,
set_ticket_paid,
update_event,
)

View file

@ -5,13 +5,13 @@ animals = [
"duck",
"eagle",
"flamingo",
"gorila",
"gorilla",
"hamster",
"iguana",
"jaguar",
"koala",
"llama",
"macaroni penguim",
"macaroni penguin",
"numbat",
"octopus",
"platypus",

View file

@ -138,8 +138,9 @@
hide-dropdown-icon
input-debounce="0"
new-value-mode="add-unique"
label="Tip % Options"
></q-select>
label="Tip % Options (hit enter to add values)"
><q-tooltip>Hit enter to add values</q-tooltip></q-select
>
<div class="row q-mt-lg">
<q-btn
unelevated

View file

@ -253,7 +253,7 @@
name="check"
transition-show="fade"
class="text-light-green"
style="font-size: 40em"
style="font-size: min(90vw, 40em)"
></q-icon>
</q-dialog>
</q-page>
@ -294,6 +294,7 @@
exchangeRate: null,
stack: [],
tipAmount: 0.0,
hasNFC: false,
nfcTagReading: false,
invoiceDialog: {
show: false,
@ -370,7 +371,7 @@
this.showInvoice()
},
submitForm: function () {
if (this.tip_options.length) {
if (this.tip_options && this.tip_options.length) {
this.showTipModal()
} else {
this.showInvoice()
@ -413,9 +414,6 @@
dialog.show = false
self.complete.show = true
setTimeout(function () {
self.complete.show = false
}, 5000)
}
})
}, 3000)

View file

@ -3,23 +3,36 @@
<p>
Onchain Wallet (watch-only) extension uses mempool.space<br />
For use with "account Extended Public Key"
<a href="https://iancoleman.io/bip39/">https://iancoleman.io/bip39/</a>
<a
href="https://iancoleman.io/bip39/"
target="_blank"
style="color: unset"
>https://iancoleman.io/bip39/</a
>
<br />
Flash binaries
<a
href="https://lnbits.github.io/hardware-wallet"
target="_blank"
style="color: unset"
>directly from browser</a
>
<small>
<br />Created by,
<a target="_blank" class="text-white" href="https://github.com/arcbtc"
<a target="_blank" style="color: unset" href="https://github.com/arcbtc"
>Ben Arc</a
>
(using,
<a
target="_blank"
class="text-white"
style="color: unset"
href="https://github.com/diybitcoinhardware/embit"
>Embit</a
></small
>)
<br />
<br />
<a target="_blank" href="/docs#/watchonly" class="text-white"
<a target="_blank" href="/docs#/watchonly" style="color: unset"
>Swagger REST API Documentation</a
>
</p>

View file

@ -103,7 +103,7 @@ async def check_pending_payments():
conn=conn,
)
for payment in pending_payments:
await payment.check_status()
await payment.check_status(conn=conn)
logger.debug(
f"Task: pending check finished for {len(pending_payments)} payments (took {time.time() - start_time:0.3f} s)"