lnbits-legend/lnbits/extensions/lnurlpos/lnurl.py
2021-11-03 14:41:36 +00:00

118 lines
3.5 KiB
Python

import json
import hashlib
import math
from lnurl import LnurlPayResponse, LnurlPayActionResponse, LnurlErrorResponse # type: ignore
from lnurl.types import LnurlPayMetadata
from lnbits.core.services import create_invoice
from hashlib import md5
from fastapi import Request
from fastapi.param_functions import Query
from . import lnurlpos_ext
from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException
from starlette.responses import HTMLResponse
from http import HTTPStatus
from fastapi.params import Depends
from fastapi.param_functions import Query
from .crud import (
get_lnurlpos,
create_lnurlpospayment,
get_lnurlpospayment,
update_lnurlpospayment,
)
from lnbits.utils.exchange_rates import fiat_amount_as_satoshis
@lnurlpos_ext.get(
"/api/v1/lnurl/{nonce}/{payload}/{pos_id}",
status_code=HTTPStatus.OK,
name="lnurlpos.lnurl_response",
)
async def lnurl_response(
request: Request,
nonce: str = Query(None),
pos_id: str = Query(None),
payload: str = Query(None),
):
pos = await get_lnurlpos(pos_id)
if not pos:
raise HTTPException(
status_code=HTTPStatus.NOT_FOUND, detail="lnurlpos not found."
)
nonce1 = bytes.fromhex(nonce)
payload1 = bytes.fromhex(payload)
h = hashlib.sha256(nonce1)
h.update(pos.key.encode())
s = h.digest()
res = bytearray(payload1)
for i in range(len(res)):
res[i] = res[i] ^ s[i]
decryptedAmount = float(int.from_bytes(res[2:6], "little") / 100)
decryptedPin = int.from_bytes(res[:2], "little")
if type(decryptedAmount) != float:
raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not an amount.")
price_msat = (
await fiat_amount_as_satoshis(decryptedAmount, pos.currency)
if pos.currency != "sat"
else pos.currency
) * 1000
lnurlpospayment = await create_lnurlpospayment(
posid=pos.id,
payload=payload,
sats=price_msat,
pin=decryptedPin,
payhash="payment_hash",
)
if not lnurlpospayment:
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN, detail="Could not create payment"
)
resp = LnurlPayResponse(
callback=request.url_for(
"lnurlpos.lnurl_callback", paymentid=lnurlpospayment.id
),
min_sendable=price_msat,
max_sendable=price_msat,
metadata=await pos.lnurlpay_metadata(),
)
return resp.dict()
@lnurlpos_ext.get(
"/api/v1/lnurl/cb/{paymentid}",
status_code=HTTPStatus.OK,
name="lnurlpos.lnurl_callback",
)
async def lnurl_callback(request: Request, paymentid: str = Query(None)):
print("lnurlpospayment")
lnurlpospayment = await get_lnurlpospayment(paymentid)
print(lnurlpospayment)
pos = await get_lnurlpos(lnurlpospayment.posid)
if not pos:
raise HTTPException(
status_code=HTTPStatus.FORBIDDEN, detail="lnurlpos not found."
)
payment_hash, payment_request = await create_invoice(
wallet_id=pos.wallet,
amount=int(lnurlpospayment.sats / 1000),
memo=pos.title,
description_hash=hashlib.sha256(
(await pos.lnurlpay_metadata()).encode("utf-8")
).digest(),
extra={"tag": "lnurlpos"},
)
lnurlpospayment = await update_lnurlpospayment(
lnurlpospayment_id=paymentid, payhash=payment_hash
)
resp = LnurlPayActionResponse(
pr=payment_request,
success_action=pos.success_action(paymentid, request),
routes=[],
)
return resp.dict()