From 7bfc0848ef31f03342c6b016ebfd03e5eb67d429 Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 29 Aug 2022 14:18:18 +0100 Subject: [PATCH] Black/prettier --- lnbits/extensions/boltcards/__init__.py | 2 + lnbits/extensions/boltcards/config.json | 2 +- lnbits/extensions/boltcards/crud.py | 21 +- lnbits/extensions/boltcards/lnurl.py | 31 ++- lnbits/extensions/boltcards/models.py | 9 +- .../extensions/boltcards/static/js/index.js | 14 +- lnbits/extensions/boltcards/tasks.py | 7 +- .../templates/boltcards/_api_docs.html | 4 - .../boltcards/templates/boltcards/index.html | 193 ++++++++++-------- lnbits/extensions/boltcards/views_api.py | 14 +- 10 files changed, 161 insertions(+), 136 deletions(-) diff --git a/lnbits/extensions/boltcards/__init__.py b/lnbits/extensions/boltcards/__init__.py index fe99ee2e..11b8dd2d 100644 --- a/lnbits/extensions/boltcards/__init__.py +++ b/lnbits/extensions/boltcards/__init__.py @@ -16,9 +16,11 @@ boltcards_static_files = [ boltcards_ext: APIRouter = APIRouter(prefix="/boltcards", tags=["boltcards"]) + def boltcards_renderer(): return template_renderer(["lnbits/extensions/boltcards/templates"]) + from .lnurl import * # noqa from .tasks import * # noqa from .views import * # noqa diff --git a/lnbits/extensions/boltcards/config.json b/lnbits/extensions/boltcards/config.json index ef98a35a..e46070d3 100644 --- a/lnbits/extensions/boltcards/config.json +++ b/lnbits/extensions/boltcards/config.json @@ -2,5 +2,5 @@ "name": "Bolt Cards", "short_description": "Self custody Bolt Cards with one time LNURLw", "icon": "payment", - "contributors": ["iwarpbtc"] + "contributors": ["iwarpbtc", "arcbtc", "leesalminen"] } diff --git a/lnbits/extensions/boltcards/crud.py b/lnbits/extensions/boltcards/crud.py index c6b09694..1c48500d 100644 --- a/lnbits/extensions/boltcards/crud.py +++ b/lnbits/extensions/boltcards/crud.py @@ -116,7 +116,9 @@ async def delete_card(card_id: str) -> None: # Delete refunds refunds = await get_refunds([hit]) for refund in refunds: - await db.execute("DELETE FROM boltcards.refunds WHERE id = ?", (refund.hit_id,)) + await db.execute( + "DELETE FROM boltcards.refunds WHERE id = ?", (refund.hit_id,) + ) async def update_card_counter(counter: int, id: str): @@ -125,6 +127,7 @@ async def update_card_counter(counter: int, id: str): (counter, id), ) + async def enable_disable_card(enable: bool, id: str) -> Optional[Card]: row = await db.execute( "UPDATE boltcards.cards SET enable = ? WHERE id = ?", @@ -132,6 +135,7 @@ async def enable_disable_card(enable: bool, id: str) -> Optional[Card]: ) return await get_card(id) + async def update_card_otp(otp: str, id: str): await db.execute( "UPDATE boltcards.cards SET otp = ? WHERE id = ?", @@ -157,19 +161,23 @@ async def get_hits(cards_ids: Union[str, List[str]]) -> List[Hit]: return [Hit(**row) for row in rows] + async def get_hits_today(card_id: Union[str, List[str]]) -> List[Hit]: rows = await db.fetchall( - f"SELECT * FROM boltcards.hits WHERE card_id = ? AND time >= DATE('now') AND time < DATE('now', '+1 day')", (card_id,) + f"SELECT * FROM boltcards.hits WHERE card_id = ? AND time >= DATE('now') AND time < DATE('now', '+1 day')", + (card_id,), ) return [Hit(**row) for row in rows] + async def spend_hit(id: str): await db.execute( "UPDATE boltcards.hits SET spent = ? WHERE id = ?", (True, id), ) + async def create_hit(card_id, ip, useragent, old_ctr, new_ctr) -> Hit: hit_id = urlsafe_short_hash() await db.execute( @@ -201,6 +209,7 @@ async def create_hit(card_id, ip, useragent, old_ctr, new_ctr) -> Hit: assert hit, "Newly recorded hit couldn't be retrieved" return hit + async def create_refund(hit_id, refund_amount) -> Refund: refund_id = urlsafe_short_hash() await db.execute( @@ -224,17 +233,21 @@ async def create_refund(hit_id, refund_amount) -> Refund: assert refund, "Newly recorded hit couldn't be retrieved" return refund + async def get_refund(refund_id: str) -> Optional[Refund]: - row = await db.fetchone(f"SELECT * FROM boltcards.refunds WHERE id = ?", (refund_id)) + row = await db.fetchone( + f"SELECT * FROM boltcards.refunds WHERE id = ?", (refund_id) + ) if not row: return None refund = dict(**row) return Refund.parse_obj(refund) + async def get_refunds(hits_ids: Union[str, List[str]]) -> List[Refund]: q = ",".join(["?"] * len(hits_ids)) rows = await db.fetchall( f"SELECT * FROM boltcards.refunds WHERE hit_id IN ({q})", (*hits_ids,) ) - return [Refund(**row) for row in rows] \ No newline at end of file + return [Refund(**row) for row in rows] diff --git a/lnbits/extensions/boltcards/lnurl.py b/lnbits/extensions/boltcards/lnurl.py index 93ca6390..a1630e2b 100644 --- a/lnbits/extensions/boltcards/lnurl.py +++ b/lnbits/extensions/boltcards/lnurl.py @@ -59,7 +59,7 @@ async def api_scan(p, c, request: Request, card_uid: str = None): if not card: return {"status": "ERROR", "reason": "No card."} if not card.enable: - return {"status": "ERROR", "reason": "Card is disabled."} + return {"status": "ERROR", "reason": "Card is disabled."} try: card_uid, counter = decryptSUN(bytes.fromhex(p), bytes.fromhex(card.k1)) if card.uid.upper() != card_uid.hex().upper(): @@ -70,7 +70,7 @@ async def api_scan(p, c, request: Request, card_uid: str = None): return {"status": "ERROR", "reason": "Error decrypting card."} ctr_int = int.from_bytes(counter, "little") - + if ctr_int <= card.counter: return {"status": "ERROR", "reason": "This link is already used."} @@ -95,15 +95,14 @@ async def api_scan(p, c, request: Request, card_uid: str = None): lnurlpay = lnurl_encode(request.url_for("boltcards.lnurlp_response", hit_id=hit.id)) return { "tag": "withdrawRequest", - "callback": request.url_for( - "boltcards.lnurl_callback", hitid=hit.id - ), + "callback": request.url_for("boltcards.lnurl_callback", hitid=hit.id), "k1": hit.id, "minWithdrawable": 1 * 1000, "maxWithdrawable": card.tx_limit * 1000, "defaultDescription": f"Boltcard (refund address {lnurlpay})", } + @boltcards_ext.get( "/api/v1/lnurl/cb/{hitid}", status_code=HTTPStatus.OK, @@ -114,8 +113,8 @@ async def lnurl_callback( pr: str = Query(None), k1: str = Query(None), ): - hit = await get_hit(k1) - card = await get_card(hit.card_id) + hit = await get_hit(k1) + card = await get_card(hit.card_id) if not hit: return {"status": "ERROR", "reason": f"LNURL-pay record not found."} try: @@ -158,16 +157,18 @@ async def api_auth(a, request: Request): return response + ###############LNURLPAY REFUNDS################# + @boltcards_ext.get( "/api/v1/lnurlp/{hit_id}", response_class=HTMLResponse, name="boltcards.lnurlp_response", ) async def lnurlp_response(req: Request, hit_id: str = Query(None)): - hit = await get_hit(hit_id) - card = await get_card(hit.card_id) + hit = await get_hit(hit_id) + card = await get_card(hit.card_id) if not hit: return {"status": "ERROR", "reason": f"LNURL-pay record not found."} if not card.enable: @@ -190,8 +191,8 @@ async def lnurlp_response(req: Request, hit_id: str = Query(None)): async def lnurlp_callback( req: Request, hit_id: str = Query(None), amount: str = Query(None) ): - hit = await get_hit(hit_id) - card = await get_card(hit.card_id) + hit = await get_hit(hit_id) + card = await get_card(hit.card_id) if not hit: return {"status": "ERROR", "reason": f"LNURL-pay record not found."} @@ -199,14 +200,12 @@ async def lnurlp_callback( wallet_id=card.wallet, amount=int(amount) / 1000, memo=f"Refund {hit_id}", - unhashed_description=LnurlPayMetadata(json.dumps([["text/plain", "Refund"]])).encode("utf-8"), + unhashed_description=LnurlPayMetadata( + json.dumps([["text/plain", "Refund"]]) + ).encode("utf-8"), extra={"refund": hit_id}, ) payResponse = {"pr": payment_request, "successAction": success_action, "routes": []} return json.dumps(payResponse) - - - - diff --git a/lnbits/extensions/boltcards/models.py b/lnbits/extensions/boltcards/models.py index c1b113af..80e3b973 100644 --- a/lnbits/extensions/boltcards/models.py +++ b/lnbits/extensions/boltcards/models.py @@ -36,14 +36,13 @@ class Card(BaseModel): return cls(**dict(row)) def lnurl(self, req: Request) -> Lnurl: - url = req.url_for( - "boltcard.lnurl_response", device_id=self.id, _external=True - ) + url = req.url_for("boltcard.lnurl_response", device_id=self.id, _external=True) return lnurl_encode(url) async def lnurlpay_metadata(self) -> LnurlPayMetadata: return LnurlPayMetadata(json.dumps([["text/plain", self.title]])) + class CreateCardData(BaseModel): card_name: str = Query(...) uid: str = Query(...) @@ -58,6 +57,7 @@ class CreateCardData(BaseModel): prev_k1: str = Query(ZERO_KEY) prev_k2: str = Query(ZERO_KEY) + class Hit(BaseModel): id: str card_id: str @@ -72,6 +72,7 @@ class Hit(BaseModel): def from_row(cls, row: Row) -> "Hit": return cls(**dict(row)) + class Refund(BaseModel): id: str hit_id: str @@ -79,4 +80,4 @@ class Refund(BaseModel): time: int def from_row(cls, row: Row) -> "Refund": - return cls(**dict(row)) \ No newline at end of file + return cls(**dict(row)) diff --git a/lnbits/extensions/boltcards/static/js/index.js b/lnbits/extensions/boltcards/static/js/index.js index 8bd9c411..33704f3a 100644 --- a/lnbits/extensions/boltcards/static/js/index.js +++ b/lnbits/extensions/boltcards/static/js/index.js @@ -9,12 +9,11 @@ const mapCards = obj => { return obj } - new Vue({ el: '#vue', mixins: [windowMixin], data: function () { - return { + return { toggleAdvanced: false, nfcTagReading: false, cards: [], @@ -23,11 +22,12 @@ new Vue({ cardDialog: { show: false, data: { - counter:1, + counter: 1, k0: '', k1: '', k2: '', - card_name:''}, + card_name: '' + }, temp: {} }, cardsTable: { @@ -190,7 +190,7 @@ new Vue({ }) }) }, - openQrCodeDialog(cardId) { + openQrCodeDialog (cardId) { var card = _.findWhere(this.cards, {id: cardId}) this.qrCodeDialog.data = { link: window.location.origin + '/boltcards/api/v1/auth?a=' + card.otp, @@ -217,7 +217,7 @@ new Vue({ typeof this.cardDialog.data.card_name === 'string' && this.cardDialog.data.card_name.search('debug') > -1 - self.cardDialog.data.k0 = debugcard + self.cardDialog.data.k0 = debugcard ? '11111111111111111111111111111111' : genRanHex(32) @@ -352,7 +352,7 @@ new Vue({ }, exportRefundsCSV: function () { LNbits.utils.exportCSV(this.refundsTable.columns, this.refunds) - }, + } }, created: function () { if (this.g.user.wallets.length) { diff --git a/lnbits/extensions/boltcards/tasks.py b/lnbits/extensions/boltcards/tasks.py index 30a290e9..bfe4f257 100644 --- a/lnbits/extensions/boltcards/tasks.py +++ b/lnbits/extensions/boltcards/tasks.py @@ -27,8 +27,9 @@ async def on_invoice_paid(payment: Payment) -> None: if payment.extra.get("wh_status"): # this webhook has already been sent return - hit = await get_hit(payment.extra.get("tag")[7:len(payment.extra.get("tag"))]) + hit = await get_hit(payment.extra.get("tag")[7 : len(payment.extra.get("tag"))]) if hit: - refund = await create_refund(hit_id=hit.id, refund_amount=payment.extra.get("amount")) + refund = await create_refund( + hit_id=hit.id, refund_amount=payment.extra.get("amount") + ) await mark_webhook_sent(payment, 1) - diff --git a/lnbits/extensions/boltcards/templates/boltcards/_api_docs.html b/lnbits/extensions/boltcards/templates/boltcards/_api_docs.html index e67ba14b..be4e2ae8 100644 --- a/lnbits/extensions/boltcards/templates/boltcards/_api_docs.html +++ b/lnbits/extensions/boltcards/templates/boltcards/_api_docs.html @@ -15,10 +15,6 @@ >More details
- - Created by, - iWarp

diff --git a/lnbits/extensions/boltcards/templates/boltcards/index.html b/lnbits/extensions/boltcards/templates/boltcards/index.html index 96f4f994..2a613fda 100644 --- a/lnbits/extensions/boltcards/templates/boltcards/index.html +++ b/lnbits/extensions/boltcards/templates/boltcards/index.html @@ -7,12 +7,19 @@
-
-
+
+
Cards
- + Add card
@@ -53,32 +60,38 @@ icon="qr_code" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'" @click="openQrCodeDialog(props.row.id)" - >Card key credentials + >Card key credentials lnurl://...Click to copy, then add to NFC card - + lnurlLink + >lnurl://...Click to copy, then add to NFC card + {{ col.value }} - DISABLE + >DISABLE ENABLE + v-else + dense + @click="enableCard(props.row.wallet, props.row.id, true)" + color="green" + >ENABLE Edit card + >Edit card Deleting card will also delete all records + >Deleting card will also delete all records @@ -220,7 +237,7 @@ type="number" label="Max transaction (sats)" class="q-pr-sm" - > + >
+ filled + dense + emit-value + v-model.trim="cardDialog.data.card_name" + type="text" + label="Card name " + >
- - - Get from the card you'll use, using an NFC app - - + Get from the card you'll use, using an NFC app
Tap card to scan UID (coming soon) + outline + disable + color="grey" + icon="nfc" + :disable="nfcTagReading" + >Tap card to scan UID (coming soon) +
-
- - + -
- - - - - - Zero if you don't know. - +
+ + + + + + Zero if you don't know. + Generate keys -
+