From 42704eaf1bcf0a0ec6fc4309ea63f692f0721286 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Tue, 18 Oct 2022 08:49:27 +0200 Subject: [PATCH 01/11] change boltz logs from warn to debug (#1057) --- lnbits/extensions/boltz/tasks.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/boltz/tasks.py b/lnbits/extensions/boltz/tasks.py index ace94557..d1ace04b 100644 --- a/lnbits/extensions/boltz/tasks.py +++ b/lnbits/extensions/boltz/tasks.py @@ -57,7 +57,7 @@ async def check_for_pending_swaps(): swap_status = get_swap_status(swap) # should only happen while development when regtest is reset if swap_status.exists is False: - logger.warning(f"Boltz - swap: {swap.boltz_id} does not exist.") + logger.debug(f"Boltz - swap: {swap.boltz_id} does not exist.") await update_swap_status(swap.id, "failed") continue @@ -73,7 +73,7 @@ async def check_for_pending_swaps(): else: if swap_status.hit_timeout: if not swap_status.has_lockup: - logger.warning( + logger.debug( f"Boltz - swap: {swap.id} hit timeout, but no lockup tx..." ) await update_swap_status(swap.id, "timeout") From 9de38f908bfa603c1cfb98cfd078e0136e815320 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Thu, 20 Oct 2022 17:40:23 +0300 Subject: [PATCH 02/11] fix: wallet not found error (#1063) --- lnbits/extensions/satspay/crud.py | 9 ++++++++- lnbits/extensions/satspay/helpers.py | 17 +++++++++++++++++ lnbits/extensions/satspay/models.py | 1 - .../satspay/templates/satspay/display.html | 15 +++------------ lnbits/extensions/satspay/views.py | 5 ++--- lnbits/extensions/satspay/views_api.py | 17 +++-------------- 6 files changed, 33 insertions(+), 31 deletions(-) create mode 100644 lnbits/extensions/satspay/helpers.py diff --git a/lnbits/extensions/satspay/crud.py b/lnbits/extensions/satspay/crud.py index 47d7a4a8..23d391b7 100644 --- a/lnbits/extensions/satspay/crud.py +++ b/lnbits/extensions/satspay/crud.py @@ -102,7 +102,7 @@ async def check_address_balance(charge_id: str) -> List[Charges]: charge = await get_charge(charge_id) if not charge.paid: if charge.onchainaddress: - config = await get_config(charge.user) + config = await get_charge_config(charge_id) try: async with httpx.AsyncClient() as client: r = await client.get( @@ -122,3 +122,10 @@ async def check_address_balance(charge_id: str) -> List[Charges]: return await update_charge(charge_id=charge_id, balance=charge.amount) row = await db.fetchone("SELECT * FROM satspay.charges WHERE id = ?", (charge_id,)) return Charges.from_row(row) if row else None + + +async def get_charge_config(charge_id: str): + row = await db.fetchone( + """SELECT "user" FROM satspay.charges WHERE id = ?""", (charge_id,) + ) + return await get_config(row.user) diff --git a/lnbits/extensions/satspay/helpers.py b/lnbits/extensions/satspay/helpers.py new file mode 100644 index 00000000..2d15b557 --- /dev/null +++ b/lnbits/extensions/satspay/helpers.py @@ -0,0 +1,17 @@ +from .models import Charges + + +def compact_charge(charge: Charges): + return { + "id": charge.id, + "description": charge.description, + "onchainaddress": charge.onchainaddress, + "payment_request": charge.payment_request, + "payment_hash": charge.payment_hash, + "time": charge.time, + "amount": charge.amount, + "balance": charge.balance, + "paid": charge.paid, + "timestamp": charge.timestamp, + "completelink": charge.completelink, # should be secret? + } diff --git a/lnbits/extensions/satspay/models.py b/lnbits/extensions/satspay/models.py index e8638d5e..daf63f42 100644 --- a/lnbits/extensions/satspay/models.py +++ b/lnbits/extensions/satspay/models.py @@ -19,7 +19,6 @@ class CreateCharge(BaseModel): class Charges(BaseModel): id: str - user: str description: Optional[str] onchainwallet: Optional[str] onchainaddress: Optional[str] diff --git a/lnbits/extensions/satspay/templates/satspay/display.html b/lnbits/extensions/satspay/templates/satspay/display.html index f34ac509..12288c80 100644 --- a/lnbits/extensions/satspay/templates/satspay/display.html +++ b/lnbits/extensions/satspay/templates/satspay/display.html @@ -328,7 +328,7 @@ ) }, checkBalances: async function () { - if (!this.charge.hasStaleBalance) await this.refreshCharge() + if (this.charge.hasStaleBalance) return try { const {data} = await LNbits.api.request( 'GET', @@ -339,18 +339,9 @@ LNbits.utils.notifyApiError(error) } }, - refreshCharge: async function () { - try { - const {data} = await LNbits.api.request( - 'GET', - `/satspay/api/v1/charge/${this.charge.id}` - ) - this.charge = mapCharge(data, this.charge) - } catch (error) { - LNbits.utils.notifyApiError(error) - } - }, checkPendingOnchain: async function () { + if (!this.charge.onchainaddress) return + const { bitcoin: {addresses: addressesAPI} } = mempoolJS({ diff --git a/lnbits/extensions/satspay/views.py b/lnbits/extensions/satspay/views.py index 69d81dad..b789bf8f 100644 --- a/lnbits/extensions/satspay/views.py +++ b/lnbits/extensions/satspay/views.py @@ -9,10 +9,9 @@ from starlette.responses import HTMLResponse from lnbits.core.crud import get_wallet from lnbits.core.models import User from lnbits.decorators import check_user_exists -from lnbits.extensions.watchonly.crud import get_config from . import satspay_ext, satspay_renderer -from .crud import get_charge +from .crud import get_charge, get_charge_config templates = Jinja2Templates(directory="templates") @@ -32,7 +31,7 @@ async def display(request: Request, charge_id: str): status_code=HTTPStatus.NOT_FOUND, detail="Charge link does not exist." ) wallet = await get_wallet(charge.lnbitswallet) - onchainwallet_config = await get_config(charge.user) + onchainwallet_config = await get_charge_config(charge_id) inkey = wallet.inkey if wallet else None mempool_endpoint = ( onchainwallet_config.mempool_endpoint if onchainwallet_config else None diff --git a/lnbits/extensions/satspay/views_api.py b/lnbits/extensions/satspay/views_api.py index f94b970a..73c87e7c 100644 --- a/lnbits/extensions/satspay/views_api.py +++ b/lnbits/extensions/satspay/views_api.py @@ -20,6 +20,7 @@ from .crud import ( get_charges, update_charge, ) +from .helpers import compact_charge from .models import CreateCharge #############################CHARGES########################## @@ -123,25 +124,13 @@ async def api_charge_balance(charge_id): try: r = await client.post( charge.webhook, - json={ - "id": charge.id, - "description": charge.description, - "onchainaddress": charge.onchainaddress, - "payment_request": charge.payment_request, - "payment_hash": charge.payment_hash, - "time": charge.time, - "amount": charge.amount, - "balance": charge.balance, - "paid": charge.paid, - "timestamp": charge.timestamp, - "completelink": charge.completelink, - }, + json=compact_charge(charge), timeout=40, ) except AssertionError: charge.webhook = None return { - **charge.dict(), + **compact_charge(charge), **{"time_elapsed": charge.time_elapsed}, **{"time_left": charge.time_left}, **{"paid": charge.paid}, From daf5768d52c39cbcf24279d2c8604a2fefa1a197 Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Fri, 21 Oct 2022 15:49:17 +0300 Subject: [PATCH 03/11] fix: remove user from model (#1067) --- lnbits/extensions/watchonly/crud.py | 4 ++-- lnbits/extensions/watchonly/models.py | 1 - lnbits/extensions/watchonly/views_api.py | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lnbits/extensions/watchonly/crud.py b/lnbits/extensions/watchonly/crud.py index de338b91..c4a1df72 100644 --- a/lnbits/extensions/watchonly/crud.py +++ b/lnbits/extensions/watchonly/crud.py @@ -10,7 +10,7 @@ from .models import Address, Config, WalletAccount ##########################WALLETS#################### -async def create_watch_wallet(w: WalletAccount) -> WalletAccount: +async def create_watch_wallet(user: str, w: WalletAccount) -> WalletAccount: wallet_id = urlsafe_short_hash() await db.execute( """ @@ -30,7 +30,7 @@ async def create_watch_wallet(w: WalletAccount) -> WalletAccount: """, ( wallet_id, - w.user, + user, w.masterpub, w.fingerprint, w.title, diff --git a/lnbits/extensions/watchonly/models.py b/lnbits/extensions/watchonly/models.py index 622f5ec8..d8c278ff 100644 --- a/lnbits/extensions/watchonly/models.py +++ b/lnbits/extensions/watchonly/models.py @@ -14,7 +14,6 @@ class CreateWallet(BaseModel): class WalletAccount(BaseModel): id: str - user: str masterpub: str fingerprint: str title: str diff --git a/lnbits/extensions/watchonly/views_api.py b/lnbits/extensions/watchonly/views_api.py index 750d46c9..9030b9c3 100644 --- a/lnbits/extensions/watchonly/views_api.py +++ b/lnbits/extensions/watchonly/views_api.py @@ -86,7 +86,6 @@ async def api_wallet_create_or_update( new_wallet = WalletAccount( id="none", - user=w.wallet.user, masterpub=data.masterpub, fingerprint=descriptor.keys[0].fingerprint.hex(), type=descriptor.scriptpubkey_type(), @@ -115,7 +114,7 @@ async def api_wallet_create_or_update( ) ) - wallet = await create_watch_wallet(new_wallet) + wallet = await create_watch_wallet(w.wallet.user, new_wallet) await api_get_addresses(wallet.id, w) except Exception as e: From 2d61a8854f38a61507289af3520e52ff54ccb1a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Fri, 21 Oct 2022 17:35:58 +0200 Subject: [PATCH 04/11] improving on split payment handling --- lnbits/extensions/splitpayments/models.py | 2 +- lnbits/extensions/splitpayments/tasks.py | 72 ++++++++--------------- 2 files changed, 24 insertions(+), 50 deletions(-) diff --git a/lnbits/extensions/splitpayments/models.py b/lnbits/extensions/splitpayments/models.py index 4b95ed18..6338d97f 100644 --- a/lnbits/extensions/splitpayments/models.py +++ b/lnbits/extensions/splitpayments/models.py @@ -14,7 +14,7 @@ class Target(BaseModel): class TargetPutList(BaseModel): wallet: str = Query(...) alias: str = Query("") - percent: float = Query(..., ge=0.01) + percent: float = Query(..., ge=0.01, lt=100) class TargetPut(BaseModel): diff --git a/lnbits/extensions/splitpayments/tasks.py b/lnbits/extensions/splitpayments/tasks.py index cfc6c226..53378b20 100644 --- a/lnbits/extensions/splitpayments/tasks.py +++ b/lnbits/extensions/splitpayments/tasks.py @@ -1,13 +1,11 @@ import asyncio -import json from loguru import logger -from lnbits.core import db as core_db -from lnbits.core.crud import create_payment from lnbits.core.models import Payment -from lnbits.helpers import get_current_extension_name, urlsafe_short_hash -from lnbits.tasks import internal_invoice_queue, register_invoice_listener +from lnbits.core.services import create_invoice, pay_invoice +from lnbits.helpers import get_current_extension_name +from lnbits.tasks import register_invoice_listener from .crud import get_targets @@ -22,60 +20,36 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if payment.extra.get("tag") == "splitpayments" or payment.extra.get("splitted"): - # already splitted, ignore + if payment.extra.get("tag") == "splitpayments": + # already a splitted payment, ignore return - # now we make some special internal transfers (from no one to the receiver) targets = await get_targets(payment.wallet_id) if not targets: return - transfers = [ - (target.wallet, int(target.percent * payment.amount / 100)) - for target in targets - ] - transfers = [(wallet, amount) for wallet, amount in transfers if amount > 0] - amount_left = payment.amount - sum([amount for _, amount in transfers]) + total_percent = sum([target.percent for target in targets]) - if amount_left < 0: - logger.error( - "splitpayments failure: amount_left is negative.", payment.payment_hash - ) + if total_percent > 100: + logger.error("splitpayment failure: total percent adds up to more than 100%") return - # mark the original payment with one extra key, "splitted" - # (this prevents us from doing this process again and it's informative) - # and reduce it by the amount we're going to send to the producer - await core_db.execute( - """ - UPDATE apipayments - SET extra = ?, amount = ? - WHERE hash = ? - AND checking_id NOT LIKE 'internal_%' - """, - ( - json.dumps(dict(**payment.extra, splitted=True)), - amount_left, - payment.payment_hash, - ), - ) - - # perform the internal transfer using the same payment_hash - for wallet, amount in transfers: - internal_checking_id = f"internal_{urlsafe_short_hash()}" - await create_payment( - wallet_id=wallet, - checking_id=internal_checking_id, - payment_request="", - payment_hash=payment.payment_hash, - amount=amount, - memo=payment.memo, - pending=False, + logger.debug(f"performing split payments to {len(targets)} targets") + for target in targets: + amount = int(payment.amount * target.percent / 100) # msats + payment_hash, payment_request = await create_invoice( + wallet_id=target.wallet, + amount=int(amount / 1000), # sats + internal=True, + memo=f"split payment: {target.percent}% for {target.alias or target.wallet}", extra={"tag": "splitpayments"}, ) + logger.debug(f"created split invoice: {payment_hash}") - # manually send this for now - await internal_invoice_queue.put(internal_checking_id) - return + checking_id = await pay_invoice( + payment_request=payment_request, + wallet_id=payment.wallet_id, + extra={"tag": "splitpayments"}, + ) + logger.debug(f"paid split invoice: {checking_id}") From fe879ad9b964766c25f8b59a0323d009d332166d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Fri, 21 Oct 2022 18:15:27 +0200 Subject: [PATCH 05/11] add tpos to pr --- lnbits/extensions/tpos/tasks.py | 58 ++++++++++----------------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/lnbits/extensions/tpos/tasks.py b/lnbits/extensions/tpos/tasks.py index f18d1689..6369bbc7 100644 --- a/lnbits/extensions/tpos/tasks.py +++ b/lnbits/extensions/tpos/tasks.py @@ -1,11 +1,11 @@ import asyncio -import json -from lnbits.core import db as core_db -from lnbits.core.crud import create_payment +from loguru import logger + from lnbits.core.models import Payment -from lnbits.helpers import get_current_extension_name, urlsafe_short_hash -from lnbits.tasks import internal_invoice_queue, register_invoice_listener +from lnbits.core.services import create_invoice, pay_invoice +from lnbits.helpers import get_current_extension_name +from lnbits.tasks import register_invoice_listener from .crud import get_tpos @@ -20,11 +20,9 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if payment.extra.get("tag") == "tpos" and payment.extra.get("tipSplitted"): - # already splitted, ignore + if payment.extra.get("tag") != "tpos": return - # now we make some special internal transfers (from no one to the receiver) tpos = await get_tpos(payment.extra.get("tposId")) tipAmount = payment.extra.get("tipAmount") @@ -32,39 +30,17 @@ async def on_invoice_paid(payment: Payment) -> None: # no tip amount return - tipAmount = tipAmount * 1000 - amount = payment.amount - tipAmount - - # mark the original payment with one extra key, "splitted" - # (this prevents us from doing this process again and it's informative) - # and reduce it by the amount we're going to send to the producer - await core_db.execute( - """ - UPDATE apipayments - SET extra = ?, amount = ? - WHERE hash = ? - AND checking_id NOT LIKE 'internal_%' - """, - ( - json.dumps(dict(**payment.extra, tipSplitted=True)), - amount, - payment.payment_hash, - ), - ) - - # perform the internal transfer using the same payment_hash - internal_checking_id = f"internal_{urlsafe_short_hash()}" - await create_payment( + payment_hash, payment_request = await create_invoice( wallet_id=tpos.tip_wallet, - checking_id=internal_checking_id, - payment_request="", - payment_hash=payment.payment_hash, - amount=tipAmount, - memo=f"Tip for {payment.memo}", - pending=False, - extra={"tipSplitted": True}, + amount=int(tipAmount), # sats + internal=True, + memo=f"tpos tip", ) + logger.debug(f"tpos: tip invoice created: {payment_hash}") - # manually send this for now - await internal_invoice_queue.put(internal_checking_id) - return + checking_id = await pay_invoice( + payment_request=payment_request, + wallet_id=payment.wallet_id, + extra={"tag": "tpos"}, + ) + logger.debug(f"tpos: tip invoice paid: {checking_id}") From e1fbb8c3cd112d56bbd147565cc649f007d42287 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Fri, 21 Oct 2022 18:28:39 +0200 Subject: [PATCH 06/11] fix livestream extension --- lnbits/extensions/livestream/tasks.py | 52 ++++++++------------------- 1 file changed, 14 insertions(+), 38 deletions(-) diff --git a/lnbits/extensions/livestream/tasks.py b/lnbits/extensions/livestream/tasks.py index 626c698c..d081332f 100644 --- a/lnbits/extensions/livestream/tasks.py +++ b/lnbits/extensions/livestream/tasks.py @@ -4,10 +4,10 @@ import json from loguru import logger from lnbits.core import db as core_db -from lnbits.core.crud import create_payment from lnbits.core.models import Payment -from lnbits.helpers import get_current_extension_name, urlsafe_short_hash -from lnbits.tasks import internal_invoice_listener, register_invoice_listener +from lnbits.core.services import create_invoice, pay_invoice +from lnbits.helpers import get_current_extension_name +from lnbits.tasks import register_invoice_listener from .crud import get_livestream_by_track, get_producer, get_track @@ -44,44 +44,20 @@ async def on_invoice_paid(payment: Payment) -> None: # now we make a special kind of internal transfer amount = int(payment.amount * (100 - ls.fee_pct) / 100) - # mark the original payment with two extra keys, "shared_with" and "received" - # (this prevents us from doing this process again and it's informative) - # and reduce it by the amount we're going to send to the producer - await core_db.execute( - """ - UPDATE apipayments - SET extra = ?, amount = ? - WHERE hash = ? - AND checking_id NOT LIKE 'internal_%' - """, - ( - json.dumps( - dict( - **payment.extra, - shared_with=[producer.name, producer.id], - received=payment.amount, - ) - ), - payment.amount - amount, - payment.payment_hash, - ), - ) - - # perform an internal transfer using the same payment_hash to the producer wallet - internal_checking_id = f"internal_{urlsafe_short_hash()}" - await create_payment( - wallet_id=producer.wallet, - checking_id=internal_checking_id, - payment_request="", - payment_hash=payment.payment_hash, - amount=amount, + payment_hash, payment_request = await create_invoice( + wallet_id=tpos.tip_wallet, + amount=amount, # sats + internal=True, memo=f"Revenue from '{track.name}'.", - pending=False, ) + logger.debug(f"livestream: producer invoice created: {payment_hash}") - # manually send this for now - # await internal_invoice_paid.send(internal_checking_id) - await internal_invoice_listener.put(internal_checking_id) + checking_id = await pay_invoice( + payment_request=payment_request, + wallet_id=payment.wallet_id, + extra={"tag": "livestream"}, + ) + logger.debug(f"livestream: producer invoice paid: {checking_id}") # so the flow is the following: # - we receive, say, 1000 satoshis From 3814989b3a142baaea1d010f7022882b72280f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Pha=CC=A3m-Bachelart?= Date: Mon, 24 Oct 2022 11:46:32 +0200 Subject: [PATCH 07/11] Add cliche wallet (#1071) --- docs/guide/wallets.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/guide/wallets.md b/docs/guide/wallets.md index 80fb54c0..10724f34 100644 --- a/docs/guide/wallets.md +++ b/docs/guide/wallets.md @@ -79,3 +79,8 @@ For the invoice to work you must have a publicly accessible URL in your LNbits. - `LNBITS_BACKEND_WALLET_CLASS`: **OpenNodeWallet** - `OPENNODE_API_ENDPOINT`: https://api.opennode.com/ - `OPENNODE_KEY`: opennodeAdminApiKey + + +### Cliche Wallet + +- `CLICHE_ENDPOINT`: ws://127.0.0.1:12000 From fc1a87f617a60de29552c8196a7f08050bb60ce5 Mon Sep 17 00:00:00 2001 From: Aaron Dewes Date: Mon, 24 Oct 2022 11:50:52 +0200 Subject: [PATCH 08/11] Remove unused proxy_fix (#1007) --- lnbits/app.py | 1 - lnbits/proxy_fix.py | 95 --------------------------------------------- 2 files changed, 96 deletions(-) delete mode 100644 lnbits/proxy_fix.py diff --git a/lnbits/app.py b/lnbits/app.py index 8b9cf798..075828ef 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -91,7 +91,6 @@ def create_app(config_object="lnbits.settings") -> FastAPI: ) app.add_middleware(GZipMiddleware, minimum_size=1000) - # app.add_middleware(ASGIProxyFix) check_funding_source(app) register_assets(app) diff --git a/lnbits/proxy_fix.py b/lnbits/proxy_fix.py deleted file mode 100644 index 897835e0..00000000 --- a/lnbits/proxy_fix.py +++ /dev/null @@ -1,95 +0,0 @@ -from functools import partial -from typing import Callable, List, Optional -from urllib.parse import urlparse -from urllib.request import parse_http_list as _parse_list_header - -from quart import Request -from quart_trio.asgi import TrioASGIHTTPConnection -from werkzeug.datastructures import Headers - - -class ASGIProxyFix(TrioASGIHTTPConnection): - def _create_request_from_scope(self, send: Callable) -> Request: - headers = Headers() - headers["Remote-Addr"] = (self.scope.get("client") or [""])[0] - for name, value in self.scope["headers"]: - headers.add(name.decode("latin1").title(), value.decode("latin1")) - if self.scope["http_version"] < "1.1": - headers.setdefault("Host", self.app.config["SERVER_NAME"] or "") - - path = self.scope["path"] - path = path if path[0] == "/" else urlparse(path).path - - x_proto = self._get_real_value(1, headers.get("X-Forwarded-Proto")) - if x_proto: - self.scope["scheme"] = x_proto - - x_host = self._get_real_value(1, headers.get("X-Forwarded-Host")) - if x_host: - headers["host"] = x_host.lower() - - return self.app.request_class( - self.scope["method"], - self.scope["scheme"], - path, - self.scope["query_string"], - headers, - self.scope.get("root_path", ""), - self.scope["http_version"], - max_content_length=self.app.config["MAX_CONTENT_LENGTH"], - body_timeout=self.app.config["BODY_TIMEOUT"], - send_push_promise=partial(self._send_push_promise, send), - scope=self.scope, - ) - - def _get_real_value(self, trusted: int, value: Optional[str]) -> Optional[str]: - """Get the real value from a list header based on the configured - number of trusted proxies. - :param trusted: Number of values to trust in the header. - :param value: Comma separated list header value to parse. - :return: The real value, or ``None`` if there are fewer values - than the number of trusted proxies. - .. versionchanged:: 1.0 - Renamed from ``_get_trusted_comma``. - .. versionadded:: 0.15 - """ - if not (trusted and value): - return None - - values = self.parse_list_header(value) - if len(values) >= trusted: - return values[-trusted] - - return None - - def parse_list_header(self, value: str) -> List[str]: - result = [] - for item in _parse_list_header(value): - if item[:1] == item[-1:] == '"': - item = self.unquote_header_value(item[1:-1]) - result.append(item) - return result - - def unquote_header_value(self, value: str, is_filename: bool = False) -> str: - r"""Unquotes a header value. (Reversal of :func:`quote_header_value`). - This does not use the real unquoting but what browsers are actually - using for quoting. - .. versionadded:: 0.5 - :param value: the header value to unquote. - :param is_filename: The value represents a filename or path. - """ - if value and value[0] == value[-1] == '"': - # this is not the real unquoting, but fixing this so that the - # RFC is met will result in bugs with internet explorer and - # probably some other browsers as well. IE for example is - # uploading files with "C:\foo\bar.txt" as filename - value = value[1:-1] - - # if this is a filename and the starting characters look like - # a UNC path, then just return the value without quotes. Using the - # replace sequence below on a UNC path has the effect of turning - # the leading double slash into a single slash and then - # _fix_ie_filename() doesn't work correctly. See #458. - if not is_filename or value[:2] != "\\\\": - return value.replace("\\\\", "\\").replace('\\"', '"') - return value From 193d037ad6aa102152a824611c65a96a6ff876df Mon Sep 17 00:00:00 2001 From: Anton Kovalenko Date: Mon, 24 Oct 2022 13:23:11 +0300 Subject: [PATCH 09/11] Allow more than 2-nd level domain in incoming ln-addresses (#914) --- lnbits/core/views/api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index c07df568..983d5a26 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -476,7 +476,7 @@ async def api_lnurlscan(code: str, wallet: WalletTypeInfo = Depends(get_key_type except: # parse internet identifier (user@domain.com) name_domain = code.split("@") - if len(name_domain) == 2 and len(name_domain[1].split(".")) == 2: + if len(name_domain) == 2 and len(name_domain[1].split(".")) >= 2: name, domain = name_domain url = ( ("http://" if domain.endswith(".onion") else "https://") From 09cf654427d8f42baee484a5146a180b1261b1e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 24 Oct 2022 12:32:20 +0200 Subject: [PATCH 10/11] Proper Error Handling for qrcode-stream components (#1076) * proper errorhandling for camera * fix javascript for calle --- lnbits/core/static/js/wallet.js | 29 ++++++++++++++++++++++++++ lnbits/core/templates/core/wallet.html | 2 ++ 2 files changed, 31 insertions(+) diff --git a/lnbits/core/static/js/wallet.js b/lnbits/core/static/js/wallet.js index 76d82ad4..66801313 100644 --- a/lnbits/core/static/js/wallet.js +++ b/lnbits/core/static/js/wallet.js @@ -361,6 +361,35 @@ new Vue({ this.receive.status = 'pending' }) }, + onInitQR: async function (promise) { + try { + await promise + } catch (error) { + let mapping = { + NotAllowedError: 'ERROR: you need to grant camera access permission', + NotFoundError: 'ERROR: no camera on this device', + NotSupportedError: + 'ERROR: secure context required (HTTPS, localhost)', + NotReadableError: 'ERROR: is the camera already in use?', + OverconstrainedError: 'ERROR: installed cameras are not suitable', + StreamApiNotSupportedError: + 'ERROR: Stream API is not supported in this browser', + InsecureContextError: + 'ERROR: Camera access is only permitted in secure context. Use HTTPS or localhost rather than HTTP.' + } + let valid_error = Object.keys(mapping).filter(key => { + return error.name === key + }) + let camera_error = valid_error + ? mapping[valid_error] + : `ERROR: Camera error (${error.name})` + this.parse.camera.show = false + this.$q.notify({ + message: camera_error, + type: 'negative' + }) + } + }, decodeQR: function (res) { this.parse.data.request = res this.decodeRequest() diff --git a/lnbits/core/templates/core/wallet.html b/lnbits/core/templates/core/wallet.html index bccdc2b4..4bf6067c 100644 --- a/lnbits/core/templates/core/wallet.html +++ b/lnbits/core/templates/core/wallet.html @@ -653,6 +653,7 @@ @@ -671,6 +672,7 @@
From 09871bbabc27b69886d56770178b19f445b7c48f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 24 Oct 2022 16:29:30 +0200 Subject: [PATCH 11/11] fix mypy for extensions (#873) * explicitly exclude all extensions from mypy * fix example extension mypy * fix subdomains extension mypy + 1 type error fixed * fix mypy discordbot * mypy check copilot extensnion * copilot black * add invoices ext to ignore * add boltz and boltcard * copilit id is necessary * was discordbot is ok Co-authored-by: dni --- lnbits/extensions/copilot/crud.py | 8 ++--- lnbits/extensions/copilot/tasks.py | 20 ++++++------ lnbits/extensions/copilot/views.py | 8 +++-- lnbits/extensions/copilot/views_api.py | 9 +++--- lnbits/extensions/discordbot/crud.py | 6 ++-- lnbits/extensions/discordbot/views.py | 4 ++- lnbits/extensions/discordbot/views_api.py | 39 +++++++++++++---------- lnbits/extensions/example/views.py | 5 ++- lnbits/extensions/subdomains/crud.py | 4 +-- lnbits/extensions/subdomains/models.py | 30 ++++++++--------- lnbits/extensions/subdomains/tasks.py | 4 +-- lnbits/extensions/subdomains/views.py | 4 ++- lnbits/extensions/subdomains/views_api.py | 25 +++++++++++---- pyproject.toml | 30 +++++++++++++++-- 14 files changed, 125 insertions(+), 71 deletions(-) diff --git a/lnbits/extensions/copilot/crud.py b/lnbits/extensions/copilot/crud.py index d0da044e..5ecb5cd4 100644 --- a/lnbits/extensions/copilot/crud.py +++ b/lnbits/extensions/copilot/crud.py @@ -10,7 +10,7 @@ from .models import Copilots, CreateCopilotData async def create_copilot( data: CreateCopilotData, inkey: Optional[str] = "" -) -> Copilots: +) -> Optional[Copilots]: copilot_id = urlsafe_short_hash() await db.execute( """ @@ -67,19 +67,19 @@ async def create_copilot( async def update_copilot( - data: CreateCopilotData, copilot_id: Optional[str] = "" + data: CreateCopilotData, copilot_id: str ) -> Optional[Copilots]: q = ", ".join([f"{field[0]} = ?" for field in data]) items = [f"{field[1]}" for field in data] items.append(copilot_id) - await db.execute(f"UPDATE copilot.newer_copilots SET {q} WHERE id = ?", (items)) + await db.execute(f"UPDATE copilot.newer_copilots SET {q} WHERE id = ?", (items,)) row = await db.fetchone( "SELECT * FROM copilot.newer_copilots WHERE id = ?", (copilot_id,) ) return Copilots(**row) if row else None -async def get_copilot(copilot_id: str) -> Copilots: +async def get_copilot(copilot_id: str) -> Optional[Copilots]: row = await db.fetchone( "SELECT * FROM copilot.newer_copilots WHERE id = ?", (copilot_id,) ) diff --git a/lnbits/extensions/copilot/tasks.py b/lnbits/extensions/copilot/tasks.py index c59ef4cc..48ad7813 100644 --- a/lnbits/extensions/copilot/tasks.py +++ b/lnbits/extensions/copilot/tasks.py @@ -26,7 +26,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: webhook = None data = None - if payment.extra.get("tag") != "copilot": + if not payment.extra or payment.extra.get("tag") != "copilot": # not an copilot invoice return @@ -71,12 +71,12 @@ async def on_invoice_paid(payment: Payment) -> None: async def mark_webhook_sent(payment: Payment, status: int) -> None: - payment.extra["wh_status"] = status - - await core_db.execute( - """ - UPDATE apipayments SET extra = ? - WHERE hash = ? - """, - (json.dumps(payment.extra), payment.payment_hash), - ) + if payment.extra: + payment.extra["wh_status"] = status + await core_db.execute( + """ + UPDATE apipayments SET extra = ? + WHERE hash = ? + """, + (json.dumps(payment.extra), payment.payment_hash), + ) diff --git a/lnbits/extensions/copilot/views.py b/lnbits/extensions/copilot/views.py index 7ee7f590..b4a2354a 100644 --- a/lnbits/extensions/copilot/views.py +++ b/lnbits/extensions/copilot/views.py @@ -15,7 +15,9 @@ templates = Jinja2Templates(directory="templates") @copilot_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): +async def index( + request: Request, user: User = Depends(check_user_exists) # type: ignore +): return copilot_renderer().TemplateResponse( "copilot/index.html", {"request": request, "user": user.dict()} ) @@ -44,7 +46,7 @@ class ConnectionManager: async def connect(self, websocket: WebSocket, copilot_id: str): await websocket.accept() - websocket.id = copilot_id + websocket.id = copilot_id # type: ignore self.active_connections.append(websocket) def disconnect(self, websocket: WebSocket): @@ -52,7 +54,7 @@ class ConnectionManager: async def send_personal_message(self, message: str, copilot_id: str): for connection in self.active_connections: - if connection.id == copilot_id: + if connection.id == copilot_id: # type: ignore await connection.send_text(message) async def broadcast(self, message: str): diff --git a/lnbits/extensions/copilot/views_api.py b/lnbits/extensions/copilot/views_api.py index 91b0572a..46611a2e 100644 --- a/lnbits/extensions/copilot/views_api.py +++ b/lnbits/extensions/copilot/views_api.py @@ -23,7 +23,7 @@ from .views import updater @copilot_ext.get("/api/v1/copilot") async def api_copilots_retrieve( - req: Request, wallet: WalletTypeInfo = Depends(get_key_type) + req: Request, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore ): wallet_user = wallet.wallet.user copilots = [copilot.dict() for copilot in await get_copilots(wallet_user)] @@ -37,7 +37,7 @@ async def api_copilots_retrieve( async def api_copilot_retrieve( req: Request, copilot_id: str = Query(None), - wallet: WalletTypeInfo = Depends(get_key_type), + wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore ): copilot = await get_copilot(copilot_id) if not copilot: @@ -54,7 +54,7 @@ async def api_copilot_retrieve( async def api_copilot_create_or_update( data: CreateCopilotData, copilot_id: str = Query(None), - wallet: WalletTypeInfo = Depends(require_admin_key), + wallet: WalletTypeInfo = Depends(require_admin_key), # type: ignore ): data.user = wallet.wallet.user data.wallet = wallet.wallet.id @@ -67,7 +67,8 @@ async def api_copilot_create_or_update( @copilot_ext.delete("/api/v1/copilot/{copilot_id}") async def api_copilot_delete( - copilot_id: str = Query(None), wallet: WalletTypeInfo = Depends(require_admin_key) + copilot_id: str = Query(None), + wallet: WalletTypeInfo = Depends(require_admin_key), # type: ignore ): copilot = await get_copilot(copilot_id) diff --git a/lnbits/extensions/discordbot/crud.py b/lnbits/extensions/discordbot/crud.py index 5661fcb4..629a5c00 100644 --- a/lnbits/extensions/discordbot/crud.py +++ b/lnbits/extensions/discordbot/crud.py @@ -98,21 +98,21 @@ async def get_discordbot_wallet(wallet_id: str) -> Optional[Wallets]: return Wallets(**row) if row else None -async def get_discordbot_wallets(admin_id: str) -> Optional[Wallets]: +async def get_discordbot_wallets(admin_id: str) -> List[Wallets]: rows = await db.fetchall( "SELECT * FROM discordbot.wallets WHERE admin = ?", (admin_id,) ) return [Wallets(**row) for row in rows] -async def get_discordbot_users_wallets(user_id: str) -> Optional[Wallets]: +async def get_discordbot_users_wallets(user_id: str) -> List[Wallets]: rows = await db.fetchall( """SELECT * FROM discordbot.wallets WHERE "user" = ?""", (user_id,) ) return [Wallets(**row) for row in rows] -async def get_discordbot_wallet_transactions(wallet_id: str) -> Optional[Payment]: +async def get_discordbot_wallet_transactions(wallet_id: str) -> List[Payment]: return await get_payments( wallet_id=wallet_id, complete=True, pending=False, outgoing=True, incoming=True ) diff --git a/lnbits/extensions/discordbot/views.py b/lnbits/extensions/discordbot/views.py index a5395e21..ec7d18cc 100644 --- a/lnbits/extensions/discordbot/views.py +++ b/lnbits/extensions/discordbot/views.py @@ -9,7 +9,9 @@ from . import discordbot_ext, discordbot_renderer @discordbot_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): +async def index( + request: Request, user: User = Depends(check_user_exists) # type: ignore +): return discordbot_renderer().TemplateResponse( "discordbot/index.html", {"request": request, "user": user.dict()} ) diff --git a/lnbits/extensions/discordbot/views_api.py b/lnbits/extensions/discordbot/views_api.py index 6f213a89..e6d004db 100644 --- a/lnbits/extensions/discordbot/views_api.py +++ b/lnbits/extensions/discordbot/views_api.py @@ -27,32 +27,37 @@ from .models import CreateUserData, CreateUserWallet @discordbot_ext.get("/api/v1/users", status_code=HTTPStatus.OK) -async def api_discordbot_users(wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_discordbot_users( + wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore +): user_id = wallet.wallet.user return [user.dict() for user in await get_discordbot_users(user_id)] @discordbot_ext.get("/api/v1/users/{user_id}", status_code=HTTPStatus.OK) -async def api_discordbot_user(user_id, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_discordbot_user( + user_id, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore +): user = await get_discordbot_user(user_id) - return user.dict() + if user: + return user.dict() @discordbot_ext.post("/api/v1/users", status_code=HTTPStatus.CREATED) async def api_discordbot_users_create( - data: CreateUserData, wallet: WalletTypeInfo = Depends(get_key_type) + data: CreateUserData, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore ): user = await create_discordbot_user(data) full = user.dict() - full["wallets"] = [ - wallet.dict() for wallet in await get_discordbot_users_wallets(user.id) - ] + wallets = await get_discordbot_users_wallets(user.id) + if wallets: + full["wallets"] = [wallet for wallet in wallets] return full @discordbot_ext.delete("/api/v1/users/{user_id}") async def api_discordbot_users_delete( - user_id, wallet: WalletTypeInfo = Depends(get_key_type) + user_id, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore ): user = await get_discordbot_user(user_id) if not user: @@ -75,7 +80,7 @@ async def api_discordbot_activate_extension( raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) - update_user_extension(user_id=userid, extension=extension, active=active) + await update_user_extension(user_id=userid, extension=extension, active=active) return {"extension": "updated"} @@ -84,7 +89,7 @@ async def api_discordbot_activate_extension( @discordbot_ext.post("/api/v1/wallets") async def api_discordbot_wallets_create( - data: CreateUserWallet, wallet: WalletTypeInfo = Depends(get_key_type) + data: CreateUserWallet, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore ): user = await create_discordbot_wallet( user_id=data.user_id, wallet_name=data.wallet_name, admin_id=data.admin_id @@ -93,28 +98,30 @@ async def api_discordbot_wallets_create( @discordbot_ext.get("/api/v1/wallets") -async def api_discordbot_wallets(wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_discordbot_wallets( + wallet: WalletTypeInfo = Depends(get_key_type), # type: ignore +): admin_id = wallet.wallet.user - return [wallet.dict() for wallet in await get_discordbot_wallets(admin_id)] + return await get_discordbot_wallets(admin_id) @discordbot_ext.get("/api/v1/transactions/{wallet_id}") async def api_discordbot_wallet_transactions( - wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) + wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore ): return await get_discordbot_wallet_transactions(wallet_id) @discordbot_ext.get("/api/v1/wallets/{user_id}") async def api_discordbot_users_wallets( - user_id, wallet: WalletTypeInfo = Depends(get_key_type) + user_id, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore ): - return [s_wallet.dict() for s_wallet in await get_discordbot_users_wallets(user_id)] + return await get_discordbot_users_wallets(user_id) @discordbot_ext.delete("/api/v1/wallets/{wallet_id}") async def api_discordbot_wallets_delete( - wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) + wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) # type: ignore ): get_wallet = await get_discordbot_wallet(wallet_id) if not get_wallet: diff --git a/lnbits/extensions/example/views.py b/lnbits/extensions/example/views.py index 252b4726..29b257f4 100644 --- a/lnbits/extensions/example/views.py +++ b/lnbits/extensions/example/views.py @@ -12,7 +12,10 @@ templates = Jinja2Templates(directory="templates") @example_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): +async def index( + request: Request, + user: User = Depends(check_user_exists), # type: ignore +): return example_renderer().TemplateResponse( "example/index.html", {"request": request, "user": user.dict()} ) diff --git a/lnbits/extensions/subdomains/crud.py b/lnbits/extensions/subdomains/crud.py index 207e2d1d..aa358d11 100644 --- a/lnbits/extensions/subdomains/crud.py +++ b/lnbits/extensions/subdomains/crud.py @@ -3,10 +3,10 @@ from typing import List, Optional, Union from lnbits.helpers import urlsafe_short_hash from . import db -from .models import CreateDomain, Domains, Subdomains +from .models import CreateDomain, CreateSubdomain, Domains, Subdomains -async def create_subdomain(payment_hash, wallet, data: CreateDomain) -> Subdomains: +async def create_subdomain(payment_hash, wallet, data: CreateSubdomain) -> Subdomains: await db.execute( """ INSERT INTO subdomains.subdomain (id, domain, email, subdomain, ip, wallet, sats, duration, paid, record_type) diff --git a/lnbits/extensions/subdomains/models.py b/lnbits/extensions/subdomains/models.py index 17004504..39e17615 100644 --- a/lnbits/extensions/subdomains/models.py +++ b/lnbits/extensions/subdomains/models.py @@ -3,24 +3,24 @@ from pydantic.main import BaseModel class CreateDomain(BaseModel): - wallet: str = Query(...) - domain: str = Query(...) - cf_token: str = Query(...) - cf_zone_id: str = Query(...) - webhook: str = Query("") - description: str = Query(..., min_length=0) - cost: int = Query(..., ge=0) - allowed_record_types: str = Query(...) + wallet: str = Query(...) # type: ignore + domain: str = Query(...) # type: ignore + cf_token: str = Query(...) # type: ignore + cf_zone_id: str = Query(...) # type: ignore + webhook: str = Query("") # type: ignore + description: str = Query(..., min_length=0) # type: ignore + cost: int = Query(..., ge=0) # type: ignore + allowed_record_types: str = Query(...) # type: ignore class CreateSubdomain(BaseModel): - domain: str = Query(...) - subdomain: str = Query(...) - email: str = Query(...) - ip: str = Query(...) - sats: int = Query(..., ge=0) - duration: int = Query(...) - record_type: str = Query(...) + domain: str = Query(...) # type: ignore + subdomain: str = Query(...) # type: ignore + email: str = Query(...) # type: ignore + ip: str = Query(...) # type: ignore + sats: int = Query(..., ge=0) # type: ignore + duration: int = Query(...) # type: ignore + record_type: str = Query(...) # type: ignore class Domains(BaseModel): diff --git a/lnbits/extensions/subdomains/tasks.py b/lnbits/extensions/subdomains/tasks.py index 04ee2dd4..c5a7f47b 100644 --- a/lnbits/extensions/subdomains/tasks.py +++ b/lnbits/extensions/subdomains/tasks.py @@ -20,7 +20,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if payment.extra.get("tag") != "lnsubdomain": + if not payment.extra or payment.extra.get("tag") != "lnsubdomain": # not an lnurlp invoice return @@ -37,7 +37,7 @@ async def on_invoice_paid(payment: Payment) -> None: ) ### Use webhook to notify about cloudflare registration - if domain.webhook: + if domain and domain.webhook: async with httpx.AsyncClient() as client: try: r = await client.post( diff --git a/lnbits/extensions/subdomains/views.py b/lnbits/extensions/subdomains/views.py index df387ba8..962f850d 100644 --- a/lnbits/extensions/subdomains/views.py +++ b/lnbits/extensions/subdomains/views.py @@ -16,7 +16,9 @@ templates = Jinja2Templates(directory="templates") @subdomains_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): +async def index( + request: Request, user: User = Depends(check_user_exists) # type:ignore +): return subdomains_renderer().TemplateResponse( "subdomains/index.html", {"request": request, "user": user.dict()} ) diff --git a/lnbits/extensions/subdomains/views_api.py b/lnbits/extensions/subdomains/views_api.py index b01e6ffb..34d8e75b 100644 --- a/lnbits/extensions/subdomains/views_api.py +++ b/lnbits/extensions/subdomains/views_api.py @@ -29,12 +29,15 @@ from .crud import ( @subdomains_ext.get("/api/v1/domains") async def api_domains( - g: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False) + g: WalletTypeInfo = Depends(get_key_type), # type: ignore + all_wallets: bool = Query(False), ): wallet_ids = [g.wallet.id] if all_wallets: - wallet_ids = (await get_user(g.wallet.user)).wallet_ids + user = await get_user(g.wallet.user) + if user is not None: + wallet_ids = user.wallet_ids return [domain.dict() for domain in await get_domains(wallet_ids)] @@ -42,7 +45,9 @@ async def api_domains( @subdomains_ext.post("/api/v1/domains") @subdomains_ext.put("/api/v1/domains/{domain_id}") async def api_domain_create( - data: CreateDomain, domain_id=None, g: WalletTypeInfo = Depends(get_key_type) + data: CreateDomain, + domain_id=None, + g: WalletTypeInfo = Depends(get_key_type), # type: ignore ): if domain_id: domain = await get_domain(domain_id) @@ -63,7 +68,9 @@ async def api_domain_create( @subdomains_ext.delete("/api/v1/domains/{domain_id}") -async def api_domain_delete(domain_id, g: WalletTypeInfo = Depends(get_key_type)): +async def api_domain_delete( + domain_id, g: WalletTypeInfo = Depends(get_key_type) # type: ignore +): domain = await get_domain(domain_id) if not domain: @@ -82,12 +89,14 @@ async def api_domain_delete(domain_id, g: WalletTypeInfo = Depends(get_key_type) @subdomains_ext.get("/api/v1/subdomains") async def api_subdomains( - all_wallets: bool = Query(False), g: WalletTypeInfo = Depends(get_key_type) + all_wallets: bool = Query(False), g: WalletTypeInfo = Depends(get_key_type) # type: ignore ): wallet_ids = [g.wallet.id] if all_wallets: - wallet_ids = (await get_user(g.wallet.user)).wallet_ids + user = await get_user(g.wallet.user) + if user is not None: + wallet_ids = user.wallet_ids return [domain.dict() for domain in await get_subdomains(wallet_ids)] @@ -173,7 +182,9 @@ async def api_subdomain_send_subdomain(payment_hash): @subdomains_ext.delete("/api/v1/subdomains/{subdomain_id}") -async def api_subdomain_delete(subdomain_id, g: WalletTypeInfo = Depends(get_key_type)): +async def api_subdomain_delete( + subdomain_id, g: WalletTypeInfo = Depends(get_key_type) # type: ignore +): subdomain = await get_subdomain(subdomain_id) if not subdomain: diff --git a/pyproject.toml b/pyproject.toml index 19dac860..7418de27 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,8 +89,34 @@ profile = "black" ignore_missing_imports = "True" files = "lnbits" exclude = """(?x)( - ^lnbits/extensions. - | ^lnbits/wallets/lnd_grpc_files. + ^lnbits/extensions/bleskomat. + | ^lnbits/extensions/boltz. + | ^lnbits/extensions/boltcards. + | ^lnbits/extensions/events. + | ^lnbits/extensions/hivemind. + | ^lnbits/extensions/invoices. + | ^lnbits/extensions/jukebox. + | ^lnbits/extensions/livestream. + | ^lnbits/extensions/lnaddress. + | ^lnbits/extensions/lndhub. + | ^lnbits/extensions/lnticket. + | ^lnbits/extensions/lnurldevice. + | ^lnbits/extensions/lnurlp. + | ^lnbits/extensions/lnurlpayout. + | ^lnbits/extensions/ngrok. + | ^lnbits/extensions/offlineshop. + | ^lnbits/extensions/paywall. + | ^lnbits/extensions/satsdice. + | ^lnbits/extensions/satspay. + | ^lnbits/extensions/scrub. + | ^lnbits/extensions/splitpayments. + | ^lnbits/extensions/streamalerts. + | ^lnbits/extensions/tipjar. + | ^lnbits/extensions/tpos. + | ^lnbits/extensions/usermanager. + | ^lnbits/extensions/watchonly. + | ^lnbits/extensions/withdraw. + | ^lnbits/wallets/lnd_grpc_files. )""" [tool.pytest.ini_options]