diff --git a/lnbits/extensions/boltcards/crud.py b/lnbits/extensions/boltcards/crud.py index 39ee3f40..0724ea04 100644 --- a/lnbits/extensions/boltcards/crud.py +++ b/lnbits/extensions/boltcards/crud.py @@ -114,8 +114,14 @@ async def get_card_by_external_id(external_id: str) -> Optional[Card]: return Card.parse_obj(card) -async def get_card_by_otp(otp: str) -> Optional[Card]: - row = await db.fetchone("SELECT * FROM boltcards.cards WHERE otp = ?", (otp,)) +async def get_card_by_otp(otp: str, half: bool = False) -> Optional[Card]: + if half and len(otp) == 16: + otp = "%" + otp + row = await db.fetchone( + "SELECT * FROM boltcards.cards WHERE otp LIKE ?", (otp,) + ) + else: + row = await db.fetchone("SELECT * FROM boltcards.cards WHERE otp = ?", (otp,)) if not row: return None diff --git a/lnbits/extensions/boltcards/lnurl.py b/lnbits/extensions/boltcards/lnurl.py index 320b1666..064bde2c 100644 --- a/lnbits/extensions/boltcards/lnurl.py +++ b/lnbits/extensions/boltcards/lnurl.py @@ -119,6 +119,9 @@ async def lnurl_callback( "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 diff --git a/lnbits/extensions/boltcards/views_api.py b/lnbits/extensions/boltcards/views_api.py index 2fc11dbc..d7f5cf7c 100644 --- a/lnbits/extensions/boltcards/views_api.py +++ b/lnbits/extensions/boltcards/views_api.py @@ -15,11 +15,13 @@ from .crud import ( delete_card, enable_disable_card, get_card, + get_card_by_otp, get_card_by_uid, get_cards, get_hits, get_refunds, update_card, + update_card_otp, ) from .models import CreateCardData @@ -111,6 +113,22 @@ async def enable_card( 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}") async def api_card_delete(card_id, wallet: WalletTypeInfo = Depends(require_admin_key)): card = await get_card(card_id)