Merge branch 'lnbits:main' into main

This commit is contained in:
Uthpala 2023-01-06 00:34:57 +01:00 committed by GitHub
commit 453d65a91d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
41 changed files with 221 additions and 174 deletions

View File

@ -88,7 +88,7 @@ class Payment(BaseModel):
preimage: str preimage: str
payment_hash: str payment_hash: str
expiry: Optional[float] expiry: Optional[float]
extra: Optional[Dict] = {} extra: Dict = {}
wallet_id: str wallet_id: str
webhook: Optional[str] webhook: Optional[str]
webhook_status: Optional[int] webhook_status: Optional[int]

View File

@ -1,5 +1,5 @@
import secrets import secrets
from datetime import date, datetime from datetime import datetime
from typing import List, Optional, Union from typing import List, Optional, Union
from lnbits.helpers import urlsafe_short_hash from lnbits.helpers import urlsafe_short_hash
@ -124,7 +124,6 @@ async def get_card_by_otp(otp: str) -> Optional[Card]:
async def delete_card(card_id: str) -> None: async def delete_card(card_id: str) -> None:
# Delete cards # Delete cards
card = await get_card(card_id)
await db.execute("DELETE FROM boltcards.cards WHERE id = ?", (card_id,)) await db.execute("DELETE FROM boltcards.cards WHERE id = ?", (card_id,))
# Delete hits # Delete hits
hits = await get_hits([card_id]) hits = await get_hits([card_id])
@ -146,7 +145,7 @@ async def update_card_counter(counter: int, id: str):
async def enable_disable_card(enable: bool, id: str) -> Optional[Card]: async def enable_disable_card(enable: bool, id: str) -> Optional[Card]:
row = await db.execute( await db.execute(
"UPDATE boltcards.cards SET enable = ? WHERE id = ?", "UPDATE boltcards.cards SET enable = ? WHERE id = ?",
(enable, id), (enable, id),
) )
@ -161,7 +160,7 @@ async def update_card_otp(otp: str, id: str):
async def get_hit(hit_id: str) -> Optional[Hit]: async def get_hit(hit_id: str) -> Optional[Hit]:
row = await db.fetchone(f"SELECT * FROM boltcards.hits WHERE id = ?", (hit_id)) row = await db.fetchone(f"SELECT * FROM boltcards.hits WHERE id = ?", (hit_id,))
if not row: if not row:
return None return None
@ -182,7 +181,7 @@ async def get_hits(cards_ids: Union[str, List[str]]) -> List[Hit]:
return [Hit(**row) for row in rows] return [Hit(**row) for row in rows]
async def get_hits_today(card_id: str) -> Optional[Hit]: async def get_hits_today(card_id: str) -> List[Hit]:
rows = await db.fetchall( rows = await db.fetchall(
f"SELECT * FROM boltcards.hits WHERE card_id = ?", f"SELECT * FROM boltcards.hits WHERE card_id = ?",
(card_id,), (card_id,),
@ -259,7 +258,7 @@ async def create_refund(hit_id, refund_amount) -> Refund:
async def get_refund(refund_id: str) -> Optional[Refund]: async def get_refund(refund_id: str) -> Optional[Refund]:
row = await db.fetchone( row = await db.fetchone(
f"SELECT * FROM boltcards.refunds WHERE id = ?", (refund_id) f"SELECT * FROM boltcards.refunds WHERE id = ?", (refund_id,)
) )
if not row: if not row:
return None return None
@ -267,7 +266,7 @@ async def get_refund(refund_id: str) -> Optional[Refund]:
return Refund.parse_obj(refund) return Refund.parse_obj(refund)
async def get_refunds(hits_ids: Union[str, List[str]]) -> List[Refund]: async def get_refunds(hits_ids: List[Hit]) -> List[Refund]:
if len(hits_ids) == 0: if len(hits_ids) == 0:
return [] return []

View File

@ -3,13 +3,9 @@ import secrets
from http import HTTPStatus from http import HTTPStatus
from urllib.parse import urlparse from urllib.parse import urlparse
from fastapi import Request from fastapi import HTTPException, Query, Request
from fastapi.param_functions import Query from lnurl import encode as lnurl_encode
from fastapi.params import Depends, Query from lnurl.types import LnurlPayMetadata
from lnurl import encode as lnurl_encode # type: ignore
from lnurl.types import LnurlPayMetadata # type: ignore
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse
from lnbits import bolt11 from lnbits import bolt11
@ -28,14 +24,13 @@ from .crud import (
update_card_counter, update_card_counter,
update_card_otp, update_card_otp,
) )
from .models import CreateCardData
from .nxp424 import decryptSUN, getSunMAC from .nxp424 import decryptSUN, getSunMAC
###############LNURLWITHDRAW################# ###############LNURLWITHDRAW#################
# /boltcards/api/v1/scan?p=00000000000000000000000000000000&c=0000000000000000 # /boltcards/api/v1/scan?p=00000000000000000000000000000000&c=0000000000000000
@boltcards_ext.get("/api/v1/scan/{external_id}") @boltcards_ext.get("/api/v1/scan/{external_id}")
async def api_scan(p, c, request: Request, external_id: str = None): async def api_scan(p, c, request: Request, external_id: str = Query(None)):
# some wallets send everything as lower case, no bueno # some wallets send everything as lower case, no bueno
p = p.upper() p = p.upper()
c = c.upper() c = c.upper()
@ -63,6 +58,7 @@ async def api_scan(p, c, request: Request, external_id: str = None):
await update_card_counter(ctr_int, card.id) await update_card_counter(ctr_int, card.id)
# gathering some info for hit record # gathering some info for hit record
assert request.client
ip = request.client.host ip = request.client.host
if "x-real-ip" in request.headers: if "x-real-ip" in request.headers:
ip = request.headers["x-real-ip"] ip = request.headers["x-real-ip"]
@ -95,7 +91,6 @@ async def api_scan(p, c, request: Request, external_id: str = None):
name="boltcards.lnurl_callback", name="boltcards.lnurl_callback",
) )
async def lnurl_callback( async def lnurl_callback(
request: Request,
pr: str = Query(None), pr: str = Query(None),
k1: str = Query(None), k1: str = Query(None),
): ):
@ -120,7 +115,9 @@ async def lnurl_callback(
return {"status": "ERROR", "reason": "Failed to decode payment request"} return {"status": "ERROR", "reason": "Failed to decode payment request"}
card = await get_card(hit.card_id) card = await get_card(hit.card_id)
assert card
hit = await spend_hit(id=hit.id, amount=int(invoice.amount_msat / 1000)) hit = await spend_hit(id=hit.id, amount=int(invoice.amount_msat / 1000))
assert hit
try: try:
await pay_invoice( await pay_invoice(
wallet_id=card.wallet, wallet_id=card.wallet,
@ -155,7 +152,7 @@ async def api_auth(a, request: Request):
response = { response = {
"card_name": card.card_name, "card_name": card.card_name,
"id": 1, "id": str(1),
"k0": card.k0, "k0": card.k0,
"k1": card.k1, "k1": card.k1,
"k2": card.k2, "k2": card.k2,
@ -163,7 +160,7 @@ async def api_auth(a, request: Request):
"k4": card.k2, "k4": card.k2,
"lnurlw_base": "lnurlw://" + lnurlw_base, "lnurlw_base": "lnurlw://" + lnurlw_base,
"protocol_name": "new_bolt_card_response", "protocol_name": "new_bolt_card_response",
"protocol_version": 1, "protocol_version": str(1),
} }
return response return response
@ -179,7 +176,9 @@ async def api_auth(a, request: Request):
) )
async def lnurlp_response(req: Request, hit_id: str = Query(None)): async def lnurlp_response(req: Request, hit_id: str = Query(None)):
hit = await get_hit(hit_id) hit = await get_hit(hit_id)
assert hit
card = await get_card(hit.card_id) card = await get_card(hit.card_id)
assert card
if not hit: if not hit:
return {"status": "ERROR", "reason": f"LNURL-pay record not found."} return {"status": "ERROR", "reason": f"LNURL-pay record not found."}
if not card.enable: if not card.enable:
@ -199,17 +198,17 @@ async def lnurlp_response(req: Request, hit_id: str = Query(None)):
response_class=HTMLResponse, response_class=HTMLResponse,
name="boltcards.lnurlp_callback", name="boltcards.lnurlp_callback",
) )
async def lnurlp_callback( async def lnurlp_callback(hit_id: str = Query(None), amount: str = Query(None)):
req: Request, hit_id: str = Query(None), amount: str = Query(None)
):
hit = await get_hit(hit_id) hit = await get_hit(hit_id)
assert hit
card = await get_card(hit.card_id) card = await get_card(hit.card_id)
assert card
if not hit: if not hit:
return {"status": "ERROR", "reason": f"LNURL-pay record not found."} return {"status": "ERROR", "reason": f"LNURL-pay record not found."}
payment_hash, payment_request = await create_invoice( _, payment_request = await create_invoice(
wallet_id=card.wallet, wallet_id=card.wallet,
amount=int(amount) / 1000, amount=int(int(amount) / 1000),
memo=f"Refund {hit_id}", memo=f"Refund {hit_id}",
unhashed_description=LnurlPayMetadata( unhashed_description=LnurlPayMetadata(
json.dumps([["text/plain", "Refund"]]) json.dumps([["text/plain", "Refund"]])

View File

@ -1,14 +1,11 @@
import json
from sqlite3 import Row from sqlite3 import Row
from typing import Optional
from fastapi import Request from fastapi import Query, Request
from fastapi.params import Query
from lnurl import Lnurl from lnurl import Lnurl
from lnurl import encode as lnurl_encode # type: ignore from lnurl import encode as lnurl_encode
from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore from lnurl.types import LnurlPayMetadata
from lnurl.types import LnurlPayMetadata # type: ignore
from pydantic import BaseModel from pydantic import BaseModel
from pydantic.main import BaseModel
ZERO_KEY = "00000000000000000000000000000000" ZERO_KEY = "00000000000000000000000000000000"
@ -32,6 +29,7 @@ class Card(BaseModel):
otp: str otp: str
time: int time: int
@classmethod
def from_row(cls, row: Row) -> "Card": def from_row(cls, row: Row) -> "Card":
return cls(**dict(row)) return cls(**dict(row))
@ -40,7 +38,7 @@ class Card(BaseModel):
return lnurl_encode(url) return lnurl_encode(url)
async def lnurlpay_metadata(self) -> LnurlPayMetadata: async def lnurlpay_metadata(self) -> LnurlPayMetadata:
return LnurlPayMetadata(json.dumps([["text/plain", self.title]])) return LnurlPayMetadata(json.dumps([["text/plain", self.card_name]]))
class CreateCardData(BaseModel): class CreateCardData(BaseModel):
@ -69,6 +67,7 @@ class Hit(BaseModel):
amount: int amount: int
time: int time: int
@classmethod
def from_row(cls, row: Row) -> "Hit": def from_row(cls, row: Row) -> "Hit":
return cls(**dict(row)) return cls(**dict(row))
@ -79,5 +78,6 @@ class Refund(BaseModel):
refund_amount: int refund_amount: int
time: int time: int
@classmethod
def from_row(cls, row: Row) -> "Refund": def from_row(cls, row: Row) -> "Refund":
return cls(**dict(row)) return cls(**dict(row))

View File

@ -1,8 +1,6 @@
import asyncio import asyncio
import json import json
import httpx
from lnbits.core import db as core_db from lnbits.core import db as core_db
from lnbits.core.models import Payment from lnbits.core.models import Payment
from lnbits.helpers import get_current_extension_name from lnbits.helpers import get_current_extension_name
@ -21,22 +19,23 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if not payment.extra.get("refund"): if not payment.extra.get("refund"):
return return
if payment.extra.get("wh_status"): if payment.extra.get("wh_status"):
# this webhook has already been sent # this webhook has already been sent
return return
hit = await get_hit(payment.extra.get("refund"))
hit = await get_hit(str(payment.extra.get("refund")))
if hit: if hit:
refund = await create_refund( await create_refund(hit_id=hit.id, refund_amount=(payment.amount / 1000))
hit_id=hit.id, refund_amount=(payment.amount / 1000)
)
await mark_webhook_sent(payment, 1) await mark_webhook_sent(payment, 1)
async def mark_webhook_sent(payment: Payment, status: int) -> None: async def mark_webhook_sent(payment: Payment, status: int) -> None:
payment.extra["wh_status"] = status payment.extra["wh_status"] = status
await core_db.execute( await core_db.execute(

View File

@ -1,5 +1,4 @@
from fastapi import FastAPI, Request from fastapi import Depends, Request
from fastapi.params import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse

View File

@ -1,10 +1,6 @@
import secrets
from http import HTTPStatus from http import HTTPStatus
from fastapi.params import Depends, Query from fastapi import Depends, HTTPException, Query
from loguru import logger
from starlette.exceptions import HTTPException
from starlette.requests import Request
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
@ -15,13 +11,11 @@ from .crud import (
delete_card, delete_card,
enable_disable_card, enable_disable_card,
get_card, get_card,
get_card_by_otp,
get_card_by_uid, get_card_by_uid,
get_cards, get_cards,
get_hits, get_hits,
get_refunds, get_refunds,
update_card, update_card,
update_card_otp,
) )
from .models import CreateCardData from .models import CreateCardData
@ -33,7 +27,8 @@ async def api_cards(
wallet_ids = [g.wallet.id] wallet_ids = [g.wallet.id]
if all_wallets: if all_wallets:
wallet_ids = (await get_user(g.wallet.user)).wallet_ids user = await get_user(g.wallet.user)
wallet_ids = user.wallet_ids if user else []
return [card.dict() for card in await get_cards(wallet_ids)] return [card.dict() for card in await get_cards(wallet_ids)]
@ -41,9 +36,8 @@ async def api_cards(
@boltcards_ext.post("/api/v1/cards", status_code=HTTPStatus.CREATED) @boltcards_ext.post("/api/v1/cards", status_code=HTTPStatus.CREATED)
@boltcards_ext.put("/api/v1/cards/{card_id}", status_code=HTTPStatus.OK) @boltcards_ext.put("/api/v1/cards/{card_id}", status_code=HTTPStatus.OK)
async def api_card_create_or_update( async def api_card_create_or_update(
# req: Request,
data: CreateCardData, data: CreateCardData,
card_id: str = None, card_id: str = Query(None),
wallet: WalletTypeInfo = Depends(require_admin_key), wallet: WalletTypeInfo = Depends(require_admin_key),
): ):
try: try:
@ -95,6 +89,7 @@ async def api_card_create_or_update(
status_code=HTTPStatus.BAD_REQUEST, status_code=HTTPStatus.BAD_REQUEST,
) )
card = await create_card(wallet_id=wallet.wallet.id, data=data) card = await create_card(wallet_id=wallet.wallet.id, data=data)
assert card
return card.dict() return card.dict()
@ -110,6 +105,7 @@ async def enable_card(
if card.wallet != wallet.wallet.id: if card.wallet != wallet.wallet.id:
raise HTTPException(detail="Not your card.", status_code=HTTPStatus.FORBIDDEN) raise HTTPException(detail="Not your card.", status_code=HTTPStatus.FORBIDDEN)
card = await enable_disable_card(enable=enable, id=card_id) card = await enable_disable_card(enable=enable, id=card_id)
assert card
return card.dict() return card.dict()
@ -136,7 +132,8 @@ async def api_hits(
wallet_ids = [g.wallet.id] wallet_ids = [g.wallet.id]
if all_wallets: if all_wallets:
wallet_ids = (await get_user(g.wallet.user)).wallet_ids user = await get_user(g.wallet.user)
wallet_ids = user.wallet_ids if user else []
cards = await get_cards(wallet_ids) cards = await get_cards(wallet_ids)
cards_ids = [] cards_ids = []
@ -153,15 +150,13 @@ async def api_refunds(
wallet_ids = [g.wallet.id] wallet_ids = [g.wallet.id]
if all_wallets: if all_wallets:
wallet_ids = (await get_user(g.wallet.user)).wallet_ids user = await get_user(g.wallet.user)
wallet_ids = user.wallet_ids if user else []
cards = await get_cards(wallet_ids) cards = await get_cards(wallet_ids)
cards_ids = [] cards_ids = []
for card in cards: for card in cards:
cards_ids.append(card.id) cards_ids.append(card.id)
hits = await get_hits(cards_ids) hits = await get_hits(cards_ids)
hits_ids = []
for hit in hits:
hits_ids.append(hit.id)
return [refund.dict() for refund in await get_refunds(hits_ids)] return [refund.dict() for refund in await get_refunds(hits)]

View File

@ -28,6 +28,7 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if payment.extra and not payment.extra.get("tag") == "cashu": if payment.extra.get("tag") != "cashu":
return return
return return

View File

@ -24,12 +24,12 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
webhook = None if payment.extra.get("tag") != "copilot":
data = None
if not payment.extra or payment.extra.get("tag") != "copilot":
# not an copilot invoice # not an copilot invoice
return return
webhook = None
data = None
copilot = await get_copilot(payment.extra.get("copilotid", -1)) copilot = await get_copilot(payment.extra.get("copilotid", -1))
if not copilot: if not copilot:

View File

@ -122,7 +122,7 @@ async def get_mempool_info(endPoint: str, gerty) -> dict:
), ),
) )
return response.json() return response.json()
if int(time.time()) - row.time > 20: if float(time.time()) - row.time > 20:
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.get(gerty.mempool_endpoint + url) response = await client.get(gerty.mempool_endpoint + url)
await db.execute( await db.execute(

View File

@ -1,3 +1,6 @@
import time
async def m001_initial(db): async def m001_initial(db):
""" """
Initial Gertys table. Initial Gertys table.
@ -57,3 +60,46 @@ async def m005_add_gerty_model_col(db):
support for Gerty model col support for Gerty model col
""" """
await db.execute("ALTER TABLE gerty.gertys ADD COLUMN urls TEXT;") await db.execute("ALTER TABLE gerty.gertys ADD COLUMN urls TEXT;")
async def m006_add_gerty_model_col(db):
"""
Add UUID ID's to links and migrates existing data
"""
await db.execute("ALTER TABLE gerty.mempool RENAME TO mempool_old")
await db.execute(
f"""
CREATE TABLE gerty.mempool (
id TEXT PRIMARY KEY,
mempool_endpoint TEXT NOT NULL,
endpoint TEXT NOT NULL,
data TEXT NOT NULL,
time FLOAT
);
"""
)
for row in [
list(row) for row in await db.fetchall("SELECT * FROM gerty.mempool_old")
]:
await db.execute(
"""
INSERT INTO gerty.mempool (
id,
mempool_endpoint,
endpoint,
data,
time
)
VALUES (?, ?, ?, ?, ?)
""",
(
row[0],
row[1],
row[2],
row[3],
time.time(),
),
)
await db.execute("DROP TABLE gerty.mempool_old")

View File

@ -6,7 +6,7 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %}
v-if="fun_exchange_market_rate || fun_satoshi_quotes" v-if="fun_exchange_market_rate || fun_satoshi_quotes"
> >
<q-card <q-card
v-if="fun_exchange_market_rate" v-if="fun_exchange_market_rate['unit'] != ''"
unelevated unelevated
class="q-pa-sm" class="q-pa-sm"
style="background: none !important" style="background: none !important"
@ -96,7 +96,7 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %}
</p> </p>
</q-card-section> </q-card-section>
</q-card> </q-card>
<q-card class="q-pa-sm" v-if="url_checker" unelevated class="q-pa-sm"> <q-card class="q-pa-sm" v-if="url_checker[0]" unelevated class="q-pa-sm">
<q-card-section> <q-card-section>
<div class="text-h6">Servers to check</div> <div class="text-h6">Servers to check</div>
</q-card-section> </q-card-section>
@ -126,7 +126,7 @@ gertyname }}{% endraw %}{% endblock %}{% block page %} {% raw %}
v-else-if="item[1].value >= 300" v-else-if="item[1].value >= 300"
square square
size="sm" size="sm"
color="yellow" color="orange"
text-color="white" text-color="white"
icon="sentiment_dissatisfied" icon="sentiment_dissatisfied"
> >

View File

@ -25,9 +25,6 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if not payment.extra:
return
if payment.extra.get("tag") != "invoices": if payment.extra.get("tag") != "invoices":
return return

View File

@ -17,8 +17,8 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if payment.extra: if payment.extra.get("tag") != "jukebox":
if payment.extra.get("tag") != "jukebox": # not a jukebox invoice
# not a jukebox invoice return
return
await update_jukebox_payment(payment.payment_hash, paid=True) await update_jukebox_payment(payment.payment_hash, paid=True)

View File

@ -16,7 +16,7 @@ async def cloudflare_create_record(domain: Domains, ip: str):
"Content-Type": "application/json", "Content-Type": "application/json",
} }
cf_response = "" cf_response = {}
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
try: try:
r = await client.post( r = await client.post(
@ -31,9 +31,9 @@ async def cloudflare_create_record(domain: Domains, ip: str):
}, },
timeout=40, timeout=40,
) )
cf_response = json.loads(r.text) cf_response = r.json()
except AssertionError: except AssertionError:
cf_response = "Error occured" cf_response = {"error": "Error occured"}
return cf_response return cf_response
@ -53,3 +53,4 @@ async def cloudflare_deleterecord(domain: Domains, domain_id: str):
cf_response = r.text cf_response = r.text
except AssertionError: except AssertionError:
cf_response = "Error occured" cf_response = "Error occured"
return cf_response

