mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-02-24 22:58:46 +01:00
Merge branch 'bensbits' into ext-boltcards-2
This commit is contained in:
commit
d858a3c7cd
3 changed files with 59 additions and 227 deletions
|
@ -5,10 +5,10 @@ async def m001_initial(db):
|
|||
await db.execute(
|
||||
"""
|
||||
CREATE TABLE boltcards.cards (
|
||||
id TEXT PRIMARY KEY,
|
||||
id TEXT PRIMARY KEY UNIQUE,
|
||||
wallet TEXT NOT NULL,
|
||||
card_name TEXT NOT NULL,
|
||||
uid TEXT NOT NULL,
|
||||
uid TEXT NOT NULL UNIQUE,
|
||||
counter INT NOT NULL DEFAULT 0,
|
||||
tx_limit TEXT NOT NULL,
|
||||
daily_limit TEXT NOT NULL,
|
||||
|
@ -30,7 +30,7 @@ async def m001_initial(db):
|
|||
await db.execute(
|
||||
"""
|
||||
CREATE TABLE boltcards.hits (
|
||||
id TEXT PRIMARY KEY,
|
||||
id TEXT PRIMARY KEY UNIQUE,
|
||||
card_id TEXT NOT NULL,
|
||||
ip TEXT NOT NULL,
|
||||
spent BOOL NOT NULL DEFAULT True,
|
||||
|
@ -48,7 +48,7 @@ async def m001_initial(db):
|
|||
await db.execute(
|
||||
"""
|
||||
CREATE TABLE boltcards.refunds (
|
||||
id TEXT PRIMARY KEY,
|
||||
id TEXT PRIMARY KEY UNIQUE,
|
||||
hit_id TEXT NOT NULL,
|
||||
refund_amount INT NOT NULL,
|
||||
time TIMESTAMP NOT NULL DEFAULT """
|
||||
|
|
|
@ -12,33 +12,18 @@
|
|||
<h5 class="text-subtitle1 q-my-none">Cards</h5>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-btn
|
||||
round
|
||||
size="sm"
|
||||
icon="add"
|
||||
unelevated
|
||||
color="primary"
|
||||
@click="addCardOpen"
|
||||
>
|
||||
<q-btn round size="sm" icon="add" unelevated color="primary" @click="addCardOpen">
|
||||
<q-tooltip>Add card</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn flat color="grey" @click="exportCardsCSV"
|
||||
>Export to CSV</q-btn
|
||||
>
|
||||
<q-btn flat color="grey" @click="exportCardsCSV">Export to CSV</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<q-table
|
||||
dense
|
||||
flat
|
||||
:data="cards"
|
||||
row-key="id"
|
||||
:columns="cardsTable.columns"
|
||||
:pagination.sync="cardsTable.pagination"
|
||||
>
|
||||
<q-table dense flat :data="cards" row-key="id" :columns="cardsTable.columns"
|
||||
:pagination.sync="cardsTable.pagination">
|
||||
{% raw %}
|
||||
<template v-slot:header="props">
|
||||
<q-tr :props="props">
|
||||
|
@ -53,13 +38,8 @@
|
|||
<template v-slot:body="props">
|
||||
<q-tr :props="props">
|
||||
<q-td auto-width>
|
||||
<q-btn
|
||||
unelevated
|
||||
dense
|
||||
icon="qr_code"
|
||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||
@click="openQrCodeDialog(props.row.id)"
|
||||
>
|
||||
<q-btn unelevated dense icon="qr_code" :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||
@click="openQrCodeDialog(props.row.id)">
|
||||
<q-tooltip>Card key credentials</q-tooltip>
|
||||
</q-btn>
|
||||
</q-td>
|
||||
|
@ -67,45 +47,19 @@
|
|||
{{ col.value }}
|
||||
</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 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-btn
|
||||
flat
|
||||
dense
|
||||
size="xs"
|
||||
@click="updateCardDialog(props.row.id)"
|
||||
icon="edit"
|
||||
color="light-blue"
|
||||
>
|
||||
<q-btn flat dense size="xs" @click="updateCardDialog(props.row.id)" icon="edit" color="light-blue">
|
||||
<q-tooltip>Edit card</q-tooltip>
|
||||
</q-btn>
|
||||
</q-td>
|
||||
<q-td auto-width>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
size="xs"
|
||||
@click="deleteCard(props.row.id)"
|
||||
icon="cancel"
|
||||
color="pink"
|
||||
>
|
||||
<q-tooltip
|
||||
>Deleting card will also delete all records</q-tooltip
|
||||
>
|
||||
<q-btn flat dense size="xs" @click="deleteCard(props.row.id)" icon="cancel" color="pink">
|
||||
<q-tooltip>Deleting card will also delete all records</q-tooltip>
|
||||
</q-btn>
|
||||
</q-td>
|
||||
</q-tr>
|
||||
|
@ -121,19 +75,11 @@
|
|||
<h5 class="text-subtitle1 q-my-none">Hits</h5>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn flat color="grey" @click="exportCardsCSV"
|
||||
>Export to CSV</q-btn
|
||||
>
|
||||
<q-btn flat color="grey" @click="exportCardsCSV">Export to CSV</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<q-table
|
||||
dense
|
||||
flat
|
||||
:data="hits"
|
||||
row-key="id"
|
||||
:columns="hitsTable.columns"
|
||||
:pagination.sync="hitsTable.pagination"
|
||||
>
|
||||
<q-table dense flat :data="hits" row-key="id" :columns="hitsTable.columns"
|
||||
:pagination.sync="hitsTable.pagination">
|
||||
{% raw %}
|
||||
<template v-slot:header="props">
|
||||
<q-tr :props="props">
|
||||
|
@ -160,19 +106,11 @@
|
|||
<h5 class="text-subtitle1 q-my-none">Refunds</h5>
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<q-btn flat color="grey" @click="exportRefundsCSV"
|
||||
>Export to CSV</q-btn
|
||||
>
|
||||
<q-btn flat color="grey" @click="exportRefundsCSV">Export to CSV</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
<q-table
|
||||
dense
|
||||
flat
|
||||
:data="refunds"
|
||||
row-key="id"
|
||||
:columns="refundsTable.columns"
|
||||
:pagination.sync="refundsTable.pagination"
|
||||
>
|
||||
<q-table dense flat :data="refunds" row-key="id" :columns="refundsTable.columns"
|
||||
:pagination.sync="refundsTable.pagination">
|
||||
{% raw %}
|
||||
<template v-slot:header="props">
|
||||
<q-tr :props="props">
|
||||
|
@ -209,148 +147,55 @@
|
|||
<q-dialog v-model="cardDialog.show" position="top" @hide="closeFormDialog">
|
||||
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
||||
<q-form @submit="sendFormData" class="q-gutter-md">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
v-model="cardDialog.data.wallet"
|
||||
:options="g.user.walletOptions"
|
||||
label="Wallet *"
|
||||
>
|
||||
<q-select filled dense emit-value v-model="cardDialog.data.wallet" :options="g.user.walletOptions"
|
||||
label="Wallet *">
|
||||
</q-select>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
v-model.trim="cardDialog.data.tx_limit"
|
||||
type="number"
|
||||
label="Max transaction (sats)"
|
||||
class="q-pr-sm"
|
||||
></q-input>
|
||||
<q-input filled dense emit-value v-model.trim="cardDialog.data.tx_limit" type="number"
|
||||
label="Max transaction (sats)" class="q-pr-sm"></q-input>
|
||||
</div>
|
||||
<div class="col">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
v-model.trim="cardDialog.data.daily_limit"
|
||||
type="number"
|
||||
label="Daily limit (sats)"
|
||||
></q-input>
|
||||
<q-input filled dense emit-value v-model.trim="cardDialog.data.daily_limit" type="number"
|
||||
label="Daily limit (sats)"></q-input>
|
||||
</div>
|
||||
</div>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
v-model.trim="cardDialog.data.card_name"
|
||||
type="text"
|
||||
label="Card name "
|
||||
>
|
||||
<q-input filled dense emit-value v-model.trim="cardDialog.data.card_name" type="text" label="Card name ">
|
||||
</q-input>
|
||||
<div class="row">
|
||||
<div class="col-10">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
v-model.trim="cardDialog.data.uid"
|
||||
type="text"
|
||||
label="Card UID "
|
||||
>
|
||||
<q-tooltip
|
||||
>Get from the card you'll use, using an NFC app</q-tooltip
|
||||
>
|
||||
<q-input filled dense emit-value v-model.trim="cardDialog.data.uid" type="text" label="Card UID ">
|
||||
<q-tooltip>Get from the card you'll use, using an NFC app</q-tooltip>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="col-2 q-pl-sm">
|
||||
<q-btn
|
||||
outline
|
||||
disable
|
||||
color="grey"
|
||||
icon="nfc"
|
||||
:disable="nfcTagReading"
|
||||
@click="readNfcTag()"
|
||||
>
|
||||
<q-btn outline disable color="grey" icon="nfc" :disable="nfcTagReading" @click="readNfcTag()">
|
||||
<q-tooltip>Tap card to scan UID</q-tooltip>
|
||||
</q-btn>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-toggle
|
||||
v-model="toggleAdvanced"
|
||||
label="Show advanced options"
|
||||
></q-toggle>
|
||||
<q-toggle v-model="toggleAdvanced" label="Show advanced options"></q-toggle>
|
||||
<div v-show="toggleAdvanced">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="cardDialog.data.k0"
|
||||
type="text"
|
||||
label="Card Auth key (K0)"
|
||||
hint="Used to authentificate with the card (16 bytes in HEX). "
|
||||
@randomkey
|
||||
>
|
||||
<q-input filled dense v-model.trim="cardDialog.data.k0" type="text" label="Card Auth key (K0)"
|
||||
hint="Used to authentificate with the card (16 bytes in HEX). " @randomkey>
|
||||
</q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="cardDialog.data.k1"
|
||||
type="text"
|
||||
label="Card Meta key (K1)"
|
||||
hint="Used for encypting of the message (16 bytes in HEX)."
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="cardDialog.data.k2"
|
||||
type="text"
|
||||
label="Card File key (K2)"
|
||||
hint="Used for CMAC of the message (16 bytes in HEX)."
|
||||
>
|
||||
<q-input filled dense v-model.trim="cardDialog.data.k1" type="text" label="Card Meta key (K1)"
|
||||
hint="Used for encypting of the message (16 bytes in HEX)."></q-input>
|
||||
<q-input filled dense v-model.trim="cardDialog.data.k2" type="text" label="Card File key (K2)"
|
||||
hint="Used for CMAC of the message (16 bytes in HEX).">
|
||||
</q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.number="cardDialog.data.counter"
|
||||
type="number"
|
||||
label="Initial counter"
|
||||
>
|
||||
<q-tooltip class="bg-grey-8" anchor="bottom left" self="top left"
|
||||
>Zero if you don't know.</q-tooltip
|
||||
>
|
||||
<q-input filled dense v-model.number="cardDialog.data.counter" type="number" label="Initial counter">
|
||||
<q-tooltip class="bg-grey-8" anchor="bottom left" self="top left">Zero if you don't know.</q-tooltip>
|
||||
</q-input>
|
||||
<q-btn
|
||||
unelevated
|
||||
color="primary"
|
||||
class="q-ml-auto"
|
||||
v-on:click="generateKeys"
|
||||
v-on:click.right="debugKeys"
|
||||
v-el:keybtn
|
||||
>Generate keys</q-btn
|
||||
>
|
||||
<q-btn unelevated color="primary" class="q-ml-auto" v-on:click="generateKeys" v-on:click.right="debugKeys"
|
||||
v-el:keybtn>Generate keys</q-btn>
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn
|
||||
v-if="cardDialog.data.id"
|
||||
unelevated
|
||||
color="primary"
|
||||
type="submit"
|
||||
>Update Card</q-btn
|
||||
>
|
||||
<q-btn
|
||||
v-else
|
||||
unelevated
|
||||
color="primary"
|
||||
:disable="cardDialog.data.uid == null"
|
||||
type="submit"
|
||||
>Create Card
|
||||
<q-btn v-if="cardDialog.data.id" unelevated color="primary" type="submit">Update Card</q-btn>
|
||||
<q-btn v-else unelevated color="primary" :disable="cardDialog.data.uid == null" type="submit">Create Card
|
||||
</q-btn>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
|
||||
>Cancel</q-btn
|
||||
>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Cancel</q-btn>
|
||||
</div>
|
||||
</q-form>
|
||||
</q-card>
|
||||
|
@ -360,11 +205,7 @@
|
|||
<q-card v-if="qrCodeDialog.data" class="q-pa-lg lnbits__dialog-card">
|
||||
{% raw %}
|
||||
<q-responsive :ratio="1" class="q-mx-xl q-mb-md">
|
||||
<qrcode
|
||||
:value="qrCodeDialog.data.link"
|
||||
:options="{width: 800}"
|
||||
class="rounded-borders"
|
||||
></qrcode>
|
||||
<qrcode :value="qrCodeDialog.data.link" :options="{width: 800}" class="rounded-borders"></qrcode>
|
||||
</q-responsive>
|
||||
<p style="word-break: break-all" class="text-center">
|
||||
(Keys for bolt-nfc-android-app)
|
||||
|
@ -375,27 +216,14 @@
|
|||
<strong>Lock key:</strong> {{ qrCodeDialog.data.k0 }}<br />
|
||||
<strong>Meta key:</strong> {{ qrCodeDialog.data.k1 }}<br />
|
||||
<strong>File key:</strong> {{ qrCodeDialog.data.k2 }}<br />
|
||||
</p>
|
||||
<br />
|
||||
|
||||
<q-btn
|
||||
unelevated
|
||||
outline
|
||||
color="grey"
|
||||
@click="copyText(lnurlLink + qrCodeDialog.data.uid)"
|
||||
label="Base url (LNURL://)"
|
||||
>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
unelevated
|
||||
outline
|
||||
color="grey"
|
||||
@click="copyText(qrCodeDialog.data.link)"
|
||||
label="Keys/Auth link"
|
||||
>
|
||||
</p><br />
|
||||
|
||||
<q-btn unelevated outline color="grey" @click="copyText(lnurlLink + qrCodeDialog.data.uid)" label="Base url (LNURL://)">
|
||||
</q-btn>
|
||||
<q-btn unelevated outline color="grey" @click="copyText(qrCodeDialog.data.link)" label="Keys/Auth link">
|
||||
</q-btn>
|
||||
<q-tooltip>Click to copy, then add to NFC card</q-tooltip>
|
||||
|
||||
|
||||
{% endraw %}
|
||||
<div class="row q-mt-lg q-gutter-sm">
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto">Close</q-btn>
|
||||
|
@ -406,4 +234,4 @@
|
|||
|
||||
{% endblock %} {% block scripts %} {{ window_vars(user) }}
|
||||
<script src="/boltcards/static/js/index.js"></script>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
|
@ -74,7 +74,11 @@ async def api_card_create_or_update(
|
|||
raise HTTPException(
|
||||
detail="Invalid byte data provided.", status_code=HTTPStatus.BAD_REQUEST
|
||||
)
|
||||
|
||||
checkUid = await get_card_by_uid(data.uid)
|
||||
if checkUid:
|
||||
raise HTTPException(
|
||||
detail="UID already registered. Delete registered card and try again.", status_code=HTTPStatus.BAD_REQUEST
|
||||
)
|
||||
if card_id:
|
||||
card = await get_card(card_id)
|
||||
if not card:
|
||||
|
|
Loading…
Add table
Reference in a new issue