Skip to content

Commit

Permalink
feat: code quality (#59)
Browse files Browse the repository at this point in the history
* feat: code quality
* fixup!
  • Loading branch information
dni authored Aug 5, 2024
1 parent 8aefea7 commit badc420
Show file tree
Hide file tree
Showing 29 changed files with 3,048 additions and 212 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
name: lint
on:
push:
branches:
- main
pull_request:

jobs:
lint:
uses: lnbits/lnbits/.github/workflows/lint.yml@dev
15 changes: 7 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
- 'v[0-9]+.[0-9]+.[0-9]+'

jobs:

release:
runs-on: ubuntu-latest
steps:
Expand Down Expand Up @@ -34,12 +33,12 @@ jobs:
- name: Create pull request in extensions repo
env:
GH_TOKEN: ${{ secrets.EXT_GITHUB }}
repo_name: "${{ github.event.repository.name }}"
tag: "${{ github.ref_name }}"
branch: "update-${{ github.event.repository.name }}-${{ github.ref_name }}"
title: "[UPDATE] ${{ github.event.repository.name }} to ${{ github.ref_name }}"
body: "https://github.com/lnbits/${{ github.event.repository.name }}/releases/${{ github.ref_name }}"
archive: "https://github.com/lnbits/${{ github.event.repository.name }}/archive/refs/tags/${{ github.ref_name }}.zip"
repo_name: '${{ github.event.repository.name }}'
tag: '${{ github.ref_name }}'
branch: 'update-${{ github.event.repository.name }}-${{ github.ref_name }}'
title: '[UPDATE] ${{ github.event.repository.name }} to ${{ github.ref_name }}'
body: 'https://github.com/lnbits/${{ github.event.repository.name }}/releases/${{ github.ref_name }}'
archive: 'https://github.com/lnbits/${{ github.event.repository.name }}/archive/refs/tags/${{ github.ref_name }}.zip'
run: |
cd lnbits-extensions
git checkout -b $branch
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
__pycache__
node_modules
.mypy_cache
.venv
12 changes: 12 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"semi": false,
"arrowParens": "avoid",
"insertPragma": false,
"printWidth": 80,
"proseWrap": "preserve",
"singleQuote": true,
"trailingComma": "none",
"useTabs": false,
"bracketSameLine": false,
"bracketSpacing": false
}
47 changes: 47 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
all: format check

format: prettier black ruff

check: mypy pyright checkblack checkruff checkprettier

prettier:
poetry run ./node_modules/.bin/prettier --write .
pyright:
poetry run ./node_modules/.bin/pyright

mypy:
poetry run mypy .

black:
poetry run black .

ruff:
poetry run ruff check . --fix

checkruff:
poetry run ruff check .

checkprettier:
poetry run ./node_modules/.bin/prettier --check .

checkblack:
poetry run black --check .

checkeditorconfig:
editorconfig-checker

test:
PYTHONUNBUFFERED=1 \
DEBUG=true \
poetry run pytest
install-pre-commit-hook:
@echo "Installing pre-commit hook to git"
@echo "Uninstall the hook with poetry run pre-commit uninstall"
poetry run pre-commit install

pre-commit:
poetry run pre-commit run --all-files


checkbundle:
@echo "skipping checkbundle"
36 changes: 21 additions & 15 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@

from fastapi import APIRouter

from lnbits.db import Database
from lnbits.helpers import template_renderer
from lnbits.tasks import create_permanent_unique_task


db = Database("ext_lnurlp")
from .crud import db
from .tasks import wait_for_paid_invoices
from .views import lnurlp_generic_router
from .views_api import lnurlp_api_router
from .views_lnurl import lnurlp_lnurl_router

