From b938103a075162e36416b3fd489a961f3ec5aeec Mon Sep 17 00:00:00 2001 From: ben Date: Tue, 14 Feb 2023 14:14:07 +0000 Subject: [PATCH] removes lnurldevice --- lnbits/extensions/lnurldevice/README.md | 3 - lnbits/extensions/lnurldevice/__init__.py | 35 - lnbits/extensions/lnurldevice/config.json | 6 - lnbits/extensions/lnurldevice/crud.py | 177 ---- lnbits/extensions/lnurldevice/lnurl.py | 295 ------ lnbits/extensions/lnurldevice/migrations.py | 139 --- lnbits/extensions/lnurldevice/models.py | 171 ---- .../lnurldevice/static/image/lnurldevice.png | Bin 13746 -> 0 bytes lnbits/extensions/lnurldevice/tasks.py | 36 - .../templates/lnurldevice/_api_docs.html | 190 ---- .../templates/lnurldevice/error.html | 34 - .../templates/lnurldevice/index.html | 881 ------------------ .../templates/lnurldevice/paid.html | 27 - lnbits/extensions/lnurldevice/views.py | 62 -- lnbits/extensions/lnurldevice/views_api.py | 88 -- 15 files changed, 2144 deletions(-) delete mode 100644 lnbits/extensions/lnurldevice/README.md delete mode 100644 lnbits/extensions/lnurldevice/__init__.py delete mode 100644 lnbits/extensions/lnurldevice/config.json delete mode 100644 lnbits/extensions/lnurldevice/crud.py delete mode 100644 lnbits/extensions/lnurldevice/lnurl.py delete mode 100644 lnbits/extensions/lnurldevice/migrations.py delete mode 100644 lnbits/extensions/lnurldevice/models.py delete mode 100644 lnbits/extensions/lnurldevice/static/image/lnurldevice.png delete mode 100644 lnbits/extensions/lnurldevice/tasks.py delete mode 100644 lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html delete mode 100644 lnbits/extensions/lnurldevice/templates/lnurldevice/error.html delete mode 100644 lnbits/extensions/lnurldevice/templates/lnurldevice/index.html delete mode 100644 lnbits/extensions/lnurldevice/templates/lnurldevice/paid.html delete mode 100644 lnbits/extensions/lnurldevice/views.py delete mode 100644 lnbits/extensions/lnurldevice/views_api.py diff --git a/lnbits/extensions/lnurldevice/README.md b/lnbits/extensions/lnurldevice/README.md deleted file mode 100644 index 01ce63825..000000000 --- a/lnbits/extensions/lnurldevice/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# LNURLDevice - -For offline LNURL devices diff --git a/lnbits/extensions/lnurldevice/__init__.py b/lnbits/extensions/lnurldevice/__init__.py deleted file mode 100644 index 56e9d8f7d..000000000 --- a/lnbits/extensions/lnurldevice/__init__.py +++ /dev/null @@ -1,35 +0,0 @@ -import asyncio - -from fastapi import APIRouter -from starlette.staticfiles import StaticFiles - -from lnbits.db import Database -from lnbits.helpers import template_renderer -from lnbits.tasks import catch_everything_and_restart - -db = Database("ext_lnurldevice") - -lnurldevice_ext: APIRouter = APIRouter(prefix="/lnurldevice", tags=["lnurldevice"]) - -lnurldevice_static_files = [ - { - "path": "/lnurldevice/static", - "app": StaticFiles(directory="lnbits/extensions/lnurldevice/static"), - "name": "lnurldevice_static", - } -] - - -def lnurldevice_renderer(): - return template_renderer(["lnbits/extensions/lnurldevice/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 - - -def lnurldevice_start(): - loop = asyncio.get_event_loop() - loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) diff --git a/lnbits/extensions/lnurldevice/config.json b/lnbits/extensions/lnurldevice/config.json deleted file mode 100644 index 0712d7292..000000000 --- a/lnbits/extensions/lnurldevice/config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "LNURLDevice", - "short_description": "For offline LNURL devices", - "tile": "/lnurldevice/static/image/lnurldevice.png", - "contributors": ["arcbtc"] -} diff --git a/lnbits/extensions/lnurldevice/crud.py b/lnbits/extensions/lnurldevice/crud.py deleted file mode 100644 index 8e15d4ec6..000000000 --- a/lnbits/extensions/lnurldevice/crud.py +++ /dev/null @@ -1,177 +0,0 @@ -from typing import List, Optional - -import shortuuid - -from lnbits.helpers import urlsafe_short_hash - -from . import db -from .models import createLnurldevice, lnurldevicepayment, lnurldevices - - -async def create_lnurldevice( - data: createLnurldevice, -) -> lnurldevices: - if data.device == "pos" or data.device == "atm": - lnurldevice_id = shortuuid.uuid()[:5] - else: - lnurldevice_id = urlsafe_short_hash() - lnurldevice_key = urlsafe_short_hash() - await db.execute( - """ - INSERT INTO lnurldevice.lnurldevices ( - id, - key, - title, - wallet, - currency, - device, - profit, - amount, - pin, - profit1, - amount1, - pin1, - profit2, - amount2, - pin2, - profit3, - amount3, - pin3, - profit4, - amount4, - pin4 - ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - lnurldevice_id, - lnurldevice_key, - data.title, - data.wallet, - data.currency, - data.device, - data.profit, - data.amount, - data.pin, - data.profit1, - data.amount1, - data.pin1, - data.profit2, - data.amount2, - data.pin2, - data.profit3, - data.amount3, - data.pin3, - data.profit4, - data.amount4, - data.pin4, - ), - ) - device = await get_lnurldevice(lnurldevice_id) - assert device - return device - - -async def update_lnurldevice(lnurldevice_id: str, **kwargs) -> lnurldevices: - q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) - await db.execute( - f"UPDATE lnurldevice.lnurldevices SET {q} WHERE id = ?", - (*kwargs.values(), lnurldevice_id), - ) - row = await db.fetchone( - "SELECT * FROM lnurldevice.lnurldevices WHERE id = ?", (lnurldevice_id,) - ) - return lnurldevices(**row) - - -async def get_lnurldevice(lnurldevice_id: str) -> Optional[lnurldevices]: - row = await db.fetchone( - "SELECT * FROM lnurldevice.lnurldevices WHERE id = ?", (lnurldevice_id,) - ) - return lnurldevices(**row) if row else None - - -async def get_lnurldevices(wallet_ids: List[str]) -> List[lnurldevices]: - q = ",".join(["?"] * len(wallet_ids)) - rows = await db.fetchall( - f""" - SELECT * FROM lnurldevice.lnurldevices WHERE wallet IN ({q}) - ORDER BY id - """, - (*wallet_ids,), - ) - - return [lnurldevices(**row) for row in rows] - - -async def delete_lnurldevice(lnurldevice_id: str) -> None: - await db.execute( - "DELETE FROM lnurldevice.lnurldevices WHERE id = ?", (lnurldevice_id,) - ) - - -async def create_lnurldevicepayment( - deviceid: str, - payload: Optional[str] = None, - pin: Optional[str] = None, - payhash: Optional[str] = None, - sats: Optional[int] = 0, -) -> lnurldevicepayment: - device = await get_lnurldevice(deviceid) - assert device - if device.device == "atm": - lnurldevicepayment_id = shortuuid.uuid(name=payload) - else: - lnurldevicepayment_id = urlsafe_short_hash() - await db.execute( - """ - INSERT INTO lnurldevice.lnurldevicepayment ( - id, - deviceid, - payload, - pin, - payhash, - sats - ) - VALUES (?, ?, ?, ?, ?, ?) - """, - (lnurldevicepayment_id, deviceid, payload, pin, payhash, sats), - ) - dpayment = await get_lnurldevicepayment(lnurldevicepayment_id) - assert dpayment - return dpayment - - -async def update_lnurldevicepayment( - lnurldevicepayment_id: str, **kwargs -) -> Optional[lnurldevicepayment]: - q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) - await db.execute( - f"UPDATE lnurldevice.lnurldevicepayment SET {q} WHERE id = ?", - (*kwargs.values(), lnurldevicepayment_id), - ) - row = await db.fetchone( - "SELECT * FROM lnurldevice.lnurldevicepayment WHERE id = ?", - (lnurldevicepayment_id,), - ) - return lnurldevicepayment(**row) if row else None - - -async def get_lnurldevicepayment( - lnurldevicepayment_id: str, -) -> Optional[lnurldevicepayment]: - row = await db.fetchone( - "SELECT * FROM lnurldevice.lnurldevicepayment WHERE id = ?", - (lnurldevicepayment_id,), - ) - return lnurldevicepayment(**row) if row else None - - -async def get_lnurlpayload( - lnurldevicepayment_payload: str, -) -> Optional[lnurldevicepayment]: - row = await db.fetchone( - "SELECT * FROM lnurldevice.lnurldevicepayment WHERE payload = ?", - (lnurldevicepayment_payload,), - ) - return lnurldevicepayment(**row) if row else None diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py deleted file mode 100644 index 20e113d54..000000000 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ /dev/null @@ -1,295 +0,0 @@ -import base64 -import hmac -from http import HTTPStatus -from io import BytesIO - -from embit import bech32, compact -from fastapi import HTTPException, Query, Request - -from lnbits import bolt11 -from lnbits.core.services import create_invoice -from lnbits.core.views.api import pay_invoice -from lnbits.utils.exchange_rates import fiat_amount_as_satoshis - -from . import lnurldevice_ext -from .crud import ( - create_lnurldevicepayment, - get_lnurldevice, - get_lnurldevicepayment, - update_lnurldevicepayment, -) - - -def bech32_decode(bech): - """tweaked version of bech32_decode that ignores length limitations""" - if (any(ord(x) < 33 or ord(x) > 126 for x in bech)) or ( - bech.lower() != bech and bech.upper() != bech - ): - return - bech = bech.lower() - device = bech.rfind("1") - if device < 1 or device + 7 > len(bech): - return - if not all(x in bech32.CHARSET for x in bech[device + 1 :]): - return - hrp = bech[:device] - data = [bech32.CHARSET.find(x) for x in bech[device + 1 :]] - encoding = bech32.bech32_verify_checksum(hrp, data) - if encoding is None: - return - bits = bech32.convertbits(data[:-6], 5, 8, False) - assert bits - return bytes(bits) - - -def xor_decrypt(key, blob): - s = BytesIO(blob) - variant = s.read(1)[0] - if variant != 1: - raise RuntimeError("Not implemented") - # reading nonce - l = s.read(1)[0] - nonce = s.read(l) - if len(nonce) != l: - raise RuntimeError("Missing nonce bytes") - if l < 8: - raise RuntimeError("Nonce is too short") - # reading payload - l = s.read(1)[0] - payload = s.read(l) - if len(payload) > 32: - raise RuntimeError("Payload is too long for this encryption method") - if len(payload) != l: - raise RuntimeError("Missing payload bytes") - hmacval = s.read() - expected = hmac.new( - key, b"Data:" + blob[: -len(hmacval)], digestmod="sha256" - ).digest() - if len(hmacval) < 8: - raise RuntimeError("HMAC is too short") - if hmacval != expected[: len(hmacval)]: - raise RuntimeError("HMAC is invalid") - secret = hmac.new(key, b"Round secret:" + nonce, digestmod="sha256").digest() - payload = bytearray(payload) - for i in range(len(payload)): - payload[i] = payload[i] ^ secret[i] - s = BytesIO(payload) - pin = compact.read_from(s) - amount_in_cent = compact.read_from(s) - return pin, amount_in_cent - - -@lnurldevice_ext.get( - "/api/v1/lnurl/{device_id}", - status_code=HTTPStatus.OK, - name="lnurldevice.lnurl_v1_params", -) -async def lnurl_v1_params( - request: Request, - device_id: str = Query(None), - p: str = Query(None), - atm: str = Query(None), - gpio: str = Query(None), - profit: str = Query(None), - amount: str = Query(None), -): - device = await get_lnurldevice(device_id) - if not device: - return { - "status": "ERROR", - "reason": f"lnurldevice {device_id} not found on this server", - } - if device.device == "switch": - # TODO: AMOUNT IN CENT was never reference here - amount_in_cent = 0 - price_msat = ( - await fiat_amount_as_satoshis(float(profit), device.currency) - if device.currency != "sat" - else amount_in_cent - ) * 1000 - - # Check they're not trying to trick the switch! - check = False - for switch in device.switches(request): - if switch[0] == gpio and switch[1] == profit and switch[2] == amount: - check = True - if not check: - return {"status": "ERROR", "reason": "Switch params wrong"} - - lnurldevicepayment = await create_lnurldevicepayment( - deviceid=device.id, - payload=amount, - sats=price_msat, - pin=gpio, - payhash="bla", - ) - if not lnurldevicepayment: - return {"status": "ERROR", "reason": "Could not create payment."} - return { - "tag": "payRequest", - "callback": request.url_for( - "lnurldevice.lnurl_callback", paymentid=lnurldevicepayment.id - ), - "minSendable": price_msat, - "maxSendable": price_msat, - "metadata": device.lnurlpay_metadata, - } - if len(p) % 4 > 0: - p += "=" * (4 - (len(p) % 4)) - - data = base64.urlsafe_b64decode(p) - pin = 0 - amount_in_cent = 0 - try: - result = xor_decrypt(device.key.encode(), data) - pin = result[0] - amount_in_cent = result[1] - except Exception as exc: - return {"status": "ERROR", "reason": str(exc)} - - price_msat = ( - await fiat_amount_as_satoshis(float(amount_in_cent) / 100, device.currency) - if device.currency != "sat" - else amount_in_cent - ) * 1000 - - if atm: - if device.device != "atm": - return {"status": "ERROR", "reason": "Not ATM device."} - price_msat = int(price_msat * (1 - (device.profit / 100)) / 1000) - try: - lnurldevicepayment = await create_lnurldevicepayment( - deviceid=device.id, - payload=p, - sats=price_msat * 1000, - pin=str(pin), - payhash="payment_hash", - ) - except: - return {"status": "ERROR", "reason": "Could not create ATM payment."} - if not lnurldevicepayment: - return {"status": "ERROR", "reason": "Could not create ATM payment."} - return { - "tag": "withdrawRequest", - "callback": request.url_for( - "lnurldevice.lnurl_callback", paymentid=lnurldevicepayment.id - ), - "k1": p, - "minWithdrawable": price_msat * 1000, - "maxWithdrawable": price_msat * 1000, - "defaultDescription": device.title, - } - price_msat = int(price_msat * ((device.profit / 100) + 1) / 1000) - - lnurldevicepayment = await create_lnurldevicepayment( - deviceid=device.id, - payload=p, - sats=price_msat * 1000, - pin=str(pin), - payhash="payment_hash", - ) - if not lnurldevicepayment: - return {"status": "ERROR", "reason": "Could not create payment."} - return { - "tag": "payRequest", - "callback": request.url_for( - "lnurldevice.lnurl_callback", paymentid=lnurldevicepayment.id - ), - "minSendable": price_msat * 1000, - "maxSendable": price_msat * 1000, - "metadata": device.lnurlpay_metadata, - } - - -@lnurldevice_ext.get( - "/api/v1/lnurl/cb/{paymentid}", - status_code=HTTPStatus.OK, - name="lnurldevice.lnurl_callback", -) -async def lnurl_callback( - request: Request, - paymentid: str = Query(None), - pr: str = Query(None), - k1: str = Query(None), -): - lnurldevicepayment = await get_lnurldevicepayment(paymentid) - if not lnurldevicepayment: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="lnurldevicepayment not found." - ) - device = await get_lnurldevice(lnurldevicepayment.deviceid) - if not device: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="lnurldevice not found." - ) - if device.device == "atm": - if lnurldevicepayment.payload == lnurldevicepayment.payhash: - return {"status": "ERROR", "reason": "Payment already claimed"} - if not pr: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="No payment request" - ) - invoice = bolt11.decode(pr) - if not invoice.payment_hash: - raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Not valid payment request" - ) - else: - if lnurldevicepayment.payload != k1: - return {"status": "ERROR", "reason": "Bad K1"} - if lnurldevicepayment.payhash != "payment_hash": - return {"status": "ERROR", "reason": "Payment already claimed"} - - lnurldevicepayment_updated = await update_lnurldevicepayment( - lnurldevicepayment_id=paymentid, payhash=lnurldevicepayment.payload - ) - assert lnurldevicepayment_updated - await pay_invoice( - wallet_id=device.wallet, - payment_request=pr, - max_sat=int(lnurldevicepayment_updated.sats / 1000), - extra={"tag": "withdraw"}, - ) - return {"status": "OK"} - if device.device == "switch": - payment_hash, payment_request = await create_invoice( - wallet_id=device.wallet, - amount=int(lnurldevicepayment.sats / 1000), - memo=device.id + " PIN " + str(lnurldevicepayment.pin), - unhashed_description=device.lnurlpay_metadata.encode(), - extra={ - "tag": "Switch", - "pin": str(lnurldevicepayment.pin), - "amount": str(lnurldevicepayment.payload), - "id": paymentid, - }, - ) - - lnurldevicepayment = await update_lnurldevicepayment( - lnurldevicepayment_id=paymentid, payhash=payment_hash - ) - return { - "pr": payment_request, - "routes": [], - } - - payment_hash, payment_request = await create_invoice( - wallet_id=device.wallet, - amount=int(lnurldevicepayment.sats / 1000), - memo=device.title, - unhashed_description=device.lnurlpay_metadata.encode(), - extra={"tag": "PoS"}, - ) - lnurldevicepayment = await update_lnurldevicepayment( - lnurldevicepayment_id=paymentid, payhash=payment_hash - ) - - return { - "pr": payment_request, - "successAction": { - "tag": "url", - "description": "Check the attached link", - "url": request.url_for("lnurldevice.displaypin", paymentid=paymentid), - }, - "routes": [], - } diff --git a/lnbits/extensions/lnurldevice/migrations.py b/lnbits/extensions/lnurldevice/migrations.py deleted file mode 100644 index 7fd7d6c40..000000000 --- a/lnbits/extensions/lnurldevice/migrations.py +++ /dev/null @@ -1,139 +0,0 @@ -from lnbits.db import Database - -db2 = Database("ext_lnurlpos") - - -async def m001_initial(db): - """ - Initial lnurldevice table. - """ - await db.execute( - f""" - CREATE TABLE lnurldevice.lnurldevices ( - id TEXT NOT NULL PRIMARY KEY, - key TEXT NOT NULL, - title TEXT NOT NULL, - wallet TEXT NOT NULL, - currency TEXT NOT NULL, - device TEXT NOT NULL, - profit FLOAT NOT NULL, - timestamp TIMESTAMP NOT NULL DEFAULT {db.timestamp_now} - ); - """ - ) - await db.execute( - f""" - CREATE TABLE lnurldevice.lnurldevicepayment ( - id TEXT NOT NULL PRIMARY KEY, - deviceid TEXT NOT NULL, - payhash TEXT, - payload TEXT NOT NULL, - pin INT, - sats {db.big_int}, - timestamp TIMESTAMP NOT NULL DEFAULT {db.timestamp_now} - ); - """ - ) - - -async def m002_redux(db): - """ - Moves everything from lnurlpos to lnurldevice - """ - try: - for row in [ - list(row) for row in await db2.fetchall("SELECT * FROM lnurlpos.lnurlposs") - ]: - await db.execute( - """ - INSERT INTO lnurldevice.lnurldevices ( - id, - key, - title, - wallet, - currency, - device, - profit - ) - VALUES (?, ?, ?, ?, ?, ?, ?) - """, - (row[0], row[1], row[2], row[3], row[4], "pos", 0), - ) - for row in [ - list(row) - for row in await db2.fetchall("SELECT * FROM lnurlpos.lnurlpospayment") - ]: - await db.execute( - """ - INSERT INTO lnurldevice.lnurldevicepayment ( - id, - deviceid, - payhash, - payload, - pin, - sats - ) - VALUES (?, ?, ?, ?, ?, ?) - """, - (row[0], row[1], row[3], row[4], row[5], row[6]), - ) - except: - return - - -async def m003_redux(db): - """ - Add 'meta' for storing various metadata about the wallet - """ - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount INT DEFAULT 0;" - ) - - -async def m004_redux(db): - """ - Add 'meta' for storing various metadata about the wallet - """ - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin INT DEFAULT 0" - ) - - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit1 FLOAT DEFAULT 0" - ) - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount1 INT DEFAULT 0" - ) - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin1 INT DEFAULT 0" - ) - - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit2 FLOAT DEFAULT 0" - ) - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount2 INT DEFAULT 0" - ) - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin2 INT DEFAULT 0" - ) - - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit3 FLOAT DEFAULT 0" - ) - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount3 INT DEFAULT 0" - ) - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin3 INT DEFAULT 0" - ) - - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN profit4 FLOAT DEFAULT 0" - ) - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN amount4 INT DEFAULT 0" - ) - await db.execute( - "ALTER TABLE lnurldevice.lnurldevices ADD COLUMN pin4 INT DEFAULT 0" - ) diff --git a/lnbits/extensions/lnurldevice/models.py b/lnbits/extensions/lnurldevice/models.py deleted file mode 100644 index f9640de1c..000000000 --- a/lnbits/extensions/lnurldevice/models.py +++ /dev/null @@ -1,171 +0,0 @@ -import json -from sqlite3 import Row -from typing import List, Optional - -from fastapi import Request -from lnurl import encode as lnurl_encode -from lnurl.types import LnurlPayMetadata -from pydantic import BaseModel - - -class createLnurldevice(BaseModel): - title: str - wallet: str - currency: str - device: str - profit: float = 0 - amount: Optional[int] = 0 - pin: int = 0 - profit1: float = 0 - amount1: int = 0 - pin1: int = 0 - profit2: float = 0 - amount2: int = 0 - pin2: int = 0 - profit3: float = 0 - amount3: int = 0 - pin3: int = 0 - profit4: float = 0 - amount4: int = 0 - pin4: int = 0 - - -class lnurldevices(BaseModel): - id: str - key: str - title: str - wallet: str - currency: str - device: str - profit: float - amount: int - pin: int - profit1: float - amount1: int - pin1: int - profit2: float - amount2: int - pin2: int - profit3: float - amount3: int - pin3: int - profit4: float - amount4: int - pin4: int - timestamp: str - - @classmethod - def from_row(cls, row: Row) -> "lnurldevices": - return cls(**dict(row)) - - @property - def lnurlpay_metadata(self) -> LnurlPayMetadata: - return LnurlPayMetadata(json.dumps([["text/plain", self.title]])) - - def switches(self, req: Request) -> List: - switches = [] - if self.profit > 0: - url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - switches.append( - [ - str(self.pin), - str(self.profit), - str(self.amount), - lnurl_encode( - url - + "?gpio=" - + str(self.pin) - + "&profit=" - + str(self.profit) - + "&amount=" - + str(self.amount) - ), - ] - ) - if self.profit1 > 0: - url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - switches.append( - [ - str(self.pin1), - str(self.profit1), - str(self.amount1), - lnurl_encode( - url - + "?gpio=" - + str(self.pin1) - + "&profit=" - + str(self.profit1) - + "&amount=" - + str(self.amount1) - ), - ] - ) - if self.profit2 > 0: - url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - switches.append( - [ - str(self.pin2), - str(self.profit2), - str(self.amount2), - lnurl_encode( - url - + "?gpio=" - + str(self.pin2) - + "&profit=" - + str(self.profit2) - + "&amount=" - + str(self.amount2) - ), - ] - ) - if self.profit3 > 0: - url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - switches.append( - [ - str(self.pin3), - str(self.profit3), - str(self.amount3), - lnurl_encode( - url - + "?gpio=" - + str(self.pin3) - + "&profit=" - + str(self.profit3) - + "&amount=" - + str(self.amount3) - ), - ] - ) - if self.profit4 > 0: - url = req.url_for("lnurldevice.lnurl_v1_params", device_id=self.id) - switches.append( - [ - str(self.pin4), - str(self.profit4), - str(self.amount4), - lnurl_encode( - url - + "?gpio=" - + str(self.pin4) - + "&profit=" - + str(self.profit4) - + "&amount=" - + str(self.amount4) - ), - ] - ) - return switches - - -class lnurldevicepayment(BaseModel): - id: str - deviceid: str - payhash: str - payload: str - pin: int - sats: int - timestamp: str - - @classmethod - def from_row(cls, row: Row) -> "lnurldevicepayment": - return cls(**dict(row)) diff --git a/lnbits/extensions/lnurldevice/static/image/lnurldevice.png b/lnbits/extensions/lnurldevice/static/image/lnurldevice.png deleted file mode 100644 index 3a5304f62bdb9db77cad3d7742ebad791200d151..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13746 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 Fe*r)JP9gvR diff --git a/lnbits/extensions/lnurldevice/tasks.py b/lnbits/extensions/lnurldevice/tasks.py deleted file mode 100644 index 9aec173ec..000000000 --- a/lnbits/extensions/lnurldevice/tasks.py +++ /dev/null @@ -1,36 +0,0 @@ -import asyncio - -from lnbits.core.models import Payment -from lnbits.core.services import websocketUpdater -from lnbits.helpers import get_current_extension_name -from lnbits.tasks import register_invoice_listener - -from .crud import get_lnurldevicepayment, update_lnurldevicepayment - - -async def wait_for_paid_invoices(): - invoice_queue = asyncio.Queue() - register_invoice_listener(invoice_queue, get_current_extension_name()) - - while True: - payment = await invoice_queue.get() - await on_invoice_paid(payment) - - -async def on_invoice_paid(payment: Payment) -> None: - # (avoid loops) - if "Switch" == payment.extra.get("tag"): - lnurldevicepayment = await get_lnurldevicepayment(payment.extra["id"]) - if not lnurldevicepayment: - return - if lnurldevicepayment.payhash == "used": - return - lnurldevicepayment = await update_lnurldevicepayment( - lnurldevicepayment_id=payment.extra["id"], payhash="used" - ) - assert lnurldevicepayment - return await websocketUpdater( - lnurldevicepayment.deviceid, - str(lnurldevicepayment.pin) + "-" + str(lnurldevicepayment.payload), - ) - return diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html deleted file mode 100644 index 712f0e590..000000000 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html +++ /dev/null @@ -1,190 +0,0 @@ - - -

