Merge branch 'lnbits:main' into ext-boltcards_keys
This commit is contained in:
commit
01fb80d739
16 changed files with 112 additions and 106 deletions
|
|
@ -1,6 +1,7 @@
|
|||
FROM python:3.9-slim
|
||||
RUN apt-get clean
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y curl
|
||||
RUN apt-get install -y curl pkg-config build-essential
|
||||
RUN curl -sSL https://install.python-poetry.org | python3 -
|
||||
ENV PATH="/root/.local/bin:$PATH"
|
||||
WORKDIR /app
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ By default, LNbits will use SQLite as its database. You can also use PostgreSQL
|
|||
|
||||
## Option 1 (recommended): poetry
|
||||
|
||||
If you have problems installing LNbits using these instructions, please have a look at the [Troubleshooting](#troubleshooting) section.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/lnbits/lnbits-legend.git
|
||||
cd lnbits-legend/
|
||||
|
|
@ -26,12 +28,11 @@ curl -sSL https://install.python-poetry.org | python3 -
|
|||
export PATH="/home/ubuntu/.local/bin:$PATH" # or whatever is suggested in the poetry install notes printed to terminal
|
||||
poetry env use python3.9
|
||||
poetry install --no-dev
|
||||
poetry run python build.py
|
||||
|
||||
mkdir data
|
||||
cp .env.example .env
|
||||
sudo nano .env # set funding source
|
||||
|
||||
|
||||
nano .env # set funding source
|
||||
```
|
||||
|
||||
#### Running the server
|
||||
|
|
@ -176,13 +177,15 @@ Problems installing? These commands have helped us install LNbits.
|
|||
```sh
|
||||
sudo apt install pkg-config libffi-dev libpq-dev
|
||||
|
||||
# build essentials for debian/ubuntu
|
||||
sudo apt install python3.9-dev gcc build-essential
|
||||
|
||||
# if the secp256k1 build fails:
|
||||
# if you used venv
|
||||
./venv/bin/pip install setuptools wheel
|
||||
# if you used poetry
|
||||
poetry add setuptools wheel
|
||||
# build essentials for debian/ubuntu
|
||||
sudo apt install python3-dev gcc build-essential
|
||||
|
||||
# if you used venv
|
||||
./venv/bin/pip install setuptools wheel
|
||||
```
|
||||
|
||||
### Optional: PostgreSQL database
|
||||
|
|
|
|||
|
|
@ -452,6 +452,15 @@ async def delete_payment(checking_id: str, conn: Optional[Connection] = None) ->
|
|||
)
|
||||
|
||||
|
||||
async def delete_wallet_payment(
|
||||
checking_id: str, wallet_id: str, conn: Optional[Connection] = None
|
||||
) -> None:
|
||||
await (conn or db).execute(
|
||||
"DELETE FROM apipayments WHERE checking_id = ? AND wallet = ?",
|
||||
(checking_id, wallet_id),
|
||||
)
|
||||
|
||||
|
||||
async def check_internal(
|
||||
payment_hash: str, conn: Optional[Connection] = None
|
||||
) -> Optional[str]:
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from lnurl import encode as lnurl_encode # type: ignore
|
|||
from loguru import logger
|
||||
from pydantic import BaseModel
|
||||
|
||||
from lnbits.db import Connection
|
||||
from lnbits.helpers import url_for
|
||||
from lnbits.settings import WALLET
|
||||
from lnbits.wallets.base import PaymentStatus
|
||||
|
|
@ -131,7 +132,11 @@ class Payment(BaseModel):
|
|||
def is_uncheckable(self) -> bool:
|
||||
return self.checking_id.startswith("internal_")
|
||||
|
||||
async def update_status(self, status: PaymentStatus) -> None:
|
||||
async def update_status(
|
||||
self,
|
||||
status: PaymentStatus,
|
||||
conn: Optional[Connection] = None,
|
||||
) -> None:
|
||||
from .crud import update_payment_details
|
||||
|
||||
await update_payment_details(
|
||||
|
|
@ -139,6 +144,7 @@ class Payment(BaseModel):
|
|||
pending=status.pending,
|
||||
fee=status.fee_msat,
|
||||
preimage=status.preimage,
|
||||
conn=conn,
|
||||
)
|
||||
|
||||
async def set_pending(self, pending: bool) -> None:
|
||||
|
|
@ -146,7 +152,10 @@ class Payment(BaseModel):
|
|||
|
||||
await update_payment_status(self.checking_id, pending)
|
||||
|
||||
async def check_status(self) -> PaymentStatus:
|
||||
async def check_status(
|
||||
self,
|
||||
conn: Optional[Connection] = None,
|
||||
) -> PaymentStatus:
|
||||
if self.is_uncheckable:
|
||||
return PaymentStatus(None)
|
||||
|
||||
|
|
@ -165,18 +174,18 @@ class Payment(BaseModel):
|
|||
logger.warning(
|
||||
f"Deleting outgoing failed payment {self.checking_id}: {status}"
|
||||
)
|
||||
await self.delete()
|
||||
await self.delete(conn)
|
||||
elif not status.pending:
|
||||
logger.info(
|
||||
f"Marking '{'in' if self.is_in else 'out'}' {self.checking_id} as not pending anymore: {status}"
|
||||
)
|
||||
await self.update_status(status)
|
||||
await self.update_status(status, conn=conn)
|
||||
return status
|
||||
|
||||
async def delete(self) -> None:
|
||||
async def delete(self, conn: Optional[Connection] = None) -> None:
|
||||
from .crud import delete_payment
|
||||
|
||||
await delete_payment(self.checking_id)
|
||||
await delete_payment(self.checking_id, conn=conn)
|
||||
|
||||
|
||||
class BalanceCheck(BaseModel):
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ from . import db
|
|||
from .crud import (
|
||||
check_internal,
|
||||
create_payment,
|
||||
delete_payment,
|
||||
delete_wallet_payment,
|
||||
get_wallet,
|
||||
get_wallet_payment,
|
||||
update_payment_details,
|
||||
|
|
@ -221,7 +221,7 @@ async def pay_invoice(
|
|||
logger.warning(f"backend sent payment failure")
|
||||
async with db.connect() as conn:
|
||||
logger.debug(f"deleting temporary payment {temp_id}")
|
||||
await delete_payment(temp_id, conn=conn)
|
||||
await delete_wallet_payment(temp_id, wallet_id, conn=conn)
|
||||
raise PaymentFailure(
|
||||
f"payment failed: {payment.error_message}"
|
||||
or "payment failed, but backend didn't give us an error message"
|
||||
|
|
|
|||
|
|
@ -369,9 +369,9 @@ new Vue({
|
|||
decodeRequest: function () {
|
||||
this.parse.show = true
|
||||
let req = this.parse.data.request.toLowerCase()
|
||||
if (this.parse.data.request.startsWith('lightning:')) {
|
||||
if (this.parse.data.request.toLowerCase().startsWith('lightning:')) {
|
||||
this.parse.data.request = this.parse.data.request.slice(10)
|
||||
} else if (this.parse.data.request.startsWith('lnurl:')) {
|
||||
} else if (this.parse.data.request.toLowerCase().startsWith('lnurl:')) {
|
||||
this.parse.data.request = this.parse.data.request.slice(6)
|
||||
} else if (req.indexOf('lightning=lnurl1') !== -1) {
|
||||
this.parse.data.request = this.parse.data.request
|
||||
|
|
|
|||
|
|
@ -711,7 +711,7 @@
|
|||
<q-card class="q-pa-lg">
|
||||
<h6 class="q-my-md text-primary">Warning</h6>
|
||||
<p>
|
||||
Login functionality to be released in v0.2, for now,
|
||||
Login functionality to be released in a future update, for now,
|
||||
<strong
|
||||
>make sure you bookmark this page for future access to your
|
||||
wallet</strong
|
||||
|
|
|
|||
|
|
@ -402,10 +402,6 @@ async def subscribe(request: Request, wallet: Wallet):
|
|||
async def api_payments_sse(
|
||||
request: Request, wallet: WalletTypeInfo = Depends(get_key_type)
|
||||
):
|
||||
if wallet is None or wallet.wallet is None:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist."
|
||||
)
|
||||
return EventSourceResponse(
|
||||
subscribe(request, wallet.wallet), ping=20, media_type="text/event-stream"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -138,44 +138,38 @@ async def get_key_type(
|
|||
detail="Invoice (or Admin) key required.",
|
||||
)
|
||||
|
||||
try:
|
||||
admin_checker = WalletAdminKeyChecker(api_key=token)
|
||||
await admin_checker.__call__(r)
|
||||
wallet = WalletTypeInfo(0, admin_checker.wallet) # type: ignore
|
||||
if (LNBITS_ADMIN_USERS and wallet.wallet.user not in LNBITS_ADMIN_USERS) and (
|
||||
LNBITS_ADMIN_EXTENSIONS and pathname in LNBITS_ADMIN_EXTENSIONS
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
|
||||
)
|
||||
return wallet
|
||||
except HTTPException as e:
|
||||
if e.status_code == HTTPStatus.BAD_REQUEST:
|
||||
for typenr, WalletChecker in zip(
|
||||
[0, 1], [WalletAdminKeyChecker, WalletInvoiceKeyChecker]
|
||||
):
|
||||
try:
|
||||
checker = WalletChecker(api_key=token)
|
||||
await checker.__call__(r)
|
||||
wallet = WalletTypeInfo(typenr, checker.wallet) # type: ignore
|
||||
if wallet is None or wallet.wallet is None:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist."
|
||||
)
|
||||
if (
|
||||
LNBITS_ADMIN_USERS and wallet.wallet.user not in LNBITS_ADMIN_USERS
|
||||
) and (LNBITS_ADMIN_EXTENSIONS and pathname in LNBITS_ADMIN_EXTENSIONS):
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.FORBIDDEN,
|
||||
detail="User not authorized for this extension.",
|
||||
)
|
||||
return wallet
|
||||
except HTTPException as e:
|
||||
if e.status_code == HTTPStatus.BAD_REQUEST:
|
||||
raise
|
||||
elif e.status_code == HTTPStatus.UNAUTHORIZED:
|
||||
# we pass this in case it is not an invoice key, nor an admin key, and then return NOT_FOUND at the end of this block
|
||||
pass
|
||||
else:
|
||||
raise
|
||||
except:
|
||||
raise
|
||||
if e.status_code == HTTPStatus.UNAUTHORIZED:
|
||||
pass
|
||||
except:
|
||||
raise
|
||||
|
||||
try:
|
||||
invoice_checker = WalletInvoiceKeyChecker(api_key=token)
|
||||
await invoice_checker.__call__(r)
|
||||
wallet = WalletTypeInfo(1, invoice_checker.wallet) # type: ignore
|
||||
if (LNBITS_ADMIN_USERS and wallet.wallet.user not in LNBITS_ADMIN_USERS) and (
|
||||
LNBITS_ADMIN_EXTENSIONS and pathname in LNBITS_ADMIN_EXTENSIONS
|
||||
):
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized."
|
||||
)
|
||||
return wallet
|
||||
except HTTPException as e:
|
||||
if e.status_code == HTTPStatus.BAD_REQUEST:
|
||||
raise
|
||||
if e.status_code == HTTPStatus.UNAUTHORIZED:
|
||||
return WalletTypeInfo(2, None) # type: ignore
|
||||
except:
|
||||
raise
|
||||
return wallet
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Wallet does not exist."
|
||||
)
|
||||
|
||||
|
||||
async def require_admin_key(
|
||||
|
|
|
|||
|
|
@ -19,42 +19,25 @@ async def create_ticket(
|
|||
(payment_hash, wallet, event, name, email, False, True),
|
||||
)
|
||||
|
||||
# UPDATE EVENT DATA ON SOLD TICKET
|
||||
eventdata = await get_event(event)
|
||||
assert eventdata, "Couldn't get event from ticket being paid"
|
||||
sold = eventdata.sold + 1
|
||||
amount_tickets = eventdata.amount_tickets - 1
|
||||
await db.execute(
|
||||
"""
|
||||
UPDATE events.events
|
||||
SET sold = ?, amount_tickets = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(sold, amount_tickets, event),
|
||||
)
|
||||
|
||||
ticket = await get_ticket(payment_hash)
|
||||
assert ticket, "Newly created ticket couldn't be retrieved"
|
||||
return ticket
|
||||
|
||||
|
||||
async def set_ticket_paid(payment_hash: str) -> Tickets:
|
||||
row = await db.fetchone("SELECT * FROM events.ticket WHERE id = ?", (payment_hash,))
|
||||
if row[6] != True:
|
||||
await db.execute(
|
||||
"""
|
||||
UPDATE events.ticket
|
||||
SET paid = true
|
||||
WHERE id = ?
|
||||
""",
|
||||
(payment_hash,),
|
||||
)
|
||||
|
||||
eventdata = await get_event(row[2])
|
||||
assert eventdata, "Couldn't get event from ticket being paid"
|
||||
|
||||
sold = eventdata.sold + 1
|
||||
amount_tickets = eventdata.amount_tickets - 1
|
||||
await db.execute(
|
||||
"""
|
||||
UPDATE events.events
|
||||
SET sold = ?, amount_tickets = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(sold, amount_tickets, row[2]),
|
||||
)
|
||||
|
||||
ticket = await get_ticket(payment_hash)
|
||||
assert ticket, "Newly updated ticket couldn't be retrieved"
|
||||
return ticket
|
||||
|
||||
|
||||
async def get_ticket(payment_hash: str) -> Optional[Tickets]:
|
||||
row = await db.fetchone("SELECT * FROM events.ticket WHERE id = ?", (payment_hash,))
|
||||
return Tickets(**row) if row else None
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ from .crud import (
|
|||
get_ticket,
|
||||
get_tickets,
|
||||
reg_ticket,
|
||||
set_ticket_paid,
|
||||
update_event,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,13 @@ animals = [
|
|||
"duck",
|
||||
"eagle",
|
||||
"flamingo",
|
||||
"gorila",
|
||||
"gorilla",
|
||||
"hamster",
|
||||
"iguana",
|
||||
"jaguar",
|
||||
"koala",
|
||||
"llama",
|
||||
"macaroni penguim",
|
||||
"macaroni penguin",
|
||||
"numbat",
|
||||
"octopus",
|
||||
"platypus",
|
||||
|
|
|
|||
|
|
@ -138,8 +138,9 @@
|
|||
hide-dropdown-icon
|
||||
input-debounce="0"
|
||||
new-value-mode="add-unique"
|
||||
label="Tip % Options"
|
||||
></q-select>
|
||||
label="Tip % Options (hit enter to add values)"
|
||||
><q-tooltip>Hit enter to add values</q-tooltip></q-select
|
||||
>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn
|
||||
unelevated
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@
|
|||
name="check"
|
||||
transition-show="fade"
|
||||
class="text-light-green"
|
||||
style="font-size: 40em"
|
||||
style="font-size: min(90vw, 40em)"
|
||||
></q-icon>
|
||||
</q-dialog>
|
||||
</q-page>
|
||||
|
|
@ -294,6 +294,7 @@
|
|||
exchangeRate: null,
|
||||
stack: [],
|
||||
tipAmount: 0.0,
|
||||
hasNFC: false,
|
||||
nfcTagReading: false,
|
||||
invoiceDialog: {
|
||||
show: false,
|
||||
|
|
@ -370,7 +371,7 @@
|
|||
this.showInvoice()
|
||||
},
|
||||
submitForm: function () {
|
||||
if (this.tip_options.length) {
|
||||
if (this.tip_options && this.tip_options.length) {
|
||||
this.showTipModal()
|
||||
} else {
|
||||
this.showInvoice()
|
||||
|
|
@ -413,9 +414,6 @@
|
|||
dialog.show = false
|
||||
|
||||
self.complete.show = true
|
||||
setTimeout(function () {
|
||||
self.complete.show = false
|
||||
}, 5000)
|
||||
}
|
||||
})
|
||||
}, 3000)
|
||||
|
|
|
|||
|
|
@ -3,23 +3,36 @@
|
|||
<p>
|
||||
Onchain Wallet (watch-only) extension uses mempool.space<br />
|
||||
For use with "account Extended Public Key"
|
||||
<a href="https://iancoleman.io/bip39/">https://iancoleman.io/bip39/</a>
|
||||
<a
|
||||
href="https://iancoleman.io/bip39/"
|
||||
target="_blank"
|
||||
style="color: unset"
|
||||
>https://iancoleman.io/bip39/</a
|
||||
>
|
||||
<br />
|
||||
Flash binaries
|
||||
<a
|
||||
href="https://lnbits.github.io/hardware-wallet"
|
||||
target="_blank"
|
||||
style="color: unset"
|
||||
>directly from browser</a
|
||||
>
|
||||
<small>
|
||||
<br />Created by,
|
||||
<a target="_blank" class="text-white" href="https://github.com/arcbtc"
|
||||
<a target="_blank" style="color: unset" href="https://github.com/arcbtc"
|
||||
>Ben Arc</a
|
||||
>
|
||||
(using,
|
||||
<a
|
||||
target="_blank"
|
||||
class="text-white"
|
||||
style="color: unset"
|
||||
href="https://github.com/diybitcoinhardware/embit"
|
||||
>Embit</a
|
||||
></small
|
||||
>)
|
||||
<br />
|
||||
<br />
|
||||
<a target="_blank" href="/docs#/watchonly" class="text-white"
|
||||
<a target="_blank" href="/docs#/watchonly" style="color: unset"
|
||||
>Swagger REST API Documentation</a
|
||||
>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ async def check_pending_payments():
|
|||
conn=conn,
|
||||
)
|
||||
for payment in pending_payments:
|
||||
await payment.check_status()
|
||||
await payment.check_status(conn=conn)
|
||||
|
||||
logger.debug(
|
||||
f"Task: pending check finished for {len(pending_payments)} payments (took {time.time() - start_time:0.3f} s)"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue