mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2024-11-20 02:28:10 +01:00
reducing the PR
This commit is contained in:
parent
afe07ad0ba
commit
3aee76be39
@ -2,7 +2,7 @@ import asyncio
|
|||||||
import json
|
import json
|
||||||
from binascii import unhexlify
|
from binascii import unhexlify
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Dict, Optional, Tuple, Union
|
from typing import Dict, Optional, Tuple
|
||||||
from urllib.parse import parse_qs, urlparse
|
from urllib.parse import parse_qs, urlparse
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
@ -102,7 +102,6 @@ async def pay_invoice(
|
|||||||
extra: Optional[Dict] = None,
|
extra: Optional[Dict] = None,
|
||||||
description: str = "",
|
description: str = "",
|
||||||
conn: Optional[Connection] = None,
|
conn: Optional[Connection] = None,
|
||||||
webhook: Optional[Union[str, tuple]] = None,
|
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Pay a Lightning invoice.
|
Pay a Lightning invoice.
|
||||||
@ -232,35 +231,6 @@ async def pay_invoice(
|
|||||||
f"didn't receive checking_id from backend, payment may be stuck in database: {temp_id}"
|
f"didn't receive checking_id from backend, payment may be stuck in database: {temp_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
additionals = None
|
|
||||||
if type(webhook) is str:
|
|
||||||
webhook_url = webhook
|
|
||||||
elif type(webhook) is tuple:
|
|
||||||
webhook_url = webhook[0]
|
|
||||||
additionals = webhook[1]
|
|
||||||
else:
|
|
||||||
webhook_url = None
|
|
||||||
|
|
||||||
if webhook_url:
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
try:
|
|
||||||
json = {
|
|
||||||
"payment_hash": invoice.payment_hash,
|
|
||||||
"payment_request": payment_request,
|
|
||||||
"amount": int(invoice.amount_msat / 1000),
|
|
||||||
}
|
|
||||||
if type(additionals) is dict:
|
|
||||||
json.update(additionals)
|
|
||||||
|
|
||||||
r = await client.post(
|
|
||||||
webhook_url,
|
|
||||||
json=json,
|
|
||||||
timeout=40,
|
|
||||||
)
|
|
||||||
except Exception as exc:
|
|
||||||
# webhook fails shouldn't cause the lnurlw to fail since invoice is already paid
|
|
||||||
logger.error("Caught exception when dispatching webhook url:", exc)
|
|
||||||
|
|
||||||
return invoice.payment_hash
|
return invoice.payment_hash
|
||||||
|
|
||||||
|
|
||||||
|
@ -27,10 +27,9 @@ async def create_card(data: CreateCardData, wallet_id: str) -> Card:
|
|||||||
k0,
|
k0,
|
||||||
k1,
|
k1,
|
||||||
k2,
|
k2,
|
||||||
otp,
|
otp
|
||||||
webhook_url
|
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
""",
|
""",
|
||||||
(
|
(
|
||||||
card_id,
|
card_id,
|
||||||
@ -46,7 +45,6 @@ async def create_card(data: CreateCardData, wallet_id: str) -> Card:
|
|||||||
data.k1,
|
data.k1,
|
||||||
data.k2,
|
data.k2,
|
||||||
secrets.token_hex(16),
|
secrets.token_hex(16),
|
||||||
data.webhook_url,
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
card = await get_card(card_id)
|
card = await get_card(card_id)
|
||||||
@ -179,9 +177,6 @@ async def get_hit(hit_id: str) -> Optional[Hit]:
|
|||||||
|
|
||||||
|
|
||||||
async def get_hits(cards_ids: Union[str, List[str]]) -> List[Hit]:
|
async def get_hits(cards_ids: Union[str, List[str]]) -> List[Hit]:
|
||||||
if len(cards_ids) == 0:
|
|
||||||
return []
|
|
||||||
|
|
||||||
q = ",".join(["?"] * len(cards_ids))
|
q = ",".join(["?"] * len(cards_ids))
|
||||||
rows = await db.fetchall(
|
rows = await db.fetchall(
|
||||||
f"SELECT * FROM boltcards.hits WHERE card_id IN ({q})", (*cards_ids,)
|
f"SELECT * FROM boltcards.hits WHERE card_id IN ({q})", (*cards_ids,)
|
||||||
@ -276,9 +271,6 @@ async def get_refund(refund_id: str) -> Optional[Refund]:
|
|||||||
|
|
||||||
|
|
||||||
async def get_refunds(hits_ids: Union[str, List[str]]) -> List[Refund]:
|
async def get_refunds(hits_ids: Union[str, List[str]]) -> List[Refund]:
|
||||||
if len(hits_ids) == 0:
|
|
||||||
return []
|
|
||||||
|
|
||||||
q = ",".join(["?"] * len(hits_ids))
|
q = ",".join(["?"] * len(hits_ids))
|
||||||
rows = await db.fetchall(
|
rows = await db.fetchall(
|
||||||
f"SELECT * FROM boltcards.refunds WHERE hit_id IN ({q})", (*hits_ids,)
|
f"SELECT * FROM boltcards.refunds WHERE hit_id IN ({q})", (*hits_ids,)
|
||||||
|
@ -112,27 +112,11 @@ async def lnurl_callback(
|
|||||||
invoice = bolt11.decode(pr)
|
invoice = bolt11.decode(pr)
|
||||||
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))
|
||||||
try:
|
try:
|
||||||
webhook = (
|
|
||||||
(
|
|
||||||
card.webhook_url,
|
|
||||||
{
|
|
||||||
"notification": "card_payment",
|
|
||||||
"card_external_id": card.external_id,
|
|
||||||
"card_name": card.card_name,
|
|
||||||
"card_otp": card.otp[
|
|
||||||
-16:
|
|
||||||
], # actually only half of the OTP is sent (full otp reveals the keys)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if card.webhook_url
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
await pay_invoice(
|
await pay_invoice(
|
||||||
wallet_id=card.wallet,
|
wallet_id=card.wallet,
|
||||||
payment_request=pr,
|
payment_request=pr,
|
||||||
max_sat=card.tx_limit,
|
max_sat=card.tx_limit,
|
||||||
extra={"tag": "boltcard", "tag": hit.id},
|
extra={"tag": "boltcard", "tag": hit.id},
|
||||||
webhook=webhook,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return {"status": "OK"}
|
return {"status": "OK"}
|
||||||
|
@ -58,11 +58,3 @@ async def m001_initial(db):
|
|||||||
);
|
);
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def m002_add_webhook(db):
|
|
||||||
await db.execute(
|
|
||||||
"""
|
|
||||||
ALTER TABLE boltcards.cards ADD COLUMN webhook_url TEXT NOT NULL DEFAULT '';
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
@ -30,7 +30,6 @@ class Card(BaseModel):
|
|||||||
prev_k1: str
|
prev_k1: str
|
||||||
prev_k2: str
|
prev_k2: str
|
||||||
otp: str
|
otp: str
|
||||||
webhook_url: str
|
|
||||||
time: int
|
time: int
|
||||||
|
|
||||||
def from_row(cls, row: Row) -> "Card":
|
def from_row(cls, row: Row) -> "Card":
|
||||||
@ -57,7 +56,6 @@ class CreateCardData(BaseModel):
|
|||||||
prev_k0: str = Query(ZERO_KEY)
|
prev_k0: str = Query(ZERO_KEY)
|
||||||
prev_k1: str = Query(ZERO_KEY)
|
prev_k1: str = Query(ZERO_KEY)
|
||||||
prev_k2: str = Query(ZERO_KEY)
|
prev_k2: str = Query(ZERO_KEY)
|
||||||
webhook_url: str = Query(...)
|
|
||||||
|
|
||||||
|
|
||||||
class Hit(BaseModel):
|
class Hit(BaseModel):
|
||||||
|
@ -23,7 +23,6 @@ new Vue({
|
|||||||
cardDialog: {
|
cardDialog: {
|
||||||
show: false,
|
show: false,
|
||||||
data: {
|
data: {
|
||||||
webhook_url: '',
|
|
||||||
counter: 1,
|
counter: 1,
|
||||||
k0: '',
|
k0: '',
|
||||||
k1: '',
|
k1: '',
|
||||||
@ -273,8 +272,7 @@ new Vue({
|
|||||||
k1: card.k1,
|
k1: card.k1,
|
||||||
k2: card.k2,
|
k2: card.k2,
|
||||||
k3: card.k1,
|
k3: card.k1,
|
||||||
k4: card.k2,
|
k4: card.k2
|
||||||
webhook_url: card.webhook_url
|
|
||||||
}
|
}
|
||||||
this.qrCodeDialog.data_wipe = JSON.stringify({
|
this.qrCodeDialog.data_wipe = JSON.stringify({
|
||||||
action: 'wipe',
|
action: 'wipe',
|
||||||
|
@ -9,7 +9,7 @@ from lnbits.core.models import Payment
|
|||||||
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 create_refund, get_card, get_hit
|
from .crud import create_refund, get_hit
|
||||||
|
|
||||||
|
|
||||||
async def wait_for_paid_invoices():
|
async def wait_for_paid_invoices():
|
||||||
@ -36,25 +36,6 @@ async def on_invoice_paid(payment: Payment) -> None:
|
|||||||
)
|
)
|
||||||
await mark_webhook_sent(payment, 1)
|
await mark_webhook_sent(payment, 1)
|
||||||
|
|
||||||
card = await get_card(hit.card_id)
|
|
||||||
if card.webhook_url:
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
try:
|
|
||||||
r = await client.post(
|
|
||||||
card.webhook_url,
|
|
||||||
json={
|
|
||||||
"notification": "card_refund",
|
|
||||||
"payment_hash": payment.payment_hash,
|
|
||||||
"payment_request": payment.bolt11,
|
|
||||||
"card_external_id": card.external_id,
|
|
||||||
"card_name": card.card_name,
|
|
||||||
"amount": int(payment.amount / 1000),
|
|
||||||
},
|
|
||||||
timeout=40,
|
|
||||||
)
|
|
||||||
except Exception as exc:
|
|
||||||
logger.error("Caught exception when dispatching webhook url:", exc)
|
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
@ -324,14 +324,6 @@
|
|||||||
>Zero if you don't know.</q-tooltip
|
>Zero if you don't know.</q-tooltip
|
||||||
>
|
>
|
||||||
</q-input>
|
</q-input>
|
||||||
<q-input
|
|
||||||
filled
|
|
||||||
dense
|
|
||||||
v-model.number="cardDialog.data.webhook_url"
|
|
||||||
type="text"
|
|
||||||
label="Notification webhook"
|
|
||||||
>
|
|
||||||
</q-input>
|
|
||||||
<q-btn
|
<q-btn
|
||||||
unelevated
|
unelevated
|
||||||
color="primary"
|
color="primary"
|
||||||
@ -431,8 +423,6 @@
|
|||||||
<strong>Lock key:</strong> {{ qrCodeDialog.data.k0 }}<br />
|
<strong>Lock key:</strong> {{ qrCodeDialog.data.k0 }}<br />
|
||||||
<strong>Meta key:</strong> {{ qrCodeDialog.data.k1 }}<br />
|
<strong>Meta key:</strong> {{ qrCodeDialog.data.k1 }}<br />
|
||||||
<strong>File key:</strong> {{ qrCodeDialog.data.k2 }}<br />
|
<strong>File key:</strong> {{ qrCodeDialog.data.k2 }}<br />
|
||||||
<strong>Notification webhook:</strong> {{ qrCodeDialog.data.webhook_url
|
|
||||||
}}<br />
|
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Always backup all keys that you're trying to write on the card. Without
|
Always backup all keys that you're trying to write on the card. Without
|
||||||
|
@ -113,22 +113,6 @@ async def enable_card(
|
|||||||
return card.dict()
|
return card.dict()
|
||||||
|
|
||||||
|
|
||||||
@boltcards_ext.post("/api/v1/disablecard")
|
|
||||||
async def disble_card_with_otp(a):
|
|
||||||
if len(a) < 16:
|
|
||||||
raise HTTPException(detail="Invalid OTP.", status_code=HTTPStatus.BAD_REQUEST)
|
|
||||||
card = await get_card_by_otp(a, half=True)
|
|
||||||
if not card:
|
|
||||||
raise HTTPException(detail="No card found.", status_code=HTTPStatus.NOT_FOUND)
|
|
||||||
|
|
||||||
new_otp = secrets.token_hex(16)
|
|
||||||
await update_card_otp(new_otp, card.id)
|
|
||||||
|
|
||||||
card = await enable_disable_card(enable=False, id=card.id)
|
|
||||||
|
|
||||||
return {"status": "OK"}
|
|
||||||
|
|
||||||
|
|
||||||
@boltcards_ext.delete("/api/v1/cards/{card_id}")
|
@boltcards_ext.delete("/api/v1/cards/{card_id}")
|
||||||
async def api_card_delete(card_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
|
async def api_card_delete(card_id, wallet: WalletTypeInfo = Depends(require_admin_key)):
|
||||||
card = await get_card(card_id)
|
card = await get_card(card_id)
|
||||||
|
@ -3,6 +3,7 @@ import traceback
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
|
import httpx
|
||||||
import shortuuid # type: ignore
|
import shortuuid # type: ignore
|
||||||
from fastapi import HTTPException
|
from fastapi import HTTPException
|
||||||
from fastapi.param_functions import Query
|
from fastapi.param_functions import Query
|
||||||
@ -132,24 +133,29 @@ async def api_lnurl_callback(
|
|||||||
|
|
||||||
payment_request = pr
|
payment_request = pr
|
||||||
|
|
||||||
webhook = (
|
payment_hash = await pay_invoice(
|
||||||
(
|
|
||||||
link.webhook_url,
|
|
||||||
{
|
|
||||||
"lnurlw": link.id,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
if link.webhook_url
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
await pay_invoice(
|
|
||||||
wallet_id=link.wallet,
|
wallet_id=link.wallet,
|
||||||
payment_request=payment_request,
|
payment_request=payment_request,
|
||||||
max_sat=link.max_withdrawable,
|
max_sat=link.max_withdrawable,
|
||||||
extra={"tag": "withdraw"},
|
extra={"tag": "withdraw"},
|
||||||
webhook=webhook,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if link.webhook_url:
|
||||||
|
async with httpx.AsyncClient() as client:
|
||||||
|
try:
|
||||||
|
r = await client.post(
|
||||||
|
link.webhook_url,
|
||||||
|
json={
|
||||||
|
"payment_hash": payment_hash,
|
||||||
|
"payment_request": payment_request,
|
||||||
|
"lnurlw": link.id,
|
||||||
|
},
|
||||||
|
timeout=40,
|
||||||
|
)
|
||||||
|
except Exception as exc:
|
||||||
|
# webhook fails shouldn't cause the lnurlw to fail since invoice is already paid
|
||||||
|
logger.error("Caught exception when dispatching webhook url:", exc)
|
||||||
|
|
||||||
return {"status": "OK"}
|
return {"status": "OK"}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
Loading…
Reference in New Issue
Block a user