- For LNURL based Points of Sale, ATMs, and relay devices
- Use with:
- LNPoS - - https://lnbits.github.io/lnpos
- bitcoinSwitch - - https://github.com/lnbits/bitcoinSwitch
- FOSSA - - https://github.com/lnbits/fossa
- - Created by, - Ben Arc, - BC, - Vlad Stan -

-
- - - - - - /lnurldevice/api/v1/lnurlpos -
Headers
- {"X-Api-Key": <admin_key>}
-
- Body (application/json) -
-
- Returns 200 OK (application/json) -
- [<lnurldevice_object>, ...] -
Curl example
- curl -X POST {{ request.base_url }}lnurldevice/api/v1/lnurlpos -d - '{"title": <string>, "message":<string>, "currency": - <integer>}' -H "Content-type: application/json" -H "X-Api-Key: - {{user.wallets[0].adminkey }}" - -
-
-
- - - - PUT - /lnurldevice/api/v1/lnurlpos/<lnurldevice_id> -
Headers
- {"X-Api-Key": <admin_key>}
-
- Body (application/json) -
-
- Returns 200 OK (application/json) -
- [<lnurldevice_object>, ...] -
Curl example
- curl -X POST {{ request.base_url - }}lnurldevice/api/v1/lnurlpos/<lnurldevice_id> -d ''{"title": - <string>, "message":<string>, "currency": - <integer>} -H "Content-type: application/json" -H "X-Api-Key: - {{user.wallets[0].adminkey }}" - -
-
-
- - - - - GET - /lnurldevice/api/v1/lnurlpos/<lnurldevice_id> -
Headers
- {"X-Api-Key": <invoice_key>}
-
- Body (application/json) -
-
- Returns 200 OK (application/json) -
- [<lnurldevice_object>, ...] -
Curl example
- curl -X GET {{ request.base_url - }}lnurldevice/api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: - {{ user.wallets[0].inkey }}" - -
-
-
- - - - GET - /lnurldevice/api/v1/lnurlpos -
Headers
- {"X-Api-Key": <invoice_key>}
-
- Body (application/json) -
-
- Returns 200 OK (application/json) -
- [<lnurldevice_object>, ...] -
Curl example
- curl -X GET {{ request.base_url }}lnurldevice/api/v1/lnurlpos -H - "X-Api-Key: {{ user.wallets[0].inkey }}" - -
-
-
- - - - DELETE - /lnurldevice/api/v1/lnurlpos/<lnurldevice_id> -
Headers
- {"X-Api-Key": <admin_key>}
-
Returns 204 NO CONTENT
- -
Curl example
- curl -X DELETE {{ request.base_url - }}lnurldevice/api/v1/lnurlpos/<lnurldevice_id> -H "X-Api-Key: - {{ user.wallets[0].adminkey }}" - -
-
-
-
-
diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/error.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/error.html deleted file mode 100644 index d8e418329..000000000 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/error.html +++ /dev/null @@ -1,34 +0,0 @@ -{% extends "public.html" %} {% block page %} -
-
- - -
-

