Merge pull request #1304 from lnbits/fix/mypy-lnurldevices

fix mypy lnurldevices
This commit is contained in:
Arc
2023-01-09 16:44:23 +00:00
committed by GitHub
7 changed files with 64 additions and 80 deletions

View File

@@ -7,8 +7,6 @@ from lnbits.helpers import urlsafe_short_hash
from . import db from . import db
from .models import createLnurldevice, lnurldevicepayment, lnurldevices from .models import createLnurldevice, lnurldevicepayment, lnurldevices
###############lnurldeviceS##########################
async def create_lnurldevice( async def create_lnurldevice(
data: createLnurldevice, data: createLnurldevice,
@@ -69,10 +67,12 @@ async def create_lnurldevice(
data.pin4, data.pin4,
), ),
) )
return await get_lnurldevice(lnurldevice_id) device = await get_lnurldevice(lnurldevice_id)
assert device
return device
async def update_lnurldevice(lnurldevice_id: str, **kwargs) -> Optional[lnurldevices]: async def update_lnurldevice(lnurldevice_id: str, **kwargs) -> lnurldevices:
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
await db.execute( await db.execute(
f"UPDATE lnurldevice.lnurldevices SET {q} WHERE id = ?", f"UPDATE lnurldevice.lnurldevices SET {q} WHERE id = ?",
@@ -81,19 +81,18 @@ async def update_lnurldevice(lnurldevice_id: str, **kwargs) -> Optional[lnurldev
row = await db.fetchone( row = await db.fetchone(
"SELECT * FROM lnurldevice.lnurldevices WHERE id = ?", (lnurldevice_id,) "SELECT * FROM lnurldevice.lnurldevices WHERE id = ?", (lnurldevice_id,)
) )
return lnurldevices(**row) if row else None return lnurldevices(**row)
async def get_lnurldevice(lnurldevice_id: str) -> lnurldevices: async def get_lnurldevice(lnurldevice_id: str) -> Optional[lnurldevices]:
row = await db.fetchone( row = await db.fetchone(
"SELECT * FROM lnurldevice.lnurldevices WHERE id = ?", (lnurldevice_id,) "SELECT * FROM lnurldevice.lnurldevices WHERE id = ?", (lnurldevice_id,)
) )
return lnurldevices(**row) if row else None return lnurldevices(**row) if row else None
async def get_lnurldevices(wallet_ids: Union[str, List[str]]) -> List[lnurldevices]: async def get_lnurldevices(wallet_ids: List[str]) -> List[lnurldevices]:
wallet_ids = [wallet_ids] q = ",".join(["?"] * len(wallet_ids))
q = ",".join(["?"] * len(wallet_ids[0]))
rows = await db.fetchall( rows = await db.fetchall(
f""" f"""
SELECT * FROM lnurldevice.lnurldevices WHERE wallet IN ({q}) SELECT * FROM lnurldevice.lnurldevices WHERE wallet IN ({q})
@@ -102,7 +101,7 @@ async def get_lnurldevices(wallet_ids: Union[str, List[str]]) -> List[lnurldevic
(*wallet_ids,), (*wallet_ids,),
) )
return [lnurldevices(**row) if row else None for row in rows] return [lnurldevices(**row) for row in rows]
async def delete_lnurldevice(lnurldevice_id: str) -> None: async def delete_lnurldevice(lnurldevice_id: str) -> None:
@@ -110,8 +109,6 @@ async def delete_lnurldevice(lnurldevice_id: str) -> None:
"DELETE FROM lnurldevice.lnurldevices WHERE id = ?", (lnurldevice_id,) "DELETE FROM lnurldevice.lnurldevices WHERE id = ?", (lnurldevice_id,)
) )
########################lnuldevice payments###########################
async def create_lnurldevicepayment( async def create_lnurldevicepayment(
deviceid: str, deviceid: str,
@@ -121,6 +118,7 @@ async def create_lnurldevicepayment(
sats: Optional[int] = 0, sats: Optional[int] = 0,
) -> lnurldevicepayment: ) -> lnurldevicepayment:
device = await get_lnurldevice(deviceid) device = await get_lnurldevice(deviceid)
assert device
if device.device == "atm": if device.device == "atm":
lnurldevicepayment_id = shortuuid.uuid(name=payload) lnurldevicepayment_id = shortuuid.uuid(name=payload)
else: else:
@@ -139,7 +137,9 @@ async def create_lnurldevicepayment(
""", """,
(lnurldevicepayment_id, deviceid, payload, pin, payhash, sats), (lnurldevicepayment_id, deviceid, payload, pin, payhash, sats),
) )
return await get_lnurldevicepayment(lnurldevicepayment_id) dpayment = await get_lnurldevicepayment(lnurldevicepayment_id)
assert dpayment
return dpayment
async def update_lnurldevicepayment( async def update_lnurldevicepayment(
@@ -157,7 +157,9 @@ async def update_lnurldevicepayment(
return lnurldevicepayment(**row) if row else None return lnurldevicepayment(**row) if row else None
async def get_lnurldevicepayment(lnurldevicepayment_id: str) -> lnurldevicepayment: async def get_lnurldevicepayment(
lnurldevicepayment_id: str,
) -> Optional[lnurldevicepayment]:
row = await db.fetchone( row = await db.fetchone(
"SELECT * FROM lnurldevice.lnurldevicepayment WHERE id = ?", "SELECT * FROM lnurldevice.lnurldevicepayment WHERE id = ?",
(lnurldevicepayment_id,), (lnurldevicepayment_id,),
@@ -165,7 +167,9 @@ async def get_lnurldevicepayment(lnurldevicepayment_id: str) -> lnurldevicepayme
return lnurldevicepayment(**row) if row else None return lnurldevicepayment(**row) if row else None
async def get_lnurlpayload(lnurldevicepayment_payload: str) -> lnurldevicepayment: async def get_lnurlpayload(
lnurldevicepayment_payload: str,
) -> Optional[lnurldevicepayment]:
row = await db.fetchone( row = await db.fetchone(
"SELECT * FROM lnurldevice.lnurldevicepayment WHERE payload = ?", "SELECT * FROM lnurldevice.lnurldevicepayment WHERE payload = ?",
(lnurldevicepayment_payload,), (lnurldevicepayment_payload,),

View File

@@ -1,16 +1,11 @@
import base64 import base64
import hashlib
import hmac import hmac
from http import HTTPStatus from http import HTTPStatus
from io import BytesIO from io import BytesIO
from typing import Optional
import shortuuid import shortuuid
from embit import bech32, compact from embit import bech32, compact
from fastapi import Request from fastapi import HTTPException, Query, Request
from fastapi.param_functions import Query
from loguru import logger
from starlette.exceptions import HTTPException
from lnbits import bolt11 from lnbits import bolt11
from lnbits.core.services import create_invoice from lnbits.core.services import create_invoice
@@ -44,7 +39,9 @@ def bech32_decode(bech):
encoding = bech32.bech32_verify_checksum(hrp, data) encoding = bech32.bech32_verify_checksum(hrp, data)
if encoding is None: if encoding is None:
return return
return bytes(bech32.convertbits(data[:-6], 5, 8, False)) bits = bech32.convertbits(data[:-6], 5, 8, False)
assert bits
return bytes(bits)
def xor_decrypt(key, blob): def xor_decrypt(key, blob):
@@ -105,6 +102,8 @@ async def lnurl_v1_params(
"reason": f"lnurldevice {device_id} not found on this server", "reason": f"lnurldevice {device_id} not found on this server",
} }
if device.device == "switch": if device.device == "switch":
# TODO: AMOUNT IN CENT was never reference here
amount_in_cent = 0
price_msat = ( price_msat = (
await fiat_amount_as_satoshis(float(profit), device.currency) await fiat_amount_as_satoshis(float(profit), device.currency)
if device.currency != "sat" if device.currency != "sat"
@@ -160,23 +159,18 @@ async def lnurl_v1_params(
if device.device != "atm": if device.device != "atm":
return {"status": "ERROR", "reason": "Not ATM device."} return {"status": "ERROR", "reason": "Not ATM device."}
price_msat = int(price_msat * (1 - (device.profit / 100)) / 1000) price_msat = int(price_msat * (1 - (device.profit / 100)) / 1000)
lnurldevicepayment = await get_lnurldevicepayment(shortuuid.uuid(name=p)) try:
if lnurldevicepayment:
logger.debug("lnurldevicepayment")
logger.debug(lnurldevicepayment)
logger.debug("lnurldevicepayment")
if lnurldevicepayment.payload == lnurldevicepayment.payhash:
return {"status": "ERROR", "reason": f"Payment already claimed"}
else:
lnurldevicepayment = await create_lnurldevicepayment( lnurldevicepayment = await create_lnurldevicepayment(
deviceid=device.id, deviceid=device.id,
payload=p, payload=p,
sats=price_msat * 1000, sats=price_msat * 1000,
pin=pin, pin=str(pin),
payhash="payment_hash", payhash="payment_hash",
) )
except:
return {"status": "ERROR", "reason": "Could not create ATM payment."}
if not lnurldevicepayment: if not lnurldevicepayment:
return {"status": "ERROR", "reason": "Could not create payment."} return {"status": "ERROR", "reason": "Could not create ATM payment."}
return { return {
"tag": "withdrawRequest", "tag": "withdrawRequest",
"callback": request.url_for( "callback": request.url_for(
@@ -193,7 +187,7 @@ async def lnurl_v1_params(
deviceid=device.id, deviceid=device.id,
payload=p, payload=p,
sats=price_msat * 1000, sats=price_msat * 1000,
pin=pin, pin=str(pin),
payhash="payment_hash", payhash="payment_hash",
) )
if not lnurldevicepayment: if not lnurldevicepayment:
@@ -221,6 +215,10 @@ async def lnurl_callback(
k1: str = Query(None), k1: str = Query(None),
): ):
lnurldevicepayment = await get_lnurldevicepayment(paymentid) lnurldevicepayment = await get_lnurldevicepayment(paymentid)
if not lnurldevicepayment:
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN, detail="lnurldevicepayment not found."
)
device = await get_lnurldevice(lnurldevicepayment.deviceid) device = await get_lnurldevice(lnurldevicepayment.deviceid)
if not device: if not device:
raise HTTPException( raise HTTPException(
@@ -241,13 +239,17 @@ async def lnurl_callback(
else: else:
if lnurldevicepayment.payload != k1: if lnurldevicepayment.payload != k1:
return {"status": "ERROR", "reason": "Bad K1"} return {"status": "ERROR", "reason": "Bad K1"}
lnurldevicepayment = await update_lnurldevicepayment( if lnurldevicepayment.payhash != "payment_hash":
return {"status": "ERROR", "reason": f"Payment already claimed"}
lnurldevicepayment_updated = await update_lnurldevicepayment(
lnurldevicepayment_id=paymentid, payhash=lnurldevicepayment.payload lnurldevicepayment_id=paymentid, payhash=lnurldevicepayment.payload
) )
assert lnurldevicepayment_updated
await pay_invoice( await pay_invoice(
wallet_id=device.wallet, wallet_id=device.wallet,
payment_request=pr, payment_request=pr,
max_sat=lnurldevicepayment.sats / 1000, max_sat=int(lnurldevicepayment_updated.sats / 1000),
extra={"tag": "withdraw"}, extra={"tag": "withdraw"},
) )
return {"status": "OK"} return {"status": "OK"}

View File

@@ -3,13 +3,9 @@ from sqlite3 import Row
from typing import List, Optional from typing import List, Optional
from fastapi import Request from fastapi import Request
from lnurl import Lnurl from lnurl import encode as lnurl_encode
from lnurl import encode as lnurl_encode # type: ignore from lnurl.types import LnurlPayMetadata
from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore
from lnurl.types import LnurlPayMetadata # type: ignore
from loguru import logger
from pydantic import BaseModel from pydantic import BaseModel
from pydantic.main import BaseModel
class createLnurldevice(BaseModel): class createLnurldevice(BaseModel):
@@ -58,6 +54,7 @@ class lnurldevices(BaseModel):
pin4: int pin4: int
timestamp: str timestamp: str
@classmethod
def from_row(cls, row: Row) -> "lnurldevices": def from_row(cls, row: Row) -> "lnurldevices":
return cls(**dict(row)) return cls(**dict(row))

View File

@@ -1,18 +1,11 @@
import asyncio import asyncio
import json
from http import HTTPStatus
from urllib.parse import urlparse
import httpx
from fastapi import HTTPException
from lnbits import bolt11
from lnbits.core.models import Payment from lnbits.core.models import Payment
from lnbits.core.services import pay_invoice, websocketUpdater from lnbits.core.services import websocketUpdater
from lnbits.helpers import get_current_extension_name from lnbits.helpers import get_current_extension_name
from lnbits.tasks import register_invoice_listener from lnbits.tasks import register_invoice_listener
from .crud import get_lnurldevice, get_lnurldevicepayment, update_lnurldevicepayment from .crud import get_lnurldevicepayment, update_lnurldevicepayment
async def wait_for_paid_invoices(): async def wait_for_paid_invoices():
@@ -27,14 +20,15 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
# (avoid loops) # (avoid loops)
if "Switch" == payment.extra.get("tag"): if "Switch" == payment.extra.get("tag"):
lnurldevicepayment = await get_lnurldevicepayment(payment.extra.get("id")) lnurldevicepayment = await get_lnurldevicepayment(payment.extra["id"])
if not lnurldevicepayment: if not lnurldevicepayment:
return return
if lnurldevicepayment.payhash == "used": if lnurldevicepayment.payhash == "used":
return return
lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment = await update_lnurldevicepayment(
lnurldevicepayment_id=payment.extra.get("id"), payhash="used" lnurldevicepayment_id=payment.extra["id"], payhash="used"
) )
assert lnurldevicepayment
return await websocketUpdater( return await websocketUpdater(
lnurldevicepayment.deviceid, lnurldevicepayment.deviceid,
str(lnurldevicepayment.pin) + "-" + str(lnurldevicepayment.payload), str(lnurldevicepayment.pin) + "-" + str(lnurldevicepayment.payload),

View File

@@ -1,12 +1,7 @@
from http import HTTPStatus from http import HTTPStatus
from io import BytesIO
import pyqrcode from fastapi import Depends, HTTPException, Query, Request
from fastapi import Request
from fastapi.param_functions import Query
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse, StreamingResponse from starlette.responses import HTMLResponse, StreamingResponse
from lnbits.core.crud import update_payment_status from lnbits.core.crud import update_payment_status
@@ -62,4 +57,6 @@ async def img(request: Request, lnurldevice_id):
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="LNURLDevice does not exist." status_code=HTTPStatus.NOT_FOUND, detail="LNURLDevice does not exist."
) )
return lnurldevice.lnurl(request) # error: "lnurldevices" has no attribute "lnurl"
# return lnurldevice.lnurl(request)
return None

View File

@@ -1,9 +1,6 @@
from http import HTTPStatus from http import HTTPStatus
from fastapi import Request from fastapi import Depends, HTTPException, Query, Request
from fastapi.param_functions import Query
from fastapi.params import Depends
from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user from lnbits.core.crud import get_user
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
@@ -26,9 +23,6 @@ async def api_list_currencies_available():
return list(currencies.keys()) return list(currencies.keys())
#######################lnurldevice##########################
@lnurldevice_ext.post("/api/v1/lnurlpos") @lnurldevice_ext.post("/api/v1/lnurlpos")
@lnurldevice_ext.put("/api/v1/lnurlpos/{lnurldevice_id}") @lnurldevice_ext.put("/api/v1/lnurlpos/{lnurldevice_id}")
async def api_lnurldevice_create_or_update( async def api_lnurldevice_create_or_update(
@@ -41,7 +35,7 @@ async def api_lnurldevice_create_or_update(
lnurldevice = await create_lnurldevice(data) lnurldevice = await create_lnurldevice(data)
return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}}
else: else:
lnurldevice = await update_lnurldevice(data, lnurldevice_id=lnurldevice_id) lnurldevice = await update_lnurldevice(lnurldevice_id, **data.dict())
return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}}
@@ -49,7 +43,8 @@ async def api_lnurldevice_create_or_update(
async def api_lnurldevices_retrieve( async def api_lnurldevices_retrieve(
req: Request, wallet: WalletTypeInfo = Depends(get_key_type) req: Request, wallet: WalletTypeInfo = Depends(get_key_type)
): ):
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids user = await get_user(wallet.wallet.user)
wallet_ids = user.wallet_ids if user else []
try: try:
return [ return [
{**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}}
@@ -65,10 +60,11 @@ async def api_lnurldevices_retrieve(
return "" return ""
@lnurldevice_ext.get("/api/v1/lnurlpos/{lnurldevice_id}") @lnurldevice_ext.get(
"/api/v1/lnurlpos/{lnurldevice_id}", dependencies=[Depends(get_key_type)]
)
async def api_lnurldevice_retrieve( async def api_lnurldevice_retrieve(
req: Request, req: Request,
wallet: WalletTypeInfo = Depends(get_key_type),
lnurldevice_id: str = Query(None), lnurldevice_id: str = Query(None),
): ):
lnurldevice = await get_lnurldevice(lnurldevice_id) lnurldevice = await get_lnurldevice(lnurldevice_id)
@@ -76,23 +72,18 @@ async def api_lnurldevice_retrieve(
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="lnurldevice does not exist" status_code=HTTPStatus.NOT_FOUND, detail="lnurldevice does not exist"
) )
if not lnurldevice.lnurl_toggle:
return {**lnurldevice.dict()}
return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}} return {**lnurldevice.dict(), **{"switches": lnurldevice.switches(req)}}
@lnurldevice_ext.delete("/api/v1/lnurlpos/{lnurldevice_id}") @lnurldevice_ext.delete(
async def api_lnurldevice_delete( "/api/v1/lnurlpos/{lnurldevice_id}", dependencies=[Depends(require_admin_key)]
wallet: WalletTypeInfo = Depends(require_admin_key), )
lnurldevice_id: str = Query(None), async def api_lnurldevice_delete(lnurldevice_id: str = Query(None)):
):
lnurldevice = await get_lnurldevice(lnurldevice_id) lnurldevice = await get_lnurldevice(lnurldevice_id)
if not lnurldevice: if not lnurldevice:
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="Wallet link does not exist." status_code=HTTPStatus.NOT_FOUND, detail="Wallet link does not exist."
) )
await delete_lnurldevice(lnurldevice_id) await delete_lnurldevice(lnurldevice_id)
return "", HTTPStatus.NO_CONTENT return "", HTTPStatus.NO_CONTENT

View File

@@ -92,7 +92,6 @@ exclude = """(?x)(
^lnbits/extensions/bleskomat. ^lnbits/extensions/bleskomat.
| ^lnbits/extensions/boltz. | ^lnbits/extensions/boltz.
| ^lnbits/extensions/livestream. | ^lnbits/extensions/livestream.
| ^lnbits/extensions/lnurldevice.
| ^lnbits/wallets/lnd_grpc_files. | ^lnbits/wallets/lnd_grpc_files.
)""" )"""