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