From 85cb8526befc72e5e98e6a3285d82dad4d705a0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Sat, 7 Jan 2023 13:15:29 +0100 Subject: [PATCH 01/27] fix mypy bleskomat issues --- lnbits/extensions/bleskomat/exchange_rates.py | 21 ++++++++-------- lnbits/extensions/bleskomat/helpers.py | 24 +++++++++---------- lnbits/extensions/bleskomat/lnurl_api.py | 13 ++++++---- lnbits/extensions/bleskomat/models.py | 7 +++--- lnbits/extensions/bleskomat/views.py | 3 +-- lnbits/extensions/bleskomat/views_api.py | 8 ++++--- pyproject.toml | 3 +-- 7 files changed, 40 insertions(+), 39 deletions(-) diff --git a/lnbits/extensions/bleskomat/exchange_rates.py b/lnbits/extensions/bleskomat/exchange_rates.py index e5eb843f..98193001 100644 --- a/lnbits/extensions/bleskomat/exchange_rates.py +++ b/lnbits/extensions/bleskomat/exchange_rates.py @@ -1,5 +1,6 @@ import json import os +from typing import Callable import httpx @@ -65,17 +66,15 @@ async def fetch_fiat_exchange_rate(currency: str, provider: str): "to": currency.lower(), } - url = exchange_rate_providers[provider]["api_url"] - if url: - for key in replacements.keys(): - url = url.replace("{" + key + "}", replacements[key]) - async with httpx.AsyncClient() as client: - r = await client.get(url) - r.raise_for_status() - data = r.json() - else: - data = {} + api_url = str(exchange_rate_providers[provider]["api_url"]) + for key in replacements.keys(): + api_url = api_url.replace("{" + key + "}", replacements[key]) + async with httpx.AsyncClient() as client: + r = await client.get(api_url) + r.raise_for_status() + data = r.json() getter = exchange_rate_providers[provider]["getter"] - rate = float(getter(data, replacements)) + # TODO: mypy typing does not work out + rate = float(getter(data, replacements)) # type: ignore return rate diff --git a/lnbits/extensions/bleskomat/helpers.py b/lnbits/extensions/bleskomat/helpers.py index cec7434d..0b2f3471 100644 --- a/lnbits/extensions/bleskomat/helpers.py +++ b/lnbits/extensions/bleskomat/helpers.py @@ -1,11 +1,11 @@ import base64 import hashlib import hmac -import urllib from http import HTTPStatus from typing import Dict +from urllib import parse -from starlette.requests import Request +from fastapi import Request def generate_bleskomat_lnurl_hash(secret: str): @@ -22,7 +22,7 @@ def generate_bleskomat_lnurl_signature( elif api_key_encoding == "base64": key = base64.b64decode(api_key_secret) else: - key = bytes(f"{api_key_secret}") + key = bytes.fromhex(api_key_secret) return hmac.new(key=key, msg=payload.encode(), digestmod=hashlib.sha256).hexdigest() @@ -57,8 +57,8 @@ class LnurlValidationError(Exception): pass -def prepare_lnurl_params(tag: str, query: Dict[str, str]): - params = {} +def prepare_lnurl_params(tag: str, query: dict) -> dict: + params: dict = {} if not is_supported_lnurl_subprotocol(tag): raise LnurlValidationError(f'Unsupported subprotocol: "{tag}"') if tag == "withdrawRequest": @@ -85,15 +85,15 @@ def query_to_signing_payload(query: Dict[str, str]) -> str: payload = [] for key in sorted_keys: if not key == "signature": - encoded_key = urllib.parse.quote(key, safe=encode_uri_component_safe_chars) - encoded_value = urllib.parse.quote( + encoded_key = parse.quote(key, safe=encode_uri_component_safe_chars) + encoded_value = parse.quote( query[key], safe=encode_uri_component_safe_chars ) payload.append(f"{encoded_key}={encoded_value}") return "&".join(payload) -unshorten_rules = { +unshorten_rules: dict[str, dict] = { "query": {"n": "nonce", "s": "signature", "t": "tag"}, "tags": { "c": "channelRequest", @@ -114,7 +114,7 @@ unshorten_rules = { } -def unshorten_lnurl_query(query: Dict[str, str]) -> Dict[str, str]: +def unshorten_lnurl_query(query: dict) -> Dict[str, str]: new_query = {} rules = unshorten_rules if "tag" in query: @@ -131,9 +131,9 @@ def unshorten_lnurl_query(query: Dict[str, str]) -> Dict[str, str]: if not tag in rules["params"]: raise LnurlValidationError(f'Unknown tag: "{tag}"') for key in query: - if key in rules["params"][tag]: + if key in rules["params"][str(tag)]: short_param_key = key - long_param_key = rules["params"][tag][short_param_key] + long_param_key = rules["params"][str(tag)][short_param_key] if short_param_key in query: new_query[long_param_key] = query[short_param_key] else: @@ -146,7 +146,7 @@ def unshorten_lnurl_query(query: Dict[str, str]) -> Dict[str, str]: if short_key in query: new_query[long_key] = query[short_key] else: - new_query[long_key] = query[long_key] + new_query[long_key] = query[str(long_key)] else: # Keep unknown key/value pairs unchanged: new_query[key] = query[key] diff --git a/lnbits/extensions/bleskomat/lnurl_api.py b/lnbits/extensions/bleskomat/lnurl_api.py index 33e33a70..bdac5fec 100644 --- a/lnbits/extensions/bleskomat/lnurl_api.py +++ b/lnbits/extensions/bleskomat/lnurl_api.py @@ -1,6 +1,5 @@ import json import math -import traceback from http import HTTPStatus from loguru import logger @@ -28,7 +27,7 @@ from .helpers import ( @bleskomat_ext.get("/u", name="bleskomat.api_bleskomat_lnurl") async def api_bleskomat_lnurl(req: Request): try: - query = req.query_params + query = dict(req.query_params) # Unshorten query if "s" is used instead of "signature". if "s" in query: @@ -89,11 +88,15 @@ async def api_bleskomat_lnurl(req: Request): # Convert to msats: params[key] = int(amount_sats_less_fee * 1e3) except LnurlValidationError as e: - raise LnurlHttpError(e.message, HTTPStatus.BAD_REQUEST) + raise LnurlHttpError(str(e), HTTPStatus.BAD_REQUEST) # Create a new LNURL using the query parameters provided in the signed URL. - params = json.JSONEncoder().encode(params) + json_params = json.JSONEncoder().encode(params) lnurl = await create_bleskomat_lnurl( - bleskomat=bleskomat, secret=secret, tag=tag, params=params, uses=1 + bleskomat=bleskomat, + secret=secret, + tag=tag, + params=json_params, + uses=1, ) # Reply with LNURL response object. diff --git a/lnbits/extensions/bleskomat/models.py b/lnbits/extensions/bleskomat/models.py index 364cbe22..6dc88dc0 100644 --- a/lnbits/extensions/bleskomat/models.py +++ b/lnbits/extensions/bleskomat/models.py @@ -2,10 +2,9 @@ import json import time from typing import Dict -from fastapi.params import Query +from fastapi import Query, Request from loguru import logger from pydantic import BaseModel, validator -from starlette.requests import Request from lnbits import bolt11 from lnbits.core.services import PaymentFailure, pay_invoice @@ -80,7 +79,7 @@ class BleskomatLnurl(BaseModel): response["k1"] = secret return response - def validate_action(self, query: Dict[str, str]) -> None: + def validate_action(self, query) -> None: tag = self.tag params = json.loads(self.params) # Perform tag-specific checks. @@ -109,7 +108,7 @@ class BleskomatLnurl(BaseModel): else: raise LnurlValidationError(f'Unknown subprotocol: "{tag}"') - async def execute_action(self, query: Dict[str, str]): + async def execute_action(self, query): self.validate_action(query) used = False async with db.connect() as conn: diff --git a/lnbits/extensions/bleskomat/views.py b/lnbits/extensions/bleskomat/views.py index 92d47513..370f2ec3 100644 --- a/lnbits/extensions/bleskomat/views.py +++ b/lnbits/extensions/bleskomat/views.py @@ -1,5 +1,4 @@ -from fastapi import Request -from fastapi.params import Depends +from fastapi import Depends, Request from fastapi.templating import Jinja2Templates from starlette.responses import HTMLResponse diff --git a/lnbits/extensions/bleskomat/views_api.py b/lnbits/extensions/bleskomat/views_api.py index b6e417bb..9f59c098 100644 --- a/lnbits/extensions/bleskomat/views_api.py +++ b/lnbits/extensions/bleskomat/views_api.py @@ -27,7 +27,8 @@ async def api_bleskomats( wallet_ids = [wallet.wallet.id] 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 [] return [bleskomat.dict() for bleskomat in await get_bleskomats(wallet_ids)] @@ -54,9 +55,9 @@ async def api_bleskomat_create_or_update( wallet: WalletTypeInfo = Depends(require_admin_key), bleskomat_id=None, ): + fiat_currency = data.fiat_currency + exchange_rate_provider = data.exchange_rate_provider try: - fiat_currency = data.fiat_currency - exchange_rate_provider = data.exchange_rate_provider await fetch_fiat_exchange_rate( currency=fiat_currency, provider=exchange_rate_provider ) @@ -79,6 +80,7 @@ async def api_bleskomat_create_or_update( else: bleskomat = await create_bleskomat(wallet_id=wallet.wallet.id, data=data) + assert bleskomat return bleskomat.dict() diff --git a/pyproject.toml b/pyproject.toml index 03dbbc8d..22725ebb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,8 +89,7 @@ profile = "black" ignore_missing_imports = "True" files = "lnbits" exclude = """(?x)( - ^lnbits/extensions/bleskomat. - | ^lnbits/extensions/boltz. + ^lnbits/extensions/boltz. | ^lnbits/extensions/livestream. | ^lnbits/extensions/lnurldevice. | ^lnbits/extensions/watchonly. From b32404ca5f883f83313a553ddbc96fe05f02d776 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 10 Jan 2023 11:39:21 +0100 Subject: [PATCH 02/27] correct typing of the callable --- lnbits/extensions/bleskomat/exchange_rates.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lnbits/extensions/bleskomat/exchange_rates.py b/lnbits/extensions/bleskomat/exchange_rates.py index 98193001..47897191 100644 --- a/lnbits/extensions/bleskomat/exchange_rates.py +++ b/lnbits/extensions/bleskomat/exchange_rates.py @@ -1,6 +1,6 @@ import json import os -from typing import Callable +from typing import Callable, Union, Dict import httpx @@ -13,7 +13,9 @@ fiat_currencies = json.load( ) ) -exchange_rate_providers = { +exchange_rate_providers: dict[ + str, dict[str, Union[str, Callable[[dict, dict], str]]] +] = { "bitfinex": { "name": "Bitfinex", "domain": "bitfinex.com", @@ -75,6 +77,6 @@ async def fetch_fiat_exchange_rate(currency: str, provider: str): data = r.json() getter = exchange_rate_providers[provider]["getter"] - # TODO: mypy typing does not work out - rate = float(getter(data, replacements)) # type: ignore + if callable(getter): + rate = float(getter(data, replacements)) return rate From 6d25fa4fa062c2bbd403ef0321e95ba801afb04c Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 11 Jan 2023 17:32:39 +0100 Subject: [PATCH 03/27] fix it! --- lnbits/extensions/bleskomat/exchange_rates.py | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/lnbits/extensions/bleskomat/exchange_rates.py b/lnbits/extensions/bleskomat/exchange_rates.py index 47897191..764e66c0 100644 --- a/lnbits/extensions/bleskomat/exchange_rates.py +++ b/lnbits/extensions/bleskomat/exchange_rates.py @@ -68,15 +68,19 @@ async def fetch_fiat_exchange_rate(currency: str, provider: str): "to": currency.lower(), } - api_url = str(exchange_rate_providers[provider]["api_url"]) - for key in replacements.keys(): - api_url = api_url.replace("{" + key + "}", replacements[key]) - async with httpx.AsyncClient() as client: - r = await client.get(api_url) - r.raise_for_status() - data = r.json() - + api_url_or_none = exchange_rate_providers[provider]["api_url"] + if api_url_or_none is not None: + api_url = str(api_url_or_none) + for key in replacements.keys(): + api_url = api_url.replace("{" + key + "}", replacements[key]) + async with httpx.AsyncClient() as client: + r = await client.get(api_url) + r.raise_for_status() + data = r.json() + else: + data = {} getter = exchange_rate_providers[provider]["getter"] + print(getter) if callable(getter): rate = float(getter(data, replacements)) return rate From fc7a799b89513169bf419fa30450c5e797320bab Mon Sep 17 00:00:00 2001 From: Tiago Vasconcelos Date: Wed, 11 Jan 2023 16:33:01 +0000 Subject: [PATCH 04/27] add image by URL and limit size on API --- .../extensions/offlineshop/static/js/index.js | 29 ++++++++++++------- .../templates/offlineshop/index.html | 15 +++++++++- lnbits/extensions/offlineshop/views_api.py | 16 ++++++++++ 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/lnbits/extensions/offlineshop/static/js/index.js b/lnbits/extensions/offlineshop/static/js/index.js index c0390609..7ade1bb9 100644 --- a/lnbits/extensions/offlineshop/static/js/index.js +++ b/lnbits/extensions/offlineshop/static/js/index.js @@ -4,6 +4,15 @@ Vue.component(VueQrcode.name, VueQrcode) const pica = window.pica() +function imgSizeFit(img, maxWidth = 1024, maxHeight = 768) { + let ratio = Math.min( + 1, + maxWidth / img.naturalWidth, + maxHeight / img.naturalHeight + ) + return {width: img.naturalWidth * ratio, height: img.naturalHeight * ratio} +} + const defaultItemData = { unit: 'sat' } @@ -23,6 +32,7 @@ new Vue({ }, itemDialog: { show: false, + urlImg: true, data: {...defaultItemData}, units: ['sat'] } @@ -41,6 +51,9 @@ new Vue({ openUpdateDialog(itemId) { this.itemDialog.show = true let item = this.offlineshop.items.find(item => item.id === itemId) + if (item.image.startsWith('data:')) { + this.itemDialog.urlImg = false + } this.itemDialog.data = item }, imageAdded(file) { @@ -48,17 +61,12 @@ new Vue({ let image = new Image() image.src = blobURL image.onload = async () => { + let fit = imgSizeFit(image, 100, 100) let canvas = document.createElement('canvas') - canvas.setAttribute('width', 100) - canvas.setAttribute('height', 100) - await pica.resize(image, canvas, { - quality: 0, - alpha: true, - unsharpAmount: 95, - unsharpRadius: 0.9, - unsharpThreshold: 70 - }) - this.itemDialog.data.image = canvas.toDataURL() + canvas.setAttribute('width', fit.width) + canvas.setAttribute('height', fit.height) + output = await pica.resize(image, canvas) + this.itemDialog.data.image = output.toDataURL('image/jpeg', 0.4) this.itemDialog = {...this.itemDialog} } }, @@ -155,6 +163,7 @@ new Vue({ this.loadShop() this.itemDialog.show = false + this.itemDialog.urlImg = true this.itemDialog.data = {...defaultItemData} }, toggleItem(itemId) { diff --git a/lnbits/extensions/offlineshop/templates/offlineshop/index.html b/lnbits/extensions/offlineshop/templates/offlineshop/index.html index 61f6093e..80a7bbb8 100644 --- a/lnbits/extensions/offlineshop/templates/offlineshop/index.html +++ b/lnbits/extensions/offlineshop/templates/offlineshop/index.html @@ -237,7 +237,7 @@ @@ -266,7 +266,16 @@ type="text" label="Brief description" > + + Date: Wed, 11 Jan 2023 17:35:59 +0100 Subject: [PATCH 05/27] fix pyproject --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 22725ebb..49e802f4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,7 +89,7 @@ profile = "black" ignore_missing_imports = "True" files = "lnbits" exclude = """(?x)( - ^lnbits/extensions/boltz. + | ^lnbits/extensions/boltz. | ^lnbits/extensions/livestream. | ^lnbits/extensions/lnurldevice. | ^lnbits/extensions/watchonly. From 8efa81136bfd3cf3c36559a04eb78ce96f5eee4a Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 11 Jan 2023 17:41:36 +0100 Subject: [PATCH 06/27] maybe one day Ill learn to use poetry --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 49e802f4..22725ebb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,7 +89,7 @@ profile = "black" ignore_missing_imports = "True" files = "lnbits" exclude = """(?x)( - | ^lnbits/extensions/boltz. + ^lnbits/extensions/boltz. | ^lnbits/extensions/livestream. | ^lnbits/extensions/lnurldevice. | ^lnbits/extensions/watchonly. From 701b66e71e30f5a4d1054f62994514aa4af6b24e Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 11 Jan 2023 17:53:58 +0100 Subject: [PATCH 07/27] make format --- lnbits/extensions/bleskomat/exchange_rates.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/bleskomat/exchange_rates.py b/lnbits/extensions/bleskomat/exchange_rates.py index 764e66c0..c6f1d880 100644 --- a/lnbits/extensions/bleskomat/exchange_rates.py +++ b/lnbits/extensions/bleskomat/exchange_rates.py @@ -1,6 +1,6 @@ import json import os -from typing import Callable, Union, Dict +from typing import Callable, Dict, Union import httpx From c3ded0b51c7dc9c370220e43c4b417188334a383 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 11 Jan 2023 18:01:21 +0100 Subject: [PATCH 08/27] come on bro --- pyproject.toml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 46808433..5e764719 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -88,8 +88,7 @@ profile = "black" [tool.mypy] files = "lnbits" exclude = """(?x)( - ^lnbits/extensions/bleskomat. - | ^lnbits/extensions/boltz. + ^lnbits/extensions/boltz. | ^lnbits/wallets/lnd_grpc_files. )""" From a0c66871fa09b6c1fdfc7a4667c3131d3411f17f Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 11 Jan 2023 18:03:50 +0100 Subject: [PATCH 09/27] relative import --- lnbits/extensions/bleskomat/views_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/bleskomat/views_api.py b/lnbits/extensions/bleskomat/views_api.py index 9f59c098..1bb669c4 100644 --- a/lnbits/extensions/bleskomat/views_api.py +++ b/lnbits/extensions/bleskomat/views_api.py @@ -6,7 +6,7 @@ from starlette.exceptions import HTTPException from lnbits.core.crud import get_user from lnbits.decorators import WalletTypeInfo, require_admin_key -from lnbits.extensions.bleskomat.models import CreateBleskomat +from .models import CreateBleskomat from . import bleskomat_ext from .crud import ( From 5f60b025d5b814b423e28a14c56d15015f5e6116 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Wed, 11 Jan 2023 18:06:42 +0100 Subject: [PATCH 10/27] if this isnt the last commit I will burn it all down --- lnbits/extensions/bleskomat/views_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/bleskomat/views_api.py b/lnbits/extensions/bleskomat/views_api.py index 1bb669c4..3e7573bc 100644 --- a/lnbits/extensions/bleskomat/views_api.py +++ b/lnbits/extensions/bleskomat/views_api.py @@ -6,7 +6,6 @@ from starlette.exceptions import HTTPException from lnbits.core.crud import get_user from lnbits.decorators import WalletTypeInfo, require_admin_key -from .models import CreateBleskomat from . import bleskomat_ext from .crud import ( @@ -17,6 +16,7 @@ from .crud import ( update_bleskomat, ) from .exchange_rates import fetch_fiat_exchange_rate +from .models import CreateBleskomat @bleskomat_ext.get("/api/v1/bleskomats") From 569990a760a5209c7e3882a1e2ef77023c124411 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 11 Jan 2023 19:21:13 +0100 Subject: [PATCH 11/27] feature request from ben new pr --- lnbits/extensions/smtp/crud.py | 70 ++++---- lnbits/extensions/smtp/migrations.py | 4 + lnbits/extensions/smtp/models.py | 4 +- lnbits/extensions/smtp/smtp.py | 158 ++++++++++-------- lnbits/extensions/smtp/tasks.py | 4 +- .../extensions/smtp/templates/smtp/index.html | 79 ++++++++- lnbits/extensions/smtp/views_api.py | 27 ++- 7 files changed, 229 insertions(+), 117 deletions(-) diff --git a/lnbits/extensions/smtp/crud.py b/lnbits/extensions/smtp/crud.py index 2eee4c3d..62159703 100644 --- a/lnbits/extensions/smtp/crud.py +++ b/lnbits/extensions/smtp/crud.py @@ -1,10 +1,9 @@ -from http import HTTPStatus from typing import List, Optional, Union from lnbits.helpers import urlsafe_short_hash from . import db -from .models import CreateEmail, CreateEmailaddress, Emailaddresses, Emails +from .models import CreateEmail, CreateEmailaddress, Email, Emailaddress from .smtp import send_mail @@ -17,7 +16,7 @@ def get_test_mail(email, testemail): ) -async def create_emailaddress(data: CreateEmailaddress) -> Emailaddresses: +async def create_emailaddress(data: CreateEmailaddress) -> Emailaddress: emailaddress_id = urlsafe_short_hash() @@ -50,7 +49,7 @@ async def create_emailaddress(data: CreateEmailaddress) -> Emailaddresses: return new_emailaddress -async def update_emailaddress(emailaddress_id: str, **kwargs) -> Emailaddresses: +async def update_emailaddress(emailaddress_id: str, **kwargs) -> Emailaddress: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) await db.execute( f"UPDATE smtp.emailaddress SET {q} WHERE id = ?", @@ -65,30 +64,22 @@ async def update_emailaddress(emailaddress_id: str, **kwargs) -> Emailaddresses: await send_mail(row, email) assert row, "Newly updated emailaddress couldn't be retrieved" - return Emailaddresses(**row) + return Emailaddress(**row) -async def get_emailaddress(emailaddress_id: str) -> Optional[Emailaddresses]: +async def get_emailaddress(emailaddress_id: str) -> Optional[Emailaddress]: row = await db.fetchone( "SELECT * FROM smtp.emailaddress WHERE id = ?", (emailaddress_id,) ) - return Emailaddresses(**row) if row else None + return Emailaddress(**row) if row else None -async def get_emailaddress_by_email(email: str) -> Optional[Emailaddresses]: +async def get_emailaddress_by_email(email: str) -> Optional[Emailaddress]: row = await db.fetchone("SELECT * FROM smtp.emailaddress WHERE email = ?", (email,)) - return Emailaddresses(**row) if row else None + return Emailaddress(**row) if row else None -# async def get_emailAddressByEmail(email: str) -> Optional[Emails]: -# row = await db.fetchone( -# "SELECT s.*, d.emailaddress as emailaddress FROM smtp.email s INNER JOIN smtp.emailaddress d ON (s.emailaddress_id = d.id) WHERE s.emailaddress = ?", -# (email,), -# ) -# return Subdomains(**row) if row else None - - -async def get_emailaddresses(wallet_ids: Union[str, List[str]]) -> List[Emailaddresses]: +async def get_emailaddresses(wallet_ids: Union[str, List[str]]) -> List[Emailaddress]: if isinstance(wallet_ids, str): wallet_ids = [wallet_ids] @@ -97,21 +88,22 @@ async def get_emailaddresses(wallet_ids: Union[str, List[str]]) -> List[Emailadd f"SELECT * FROM smtp.emailaddress WHERE wallet IN ({q})", (*wallet_ids,) ) - return [Emailaddresses(**row) for row in rows] + return [Emailaddress(**row) for row in rows] async def delete_emailaddress(emailaddress_id: str) -> None: await db.execute("DELETE FROM smtp.emailaddress WHERE id = ?", (emailaddress_id,)) -## create emails -async def create_email(payment_hash, wallet, data: CreateEmail) -> Emails: +async def create_email(wallet: str, data: CreateEmail, payment_hash: str = "") -> Email: + id = urlsafe_short_hash() await db.execute( """ - INSERT INTO smtp.email (id, wallet, emailaddress_id, subject, receiver, message, paid) + INSERT INTO smtp.email (id, payment_hash, wallet, emailaddress_id, subject, receiver, message, paid) VALUES (?, ?, ?, ?, ?, ?, ?) """, ( + id, payment_hash, wallet, data.emailaddress_id, @@ -122,36 +114,34 @@ async def create_email(payment_hash, wallet, data: CreateEmail) -> Emails: ), ) - new_email = await get_email(payment_hash) + new_email = await get_email(id) assert new_email, "Newly created email couldn't be retrieved" return new_email -async def set_email_paid(payment_hash: str) -> Emails: - email = await get_email(payment_hash) +async def set_email_paid(payment_hash: str) -> bool: + email = await get_email_by_payment_hash(payment_hash) if email and email.paid == False: await db.execute( - """ - UPDATE smtp.email - SET paid = true - WHERE id = ? - """, - (payment_hash,), + f"UPDATE smtp.email SET paid = true WHERE payment_hash = {payment_hash}" ) - new_email = await get_email(payment_hash) - assert new_email, "Newly paid email couldn't be retrieved" - return new_email + return True + return False -async def get_email(email_id: str) -> Optional[Emails]: +async def get_email_by_payment_hash(payment_hash: str) -> Optional[Email]: row = await db.fetchone( - "SELECT s.*, d.email as emailaddress FROM smtp.email s INNER JOIN smtp.emailaddress d ON (s.emailaddress_id = d.id) WHERE s.id = ?", - (email_id,), + f"SELECT * FROM smtp.email WHERE payment_hash = {payment_hash}" ) - return Emails(**row) if row else None + return Email(**row) if row else None -async def get_emails(wallet_ids: Union[str, List[str]]) -> List[Emails]: +async def get_email(id: str) -> Optional[Email]: + row = await db.fetchone(f"SELECT * FROM smtp.email WHERE id = {id}") + return Email(**row) if row else None + + +async def get_emails(wallet_ids: Union[str, List[str]]) -> List[Email]: if isinstance(wallet_ids, str): wallet_ids = [wallet_ids] @@ -161,7 +151,7 @@ async def get_emails(wallet_ids: Union[str, List[str]]) -> List[Emails]: (*wallet_ids,), ) - return [Emails(**row) for row in rows] + return [Email(**row) for row in rows] async def delete_email(email_id: str) -> None: diff --git a/lnbits/extensions/smtp/migrations.py b/lnbits/extensions/smtp/migrations.py index 16d50166..f8f39635 100644 --- a/lnbits/extensions/smtp/migrations.py +++ b/lnbits/extensions/smtp/migrations.py @@ -33,3 +33,7 @@ async def m001_initial(db): ); """ ) + + +async def m002_add_payment_hash(db): + await db.execute(f"ALTER TABLE smtp.email ADD COLUMN payment_hash TEXT NOT NULL;") diff --git a/lnbits/extensions/smtp/models.py b/lnbits/extensions/smtp/models.py index e2f3fc13..bb0e1f2c 100644 --- a/lnbits/extensions/smtp/models.py +++ b/lnbits/extensions/smtp/models.py @@ -15,7 +15,7 @@ class CreateEmailaddress(BaseModel): cost: int = Query(..., ge=0) -class Emailaddresses(BaseModel): +class Emailaddress(BaseModel): id: str wallet: str email: str @@ -36,7 +36,7 @@ class CreateEmail(BaseModel): message: str = Query(...) -class Emails(BaseModel): +class Email(BaseModel): id: str wallet: str emailaddress_id: str diff --git a/lnbits/extensions/smtp/smtp.py b/lnbits/extensions/smtp/smtp.py index e77bc0fa..43253b54 100644 --- a/lnbits/extensions/smtp/smtp.py +++ b/lnbits/extensions/smtp/smtp.py @@ -4,83 +4,107 @@ import time from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText from email.utils import formatdate -from http import HTTPStatus from smtplib import SMTP_SSL as SMTP +from typing import Union from loguru import logger -from starlette.exceptions import HTTPException + +from .models import CreateEmail, CreateEmailaddress, Email, Emailaddress + + +async def send_mail( + emailaddress: Union[Emailaddress, CreateEmailaddress], + email: Union[Email, CreateEmail], +): + smtp_client = SmtpService(emailaddress) + message = smtp_client.create_message(email) + await smtp_client.send_mail(email.receiver, message) def valid_email(s): # https://regexr.com/2rhq7 - pat = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?" + pat = r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?" if re.match(pat, s): return True - msg = f"SMTP - invalid email: {s}." - logger.error(msg) - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=msg) + log = f"SMTP - invalid email: {s}." + logger.error(log) + raise Exception(log) -async def send_mail(emailaddress, email): - valid_email(emailaddress.email) - valid_email(email.receiver) +class SmtpService: + def __init__(self, emailaddress: Union[Emailaddress, CreateEmailaddress]) -> None: + self.sender = emailaddress.email + self.smtp_server = emailaddress.smtp_server + self.smtp_port = emailaddress.smtp_port + self.smtp_user = emailaddress.smtp_user + self.smtp_password = emailaddress.smtp_password - ts = time.time() - date = formatdate(ts, True) - - msg = MIMEMultipart("alternative") - msg = MIMEMultipart("alternative") - msg["Date"] = date - msg["Subject"] = email.subject - msg["From"] = emailaddress.email - msg["To"] = email.receiver - - signature = "Email sent anonymiously by LNbits Sendmail extension." - text = f""" -{email.message} - -{signature} -""" - - html = f""" - - - -