View File

@ -128,6 +128,7 @@ async def get_addresses(wallet_ids: Union[str, List[str]]) -> List[Addresses]:
async def set_address_paid(payment_hash: str) -> Addresses: async def set_address_paid(payment_hash: str) -> Addresses:
address = await get_address(payment_hash) address = await get_address(payment_hash)
assert address
if address.paid == False: if address.paid == False:
await db.execute( await db.execute(
@ -146,6 +147,7 @@ async def set_address_paid(payment_hash: str) -> Addresses:
async def set_address_renewed(address_id: str, duration: int): async def set_address_renewed(address_id: str, duration: int):
address = await get_address(address_id) address = await get_address(address_id)
assert address
extend_duration = int(address.duration) + duration extend_duration = int(address.duration) + duration
await db.execute( await db.execute(

View File

@ -1,17 +1,9 @@
import hashlib
import json
from datetime import datetime, timedelta from datetime import datetime, timedelta
import httpx import httpx
from fastapi.params import Query from fastapi import Query, Request
from lnurl import ( # type: ignore from lnurl import LnurlErrorResponse
LnurlErrorResponse,
LnurlPayActionResponse,
LnurlPayResponse,
)
from loguru import logger from loguru import logger
from starlette.requests import Request
from starlette.responses import HTMLResponse
from . import lnaddress_ext from . import lnaddress_ext
from .crud import get_address, get_address_by_username, get_domain from .crud import get_address, get_address_by_username, get_domain
@ -52,6 +44,7 @@ async def lnurl_callback(address_id, amount: int = Query(...)):
amount_received = amount amount_received = amount
domain = await get_domain(address.domain) domain = await get_domain(address.domain)
assert domain
base_url = ( base_url = (
address.wallet_endpoint[:-1] address.wallet_endpoint[:-1]
@ -79,7 +72,7 @@ async def lnurl_callback(address_id, amount: int = Query(...)):
) )
r = call.json() r = call.json()
except AssertionError as e: except Exception:
return LnurlErrorResponse(reason="ERROR") return LnurlErrorResponse(reason="ERROR")
# resp = LnurlPayActionResponse(pr=r["payment_request"], routes=[]) # resp = LnurlPayActionResponse(pr=r["payment_request"], routes=[])

View File

@ -1,9 +1,9 @@
import json import json
from typing import Optional from typing import Optional
from fastapi.params import Query from fastapi import Query
from lnurl.types import LnurlPayMetadata from lnurl.types import LnurlPayMetadata
from pydantic.main import BaseModel from pydantic import BaseModel
class CreateDomain(BaseModel): class CreateDomain(BaseModel):

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
import httpx import httpx
from loguru import logger
from lnbits.core.models import Payment from lnbits.core.models import Payment
from lnbits.helpers import get_current_extension_name from lnbits.helpers import get_current_extension_name
@ -21,7 +22,9 @@ async def wait_for_paid_invoices():
async def call_webhook_on_paid(payment_hash): async def call_webhook_on_paid(payment_hash):
### Use webhook to notify about cloudflare registration ### Use webhook to notify about cloudflare registration
address = await get_address(payment_hash) address = await get_address(payment_hash)
assert address
domain = await get_domain(address.domain) domain = await get_domain(address.domain)
assert domain
if not domain.webhook: if not domain.webhook:
return return
@ -39,24 +42,23 @@ async def call_webhook_on_paid(payment_hash):
}, },
timeout=40, timeout=40,
) )
except AssertionError: r.raise_for_status()
webhook = None except Exception as e:
logger.error(f"lnaddress: error calling webhook on paid: {str(e)}")
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if payment.extra.get("tag") == "lnaddress":
if payment.extra.get("tag") == "lnaddress":
await payment.set_pending(False) await payment.set_pending(False)
await set_address_paid(payment_hash=payment.payment_hash) await set_address_paid(payment_hash=payment.payment_hash)
await call_webhook_on_paid(payment_hash=payment.payment_hash) await call_webhook_on_paid(payment_hash=payment.payment_hash)
elif payment.extra.get("tag") == "renew lnaddress": elif payment.extra.get("tag") == "renew lnaddress":
await payment.set_pending(False) await payment.set_pending(False)
await set_address_renewed( await set_address_renewed(
address_id=payment.extra["id"], duration=payment.extra["duration"] address_id=payment.extra["id"], duration=payment.extra["duration"]
) )
await call_webhook_on_paid(payment_hash=payment.payment_hash) await call_webhook_on_paid(payment_hash=payment.payment_hash)
else: else:
return return

