From 1d3bb016a2421e4ced5168611c1c8a72382468f3 Mon Sep 17 00:00:00 2001 From: benarc Date: Sun, 17 Oct 2021 18:33:29 +0100 Subject: [PATCH] I want them to turn black --- lnbits/__main__.py | 11 +- lnbits/app.py | 50 ++++-- lnbits/auth_bearer.py | 12 +- lnbits/bolt11.py | 13 +- lnbits/core/__init__.py | 2 - lnbits/core/crud.py | 48 ++---- lnbits/core/models.py | 13 +- lnbits/core/services.py | 18 +- lnbits/core/tasks.py | 11 +- lnbits/core/views/api.py | 190 ++++++++++++--------- lnbits/core/views/generic.py | 162 +++++++++++------- lnbits/core/views/public_api.py | 12 +- lnbits/decorators.py | 92 +++++++--- lnbits/extensions/copilot/__init__.py | 6 +- lnbits/extensions/copilot/lnurl.py | 17 +- lnbits/extensions/copilot/tasks.py | 3 +- lnbits/extensions/copilot/views_api.py | 26 +-- lnbits/extensions/jukebox/__init__.py | 6 +- lnbits/extensions/jukebox/crud.py | 10 +- lnbits/extensions/jukebox/views_api.py | 111 ++++-------- lnbits/extensions/lndhub/__init__.py | 6 +- lnbits/extensions/lndhub/decorators.py | 26 ++- lnbits/extensions/lndhub/views_api.py | 32 ++-- lnbits/extensions/lnticket/__init__.py | 8 +- lnbits/extensions/lnticket/crud.py | 31 +++- lnbits/extensions/lnticket/migrations.py | 31 +--- lnbits/extensions/lnticket/models.py | 3 + lnbits/extensions/lnticket/views.py | 24 +-- lnbits/extensions/lnticket/views_api.py | 54 +++--- lnbits/extensions/lnurlp/__init__.py | 6 +- lnbits/extensions/lnurlp/crud.py | 5 +- lnbits/extensions/lnurlp/lnurl.py | 55 +++--- lnbits/extensions/lnurlp/models.py | 24 ++- lnbits/extensions/lnurlp/tasks.py | 1 + lnbits/extensions/lnurlp/views.py | 19 ++- lnbits/extensions/offlineshop/__init__.py | 6 +- lnbits/extensions/offlineshop/crud.py | 7 +- lnbits/extensions/offlineshop/helpers.py | 4 +- lnbits/extensions/offlineshop/lnurl.py | 14 +- lnbits/extensions/offlineshop/models.py | 12 +- lnbits/extensions/offlineshop/views.py | 25 ++- lnbits/extensions/offlineshop/views_api.py | 26 ++- lnbits/extensions/satsdice/__init__.py | 6 +- lnbits/extensions/satsdice/crud.py | 25 +-- lnbits/extensions/satsdice/lnurl.py | 42 ++--- lnbits/extensions/satsdice/models.py | 14 +- lnbits/extensions/satsdice/views.py | 4 +- lnbits/extensions/satsdice/views_api.py | 40 ++--- lnbits/extensions/satspay/__init__.py | 12 +- lnbits/extensions/satspay/crud.py | 5 +- lnbits/extensions/satspay/models.py | 2 + lnbits/extensions/satspay/views.py | 12 +- lnbits/extensions/satspay/views_api.py | 44 ++--- lnbits/extensions/tpos/__init__.py | 7 +- lnbits/extensions/tpos/models.py | 1 + lnbits/extensions/tpos/views.py | 12 +- lnbits/extensions/tpos/views_api.py | 35 ++-- lnbits/extensions/usermanager/__init__.py | 9 +- lnbits/extensions/usermanager/crud.py | 15 +- lnbits/extensions/usermanager/models.py | 1 + lnbits/extensions/usermanager/views.py | 5 +- lnbits/extensions/usermanager/views_api.py | 51 +++--- lnbits/extensions/watchonly/__init__.py | 12 +- lnbits/extensions/watchonly/models.py | 2 + lnbits/extensions/watchonly/views.py | 5 +- lnbits/extensions/watchonly/views_api.py | 27 ++- lnbits/extensions/withdraw/__init__.py | 7 +- lnbits/extensions/withdraw/crud.py | 14 +- lnbits/extensions/withdraw/lnurl.py | 42 ++--- lnbits/extensions/withdraw/models.py | 19 +-- lnbits/extensions/withdraw/views.py | 39 +++-- lnbits/extensions/withdraw/views_api.py | 48 +++--- lnbits/helpers.py | 18 +- lnbits/jinja2_templating.py | 4 +- lnbits/requestvars.py | 5 +- lnbits/settings.py | 3 +- lnbits/wallets/clightning.py | 11 +- lnbits/wallets/lnbits.py | 8 +- lnbits/wallets/lndgrpc.py | 25 +-- lnbits/wallets/lndrest.py | 19 +-- lnbits/wallets/lnpay.py | 4 +- lnbits/wallets/lntxbot.py | 12 +- lnbits/wallets/opennode.py | 6 +- lnbits/wallets/spark.py | 3 +- 84 files changed, 899 insertions(+), 1008 deletions(-) diff --git a/lnbits/__main__.py b/lnbits/__main__.py index e9c43cda..8461eb42 100644 --- a/lnbits/__main__.py +++ b/lnbits/__main__.py @@ -4,8 +4,15 @@ import uvloop from starlette.requests import Request from .commands import bundle_vendored, migrate_databases, transpile_scss -from .settings import (DEBUG, LNBITS_COMMIT, LNBITS_DATA_FOLDER, - LNBITS_SITE_TITLE, PORT, SERVICE_FEE, WALLET) +from .settings import ( + DEBUG, + LNBITS_COMMIT, + LNBITS_DATA_FOLDER, + LNBITS_SITE_TITLE, + PORT, + SERVICE_FEE, + WALLET, +) uvloop.install() diff --git a/lnbits/app.py b/lnbits/app.py index 8ffe4318..f85a009f 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -16,12 +16,23 @@ import lnbits.settings from .commands import db_migrate, handle_assets from .core import core_app from .core.views.generic import core_html_routes -from .helpers import (get_css_vendored, get_js_vendored, get_valid_extensions, - template_renderer, url_for_vendored) +from .helpers import ( + get_css_vendored, + get_js_vendored, + get_valid_extensions, + template_renderer, + url_for_vendored, +) from .requestvars import g from .settings import WALLET -from .tasks import (catch_everything_and_restart, check_pending_payments, internal_invoice_listener, - invoice_listener, run_deferred_async, webhook_handler) +from .tasks import ( + catch_everything_and_restart, + check_pending_payments, + internal_invoice_listener, + invoice_listener, + run_deferred_async, + webhook_handler, +) def create_app(config_object="lnbits.settings") -> FastAPI: @@ -30,12 +41,11 @@ def create_app(config_object="lnbits.settings") -> FastAPI: """ app = FastAPI() app.mount("/static", StaticFiles(directory="lnbits/static"), name="static") - app.mount("/core/static", StaticFiles(directory="lnbits/core/static"), name="core_static") + app.mount( + "/core/static", StaticFiles(directory="lnbits/core/static"), name="core_static" + ) - origins = [ - "http://localhost", - "http://localhost:5000", - ] + origins = ["http://localhost", "http://localhost:5000"] app.add_middleware( CORSMiddleware, @@ -44,14 +54,19 @@ def create_app(config_object="lnbits.settings") -> FastAPI: allow_methods=["*"], allow_headers=["*"], ) - + g().config = lnbits.settings g().base_url = f"http://{lnbits.settings.HOST}:{lnbits.settings.PORT}" @app.exception_handler(RequestValidationError) - async def validation_exception_handler(request: Request, exc: RequestValidationError): - return template_renderer().TemplateResponse("error.html", {"request": request, "err": f"`{exc.errors()}` is not a valid UUID."}) - + async def validation_exception_handler( + request: Request, exc: RequestValidationError + ): + return template_renderer().TemplateResponse( + "error.html", + {"request": request, "err": f"`{exc.errors()}` is not a valid UUID."}, + ) + # return HTMLResponse( # status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, # content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}), @@ -69,6 +84,7 @@ def create_app(config_object="lnbits.settings") -> FastAPI: return app + def check_funding_source(app: FastAPI) -> None: @app.on_event("startup") async def check_wallet_status(): @@ -95,7 +111,7 @@ def register_routes(app: FastAPI) -> None: try: ext_module = importlib.import_module(f"lnbits.extensions.{ext.code}") ext_route = getattr(ext_module, f"{ext.code}_ext") - + if hasattr(ext_module, f"{ext.code}_start"): ext_start_func = getattr(ext_module, f"{ext.code}_start") ext_start_func() @@ -150,6 +166,7 @@ def register_async_tasks(app): async def stop_listeners(): pass + def register_exception_handlers(app: FastAPI): @app.exception_handler(Exception) async def basic_error(request: Request, err): @@ -157,5 +174,6 @@ def register_exception_handlers(app: FastAPI): etype, _, tb = sys.exc_info() traceback.print_exception(etype, err, tb) exc = traceback.format_exc() - return template_renderer().TemplateResponse("error.html", {"request": request, "err": err}) - + return template_renderer().TemplateResponse( + "error.html", {"request": request, "err": err} + ) diff --git a/lnbits/auth_bearer.py b/lnbits/auth_bearer.py index 81b93427..163785dd 100644 --- a/lnbits/auth_bearer.py +++ b/lnbits/auth_bearer.py @@ -8,7 +8,6 @@ from fastapi.security.api_key import APIKeyQuery, APIKeyCookie, APIKeyHeader, AP from fastapi.security.base import SecurityBase - API_KEY = "usr" API_KEY_NAME = "X-API-key" @@ -16,12 +15,11 @@ api_key_query = APIKeyQuery(name=API_KEY_NAME, auto_error=False) api_key_header = APIKeyHeader(name=API_KEY_NAME, auto_error=False) - class AuthBearer(SecurityBase): def __init__(self, scheme_name: str = None, auto_error: bool = True): self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error - + async def __call__(self, request: Request): key = await self.get_api_key() print(key) @@ -37,7 +35,9 @@ class AuthBearer(SecurityBase): # else: # raise HTTPException( # status_code=403, detail="Invalid authorization code.") - async def get_api_key(self, + + async def get_api_key( + self, api_key_query: str = Security(api_key_query), api_key_header: str = Security(api_key_header), ): @@ -46,4 +46,6 @@ class AuthBearer(SecurityBase): elif api_key_header == API_KEY: return api_key_header else: - raise HTTPException(status_code=403, detail="Could not validate credentials") \ No newline at end of file + raise HTTPException( + status_code=403, detail="Could not validate credentials" + ) diff --git a/lnbits/bolt11.py b/lnbits/bolt11.py index b9f3270b..7cd7a44c 100644 --- a/lnbits/bolt11.py +++ b/lnbits/bolt11.py @@ -125,12 +125,7 @@ def _unshorten_amount(amount: str) -> int: # * `u` (micro): multiply by 0.000001 # * `n` (nano): multiply by 0.000000001 # * `p` (pico): multiply by 0.000000000001 - units = { - "p": 10 ** 12, - "n": 10 ** 9, - "u": 10 ** 6, - "m": 10 ** 3, - } + units = {"p": 10 ** 12, "n": 10 ** 9, "u": 10 ** 6, "m": 10 ** 3} unit = str(amount)[-1] # BOLT #11: @@ -161,9 +156,9 @@ def _trim_to_bytes(barr): def _readable_scid(short_channel_id: int) -> str: return "{blockheight}x{transactionindex}x{outputindex}".format( - blockheight=((short_channel_id >> 40) & 0xffffff), - transactionindex=((short_channel_id >> 16) & 0xffffff), - outputindex=(short_channel_id & 0xffff), + blockheight=((short_channel_id >> 40) & 0xFFFFFF), + transactionindex=((short_channel_id >> 16) & 0xFFFFFF), + outputindex=(short_channel_id & 0xFFFF), ) diff --git a/lnbits/core/__init__.py b/lnbits/core/__init__.py index e632fba8..85e72d50 100644 --- a/lnbits/core/__init__.py +++ b/lnbits/core/__init__.py @@ -9,5 +9,3 @@ core_app: APIRouter = APIRouter() from .views.api import * # noqa from .views.generic import * # noqa from .views.public_api import * # noqa - - diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index e981f22c..f69ca95b 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -58,10 +58,11 @@ async def get_user(user_id: str, conn: Optional[Connection] = None) -> Optional[ return None return User( - id = user['id'], - email = user['email'], - extensions = [e[0] for e in extensions], - wallets = [Wallet(**w) for w in wallets]) + id=user["id"], + email=user["email"], + extensions=[e[0] for e in extensions], + wallets=[Wallet(**w) for w in wallets], + ) async def update_user_extension( @@ -106,6 +107,7 @@ async def create_wallet( return new_wallet + async def update_wallet( wallet_id: str, new_name: str, conn: Optional[Connection] = None ) -> Optional[Wallet]: @@ -115,7 +117,7 @@ async def update_wallet( name = ? WHERE id = ? """, - (new_name, wallet_id) + (new_name, wallet_id), ) @@ -276,9 +278,7 @@ async def get_payments( return [Payment.from_row(row) for row in rows] -async def delete_expired_invoices( - conn: Optional[Connection] = None, -) -> None: +async def delete_expired_invoices(conn: Optional[Connection] = None,) -> None: # first we delete all invoices older than one month await (conn or db).execute( f""" @@ -367,31 +367,22 @@ async def create_payment( async def update_payment_status( - checking_id: str, - pending: bool, - conn: Optional[Connection] = None, + checking_id: str, pending: bool, conn: Optional[Connection] = None ) -> None: await (conn or db).execute( "UPDATE apipayments SET pending = ? WHERE checking_id = ?", - ( - pending, - checking_id, - ), + (pending, checking_id), ) -async def delete_payment( - checking_id: str, - conn: Optional[Connection] = None, -) -> None: +async def delete_payment(checking_id: str, conn: Optional[Connection] = None) -> None: await (conn or db).execute( "DELETE FROM apipayments WHERE checking_id = ?", (checking_id,) ) async def check_internal( - payment_hash: str, - conn: Optional[Connection] = None, + payment_hash: str, conn: Optional[Connection] = None ) -> Optional[str]: row = await (conn or db).fetchone( """ @@ -411,9 +402,7 @@ async def check_internal( async def save_balance_check( - wallet_id: str, - url: str, - conn: Optional[Connection] = None, + wallet_id: str, url: str, conn: Optional[Connection] = None ): domain = urlparse(url).netloc @@ -427,9 +416,7 @@ async def save_balance_check( async def get_balance_check( - wallet_id: str, - domain: str, - conn: Optional[Connection] = None, + wallet_id: str, domain: str, conn: Optional[Connection] = None ) -> Optional[BalanceCheck]: row = await (conn or db).fetchone( """ @@ -452,9 +439,7 @@ async def get_balance_checks(conn: Optional[Connection] = None) -> List[BalanceC async def save_balance_notify( - wallet_id: str, - url: str, - conn: Optional[Connection] = None, + wallet_id: str, url: str, conn: Optional[Connection] = None ): await (conn or db).execute( """ @@ -466,8 +451,7 @@ async def save_balance_notify( async def get_balance_notify( - wallet_id: str, - conn: Optional[Connection] = None, + wallet_id: str, conn: Optional[Connection] = None ) -> Optional[str]: row = await (conn or db).fetchone( """ diff --git a/lnbits/core/models.py b/lnbits/core/models.py index 672a252c..c72c9dbe 100644 --- a/lnbits/core/models.py +++ b/lnbits/core/models.py @@ -30,13 +30,8 @@ class Wallet(BaseModel): @property def lnurlwithdraw_full(self) -> str: - - url = url_for( - "/withdraw", - external=True, - usr=self.user, - wal=self.id, - ) + + url = url_for("/withdraw", external=True, usr=self.user, wal=self.id) try: return lnurl_encode(url) except: @@ -47,9 +42,7 @@ class Wallet(BaseModel): linking_key = hmac.digest(hashing_key, domain.encode("utf-8"), "sha256") return SigningKey.from_string( - linking_key, - curve=SECP256k1, - hashfunc=hashlib.sha256, + linking_key, curve=SECP256k1, hashfunc=hashlib.sha256 ) async def get_payment(self, payment_hash: str) -> Optional["Payment"]: diff --git a/lnbits/core/services.py b/lnbits/core/services.py index ee83b338..21909d6e 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -147,9 +147,7 @@ async def pay_invoice( # so the other side only has access to his new money when we are sure # the payer has enough to deduct from await update_payment_status( - checking_id=internal_checking_id, - pending=False, - conn=conn, + checking_id=internal_checking_id, pending=False, conn=conn ) # notify receiver asynchronously @@ -213,10 +211,7 @@ async def redeem_lnurl_withdraw( if wait_seconds: await asyncio.sleep(wait_seconds) - params = { - "k1": res["k1"], - "pr": payment_request, - } + params = {"k1": res["k1"], "pr": payment_request} try: params["balanceNotify"] = url_for( @@ -235,8 +230,7 @@ async def redeem_lnurl_withdraw( async def perform_lnurlauth( - callback: str, - conn: Optional[Connection] = None, + callback: str, conn: Optional[Connection] = None ) -> Optional[LnurlErrorResponse]: cb = urlparse(callback) @@ -304,14 +298,12 @@ async def perform_lnurlauth( return LnurlErrorResponse(reason=resp["reason"]) except (KeyError, json.decoder.JSONDecodeError): return LnurlErrorResponse( - reason=r.text[:200] + "..." if len(r.text) > 200 else r.text, + reason=r.text[:200] + "..." if len(r.text) > 200 else r.text ) async def check_invoice_status( - wallet_id: str, - payment_hash: str, - conn: Optional[Connection] = None, + wallet_id: str, payment_hash: str, conn: Optional[Connection] = None ) -> PaymentStatus: payment = await get_wallet_payment(wallet_id, payment_hash, conn=conn) if not payment: diff --git a/lnbits/core/tasks.py b/lnbits/core/tasks.py index c75fbac8..9b5adcea 100644 --- a/lnbits/core/tasks.py +++ b/lnbits/core/tasks.py @@ -33,10 +33,7 @@ async def wait_for_paid_invoices(invoice_paid_queue: asyncio.Queue): if url: async with httpx.AsyncClient() as client: try: - r = await client.post( - url, - timeout=4, - ) + r = await client.post(url, timeout=4) await mark_webhook_sent(payment, r.status_code) except (httpx.ConnectError, httpx.RequestError): pass @@ -55,11 +52,7 @@ async def dispatch_webhook(payment: Payment): async with httpx.AsyncClient() as client: data = payment._asdict() try: - r = await client.post( - payment.webhook, - json=data, - timeout=40, - ) + r = await client.post(payment.webhook, json=data, timeout=40) await mark_webhook_sent(payment, r.status_code) except (httpx.ConnectError, httpx.RequestError): await mark_webhook_sent(payment, -1) diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index 2fc86095..ee330707 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -16,53 +16,67 @@ from pydantic import BaseModel from lnbits import bolt11, lnurl from lnbits.core.models import Payment, Wallet -from lnbits.decorators import (WalletAdminKeyChecker, WalletInvoiceKeyChecker, - WalletTypeInfo, get_key_type) +from lnbits.decorators import ( + WalletAdminKeyChecker, + WalletInvoiceKeyChecker, + WalletTypeInfo, + get_key_type, +) from lnbits.helpers import url_for from lnbits.requestvars import g from lnbits.utils.exchange_rates import currencies, fiat_amount_as_satoshis from .. import core_app, db from ..crud import get_payments, save_balance_check, update_wallet -from ..services import (InvoiceFailure, PaymentFailure, create_invoice, - pay_invoice, perform_lnurlauth) +from ..services import ( + InvoiceFailure, + PaymentFailure, + create_invoice, + pay_invoice, + perform_lnurlauth, +) from ..tasks import api_invoice_listeners @core_app.get("/api/v1/wallet") async def api_wallet(wallet: WalletTypeInfo = Depends(get_key_type)): - return {"id": wallet.wallet.id, "name": wallet.wallet.name, "balance": wallet.wallet.balance_msat} - + return { + "id": wallet.wallet.id, + "name": wallet.wallet.name, + "balance": wallet.wallet.balance_msat, + } + @core_app.put("/api/v1/wallet/{new_name}") -async def api_update_wallet(new_name: str, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_update_wallet( + new_name: str, wallet: WalletTypeInfo = Depends(get_key_type) +): await update_wallet(wallet.wallet.id, new_name) return { "id": wallet.wallet.id, "name": wallet.wallet.name, "balance": wallet.wallet.balance_msat, } - @core_app.get("/api/v1/payments") async def api_payments(wallet: WalletTypeInfo = Depends(get_key_type)): return await get_payments(wallet_id=wallet.wallet.id, pending=True, complete=True) - - + class CreateInvoiceData(BaseModel): out: Optional[bool] = True - amount: int = Query(None, ge=1) - memo: str = None - unit: Optional[str] = None - description_hash: str = None - lnurl_callback: Optional[str] = None - lnurl_balance_check: Optional[str] = None - extra: Optional[dict] = None - webhook: Optional[str] = None + amount: int = Query(None, ge=1) + memo: str = None + unit: Optional[str] = None + description_hash: str = None + lnurl_callback: Optional[str] = None + lnurl_balance_check: Optional[str] = None + extra: Optional[dict] = None + webhook: Optional[str] = None bolt11: Optional[str] = None + async def api_payments_create_invoice(data: CreateInvoiceData, wallet: Wallet): if "description_hash" in data: description_hash = unhexlify(data.description_hash) @@ -89,7 +103,7 @@ async def api_payments_create_invoice(data: CreateInvoiceData, wallet: Wallet): conn=conn, ) except InvoiceFailure as e: - raise HTTPException(status_code=520, detail=str(e)) + raise HTTPException(status_code=520, detail=str(e)) except Exception as exc: raise exc @@ -132,31 +146,17 @@ async def api_payments_create_invoice(data: CreateInvoiceData, wallet: Wallet): "checking_id": invoice.payment_hash, "lnurl_response": lnurl_response, } - - async def api_payments_pay_invoice(bolt11: str, wallet: Wallet): try: - payment_hash = await pay_invoice( - wallet_id=wallet.id, - payment_request=bolt11, - ) + payment_hash = await pay_invoice(wallet_id=wallet.id, payment_request=bolt11) except ValueError as e: - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail=str(e) - ) + raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e)) except PermissionError as e: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail=str(e) - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail=str(e)) except PaymentFailure as e: - raise HTTPException( - status_code=520, - detail=str(e) - ) + raise HTTPException(status_code=520, detail=str(e)) except Exception as exc: raise exc @@ -165,34 +165,46 @@ async def api_payments_pay_invoice(bolt11: str, wallet: Wallet): # maintain backwards compatibility with API clients: "checking_id": payment_hash, } - -@core_app.post("/api/v1/payments", deprecated=True, - description="DEPRECATED. Use /api/v2/TBD and /api/v2/TBD instead", - status_code=HTTPStatus.CREATED) -async def api_payments_create(wallet: WalletTypeInfo = Depends(get_key_type), - invoiceData: CreateInvoiceData = Body(...)): - +@core_app.post( + "/api/v1/payments", + deprecated=True, + description="DEPRECATED. Use /api/v2/TBD and /api/v2/TBD instead", + status_code=HTTPStatus.CREATED, +) +async def api_payments_create( + wallet: WalletTypeInfo = Depends(get_key_type), + invoiceData: CreateInvoiceData = Body(...), +): + if wallet.wallet_type < 0 or wallet.wallet_type > 2: raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Key is invalid") if invoiceData.out is True and wallet.wallet_type == 0: if not invoiceData.bolt11: - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="BOLT11 string is invalid or not given") - return await api_payments_pay_invoice(invoiceData.bolt11, wallet.wallet) # admin key - return await api_payments_create_invoice(invoiceData, wallet.wallet) # invoice key + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail="BOLT11 string is invalid or not given", + ) + return await api_payments_pay_invoice( + invoiceData.bolt11, wallet.wallet + ) # admin key + return await api_payments_create_invoice(invoiceData, wallet.wallet) # invoice key + class CreateLNURLData(BaseModel): - description_hash: str - callback: str - amount: int - comment: Optional[str] = None - description: Optional[str] = None + description_hash: str + callback: str + amount: int + comment: Optional[str] = None + description: Optional[str] = None + @core_app.post("/api/v1/payments/lnurl") -async def api_payments_pay_lnurl(data: CreateLNURLData, - wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_payments_pay_lnurl( + data: CreateLNURLData, wallet: WalletTypeInfo = Depends(get_key_type) +): domain = urlparse(data.callback).netloc async with httpx.AsyncClient() as client: @@ -207,30 +219,28 @@ async def api_payments_pay_lnurl(data: CreateLNURLData, except (httpx.ConnectError, httpx.RequestError): raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, - detail=f"Failed to connect to {domain}." + detail=f"Failed to connect to {domain}.", ) params = json.loads(r.text) if params.get("status") == "ERROR": raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail=f"{domain} said: '{params.get('reason', '')}'" + status_code=HTTPStatus.BAD_REQUEST, + detail=f"{domain} said: '{params.get('reason', '')}'", ) - invoice = bolt11.decode(params["pr"]) if invoice.amount_msat != data.amount: raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail=f"{domain} returned an invalid invoice. Expected {data['amount']} msat, got {invoice.amount_msat}." + status_code=HTTPStatus.BAD_REQUEST, + detail=f"{domain} returned an invalid invoice. Expected {data['amount']} msat, got {invoice.amount_msat}.", ) - + if invoice.description_hash != data.description_hash: raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail=f"{domain} returned an invalid invoice. Expected description_hash == {data['description_hash']}, got {invoice.description_hash}." + status_code=HTTPStatus.BAD_REQUEST, + detail=f"{domain} returned an invalid invoice. Expected description_hash == {data['description_hash']}, got {invoice.description_hash}.", ) - extra = {} @@ -252,7 +262,7 @@ async def api_payments_pay_lnurl(data: CreateLNURLData, # maintain backwards compatibility with API clients: "checking_id": payment_hash, } - + async def subscribe(request: Request, wallet: Wallet): this_wallet_id = wallet.wallet.id @@ -278,7 +288,7 @@ async def subscribe(request: Request, wallet: Wallet): if data: jdata = json.dumps(dict(data.dict(), pending=False)) - + # yield dict(id=1, event="this", data="1234") # await asyncio.sleep(2) yield dict(data=jdata, event=typ) @@ -288,8 +298,12 @@ async def subscribe(request: Request, wallet: Wallet): @core_app.get("/api/v1/payments/sse") -async def api_payments_sse(request: Request, wallet: WalletTypeInfo = Depends(get_key_type)): - return EventSourceResponse(subscribe(request, wallet), ping=20, media_type="text/event-stream") +async def api_payments_sse( + request: Request, wallet: WalletTypeInfo = Depends(get_key_type) +): + return EventSourceResponse( + subscribe(request, wallet), ping=20, media_type="text/event-stream" + ) @core_app.get("/api/v1/payments/{payment_hash}") @@ -307,9 +321,11 @@ async def api_payment(payment_hash, wallet: WalletTypeInfo = Depends(get_key_typ return {"paid": False} return {"paid": not payment.pending, "preimage": payment.preimage} - -@core_app.get("/api/v1/lnurlscan/{code}", dependencies=[Depends(WalletInvoiceKeyChecker())]) + +@core_app.get( + "/api/v1/lnurlscan/{code}", dependencies=[Depends(WalletInvoiceKeyChecker())] +) async def api_lnurlscan(code: str): try: url = lnurl.decode(code) @@ -327,7 +343,9 @@ async def api_lnurlscan(code: str): ) # will proceed with these values else: - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="invalid lnurl") + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, detail="invalid lnurl" + ) # params is what will be returned to the client params: Dict = {"domain": domain} @@ -343,24 +361,31 @@ async def api_lnurlscan(code: str): r = await client.get(url, timeout=5) if r.is_error: raise HTTPException( - status_code=HTTPStatus.SERVICE_UNAVAILABLE, - detail={"domain": domain, "message": "failed to get parameters"} + status_code=HTTPStatus.SERVICE_UNAVAILABLE, + detail={"domain": domain, "message": "failed to get parameters"}, ) try: data = json.loads(r.text) except json.decoder.JSONDecodeError: raise HTTPException( - status_code=HTTPStatus.SERVICE_UNAVAILABLE, - detail={"domain": domain, "message": f"got invalid response '{r.text[:200]}'"} + status_code=HTTPStatus.SERVICE_UNAVAILABLE, + detail={ + "domain": domain, + "message": f"got invalid response '{r.text[:200]}'", + }, ) try: tag = data["tag"] if tag == "channelRequest": raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail={"domain": domain, "kind": "channel", "message": "unsupported"} + status_code=HTTPStatus.BAD_REQUEST, + detail={ + "domain": domain, + "kind": "channel", + "message": "unsupported", + }, ) params.update(**data) @@ -410,8 +435,9 @@ async def api_lnurlscan(code: str): detail={ "domain": domain, "message": f"lnurl JSON response invalid: {exc}", - }) - + }, + ) + return params @@ -419,8 +445,10 @@ async def api_lnurlscan(code: str): async def api_perform_lnurlauth(callback: str): err = await perform_lnurlauth(callback) if err: - raise HTTPException(status_code=HTTPStatus.SERVICE_UNAVAILABLE, detail=err.reason) - + raise HTTPException( + status_code=HTTPStatus.SERVICE_UNAVAILABLE, detail=err.reason + ) + return "" diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index b0055af8..173e41ee 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -17,38 +17,48 @@ from lnbits.helpers import template_renderer, url_for from lnbits.requestvars import g from lnbits.core.models import User from lnbits.decorators import check_user_exists -from lnbits.settings import (LNBITS_ALLOWED_USERS, LNBITS_SITE_TITLE, - SERVICE_FEE) +from lnbits.settings import LNBITS_ALLOWED_USERS, LNBITS_SITE_TITLE, SERVICE_FEE -from ..crud import (create_account, create_wallet, delete_wallet, - get_balance_check, get_user, save_balance_notify, - update_user_extension) +from ..crud import ( + create_account, + create_wallet, + delete_wallet, + get_balance_check, + get_user, + save_balance_notify, + update_user_extension, +) from ..services import pay_invoice, redeem_lnurl_withdraw core_html_routes: APIRouter = APIRouter(tags=["Core NON-API Website Routes"]) + @core_html_routes.get("/favicon.ico") async def favicon(): return FileResponse("lnbits/core/static/favicon.ico") - + @core_html_routes.get("/", response_class=HTMLResponse) async def home(request: Request, lightning: str = None): - return template_renderer().TemplateResponse("core/index.html", {"request": request, "lnurl": lightning}) + return template_renderer().TemplateResponse( + "core/index.html", {"request": request, "lnurl": lightning} + ) @core_html_routes.get("/extensions", name="core.extensions") async def extensions( - request: Request, + request: Request, user: User = Depends(check_user_exists), - enable: str= Query(None), - disable: str = Query(None) - ): + enable: str = Query(None), + disable: str = Query(None), +): extension_to_enable = enable extension_to_disable = disable if extension_to_enable and extension_to_disable: - raise HTTPException(HTTPStatus.BAD_REQUEST, "You can either `enable` or `disable` an extension.") + raise HTTPException( + HTTPStatus.BAD_REQUEST, "You can either `enable` or `disable` an extension." + ) if extension_to_enable: await update_user_extension( @@ -63,14 +73,20 @@ async def extensions( if extension_to_enable or extension_to_disable: user = await get_user(user.id) - return template_renderer().TemplateResponse("core/extensions.html", {"request": request, "user": user.dict()}) + return template_renderer().TemplateResponse( + "core/extensions.html", {"request": request, "user": user.dict()} + ) @core_html_routes.get("/wallet", response_class=HTMLResponse) -#Not sure how to validate +# Not sure how to validate # @validate_uuids(["usr", "nme"]) -async def wallet(request: Request = Query(None), nme: Optional[str] = Query(None), - usr: Optional[UUID4] = Query(None), wal: Optional[UUID4] = Query(None)): +async def wallet( + request: Request = Query(None), + nme: Optional[str] = Query(None), + usr: Optional[UUID4] = Query(None), + wal: Optional[UUID4] = Query(None), +): user_id = usr.hex if usr else None wallet_id = wal.hex if wal else None wallet_name = nme @@ -87,23 +103,38 @@ async def wallet(request: Request = Query(None), nme: Optional[str] = Query(None else: user = await get_user(user_id) if not user: - return template_renderer().TemplateResponse("error.html", {"request": request, "err": "User does not exist."}) + return template_renderer().TemplateResponse( + "error.html", {"request": request, "err": "User does not exist."} + ) if LNBITS_ALLOWED_USERS and user_id not in LNBITS_ALLOWED_USERS: - return template_renderer().TemplateResponse("error.html", {"request": request, "err": "User not authorized."}) + return template_renderer().TemplateResponse( + "error.html", {"request": request, "err": "User not authorized."} + ) if not wallet_id: if user.wallets and not wallet_name: wallet = user.wallets[0] else: wallet = await create_wallet(user_id=user.id, wallet_name=wallet_name) - return RedirectResponse(f"/wallet?usr={user.id}&wal={wallet.id}", status_code=status.HTTP_307_TEMPORARY_REDIRECT) + return RedirectResponse( + f"/wallet?usr={user.id}&wal={wallet.id}", + status_code=status.HTTP_307_TEMPORARY_REDIRECT, + ) wallet = user.get_wallet(wallet_id) if not wallet: - return template_renderer().TemplateResponse("error.html", {"request": request, "err": "Wallet not found"}) + return template_renderer().TemplateResponse( + "error.html", {"request": request, "err": "Wallet not found"} + ) return template_renderer().TemplateResponse( - "core/wallet.html", {"request":request,"user":user.dict(), "wallet":wallet.dict(), "service_fee":service_fee} + "core/wallet.html", + { + "request": request, + "user": user.dict(), + "wallet": wallet.dict(), + "service_fee": service_fee, + }, ) @@ -116,22 +147,17 @@ async def lnurl_full_withdraw(request: Request): wallet = user.get_wallet(request.args.get("wal")) if not wallet: - return{"status": "ERROR", "reason": "Wallet does not exist."} + return {"status": "ERROR", "reason": "Wallet does not exist."} return { - "tag": "withdrawRequest", - "callback": url_for( - "/withdraw/cb", - external=True, - usr=user.id, - wal=wallet.id, - ), - "k1": "0", - "minWithdrawable": 1000 if wallet.withdrawable_balance else 0, - "maxWithdrawable": wallet.withdrawable_balance, - "defaultDescription": f"{LNBITS_SITE_TITLE} balance withdraw from {wallet.id[0:5]}", - "balanceCheck": url_for("/withdraw", external=True, usr=user.id, wal=wallet.id), - } + "tag": "withdrawRequest", + "callback": url_for("/withdraw/cb", external=True, usr=user.id, wal=wallet.id), + "k1": "0", + "minWithdrawable": 1000 if wallet.withdrawable_balance else 0, + "maxWithdrawable": wallet.withdrawable_balance, + "defaultDescription": f"{LNBITS_SITE_TITLE} balance withdraw from {wallet.id[0:5]}", + "balanceCheck": url_for("/withdraw", external=True, usr=user.id, wal=wallet.id), + } @core_html_routes.get("/withdraw/cb") @@ -176,10 +202,14 @@ async def deletewallet(request: Request): user_wallet_ids.remove(wallet_id) if user_wallet_ids: - return RedirectResponse(url_for("/wallet", usr=g().user.id, wal=user_wallet_ids[0]), - status_code=status.HTTP_307_TEMPORARY_REDIRECT) + return RedirectResponse( + url_for("/wallet", usr=g().user.id, wal=user_wallet_ids[0]), + status_code=status.HTTP_307_TEMPORARY_REDIRECT, + ) - return RedirectResponse(url_for("/"), status_code=status.HTTP_307_TEMPORARY_REDIRECT) + return RedirectResponse( + url_for("/"), status_code=status.HTTP_307_TEMPORARY_REDIRECT + ) @core_html_routes.get("/withdraw/notify/{service}") @@ -203,11 +233,14 @@ async def lnurlwallet(request: Request): request.args.get("lightning"), "LNbits initial funding: voucher redeem.", {"tag": "lnurlwallet"}, - 5 # wait 5 seconds before sending the invoice to the service + 5, # wait 5 seconds before sending the invoice to the service ) ) - return RedirectResponse(f"/wallet?usr={user.id}&wal={wallet.id}", status_code=status.HTTP_307_TEMPORARY_REDIRECT) + return RedirectResponse( + f"/wallet?usr={user.id}&wal={wallet.id}", + status_code=status.HTTP_307_TEMPORARY_REDIRECT, + ) @core_html_routes.get("/manifest/{usr}.webmanifest") @@ -217,27 +250,28 @@ async def manifest(usr: str): raise HTTPException(status_code=HTTPStatus.NOT_FOUND) return { - "short_name": "LNbits", - "name": "LNbits Wallet", - "icons": [ - { - "src": "https://cdn.jsdelivr.net/gh/lnbits/lnbits@0.3.0/docs/logos/lnbits.png", - "type": "image/png", - "sizes": "900x900", - } - ], - "start_url": "/wallet?usr=" + usr, - "background_color": "#3367D6", - "description": "Weather forecast information", - "display": "standalone", - "scope": "/", - "theme_color": "#3367D6", - "shortcuts": [ - { - "name": wallet.name, - "short_name": wallet.name, - "description": wallet.name, - "url": "/wallet?usr=" + usr + "&wal=" + wallet.id, - } - for wallet in user.wallets - ],} + "short_name": "LNbits", + "name": "LNbits Wallet", + "icons": [ + { + "src": "https://cdn.jsdelivr.net/gh/lnbits/lnbits@0.3.0/docs/logos/lnbits.png", + "type": "image/png", + "sizes": "900x900", + } + ], + "start_url": "/wallet?usr=" + usr, + "background_color": "#3367D6", + "description": "Weather forecast information", + "display": "standalone", + "scope": "/", + "theme_color": "#3367D6", + "shortcuts": [ + { + "name": wallet.name, + "short_name": wallet.name, + "description": wallet.name, + "url": "/wallet?usr=" + usr + "&wal=" + wallet.id, + } + for wallet in user.wallets + ], + } diff --git a/lnbits/core/views/public_api.py b/lnbits/core/views/public_api.py index 70f949dc..d9213d6c 100644 --- a/lnbits/core/views/public_api.py +++ b/lnbits/core/views/public_api.py @@ -15,8 +15,7 @@ async def api_public_payment_longpolling(payment_hash): if not payment: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Payment does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Payment does not exist." ) elif not payment.pending: return {"status": "paid"} @@ -28,8 +27,7 @@ async def api_public_payment_longpolling(payment_hash): return {"status": "expired"} except: raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail="Invalid bolt11 invoice." + status_code=HTTPStatus.BAD_REQUEST, detail="Invalid bolt11 invoice." ) payment_queue = asyncio.Queue(0) @@ -50,14 +48,10 @@ async def api_public_payment_longpolling(payment_hash): await asyncio.sleep(45) cancel_scope.cancel() - asyncio.create_task(payment_info_receiver()) asyncio.create_task(timeouter()) if response: return response else: - raise HTTPException( - status_code=HTTPStatus.REQUEST_TIMEOUT, - detail="timeout" - ) + raise HTTPException(status_code=HTTPStatus.REQUEST_TIMEOUT, detail="timeout") diff --git a/lnbits/decorators.py b/lnbits/decorators.py index 5962c11e..74dc42b3 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -24,34 +24,49 @@ from lnbits.settings import LNBITS_ALLOWED_USERS class KeyChecker(SecurityBase): - def __init__(self, scheme_name: str = None, auto_error: bool = True, api_key: str = None): + def __init__( + self, scheme_name: str = None, auto_error: bool = True, api_key: str = None + ): self.scheme_name = scheme_name or self.__class__.__name__ self.auto_error = auto_error self._key_type = "invoice" self._api_key = api_key if api_key: - self.model: APIKey= APIKey( - **{"in": APIKeyIn.query}, name="X-API-KEY", description="Wallet API Key - QUERY" + self.model: APIKey = APIKey( + **{"in": APIKeyIn.query}, + name="X-API-KEY", + description="Wallet API Key - QUERY", ) else: - self.model: APIKey= APIKey( - **{"in": APIKeyIn.header}, name="X-API-KEY", description="Wallet API Key - HEADER" + self.model: APIKey = APIKey( + **{"in": APIKeyIn.header}, + name="X-API-KEY", + description="Wallet API Key - HEADER", ) self.wallet = None async def __call__(self, request: Request) -> Wallet: try: - key_value = self._api_key if self._api_key else request.headers.get("X-API-KEY") or request.query_params["api-key"] + key_value = ( + self._api_key + if self._api_key + else request.headers.get("X-API-KEY") or request.query_params["api-key"] + ) # FIXME: Find another way to validate the key. A fetch from DB should be avoided here. # Also, we should not return the wallet here - thats silly. # Possibly store it in a Redis DB self.wallet = await get_wallet_for_key(key_value, self._key_type) if not self.wallet: - raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED, detail="Invalid key or expired key.") + raise HTTPException( + status_code=HTTPStatus.UNAUTHORIZED, + detail="Invalid key or expired key.", + ) except KeyError: - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, - detail="`X-API-KEY` header missing.") + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, detail="`X-API-KEY` header missing." + ) + class WalletInvoiceKeyChecker(KeyChecker): """ @@ -61,10 +76,14 @@ class WalletInvoiceKeyChecker(KeyChecker): The checker will raise an HTTPException when the key is wrong in some ways. """ - def __init__(self, scheme_name: str = None, auto_error: bool = True, api_key: str = None): + + def __init__( + self, scheme_name: str = None, auto_error: bool = True, api_key: str = None + ): super().__init__(scheme_name, auto_error, api_key) self._key_type = "invoice" + class WalletAdminKeyChecker(KeyChecker): """ WalletAdminKeyChecker will ensure that the provided admin @@ -73,11 +92,15 @@ class WalletAdminKeyChecker(KeyChecker): The checker will raise an HTTPException when the key is wrong in some ways. """ - def __init__(self, scheme_name: str = None, auto_error: bool = True, api_key: str = None): + + def __init__( + self, scheme_name: str = None, auto_error: bool = True, api_key: str = None + ): super().__init__(scheme_name, auto_error, api_key) self._key_type = "admin" -class WalletTypeInfo(): + +class WalletTypeInfo: wallet_type: int wallet: Wallet @@ -85,20 +108,33 @@ class WalletTypeInfo(): self.wallet_type = wallet_type self.wallet = wallet -api_key_header = APIKeyHeader(name="X-API-KEY", auto_error=False, description="Admin or Invoice key for wallet API's") -api_key_query = APIKeyQuery(name="api-key", auto_error=False, description="Admin or Invoice key for wallet API's") -async def get_key_type(r: Request, - api_key_header: str = Security(api_key_header), - api_key_query: str = Security(api_key_query)) -> WalletTypeInfo: + +api_key_header = APIKeyHeader( + name="X-API-KEY", + auto_error=False, + description="Admin or Invoice key for wallet API's", +) +api_key_query = APIKeyQuery( + name="api-key", + auto_error=False, + description="Admin or Invoice key for wallet API's", +) + + +async def get_key_type( + r: Request, + api_key_header: str = Security(api_key_header), + api_key_query: str = Security(api_key_query), +) -> WalletTypeInfo: # 0: admin # 1: invoice # 2: invalid - - if not api_key_header and not api_key_query: + + if not api_key_header and not api_key_query: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST) token = api_key_header if api_key_header else api_key_query - + try: checker = WalletAdminKeyChecker(api_key=token) await checker.__call__(r) @@ -122,6 +158,8 @@ async def get_key_type(r: Request, return WalletTypeInfo(2, None) except: raise + + # api_key_header = APIKeyHeader(name="X-API-KEY", auto_error=False, description="Admin or Invoice key for wallet API's") # api_key_query = APIKeyQuery(name="api-key", auto_error=False, description="Admin or Invoice key for wallet API's") # oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") @@ -159,6 +197,7 @@ async def get_key_type(r: Request, # except: # raise + def api_validate_post_request(*, schema: dict): def wrap(view): @wraps(view) @@ -166,7 +205,9 @@ def api_validate_post_request(*, schema: dict): if "application/json" not in request.headers["Content-Type"]: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, - detail=jsonify({"message": "Content-Type must be `application/json`."}) + detail=jsonify( + {"message": "Content-Type must be `application/json`."} + ), ) v = Validator(schema) @@ -176,10 +217,9 @@ def api_validate_post_request(*, schema: dict): if not v.validate(g().data): raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, - detail=jsonify({"message": f"Errors in request data: {v.errors}"}) + detail=jsonify({"message": f"Errors in request data: {v.errors}"}), ) - return await view(**kwargs) return wrapped_view @@ -191,14 +231,12 @@ async def check_user_exists(usr: UUID4) -> User: g().user = await get_user(usr.hex) if not g().user: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="User does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) if LNBITS_ALLOWED_USERS and g().user.id not in LNBITS_ALLOWED_USERS: raise HTTPException( - status_code=HTTPStatus.UNAUTHORIZED, - detail="User not authorized." + status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized." ) return g().user diff --git a/lnbits/extensions/copilot/__init__.py b/lnbits/extensions/copilot/__init__.py index 94d1e74c..4252eddc 100644 --- a/lnbits/extensions/copilot/__init__.py +++ b/lnbits/extensions/copilot/__init__.py @@ -19,11 +19,7 @@ copilot_ext: APIRouter = APIRouter(prefix="/copilot", tags=["copilot"]) def copilot_renderer(): - return template_renderer( - [ - "lnbits/extensions/copilot/templates", - ] - ) + return template_renderer(["lnbits/extensions/copilot/templates"]) from .views_api import * # noqa diff --git a/lnbits/extensions/copilot/lnurl.py b/lnbits/extensions/copilot/lnurl.py index 518b07f3..c7b99f40 100644 --- a/lnbits/extensions/copilot/lnurl.py +++ b/lnbits/extensions/copilot/lnurl.py @@ -8,7 +8,11 @@ from http import HTTPStatus from starlette.exceptions import HTTPException from starlette.responses import HTMLResponse, JSONResponse # type: ignore import base64 -from lnurl import LnurlPayResponse, LnurlPayActionResponse, LnurlErrorResponse # type: ignore +from lnurl import ( + LnurlPayResponse, + LnurlPayActionResponse, + LnurlErrorResponse, +) # type: ignore from lnurl.types import LnurlPayMetadata from lnbits.core.services import create_invoice from .models import Copilots, CreateCopilotData @@ -24,8 +28,7 @@ async def lnurl_response(req: Request, cp_id: str = Query(None)): cp = await get_copilot(cp_id) if not cp: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Copilot not found", + status_code=HTTPStatus.NOT_FOUND, detail="Copilot not found" ) resp = LnurlPayResponse( @@ -49,8 +52,7 @@ async def lnurl_callback( cp = await get_copilot(cp_id) if not cp: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Copilot not found", + status_code=HTTPStatus.NOT_FOUND, detail="Copilot not found" ) amount_received = int(amount) @@ -84,9 +86,6 @@ async def lnurl_callback( extra={"tag": "copilot", "copilot": cp.id, "comment": comment}, ) resp = LnurlPayActionResponse( - pr=payment_request, - success_action=None, - disposable=False, - routes=[], + pr=payment_request, success_action=None, disposable=False, routes=[] ) return resp.dict() diff --git a/lnbits/extensions/copilot/tasks.py b/lnbits/extensions/copilot/tasks.py index ea678222..b3b6c65c 100644 --- a/lnbits/extensions/copilot/tasks.py +++ b/lnbits/extensions/copilot/tasks.py @@ -38,8 +38,7 @@ async def on_invoice_paid(payment: Payment) -> None: if not copilot: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Copilot does not exist", + status_code=HTTPStatus.NOT_FOUND, detail="Copilot does not exist" ) if copilot.animation1threshold: if int(payment.amount / 1000) >= copilot.animation1threshold: diff --git a/lnbits/extensions/copilot/views_api.py b/lnbits/extensions/copilot/views_api.py index 58b486bf..1481ee77 100644 --- a/lnbits/extensions/copilot/views_api.py +++ b/lnbits/extensions/copilot/views_api.py @@ -44,10 +44,7 @@ async def api_copilots_retrieve( try: return copilots except: - raise HTTPException( - status_code=HTTPStatus.NO_CONTENT, - detail="No copilots", - ) + raise HTTPException(status_code=HTTPStatus.NO_CONTENT, detail="No copilots") @copilot_ext.get("/api/v1/copilot/{copilot_id}") @@ -57,8 +54,7 @@ async def api_copilot_retrieve( copilot = await get_copilot(copilot_id) if not copilot: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Copilot not found", + status_code=HTTPStatus.NOT_FOUND, detail="Copilot not found" ) if not copilot.lnurl_toggle: return copilot.dict() @@ -83,15 +79,13 @@ 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(get_key_type), + copilot_id: str = Query(None), wallet: WalletTypeInfo = Depends(get_key_type) ): copilot = await get_copilot(copilot_id) if not copilot: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Copilot does not exist", + status_code=HTTPStatus.NOT_FOUND, detail="Copilot does not exist" ) await delete_copilot(copilot_id) @@ -101,22 +95,16 @@ async def api_copilot_delete( @copilot_ext.get("/api/v1/copilot/ws/{copilot_id}/{comment}/{data}") async def api_copilot_ws_relay( - copilot_id: str = Query(None), - comment: str = Query(None), - data: str = Query(None), + copilot_id: str = Query(None), comment: str = Query(None), data: str = Query(None) ): copilot = await get_copilot(copilot_id) print(copilot) if not copilot: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Copilot does not exist", + status_code=HTTPStatus.NOT_FOUND, detail="Copilot does not exist" ) try: await updater(copilot_id, data, comment) except: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Not your copilot", - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your copilot") return "" diff --git a/lnbits/extensions/jukebox/__init__.py b/lnbits/extensions/jukebox/__init__.py index 93e1157a..0d4524a7 100644 --- a/lnbits/extensions/jukebox/__init__.py +++ b/lnbits/extensions/jukebox/__init__.py @@ -20,11 +20,7 @@ jukebox_ext: APIRouter = APIRouter(prefix="/jukebox", tags=["jukebox"]) def jukebox_renderer(): - return template_renderer( - [ - "lnbits/extensions/jukebox/templates", - ] - ) + return template_renderer(["lnbits/extensions/jukebox/templates"]) from .views_api import * # noqa diff --git a/lnbits/extensions/jukebox/crud.py b/lnbits/extensions/jukebox/crud.py index c7a045f1..3f8ce96c 100644 --- a/lnbits/extensions/jukebox/crud.py +++ b/lnbits/extensions/jukebox/crud.py @@ -6,8 +6,7 @@ from lnbits.helpers import urlsafe_short_hash async def create_jukebox( - data: CreateJukeLinkData, - inkey: Optional[str] = "", + data: CreateJukeLinkData, inkey: Optional[str] = "" ) -> Jukebox: juke_id = urlsafe_short_hash() result = await db.execute( @@ -87,12 +86,7 @@ async def create_jukebox_payment(data: CreateJukeboxPayment) -> JukeboxPayment: INSERT INTO jukebox.jukebox_payment (payment_hash, juke_id, song_id, paid) VALUES (?, ?, ?, ?) """, - ( - data.payment_hash, - data.juke_id, - data.song_id, - False, - ), + (data.payment_hash, data.juke_id, data.song_id, False), ) jukebox_payment = await get_jukebox_payment(data.payment_hash) assert jukebox_payment, "Newly created Jukebox Payment couldn't be retrieved" diff --git a/lnbits/extensions/jukebox/views_api.py b/lnbits/extensions/jukebox/views_api.py index 789eacb0..3065d4f6 100644 --- a/lnbits/extensions/jukebox/views_api.py +++ b/lnbits/extensions/jukebox/views_api.py @@ -44,10 +44,7 @@ async def api_get_jukeboxs( return jukeboxs except: - raise HTTPException( - status_code=HTTPStatus.NO_CONTENT, - detail="No Jukeboxes", - ) + raise HTTPException(status_code=HTTPStatus.NO_CONTENT, detail="No Jukeboxes") ##################SPOTIFY AUTH##################### @@ -102,18 +99,12 @@ async def api_create_update_jukebox( @jukebox_ext.delete("/api/v1/jukebox/{juke_id}") -async def api_delete_item( - juke_id=None, - wallet: WalletTypeInfo = Depends(get_key_type), -): +async def api_delete_item(juke_id=None, wallet: WalletTypeInfo = Depends(get_key_type)): await delete_jukebox(juke_id) try: return [{**jukebox} for jukebox in await get_jukeboxs(wallet.wallet.user)] except: - raise HTTPException( - status_code=HTTPStatus.NO_CONTENT, - detail="No Jukebox", - ) + raise HTTPException(status_code=HTTPStatus.NO_CONTENT, detail="No Jukebox") ################JUKEBOX ENDPOINTS################## @@ -130,10 +121,7 @@ async def api_get_jukebox_song( try: jukebox = await get_jukebox(juke_id) except: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="No Jukeboxes", - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No Jukeboxes") tracks = [] async with httpx.AsyncClient() as client: try: @@ -176,10 +164,7 @@ async def api_get_token(juke_id=None): try: jukebox = await get_jukebox(juke_id) except: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="No Jukeboxes", - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No Jukeboxes") async with httpx.AsyncClient() as client: try: @@ -215,16 +200,12 @@ async def api_get_token(juke_id=None): @jukebox_ext.get("/api/v1/jukebox/jb/{juke_id}") async def api_get_jukebox_device_check( - juke_id: str = Query(None), - retry: bool = Query(False), + juke_id: str = Query(None), retry: bool = Query(False) ): try: jukebox = await get_jukebox(juke_id) except: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="No Jukeboxes", - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No Jukeboxes") async with httpx.AsyncClient() as client: rDevice = await client.get( "https://api.spotify.com/v1/me/player/devices", @@ -237,20 +218,17 @@ async def api_get_jukebox_device_check( token = await api_get_token(juke_id) if token == False: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="No devices connected", + status_code=HTTPStatus.FORBIDDEN, detail="No devices connected" ) elif retry: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Failed to get auth", + status_code=HTTPStatus.FORBIDDEN, detail="Failed to get auth" ) else: return api_get_jukebox_device_check(juke_id, retry=True) else: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="No device connected", + status_code=HTTPStatus.FORBIDDEN, detail="No device connected" ) @@ -263,10 +241,7 @@ async def api_get_jukebox_invoice(juke_id, song_id): jukebox = await get_jukebox(juke_id) print(jukebox) except: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="No jukebox", - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") try: devices = await api_get_jukebox_device_check(juke_id) @@ -276,13 +251,11 @@ async def api_get_jukebox_invoice(juke_id, song_id): deviceConnected = True if not deviceConnected: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="No device connected", + status_code=HTTPStatus.NOT_FOUND, detail="No device connected" ) except: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="No device connected", + status_code=HTTPStatus.NOT_FOUND, detail="No device connected" ) invoice = await create_invoice( @@ -304,16 +277,12 @@ async def api_get_jukebox_invoice(juke_id, song_id): @jukebox_ext.get("/api/v1/jukebox/jb/checkinvoice/{pay_hash}/{juke_id}") async def api_get_jukebox_invoice_check( - pay_hash: str = Query(None), - juke_id: str = Query(None), + pay_hash: str = Query(None), juke_id: str = Query(None) ): try: jukebox = await get_jukebox(juke_id) except: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="No jukebox", - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") try: status = await check_invoice_status(jukebox.wallet, pay_hash) is_paid = not status.pending @@ -338,10 +307,7 @@ async def api_get_jukebox_invoice_paid( try: jukebox = await get_jukebox(juke_id) except: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="No jukebox", - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") await api_get_jukebox_invoice_check(pay_hash, juke_id) jukebox_payment = await get_jukebox_payment(pay_hash) if jukebox_payment.paid: @@ -390,8 +356,7 @@ async def api_get_jukebox_invoice_paid( ) else: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Invoice not paid", + status_code=HTTPStatus.FORBIDDEN, detail="Invoice not paid" ) elif r.status_code == 200: async with httpx.AsyncClient() as client: @@ -424,29 +389,23 @@ async def api_get_jukebox_invoice_paid( ) else: raise HTTPException( - status_code=HTTPStatus.OK, - detail="Invoice not paid", + status_code=HTTPStatus.OK, detail="Invoice not paid" ) elif r.status_code == 401 or r.status_code == 403: token = await api_get_token(juke_id) if token == False: raise HTTPException( - status_code=HTTPStatus.OK, - detail="Invoice not paid", + status_code=HTTPStatus.OK, detail="Invoice not paid" ) elif retry: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Failed to get auth", + status_code=HTTPStatus.FORBIDDEN, detail="Failed to get auth" ) else: return await api_get_jukebox_invoice_paid( song_id, juke_id, pay_hash ) - raise HTTPException( - status_code=HTTPStatus.OK, - detail="Invoice not paid", - ) + raise HTTPException(status_code=HTTPStatus.OK, detail="Invoice not paid") ############################GET TRACKS @@ -454,16 +413,12 @@ async def api_get_jukebox_invoice_paid( @jukebox_ext.get("/api/v1/jukebox/jb/currently/{juke_id}") async def api_get_jukebox_currently( - retry: bool = Query(False), - juke_id: str = Query(None), + retry: bool = Query(False), juke_id: str = Query(None) ): try: jukebox = await get_jukebox(juke_id) except: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="No jukebox", - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="No jukebox") async with httpx.AsyncClient() as client: try: r = await client.get( @@ -472,10 +427,7 @@ async def api_get_jukebox_currently( headers={"Authorization": "Bearer " + jukebox.sp_access_token}, ) if r.status_code == 204: - raise HTTPException( - status_code=HTTPStatus.OK, - detail="Nothing", - ) + raise HTTPException(status_code=HTTPStatus.OK, detail="Nothing") elif r.status_code == 200: try: response = r.json() @@ -490,31 +442,26 @@ async def api_get_jukebox_currently( return track except: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Something went wrong", + status_code=HTTPStatus.NOT_FOUND, detail="Something went wrong" ) elif r.status_code == 401: token = await api_get_token(juke_id) if token == False: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="INvoice not paid", + status_code=HTTPStatus.FORBIDDEN, detail="INvoice not paid" ) elif retry: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Failed to get auth", + status_code=HTTPStatus.FORBIDDEN, detail="Failed to get auth" ) else: return await api_get_jukebox_currently(retry=True, juke_id=juke_id) else: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Something went wrong", + status_code=HTTPStatus.NOT_FOUND, detail="Something went wrong" ) except: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Something went wrong", + status_code=HTTPStatus.NOT_FOUND, detail="Something went wrong" ) diff --git a/lnbits/extensions/lndhub/__init__.py b/lnbits/extensions/lndhub/__init__.py index 13d9069c..cdd363fd 100644 --- a/lnbits/extensions/lndhub/__init__.py +++ b/lnbits/extensions/lndhub/__init__.py @@ -12,11 +12,7 @@ lndhub_ext: APIRouter = APIRouter(prefix="/lndhub", tags=["lndhub"]) def lndhub_renderer(): - return template_renderer( - [ - "lnbits/extensions/lndhub/templates", - ] - ) + return template_renderer(["lnbits/extensions/lndhub/templates"]) from .views_api import * # noqa diff --git a/lnbits/extensions/lndhub/decorators.py b/lnbits/extensions/lndhub/decorators.py index 47bf9c7c..8cb765ff 100644 --- a/lnbits/extensions/lndhub/decorators.py +++ b/lnbits/extensions/lndhub/decorators.py @@ -12,12 +12,19 @@ from starlette.responses import HTMLResponse, JSONResponse from lnbits.decorators import WalletTypeInfo, get_key_type # type: ignore -api_key_header_auth = APIKeyHeader(name="AUTHORIZATION", auto_error=False, description="Admin or Invoice key for LNDHub API's") -async def check_wallet(r: Request, api_key_header_auth: str = Security(api_key_header_auth)) -> WalletTypeInfo: +api_key_header_auth = APIKeyHeader( + name="AUTHORIZATION", + auto_error=False, + description="Admin or Invoice key for LNDHub API's", +) + + +async def check_wallet( + r: Request, api_key_header_auth: str = Security(api_key_header_auth) +) -> WalletTypeInfo: if not api_key_header_auth: raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Invalid auth key" + status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid auth key" ) t = api_key_header_auth.split(" ")[1] @@ -26,14 +33,15 @@ async def check_wallet(r: Request, api_key_header_auth: str = Security(api_key_h return await get_key_type(r, api_key_header=token) -async def require_admin_key(r: Request, api_key_header_auth: str = Security(api_key_header_auth)): +async def require_admin_key( + r: Request, api_key_header_auth: str = Security(api_key_header_auth) +): wallet = await check_wallet(r, api_key_header_auth) if wallet.wallet_type != 0: # If wallet type is not admin then return the unauthorized status # This also covers when the user passes an invalid key type raise HTTPException( - status_code=status.HTTP_401_UNAUTHORIZED, - detail="Admin key required.", + status_code=status.HTTP_401_UNAUTHORIZED, detail="Admin key required." ) - else: - return wallet \ No newline at end of file + else: + return wallet diff --git a/lnbits/extensions/lndhub/views_api.py b/lnbits/extensions/lndhub/views_api.py index 376afe9f..7079703c 100644 --- a/lnbits/extensions/lndhub/views_api.py +++ b/lnbits/extensions/lndhub/views_api.py @@ -23,10 +23,8 @@ from fastapi.security import OAuth2PasswordBearer @lndhub_ext.get("/ext/getinfo") async def lndhub_getinfo(): - raise HTTPException( - status_code=HTTPStatus.UNAUTHORIZED, - detail="bad auth", - ) + raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED, detail="bad auth") + class AuthData(BaseModel): login: str = Query(None) @@ -35,16 +33,17 @@ class AuthData(BaseModel): @lndhub_ext.post("/ext/auth") -async def lndhub_auth( - data: AuthData -): +async def lndhub_auth(data: AuthData): token = ( data.refresh_token if data.refresh_token - else urlsafe_b64encode((data.login + ":" + data.password).encode("utf-8")).decode("ascii") + else urlsafe_b64encode( + (data.login + ":" + data.password).encode("utf-8") + ).decode("ascii") ) return {"refresh_token": token, "access_token": token} + class AddInvoice(BaseModel): amt: str = Query(None) memo: str = Query(None) @@ -53,8 +52,7 @@ class AddInvoice(BaseModel): @lndhub_ext.post("/ext/addinvoice") async def lndhub_addinvoice( - data: AddInvoice, - wallet: WalletTypeInfo = Depends(check_wallet) + data: AddInvoice, wallet: WalletTypeInfo = Depends(check_wallet) ): try: _, pr = await create_invoice( @@ -65,8 +63,7 @@ async def lndhub_addinvoice( ) except: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Failed to create invoice", + status_code=HTTPStatus.NOT_FOUND, detail="Failed to create invoice" ) invoice = bolt11.decode(pr) @@ -78,9 +75,11 @@ async def lndhub_addinvoice( "hash": invoice.payment_hash, } + class Invoice(BaseModel): invoice: str + @lndhub_ext.post("/ext/payinvoice") async def lndhub_payinvoice( r_invoice: Invoice, wallet: WalletTypeInfo = Depends(require_admin_key) @@ -92,10 +91,7 @@ async def lndhub_payinvoice( extra={"tag": "lndhub"}, ) except: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Payment failed", - ) + raise HTTPException(status_code=HTTPStatus.NOT_FOUND, detail="Payment failed") invoice: bolt11.Invoice = bolt11.decode(r_invoice.invoice) print("INV2", invoice) @@ -116,9 +112,7 @@ async def lndhub_payinvoice( @lndhub_ext.get("/ext/balance") # @check_wallet() -async def lndhub_balance( - wallet: WalletTypeInfo = Depends(check_wallet), -): +async def lndhub_balance(wallet: WalletTypeInfo = Depends(check_wallet),): return {"BTC": {"AvailableBalance": wallet.wallet.balance}} diff --git a/lnbits/extensions/lnticket/__init__.py b/lnbits/extensions/lnticket/__init__.py index 9394a1c9..c1f382eb 100644 --- a/lnbits/extensions/lnticket/__init__.py +++ b/lnbits/extensions/lnticket/__init__.py @@ -14,12 +14,9 @@ lnticket_ext: APIRouter = APIRouter( # "lnticket", __name__, static_folder="static", template_folder="templates" ) + def lnticket_renderer(): - return template_renderer( - [ - "lnbits/extensions/lnticket/templates", - ] - ) + return template_renderer(["lnbits/extensions/lnticket/templates"]) from .views_api import * # noqa @@ -30,4 +27,3 @@ from .tasks import wait_for_paid_invoices def lnticket_start(): loop = asyncio.get_event_loop() loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) - diff --git a/lnbits/extensions/lnticket/crud.py b/lnbits/extensions/lnticket/crud.py index e391abb5..8fe17090 100644 --- a/lnbits/extensions/lnticket/crud.py +++ b/lnbits/extensions/lnticket/crud.py @@ -9,16 +9,23 @@ import httpx async def create_ticket( - payment_hash: str, - wallet: str, - data: CreateTicketData + payment_hash: str, wallet: str, data: CreateTicketData ) -> Tickets: await db.execute( """ INSERT INTO lnticket.ticket (id, form, email, ltext, name, wallet, sats, paid) VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, - (payment_hash, data.form, data.email, data.ltext, data.name, wallet, data.sats, False), + ( + payment_hash, + data.form, + data.email, + data.ltext, + data.name, + wallet, + data.sats, + False, + ), ) ticket = await get_ticket(payment_hash) @@ -99,17 +106,23 @@ async def delete_ticket(ticket_id: str) -> None: # FORMS -async def create_form( - data: CreateFormData, - wallet: Wallet, -) -> Forms: +async def create_form(data: CreateFormData, wallet: Wallet) -> Forms: form_id = urlsafe_short_hash() await db.execute( """ INSERT INTO lnticket.form2 (id, wallet, name, webhook, description, flatrate, amount, amountmade) VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, - (form_id, wallet.id, wallet.name, data.webhook, data.description, data.flatrate, data.amount, 0), + ( + form_id, + wallet.id, + wallet.name, + data.webhook, + data.description, + data.flatrate, + data.amount, + 0, + ), ) form = await get_form(form_id) diff --git a/lnbits/extensions/lnticket/migrations.py b/lnbits/extensions/lnticket/migrations.py index abcd5c7f..37fbdc86 100644 --- a/lnbits/extensions/lnticket/migrations.py +++ b/lnbits/extensions/lnticket/migrations.py @@ -79,16 +79,7 @@ async def m002_changed(db): ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, - ( - row[0], - row[1], - row[2], - row[3], - row[4], - row[5], - row[6], - True, - ), + (row[0], row[1], row[2], row[3], row[4], row[5], row[6], True), ) await db.execute("DROP TABLE lnticket.tickets") @@ -134,15 +125,7 @@ async def m003_changed(db): ) VALUES (?, ?, ?, ?, ?, ?, ?) """, - ( - row[0], - row[1], - row[2], - row[3], - row[4], - row[5], - row[6], - ), + (row[0], row[1], row[2], row[3], row[4], row[5], row[6]), ) await db.execute("DROP TABLE lnticket.forms") @@ -189,14 +172,6 @@ async def m004_changed(db): ) VALUES (?, ?, ?, ?, ?, ?, ?) """, - ( - row[0], - row[1], - row[2], - row[3], - row[4], - row[5], - row[6], - ), + (row[0], row[1], row[2], row[3], row[4], row[5], row[6]), ) await db.execute("DROP TABLE lnticket.form") diff --git a/lnbits/extensions/lnticket/models.py b/lnbits/extensions/lnticket/models.py index 6fac90c2..50ffc1e1 100644 --- a/lnbits/extensions/lnticket/models.py +++ b/lnbits/extensions/lnticket/models.py @@ -2,6 +2,7 @@ from typing import Optional from fastapi.param_functions import Query from pydantic import BaseModel + class CreateFormData(BaseModel): name: str = Query(...) webhook: str = Query(None) @@ -9,6 +10,7 @@ class CreateFormData(BaseModel): amount: int = Query(..., ge=0) flatrate: int = Query(...) + class CreateTicketData(BaseModel): form: str = Query(...) name: str = Query(...) @@ -16,6 +18,7 @@ class CreateTicketData(BaseModel): ltext: str = Query(...) sats: int = Query(..., ge=0) + class Forms(BaseModel): id: str wallet: str diff --git a/lnbits/extensions/lnticket/views.py b/lnbits/extensions/lnticket/views.py index f7f50e37..85be27b5 100644 --- a/lnbits/extensions/lnticket/views.py +++ b/lnbits/extensions/lnticket/views.py @@ -14,13 +14,16 @@ from fastapi.templating import Jinja2Templates templates = Jinja2Templates(directory="templates") + @lnticket_ext.get("/", response_class=HTMLResponse) # not needed as we automatically get the user with the given ID # If no user with this ID is found, an error is raised # @validate_uuids(["usr"], required=True) # @check_user_exists() async def index(request: Request, user: User = Depends(check_user_exists)): - return lnticket_renderer().TemplateResponse("lnticket/index.html", {"request": request,"user": user.dict()}) + return lnticket_renderer().TemplateResponse( + "lnticket/index.html", {"request": request, "user": user.dict()} + ) @lnticket_ext.get("/{form_id}") @@ -28,8 +31,7 @@ async def display(request: Request, form_id): form = await get_form(form_id) if not form: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="LNTicket does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="LNTicket does not exist." ) # abort(HTTPStatus.NOT_FOUND, "LNTicket does not exist.") @@ -37,11 +39,13 @@ async def display(request: Request, form_id): return lnticket_renderer().TemplateResponse( "lnticket/display.html", - {"request": request, - "form_id":form.id, - "form_name":form.name, - "form_desc":form.description, - "form_amount":form.amount, - "form_flatrate":form.flatrate, - "form_wallet":wallet.inkey} + { + "request": request, + "form_id": form.id, + "form_name": form.name, + "form_desc": form.description, + "form_amount": form.amount, + "form_flatrate": form.flatrate, + "form_wallet": wallet.inkey, + }, ) diff --git a/lnbits/extensions/lnticket/views_api.py b/lnbits/extensions/lnticket/views_api.py index 1474518b..e78a4c71 100644 --- a/lnbits/extensions/lnticket/views_api.py +++ b/lnbits/extensions/lnticket/views_api.py @@ -34,7 +34,11 @@ from .crud import ( @lnticket_ext.get("/api/v1/forms") -async def api_forms_get(r: Request, all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_forms_get( + r: Request, + all_wallets: bool = Query(False), + wallet: WalletTypeInfo = Depends(get_key_type), +): wallet_ids = [wallet.wallet.id] if all_wallets: @@ -42,6 +46,7 @@ async def api_forms_get(r: Request, all_wallets: bool = Query(False), wallet: Wa return [form.dict() for form in await get_forms(wallet_ids)] + @lnticket_ext.post("/api/v1/forms", status_code=HTTPStatus.CREATED) @lnticket_ext.put("/api/v1/forms/{form_id}") # @api_check_wallet_key("invoice") @@ -55,21 +60,21 @@ async def api_forms_get(r: Request, all_wallets: bool = Query(False), wallet: Wa # "flatrate": {"type": "integer", "required": True}, # } # ) -async def api_form_create(data: CreateFormData, form_id=None, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_form_create( + data: CreateFormData, form_id=None, wallet: WalletTypeInfo = Depends(get_key_type) +): if form_id: form = await get_form(form_id) if not form: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail=f"Form does not exist." + status_code=HTTPStatus.NOT_FOUND, detail=f"Form does not exist." ) # return {"message": "Form does not exist."}, HTTPStatus.NOT_FOUND if form.wallet != wallet.wallet.id: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail=f"Not your form." + status_code=HTTPStatus.FORBIDDEN, detail=f"Not your form." ) # return {"message": "Not your form."}, HTTPStatus.FORBIDDEN @@ -86,16 +91,12 @@ async def api_form_delete(form_id, wallet: WalletTypeInfo = Depends(get_key_type if not form: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail=f"Form does not exist." + status_code=HTTPStatus.NOT_FOUND, detail=f"Form does not exist." ) # return {"message": "Form does not exist."}, HTTPStatus.NOT_FOUND if form.wallet != wallet.wallet.id: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail=f"Not your form." - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail=f"Not your form.") # return {"message": "Not your form."}, HTTPStatus.FORBIDDEN await delete_form(form_id) @@ -109,7 +110,9 @@ async def api_form_delete(form_id, wallet: WalletTypeInfo = Depends(get_key_type @lnticket_ext.get("/api/v1/tickets") # @api_check_wallet_key("invoice") -async def api_tickets(all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_tickets( + all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type) +): wallet_ids = [wallet.wallet.id] if all_wallets: @@ -117,6 +120,7 @@ async def api_tickets(all_wallets: bool = Query(False), wallet: WalletTypeInfo = return [form.dict() for form in await get_tickets(wallet_ids)] + @lnticket_ext.post("/api/v1/tickets/{form_id}", status_code=HTTPStatus.CREATED) # @api_validate_post_request( # schema={ @@ -131,8 +135,7 @@ async def api_ticket_make_ticket(data: CreateTicketData, form_id): form = await get_form(form_id) if not form: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail=f"LNTicket does not exist." + status_code=HTTPStatus.NOT_FOUND, detail=f"LNTicket does not exist." ) # return {"message": "LNTicket does not exist."}, HTTPStatus.NOT_FOUND @@ -146,10 +149,7 @@ async def api_ticket_make_ticket(data: CreateTicketData, form_id): extra={"tag": "lnticket"}, ) except Exception as e: - raise HTTPException( - status_code=HTTPStatus.INTERNAL_SERVER_ERROR, - detail=str(e) - ) + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) # return {"message": str(e)}, HTTPStatus.INTERNAL_SERVER_ERROR ticket = await create_ticket( @@ -158,18 +158,14 @@ async def api_ticket_make_ticket(data: CreateTicketData, form_id): if not ticket: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="LNTicket could not be fetched." + status_code=HTTPStatus.NOT_FOUND, detail="LNTicket could not be fetched." ) # return ( # {"message": "LNTicket could not be fetched."}, # HTTPStatus.NOT_FOUND, # ) - return { - "payment_hash": payment_hash, - "payment_request": payment_request - } + return {"payment_hash": payment_hash, "payment_request": payment_request} @lnticket_ext.get("/api/v1/tickets/{payment_hash}", status_code=HTTPStatus.OK) @@ -198,16 +194,12 @@ async def api_ticket_delete(ticket_id, wallet: WalletTypeInfo = Depends(get_key_ if not ticket: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail=f"LNTicket does not exist." + status_code=HTTPStatus.NOT_FOUND, detail=f"LNTicket does not exist." ) # return {"message": "Paywall does not exist."}, HTTPStatus.NOT_FOUND if ticket.wallet != wallet.wallet.id: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Not your ticket." - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your ticket.") # return {"message": "Not your ticket."}, HTTPStatus.FORBIDDEN await delete_ticket(ticket_id) diff --git a/lnbits/extensions/lnurlp/__init__.py b/lnbits/extensions/lnurlp/__init__.py index b163dfb7..ea8e509a 100644 --- a/lnbits/extensions/lnurlp/__init__.py +++ b/lnbits/extensions/lnurlp/__init__.py @@ -26,11 +26,7 @@ lnurlp_ext: APIRouter = APIRouter( def lnurlp_renderer(): - return template_renderer( - [ - "lnbits/extensions/lnurlp/templates", - ] - ) + return template_renderer(["lnbits/extensions/lnurlp/templates"]) from .views_api import * # noqa diff --git a/lnbits/extensions/lnurlp/crud.py b/lnbits/extensions/lnurlp/crud.py index 892d9e98..4215faf6 100644 --- a/lnbits/extensions/lnurlp/crud.py +++ b/lnbits/extensions/lnurlp/crud.py @@ -5,10 +5,7 @@ from . import db from .models import PayLink, CreatePayLinkData -async def create_pay_link( - data: CreatePayLinkData, - wallet_id: str -) -> PayLink: +async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink: returning = "" if db.type == SQLITE else "RETURNING ID" method = db.execute if db.type == SQLITE else db.fetchone diff --git a/lnbits/extensions/lnurlp/lnurl.py b/lnbits/extensions/lnurlp/lnurl.py index fc6cc545..f7a615a4 100644 --- a/lnbits/extensions/lnurlp/lnurl.py +++ b/lnbits/extensions/lnurlp/lnurl.py @@ -3,7 +3,11 @@ import math from http import HTTPStatus from fastapi import FastAPI, Request from starlette.exceptions import HTTPException -from lnurl import LnurlPayResponse, LnurlPayActionResponse, LnurlErrorResponse # type: ignore +from lnurl import ( + LnurlPayResponse, + LnurlPayActionResponse, + LnurlErrorResponse, +) # type: ignore from lnbits.core.services import create_invoice from lnbits.utils.exchange_rates import get_fiat_rate_satoshis @@ -12,13 +16,16 @@ from . import lnurlp_ext from .crud import increment_pay_link -@lnurlp_ext.get("/api/v1/lnurl/{link_id}", status_code=HTTPStatus.OK, name="lnurlp.api_lnurl_response") +@lnurlp_ext.get( + "/api/v1/lnurl/{link_id}", + status_code=HTTPStatus.OK, + name="lnurlp.api_lnurl_response", +) async def api_lnurl_response(request: Request, link_id): link = await increment_pay_link(link_id, served_meta=1) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Pay link does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist." ) rate = await get_fiat_rate_satoshis(link.currency) if link.currency else 1 @@ -37,13 +44,16 @@ async def api_lnurl_response(request: Request, link_id): return params -@lnurlp_ext.get("/api/v1/lnurl/cb/{link_id}", status_code=HTTPStatus.OK, name="lnurlp.api_lnurl_callback") +@lnurlp_ext.get( + "/api/v1/lnurl/cb/{link_id}", + status_code=HTTPStatus.OK, + name="lnurlp.api_lnurl_callback", +) async def api_lnurl_callback(request: Request, link_id): link = await increment_pay_link(link_id, served_pr=1) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Pay link does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist." ) min, max = link.min, link.max rate = await get_fiat_rate_satoshis(link.currency) if link.currency else 1 @@ -55,23 +65,22 @@ async def api_lnurl_callback(request: Request, link_id): min = link.min * 1000 max = link.max * 1000 - amount_received = int(request.query_params.get('amount') or 0) + amount_received = int(request.query_params.get("amount") or 0) if amount_received < min: return LnurlErrorResponse( - reason=f"Amount {amount_received} is smaller than minimum {min}." - ).dict() + reason=f"Amount {amount_received} is smaller than minimum {min}." + ).dict() elif amount_received > max: return LnurlErrorResponse( - reason=f"Amount {amount_received} is greater than maximum {max}." - ).dict() - + reason=f"Amount {amount_received} is greater than maximum {max}." + ).dict() comment = request.query_params.get("comment") if len(comment or "") > link.comment_chars: return LnurlErrorResponse( - reason=f"Got a comment with {len(comment)} characters, but can only accept {link.comment_chars}" - ).dict() + reason=f"Got a comment with {len(comment)} characters, but can only accept {link.comment_chars}" + ).dict() payment_hash, payment_request = await create_invoice( wallet_id=link.wallet, @@ -80,20 +89,20 @@ async def api_lnurl_callback(request: Request, link_id): description_hash=hashlib.sha256( link.lnurlpay_metadata.encode("utf-8") ).digest(), - extra={"tag": "lnurlp", "link": link.id, "comment": comment, 'extra': request.query_params.get('amount')}, + extra={ + "tag": "lnurlp", + "link": link.id, + "comment": comment, + "extra": request.query_params.get("amount"), + }, ) success_action = link.success_action(payment_hash) if success_action: resp = LnurlPayActionResponse( - pr=payment_request, - success_action=success_action, - routes=[], + pr=payment_request, success_action=success_action, routes=[] ) else: - resp = LnurlPayActionResponse( - pr=payment_request, - routes=[], - ) + resp = LnurlPayActionResponse(pr=payment_request, routes=[]) return resp.dict() diff --git a/lnbits/extensions/lnurlp/models.py b/lnbits/extensions/lnurlp/models.py index 4dfef94a..6fc9cc1a 100644 --- a/lnbits/extensions/lnurlp/models.py +++ b/lnbits/extensions/lnurlp/models.py @@ -8,15 +8,17 @@ from lnurl.types import LnurlPayMetadata # type: ignore from sqlite3 import Row from pydantic import BaseModel + class CreatePayLinkData(BaseModel): - description: str - min: int = Query(0.01, ge=0.01) - max: int = Query(0.01, ge=0.01) - currency: str = Query(None) - comment_chars: int = Query(0, ge=0, lt=800) - webhook_url: str = Query(None) - success_text: str = Query(None) - success_url: str = Query(None) + description: str + min: int = Query(0.01, ge=0.01) + max: int = Query(0.01, ge=0.01) + currency: str = Query(None) + comment_chars: int = Query(0, ge=0, lt=800) + webhook_url: str = Query(None) + success_text: str = Query(None) + success_url: str = Query(None) + class PayLink(BaseModel): id: int @@ -37,7 +39,6 @@ class PayLink(BaseModel): data = dict(row) return cls(**data) - def lnurl(self, req: Request) -> str: url = req.url_for("lnurlp.api_lnurl_response", link_id=self.id) return lnurl_encode(url) @@ -58,9 +59,6 @@ class PayLink(BaseModel): "url": urlunparse(url), } elif self.success_text: - return { - "tag": "message", - "message": self.success_text, - } + return {"tag": "message", "message": self.success_text} else: return None diff --git a/lnbits/extensions/lnurlp/tasks.py b/lnbits/extensions/lnurlp/tasks.py index 470fdea9..b632fa13 100644 --- a/lnbits/extensions/lnurlp/tasks.py +++ b/lnbits/extensions/lnurlp/tasks.py @@ -17,6 +17,7 @@ async def wait_for_paid_invoices(): payment = await invoice_queue.get() await on_invoice_paid(payment) + async def on_invoice_paid(payment: Payment) -> None: if "lnurlp" != payment.extra.get("tag"): # not an lnurlp invoice diff --git a/lnbits/extensions/lnurlp/views.py b/lnbits/extensions/lnurlp/views.py index 74cbd87b..d39a5ebf 100644 --- a/lnbits/extensions/lnurlp/views.py +++ b/lnbits/extensions/lnurlp/views.py @@ -14,34 +14,35 @@ from lnbits.core.models import User templates = Jinja2Templates(directory="templates") + @lnurlp_ext.get("/", response_class=HTMLResponse) # @validate_uuids(["usr"], required=True) # @check_user_exists() async def index(request: Request, user: User = Depends(check_user_exists)): - return lnurlp_renderer().TemplateResponse("lnurlp/index.html", {"request": request, "user": user.dict()}) + return lnurlp_renderer().TemplateResponse( + "lnurlp/index.html", {"request": request, "user": user.dict()} + ) @lnurlp_ext.get("/{link_id}", response_class=HTMLResponse) -async def display(request: Request,link_id): +async def display(request: Request, link_id): link = await get_pay_link(link_id) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Pay link does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist." ) # abort(HTTPStatus.NOT_FOUND, "Pay link does not exist.") - ctx = {"request": request, "lnurl":link.lnurl(req=request)} + ctx = {"request": request, "lnurl": link.lnurl(req=request)} return lnurlp_renderer().TemplateResponse("lnurlp/display.html", ctx) @lnurlp_ext.get("/print/{link_id}", response_class=HTMLResponse) -async def print_qr(request: Request,link_id): +async def print_qr(request: Request, link_id): link = await get_pay_link(link_id) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Pay link does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist." ) # abort(HTTPStatus.NOT_FOUND, "Pay link does not exist.") - ctx = {"request": request, "lnurl":link.lnurl(req=request)} + ctx = {"request": request, "lnurl": link.lnurl(req=request)} return lnurlp_renderer().TemplateResponse("lnurlp/print_qr.html", ctx) diff --git a/lnbits/extensions/offlineshop/__init__.py b/lnbits/extensions/offlineshop/__init__.py index d0912a64..0cc3201d 100644 --- a/lnbits/extensions/offlineshop/__init__.py +++ b/lnbits/extensions/offlineshop/__init__.py @@ -29,11 +29,7 @@ offlineshop_ext: APIRouter = APIRouter( def offlineshop_renderer(): - return template_renderer( - [ - "lnbits/extensions/offlineshop/templates", - ] - ) + return template_renderer(["lnbits/extensions/offlineshop/templates"]) from .lnurl import * # noqa diff --git a/lnbits/extensions/offlineshop/crud.py b/lnbits/extensions/offlineshop/crud.py index 2ee931cd..0ecb3d52 100644 --- a/lnbits/extensions/offlineshop/crud.py +++ b/lnbits/extensions/offlineshop/crud.py @@ -51,12 +51,7 @@ async def set_method(shop: int, method: str, wordlist: str = "") -> Optional[Sho async def add_item( - shop: int, - name: str, - description: str, - image: Optional[str], - price: int, - unit: str, + shop: int, name: str, description: str, image: Optional[str], price: int, unit: str ) -> int: result = await db.execute( """ diff --git a/lnbits/extensions/offlineshop/helpers.py b/lnbits/extensions/offlineshop/helpers.py index db2c19cc..6b56cf55 100644 --- a/lnbits/extensions/offlineshop/helpers.py +++ b/lnbits/extensions/offlineshop/helpers.py @@ -8,8 +8,8 @@ def hotp(key, counter, digits=6, digest="sha1"): key = base64.b32decode(key.upper() + "=" * ((8 - len(key)) % 8)) counter = struct.pack(">Q", counter) mac = hmac.new(key, counter, digest).digest() - offset = mac[-1] & 0x0f - binary = struct.unpack(">L", mac[offset : offset + 4])[0] & 0x7fffffff + offset = mac[-1] & 0x0F + binary = struct.unpack(">L", mac[offset : offset + 4])[0] & 0x7FFFFFFF return str(binary)[-digits:].zfill(digits) diff --git a/lnbits/extensions/offlineshop/lnurl.py b/lnbits/extensions/offlineshop/lnurl.py index b04d8512..ea576f1d 100644 --- a/lnbits/extensions/offlineshop/lnurl.py +++ b/lnbits/extensions/offlineshop/lnurl.py @@ -4,7 +4,11 @@ from fastapi.params import Query from starlette.requests import Request from lnbits.helpers import url_for -from lnurl import LnurlPayResponse, LnurlPayActionResponse, LnurlErrorResponse # type: ignore +from lnurl import ( + LnurlPayResponse, + LnurlPayActionResponse, + LnurlErrorResponse, +) # type: ignore from lnbits.core.services import create_invoice from lnbits.utils.exchange_rates import fiat_amount_as_satoshis @@ -15,7 +19,7 @@ from .crud import get_shop, get_item @offlineshop_ext.get("/lnurl/{item_id}", name="offlineshop.lnurl_response") async def lnurl_response(req: Request, item_id: int = Query(...)): - item = await get_item(item_id) # type: Item + item = await get_item(item_id) # type: Item if not item: return {"status": "ERROR", "reason": "Item not found."} @@ -40,7 +44,7 @@ async def lnurl_response(req: Request, item_id: int = Query(...)): @offlineshop_ext.get("/lnurl/cb/{item_id}", name="offlineshop.lnurl_callback") async def lnurl_callback(request: Request, item_id: int): - item = await get_item(item_id) # type: Item + item = await get_item(item_id) # type: Item if not item: return {"status": "ERROR", "reason": "Couldn't find item."} @@ -80,7 +84,9 @@ async def lnurl_callback(request: Request, item_id: int): resp = LnurlPayActionResponse( pr=payment_request, - success_action=item.success_action(shop, payment_hash, request) if shop.method else None, + success_action=item.success_action(shop, payment_hash, request) + if shop.method + else None, routes=[], ) diff --git a/lnbits/extensions/offlineshop/models.py b/lnbits/extensions/offlineshop/models.py index 12616022..06225351 100644 --- a/lnbits/extensions/offlineshop/models.py +++ b/lnbits/extensions/offlineshop/models.py @@ -14,7 +14,7 @@ from .helpers import totp shop_counters: Dict = {} -class ShopCounter(): +class ShopCounter: wordlist: List[str] fulfilled_payments: OrderedDict counter: int @@ -66,7 +66,7 @@ class Shop(BaseModel): def otp_key(self) -> str: return base64.b32encode( hashlib.sha256( - ("otpkey" + str(self.id) + self.wallet).encode("ascii"), + ("otpkey" + str(self.id) + self.wallet).encode("ascii") ).digest() ).decode("ascii") @@ -90,9 +90,7 @@ class Item(BaseModel): unit: str def lnurl(self, req: Request) -> str: - return lnurl_encode( - req.url_for("offlineshop.lnurl_response", item_id=self.id) - ) + return lnurl_encode(req.url_for("offlineshop.lnurl_response", item_id=self.id)) def values(self, req: Request): values = self.dict() @@ -116,8 +114,6 @@ class Item(BaseModel): return None return UrlAction( - url=req.url_for( - "offlineshop.confirmation_code", p=payment_hash - ), + url=req.url_for("offlineshop.confirmation_code", p=payment_hash), description="Open to get the confirmation code for your purchase.", ) diff --git a/lnbits/extensions/offlineshop/views.py b/lnbits/extensions/offlineshop/views.py index e8bea173..748d2024 100644 --- a/lnbits/extensions/offlineshop/views.py +++ b/lnbits/extensions/offlineshop/views.py @@ -18,14 +18,16 @@ from fastapi import Request, HTTPException @offlineshop_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): - return offlineshop_renderer().TemplateResponse("offlineshop/index.html", {"request": request, "user": user.dict()}) + return offlineshop_renderer().TemplateResponse( + "offlineshop/index.html", {"request": request, "user": user.dict()} + ) @offlineshop_ext.get("/print", response_class=HTMLResponse) async def print_qr_codes(request: Request, items: List[int] = None): items = [] for item_id in request.query_params.get("items").split(","): - item = await get_item(item_id) # type: Item + item = await get_item(item_id) # type: Item if item: items.append( { @@ -35,11 +37,16 @@ async def print_qr_codes(request: Request, items: List[int] = None): } ) - return offlineshop_renderer().TemplateResponse("offlineshop/print.html", {"request": request,"items":items}) + return offlineshop_renderer().TemplateResponse( + "offlineshop/print.html", {"request": request, "items": items} + ) -@offlineshop_ext.get("/confirmation/{p}", name="offlineshop.confirmation_code", - response_class=HTMLResponse) +@offlineshop_ext.get( + "/confirmation/{p}", + name="offlineshop.confirmation_code", + response_class=HTMLResponse, +) async def confirmation_code(p: str = Query(...)): style = "" @@ -48,20 +55,20 @@ async def confirmation_code(p: str = Query(...)): if not payment: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, - detail=f"Couldn't find the payment {payment_hash}." + style + detail=f"Couldn't find the payment {payment_hash}." + style, ) if payment.pending: raise HTTPException( status_code=HTTPStatus.PAYMENT_REQUIRED, - detail=f"Payment {payment_hash} wasn't received yet. Please try again in a minute." + style + detail=f"Payment {payment_hash} wasn't received yet. Please try again in a minute." + + style, ) if payment.time + 60 * 15 < time.time(): raise HTTPException( status_code=HTTPStatus.REQUEST_TIMEOUT, - detail="Too much time has passed." + style + detail="Too much time has passed." + style, ) - item = await get_item(payment.extra.get("item")) shop = await get_shop(item.shop) diff --git a/lnbits/extensions/offlineshop/views_api.py b/lnbits/extensions/offlineshop/views_api.py index 58b95935..f3968948 100644 --- a/lnbits/extensions/offlineshop/views_api.py +++ b/lnbits/extensions/offlineshop/views_api.py @@ -33,17 +33,16 @@ async def api_list_currencies_available(): @offlineshop_ext.get("/api/v1/offlineshop") # @api_check_wallet_key("invoice") -async def api_shop_from_wallet(r: Request, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_shop_from_wallet( + r: Request, wallet: WalletTypeInfo = Depends(get_key_type) +): shop = await get_or_create_shop_by_wallet(wallet.wallet.id) items = await get_items(shop.id) try: return { **shop.dict(), - **{ - "otp_key": shop.otp_key, - "items": [item.values(r) for item in items], - }, + **{"otp_key": shop.otp_key, "items": [item.values(r) for item in items]}, } except LnurlInvalidUrl: raise HTTPException( @@ -63,18 +62,15 @@ class CreateItemsData(BaseModel): @offlineshop_ext.post("/api/v1/offlineshop/items") @offlineshop_ext.put("/api/v1/offlineshop/items/{item_id}") # @api_check_wallet_key("invoice") -async def api_add_or_update_item(data: CreateItemsData, item_id=None, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_add_or_update_item( + data: CreateItemsData, item_id=None, wallet: WalletTypeInfo = Depends(get_key_type) +): shop = await get_or_create_shop_by_wallet(wallet.wallet.id) if item_id == None: await add_item( - shop.id, - data.name, - data.description, - data.image, - data.price, - data.unit, + shop.id, data.name, data.description, data.image, data.price, data.unit ) - return HTMLResponse(status_code=HTTPStatus.CREATED) + return HTMLResponse(status_code=HTTPStatus.CREATED) else: await update_item( shop.id, @@ -102,7 +98,9 @@ class CreateMethodData(BaseModel): @offlineshop_ext.put("/api/v1/offlineshop/method") # @api_check_wallet_key("invoice") -async def api_set_method(data: CreateMethodData, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_set_method( + data: CreateMethodData, wallet: WalletTypeInfo = Depends(get_key_type) +): method = data.method wordlist = data.wordlist.split("\n") if data.wordlist else None diff --git a/lnbits/extensions/satsdice/__init__.py b/lnbits/extensions/satsdice/__init__.py index 2149760f..5a645618 100644 --- a/lnbits/extensions/satsdice/__init__.py +++ b/lnbits/extensions/satsdice/__init__.py @@ -12,11 +12,7 @@ satsdice_ext: APIRouter = APIRouter(prefix="/satsdice", tags=["satsdice"]) def satsdice_renderer(): - return template_renderer( - [ - "lnbits/extensions/satsdice/templates", - ] - ) + return template_renderer(["lnbits/extensions/satsdice/templates"]) from .views_api import * # noqa diff --git a/lnbits/extensions/satsdice/crud.py b/lnbits/extensions/satsdice/crud.py index ddf54eb5..e4476a11 100644 --- a/lnbits/extensions/satsdice/crud.py +++ b/lnbits/extensions/satsdice/crud.py @@ -15,9 +15,7 @@ from .models import ( from lnbits.helpers import urlsafe_short_hash -async def create_satsdice_pay( - data: CreateSatsDiceLink, -) -> satsdiceLink: +async def create_satsdice_pay(data: CreateSatsDiceLink,) -> satsdiceLink: satsdice_id = urlsafe_short_hash() await db.execute( """ @@ -124,13 +122,7 @@ async def create_satsdice_payment(data: CreateSatsDicePayment) -> satsdicePaymen ) VALUES (?, ?, ?, ?, ?) """, - ( - data.payment_hash, - data.satsdice_pay, - data.value, - False, - False, - ), + (data.payment_hash, data.satsdice_pay, data.value, False, False), ) payment = await get_satsdice_payment(payment_hash) assert payment, "Newly created withdraw couldn't be retrieved" @@ -211,8 +203,7 @@ async def get_satsdice_withdraw_by_hash( unique_hash: str, num=0 ) -> Optional[satsdiceWithdraw]: row = await db.fetchone( - "SELECT * FROM satsdice.satsdice_withdraw WHERE unique_hash = ?", - (unique_hash,), + "SELECT * FROM satsdice.satsdice_withdraw WHERE unique_hash = ?", (unique_hash,) ) if not row: return None @@ -259,10 +250,7 @@ async def delete_satsdice_withdraw(withdraw_id: str) -> None: ) -async def create_withdraw_hash_check( - the_hash: str, - lnurl_id: str, -) -> HashCheck: +async def create_withdraw_hash_check(the_hash: str, lnurl_id: str) -> HashCheck: await db.execute( """ INSERT INTO satsdice.hash_checkw ( @@ -271,10 +259,7 @@ async def create_withdraw_hash_check( ) VALUES (?, ?) """, - ( - the_hash, - lnurl_id, - ), + (the_hash, lnurl_id), ) hashCheck = await get_withdraw_hash_checkw(the_hash, lnurl_id) return hashCheck diff --git a/lnbits/extensions/satsdice/lnurl.py b/lnbits/extensions/satsdice/lnurl.py index 705eb700..f2b4cf98 100644 --- a/lnbits/extensions/satsdice/lnurl.py +++ b/lnbits/extensions/satsdice/lnurl.py @@ -19,7 +19,11 @@ from .crud import ( get_satsdice_pay, create_satsdice_payment, ) -from lnurl import LnurlPayResponse, LnurlPayActionResponse, LnurlErrorResponse # type: ignore +from lnurl import ( + LnurlPayResponse, + LnurlPayActionResponse, + LnurlErrorResponse, +) # type: ignore ##############LNURLP STUFF @@ -30,8 +34,7 @@ async def api_lnurlp_response(req: Request, link_id: str = Query(None)): link = await get_satsdice_pay(link_id) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="LNURL-pay not found.", + status_code=HTTPStatus.NOT_FOUND, detail="LNURL-pay not found." ) resp = LnurlPayResponse( callback=req.url_for( @@ -51,8 +54,7 @@ async def api_lnurlp_callback(link_id: str = Query(None), amount: str = Query(No link = await get_satsdice_pay(link_id) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="LNURL-pay not found.", + status_code=HTTPStatus.NOT_FOUND, detail="LNURL-pay not found." ) min, max = link.min_bet, link.max_bet @@ -87,15 +89,10 @@ async def api_lnurlp_callback(link_id: str = Query(None), amount: str = Query(No link = await create_satsdice_payment(data) if success_action: resp = LnurlPayActionResponse( - pr=payment_request, - success_action=success_action, - routes=[], + pr=payment_request, success_action=success_action, routes=[] ) else: - resp = LnurlPayActionResponse( - pr=payment_request, - routes=[], - ) + resp = LnurlPayActionResponse(pr=payment_request, routes=[]) return resp.dict() @@ -109,15 +106,11 @@ async def api_lnurlw_response(unique_hash: str = Query(None)): if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="LNURL-satsdice not found.", + status_code=HTTPStatus.NOT_FOUND, detail="LNURL-satsdice not found." ) if link.used: - raise HTTPException( - status_code=HTTPStatus.OK, - detail="satsdice is spent.", - ) + raise HTTPException(status_code=HTTPStatus.OK, detail="satsdice is spent.") return link.lnurl_response.dict() @@ -136,21 +129,14 @@ async def api_lnurlw_callback( if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="LNURL-satsdice not found.", + status_code=HTTPStatus.NOT_FOUND, detail="LNURL-satsdice not found." ) if link.used: - raise HTTPException( - status_code=HTTPStatus.OK, - detail="satsdice is spent.", - ) + raise HTTPException(status_code=HTTPStatus.OK, detail="satsdice is spent.") if link.k1 != k1: - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail="Bad request..", - ) + raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Bad request..") if now < link.open_time: return {"status": "ERROR", "reason": f"Wait {link.open_time - now} seconds."} diff --git a/lnbits/extensions/satsdice/models.py b/lnbits/extensions/satsdice/models.py index 820a6ed1..b38d7522 100644 --- a/lnbits/extensions/satsdice/models.py +++ b/lnbits/extensions/satsdice/models.py @@ -51,11 +51,7 @@ class satsdiceLink(BaseModel): # qs: Dict = parse_qs(url.query) # qs["payment_hash"] = payment_hash # url = url._replace(query=urlencode(qs, doseq=True)) - return { - "tag": "url", - "description": "Check the attached link", - "url": url, - } + return {"tag": "url", "description": "Check the attached link", "url": url} class satsdicePayment(BaseModel): @@ -78,9 +74,7 @@ class satsdiceWithdraw(BaseModel): def lnurl(self, req: Request) -> Lnurl: return lnurl_encode( req.url_for( - "satsdice.lnurlw_response", - unique_hash=self.unique_hash, - _external=True, + "satsdice.lnurlw_response", unique_hash=self.unique_hash, _external=True ) ) @@ -91,9 +85,7 @@ class satsdiceWithdraw(BaseModel): @property def lnurl_response(self, req: Request) -> LnurlWithdrawResponse: url = req.url_for( - "satsdice.api_lnurlw_callback", - unique_hash=self.unique_hash, - _external=True, + "satsdice.api_lnurlw_callback", unique_hash=self.unique_hash, _external=True ) return LnurlWithdrawResponse( callback=url, diff --git a/lnbits/extensions/satsdice/views.py b/lnbits/extensions/satsdice/views.py index ceebf822..fe0ad481 100644 --- a/lnbits/extensions/satsdice/views.py +++ b/lnbits/extensions/satsdice/views.py @@ -15,9 +15,7 @@ from lnbits.core.crud import ( delete_expired_invoices, get_balance_checks, ) -from lnbits.core.services import ( - check_invoice_status, -) +from lnbits.core.services import check_invoice_status from fastapi import FastAPI, Request from fastapi.params import Depends from fastapi.templating import Jinja2Templates diff --git a/lnbits/extensions/satsdice/views_api.py b/lnbits/extensions/satsdice/views_api.py index 466f6483..8c5f9d0e 100644 --- a/lnbits/extensions/satsdice/views_api.py +++ b/lnbits/extensions/satsdice/views_api.py @@ -67,14 +67,12 @@ async def api_link_retrieve( if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Pay link does not exist.", + status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist." ) if link.wallet != wallet.wallet.id: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Not your pay link.", + status_code=HTTPStatus.FORBIDDEN, detail="Not your pay link." ) return {**link._asdict(), **{"lnurl": link.lnurl}} @@ -88,17 +86,13 @@ async def api_link_create_or_update( link_id: str = Query(None), ): if data.min_bet > data.max_bet: - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail="Bad request", - ) + raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Bad request") if link_id: link = await get_satsdice_pay(link_id) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Satsdice does not exist", + status_code=HTTPStatus.NOT_FOUND, detail="Satsdice does not exist" ) if link.wallet != wallet.wallet.id: @@ -123,14 +117,12 @@ async def api_link_delete( if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Pay link does not exist.", + status_code=HTTPStatus.NOT_FOUND, detail="Pay link does not exist." ) if link.wallet != g.wallet.id: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Not your pay link.", + status_code=HTTPStatus.FORBIDDEN, detail="Not your pay link." ) await delete_satsdice_pay(link_id) @@ -153,10 +145,7 @@ async def api_withdraws( return ( jsonify( [ - { - **withdraw._asdict(), - **{"lnurl": withdraw.lnurl}, - } + {**withdraw._asdict(), **{"lnurl": withdraw.lnurl}} for withdraw in await get_satsdice_withdraws(wallet_ids) ] ), @@ -177,14 +166,12 @@ async def api_withdraw_retrieve( if not withdraw: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="satsdice withdraw does not exist.", + status_code=HTTPStatus.NOT_FOUND, detail="satsdice withdraw does not exist." ) if withdraw.wallet != wallet.wallet.id: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Not your satsdice withdraw.", + status_code=HTTPStatus.FORBIDDEN, detail="Not your satsdice withdraw." ) return {**withdraw._asdict(), **{"lnurl": withdraw.lnurl}}, HTTPStatus.OK @@ -220,8 +207,7 @@ async def api_withdraw_create_or_update( ) if withdraw.wallet != wallet.wallet.id: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Not your satsdice withdraw.", + status_code=HTTPStatus.FORBIDDEN, detail="Not your satsdice withdraw." ) withdraw = await update_satsdice_withdraw( @@ -245,14 +231,12 @@ async def api_withdraw_delete( if not withdraw: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="satsdice withdraw does not exist.", + status_code=HTTPStatus.NOT_FOUND, detail="satsdice withdraw does not exist." ) if withdraw.wallet != wallet.wallet.id: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Not your satsdice withdraw.", + status_code=HTTPStatus.FORBIDDEN, detail="Not your satsdice withdraw." ) await delete_satsdice_withdraw(withdraw_id) diff --git a/lnbits/extensions/satspay/__init__.py b/lnbits/extensions/satspay/__init__.py index 7b7f0bde..b9c67e40 100644 --- a/lnbits/extensions/satspay/__init__.py +++ b/lnbits/extensions/satspay/__init__.py @@ -8,17 +8,11 @@ from lnbits.helpers import template_renderer db = Database("ext_satspay") -satspay_ext: APIRouter = APIRouter( - prefix="/satspay", - tags=["satspay"] -) +satspay_ext: APIRouter = APIRouter(prefix="/satspay", tags=["satspay"]) + def satspay_renderer(): - return template_renderer( - [ - "lnbits/extensions/satspay/templates", - ] - ) + return template_renderer(["lnbits/extensions/satspay/templates"]) from .views_api import * # noqa diff --git a/lnbits/extensions/satspay/crud.py b/lnbits/extensions/satspay/crud.py index e707dc00..50545d9c 100644 --- a/lnbits/extensions/satspay/crud.py +++ b/lnbits/extensions/satspay/crud.py @@ -14,10 +14,7 @@ from ..watchonly.crud import get_watch_wallet, get_fresh_address, get_mempool ###############CHARGES########################## -async def create_charge( - user: str, - data: CreateCharge -) -> Charges: +async def create_charge(user: str, data: CreateCharge) -> Charges: charge_id = urlsafe_short_hash() if data.onchainwallet: wallet = await get_watch_wallet(data.onchainwallet) diff --git a/lnbits/extensions/satspay/models.py b/lnbits/extensions/satspay/models.py index 4cf3efad..d67e478a 100644 --- a/lnbits/extensions/satspay/models.py +++ b/lnbits/extensions/satspay/models.py @@ -4,6 +4,7 @@ from fastapi.param_functions import Query from pydantic import BaseModel import time + class CreateCharge(BaseModel): onchainwallet: str = Query(None) lnbitswallet: str = Query(None) @@ -14,6 +15,7 @@ class CreateCharge(BaseModel): time: int = Query(..., ge=1) amount: int = Query(..., ge=1) + class Charges(BaseModel): id: str user: str diff --git a/lnbits/extensions/satspay/views.py b/lnbits/extensions/satspay/views.py index 020b5897..f6694034 100644 --- a/lnbits/extensions/satspay/views.py +++ b/lnbits/extensions/satspay/views.py @@ -14,9 +14,12 @@ from .crud import get_charge templates = Jinja2Templates(directory="templates") + @satspay_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): - return satspay_renderer().TemplateResponse("satspay/index.html", {"request": request,"user": user.dict()}) + return satspay_renderer().TemplateResponse( + "satspay/index.html", {"request": request, "user": user.dict()} + ) @satspay_ext.get("/{charge_id}", response_class=HTMLResponse) @@ -24,7 +27,8 @@ async def display(request: Request, charge_id): charge = await get_charge(charge_id) if not charge: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Charge link does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Charge link does not exist." ) - return satspay_renderer().TemplateResponse("satspay/display.html", {"request": request, "charge": charge}) + return satspay_renderer().TemplateResponse( + "satspay/display.html", {"request": request, "charge": charge} + ) diff --git a/lnbits/extensions/satspay/views_api.py b/lnbits/extensions/satspay/views_api.py index 0bfe5f04..2ca16370 100644 --- a/lnbits/extensions/satspay/views_api.py +++ b/lnbits/extensions/satspay/views_api.py @@ -30,8 +30,9 @@ from .crud import ( @satspay_ext.post("/api/v1/charge") @satspay_ext.put("/api/v1/charge/{charge_id}") - -async def api_charge_create_or_update(data: CreateCharge, wallet: WalletTypeInfo = Depends(get_key_type), charge_id=None): +async def api_charge_create_or_update( + data: CreateCharge, wallet: WalletTypeInfo = Depends(get_key_type), charge_id=None +): if not charge_id: charge = await create_charge(user=wallet.wallet.user, data=data) return charge.dict() @@ -44,32 +45,33 @@ async def api_charge_create_or_update(data: CreateCharge, wallet: WalletTypeInfo async def api_charges_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)): try: return [ - { - **charge.dict(), - **{"time_elapsed": charge.time_elapsed}, - **{"paid": charge.paid}, - } - for charge in await get_charges(wallet.wallet.user) - ] + { + **charge.dict(), + **{"time_elapsed": charge.time_elapsed}, + **{"paid": charge.paid}, + } + for charge in await get_charges(wallet.wallet.user) + ] except: return "" @satspay_ext.get("/api/v1/charge/{charge_id}") -async def api_charge_retrieve(charge_id, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_charge_retrieve( + charge_id, wallet: WalletTypeInfo = Depends(get_key_type) +): charge = await get_charge(charge_id) if not charge: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Charge does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Charge does not exist." ) return { - **charge.dict(), - **{"time_elapsed": charge.time_elapsed}, - **{"paid": charge.paid}, - } + **charge.dict(), + **{"time_elapsed": charge.time_elapsed}, + **{"paid": charge.paid}, + } @satspay_ext.delete("/api/v1/charge/{charge_id}") @@ -78,8 +80,7 @@ async def api_charge_delete(charge_id, wallet: WalletTypeInfo = Depends(get_key_ if not charge: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Charge does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Charge does not exist." ) await delete_charge(charge_id) @@ -96,8 +97,7 @@ async def api_charges_balance(charge_id): if not charge: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Charge does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Charge does not exist." ) if charge.paid and charge.webhook: @@ -129,7 +129,9 @@ async def api_charges_balance(charge_id): @satspay_ext.put("/api/v1/mempool") -async def api_update_mempool(endpoint: str = Query(...), wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_update_mempool( + endpoint: str = Query(...), wallet: WalletTypeInfo = Depends(get_key_type) +): mempool = await update_mempool(endpoint, user=wallet.wallet.user) return mempool.dict() diff --git a/lnbits/extensions/tpos/__init__.py b/lnbits/extensions/tpos/__init__.py index ea7a0504..eb5affe0 100644 --- a/lnbits/extensions/tpos/__init__.py +++ b/lnbits/extensions/tpos/__init__.py @@ -14,12 +14,9 @@ tpos_ext: APIRouter = APIRouter( # "tpos", __name__, static_folder="static", template_folder="templates" ) + def tpos_renderer(): - return template_renderer( - [ - "lnbits/extensions/tpos/templates", - ] - ) + return template_renderer(["lnbits/extensions/tpos/templates"]) from .views_api import * # noqa diff --git a/lnbits/extensions/tpos/models.py b/lnbits/extensions/tpos/models.py index a474a05d..7d5f9964 100644 --- a/lnbits/extensions/tpos/models.py +++ b/lnbits/extensions/tpos/models.py @@ -7,6 +7,7 @@ class CreateTposData(BaseModel): name: str currency: str + class TPoS(BaseModel): id: str wallet: str diff --git a/lnbits/extensions/tpos/views.py b/lnbits/extensions/tpos/views.py index 1c7fedcd..80c53684 100644 --- a/lnbits/extensions/tpos/views.py +++ b/lnbits/extensions/tpos/views.py @@ -13,11 +13,14 @@ from fastapi.templating import Jinja2Templates templates = Jinja2Templates(directory="templates") + @tpos_ext.get("/", response_class=HTMLResponse) # @validate_uuids(["usr"], required=True) # @check_user_exists() async def index(request: Request, user: User = Depends(check_user_exists)): - return tpos_renderer().TemplateResponse("tpos/index.html", {"request": request,"user": user.dict()}) + return tpos_renderer().TemplateResponse( + "tpos/index.html", {"request": request, "user": user.dict()} + ) @tpos_ext.get("/{tpos_id}") @@ -25,9 +28,10 @@ async def tpos(request: Request, tpos_id): tpos = await get_tpos(tpos_id) if not tpos: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="TPoS does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." ) # abort(HTTPStatus.NOT_FOUND, "TPoS does not exist.") - return tpos_renderer().TemplateResponse("tpos/tpos.html", {"request": request, "tpos": tpos}) + return tpos_renderer().TemplateResponse( + "tpos/tpos.html", {"request": request, "tpos": tpos} + ) diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py index b73dc83e..197fe168 100644 --- a/lnbits/extensions/tpos/views_api.py +++ b/lnbits/extensions/tpos/views_api.py @@ -19,18 +19,19 @@ from .models import TPoS, CreateTposData @tpos_ext.get("/api/v1/tposs", status_code=HTTPStatus.OK) async def api_tposs( - all_wallets: bool = Query(None), - wallet: WalletTypeInfo = Depends(get_key_type) - ): + all_wallets: bool = Query(None), wallet: WalletTypeInfo = Depends(get_key_type) +): wallet_ids = [wallet.wallet.id] if all_wallets: - wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids return [tpos.dict() for tpos in await get_tposs(wallet_ids)] @tpos_ext.post("/api/v1/tposs", status_code=HTTPStatus.CREATED) -async def api_tpos_create(data: CreateTposData, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_tpos_create( + data: CreateTposData, wallet: WalletTypeInfo = Depends(get_key_type) +): tpos = await create_tpos(wallet_id=wallet.wallet.id, data=data) return tpos.dict() @@ -41,30 +42,26 @@ async def api_tpos_delete(tpos_id: str, wallet: WalletTypeInfo = Depends(get_key if not tpos: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="TPoS does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." ) # return {"message": "TPoS does not exist."}, HTTPStatus.NOT_FOUND if tpos.wallet != wallet.wallet.id: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, - detail="Not your TPoS." - ) + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your TPoS.") # return {"message": "Not your TPoS."}, HTTPStatus.FORBIDDEN await delete_tpos(tpos_id) raise HTTPException(status_code=HTTPStatus.NO_CONTENT) # return "", HTTPStatus.NO_CONTENT + @tpos_ext.post("/api/v1/tposs/{tpos_id}/invoices", status_code=HTTPStatus.CREATED) async def api_tpos_create_invoice(amount: int = Query(..., ge=1), tpos_id: str = None): tpos = await get_tpos(tpos_id) if not tpos: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="TPoS does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." ) # return {"message": "TPoS does not exist."}, HTTPStatus.NOT_FOUND @@ -76,22 +73,20 @@ async def api_tpos_create_invoice(amount: int = Query(..., ge=1), tpos_id: str = extra={"tag": "tpos"}, ) except Exception as e: - raise HTTPException( - status_code=HTTPStatus.INTERNAL_SERVER_ERROR, - detail=str(e) - ) + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) # return {"message": str(e)}, HTTPStatus.INTERNAL_SERVER_ERROR return {"payment_hash": payment_hash, "payment_request": payment_request} -@tpos_ext.get("/api/v1/tposs/{tpos_id}/invoices/{payment_hash}", status_code=HTTPStatus.OK) +@tpos_ext.get( + "/api/v1/tposs/{tpos_id}/invoices/{payment_hash}", status_code=HTTPStatus.OK +) async def api_tpos_check_invoice(tpos_id: str, payment_hash: str): tpos = await get_tpos(tpos_id) if not tpos: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="TPoS does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." ) # return {"message": "TPoS does not exist."}, HTTPStatus.NOT_FOUND diff --git a/lnbits/extensions/usermanager/__init__.py b/lnbits/extensions/usermanager/__init__.py index f421a15c..2e3d6d5a 100644 --- a/lnbits/extensions/usermanager/__init__.py +++ b/lnbits/extensions/usermanager/__init__.py @@ -10,15 +10,12 @@ db = Database("ext_usermanager") usermanager_ext: APIRouter = APIRouter( prefix="/usermanager", tags=["usermanager"] - #"usermanager", __name__, static_folder="static", template_folder="templates" + # "usermanager", __name__, static_folder="static", template_folder="templates" ) + def usermanager_renderer(): - return template_renderer( - [ - "lnbits/extensions/usermanager/templates", - ] - ) + return template_renderer(["lnbits/extensions/usermanager/templates"]) from .views_api import * # noqa diff --git a/lnbits/extensions/usermanager/crud.py b/lnbits/extensions/usermanager/crud.py index e1c8aebd..f27acd68 100644 --- a/lnbits/extensions/usermanager/crud.py +++ b/lnbits/extensions/usermanager/crud.py @@ -16,9 +16,7 @@ from .models import Users, Wallets, CreateUserData ### Users -async def create_usermanager_user( - data: CreateUserData -) -> Users: +async def create_usermanager_user(data: CreateUserData) -> Users: account = await create_account() user = await get_user(account.id) assert user, "Newly created user couldn't be retrieved" @@ -38,7 +36,14 @@ async def create_usermanager_user( INSERT INTO usermanager.wallets (id, admin, name, "user", adminkey, inkey) VALUES (?, ?, ?, ?, ?, ?) """, - (wallet.id, data.admin_id, data.wallet_name, user.id, wallet.adminkey, wallet.inkey), + ( + wallet.id, + data.admin_id, + data.wallet_name, + user.id, + wallet.adminkey, + wallet.inkey, + ), ) user_created = await get_usermanager_user(user.id) @@ -55,7 +60,7 @@ async def get_usermanager_users(user_id: str) -> List[Users]: rows = await db.fetchall( "SELECT * FROM usermanager.users WHERE admin = ?", (user_id,) ) - + return [Users(**row) for row in rows] diff --git a/lnbits/extensions/usermanager/models.py b/lnbits/extensions/usermanager/models.py index 005ed8af..4dbe4389 100644 --- a/lnbits/extensions/usermanager/models.py +++ b/lnbits/extensions/usermanager/models.py @@ -2,6 +2,7 @@ from pydantic import BaseModel from fastapi.param_functions import Query from sqlite3 import Row + class CreateUserData(BaseModel): user_name: str = Query(...) wallet_name: str = Query(...) diff --git a/lnbits/extensions/usermanager/views.py b/lnbits/extensions/usermanager/views.py index 395e0c0b..5faec4db 100644 --- a/lnbits/extensions/usermanager/views.py +++ b/lnbits/extensions/usermanager/views.py @@ -8,6 +8,9 @@ from lnbits.decorators import check_user_exists from . import usermanager_ext, usermanager_renderer + @usermanager_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): - return usermanager_renderer().TemplateResponse("usermanager/index.html", {"request": request,"user": user.dict()}) + return usermanager_renderer().TemplateResponse( + "usermanager/index.html", {"request": request, "user": user.dict()} + ) diff --git a/lnbits/extensions/usermanager/views_api.py b/lnbits/extensions/usermanager/views_api.py index caa513c8..08d0e4f5 100644 --- a/lnbits/extensions/usermanager/views_api.py +++ b/lnbits/extensions/usermanager/views_api.py @@ -49,20 +49,25 @@ async def api_usermanager_user(user_id, wallet: WalletTypeInfo = Depends(get_key # "password": {"type": "string", "required": False}, # } # ) -async def api_usermanager_users_create(data: CreateUserData, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_usermanager_users_create( + data: CreateUserData, wallet: WalletTypeInfo = Depends(get_key_type) +): user = await create_usermanager_user(data) full = user.dict() - full["wallets"] = [wallet.dict() for wallet in await get_usermanager_users_wallets(user.id)] + full["wallets"] = [ + wallet.dict() for wallet in await get_usermanager_users_wallets(user.id) + ] return full @usermanager_ext.delete("/api/v1/users/{user_id}") -async def api_usermanager_users_delete(user_id, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_usermanager_users_delete( + user_id, wallet: WalletTypeInfo = Depends(get_key_type) +): user = await get_usermanager_user(user_id) if not user: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="User does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) await delete_usermanager_user(user_id) raise HTTPException(status_code=HTTPStatus.NO_CONTENT) @@ -72,16 +77,15 @@ async def api_usermanager_users_delete(user_id, wallet: WalletTypeInfo = Depends @usermanager_ext.post("/api/v1/extensions") -async def api_usermanager_activate_extension(extension: str = Query(...), userid: str = Query(...), active: bool = Query(...)): +async def api_usermanager_activate_extension( + extension: str = Query(...), userid: str = Query(...), active: bool = Query(...) +): user = await get_user(userid) if not user: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="User does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) - update_user_extension( - user_id=userid, extension=extension, active=active - ) + update_user_extension(user_id=userid, extension=extension, active=active) return {"extension": "updated"} @@ -93,11 +97,9 @@ async def api_usermanager_wallets_create( wallet: WalletTypeInfo = Depends(get_key_type), user_id: str = Query(...), wallet_name: str = Query(...), - admin_id: str = Query(...) + admin_id: str = Query(...), ): - user = await create_usermanager_wallet( - user_id, wallet_name, admin_id - ) + user = await create_usermanager_wallet(user_id, wallet_name, admin_id) return user.dict() @@ -108,23 +110,30 @@ async def api_usermanager_wallets(wallet: WalletTypeInfo = Depends(get_key_type) @usermanager_ext.get("/api/v1/wallets/{wallet_id}") -async def api_usermanager_wallet_transactions(wallet_id, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_usermanager_wallet_transactions( + wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) +): return await get_usermanager_wallet_transactions(wallet_id) @usermanager_ext.get("/api/v1/wallets/{user_id}") -async def api_usermanager_users_wallets(user_id, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_usermanager_users_wallets( + user_id, wallet: WalletTypeInfo = Depends(get_key_type) +): # wallet = await get_usermanager_users_wallets(user_id) - return [s_wallet.dict() for s_wallet in await get_usermanager_users_wallets(user_id)] + return [ + s_wallet.dict() for s_wallet in await get_usermanager_users_wallets(user_id) + ] @usermanager_ext.delete("/api/v1/wallets/{wallet_id}") -async def api_usermanager_wallets_delete(wallet_id, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_usermanager_wallets_delete( + wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) +): get_wallet = await get_usermanager_wallet(wallet_id) if not get_wallet: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Wallet does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist." ) await delete_usermanager_wallet(wallet_id, get_wallet.user) raise HTTPException(status_code=HTTPStatus.NO_CONTENT) diff --git a/lnbits/extensions/watchonly/__init__.py b/lnbits/extensions/watchonly/__init__.py index 8a1632f5..9cd4d69a 100644 --- a/lnbits/extensions/watchonly/__init__.py +++ b/lnbits/extensions/watchonly/__init__.py @@ -8,17 +8,11 @@ from lnbits.helpers import template_renderer db = Database("ext_watchonly") -watchonly_ext: APIRouter = APIRouter( - prefix="/watchonly", - tags=["watchonly"] -) +watchonly_ext: APIRouter = APIRouter(prefix="/watchonly", tags=["watchonly"]) + def watchonly_renderer(): - return template_renderer( - [ - "lnbits/extensions/watchonly/templates", - ] - ) + return template_renderer(["lnbits/extensions/watchonly/templates"]) from .views_api import * # noqa diff --git a/lnbits/extensions/watchonly/models.py b/lnbits/extensions/watchonly/models.py index 2fc4bf2e..aed4ca61 100644 --- a/lnbits/extensions/watchonly/models.py +++ b/lnbits/extensions/watchonly/models.py @@ -2,10 +2,12 @@ from sqlite3 import Row from fastapi.param_functions import Query from pydantic import BaseModel + class CreateWallet(BaseModel): masterpub: str = Query("") title: str = Query("") + class Wallets(BaseModel): id: str user: str diff --git a/lnbits/extensions/watchonly/views.py b/lnbits/extensions/watchonly/views.py index c56f0b9c..37f8b089 100644 --- a/lnbits/extensions/watchonly/views.py +++ b/lnbits/extensions/watchonly/views.py @@ -8,6 +8,7 @@ from lnbits.core.models import User from lnbits.decorators import check_user_exists from . import watchonly_ext, watchonly_renderer + # from .crud import get_payment from fastapi.templating import Jinja2Templates @@ -17,7 +18,9 @@ templates = Jinja2Templates(directory="templates") @watchonly_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): - return watchonly_renderer().TemplateResponse("watchonly/index.html", {"request": request,"user": user.dict()}) + return watchonly_renderer().TemplateResponse( + "watchonly/index.html", {"request": request, "user": user.dict()} + ) # @watchonly_ext.get("/{charge_id}", response_class=HTMLResponse) diff --git a/lnbits/extensions/watchonly/views_api.py b/lnbits/extensions/watchonly/views_api.py index 8b3d92c5..c457f06f 100644 --- a/lnbits/extensions/watchonly/views_api.py +++ b/lnbits/extensions/watchonly/views_api.py @@ -38,29 +38,29 @@ async def api_wallets_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)): @watchonly_ext.get("/api/v1/wallet/{wallet_id}") -async def api_wallet_retrieve(wallet_id, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_wallet_retrieve( + wallet_id, wallet: WalletTypeInfo = Depends(get_key_type) +): w_wallet = await get_watch_wallet(wallet_id) if not w_wallet: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Wallet does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist." ) return w_wallet.dict() @watchonly_ext.post("/api/v1/wallet") -async def api_wallet_create_or_update(data: CreateWallet, wallet_id=None, w: WalletTypeInfo = Depends(get_key_type)): +async def api_wallet_create_or_update( + data: CreateWallet, wallet_id=None, w: WalletTypeInfo = Depends(get_key_type) +): try: wallet = await create_watch_wallet( user=w.wallet.user, masterpub=data.masterpub, title=data.title ) except Exception as e: - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail=str(e) - ) + raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=str(e)) mempool = await get_mempool(w.wallet.user) if not mempool: @@ -74,8 +74,7 @@ async def api_wallet_delete(wallet_id, w: WalletTypeInfo = Depends(get_key_type) if not wallet: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Wallet does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist." ) await delete_watch_wallet(wallet_id) @@ -96,14 +95,12 @@ async def api_fresh_address(wallet_id, w: WalletTypeInfo = Depends(get_key_type) @watchonly_ext.get("/api/v1/addresses/{wallet_id}") - async def api_get_addresses(wallet_id, w: WalletTypeInfo = Depends(get_key_type)): wallet = await get_watch_wallet(wallet_id) if not wallet: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Wallet does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist." ) addresses = await get_addresses(wallet_id) @@ -119,7 +116,9 @@ async def api_get_addresses(wallet_id, w: WalletTypeInfo = Depends(get_key_type) @watchonly_ext.put("/api/v1/mempool") -async def api_update_mempool(endpoint: str = Query(...), w: WalletTypeInfo = Depends(get_key_type)): +async def api_update_mempool( + endpoint: str = Query(...), w: WalletTypeInfo = Depends(get_key_type) +): mempool = await update_mempool(endpoint, user=w.wallet.user) return mempool.dict() diff --git a/lnbits/extensions/withdraw/__init__.py b/lnbits/extensions/withdraw/__init__.py index 184b4f01..98efd0bf 100644 --- a/lnbits/extensions/withdraw/__init__.py +++ b/lnbits/extensions/withdraw/__init__.py @@ -21,12 +21,9 @@ withdraw_ext: APIRouter = APIRouter( # "withdraw", __name__, static_folder="static", template_folder="templates" ) + def withdraw_renderer(): - return template_renderer( - [ - "lnbits/extensions/withdraw/templates", - ] - ) + return template_renderer(["lnbits/extensions/withdraw/templates"]) from .views_api import * # noqa diff --git a/lnbits/extensions/withdraw/crud.py b/lnbits/extensions/withdraw/crud.py index 839e7a40..a060c722 100644 --- a/lnbits/extensions/withdraw/crud.py +++ b/lnbits/extensions/withdraw/crud.py @@ -7,9 +7,7 @@ from .models import WithdrawLink, HashCheck, CreateWithdrawData async def create_withdraw_link( - data: CreateWithdrawData, - wallet_id: str, - usescsv: str, + data: CreateWithdrawData, wallet_id: str, usescsv: str ) -> WithdrawLink: link_id = urlsafe_short_hash() await db.execute( @@ -115,10 +113,7 @@ def chunks(lst, n): yield lst[i : i + n] -async def create_hash_check( - the_hash: str, - lnurl_id: str, -) -> HashCheck: +async def create_hash_check(the_hash: str, lnurl_id: str) -> HashCheck: await db.execute( """ INSERT INTO withdraw.hash_check ( @@ -127,10 +122,7 @@ async def create_hash_check( ) VALUES (?, ?) """, - ( - the_hash, - lnurl_id, - ), + (the_hash, lnurl_id), ) hashCheck = await get_hash_check(the_hash, lnurl_id) return hashCheck diff --git a/lnbits/extensions/withdraw/lnurl.py b/lnbits/extensions/withdraw/lnurl.py index 3b5f42fc..1429d0d2 100644 --- a/lnbits/extensions/withdraw/lnurl.py +++ b/lnbits/extensions/withdraw/lnurl.py @@ -14,14 +14,17 @@ from .crud import get_withdraw_link_by_hash, update_withdraw_link # FOR LNURLs WHICH ARE NOT UNIQUE -@withdraw_ext.get("/api/v1/lnurl/{unique_hash}", status_code=HTTPStatus.OK, name="withdraw.api_lnurl_response") +@withdraw_ext.get( + "/api/v1/lnurl/{unique_hash}", + status_code=HTTPStatus.OK, + name="withdraw.api_lnurl_response", +) async def api_lnurl_response(request: Request, unique_hash): link = await get_withdraw_link_by_hash(unique_hash) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Withdraw link does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Withdraw link does not exist." ) # return ({"status": "ERROR", "reason": "LNURL-withdraw not found."}, # HTTPStatus.OK, @@ -39,23 +42,22 @@ async def api_lnurl_response(request: Request, unique_hash): return link.lnurl_response(request).dict() - # CALLBACK @withdraw_ext.get("/api/v1/lnurl/cb/{unique_hash}", name="withdraw.api_lnurl_callback") -async def api_lnurl_callback(request: Request, - unique_hash: str=Query(...), - k1: str = Query(...), - payment_request: str = Query(..., alias="pr") - ): +async def api_lnurl_callback( + request: Request, + unique_hash: str = Query(...), + k1: str = Query(...), + payment_request: str = Query(..., alias="pr"), +): link = await get_withdraw_link_by_hash(unique_hash) now = int(datetime.now().timestamp()) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="LNURL-withdraw not found." + status_code=HTTPStatus.NOT_FOUND, detail="LNURL-withdraw not found." ) # return ( # {"status": "ERROR", "reason": "LNURL-withdraw not found."}, @@ -73,10 +75,7 @@ async def api_lnurl_callback(request: Request, # ) if link.k1 != k1: - raise HTTPException( - status_code=HTTPStatus.BAD_REQUEST, - detail="Bad request." - ) + raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail="Bad request.") # return {"status": "ERROR", "reason": "Bad request."}, HTTPStatus.OK if now < link.open_time: @@ -123,17 +122,21 @@ async def api_lnurl_callback(request: Request, return {"status": "OK"} + # FOR LNURLs WHICH ARE UNIQUE -@withdraw_ext.get("/api/v1/lnurl/{unique_hash}/{id_unique_hash}", status_code=HTTPStatus.OK, name="withdraw.api_lnurl_multi_response") +@withdraw_ext.get( + "/api/v1/lnurl/{unique_hash}/{id_unique_hash}", + status_code=HTTPStatus.OK, + name="withdraw.api_lnurl_multi_response", +) async def api_lnurl_multi_response(request: Request, unique_hash, id_unique_hash): link = await get_withdraw_link_by_hash(unique_hash) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="LNURL-withdraw not found." + status_code=HTTPStatus.NOT_FOUND, detail="LNURL-withdraw not found." ) # return ( # {"status": "ERROR", "reason": "LNURL-withdraw not found."}, @@ -158,8 +161,7 @@ async def api_lnurl_multi_response(request: Request, unique_hash, id_unique_hash found = True if not found: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="LNURL-withdraw not found." + status_code=HTTPStatus.NOT_FOUND, detail="LNURL-withdraw not found." ) # return ( # {"status": "ERROR", "reason": "LNURL-withdraw not found."}, diff --git a/lnbits/extensions/withdraw/models.py b/lnbits/extensions/withdraw/models.py index b01ad654..e2b057fd 100644 --- a/lnbits/extensions/withdraw/models.py +++ b/lnbits/extensions/withdraw/models.py @@ -5,13 +5,14 @@ from sqlite3 import Row from pydantic import BaseModel import shortuuid # type: ignore + class CreateWithdrawData(BaseModel): - title: str = Query(...) - min_withdrawable: int = Query(..., ge=1) - max_withdrawable: int = Query(..., ge=1) - uses: int = Query(..., ge=1) - wait_time: int = Query(..., ge=1) - is_unique: bool + title: str = Query(...) + min_withdrawable: int = Query(..., ge=1) + max_withdrawable: int = Query(..., ge=1) + uses: int = Query(..., ge=1) + wait_time: int = Query(..., ge=1) + is_unique: bool class WithdrawLink(BaseModel): @@ -49,17 +50,15 @@ class WithdrawLink(BaseModel): url = req.url_for( "withdraw.api_lnurl_multi_response", unique_hash=self.unique_hash, - id_unique_hash=multihash + id_unique_hash=multihash, ) else: url = req.url_for( - "withdraw.api_lnurl_response", - unique_hash=self.unique_hash + "withdraw.api_lnurl_response", unique_hash=self.unique_hash ) return lnurl_encode(url) - def lnurl_response(self, req: Request) -> LnurlWithdrawResponse: url = req.url_for( name="withdraw.api_lnurl_callback", unique_hash=self.unique_hash diff --git a/lnbits/extensions/withdraw/views.py b/lnbits/extensions/withdraw/views.py index 8d6eeee2..82189c53 100644 --- a/lnbits/extensions/withdraw/views.py +++ b/lnbits/extensions/withdraw/views.py @@ -15,11 +15,14 @@ from lnbits.core.models import User templates = Jinja2Templates(directory="templates") + @withdraw_ext.get("/", response_class=HTMLResponse) # @validate_uuids(["usr"], required=True) # @check_user_exists() async def index(request: Request, user: User = Depends(check_user_exists)): - return withdraw_renderer().TemplateResponse("withdraw/index.html", {"request":request,"user": user.dict()}) + return withdraw_renderer().TemplateResponse( + "withdraw/index.html", {"request": request, "user": user.dict()} + ) @withdraw_ext.get("/{link_id}", response_class=HTMLResponse) @@ -28,13 +31,20 @@ async def display(request: Request, link_id): if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Withdraw link does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Withdraw link does not exist." ) # response.status_code = HTTPStatus.NOT_FOUND # return "Withdraw link does not exist." #probably here is where we should return the 404?? print("LINK", link) - return withdraw_renderer().TemplateResponse("withdraw/display.html", {"request":request,"link":link.dict(), "lnurl": link.lnurl(req=request), "unique":True}) + return withdraw_renderer().TemplateResponse( + "withdraw/display.html", + { + "request": request, + "link": link.dict(), + "lnurl": link.lnurl(req=request), + "unique": True, + }, + ) @withdraw_ext.get("/img/{link_id}", response_class=StreamingResponse) @@ -42,8 +52,7 @@ async def img(request: Request, link_id): link = await get_withdraw_link(link_id, 0) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Withdraw link does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Withdraw link does not exist." ) # response.status_code = HTTPStatus.NOT_FOUND # return "Withdraw link does not exist." @@ -63,7 +72,8 @@ async def img(request: Request, link_id): "Cache-Control": "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0", - }) + }, + ) @withdraw_ext.get("/print/{link_id}", response_class=HTMLResponse) @@ -71,15 +81,17 @@ async def print_qr(request: Request, link_id): link = await get_withdraw_link(link_id) if not link: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Withdraw link does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Withdraw link does not exist." ) # response.status_code = HTTPStatus.NOT_FOUND # return "Withdraw link does not exist." if link.uses == 0: - return withdraw_renderer().TemplateResponse("withdraw/print_qr.html", {"request":request,"link":link.dict(), unique:False}) + return withdraw_renderer().TemplateResponse( + "withdraw/print_qr.html", + {"request": request, "link": link.dict(), unique: False}, + ) links = [] count = 0 @@ -87,8 +99,7 @@ async def print_qr(request: Request, link_id): linkk = await get_withdraw_link(link_id, count) if not linkk: raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, - detail="Withdraw link does not exist." + status_code=HTTPStatus.NOT_FOUND, detail="Withdraw link does not exist." ) # response.status_code = HTTPStatus.NOT_FOUND # return "Withdraw link does not exist." @@ -97,4 +108,6 @@ async def print_qr(request: Request, link_id): page_link = list(chunks(links, 2)) linked = list(chunks(page_link, 5)) print("LINKED", linked) - return withdraw_renderer().TemplateResponse("withdraw/print_qr.html", {"request":request,"link":linked, "unique":True}) + return withdraw_renderer().TemplateResponse( + "withdraw/print_qr.html", {"request": request, "link": linked, "unique": True} + ) diff --git a/lnbits/extensions/withdraw/views_api.py b/lnbits/extensions/withdraw/views_api.py index 93b498ef..21c01973 100644 --- a/lnbits/extensions/withdraw/views_api.py +++ b/lnbits/extensions/withdraw/views_api.py @@ -28,7 +28,11 @@ from .crud import ( @withdraw_ext.get("/api/v1/links", status_code=HTTPStatus.OK) # @api_check_wallet_key("invoice") -async def api_links(req: Request, wallet: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)): +async def api_links( + req: Request, + wallet: WalletTypeInfo = Depends(get_key_type), + all_wallets: bool = Query(False), +): wallet_ids = [wallet.wallet.id] if all_wallets: @@ -36,12 +40,9 @@ async def api_links(req: Request, wallet: WalletTypeInfo = Depends(get_key_type) try: return [ - { - **link.dict(), - **{"lnurl": link.lnurl(req)}, - } - for link in await get_withdraw_links(wallet_ids) - ] + {**link.dict(), **{"lnurl": link.lnurl(req)}} + for link in await get_withdraw_links(wallet_ids) + ] except LnurlInvalidUrl: raise HTTPException( @@ -59,21 +60,20 @@ async def api_link_retrieve(link_id, wallet: WalletTypeInfo = Depends(get_key_ty if not link: raise HTTPException( - detail="Withdraw link does not exist.", - status_code=HTTPStatus.NOT_FOUND + detail="Withdraw link does not exist.", status_code=HTTPStatus.NOT_FOUND ) # response.status_code = HTTPStatus.NOT_FOUND # return {"message": "Withdraw link does not exist."} if link.wallet != wallet.wallet.id: raise HTTPException( - detail="Not your withdraw link.", - status_code=HTTPStatus.FORBIDDEN + detail="Not your withdraw link.", status_code=HTTPStatus.FORBIDDEN ) # response.status_code = HTTPStatus.FORBIDDEN # return {"message": "Not your withdraw link."} return {**link, **{"lnurl": link.lnurl(request)}} + # class CreateData(BaseModel): # title: str = Query(...) # min_withdrawable: int = Query(..., ge=1) @@ -82,14 +82,20 @@ async def api_link_retrieve(link_id, wallet: WalletTypeInfo = Depends(get_key_ty # wait_time: int = Query(..., ge=1) # is_unique: bool + @withdraw_ext.post("/api/v1/links", status_code=HTTPStatus.CREATED) @withdraw_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK) # @api_check_wallet_key("admin") -async def api_link_create_or_update(req: Request, data: CreateWithdrawData, link_id: str = None, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_link_create_or_update( + req: Request, + data: CreateWithdrawData, + link_id: str = None, + wallet: WalletTypeInfo = Depends(get_key_type), +): if data.max_withdrawable < data.min_withdrawable: raise HTTPException( detail="`max_withdrawable` needs to be at least `min_withdrawable`.", - status_code=HTTPStatus.BAD_REQUEST + status_code=HTTPStatus.BAD_REQUEST, ) # response.status_code = HTTPStatus.BAD_REQUEST # return { @@ -108,15 +114,13 @@ async def api_link_create_or_update(req: Request, data: CreateWithdrawData, link link = await get_withdraw_link(link_id, 0) if not link: raise HTTPException( - detail="Withdraw link does not exist.", - status_code=HTTPStatus.NOT_FOUND + detail="Withdraw link does not exist.", status_code=HTTPStatus.NOT_FOUND ) # response.status_code = HTTPStatus.NOT_FOUND # return {"message": "Withdraw link does not exist."} if link.wallet != wallet.wallet.id: raise HTTPException( - detail="Not your withdraw link.", - status_code=HTTPStatus.FORBIDDEN + detail="Not your withdraw link.", status_code=HTTPStatus.FORBIDDEN ) # response.status_code = HTTPStatus.FORBIDDEN # return {"message": "Not your withdraw link."} @@ -137,16 +141,14 @@ async def api_link_delete(link_id, wallet: WalletTypeInfo = Depends(get_key_type if not link: raise HTTPException( - detail="Withdraw link does not exist.", - status_code=HTTPStatus.NOT_FOUND + detail="Withdraw link does not exist.", status_code=HTTPStatus.NOT_FOUND ) # response.status_code = HTTPStatus.NOT_FOUND # return {"message": "Withdraw link does not exist."} if link.wallet != wallet.wallet.id: raise HTTPException( - detail="Not your withdraw link.", - status_code=HTTPStatus.FORBIDDEN + detail="Not your withdraw link.", status_code=HTTPStatus.FORBIDDEN ) # response.status_code = HTTPStatus.FORBIDDEN # return {"message": "Not your withdraw link."} @@ -158,6 +160,8 @@ async def api_link_delete(link_id, wallet: WalletTypeInfo = Depends(get_key_type @withdraw_ext.get("/api/v1/links/{the_hash}/{lnurl_id}", status_code=HTTPStatus.OK) # @api_check_wallet_key("invoice") -async def api_hash_retrieve(the_hash, lnurl_id, wallet: WalletTypeInfo = Depends(get_key_type)): +async def api_hash_retrieve( + the_hash, lnurl_id, wallet: WalletTypeInfo = Depends(get_key_type) +): hashCheck = await get_hash_check(the_hash, lnurl_id) return hashCheck diff --git a/lnbits/helpers.py b/lnbits/helpers.py index dbb060a5..a1396411 100644 --- a/lnbits/helpers.py +++ b/lnbits/helpers.py @@ -41,7 +41,9 @@ class ExtensionManager: ]: try: with open( - os.path.join(settings.LNBITS_PATH, "extensions", extension, "config.json") + os.path.join( + settings.LNBITS_PATH, "extensions", extension, "config.json" + ) ) as json_file: config = json.load(json_file) is_valid = True @@ -137,11 +139,8 @@ def get_vendored(ext: str, prefer_minified: bool = False) -> List[str]: def url_for_vendored(abspath: str) -> str: return "/" + os.path.relpath(abspath, settings.LNBITS_PATH) -def url_for( - endpoint: str, - external: Optional[bool] = False, - **params: Any, -) -> str: + +def url_for(endpoint: str, external: Optional[bool] = False, **params: Any) -> str: base = g().base_url if external else "" url_params = "?" for key in params: @@ -149,9 +148,12 @@ def url_for( url = f"{base}{endpoint}{url_params}" return url + def template_renderer(additional_folders: List = []) -> Jinja2Templates: t = Jinja2Templates( - loader=jinja2.FileSystemLoader(["lnbits/templates", "lnbits/core/templates", *additional_folders]), + loader=jinja2.FileSystemLoader( + ["lnbits/templates", "lnbits/core/templates", *additional_folders] + ) ) t.env.globals["SITE_TITLE"] = settings.LNBITS_SITE_TITLE t.env.globals["SITE_TAGLINE"] = settings.LNBITS_SITE_TAGLINE @@ -159,7 +161,7 @@ def template_renderer(additional_folders: List = []) -> Jinja2Templates: t.env.globals["LNBITS_THEME_OPTIONS"] = settings.LNBITS_THEME_OPTIONS t.env.globals["LNBITS_VERSION"] = settings.LNBITS_COMMIT t.env.globals["EXTENSIONS"] = get_valid_extensions() - + if settings.DEBUG: t.env.globals["VENDORED_JS"] = map(url_for_vendored, get_js_vendored()) t.env.globals["VENDORED_CSS"] = map(url_for_vendored, get_css_vendored()) diff --git a/lnbits/jinja2_templating.py b/lnbits/jinja2_templating.py index 5e3ceba2..f74f05c0 100644 --- a/lnbits/jinja2_templating.py +++ b/lnbits/jinja2_templating.py @@ -1,4 +1,4 @@ -# Borrowed from the excellent accent-starlette +# Borrowed from the excellent accent-starlette # https://github.com/accent-starlette/starlette-core/blob/master/starlette_core/templating.py import typing @@ -23,7 +23,7 @@ class Jinja2Templates(templating.Jinja2Templates): def get_environment(self, loader: "jinja2.BaseLoader") -> "jinja2.Environment": @jinja2.contextfunction def url_for(context: dict, name: str, **path_params: typing.Any) -> str: - request: Request = context["request"] # type: starlette.requests.Request + request: Request = context["request"] # type: starlette.requests.Request return request.app.url_path_for(name, **path_params) def url_params_update(init: QueryParams, **new: typing.Any) -> QueryParams: diff --git a/lnbits/requestvars.py b/lnbits/requestvars.py index 7dcf9203..2f7139d8 100644 --- a/lnbits/requestvars.py +++ b/lnbits/requestvars.py @@ -1,8 +1,9 @@ import contextvars import types -request_global = contextvars.ContextVar("request_global", - default=types.SimpleNamespace()) +request_global = contextvars.ContextVar( + "request_global", default=types.SimpleNamespace() +) def g() -> types.SimpleNamespace: diff --git a/lnbits/settings.py b/lnbits/settings.py index a351b5f1..475f5f47 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -52,8 +52,7 @@ SERVICE_FEE = env.float("LNBITS_SERVICE_FEE", default=0.0) try: LNBITS_COMMIT = ( subprocess.check_output( - ["git", "-C", LNBITS_PATH, "rev-parse", "HEAD"], - stderr=subprocess.DEVNULL, + ["git", "-C", LNBITS_PATH, "rev-parse", "HEAD"], stderr=subprocess.DEVNULL ) .strip() .decode("ascii") diff --git a/lnbits/wallets/clightning.py b/lnbits/wallets/clightning.py index 0780776f..c1b10220 100644 --- a/lnbits/wallets/clightning.py +++ b/lnbits/wallets/clightning.py @@ -35,7 +35,7 @@ class CLightningWallet(Wallet): try: answer = self.ln.help("invoicewithdescriptionhash") if answer["help"][0]["command"].startswith( - "invoicewithdescriptionhash msatoshi label description_hash", + "invoicewithdescriptionhash msatoshi label description_hash" ): self.supports_description_hash = True except: @@ -53,8 +53,7 @@ class CLightningWallet(Wallet): try: funds = self.ln.listfunds() return StatusResponse( - None, - sum([ch["channel_sat"] * 1000 for ch in funds["channels"]]), + None, sum([ch["channel_sat"] * 1000 for ch in funds["channels"]]) ) except RpcError as exc: error_message = f"lightningd '{exc.method}' failed with '{exc.error}'." @@ -121,11 +120,7 @@ class CLightningWallet(Wallet): i = 0 while True: call = json.dumps( - { - "method": "waitanyinvoice", - "id": 0, - "params": [self.last_pay_index], - } + {"method": "waitanyinvoice", "id": 0, "params": [self.last_pay_index]} ) await stream.send_all(call.encode("utf-8")) diff --git a/lnbits/wallets/lnbits.py b/lnbits/wallets/lnbits.py index b262cb1e..638fb7c1 100644 --- a/lnbits/wallets/lnbits.py +++ b/lnbits/wallets/lnbits.py @@ -30,9 +30,7 @@ class LNbitsWallet(Wallet): async with httpx.AsyncClient() as client: try: r = await client.get( - url=f"{self.endpoint}/api/v1/wallet", - headers=self.key, - timeout=15, + url=f"{self.endpoint}/api/v1/wallet", headers=self.key, timeout=15 ) except Exception as exc: return StatusResponse( @@ -65,9 +63,7 @@ class LNbitsWallet(Wallet): async with httpx.AsyncClient() as client: r = await client.post( - url=f"{self.endpoint}/api/v1/payments", - headers=self.key, - json=data, + url=f"{self.endpoint}/api/v1/payments", headers=self.key, json=data ) ok, checking_id, payment_request, error_message = ( not r.is_error, diff --git a/lnbits/wallets/lndgrpc.py b/lnbits/wallets/lndgrpc.py index 99ff3637..89cbded7 100644 --- a/lnbits/wallets/lndgrpc.py +++ b/lnbits/wallets/lndgrpc.py @@ -64,19 +64,11 @@ def load_macaroon(macaroon_path: str): def parse_checking_id(checking_id: str) -> bytes: - return base64.b64decode( - checking_id.replace("_", "/"), - ) + return base64.b64decode(checking_id.replace("_", "/")) def stringify_checking_id(r_hash: bytes) -> str: - return ( - base64.b64encode( - r_hash, - ) - .decode("utf-8") - .replace("/", "_") - ) + return base64.b64encode(r_hash).decode("utf-8").replace("/", "_") class LndWallet(Wallet): @@ -177,28 +169,23 @@ class LndWallet(Wallet): async def paid_invoices_stream(self) -> AsyncGenerator[str, None]: async with purerpc.secure_channel( - self.endpoint, - self.port, - get_ssl_context(self.cert_path), + self.endpoint, self.port, get_ssl_context(self.cert_path) ) as channel: client = purerpc.Client("lnrpc.Lightning", channel) subscribe_invoices = client.get_method_stub( "SubscribeInvoices", purerpc.RPCSignature( - purerpc.Cardinality.UNARY_STREAM, - ln.InvoiceSubscription, - ln.Invoice, + purerpc.Cardinality.UNARY_STREAM, ln.InvoiceSubscription, ln.Invoice ), ) - if self.macaroon_path.split('.')[-1] == 'macaroon': + if self.macaroon_path.split(".")[-1] == "macaroon": macaroon = load_macaroon(self.macaroon_path) else: macaroon = self.macaroon_path async for inv in subscribe_invoices( - ln.InvoiceSubscription(), - metadata=[("macaroon", macaroon)], + ln.InvoiceSubscription(), metadata=[("macaroon", macaroon)] ): if not inv.settled: continue diff --git a/lnbits/wallets/lndrest.py b/lnbits/wallets/lndrest.py index 4b31c726..f0824dac 100644 --- a/lnbits/wallets/lndrest.py +++ b/lnbits/wallets/lndrest.py @@ -39,8 +39,7 @@ class LndRestWallet(Wallet): try: async with httpx.AsyncClient(verify=self.cert) as client: r = await client.get( - f"{self.endpoint}/v1/balance/channels", - headers=self.auth, + f"{self.endpoint}/v1/balance/channels", headers=self.auth ) except (httpx.ConnectError, httpx.RequestError): return StatusResponse(f"Unable to connect to {self.endpoint}.", 0) @@ -60,10 +59,7 @@ class LndRestWallet(Wallet): memo: Optional[str] = None, description_hash: Optional[bytes] = None, ) -> InvoiceResponse: - data: Dict = { - "value": amount, - "private": True, - } + data: Dict = {"value": amount, "private": True} if description_hash: data["description_hash"] = base64.b64encode(description_hash).decode( "ascii" @@ -73,9 +69,7 @@ class LndRestWallet(Wallet): async with httpx.AsyncClient(verify=self.cert) as client: r = await client.post( - url=f"{self.endpoint}/v1/invoices", - headers=self.auth, - json=data, + url=f"{self.endpoint}/v1/invoices", headers=self.auth, json=data ) if r.is_error: @@ -117,8 +111,7 @@ class LndRestWallet(Wallet): async with httpx.AsyncClient(verify=self.cert) as client: r = await client.get( - url=f"{self.endpoint}/v1/invoice/{checking_id}", - headers=self.auth, + url=f"{self.endpoint}/v1/invoice/{checking_id}", headers=self.auth ) if r.is_error or not r.json().get("settled"): @@ -164,9 +157,7 @@ class LndRestWallet(Wallet): while True: try: async with httpx.AsyncClient( - timeout=None, - headers=self.auth, - verify=self.cert, + timeout=None, headers=self.auth, verify=self.cert ) as client: async with client.stream("GET", url) as r: async for line in r.aiter_lines(): diff --git a/lnbits/wallets/lnpay.py b/lnbits/wallets/lnpay.py index ab8e0d81..98610a79 100644 --- a/lnbits/wallets/lnpay.py +++ b/lnbits/wallets/lnpay.py @@ -139,12 +139,10 @@ class LNPayWallet(Wallet): lntx_id = data["data"]["wtx"]["lnTx"]["id"] async with httpx.AsyncClient() as client: r = await client.get( - f"{self.endpoint}/lntx/{lntx_id}?fields=settled", - headers=self.auth, + f"{self.endpoint}/lntx/{lntx_id}?fields=settled", headers=self.auth ) data = r.json() if data["settled"]: await self.queue.put(lntx_id) raise HTTPException(status_code=HTTPStatus.NO_CONTENT) - diff --git a/lnbits/wallets/lntxbot.py b/lnbits/wallets/lntxbot.py index c804542a..190336a3 100644 --- a/lnbits/wallets/lntxbot.py +++ b/lnbits/wallets/lntxbot.py @@ -30,9 +30,7 @@ class LntxbotWallet(Wallet): async def status(self) -> StatusResponse: async with httpx.AsyncClient() as client: r = await client.get( - f"{self.endpoint}/balance", - headers=self.auth, - timeout=40, + f"{self.endpoint}/balance", headers=self.auth, timeout=40 ) try: data = r.json() @@ -60,10 +58,7 @@ class LntxbotWallet(Wallet): async with httpx.AsyncClient() as client: r = await client.post( - f"{self.endpoint}/addinvoice", - headers=self.auth, - json=data, - timeout=40, + f"{self.endpoint}/addinvoice", headers=self.auth, json=data, timeout=40 ) if r.is_error: @@ -123,8 +118,7 @@ class LntxbotWallet(Wallet): async def get_payment_status(self, checking_id: str) -> PaymentStatus: async with httpx.AsyncClient() as client: r = await client.post( - url=f"{self.endpoint}/paymentstatus/{checking_id}", - headers=self.auth, + url=f"{self.endpoint}/paymentstatus/{checking_id}", headers=self.auth ) data = r.json() diff --git a/lnbits/wallets/opennode.py b/lnbits/wallets/opennode.py index ddc2849e..965b6d66 100644 --- a/lnbits/wallets/opennode.py +++ b/lnbits/wallets/opennode.py @@ -36,9 +36,7 @@ class OpenNodeWallet(Wallet): try: async with httpx.AsyncClient() as client: r = await client.get( - f"{self.endpoint}/v1/account/balance", - headers=self.auth, - timeout=40, + f"{self.endpoint}/v1/account/balance", headers=self.auth, timeout=40 ) except (httpx.ConnectError, httpx.RequestError): return StatusResponse(f"Unable to connect to '{self.endpoint}'", 0) @@ -137,7 +135,6 @@ class OpenNodeWallet(Wallet): if "status" not in data or data["status"] != "paid": raise HTTPException(status_code=HTTPStatus.NO_CONTENT) - charge_id = data["id"] x = hmac.new(self.auth["Authorization"].encode("ascii"), digestmod="sha256") x.update(charge_id.encode("ascii")) @@ -147,4 +144,3 @@ class OpenNodeWallet(Wallet): await self.queue.put(charge_id) raise HTTPException(status_code=HTTPStatus.NO_CONTENT) - diff --git a/lnbits/wallets/spark.py b/lnbits/wallets/spark.py index ca8f6efe..a97ad310 100644 --- a/lnbits/wallets/spark.py +++ b/lnbits/wallets/spark.py @@ -75,8 +75,7 @@ class SparkWallet(Wallet): return StatusResponse(str(e), 0) return StatusResponse( - None, - sum([ch["channel_sat"] * 1000 for ch in funds["channels"]]), + None, sum([ch["channel_sat"] * 1000 for ch in funds["channels"]]) ) async def create_invoice(