diff --git a/lnbits/extensions/lnurldevice/README.md b/lnbits/extensions/lnurldevice/README.md deleted file mode 100644 index 01ce6382..00000000 --- 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 56e9d8f7..00000000 --- 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 0712d729..00000000 --- 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 8e15d4ec..00000000 --- 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 20e113d5..00000000 --- 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 7fd7d6c4..00000000 --- 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 f9640de1..00000000 --- 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 3a5304f6..00000000 Binary files a/lnbits/extensions/lnurldevice/static/image/lnurldevice.png and /dev/null differ diff --git a/lnbits/extensions/lnurldevice/tasks.py b/lnbits/extensions/lnurldevice/tasks.py deleted file mode 100644 index 9aec173e..00000000 --- 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 712f0e59..00000000 --- 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 d8e41832..00000000 --- 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 f308cc65..00000000 --- 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 c185ecce..00000000 --- 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 a6256a41..00000000 --- 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 2fd1bd12..00000000 --- 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