Revert "fix: extend RFC1918 LNURL carve-out to the HTTP-views path"

This reverts commit 40dce41.

Going with TLS termination on the dev LNbits instead, so the
RFC1918 carve-out becomes unnecessary. The lnbits-core
`/api/v1/lnurlscan` consumer-side validator applies the same
HTTPS-required rule python-lnurl enforces; carving the producer
side out only got greg's LNURL generated, not redeemed.
This commit is contained in:
Padreug 2026-06-01 21:43:37 +02:00
commit 0e06ab2087
2 changed files with 38 additions and 51 deletions

View file

@ -1,9 +1,9 @@
import ipaddress
from dataclasses import dataclass
from urllib.parse import urlparse
from fastapi import Request
from lnbits.settings import settings
from lnurl import Lnurl
from lnurl import encode as lnurl_encode
from lnurl.helpers import url_encode
from shortuuid import uuid
@ -11,18 +11,26 @@ from shortuuid import uuid
from .models import WithdrawLink
@dataclass(frozen=True)
class _EncodedLnurl:
"""Minimal duck-typed stand-in for `lnurl.Lnurl` exposing just the
`.bech32` and `.url` attributes the callers (views.py, views_api.py,
transport_rpcs.py) read. We can't always return a real `Lnurl` —
its `__new__` re-runs python-lnurl's HTTPS-required host check on
bech32-decode, which rejects RFC1918/loopback HTTP URLs even after
we've intentionally encoded one. See #2.
"""
def create_lnurl(link: WithdrawLink, req: Request) -> Lnurl:
if link.is_unique:
usescssv = link.usescsv.split(",")
tohash = link.id + link.unique_hash + usescssv[link.number]
multihash = uuid(name=tohash)
url = req.url_for(
"withdraw.api_lnurl_multi_response",
unique_hash=link.unique_hash,
id_unique_hash=multihash,
)
else:
url = req.url_for("withdraw.api_lnurl_response", unique_hash=link.unique_hash)
bech32: str
url: str
try:
return lnurl_encode(str(url))
except Exception as e:
raise ValueError(
f"Error creating LNURL with url: `{url!s}`, "
"check your webserver proxy configuration."
) from e
def _is_private_network_http(url: str) -> bool:
@ -49,46 +57,17 @@ def _is_private_network_http(url: str) -> bool:
return ip.is_loopback or ip.is_private
def _encode_lnurl(url: str, error_hint: str) -> _EncodedLnurl:
"""Bech32-encode `url` as an LNURL. LAN-local HTTP URLs (loopback /
RFC1918) skip python-lnurl's HTTPS-required host validation via the
public `lnurl.helpers.url_encode` helper. Everything else goes
through the validated `lnurl_encode` path. See #2.
"""
if _is_private_network_http(url):
return _EncodedLnurl(bech32=url_encode(url), url=url)
try:
encoded = lnurl_encode(url)
except Exception as e:
raise ValueError(
f"Error creating LNURL with url: `{url!s}`, {error_hint}"
) from e
return _EncodedLnurl(bech32=str(encoded.bech32), url=str(encoded.url))
def create_lnurl(link: WithdrawLink, req: Request) -> _EncodedLnurl:
if link.is_unique:
usescssv = link.usescsv.split(",")
tohash = link.id + link.unique_hash + usescssv[link.number]
multihash = uuid(name=tohash)
url = req.url_for(
"withdraw.api_lnurl_multi_response",
unique_hash=link.unique_hash,
id_unique_hash=multihash,
)
else:
url = req.url_for("withdraw.api_lnurl_response", unique_hash=link.unique_hash)
return _encode_lnurl(str(url), "check your webserver proxy configuration.")
def create_lnurl_from_baseurl(link: WithdrawLink) -> _EncodedLnurl:
def create_lnurl_from_baseurl(link: WithdrawLink) -> tuple[str, str]:
"""
Same shape as `create_lnurl`, but composes the callback URL from
`settings.lnbits_baseurl` instead of a FastAPI `Request`. Used by
the nostr-transport RPC handlers, which have no HTTP request to
derive a base URL from.
Returns `(bech32, url)` the two fields `_populate_lnurl` writes
onto `WithdrawLink.lnurl` / `lnurl_url`. LAN-local HTTP URLs
(loopback / RFC1918) skip python-lnurl's HTTPS-required check via
the public `lnurl.helpers.url_encode` helper; see #2.
"""
base = settings.lnbits_baseurl.rstrip("/")
if link.is_unique:
@ -99,4 +78,14 @@ def create_lnurl_from_baseurl(link: WithdrawLink) -> _EncodedLnurl:
else:
url = f"{base}/withdraw/api/v1/lnurl/{link.unique_hash}"
return _encode_lnurl(url, "check your `LNBITS_BASEURL` configuration.")
if _is_private_network_http(url):
return url_encode(url), url
try:
encoded = lnurl_encode(url)
except Exception as e:
raise ValueError(
f"Error creating LNURL with url: `{url!s}`, "
"check your `LNBITS_BASEURL` configuration."
) from e
return str(encoded.bech32), str(encoded.url)