LNURL-pay not paid

-
- - -
-
-
-
-
- - {% endblock %} {% block scripts %} - - - - {% endblock %} -
diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html deleted file mode 100644 index f308cc652..000000000 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/index.html +++ /dev/null @@ -1,881 +0,0 @@ -{% extends "base.html" %} {% from "macros.jinja" import window_vars with context -%} {% block page %} -
-
- - - {% raw %} - New LNURLDevice instance - - - - - - -
-
-
lNURLdevice
-
- -
- - - - Export to CSV -
-
- - - - - {% endraw %} - -
-
-
- -
- - -
- {{SITE_TITLE}} LNURLDevice Extension -
-
- - - {% include "lnurldevice/_api_docs.html" %} - -
-
- - - -
LNURLDevice device string
-
- {% raw %}{{wslocation}}/api/v1/ws/{{settingsDialog.data.id}}{% endraw - %} Click to copy URL - - {% raw - %}{{location}}/lnurldevice/api/v1/lnurl/{{settingsDialog.data.id}}, - {{settingsDialog.data.key}}, {{settingsDialog.data.currency}}{% endraw - %} Click to copy URL - -
-
- -
-
-
- - - - - - - - - - - -
- - - -
-
-
- -
-
- -
-
- -
-
-
-
-
-
- -
-
- -
-
- -
-
-
- -
-
-
- -
-
- -
-
- -
-
-
- -
-
-
- -
-
- -
-
- -
-
-
- -
-
-
- -
-
- -
-
- -
-
-
-
-
- Update lnurldevice - Create lnurldevice - Cancel -
-
-
-
- - - - - - - Copy LNURL - {% raw %}{{ wsMessage }}{% endraw %} - {% raw %}{{ wsMessage }}{% endraw %} -
-
- - Close -
-
-
-
-{% endblock %} {% block scripts %} {{ window_vars(user) }} - - -{% endblock %} diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/paid.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/paid.html deleted file mode 100644 index c185ecce6..000000000 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/paid.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends "public.html" %} {% block page %} -
-
- - -
-

