From b1c92a067dc6539b299af14e080b10e0bfa196ef Mon Sep 17 00:00:00 2001 From: Vlad Stan Date: Mon, 6 Oct 2025 10:29:09 +0300 Subject: [PATCH] [fix] add lnurl field back (#105) --- helpers.py | 13 +++++++++++++ models.py | 10 ++++++++++ views_api.py | 13 ++++++++++--- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/helpers.py b/helpers.py index f4b3d89..ecc45f1 100644 --- a/helpers.py +++ b/helpers.py @@ -1,3 +1,6 @@ +from fastapi import Request +from lnurl import encode as lnurl_encode + from .nostr.key import PrivateKey @@ -6,3 +9,13 @@ def parse_nostr_private_key(key: str) -> PrivateKey: return PrivateKey.from_nsec(key) else: return PrivateKey(bytes.fromhex(key)) + + +def lnurl_encode_link_id(req: Request, link_id: str) -> str: + url = req.url_for("lnurlp.api_lnurl_response", link_id=link_id) + url = url.replace(path=url.path) + url_str = str(url) + if url.netloc.endswith(".onion"): + # change url string scheme to http + url_str = url_str.replace("https://", "http://") + return str(lnurl_encode(url_str).bech32) diff --git a/models.py b/models.py index e6b6cfa..d8e6d6d 100644 --- a/models.py +++ b/models.py @@ -48,6 +48,16 @@ class PayLink(BaseModel): comment_chars: int created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc)) + lnurl: str | None = Field( + default=None, + no_database=True, + deprecated=True, + description=( + "Deprecated: Instead of using this bech32 encoded string, dynamically " + "generate your own static link (lud17/bech32) on the client side. " + "Example: lnurlp://${window.location.hostname}/lnurlp/${paylink_id}" + ), + ) username: str | None = None zaps: bool | None = None webhook_url: str | None = None diff --git a/views_api.py b/views_api.py index 98d2118..6d9bb86 100644 --- a/views_api.py +++ b/views_api.py @@ -2,7 +2,7 @@ import json import re from http import HTTPStatus -from fastapi import APIRouter, Depends, HTTPException, Query +from fastapi import APIRouter, Depends, HTTPException, Query, Request from lnbits.core.crud import get_user, get_wallet from lnbits.core.models import SimpleStatus, WalletTypeInfo from lnbits.decorators import ( @@ -22,7 +22,7 @@ from .crud import ( update_lnurlp_settings, update_pay_link, ) -from .helpers import parse_nostr_private_key +from .helpers import lnurl_encode_link_id, parse_nostr_private_key from .models import CreatePayLinkData, LnurlpSettings, PayLink lnurlp_api_router = APIRouter() @@ -30,6 +30,7 @@ lnurlp_api_router = APIRouter() @lnurlp_api_router.get("/api/v1/links", status_code=HTTPStatus.OK) async def api_links( + req: Request, key_info: WalletTypeInfo = Depends(require_invoice_key), all_wallets: bool = Query(False), ) -> list[PayLink]: @@ -39,12 +40,14 @@ async def api_links( wallet_ids = user.wallet_ids if user else [] links = await get_pay_links(wallet_ids) + for link in links: + link.lnurl = lnurl_encode_link_id(req=req, link_id=link.id) return links @lnurlp_api_router.get("/api/v1/links/{link_id}", status_code=HTTPStatus.OK) async def api_link_retrieve( - link_id: str, key_info: WalletTypeInfo = Depends(require_invoice_key) + req: Request, link_id: str, key_info: WalletTypeInfo = Depends(require_invoice_key) ) -> PayLink: link = await get_pay_link(link_id) @@ -62,6 +65,8 @@ async def api_link_retrieve( raise HTTPException( detail="Not your pay link.", status_code=HTTPStatus.FORBIDDEN ) + + link.lnurl = lnurl_encode_link_id(req, link.id) return link @@ -77,6 +82,7 @@ async def check_username_exists(username: str): @lnurlp_api_router.post("/api/v1/links", status_code=HTTPStatus.CREATED) @lnurlp_api_router.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK) async def api_link_create_or_update( + req: Request, data: CreatePayLinkData, link_id: str | None = None, key_info: WalletTypeInfo = Depends(require_admin_key), @@ -172,6 +178,7 @@ async def api_link_create_or_update( link = await create_pay_link(data) + link.lnurl = lnurl_encode_link_id(req, link.id) return link