{email.message}

-
-

{signature}

- - -""" - - part1 = MIMEText(text, "plain") - part2 = MIMEText(html, "html") - msg.attach(part1) - msg.attach(part2) - - try: - conn = SMTP( - host=emailaddress.smtp_server, port=emailaddress.smtp_port, timeout=10 + def render_email(self, email: Union[Email, CreateEmail]): + signature: str = "Email sent by LNbits SMTP extension." + text = f"{email.message}\n\n{signature}" + html = ( + """ + + + +

""" + + email.message + + """

+

""" + + signature + + """

+ + + """ ) - logger.debug("SMTP - connected to smtp server.") - # conn.set_debuglevel(True) - except: - msg = f"SMTP - error connecting to smtp server: {emailaddress.smtp_server}:{emailaddress.smtp_port}." - logger.error(msg) - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=msg) - try: - conn.login(emailaddress.smtp_user, emailaddress.smtp_password) - logger.debug("SMTP - successful login to smtp server.") - except: - msg = f"SMTP - error login into smtp {emailaddress.smtp_user}." - logger.error(msg) - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=msg) - try: - conn.sendmail(emailaddress.email, email.receiver, msg.as_string()) - logger.debug("SMTP - successfully send email.") - except socket.error as e: - msg = f"SMTP - error sending email: {str(e)}." - logger.error(msg) - raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=msg) - finally: - conn.quit() + return text, html + + def create_message(self, email: Union[Email, CreateEmail]): + ts = time.time() + date = formatdate(ts, True) + + msg = MIMEMultipart("alternative") + msg["Date"] = date + msg["Subject"] = email.subject + msg["From"] = self.sender + msg["To"] = email.receiver + + text, html = self.render_email(email) + + part1 = MIMEText(text, "plain") + part2 = MIMEText(html, "html") + msg.attach(part1) + msg.attach(part2) + return msg + + async def send_mail(self, receiver, msg: MIMEMultipart): + + valid_email(self.sender) + valid_email(receiver) + + try: + conn = SMTP(host=self.smtp_server, port=int(self.smtp_port), timeout=10) + logger.debug("SMTP - connected to smtp server.") + # conn.set_debuglevel(True) + except: + log = f"SMTP - error connecting to smtp server: {self.smtp_server}:{self.smtp_port}." + logger.debug(log) + raise Exception(log) + + try: + conn.login(self.smtp_user, self.smtp_password) + logger.debug("SMTP - successful login to smtp server.") + except: + log = f"SMTP - error login into smtp {self.smtp_user}." + logger.error(log) + raise Exception(log) + + try: + conn.sendmail(self.sender, receiver, msg.as_string()) + logger.debug("SMTP - successfully send email.") + except socket.error as e: + log = f"SMTP - error sending email: {str(e)}." + logger.error(log) + raise Exception(log) + finally: + conn.quit() diff --git a/lnbits/extensions/smtp/tasks.py b/lnbits/extensions/smtp/tasks.py index 9c544473..93ed33ba 100644 --- a/lnbits/extensions/smtp/tasks.py +++ b/lnbits/extensions/smtp/tasks.py @@ -5,7 +5,7 @@ from loguru import logger from lnbits.core.models import Payment from lnbits.tasks import register_invoice_listener -from .crud import get_email, get_emailaddress, set_email_paid +from .crud import get_email_by_payment_hash, get_emailaddress, set_email_paid from .smtp import send_mail @@ -21,7 +21,7 @@ async def on_invoice_paid(payment: Payment) -> None: if payment.extra.get("tag") != "smtp": return - email = await get_email(payment.checking_id) + email = await get_email_by_payment_hash(payment.checking_id) if not email: logger.error("SMTP: email can not by fetched") return diff --git a/lnbits/extensions/smtp/templates/smtp/index.html b/lnbits/extensions/smtp/templates/smtp/index.html index bf43ad7f..c64cdcfa 100644 --- a/lnbits/extensions/smtp/templates/smtp/index.html +++ b/lnbits/extensions/smtp/templates/smtp/index.html @@ -57,6 +57,14 @@ :href="props.row.displayUrl" target="_blank" > + {{ col.value }} @@ -154,6 +162,42 @@ + + + + + + +
+ Submit +
+
+
+
@@ -316,10 +360,10 @@ emailsTable: { columns: [ { - name: 'emailaddress', + name: 'emailaddress_id', align: 'left', label: 'From', - field: 'emailaddress' + field: 'emailaddress_id' }, { name: 'receiver', @@ -350,6 +394,10 @@ rowsPerPage: 10 } }, + emailDialog: { + show: false, + data: {} + }, emailaddressDialog: { show: false, data: {} @@ -453,6 +501,33 @@ LNbits.utils.notifyApiError(error) }) }, + sendEmail: function () { + var self = this + var emailaddress = _.findWhere(this.emailaddresses, { + id: self.emailDialog.data.emailaddress_id + }) + var wallet = _.findWhere(this.g.user.wallets, { + id: emailaddress.wallet + }) + LNbits.api + .request( + 'POST', + '/smtp/api/v1/email/' + emailaddress.id + '/send', + wallet.adminkey, + self.emailDialog.data + ) + .then(function (response) { + self.emailDialog.show = false + self.emailDialog.data = {} + }) + .catch(function (error) { + LNbits.utils.notifyApiError(error) + }) + }, + showEmailDialog: function (emailaddress_id) { + this.emailDialog.data.emailaddress_id = emailaddress_id + this.emailDialog.show = true + }, updateEmailaddressDialog: function (formId) { var link = _.findWhere(this.emailaddresses, {id: formId}) this.emailaddressDialog.data = _.clone(link) diff --git a/lnbits/extensions/smtp/views_api.py b/lnbits/extensions/smtp/views_api.py index 4ae1f966..92b2d0bd 100644 --- a/lnbits/extensions/smtp/views_api.py +++ b/lnbits/extensions/smtp/views_api.py @@ -4,7 +4,7 @@ from fastapi import Depends, HTTPException, Query from lnbits.core.crud import get_user from lnbits.core.services import check_transaction_status, create_invoice -from lnbits.decorators import WalletTypeInfo, get_key_type +from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key from . import smtp_ext from .crud import ( @@ -19,7 +19,7 @@ from .crud import ( update_emailaddress, ) from .models import CreateEmail, CreateEmailaddress -from .smtp import valid_email +from .smtp import send_mail, valid_email ## EMAILS @@ -44,6 +44,7 @@ async def api_smtp_send_email(payment_hash): ) emailaddress = await get_emailaddress(email.emailaddress_id) + assert emailaddress try: status = await check_transaction_status(email.wallet, payment_hash) @@ -59,11 +60,9 @@ async def api_smtp_send_email(payment_hash): @smtp_ext.post("/api/v1/email/{emailaddress_id}") async def api_smtp_make_email(emailaddress_id, data: CreateEmail): - valid_email(data.receiver) emailaddress = await get_emailaddress(emailaddress_id) - # If the request is coming for the non-existant emailaddress if not emailaddress: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, @@ -94,6 +93,26 @@ async def api_smtp_make_email(emailaddress_id, data: CreateEmail): return {"payment_hash": payment_hash, "payment_request": payment_request} +@smtp_ext.post( + "/api/v1/email/{emailaddress_id}/send", dependencies=[Depends(require_admin_key)] +) +async def api_smtp_make_email_send(emailaddress_id, data: CreateEmail): + valid_email(data.receiver) + emailaddress = await get_emailaddress(emailaddress_id) + if not emailaddress: + raise HTTPException( + status_code=HTTPStatus.BAD_REQUEST, + detail="Emailaddress address does not exist.", + ) + email = await create_email(wallet=emailaddress.wallet, data=data) + if not email: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="Email could not be fetched." + ) + await send_mail(emailaddress, email) + return {"sent": True} + + @smtp_ext.delete("/api/v1/email/{email_id}") async def api_email_delete(email_id, g: WalletTypeInfo = Depends(get_key_type)): email = await get_email(email_id) From 85afb39388cc15c86c1554e09f7fca8e3c5d1e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Wed, 11 Jan 2023 19:24:19 +0100 Subject: [PATCH 12/27] add mission column in sql --- lnbits/extensions/smtp/crud.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/smtp/crud.py b/lnbits/extensions/smtp/crud.py index 62159703..a4158fa4 100644 --- a/lnbits/extensions/smtp/crud.py +++ b/lnbits/extensions/smtp/crud.py @@ -100,7 +100,7 @@ async def create_email(wallet: str, data: CreateEmail, payment_hash: str = "") - await db.execute( """ INSERT INTO smtp.email (id, payment_hash, wallet, emailaddress_id, subject, receiver, message, paid) - VALUES (?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, ( id, From a5825f1aa91fc5c82f2d97eb11b6e2f880d06a4f Mon Sep 17 00:00:00 2001 From: Joel Klabo Date: Wed, 11 Jan 2023 14:44:51 -0800 Subject: [PATCH 13/27] Enabled Editing the Price for NIP-5 Domains --- lnbits/extensions/nostrnip5/crud.py | 20 ++++- lnbits/extensions/nostrnip5/models.py | 9 +++ .../nostrnip5/templates/nostrnip5/index.html | 73 +++++++++++++++++++ lnbits/extensions/nostrnip5/views_api.py | 11 ++- 4 files changed, 111 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/nostrnip5/crud.py b/lnbits/extensions/nostrnip5/crud.py index fe71b981..b71670c7 100644 --- a/lnbits/extensions/nostrnip5/crud.py +++ b/lnbits/extensions/nostrnip5/crud.py @@ -3,7 +3,7 @@ from typing import List, Optional, Union from lnbits.helpers import urlsafe_short_hash from . import db -from .models import Address, CreateAddressData, CreateDomainData, Domain +from .models import Address, CreateAddressData, CreateDomainData, EditDomainData, Domain async def get_domain(domain_id: str) -> Optional[Domain]: @@ -169,6 +169,24 @@ async def create_address_internal(domain_id: str, data: CreateAddressData) -> Ad assert address, "Newly created address couldn't be retrieved" return address +async def update_domain_internal(wallet_id: str, data: EditDomainData) -> Domain: + if data.currency != "Satoshis": + amount = data.amount * 100 + else: + amount = data.amount + print(data) + await db.execute( + """ + UPDATE nostrnip5.domains + SET amount = ?, currency = ? + WHERE id = ? + """, + (int(amount), data.currency, data.id), + ) + + domain = await get_domain(data.id) + assert domain, "Domain couldn't be updated" + return domain async def create_domain_internal(wallet_id: str, data: CreateDomainData) -> Domain: domain_id = urlsafe_short_hash() diff --git a/lnbits/extensions/nostrnip5/models.py b/lnbits/extensions/nostrnip5/models.py index e02f2909..71e32c37 100644 --- a/lnbits/extensions/nostrnip5/models.py +++ b/lnbits/extensions/nostrnip5/models.py @@ -1,4 +1,5 @@ from enum import Enum +from locale import currency from sqlite3 import Row from typing import List, Optional @@ -23,6 +24,14 @@ class CreateDomainData(BaseModel): amount: float = Query(..., ge=0.01) domain: str +class EditDomainData(BaseModel): + id: str + currency: str + amount: float = Query(..., ge=0.01) + + @classmethod + def from_row(cls, row: Row) -> "Domain": + return cls(**dict(row)) class Domain(BaseModel): id: str diff --git a/lnbits/extensions/nostrnip5/templates/nostrnip5/index.html b/lnbits/extensions/nostrnip5/templates/nostrnip5/index.html index 6b805ccc..6d66ecd8 100644 --- a/lnbits/extensions/nostrnip5/templates/nostrnip5/index.html +++ b/lnbits/extensions/nostrnip5/templates/nostrnip5/index.html @@ -73,6 +73,14 @@ :color="($q.dark.isActive) ? 'grey-7' : 'grey-5'" @click="deleteDomain(props.row.id)" > +
{{ col.value }} @@ -226,6 +234,40 @@ + + + + + + +
+ Update Amount + Cancel +
+
+
+
+ Date: Wed, 11 Jan 2023 15:45:43 -0800 Subject: [PATCH 14/27] Formatting --- lnbits/extensions/nostrnip5/crud.py | 4 +++- lnbits/extensions/nostrnip5/models.py | 4 +++- .../nostrnip5/templates/nostrnip5/index.html | 22 +++++++++---------- lnbits/extensions/nostrnip5/views_api.py | 9 +++++++- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/lnbits/extensions/nostrnip5/crud.py b/lnbits/extensions/nostrnip5/crud.py index b71670c7..66b9840b 100644 --- a/lnbits/extensions/nostrnip5/crud.py +++ b/lnbits/extensions/nostrnip5/crud.py @@ -3,7 +3,7 @@ from typing import List, Optional, Union from lnbits.helpers import urlsafe_short_hash from . import db -from .models import Address, CreateAddressData, CreateDomainData, EditDomainData, Domain +from .models import Address, CreateAddressData, CreateDomainData, Domain, EditDomainData async def get_domain(domain_id: str) -> Optional[Domain]: @@ -169,6 +169,7 @@ async def create_address_internal(domain_id: str, data: CreateAddressData) -> Ad assert address, "Newly created address couldn't be retrieved" return address + async def update_domain_internal(wallet_id: str, data: EditDomainData) -> Domain: if data.currency != "Satoshis": amount = data.amount * 100 @@ -188,6 +189,7 @@ async def update_domain_internal(wallet_id: str, data: EditDomainData) -> Domain assert domain, "Domain couldn't be updated" return domain + async def create_domain_internal(wallet_id: str, data: CreateDomainData) -> Domain: domain_id = urlsafe_short_hash() diff --git a/lnbits/extensions/nostrnip5/models.py b/lnbits/extensions/nostrnip5/models.py index 71e32c37..0059a4ef 100644 --- a/lnbits/extensions/nostrnip5/models.py +++ b/lnbits/extensions/nostrnip5/models.py @@ -24,8 +24,9 @@ class CreateDomainData(BaseModel): amount: float = Query(..., ge=0.01) domain: str + class EditDomainData(BaseModel): - id: str + id: str currency: str amount: float = Query(..., ge=0.01) @@ -33,6 +34,7 @@ class EditDomainData(BaseModel): def from_row(cls, row: Row) -> "Domain": return cls(**dict(row)) + class Domain(BaseModel): id: str wallet: str diff --git a/lnbits/extensions/nostrnip5/templates/nostrnip5/index.html b/lnbits/extensions/nostrnip5/templates/nostrnip5/index.html index 6d66ecd8..8ebaa502 100644 --- a/lnbits/extensions/nostrnip5/templates/nostrnip5/index.html +++ b/lnbits/extensions/nostrnip5/templates/nostrnip5/index.html @@ -235,7 +235,11 @@ - +
- Update Amount + Update Amount Cancel @@ -627,13 +626,14 @@ saveEditedDomain: function () { var data = this.editFormDialog.data var self = this - + LNbits.api .request( 'PUT', '/nostrnip5/api/v1/domain', - _.findWhere(this.g.user.wallets, {id: this.editFormDialog.data.wallet}) - .inkey, + _.findWhere(this.g.user.wallets, { + id: this.editFormDialog.data.wallet + }).inkey, data ) .then(function (response) { @@ -647,7 +647,7 @@ editDomain: function (domain_id) { var self = this var data = _.findWhere(this.domains, {id: domain_id}) - + self.editFormDialog.show = true self.editFormDialog.data = data }, diff --git a/lnbits/extensions/nostrnip5/views_api.py b/lnbits/extensions/nostrnip5/views_api.py index 3dc1cbc8..99a0fe01 100644 --- a/lnbits/extensions/nostrnip5/views_api.py +++ b/lnbits/extensions/nostrnip5/views_api.py @@ -28,7 +28,12 @@ from .crud import ( rotate_address, update_domain_internal, ) -from .models import CreateAddressData, CreateDomainData, RotateAddressData, EditDomainData +from .models import ( + CreateAddressData, + CreateDomainData, + EditDomainData, + RotateAddressData, +) @nostrnip5_ext.get("/api/v1/domains", status_code=HTTPStatus.OK) @@ -89,6 +94,7 @@ async def api_domain_create( return domain + @nostrnip5_ext.put("/api/v1/domain", status_code=HTTPStatus.OK) async def api_domain_update( data: EditDomainData, wallet: WalletTypeInfo = Depends(get_key_type) @@ -98,6 +104,7 @@ async def api_domain_update( return domain + @nostrnip5_ext.delete("/api/v1/domain/{domain_id}", status_code=HTTPStatus.CREATED) async def api_domain_delete( domain_id: str, From 731ebf9f852a098060c6ca2e5fe712208ffab341 Mon Sep 17 00:00:00 2001 From: Joel Klabo Date: Wed, 11 Jan 2023 15:51:05 -0800 Subject: [PATCH 15/27] Fix EditDomainData in Test --- lnbits/extensions/nostrnip5/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/nostrnip5/models.py b/lnbits/extensions/nostrnip5/models.py index 0059a4ef..f6492d1a 100644 --- a/lnbits/extensions/nostrnip5/models.py +++ b/lnbits/extensions/nostrnip5/models.py @@ -31,7 +31,7 @@ class EditDomainData(BaseModel): amount: float = Query(..., ge=0.01) @classmethod - def from_row(cls, row: Row) -> "Domain": + def from_row(cls, row: Row) -> "EditDomainData": return cls(**dict(row)) From 76e84359cee57e2608684f14b6016597a6146606 Mon Sep 17 00:00:00 2001 From: Joel Klabo Date: Wed, 11 Jan 2023 18:51:09 -0800 Subject: [PATCH 16/27] Remove Accidental Import --- lnbits/extensions/nostrnip5/models.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lnbits/extensions/nostrnip5/models.py b/lnbits/extensions/nostrnip5/models.py index f6492d1a..5abbf128 100644 --- a/lnbits/extensions/nostrnip5/models.py +++ b/lnbits/extensions/nostrnip5/models.py @@ -1,5 +1,4 @@ from enum import Enum -from locale import currency from sqlite3 import Row from typing import List, Optional From 12688efd5fc19500e1053a1ef9dc95980b4ffa52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 9 Jan 2023 09:03:27 +0100 Subject: [PATCH 17/27] add additional data --- pyproject.toml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5e764719..9ddd249e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,8 +1,12 @@ [tool.poetry] name = "lnbits" -version = "0.1.0" -description = "" -authors = ["matthewcroughan "] +version = "0.9.5.3" +description = "LNbits, free and open-source lightning-network wallet/accounts system" +authors = [ + "benarc " +] [tool.poetry.build] generate-setup-file = false From 1cc3801e38a0198ce8791f59be8bcb1210dbf0eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 9 Jan 2023 09:06:53 +0100 Subject: [PATCH 18/27] invalid author string -.- --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 9ddd249e..d3f66bc4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,8 +3,8 @@ name = "lnbits" version = "0.9.5.3" description = "LNbits, free and open-source lightning-network wallet/accounts system" authors = [ - "benarc ", + "dni ", "matthewcroughan " ] From a3f7636db06605f781fc172d210846148cc90266 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Tue, 10 Jan 2023 12:25:11 +0100 Subject: [PATCH 19/27] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d3f66bc4..f8f33f3b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "lnbits" version = "0.9.5.3" -description = "LNbits, free and open-source lightning-network wallet/accounts system" +description = "LNbits, free and open-source Lightning wallet and accounts system." authors = [ "benarc ", "dni ", From 08c485e34bbf5b37ee0dcf81a9afb3ec41627351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 12 Jan 2023 07:54:30 +0100 Subject: [PATCH 20/27] add only 1 general author --- pyproject.toml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f8f33f3b..1673048c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,11 +2,7 @@ name = "lnbits" version = "0.9.5.3" description = "LNbits, free and open-source Lightning wallet and accounts system." -authors = [ - "benarc ", - "dni ", - "matthewcroughan " -] +authors = ["lnbits "] [tool.poetry.build] generate-setup-file = false From bb57831c53123596a5ce629373e91ff14063bf2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 12 Jan 2023 08:05:05 +0100 Subject: [PATCH 21/27] fix little issues after refactor :) --- lnbits/extensions/smtp/crud.py | 6 +++--- lnbits/extensions/smtp/views_api.py | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lnbits/extensions/smtp/crud.py b/lnbits/extensions/smtp/crud.py index a4158fa4..c7b96df5 100644 --- a/lnbits/extensions/smtp/crud.py +++ b/lnbits/extensions/smtp/crud.py @@ -123,7 +123,7 @@ async def set_email_paid(payment_hash: str) -> bool: email = await get_email_by_payment_hash(payment_hash) if email and email.paid == False: await db.execute( - f"UPDATE smtp.email SET paid = true WHERE payment_hash = {payment_hash}" + f"UPDATE smtp.email SET paid = true WHERE payment_hash = ?", (payment_hash,) ) return True return False @@ -131,13 +131,13 @@ async def set_email_paid(payment_hash: str) -> bool: async def get_email_by_payment_hash(payment_hash: str) -> Optional[Email]: row = await db.fetchone( - f"SELECT * FROM smtp.email WHERE payment_hash = {payment_hash}" + f"SELECT * FROM smtp.email WHERE payment_hash = ?", (payment_hash,) ) return Email(**row) if row else None async def get_email(id: str) -> Optional[Email]: - row = await db.fetchone(f"SELECT * FROM smtp.email WHERE id = {id}") + row = await db.fetchone(f"SELECT * FROM smtp.email WHERE id = ?", (id,)) return Email(**row) if row else None diff --git a/lnbits/extensions/smtp/views_api.py b/lnbits/extensions/smtp/views_api.py index 92b2d0bd..66bc4983 100644 --- a/lnbits/extensions/smtp/views_api.py +++ b/lnbits/extensions/smtp/views_api.py @@ -13,6 +13,7 @@ from .crud import ( delete_email, delete_emailaddress, get_email, + get_email_by_payment_hash, get_emailaddress, get_emailaddresses, get_emails, @@ -37,7 +38,7 @@ async def api_email( @smtp_ext.get("/api/v1/email/{payment_hash}") async def api_smtp_send_email(payment_hash): - email = await get_email(payment_hash) + email = await get_email_by_payment_hash(payment_hash) if not email: raise HTTPException( status_code=HTTPStatus.BAD_REQUEST, detail="paymenthash is wrong" From ca4df159e1be95c3f439b59a53c5d07b84a2cb5e Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 12 Jan 2023 11:07:19 +0000 Subject: [PATCH 22/27] update poetry --- docs/guide/installation.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 2bbdfb11..1b2e07e9 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -53,6 +53,7 @@ poetry run lnbits cd lnbits-legend/ # Stop LNbits with `ctrl + x` git pull +# Keep your poetry install up to date, this can be done with `poetry self update` poetry install --only main # Start LNbits with `poetry run lnbits` ``` From 97fd5eac8f66fb7ad35f0f9459255ec5b26e6702 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Thu, 12 Jan 2023 15:47:42 +0100 Subject: [PATCH 23/27] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 1673048c..383c4ff9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "lnbits" version = "0.9.5.3" description = "LNbits, free and open-source Lightning wallet and accounts system." -authors = ["lnbits "] +authors = ["Alan Bits "] [tool.poetry.build] generate-setup-file = false From f624b54cfb3e119bd2b6fcb3ae9bda9ba10cbadb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 12 Jan 2023 16:05:25 +0100 Subject: [PATCH 24/27] fix wrong migration --- lnbits/extensions/smtp/migrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/smtp/migrations.py b/lnbits/extensions/smtp/migrations.py index f8f39635..fbe77d73 100644 --- a/lnbits/extensions/smtp/migrations.py +++ b/lnbits/extensions/smtp/migrations.py @@ -36,4 +36,4 @@ async def m001_initial(db): async def m002_add_payment_hash(db): - await db.execute(f"ALTER TABLE smtp.email ADD COLUMN payment_hash TEXT NOT NULL;") + await db.execute(f"ALTER TABLE smtp.email ADD COLUMN payment_hash TEXT;") From 20e6ca019ee0c523ef74bb011f44b4923e400319 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Sat, 14 Jan 2023 11:26:17 +0000 Subject: [PATCH 25/27] replace lnbits-legend with lnbits in github links (#1366) --- docs/guide/installation.md | 28 +++++++++---------- lnbits/core/templates/core/index.html | 2 +- .../boltz/templates/boltz/_api_docs.html | 2 +- .../templates/lnaddress/_api_docs.html | 2 +- .../lnaddress/templates/lnaddress/index.html | 2 +- .../templates/subdomains/_api_docs.html | 2 +- lnbits/wallets/eclair.py | 2 +- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/guide/installation.md b/docs/guide/installation.md index 1b2e07e9..52ce6420 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -15,8 +15,8 @@ By default, LNbits will use SQLite as its database. You can also use PostgreSQL If you have problems installing LNbits using these instructions, please have a look at the [Troubleshooting](#troubleshooting) section. ```sh -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend/ +git clone https://github.com/lnbits/lnbits.git +cd lnbits # for making sure python 3.9 is installed, skip if installed. To check your installed version: python3 --version sudo apt update @@ -50,7 +50,7 @@ poetry run lnbits #### Updating the server ``` -cd lnbits-legend/ +cd lnbits # Stop LNbits with `ctrl + x` git pull # Keep your poetry install up to date, this can be done with `poetry self update` @@ -63,8 +63,8 @@ poetry install --only main > note: currently not supported while we make some architectural changes on the path to leave beta ```sh -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend/ +git clone https://github.com/lnbits/lnbits.git +cd lnbits # Modern debian distros usually include Nix, however you can install with: # 'sh <(curl -L https://nixos.org/nix/install) --daemon', or use setup here https://nixos.org/download.html#nix-verify-installation @@ -83,8 +83,8 @@ LNBITS_DATA_FOLDER=data LNBITS_BACKEND_WALLET_CLASS=LNbitsWallet LNBITS_ENDPOINT ## Option 3: venv ```sh -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend/ +git clone https://github.com/lnbits/lnbits.git +cd lnbits # ensure you have virtualenv installed, on debian/ubuntu 'apt install python3.9-venv' python3.9 -m venv venv # If you have problems here, try `sudo apt install -y pkg-config libpq-dev` @@ -106,9 +106,9 @@ If you want to host LNbits on the internet, run with the option `--host 0.0.0.0` ## Option 4: Docker ```sh -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend -docker build -t lnbits-legend . +git clone https://github.com/lnbits/lnbits.git +cd lnbits +docker build -t lnbits . cp .env.example .env mkdir data docker run --detach --publish 5000:5000 --name lnbits-legend --volume ${PWD}/.env:/app/.env --volume ${PWD}/data/:/app/data lnbits-legend @@ -136,8 +136,8 @@ You can either run those commands, then `source ~/.bash_profile` or, if you don' Once installed, run the following commands. ``` -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend +git clone https://github.com/lnbits/lnbits.git +cd lnbits fly auth login [complete login process] fly launch @@ -438,8 +438,8 @@ If you want to run LNbits on your Umbrel but want it to be reached through clear To install using docker you first need to build the docker image as: ``` -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend +git clone https://github.com/lnbits/lnbits.git +cd lnbits docker build -t lnbits-legend . ``` diff --git a/lnbits/core/templates/core/index.html b/lnbits/core/templates/core/index.html index a28030c0..104dccd9 100644 --- a/lnbits/core/templates/core/index.html +++ b/lnbits/core/templates/core/index.html @@ -66,7 +66,7 @@ outline color="grey" type="a" - href="https://github.com/lnbits/lnbits-legend" + href="https://github.com/lnbits/lnbits" target="_blank" rel="noopener" >View project in GitHubMore details

diff --git a/lnbits/extensions/lnaddress/templates/lnaddress/_api_docs.html b/lnbits/extensions/lnaddress/templates/lnaddress/_api_docs.html index 300f56e9..f4d1f651 100644 --- a/lnbits/extensions/lnaddress/templates/lnaddress/_api_docs.html +++ b/lnbits/extensions/lnaddress/templates/lnaddress/_api_docs.html @@ -14,7 +14,7 @@ More details
diff --git a/lnbits/extensions/lnaddress/templates/lnaddress/index.html b/lnbits/extensions/lnaddress/templates/lnaddress/index.html index 55d900f4..41602581 100644 --- a/lnbits/extensions/lnaddress/templates/lnaddress/index.html +++ b/lnbits/extensions/lnaddress/templates/lnaddress/index.html @@ -195,7 +195,7 @@ Check extension documentation! diff --git a/lnbits/extensions/subdomains/templates/subdomains/_api_docs.html b/lnbits/extensions/subdomains/templates/subdomains/_api_docs.html index 08a2806e..035d67a6 100644 --- a/lnbits/extensions/subdomains/templates/subdomains/_api_docs.html +++ b/lnbits/extensions/subdomains/templates/subdomains/_api_docs.html @@ -14,7 +14,7 @@ More details
diff --git a/lnbits/wallets/eclair.py b/lnbits/wallets/eclair.py index 57eec582..b0c00db2 100644 --- a/lnbits/wallets/eclair.py +++ b/lnbits/wallets/eclair.py @@ -8,7 +8,7 @@ from typing import AsyncGenerator, Dict, Optional import httpx from loguru import logger -# TODO: https://github.com/lnbits/lnbits-legend/issues/764 +# TODO: https://github.com/lnbits/lnbits/issues/764 # mypy https://github.com/aaugustin/websockets/issues/940 from websockets import connect # type: ignore from websockets.exceptions import ( From 265ea16d301fc923c6ddc902c400ac01ae3de0ea Mon Sep 17 00:00:00 2001 From: Sam Korn Date: Sat, 14 Jan 2023 04:31:00 -0700 Subject: [PATCH 26/27] add example configuration for connecting LND over grpc (#1364) --- .env.example | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 6a3710c2..56943c4d 100644 --- a/.env.example +++ b/.env.example @@ -54,8 +54,9 @@ LNBITS_SITE_DESCRIPTION="Some description about your service, will display if ti LNBITS_THEME_OPTIONS="classic, bitcoin, flamingo, freedom, mint, autumn, monochrome, salvador" # LNBITS_CUSTOM_LOGO="https://lnbits.com/assets/images/logo/logo.svg" -# Choose from LNPayWallet, OpenNodeWallet, LntxbotWallet, ClicheWallet, LnTipsWallet -# LndRestWallet, CoreLightningWallet, LNbitsWallet, SparkWallet, FakeWallet, EclairWallet +# Choose from LNPayWallet, OpenNodeWallet, LntxbotWallet, ClicheWallet, +# LndWallet, LndRestWallet, CoreLightningWallet, EclairWallet, +# LnTipsWallet, LNbitsWallet, SparkWallet, FakeWallet, LNBITS_BACKEND_WALLET_CLASS=VoidWallet # VoidWallet is just a fallback that works without any actual Lightning capabilities, # just so you can see the UI before dealing with this file. @@ -76,6 +77,14 @@ CORELIGHTNING_RPC="/home/bob/.lightning/bitcoin/lightning-rpc" LNBITS_ENDPOINT=https://legend.lnbits.com LNBITS_KEY=LNBITS_ADMIN_KEY +# LndWallet +LND_GRPC_ENDPOINT=127.0.0.1 +LND_GRPC_PORT=10009 +LND_GRPC_CERT="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/tls.cert" +LND_GRPC_MACAROON="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/admin.macaroon or HEXSTRING" +# To use an AES-encrypted macaroon, set +# LND_GRPC_MACAROON="eNcRyPtEdMaCaRoOn" + # LndRestWallet LND_REST_ENDPOINT=https://127.0.0.1:8080/ LND_REST_CERT="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/tls.cert" From 17f5b734b277f3ca5c99dc410d40dc116f5cd848 Mon Sep 17 00:00:00 2001 From: calle <93376500+callebtc@users.noreply.github.com> Date: Sun, 15 Jan 2023 11:24:11 +0100 Subject: [PATCH 27/27] Cashu 0.8 (#1370) * support cashu 0.8 * dont comment out script * update cashu logo on mint page * fixing versions * installing cashu from pypi works * update requirements.txt --- .../cashu/templates/cashu/mint.html | 57 +-- .../cashu/templates/cashu/wallet.html | 120 ++----- lnbits/extensions/cashu/views_api.py | 23 +- poetry.lock | 340 +++++++++--------- pyproject.toml | 16 +- requirements.txt | 38 +- 6 files changed, 271 insertions(+), 323 deletions(-) diff --git a/lnbits/extensions/cashu/templates/cashu/mint.html b/lnbits/extensions/cashu/templates/cashu/mint.html index bcb919ff..a6959ec2 100644 --- a/lnbits/extensions/cashu/templates/cashu/mint.html +++ b/lnbits/extensions/cashu/templates/cashu/mint.html @@ -4,18 +4,19 @@
- -

{{ mint_name }}

+ +

{{ mint_name }}

+ Open walletclick to open wallet
@@ -58,24 +59,34 @@

This service is in BETA
- We hold no responsibility for people losing access to funds. Use at - your own risk! + Cashu is still experimental and in active development. There are + likely bugs in this implementation so please use this with caution. We + hold no responsibility for people losing access to funds. Use at your + own risk!

- - {% endblock %} {% block scripts %} - - - - {% endblock %} + +{% endblock %} {% block scripts %} + + + +{% endblock %} diff --git a/lnbits/extensions/cashu/templates/cashu/wallet.html b/lnbits/extensions/cashu/templates/cashu/wallet.html index d075009e..1bf6241f 100644 --- a/lnbits/extensions/cashu/templates/cashu/wallet.html +++ b/lnbits/extensions/cashu/templates/cashu/wallet.html @@ -1479,15 +1479,15 @@ page_container %} }, constructOutputs: async function (amounts, secrets) { - const blindedMessages = [] + const outputs = [] const rs = [] for (let i = 0; i < amounts.length; i++) { const {B_, r} = await step1Alice(secrets[i]) - blindedMessages.push({amount: amounts[i], B_: B_}) + outputs.push({amount: amounts[i], B_: B_}) rs.push(r) } return { - blindedMessages, + outputs, rs } }, @@ -1581,25 +1581,26 @@ page_container %} mintApi: async function (amounts, payment_hash, verbose = true) { /* asks the mint to check whether the invoice with payment_hash has been paid - and requests signing of the attached outputs (blindedMessages) + and requests signing of the attached outputs. */ console.log('### promises', payment_hash) try { let secrets = await this.generateSecrets(amounts) - let {blindedMessages, rs} = await this.constructOutputs( - amounts, - secrets - ) + let {outputs, rs} = await this.constructOutputs(amounts, secrets) const promises = await LNbits.api.request( 'POST', `/cashu/api/v1/${this.mintId}/mint?payment_hash=${payment_hash}`, '', { - blinded_messages: blindedMessages + outputs } ) - console.log('### promises data', promises.data) - let proofs = await this.constructProofs(promises.data, secrets, rs) + console.log('### promises data', promises.data.promises) + let proofs = await this.constructProofs( + promises.data.promises, + secrets, + rs + ) return proofs } catch (error) { console.error(error) @@ -1682,16 +1683,11 @@ page_container %} 'number of secrets does not match number of outputs.' ) } - let {blindedMessages, rs} = await this.constructOutputs( - amounts, - secrets - ) + let {outputs, rs} = await this.constructOutputs(amounts, secrets) const payload = { amount, proofs, - outputs: { - blinded_messages: blindedMessages - } + outputs } console.log('payload', JSON.stringify(payload)) @@ -1881,10 +1877,7 @@ page_container %} 'amount with fees', amount ) - // if (amount > balance()) { - // LNbits.utils.notifyApiError('Balance too low') - // return - // } + let {fristProofs, scndProofs} = await this.splitToSend( this.proofs, amount @@ -2132,6 +2125,19 @@ page_container %} return paid }, + findTokenForAmount: function (amount) { + for (const token of this.proofs) { + const index = token.promises?.findIndex(p => p.amount === amount) + if (index >= 0) { + return { + promise: token.promises[index], + secret: token.secrets[index], + r: token.rs[index] + } + } + } + }, + ////////////// WORKERS ////////////// clearAllWorkers: function () { @@ -2220,76 +2226,6 @@ page_container %} //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - findTokenForAmount: function (amount) { - for (const token of this.proofs) { - const index = token.promises?.findIndex(p => p.amount === amount) - if (index >= 0) { - return { - promise: token.promises[index], - secret: token.secrets[index], - r: token.rs[index] - } - } - } - }, - - // checkInvoice: function () { - // console.log('#### checkInvoice') - // try { - // const invoice = decode(this.payInvoiceData.data.request) - - // const cleanInvoice = { - // msat: invoice.human_readable_part.amount, - // sat: invoice.human_readable_part.amount / 1000, - // fsat: LNbits.utils.formatSat( - // invoice.human_readable_part.amount / 1000 - // ) - // } - - // _.each(invoice.data.tags, tag => { - // if (_.isObject(tag) && _.has(tag, 'description')) { - // if (tag.description === 'payment_hash') { - // cleanInvoice.hash = tag.value - // } else if (tag.description === 'description') { - // cleanInvoice.description = tag.value - // } else if (tag.description === 'expiry') { - // var expireDate = new Date( - // (invoice.data.time_stamp + tag.value) * 1000 - // ) - // cleanInvoice.expireDate = Quasar.utils.date.formatDate( - // expireDate, - // 'YYYY-MM-DDTHH:mm:ss.SSSZ' - // ) - // cleanInvoice.expired = false // TODO - // } - // } - - // this.payInvoiceData.invoice = cleanInvoice - // }) - - // console.log( - // '#### this.payInvoiceData.invoice', - // this.payInvoiceData.invoice - // ) - // } catch (error) { - // this.$q.notify({ - // timeout: 5000, - // type: 'warning', - // message: 'Could not decode invoice', - // caption: error + '', - // position: 'top', - // actions: [ - // { - // icon: 'close', - // color: 'white', - // handler: () => {} - // } - // ] - // }) - // throw error - // } - // }, - ////////////// STORAGE ///////////// getLocalstorageToFile: async function () { diff --git a/lnbits/extensions/cashu/views_api.py b/lnbits/extensions/cashu/views_api.py index b66bbdc1..2017df00 100644 --- a/lnbits/extensions/cashu/views_api.py +++ b/lnbits/extensions/cashu/views_api.py @@ -12,7 +12,8 @@ from cashu.core.base import ( GetMintResponse, Invoice, MeltRequest, - MintRequest, + PostMintRequest, + PostMintResponse, PostSplitResponse, SplitRequest, ) @@ -204,10 +205,10 @@ async def request_mint(cashu_id: str = Query(None), amount: int = 0) -> GetMintR @cashu_ext.post("/api/v1/{cashu_id}/mint") async def mint( - data: MintRequest, + data: PostMintRequest, cashu_id: str = Query(None), payment_hash: str = Query(None), -) -> List[BlindedSignature]: +) -> PostMintResponse: """ Requests the minting of tokens belonging to a paid payment request. Call this endpoint after `GET /mint`. @@ -245,7 +246,7 @@ async def mint( ) try: - total_requested = sum([bm.amount for bm in data.blinded_messages]) + total_requested = sum([bm.amount for bm in data.outputs]) if total_requested > invoice.amount: raise HTTPException( status_code=HTTPStatus.PAYMENT_REQUIRED, @@ -257,10 +258,8 @@ async def mint( status_code=HTTPStatus.PAYMENT_REQUIRED, detail="Invoice not paid." ) - promises = await ledger._generate_promises( - B_s=data.blinded_messages, keyset=keyset - ) - return promises + promises = await ledger._generate_promises(B_s=data.outputs, keyset=keyset) + return PostMintResponse(promises=promises) except (Exception, HTTPException) as e: logger.debug(f"Cashu: /melt {str(e) or getattr(e, 'detail')}") # unset issued flag because something went wrong @@ -274,10 +273,8 @@ async def mint( ) else: # only used for testing when LIGHTNING=false - promises = await ledger._generate_promises( - B_s=data.blinded_messages, keyset=keyset - ) - return promises + promises = await ledger._generate_promises(B_s=data.outputs, keyset=keyset) + return PostMintResponse(promises=promises) @cashu_ext.post("/api/v1/{cashu_id}/melt") @@ -421,7 +418,7 @@ async def split( ) amount = payload.amount - outputs = payload.outputs.blinded_messages + outputs = payload.outputs assert outputs, Exception("no outputs provided.") split_return = None try: diff --git a/poetry.lock b/poetry.lock index 698d700d..5a99e198 100644 --- a/poetry.lock +++ b/poetry.lock @@ -81,21 +81,22 @@ typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""} [[package]] name = "attrs" -version = "22.1.0" +version = "22.2.0" description = "Classes Without Boilerplate" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, + {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, + {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, ] [package.extras] -dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] -docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] -tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] -tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] +cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] +tests = ["attrs[tests-no-zope]", "zope.interface"] +tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] [[package]] name = "base58" @@ -176,61 +177,65 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "cashu" -version = "0.6.0" -description = "Ecash wallet and mint with Bitcoin Lightning support" +version = "0.8.2" +description = "Ecash wallet and mint for Bitcoin Lightning" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "cashu-0.6.0-py3-none-any.whl", hash = "sha256:54096af145643aab45943b235f95a3357b0ec697835c1411e66523049ffb81f6"}, - {file = "cashu-0.6.0.tar.gz", hash = "sha256:503a90c4ca8d25d0b2c3f78a11b163c32902a726ea5b58e5337dc00eca8e96ad"}, + {file = "cashu-0.8.2-py3-none-any.whl", hash = "sha256:53893911763c424255bc7112aaba356e0a265e850d770338c70b2d282f67bf99"}, + {file = "cashu-0.8.2.tar.gz", hash = "sha256:4cdd34a50d14960d2dcc6f5b6120f462688090dd084387860f7a59d16aa102ff"}, ] [package.dependencies] anyio = {version = "3.6.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -attrs = {version = "22.1.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +attrs = {version = "22.2.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} bech32 = {version = "1.2.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} bitstring = {version = "3.1.9", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -certifi = {version = "2022.9.24", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +certifi = {version = "2022.12.7", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} cffi = {version = "1.15.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} charset-normalizer = {version = "2.0.12", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} click = {version = "8.0.4", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -colorama = {version = "0.4.5", markers = "python_version >= \"3.7\" and python_version < \"4.0\" and platform_system == \"Windows\" or python_version >= \"3.7\" and python_version < \"4.0\" and sys_platform == \"win32\""} +colorama = {version = "0.4.6", markers = "python_version >= \"3.7\" and python_version < \"4.0\" and platform_system == \"Windows\" or python_version >= \"3.7\" and python_version < \"4.0\" and sys_platform == \"win32\""} +cryptography = {version = "36.0.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} ecdsa = {version = "0.18.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} environs = {version = "9.5.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +exceptiongroup = {version = "1.1.0", markers = "python_version >= \"3.7\" and python_version < \"3.11\""} fastapi = {version = "0.83.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} h11 = {version = "0.12.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} idna = {version = "3.4", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -importlib-metadata = {version = "5.0.0", markers = "python_version >= \"3.7\" and python_version < \"3.8\""} -iniconfig = {version = "1.1.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +importlib-metadata = {version = "5.2.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +iniconfig = {version = "2.0.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} loguru = {version = "0.6.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -marshmallow = {version = "3.18.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +marshmallow = {version = "3.19.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} outcome = {version = "1.2.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -packaging = {version = "21.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +packaging = {version = "23.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} pluggy = {version = "1.0.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -py = {version = "1.11.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} pycparser = {version = "2.21", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -pydantic = {version = "1.10.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -pyparsing = {version = "3.0.9", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +pycryptodomex = {version = "3.16.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +pydantic = {version = "1.10.4", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} pysocks = {version = "1.7.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -pytest = {version = "7.1.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +pytest = {version = "7.2.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} pytest-asyncio = {version = "0.19.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} python-bitcoinlib = {version = "0.11.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} python-dotenv = {version = "0.21.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} represent = {version = "1.6.0.post0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} requests = {version = "2.27.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} secp256k1 = {version = "0.14.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +setuptools = {version = "65.7.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} six = {version = "1.16.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} sniffio = {version = "1.3.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} sqlalchemy = {version = "1.3.24", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} sqlalchemy-aio = {version = "0.17.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} starlette = {version = "0.19.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -tomli = {version = "2.0.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +tomli = {version = "2.0.1", markers = "python_version >= \"3.7\" and python_version < \"3.11\""} typing-extensions = {version = "4.4.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -urllib3 = {version = "1.26.12", markers = "python_version >= \"3.7\" and python_version < \"4\""} +urllib3 = {version = "1.26.14", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} uvicorn = {version = "0.18.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +websocket-client = {version = "1.3.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +wheel = {version = "0.38.4", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} win32-setctime = {version = "1.1.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\" and sys_platform == \"win32\""} -zipp = {version = "3.9.0", markers = "python_version >= \"3.7\" and python_version < \"3.8\""} +zipp = {version = "3.11.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} [[package]] name = "cerberus" @@ -248,14 +253,14 @@ setuptools = "*" [[package]] name = "certifi" -version = "2022.9.24" +version = "2022.12.7" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, - {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, + {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, + {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, ] [[package]] @@ -416,14 +421,14 @@ cffi = ">=1.3.0" [[package]] name = "colorama" -version = "0.4.5" +version = "0.4.6" description = "Cross-platform colored terminal text." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, - {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] [[package]] @@ -527,10 +532,10 @@ files = [ cffi = ">=1.12" [package.extras] -docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx_rtd_theme"] +docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"] docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"] -sdist = ["setuptools_rust (>=0.11.4)"] +sdist = ["setuptools-rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"] @@ -599,6 +604,21 @@ django = ["dj-database-url", "dj-email-url", "django-cache-url"] lint = ["flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)"] tests = ["dj-database-url", "dj-email-url", "django-cache-url", "pytest"] +[[package]] +name = "exceptiongroup" +version = "1.1.0" +description = "Backport of PEP 654 (exception groups)" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, + {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, +] + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "fastapi" version = "0.83.0" @@ -798,14 +818,14 @@ files = [ [[package]] name = "importlib-metadata" -version = "5.0.0" +version = "5.2.0" description = "Read metadata from Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"}, - {file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"}, + {file = "importlib_metadata-5.2.0-py3-none-any.whl", hash = "sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f"}, + {file = "importlib_metadata-5.2.0.tar.gz", hash = "sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd"}, ] [package.dependencies] @@ -813,20 +833,20 @@ typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] [[package]] name = "iniconfig" -version = "1.1.1" -description = "iniconfig: brain-dead simple config-ini parsing" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, - {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] [[package]] @@ -982,23 +1002,23 @@ files = [ [[package]] name = "marshmallow" -version = "3.18.0" +version = "3.19.0" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "marshmallow-3.18.0-py3-none-any.whl", hash = "sha256:35e02a3a06899c9119b785c12a22f4cda361745d66a71ab691fd7610202ae104"}, - {file = "marshmallow-3.18.0.tar.gz", hash = "sha256:6804c16114f7fce1f5b4dadc31f4674af23317fcc7f075da21e35c1a35d781f7"}, + {file = "marshmallow-3.19.0-py3-none-any.whl", hash = "sha256:93f0958568da045b0021ec6aeb7ac37c81bfcccbb9a0e7ed8559885070b3a19b"}, + {file = "marshmallow-3.19.0.tar.gz", hash = "sha256:90032c0fd650ce94b6ec6dc8dfeb0e3ff50c144586462c389b81a07205bedb78"}, ] [package.dependencies] packaging = ">=17.0" [package.extras] -dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.9.11)", "mypy (==0.971)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"] -docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.1.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] -lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.9.11)", "mypy (==0.971)", "pre-commit (>=2.4,<3.0)"] +dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"] +docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.3.0)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"] +lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)"] tests = ["pytest", "pytz", "simplejson"] [[package]] @@ -1091,19 +1111,16 @@ attrs = ">=19.2.0" [[package]] name = "packaging" -version = "21.3" +version = "23.0" description = "Core utilities for Python packages" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, - {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, + {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, + {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, ] -[package.dependencies] -pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" - [[package]] name = "pathlib2" version = "2.3.7.post1" @@ -1239,18 +1256,6 @@ files = [ {file = "psycopg2_binary-2.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:b4d7679a08fea64573c969f6994a2631908bb2c0e69a7235648642f3d2e39a68"}, ] -[[package]] -name = "py" -version = "1.11.0" -description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -files = [ - {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, - {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, -] - [[package]] name = "pycparser" version = "2.21" @@ -1265,89 +1270,88 @@ files = [ [[package]] name = "pycryptodomex" -version = "3.14.1" +version = "3.16.0" description = "Cryptographic library for Python" category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" files = [ - {file = "pycryptodomex-3.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca88f2f7020002638276439a01ffbb0355634907d1aa5ca91f3dc0c2e44e8f3b"}, - {file = "pycryptodomex-3.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:8536bc08d130cae6dcba1ea689f2913dfd332d06113904d171f2f56da6228e89"}, - {file = "pycryptodomex-3.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:406ec8cfe0c098fadb18d597dc2ee6de4428d640c0ccafa453f3d9b2e58d29e2"}, - {file = "pycryptodomex-3.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:da8db8374295fb532b4b0c467e66800ef17d100e4d5faa2bbbd6df35502da125"}, - {file = "pycryptodomex-3.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:d709572d64825d8d59ea112e11cc7faf6007f294e9951324b7574af4251e4de8"}, - {file = "pycryptodomex-3.14.1-cp27-cp27m-win32.whl", hash = "sha256:3da13c2535b7aea94cc2a6d1b1b37746814c74b6e80790daddd55ca5c120a489"}, - {file = "pycryptodomex-3.14.1-cp27-cp27m-win_amd64.whl", hash = "sha256:298c00ea41a81a491d5b244d295d18369e5aac4b61b77b2de5b249ca61cd6659"}, - {file = "pycryptodomex-3.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:77931df40bb5ce5e13f4de2bfc982b2ddc0198971fbd947776c8bb5050896eb2"}, - {file = "pycryptodomex-3.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:c5dd3ffa663c982d7f1be9eb494a8924f6d40e2e2f7d1d27384cfab1b2ac0662"}, - {file = "pycryptodomex-3.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa887683eee493e015545bd69d3d21ac8d5ad582674ec98f4af84511e353e45"}, - {file = "pycryptodomex-3.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:8085bd0ad2034352eee4d4f3e2da985c2749cb7344b939f4d95ead38c2520859"}, - {file = "pycryptodomex-3.14.1-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e95a4a6c54d27a84a4624d2af8bb9ee178111604653194ca6880c98dcad92f48"}, - {file = "pycryptodomex-3.14.1-cp35-abi3-manylinux1_i686.whl", hash = "sha256:a4d412eba5679ede84b41dbe48b1bed8f33131ab9db06c238a235334733acc5e"}, - {file = "pycryptodomex-3.14.1-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:d2cce1c82a7845d7e2e8a0956c6b7ed3f1661c9acf18eb120fc71e098ab5c6fe"}, - {file = "pycryptodomex-3.14.1-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:f75009715dcf4a3d680c2338ab19dac5498f8121173a929872950f4fb3a48fbf"}, - {file = "pycryptodomex-3.14.1-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:1ca8e1b4c62038bb2da55451385246f51f412c5f5eabd64812c01766a5989b4a"}, - {file = "pycryptodomex-3.14.1-cp35-abi3-win32.whl", hash = "sha256:ee835def05622e0c8b1435a906491760a43d0c462f065ec9143ec4b8d79f8bff"}, - {file = "pycryptodomex-3.14.1-cp35-abi3-win_amd64.whl", hash = "sha256:b5a185ae79f899b01ca49f365bdf15a45d78d9856f09b0de1a41b92afce1a07f"}, - {file = "pycryptodomex-3.14.1-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:797a36bd1f69df9e2798e33edb4bd04e5a30478efc08f9428c087f17f65a7045"}, - {file = "pycryptodomex-3.14.1-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:aebecde2adc4a6847094d3bd6a8a9538ef3438a5ea84ac1983fcb167db614461"}, - {file = "pycryptodomex-3.14.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:f8524b8bc89470cec7ac51734907818d3620fb1637f8f8b542d650ebec42a126"}, - {file = "pycryptodomex-3.14.1-pp27-pypy_73-win32.whl", hash = "sha256:4d0db8df9ffae36f416897ad184608d9d7a8c2b46c4612c6bc759b26c073f750"}, - {file = "pycryptodomex-3.14.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b276cc4deb4a80f9dfd47a41ebb464b1fe91efd8b1b8620cf5ccf8b824b850d6"}, - {file = "pycryptodomex-3.14.1-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:e36c7e3b5382cd5669cf199c4a04a0279a43b2a3bdd77627e9b89778ac9ec08c"}, - {file = "pycryptodomex-3.14.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:c4d8977ccda886d88dc3ca789de2f1adc714df912ff3934b3d0a3f3d777deafb"}, - {file = "pycryptodomex-3.14.1-pp36-pypy36_pp73-win32.whl", hash = "sha256:530756d2faa40af4c1f74123e1d889bd07feae45bac2fd32f259a35f7aa74151"}, - {file = "pycryptodomex-3.14.1.tar.gz", hash = "sha256:2ce76ed0081fd6ac8c74edc75b9d14eca2064173af79843c24fa62573263c1f2"}, + {file = "pycryptodomex-3.16.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b3d04c00d777c36972b539fb79958790126847d84ec0129fce1efef250bfe3ce"}, + {file = "pycryptodomex-3.16.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e5a670919076b71522c7d567a9043f66f14b202414a63c3a078b5831ae342c03"}, + {file = "pycryptodomex-3.16.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:ce338a9703f54b2305a408fc9890eb966b727ce72b69f225898bb4e9d9ed3f1f"}, + {file = "pycryptodomex-3.16.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:a1c0ae7123448ecb034c75c713189cb00ebe2d415b11682865b6c54d200d9c93"}, + {file = "pycryptodomex-3.16.0-cp27-cp27m-win32.whl", hash = "sha256:8851585ff19871e5d69e1790f4ca5f6fd1699d6b8b14413b472a4c0dbc7ea780"}, + {file = "pycryptodomex-3.16.0-cp27-cp27m-win_amd64.whl", hash = "sha256:8dd2d9e3c617d0712ed781a77efd84ea579e76c5f9b2a4bc0b684ebeddf868b2"}, + {file = "pycryptodomex-3.16.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2ad9bb86b355b6104796567dd44c215b3dc953ef2fae5e0bdfb8516731df92cf"}, + {file = "pycryptodomex-3.16.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:e25a2f5667d91795f9417cb856f6df724ccdb0cdd5cbadb212ee9bf43946e9f8"}, + {file = "pycryptodomex-3.16.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:b0789a8490114a2936ed77c87792cfe77582c829cb43a6d86ede0f9624ba8aa3"}, + {file = "pycryptodomex-3.16.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0da835af786fdd1c9930994c78b23e88d816dc3f99aa977284a21bbc26d19735"}, + {file = "pycryptodomex-3.16.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:22aed0868622d95179217c298e37ed7410025c7b29dac236d3230617d1e4ed56"}, + {file = "pycryptodomex-3.16.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1619087fb5b31510b0b0b058a54f001a5ffd91e6ffee220d9913064519c6a69d"}, + {file = "pycryptodomex-3.16.0-cp35-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:70288d9bfe16b2fd0d20b6c365db614428f1bcde7b20d56e74cf88ade905d9eb"}, + {file = "pycryptodomex-3.16.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7993d26dae4d83b8f4ce605bb0aecb8bee330bb3c95475ef06f3694403621e71"}, + {file = "pycryptodomex-3.16.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:1cda60207be8c1cf0b84b9138f9e3ca29335013d2b690774a5e94678ff29659a"}, + {file = "pycryptodomex-3.16.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:04610536921c1ec7adba158ef570348550c9f3a40bc24be9f8da2ef7ab387981"}, + {file = "pycryptodomex-3.16.0-cp35-abi3-win32.whl", hash = "sha256:daa67f5ebb6fbf1ee9c90decaa06ca7fc88a548864e5e484d52b0920a57fe8a5"}, + {file = "pycryptodomex-3.16.0-cp35-abi3-win_amd64.whl", hash = "sha256:231dc8008cbdd1ae0e34645d4523da2dbc7a88c325f0d4a59635a86ee25b41dd"}, + {file = "pycryptodomex-3.16.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:4dbbe18cc232b5980c7633972ae5417d0df76fe89e7db246eefd17ef4d8e6d7a"}, + {file = "pycryptodomex-3.16.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:893f8a97d533c66cc3a56e60dd3ed40a3494ddb4aafa7e026429a08772f8a849"}, + {file = "pycryptodomex-3.16.0-pp27-pypy_73-win32.whl", hash = "sha256:6a465e4f856d2a4f2a311807030c89166529ccf7ccc65bef398de045d49144b6"}, + {file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba57ac7861fd2c837cdb33daf822f2a052ff57dd769a2107807f52a36d0e8d38"}, + {file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f2b971a7b877348a27dcfd0e772a0343fb818df00b74078e91c008632284137d"}, + {file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e2453162f473c1eae4826eb10cd7bce19b5facac86d17fb5f29a570fde145abd"}, + {file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0ba28aa97cdd3ff5ed1a4f2b7f5cd04e721166bd75bd2b929e2734433882b583"}, + {file = "pycryptodomex-3.16.0.tar.gz", hash = "sha256:e9ba9d8ed638733c9e95664470b71d624a6def149e2db6cc52c1aca5a6a2df1d"}, ] [[package]] name = "pydantic" -version = "1.10.2" +version = "1.10.4" description = "Data validation and settings management using python type hints" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"}, - {file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"}, - {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912"}, - {file = "pydantic-1.10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559"}, - {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"}, - {file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c"}, - {file = "pydantic-1.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644"}, - {file = "pydantic-1.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f"}, - {file = "pydantic-1.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a"}, - {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525"}, - {file = "pydantic-1.10.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283"}, - {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42"}, - {file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52"}, - {file = "pydantic-1.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c"}, - {file = "pydantic-1.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5"}, - {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c"}, - {file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254"}, - {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5"}, - {file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d"}, - {file = "pydantic-1.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2"}, - {file = "pydantic-1.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13"}, - {file = "pydantic-1.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116"}, - {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624"}, - {file = "pydantic-1.10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1"}, - {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9"}, - {file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965"}, - {file = "pydantic-1.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e"}, - {file = "pydantic-1.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488"}, - {file = "pydantic-1.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41"}, - {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b"}, - {file = "pydantic-1.10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe"}, - {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d"}, - {file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda"}, - {file = "pydantic-1.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6"}, - {file = "pydantic-1.10.2-py3-none-any.whl", hash = "sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709"}, - {file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"}, + {file = "pydantic-1.10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5635de53e6686fe7a44b5cf25fcc419a0d5e5c1a1efe73d49d48fe7586db854"}, + {file = "pydantic-1.10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6dc1cc241440ed7ca9ab59d9929075445da6b7c94ced281b3dd4cfe6c8cff817"}, + {file = "pydantic-1.10.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51bdeb10d2db0f288e71d49c9cefa609bca271720ecd0c58009bd7504a0c464c"}, + {file = "pydantic-1.10.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78cec42b95dbb500a1f7120bdf95c401f6abb616bbe8785ef09887306792e66e"}, + {file = "pydantic-1.10.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8775d4ef5e7299a2f4699501077a0defdaac5b6c4321173bcb0f3c496fbadf85"}, + {file = "pydantic-1.10.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:572066051eeac73d23f95ba9a71349c42a3e05999d0ee1572b7860235b850cc6"}, + {file = "pydantic-1.10.4-cp310-cp310-win_amd64.whl", hash = "sha256:7feb6a2d401f4d6863050f58325b8d99c1e56f4512d98b11ac64ad1751dc647d"}, + {file = "pydantic-1.10.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39f4a73e5342b25c2959529f07f026ef58147249f9b7431e1ba8414a36761f53"}, + {file = "pydantic-1.10.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:983e720704431a6573d626b00662eb78a07148c9115129f9b4351091ec95ecc3"}, + {file = "pydantic-1.10.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75d52162fe6b2b55964fbb0af2ee58e99791a3138588c482572bb6087953113a"}, + {file = "pydantic-1.10.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdf8d759ef326962b4678d89e275ffc55b7ce59d917d9f72233762061fd04a2d"}, + {file = "pydantic-1.10.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05a81b006be15655b2a1bae5faa4280cf7c81d0e09fcb49b342ebf826abe5a72"}, + {file = "pydantic-1.10.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d88c4c0e5c5dfd05092a4b271282ef0588e5f4aaf345778056fc5259ba098857"}, + {file = "pydantic-1.10.4-cp311-cp311-win_amd64.whl", hash = "sha256:6a05a9db1ef5be0fe63e988f9617ca2551013f55000289c671f71ec16f4985e3"}, + {file = "pydantic-1.10.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:887ca463c3bc47103c123bc06919c86720e80e1214aab79e9b779cda0ff92a00"}, + {file = "pydantic-1.10.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdf88ab63c3ee282c76d652fc86518aacb737ff35796023fae56a65ced1a5978"}, + {file = "pydantic-1.10.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a48f1953c4a1d9bd0b5167ac50da9a79f6072c63c4cef4cf2a3736994903583e"}, + {file = "pydantic-1.10.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a9f2de23bec87ff306aef658384b02aa7c32389766af3c5dee9ce33e80222dfa"}, + {file = "pydantic-1.10.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cd8702c5142afda03dc2b1ee6bc358b62b3735b2cce53fc77b31ca9f728e4bc8"}, + {file = "pydantic-1.10.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6e7124d6855b2780611d9f5e1e145e86667eaa3bd9459192c8dc1a097f5e9903"}, + {file = "pydantic-1.10.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b53e1d41e97063d51a02821b80538053ee4608b9a181c1005441f1673c55423"}, + {file = "pydantic-1.10.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:55b1625899acd33229c4352ce0ae54038529b412bd51c4915349b49ca575258f"}, + {file = "pydantic-1.10.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:301d626a59edbe5dfb48fcae245896379a450d04baeed50ef40d8199f2733b06"}, + {file = "pydantic-1.10.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6f9d649892a6f54a39ed56b8dfd5e08b5f3be5f893da430bed76975f3735d15"}, + {file = "pydantic-1.10.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d7b5a3821225f5c43496c324b0d6875fde910a1c2933d726a743ce328fbb2a8c"}, + {file = "pydantic-1.10.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f2f7eb6273dd12472d7f218e1fef6f7c7c2f00ac2e1ecde4db8824c457300416"}, + {file = "pydantic-1.10.4-cp38-cp38-win_amd64.whl", hash = "sha256:4b05697738e7d2040696b0a66d9f0a10bec0efa1883ca75ee9e55baf511909d6"}, + {file = "pydantic-1.10.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a9a6747cac06c2beb466064dda999a13176b23535e4c496c9d48e6406f92d42d"}, + {file = "pydantic-1.10.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb992a1ef739cc7b543576337bebfc62c0e6567434e522e97291b251a41dad7f"}, + {file = "pydantic-1.10.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:990406d226dea0e8f25f643b370224771878142155b879784ce89f633541a024"}, + {file = "pydantic-1.10.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e82a6d37a95e0b1b42b82ab340ada3963aea1317fd7f888bb6b9dfbf4fff57c"}, + {file = "pydantic-1.10.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9193d4f4ee8feca58bc56c8306bcb820f5c7905fd919e0750acdeeeef0615b28"}, + {file = "pydantic-1.10.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2b3ce5f16deb45c472dde1a0ee05619298c864a20cded09c4edd820e1454129f"}, + {file = "pydantic-1.10.4-cp39-cp39-win_amd64.whl", hash = "sha256:9cbdc268a62d9a98c56e2452d6c41c0263d64a2009aac69246486f01b4f594c4"}, + {file = "pydantic-1.10.4-py3-none-any.whl", hash = "sha256:4948f264678c703f3877d1c8877c4e3b2e12e549c57795107f08cf70c6ec7774"}, + {file = "pydantic-1.10.4.tar.gz", hash = "sha256:b9a3859f24eb4e097502a3be1fb4b2abb79b6103dd9e2e0edb70613a4459a648"}, ] [package.dependencies] -typing-extensions = ">=4.1.0" +typing-extensions = ">=4.2.0" [package.extras] dotenv = ["python-dotenv (>=0.10.4)"] @@ -1400,21 +1404,6 @@ coincurve = ">=17.0.0,<18.0.0" cryptography = ">=36.0.1,<37.0.0" PySocks = ">=1.7.1,<2.0.0" -[[package]] -name = "pyparsing" -version = "3.0.9" -description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "main" -optional = false -python-versions = ">=3.6.8" -files = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, -] - -[package.extras] -diagrams = ["jinja2", "railroad-diagrams"] - [[package]] name = "pypng" version = "0.0.21" @@ -1472,25 +1461,25 @@ files = [ [[package]] name = "pytest" -version = "7.1.3" +version = "7.2.1" description = "pytest: simple powerful testing with Python" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, - {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, + {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, + {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, ] [package.dependencies] attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" -py = ">=1.8.2" -tomli = ">=1.0.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] @@ -1695,18 +1684,18 @@ cffi = ">=1.3.0" [[package]] name = "setuptools" -version = "65.6.3" +version = "65.7.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"}, - {file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"}, + {file = "setuptools-65.7.0-py3-none-any.whl", hash = "sha256:8ab4f1dbf2b4a65f7eec5ad0c620e84c34111a68d3349833494b9088212214dd"}, + {file = "setuptools-65.7.0.tar.gz", hash = "sha256:4d3c92fac8f1118bb77a22181355e29c239cabfe2b9effdaa665c66b711136d7"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] @@ -1795,7 +1784,7 @@ mssql = ["pyodbc"] mssql-pymssql = ["pymssql"] mssql-pyodbc = ["pyodbc"] mysql = ["mysqlclient"] -oracle = ["cx_oracle"] +oracle = ["cx-oracle"] postgresql = ["psycopg2"] postgresql-pg8000 = ["pg8000 (<1.16.6)"] postgresql-psycopg2binary = ["psycopg2-binary"] @@ -1926,14 +1915,14 @@ files = [ [[package]] name = "urllib3" -version = "1.26.12" +version = "1.26.14" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, - {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, + {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"}, + {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"}, ] [package.extras] @@ -2056,6 +2045,21 @@ files = [ {file = "websockets-10.0.tar.gz", hash = "sha256:c4fc9a1d242317892590abe5b61a9127f1a61740477bfb121743f290b8054002"}, ] +[[package]] +name = "wheel" +version = "0.38.4" +description = "A built-package format for Python" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "wheel-0.38.4-py3-none-any.whl", hash = "sha256:b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8"}, + {file = "wheel-0.38.4.tar.gz", hash = "sha256:965f5259b566725405b05e7cf774052044b1ed30119b5d586b2703aafe8719ac"}, +] + +[package.extras] +test = ["pytest (>=3.0.0)"] + [[package]] name = "win32-setctime" version = "1.1.0" @@ -2073,14 +2077,14 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [[package]] name = "zipp" -version = "3.9.0" +version = "3.11.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"}, - {file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"}, + {file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"}, + {file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"}, ] [package.extras] @@ -2090,4 +2094,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools" [metadata] lock-version = "2.0" python-versions = "^3.10 | ^3.9 | ^3.8 | ^3.7" -content-hash = "73e1443abc1eed24639a5297a66b2eb16e80491f8849b8008e065f153de215c7" +content-hash = "9daf94dd600a7e23dcefcc8752fae1694e0084e56553dc578a63272776a8fe53" diff --git a/pyproject.toml b/pyproject.toml index 383c4ff9..68e06db5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,10 +12,10 @@ script = "build.py" python = "^3.10 | ^3.9 | ^3.8 | ^3.7" aiofiles = "0.8.0" asgiref = "3.4.1" -attrs = "22.1.0" +attrs = "22.2.0" bech32 = "1.2.0" bitstring = "3.1.9" -certifi = "2022.9.24" +certifi = "2022.12.7" charset-normalizer = "2.0.12" click = "8.0.4" ecdsa = "0.18.0" @@ -26,15 +26,15 @@ httpcore = "0.15.0" httptools = "0.4.0" httpx = "0.23.0" idna = "3.4" -importlib-metadata = "5.0.0" +importlib-metadata = "5.2.0" jinja2 = "3.0.1" lnurl = "0.3.6" markupsafe = "2.0.1" -marshmallow = "3.18.0" +marshmallow = "3.19.0" outcome = "1.2.0" psycopg2-binary = "2.9.1" -pycryptodomex = "3.14.1" -pydantic = "1.10.2" +pycryptodomex = "3.16.0" +pydantic = "1.10.4" pypng = "0.0.21" pyqrcode = "1.2.1" pyScss = "1.4.0" @@ -53,7 +53,7 @@ uvicorn = "0.18.3" uvloop = "0.16.0" watchgod = "0.7" websockets = "10.0" -zipp = "3.9.0" +zipp = "3.11.0" loguru = "0.6.0" cffi = "1.15.1" websocket-client = "1.3.3" @@ -62,7 +62,7 @@ protobuf = "^4.21.6" Cerberus = "^1.3.4" async-timeout = "^4.0.2" pyln-client = "0.11.1" -cashu = "^0.6.0" +cashu = "0.8.2" [tool.poetry.dev-dependencies] diff --git a/requirements.txt b/requirements.txt index da2044d7..c5332811 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,57 +3,56 @@ anyio==3.6.2 ; python_version >= "3.7" and python_version < "4.0" asgiref==3.4.1 ; python_version >= "3.7" and python_version < "4.0" asn1crypto==1.5.1 ; python_version >= "3.7" and python_version < "4.0" async-timeout==4.0.2 ; python_version >= "3.7" and python_version < "4.0" -attrs==22.1.0 ; python_version >= "3.7" and python_version < "4.0" +attrs==22.2.0 ; python_version >= "3.7" and python_version < "4.0" base58==2.1.1 ; python_version >= "3.7" and python_version < "4.0" bech32==1.2.0 ; python_version >= "3.7" and python_version < "4.0" bitstring==3.1.9 ; python_version >= "3.7" and python_version < "4.0" -cashu==0.6.0 ; python_version >= "3.7" and python_version < "4.0" +cashu==0.8.2 ; python_version >= "3.7" and python_version < "4.0" cerberus==1.3.4 ; python_version >= "3.7" and python_version < "4.0" -certifi==2022.9.24 ; python_version >= "3.7" and python_version < "4.0" +certifi==2022.12.7 ; python_version >= "3.7" and python_version < "4.0" cffi==1.15.1 ; python_version >= "3.7" and python_version < "4.0" charset-normalizer==2.0.12 ; python_version >= "3.7" and python_version < "4.0" click==8.0.4 ; python_version >= "3.7" and python_version < "4.0" coincurve==17.0.0 ; python_version >= "3.7" and python_version < "4.0" -colorama==0.4.5 ; python_version >= "3.7" and python_version < "4.0" and platform_system == "Windows" or python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32" +colorama==0.4.6 ; python_version >= "3.7" and python_version < "4.0" and platform_system == "Windows" or python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32" cryptography==36.0.2 ; python_version >= "3.7" and python_version < "4.0" ecdsa==0.18.0 ; python_version >= "3.7" and python_version < "4.0" embit==0.4.9 ; python_version >= "3.7" and python_version < "4.0" enum34==1.1.10 ; python_version >= "3.7" and python_version < "4.0" environs==9.5.0 ; python_version >= "3.7" and python_version < "4.0" +exceptiongroup==1.1.0 ; python_version >= "3.7" and python_version < "3.11" fastapi==0.83.0 ; python_version >= "3.7" and python_version < "4.0" -grpcio==1.50.0 ; python_version >= "3.7" and python_version < "4.0" +grpcio==1.51.1 ; python_version >= "3.7" and python_version < "4.0" h11==0.12.0 ; python_version >= "3.7" and python_version < "4.0" httpcore==0.15.0 ; python_version >= "3.7" and python_version < "4.0" httptools==0.4.0 ; python_version >= "3.7" and python_version < "4.0" httpx==0.23.0 ; python_version >= "3.7" and python_version < "4.0" idna==3.4 ; python_version >= "3.7" and python_version < "4.0" -importlib-metadata==5.0.0 ; python_version >= "3.7" and python_version < "4.0" -iniconfig==1.1.1 ; python_version >= "3.7" and python_version < "4.0" +importlib-metadata==5.2.0 ; python_version >= "3.7" and python_version < "4.0" +iniconfig==2.0.0 ; python_version >= "3.7" and python_version < "4.0" jinja2==3.0.1 ; python_version >= "3.7" and python_version < "4.0" lnurl==0.3.6 ; python_version >= "3.7" and python_version < "4.0" loguru==0.6.0 ; python_version >= "3.7" and python_version < "4.0" markupsafe==2.0.1 ; python_version >= "3.7" and python_version < "4.0" -marshmallow==3.18.0 ; python_version >= "3.7" and python_version < "4.0" +marshmallow==3.19.0 ; python_version >= "3.7" and python_version < "4.0" outcome==1.2.0 ; python_version >= "3.7" and python_version < "4.0" -packaging==21.3 ; python_version >= "3.7" and python_version < "4.0" +packaging==23.0 ; python_version >= "3.7" and python_version < "4.0" pathlib2==2.3.7.post1 ; python_version >= "3.7" and python_version < "4.0" pluggy==1.0.0 ; python_version >= "3.7" and python_version < "4.0" -protobuf==4.21.9 ; python_version >= "3.7" and python_version < "4.0" +protobuf==4.21.12 ; python_version >= "3.7" and python_version < "4.0" psycopg2-binary==2.9.1 ; python_version >= "3.7" and python_version < "4.0" -py==1.11.0 ; python_version >= "3.7" and python_version < "4.0" pycparser==2.21 ; python_version >= "3.7" and python_version < "4.0" -pycryptodomex==3.14.1 ; python_version >= "3.7" and python_version < "4.0" -pydantic==1.10.2 ; python_version >= "3.7" and python_version < "4.0" +pycryptodomex==3.16.0 ; python_version >= "3.7" and python_version < "4.0" +pydantic==1.10.4 ; python_version >= "3.7" and python_version < "4.0" pyln-bolt7==1.0.246 ; python_version >= "3.7" and python_version < "4.0" pyln-client==0.11.1 ; python_version >= "3.7" and python_version < "4.0" pyln-proto==0.11.1 ; python_version >= "3.7" and python_version < "4.0" -pyparsing==3.0.9 ; python_version >= "3.7" and python_version < "4.0" pypng==0.0.21 ; python_version >= "3.7" and python_version < "4.0" pyqrcode==1.2.1 ; python_version >= "3.7" and python_version < "4.0" pyscss==1.4.0 ; python_version >= "3.7" and python_version < "4.0" pysocks==1.7.1 ; python_version >= "3.7" and python_version < "4.0" pytest-asyncio==0.19.0 ; python_version >= "3.7" and python_version < "4.0" -pytest==7.1.3 ; python_version >= "3.7" and python_version < "4.0" +pytest==7.2.1 ; python_version >= "3.7" and python_version < "4.0" python-bitcoinlib==0.11.2 ; python_version >= "3.7" and python_version < "4.0" python-dotenv==0.21.0 ; python_version >= "3.7" and python_version < "4.0" pyyaml==5.4.1 ; python_version >= "3.7" and python_version < "4.0" @@ -62,7 +61,7 @@ requests==2.27.1 ; python_version >= "3.7" and python_version < "4.0" rfc3986==1.5.0 ; python_version >= "3.7" and python_version < "4.0" rfc3986[idna2008]==1.5.0 ; python_version >= "3.7" and python_version < "4.0" secp256k1==0.14.0 ; python_version >= "3.7" and python_version < "4.0" -setuptools==65.6.3 ; python_version >= "3.7" and python_version < "4.0" +setuptools==65.7.0 ; python_version >= "3.7" and python_version < "4.0" shortuuid==1.0.1 ; python_version >= "3.7" and python_version < "4.0" six==1.16.0 ; python_version >= "3.7" and python_version < "4.0" sniffio==1.3.0 ; python_version >= "3.7" and python_version < "4.0" @@ -70,13 +69,14 @@ sqlalchemy-aio==0.17.0 ; python_version >= "3.7" and python_version < "4.0" sqlalchemy==1.3.24 ; python_version >= "3.7" and python_version < "4.0" sse-starlette==0.6.2 ; python_version >= "3.7" and python_version < "4.0" starlette==0.19.1 ; python_version >= "3.7" and python_version < "4.0" -tomli==2.0.1 ; python_version >= "3.7" and python_version < "4.0" +tomli==2.0.1 ; python_version >= "3.7" and python_version < "3.11" typing-extensions==4.4.0 ; python_version >= "3.7" and python_version < "4.0" -urllib3==1.26.12 ; python_version >= "3.7" and python_version < "4" +urllib3==1.26.14 ; python_version >= "3.7" and python_version < "4.0" uvicorn==0.18.3 ; python_version >= "3.7" and python_version < "4.0" uvloop==0.16.0 ; python_version >= "3.7" and python_version < "4.0" watchgod==0.7 ; python_version >= "3.7" and python_version < "4.0" websocket-client==1.3.3 ; python_version >= "3.7" and python_version < "4.0" websockets==10.0 ; python_version >= "3.7" and python_version < "4.0" +wheel==0.38.4 ; python_version >= "3.7" and python_version < "4.0" win32-setctime==1.1.0 ; python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32" -zipp==3.9.0 ; python_version >= "3.7" and python_version < "4.0" +zipp==3.11.0 ; python_version >= "3.7" and python_version < "4.0"