Merge branch 'main' into matthewcroughan/nixify
This commit is contained in:
+3
-5
@@ -1,21 +1,19 @@
|
||||
import asyncio
|
||||
|
||||
import uvloop
|
||||
from starlette.requests import Request
|
||||
|
||||
from loguru import logger
|
||||
from starlette.requests import Request
|
||||
|
||||
from .commands import migrate_databases
|
||||
from .settings import (
|
||||
DEBUG,
|
||||
HOST,
|
||||
LNBITS_COMMIT,
|
||||
LNBITS_DATA_FOLDER,
|
||||
LNBITS_DATABASE_URL,
|
||||
LNBITS_SITE_TITLE,
|
||||
HOST,
|
||||
PORT,
|
||||
WALLET,
|
||||
LNBITS_DATABASE_URL,
|
||||
LNBITS_DATA_FOLDER,
|
||||
)
|
||||
|
||||
uvloop.install()
|
||||
|
||||
+32
-8
@@ -1,11 +1,9 @@
|
||||
import asyncio
|
||||
import importlib
|
||||
import logging
|
||||
import sys
|
||||
import traceback
|
||||
import warnings
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from http import HTTPStatus
|
||||
|
||||
from fastapi import FastAPI, Request
|
||||
@@ -14,6 +12,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.middleware.gzip import GZipMiddleware
|
||||
from fastapi.responses import JSONResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from loguru import logger
|
||||
|
||||
import lnbits.settings
|
||||
from lnbits.core.tasks import register_task_listeners
|
||||
@@ -199,8 +198,33 @@ def register_exception_handlers(app: FastAPI):
|
||||
def configure_logger() -> None:
|
||||
logger.remove()
|
||||
log_level: str = "DEBUG" if lnbits.settings.DEBUG else "INFO"
|
||||
if lnbits.settings.DEBUG:
|
||||
fmt: str = "<green>{time:YYYY-MM-DD HH:mm:ss.SS}</green> | <level>{level: <6}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | <level>{message}</level>"
|
||||
else:
|
||||
fmt: str = "<green>{time:YYYY-MM-DD HH:mm:ss.SS}</green> | <level>{level}</level> | <level>{message}</level>"
|
||||
logger.add(sys.stderr, level=log_level, format=fmt)
|
||||
formatter = Formatter()
|
||||
logger.add(sys.stderr, level=log_level, format=formatter.format)
|
||||
|
||||
logging.getLogger("uvicorn").handlers = [InterceptHandler()]
|
||||
logging.getLogger("uvicorn.access").handlers = [InterceptHandler()]
|
||||
|
||||
|
||||
class Formatter:
|
||||
def __init__(self):
|
||||
self.padding = 0
|
||||
self.minimal_fmt: str = "<green>{time:YYYY-MM-DD HH:mm:ss.SS}</green> | <level>{level}</level> | <level>{message}</level>\n"
|
||||
if lnbits.settings.DEBUG:
|
||||
self.fmt: str = "<green>{time:YYYY-MM-DD HH:mm:ss.SS}</green> | <level>{level: <4}</level> | <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> | <level>{message}</level>\n"
|
||||
else:
|
||||
self.fmt: str = self.minimal_fmt
|
||||
|
||||
def format(self, record):
|
||||
function = "{function}".format(**record)
|
||||
if function == "emit": # uvicorn logs
|
||||
return self.minimal_fmt
|
||||
return self.fmt
|
||||
|
||||
|
||||
class InterceptHandler(logging.Handler):
|
||||
def emit(self, record):
|
||||
try:
|
||||
level = logger.level(record.levelname).name
|
||||
except ValueError:
|
||||
level = record.levelno
|
||||
logger.log(level, record.getMessage())
|
||||
|
||||
+8
-7
@@ -1,15 +1,16 @@
|
||||
import bitstring # type: ignore
|
||||
import re
|
||||
import hashlib
|
||||
from typing import List, NamedTuple, Optional
|
||||
from bech32 import bech32_encode, bech32_decode, CHARSET
|
||||
from ecdsa import SECP256k1, VerifyingKey # type: ignore
|
||||
from ecdsa.util import sigdecode_string # type: ignore
|
||||
from binascii import unhexlify
|
||||
import re
|
||||
import time
|
||||
from binascii import unhexlify
|
||||
from decimal import Decimal
|
||||
from typing import List, NamedTuple, Optional
|
||||
|
||||
import bitstring # type: ignore
|
||||
import embit
|
||||
import secp256k1
|
||||
from bech32 import CHARSET, bech32_decode, bech32_encode
|
||||
from ecdsa import SECP256k1, VerifyingKey # type: ignore
|
||||
from ecdsa.util import sigdecode_string # type: ignore
|
||||
|
||||
|
||||
class Route(NamedTuple):
|
||||
|
||||
+7
-6
@@ -1,18 +1,19 @@
|
||||
import asyncio
|
||||
import warnings
|
||||
import click
|
||||
import importlib
|
||||
import re
|
||||
import os
|
||||
import re
|
||||
import warnings
|
||||
|
||||
import click
|
||||
from loguru import logger
|
||||
|
||||
from .db import SQLITE, POSTGRES, COCKROACH
|
||||
from .core import db as core_db, migrations as core_migrations
|
||||
from .core import db as core_db
|
||||
from .core import migrations as core_migrations
|
||||
from .db import COCKROACH, POSTGRES, SQLITE
|
||||
from .helpers import (
|
||||
get_valid_extensions,
|
||||
get_css_vendored,
|
||||
get_js_vendored,
|
||||
get_valid_extensions,
|
||||
url_for_vendored,
|
||||
)
|
||||
from .settings import LNBITS_PATH
|
||||
|
||||
+5
-5
@@ -1,15 +1,15 @@
|
||||
import json
|
||||
import datetime
|
||||
from uuid import uuid4
|
||||
from typing import List, Optional, Dict, Any
|
||||
import json
|
||||
from typing import Any, Dict, List, Optional
|
||||
from urllib.parse import urlparse
|
||||
from uuid import uuid4
|
||||
|
||||
from lnbits import bolt11
|
||||
from lnbits.db import Connection, POSTGRES, COCKROACH
|
||||
from lnbits.db import COCKROACH, POSTGRES, Connection
|
||||
from lnbits.settings import DEFAULT_WALLET_NAME, LNBITS_ADMIN_USERS
|
||||
|
||||
from . import db
|
||||
from .models import User, Wallet, Payment, BalanceCheck
|
||||
from .models import BalanceCheck, Payment, User, Wallet
|
||||
|
||||
# accounts
|
||||
# --------
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import json
|
||||
import hmac
|
||||
import hashlib
|
||||
from lnbits.helpers import url_for
|
||||
import hmac
|
||||
import json
|
||||
from sqlite3 import Row
|
||||
from typing import Dict, List, NamedTuple, Optional
|
||||
|
||||
from ecdsa import SECP256k1, SigningKey # type: ignore
|
||||
from lnurl import encode as lnurl_encode # type: ignore
|
||||
from typing import List, NamedTuple, Optional, Dict
|
||||
from sqlite3 import Row
|
||||
from loguru import logger
|
||||
from pydantic import BaseModel
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from lnbits.helpers import url_for
|
||||
from lnbits.settings import WALLET
|
||||
|
||||
|
||||
|
||||
+20
-9
@@ -3,20 +3,25 @@ import json
|
||||
from binascii import unhexlify
|
||||
from io import BytesIO
|
||||
from typing import Dict, Optional, Tuple
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
import httpx
|
||||
from fastapi import Depends
|
||||
from lnurl import LnurlErrorResponse
|
||||
from lnurl import decode as decode_lnurl # type: ignore
|
||||
from loguru import logger
|
||||
|
||||
from lnbits import bolt11
|
||||
from lnbits.db import Connection
|
||||
from lnbits.decorators import (
|
||||
WalletTypeInfo,
|
||||
get_key_type,
|
||||
require_admin_key,
|
||||
require_invoice_key,
|
||||
)
|
||||
from lnbits.helpers import url_for, urlsafe_short_hash
|
||||
from lnbits.requestvars import g
|
||||
from lnbits.settings import WALLET
|
||||
from lnbits.settings import FAKE_WALLET, WALLET
|
||||
from lnbits.wallets.base import PaymentResponse, PaymentStatus
|
||||
|
||||
from . import db
|
||||
@@ -51,15 +56,19 @@ async def create_invoice(
|
||||
description_hash: Optional[bytes] = None,
|
||||
extra: Optional[Dict] = None,
|
||||
webhook: Optional[str] = None,
|
||||
internal: Optional[bool] = False,
|
||||
conn: Optional[Connection] = None,
|
||||
) -> Tuple[str, str]:
|
||||
invoice_memo = None if description_hash else memo
|
||||
|
||||
ok, checking_id, payment_request, error_message = await WALLET.create_invoice(
|
||||
# use the fake wallet if the invoice is for internal use only
|
||||
wallet = FAKE_WALLET if internal else WALLET
|
||||
|
||||
ok, checking_id, payment_request, error_message = await wallet.create_invoice(
|
||||
amount=amount, memo=invoice_memo, description_hash=description_hash
|
||||
)
|
||||
if not ok:
|
||||
raise InvoiceFailure(error_message or "Unexpected backend error.")
|
||||
raise InvoiceFailure(error_message or "unexpected backend error.")
|
||||
|
||||
invoice = bolt11.decode(payment_request)
|
||||
|
||||
@@ -229,7 +238,7 @@ async def redeem_lnurl_withdraw(
|
||||
conn=conn,
|
||||
)
|
||||
except:
|
||||
logger.warn(
|
||||
logger.warning(
|
||||
f"failed to create invoice on redeem_lnurl_withdraw from {lnurl}. params: {res}"
|
||||
)
|
||||
return None
|
||||
@@ -256,12 +265,14 @@ async def redeem_lnurl_withdraw(
|
||||
|
||||
|
||||
async def perform_lnurlauth(
|
||||
callback: str, conn: Optional[Connection] = None
|
||||
callback: str,
|
||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||
conn: Optional[Connection] = None,
|
||||
) -> Optional[LnurlErrorResponse]:
|
||||
cb = urlparse(callback)
|
||||
|
||||
k1 = unhexlify(parse_qs(cb.query)["k1"][0])
|
||||
key = g().wallet.lnurlauth_key(cb.netloc)
|
||||
key = wallet.wallet.lnurlauth_key(cb.netloc)
|
||||
|
||||
def int_to_bytes_suitable_der(x: int) -> bytes:
|
||||
"""for strict DER we need to encode the integer with some quirks"""
|
||||
|
||||
@@ -1,4 +1,36 @@
|
||||
new Vue({
|
||||
el: '#vue',
|
||||
data: function () {
|
||||
return {
|
||||
searchTerm: '',
|
||||
filteredExtensions: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.filteredExtensions = this.g.extensions
|
||||
},
|
||||
watch: {
|
||||
searchTerm(term) {
|
||||
// Reset the filter
|
||||
this.filteredExtensions = this.g.extensions
|
||||
if (term !== '') {
|
||||
// Filter the extensions list
|
||||
function extensionNameContains(searchTerm) {
|
||||
return function (extension) {
|
||||
return (
|
||||
extension.name.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
extension.shortDescription
|
||||
.toLowerCase()
|
||||
.includes(searchTerm.toLowerCase())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
this.filteredExtensions = this.filteredExtensions.filter(
|
||||
extensionNameContains(term)
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
mixins: [windowMixin]
|
||||
})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import asyncio
|
||||
import httpx
|
||||
from typing import List
|
||||
|
||||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
from lnbits.tasks import register_invoice_listener
|
||||
|
||||
@@ -49,7 +49,8 @@
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Body (application/json)</h5>
|
||||
<code
|
||||
>{"out": false, "amount": <int>, "memo": <string>, "unit":
|
||||
<string>, "webhook": <url:string>}</code
|
||||
<string>, "webhook": <url:string>, "internal":
|
||||
<bool>}</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">
|
||||
Returns 201 CREATED (application/json)
|
||||
|
||||
@@ -2,10 +2,23 @@
|
||||
%} {% block scripts %} {{ window_vars(user) }}
|
||||
<script src="/core/static/js/extensions.js"></script>
|
||||
{% endblock %} {% block page %}
|
||||
<div class="row q-col-gutter-md q-mb-md">
|
||||
<div class="col-sm-3 col-xs-8 q-ml-auto">
|
||||
<q-input v-model="searchTerm" label="Search extensions">
|
||||
<q-icon
|
||||
v-if="searchTerm !== ''"
|
||||
name="close"
|
||||
@click="searchTerm = ''"
|
||||
class="cursor-pointer q-mt-lg"
|
||||
/>
|
||||
</q-input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row q-col-gutter-md">
|
||||
<div
|
||||
class="col-6 col-md-4 col-lg-3"
|
||||
v-for="extension in g.extensions"
|
||||
v-for="extension in filteredExtensions"
|
||||
:key="extension.code"
|
||||
>
|
||||
<q-card>
|
||||
|
||||
+17
-19
@@ -7,30 +7,23 @@ from typing import Dict, List, Optional, Union
|
||||
from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse
|
||||
|
||||
import httpx
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from fastapi import Header, Query, Request
|
||||
from fastapi import Depends, Header, Query, Request
|
||||
from fastapi.exceptions import HTTPException
|
||||
from fastapi.param_functions import Depends
|
||||
from fastapi.params import Body
|
||||
from loguru import logger
|
||||
from pydantic import BaseModel
|
||||
from pydantic.fields import Field
|
||||
from sse_starlette.sse import EventSourceResponse
|
||||
|
||||
from lnbits import bolt11, lnurl
|
||||
from lnbits.bolt11 import Invoice
|
||||
from lnbits.core.models import Payment, Wallet
|
||||
from lnbits.decorators import (
|
||||
WalletAdminKeyChecker,
|
||||
WalletInvoiceKeyChecker,
|
||||
WalletTypeInfo,
|
||||
get_key_type,
|
||||
require_admin_key,
|
||||
require_invoice_key,
|
||||
)
|
||||
from lnbits.helpers import url_for, urlsafe_short_hash
|
||||
from lnbits.requestvars import g
|
||||
from lnbits.settings import LNBITS_ADMIN_USERS, LNBITS_SITE_TITLE
|
||||
from lnbits.utils.exchange_rates import (
|
||||
currencies,
|
||||
@@ -149,6 +142,7 @@ class CreateInvoiceData(BaseModel):
|
||||
lnurl_balance_check: Optional[str] = None
|
||||
extra: Optional[dict] = None
|
||||
webhook: Optional[str] = None
|
||||
internal: Optional[bool] = False
|
||||
bolt11: Optional[str] = None
|
||||
|
||||
|
||||
@@ -175,6 +169,7 @@ async def api_payments_create_invoice(data: CreateInvoiceData, wallet: Wallet):
|
||||
description_hash=description_hash,
|
||||
extra=data.extra,
|
||||
webhook=data.webhook,
|
||||
internal=data.internal,
|
||||
conn=conn,
|
||||
)
|
||||
except InvoiceFailure as e:
|
||||
@@ -395,7 +390,7 @@ async def api_payment(payment_hash, X_Api_Key: Optional[str] = Header(None)):
|
||||
wallet = None
|
||||
try:
|
||||
if X_Api_Key.extra:
|
||||
logger.warn("No key")
|
||||
logger.warning("No key")
|
||||
except:
|
||||
wallet = await get_wallet_for_key(X_Api_Key)
|
||||
payment = await get_standalone_payment(
|
||||
@@ -435,10 +430,8 @@ async def api_payment(payment_hash, X_Api_Key: Optional[str] = Header(None)):
|
||||
return {"paid": not payment.pending, "preimage": payment.preimage}
|
||||
|
||||
|
||||
@core_app.get(
|
||||
"/api/v1/lnurlscan/{code}", dependencies=[Depends(WalletInvoiceKeyChecker())]
|
||||
)
|
||||
async def api_lnurlscan(code: str):
|
||||
@core_app.get("/api/v1/lnurlscan/{code}")
|
||||
async def api_lnurlscan(code: str, wallet: WalletTypeInfo = Depends(get_key_type)):
|
||||
try:
|
||||
url = lnurl.decode(code)
|
||||
domain = urlparse(url).netloc
|
||||
@@ -466,7 +459,7 @@ async def api_lnurlscan(code: str):
|
||||
params.update(kind="auth")
|
||||
params.update(callback=url) # with k1 already in it
|
||||
|
||||
lnurlauth_key = g().wallet.lnurlauth_key(domain)
|
||||
lnurlauth_key = wallet.wallet.lnurlauth_key(domain)
|
||||
params.update(pubkey=lnurlauth_key.verifying_key.to_string("compressed").hex())
|
||||
else:
|
||||
async with httpx.AsyncClient() as client:
|
||||
@@ -582,14 +575,19 @@ async def api_payments_decode(data: DecodePayment):
|
||||
return {"message": "Failed to decode"}
|
||||
|
||||
|
||||
@core_app.post("/api/v1/lnurlauth", dependencies=[Depends(WalletAdminKeyChecker())])
|
||||
async def api_perform_lnurlauth(callback: str):
|
||||
err = await perform_lnurlauth(callback)
|
||||
class Callback(BaseModel):
|
||||
callback: str = Query(...)
|
||||
|
||||
|
||||
@core_app.post("/api/v1/lnurlauth")
|
||||
async def api_perform_lnurlauth(
|
||||
callback: Callback, wallet: WalletTypeInfo = Depends(require_admin_key)
|
||||
):
|
||||
err = await perform_lnurlauth(callback.callback, wallet=wallet)
|
||||
if err:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.SERVICE_UNAVAILABLE, detail=err.reason
|
||||
)
|
||||
|
||||
return ""
|
||||
|
||||
|
||||
|
||||
@@ -7,11 +7,10 @@ from fastapi.exceptions import HTTPException
|
||||
from fastapi.params import Depends, Query
|
||||
from fastapi.responses import FileResponse, RedirectResponse
|
||||
from fastapi.routing import APIRouter
|
||||
from loguru import logger
|
||||
from pydantic.types import UUID4
|
||||
from starlette.responses import HTMLResponse, JSONResponse
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from lnbits.core import db
|
||||
from lnbits.core.models import User
|
||||
from lnbits.decorators import check_user_exists
|
||||
@@ -113,7 +112,7 @@ async def wallet(
|
||||
|
||||
if not user_id:
|
||||
user = await get_user((await create_account()).id)
|
||||
logger.info(f"Created new account for user {user.id}")
|
||||
logger.info(f"Create user {user.id}")
|
||||
else:
|
||||
user = await get_user(user_id)
|
||||
if not user:
|
||||
@@ -140,7 +139,7 @@ async def wallet(
|
||||
status_code=status.HTTP_307_TEMPORARY_REDIRECT,
|
||||
)
|
||||
|
||||
logger.info(f"Access wallet {wallet_name} of user {user.id}")
|
||||
logger.debug(f"Access wallet {wallet_name}{'of user '+ user.id if user else ''}")
|
||||
wallet = user.get_wallet(wallet_id)
|
||||
if not wallet:
|
||||
return template_renderer().TemplateResponse(
|
||||
|
||||
@@ -4,11 +4,10 @@ from http import HTTPStatus
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from fastapi import HTTPException
|
||||
from loguru import logger
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import HTMLResponse
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from lnbits import bolt11
|
||||
|
||||
from .. import core_app
|
||||
|
||||
@@ -6,7 +6,6 @@ from contextlib import asynccontextmanager
|
||||
from typing import Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy_aio.base import AsyncConnection
|
||||
from sqlalchemy_aio.strategy import ASYNCIO_STRATEGY # type: ignore
|
||||
|
||||
@@ -14,9 +14,9 @@ from lnbits.core.crud import get_user, get_wallet_for_key
|
||||
from lnbits.core.models import User, Wallet
|
||||
from lnbits.requestvars import g
|
||||
from lnbits.settings import (
|
||||
LNBITS_ALLOWED_USERS,
|
||||
LNBITS_ADMIN_USERS,
|
||||
LNBITS_ADMIN_EXTENSIONS,
|
||||
LNBITS_ADMIN_USERS,
|
||||
LNBITS_ALLOWED_USERS,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import httpx
|
||||
import json
|
||||
import os
|
||||
|
||||
import httpx
|
||||
|
||||
fiat_currencies = json.load(
|
||||
open(
|
||||
os.path.join(
|
||||
|
||||
@@ -3,9 +3,8 @@ import math
|
||||
import traceback
|
||||
from http import HTTPStatus
|
||||
|
||||
from starlette.requests import Request
|
||||
|
||||
from loguru import logger
|
||||
from starlette.requests import Request
|
||||
|
||||
from . import bleskomat_ext
|
||||
from .crud import (
|
||||
|
||||
@@ -3,13 +3,12 @@ import time
|
||||
from typing import Dict
|
||||
|
||||
from fastapi.params import Query
|
||||
from loguru import logger
|
||||
from pydantic import BaseModel, validator
|
||||
from starlette.requests import Request
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from lnbits import bolt11
|
||||
from lnbits.core.services import pay_invoice, PaymentFailure
|
||||
from lnbits.core.services import PaymentFailure, pay_invoice
|
||||
|
||||
from . import db
|
||||
from .exchange_rates import exchange_rate_providers, fiat_currencies
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
from http import HTTPStatus
|
||||
|
||||
from fastapi import Depends, Query
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from loguru import logger
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from lnbits.core.crud import get_user
|
||||
from lnbits.decorators import WalletTypeInfo, require_admin_key
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult
|
||||
from starlette.requests import Request
|
||||
from fastapi.param_functions import Query
|
||||
from typing import Optional, Dict
|
||||
from lnbits.lnurl import encode as lnurl_encode # type: ignore
|
||||
from lnurl.types import LnurlPayMetadata # type: ignore
|
||||
from pydantic import BaseModel
|
||||
import json
|
||||
from sqlite3 import Row
|
||||
from typing import Dict, Optional
|
||||
from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse
|
||||
|
||||
from fastapi.param_functions import Query
|
||||
from lnurl.types import LnurlPayMetadata # type: ignore
|
||||
from pydantic import BaseModel
|
||||
from starlette.requests import Request
|
||||
|
||||
from lnbits.lnurl import encode as lnurl_encode # type: ignore
|
||||
|
||||
|
||||
class CreateCopilotData(BaseModel):
|
||||
|
||||
@@ -25,7 +25,7 @@ async def wait_for_paid_invoices():
|
||||
async def on_invoice_paid(payment: Payment) -> None:
|
||||
webhook = None
|
||||
data = None
|
||||
if "copilot" != payment.extra.get("tag"):
|
||||
if payment.extra.get("tag") != "copilot":
|
||||
# not an copilot invoice
|
||||
return
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from sqlite3 import Row
|
||||
from typing import Optional
|
||||
|
||||
from fastapi.param_functions import Query
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class CreateUserData(BaseModel):
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
from typing import NamedTuple
|
||||
from sqlite3 import Row
|
||||
from typing import NamedTuple, Optional
|
||||
|
||||
from fastapi.param_functions import Query
|
||||
from pydantic.main import BaseModel
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
from pydantic.main import BaseModel
|
||||
|
||||
|
||||
class CreateJukeLinkData(BaseModel):
|
||||
|
||||
@@ -16,7 +16,7 @@ async def wait_for_paid_invoices():
|
||||
|
||||
|
||||
async def on_invoice_paid(payment: Payment) -> None:
|
||||
if "jukebox" != payment.extra.get("tag"):
|
||||
if payment.extra.get("tag") != "jukebox":
|
||||
# not a jukebox invoice
|
||||
return
|
||||
await update_jukebox_payment(payment.payment_hash, paid=True)
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
>
|
||||
<q-step
|
||||
:name="1"
|
||||
title="Pick wallet, price"
|
||||
title="1. Pick Wallet and Price"
|
||||
icon="account_balance_wallet"
|
||||
:done="step > 1"
|
||||
>
|
||||
@@ -170,16 +170,25 @@
|
||||
<br />
|
||||
</q-step>
|
||||
|
||||
<q-step :name="2" title="Add api keys" icon="vpn_key" :done="step > 2">
|
||||
<q-step
|
||||
:name="2"
|
||||
title="2. Add API keys"
|
||||
icon="vpn_key"
|
||||
:done="step > 2"
|
||||
>
|
||||
<img src="/jukebox/static/spotapi.gif" />
|
||||
To use this extension you need a Spotify client ID and client secret.
|
||||
You get these by creating an app in the Spotify developers dashboard
|
||||
<a
|
||||
You get these by creating an app in the Spotify Developer Dashboard
|
||||
<br />
|
||||
<br />
|
||||
<q-btn
|
||||
type="a"
|
||||
target="_blank"
|
||||
style="color: #43a047"
|
||||
color="primary"
|
||||
href="https://developer.spotify.com/dashboard/applications"
|
||||
>here</a
|
||||
>.
|
||||
>Open the Spotify Developer Dashboard</q-btn
|
||||
>
|
||||
|
||||
<q-input
|
||||
filled
|
||||
class="q-pb-md q-pt-md"
|
||||
@@ -231,28 +240,39 @@
|
||||
<br />
|
||||
</q-step>
|
||||
|
||||
<q-step :name="3" title="Add Redirect URI" icon="link" :done="step > 3">
|
||||
<q-step
|
||||
:name="3"
|
||||
title="3. Add Redirect URI"
|
||||
icon="link"
|
||||
:done="step > 3"
|
||||
>
|
||||
<img src="/jukebox/static/spotapi1.gif" />
|
||||
In the app go to edit-settings, set the redirect URI to this link
|
||||
<p>
|
||||
In the app go to edit-settings, set the redirect URI to this link
|
||||
</p>
|
||||
<q-card
|
||||
class="cursor-pointer word-break"
|
||||
@click="copyText(locationcb + jukeboxDialog.data.sp_id, 'Link copied to clipboard!')"
|
||||
>
|
||||
<q-card-section style="word-break: break-all">
|
||||
{% raw %}{{ locationcb }}{{ jukeboxDialog.data.sp_id }}{% endraw
|
||||
%}
|
||||
</q-card-section>
|
||||
<q-tooltip> Click to copy URL </q-tooltip>
|
||||
</q-card>
|
||||
<br />
|
||||
<q-btn
|
||||
dense
|
||||
outline
|
||||
unelevated
|
||||
color="primary"
|
||||
size="xs"
|
||||
@click="copyText(locationcb + jukeboxDialog.data.sp_id, 'Link copied to clipboard!')"
|
||||
>{% raw %}{{ locationcb }}{{ jukeboxDialog.data.sp_id }}{% endraw
|
||||
%}<q-tooltip> Click to copy URL </q-tooltip>
|
||||
</q-btn>
|
||||
<br />
|
||||
Settings can be found
|
||||
<a
|
||||
type="a"
|
||||
target="_blank"
|
||||
style="color: #43a047"
|
||||
color="primary"
|
||||
href="https://developer.spotify.com/dashboard/applications"
|
||||
>here</a
|
||||
>.
|
||||
>Open the Spotify Application Settings</q-btn
|
||||
>
|
||||
<br /><br />
|
||||
<p>
|
||||
After adding the redirect URI, click the "Authorise access" button
|
||||
below.
|
||||
</p>
|
||||
|
||||
<div class="row q-mt-md">
|
||||
<div class="col-4">
|
||||
@@ -281,7 +301,7 @@
|
||||
|
||||
<q-step
|
||||
:name="4"
|
||||
title="Select playlists"
|
||||
title="4. Select Device and Playlists"
|
||||
icon="queue_music"
|
||||
active-color="primary"
|
||||
:done="step > 4"
|
||||
|
||||
@@ -22,7 +22,7 @@ async def wait_for_paid_invoices():
|
||||
|
||||
|
||||
async def on_invoice_paid(payment: Payment) -> None:
|
||||
if "livestream" != payment.extra.get("tag"):
|
||||
if payment.extra.get("tag") != "livestream":
|
||||
# not a livestream invoice
|
||||
return
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from http import HTTPStatus
|
||||
|
||||
# from mmap import MAP_DENYWRITE
|
||||
|
||||
from fastapi.param_functions import Depends
|
||||
from fastapi.params import Query
|
||||
from starlette.exceptions import HTTPException
|
||||
@@ -15,6 +13,8 @@ from lnbits.decorators import check_user_exists
|
||||
from . import livestream_ext, livestream_renderer
|
||||
from .crud import get_livestream_by_track, get_track
|
||||
|
||||
# from mmap import MAP_DENYWRITE
|
||||
|
||||
|
||||
@livestream_ext.get("/", response_class=HTMLResponse)
|
||||
async def index(request: Request, user: User = Depends(check_user_exists)):
|
||||
|
||||
@@ -3,15 +3,13 @@ import json
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import httpx
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from fastapi.params import Query
|
||||
from lnurl import ( # type: ignore
|
||||
LnurlErrorResponse,
|
||||
LnurlPayActionResponse,
|
||||
LnurlPayResponse,
|
||||
)
|
||||
from loguru import logger
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import HTMLResponse
|
||||
|
||||
|
||||
@@ -43,13 +43,13 @@ async def call_webhook_on_paid(payment_hash):
|
||||
|
||||
|
||||
async def on_invoice_paid(payment: Payment) -> None:
|
||||
if "lnaddress" == payment.extra.get("tag"):
|
||||
if payment.extra.get("tag") == "lnaddress":
|
||||
|
||||
await payment.set_pending(False)
|
||||
await set_address_paid(payment_hash=payment.payment_hash)
|
||||
await call_webhook_on_paid(payment_hash=payment.payment_hash)
|
||||
|
||||
elif "renew lnaddress" == payment.extra.get("tag"):
|
||||
elif payment.extra.get("tag") == "renew lnaddress":
|
||||
|
||||
await payment.set_pending(False)
|
||||
await set_address_renewed(
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
from base64 import b64decode
|
||||
from fastapi.param_functions import Security
|
||||
|
||||
from fastapi.security.api_key import APIKeyHeader
|
||||
|
||||
from fastapi import Request, status
|
||||
from fastapi.param_functions import Security
|
||||
from fastapi.security.api_key import APIKeyHeader
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from lnbits.decorators import WalletTypeInfo, get_key_type # type: ignore
|
||||
|
||||
|
||||
api_key_header_auth = APIKeyHeader(
|
||||
name="AUTHORIZATION",
|
||||
auto_error=False,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
from lnbits.decorators import check_user_exists
|
||||
from . import lndhub_ext, lndhub_renderer
|
||||
from fastapi import Request
|
||||
from fastapi.params import Depends
|
||||
|
||||
from lnbits.core.models import User
|
||||
from lnbits.decorators import check_user_exists
|
||||
|
||||
from . import lndhub_ext, lndhub_renderer
|
||||
|
||||
|
||||
@lndhub_ext.get("/")
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import time
|
||||
import asyncio
|
||||
|
||||
import time
|
||||
from base64 import urlsafe_b64encode
|
||||
from http import HTTPStatus
|
||||
|
||||
@@ -13,7 +12,7 @@ from lnbits import bolt11
|
||||
from lnbits.core.crud import delete_expired_invoices, get_payments
|
||||
from lnbits.core.services import create_invoice, pay_invoice
|
||||
from lnbits.decorators import WalletTypeInfo
|
||||
from lnbits.settings import WALLET, LNBITS_SITE_TITLE
|
||||
from lnbits.settings import LNBITS_SITE_TITLE, WALLET
|
||||
|
||||
from . import lndhub_ext
|
||||
from .decorators import check_wallet, require_admin_key
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from lnbits.core.models import Wallet
|
||||
from typing import List, Optional, Union
|
||||
|
||||
import httpx
|
||||
|
||||
from lnbits.core.models import Wallet
|
||||
from lnbits.helpers import urlsafe_short_hash
|
||||
|
||||
from . import db
|
||||
from .models import CreateFormData, CreateTicketData, Tickets, Forms
|
||||
import httpx
|
||||
from .models import CreateFormData, CreateTicketData, Forms, Tickets
|
||||
|
||||
|
||||
async def create_ticket(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from typing import Optional
|
||||
|
||||
from fastapi.param_functions import Query
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ async def wait_for_paid_invoices():
|
||||
|
||||
|
||||
async def on_invoice_paid(payment: Payment) -> None:
|
||||
if "lnticket" != payment.extra.get("tag"):
|
||||
if payment.extra.get("tag") != "lnticket":
|
||||
# not a lnticket invoice
|
||||
return
|
||||
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
from http import HTTPStatus
|
||||
from io import BytesIO
|
||||
from typing import Optional
|
||||
|
||||
from embit import bech32
|
||||
from embit import compact
|
||||
import base64
|
||||
from io import BytesIO
|
||||
import hmac
|
||||
|
||||
from embit import bech32, compact
|
||||
from fastapi import Request
|
||||
from fastapi.param_functions import Query
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from lnbits.core.services import create_invoice
|
||||
from lnbits.utils.exchange_rates import fiat_amount_as_satoshis
|
||||
from lnbits.core.views.api import pay_invoice
|
||||
|
||||
from lnbits.utils.exchange_rates import fiat_amount_as_satoshis
|
||||
|
||||
from . import lnurldevice_ext
|
||||
from .crud import (
|
||||
create_lnurldevicepayment,
|
||||
get_lnurldevice,
|
||||
get_lnurldevicepayment,
|
||||
update_lnurldevicepayment,
|
||||
get_lnurlpayload,
|
||||
update_lnurldevicepayment,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ async def m001_initial(db):
|
||||
|
||||
async def m002_redux(db):
|
||||
"""
|
||||
Moves everything from lnurlpos to lnurldevices
|
||||
Moves everything from lnurlpos to lnurldevice
|
||||
"""
|
||||
try:
|
||||
for row in [
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
<q-card-section>
|
||||
<code
|
||||
><span class="text-blue">GET</span>
|
||||
/lnurldevice/api/v1/lnurlposs</code
|
||||
/lnurldevice/api/v1/lnurlpos</code
|
||||
>
|
||||
<h5 class="text-caption q-mt-sm q-mb-none">Headers</h5>
|
||||
<code>{"X-Api-Key": <invoice_key>}</code><br />
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from lnbits.db import SQLITE
|
||||
|
||||
from . import db
|
||||
from .models import PayLink, CreatePayLinkData
|
||||
from .models import CreatePayLinkData, PayLink
|
||||
|
||||
|
||||
async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink:
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import json
|
||||
from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult
|
||||
from starlette.requests import Request
|
||||
from fastapi.param_functions import Query
|
||||
from typing import Optional, Dict
|
||||
from lnbits.lnurl import encode as lnurl_encode # type: ignore
|
||||
from lnurl.types import LnurlPayMetadata # type: ignore
|
||||
from sqlite3 import Row
|
||||
from typing import Dict, Optional
|
||||
from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse
|
||||
|
||||
from fastapi.param_functions import Query
|
||||
from lnurl.types import LnurlPayMetadata # type: ignore
|
||||
from pydantic import BaseModel
|
||||
from starlette.requests import Request
|
||||
|
||||
from lnbits.lnurl import encode as lnurl_encode # type: ignore
|
||||
|
||||
|
||||
class CreatePayLinkData(BaseModel):
|
||||
|
||||
@@ -35,6 +35,7 @@ new Vue({
|
||||
rowsPerPage: 10
|
||||
}
|
||||
},
|
||||
nfcTagWriting: false,
|
||||
formDialog: {
|
||||
show: false,
|
||||
fixedAmount: true,
|
||||
@@ -205,6 +206,42 @@ new Vue({
|
||||
.catch(err => {
|
||||
LNbits.utils.notifyApiError(err)
|
||||
})
|
||||
},
|
||||
writeNfcTag: async function (lnurl) {
|
||||
try {
|
||||
if (typeof NDEFReader == 'undefined') {
|
||||
throw {
|
||||
toString: function () {
|
||||
return 'NFC not supported on this device or browser.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ndef = new NDEFReader()
|
||||
|
||||
this.nfcTagWriting = true
|
||||
this.$q.notify({
|
||||
message: 'Tap your NFC tag to write the LNURL-pay link to it.'
|
||||
})
|
||||
|
||||
await ndef.write({
|
||||
records: [{recordType: 'url', data: 'lightning:' + lnurl, lang: 'en'}]
|
||||
})
|
||||
|
||||
this.nfcTagWriting = false
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'NFC tag written successfully.'
|
||||
})
|
||||
} catch (error) {
|
||||
this.nfcTagWriting = false
|
||||
this.$q.notify({
|
||||
type: 'negative',
|
||||
message: error
|
||||
? error.toString()
|
||||
: 'An unexpected error has occurred.'
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
import httpx
|
||||
|
||||
from lnbits.core import db as core_db
|
||||
@@ -19,7 +20,7 @@ async def wait_for_paid_invoices():
|
||||
|
||||
|
||||
async def on_invoice_paid(payment: Payment) -> None:
|
||||
if "lnurlp" != payment.extra.get("tag"):
|
||||
if payment.extra.get("tag") != "lnurlp":
|
||||
# not an lnurlp invoice
|
||||
return
|
||||
|
||||
|
||||
@@ -14,10 +14,17 @@
|
||||
</q-responsive>
|
||||
</a>
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
<div class="row q-mt-lg q-gutter-sm">
|
||||
<q-btn outline color="grey" @click="copyText('{{ lnurl }}')"
|
||||
>Copy LNURL</q-btn
|
||||
>
|
||||
<q-btn
|
||||
outline
|
||||
color="grey"
|
||||
icon="nfc"
|
||||
@click="writeNfcTag(' {{ lnurl }} ')"
|
||||
:disable="nfcTagWriting"
|
||||
></q-btn>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
@@ -99,7 +99,8 @@
|
||||
@click="openUpdateDialog(props.row.id)"
|
||||
icon="edit"
|
||||
color="light-blue"
|
||||
></q-btn>
|
||||
>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
flat
|
||||
dense
|
||||
@@ -153,7 +154,8 @@
|
||||
v-model.trim="formDialog.data.description"
|
||||
type="text"
|
||||
label="Item description *"
|
||||
></q-input>
|
||||
>
|
||||
</q-input>
|
||||
<div class="row q-col-gutter-sm">
|
||||
<q-input
|
||||
filled
|
||||
@@ -171,7 +173,8 @@
|
||||
type="number"
|
||||
:step="formDialog.data.currency && formDialog.data.currency !== 'satoshis' ? '0.01' : '1'"
|
||||
label="Max *"
|
||||
></q-input>
|
||||
>
|
||||
</q-input>
|
||||
</div>
|
||||
<div class="row q-col-gutter-sm">
|
||||
<div class="col">
|
||||
@@ -200,7 +203,8 @@
|
||||
type="number"
|
||||
label="Comment maximum characters"
|
||||
hint="Tell wallets to prompt users for a comment that will be sent along with the payment. LNURLp will store the comment and send it in the webhook."
|
||||
></q-input>
|
||||
>
|
||||
</q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
@@ -224,7 +228,8 @@
|
||||
type="text"
|
||||
label="Success URL (optional)"
|
||||
hint="Will be shown as a clickable link to the user in his wallet after a successful payment, appended by the payment_hash as a query string."
|
||||
></q-input>
|
||||
>
|
||||
</q-input>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn
|
||||
v-if="formDialog.data.id"
|
||||
@@ -294,6 +299,14 @@
|
||||
@click="copyText(qrCodeDialog.data.pay_url, 'Link copied to clipboard!')"
|
||||
>Shareable link</q-btn
|
||||
>
|
||||
<q-btn
|
||||
outline
|
||||
color="grey"
|
||||
icon="nfc"
|
||||
@click="writeNfcTag(qrCodeDialog.data.lnurl)"
|
||||
:disable="nfcTagWriting"
|
||||
>
|
||||
</q-btn>
|
||||
<q-btn
|
||||
outline
|
||||
color="grey"
|
||||
|
||||
@@ -73,6 +73,7 @@ async def api_link_retrieve(
|
||||
@lnurlp_ext.put("/api/v1/links/{link_id}", status_code=HTTPStatus.OK)
|
||||
async def api_link_create_or_update(
|
||||
data: CreatePayLinkData,
|
||||
request: Request,
|
||||
link_id=None,
|
||||
wallet: WalletTypeInfo = Depends(get_key_type),
|
||||
):
|
||||
@@ -117,7 +118,7 @@ async def api_link_create_or_update(
|
||||
link = await update_pay_link(**data.dict(), link_id=link_id)
|
||||
else:
|
||||
link = await create_pay_link(data, wallet_id=wallet.wallet.id)
|
||||
return {**link.dict(), "lnurl": link.lnurl}
|
||||
return {**link.dict(), "lnurl": link.lnurl(request)}
|
||||
|
||||
|
||||
@lnurlp_ext.delete("/api/v1/links/{link_id}")
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import asyncio
|
||||
|
||||
from fastapi import APIRouter
|
||||
|
||||
from lnbits.db import Database
|
||||
|
||||
@@ -3,7 +3,7 @@ from typing import List, Optional, Union
|
||||
from lnbits.helpers import urlsafe_short_hash
|
||||
|
||||
from . import db
|
||||
from .models import lnurlpayout, CreateLnurlPayoutData
|
||||
from .models import CreateLnurlPayoutData, lnurlpayout
|
||||
|
||||
|
||||
async def create_lnurlpayout(
|
||||
|
||||
@@ -2,9 +2,7 @@ import asyncio
|
||||
from http import HTTPStatus
|
||||
|
||||
import httpx
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from lnbits.core import db as core_db
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from typing import List, Optional
|
||||
|
||||
from lnbits.db import SQLITE
|
||||
|
||||
from . import db
|
||||
from .models import Item, Shop
|
||||
from .wordlists import animals
|
||||
from .models import Shop, Item
|
||||
|
||||
|
||||
async def create_shop(*, wallet_id: str) -> int:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import base64
|
||||
import struct
|
||||
import hmac
|
||||
import struct
|
||||
import time
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
import json
|
||||
import base64
|
||||
import hashlib
|
||||
import json
|
||||
from collections import OrderedDict
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
from typing import Optional, List, Dict
|
||||
from lnurl import encode as lnurl_encode # type: ignore
|
||||
from lnurl.types import LnurlPayMetadata # type: ignore
|
||||
from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore
|
||||
from lnurl.types import LnurlPayMetadata # type: ignore
|
||||
from pydantic import BaseModel
|
||||
from starlette.requests import Request
|
||||
|
||||
from .helpers import totp
|
||||
|
||||
shop_counters: Dict = {}
|
||||
|
||||
@@ -3,18 +3,18 @@ from datetime import datetime
|
||||
from http import HTTPStatus
|
||||
from typing import List
|
||||
|
||||
from fastapi import HTTPException, Request
|
||||
from fastapi.params import Depends, Query
|
||||
from starlette.responses import HTMLResponse
|
||||
|
||||
from lnbits.decorators import check_user_exists
|
||||
from lnbits.core.models import Payment, User
|
||||
from lnbits.core.crud import get_standalone_payment
|
||||
from lnbits.core.models import Payment, User
|
||||
from lnbits.core.views.api import api_payment
|
||||
from lnbits.decorators import check_user_exists
|
||||
|
||||
from . import offlineshop_ext, offlineshop_renderer
|
||||
from .models import Item
|
||||
from .crud import get_item, get_shop
|
||||
from fastapi import Request, HTTPException
|
||||
from .models import Item
|
||||
|
||||
|
||||
@offlineshop_ext.get("/", response_class=HTMLResponse)
|
||||
|
||||
@@ -19,7 +19,7 @@ async def wait_for_paid_invoices():
|
||||
|
||||
|
||||
async def on_invoice_paid(payment: Payment) -> None:
|
||||
if "charge" != payment.extra.get("tag"):
|
||||
if payment.extra.get("tag") != "charge":
|
||||
# not a charge invoice
|
||||
return
|
||||
|
||||
|
||||
@@ -14,3 +14,41 @@ async def m001_initial(db):
|
||||
);
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
async def m002_float_percent(db):
|
||||
"""
|
||||
Add float percent and migrates the existing data.
|
||||
"""
|
||||
await db.execute("ALTER TABLE splitpayments.targets RENAME TO splitpayments_old")
|
||||
await db.execute(
|
||||
"""
|
||||
CREATE TABLE splitpayments.targets (
|
||||
wallet TEXT NOT NULL,
|
||||
source TEXT NOT NULL,
|
||||
percent REAL NOT NULL CHECK (percent >= 0 AND percent <= 100),
|
||||
alias TEXT,
|
||||
|
||||
UNIQUE (source, wallet)
|
||||
);
|
||||
"""
|
||||
)
|
||||
|
||||
for row in [
|
||||
list(row)
|
||||
for row in await db.fetchall("SELECT * FROM splitpayments.splitpayments_old")
|
||||
]:
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO splitpayments.targets (
|
||||
wallet,
|
||||
source,
|
||||
percent,
|
||||
alias
|
||||
)
|
||||
VALUES (?, ?, ?, ?)
|
||||
""",
|
||||
(row[0], row[1], row[2], row[3]),
|
||||
)
|
||||
|
||||
await db.execute("DROP TABLE splitpayments.splitpayments_old")
|
||||
|
||||
@@ -7,14 +7,14 @@ from pydantic import BaseModel
|
||||
class Target(BaseModel):
|
||||
wallet: str
|
||||
source: str
|
||||
percent: int
|
||||
percent: float
|
||||
alias: Optional[str]
|
||||
|
||||
|
||||
class TargetPutList(BaseModel):
|
||||
wallet: str = Query(...)
|
||||
alias: str = Query("")
|
||||
percent: int = Query(..., ge=1)
|
||||
percent: float = Query(..., ge=0.01)
|
||||
|
||||
|
||||
class TargetPut(BaseModel):
|
||||
|
||||
@@ -105,7 +105,7 @@ new Vue({
|
||||
if (currentTotal > 100 && isPercent) {
|
||||
let diff = (currentTotal - 100) / (100 - this.targets[index].percent)
|
||||
this.targets.forEach((target, t) => {
|
||||
if (t !== index) target.percent -= Math.round(diff * target.percent)
|
||||
if (t !== index) target.percent -= +(diff * target.percent).toFixed(2)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ async def wait_for_paid_invoices():
|
||||
|
||||
|
||||
async def on_invoice_paid(payment: Payment) -> None:
|
||||
if "splitpayments" == payment.extra.get("tag") or payment.extra.get("splitted"):
|
||||
if payment.extra.get("tag") == "splitpayments" or payment.extra.get("splitted"):
|
||||
# already splitted, ignore
|
||||
return
|
||||
|
||||
|
||||
@@ -58,14 +58,14 @@
|
||||
></q-input>
|
||||
</div>
|
||||
|
||||
<q-row class="row justify-evenly q-pa-lg">
|
||||
<q-col>
|
||||
<div class="row justify-evenly q-pa-lg">
|
||||
<div>
|
||||
<q-btn unelevated outline color="secondary" @click="clearTargets">
|
||||
Clear
|
||||
</q-btn>
|
||||
</q-col>
|
||||
</div>
|
||||
|
||||
<q-col>
|
||||
<div>
|
||||
<q-btn
|
||||
unelevated
|
||||
color="primary"
|
||||
@@ -74,8 +74,8 @@
|
||||
>
|
||||
Save Targets
|
||||
</q-btn>
|
||||
</q-col>
|
||||
</q-row>
|
||||
</div>
|
||||
</div>
|
||||
</q-form>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import json
|
||||
|
||||
import httpx
|
||||
|
||||
from lnbits.extensions.subdomains.models import Domains
|
||||
import httpx, json
|
||||
|
||||
|
||||
async def cloudflare_create_subdomain(
|
||||
|
||||
@@ -19,7 +19,7 @@ async def wait_for_paid_invoices():
|
||||
|
||||
|
||||
async def on_invoice_paid(payment: Payment) -> None:
|
||||
if "lnsubdomain" != payment.extra.get("tag"):
|
||||
if payment.extra.get("tag") != "lnsubdomain":
|
||||
# not an lnurlp invoice
|
||||
return
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ def tpos_renderer():
|
||||
|
||||
|
||||
from .tasks import wait_for_paid_invoices
|
||||
from .views_api import * # noqa
|
||||
from .views import * # noqa
|
||||
from .views_api import * # noqa
|
||||
|
||||
|
||||
def tpos_start():
|
||||
|
||||
@@ -20,7 +20,7 @@ async def wait_for_paid_invoices():
|
||||
|
||||
|
||||
async def on_invoice_paid(payment: Payment) -> None:
|
||||
if "tpos" == payment.extra.get("tag") and payment.extra.get("tipSplitted"):
|
||||
if payment.extra.get("tag") == "tpos" and payment.extra.get("tipSplitted"):
|
||||
# already splitted, ignore
|
||||
return
|
||||
|
||||
|
||||
@@ -8,10 +8,7 @@ from starlette.responses import HTMLResponse
|
||||
|
||||
from lnbits.core.models import User
|
||||
from lnbits.decorators import check_user_exists
|
||||
from lnbits.settings import (
|
||||
LNBITS_CUSTOM_LOGO,
|
||||
LNBITS_SITE_TITLE,
|
||||
)
|
||||
from lnbits.settings import LNBITS_CUSTOM_LOGO, LNBITS_SITE_TITLE
|
||||
|
||||
from . import tpos_ext, tpos_renderer
|
||||
from .crud import get_tpos
|
||||
|
||||
@@ -2,9 +2,8 @@ from http import HTTPStatus
|
||||
|
||||
from fastapi import Query
|
||||
from fastapi.params import Depends
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from loguru import logger
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from lnbits.core.crud import get_user
|
||||
from lnbits.core.services import create_invoice
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from sqlite3 import Row
|
||||
from typing import Optional
|
||||
|
||||
from fastapi.param_functions import Query
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional
|
||||
|
||||
|
||||
class CreateUserData(BaseModel):
|
||||
|
||||
@@ -75,7 +75,7 @@ async def api_usermanager_activate_extension(
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="User does not exist."
|
||||
)
|
||||
update_user_extension(user_id=userid, extension=extension, active=active)
|
||||
await update_user_extension(user_id=userid, extension=extension, active=active)
|
||||
return {"extension": "updated"}
|
||||
|
||||
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
import json
|
||||
import traceback
|
||||
import httpx
|
||||
|
||||
from datetime import datetime
|
||||
from http import HTTPStatus
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import httpx
|
||||
import shortuuid # type: ignore
|
||||
from fastapi import HTTPException
|
||||
from fastapi.param_functions import Query
|
||||
from loguru import logger
|
||||
from starlette.requests import Request
|
||||
from starlette.responses import HTMLResponse # type: ignore
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ new Vue({
|
||||
rowsPerPage: 10
|
||||
}
|
||||
},
|
||||
nfcTagWriting: false,
|
||||
formDialog: {
|
||||
show: false,
|
||||
secondMultiplier: 'seconds',
|
||||
@@ -231,6 +232,42 @@ new Vue({
|
||||
})
|
||||
})
|
||||
},
|
||||
writeNfcTag: async function (lnurl) {
|
||||
try {
|
||||
if (typeof NDEFReader == 'undefined') {
|
||||
throw {
|
||||
toString: function () {
|
||||
return 'NFC not supported on this device or browser.'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const ndef = new NDEFReader()
|
||||
|
||||
this.nfcTagWriting = true
|
||||
this.$q.notify({
|
||||
message: 'Tap your NFC tag to write the LNURL-withdraw link to it.'
|
||||
})
|
||||
|
||||
await ndef.write({
|
||||
records: [{recordType: 'url', data: 'lightning:' + lnurl, lang: 'en'}]
|
||||
})
|
||||
|
||||
this.nfcTagWriting = false
|
||||
this.$q.notify({
|
||||
type: 'positive',
|
||||
message: 'NFC tag written successfully.'
|
||||
})
|
||||
} catch (error) {
|
||||
this.nfcTagWriting = false
|
||||
this.$q.notify({
|
||||
type: 'negative',
|
||||
message: error
|
||||
? error.toString()
|
||||
: 'An unexpected error has occurred.'
|
||||
})
|
||||
}
|
||||
},
|
||||
exportCSV: function () {
|
||||
LNbits.utils.exportCSV(this.paywallsTable.columns, this.paywalls)
|
||||
}
|
||||
|
||||
@@ -13,14 +13,22 @@
|
||||
:value="this.here + '/?lightning={{lnurl }}'"
|
||||
:options="{width: 800}"
|
||||
class="rounded-borders"
|
||||
></qrcode>
|
||||
>
|
||||
</qrcode>
|
||||
</q-responsive>
|
||||
</a>
|
||||
</div>
|
||||
<div class="row q-mt-lg">
|
||||
<div class="row q-mt-lg q-gutter-sm">
|
||||
<q-btn outline color="grey" @click="copyText('{{ lnurl }}')"
|
||||
>Copy LNURL</q-btn
|
||||
>
|
||||
<q-btn
|
||||
outline
|
||||
color="grey"
|
||||
icon="nfc"
|
||||
@click="writeNfcTag(' {{ lnurl }} ')"
|
||||
:disable="nfcTagWriting"
|
||||
></q-btn>
|
||||
</div>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
@@ -51,7 +59,8 @@
|
||||
mixins: [windowMixin],
|
||||
data: function () {
|
||||
return {
|
||||
here: location.protocol + '//' + location.host
|
||||
here: location.protocol + '//' + location.host,
|
||||
nfcTagWriting: false
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -369,6 +369,13 @@
|
||||
@click="copyText(qrCodeDialog.data.withdraw_url, 'Link copied to clipboard!')"
|
||||
>Shareable link</q-btn
|
||||
>
|
||||
<q-btn
|
||||
outline
|
||||
color="grey"
|
||||
icon="nfc"
|
||||
@click="writeNfcTag(qrCodeDialog.data.lnurl)"
|
||||
:disable="nfcTagWriting"
|
||||
></q-btn>
|
||||
<q-btn
|
||||
outline
|
||||
color="grey"
|
||||
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
from typing import Optional, List, Callable
|
||||
from functools import partial
|
||||
from urllib.request import parse_http_list as _parse_list_header
|
||||
from typing import Callable, List, Optional
|
||||
from urllib.parse import urlparse
|
||||
from werkzeug.datastructures import Headers
|
||||
from urllib.request import parse_http_list as _parse_list_header
|
||||
|
||||
from quart import Request
|
||||
from quart_trio.asgi import TrioASGIHTTPConnection
|
||||
from werkzeug.datastructures import Headers
|
||||
|
||||
|
||||
class ASGIProxyFix(TrioASGIHTTPConnection):
|
||||
|
||||
@@ -51,6 +51,7 @@ LNBITS_THEME_OPTIONS: List[str] = env.list(
|
||||
LNBITS_CUSTOM_LOGO = env.str("LNBITS_CUSTOM_LOGO", default="")
|
||||
|
||||
WALLET = wallet_class()
|
||||
FAKE_WALLET = getattr(wallets_module, "FakeWallet")()
|
||||
DEFAULT_WALLET_NAME = env.str("LNBITS_DEFAULT_WALLET_NAME", default="LNbits wallet")
|
||||
PREFER_SECURE_URLS = env.bool("LNBITS_FORCE_HTTPS", default=True)
|
||||
|
||||
|
||||
@@ -392,7 +392,7 @@ window.windowMixin = {
|
||||
}
|
||||
if (window.extensions) {
|
||||
var user = this.g.user
|
||||
this.g.extensions = Object.freeze(
|
||||
const extensions = Object.freeze(
|
||||
window.extensions
|
||||
.map(function (data) {
|
||||
return window.LNbits.map.extension(data)
|
||||
@@ -413,9 +413,13 @@ window.windowMixin = {
|
||||
return obj
|
||||
})
|
||||
.sort(function (a, b) {
|
||||
return a.name > b.name
|
||||
const nameA = a.name.toUpperCase()
|
||||
const nameB = b.name.toUpperCase()
|
||||
return nameA < nameB ? -1 : nameA > nameB ? 1 : 0
|
||||
})
|
||||
)
|
||||
|
||||
this.g.extensions = extensions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-8
@@ -1,22 +1,20 @@
|
||||
import time
|
||||
import asyncio
|
||||
import time
|
||||
import traceback
|
||||
from http import HTTPStatus
|
||||
from typing import List, Callable
|
||||
|
||||
from loguru import logger
|
||||
from typing import Callable, List
|
||||
|
||||
from fastapi.exceptions import HTTPException
|
||||
from loguru import logger
|
||||
|
||||
from lnbits.settings import WALLET
|
||||
from lnbits.core.crud import (
|
||||
get_payments,
|
||||
get_standalone_payment,
|
||||
delete_expired_invoices,
|
||||
get_balance_checks,
|
||||
get_payments,
|
||||
get_standalone_payment,
|
||||
)
|
||||
from lnbits.core.services import redeem_lnurl_withdraw
|
||||
|
||||
from lnbits.settings import WALLET
|
||||
|
||||
deferred_async: List[Callable] = []
|
||||
|
||||
|
||||
@@ -228,7 +228,6 @@
|
||||
<script type="text/javascript">
|
||||
const themes = {{ LNBITS_THEME_OPTIONS | tojson }}
|
||||
const LNBITS_DENOMINATION = {{ LNBITS_DENOMINATION | tojson}}
|
||||
console.log(LNBITS_DENOMINATION)
|
||||
if(themes && themes.length) {
|
||||
window.allowedThemes = themes.map(str => str.trim())
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import asyncio
|
||||
from typing import Callable, NamedTuple
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
currencies = {
|
||||
"AED": "United Arab Emirates Dirham",
|
||||
@@ -282,7 +281,7 @@ async def btc_price(currency: str) -> float:
|
||||
if not rates:
|
||||
return 9999999999
|
||||
elif len(rates) == 1:
|
||||
logger.warn("Could only fetch one Bitcoin price.")
|
||||
logger.warning("Could only fetch one Bitcoin price.")
|
||||
|
||||
return sum([rate for rate in rates]) / len(rates)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import NamedTuple, Optional, AsyncGenerator, Coroutine
|
||||
from typing import AsyncGenerator, Coroutine, NamedTuple, Optional
|
||||
|
||||
|
||||
class StatusResponse(NamedTuple):
|
||||
|
||||
@@ -5,10 +5,12 @@ except ImportError: # pragma: nocover
|
||||
|
||||
import asyncio
|
||||
import random
|
||||
import time
|
||||
from functools import partial, wraps
|
||||
from os import getenv
|
||||
from typing import AsyncGenerator, Optional
|
||||
import time
|
||||
|
||||
from lnbits import bolt11 as lnbits_bolt11
|
||||
|
||||
from .base import (
|
||||
InvoiceResponse,
|
||||
@@ -18,7 +20,6 @@ from .base import (
|
||||
Unsupported,
|
||||
Wallet,
|
||||
)
|
||||
from lnbits import bolt11 as lnbits_bolt11
|
||||
|
||||
|
||||
def async_wrap(func):
|
||||
|
||||
@@ -5,9 +5,8 @@ import urllib.parse
|
||||
from os import getenv
|
||||
from typing import AsyncGenerator, Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
import httpx
|
||||
from loguru import logger
|
||||
from websockets import connect
|
||||
from websockets.exceptions import (
|
||||
ConnectionClosed,
|
||||
|
||||
+16
-10
@@ -1,23 +1,27 @@
|
||||
import asyncio
|
||||
|
||||
from os import getenv
|
||||
from datetime import datetime
|
||||
from typing import Optional, Dict, AsyncGenerator
|
||||
import hashlib
|
||||
import random
|
||||
from datetime import datetime
|
||||
from os import getenv
|
||||
from typing import AsyncGenerator, Dict, Optional
|
||||
|
||||
from environs import Env # type: ignore
|
||||
from loguru import logger
|
||||
|
||||
from lnbits.helpers import urlsafe_short_hash
|
||||
import hashlib
|
||||
from ..bolt11 import encode, decode
|
||||
|
||||
from ..bolt11 import decode, encode
|
||||
from .base import (
|
||||
StatusResponse,
|
||||
InvoiceResponse,
|
||||
PaymentResponse,
|
||||
PaymentStatus,
|
||||
StatusResponse,
|
||||
Wallet,
|
||||
)
|
||||
|
||||
env = Env()
|
||||
env.read_env()
|
||||
|
||||
|
||||
class FakeWallet(Wallet):
|
||||
async def status(self) -> StatusResponse:
|
||||
@@ -32,7 +36,9 @@ class FakeWallet(Wallet):
|
||||
memo: Optional[str] = None,
|
||||
description_hash: Optional[bytes] = None,
|
||||
) -> InvoiceResponse:
|
||||
secret = getenv("FAKE_WALLET_SECRET")
|
||||
# we set a default secret since FakeWallet is used for internal=True invoices
|
||||
# and the user might not have configured a secret yet
|
||||
secret = env.str("FAKE_WALLET_SECTRET", default="ToTheMoon1")
|
||||
data: Dict = {
|
||||
"out": False,
|
||||
"amount": amount,
|
||||
@@ -85,10 +91,10 @@ class FakeWallet(Wallet):
|
||||
)
|
||||
|
||||
async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
|
||||
return PaymentStatus(False)
|
||||
return PaymentStatus(None)
|
||||
|
||||
async def get_payment_status(self, checking_id: str) -> PaymentStatus:
|
||||
return PaymentStatus(False)
|
||||
return PaymentStatus(None)
|
||||
|
||||
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
||||
self.queue = asyncio.Queue(0)
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import asyncio
|
||||
import json
|
||||
import httpx
|
||||
from os import getenv
|
||||
from typing import Optional, Dict, AsyncGenerator
|
||||
from typing import AsyncGenerator, Dict, Optional
|
||||
|
||||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
from .base import (
|
||||
StatusResponse,
|
||||
InvoiceResponse,
|
||||
PaymentResponse,
|
||||
PaymentStatus,
|
||||
StatusResponse,
|
||||
Wallet,
|
||||
)
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: lightning.proto
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import reflection as _reflection
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import enum_type_wrapper
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
imports_ok = True
|
||||
try:
|
||||
from google import protobuf
|
||||
import grpc
|
||||
from google import protobuf
|
||||
except ImportError: # pragma: nocover
|
||||
imports_ok = False
|
||||
|
||||
|
||||
import binascii
|
||||
import base64
|
||||
import binascii
|
||||
import hashlib
|
||||
from os import environ, error, getenv
|
||||
from typing import Optional, Dict, AsyncGenerator
|
||||
from typing import AsyncGenerator, Dict, Optional
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from .macaroon import load_macaroon, AESCipher
|
||||
from .macaroon import AESCipher, load_macaroon
|
||||
|
||||
if imports_ok:
|
||||
import lnbits.wallets.lnd_grpc_files.lightning_pb2 as ln
|
||||
import lnbits.wallets.lnd_grpc_files.lightning_pb2_grpc as lnrpc
|
||||
|
||||
from .base import (
|
||||
StatusResponse,
|
||||
InvoiceResponse,
|
||||
PaymentResponse,
|
||||
PaymentStatus,
|
||||
StatusResponse,
|
||||
Wallet,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
import asyncio
|
||||
from pydoc import describe
|
||||
import httpx
|
||||
import json
|
||||
import base64
|
||||
import json
|
||||
from os import getenv
|
||||
from typing import Optional, Dict, AsyncGenerator
|
||||
from pydoc import describe
|
||||
from typing import AsyncGenerator, Dict, Optional
|
||||
|
||||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
from lnbits import bolt11 as lnbits_bolt11
|
||||
from .macaroon import load_macaroon, AESCipher
|
||||
|
||||
from .base import (
|
||||
StatusResponse,
|
||||
InvoiceResponse,
|
||||
PaymentResponse,
|
||||
PaymentStatus,
|
||||
StatusResponse,
|
||||
Wallet,
|
||||
)
|
||||
from .macaroon import AESCipher, load_macaroon
|
||||
|
||||
|
||||
class LndRestWallet(Wallet):
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import json
|
||||
import asyncio
|
||||
from fastapi.exceptions import HTTPException
|
||||
import httpx
|
||||
from os import getenv
|
||||
import json
|
||||
from http import HTTPStatus
|
||||
from typing import Optional, Dict, AsyncGenerator
|
||||
from os import getenv
|
||||
from typing import AsyncGenerator, Dict, Optional
|
||||
|
||||
import httpx
|
||||
from fastapi.exceptions import HTTPException
|
||||
from loguru import logger
|
||||
|
||||
from .base import (
|
||||
StatusResponse,
|
||||
InvoiceResponse,
|
||||
PaymentResponse,
|
||||
PaymentStatus,
|
||||
StatusResponse,
|
||||
Wallet,
|
||||
)
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import asyncio
|
||||
import json
|
||||
import httpx
|
||||
from os import getenv
|
||||
from typing import Optional, Dict, AsyncGenerator
|
||||
from typing import AsyncGenerator, Dict, Optional
|
||||
|
||||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
from .base import (
|
||||
StatusResponse,
|
||||
InvoiceResponse,
|
||||
PaymentResponse,
|
||||
PaymentStatus,
|
||||
StatusResponse,
|
||||
Wallet,
|
||||
)
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
from .macaroon import load_macaroon, AESCipher
|
||||
from .macaroon import AESCipher, load_macaroon
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import base64
|
||||
import getpass
|
||||
from hashlib import md5
|
||||
|
||||
from Cryptodome import Random
|
||||
from Cryptodome.Cipher import AES
|
||||
import base64
|
||||
from hashlib import md5
|
||||
import getpass
|
||||
|
||||
from loguru import logger
|
||||
|
||||
BLOCK_SIZE = 16
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
import asyncio
|
||||
|
||||
from fastapi.exceptions import HTTPException
|
||||
from lnbits.helpers import url_for
|
||||
import hmac
|
||||
import httpx
|
||||
from http import HTTPStatus
|
||||
from os import getenv
|
||||
from typing import Optional, AsyncGenerator
|
||||
from typing import AsyncGenerator, Optional
|
||||
|
||||
import httpx
|
||||
from fastapi.exceptions import HTTPException
|
||||
from loguru import logger
|
||||
|
||||
from lnbits.helpers import url_for
|
||||
|
||||
from .base import (
|
||||
StatusResponse,
|
||||
InvoiceResponse,
|
||||
PaymentResponse,
|
||||
PaymentStatus,
|
||||
Wallet,
|
||||
StatusResponse,
|
||||
Unsupported,
|
||||
Wallet,
|
||||
)
|
||||
|
||||
|
||||
|
||||
+19
-6
@@ -1,17 +1,17 @@
|
||||
import asyncio
|
||||
import json
|
||||
import httpx
|
||||
import random
|
||||
from os import getenv
|
||||
from typing import Optional, AsyncGenerator
|
||||
from typing import AsyncGenerator, Optional
|
||||
|
||||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
from .base import (
|
||||
StatusResponse,
|
||||
InvoiceResponse,
|
||||
PaymentResponse,
|
||||
PaymentStatus,
|
||||
StatusResponse,
|
||||
Wallet,
|
||||
)
|
||||
|
||||
@@ -48,9 +48,16 @@ class SparkWallet(Wallet):
|
||||
self.url + "/rpc",
|
||||
headers={"X-Access": self.token},
|
||||
json={"method": key, "params": params},
|
||||
timeout=40,
|
||||
timeout=60 * 60 * 24,
|
||||
)
|
||||
except (OSError, httpx.ConnectError, httpx.RequestError) as exc:
|
||||
r.raise_for_status()
|
||||
except (
|
||||
OSError,
|
||||
httpx.ConnectError,
|
||||
httpx.RequestError,
|
||||
httpx.HTTPError,
|
||||
httpx.TimeoutException,
|
||||
) as exc:
|
||||
raise UnknownError("error connecting to spark: " + str(exc))
|
||||
|
||||
try:
|
||||
@@ -203,7 +210,13 @@ class SparkWallet(Wallet):
|
||||
data = json.loads(line[5:])
|
||||
if "pay_index" in data and data.get("status") == "paid":
|
||||
yield data["label"]
|
||||
except (OSError, httpx.ReadError, httpx.ConnectError, httpx.ReadTimeout):
|
||||
except (
|
||||
OSError,
|
||||
httpx.ReadError,
|
||||
httpx.ConnectError,
|
||||
httpx.ReadTimeout,
|
||||
httpx.HTTPError,
|
||||
):
|
||||
pass
|
||||
|
||||
logger.error("lost connection to spark /stream, retrying in 5 seconds")
|
||||
|
||||
Reference in New Issue
Block a user