Skip to content

Commit

Permalink
feat: add lnaddress
Browse files Browse the repository at this point in the history
to handle function aswell as types
  • Loading branch information
dni committed Apr 22, 2024
1 parent 9fb7e5e commit 5776d9a
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
7 changes: 5 additions & 2 deletions lnurl/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from .exceptions import InvalidLnurl, InvalidUrl, LnurlResponseException
from .helpers import _url_encode
from .models import LnurlAuthResponse, LnurlResponse, LnurlResponseModel
from .types import ClearnetUrl, DebugUrl, Lnurl, OnionUrl
from .types import ClearnetUrl, DebugUrl, Lnaddress, Lnurl, OnionUrl


def decode(bech32_lnurl: str) -> Union[OnionUrl, ClearnetUrl, DebugUrl]:
Expand Down Expand Up @@ -41,11 +41,14 @@ def handle(
bech32_lnurl: str, *, response_class: Optional[LnurlResponseModel] = None, verify: Union[str, bool] = True
) -> LnurlResponseModel:
try:
if "@" in bech32_lnurl:
lnaddress = Lnaddress(bech32_lnurl)
return get(lnaddress.url, response_class=response_class, verify=verify)
lnurl = Lnurl(bech32_lnurl)
except (ValidationError, ValueError):
raise InvalidLnurl

if lnurl.is_login:
return LnurlAuthResponse(callback=lnurl.url, k1=lnurl.url.query_params["k1"])

return get(lnurl.url, response_class=response_class)
return get(lnurl.url, response_class=response_class, verify=verify)
22 changes: 22 additions & 0 deletions lnurl/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,28 @@ def is_login(self) -> bool:
return "tag" in self.url.query_params and self.url.query_params["tag"] == "login"


class Lnaddress(ReprMixin, str):
"""Lightning address of form `user@host`"""

def __new__(cls, address: str, **_) -> "Lnaddress":
return str.__new__(cls, address)

def __init__(self, address: str):
str.__init__(address)
self.address = address
self.url = self.__get_url__(address)

@classmethod
def __get_url__(cls, address: str) -> Union[OnionUrl, ClearnetUrl, DebugUrl]:
name_domain = address.split("@")
if len(name_domain) != 2 or len(name_domain[1].split(".")) < 2:
raise ValueError("Invalid Lightning address.")

name, domain = name_domain
url = ("http://" if domain.endswith(".onion") else "https://") + domain + "/.well-known/lnurlp/" + name
return parse_obj_as(Union[OnionUrl, ClearnetUrl, DebugUrl], url) # type: ignore


class LnurlPayMetadata(ReprMixin, str):
valid_metadata_mime_types = {"text/plain", "image/png;base64", "image/jpeg;base64"}

Expand Down
23 changes: 23 additions & 0 deletions tests/test_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
DebugUrl,
LightningInvoice,
LightningNodeUri,
Lnaddress,
Lnurl,
LnurlPayMetadata,
OnionUrl,
Expand Down Expand Up @@ -185,3 +186,25 @@ def test_valid(self, metadata, image_type):
def test_invalid_data(self, metadata):
with pytest.raises(ValidationError):
parse_obj_as(LnurlPayMetadata, metadata)


@pytest.mark.parametrize(
"lnaddress",
[
"[email protected]",
],
)
def test_valid_lnaddress(self, lnaddress):
lnaddress = Lnaddress(lnaddress)
assert isinstance(lnaddress.url, (OnionUrl, DebugUrl, ClearnetUrl))


@pytest.mark.parametrize(
"lnaddress",
[
"legend.lnbits.com",
],
)
def test_invalid_lnaddress(self, lnaddress):
with pytest.raises(ValueError):
lnaddress = Lnaddress(lnaddress)

0 comments on commit 5776d9a

Please sign in to comment.