{{ pin }}

-
-
-
-
-
- - {% endblock %} {% block scripts %} - - - - {% endblock %} -
diff --git a/lnbits/extensions/lnurldevice/views.py b/lnbits/extensions/lnurldevice/views.py deleted file mode 100644 index a6256a415..000000000 --- a/lnbits/extensions/lnurldevice/views.py +++ /dev/null @@ -1,62 +0,0 @@ -from http import HTTPStatus - -from fastapi import Depends, HTTPException, Query, Request -from fastapi.templating import Jinja2Templates -from starlette.responses import HTMLResponse, StreamingResponse - -from lnbits.core.crud import update_payment_status -from lnbits.core.models import User -from lnbits.core.views.api import api_payment -from lnbits.decorators import check_user_exists - -from . import lnurldevice_ext, lnurldevice_renderer -from .crud import get_lnurldevice, get_lnurldevicepayment - -templates = Jinja2Templates(directory="templates") - - -@lnurldevice_ext.get("/", response_class=HTMLResponse) -async def index(request: Request, user: User = Depends(check_user_exists)): - return lnurldevice_renderer().TemplateResponse( - "lnurldevice/index.html", {"request": request, "user": user.dict()} - ) - - -@lnurldevice_ext.get( - "/{paymentid}", name="lnurldevice.displaypin", response_class=HTMLResponse -) -async def displaypin(request: Request, paymentid: str = Query(None)): - lnurldevicepayment = await get_lnurldevicepayment(paymentid) - if not lnurldevicepayment: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="No lmurldevice payment" - ) - device = await get_lnurldevice(lnurldevicepayment.deviceid) - if not device: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="lnurldevice not found." - ) - status = await api_payment(lnurldevicepayment.payhash) - if status["paid"]: - await update_payment_status( - checking_id=lnurldevicepayment.payhash, pending=True - ) - return lnurldevice_renderer().TemplateResponse( - "lnurldevice/paid.html", {"request": request, "pin": lnurldevicepayment.pin} - ) - return lnurldevice_renderer().TemplateResponse( - "lnurldevice/error.html", - {"request": request, "pin": "filler", "not_paid": True}, - ) - - -@lnurldevice_ext.get("/img/{lnurldevice_id}", response_class=StreamingResponse) -async def img(request: Request, lnurldevice_id): - lnurldevice = await get_lnurldevice(lnurldevice_id) - if not lnurldevice: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="LNURLDevice does not exist." - ) - # error: "lnurldevices" has no attribute "lnurl" - # return lnurldevice.lnurl(request) - return None diff --git a/lnbits/extensions/lnurldevice/views_api.py b/lnbits/extensions/lnurldevice/views_api.py deleted file mode 100644 index 2fd1bd122..000000000 --- a/lnbits/extensions/lnurldevice/views_api.py +++ /dev/null @@ -1,88 +0,0 @@ -from http import HTTPStatus - -from fastapi import Depends, HTTPException, Query, Request - -from lnbits.core.crud import get_user -from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key -from lnbits.utils.exchange_rates import currencies - -from . import lnurldevice_ext -from .crud import ( - create_lnurldevice, - delete_lnurldevice, - get_lnurldevice, - get_lnurldevices, - update_lnurldevice, -) -from .models import createLnurldevice - - -@lnurldevice_ext.get("/api/v1/currencies") -async def api_list_currencies_available(): - return list(currencies.keys()) - - -@lnurldevice_ext.post("/api/v1/lnurlpos") -@lnurldevice_ext.put("/api/v1/lnurlpos/{lnurldevice_id}") -async def api_lnurldevice_create_or_update( - req: Request, - data: createLnurldevice, - wallet: WalletTypeInfo = Depends(require_admin_key), - lnurldevice_id: str = Query(None), -): - if not lnurldevice_id: - lnurldevice = await create_lnurldevice(data) - return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} - else: - lnurldevice = await update_lnurldevice(lnurldevice_id, **data.dict()) - return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} - - -@lnurldevice_ext.get("/api/v1/lnurlpos") -async def api_lnurldevices_retrieve( - req: Request, wallet: WalletTypeInfo = Depends(get_key_type) -): - user = await get_user(wallet.wallet.user) - wallet_ids = user.wallet_ids if user else [] - try: - return [ - {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} - for lnurldevice in await get_lnurldevices(wallet_ids) - ] - except: - try: - return [ - {**lnurldevice.dict()} - for lnurldevice in await get_lnurldevices(wallet_ids) - ] - except: - return "" - - -@lnurldevice_ext.get( - "/api/v1/lnurlpos/{lnurldevice_id}", dependencies=[Depends(get_key_type)] -) -async def api_lnurldevice_retrieve( - req: Request, - lnurldevice_id: str = Query(None), -): - lnurldevice = await get_lnurldevice(lnurldevice_id) - if not lnurldevice: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="lnurldevice does not exist" - ) - return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} - - -@lnurldevice_ext.delete( - "/api/v1/lnurlpos/{lnurldevice_id}", dependencies=[Depends(require_admin_key)] -) -async def api_lnurldevice_delete(lnurldevice_id: str = Query(None)): - lnurldevice = await get_lnurldevice(lnurldevice_id) - if not lnurldevice: - raise HTTPException( - status_code=HTTPStatus.NOT_FOUND, detail="Wallet link does not exist." - ) - - await delete_lnurldevice(lnurldevice_id) - return "", HTTPStatus.NO_CONTENT