View File

@ -1,10 +1,8 @@
from http import HTTPStatus from http import HTTPStatus
from urllib.parse import urlparse from urllib.parse import urlparse
from fastapi import Request from fastapi import Depends, HTTPException, Request
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 from starlette.responses import HTMLResponse
from lnbits.core.crud import get_wallet from lnbits.core.crud import get_wallet
@ -35,6 +33,7 @@ async def display(domain_id, request: Request):
await purge_addresses(domain_id) await purge_addresses(domain_id)
wallet = await get_wallet(domain.wallet) wallet = await get_wallet(domain.wallet)
assert wallet
url = urlparse(str(request.url)) url = urlparse(str(request.url))
return lnaddress_renderer().TemplateResponse( return lnaddress_renderer().TemplateResponse(

View File

@ -1,9 +1,7 @@
from http import HTTPStatus from http import HTTPStatus
from urllib.parse import urlparse from urllib.parse import urlparse
from fastapi import Request from fastapi import Depends, HTTPException, Query, Request
from fastapi.params import Depends, Query
from starlette.exceptions import HTTPException
from lnbits.core.crud import get_user from lnbits.core.crud import get_user
from lnbits.core.services import check_transaction_status, create_invoice from lnbits.core.services import check_transaction_status, create_invoice
@ -11,7 +9,7 @@ from lnbits.decorators import WalletTypeInfo, get_key_type
from lnbits.extensions.lnaddress.models import CreateAddress, CreateDomain from lnbits.extensions.lnaddress.models import CreateAddress, CreateDomain
from . import lnaddress_ext from . import lnaddress_ext
from .cloudflare import cloudflare_create_record, cloudflare_deleterecord from .cloudflare import cloudflare_create_record
from .crud import ( from .crud import (
check_address_available, check_address_available,
create_address, create_address,
@ -35,7 +33,8 @@ async def api_domains(
wallet_ids = [g.wallet.id] wallet_ids = [g.wallet.id]
if all_wallets: if all_wallets:
wallet_ids = (await get_user(g.wallet.user)).wallet_ids user = await get_user(g.wallet.user)
wallet_ids = user.wallet_ids if user else []
return [domain.dict() for domain in await get_domains(wallet_ids)] return [domain.dict() for domain in await get_domains(wallet_ids)]
@ -69,7 +68,7 @@ async def api_domain_create(
cf_response = await cloudflare_create_record(domain=domain, ip=root_url) cf_response = await cloudflare_create_record(domain=domain, ip=root_url)
if not cf_response or cf_response["success"] != True: if not cf_response or not cf_response["success"]:
await delete_domain(domain.id) await delete_domain(domain.id)
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, status_code=HTTPStatus.BAD_REQUEST,
@ -106,7 +105,8 @@ async def api_addresses(
wallet_ids = [g.wallet.id] wallet_ids = [g.wallet.id]
if all_wallets: if all_wallets:
wallet_ids = (await get_user(g.wallet.user)).wallet_ids user = await get_user(g.wallet.user)
wallet_ids = user.wallet_ids if user else []
return [address.dict() for address in await get_addresses(wallet_ids)] return [address.dict() for address in await get_addresses(wallet_ids)]
@ -227,7 +227,9 @@ async def api_lnaddress_make_address(
@lnaddress_ext.get("/api/v1/addresses/{payment_hash}") @lnaddress_ext.get("/api/v1/addresses/{payment_hash}")
async def api_address_send_address(payment_hash): async def api_address_send_address(payment_hash):
address = await get_address(payment_hash) address = await get_address(payment_hash)
assert address
domain = await get_domain(address.domain) domain = await get_domain(address.domain)
assert domain
try: try:
status = await check_transaction_status(domain.wallet, payment_hash) status = await check_transaction_status(domain.wallet, payment_hash)
is_paid = not status.pending is_paid = not status.pending

View File

@ -19,7 +19,7 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if not payment.extra or payment.extra.get("tag") != "lnticket": if payment.extra.get("tag") != "lnticket":
# not a lnticket invoice # not a lnticket invoice
return return

View File

@ -120,7 +120,11 @@ async def create_lnurldevicepayment(
payhash: Optional[str] = None, payhash: Optional[str] = None,
sats: Optional[int] = 0, sats: Optional[int] = 0,
) -> lnurldevicepayment: ) -> lnurldevicepayment:
lnurldevicepayment_id = urlsafe_short_hash() device = await get_lnurldevice(deviceid)
if device.device == "atm":
lnurldevicepayment_id = shortuuid.uuid(name=payload)
else:
lnurldevicepayment_id = urlsafe_short_hash()
await db.execute( await db.execute(
""" """
INSERT INTO lnurldevice.lnurldevicepayment ( INSERT INTO lnurldevice.lnurldevicepayment (

View File

@ -5,12 +5,14 @@ from http import HTTPStatus
from io import BytesIO from io import BytesIO
from typing import Optional from typing import Optional
import shortuuid
from embit import bech32, compact from embit import bech32, compact
from fastapi import Request from fastapi import Request
from fastapi.param_functions import Query from fastapi.param_functions import Query
from loguru import logger from loguru import logger
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from lnbits import bolt11
from lnbits.core.services import create_invoice from lnbits.core.services import create_invoice
from lnbits.core.views.api import pay_invoice from lnbits.core.views.api import pay_invoice
from lnbits.utils.exchange_rates import fiat_amount_as_satoshis from lnbits.utils.exchange_rates import fiat_amount_as_satoshis
@ -102,11 +104,6 @@ async def lnurl_v1_params(
"status": "ERROR", "status": "ERROR",
"reason": f"lnurldevice {device_id} not found on this server", "reason": f"lnurldevice {device_id} not found on this server",
} }
paymentcheck = await get_lnurlpayload(p)
if device.device == "atm":
if paymentcheck:
if paymentcheck.payhash != "payment_hash":
return {"status": "ERROR", "reason": f"Payment already claimed"}
if device.device == "switch": if device.device == "switch":
price_msat = ( price_msat = (
await fiat_amount_as_satoshis(float(profit), device.currency) await fiat_amount_as_satoshis(float(profit), device.currency)
@ -163,13 +160,21 @@ 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 create_lnurldevicepayment( lnurldevicepayment = await get_lnurldevicepayment(shortuuid.uuid(name=p))
deviceid=device.id, if lnurldevicepayment:
payload=p, logger.debug("lnurldevicepayment")
sats=price_msat * 1000, logger.debug(lnurldevicepayment)
pin=pin, logger.debug("lnurldevicepayment")
payhash="payment_hash", if lnurldevicepayment.payload == lnurldevicepayment.payhash:
) return {"status": "ERROR", "reason": f"Payment already claimed"}
else:
lnurldevicepayment = await create_lnurldevicepayment(
deviceid=device.id,
payload=p,
sats=price_msat * 1000,
pin=pin,
payhash="payment_hash",
)
if not lnurldevicepayment: if not lnurldevicepayment:
return {"status": "ERROR", "reason": "Could not create payment."} return {"status": "ERROR", "reason": "Could not create payment."}
return { return {
@ -222,15 +227,20 @@ async def lnurl_callback(
status_code=HTTPStatus.FORBIDDEN, detail="lnurldevice not found." status_code=HTTPStatus.FORBIDDEN, detail="lnurldevice not found."
) )
if device.device == "atm": if device.device == "atm":
if lnurldevicepayment.payload == lnurldevicepayment.payhash:
return {"status": "ERROR", "reason": f"Payment already claimed"}
if not pr: if not pr:
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.FORBIDDEN, detail="No payment request" 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: else:
if lnurldevicepayment.payload != k1: if lnurldevicepayment.payload != k1:
return {"status": "ERROR", "reason": "Bad K1"} return {"status": "ERROR", "reason": "Bad K1"}
if lnurldevicepayment.payhash != "payment_hash":
return {"status": "ERROR", "reason": f"Payment already claimed"}
lnurldevicepayment = await update_lnurldevicepayment( lnurldevicepayment = await update_lnurldevicepayment(
lnurldevicepayment_id=paymentid, payhash=lnurldevicepayment.payload lnurldevicepayment_id=paymentid, payhash=lnurldevicepayment.payload
) )

View File

@ -22,7 +22,7 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment): async def on_invoice_paid(payment: Payment):
if not payment.extra or payment.extra.get("tag") != "lnurlp": if payment.extra.get("tag") != "lnurlp":
return return
if payment.extra.get("wh_status"): if payment.extra.get("wh_status"):

View File

@ -23,9 +23,6 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if not payment.extra:
return
if payment.extra.get("tag") != "market": if payment.extra.get("tag") != "market":
return return

View File

@ -18,8 +18,6 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if not payment.extra:
return
if payment.extra.get("tag") != "nostrnip5": if payment.extra.get("tag") != "nostrnip5":
return return

View File

@ -12,14 +12,13 @@ from . import db
from .helpers import fetch_onchain_balance from .helpers import fetch_onchain_balance
from .models import Charges, CreateCharge, SatsPayThemes from .models import Charges, CreateCharge, SatsPayThemes
###############CHARGES##########################
async def create_charge(user: str, data: CreateCharge) -> Optional[Charges]:
async def create_charge(user: str, data: CreateCharge) -> Charges:
data = CreateCharge(**data.dict()) data = CreateCharge(**data.dict())
charge_id = urlsafe_short_hash() charge_id = urlsafe_short_hash()
if data.onchainwallet: if data.onchainwallet:
config = await get_config(user) config = await get_config(user)
assert config
data.extra = json.dumps( data.extra = json.dumps(
{"mempool_endpoint": config.mempool_endpoint, "network": config.network} {"mempool_endpoint": config.mempool_endpoint, "network": config.network}
) )
@ -92,7 +91,7 @@ async def update_charge(charge_id: str, **kwargs) -> Optional[Charges]:
return Charges.from_row(row) if row else None return Charges.from_row(row) if row else None
async def get_charge(charge_id: str) -> Charges: async def get_charge(charge_id: str) -> Optional[Charges]:
row = await db.fetchone("SELECT * FROM satspay.charges WHERE id = ?", (charge_id,)) row = await db.fetchone("SELECT * FROM satspay.charges WHERE id = ?", (charge_id,))
return Charges.from_row(row) if row else None return Charges.from_row(row) if row else None
@ -111,6 +110,7 @@ async def delete_charge(charge_id: str) -> None:
async def check_address_balance(charge_id: str) -> Optional[Charges]: async def check_address_balance(charge_id: str) -> Optional[Charges]:
charge = await get_charge(charge_id) charge = await get_charge(charge_id)
assert charge
if not charge.paid: if not charge.paid:
if charge.onchainaddress: if charge.onchainaddress:
@ -131,7 +131,7 @@ async def check_address_balance(charge_id: str) -> Optional[Charges]:
################## SETTINGS ################### ################## SETTINGS ###################
async def save_theme(data: SatsPayThemes, css_id: str = None): async def save_theme(data: SatsPayThemes, css_id: Optional[str]):
# insert or update # insert or update
if css_id: if css_id:
await db.execute( await db.execute(
@ -162,7 +162,7 @@ async def save_theme(data: SatsPayThemes, css_id: str = None):
return await get_theme(css_id) return await get_theme(css_id)
async def get_theme(css_id: str) -> SatsPayThemes: async def get_theme(css_id: str) -> Optional[SatsPayThemes]:
row = await db.fetchone("SELECT * FROM satspay.themes WHERE css_id = ?", (css_id,)) row = await db.fetchone("SELECT * FROM satspay.themes WHERE css_id = ?", (css_id,))
return SatsPayThemes.from_row(row) if row else None return SatsPayThemes.from_row(row) if row else None

View File

@ -32,6 +32,7 @@ def public_charge(charge: Charges):
async def call_webhook(charge: Charges): async def call_webhook(charge: Charges):
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
try: try:
assert charge.webhook
r = await client.post( r = await client.post(
charge.webhook, charge.webhook,
json=public_charge(charge), json=public_charge(charge),
@ -54,6 +55,8 @@ async def fetch_onchain_balance(charge: Charges):
if charge.config.network == "Testnet" if charge.config.network == "Testnet"
else charge.config.mempool_endpoint else charge.config.mempool_endpoint
) )
assert endpoint
assert charge.onchainaddress
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
r = await client.get(endpoint + "/api/address/" + charge.onchainaddress) r = await client.get(endpoint + "/api/address/" + charge.onchainaddress)
return r.json()["chain_stats"]["funded_txo_sum"] return r.json()["chain_stats"]["funded_txo_sum"]

View File

@ -22,10 +22,12 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if payment.extra.get("tag") != "charge": if payment.extra.get("tag") != "charge":
# not a charge invoice # not a charge invoice
return return
assert payment.memo
charge = await get_charge(payment.memo) charge = await get_charge(payment.memo)
if not charge: if not charge:
logger.error("this should never happen", payment) logger.error("this should never happen", payment)
@ -33,6 +35,7 @@ async def on_invoice_paid(payment: Payment) -> None:
await payment.set_pending(False) await payment.set_pending(False)
charge = await check_address_balance(charge_id=charge.id) charge = await check_address_balance(charge_id=charge.id)
assert charge
if charge.must_call_webhook(): if charge.must_call_webhook():
resp = await call_webhook(charge) resp = await call_webhook(charge)

View File

@ -1,10 +1,7 @@
from http import HTTPStatus from http import HTTPStatus
from fastapi import Response from fastapi import Depends, HTTPException, Request, Response
from fastapi.param_functions import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException
from starlette.requests import Request
from starlette.responses import HTMLResponse from starlette.responses import HTMLResponse
from lnbits.core.models import User from lnbits.core.models import User

View File

@ -1,9 +1,8 @@
import json import json
from http import HTTPStatus from http import HTTPStatus
from fastapi import Depends, Query from fastapi import Depends, HTTPException, Query
from loguru import logger from loguru import logger
from starlette.exceptions import HTTPException
from lnbits.decorators import ( from lnbits.decorators import (
WalletTypeInfo, WalletTypeInfo,
@ -29,8 +28,6 @@ from .crud import (
from .helpers import call_webhook, public_charge from .helpers import call_webhook, public_charge
from .models import CreateCharge, SatsPayThemes from .models import CreateCharge, SatsPayThemes
#############################CHARGES##########################
@satspay_ext.post("/api/v1/charge") @satspay_ext.post("/api/v1/charge")
async def api_charge_create( async def api_charge_create(
@ -38,6 +35,7 @@ async def api_charge_create(
): ):
try: try:
charge = await create_charge(user=wallet.wallet.user, data=data) charge = await create_charge(user=wallet.wallet.user, data=data)
assert charge
return { return {
**charge.dict(), **charge.dict(),
**{"time_elapsed": charge.time_elapsed}, **{"time_elapsed": charge.time_elapsed},
@ -51,13 +49,15 @@ async def api_charge_create(
) )
@satspay_ext.put("/api/v1/charge/{charge_id}") @satspay_ext.put(
"/api/v1/charge/{charge_id}", dependencies=[Depends(require_admin_key)]
)
async def api_charge_update( async def api_charge_update(
data: CreateCharge, data: CreateCharge,
wallet: WalletTypeInfo = Depends(require_admin_key), charge_id: str,
charge_id=None,
): ):
charge = await update_charge(charge_id=charge_id, data=data) charge = await update_charge(charge_id=charge_id, data=data)
assert charge
return charge.dict() return charge.dict()
@ -78,10 +78,8 @@ async def api_charges_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
return "" return ""
@satspay_ext.get("/api/v1/charge/{charge_id}") @satspay_ext.get("/api/v1/charge/{charge_id}", dependencies=[Depends(get_key_type)])
async def api_charge_retrieve( async def api_charge_retrieve(charge_id: str):
charge_id, wallet: WalletTypeInfo = Depends(get_key_type)
):
charge = await get_charge(charge_id) charge = await get_charge(charge_id)
if not charge: if not charge:
@ -97,8 +95,8 @@ async def api_charge_retrieve(
} }
@satspay_ext.delete("/api/v1/charge/{charge_id}") @satspay_ext.delete("/api/v1/charge/{charge_id}", dependencies=[Depends(get_key_type)])
async def api_charge_delete(charge_id, wallet: WalletTypeInfo = Depends(get_key_type)): async def api_charge_delete(charge_id: str):
charge = await get_charge(charge_id) charge = await get_charge(charge_id)
if not charge: if not charge:
@ -155,7 +153,7 @@ async def api_themes_save(
theme = await save_theme(css_id=css_id, data=data) theme = await save_theme(css_id=css_id, data=data)
else: else:
data.user = wallet.wallet.user data.user = wallet.wallet.user
theme = await save_theme(data=data) theme = await save_theme(data=data, css_id="no_id")
return theme return theme
@ -169,8 +167,8 @@ async def api_themes_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
return "" return ""
@satspay_ext.delete("/api/v1/themes/{theme_id}") @satspay_ext.delete("/api/v1/themes/{theme_id}", dependencies=[Depends(get_key_type)])
async def api_theme_delete(theme_id, wallet: WalletTypeInfo = Depends(get_key_type)): async def api_theme_delete(theme_id):
theme = await get_theme(theme_id) theme = await get_theme(theme_id)
if not theme: if not theme:

View File

@ -27,7 +27,7 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment): async def on_invoice_paid(payment: Payment):
# (avoid loops) # (avoid loops)
if payment.extra and payment.extra.get("tag") == "scrubed": if payment.extra.get("tag") == "scrubed":
# already scrubbed # already scrubbed
return return

View File

@ -20,7 +20,7 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if not payment.extra or payment.extra.get("tag") == "splitpayments": if payment.extra.get("tag") == "splitpayments":
# already a splitted payment, ignore # already a splitted payment, ignore
return return

View File

@ -25,15 +25,20 @@ async def get_charge_details(service_id):
These might be different depending for services implemented in the future. These might be different depending for services implemented in the future.
""" """
details = {"time": 1440}
service = await get_service(service_id) service = await get_service(service_id)
assert service
wallet_id = service.wallet wallet_id = service.wallet
wallet = await get_wallet(wallet_id) wallet = await get_wallet(wallet_id)
assert wallet
user = wallet.user user = wallet.user
details["user"] = user return {
details["lnbitswallet"] = wallet_id "time": 1440,
details["onchainwallet"] = service.onchain "user": user,
return details "lnbitswallet": wallet_id,
"onchainwallet": service.onchain,
}
async def create_donation( async def create_donation(
@ -71,7 +76,7 @@ async def create_donation(
return donation return donation
async def post_donation(donation_id: str) -> tuple: async def post_donation(donation_id: str) -> dict:
"""Post donations to their respective third party APIs """Post donations to their respective third party APIs
If the donation has already been posted, it will not be posted again. If the donation has already been posted, it will not be posted again.
@ -97,7 +102,6 @@ async def post_donation(donation_id: str) -> tuple:
} }
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.post(url, data=data) response = await client.post(url, data=data)
status = [s for s in list(HTTPStatus) if s == response.status_code][0]
elif service.servicename == "StreamElements": elif service.servicename == "StreamElements":
return {"message": "StreamElements not yet supported!"} return {"message": "StreamElements not yet supported!"}
else: else:

View File

@ -1,8 +1,8 @@
from sqlite3 import Row from sqlite3 import Row
from typing import Optional from typing import Optional
from fastapi.params import Query from fastapi import Query
from pydantic.main import BaseModel from pydantic import BaseModel
class CreateService(BaseModel): class CreateService(BaseModel):

View File

@ -1,6 +1,6 @@
from http import HTTPStatus from http import HTTPStatus
from fastapi.param_functions import Depends from fastapi import Depends
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.requests import Request from starlette.requests import Request

View File

@ -1,6 +1,6 @@
from http import HTTPStatus from http import HTTPStatus
from fastapi.params import Depends, Query from fastapi import Depends, Query
from starlette.exceptions import HTTPException from starlette.exceptions import HTTPException
from starlette.requests import Request from starlette.requests import Request
from starlette.responses import RedirectResponse from starlette.responses import RedirectResponse
@ -84,6 +84,8 @@ async def api_authenticate_service(
""" """
service = await get_service(service_id) service = await get_service(service_id)
assert service
if service.state != state: if service.state != state:
raise HTTPException( raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST, detail="State doesn't match!" status_code=HTTPStatus.BAD_REQUEST, detail="State doesn't match!"
@ -113,6 +115,7 @@ async def api_create_donation(data: CreateDonation, request: Request):
webhook_base = request.url.scheme + "://" + request.headers["Host"] webhook_base = request.url.scheme + "://" + request.headers["Host"]
service_id = data.service service_id = data.service
service = await get_service(service_id) service = await get_service(service_id)
assert service
charge_details = await get_charge_details(service.id) charge_details = await get_charge_details(service.id)
name = data.name if data.name else "Anonymous" name = data.name if data.name else "Anonymous"
@ -157,7 +160,8 @@ async def api_post_donation(request: Request, data: ValidateDonation):
@streamalerts_ext.get("/api/v1/services") @streamalerts_ext.get("/api/v1/services")
async def api_get_services(g: WalletTypeInfo = Depends(get_key_type)): async def api_get_services(g: WalletTypeInfo = Depends(get_key_type)):
"""Return list of all services assigned to wallet with given invoice key""" """Return list of all services assigned to wallet with given invoice key"""
wallet_ids = (await get_user(g.wallet.user)).wallet_ids user = await get_user(g.wallet.user)
wallet_ids = user.wallet_ids if user else []
services = [] services = []
for wallet_id in wallet_ids: for wallet_id in wallet_ids:
new_services = await get_services(wallet_id) new_services = await get_services(wallet_id)
@ -170,7 +174,8 @@ async def api_get_donations(g: WalletTypeInfo = Depends(get_key_type)):
"""Return list of all donations assigned to wallet with given invoice """Return list of all donations assigned to wallet with given invoice
key key
""" """
wallet_ids = (await get_user(g.wallet.user)).wallet_ids user = await get_user(g.wallet.user)
wallet_ids = user.wallet_ids if user else []
donations = [] donations = []
for wallet_id in wallet_ids: for wallet_id in wallet_ids:
new_donations = await get_donations(wallet_id) new_donations = await get_donations(wallet_id)

View File

@ -20,7 +20,7 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if not payment.extra or payment.extra.get("tag") != "lnsubdomain": if payment.extra.get("tag") != "lnsubdomain":
# not an lnurlp invoice # not an lnurlp invoice
return return

View File

@ -20,8 +20,6 @@ async def wait_for_paid_invoices():
async def on_invoice_paid(payment: Payment) -> None: async def on_invoice_paid(payment: Payment) -> None:
if not payment.extra:
return
if payment.extra.get("tag") != "tpos": if payment.extra.get("tag") != "tpos":
return return

View File

@ -91,12 +91,8 @@ files = "lnbits"
exclude = """(?x)( exclude = """(?x)(
^lnbits/extensions/bleskomat. ^lnbits/extensions/bleskomat.
| ^lnbits/extensions/boltz. | ^lnbits/extensions/boltz.
| ^lnbits/extensions/boltcards.
| ^lnbits/extensions/livestream. | ^lnbits/extensions/livestream.
| ^lnbits/extensions/lnaddress.
| ^lnbits/extensions/lnurldevice. | ^lnbits/extensions/lnurldevice.
| ^lnbits/extensions/satspay.
| ^lnbits/extensions/streamalerts.
| ^lnbits/extensions/watchonly. | ^lnbits/extensions/watchonly.
| ^lnbits/wallets/lnd_grpc_files. | ^lnbits/wallets/lnd_grpc_files.
)""" )"""