mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-02-24 14:51:05 +01:00
Merge remote-tracking branch 'origin/main' into icontiles
This commit is contained in:
commit
1b201086ba
32 changed files with 134 additions and 232 deletions
4
Makefile
4
Makefile
|
@ -6,7 +6,7 @@ format: prettier isort black
|
||||||
|
|
||||||
check: mypy checkprettier checkisort checkblack
|
check: mypy checkprettier checkisort checkblack
|
||||||
|
|
||||||
prettier: $(shell find lnbits -name "*.js" -name ".html")
|
prettier: $(shell find lnbits -name "*.js" -o -name ".html")
|
||||||
./node_modules/.bin/prettier --write lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js lnbits/extensions/*/static/components/*/*.js lnbits/extensions/*/static/components/*/*.html
|
./node_modules/.bin/prettier --write lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js lnbits/extensions/*/static/components/*/*.js lnbits/extensions/*/static/components/*/*.html
|
||||||
|
|
||||||
black:
|
black:
|
||||||
|
@ -18,7 +18,7 @@ mypy:
|
||||||
isort:
|
isort:
|
||||||
poetry run isort .
|
poetry run isort .
|
||||||
|
|
||||||
checkprettier: $(shell find lnbits -name "*.js" -name ".html")
|
checkprettier: $(shell find lnbits -name "*.js" -o -name ".html")
|
||||||
./node_modules/.bin/prettier --check lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js lnbits/extensions/*/static/components/*/*.js lnbits/extensions/*/static/components/*/*.html
|
./node_modules/.bin/prettier --check lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js lnbits/extensions/*/static/components/*/*.js lnbits/extensions/*/static/components/*/*.html
|
||||||
|
|
||||||
checkblack:
|
checkblack:
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
};
|
};
|
||||||
outputs = { self, nixpkgs, poetry2nix }@inputs:
|
outputs = { self, nixpkgs, poetry2nix }@inputs:
|
||||||
let
|
let
|
||||||
supportedSystems = [ "x86_64-linux" "aarch64-linux" ];
|
supportedSystems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];
|
||||||
forSystems = systems: f:
|
forSystems = systems: f:
|
||||||
nixpkgs.lib.genAttrs systems
|
nixpkgs.lib.genAttrs systems
|
||||||
(system: f system (import nixpkgs { inherit system; overlays = [ poetry2nix.overlay self.overlays.default ]; }));
|
(system: f system (import nixpkgs { inherit system; overlays = [ poetry2nix.overlay self.overlays.default ]; }));
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from binascii import unhexlify
|
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from typing import List, NamedTuple, Optional
|
from typing import List, NamedTuple, Optional
|
||||||
|
|
||||||
|
@ -108,7 +107,7 @@ def decode(pr: str) -> Invoice:
|
||||||
message = bytearray([ord(c) for c in hrp]) + data.tobytes()
|
message = bytearray([ord(c) for c in hrp]) + data.tobytes()
|
||||||
sig = signature[0:64]
|
sig = signature[0:64]
|
||||||
if invoice.payee:
|
if invoice.payee:
|
||||||
key = VerifyingKey.from_string(unhexlify(invoice.payee), curve=SECP256k1)
|
key = VerifyingKey.from_string(bytes.fromhex(invoice.payee), curve=SECP256k1)
|
||||||
key.verify(sig, message, hashlib.sha256, sigdecode=sigdecode_string)
|
key.verify(sig, message, hashlib.sha256, sigdecode=sigdecode_string)
|
||||||
else:
|
else:
|
||||||
keys = VerifyingKey.from_public_key_recovery(
|
keys = VerifyingKey.from_public_key_recovery(
|
||||||
|
@ -131,7 +130,7 @@ def encode(options):
|
||||||
if options["timestamp"]:
|
if options["timestamp"]:
|
||||||
addr.date = int(options["timestamp"])
|
addr.date = int(options["timestamp"])
|
||||||
|
|
||||||
addr.paymenthash = unhexlify(options["paymenthash"])
|
addr.paymenthash = bytes.fromhex(options["paymenthash"])
|
||||||
|
|
||||||
if options["description"]:
|
if options["description"]:
|
||||||
addr.tags.append(("d", options["description"]))
|
addr.tags.append(("d", options["description"]))
|
||||||
|
@ -149,8 +148,8 @@ def encode(options):
|
||||||
while len(splits) >= 5:
|
while len(splits) >= 5:
|
||||||
route.append(
|
route.append(
|
||||||
(
|
(
|
||||||
unhexlify(splits[0]),
|
bytes.fromhex(splits[0]),
|
||||||
unhexlify(splits[1]),
|
bytes.fromhex(splits[1]),
|
||||||
int(splits[2]),
|
int(splits[2]),
|
||||||
int(splits[3]),
|
int(splits[3]),
|
||||||
int(splits[4]),
|
int(splits[4]),
|
||||||
|
@ -235,7 +234,7 @@ def lnencode(addr, privkey):
|
||||||
raise ValueError("Must include either 'd' or 'h'")
|
raise ValueError("Must include either 'd' or 'h'")
|
||||||
|
|
||||||
# We actually sign the hrp, then data (padded to 8 bits with zeroes).
|
# We actually sign the hrp, then data (padded to 8 bits with zeroes).
|
||||||
privkey = secp256k1.PrivateKey(bytes(unhexlify(privkey)))
|
privkey = secp256k1.PrivateKey(bytes.fromhex(privkey))
|
||||||
sig = privkey.ecdsa_sign_recoverable(
|
sig = privkey.ecdsa_sign_recoverable(
|
||||||
bytearray([ord(c) for c in hrp]) + data.tobytes()
|
bytearray([ord(c) for c in hrp]) + data.tobytes()
|
||||||
)
|
)
|
||||||
|
@ -261,7 +260,7 @@ class LnAddr(object):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "LnAddr[{}, amount={}{} tags=[{}]]".format(
|
return "LnAddr[{}, amount={}{} tags=[{}]]".format(
|
||||||
hexlify(self.pubkey.serialize()).decode("utf-8"),
|
bytes.hex(self.pubkey.serialize()).decode("utf-8"),
|
||||||
self.amount,
|
self.amount,
|
||||||
self.currency,
|
self.currency,
|
||||||
", ".join([k + "=" + str(v) for k, v in self.tags]),
|
", ".join([k + "=" + str(v) for k, v in self.tags]),
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
from binascii import unhexlify
|
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from typing import Dict, List, Optional, Tuple
|
from typing import Dict, List, Optional, Tuple
|
||||||
from urllib.parse import parse_qs, urlparse
|
from urllib.parse import parse_qs, urlparse
|
||||||
|
@ -303,7 +302,7 @@ async def perform_lnurlauth(
|
||||||
) -> Optional[LnurlErrorResponse]:
|
) -> Optional[LnurlErrorResponse]:
|
||||||
cb = urlparse(callback)
|
cb = urlparse(callback)
|
||||||
|
|
||||||
k1 = unhexlify(parse_qs(cb.query)["k1"][0])
|
k1 = bytes.fromhex(parse_qs(cb.query)["k1"][0])
|
||||||
|
|
||||||
key = wallet.wallet.lnurlauth_key(cb.netloc)
|
key = wallet.wallet.lnurlauth_key(cb.netloc)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import binascii
|
|
||||||
import hashlib
|
import hashlib
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
|
@ -142,16 +141,14 @@ async def api_payments_create_invoice(data: CreateInvoiceData, wallet: Wallet):
|
||||||
if data.description_hash or data.unhashed_description:
|
if data.description_hash or data.unhashed_description:
|
||||||
try:
|
try:
|
||||||
description_hash = (
|
description_hash = (
|
||||||
binascii.unhexlify(data.description_hash)
|
bytes.fromhex(data.description_hash) if data.description_hash else b""
|
||||||
if data.description_hash
|
|
||||||
else b""
|
|
||||||
)
|
)
|
||||||
unhashed_description = (
|
unhashed_description = (
|
||||||
binascii.unhexlify(data.unhashed_description)
|
bytes.fromhex(data.unhashed_description)
|
||||||
if data.unhashed_description
|
if data.unhashed_description
|
||||||
else b""
|
else b""
|
||||||
)
|
)
|
||||||
except binascii.Error:
|
except ValueError:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST,
|
||||||
detail="'description_hash' and 'unhashed_description' must be a valid hex strings",
|
detail="'description_hash' and 'unhashed_description' must be a valid hex strings",
|
||||||
|
|
|
@ -2,7 +2,6 @@ import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import hmac
|
import hmac
|
||||||
import urllib
|
import urllib
|
||||||
from binascii import unhexlify
|
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
|
@ -19,7 +18,7 @@ def generate_bleskomat_lnurl_signature(
|
||||||
payload: str, api_key_secret: str, api_key_encoding: str = "hex"
|
payload: str, api_key_secret: str, api_key_encoding: str = "hex"
|
||||||
):
|
):
|
||||||
if api_key_encoding == "hex":
|
if api_key_encoding == "hex":
|
||||||
key = unhexlify(api_key_secret)
|
key = bytes.fromhex(api_key_secret)
|
||||||
elif api_key_encoding == "base64":
|
elif api_key_encoding == "base64":
|
||||||
key = base64.b64decode(api_key_secret)
|
key = base64.b64decode(api_key_secret)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -42,23 +42,20 @@ Updated for v0.1.3
|
||||||
- Or you can Click the "KEYS / AUTH LINK" button to copy the auth URL to the clipboard. Then paste it into the Android app (Create Bolt Card -> PASTE AUTH URL).
|
- Or you can Click the "KEYS / AUTH LINK" button to copy the auth URL to the clipboard. Then paste it into the Android app (Create Bolt Card -> PASTE AUTH URL).
|
||||||
- Click WRITE CARD NOW and approach the NFC card to set it up. DO NOT REMOVE THE CARD PREMATURELY!
|
- Click WRITE CARD NOW and approach the NFC card to set it up. DO NOT REMOVE THE CARD PREMATURELY!
|
||||||
|
|
||||||
## Rewriting / Erasing the card - Boltcard NFC Card Creator
|
## Erasing the card - Boltcard NFC Card Creator
|
||||||
|
Updated for v0.1.3
|
||||||
|
|
||||||
It is possible not only to reset the keys but also to disable the SUN function and completely erase the card so it can be used again as a static tag or set up as a new Bolt Card.
|
Since v0.1.2 of Boltcard NFC Card Creator it is possible not only reset the keys but also disable the SUN function and do the complete erase so the card can be use again as a static tag (or set as a new Bolt Card, ofc).
|
||||||
|
|
||||||
IMPORTANT:
|
- Click the QR code button next to a card to view its details and select WIPE
|
||||||
* It is immanent that you have access to your old keys so do not erase this card in LNbits before you copied those strings!
|
- OR click the red cross icon on the right side to reach the same
|
||||||
* If you tried to write to them and failed you will need the same amount of positive writing sessions to unlock the card.
|
- In the android app (Advanced -> Reset Keys)
|
||||||
|
- Click SCAN QR CODE to scan the QR
|
||||||
- in the BoltCard-Extension click the QR code button next to your old card and copy Key0
|
- Or click WIPE DATA in LNbits to copy and paste in to the app (PASTE KEY JSON)
|
||||||
- in the BoltApp click Advanced - Reset keys and paste the Key0 into the first field named Key0
|
- Click RESET CARD NOW and approach the NFC card to erase it. DO NOT REMOVE THE CARD PREMATURELY!
|
||||||
- repeat with Key1/Key2/Key3/Key0
|
- Now if there is all success the card can be safely delete from LNbits (but keep the keys backuped anyway; batter safe than brick).
|
||||||
- when done pasting all 4 keys scan your card with the BoltApp
|
|
||||||
- Thats it 🥳
|
|
||||||
- If everything was successful the card can be safely deleted from LNbits (but keep the keys backed up anyway; batter safe than brick).
|
|
||||||
|
|
||||||
You can watch a video of this process here https://www.youtube.com/watch?time_continue=230&v=Pe0YXHawHvQ&feature=emb_logo
|
|
||||||
|
|
||||||
|
If you somehow find yourself in some non-standard state (for instance only k3 and k4 remains filled after previous unsuccessful reset), then you need edit the key fields manually (for instance leave k0-k2 to zeroes and provide the right k3 and k4).
|
||||||
|
|
||||||
## Setting the card - computer (hard way)
|
## Setting the card - computer (hard way)
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ async def api_hits(
|
||||||
|
|
||||||
|
|
||||||
@boltcards_ext.get("/api/v1/refunds")
|
@boltcards_ext.get("/api/v1/refunds")
|
||||||
async def api_hits(
|
async def api_refunds(
|
||||||
g: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)
|
g: WalletTypeInfo = Depends(get_key_type), all_wallets: bool = Query(False)
|
||||||
):
|
):
|
||||||
wallet_ids = [g.wallet.id]
|
wallet_ids = [g.wallet.id]
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import os
|
import os
|
||||||
from binascii import hexlify, unhexlify
|
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from typing import Awaitable, Union
|
from typing import Awaitable, Union
|
||||||
|
|
||||||
|
@ -56,7 +55,7 @@ async def create_swap(data: CreateSubmarineSwap) -> SubmarineSwap:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
refund_privkey = ec.PrivateKey(os.urandom(32), True, net)
|
refund_privkey = ec.PrivateKey(os.urandom(32), True, net)
|
||||||
refund_pubkey_hex = hexlify(refund_privkey.sec()).decode("UTF-8")
|
refund_pubkey_hex = bytes.hex(refund_privkey.sec()).decode("UTF-8")
|
||||||
|
|
||||||
res = req_wrap(
|
res = req_wrap(
|
||||||
"post",
|
"post",
|
||||||
|
@ -121,7 +120,7 @@ async def create_reverse_swap(
|
||||||
return False
|
return False
|
||||||
|
|
||||||
claim_privkey = ec.PrivateKey(os.urandom(32), True, net)
|
claim_privkey = ec.PrivateKey(os.urandom(32), True, net)
|
||||||
claim_pubkey_hex = hexlify(claim_privkey.sec()).decode("UTF-8")
|
claim_pubkey_hex = bytes.hex(claim_privkey.sec()).decode("UTF-8")
|
||||||
preimage = os.urandom(32)
|
preimage = os.urandom(32)
|
||||||
preimage_hash = sha256(preimage).hexdigest()
|
preimage_hash = sha256(preimage).hexdigest()
|
||||||
|
|
||||||
|
@ -311,12 +310,12 @@ async def create_onchain_tx(
|
||||||
sequence = 0xFFFFFFFE
|
sequence = 0xFFFFFFFE
|
||||||
else:
|
else:
|
||||||
privkey = ec.PrivateKey.from_wif(swap.claim_privkey)
|
privkey = ec.PrivateKey.from_wif(swap.claim_privkey)
|
||||||
preimage = unhexlify(swap.preimage)
|
preimage = bytes.fromhex(swap.preimage)
|
||||||
onchain_address = swap.onchain_address
|
onchain_address = swap.onchain_address
|
||||||
sequence = 0xFFFFFFFF
|
sequence = 0xFFFFFFFF
|
||||||
|
|
||||||
locktime = swap.timeout_block_height
|
locktime = swap.timeout_block_height
|
||||||
redeem_script = unhexlify(swap.redeem_script)
|
redeem_script = bytes.fromhex(swap.redeem_script)
|
||||||
|
|
||||||
fees = get_fee_estimation()
|
fees = get_fee_estimation()
|
||||||
|
|
||||||
|
@ -324,7 +323,7 @@ async def create_onchain_tx(
|
||||||
|
|
||||||
script_pubkey = script.address_to_scriptpubkey(onchain_address)
|
script_pubkey = script.address_to_scriptpubkey(onchain_address)
|
||||||
|
|
||||||
vin = [TransactionInput(unhexlify(txid), vout_cnt, sequence=sequence)]
|
vin = [TransactionInput(bytes.fromhex(txid), vout_cnt, sequence=sequence)]
|
||||||
vout = [TransactionOutput(vout_amount - fees, script_pubkey)]
|
vout = [TransactionOutput(vout_amount - fees, script_pubkey)]
|
||||||
tx = Transaction(vin=vin, vout=vout)
|
tx = Transaction(vin=vin, vout=vout)
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
from binascii import hexlify
|
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import websockets
|
import websockets
|
||||||
|
@ -84,7 +83,7 @@ def get_mempool_blockheight() -> int:
|
||||||
|
|
||||||
|
|
||||||
async def send_onchain_tx(tx: Transaction):
|
async def send_onchain_tx(tx: Transaction):
|
||||||
raw = hexlify(tx.serialize())
|
raw = bytes.hex(tx.serialize())
|
||||||
logger.debug(f"Boltz - mempool sending onchain tx...")
|
logger.debug(f"Boltz - mempool sending onchain tx...")
|
||||||
req_wrap(
|
req_wrap(
|
||||||
"post",
|
"post",
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import time
|
import time
|
||||||
from binascii import hexlify, unhexlify
|
|
||||||
from typing import Any, List, Optional, Union
|
from typing import Any, List, Optional, Union
|
||||||
|
|
||||||
from cashu.core.base import MintKeyset
|
from cashu.core.base import MintKeyset
|
||||||
|
|
|
@ -301,34 +301,6 @@ def gerty_should_sleep(utc_offset: int = 0):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_date_suffix(dayNumber):
|
|
||||||
if 4 <= dayNumber <= 20 or 24 <= dayNumber <= 30:
|
|
||||||
return "th"
|
|
||||||
else:
|
|
||||||
return ["st", "nd", "rd"][dayNumber % 10 - 1]
|
|
||||||
|
|
||||||
|
|
||||||
def get_time_remaining(seconds, granularity=2):
|
|
||||||
intervals = (
|
|
||||||
# ('weeks', 604800), # 60 * 60 * 24 * 7
|
|
||||||
("days", 86400), # 60 * 60 * 24
|
|
||||||
("hours", 3600), # 60 * 60
|
|
||||||
("minutes", 60),
|
|
||||||
("seconds", 1),
|
|
||||||
)
|
|
||||||
|
|
||||||
result = []
|
|
||||||
|
|
||||||
for name, count in intervals:
|
|
||||||
value = seconds // count
|
|
||||||
if value:
|
|
||||||
seconds -= value * count
|
|
||||||
if value == 1:
|
|
||||||
name = name.rstrip("s")
|
|
||||||
result.append("{} {}".format(round(value), name))
|
|
||||||
return ", ".join(result[:granularity])
|
|
||||||
|
|
||||||
|
|
||||||
async def get_mining_stat(stat_slug: str, gerty):
|
async def get_mining_stat(stat_slug: str, gerty):
|
||||||
text = []
|
text = []
|
||||||
if stat_slug == "mining_current_hash_rate":
|
if stat_slug == "mining_current_hash_rate":
|
||||||
|
|
|
@ -30,7 +30,7 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||||
|
|
||||||
|
|
||||||
@invoices_ext.get("/pay/{invoice_id}", response_class=HTMLResponse)
|
@invoices_ext.get("/pay/{invoice_id}", response_class=HTMLResponse)
|
||||||
async def index(request: Request, invoice_id: str):
|
async def pay(request: Request, invoice_id: str):
|
||||||
invoice = await get_invoice(invoice_id)
|
invoice = await get_invoice(invoice_id)
|
||||||
|
|
||||||
if not invoice:
|
if not invoice:
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
from binascii import unhexlify
|
|
||||||
|
|
||||||
from lnbits.bolt11 import Invoice
|
from lnbits.bolt11 import Invoice
|
||||||
|
|
||||||
|
|
||||||
def to_buffer(payment_hash: str):
|
def to_buffer(payment_hash: str):
|
||||||
return {"type": "Buffer", "data": [b for b in unhexlify(payment_hash)]}
|
return {"type": "Buffer", "data": [b for b in bytes.fromhex(payment_hash)]}
|
||||||
|
|
||||||
|
|
||||||
def decoded_as_lndhub(invoice: Invoice):
|
def decoded_as_lndhub(invoice: Invoice):
|
||||||
|
|
|
@ -139,7 +139,7 @@ async def delete_domain(domain_id) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def delete_address(address_id) -> bool:
|
async def delete_address(address_id):
|
||||||
await db.execute(
|
await db.execute(
|
||||||
"""
|
"""
|
||||||
DELETE FROM nostrnip5.addresses WHERE id = ?
|
DELETE FROM nostrnip5.addresses WHERE id = ?
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
from lnbits.core.models import Payment
|
from lnbits.core.models import Payment
|
||||||
from lnbits.helpers import urlsafe_short_hash
|
from lnbits.tasks import register_invoice_listener
|
||||||
from lnbits.tasks import internal_invoice_queue, register_invoice_listener
|
|
||||||
|
|
||||||
from .crud import activate_address
|
from .crud import activate_address
|
||||||
|
|
||||||
|
@ -18,17 +18,18 @@ async def wait_for_paid_invoices():
|
||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment) -> None:
|
||||||
|
if not payment.extra:
|
||||||
|
return
|
||||||
if payment.extra.get("tag") != "nostrnip5":
|
if payment.extra.get("tag") != "nostrnip5":
|
||||||
# not relevant
|
|
||||||
return
|
return
|
||||||
|
|
||||||
domain_id = payment.extra.get("domain_id")
|
domain_id = payment.extra.get("domain_id")
|
||||||
address_id = payment.extra.get("address_id")
|
address_id = payment.extra.get("address_id")
|
||||||
|
|
||||||
print("Activating NOSTR NIP-05")
|
if domain_id and address_id:
|
||||||
print(domain_id)
|
logger.info("Activating NOSTR NIP-05")
|
||||||
print(address_id)
|
logger.info(domain_id)
|
||||||
|
logger.info(address_id)
|
||||||
active = await activate_address(domain_id, address_id)
|
await activate_address(domain_id, address_id)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi import FastAPI, Request
|
from fastapi import Depends, Request
|
||||||
from fastapi.params import Depends
|
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
from starlette.responses import HTMLResponse
|
from starlette.responses import HTMLResponse
|
||||||
|
@ -24,7 +23,7 @@ async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||||
|
|
||||||
|
|
||||||
@nostrnip5_ext.get("/signup/{domain_id}", response_class=HTMLResponse)
|
@nostrnip5_ext.get("/signup/{domain_id}", response_class=HTMLResponse)
|
||||||
async def index(request: Request, domain_id: str):
|
async def signup(request: Request, domain_id: str):
|
||||||
domain = await get_domain(domain_id)
|
domain = await get_domain(domain_id)
|
||||||
|
|
||||||
if not domain:
|
if not domain:
|
||||||
|
@ -43,7 +42,7 @@ async def index(request: Request, domain_id: str):
|
||||||
|
|
||||||
|
|
||||||
@nostrnip5_ext.get("/rotate/{domain_id}/{address_id}", response_class=HTMLResponse)
|
@nostrnip5_ext.get("/rotate/{domain_id}/{address_id}", response_class=HTMLResponse)
|
||||||
async def index(request: Request, domain_id: str, address_id: str):
|
async def rotate(request: Request, domain_id: str, address_id: str):
|
||||||
domain = await get_domain(domain_id)
|
domain = await get_domain(domain_id)
|
||||||
address = await get_address(domain_id, address_id)
|
address = await get_address(domain_id, address_id)
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
import re
|
import re
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
from bech32 import bech32_decode, convertbits
|
from bech32 import bech32_decode, convertbits
|
||||||
from fastapi import Query, Request, Response
|
from fastapi import Depends, Query, Response
|
||||||
from fastapi.params import Depends
|
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
|
|
||||||
|
@ -38,7 +36,10 @@ async def api_domains(
|
||||||
):
|
):
|
||||||
wallet_ids = [wallet.wallet.id]
|
wallet_ids = [wallet.wallet.id]
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
|
user = await get_user(wallet.wallet.user)
|
||||||
|
if not user:
|
||||||
|
return []
|
||||||
|
wallet_ids = user.wallet_ids
|
||||||
|
|
||||||
return [domain.dict() for domain in await get_domains(wallet_ids)]
|
return [domain.dict() for domain in await get_domains(wallet_ids)]
|
||||||
|
|
||||||
|
@ -49,13 +50,20 @@ async def api_addresses(
|
||||||
):
|
):
|
||||||
wallet_ids = [wallet.wallet.id]
|
wallet_ids = [wallet.wallet.id]
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
|
user = await get_user(wallet.wallet.user)
|
||||||
|
if not user:
|
||||||
|
return []
|
||||||
|
wallet_ids = user.wallet_ids
|
||||||
|
|
||||||
return [address.dict() for address in await get_all_addresses(wallet_ids)]
|
return [address.dict() for address in await get_all_addresses(wallet_ids)]
|
||||||
|
|
||||||
|
|
||||||
@nostrnip5_ext.get("/api/v1/domain/{domain_id}", status_code=HTTPStatus.OK)
|
@nostrnip5_ext.get(
|
||||||
async def api_invoice(domain_id: str, wallet: WalletTypeInfo = Depends(get_key_type)):
|
"/api/v1/domain/{domain_id}",
|
||||||
|
status_code=HTTPStatus.OK,
|
||||||
|
dependencies=[Depends(get_key_type)],
|
||||||
|
)
|
||||||
|
async def api_invoice(domain_id: str):
|
||||||
domain = await get_domain(domain_id)
|
domain = await get_domain(domain_id)
|
||||||
if not domain:
|
if not domain:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
@ -104,11 +112,11 @@ async def api_address_delete(
|
||||||
@nostrnip5_ext.post(
|
@nostrnip5_ext.post(
|
||||||
"/api/v1/domain/{domain_id}/address/{address_id}/activate",
|
"/api/v1/domain/{domain_id}/address/{address_id}/activate",
|
||||||
status_code=HTTPStatus.OK,
|
status_code=HTTPStatus.OK,
|
||||||
|
dependencies=[Depends(require_admin_key)],
|
||||||
)
|
)
|
||||||
async def api_address_activate(
|
async def api_address_activate(
|
||||||
domain_id: str,
|
domain_id: str,
|
||||||
address_id: str,
|
address_id: str,
|
||||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
|
||||||
):
|
):
|
||||||
await activate_address(domain_id, address_id)
|
await activate_address(domain_id, address_id)
|
||||||
|
|
||||||
|
@ -126,9 +134,11 @@ async def api_address_rotate(
|
||||||
):
|
):
|
||||||
|
|
||||||
if post_data.pubkey.startswith("npub"):
|
if post_data.pubkey.startswith("npub"):
|
||||||
hrp, data = bech32_decode(post_data.pubkey)
|
_, data = bech32_decode(post_data.pubkey)
|
||||||
decoded_data = convertbits(data, 5, 8, False)
|
if data:
|
||||||
post_data.pubkey = bytes(decoded_data).hex()
|
decoded_data = convertbits(data, 5, 8, False)
|
||||||
|
if decoded_data:
|
||||||
|
post_data.pubkey = bytes(decoded_data).hex()
|
||||||
|
|
||||||
if len(bytes.fromhex(post_data.pubkey)) != 32:
|
if len(bytes.fromhex(post_data.pubkey)) != 32:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
@ -173,10 +183,12 @@ async def api_address_create(
|
||||||
status_code=HTTPStatus.NOT_FOUND, detail="Local part already exists."
|
status_code=HTTPStatus.NOT_FOUND, detail="Local part already exists."
|
||||||
)
|
)
|
||||||
|
|
||||||
if post_data.pubkey.startswith("npub"):
|
if post_data and post_data.pubkey.startswith("npub"):
|
||||||
hrp, data = bech32_decode(post_data.pubkey)
|
_, data = bech32_decode(post_data.pubkey)
|
||||||
decoded_data = convertbits(data, 5, 8, False)
|
if data:
|
||||||
post_data.pubkey = bytes(decoded_data).hex()
|
decoded_data = convertbits(data, 5, 8, False)
|
||||||
|
if decoded_data:
|
||||||
|
post_data.pubkey = bytes(decoded_data).hex()
|
||||||
|
|
||||||
if len(bytes.fromhex(post_data.pubkey)) != 32:
|
if len(bytes.fromhex(post_data.pubkey)) != 32:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
@ -233,15 +245,17 @@ async def api_get_nostr_json(
|
||||||
output = {}
|
output = {}
|
||||||
|
|
||||||
for address in addresses:
|
for address in addresses:
|
||||||
local_part = address.get("local_part").lower()
|
local_part = address.get("local_part")
|
||||||
|
if not local_part:
|
||||||
|
continue
|
||||||
|
|
||||||
if address.get("active") == False:
|
if address.get("active") == False:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if name and name.lower() != local_part:
|
if name and name.lower() != local_part.lower():
|
||||||
continue
|
continue
|
||||||
|
|
||||||
output[local_part] = address.get("pubkey")
|
output[local_part.lower()] = address.get("pubkey")
|
||||||
|
|
||||||
response.headers["Access-Control-Allow-Origin"] = "*"
|
response.headers["Access-Control-Allow-Origin"] = "*"
|
||||||
response.headers["Access-Control-Allow-Methods"] = "GET,OPTIONS"
|
response.headers["Access-Control-Allow-Methods"] = "GET,OPTIONS"
|
||||||
|
|
|
@ -131,53 +131,6 @@ async def check_address_balance(charge_id: str) -> Optional[Charges]:
|
||||||
################## SETTINGS ###################
|
################## SETTINGS ###################
|
||||||
|
|
||||||
|
|
||||||
async def save_theme(data: SatsPayThemes, css_id: str = None):
|
|
||||||
# insert or update
|
|
||||||
if css_id:
|
|
||||||
await db.execute(
|
|
||||||
"""
|
|
||||||
UPDATE satspay.themes SET custom_css = ?, title = ? WHERE css_id = ?
|
|
||||||
""",
|
|
||||||
(data.custom_css, data.title, css_id),
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
css_id = urlsafe_short_hash()
|
|
||||||
await db.execute(
|
|
||||||
"""
|
|
||||||
INSERT INTO satspay.themes (
|
|
||||||
css_id,
|
|
||||||
title,
|
|
||||||
user,
|
|
||||||
custom_css
|
|
||||||
)
|
|
||||||
VALUES (?, ?, ?, ?)
|
|
||||||
""",
|
|
||||||
(
|
|
||||||
css_id,
|
|
||||||
data.title,
|
|
||||||
data.user,
|
|
||||||
data.custom_css,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
return await get_theme(css_id)
|
|
||||||
|
|
||||||
|
|
||||||
async def get_theme(css_id: str) -> SatsPayThemes:
|
|
||||||
row = await db.fetchone("SELECT * FROM satspay.themes WHERE css_id = ?", (css_id,))
|
|
||||||
return SatsPayThemes.from_row(row) if row else None
|
|
||||||
|
|
||||||
|
|
||||||
async def get_themes(user_id: str) -> List[SatsPayThemes]:
|
|
||||||
rows = await db.fetchall(
|
|
||||||
"""SELECT * FROM satspay.themes WHERE "user" = ? ORDER BY "timestamp" DESC """,
|
|
||||||
(user_id,),
|
|
||||||
)
|
|
||||||
return await get_config(row.user)
|
|
||||||
|
|
||||||
|
|
||||||
################## SETTINGS ###################
|
|
||||||
|
|
||||||
|
|
||||||
async def save_theme(data: SatsPayThemes, css_id: str = None):
|
async def save_theme(data: SatsPayThemes, css_id: str = None):
|
||||||
# insert or update
|
# insert or update
|
||||||
if css_id:
|
if css_id:
|
||||||
|
|
|
@ -171,7 +171,7 @@ async def api_themes_retrieve(wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||||
|
|
||||||
|
|
||||||
@satspay_ext.delete("/api/v1/themes/{theme_id}")
|
@satspay_ext.delete("/api/v1/themes/{theme_id}")
|
||||||
async def api_charge_delete(theme_id, wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_theme_delete(theme_id, wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||||
theme = await get_theme(theme_id)
|
theme = await get_theme(theme_id)
|
||||||
|
|
||||||
if not theme:
|
if not theme:
|
||||||
|
|
|
@ -25,9 +25,9 @@ async def wait_for_paid_invoices():
|
||||||
await on_invoice_paid(payment)
|
await on_invoice_paid(payment)
|
||||||
|
|
||||||
|
|
||||||
async def on_invoice_paid(payment: Payment) -> None:
|
async def on_invoice_paid(payment: Payment):
|
||||||
# (avoid loops)
|
# (avoid loops)
|
||||||
if payment.extra.get("tag") == "scrubed":
|
if payment.extra and payment.extra.get("tag") == "scrubed":
|
||||||
# already scrubbed
|
# already scrubbed
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ async def on_invoice_paid(payment: Payment) -> None:
|
||||||
timeout=40,
|
timeout=40,
|
||||||
)
|
)
|
||||||
if r.is_error:
|
if r.is_error:
|
||||||
raise httpx.ConnectError
|
raise httpx.ConnectError("issue with scrub callback")
|
||||||
except (httpx.ConnectError, httpx.RequestError):
|
except (httpx.ConnectError, httpx.RequestError):
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST,
|
status_code=HTTPStatus.BAD_REQUEST,
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from fastapi import Request
|
from fastapi import Depends, Request
|
||||||
from fastapi.params import Depends
|
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from starlette.responses import HTMLResponse
|
from starlette.responses import HTMLResponse
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Depends, Query
|
||||||
from fastapi.param_functions import Query
|
|
||||||
from fastapi.params import Depends
|
|
||||||
from lnurl.exceptions import InvalidUrl as LnurlInvalidUrl # type: ignore
|
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
|
|
||||||
from lnbits.core.crud import get_user
|
from lnbits.core.crud import get_user
|
||||||
|
@ -23,14 +20,14 @@ from .models import CreateScrubLink
|
||||||
|
|
||||||
@scrub_ext.get("/api/v1/links", status_code=HTTPStatus.OK)
|
@scrub_ext.get("/api/v1/links", status_code=HTTPStatus.OK)
|
||||||
async def api_links(
|
async def api_links(
|
||||||
req: Request,
|
|
||||||
wallet: WalletTypeInfo = Depends(get_key_type),
|
wallet: WalletTypeInfo = Depends(get_key_type),
|
||||||
all_wallets: bool = Query(False),
|
all_wallets: bool = Query(False),
|
||||||
):
|
):
|
||||||
wallet_ids = [wallet.wallet.id]
|
wallet_ids = [wallet.wallet.id]
|
||||||
|
|
||||||
if all_wallets:
|
if all_wallets:
|
||||||
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
|
user = await get_user(wallet.wallet.user)
|
||||||
|
wallet_ids = user.wallet_ids if user else []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return [link.dict() for link in await get_scrub_links(wallet_ids)]
|
return [link.dict() for link in await get_scrub_links(wallet_ids)]
|
||||||
|
@ -43,9 +40,7 @@ async def api_links(
|
||||||
|
|
||||||
|
|
||||||
@scrub_ext.get("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
@scrub_ext.get("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
||||||
async def api_link_retrieve(
|
async def api_link_retrieve(link_id, wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||||
r: Request, link_id, wallet: WalletTypeInfo = Depends(get_key_type)
|
|
||||||
):
|
|
||||||
link = await get_scrub_link(link_id)
|
link = await get_scrub_link(link_id)
|
||||||
|
|
||||||
if not link:
|
if not link:
|
||||||
|
|
|
@ -8,7 +8,7 @@ from .models import Tip, TipJar, createTipJar
|
||||||
|
|
||||||
|
|
||||||
async def create_tip(
|
async def create_tip(
|
||||||
id: int, wallet: str, message: str, name: str, sats: int, tipjar: str
|
id: str, wallet: str, message: str, name: str, sats: int, tipjar: str
|
||||||
) -> Tip:
|
) -> Tip:
|
||||||
"""Create a new Tip"""
|
"""Create a new Tip"""
|
||||||
await db.execute(
|
await db.execute(
|
||||||
|
@ -33,11 +33,7 @@ async def create_tip(
|
||||||
|
|
||||||
async def create_tipjar(data: createTipJar) -> TipJar:
|
async def create_tipjar(data: createTipJar) -> TipJar:
|
||||||
"""Create a new TipJar"""
|
"""Create a new TipJar"""
|
||||||
|
await db.execute(
|
||||||
returning = "" if db.type == SQLITE else "RETURNING ID"
|
|
||||||
method = db.execute if db.type == SQLITE else db.fetchone
|
|
||||||
|
|
||||||
result = await (method)(
|
|
||||||
f"""
|
f"""
|
||||||
INSERT INTO tipjar.TipJars (
|
INSERT INTO tipjar.TipJars (
|
||||||
name,
|
name,
|
||||||
|
@ -46,16 +42,11 @@ async def create_tipjar(data: createTipJar) -> TipJar:
|
||||||
onchain
|
onchain
|
||||||
)
|
)
|
||||||
VALUES (?, ?, ?, ?)
|
VALUES (?, ?, ?, ?)
|
||||||
{returning}
|
|
||||||
""",
|
""",
|
||||||
(data.name, data.wallet, data.webhook, data.onchain),
|
(data.name, data.wallet, data.webhook, data.onchain),
|
||||||
)
|
)
|
||||||
if db.type == SQLITE:
|
row = await db.fetchone("SELECT * FROM tipjar.TipJars LIMIT 1")
|
||||||
tipjar_id = result._result_proxy.lastrowid
|
tipjar = TipJar(**row)
|
||||||
else:
|
|
||||||
tipjar_id = result[0]
|
|
||||||
|
|
||||||
tipjar = await get_tipjar(tipjar_id)
|
|
||||||
assert tipjar
|
assert tipjar
|
||||||
return tipjar
|
return tipjar
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,7 @@
|
||||||
from sqlite3 import Row
|
from sqlite3 import Row
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi.param_functions import Query
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
from pydantic.main import BaseModel
|
|
||||||
|
|
||||||
|
|
||||||
class CreateCharge(BaseModel):
|
|
||||||
onchainwallet: str = Query(None)
|
|
||||||
lnbitswallet: str = Query(None)
|
|
||||||
description: str = Query(...)
|
|
||||||
webhook: str = Query(None)
|
|
||||||
completelink: str = Query(None)
|
|
||||||
completelinktext: str = Query(None)
|
|
||||||
time: int = Query(..., ge=1)
|
|
||||||
amount: int = Query(..., ge=1)
|
|
||||||
|
|
||||||
|
|
||||||
class createTip(BaseModel):
|
class createTip(BaseModel):
|
||||||
|
@ -44,8 +31,8 @@ class Tip(BaseModel):
|
||||||
class createTipJar(BaseModel):
|
class createTipJar(BaseModel):
|
||||||
name: str
|
name: str
|
||||||
wallet: str
|
wallet: str
|
||||||
webhook: str = None
|
webhook: Optional[str]
|
||||||
onchain: str = None
|
onchain: Optional[str]
|
||||||
|
|
||||||
|
|
||||||
class createTips(BaseModel):
|
class createTips(BaseModel):
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi import Request
|
from fastapi import Depends, Request
|
||||||
from fastapi.param_functions import Query
|
from fastapi.param_functions import Query
|
||||||
from fastapi.params import Depends
|
|
||||||
from fastapi.templating import Jinja2Templates
|
from fastapi.templating import Jinja2Templates
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
|
||||||
from fastapi.param_functions import Query
|
from fastapi import Depends, Query
|
||||||
from fastapi.params import Depends
|
|
||||||
from starlette.exceptions import HTTPException
|
from starlette.exceptions import HTTPException
|
||||||
|
|
||||||
from lnbits.core.crud import get_user
|
from lnbits.core.crud import get_user
|
||||||
from lnbits.decorators import WalletTypeInfo, get_key_type
|
from lnbits.decorators import WalletTypeInfo, get_key_type
|
||||||
|
|
||||||
from ..satspay.crud import create_charge
|
from ..satspay.crud import create_charge
|
||||||
|
from ..satspay.models import CreateCharge
|
||||||
from . import tipjar_ext
|
from . import tipjar_ext
|
||||||
from .crud import (
|
from .crud import (
|
||||||
create_tip,
|
create_tip,
|
||||||
|
@ -22,7 +22,7 @@ from .crud import (
|
||||||
update_tipjar,
|
update_tipjar,
|
||||||
)
|
)
|
||||||
from .helpers import get_charge_details
|
from .helpers import get_charge_details
|
||||||
from .models import CreateCharge, createTipJar, createTips
|
from .models import createTip, createTipJar, createTips
|
||||||
|
|
||||||
|
|
||||||
@tipjar_ext.post("/api/v1/tipjars")
|
@tipjar_ext.post("/api/v1/tipjars")
|
||||||
|
@ -43,12 +43,16 @@ async def user_from_wallet(wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||||
@tipjar_ext.post("/api/v1/tips")
|
@tipjar_ext.post("/api/v1/tips")
|
||||||
async def api_create_tip(data: createTips):
|
async def api_create_tip(data: createTips):
|
||||||
"""Take data from tip form and return satspay charge"""
|
"""Take data from tip form and return satspay charge"""
|
||||||
sats = data.sats
|
sats = int(data.sats)
|
||||||
message = data.message
|
message = data.message
|
||||||
if not message:
|
if not message:
|
||||||
message = "No message"
|
message = "No message"
|
||||||
tipjar_id = data.tipjar
|
tipjar_id = int(data.tipjar)
|
||||||
tipjar = await get_tipjar(tipjar_id)
|
tipjar = await get_tipjar(tipjar_id)
|
||||||
|
if not tipjar:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=HTTPStatus.NOT_FOUND, detail="Tipjar does not exist."
|
||||||
|
)
|
||||||
|
|
||||||
webhook = tipjar.webhook
|
webhook = tipjar.webhook
|
||||||
charge_details = await get_charge_details(tipjar.id)
|
charge_details = await get_charge_details(tipjar.id)
|
||||||
|
@ -62,13 +66,14 @@ async def api_create_tip(data: createTips):
|
||||||
user=charge_details["user"],
|
user=charge_details["user"],
|
||||||
data=CreateCharge(
|
data=CreateCharge(
|
||||||
amount=sats,
|
amount=sats,
|
||||||
webhook=webhook,
|
webhook=webhook or "",
|
||||||
description=description,
|
description=description,
|
||||||
onchainwallet=charge_details["onchainwallet"],
|
onchainwallet=charge_details["onchainwallet"],
|
||||||
lnbitswallet=charge_details["lnbitswallet"],
|
lnbitswallet=charge_details["lnbitswallet"],
|
||||||
completelink=charge_details["completelink"],
|
completelink=charge_details["completelink"],
|
||||||
completelinktext=charge_details["completelinktext"],
|
completelinktext=charge_details["completelinktext"],
|
||||||
time=charge_details["time"],
|
time=charge_details["time"],
|
||||||
|
custom_css="",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -77,7 +82,7 @@ async def api_create_tip(data: createTips):
|
||||||
wallet=tipjar.wallet,
|
wallet=tipjar.wallet,
|
||||||
message=message,
|
message=message,
|
||||||
name=name,
|
name=name,
|
||||||
sats=data.sats,
|
sats=int(data.sats),
|
||||||
tipjar=data.tipjar,
|
tipjar=data.tipjar,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -87,28 +92,34 @@ async def api_create_tip(data: createTips):
|
||||||
@tipjar_ext.get("/api/v1/tipjars")
|
@tipjar_ext.get("/api/v1/tipjars")
|
||||||
async def api_get_tipjars(wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_get_tipjars(wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||||
"""Return list of all tipjars assigned to wallet with given invoice key"""
|
"""Return list of all tipjars assigned to wallet with given invoice key"""
|
||||||
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
|
user = await get_user(wallet.wallet.user)
|
||||||
|
if not user:
|
||||||
|
return []
|
||||||
tipjars = []
|
tipjars = []
|
||||||
for wallet_id in wallet_ids:
|
for wallet_id in user.wallet_ids:
|
||||||
new_tipjars = await get_tipjars(wallet_id)
|
new_tipjars = await get_tipjars(wallet_id)
|
||||||
tipjars += new_tipjars if new_tipjars else []
|
tipjars += new_tipjars if new_tipjars else []
|
||||||
return [tipjar.dict() for tipjar in tipjars] if tipjars else []
|
return [tipjar.dict() for tipjar in tipjars]
|
||||||
|
|
||||||
|
|
||||||
@tipjar_ext.get("/api/v1/tips")
|
@tipjar_ext.get("/api/v1/tips")
|
||||||
async def api_get_tips(wallet: WalletTypeInfo = Depends(get_key_type)):
|
async def api_get_tips(wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||||
"""Return list of all tips assigned to wallet with given invoice key"""
|
"""Return list of all tips assigned to wallet with given invoice key"""
|
||||||
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
|
user = await get_user(wallet.wallet.user)
|
||||||
|
if not user:
|
||||||
|
return []
|
||||||
tips = []
|
tips = []
|
||||||
for wallet_id in wallet_ids:
|
for wallet_id in user.wallet_ids:
|
||||||
new_tips = await get_tips(wallet_id)
|
new_tips = await get_tips(wallet_id)
|
||||||
tips += new_tips if new_tips else []
|
tips += new_tips if new_tips else []
|
||||||
return [tip.dict() for tip in tips] if tips else []
|
return [tip.dict() for tip in tips]
|
||||||
|
|
||||||
|
|
||||||
@tipjar_ext.put("/api/v1/tips/{tip_id}")
|
@tipjar_ext.put("/api/v1/tips/{tip_id}")
|
||||||
async def api_update_tip(
|
async def api_update_tip(
|
||||||
wallet: WalletTypeInfo = Depends(get_key_type), tip_id: str = Query(None)
|
data: createTip,
|
||||||
|
wallet: WalletTypeInfo = Depends(get_key_type),
|
||||||
|
tip_id: str = Query(None),
|
||||||
):
|
):
|
||||||
"""Update a tip with the data given in the request"""
|
"""Update a tip with the data given in the request"""
|
||||||
if tip_id:
|
if tip_id:
|
||||||
|
@ -125,7 +136,7 @@ async def api_update_tip(
|
||||||
status_code=HTTPStatus.FORBIDDEN, detail="Not your tip."
|
status_code=HTTPStatus.FORBIDDEN, detail="Not your tip."
|
||||||
)
|
)
|
||||||
|
|
||||||
tip = await update_tip(tip_id, **g.data)
|
tip = await update_tip(tip_id, **data.dict())
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST, detail="No tip ID specified"
|
status_code=HTTPStatus.BAD_REQUEST, detail="No tip ID specified"
|
||||||
|
@ -135,7 +146,9 @@ async def api_update_tip(
|
||||||
|
|
||||||
@tipjar_ext.put("/api/v1/tipjars/{tipjar_id}")
|
@tipjar_ext.put("/api/v1/tipjars/{tipjar_id}")
|
||||||
async def api_update_tipjar(
|
async def api_update_tipjar(
|
||||||
wallet: WalletTypeInfo = Depends(get_key_type), tipjar_id: str = Query(None)
|
data: createTipJar,
|
||||||
|
wallet: WalletTypeInfo = Depends(get_key_type),
|
||||||
|
tipjar_id: int = Query(None),
|
||||||
):
|
):
|
||||||
"""Update a tipjar with the data given in the request"""
|
"""Update a tipjar with the data given in the request"""
|
||||||
if tipjar_id:
|
if tipjar_id:
|
||||||
|
@ -151,7 +164,7 @@ async def api_update_tipjar(
|
||||||
status_code=HTTPStatus.FORBIDDEN, detail="Not your tipjar."
|
status_code=HTTPStatus.FORBIDDEN, detail="Not your tipjar."
|
||||||
)
|
)
|
||||||
|
|
||||||
tipjar = await update_tipjar(tipjar_id, **data)
|
tipjar = await update_tipjar(str(tipjar_id), **data.dict())
|
||||||
else:
|
else:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=HTTPStatus.BAD_REQUEST, detail="No tipjar ID specified"
|
status_code=HTTPStatus.BAD_REQUEST, detail="No tipjar ID specified"
|
||||||
|
@ -181,7 +194,7 @@ async def api_delete_tip(
|
||||||
|
|
||||||
@tipjar_ext.delete("/api/v1/tipjars/{tipjar_id}")
|
@tipjar_ext.delete("/api/v1/tipjars/{tipjar_id}")
|
||||||
async def api_delete_tipjar(
|
async def api_delete_tipjar(
|
||||||
wallet: WalletTypeInfo = Depends(get_key_type), tipjar_id: str = Query(None)
|
wallet: WalletTypeInfo = Depends(get_key_type), tipjar_id: int = Query(None)
|
||||||
):
|
):
|
||||||
"""Delete the tipjar with the given tipjar_id"""
|
"""Delete the tipjar with the given tipjar_id"""
|
||||||
tipjar = await get_tipjar(tipjar_id)
|
tipjar = await get_tipjar(tipjar_id)
|
||||||
|
|
|
@ -292,7 +292,7 @@ async def api_psbt_create(
|
||||||
|
|
||||||
|
|
||||||
@watchonly_ext.put("/api/v1/psbt/utxos")
|
@watchonly_ext.put("/api/v1/psbt/utxos")
|
||||||
async def api_psbt_extract_tx(
|
async def api_psbt_utxos_tx(
|
||||||
req: Request, w: WalletTypeInfo = Depends(require_admin_key)
|
req: Request, w: WalletTypeInfo = Depends(require_admin_key)
|
||||||
):
|
):
|
||||||
"""Extract previous unspent transaction outputs (tx_id, vout) from PSBT"""
|
"""Extract previous unspent transaction outputs (tx_id, vout) from PSBT"""
|
||||||
|
|
|
@ -117,7 +117,7 @@ async def print_qr(request: Request, link_id):
|
||||||
|
|
||||||
|
|
||||||
@withdraw_ext.get("/csv/{link_id}", response_class=HTMLResponse)
|
@withdraw_ext.get("/csv/{link_id}", response_class=HTMLResponse)
|
||||||
async def print_qr(request: Request, link_id):
|
async def csv(request: Request, link_id):
|
||||||
link = await get_withdraw_link(link_id)
|
link = await get_withdraw_link(link_id)
|
||||||
if not link:
|
if not link:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
|
|
|
@ -8,7 +8,6 @@ except ImportError: # pragma: nocover
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
import binascii
|
|
||||||
import hashlib
|
import hashlib
|
||||||
from os import environ, error
|
from os import environ, error
|
||||||
from typing import AsyncGenerator, Dict, Optional
|
from typing import AsyncGenerator, Dict, Optional
|
||||||
|
@ -229,8 +228,8 @@ class LndWallet(Wallet):
|
||||||
try:
|
try:
|
||||||
r_hash = hex_to_bytes(checking_id)
|
r_hash = hex_to_bytes(checking_id)
|
||||||
if len(r_hash) != 32:
|
if len(r_hash) != 32:
|
||||||
raise binascii.Error
|
raise ValueError
|
||||||
except binascii.Error:
|
except ValueError:
|
||||||
# this may happen if we switch between backend wallets
|
# this may happen if we switch between backend wallets
|
||||||
# that use different checking_id formats
|
# that use different checking_id formats
|
||||||
return PaymentStatus(None)
|
return PaymentStatus(None)
|
||||||
|
@ -250,8 +249,8 @@ class LndWallet(Wallet):
|
||||||
try:
|
try:
|
||||||
r_hash = hex_to_bytes(checking_id)
|
r_hash = hex_to_bytes(checking_id)
|
||||||
if len(r_hash) != 32:
|
if len(r_hash) != 32:
|
||||||
raise binascii.Error
|
raise ValueError
|
||||||
except binascii.Error:
|
except ValueError:
|
||||||
# this may happen if we switch between backend wallets
|
# this may happen if we switch between backend wallets
|
||||||
# that use different checking_id formats
|
# that use different checking_id formats
|
||||||
return PaymentStatus(None)
|
return PaymentStatus(None)
|
||||||
|
|
|
@ -94,7 +94,6 @@ exclude = """(?x)(
|
||||||
| ^lnbits/extensions/boltcards.
|
| ^lnbits/extensions/boltcards.
|
||||||
| ^lnbits/extensions/events.
|
| ^lnbits/extensions/events.
|
||||||
| ^lnbits/extensions/gerty.
|
| ^lnbits/extensions/gerty.
|
||||||
| ^lnbits/extensions/hivemind.
|
|
||||||
| ^lnbits/extensions/invoices.
|
| ^lnbits/extensions/invoices.
|
||||||
| ^lnbits/extensions/livestream.
|
| ^lnbits/extensions/livestream.
|
||||||
| ^lnbits/extensions/lnaddress.
|
| ^lnbits/extensions/lnaddress.
|
||||||
|
@ -102,15 +101,11 @@ exclude = """(?x)(
|
||||||
| ^lnbits/extensions/lnticket.
|
| ^lnbits/extensions/lnticket.
|
||||||
| ^lnbits/extensions/lnurldevice.
|
| ^lnbits/extensions/lnurldevice.
|
||||||
| ^lnbits/extensions/lnurlp.
|
| ^lnbits/extensions/lnurlp.
|
||||||
| ^lnbits/extensions/lnurlpayout.
|
|
||||||
| ^lnbits/extensions/nostrnip5.
|
|
||||||
| ^lnbits/extensions/offlineshop.
|
| ^lnbits/extensions/offlineshop.
|
||||||
| ^lnbits/extensions/paywall.
|
| ^lnbits/extensions/paywall.
|
||||||
| ^lnbits/extensions/satspay.
|
| ^lnbits/extensions/satspay.
|
||||||
| ^lnbits/extensions/scrub.
|
|
||||||
| ^lnbits/extensions/splitpayments.
|
| ^lnbits/extensions/splitpayments.
|
||||||
| ^lnbits/extensions/streamalerts.
|
| ^lnbits/extensions/streamalerts.
|
||||||
| ^lnbits/extensions/tipjar.
|
|
||||||
| ^lnbits/extensions/tpos.
|
| ^lnbits/extensions/tpos.
|
||||||
| ^lnbits/extensions/watchonly.
|
| ^lnbits/extensions/watchonly.
|
||||||
| ^lnbits/extensions/withdraw.
|
| ^lnbits/extensions/withdraw.
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import hashlib
|
import hashlib
|
||||||
from binascii import hexlify
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import pytest_asyncio
|
import pytest_asyncio
|
||||||
|
|
Loading…
Add table
Reference in a new issue