Added enable disable card

This commit is contained in:
ben 2022-08-28 10:58:17 +01:00
parent 20dbd879b1
commit 977f9bb8c4
7 changed files with 92 additions and 14 deletions

View file

@ -19,12 +19,13 @@ async def create_card(data: CreateCardData, wallet_id: str) -> Card:
counter, counter,
tx_limit, tx_limit,
daily_limit, daily_limit,
enable,
k0, k0,
k1, k1,
k2, k2,
otp otp
) )
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
""", """,
( (
card_id, card_id,
@ -34,6 +35,7 @@ async def create_card(data: CreateCardData, wallet_id: str) -> Card:
data.counter, data.counter,
data.tx_limit, data.tx_limit,
data.daily_limit, data.daily_limit,
True,
data.k0, data.k0,
data.k1, data.k1,
data.k2, data.k2,
@ -104,7 +106,17 @@ 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
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
hits = await get_hits([card_id])
for hit in hits:
await db.execute("DELETE FROM boltcards.hits WHERE id = ?", (hit.id,))
# Delete refunds
refunds = await get_refunds([hit])
for refund in refunds:
await db.execute("DELETE FROM boltcards.refunds WHERE id = ?", (refund.hit_id,))
async def update_card_counter(counter: int, id: str): async def update_card_counter(counter: int, id: str):
@ -113,6 +125,12 @@ async def update_card_counter(counter: int, id: str):
(counter, id), (counter, id),
) )
async def enable_disable_card(enable: bool, id: str) -> Optional[Card]:
row = await db.execute(
"UPDATE boltcards.cards SET enable = ? WHERE id = ?",
(enable, id),
)
return await get_card(id)
async def update_card_otp(otp: str, id: str): async def update_card_otp(otp: str, id: str):
await db.execute( await db.execute(

View file

@ -57,6 +57,8 @@ async def api_scan(p, c, request: Request, card_id: str = None):
try: try:
card = await get_card_by_uid(card_uid) card = await get_card_by_uid(card_uid)
if not card.enable:
return {"status": "ERROR", "reason": "Card is disabled."}
card_uid, counter = decryptSUN(bytes.fromhex(p), bytes.fromhex(card.k1)) card_uid, counter = decryptSUN(bytes.fromhex(p), bytes.fromhex(card.k1))
if card.uid.upper() != card_uid.hex().upper(): if card.uid.upper() != card_uid.hex().upper():
return {"status": "ERROR", "reason": "Card UID mis-match."} return {"status": "ERROR", "reason": "Card UID mis-match."}
@ -173,6 +175,8 @@ async def lnurlp_response(req: Request, hit_id: str = Query(None)):
card = await get_card(hit.card_id) card = await get_card(hit.card_id)
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:
return {"status": "ERROR", "reason": "Card is disabled."}
payResponse = { payResponse = {
"tag": "payRequest", "tag": "payRequest",
"callback": req.url_for("boltcards.lnurlp_callback", hit_id=hit_id), "callback": req.url_for("boltcards.lnurlp_callback", hit_id=hit_id),

View file

@ -12,6 +12,7 @@ async def m001_initial(db):
counter INT NOT NULL DEFAULT 0, counter INT NOT NULL DEFAULT 0,
tx_limit TEXT NOT NULL, tx_limit TEXT NOT NULL,
daily_limit TEXT NOT NULL, daily_limit TEXT NOT NULL,
enable BOOL NOT NULL,
k0 TEXT NOT NULL DEFAULT '00000000000000000000000000000000', k0 TEXT NOT NULL DEFAULT '00000000000000000000000000000000',
k1 TEXT NOT NULL DEFAULT '00000000000000000000000000000000', k1 TEXT NOT NULL DEFAULT '00000000000000000000000000000000',
k2 TEXT NOT NULL DEFAULT '00000000000000000000000000000000', k2 TEXT NOT NULL DEFAULT '00000000000000000000000000000000',

View file

@ -22,6 +22,7 @@ class Card(BaseModel):
counter: int counter: int
tx_limit: int tx_limit: int
daily_limit: int daily_limit: int
enable: bool
k0: str k0: str
k1: str k1: str
k2: str k2: str
@ -49,6 +50,7 @@ class CreateCardData(BaseModel):
counter: int = Query(0) counter: int = Query(0)
tx_limit: int = Query(0) tx_limit: int = Query(0)
daily_limit: int = Query(0) daily_limit: int = Query(0)
enable: bool = Query(...)
k0: str = Query(ZERO_KEY) k0: str = Query(ZERO_KEY)
k1: str = Query(ZERO_KEY) k1: str = Query(ZERO_KEY)
k2: str = Query(ZERO_KEY) k2: str = Query(ZERO_KEY)

View file

@ -16,6 +16,7 @@ new Vue({
data: function () { data: function () {
return { return {
toggleAdvanced: false, toggleAdvanced: false,
nfcTagReading: false,
cards: [], cards: [],
hits: [], hits: [],
refunds: [], refunds: [],
@ -194,6 +195,7 @@ new Vue({
this.generateKeys() this.generateKeys()
}, },
generateKeys: function () { generateKeys: function () {
var self = this
const genRanHex = size => const genRanHex = size =>
[...Array(size)] [...Array(size)]
.map(() => Math.floor(Math.random() * 16).toString(16)) .map(() => Math.floor(Math.random() * 16).toString(16))
@ -203,20 +205,17 @@ new Vue({
typeof this.cardDialog.data.card_name === 'string' && typeof this.cardDialog.data.card_name === 'string' &&
this.cardDialog.data.card_name.search('debug') > -1 this.cardDialog.data.card_name.search('debug') > -1
this.cardDialog.data.k0 = debugcard self.cardDialog.data.k0 = debugcard
? '11111111111111111111111111111111' ? '11111111111111111111111111111111'
: genRanHex(32) : genRanHex(32)
this.$refs['k0'].value = this.cardDialog.data.k0
this.cardDialog.data.k1 = debugcard self.cardDialog.data.k1 = debugcard
? '22222222222222222222222222222222' ? '22222222222222222222222222222222'
: genRanHex(32) : genRanHex(32)
this.$refs['k1'].value = this.cardDialog.data.k1
this.cardDialog.data.k2 = debugcard self.cardDialog.data.k2 = debugcard
? '33333333333333333333333333333333' ? '33333333333333333333333333333333'
: genRanHex(32) : genRanHex(32)
this.$refs['k2'].value = this.cardDialog.data.k2
}, },
closeFormDialog: function () { closeFormDialog: function () {
this.cardDialog.data = {} this.cardDialog.data = {}
@ -288,6 +287,28 @@ new Vue({
LNbits.utils.notifyApiError(error) LNbits.utils.notifyApiError(error)
}) })
}, },
enableCard: function (wallet, card_id, enable) {
var self = this
let fullWallet = _.findWhere(self.g.user.wallets, {
id: wallet
})
LNbits.api
.request(
'GET',
'/boltcards/api/v1/cards/enable/' + card_id + '/' + enable,
fullWallet.adminkey
)
.then(function (response) {
console.log(response.data)
self.cards = _.reject(self.cards, function (obj) {
return obj.id == response.data.id
})
self.cards.push(mapCards(response.data))
})
.catch(function (error) {
LNbits.utils.notifyApiError(error)
})
},
deleteCard: function (cardId) { deleteCard: function (cardId) {
let self = this let self = this
let cards = _.findWhere(this.cards, {id: cardId}) let cards = _.findWhere(this.cards, {id: cardId})

View file

@ -65,6 +65,20 @@
<q-td v-for="col in props.cols" :key="col.name" :props="props"> <q-td v-for="col in props.cols" :key="col.name" :props="props">
{{ col.value }} {{ col.value }}
</q-td> </q-td>
<q-td auto-width>
<q-btn
v-if="props.row.enable"
dense
@click="enableCard(props.row.wallet, props.row.id, false)"
color="pink"
>DISABLE</q-btn>
<q-btn
v-else
dense
@click="enableCard(props.row.wallet, props.row.id, true)"
color="green"
>ENABLE</q-btn>
</q-td>
<q-td auto-width> <q-td auto-width>
<q-btn <q-btn
flat flat
@ -73,8 +87,7 @@
@click="updateCardDialog(props.row.id)" @click="updateCardDialog(props.row.id)"
icon="edit" icon="edit"
color="light-blue" color="light-blue"
> ><q-tooltip>Edit card</q-tooltip></q-btn>
</q-btn>
</q-td> </q-td>
<q-td auto-width> <q-td auto-width>
<q-btn <q-btn
@ -84,7 +97,7 @@
@click="deleteCard(props.row.id)" @click="deleteCard(props.row.id)"
icon="cancel" icon="cancel"
color="pink" color="pink"
></q-btn> ><q-tooltip>Deleting card will also delete all records</q-tooltip></q-btn>
</q-td> </q-td>
</q-tr> </q-tr>
</template> </template>
@ -255,7 +268,6 @@
<q-toggle <q-toggle
@click="toggleKeys"
v-model="toggleAdvanced" v-model="toggleAdvanced"
label="Show advanced options" label="Show advanced options"
></q-toggle> ></q-toggle>
@ -263,7 +275,7 @@
<q-input <q-input
filled filled
dense dense
ref="k0"
v-model.trim="cardDialog.data.k0" v-model.trim="cardDialog.data.k0"
type="text" type="text"
label="Card Auth key (K0)" label="Card Auth key (K0)"
@ -274,7 +286,7 @@
<q-input <q-input
filled filled
dense dense
ref="k1"
v-model.trim="cardDialog.data.k1" v-model.trim="cardDialog.data.k1"
type="text" type="text"
label="Card Meta key (K1)" label="Card Meta key (K1)"
@ -283,7 +295,7 @@
<q-input <q-input
filled filled
dense dense
ref="k2"
v-model.trim="cardDialog.data.k2" v-model.trim="cardDialog.data.k2"
type="text" type="text"
label="Card File key (K2)" label="Card File key (K2)"

View file

@ -21,6 +21,7 @@ from .crud import (
update_card, update_card,
update_card_counter, update_card_counter,
update_card_otp, update_card_otp,
enable_disable_card,
get_refunds, get_refunds,
) )
from .models import CreateCardData from .models import CreateCardData
@ -89,6 +90,25 @@ async def api_card_create_or_update(
card = await create_card(wallet_id=wallet.wallet.id, data=data) card = await create_card(wallet_id=wallet.wallet.id, data=data)
return card.dict() return card.dict()
@boltcards_ext.get("/api/v1/cards/enable/{card_id}/{enable}", status_code=HTTPStatus.OK)
async def enable_card(
card_id,
enable,
wallet: WalletTypeInfo = Depends(require_admin_key),
):
card = await get_card(card_id)
if not card:
raise HTTPException(
detail="No card found.", status_code=HTTPStatus.NOT_FOUND
)
if card.wallet != wallet.wallet.id:
raise HTTPException(
detail="Not your card.", status_code=HTTPStatus.FORBIDDEN
)
card = await enable_disable_card(enable=enable, id=card_id)
logger.debug(enable)
logger.debug(card)
return card.dict()
@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)):