lnurlp_static_files = [
{
Expand All @@ -26,15 +25,9 @@


lnurlp_ext: APIRouter = APIRouter(prefix="/lnurlp", tags=["lnurlp"])

def lnurlp_renderer():
return template_renderer(["lnurlp/templates"])

from .lnurl import * # noqa: F401,F403
from .tasks import wait_for_paid_invoices
from .views import * # noqa: F401,F403
from .views_api import * # noqa: F401,F403

lnurlp_ext.include_router(lnurlp_generic_router)
lnurlp_ext.include_router(lnurlp_api_router)
lnurlp_ext.include_router(lnurlp_lnurl_router)

scheduled_tasks: List[asyncio.Task] = []

Expand All @@ -43,6 +36,19 @@ def lnurlp_stop():
for task in scheduled_tasks:
task.cancel()


def lnurlp_start():
from lnbits.tasks import create_permanent_unique_task

task = create_permanent_unique_task("lnurlp", wait_for_paid_invoices)
scheduled_tasks.append(task)


__all__ = [
"lnurlp_ext",
"lnurlp_static_files",
"lnurlp_redirect_paths",
"lnurlp_stop",
"lnurlp_start",
"db",
]
11 changes: 6 additions & 5 deletions crud.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from typing import List, Optional, Union

from lnbits.helpers import urlsafe_short_hash, insert_query, update_query
from lnbits.db import Database
from lnbits.helpers import insert_query, update_query, urlsafe_short_hash

from . import db
from .models import CreatePayLinkData, LnurlpSettings, PayLink
from .nostr.key import PrivateKey

db = Database("ext_lnurlp")


async def get_or_create_lnurlp_settings() -> LnurlpSettings:
row = await db.fetchone("SELECT * FROM lnurlp.settings LIMIT 1")
Expand All @@ -14,16 +16,15 @@ async def get_or_create_lnurlp_settings() -> LnurlpSettings:
else:
settings = LnurlpSettings(nostr_private_key=PrivateKey().hex())
await db.execute(
insert_query("lnurlp.settings", settings),
(*settings.dict().values(),)
insert_query("lnurlp.settings", settings), (*settings.dict().values(),)
)
return settings


async def update_lnurlp_settings(settings: LnurlpSettings) -> LnurlpSettings:
await db.execute(
update_query("lnurlp.settings", settings, where=""),
(*settings.dict().values(),)
(*settings.dict().values(),),
)
return settings

Expand Down
1 change: 0 additions & 1 deletion description.md
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
Create a static LNURLp or LNaddress people can use to pay.

8 changes: 4 additions & 4 deletions helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@


def parse_nostr_private_key(key: str) -> PrivateKey:
if key.startswith("nsec"):
return PrivateKey.from_nsec(key)
else:
return PrivateKey(bytes.fromhex(key))
if key.startswith("nsec"):
return PrivateKey.from_nsec(key)
else:
return PrivateKey(bytes.fromhex(key))
3 changes: 2 additions & 1 deletion migrations.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ async def m004_fiat_base_multiplier(db):
remember to multiply by 100 when we use it to convert to Dollars.
"""
await db.execute(
"ALTER TABLE lnurlp.pay_links ADD COLUMN fiat_base_multiplier INTEGER DEFAULT 1;"
"ALTER TABLE lnurlp.pay_links "
"ADD COLUMN fiat_base_multiplier INTEGER DEFAULT 1;"
)


Expand Down
34 changes: 8 additions & 26 deletions models.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import json
from sqlite3 import Row
from typing import Dict, Optional
from urllib.parse import ParseResult, urlparse, urlunparse
from typing import Optional

from fastapi import Request
from fastapi.param_functions import Query
from lnurl import encode as lnurl_encode
from lnurl.types import LnurlPayMetadata
from pydantic import BaseModel

from lnbits.lnurl import encode as lnurl_encode

from .helpers import parse_nostr_private_key
from .nostr.key import PrivateKey

Expand All @@ -19,7 +17,7 @@ class LnurlpSettings(BaseModel):

@property
def private_key(self) -> PrivateKey:
return parse_nostr_private_key(self.nostr_private_key)
return parse_nostr_private_key(self.nostr_private_key)

@property
def public_key(self) -> str:
Expand Down Expand Up @@ -72,29 +70,13 @@ def from_row(cls, row: Row) -> "PayLink":
return cls(**data)

def lnurl(self, req: Request) -> str:
url = str(req.url_for("lnurlp.api_lnurl_response", link_id=self.id))
# Check if url is .onion and change to http
if urlparse(url).netloc.endswith(".onion"):
url = req.url_for("lnurlp.api_lnurl_response", link_id=self.id)
url_str = str(url)
if url.netloc.endswith(".onion"):
# change url string scheme to http
url = url.replace("https://", "http://")

return lnurl_encode(url)
url_str = url_str.replace("https://", "http://")

def success_action(self, payment_hash: str) -> Optional[Dict]:
if self.success_url:
url: ParseResult = urlparse(self.success_url)
# qs = parse_qs(url.query)
# setattr(qs, "payment_hash", payment_hash)
# url = url._replace(query=urlencode(qs, doseq=True))
return {
"tag": "url",
"description": self.success_text or "~",
"url": urlunparse(url),
}
elif self.success_text:
return {"tag": "message", "message": self.success_text}
else:
return None
return lnurl_encode(url_str)

@property
def lnurlpay_metadata(self) -> LnurlPayMetadata:
Expand Down
40 changes: 28 additions & 12 deletions nostr/bech32.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,25 @@

from enum import Enum


class Encoding(Enum):
"""Enumeration type to list the various supported encodings."""

BECH32 = 1
BECH32M = 2


CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
BECH32M_CONST = 0x2bc830a3
BECH32M_CONST = 0x2BC830A3


def bech32_polymod(values):
"""Internal function that computes the Bech32 checksum."""
generator = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3]
generator = [0x3B6A57B2, 0x26508E6D, 0x1EA119FA, 0x3D4233DD, 0x2A1462B3]
chk = 1
for value in values:
top = chk >> 25
chk = (chk & 0x1ffffff) << 5 ^ value
chk = (chk & 0x1FFFFFF) << 5 ^ value
for i in range(5):
chk ^= generator[i] if ((top >> i) & 1) else 0
return chk
Expand All @@ -57,37 +61,41 @@ def bech32_verify_checksum(hrp, data):
return Encoding.BECH32M
return None


def bech32_create_checksum(hrp, data, spec):
"""Compute the checksum values given HRP and data."""
values = bech32_hrp_expand(hrp) + data
const = BECH32M_CONST if spec == Encoding.BECH32M else 1
polymod = bech32_polymod(values + [0, 0, 0, 0, 0, 0]) ^ const
polymod = bech32_polymod([*values, 0, 0, 0, 0, 0, 0]) ^ const
return [(polymod >> 5 * (5 - i)) & 31 for i in range(6)]


def bech32_encode(hrp, data, spec):
"""Compute a Bech32 string given HRP and data values."""
combined = data + bech32_create_checksum(hrp, data, spec)
return hrp + '1' + ''.join([CHARSET[d] for d in combined])
return hrp + "1" + "".join([CHARSET[d] for d in combined])


def bech32_decode(bech):
"""Validate a Bech32/Bech32m string, and determine HRP and data."""
if ((any(ord(x) < 33 or ord(x) > 126 for x in bech)) or
(bech.lower() != bech and bech.upper() != bech)):
if (any(ord(x) < 33 or ord(x) > 126 for x in bech)) or (
bech.lower() != bech and bech.upper() != bech
):
return (None, None, None)
bech = bech.lower()
pos = bech.rfind('1')
pos = bech.rfind("1")
if pos < 1 or pos + 7 > len(bech) or len(bech) > 90:
return (None, None, None)
if not all(x in CHARSET for x in bech[pos+1:]):
if not all(x in CHARSET for x in bech[pos + 1 :]):
return (None, None, None)
hrp = bech[:pos]
data = [CHARSET.find(x) for x in bech[pos+1:]]
data = [CHARSET.find(x) for x in bech[pos + 1 :]]
spec = bech32_verify_checksum(hrp, data)
if spec is None:
return (None, None, None)
return (hrp, data[:-6], spec)


def convertbits(data, frombits, tobits, pad=True):
"""General power-of-2 base conversion."""
acc = 0
Expand All @@ -114,6 +122,7 @@ def convertbits(data, frombits, tobits, pad=True):
def decode(hrp, addr):
"""Decode a segwit address."""
hrpgot, data, spec = bech32_decode(addr)
assert data, "Invalid bech32 string"
if hrpgot != hrp:
return (None, None)
decoded = convertbits(data[1:], 5, 8, False)
Expand All @@ -123,15 +132,22 @@ def decode(hrp, addr):
return (None, None)
if data[0] == 0 and len(decoded) != 20 and len(decoded) != 32:
return (None, None)
if data[0] == 0 and spec != Encoding.BECH32 or data[0] != 0 and spec != Encoding.BECH32M:
if (
data[0] == 0
and spec != Encoding.BECH32
or data[0] != 0
and spec != Encoding.BECH32M
):
return (None, None)
return (data[0], decoded)


def encode(hrp, witver, witprog):
"""Encode a segwit address."""
spec = Encoding.BECH32 if witver == 0 else Encoding.BECH32M
ret = bech32_encode(hrp, [witver] + convertbits(witprog, 8, 5), spec)
bits = convertbits(witprog, 8, 5)
assert bits, "Invalid witness program"
ret = bech32_encode(hrp, [witver, *bits], spec)
if decode(hrp, ret) == (None, None):
return None
return ret
Loading

0 comments on commit badc420

Please sign in to comment.