From 947dc50d2e6598e52e36d86741d6c12a9cd6b67d Mon Sep 17 00:00:00 2001 From: Gene Takavic <80261724+iWarpBTC@users.noreply.github.com> Date: Mon, 12 Sep 2022 17:14:24 +0200 Subject: [PATCH 0001/1058] readme update --- lnbits/extensions/boltcards/README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/lnbits/extensions/boltcards/README.md b/lnbits/extensions/boltcards/README.md index f9c59409..a7302906 100644 --- a/lnbits/extensions/boltcards/README.md +++ b/lnbits/extensions/boltcards/README.md @@ -10,18 +10,17 @@ This extension allows you to link your Bolt Card (or other compatible NXP NTAG d ## About the keys -Up to five 16-byte keys can be stored on the card, numbered from 00 to 04. In the empty state they all should be set to zeros (00000000000000000000000000000000). For this extension only two keys need to be set: +Up to five 16-byte keys can be stored on the card, numbered from 00 to 04. In the empty state they all should be set to zeros (00000000000000000000000000000000). For this extension only two keys need to be set, but for the security reasons all five keys should be changed from default (empty) state. The keys directly needed by this extension are: -One for encrypting the card UID and the counter (p parameter), let's called it meta key, key #01 or K1. +- One for encrypting the card UID and the counter (p parameter), let's called it meta key, key #01 or K1. -One for calculating CMAC (c parameter), let's called it file key, key #02 or K2. +- One for calculating CMAC (c parameter), let's called it file key, key #02 or K2. -The key #00, K0 (also know as auth key) is skipped to be use as authentification key. Is not needed by this extension, but can be filled in order to write the keys in cooperation with bolt-nfc-android-app. +The key #00, K0 (also know as auth key) is skipped to be used as authentification key. It is not needed by this extension, but should be filled in order to write the keys in cooperation with bolt-nfc-android-app. In this case also K3 is set to same value as K1 and K4 as K2, so all keys are changed from default values. Keep that in your mind in case you need to reset the keys manually. ***Always backup all keys that you're trying to write on the card. Without them you may not be able to change them in the future!*** ## Setting the card - bolt-nfc-android-app (easy way) -So far, regarding the keys, the app can only write a new key set on an empty card (with zero keys). **When you write non zero (and 'non debug') keys, they can't be rewrite with this app.** You have to do it on your computer. - Read the card with the app. Note UID so you can fill it in the extension later. - Write the link on the card. It shoud be like `YOUR_LNBITS_DOMAIN/boltcards/api/v1/scan/{external_id}` @@ -35,10 +34,10 @@ So far, regarding the keys, the app can only write a new key set on an empty car - If on an Android device with a newish version of Chrome, you can click the icon next to the input and tap your card to autofill this field. - Advanced Options - Card Keys (k0, k1, k2) will be automatically generated if not explicitly set. - - Set to 16 bytes of 0s (00000000000000000000000000000000) to leave the keys in debug mode. - - GENERATE KEY button fill the keys randomly. If there is "debug" in the card name, a debug set of keys is filled instead. + - Set to 16 bytes of 0s (00000000000000000000000000000000) to leave the keys in default state. + - GENERATE KEY button fill the keys randomly. If there is "debug" in the card name, a debug set of keys is filled instead. - Click CREATE CARD button -- Click the QR code button next to a card to view its details. You can scan the QR code with the Android app to import the keys. +- Click the QR code button next to a card to view its details. Backup the keys! You can scan the QR code with the Android app to import the keys. - Click the "KEYS / AUTH LINK" button to copy the auth URL to the clipboard. You can then paste this into the Android app to import the keys. - Tap the NFC card to write the keys to the card. @@ -48,7 +47,7 @@ Follow the guide. The URI should be `lnurlw://YOUR-DOMAIN.COM/boltcards/api/v1/scan/{YOUR_card_external_id}?p=00000000000000000000000000000000&c=0000000000000000` -Then fill up the card parameters in the extension. Card Auth key (K0) can be omitted. Initical counter can be 0. +Then fill up the card parameters in the extension. Card Auth key (K0) can be filled just for the record. Initical counter can be 0. ## Setting the card - android NXP app (hard way) - If you don't know the card ID, use NXP TagInfo app to find it out. From e1eb0895890c068a29ee32f4fe7910698522da0e Mon Sep 17 00:00:00 2001 From: Gene Takavic <80261724+iWarpBTC@users.noreply.github.com> Date: Mon, 12 Sep 2022 22:44:22 +0200 Subject: [PATCH 0002/1058] readme minor changes --- lnbits/extensions/boltcards/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/boltcards/README.md b/lnbits/extensions/boltcards/README.md index a7302906..8e093f3e 100644 --- a/lnbits/extensions/boltcards/README.md +++ b/lnbits/extensions/boltcards/README.md @@ -34,7 +34,7 @@ The key #00, K0 (also know as auth key) is skipped to be used as authentificatio - If on an Android device with a newish version of Chrome, you can click the icon next to the input and tap your card to autofill this field. - Advanced Options - Card Keys (k0, k1, k2) will be automatically generated if not explicitly set. - - Set to 16 bytes of 0s (00000000000000000000000000000000) to leave the keys in default state. + - Set to 16 bytes of 0s (00000000000000000000000000000000) to leave the keys in default (empty) state. - GENERATE KEY button fill the keys randomly. If there is "debug" in the card name, a debug set of keys is filled instead. - Click CREATE CARD button - Click the QR code button next to a card to view its details. Backup the keys! You can scan the QR code with the Android app to import the keys. @@ -47,7 +47,7 @@ Follow the guide. The URI should be `lnurlw://YOUR-DOMAIN.COM/boltcards/api/v1/scan/{YOUR_card_external_id}?p=00000000000000000000000000000000&c=0000000000000000` -Then fill up the card parameters in the extension. Card Auth key (K0) can be filled just for the record. Initical counter can be 0. +Then fill up the card parameters in the extension. Card Auth key (K0) can be filled in the extension just for the record. Initical counter can be 0. ## Setting the card - android NXP app (hard way) - If you don't know the card ID, use NXP TagInfo app to find it out. From ae06636293cd86f0692744428f7a8d01d51dd1e1 Mon Sep 17 00:00:00 2001 From: ben Date: Thu, 15 Sep 2022 18:11:59 +0100 Subject: [PATCH 0003/1058] rebuild pages From cf849b260cd97e3dbe1d2e11244d67c13962306b Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 16 Sep 2022 13:20:42 +0100 Subject: [PATCH 0004/1058] UI works well --- lnbits/extensions/cashu/README.md | 11 + lnbits/extensions/cashu/__init__.py | 25 + lnbits/extensions/cashu/config.json | 6 + lnbits/extensions/cashu/crud.py | 50 ++ lnbits/extensions/cashu/migrations.py | 33 + lnbits/extensions/cashu/models.py | 34 + lnbits/extensions/cashu/tasks.py | 70 ++ .../cashu/templates/cashu/_api_docs.html | 79 ++ .../cashu/templates/cashu/_cashu.html | 15 + .../cashu/templates/cashu/index.html | 262 ++++++ .../cashu/templates/cashu/mint.html | 33 + .../cashu/templates/cashu/wallet.html | 753 ++++++++++++++++++ lnbits/extensions/cashu/views.py | 69 ++ lnbits/extensions/cashu/views_api.py | 160 ++++ 14 files changed, 1600 insertions(+) create mode 100644 lnbits/extensions/cashu/README.md create mode 100644 lnbits/extensions/cashu/__init__.py create mode 100644 lnbits/extensions/cashu/config.json create mode 100644 lnbits/extensions/cashu/crud.py create mode 100644 lnbits/extensions/cashu/migrations.py create mode 100644 lnbits/extensions/cashu/models.py create mode 100644 lnbits/extensions/cashu/tasks.py create mode 100644 lnbits/extensions/cashu/templates/cashu/_api_docs.html create mode 100644 lnbits/extensions/cashu/templates/cashu/_cashu.html create mode 100644 lnbits/extensions/cashu/templates/cashu/index.html create mode 100644 lnbits/extensions/cashu/templates/cashu/mint.html create mode 100644 lnbits/extensions/cashu/templates/cashu/wallet.html create mode 100644 lnbits/extensions/cashu/views.py create mode 100644 lnbits/extensions/cashu/views_api.py diff --git a/lnbits/extensions/cashu/README.md b/lnbits/extensions/cashu/README.md new file mode 100644 index 00000000..8f53b474 --- /dev/null +++ b/lnbits/extensions/cashu/README.md @@ -0,0 +1,11 @@ +# Cashu + +## Create ecash mint for pegging in/out of ecash + + + +### Usage + +1. Enable extension +2. Create a Mint +3. Share wallet diff --git a/lnbits/extensions/cashu/__init__.py b/lnbits/extensions/cashu/__init__.py new file mode 100644 index 00000000..fa549ad2 --- /dev/null +++ b/lnbits/extensions/cashu/__init__.py @@ -0,0 +1,25 @@ +import asyncio + +from fastapi import APIRouter + +from lnbits.db import Database +from lnbits.helpers import template_renderer +from lnbits.tasks import catch_everything_and_restart + +db = Database("ext_cashu") + +cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["TPoS"]) + + +def cashu_renderer(): + return template_renderer(["lnbits/extensions/cashu/templates"]) + + +from .tasks import wait_for_paid_invoices +from .views import * # noqa +from .views_api import * # noqa + + +def cashu_start(): + loop = asyncio.get_event_loop() + loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) diff --git a/lnbits/extensions/cashu/config.json b/lnbits/extensions/cashu/config.json new file mode 100644 index 00000000..c688b22c --- /dev/null +++ b/lnbits/extensions/cashu/config.json @@ -0,0 +1,6 @@ +{ + "name": "Cashu Ecash", + "short_description": "Ecash mints with LN peg in/out", + "icon": "approval", + "contributors": ["shinobi", "arcbtc", "calle"] +} diff --git a/lnbits/extensions/cashu/crud.py b/lnbits/extensions/cashu/crud.py new file mode 100644 index 00000000..ce83653f --- /dev/null +++ b/lnbits/extensions/cashu/crud.py @@ -0,0 +1,50 @@ +from typing import List, Optional, Union + +from lnbits.helpers import urlsafe_short_hash + +from . import db +from .models import Cashu, Pegs + + +async def create_cashu(wallet_id: str, data: Cashu) -> Cashu: + cashu_id = urlsafe_short_hash() + await db.execute( + """ + INSERT INTO cashu.cashu (id, wallet, name, tickershort, fraction, maxsats, coins) + VALUES (?, ?, ?, ?, ?, ?, ?) + """, + ( + cashu_id, + wallet_id, + data.name, + data.tickershort, + data.fraction, + data.maxsats, + data.coins + ), + ) + + cashu = await get_cashu(cashu_id) + assert cashu, "Newly created cashu couldn't be retrieved" + return cashu + + +async def get_cashu(cashu_id: str) -> Optional[Cashu]: + row = await db.fetchone("SELECT * FROM cashu.cashu WHERE id = ?", (cashu_id,)) + return Cashu(**row) if row else None + + +async def get_cashus(wallet_ids: Union[str, List[str]]) -> List[Cashu]: + if isinstance(wallet_ids, str): + wallet_ids = [wallet_ids] + + q = ",".join(["?"] * len(wallet_ids)) + rows = await db.fetchall( + f"SELECT * FROM cashu.cashu WHERE wallet IN ({q})", (*wallet_ids,) + ) + + return [Cashu(**row) for row in rows] + + +async def delete_cashu(cashu_id: str) -> None: + await db.execute("DELETE FROM cashu.cashu WHERE id = ?", (cashu_id,)) diff --git a/lnbits/extensions/cashu/migrations.py b/lnbits/extensions/cashu/migrations.py new file mode 100644 index 00000000..95dc4815 --- /dev/null +++ b/lnbits/extensions/cashu/migrations.py @@ -0,0 +1,33 @@ +async def m001_initial(db): + """ + Initial cashu table. + """ + await db.execute( + """ + CREATE TABLE cashu.cashu ( + id TEXT PRIMARY KEY, + wallet TEXT NOT NULL, + name TEXT NOT NULL, + tickershort TEXT NOT NULL, + fraction BOOL, + maxsats INT, + coins INT + + ); + """ + ) + + """ + Initial cashus table. + """ + await db.execute( + """ + CREATE TABLE cashu.pegs ( + id TEXT PRIMARY KEY, + wallet TEXT NOT NULL, + inout BOOL NOT NULL, + amount INT + ); + """ + ) + diff --git a/lnbits/extensions/cashu/models.py b/lnbits/extensions/cashu/models.py new file mode 100644 index 00000000..0de15362 --- /dev/null +++ b/lnbits/extensions/cashu/models.py @@ -0,0 +1,34 @@ +from sqlite3 import Row +from typing import Optional + +from fastapi import Query +from pydantic import BaseModel + + +class Cashu(BaseModel): + id: str = Query(None) + name: str = Query(None) + wallet: str = Query(None) + tickershort: str + fraction: bool = Query(None) + maxsats: int = Query(0) + coins: int = Query(0) + + + @classmethod + def from_row(cls, row: Row) -> "TPoS": + return cls(**dict(row)) + +class Pegs(BaseModel): + id: str + wallet: str + inout: str + amount: str + + + @classmethod + def from_row(cls, row: Row) -> "TPoS": + return cls(**dict(row)) + +class PayLnurlWData(BaseModel): + lnurl: str \ No newline at end of file diff --git a/lnbits/extensions/cashu/tasks.py b/lnbits/extensions/cashu/tasks.py new file mode 100644 index 00000000..fe00a591 --- /dev/null +++ b/lnbits/extensions/cashu/tasks.py @@ -0,0 +1,70 @@ +import asyncio +import json + +from lnbits.core import db as core_db +from lnbits.core.crud import create_payment +from lnbits.core.models import Payment +from lnbits.helpers import urlsafe_short_hash +from lnbits.tasks import internal_invoice_queue, register_invoice_listener + +from .crud import get_cashu + + +async def wait_for_paid_invoices(): + invoice_queue = asyncio.Queue() + register_invoice_listener(invoice_queue) + + while True: + payment = await invoice_queue.get() + await on_invoice_paid(payment) + + +async def on_invoice_paid(payment: Payment) -> None: + if payment.extra.get("tag") == "cashu" and payment.extra.get("tipSplitted"): + # already splitted, ignore + return + + # now we make some special internal transfers (from no one to the receiver) + cashu = await get_cashu(payment.extra.get("cashuId")) + tipAmount = payment.extra.get("tipAmount") + + if tipAmount is None: + # no tip amount + return + + tipAmount = tipAmount * 1000 + amount = payment.amount - tipAmount + + # mark the original payment with one extra key, "splitted" + # (this prevents us from doing this process again and it's informative) + # and reduce it by the amount we're going to send to the producer + await core_db.execute( + """ + UPDATE apipayments + SET extra = ?, amount = ? + WHERE hash = ? + AND checking_id NOT LIKE 'internal_%' + """, + ( + json.dumps(dict(**payment.extra, tipSplitted=True)), + amount, + payment.payment_hash, + ), + ) + + # perform the internal transfer using the same payment_hash + internal_checking_id = f"internal_{urlsafe_short_hash()}" + await create_payment( + wallet_id=cashu.tip_wallet, + checking_id=internal_checking_id, + payment_request="", + payment_hash=payment.payment_hash, + amount=tipAmount, + memo=f"Tip for {payment.memo}", + pending=False, + extra={"tipSplitted": True}, + ) + + # manually send this for now + await internal_invoice_queue.put(internal_checking_id) + return diff --git a/lnbits/extensions/cashu/templates/cashu/_api_docs.html b/lnbits/extensions/cashu/templates/cashu/_api_docs.html new file mode 100644 index 00000000..7378eb08 --- /dev/null +++ b/lnbits/extensions/cashu/templates/cashu/_api_docs.html @@ -0,0 +1,79 @@ + + + + + + GET /cashu/api/v1/cashus +
Headers
+ {"X-Api-Key": <invoice_key>}
+
Body (application/json)
+
+ Returns 200 OK (application/json) +
+ [<cashu_object>, ...] +
Curl example
+ curl -X GET {{ request.base_url }}cashu/api/v1/cashus -H "X-Api-Key: + <invoice_key>" + +
+
+
+ + + + POST /cashu/api/v1/cashus +
Headers
+ {"X-Api-Key": <invoice_key>}
+
Body (application/json)
+ {"name": <string>, "currency": <string*ie USD*>} +
+ Returns 201 CREATED (application/json) +
+ {"currency": <string>, "id": <string>, "name": + <string>, "wallet": <string>} +
Curl example
+ curl -X POST {{ request.base_url }}cashu/api/v1/cashus -d '{"name": + <string>, "currency": <string>}' -H "Content-type: + application/json" -H "X-Api-Key: <admin_key>" + +
+
+
+ + + + + DELETE + /cashu/api/v1/cashus/<cashu_id> +
Headers
+ {"X-Api-Key": <admin_key>}
+
Returns 204 NO CONTENT
+ +
Curl example
+ curl -X DELETE {{ request.base_url + }}cashu/api/v1/cashus/<cashu_id> -H "X-Api-Key: <admin_key>" + +
+
+
+
diff --git a/lnbits/extensions/cashu/templates/cashu/_cashu.html b/lnbits/extensions/cashu/templates/cashu/_cashu.html new file mode 100644 index 00000000..3c2a38f5 --- /dev/null +++ b/lnbits/extensions/cashu/templates/cashu/_cashu.html @@ -0,0 +1,15 @@ + + + +

+ Make Ecash mints with peg in/out to a wallet, that can create and manage ecash. +

+ Created by + Calle. +
+
+
diff --git a/lnbits/extensions/cashu/templates/cashu/index.html b/lnbits/extensions/cashu/templates/cashu/index.html new file mode 100644 index 00000000..17b2a919 --- /dev/null +++ b/lnbits/extensions/cashu/templates/cashu/index.html @@ -0,0 +1,262 @@ +{% extends "base.html" %} {% from "macros.jinja" import window_vars with context +%} {% block page %} +
+
+ + + New Mint + + + + + +
+
+
Mints
+
+
+ Export to CSV +
+
+ + {% raw %} + + + + {% endraw %} + +
+
+
+ +
+ + +
{{SITE_TITLE}} Cashu extension
+
+ + + + {% include "cashu/_api_docs.html" %} + + {% include "cashu/_cashu.html" %} + + +
+
+ + + + + + + + +
+ +
+
+ + Use with hedging extension to create a stablecoin! + +
+
+ +
+
+ + +
+
+ Create Mint + + Cancel +
+
+
+
+
+{% endblock %} {% block scripts %} {{ window_vars(user) }} + +{% endblock %} \ No newline at end of file diff --git a/lnbits/extensions/cashu/templates/cashu/mint.html b/lnbits/extensions/cashu/templates/cashu/mint.html new file mode 100644 index 00000000..0f3e0e09 --- /dev/null +++ b/lnbits/extensions/cashu/templates/cashu/mint.html @@ -0,0 +1,33 @@ +{% extends "public.html" %} {% block page %} +
+
+ + +
+ +

{{ mint_name }}

+
+
+
Some data about mint here:
* whether its online
* Who to contact for support
* etc...
+
+
+
+ + {% endblock %} {% block scripts %} + + + + {% endblock %} +
diff --git a/lnbits/extensions/cashu/templates/cashu/wallet.html b/lnbits/extensions/cashu/templates/cashu/wallet.html new file mode 100644 index 00000000..a5d5f371 --- /dev/null +++ b/lnbits/extensions/cashu/templates/cashu/wallet.html @@ -0,0 +1,753 @@ +{% extends "public.html" %} {% block toolbar_title %} {% raw %} {{name}} Wallet {% endraw %} + +{% endblock %} {% block footer %}{% endblock %} {% block page_container %} + + +
+ + +
+ + +

+
{% raw %} {{balanceAmount}} + {{tickershort}}{% endraw %}
+

+
+ +
+ + +
+
+ Receive +
+
+ Send +
+
+ Peg in/out + +
+
+ scan + +
+ +
+ + + + +
+
+
Transactions
+
+
{% raw %} + {% endraw %} + Mint details + + Export to CSV + + + Show chart + +
+
+ + + + {% raw %} + + + {% endraw %} + +
+
+
+ + + {% raw %} + + +

+ {{receive.lnurl.domain}} is requesting an invoice: +

+ {% endraw %} {% if LNBITS_DENOMINATION != 'sats' %} + + {% else %} + + + {% endif %} + + + {% raw %} +
+ + + Withdraw from {{receive.lnurl.domain}} + + Create invoice + + Cancel +
+ +
+
+ + +
+ Copy invoice + Close +
+
+ {% endraw %} +
+ + + +
+
+ {% raw %} {{ parseFloat(String(parse.invoice.fsat).replaceAll(",", + "")) / 100 }} {% endraw %} {{LNBITS_DENOMINATION}} {% raw %} +
+
+ {{ parse.invoice.fsat }}{% endraw %} {{LNBITS_DENOMINATION}} {% + raw %} +
+ +

+ Description: {{ parse.invoice.description }}
+ Expire date: {{ parse.invoice.expireDate }}
+ Hash: {{ parse.invoice.hash }} +

+ {% endraw %} +
+ Pay + Cancel +
+
+ Not enough funds! + Cancel +
+
+
+ {% raw %} + +

+ Authenticate with {{ parse.lnurlauth.domain }}? +

+ +

+ For every website and for every LNbits wallet, a new keypair + will be deterministically generated so your identity can't be + tied to your LNbits wallet or linked across websites. No other + data will be shared with {{ parse.lnurlauth.domain }}. +

+

Your public key for {{ parse.lnurlauth.domain }} is:

+

+ {{ parse.lnurlauth.pubkey }} +

+
+ Login + Cancel +
+
+ {% endraw %} +
+
+ + + +
+ Read + Cancel +
+
+
+ + + +
+ + Cancel + +
+
+
+
+
+ + + +
+ +
+
+ Cancel +
+
+
+ + + + + + + + + + + + + + + + + + +
Warning
+

+ BOOKMARK THIS PAGE! If only mobile you can also click the 3 dots + and "Save to homescreen"/"Install app"! +

+

+ Ecash is a bearer asset, meaning you have the funds saved on this + page, losing the page without exporting the page will mean you will + lose the funds. +

+
+ Copy wallet URL + I understand +
+
+
+
+
+
+{% endblock %} {% block styles %} + +{% endblock %} {% block scripts %} + +{% endblock %} diff --git a/lnbits/extensions/cashu/views.py b/lnbits/extensions/cashu/views.py new file mode 100644 index 00000000..4ac1f1ce --- /dev/null +++ b/lnbits/extensions/cashu/views.py @@ -0,0 +1,69 @@ +from http import HTTPStatus + +from fastapi import Request +from fastapi.params import Depends +from fastapi.templating import Jinja2Templates +from starlette.exceptions import HTTPException +from starlette.responses import HTMLResponse + +from lnbits.core.models import User +from lnbits.decorators import check_user_exists +from lnbits.settings import LNBITS_CUSTOM_LOGO, LNBITS_SITE_TITLE + +from . import cashu_ext, cashu_renderer +from .crud import get_cashu + +templates = Jinja2Templates(directory="templates") + + +@cashu_ext.get("/", response_class=HTMLResponse) +async def index(request: Request, user: User = Depends(check_user_exists)): + return cashu_renderer().TemplateResponse( + "cashu/index.html", {"request": request, "user": user.dict()} + ) + + +@cashu_ext.get("/wallet") +async def cashu(request: Request): + return cashu_renderer().TemplateResponse("cashu/wallet.html",{"request": request}) + +@cashu_ext.get("/mint/{mintID}") +async def cashu(request: Request, mintID): + cashu = await get_cashu(mintID) + return cashu_renderer().TemplateResponse("cashu/mint.html",{"request": request, "mint_name": cashu.name}) + +@cashu_ext.get("/manifest/{cashu_id}.webmanifest") +async def manifest(cashu_id: str): + cashu = await get_cashu(cashu_id) + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." + ) + + return { + "short_name": LNBITS_SITE_TITLE, + "name": cashu.name + " - " + LNBITS_SITE_TITLE, + "icons": [ + { + "src": LNBITS_CUSTOM_LOGO + if LNBITS_CUSTOM_LOGO + else "https://cdn.jsdelivr.net/gh/lnbits/lnbits@0.3.0/docs/logos/lnbits.png", + "type": "image/png", + "sizes": "900x900", + } + ], + "start_url": "/cashu/" + cashu_id, + "background_color": "#1F2234", + "description": "Bitcoin Lightning tPOS", + "display": "standalone", + "scope": "/cashu/" + cashu_id, + "theme_color": "#1F2234", + "shortcuts": [ + { + "name": cashu.name + " - " + LNBITS_SITE_TITLE, + "short_name": cashu.name, + "description": cashu.name + " - " + LNBITS_SITE_TITLE, + "url": "/cashu/" + cashu_id, + } + ], + } diff --git a/lnbits/extensions/cashu/views_api.py b/lnbits/extensions/cashu/views_api.py new file mode 100644 index 00000000..0b16e4ba --- /dev/null +++ b/lnbits/extensions/cashu/views_api.py @@ -0,0 +1,160 @@ +from http import HTTPStatus + +import httpx +from fastapi import Query +from fastapi.params import Depends +from lnurl import decode as decode_lnurl +from loguru import logger +from starlette.exceptions import HTTPException + +from lnbits.core.crud import get_user +from lnbits.core.services import create_invoice +from lnbits.core.views.api import api_payment +from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key + +from . import cashu_ext +from .crud import create_cashu, delete_cashu, get_cashu, get_cashus +from .models import Cashu, Pegs, PayLnurlWData + + +@cashu_ext.get("/api/v1/cashus", status_code=HTTPStatus.OK) +async def api_cashus( + all_wallets: bool = Query(False), wallet: WalletTypeInfo = Depends(get_key_type) +): + wallet_ids = [wallet.wallet.id] + if all_wallets: + wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids + + return [cashu.dict() for cashu in await get_cashus(wallet_ids)] + + +@cashu_ext.post("/api/v1/cashus", status_code=HTTPStatus.CREATED) +async def api_cashu_create( + data: Cashu, wallet: WalletTypeInfo = Depends(get_key_type) +): + cashu = await create_cashu(wallet_id=wallet.wallet.id, data=data) + logger.debug(cashu) + return cashu.dict() + + +@cashu_ext.delete("/api/v1/cashus/{cashu_id}") +async def api_cashu_delete( + cashu_id: str, wallet: WalletTypeInfo = Depends(require_admin_key) +): + cashu = await get_cashu(cashu_id) + + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." + ) + + if cashu.wallet != wallet.wallet.id: + raise HTTPException(status_code=HTTPStatus.FORBIDDEN, detail="Not your TPoS.") + + await delete_cashu(cashu_id) + raise HTTPException(status_code=HTTPStatus.NO_CONTENT) + + +@cashu_ext.post("/api/v1/cashus/{cashu_id}/invoices", status_code=HTTPStatus.CREATED) +async def api_cashu_create_invoice( + amount: int = Query(..., ge=1), tipAmount: int = None, cashu_id: str = None +): + cashu = await get_cashu(cashu_id) + + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." + ) + + if tipAmount: + amount += tipAmount + + try: + payment_hash, payment_request = await create_invoice( + wallet_id=cashu.wallet, + amount=amount, + memo=f"{cashu.name}", + extra={"tag": "cashu", "tipAmount": tipAmount, "cashuId": cashu_id}, + ) + except Exception as e: + raise HTTPException(status_code=HTTPStatus.INTERNAL_SERVER_ERROR, detail=str(e)) + + return {"payment_hash": payment_hash, "payment_request": payment_request} + + +@cashu_ext.post( + "/api/v1/cashus/{cashu_id}/invoices/{payment_request}/pay", status_code=HTTPStatus.OK +) +async def api_cashu_pay_invoice( + lnurl_data: PayLnurlWData, payment_request: str = None, cashu_id: str = None +): + cashu = await get_cashu(cashu_id) + + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." + ) + + lnurl = ( + lnurl_data.lnurl.replace("lnurlw://", "") + .replace("lightning://", "") + .replace("LIGHTNING://", "") + .replace("lightning:", "") + .replace("LIGHTNING:", "") + ) + + if lnurl.lower().startswith("lnurl"): + lnurl = decode_lnurl(lnurl) + else: + lnurl = "https://" + lnurl + + async with httpx.AsyncClient() as client: + try: + r = await client.get(lnurl, follow_redirects=True) + if r.is_error: + lnurl_response = {"success": False, "detail": "Error loading"} + else: + resp = r.json() + if resp["tag"] != "withdrawRequest": + lnurl_response = {"success": False, "detail": "Wrong tag type"} + else: + r2 = await client.get( + resp["callback"], + follow_redirects=True, + params={ + "k1": resp["k1"], + "pr": payment_request, + }, + ) + resp2 = r2.json() + if r2.is_error: + lnurl_response = { + "success": False, + "detail": "Error loading callback", + } + elif resp2["status"] == "ERROR": + lnurl_response = {"success": False, "detail": resp2["reason"]} + else: + lnurl_response = {"success": True, "detail": resp2} + except (httpx.ConnectError, httpx.RequestError): + lnurl_response = {"success": False, "detail": "Unexpected error occurred"} + + return lnurl_response + + +@cashu_ext.get( + "/api/v1/cashus/{cashu_id}/invoices/{payment_hash}", status_code=HTTPStatus.OK +) +async def api_cashu_check_invoice(cashu_id: str, payment_hash: str): + cashu = await get_cashu(cashu_id) + if not cashu: + raise HTTPException( + status_code=HTTPStatus.NOT_FOUND, detail="TPoS does not exist." + ) + try: + status = await api_payment(payment_hash) + + except Exception as exc: + logger.error(exc) + return {"paid": False} + return status From 3660d96295ea75be08cd1e55b7899da60cd66eb9 Mon Sep 17 00:00:00 2001 From: Gene Takavic Date: Tue, 20 Sep 2022 15:53:57 +0200 Subject: [PATCH 0005/1058] rename setting app + delete msg --- lnbits/extensions/boltcards/README.md | 6 +++--- lnbits/extensions/boltcards/static/js/index.js | 2 +- lnbits/extensions/boltcards/templates/boltcards/index.html | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lnbits/extensions/boltcards/README.md b/lnbits/extensions/boltcards/README.md index 8e093f3e..c6d12311 100644 --- a/lnbits/extensions/boltcards/README.md +++ b/lnbits/extensions/boltcards/README.md @@ -6,7 +6,7 @@ This extension allows you to link your Bolt Card (or other compatible NXP NTAG d **Disclaimer:** ***Use this only if you either know what you are doing or are a reckless lightning pioneer. Only you are responsible for all your sats, cards and other devices. Always backup all your card keys!*** -***In order to use this extension you need to be able to setup your own card.*** That means writing a URL template pointing to your LNBits instance, configuring some SUN (SDM) settings and optionally changing the card's keys. There's a [guide](https://www.whitewolftech.com/articles/payment-card/) to set it up with a card reader connected to your computer. It can be done (without setting the keys) with [TagWriter app by NXP](https://play.google.com/store/apps/details?id=com.nxp.nfc.tagwriter) Android app. Last but not least, an OSS android app by name [bolt-nfc-android-app](https://github.com/boltcard/bolt-nfc-android-app) is being developed for these purposes. It's available from Google Play [here](https://play.google.com/store/apps/details?id=com.lightningnfcapp). +***In order to use this extension you need to be able to setup your own card.*** That means writing a URL template pointing to your LNBits instance, configuring some SUN (SDM) settings and optionally changing the card's keys. There's a [guide](https://www.whitewolftech.com/articles/payment-card/) to set it up with a card reader connected to your computer. It can be done (without setting the keys) with [TagWriter app by NXP](https://play.google.com/store/apps/details?id=com.nxp.nfc.tagwriter) Android app. Last but not least, an OSS android app by name [Boltcard NFC Card Creator](https://github.com/boltcard/bolt-nfc-android-app) is being developed for these purposes. It's available from Google Play [here](https://play.google.com/store/apps/details?id=com.lightningnfcapp). ## About the keys @@ -16,11 +16,11 @@ Up to five 16-byte keys can be stored on the card, numbered from 00 to 04. In th - One for calculating CMAC (c parameter), let's called it file key, key #02 or K2. -The key #00, K0 (also know as auth key) is skipped to be used as authentification key. It is not needed by this extension, but should be filled in order to write the keys in cooperation with bolt-nfc-android-app. In this case also K3 is set to same value as K1 and K4 as K2, so all keys are changed from default values. Keep that in your mind in case you need to reset the keys manually. +The key #00, K0 (also know as auth key) is skipped to be used as authentification key. It is not needed by this extension, but should be filled in order to write the keys in cooperation with Boltcard NFC Card Creator. In this case also K3 is set to same value as K1 and K4 as K2, so all keys are changed from default values. Keep that in your mind in case you need to reset the keys manually. ***Always backup all keys that you're trying to write on the card. Without them you may not be able to change them in the future!*** -## Setting the card - bolt-nfc-android-app (easy way) +## Setting the card - Boltcard NFC Card Creator (easy way) - Read the card with the app. Note UID so you can fill it in the extension later. - Write the link on the card. It shoud be like `YOUR_LNBITS_DOMAIN/boltcards/api/v1/scan/{external_id}` diff --git a/lnbits/extensions/boltcards/static/js/index.js b/lnbits/extensions/boltcards/static/js/index.js index 11df222a..2ecde39d 100644 --- a/lnbits/extensions/boltcards/static/js/index.js +++ b/lnbits/extensions/boltcards/static/js/index.js @@ -398,7 +398,7 @@ new Vue({ let cards = _.findWhere(this.cards, {id: cardId}) LNbits.utils - .confirmDialog('Are you sure you want to delete this card') + .confirmDialog('Are you sure you want to delete this card? Without access to the card keys you won\'t be able to reset them in the future!') .onOk(function () { LNbits.api .request( diff --git a/lnbits/extensions/boltcards/templates/boltcards/index.html b/lnbits/extensions/boltcards/templates/boltcards/index.html index 55cc1e5e..3e07024c 100644 --- a/lnbits/extensions/boltcards/templates/boltcards/index.html +++ b/lnbits/extensions/boltcards/templates/boltcards/index.html @@ -370,7 +370,7 @@ bolt-nfc-android-appBoltcard NFC Card Creator)

From a9b6dd3d30711296a7d9134dc59caf6d5ccda154 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 21 Sep 2022 15:16:38 +0100 Subject: [PATCH 0006/1058] Broke, started added private/public key --- lnbits/extensions/cashu/crud.py | 26 +++++++++++++++++++++++--- lnbits/extensions/cashu/migrations.py | 5 +++-- lnbits/extensions/cashu/models.py | 3 ++- lnbits/extensions/cashu/views_api.py | 12 +++++++++++- 4 files changed, 39 insertions(+), 7 deletions(-) diff --git a/lnbits/extensions/cashu/crud.py b/lnbits/extensions/cashu/crud.py index ce83653f..f50da111 100644 --- a/lnbits/extensions/cashu/crud.py +++ b/lnbits/extensions/cashu/crud.py @@ -5,13 +5,20 @@ from lnbits.helpers import urlsafe_short_hash from . import db from .models import Cashu, Pegs +from embit import script +from embit import ec +from embit.networks import NETWORKS +from binascii import unhexlify, hexlify async def create_cashu(wallet_id: str, data: Cashu) -> Cashu: cashu_id = urlsafe_short_hash() + prv = ec.PrivateKey.from_wif(urlsafe_short_hash()) + pub = prv.get_public_key() + await db.execute( """ - INSERT INTO cashu.cashu (id, wallet, name, tickershort, fraction, maxsats, coins) - VALUES (?, ?, ?, ?, ?, ?, ?) + INSERT INTO cashu.cashu (id, wallet, name, tickershort, fraction, maxsats, coins, prvkey, pubkey) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, ( cashu_id, @@ -20,7 +27,9 @@ async def create_cashu(wallet_id: str, data: Cashu) -> Cashu: data.tickershort, data.fraction, data.maxsats, - data.coins + data.coins, + prv, + pub ), ) @@ -29,6 +38,17 @@ async def create_cashu(wallet_id: str, data: Cashu) -> Cashu: return cashu +async def update_cashu_keys(cashu_id, wif: str = None) -> Optional[Cashu]: + if not wif: + prv = ec.PrivateKey.from_wif(urlsafe_short_hash()) + else: + prv = ec.PrivateKey.from_wif(wif) + pub = prv.get_public_key() + await db.execute("UPDATE cashu.cashu SET prv = ?, pub = ? WHERE id = ?", (hexlify(prv.serialize()), hexlify(pub.serialize()), cashu_id)) + row = await db.fetchone("SELECT * FROM cashu.cashu WHERE id = ?", (cashu_id,)) + return Cashu(**row) if row else None + + async def get_cashu(cashu_id: str) -> Optional[Cashu]: row = await db.fetchone("SELECT * FROM cashu.cashu WHERE id = ?", (cashu_id,)) return Cashu(**row) if row else None diff --git a/lnbits/extensions/cashu/migrations.py b/lnbits/extensions/cashu/migrations.py index 95dc4815..53420062 100644 --- a/lnbits/extensions/cashu/migrations.py +++ b/lnbits/extensions/cashu/migrations.py @@ -11,8 +11,9 @@ async def m001_initial(db): tickershort TEXT NOT NULL, fraction BOOL, maxsats INT, - coins INT - + coins INT, + prvkey TEXT NOT NULL, + pubkey TEXT NOT NULL ); """ ) diff --git a/lnbits/extensions/cashu/models.py b/lnbits/extensions/cashu/models.py index 0de15362..892abdf1 100644 --- a/lnbits/extensions/cashu/models.py +++ b/lnbits/extensions/cashu/models.py @@ -13,7 +13,8 @@ class Cashu(BaseModel): fraction: bool = Query(None) maxsats: int = Query(0) coins: int = Query(0) - + prvkey: str = Query(None) + pubkey: str = Query(None) @classmethod def from_row(cls, row: Row) -> "TPoS": diff --git a/lnbits/extensions/cashu/views_api.py b/lnbits/extensions/cashu/views_api.py index 0b16e4ba..49383945 100644 --- a/lnbits/extensions/cashu/views_api.py +++ b/lnbits/extensions/cashu/views_api.py @@ -13,7 +13,7 @@ from lnbits.core.views.api import api_payment from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key from . import cashu_ext -from .crud import create_cashu, delete_cashu, get_cashu, get_cashus +from .crud import create_cashu, delete_cashu, get_cashu, get_cashus, update_cashu_keys from .models import Cashu, Pegs, PayLnurlWData @@ -36,6 +36,16 @@ async def api_cashu_create( logger.debug(cashu) return cashu.dict() +@cashu_ext.post("/api/v1/cashus/upodatekeys", status_code=HTTPStatus.CREATED) +async def api_cashu_update_keys( + data: Cashu, wallet: WalletTypeInfo = Depends(get_key_type) +): + cashu = await get_cashu(data.id) + + cashu = await create_cashu(wallet_id=wallet.wallet.id, data=data) + logger.debug(cashu) + return cashu.dict() + @cashu_ext.delete("/api/v1/cashus/{cashu_id}") async def api_cashu_delete( From 632d35682d84c981b926ef47f8e6fc9d274b948e Mon Sep 17 00:00:00 2001 From: Gene Takavic Date: Fri, 23 Sep 2022 15:17:21 +0200 Subject: [PATCH 0007/1058] payment notification webhook --- lnbits/extensions/boltcards/crud.py | 6 +++-- lnbits/extensions/boltcards/lnurl.py | 23 ++++++++++++++++++- lnbits/extensions/boltcards/migrations.py | 8 +++++++ lnbits/extensions/boltcards/models.py | 2 ++ .../extensions/boltcards/static/js/index.js | 8 +++++-- .../boltcards/templates/boltcards/index.html | 12 +++++++++- 6 files changed, 53 insertions(+), 6 deletions(-) diff --git a/lnbits/extensions/boltcards/crud.py b/lnbits/extensions/boltcards/crud.py index c541346e..39ee3f40 100644 --- a/lnbits/extensions/boltcards/crud.py +++ b/lnbits/extensions/boltcards/crud.py @@ -27,9 +27,10 @@ async def create_card(data: CreateCardData, wallet_id: str) -> Card: k0, k1, k2, - otp + otp, + webhook_url ) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( card_id, @@ -45,6 +46,7 @@ async def create_card(data: CreateCardData, wallet_id: str) -> Card: data.k1, data.k2, secrets.token_hex(16), + data.webhook_url, ), ) card = await get_card(card_id) diff --git a/lnbits/extensions/boltcards/lnurl.py b/lnbits/extensions/boltcards/lnurl.py index 6fb9ad8d..be3e09d8 100644 --- a/lnbits/extensions/boltcards/lnurl.py +++ b/lnbits/extensions/boltcards/lnurl.py @@ -8,6 +8,7 @@ from io import BytesIO from typing import Optional from urllib.parse import urlparse +import httpx from embit import bech32, compact from fastapi import Request from fastapi.param_functions import Query @@ -119,12 +120,32 @@ async def lnurl_callback( invoice = bolt11.decode(pr) hit = await spend_hit(id=hit.id, amount=int(invoice.amount_msat / 1000)) try: - await pay_invoice( + payment_hash = await pay_invoice( wallet_id=card.wallet, payment_request=pr, max_sat=card.tx_limit, extra={"tag": "boltcard", "tag": hit.id}, ) + + if card.webhook_url: + async with httpx.AsyncClient() as client: + try: + r = await client.post( + card.webhook_url, + json={ + "notification": "card_payment", + "payment_hash": payment_hash, + "payment_request": pr, + "card_external_id": card.external_id, + "card_name": card.card_name, + "amount": int(invoice.amount_msat / 1000), + }, + timeout=40, + ) + except Exception as exc: + # webhook fails shouldn't cause the lnurlw to fail since invoice is already paid + logger.error("Caught exception when dispatching webhook url:", exc) + return {"status": "OK"} except: return {"status": "ERROR", "reason": f"Payment failed"} diff --git a/lnbits/extensions/boltcards/migrations.py b/lnbits/extensions/boltcards/migrations.py index 08126013..25a59fdb 100644 --- a/lnbits/extensions/boltcards/migrations.py +++ b/lnbits/extensions/boltcards/migrations.py @@ -58,3 +58,11 @@ async def m001_initial(db): ); """ ) + + +async def m002_add_webhook(db): + await db.execute( + """ + ALTER TABLE boltcards.cards ADD COLUMN webhook_url TEXT NOT NULL DEFAULT ''; + """ + ) diff --git a/lnbits/extensions/boltcards/models.py b/lnbits/extensions/boltcards/models.py index 47ca1df0..8e6f77c9 100644 --- a/lnbits/extensions/boltcards/models.py +++ b/lnbits/extensions/boltcards/models.py @@ -30,6 +30,7 @@ class Card(BaseModel): prev_k1: str prev_k2: str otp: str + webhook_url: str time: int def from_row(cls, row: Row) -> "Card": @@ -56,6 +57,7 @@ class CreateCardData(BaseModel): prev_k0: str = Query(ZERO_KEY) prev_k1: str = Query(ZERO_KEY) prev_k2: str = Query(ZERO_KEY) + webhook_url: str = Query(...) class Hit(BaseModel): diff --git a/lnbits/extensions/boltcards/static/js/index.js b/lnbits/extensions/boltcards/static/js/index.js index 2ecde39d..e13c14fb 100644 --- a/lnbits/extensions/boltcards/static/js/index.js +++ b/lnbits/extensions/boltcards/static/js/index.js @@ -23,6 +23,7 @@ new Vue({ cardDialog: { show: false, data: { + webhook_url: '', counter: 1, k0: '', k1: '', @@ -270,7 +271,8 @@ new Vue({ k1: card.k1, k2: card.k2, k3: card.k1, - k4: card.k2 + k4: card.k2, + webhook_url: card.webhook_url } this.qrCodeDialog.show = true }, @@ -398,7 +400,9 @@ new Vue({ let cards = _.findWhere(this.cards, {id: cardId}) LNbits.utils - .confirmDialog('Are you sure you want to delete this card? Without access to the card keys you won\'t be able to reset them in the future!') + .confirmDialog( + "Are you sure you want to delete this card? Without access to the card keys you won't be able to reset them in the future!" + ) .onOk(function () { LNbits.api .request( diff --git a/lnbits/extensions/boltcards/templates/boltcards/index.html b/lnbits/extensions/boltcards/templates/boltcards/index.html index 3e07024c..f795e454 100644 --- a/lnbits/extensions/boltcards/templates/boltcards/index.html +++ b/lnbits/extensions/boltcards/templates/boltcards/index.html @@ -283,7 +283,7 @@ v-model="toggleAdvanced" label="Show advanced options" > -

+
Zero if you don't know. + + Lock key: {{ qrCodeDialog.data.k0 }}
Meta key: {{ qrCodeDialog.data.k1 }}
File key: {{ qrCodeDialog.data.k2 }}
+ Notification webhook: {{ qrCodeDialog.data.webhook_url + }}


Date: Fri, 23 Sep 2022 16:19:58 +0200 Subject: [PATCH 0008/1058] Update README.md Updated for Boltcard NFC Card Creator v0.1.1 --- lnbits/extensions/boltcards/README.md | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lnbits/extensions/boltcards/README.md b/lnbits/extensions/boltcards/README.md index c6d12311..5140ecc2 100644 --- a/lnbits/extensions/boltcards/README.md +++ b/lnbits/extensions/boltcards/README.md @@ -21,10 +21,7 @@ The key #00, K0 (also know as auth key) is skipped to be used as authentificatio ***Always backup all keys that you're trying to write on the card. Without them you may not be able to change them in the future!*** ## Setting the card - Boltcard NFC Card Creator (easy way) - -- Read the card with the app. Note UID so you can fill it in the extension later. -- Write the link on the card. It shoud be like `YOUR_LNBITS_DOMAIN/boltcards/api/v1/scan/{external_id}` - - `{external_id}` should be replaced with the External ID found in the LNBits dialog. +Updated for v0.1.1 - Add new card in the extension. - Set a max sats per transaction. Any transaction greater than this amount will be rejected. @@ -32,14 +29,16 @@ The key #00, K0 (also know as auth key) is skipped to be used as authentificatio - Set a card name. This is just for your reference inside LNBits. - Set the card UID. This is the unique identifier on your NFC card and is 7 bytes. - If on an Android device with a newish version of Chrome, you can click the icon next to the input and tap your card to autofill this field. + - Otherwise read it with the Android app (Advanced -> Read NFC) and paste it to the field. - Advanced Options - Card Keys (k0, k1, k2) will be automatically generated if not explicitly set. - - Set to 16 bytes of 0s (00000000000000000000000000000000) to leave the keys in default (empty) state. - - GENERATE KEY button fill the keys randomly. If there is "debug" in the card name, a debug set of keys is filled instead. + - Set to 16 bytes of 0s (00000000000000000000000000000000) to leave the keys in default (empty) state (this is unsecure). + - GENERATE KEY button fill the keys randomly. - Click CREATE CARD button -- Click the QR code button next to a card to view its details. Backup the keys! You can scan the QR code with the Android app to import the keys. -- Click the "KEYS / AUTH LINK" button to copy the auth URL to the clipboard. You can then paste this into the Android app to import the keys. -- Tap the NFC card to write the keys to the card. +- Click the QR code button next to a card to view its details. Backup the keys now! They'll be comfortable in your password manager. + - Now you can scan the QR code with the Android app (Create Bolt Card -> SCAN QR CODE). + - Or you can Click the "KEYS / AUTH LINK" button to copy the auth URL to the clipboard. Then paste it into the Android app (Create Bolt Card -> PASTE AUTH URL). +- Click WRITE CARD NOW and tap the NFC card to set it up. DO NOT REMOVE THE CARD PREMATURELY! ## Setting the card - computer (hard way) @@ -69,4 +68,4 @@ Then fill up the card parameters in the extension. Card Auth key (K0) can be fil - Save & Write - Scan with compatible Wallet -This app afaik cannot change the keys. If you cannot change them any other way, leave them empty in the extension dialog and remember you're not secure. Card Auth key (K0) can be omitted anyway. Initical counter can be 0. +This app afaik cannot change the keys. If you cannot change them any other way, leave them empty in the extension dialog and remember you're not secured. Card Auth key (K0) can be omitted anyway. Initical counter can be 0. From ea2d66fbd628681618dbd411f544f63ee8692a5f Mon Sep 17 00:00:00 2001 From: Gene Takavic Date: Fri, 23 Sep 2022 17:11:19 +0200 Subject: [PATCH 0009/1058] refund notification --- lnbits/extensions/boltcards/tasks.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/lnbits/extensions/boltcards/tasks.py b/lnbits/extensions/boltcards/tasks.py index 1b51c98b..27929efc 100644 --- a/lnbits/extensions/boltcards/tasks.py +++ b/lnbits/extensions/boltcards/tasks.py @@ -2,12 +2,13 @@ import asyncio import json import httpx +from loguru import logger from lnbits.core import db as core_db from lnbits.core.models import Payment from lnbits.tasks import register_invoice_listener -from .crud import create_refund, get_hit +from .crud import create_refund, get_card, get_hit async def wait_for_paid_invoices(): @@ -34,6 +35,25 @@ async def on_invoice_paid(payment: Payment) -> None: ) await mark_webhook_sent(payment, 1) + card = await get_card(hit.card_id) + if card.webhook_url: + async with httpx.AsyncClient() as client: + try: + r = await client.post( + card.webhook_url, + json={ + "notification": "card_refund", + "payment_hash": payment.payment_hash, + "payment_request": payment.bolt11, + "card_external_id": card.external_id, + "card_name": card.card_name, + "amount": int(payment.amount / 1000), + }, + timeout=40, + ) + except Exception as exc: + logger.error("Caught exception when dispatching webhook url:", exc) + async def mark_webhook_sent(payment: Payment, status: int) -> None: payment.extra["wh_status"] = status From 8b3af03519c06437325e32e78a71febf9f91d3a1 Mon Sep 17 00:00:00 2001 From: Gene Takavic Date: Sun, 25 Sep 2022 17:01:22 +0200 Subject: [PATCH 0010/1058] webhook to pay_invoice --- lnbits/core/services.py | 31 ++++++++++++++++- lnbits/extensions/boltcards/lnurl.py | 42 ++++++++---------------- lnbits/extensions/boltcards/views_api.py | 5 --- lnbits/extensions/withdraw/lnurl.py | 30 +++++++---------- 4 files changed, 56 insertions(+), 52 deletions(-) diff --git a/lnbits/core/services.py b/lnbits/core/services.py index 10693f4b..aeb4f938 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -2,7 +2,7 @@ import asyncio import json from binascii import unhexlify from io import BytesIO -from typing import Dict, Optional, Tuple +from typing import Dict, Optional, Tuple, Union from urllib.parse import parse_qs, urlparse import httpx @@ -102,6 +102,7 @@ async def pay_invoice( extra: Optional[Dict] = None, description: str = "", conn: Optional[Connection] = None, + webhook: Optional[Union[str, tuple]] = None, ) -> str: """ Pay a Lightning invoice. @@ -231,6 +232,34 @@ async def pay_invoice( f"didn't receive checking_id from backend, payment may be stuck in database: {temp_id}" ) + if type(webhook) is str: + webhook_url = webhook + elif type(webhook) is tuple: + webhook_url = webhook[0] + additionals = webhook[1] + else: + webhook_url = None + + if webhook_url: + async with httpx.AsyncClient() as client: + try: + json = { + "payment_hash": invoice.payment_hash, + "payment_request": payment_request, + "amount": int(invoice.amount_msat / 1000), + } + if type(additionals) is dict: + json.update(additionals) + + r = await client.post( + webhook_url, + json=json, + timeout=40, + ) + except Exception as exc: + # webhook fails shouldn't cause the lnurlw to fail since invoice is already paid + logger.error("Caught exception when dispatching webhook url:", exc) + return invoice.payment_hash diff --git a/lnbits/extensions/boltcards/lnurl.py b/lnbits/extensions/boltcards/lnurl.py index be3e09d8..320b1666 100644 --- a/lnbits/extensions/boltcards/lnurl.py +++ b/lnbits/extensions/boltcards/lnurl.py @@ -1,19 +1,12 @@ -import base64 -import hashlib -import hmac import json import secrets from http import HTTPStatus -from io import BytesIO -from typing import Optional from urllib.parse import urlparse -import httpx from embit import bech32, compact from fastapi import Request from fastapi.param_functions import Query from fastapi.params import Depends, Query -from lnurl import Lnurl, LnurlWithdrawResponse from lnurl import encode as lnurl_encode # type: ignore from lnurl.types import LnurlPayMetadata # type: ignore from loguru import logger @@ -34,7 +27,6 @@ from .crud import ( get_hit, get_hits_today, spend_hit, - update_card, update_card_counter, update_card_otp, ) @@ -120,32 +112,26 @@ async def lnurl_callback( invoice = bolt11.decode(pr) hit = await spend_hit(id=hit.id, amount=int(invoice.amount_msat / 1000)) try: - payment_hash = await pay_invoice( + webhook = ( + ( + card.webhook_url, + { + "notification": "card_payment", + "card_external_id": card.external_id, + "card_name": card.card_name, + }, + ) + if card.webhook_url + else None + ) + await pay_invoice( wallet_id=card.wallet, payment_request=pr, max_sat=card.tx_limit, extra={"tag": "boltcard", "tag": hit.id}, + webhook=webhook, ) - if card.webhook_url: - async with httpx.AsyncClient() as client: - try: - r = await client.post( - card.webhook_url, - json={ - "notification": "card_payment", - "payment_hash": payment_hash, - "payment_request": pr, - "card_external_id": card.external_id, - "card_name": card.card_name, - "amount": int(invoice.amount_msat / 1000), - }, - timeout=40, - ) - except Exception as exc: - # webhook fails shouldn't cause the lnurlw to fail since invoice is already paid - logger.error("Caught exception when dispatching webhook url:", exc) - return {"status": "OK"} except: return {"status": "ERROR", "reason": f"Payment failed"} diff --git a/lnbits/extensions/boltcards/views_api.py b/lnbits/extensions/boltcards/views_api.py index 7b8357cf..2fc11dbc 100644 --- a/lnbits/extensions/boltcards/views_api.py +++ b/lnbits/extensions/boltcards/views_api.py @@ -12,21 +12,16 @@ from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key from . import boltcards_ext from .crud import ( create_card, - create_hit, delete_card, enable_disable_card, get_card, - get_card_by_otp, get_card_by_uid, get_cards, get_hits, get_refunds, update_card, - update_card_counter, - update_card_otp, ) from .models import CreateCardData -from .nxp424 import decryptSUN, getSunMAC @boltcards_ext.get("/api/v1/cards") diff --git a/lnbits/extensions/withdraw/lnurl.py b/lnbits/extensions/withdraw/lnurl.py index 18a99599..3379fd17 100644 --- a/lnbits/extensions/withdraw/lnurl.py +++ b/lnbits/extensions/withdraw/lnurl.py @@ -3,7 +3,6 @@ import traceback from datetime import datetime from http import HTTPStatus -import httpx import shortuuid # type: ignore from fastapi import HTTPException from fastapi.param_functions import Query @@ -115,29 +114,24 @@ async def api_lnurl_callback( payment_request = pr - payment_hash = await pay_invoice( + webhook = ( + ( + link.webhook_url, + { + "lnurlw": link.id, + }, + ) + if link.webhook_url + else None + ) + await pay_invoice( wallet_id=link.wallet, payment_request=payment_request, max_sat=link.max_withdrawable, extra={"tag": "withdraw"}, + webhook=webhook, ) - if link.webhook_url: - async with httpx.AsyncClient() as client: - try: - r = await client.post( - link.webhook_url, - json={ - "payment_hash": payment_hash, - "payment_request": payment_request, - "lnurlw": link.id, - }, - timeout=40, - ) - except Exception as exc: - # webhook fails shouldn't cause the lnurlw to fail since invoice is already paid - logger.error("Caught exception when dispatching webhook url:", exc) - return {"status": "OK"} except Exception as e: From 0bede387f5ed5620781c50b689fc7016ad5d15af Mon Sep 17 00:00:00 2001 From: Gene Takavic <80261724+iWarpBTC@users.noreply.github.com> Date: Sun, 25 Sep 2022 18:11:25 +0200 Subject: [PATCH 0011/1058] webhook to pay_invoice/fix --- lnbits/core/services.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lnbits/core/services.py b/lnbits/core/services.py index aeb4f938..4f937ec3 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -232,6 +232,7 @@ async def pay_invoice( f"didn't receive checking_id from backend, payment may be stuck in database: {temp_id}" ) + additionals = None if type(webhook) is str: webhook_url = webhook elif type(webhook) is tuple: From 5c6cd70d3bf08720a094c4aac263f53c583664e9 Mon Sep 17 00:00:00 2001 From: Gene Takavic Date: Mon, 26 Sep 2022 11:47:00 +0200 Subject: [PATCH 0012/1058] disabling card with just otp which is also part of notify --- lnbits/extensions/boltcards/crud.py | 10 ++++++++-- lnbits/extensions/boltcards/lnurl.py | 3 +++ lnbits/extensions/boltcards/views_api.py | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/boltcards/crud.py b/lnbits/extensions/boltcards/crud.py index 39ee3f40..0724ea04 100644 --- a/lnbits/extensions/boltcards/crud.py +++ b/lnbits/extensions/boltcards/crud.py @@ -114,8 +114,14 @@ async def get_card_by_external_id(external_id: str) -> Optional[Card]: return Card.parse_obj(card) -async def get_card_by_otp(otp: str) -> Optional[Card]: - row = await db.fetchone("SELECT * FROM boltcards.cards WHERE otp = ?", (otp,)) +async def get_card_by_otp(otp: str, half: bool = False) -> Optional[Card]: + if half and len(otp) == 16: + otp = "%" + otp + row = await db.fetchone( + "SELECT * FROM boltcards.cards WHERE otp LIKE ?", (otp,) + ) + else: + row = await db.fetchone("SELECT * FROM boltcards.cards WHERE otp = ?", (otp,)) if not row: return None diff --git a/lnbits/extensions/boltcards/lnurl.py b/lnbits/extensions/boltcards/lnurl.py index 320b1666..064bde2c 100644 --- a/lnbits/extensions/boltcards/lnurl.py +++ b/lnbits/extensions/boltcards/lnurl.py @@ -119,6 +119,9 @@ async def lnurl_callback( "notification": "card_payment", "card_external_id": card.external_id, "card_name": card.card_name, + "card_otp": card.otp[ + -16: + ], # actually only half of the OTP is sent (full otp reveals the keys) }, ) if card.webhook_url diff --git a/lnbits/extensions/boltcards/views_api.py b/lnbits/extensions/boltcards/views_api.py index 2fc11dbc..d7f5cf7c 100644 --- a/lnbits/extensions/boltcards/views_api.py +++ b/lnbits/extensions/boltcards/views_api.py @@ -15,11 +15,13 @@ from .crud import ( delete_card, enable_disable_card, get_card, + get_card_by_otp, get_card_by_uid, get_cards, get_hits, get_refunds, update_card, + update_card_otp, ) from .models import CreateCardData @@ -111,6 +113,22 @@ async def enable_card( return card.dict() +@boltcards_ext.post("/api/v1/disablecard") +async def disble_card_with_otp(a): + if len(a) < 16: + raise HTTPException(detail="Invalid OTP.", status_code=HTTPStatus.BAD_REQUEST) + card = await get_card_by_otp(a, half=True) + if not card: + raise HTTPException(detail="No card found.", status_code=HTTPStatus.NOT_FOUND) + + new_otp = secrets.token_hex(16) + await update_card_otp(new_otp, card.id) + + card = await enable_disable_card(enable=False, id=card.id) + + return {"status": "OK"} + + @boltcards_ext.delete("/api/v1/cards/{card_id}") async def api_card_delete(card_id, wallet: WalletTypeInfo = Depends(require_admin_key)): card = await get_card(card_id) From 4303af4f1456040f922c6283f1415052a8308ab5 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Thu, 29 Sep 2022 20:42:13 +0200 Subject: [PATCH 0013/1058] adjust versions --- lnbits/extensions/cashu/__init__.py | 5 +- lnbits/extensions/cashu/config.json | 8 +- poetry.lock | 1305 ++++++++++++++++++--------- pyproject.toml | 56 +- 4 files changed, 901 insertions(+), 473 deletions(-) diff --git a/lnbits/extensions/cashu/__init__.py b/lnbits/extensions/cashu/__init__.py index fa549ad2..d1a1d09c 100644 --- a/lnbits/extensions/cashu/__init__.py +++ b/lnbits/extensions/cashu/__init__.py @@ -6,9 +6,12 @@ from lnbits.db import Database from lnbits.helpers import template_renderer from lnbits.tasks import catch_everything_and_restart +from cashu.mint.router import router as cashu_router + db = Database("ext_cashu") -cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["TPoS"]) +cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["cashu"]) +cashu_ext.include_router(router=cashu_router) def cashu_renderer(): diff --git a/lnbits/extensions/cashu/config.json b/lnbits/extensions/cashu/config.json index c688b22c..d242a3a7 100644 --- a/lnbits/extensions/cashu/config.json +++ b/lnbits/extensions/cashu/config.json @@ -1,6 +1,6 @@ { - "name": "Cashu Ecash", - "short_description": "Ecash mints with LN peg in/out", - "icon": "approval", - "contributors": ["shinobi", "arcbtc", "calle"] + "name": "Cashu Mint", + "short_description": "Chaumian Ecash mint", + "icon": "donut_small_rounded", + "contributors": ["calle"] } diff --git a/poetry.lock b/poetry.lock index 975c62b2..ac75c80a 100644 --- a/poetry.lock +++ b/poetry.lock @@ -20,45 +20,56 @@ sniffio = ">=1.1" typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] -doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] -test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] +doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] +test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] trio = ["trio (>=0.16)"] [[package]] name = "asgiref" -version = "3.4.1" +version = "3.5.2" description = "ASGI specs, helper code, and adapters" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] -tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] +tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] [[package]] -name = "atomicwrites" -version = "1.4.1" -description = "Atomic file writes." -category = "dev" +name = "asn1crypto" +version = "1.5.1" +description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" +category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = "*" [[package]] name = "attrs" -version = "21.2.0" +version = "22.1.0" description = "Classes Without Boilerplate" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.5" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] -docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +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"] + +[[package]] +name = "base58" +version = "2.1.1" +description = "Base58 and Base58Check implementation." +category = "main" +optional = false +python-versions = ">=3.5" + +[package.extras] +tests = ["PyHamcrest (>=2.0.2)", "mypy", "pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-flake8"] [[package]] name = "bech32" @@ -78,7 +89,7 @@ python-versions = "*" [[package]] name = "black" -version = "22.6.0" +version = "22.8.0" description = "The uncompromising code formatter." category = "dev" optional = false @@ -100,24 +111,84 @@ jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] -name = "cerberus" +name = "cashu" +version = "0.1.11" +description = "Ecash wallet and mint with Bitcoin Lightning support" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +anyio = {version = "3.6.1", 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\""} +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\""} +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\""} +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\""} +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 = "4.12.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\""} +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\""} +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\""} +pluggy = {version = "1.0.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} +psycopg2-binary = {version = "2.9.3", 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\""} +pytest = {version = "7.1.3", 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-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\""} +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\""} +typing-extensions = {version = "4.3.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\""} +uvicorn = {version = "0.18.3", 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.8.1", markers = "python_version >= \"3.7\" and python_version < \"3.8\""} + +[package.source] +type = "file" +url = "../cashu/dist/cashu-0.1.11-py3-none-any.whl" + +[[package]] +name = "Cerberus" version = "1.3.4" description = "Lightweight, extensible schema and data validation tool for Python dictionaries." category = "main" optional = false python-versions = ">=2.7" +[package.dependencies] +setuptools = "*" + [[package]] name = "certifi" -version = "2021.5.30" +version = "2022.9.24" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" [[package]] name = "cffi" -version = "1.15.0" +version = "1.15.1" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -128,7 +199,7 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "2.0.6" +version = "2.0.12" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false @@ -139,7 +210,7 @@ unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.1" +version = "8.0.4" description = "Composable command line interface toolkit" category = "main" optional = false @@ -149,6 +220,18 @@ python-versions = ">=3.6" colorama = {version = "*", markers = "platform_system == \"Windows\""} importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +[[package]] +name = "coincurve" +version = "17.0.0" +description = "Cross-platform Python CFFI bindings for libsecp256k1" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +asn1crypto = "*" +cffi = ">=1.3.0" + [[package]] name = "colorama" version = "0.4.5" @@ -159,7 +242,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.4.2" +version = "6.4.4" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -171,9 +254,28 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] +[[package]] +name = "cryptography" +version = "36.0.2" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +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)"] +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"] + [[package]] name = "ecdsa" -version = "0.17.0" +version = "0.18.0" description = "ECDSA cryptographic signature library (pure python)" category = "main" optional = false @@ -194,9 +296,17 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "enum34" +version = "1.1.10" +description = "Python 3.4 Enum backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "environs" -version = "9.3.3" +version = "9.5.0" description = "simplified environment variable parsing" category = "main" optional = false @@ -207,14 +317,14 @@ marshmallow = ">=3.0.0" python-dotenv = "*" [package.extras] -dev = ["pytest", "dj-database-url", "dj-email-url", "django-cache-url", "flake8 (==3.9.2)", "flake8-bugbear (==21.4.3)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)", "tox"] +dev = ["dj-database-url", "dj-email-url", "django-cache-url", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)", "pytest", "tox"] django = ["dj-database-url", "dj-email-url", "django-cache-url"] -lint = ["flake8 (==3.9.2)", "flake8-bugbear (==21.4.3)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)"] -tests = ["pytest", "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 = "fastapi" -version = "0.78.0" +version = "0.83.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false @@ -225,10 +335,24 @@ pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1. starlette = "0.19.1" [package.extras] -all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] -dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)", "pre-commit (>=2.17.0,<3.0.0)"] -doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer (>=0.4.1,<0.5.0)", "pyyaml (>=5.3.1,<7.0.0)"] -test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==22.3.0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==4.2.1)", "types-orjson (==3.6.2)", "types-dataclasses (==0.6.5)"] +all = ["email_validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] +dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] +doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.5.0)"] +test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.3.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.6.5)", "types-orjson (==3.6.2)", "types-ujson (==4.2.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] + +[[package]] +name = "grpcio" +version = "1.49.1" +description = "HTTP/2-based RPC framework" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.dependencies] +six = ">=1.5.2" + +[package.extras] +protobuf = ["grpcio-tools (>=1.49.1)"] [[package]] name = "h11" @@ -282,14 +406,14 @@ rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} sniffio = "*" [package.extras] -brotli = ["brotlicffi", "brotli"] -cli = ["click (>=8.0.0,<9.0.0)", "rich (>=10,<13)", "pygments (>=2.0.0,<3.0.0)"] +brotli = ["brotli", "brotlicffi"] +cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "idna" -version = "3.2" +version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false @@ -297,26 +421,26 @@ python-versions = ">=3.5" [[package]] name = "importlib-metadata" -version = "4.8.1" +version = "4.12.0" description = "Read metadata from Python packages" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"] perf = ["ipython"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +testing = ["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" -category = "dev" +category = "main" optional = false python-versions = "*" @@ -329,14 +453,14 @@ optional = false python-versions = ">=3.6.1,<4.0" [package.extras] -pipfile_deprecated_finder = ["pipreqs", "requirementslib"] -requirements_deprecated_finder = ["pipreqs", "pip-api"] colors = ["colorama (>=0.4.3,<0.5.0)"] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] plugins = ["setuptools"] +requirements_deprecated_finder = ["pip-api", "pipreqs"] [[package]] -name = "jinja2" -version = "3.0.1" +name = "Jinja2" +version = "3.0.3" description = "A very fast and expressive template engine." category = "main" optional = false @@ -363,7 +487,7 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "loguru" -version = "0.5.3" +version = "0.6.0" description = "Python logging made (stupidly) simple" category = "main" optional = false @@ -374,19 +498,19 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -dev = ["isort (>=5.1.1)", "black (>=19.10b0)", "sphinx-rtd-theme (>=0.4.3)", "sphinx-autobuild (>=0.7.1)", "Sphinx (>=2.2.1)", "pytest-cov (>=2.7.1)", "pytest (>=4.6.2)", "tox-travis (>=0.12)", "tox (>=3.9.0)", "flake8 (>=3.7.7)", "colorama (>=0.3.4)", "codecov (>=2.0.15)"] +dev = ["Sphinx (>=4.1.1)", "black (>=19.10b0)", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)"] [[package]] -name = "markupsafe" -version = "2.0.1" +name = "MarkupSafe" +version = "2.1.1" description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [[package]] name = "marshmallow" -version = "3.17.0" +version = "3.18.0" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." category = "main" optional = false @@ -396,9 +520,9 @@ python-versions = ">=3.7" packaging = ">=17.0" [package.extras] -dev = ["pytest", "pytz", "simplejson", "mypy (==0.961)", "flake8 (==4.0.1)", "flake8-bugbear (==22.6.22)", "pre-commit (>=2.4,<3.0)", "tox"] -docs = ["sphinx (==4.5.0)", "sphinx-issues (==3.0.1)", "alabaster (==0.7.12)", "sphinx-version-warning (==1.1.2)", "autodocsumm (==0.2.8)"] -lint = ["mypy (==0.961)", "flake8 (==4.0.1)", "flake8-bugbear (==22.6.22)", "pre-commit (>=2.4,<3.0)"] +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)"] tests = ["pytest", "pytz", "simplejson"] [[package]] @@ -410,7 +534,7 @@ optional = false python-versions = ">=3.6" [package.extras] -build = ["twine", "wheel", "blurb"] +build = ["blurb", "twine", "wheel"] docs = ["sphinx"] test = ["pytest (<5.4)", "pytest-cov"] @@ -443,11 +567,11 @@ python-versions = "*" [[package]] name = "outcome" -version = "1.1.0" +version = "1.2.0" description = "Capture the outcome of Python function calls." category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.dependencies] attrs = ">=19.2.0" @@ -463,13 +587,24 @@ python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" +[[package]] +name = "pathlib2" +version = "2.3.7.post1" +description = "Object-oriented filesystem paths" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = "*" + [[package]] name = "pathspec" -version = "0.9.0" +version = "0.10.1" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +python-versions = ">=3.7" [[package]] name = "platformdirs" @@ -480,14 +615,14 @@ optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] -test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] [[package]] name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" -category = "dev" +category = "main" optional = false python-versions = ">=3.6" @@ -495,12 +630,20 @@ python-versions = ">=3.6" importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] -testing = ["pytest-benchmark", "pytest"] -dev = ["tox", "pre-commit"] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "protobuf" +version = "4.21.6" +description = "" +category = "main" +optional = false +python-versions = ">=3.7" [[package]] name = "psycopg2-binary" -version = "2.9.1" +version = "2.9.3" description = "psycopg2 - Python-PostgreSQL Database Adapter" category = "main" optional = false @@ -510,7 +653,7 @@ python-versions = ">=3.6" name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "dev" +category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -532,19 +675,54 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pydantic" -version = "1.8.2" -description = "Data validation and settings management using python 3.6 type hinting" +version = "1.10.2" +description = "Data validation and settings management using python type hints" category = "main" optional = false -python-versions = ">=3.6.1" +python-versions = ">=3.7" [package.dependencies] -typing-extensions = ">=3.7.4.3" +typing-extensions = ">=4.1.0" [package.extras] dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] +[[package]] +name = "pyln-bolt7" +version = "1.0.246" +description = "BOLT7" +category = "main" +optional = false +python-versions = ">=3.7,<4.0" + +[[package]] +name = "pyln-client" +version = "0.12.1" +description = "Client library and plugin library for Core Lightning" +category = "main" +optional = false +python-versions = ">=3.7,<4.0" + +[package.dependencies] +pyln-bolt7 = ">=1.0" +pyln-proto = ">=0.12" + +[[package]] +name = "pyln-proto" +version = "0.12.0" +description = "This package implements some of the Lightning Network protocol in pure python. It is intended for protocol testing and some minor tooling only. It is not deemed secure enough to handle any amount of real funds (you have been warned!)." +category = "main" +optional = false +python-versions = ">=3.7,<4.0" + +[package.dependencies] +base58 = ">=2.1.1,<3.0.0" +bitstring = ">=3.1.9,<4.0.0" +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" @@ -554,7 +732,7 @@ optional = false python-versions = ">=3.6.8" [package.extras] -diagrams = ["railroad-diagrams", "jinja2"] +diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pypng" @@ -565,7 +743,7 @@ optional = false python-versions = "*" [[package]] -name = "pyqrcode" +name = "PyQRCode" version = "1.2.1" description = "A QR code generator written purely in Python with SVG, EPS, PNG and terminal output." category = "main" @@ -576,26 +754,35 @@ python-versions = "*" PNG = ["pypng (>=0.0.13)"] [[package]] -name = "pyscss" -version = "1.3.7" +name = "pyScss" +version = "1.4.0" description = "pyScss, a Scss compiler for Python" category = "main" optional = false python-versions = "*" [package.dependencies] +enum34 = "*" +pathlib2 = "*" six = "*" +[[package]] +name = "PySocks" +version = "1.7.1" +description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + [[package]] name = "pytest" -version = "7.1.2" +version = "7.1.3" description = "pytest: simple powerful testing with Python" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" [package.dependencies] -atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} @@ -612,7 +799,7 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2. name = "pytest-asyncio" version = "0.19.0" description = "Pytest support for asyncio" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" @@ -621,7 +808,7 @@ pytest = ">=6.1.0" typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""} [package.extras] -testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] [[package]] name = "pytest-cov" @@ -636,21 +823,21 @@ coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] -testing = ["virtualenv", "pytest-xdist", "six", "process-tests", "hunter", "fields"] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] [[package]] name = "python-dotenv" -version = "0.19.0" +version = "0.21.0" description = "Read key-value pairs from a .env file and set them as environment variables" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [package.extras] cli = ["click (>=5.0)"] [[package]] -name = "pyyaml" +name = "PyYAML" version = "5.4.1" description = "YAML parser and emitter for Python" category = "main" @@ -658,7 +845,7 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [[package]] -name = "represent" +name = "Represent" version = "1.6.0.post0" description = "Create __repr__ automatically or declaratively." category = "main" @@ -669,7 +856,25 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" six = ">=1.8.0" [package.extras] -test = ["ipython", "pytest (>=3.0.5)", "mock"] +test = ["ipython", "mock", "pytest (>=3.0.5)"] + +[[package]] +name = "requests" +version = "2.27.1" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] [[package]] name = "rfc3986" @@ -696,6 +901,19 @@ python-versions = "*" [package.dependencies] cffi = ">=1.3.0" +[[package]] +name = "setuptools" +version = "65.4.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +category = "main" +optional = false +python-versions = ">=3.7" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "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)", "mock", "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-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"] + [[package]] name = "shortuuid" version = "1.0.1" @@ -714,15 +932,15 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "sniffio" -version = "1.2.0" +version = "1.3.0" description = "Sniff out which async library your code is running under" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.7" [[package]] -name = "sqlalchemy" -version = "1.3.23" +name = "SQLAlchemy" +version = "1.3.24" description = "Database Abstraction Library" category = "main" optional = false @@ -733,12 +951,12 @@ 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"] postgresql_psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql (<1)", "pymysql"] +pymysql = ["pymysql", "pymysql (<1)"] [[package]] name = "sqlalchemy-aio" @@ -785,7 +1003,7 @@ full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" +category = "main" optional = false python-versions = ">=3.7" @@ -799,7 +1017,7 @@ python-versions = ">=3.6" [[package]] name = "types-protobuf" -version = "3.19.22" +version = "3.20.4" description = "Typing stubs for protobuf" category = "dev" optional = false @@ -807,15 +1025,28 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "3.10.0.2" -description = "Backported and Experimental Type Hints for Python 3.5+" +version = "4.3.0" +description = "Backported and Experimental Type Hints for Python 3.7+" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.7" + +[[package]] +name = "urllib3" +version = "1.26.12" +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" + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "uvicorn" -version = "0.18.1" +version = "0.18.3" description = "The lightning-fast ASGI server." category = "main" optional = false @@ -827,7 +1058,7 @@ h11 = ">=0.8" typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] -standard = ["websockets (>=10.0)", "httptools (>=0.4.0)", "watchfiles (>=0.13)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] +standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"] [[package]] name = "uvloop" @@ -838,9 +1069,9 @@ optional = false python-versions = ">=3.7" [package.extras] -dev = ["Cython (>=0.29.24,<0.30.0)", "pytest (>=3.6.0)", "Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] -docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)"] -test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] +dev = ["Cython (>=0.29.24,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=19.0.0,<19.1.0)", "pycodestyle (>=2.7.0,<2.8.0)", "pytest (>=3.6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] +test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=19.0.0,<19.1.0)", "pycodestyle (>=2.7.0,<2.8.0)"] [[package]] name = "watchgod" @@ -884,20 +1115,20 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [[package]] name = "zipp" -version = "3.5.0" +version = "3.8.1" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] +testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "1.1" python-versions = "^3.9 | ^3.8 | ^3.7" -content-hash = "cadb8f2e46f0c083e91956f4f0f70b53b6c106f1c0b47972b57132dfee357367" +content-hash = "0b5a58944599b4218ce2f74e1d101002d7b97072b9069d0e32772fb23d35da69" [metadata.files] aiofiles = [ @@ -909,15 +1140,20 @@ anyio = [ {file = "anyio-3.6.1.tar.gz", hash = "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b"}, ] asgiref = [ - {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, - {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, + {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"}, + {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"}, ] -atomicwrites = [ - {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, +asn1crypto = [ + {file = "asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"}, + {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, ] attrs = [ - {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, - {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, + {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, + {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, +] +base58 = [ + {file = "base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2"}, + {file = "base58-2.1.1.tar.gz", hash = "sha256:c5d0cb3f5b6e81e8e35da5754388ddcc6d0d14b6c6a132cb93d69ed580a7278c"}, ] bech32 = [ {file = "bech32-1.2.0-py3-none-any.whl", hash = "sha256:990dc8e5a5e4feabbdf55207b5315fdd9b73db40be294a19b3752cde9e79d981"}, @@ -929,158 +1165,294 @@ bitstring = [ {file = "bitstring-3.1.9.tar.gz", hash = "sha256:a5848a3f63111785224dca8bb4c0a75b62ecdef56a042c8d6be74b16f7e860e7"}, ] black = [ - {file = "black-22.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f586c26118bc6e714ec58c09df0157fe2d9ee195c764f630eb0d8e7ccce72e69"}, - {file = "black-22.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b270a168d69edb8b7ed32c193ef10fd27844e5c60852039599f9184460ce0807"}, - {file = "black-22.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6797f58943fceb1c461fb572edbe828d811e719c24e03375fd25170ada53825e"}, - {file = "black-22.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c85928b9d5f83b23cee7d0efcb310172412fbf7cb9d9ce963bd67fd141781def"}, - {file = "black-22.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6fe02afde060bbeef044af7996f335fbe90b039ccf3f5eb8f16df8b20f77666"}, - {file = "black-22.6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cfaf3895a9634e882bf9d2363fed5af8888802d670f58b279b0bece00e9a872d"}, - {file = "black-22.6.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94783f636bca89f11eb5d50437e8e17fbc6a929a628d82304c80fa9cd945f256"}, - {file = "black-22.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2ea29072e954a4d55a2ff58971b83365eba5d3d357352a07a7a4df0d95f51c78"}, - {file = "black-22.6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e439798f819d49ba1c0bd9664427a05aab79bfba777a6db94fd4e56fae0cb849"}, - {file = "black-22.6.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:187d96c5e713f441a5829e77120c269b6514418f4513a390b0499b0987f2ff1c"}, - {file = "black-22.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:074458dc2f6e0d3dab7928d4417bb6957bb834434516f21514138437accdbe90"}, - {file = "black-22.6.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a218d7e5856f91d20f04e931b6f16d15356db1c846ee55f01bac297a705ca24f"}, - {file = "black-22.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:568ac3c465b1c8b34b61cd7a4e349e93f91abf0f9371eda1cf87194663ab684e"}, - {file = "black-22.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6c1734ab264b8f7929cef8ae5f900b85d579e6cbfde09d7387da8f04771b51c6"}, - {file = "black-22.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9a3ac16efe9ec7d7381ddebcc022119794872abce99475345c5a61aa18c45ad"}, - {file = "black-22.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:b9fd45787ba8aa3f5e0a0a98920c1012c884622c6c920dbe98dbd05bc7c70fbf"}, - {file = "black-22.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7ba9be198ecca5031cd78745780d65a3f75a34b2ff9be5837045dce55db83d1c"}, - {file = "black-22.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3db5b6409b96d9bd543323b23ef32a1a2b06416d525d27e0f67e74f1446c8f2"}, - {file = "black-22.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:560558527e52ce8afba936fcce93a7411ab40c7d5fe8c2463e279e843c0328ee"}, - {file = "black-22.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b154e6bbde1e79ea3260c4b40c0b7b3109ffcdf7bc4ebf8859169a6af72cd70b"}, - {file = "black-22.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:4af5bc0e1f96be5ae9bd7aaec219c901a94d6caa2484c21983d043371c733fc4"}, - {file = "black-22.6.0-py3-none-any.whl", hash = "sha256:ac609cf8ef5e7115ddd07d85d988d074ed00e10fbc3445aee393e70164a2219c"}, - {file = "black-22.6.0.tar.gz", hash = "sha256:6c6d39e28aed379aec40da1c65434c77d75e65bb59a1e1c283de545fb4e7c6c9"}, + {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"}, + {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"}, + {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"}, + {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"}, + {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"}, + {file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"}, + {file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"}, + {file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"}, + {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"}, + {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"}, + {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"}, + {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"}, + {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"}, + {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"}, + {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"}, + {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"}, + {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"}, + {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"}, + {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"}, + {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"}, + {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"}, + {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, + {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, ] -cerberus = [ +cashu = [ + {file = "cashu-0.1.11-py3-none-any.whl", hash = "sha256:d2c5a72648fa4487fdf694e5669dfaa8d62445d83cced33b5bc63eccbce6a00c"}, +] +Cerberus = [ {file = "Cerberus-1.3.4.tar.gz", hash = "sha256:d1b21b3954b2498d9a79edf16b3170a3ac1021df88d197dc2ce5928ba519237c"}, ] certifi = [ - {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, - {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, + {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, + {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, ] cffi = [ - {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, - {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, - {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"}, - {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"}, - {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"}, - {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"}, - {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"}, - {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"}, - {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"}, - {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"}, - {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"}, - {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"}, - {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"}, - {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"}, - {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"}, - {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"}, - {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"}, - {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"}, - {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"}, - {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"}, - {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"}, - {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"}, - {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"}, - {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"}, - {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"}, - {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"}, - {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"}, - {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"}, - {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, - {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, ] charset-normalizer = [ - {file = "charset-normalizer-2.0.6.tar.gz", hash = "sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"}, - {file = "charset_normalizer-2.0.6-py3-none-any.whl", hash = "sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6"}, + {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, + {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, ] click = [ - {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, - {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, + {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, + {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, +] +coincurve = [ + {file = "coincurve-17.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac8c87d6fd080faa74e7ecf64a6ed20c11a254863238759eb02c3f13ad12b0c4"}, + {file = "coincurve-17.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:25dfa105beba24c8de886f8ed654bb1133866e4e22cfd7ea5ad8438cae6ed924"}, + {file = "coincurve-17.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:698efdd53e4fe1bbebaee9b75cbc851be617974c1c60098e9145cb7198ae97fb"}, + {file = "coincurve-17.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30dd44d1039f1d237aaa2da6d14a455ca88df3bcb00610b41f3253fdca1be97b"}, + {file = "coincurve-17.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d154e2eb5711db8c5ef52fcd80935b5a0e751c057bc6ffb215a7bb409aedef03"}, + {file = "coincurve-17.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c71caffb97dd3d0c243beb62352669b1e5dafa3a4bccdbb27d36bd82f5e65d20"}, + {file = "coincurve-17.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:747215254e51dd4dfbe6dded9235491263da5d88fe372d66541ca16b51ea078f"}, + {file = "coincurve-17.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad2f6df39ba1e2b7b14bb984505ffa7d0a0ecdd697e8d7dbd19e04bc245c87ed"}, + {file = "coincurve-17.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0503326963916c85b61d16f611ea0545f03c9e418fa8007c233c815429e381e8"}, + {file = "coincurve-17.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1013c1597b65684ae1c3e42497f9ef5a04527fa6136a84a16b34602606428c74"}, + {file = "coincurve-17.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4beef321fd6434448aab03a0c245f31c4e77f43b54b82108c0948d29852ac7e"}, + {file = "coincurve-17.0.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f47806527d3184da3e8b146fac92a8ed567bbd225194f4517943d8cdc85f9542"}, + {file = "coincurve-17.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:51e56373ac79f4ec1cfc5da53d72c55f5e5ac28d848b0849ef5e687ace857888"}, + {file = "coincurve-17.0.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3d694ad194bee9e8792e2e75879dc5238d8a184010cde36c5ad518fcfe2cd8f2"}, + {file = "coincurve-17.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:74cedb3d3a1dc5abe0c9c2396e1b82cc64496babc5b42e007e72e185cb1edad8"}, + {file = "coincurve-17.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:db874c5c1dcb1f3a19379773b5e8cffc777625a7a7a60dd9a67206e31e62e2e9"}, + {file = "coincurve-17.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:896b01941254f0a218cf331a9bddfe2d43892f7f1ba10d6e372e2eb744a744c2"}, + {file = "coincurve-17.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6aec70238dbe7a5d66b5f9438ff45b08eb5e0990d49c32ebb65247c5d5b89d7a"}, + {file = "coincurve-17.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d24284d17162569df917a640f19d9654ba3b43cf560ced8864f270da903f73a5"}, + {file = "coincurve-17.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ea057f777842396d387103c606babeb3a1b4c6126769cc0a12044312fc6c465"}, + {file = "coincurve-17.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b88642edf7f281649b0c0b6ffade051945ccceae4b885e40445634877d0b3049"}, + {file = "coincurve-17.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a80a207131813b038351c5bdae8f20f5f774bbf53622081f208d040dd2b7528f"}, + {file = "coincurve-17.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1ef72574aa423bc33665ef4be859164a478bad24d48442da874ef3dc39a474d"}, + {file = "coincurve-17.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dfd4fab857bcd975edc39111cb5f5c104f138dac2e9ace35ea8434d37bcea3be"}, + {file = "coincurve-17.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:73f39579dd651a9fc29da5a8fc0d8153d872bcbc166f876457baced1a1c01501"}, + {file = "coincurve-17.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8852dc01af4f0fe941ffd04069f7e4fecdce9b867a016f823a02286a1a1f07b5"}, + {file = "coincurve-17.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1bef812da1da202cdd601a256825abcf26d86e8634fac3ec3e615e3bb3ff08c"}, + {file = "coincurve-17.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abbefc9ccb170cb255a31df32457c2e43084b9f37589d0694dacc2dea6ddaf7c"}, + {file = "coincurve-17.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:abbd9d017a7638dc38a3b9bb4851f8801b7818d4e5ac22e0c75e373b3c1dbff0"}, + {file = "coincurve-17.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e2c2e8a1f0b1f8e48049c891af4ae3cad65d115d358bde72f6b8abdbb8a23170"}, + {file = "coincurve-17.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c571445b166c714af4f8155e38a894376c16c0431e88963f2fff474a9985d87"}, + {file = "coincurve-17.0.0-py3-none-win32.whl", hash = "sha256:b956b0b2c85e25a7d00099970ff5d8338254b45e46f0a940f4a2379438ce0dde"}, + {file = "coincurve-17.0.0-py3-none-win_amd64.whl", hash = "sha256:630388080da3026e0b0176cc6762eaabecba857ee3fc85767577dea063ea7c6e"}, + {file = "coincurve-17.0.0.tar.gz", hash = "sha256:68da55aff898702952fda3ee04fd6ed60bb6b91f919c69270786ed766b548b93"}, ] colorama = [ {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, ] coverage = [ - {file = "coverage-6.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a9032f9b7d38bdf882ac9f66ebde3afb8145f0d4c24b2e600bc4c6304aafb87e"}, - {file = "coverage-6.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e0524adb49c716ca763dbc1d27bedce36b14f33e6b8af6dba56886476b42957c"}, - {file = "coverage-6.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4548be38a1c810d79e097a38107b6bf2ff42151900e47d49635be69943763d8"}, - {file = "coverage-6.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23876b018dfa5d3e98e96f5644b109090f16a4acb22064e0f06933663005d39"}, - {file = "coverage-6.4.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fe75dcfcb889b6800f072f2af5a331342d63d0c1b3d2bf0f7b4f6c353e8c9c0"}, - {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2f8553878a24b00d5ab04b7a92a2af50409247ca5c4b7a2bf4eabe94ed20d3ee"}, - {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d774d9e97007b018a651eadc1b3970ed20237395527e22cbeb743d8e73e0563d"}, - {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d56f105592188ce7a797b2bd94b4a8cb2e36d5d9b0d8a1d2060ff2a71e6b9bbc"}, - {file = "coverage-6.4.2-cp310-cp310-win32.whl", hash = "sha256:d230d333b0be8042ac34808ad722eabba30036232e7a6fb3e317c49f61c93386"}, - {file = "coverage-6.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:5ef42e1db047ca42827a85e34abe973971c635f83aed49611b7f3ab49d0130f0"}, - {file = "coverage-6.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:25b7ec944f114f70803d6529394b64f8749e93cbfac0fe6c5ea1b7e6c14e8a46"}, - {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bb00521ab4f99fdce2d5c05a91bddc0280f0afaee0e0a00425e28e209d4af07"}, - {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dff52b3e7f76ada36f82124703f4953186d9029d00d6287f17c68a75e2e6039"}, - {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:147605e1702d996279bb3cc3b164f408698850011210d133a2cb96a73a2f7996"}, - {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:422fa44070b42fef9fb8dabd5af03861708cdd6deb69463adc2130b7bf81332f"}, - {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8af6c26ba8df6338e57bedbf916d76bdae6308e57fc8f14397f03b5da8622b4e"}, - {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5336e0352c0b12c7e72727d50ff02557005f79a0b8dcad9219c7c4940a930083"}, - {file = "coverage-6.4.2-cp37-cp37m-win32.whl", hash = "sha256:0f211df2cba951ffcae210ee00e54921ab42e2b64e0bf2c0befc977377fb09b7"}, - {file = "coverage-6.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a13772c19619118903d65a91f1d5fea84be494d12fd406d06c849b00d31bf120"}, - {file = "coverage-6.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f7bd0ffbcd03dc39490a1f40b2669cc414fae0c4e16b77bb26806a4d0b7d1452"}, - {file = "coverage-6.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0895ea6e6f7f9939166cc835df8fa4599e2d9b759b02d1521b574e13b859ac32"}, - {file = "coverage-6.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e7ced84a11c10160c0697a6cc0b214a5d7ab21dfec1cd46e89fbf77cc66fae"}, - {file = "coverage-6.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80db4a47a199c4563d4a25919ff29c97c87569130375beca3483b41ad5f698e8"}, - {file = "coverage-6.4.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3def6791adf580d66f025223078dc84c64696a26f174131059ce8e91452584e1"}, - {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4f89d8e03c8a3757aae65570d14033e8edf192ee9298303db15955cadcff0c63"}, - {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6d0b48aff8e9720bdec315d67723f0babd936a7211dc5df453ddf76f89c59933"}, - {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b20286c2b726f94e766e86a3fddb7b7e37af5d0c635bdfa7e4399bc523563de"}, - {file = "coverage-6.4.2-cp38-cp38-win32.whl", hash = "sha256:d714af0bdba67739598849c9f18efdcc5a0412f4993914a0ec5ce0f1e864d783"}, - {file = "coverage-6.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:5f65e5d3ff2d895dab76b1faca4586b970a99b5d4b24e9aafffc0ce94a6022d6"}, - {file = "coverage-6.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a697977157adc052284a7160569b36a8bbec09db3c3220642e6323b47cec090f"}, - {file = "coverage-6.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c77943ef768276b61c96a3eb854eba55633c7a3fddf0a79f82805f232326d33f"}, - {file = "coverage-6.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54d8d0e073a7f238f0666d3c7c0d37469b2aa43311e4024c925ee14f5d5a1cbe"}, - {file = "coverage-6.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22325010d8824594820d6ce84fa830838f581a7fd86a9235f0d2ed6deb61e29"}, - {file = "coverage-6.4.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b04d305ea172ccb21bee5bacd559383cba2c6fcdef85b7701cf2de4188aa55"}, - {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:866ebf42b4c5dbafd64455b0a1cd5aa7b4837a894809413b930026c91e18090b"}, - {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e36750fbbc422c1c46c9d13b937ab437138b998fe74a635ec88989afb57a3978"}, - {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:79419370d6a637cb18553ecb25228893966bd7935a9120fa454e7076f13b627c"}, - {file = "coverage-6.4.2-cp39-cp39-win32.whl", hash = "sha256:b5e28db9199dd3833cc8a07fa6cf429a01227b5d429facb56eccd765050c26cd"}, - {file = "coverage-6.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:edfdabe7aa4f97ed2b9dd5dde52d2bb29cb466993bb9d612ddd10d0085a683cf"}, - {file = "coverage-6.4.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:e2618cb2cf5a7cc8d698306e42ebcacd02fb7ef8cfc18485c59394152c70be97"}, - {file = "coverage-6.4.2.tar.gz", hash = "sha256:6c3ccfe89c36f3e5b9837b9ee507472310164f352c9fe332120b764c9d60adbe"}, + {file = "coverage-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc"}, + {file = "coverage-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60"}, + {file = "coverage-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d"}, + {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760"}, + {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74"}, + {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c"}, + {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa"}, + {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973"}, + {file = "coverage-6.4.4-cp310-cp310-win32.whl", hash = "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0"}, + {file = "coverage-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875"}, + {file = "coverage-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac"}, + {file = "coverage-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782"}, + {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f"}, + {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7"}, + {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa"}, + {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892"}, + {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0"}, + {file = "coverage-6.4.4-cp311-cp311-win32.whl", hash = "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796"}, + {file = "coverage-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a"}, + {file = "coverage-6.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a"}, + {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817"}, + {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f"}, + {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3"}, + {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3"}, + {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820"}, + {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928"}, + {file = "coverage-6.4.4-cp37-cp37m-win32.whl", hash = "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c"}, + {file = "coverage-6.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d"}, + {file = "coverage-6.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c"}, + {file = "coverage-6.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685"}, + {file = "coverage-6.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1"}, + {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e"}, + {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa"}, + {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e"}, + {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a"}, + {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b"}, + {file = "coverage-6.4.4-cp38-cp38-win32.whl", hash = "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781"}, + {file = "coverage-6.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2"}, + {file = "coverage-6.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86"}, + {file = "coverage-6.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908"}, + {file = "coverage-6.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f"}, + {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2"}, + {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558"}, + {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19"}, + {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d"}, + {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a"}, + {file = "coverage-6.4.4-cp39-cp39-win32.whl", hash = "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145"}, + {file = "coverage-6.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827"}, + {file = "coverage-6.4.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1"}, + {file = "coverage-6.4.4.tar.gz", hash = "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58"}, +] +cryptography = [ + {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:4e2dddd38a5ba733be6a025a1475a9f45e4e41139d1321f412c6b360b19070b6"}, + {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:4881d09298cd0b669bb15b9cfe6166f16fc1277b4ed0d04a22f3d6430cb30f1d"}, + {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea634401ca02367c1567f012317502ef3437522e2fc44a3ea1844de028fa4b84"}, + {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7be666cc4599b415f320839e36367b273db8501127b38316f3b9f22f17a0b815"}, + {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8241cac0aae90b82d6b5c443b853723bcc66963970c67e56e71a2609dc4b5eaf"}, + {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2d54e787a884ffc6e187262823b6feb06c338084bbe80d45166a1cb1c6c5bf"}, + {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:c2c5250ff0d36fd58550252f54915776940e4e866f38f3a7866d92b32a654b86"}, + {file = "cryptography-36.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ec6597aa85ce03f3e507566b8bcdf9da2227ec86c4266bd5e6ab4d9e0cc8dab2"}, + {file = "cryptography-36.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ca9f686517ec2c4a4ce930207f75c00bf03d94e5063cbc00a1dc42531511b7eb"}, + {file = "cryptography-36.0.2-cp36-abi3-win32.whl", hash = "sha256:f64b232348ee82f13aac22856515ce0195837f6968aeaa94a3d0353ea2ec06a6"}, + {file = "cryptography-36.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:53e0285b49fd0ab6e604f4c5d9c5ddd98de77018542e88366923f152dbeb3c29"}, + {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:32db5cc49c73f39aac27574522cecd0a4bb7384e71198bc65a0d23f901e89bb7"}, + {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b3d199647468d410994dbeb8cec5816fb74feb9368aedf300af709ef507e3e"}, + {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:da73d095f8590ad437cd5e9faf6628a218aa7c387e1fdf67b888b47ba56a17f0"}, + {file = "cryptography-36.0.2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:0a3bf09bb0b7a2c93ce7b98cb107e9170a90c51a0162a20af1c61c765b90e60b"}, + {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8897b7b7ec077c819187a123174b645eb680c13df68354ed99f9b40a50898f77"}, + {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82740818f2f240a5da8dfb8943b360e4f24022b093207160c77cadade47d7c85"}, + {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:1f64a62b3b75e4005df19d3b5235abd43fa6358d5516cfc43d87aeba8d08dd51"}, + {file = "cryptography-36.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e167b6b710c7f7bc54e67ef593f8731e1f45aa35f8a8a7b72d6e42ec76afd4b3"}, + {file = "cryptography-36.0.2.tar.gz", hash = "sha256:70f8f4f7bb2ac9f340655cbac89d68c527af5bb4387522a8413e841e3e6628c9"}, ] ecdsa = [ - {file = "ecdsa-0.17.0-py2.py3-none-any.whl", hash = "sha256:5cf31d5b33743abe0dfc28999036c849a69d548f994b535e527ee3cb7f3ef676"}, - {file = "ecdsa-0.17.0.tar.gz", hash = "sha256:b9f500bb439e4153d0330610f5d26baaf18d17b8ced1bc54410d189385ea68aa"}, + {file = "ecdsa-0.18.0-py2.py3-none-any.whl", hash = "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd"}, + {file = "ecdsa-0.18.0.tar.gz", hash = "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49"}, ] embit = [ {file = "embit-0.4.9.tar.gz", hash = "sha256:992332bd89af6e2d027e26fe437eb14aa33997db08c882c49064d49c3e6f4ab9"}, ] +enum34 = [ + {file = "enum34-1.1.10-py2-none-any.whl", hash = "sha256:a98a201d6de3f2ab3db284e70a33b0f896fbf35f8086594e8c9e74b909058d53"}, + {file = "enum34-1.1.10-py3-none-any.whl", hash = "sha256:c3858660960c984d6ab0ebad691265180da2b43f07e061c0f8dca9ef3cffd328"}, + {file = "enum34-1.1.10.tar.gz", hash = "sha256:cce6a7477ed816bd2542d03d53db9f0db935dd013b70f336a95c73979289f248"}, +] environs = [ - {file = "environs-9.3.3-py2.py3-none-any.whl", hash = "sha256:ee5466156b50fe03aa9fec6e720feea577b5bf515d7f21b2c46608272557ba26"}, - {file = "environs-9.3.3.tar.gz", hash = "sha256:72b867ff7b553076cdd90f3ee01ecc1cf854987639c9c459f0ed0d3d44ae490c"}, + {file = "environs-9.5.0-py2.py3-none-any.whl", hash = "sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124"}, + {file = "environs-9.5.0.tar.gz", hash = "sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9"}, ] fastapi = [ - {file = "fastapi-0.78.0-py3-none-any.whl", hash = "sha256:15fcabd5c78c266fa7ae7d8de9b384bfc2375ee0503463a6febbe3bab69d6f65"}, - {file = "fastapi-0.78.0.tar.gz", hash = "sha256:3233d4a789ba018578658e2af1a4bb5e38bdd122ff722b313666a9b2c6786a83"}, + {file = "fastapi-0.83.0-py3-none-any.whl", hash = "sha256:694a2b6c2607a61029a4be1c6613f84d74019cb9f7a41c7a475dca8e715f9368"}, + {file = "fastapi-0.83.0.tar.gz", hash = "sha256:96eb692350fe13d7a9843c3c87a874f0d45102975257dd224903efd6c0fde3bd"}, +] +grpcio = [ + {file = "grpcio-1.49.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:fd86040232e805b8e6378b2348c928490ee595b058ce9aaa27ed8e4b0f172b20"}, + {file = "grpcio-1.49.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6fd0c9cede9552bf00f8c5791d257d5bf3790d7057b26c59df08be5e7a1e021d"}, + {file = "grpcio-1.49.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:d0d402e158d4e84e49c158cb5204119d55e1baf363ee98d6cb5dce321c3a065d"}, + {file = "grpcio-1.49.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:822ceec743d42a627e64ea266059a62d214c5a3cdfcd0d7fe2b7a8e4e82527c7"}, + {file = "grpcio-1.49.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2106d9c16527f0a85e2eea6e6b91a74fc99579c60dd810d8690843ea02bc0f5f"}, + {file = "grpcio-1.49.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:52dd02b7e7868233c571b49bc38ebd347c3bb1ff8907bb0cb74cb5f00c790afc"}, + {file = "grpcio-1.49.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:120fecba2ec5d14b5a15d11063b39783fda8dc8d24addd83196acb6582cabd9b"}, + {file = "grpcio-1.49.1-cp310-cp310-win32.whl", hash = "sha256:f1a3b88e3c53c1a6e6bed635ec1bbb92201bb6a1f2db186179f7f3f244829788"}, + {file = "grpcio-1.49.1-cp310-cp310-win_amd64.whl", hash = "sha256:a7d0017b92d3850abea87c1bdec6ea41104e71c77bca44c3e17f175c6700af62"}, + {file = "grpcio-1.49.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:9fb17ff8c0d56099ac6ebfa84f670c5a62228d6b5c695cf21c02160c2ac1446b"}, + {file = "grpcio-1.49.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:075f2d06e3db6b48a2157a1bcd52d6cbdca980dd18988fe6afdb41795d51625f"}, + {file = "grpcio-1.49.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46d93a1b4572b461a227f1db6b8d35a88952db1c47e5fadcf8b8a2f0e1dd9201"}, + {file = "grpcio-1.49.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc79b2b37d779ac42341ddef40ad5bf0966a64af412c89fc2b062e3ddabb093f"}, + {file = "grpcio-1.49.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5f8b3a971c7820ea9878f3fd70086240a36aeee15d1b7e9ecbc2743b0e785568"}, + {file = "grpcio-1.49.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49b301740cf5bc8fed4fee4c877570189ae3951432d79fa8e524b09353659811"}, + {file = "grpcio-1.49.1-cp311-cp311-win32.whl", hash = "sha256:1c66a25afc6c71d357867b341da594a5587db5849b48f4b7d5908d236bb62ede"}, + {file = "grpcio-1.49.1-cp311-cp311-win_amd64.whl", hash = "sha256:6b6c3a95d27846f4145d6967899b3ab25fffc6ae99544415e1adcacef84842d2"}, + {file = "grpcio-1.49.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:1cc400c8a2173d1c042997d98a9563e12d9bb3fb6ad36b7f355bc77c7663b8af"}, + {file = "grpcio-1.49.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:34f736bd4d0deae90015c0e383885b431444fe6b6c591dea288173df20603146"}, + {file = "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:196082b9c89ebf0961dcd77cb114bed8171964c8e3063b9da2fb33536a6938ed"}, + {file = "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c9f89c42749890618cd3c2464e1fbf88446e3d2f67f1e334c8e5db2f3272bbd"}, + {file = "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64419cb8a5b612cdb1550c2fd4acbb7d4fb263556cf4625f25522337e461509e"}, + {file = "grpcio-1.49.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8a5272061826e6164f96e3255405ef6f73b88fd3e8bef464c7d061af8585ac62"}, + {file = "grpcio-1.49.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ea9d0172445241ad7cb49577314e39d0af2c5267395b3561d7ced5d70458a9f3"}, + {file = "grpcio-1.49.1-cp37-cp37m-win32.whl", hash = "sha256:2070e87d95991473244c72d96d13596c751cb35558e11f5df5414981e7ed2492"}, + {file = "grpcio-1.49.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fcedcab49baaa9db4a2d240ac81f2d57eb0052b1c6a9501b46b8ae912720fbf"}, + {file = "grpcio-1.49.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:afbb3475cf7f4f7d380c2ca37ee826e51974f3e2665613996a91d6a58583a534"}, + {file = "grpcio-1.49.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a4f9ba141380abde6c3adc1727f21529137a2552002243fa87c41a07e528245c"}, + {file = "grpcio-1.49.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:cf0a1fb18a7204b9c44623dfbd1465b363236ce70c7a4ed30402f9f60d8b743b"}, + {file = "grpcio-1.49.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17bb6fe72784b630728c6cff9c9d10ccc3b6d04e85da6e0a7b27fb1d135fac62"}, + {file = "grpcio-1.49.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18305d5a082d1593b005a895c10041f833b16788e88b02bb81061f5ebcc465df"}, + {file = "grpcio-1.49.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b6a1b39e59ac5a3067794a0e498911cf2e37e4b19ee9e9977dc5e7051714f13f"}, + {file = "grpcio-1.49.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0e20d59aafc086b1cc68400463bddda6e41d3e5ed30851d1e2e0f6a2e7e342d3"}, + {file = "grpcio-1.49.1-cp38-cp38-win32.whl", hash = "sha256:e1e83233d4680863a421f3ee4a7a9b80d33cd27ee9ed7593bc93f6128302d3f2"}, + {file = "grpcio-1.49.1-cp38-cp38-win_amd64.whl", hash = "sha256:221d42c654d2a41fa31323216279c73ed17d92f533bc140a3390cc1bd78bf63c"}, + {file = "grpcio-1.49.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:fa9e6e61391e99708ac87fc3436f6b7b9c6b845dc4639b406e5e61901e1aacde"}, + {file = "grpcio-1.49.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9b449e966ef518ce9c860d21f8afe0b0f055220d95bc710301752ac1db96dd6a"}, + {file = "grpcio-1.49.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:aa34d2ad9f24e47fa9a3172801c676e4037d862247e39030165fe83821a7aafd"}, + {file = "grpcio-1.49.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5207f4eed1b775d264fcfe379d8541e1c43b878f2b63c0698f8f5c56c40f3d68"}, + {file = "grpcio-1.49.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b24a74651438d45619ac67004638856f76cc13d78b7478f2457754cbcb1c8ad"}, + {file = "grpcio-1.49.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fe763781669790dc8b9618e7e677c839c87eae6cf28b655ee1fa69ae04eea03f"}, + {file = "grpcio-1.49.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2f2ff7ba0f8f431f32d4b4bc3a3713426949d3533b08466c4ff1b2b475932ca8"}, + {file = "grpcio-1.49.1-cp39-cp39-win32.whl", hash = "sha256:08ff74aec8ff457a89b97152d36cb811dcc1d17cd5a92a65933524e363327394"}, + {file = "grpcio-1.49.1-cp39-cp39-win_amd64.whl", hash = "sha256:274ffbb39717918c514b35176510ae9be06e1d93121e84d50b350861dcb9a705"}, + {file = "grpcio-1.49.1.tar.gz", hash = "sha256:d4725fc9ec8e8822906ae26bb26f5546891aa7fbc3443de970cc556d43a5c99f"}, ] h11 = [ {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, @@ -1131,12 +1503,12 @@ httpx = [ {file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"}, ] idna = [ - {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, - {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, - {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, + {file = "importlib_metadata-4.12.0-py3-none-any.whl", hash = "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23"}, + {file = "importlib_metadata-4.12.0.tar.gz", hash = "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -1146,92 +1518,63 @@ isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] -jinja2 = [ - {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, - {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, +Jinja2 = [ + {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, + {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, ] lnurl = [ {file = "lnurl-0.3.6-py3-none-any.whl", hash = "sha256:579982fd8c4d25bc84c61c74ec45cb7999fa1fa2426f5d5aeb0160ba333b9c92"}, {file = "lnurl-0.3.6.tar.gz", hash = "sha256:8af07460115a48f3122a5a9c9a6062bee3897d5f6ab4c9a60f6561a83a8234f6"}, ] loguru = [ - {file = "loguru-0.5.3-py3-none-any.whl", hash = "sha256:f8087ac396b5ee5f67c963b495d615ebbceac2796379599820e324419d53667c"}, - {file = "loguru-0.5.3.tar.gz", hash = "sha256:b28e72ac7a98be3d28ad28570299a393dfcd32e5e3f6a353dec94675767b6319"}, + {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, + {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, ] -markupsafe = [ - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, - {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, - {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, - {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, - {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, - {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, - {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, +MarkupSafe = [ + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, + {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, + {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, + {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, + {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, + {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, ] marshmallow = [ - {file = "marshmallow-3.17.0-py3-none-any.whl", hash = "sha256:00040ab5ea0c608e8787137627a8efae97fabd60552a05dc889c888f814e75eb"}, - {file = "marshmallow-3.17.0.tar.gz", hash = "sha256:635fb65a3285a31a30f276f30e958070f5214c7196202caa5c7ecf28f5274bc7"}, + {file = "marshmallow-3.18.0-py3-none-any.whl", hash = "sha256:35e02a3a06899c9119b785c12a22f4cda361745d66a71ab691fd7610202ae104"}, + {file = "marshmallow-3.18.0.tar.gz", hash = "sha256:6804c16114f7fce1f5b4dadc31f4674af23317fcc7f075da21e35c1a35d781f7"}, ] mock = [ {file = "mock-4.0.3-py3-none-any.whl", hash = "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62"}, @@ -1267,16 +1610,20 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] outcome = [ - {file = "outcome-1.1.0-py2.py3-none-any.whl", hash = "sha256:c7dd9375cfd3c12db9801d080a3b63d4b0a261aa996c4c13152380587288d958"}, - {file = "outcome-1.1.0.tar.gz", hash = "sha256:e862f01d4e626e63e8f92c38d1f8d5546d3f9cce989263c521b2e7990d186967"}, + {file = "outcome-1.2.0-py2.py3-none-any.whl", hash = "sha256:c4ab89a56575d6d38a05aa16daeaa333109c1f96167aba8901ab18b6b5e0f7f5"}, + {file = "outcome-1.2.0.tar.gz", hash = "sha256:6f82bd3de45da303cf1f771ecafa1633750a358436a8bb60e06a1ceb745d2672"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] +pathlib2 = [ + {file = "pathlib2-2.3.7.post1-py2.py3-none-any.whl", hash = "sha256:5266a0fd000452f1b3467d782f079a4343c63aaa119221fbdc4e39577489ca5b"}, + {file = "pathlib2-2.3.7.post1.tar.gz", hash = "sha256:9fe0edad898b83c0c3e199c842b27ed216645d2e177757b2dd67384d4113c641"}, +] pathspec = [ - {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, - {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, + {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, + {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, ] platformdirs = [ {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, @@ -1286,43 +1633,79 @@ pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] +protobuf = [ + {file = "protobuf-4.21.6-cp310-abi3-win32.whl", hash = "sha256:49f88d56a9180dbb7f6199c920f5bb5c1dd0172f672983bb281298d57c2ac8eb"}, + {file = "protobuf-4.21.6-cp310-abi3-win_amd64.whl", hash = "sha256:7a6cc8842257265bdfd6b74d088b829e44bcac3cca234c5fdd6052730017b9ea"}, + {file = "protobuf-4.21.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ba596b9ffb85c909fcfe1b1a23136224ed678af3faf9912d3fa483d5f9813c4e"}, + {file = "protobuf-4.21.6-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:4143513c766db85b9d7c18dbf8339673c8a290131b2a0fe73855ab20770f72b0"}, + {file = "protobuf-4.21.6-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:b6cea204865595a92a7b240e4b65bcaaca3ad5d2ce25d9db3756eba06041138e"}, + {file = "protobuf-4.21.6-cp37-cp37m-win32.whl", hash = "sha256:9666da97129138585b26afcb63ad4887f602e169cafe754a8258541c553b8b5d"}, + {file = "protobuf-4.21.6-cp37-cp37m-win_amd64.whl", hash = "sha256:308173d3e5a3528787bb8c93abea81d5a950bdce62840d9760effc84127fb39c"}, + {file = "protobuf-4.21.6-cp38-cp38-win32.whl", hash = "sha256:aa29113ec901281f29d9d27b01193407a98aa9658b8a777b0325e6d97149f5ce"}, + {file = "protobuf-4.21.6-cp38-cp38-win_amd64.whl", hash = "sha256:8f9e60f7d44592c66e7b332b6a7b4b6e8d8b889393c79dbc3a91f815118f8eac"}, + {file = "protobuf-4.21.6-cp39-cp39-win32.whl", hash = "sha256:80e6540381080715fddac12690ee42d087d0d17395f8d0078dfd6f1181e7be4c"}, + {file = "protobuf-4.21.6-cp39-cp39-win_amd64.whl", hash = "sha256:77b355c8604fe285536155286b28b0c4cbc57cf81b08d8357bf34829ea982860"}, + {file = "protobuf-4.21.6-py2.py3-none-any.whl", hash = "sha256:07a0bb9cc6114f16a39c866dc28b6e3d96fa4ffb9cc1033057412547e6e75cb9"}, + {file = "protobuf-4.21.6-py3-none-any.whl", hash = "sha256:c7c864148a237f058c739ae7a05a2b403c0dfa4ce7d1f3e5213f352ad52d57c6"}, + {file = "protobuf-4.21.6.tar.gz", hash = "sha256:6b1040a5661cd5f6e610cbca9cfaa2a17d60e2bb545309bc1b278bb05be44bdd"}, +] psycopg2-binary = [ - {file = "psycopg2-binary-2.9.1.tar.gz", hash = "sha256:b0221ca5a9837e040ebf61f48899926b5783668b7807419e4adae8175a31f773"}, - {file = "psycopg2_binary-2.9.1-cp310-cp310-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:24b0b6688b9f31a911f2361fe818492650795c9e5d3a1bc647acbd7440142a4f"}, - {file = "psycopg2_binary-2.9.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:542875f62bc56e91c6eac05a0deadeae20e1730be4c6334d8f04c944fcd99759"}, - {file = "psycopg2_binary-2.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:661509f51531ec125e52357a489ea3806640d0ca37d9dada461ffc69ee1e7b6e"}, - {file = "psycopg2_binary-2.9.1-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:d92272c7c16e105788efe2cfa5d680f07e34e0c29b03c1908f8636f55d5f915a"}, - {file = "psycopg2_binary-2.9.1-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:736b8797b58febabb85494142c627bd182b50d2a7ec65322983e71065ad3034c"}, - {file = "psycopg2_binary-2.9.1-cp310-cp310-win32.whl", hash = "sha256:ebccf1123e7ef66efc615a68295bf6fdba875a75d5bba10a05073202598085fc"}, - {file = "psycopg2_binary-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:1f6ca4a9068f5c5c57e744b4baa79f40e83e3746875cac3c45467b16326bab45"}, - {file = "psycopg2_binary-2.9.1-cp36-cp36m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:c250a7ec489b652c892e4f0a5d122cc14c3780f9f643e1a326754aedf82d9a76"}, - {file = "psycopg2_binary-2.9.1-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aef9aee84ec78af51107181d02fe8773b100b01c5dfde351184ad9223eab3698"}, - {file = "psycopg2_binary-2.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:123c3fb684e9abfc47218d3784c7b4c47c8587951ea4dd5bc38b6636ac57f616"}, - {file = "psycopg2_binary-2.9.1-cp36-cp36m-manylinux_2_24_aarch64.whl", hash = "sha256:995fc41ebda5a7a663a254a1dcac52638c3e847f48307b5416ee373da15075d7"}, - {file = "psycopg2_binary-2.9.1-cp36-cp36m-manylinux_2_24_ppc64le.whl", hash = "sha256:fbb42a541b1093385a2d8c7eec94d26d30437d0e77c1d25dae1dcc46741a385e"}, - {file = "psycopg2_binary-2.9.1-cp36-cp36m-win32.whl", hash = "sha256:20f1ab44d8c352074e2d7ca67dc00843067788791be373e67a0911998787ce7d"}, - {file = "psycopg2_binary-2.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f6fac64a38f6768e7bc7b035b9e10d8a538a9fadce06b983fb3e6fa55ac5f5ce"}, - {file = "psycopg2_binary-2.9.1-cp37-cp37m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:1e3a362790edc0a365385b1ac4cc0acc429a0c0d662d829a50b6ce743ae61b5a"}, - {file = "psycopg2_binary-2.9.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f8559617b1fcf59a9aedba2c9838b5b6aa211ffedecabca412b92a1ff75aac1a"}, - {file = "psycopg2_binary-2.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a36c7eb6152ba5467fb264d73844877be8b0847874d4822b7cf2d3c0cb8cdcb0"}, - {file = "psycopg2_binary-2.9.1-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:2f62c207d1740b0bde5c4e949f857b044818f734a3d57f1d0d0edc65050532ed"}, - {file = "psycopg2_binary-2.9.1-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:cfc523edecddaef56f6740d7de1ce24a2fdf94fd5e704091856a201872e37f9f"}, - {file = "psycopg2_binary-2.9.1-cp37-cp37m-win32.whl", hash = "sha256:1e85b74cbbb3056e3656f1cc4781294df03383127a8114cbc6531e8b8367bf1e"}, - {file = "psycopg2_binary-2.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1473c0215b0613dd938db54a653f68251a45a78b05f6fc21af4326f40e8360a2"}, - {file = "psycopg2_binary-2.9.1-cp38-cp38-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:35c4310f8febe41f442d3c65066ca93cccefd75013df3d8c736c5b93ec288140"}, - {file = "psycopg2_binary-2.9.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c13d72ed6af7fd2c8acbd95661cf9477f94e381fce0792c04981a8283b52917"}, - {file = "psycopg2_binary-2.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14db1752acdd2187d99cb2ca0a1a6dfe57fc65c3281e0f20e597aac8d2a5bd90"}, - {file = "psycopg2_binary-2.9.1-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:aed4a9a7e3221b3e252c39d0bf794c438dc5453bc2963e8befe9d4cd324dff72"}, - {file = "psycopg2_binary-2.9.1-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:da113b70f6ec40e7d81b43d1b139b9db6a05727ab8be1ee559f3a69854a69d34"}, - {file = "psycopg2_binary-2.9.1-cp38-cp38-win32.whl", hash = "sha256:4235f9d5ddcab0b8dbd723dca56ea2922b485ea00e1dafacf33b0c7e840b3d32"}, - {file = "psycopg2_binary-2.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:988b47ac70d204aed01589ed342303da7c4d84b56c2f4c4b8b00deda123372bf"}, - {file = "psycopg2_binary-2.9.1-cp39-cp39-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:7360647ea04db2e7dff1648d1da825c8cf68dc5fbd80b8fb5b3ee9f068dcd21a"}, - {file = "psycopg2_binary-2.9.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca86db5b561b894f9e5f115d6a159fff2a2570a652e07889d8a383b5fae66eb4"}, - {file = "psycopg2_binary-2.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ced67f1e34e1a450cdb48eb53ca73b60aa0af21c46b9b35ac3e581cf9f00e31"}, - {file = "psycopg2_binary-2.9.1-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:0f2e04bd2a2ab54fa44ee67fe2d002bb90cee1c0f1cc0ebc3148af7b02034cbd"}, - {file = "psycopg2_binary-2.9.1-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:3242b9619de955ab44581a03a64bdd7d5e470cc4183e8fcadd85ab9d3756ce7a"}, - {file = "psycopg2_binary-2.9.1-cp39-cp39-win32.whl", hash = "sha256:0b7dae87f0b729922e06f85f667de7bf16455d411971b2043bbd9577af9d1975"}, - {file = "psycopg2_binary-2.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:b4d7679a08fea64573c969f6994a2631908bb2c0e69a7235648642f3d2e39a68"}, + {file = "psycopg2-binary-2.9.3.tar.gz", hash = "sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:539b28661b71da7c0e428692438efbcd048ca21ea81af618d845e06ebfd29478"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e82d38390a03da28c7985b394ec3f56873174e2c88130e6966cb1c946508e65"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57804fc02ca3ce0dbfbef35c4b3a4a774da66d66ea20f4bda601294ad2ea6092"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:083a55275f09a62b8ca4902dd11f4b33075b743cf0d360419e2051a8a5d5ff76"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:0a29729145aaaf1ad8bafe663131890e2111f13416b60e460dae0a96af5905c9"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a79d622f5206d695d7824cbf609a4f5b88ea6d6dab5f7c147fc6d333a8787e4"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:090f3348c0ab2cceb6dfbe6bf721ef61262ddf518cd6cc6ecc7d334996d64efa"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a9e1f75f96ea388fbcef36c70640c4efbe4650658f3d6a2967b4cc70e907352e"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c3ae8e75eb7160851e59adc77b3a19a976e50622e44fd4fd47b8b18208189d42"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-win32.whl", hash = "sha256:7b1e9b80afca7b7a386ef087db614faebbf8839b7f4db5eb107d0f1a53225029"}, + {file = "psycopg2_binary-2.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:8b344adbb9a862de0c635f4f0425b7958bf5a4b927c8594e6e8d261775796d53"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:e847774f8ffd5b398a75bc1c18fbb56564cda3d629fe68fd81971fece2d3c67e"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68641a34023d306be959101b345732360fc2ea4938982309b786f7be1b43a4a1"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3303f8807f342641851578ee7ed1f3efc9802d00a6f83c101d21c608cb864460"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_24_aarch64.whl", hash = "sha256:e3699852e22aa68c10de06524a3721ade969abf382da95884e6a10ff798f9281"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_24_ppc64le.whl", hash = "sha256:526ea0378246d9b080148f2d6681229f4b5964543c170dd10bf4faaab6e0d27f"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:b1c8068513f5b158cf7e29c43a77eb34b407db29aca749d3eb9293ee0d3103ca"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:15803fa813ea05bef089fa78835118b5434204f3a17cb9f1e5dbfd0b9deea5af"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:152f09f57417b831418304c7f30d727dc83a12761627bb826951692cc6491e57"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:404224e5fef3b193f892abdbf8961ce20e0b6642886cfe1fe1923f41aaa75c9d"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-win32.whl", hash = "sha256:1f6b813106a3abdf7b03640d36e24669234120c72e91d5cbaeb87c5f7c36c65b"}, + {file = "psycopg2_binary-2.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:2d872e3c9d5d075a2e104540965a1cf898b52274a5923936e5bfddb58c59c7c2"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:10bb90fb4d523a2aa67773d4ff2b833ec00857f5912bafcfd5f5414e45280fb1"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a52ecab70af13e899f7847b3e074eeb16ebac5615665db33bce8a1009cf33"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a29b3ca4ec9defec6d42bf5feb36bb5817ba3c0230dd83b4edf4bf02684cd0ae"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:12b11322ea00ad8db8c46f18b7dfc47ae215e4df55b46c67a94b4effbaec7094"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:53293533fcbb94c202b7c800a12c873cfe24599656b341f56e71dd2b557be063"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c381bda330ddf2fccbafab789d83ebc6c53db126e4383e73794c74eedce855ef"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d29409b625a143649d03d0fd7b57e4b92e0ecad9726ba682244b73be91d2fdb"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:183a517a3a63503f70f808b58bfbf962f23d73b6dccddae5aa56152ef2bcb232"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:15c4e4cfa45f5a60599d9cec5f46cd7b1b29d86a6390ec23e8eebaae84e64554"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:adf20d9a67e0b6393eac162eb81fb10bc9130a80540f4df7e7355c2dd4af9fba"}, + {file = "psycopg2_binary-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:2f9ffd643bc7349eeb664eba8864d9e01f057880f510e4681ba40a6532f93c71"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:def68d7c21984b0f8218e8a15d514f714d96904265164f75f8d3a70f9c295667"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dffc08ca91c9ac09008870c9eb77b00a46b3378719584059c034b8945e26b272"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:280b0bb5cbfe8039205c7981cceb006156a675362a00fe29b16fbc264e242834"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:af9813db73395fb1fc211bac696faea4ca9ef53f32dc0cfa27e4e7cf766dcf24"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:63638d875be8c2784cfc952c9ac34e2b50e43f9f0a0660b65e2a87d656b3116c"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ffb7a888a047696e7f8240d649b43fb3644f14f0ee229077e7f6b9f9081635bd"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c9d5450c566c80c396b7402895c4369a410cab5a82707b11aee1e624da7d004"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:d1c1b569ecafe3a69380a94e6ae09a4789bbb23666f3d3a08d06bbd2451f5ef1"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8fc53f9af09426a61db9ba357865c77f26076d48669f2e1bb24d85a22fb52307"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-win32.whl", hash = "sha256:6472a178e291b59e7f16ab49ec8b4f3bdada0a879c68d3817ff0963e722a82ce"}, + {file = "psycopg2_binary-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:35168209c9d51b145e459e05c31a9eaeffa9a6b0fd61689b48e07464ffd1a83e"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:47133f3f872faf28c1e87d4357220e809dfd3fa7c64295a4a148bcd1e6e34ec9"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91920527dea30175cc02a1099f331aa8c1ba39bf8b7762b7b56cbf54bc5cce42"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887dd9aac71765ac0d0bac1d0d4b4f2c99d5f5c1382d8b770404f0f3d0ce8a39"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:1f14c8b0942714eb3c74e1e71700cbbcb415acbc311c730370e70c578a44a25c"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:7af0dd86ddb2f8af5da57a976d27cd2cd15510518d582b478fbb2292428710b4"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93cd1967a18aa0edd4b95b1dfd554cf15af657cb606280996d393dadc88c3c35"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bda845b664bb6c91446ca9609fc69f7db6c334ec5e4adc87571c34e4f47b7ddb"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:01310cf4cf26db9aea5158c217caa92d291f0500051a6469ac52166e1a16f5b7"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99485cab9ba0fa9b84f1f9e1fef106f44a46ef6afdeec8885e0b88d0772b49e8"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-win32.whl", hash = "sha256:46f0e0a6b5fa5851bbd9ab1bc805eef362d3a230fbdfbc209f4a236d0a7a990d"}, + {file = "psycopg2_binary-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:accfe7e982411da3178ec690baaceaad3c278652998b2c45828aaac66cd8285f"}, ] py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, @@ -1362,28 +1745,54 @@ pycryptodomex = [ {file = "pycryptodomex-3.14.1.tar.gz", hash = "sha256:2ce76ed0081fd6ac8c74edc75b9d14eca2064173af79843c24fa62573263c1f2"}, ] pydantic = [ - {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, - {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, - {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, - {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, - {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, - {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, - {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, - {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, - {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, - {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, - {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, - {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, - {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, - {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, - {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, - {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, - {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, - {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, - {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, - {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, - {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, - {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, + {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"}, +] +pyln-bolt7 = [ + {file = "pyln-bolt7-1.0.246.tar.gz", hash = "sha256:2b53744fa21c1b12d2c9c9df153651b122e38fa65d4a5c3f2957317ee148e089"}, + {file = "pyln_bolt7-1.0.246-py3-none-any.whl", hash = "sha256:54d48ec27fdc8751762cb068b0a9f2757a58fb57933c6d8f8255d02c27eb63c5"}, +] +pyln-client = [ + {file = "pyln-client-0.12.1.tar.gz", hash = "sha256:f14fa7947b65ecde2753984452441cf41b7b25b1a0ba7beced48786fa54d2bfe"}, + {file = "pyln_client-0.12.1-py3-none-any.whl", hash = "sha256:6b500bcc49e4028d50692b962d9c9f7e9ede920d718f9b9412f04f7db0aa0e63"}, +] +pyln-proto = [ + {file = "pyln-proto-0.12.0.tar.gz", hash = "sha256:3214d99d8385f2135a94937f0dc1da626a33b257e9ebc320841656edaefabbe5"}, + {file = "pyln_proto-0.12.0-py3-none-any.whl", hash = "sha256:dedef5d8e476a9ade5a0b2eb919ccc37e4a57f2a78fdc399f1c5e0de17e41604"}, ] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, @@ -1392,16 +1801,21 @@ pyparsing = [ pypng = [ {file = "pypng-0.0.21-py3-none-any.whl", hash = "sha256:76f8a1539ec56451da7ab7121f12a361969fe0f2d48d703d198ce2a99d6c5afd"}, ] -pyqrcode = [ +PyQRCode = [ {file = "PyQRCode-1.2.1.tar.gz", hash = "sha256:fdbf7634733e56b72e27f9bce46e4550b75a3a2c420414035cae9d9d26b234d5"}, {file = "PyQRCode-1.2.1.zip", hash = "sha256:1b2812775fa6ff5c527977c4cd2ccb07051ca7d0bc0aecf937a43864abe5eff6"}, ] -pyscss = [ - {file = "pyScss-1.3.7.tar.gz", hash = "sha256:f1df571569021a23941a538eb154405dde80bed35dc1ea7c5f3e18e0144746bf"}, +pyScss = [ + {file = "pyScss-1.4.0.tar.gz", hash = "sha256:8f35521ffe36afa8b34c7d6f3195088a7057c185c2b8f15ee459ab19748669ff"}, +] +PySocks = [ + {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, + {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, + {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, ] pytest = [ - {file = "pytest-7.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, - {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"}, + {file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"}, + {file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"}, ] pytest-asyncio = [ {file = "pytest-asyncio-0.19.0.tar.gz", hash = "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed"}, @@ -1412,10 +1826,10 @@ pytest-cov = [ {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, ] python-dotenv = [ - {file = "python-dotenv-0.19.0.tar.gz", hash = "sha256:f521bc2ac9a8e03c736f62911605c5d83970021e3fa95b37d769e2bbbe9b6172"}, - {file = "python_dotenv-0.19.0-py2.py3-none-any.whl", hash = "sha256:aae25dc1ebe97c420f50b81fb0e5c949659af713f31fdb63c749ca68748f34b1"}, + {file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"}, + {file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"}, ] -pyyaml = [ +PyYAML = [ {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, @@ -1446,10 +1860,14 @@ pyyaml = [ {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] -represent = [ +Represent = [ {file = "Represent-1.6.0.post0-py2.py3-none-any.whl", hash = "sha256:99142650756ef1998ce0661568f54a47dac8c638fb27e3816c02536575dbba8c"}, {file = "Represent-1.6.0.post0.tar.gz", hash = "sha256:026c0de2ee8385d1255b9c2426cd4f03fe9177ac94c09979bc601946c8493aa0"}, ] +requests = [ + {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, + {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, +] rfc3986 = [ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, @@ -1479,6 +1897,10 @@ secp256k1 = [ {file = "secp256k1-0.14.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c9e7c024ff17e9b9d7c392bb2a917da231d6cb40ab119389ff1f51dca10339a4"}, {file = "secp256k1-0.14.0.tar.gz", hash = "sha256:82c06712d69ef945220c8b53c1a0d424c2ff6a1f64aee609030df79ad8383397"}, ] +setuptools = [ + {file = "setuptools-65.4.0-py3-none-any.whl", hash = "sha256:c2d2709550f15aab6c9110196ea312f468f41cd546bceb24127a1be6fdcaeeb1"}, + {file = "setuptools-65.4.0.tar.gz", hash = "sha256:a8f6e213b4b0661f590ccf40de95d28a177cd747d098624ad3f69c40287297e9"}, +] shortuuid = [ {file = "shortuuid-1.0.1-py3-none-any.whl", hash = "sha256:492c7402ff91beb1342a5898bd61ea953985bf24a41cd9f247409aa2e03c8f77"}, {file = "shortuuid-1.0.1.tar.gz", hash = "sha256:3c11d2007b915c43bee3e10625f068d8a349e04f0d81f08f5fa08507427ebf1f"}, @@ -1488,48 +1910,44 @@ six = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] sniffio = [ - {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, - {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, + {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, + {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, ] -sqlalchemy = [ - {file = "SQLAlchemy-1.3.23-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:fd3b96f8c705af8e938eaa99cbd8fd1450f632d38cad55e7367c33b263bf98ec"}, - {file = "SQLAlchemy-1.3.23-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:29cccc9606750fe10c5d0e8bd847f17a97f3850b8682aef1f56f5d5e1a5a64b1"}, - {file = "SQLAlchemy-1.3.23-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:927ce09e49bff3104459e1451ce82983b0a3062437a07d883a4c66f0b344c9b5"}, - {file = "SQLAlchemy-1.3.23-cp27-cp27m-win32.whl", hash = "sha256:b4b0e44d586cd64b65b507fa116a3814a1a53d55dce4836d7c1a6eb2823ff8d1"}, - {file = "SQLAlchemy-1.3.23-cp27-cp27m-win_amd64.whl", hash = "sha256:6b8b8c80c7f384f06825612dd078e4a31f0185e8f1f6b8c19e188ff246334205"}, - {file = "SQLAlchemy-1.3.23-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9e9c25522933e569e8b53ccc644dc993cab87e922fb7e142894653880fdd419d"}, - {file = "SQLAlchemy-1.3.23-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a0e306e9bb76fd93b29ae3a5155298e4c1b504c7cbc620c09c20858d32d16234"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:6c9e6cc9237de5660bcddea63f332428bb83c8e2015c26777281f7ffbd2efb84"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:94f667d86be82dd4cb17d08de0c3622e77ca865320e0b95eae6153faa7b4ecaf"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:751934967f5336a3e26fc5993ccad1e4fee982029f9317eb6153bc0bc3d2d2da"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:63677d0c08524af4c5893c18dbe42141de7178001360b3de0b86217502ed3601"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-win32.whl", hash = "sha256:ddfb511e76d016c3a160910642d57f4587dc542ce5ee823b0d415134790eeeb9"}, - {file = "SQLAlchemy-1.3.23-cp35-cp35m-win_amd64.whl", hash = "sha256:040bdfc1d76a9074717a3f43455685f781c581f94472b010cd6c4754754e1862"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:d1a85dfc5dee741bf49cb9b6b6b8d2725a268e4992507cf151cba26b17d97c37"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:639940bbe1108ac667dcffc79925db2966826c270112e9159439ab6bb14f8d80"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e8a1750b44ad6422ace82bf3466638f1aa0862dbb9689690d5f2f48cce3476c8"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e5bb3463df697279e5459a7316ad5a60b04b0107f9392e88674d0ece70e9cf70"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-win32.whl", hash = "sha256:e273367f4076bd7b9a8dc2e771978ef2bfd6b82526e80775a7db52bff8ca01dd"}, - {file = "SQLAlchemy-1.3.23-cp36-cp36m-win_amd64.whl", hash = "sha256:ac2244e64485c3778f012951fdc869969a736cd61375fde6096d08850d8be729"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:23927c3981d1ec6b4ea71eb99d28424b874d9c696a21e5fbd9fa322718be3708"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d90010304abb4102123d10cbad2cdf2c25a9f2e66a50974199b24b468509bad5"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a8bfc1e1afe523e94974132d7230b82ca7fa2511aedde1f537ec54db0399541a"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:269990b3ab53cb035d662dcde51df0943c1417bdab707dc4a7e4114a710504b4"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-win32.whl", hash = "sha256:fdd2ed7395df8ac2dbb10cefc44737b66c6a5cd7755c92524733d7a443e5b7e2"}, - {file = "SQLAlchemy-1.3.23-cp37-cp37m-win_amd64.whl", hash = "sha256:6a939a868fdaa4b504e8b9d4a61f21aac11e3fecc8a8214455e144939e3d2aea"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:24f9569e82a009a09ce2d263559acb3466eba2617203170e4a0af91e75b4f075"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2578dbdbe4dbb0e5126fb37ffcd9793a25dcad769a95f171a2161030bea850ff"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1fe5d8d39118c2b018c215c37b73fd6893c3e1d4895be745ca8ff6eb83333ed3"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:c7dc052432cd5d060d7437e217dd33c97025287f99a69a50e2dc1478dd610d64"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-win32.whl", hash = "sha256:ecce8c021894a77d89808222b1ff9687ad84db54d18e4bd0500ca766737faaf6"}, - {file = "SQLAlchemy-1.3.23-cp38-cp38-win_amd64.whl", hash = "sha256:37b83bf81b4b85dda273aaaed5f35ea20ad80606f672d94d2218afc565fb0173"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8be835aac18ec85351385e17b8665bd4d63083a7160a017bef3d640e8e65cadb"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6ec1044908414013ebfe363450c22f14698803ce97fbb47e53284d55c5165848"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:eab063a70cca4a587c28824e18be41d8ecc4457f8f15b2933584c6c6cccd30f0"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:baeb451ee23e264de3f577fee5283c73d9bbaa8cb921d0305c0bbf700094b65b"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-win32.whl", hash = "sha256:94208867f34e60f54a33a37f1c117251be91a47e3bfdb9ab8a7847f20886ad06"}, - {file = "SQLAlchemy-1.3.23-cp39-cp39-win_amd64.whl", hash = "sha256:f4d972139d5000105fcda9539a76452039434013570d6059993120dc2a65e447"}, - {file = "SQLAlchemy-1.3.23.tar.gz", hash = "sha256:6fca33672578666f657c131552c4ef8979c1606e494f78cd5199742dfb26918b"}, +SQLAlchemy = [ + {file = "SQLAlchemy-1.3.24-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:87a2725ad7d41cd7376373c15fd8bf674e9c33ca56d0b8036add2d634dba372e"}, + {file = "SQLAlchemy-1.3.24-cp27-cp27m-win32.whl", hash = "sha256:f597a243b8550a3a0b15122b14e49d8a7e622ba1c9d29776af741f1845478d79"}, + {file = "SQLAlchemy-1.3.24-cp27-cp27m-win_amd64.whl", hash = "sha256:fc4cddb0b474b12ed7bdce6be1b9edc65352e8ce66bc10ff8cbbfb3d4047dbf4"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:f1149d6e5c49d069163e58a3196865e4321bad1803d7886e07d8710de392c548"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:14f0eb5db872c231b20c18b1e5806352723a3a89fb4254af3b3e14f22eaaec75"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:e98d09f487267f1e8d1179bf3b9d7709b30a916491997137dd24d6ae44d18d79"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:fc1f2a5a5963e2e73bac4926bdaf7790c4d7d77e8fc0590817880e22dd9d0b8b"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-win32.whl", hash = "sha256:f3c5c52f7cb8b84bfaaf22d82cb9e6e9a8297f7c2ed14d806a0f5e4d22e83fb7"}, + {file = "SQLAlchemy-1.3.24-cp35-cp35m-win_amd64.whl", hash = "sha256:0352db1befcbed2f9282e72843f1963860bf0e0472a4fa5cf8ee084318e0e6ab"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2ed6343b625b16bcb63c5b10523fd15ed8934e1ed0f772c534985e9f5e73d894"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:34fcec18f6e4b24b4a5f6185205a04f1eab1e56f8f1d028a2a03694ebcc2ddd4"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e47e257ba5934550d7235665eee6c911dc7178419b614ba9e1fbb1ce6325b14f"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:816de75418ea0953b5eb7b8a74933ee5a46719491cd2b16f718afc4b291a9658"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-win32.whl", hash = "sha256:26155ea7a243cbf23287f390dba13d7927ffa1586d3208e0e8d615d0c506f996"}, + {file = "SQLAlchemy-1.3.24-cp36-cp36m-win_amd64.whl", hash = "sha256:f03bd97650d2e42710fbe4cf8a59fae657f191df851fc9fc683ecef10746a375"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:a006d05d9aa052657ee3e4dc92544faae5fcbaafc6128217310945610d862d39"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1e2f89d2e5e3c7a88e25a3b0e43626dba8db2aa700253023b82e630d12b37109"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0d5d862b1cfbec5028ce1ecac06a3b42bc7703eb80e4b53fceb2738724311443"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:0172423a27fbcae3751ef016663b72e1a516777de324a76e30efa170dbd3dd2d"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-win32.whl", hash = "sha256:d37843fb8df90376e9e91336724d78a32b988d3d20ab6656da4eb8ee3a45b63c"}, + {file = "SQLAlchemy-1.3.24-cp37-cp37m-win_amd64.whl", hash = "sha256:c10ff6112d119f82b1618b6dc28126798481b9355d8748b64b9b55051eb4f01b"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:861e459b0e97673af6cc5e7f597035c2e3acdfb2608132665406cded25ba64c7"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5de2464c254380d8a6c20a2746614d5a436260be1507491442cf1088e59430d2"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d375d8ccd3cebae8d90270f7aa8532fe05908f79e78ae489068f3b4eee5994e8"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:014ea143572fee1c18322b7908140ad23b3994036ef4c0d630110faf942652f8"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-win32.whl", hash = "sha256:6607ae6cd3a07f8a4c3198ffbf256c261661965742e2b5265a77cd5c679c9bba"}, + {file = "SQLAlchemy-1.3.24-cp38-cp38-win_amd64.whl", hash = "sha256:fcb251305fa24a490b6a9ee2180e5f8252915fb778d3dafc70f9cc3f863827b9"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:01aa5f803db724447c1d423ed583e42bf5264c597fd55e4add4301f163b0be48"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4d0e3515ef98aa4f0dc289ff2eebb0ece6260bbf37c2ea2022aad63797eacf60"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:bce28277f308db43a6b4965734366f533b3ff009571ec7ffa583cb77539b84d6"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8110e6c414d3efc574543109ee618fe2c1f96fa31833a1ff36cc34e968c4f233"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-win32.whl", hash = "sha256:ee5f5188edb20a29c1cc4a039b074fdc5575337c9a68f3063449ab47757bb064"}, + {file = "SQLAlchemy-1.3.24-cp39-cp39-win_amd64.whl", hash = "sha256:09083c2487ca3c0865dc588e07aeaa25416da3d95f7482c07e92f47e080aa17b"}, + {file = "SQLAlchemy-1.3.24.tar.gz", hash = "sha256:ebbb777cbf9312359b897bf81ba00dae0f5cb69fba2a18265dcc18a6f5ef7519"}, ] sqlalchemy-aio = [ {file = "sqlalchemy_aio-0.17.0-py3-none-any.whl", hash = "sha256:3f4aa392c38f032d6734826a4138a0f02ed3122d442ed142be1e5964f2a33b60"}, @@ -1573,17 +1991,20 @@ typed-ast = [ {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] types-protobuf = [ - {file = "types-protobuf-3.19.22.tar.gz", hash = "sha256:d2b26861b0cb46a3c8669b0df507b7ef72e487da66d61f9f3576aa76ce028a83"}, - {file = "types_protobuf-3.19.22-py3-none-any.whl", hash = "sha256:d291388678af91bb045fafa864f142dc4ac22f5d4cdca097c7d8d8a32fa9b3ab"}, + {file = "types-protobuf-3.20.4.tar.gz", hash = "sha256:0dad3a5009895c985a56e2837f61902bad9594151265ac0ee907bb16d0b01eb7"}, + {file = "types_protobuf-3.20.4-py3-none-any.whl", hash = "sha256:5082437afe64ce3b31c8db109eae86e02fda11e4d5f9ac59cb8578a8a138aa70"}, ] typing-extensions = [ - {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, - {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, - {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, + {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, + {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, +] +urllib3 = [ + {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, + {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, ] uvicorn = [ - {file = "uvicorn-0.18.1-py3-none-any.whl", hash = "sha256:013c4ea0787cc2dc456ef4368e18c01982e6be57903e4d3183218e543eb889b7"}, - {file = "uvicorn-0.18.1.tar.gz", hash = "sha256:35703e6518105cfe53f16a5a9435db3e2e227d0784f1fd8fbc1214b1fdc108df"}, + {file = "uvicorn-0.18.3-py3-none-any.whl", hash = "sha256:0abd429ebb41e604ed8d2be6c60530de3408f250e8d2d84967d85ba9e86fe3af"}, + {file = "uvicorn-0.18.3.tar.gz", hash = "sha256:9a66e7c42a2a95222f76ec24a4b754c158261c4696e683b9dadc72b590e0311b"}, ] uvloop = [ {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d"}, @@ -1643,6 +2064,6 @@ win32-setctime = [ {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, ] zipp = [ - {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, - {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, + {file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"}, + {file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"}, ] diff --git a/pyproject.toml b/pyproject.toml index 1ae8c1fe..f106350c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,55 +11,59 @@ script = "build.py" [tool.poetry.dependencies] python = "^3.9 | ^3.8 | ^3.7" aiofiles = "0.8.0" -asgiref = "3.4.1" -attrs = "21.2.0" +asgiref = "^3.4.1" +attrs = "22.1.0" bech32 = "1.2.0" bitstring = "3.1.9" cerberus = "1.3.4" -certifi = "2021.5.30" -charset-normalizer = "2.0.6" -click = "8.0.1" -ecdsa = "0.17.0" +certifi = "2022.9.24" +charset-normalizer = "2.0.12" +click = "8.0.4" +ecdsa = "0.18.0" embit = "0.4.9" -environs = "9.3.3" -fastapi = "0.78.0" +environs = "9.5.0" +fastapi = "0.83.0" h11 = "0.12.0" -httpcore = "0.15.0" httptools = "0.4.0" httpx = "0.23.0" -idna = "3.2" -importlib-metadata = "4.8.1" -jinja2 = "3.0.1" +idna = "3.4" +importlib-metadata = "^4.8.1" +jinja2 = "3.0.3" lnurl = "0.3.6" -markupsafe = "2.0.1" -marshmallow = "3.17.0" -outcome = "1.1.0" -psycopg2-binary = "2.9.1" +markupsafe = "2.1.1" +marshmallow = "3.18.0" +outcome = "1.2.0" +psycopg2-binary = "2.9.3" pycryptodomex = "3.14.1" -pydantic = "1.8.2" +pydantic = "1.10.2" pypng = "0.0.21" pyqrcode = "1.2.1" -pyscss = "1.3.7" -python-dotenv = "0.19.0" +pyScss = "1.4.0" +python-dotenv = "0.21.0" pyyaml = "5.4.1" represent = "1.6.0.post0" rfc3986 = "1.5.0" secp256k1 = "0.14.0" shortuuid = "1.0.1" six = "1.16.0" -sniffio = "1.2.0" -sqlalchemy = "1.3.23" +sniffio = "1.3.0" +sqlalchemy = "1.3.24" sqlalchemy-aio = "0.17.0" sse-starlette = "0.6.2" -typing-extensions = "3.10.0.2" -uvicorn = "0.18.1" +typing-extensions = "4.3.0" +uvicorn = "0.18.3" uvloop = "0.16.0" watchgod = "0.7" websockets = "10.0" -zipp = "3.5.0" -loguru = "0.5.3" -cffi = "1.15.0" +zipp = "^3.5.0" +loguru = "0.6.0" +cffi = "1.15.1" websocket-client = "1.3.3" +grpcio = "^1.49.1" +protobuf = "^4.21.6" +pyln-client = "^0.12.0" +httpcore = "0.15.0" +cashu = {path = "../cashu/dist/cashu-0.1.11-py3-none-any.whl"} [tool.poetry.dev-dependencies] isort = "^5.10.1" From 1e61a05e202c8eed6271d1af3c3007e7e1a49350 Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Thu, 29 Sep 2022 20:42:13 +0200 Subject: [PATCH 0014/1058] Revert "adjust versions" This reverts commit 4303af4f1456040f922c6283f1415052a8308ab5. --- lnbits/extensions/cashu/__init__.py | 5 +- lnbits/extensions/cashu/config.json | 8 +- poetry.lock | 1305 +++++++++------------------ pyproject.toml | 56 +- 4 files changed, 473 insertions(+), 901 deletions(-) diff --git a/lnbits/extensions/cashu/__init__.py b/lnbits/extensions/cashu/__init__.py index d1a1d09c..fa549ad2 100644 --- a/lnbits/extensions/cashu/__init__.py +++ b/lnbits/extensions/cashu/__init__.py @@ -6,12 +6,9 @@ from lnbits.db import Database from lnbits.helpers import template_renderer from lnbits.tasks import catch_everything_and_restart -from cashu.mint.router import router as cashu_router - db = Database("ext_cashu") -cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["cashu"]) -cashu_ext.include_router(router=cashu_router) +cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["TPoS"]) def cashu_renderer(): diff --git a/lnbits/extensions/cashu/config.json b/lnbits/extensions/cashu/config.json index d242a3a7..c688b22c 100644 --- a/lnbits/extensions/cashu/config.json +++ b/lnbits/extensions/cashu/config.json @@ -1,6 +1,6 @@ { - "name": "Cashu Mint", - "short_description": "Chaumian Ecash mint", - "icon": "donut_small_rounded", - "contributors": ["calle"] + "name": "Cashu Ecash", + "short_description": "Ecash mints with LN peg in/out", + "icon": "approval", + "contributors": ["shinobi", "arcbtc", "calle"] } diff --git a/poetry.lock b/poetry.lock index ac75c80a..975c62b2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -20,56 +20,45 @@ sniffio = ">=1.1" typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] -doc = ["packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"] -test = ["contextlib2", "coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "mock (>=4)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "uvloop (>=0.15)"] +doc = ["packaging", "sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "contextlib2", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] trio = ["trio (>=0.16)"] [[package]] name = "asgiref" -version = "3.5.2" +version = "3.4.1" description = "ASGI specs, helper code, and adapters" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" [package.dependencies] typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] -tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] +tests = ["pytest", "pytest-asyncio", "mypy (>=0.800)"] [[package]] -name = "asn1crypto" -version = "1.5.1" -description = "Fast ASN.1 parser and serializer with definitions for private keys, public keys, certificates, CRL, OCSP, CMS, PKCS#3, PKCS#7, PKCS#8, PKCS#12, PKCS#5, X.509 and TSP" -category = "main" +name = "atomicwrites" +version = "1.4.1" +description = "Atomic file writes." +category = "dev" optional = false -python-versions = "*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "22.1.0" +version = "21.2.0" description = "Classes Without Boilerplate" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [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"] - -[[package]] -name = "base58" -version = "2.1.1" -description = "Base58 and Base58Check implementation." -category = "main" -optional = false -python-versions = ">=3.5" - -[package.extras] -tests = ["PyHamcrest (>=2.0.2)", "mypy", "pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-flake8"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] [[package]] name = "bech32" @@ -89,7 +78,7 @@ python-versions = "*" [[package]] name = "black" -version = "22.8.0" +version = "22.6.0" description = "The uncompromising code formatter." category = "dev" optional = false @@ -111,84 +100,24 @@ jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] -name = "cashu" -version = "0.1.11" -description = "Ecash wallet and mint with Bitcoin Lightning support" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -anyio = {version = "3.6.1", 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\""} -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\""} -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\""} -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\""} -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 = "4.12.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\""} -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\""} -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\""} -pluggy = {version = "1.0.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} -psycopg2-binary = {version = "2.9.3", 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\""} -pytest = {version = "7.1.3", 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-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\""} -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\""} -typing-extensions = {version = "4.3.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\""} -uvicorn = {version = "0.18.3", 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.8.1", markers = "python_version >= \"3.7\" and python_version < \"3.8\""} - -[package.source] -type = "file" -url = "../cashu/dist/cashu-0.1.11-py3-none-any.whl" - -[[package]] -name = "Cerberus" +name = "cerberus" version = "1.3.4" description = "Lightweight, extensible schema and data validation tool for Python dictionaries." category = "main" optional = false python-versions = ">=2.7" -[package.dependencies] -setuptools = "*" - [[package]] name = "certifi" -version = "2022.9.24" +version = "2021.5.30" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false -python-versions = ">=3.6" +python-versions = "*" [[package]] name = "cffi" -version = "1.15.1" +version = "1.15.0" description = "Foreign Function Interface for Python calling C code." category = "main" optional = false @@ -199,7 +128,7 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "2.0.12" +version = "2.0.6" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." category = "main" optional = false @@ -210,7 +139,7 @@ unicode_backport = ["unicodedata2"] [[package]] name = "click" -version = "8.0.4" +version = "8.0.1" description = "Composable command line interface toolkit" category = "main" optional = false @@ -220,18 +149,6 @@ python-versions = ">=3.6" colorama = {version = "*", markers = "platform_system == \"Windows\""} importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} -[[package]] -name = "coincurve" -version = "17.0.0" -description = "Cross-platform Python CFFI bindings for libsecp256k1" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -asn1crypto = "*" -cffi = ">=1.3.0" - [[package]] name = "colorama" version = "0.4.5" @@ -242,7 +159,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "coverage" -version = "6.4.4" +version = "6.4.2" description = "Code coverage measurement for Python" category = "dev" optional = false @@ -254,28 +171,9 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] -[[package]] -name = "cryptography" -version = "36.0.2" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -category = "main" -optional = false -python-versions = ">=3.6" - -[package.dependencies] -cffi = ">=1.12" - -[package.extras] -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)"] -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"] - [[package]] name = "ecdsa" -version = "0.18.0" +version = "0.17.0" description = "ECDSA cryptographic signature library (pure python)" category = "main" optional = false @@ -296,17 +194,9 @@ category = "main" optional = false python-versions = "*" -[[package]] -name = "enum34" -version = "1.1.10" -description = "Python 3.4 Enum backported to 3.3, 3.2, 3.1, 2.7, 2.6, 2.5, and 2.4" -category = "main" -optional = false -python-versions = "*" - [[package]] name = "environs" -version = "9.5.0" +version = "9.3.3" description = "simplified environment variable parsing" category = "main" optional = false @@ -317,14 +207,14 @@ marshmallow = ">=3.0.0" python-dotenv = "*" [package.extras] -dev = ["dj-database-url", "dj-email-url", "django-cache-url", "flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)", "pytest", "tox"] +dev = ["pytest", "dj-database-url", "dj-email-url", "django-cache-url", "flake8 (==3.9.2)", "flake8-bugbear (==21.4.3)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)", "tox"] 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"] +lint = ["flake8 (==3.9.2)", "flake8-bugbear (==21.4.3)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)"] +tests = ["pytest", "dj-database-url", "dj-email-url", "django-cache-url"] [[package]] name = "fastapi" -version = "0.83.0" +version = "0.78.0" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false @@ -335,24 +225,10 @@ pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1. starlette = "0.19.1" [package.extras] -all = ["email_validator (>=1.1.1,<2.0.0)", "itsdangerous (>=1.1.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "orjson (>=3.2.1,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "pyyaml (>=5.3.1,<7.0.0)", "requests (>=2.24.0,<3.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] -dev = ["autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "pre-commit (>=2.17.0,<3.0.0)", "python-jose[cryptography] (>=3.3.0,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] -doc = ["mdx-include (>=1.4.1,<2.0.0)", "mkdocs (>=1.1.2,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "typer (>=0.4.1,<0.5.0)"] -test = ["anyio[trio] (>=3.2.1,<4.0.0)", "black (==22.3.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "email_validator (>=1.1.1,<2.0.0)", "flake8 (>=3.8.3,<6.0.0)", "flask (>=1.1.2,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "isort (>=5.0.6,<6.0.0)", "mypy (==0.910)", "orjson (>=3.2.1,<4.0.0)", "peewee (>=3.13.3,<4.0.0)", "pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "requests (>=2.24.0,<3.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "types-dataclasses (==0.6.5)", "types-orjson (==3.6.2)", "types-ujson (==4.2.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)"] - -[[package]] -name = "grpcio" -version = "1.49.1" -description = "HTTP/2-based RPC framework" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.dependencies] -six = ">=1.5.2" - -[package.extras] -protobuf = ["grpcio-tools (>=1.49.1)"] +all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<7.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)"] +dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.18.0)", "pre-commit (>=2.17.0,<3.0.0)"] +doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=8.1.4,<9.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer (>=0.4.1,<0.5.0)", "pyyaml (>=5.3.1,<7.0.0)"] +test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==22.3.0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0,<6.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==4.2.1)", "types-orjson (==3.6.2)", "types-dataclasses (==0.6.5)"] [[package]] name = "h11" @@ -406,14 +282,14 @@ rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} sniffio = "*" [package.extras] -brotli = ["brotli", "brotlicffi"] -cli = ["click (>=8.0.0,<9.0.0)", "pygments (>=2.0.0,<3.0.0)", "rich (>=10,<13)"] +brotli = ["brotlicffi", "brotli"] +cli = ["click (>=8.0.0,<9.0.0)", "rich (>=10,<13)", "pygments (>=2.0.0,<3.0.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (>=1.0.0,<2.0.0)"] [[package]] name = "idna" -version = "3.4" +version = "3.2" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false @@ -421,26 +297,26 @@ python-versions = ">=3.5" [[package]] name = "importlib-metadata" -version = "4.12.0" +version = "4.8.1" description = "Read metadata from Python packages" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" [package.dependencies] typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} zipp = ">=0.5" [package.extras] -docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] perf = ["ipython"] -testing = ["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)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "iniconfig" version = "1.1.1" description = "iniconfig: brain-dead simple config-ini parsing" -category = "main" +category = "dev" optional = false python-versions = "*" @@ -453,14 +329,14 @@ optional = false python-versions = ">=3.6.1,<4.0" [package.extras] -colors = ["colorama (>=0.4.3,<0.5.0)"] pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] +colors = ["colorama (>=0.4.3,<0.5.0)"] plugins = ["setuptools"] -requirements_deprecated_finder = ["pip-api", "pipreqs"] [[package]] -name = "Jinja2" -version = "3.0.3" +name = "jinja2" +version = "3.0.1" description = "A very fast and expressive template engine." category = "main" optional = false @@ -487,7 +363,7 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "loguru" -version = "0.6.0" +version = "0.5.3" description = "Python logging made (stupidly) simple" category = "main" optional = false @@ -498,19 +374,19 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""} win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""} [package.extras] -dev = ["Sphinx (>=4.1.1)", "black (>=19.10b0)", "colorama (>=0.3.4)", "docutils (==0.16)", "flake8 (>=3.7.7)", "isort (>=5.1.1)", "pytest (>=4.6.2)", "pytest-cov (>=2.7.1)", "sphinx-autobuild (>=0.7.1)", "sphinx-rtd-theme (>=0.4.3)", "tox (>=3.9.0)"] +dev = ["isort (>=5.1.1)", "black (>=19.10b0)", "sphinx-rtd-theme (>=0.4.3)", "sphinx-autobuild (>=0.7.1)", "Sphinx (>=2.2.1)", "pytest-cov (>=2.7.1)", "pytest (>=4.6.2)", "tox-travis (>=0.12)", "tox (>=3.9.0)", "flake8 (>=3.7.7)", "colorama (>=0.3.4)", "codecov (>=2.0.15)"] [[package]] -name = "MarkupSafe" -version = "2.1.1" +name = "markupsafe" +version = "2.0.1" description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" [[package]] name = "marshmallow" -version = "3.18.0" +version = "3.17.0" description = "A lightweight library for converting complex datatypes to and from native Python datatypes." category = "main" optional = false @@ -520,9 +396,9 @@ python-versions = ">=3.7" 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 = ["pytest", "pytz", "simplejson", "mypy (==0.961)", "flake8 (==4.0.1)", "flake8-bugbear (==22.6.22)", "pre-commit (>=2.4,<3.0)", "tox"] +docs = ["sphinx (==4.5.0)", "sphinx-issues (==3.0.1)", "alabaster (==0.7.12)", "sphinx-version-warning (==1.1.2)", "autodocsumm (==0.2.8)"] +lint = ["mypy (==0.961)", "flake8 (==4.0.1)", "flake8-bugbear (==22.6.22)", "pre-commit (>=2.4,<3.0)"] tests = ["pytest", "pytz", "simplejson"] [[package]] @@ -534,7 +410,7 @@ optional = false python-versions = ">=3.6" [package.extras] -build = ["blurb", "twine", "wheel"] +build = ["twine", "wheel", "blurb"] docs = ["sphinx"] test = ["pytest (<5.4)", "pytest-cov"] @@ -567,11 +443,11 @@ python-versions = "*" [[package]] name = "outcome" -version = "1.2.0" +version = "1.1.0" description = "Capture the outcome of Python function calls." category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" [package.dependencies] attrs = ">=19.2.0" @@ -587,24 +463,13 @@ python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2,<3.0.5 || >3.0.5" -[[package]] -name = "pathlib2" -version = "2.3.7.post1" -description = "Object-oriented filesystem paths" -category = "main" -optional = false -python-versions = "*" - -[package.dependencies] -six = "*" - [[package]] name = "pathspec" -version = "0.10.1" +version = "0.9.0" description = "Utility library for gitignore style pattern matching of file paths." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [[package]] name = "platformdirs" @@ -615,14 +480,14 @@ optional = false python-versions = ">=3.7" [package.extras] -docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx (>=4)", "sphinx-autodoc-typehints (>=1.12)"] -test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] +docs = ["furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)", "sphinx (>=4)"] +test = ["appdirs (==1.4.4)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)", "pytest (>=6)"] [[package]] name = "pluggy" version = "1.0.0" description = "plugin and hook calling mechanisms for python" -category = "main" +category = "dev" optional = false python-versions = ">=3.6" @@ -630,20 +495,12 @@ python-versions = ">=3.6" importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} [package.extras] -dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] - -[[package]] -name = "protobuf" -version = "4.21.6" -description = "" -category = "main" -optional = false -python-versions = ">=3.7" +testing = ["pytest-benchmark", "pytest"] +dev = ["tox", "pre-commit"] [[package]] name = "psycopg2-binary" -version = "2.9.3" +version = "2.9.1" description = "psycopg2 - Python-PostgreSQL Database Adapter" category = "main" optional = false @@ -653,7 +510,7 @@ python-versions = ">=3.6" name = "py" version = "1.11.0" description = "library with cross-python path, ini-parsing, io, code, log facilities" -category = "main" +category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" @@ -675,54 +532,19 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [[package]] name = "pydantic" -version = "1.10.2" -description = "Data validation and settings management using python type hints" +version = "1.8.2" +description = "Data validation and settings management using python 3.6 type hinting" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6.1" [package.dependencies] -typing-extensions = ">=4.1.0" +typing-extensions = ">=3.7.4.3" [package.extras] dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] -[[package]] -name = "pyln-bolt7" -version = "1.0.246" -description = "BOLT7" -category = "main" -optional = false -python-versions = ">=3.7,<4.0" - -[[package]] -name = "pyln-client" -version = "0.12.1" -description = "Client library and plugin library for Core Lightning" -category = "main" -optional = false -python-versions = ">=3.7,<4.0" - -[package.dependencies] -pyln-bolt7 = ">=1.0" -pyln-proto = ">=0.12" - -[[package]] -name = "pyln-proto" -version = "0.12.0" -description = "This package implements some of the Lightning Network protocol in pure python. It is intended for protocol testing and some minor tooling only. It is not deemed secure enough to handle any amount of real funds (you have been warned!)." -category = "main" -optional = false -python-versions = ">=3.7,<4.0" - -[package.dependencies] -base58 = ">=2.1.1,<3.0.0" -bitstring = ">=3.1.9,<4.0.0" -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" @@ -732,7 +554,7 @@ optional = false python-versions = ">=3.6.8" [package.extras] -diagrams = ["jinja2", "railroad-diagrams"] +diagrams = ["railroad-diagrams", "jinja2"] [[package]] name = "pypng" @@ -743,7 +565,7 @@ optional = false python-versions = "*" [[package]] -name = "PyQRCode" +name = "pyqrcode" version = "1.2.1" description = "A QR code generator written purely in Python with SVG, EPS, PNG and terminal output." category = "main" @@ -754,35 +576,26 @@ python-versions = "*" PNG = ["pypng (>=0.0.13)"] [[package]] -name = "pyScss" -version = "1.4.0" +name = "pyscss" +version = "1.3.7" description = "pyScss, a Scss compiler for Python" category = "main" optional = false python-versions = "*" [package.dependencies] -enum34 = "*" -pathlib2 = "*" six = "*" -[[package]] -name = "PySocks" -version = "1.7.1" -description = "A Python SOCKS client module. See https://github.com/Anorov/PySocks for more information." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" - [[package]] name = "pytest" -version = "7.1.3" +version = "7.1.2" description = "pytest: simple powerful testing with Python" -category = "main" +category = "dev" optional = false python-versions = ">=3.7" [package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} @@ -799,7 +612,7 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2. name = "pytest-asyncio" version = "0.19.0" description = "Pytest support for asyncio" -category = "main" +category = "dev" optional = false python-versions = ">=3.7" @@ -808,7 +621,7 @@ pytest = ">=6.1.0" typing-extensions = {version = ">=3.7.2", markers = "python_version < \"3.8\""} [package.extras] -testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)", "flaky (>=3.5.0)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] [[package]] name = "pytest-cov" @@ -823,21 +636,21 @@ coverage = {version = ">=5.2.1", extras = ["toml"]} pytest = ">=4.6" [package.extras] -testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +testing = ["virtualenv", "pytest-xdist", "six", "process-tests", "hunter", "fields"] [[package]] name = "python-dotenv" -version = "0.21.0" +version = "0.19.0" description = "Read key-value pairs from a .env file and set them as environment variables" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.5" [package.extras] cli = ["click (>=5.0)"] [[package]] -name = "PyYAML" +name = "pyyaml" version = "5.4.1" description = "YAML parser and emitter for Python" category = "main" @@ -845,7 +658,7 @@ optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [[package]] -name = "Represent" +name = "represent" version = "1.6.0.post0" description = "Create __repr__ automatically or declaratively." category = "main" @@ -856,25 +669,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" six = ">=1.8.0" [package.extras] -test = ["ipython", "mock", "pytest (>=3.0.5)"] - -[[package]] -name = "requests" -version = "2.27.1" -description = "Python HTTP for Humans." -category = "main" -optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" - -[package.dependencies] -certifi = ">=2017.4.17" -charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} -idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} -urllib3 = ">=1.21.1,<1.27" - -[package.extras] -socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] +test = ["ipython", "pytest (>=3.0.5)", "mock"] [[package]] name = "rfc3986" @@ -901,19 +696,6 @@ python-versions = "*" [package.dependencies] cffi = ">=1.3.0" -[[package]] -name = "setuptools" -version = "65.4.0" -description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "main" -optional = false -python-versions = ">=3.7" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "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)", "mock", "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-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"] - [[package]] name = "shortuuid" version = "1.0.1" @@ -932,15 +714,15 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "sniffio" -version = "1.3.0" +version = "1.2.0" description = "Sniff out which async library your code is running under" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.5" [[package]] -name = "SQLAlchemy" -version = "1.3.24" +name = "sqlalchemy" +version = "1.3.23" description = "Database Abstraction Library" category = "main" optional = false @@ -951,12 +733,12 @@ 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"] postgresql_psycopg2cffi = ["psycopg2cffi"] -pymysql = ["pymysql", "pymysql (<1)"] +pymysql = ["pymysql (<1)", "pymysql"] [[package]] name = "sqlalchemy-aio" @@ -1003,7 +785,7 @@ full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "main" +category = "dev" optional = false python-versions = ">=3.7" @@ -1017,7 +799,7 @@ python-versions = ">=3.6" [[package]] name = "types-protobuf" -version = "3.20.4" +version = "3.19.22" description = "Typing stubs for protobuf" category = "dev" optional = false @@ -1025,28 +807,15 @@ python-versions = "*" [[package]] name = "typing-extensions" -version = "4.3.0" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "3.10.0.2" +description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" optional = false -python-versions = ">=3.7" - -[[package]] -name = "urllib3" -version = "1.26.12" -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" - -[package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +python-versions = "*" [[package]] name = "uvicorn" -version = "0.18.3" +version = "0.18.1" description = "The lightning-fast ASGI server." category = "main" optional = false @@ -1058,7 +827,7 @@ h11 = ">=0.8" typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [package.extras] -standard = ["colorama (>=0.4)", "httptools (>=0.4.0)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "watchfiles (>=0.13)", "websockets (>=10.0)"] +standard = ["websockets (>=10.0)", "httptools (>=0.4.0)", "watchfiles (>=0.13)", "python-dotenv (>=0.13)", "PyYAML (>=5.1)", "uvloop (>=0.14.0,!=0.15.0,!=0.15.1)", "colorama (>=0.4)"] [[package]] name = "uvloop" @@ -1069,9 +838,9 @@ optional = false python-versions = ">=3.7" [package.extras] -dev = ["Cython (>=0.29.24,<0.30.0)", "Sphinx (>=4.1.2,<4.2.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=19.0.0,<19.1.0)", "pycodestyle (>=2.7.0,<2.8.0)", "pytest (>=3.6.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=19.0.0,<19.1.0)", "pycodestyle (>=2.7.0,<2.8.0)"] +dev = ["Cython (>=0.29.24,<0.30.0)", "pytest (>=3.6.0)", "Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] +docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)"] +test = ["aiohttp", "flake8 (>=3.9.2,<3.10.0)", "psutil", "pycodestyle (>=2.7.0,<2.8.0)", "pyOpenSSL (>=19.0.0,<19.1.0)", "mypy (>=0.800)"] [[package]] name = "watchgod" @@ -1115,20 +884,20 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [[package]] name = "zipp" -version = "3.8.1" +version = "3.5.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false -python-versions = ">=3.7" +python-versions = ">=3.6" [package.extras] -docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx"] -testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" python-versions = "^3.9 | ^3.8 | ^3.7" -content-hash = "0b5a58944599b4218ce2f74e1d101002d7b97072b9069d0e32772fb23d35da69" +content-hash = "cadb8f2e46f0c083e91956f4f0f70b53b6c106f1c0b47972b57132dfee357367" [metadata.files] aiofiles = [ @@ -1140,20 +909,15 @@ anyio = [ {file = "anyio-3.6.1.tar.gz", hash = "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b"}, ] asgiref = [ - {file = "asgiref-3.5.2-py3-none-any.whl", hash = "sha256:1d2880b792ae8757289136f1db2b7b99100ce959b2aa57fd69dab783d05afac4"}, - {file = "asgiref-3.5.2.tar.gz", hash = "sha256:4a29362a6acebe09bf1d6640db38c1dc3d9217c68e6f9f6204d72667fc19a424"}, + {file = "asgiref-3.4.1-py3-none-any.whl", hash = "sha256:ffc141aa908e6f175673e7b1b3b7af4fdb0ecb738fc5c8b88f69f055c2415214"}, + {file = "asgiref-3.4.1.tar.gz", hash = "sha256:4ef1ab46b484e3c706329cedeff284a5d40824200638503f5768edb6de7d58e9"}, ] -asn1crypto = [ - {file = "asn1crypto-1.5.1-py2.py3-none-any.whl", hash = "sha256:db4e40728b728508912cbb3d44f19ce188f218e9eba635821bb4b68564f8fd67"}, - {file = "asn1crypto-1.5.1.tar.gz", hash = "sha256:13ae38502be632115abf8a24cbe5f4da52e3b5231990aff31123c805306ccb9c"}, +atomicwrites = [ + {file = "atomicwrites-1.4.1.tar.gz", hash = "sha256:81b2c9071a49367a7f770170e5eec8cb66567cfbbc8c73d20ce5ca4a8d71cf11"}, ] attrs = [ - {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, - {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, -] -base58 = [ - {file = "base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2"}, - {file = "base58-2.1.1.tar.gz", hash = "sha256:c5d0cb3f5b6e81e8e35da5754388ddcc6d0d14b6c6a132cb93d69ed580a7278c"}, + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] bech32 = [ {file = "bech32-1.2.0-py3-none-any.whl", hash = "sha256:990dc8e5a5e4feabbdf55207b5315fdd9b73db40be294a19b3752cde9e79d981"}, @@ -1165,294 +929,158 @@ bitstring = [ {file = "bitstring-3.1.9.tar.gz", hash = "sha256:a5848a3f63111785224dca8bb4c0a75b62ecdef56a042c8d6be74b16f7e860e7"}, ] black = [ - {file = "black-22.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ce957f1d6b78a8a231b18e0dd2d94a33d2ba738cd88a7fe64f53f659eea49fdd"}, - {file = "black-22.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5107ea36b2b61917956d018bd25129baf9ad1125e39324a9b18248d362156a27"}, - {file = "black-22.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e8166b7bfe5dcb56d325385bd1d1e0f635f24aae14b3ae437102dedc0c186747"}, - {file = "black-22.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd82842bb272297503cbec1a2600b6bfb338dae017186f8f215c8958f8acf869"}, - {file = "black-22.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d839150f61d09e7217f52917259831fe2b689f5c8e5e32611736351b89bb2a90"}, - {file = "black-22.8.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:a05da0430bd5ced89176db098567973be52ce175a55677436a271102d7eaa3fe"}, - {file = "black-22.8.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a098a69a02596e1f2a58a2a1c8d5a05d5a74461af552b371e82f9fa4ada8342"}, - {file = "black-22.8.0-cp36-cp36m-win_amd64.whl", hash = "sha256:5594efbdc35426e35a7defa1ea1a1cb97c7dbd34c0e49af7fb593a36bd45edab"}, - {file = "black-22.8.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a983526af1bea1e4cf6768e649990f28ee4f4137266921c2c3cee8116ae42ec3"}, - {file = "black-22.8.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b2c25f8dea5e8444bdc6788a2f543e1fb01494e144480bc17f806178378005e"}, - {file = "black-22.8.0-cp37-cp37m-win_amd64.whl", hash = "sha256:78dd85caaab7c3153054756b9fe8c611efa63d9e7aecfa33e533060cb14b6d16"}, - {file = "black-22.8.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:cea1b2542d4e2c02c332e83150e41e3ca80dc0fb8de20df3c5e98e242156222c"}, - {file = "black-22.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5b879eb439094751185d1cfdca43023bc6786bd3c60372462b6f051efa6281a5"}, - {file = "black-22.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0a12e4e1353819af41df998b02c6742643cfef58282915f781d0e4dd7a200411"}, - {file = "black-22.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3a73f66b6d5ba7288cd5d6dad9b4c9b43f4e8a4b789a94bf5abfb878c663eb3"}, - {file = "black-22.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:e981e20ec152dfb3e77418fb616077937378b322d7b26aa1ff87717fb18b4875"}, - {file = "black-22.8.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8ce13ffed7e66dda0da3e0b2eb1bdfc83f5812f66e09aca2b0978593ed636b6c"}, - {file = "black-22.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:32a4b17f644fc288c6ee2bafdf5e3b045f4eff84693ac069d87b1a347d861497"}, - {file = "black-22.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ad827325a3a634bae88ae7747db1a395d5ee02cf05d9aa7a9bd77dfb10e940c"}, - {file = "black-22.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53198e28a1fb865e9fe97f88220da2e44df6da82b18833b588b1883b16bb5d41"}, - {file = "black-22.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:bc4d4123830a2d190e9cc42a2e43570f82ace35c3aeb26a512a2102bce5af7ec"}, - {file = "black-22.8.0-py3-none-any.whl", hash = "sha256:d2c21d439b2baf7aa80d6dd4e3659259be64c6f49dfd0f32091063db0e006db4"}, - {file = "black-22.8.0.tar.gz", hash = "sha256:792f7eb540ba9a17e8656538701d3eb1afcb134e3b45b71f20b25c77a8db7e6e"}, + {file = "black-22.6.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f586c26118bc6e714ec58c09df0157fe2d9ee195c764f630eb0d8e7ccce72e69"}, + {file = "black-22.6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b270a168d69edb8b7ed32c193ef10fd27844e5c60852039599f9184460ce0807"}, + {file = "black-22.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6797f58943fceb1c461fb572edbe828d811e719c24e03375fd25170ada53825e"}, + {file = "black-22.6.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c85928b9d5f83b23cee7d0efcb310172412fbf7cb9d9ce963bd67fd141781def"}, + {file = "black-22.6.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6fe02afde060bbeef044af7996f335fbe90b039ccf3f5eb8f16df8b20f77666"}, + {file = "black-22.6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:cfaf3895a9634e882bf9d2363fed5af8888802d670f58b279b0bece00e9a872d"}, + {file = "black-22.6.0-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94783f636bca89f11eb5d50437e8e17fbc6a929a628d82304c80fa9cd945f256"}, + {file = "black-22.6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2ea29072e954a4d55a2ff58971b83365eba5d3d357352a07a7a4df0d95f51c78"}, + {file = "black-22.6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e439798f819d49ba1c0bd9664427a05aab79bfba777a6db94fd4e56fae0cb849"}, + {file = "black-22.6.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:187d96c5e713f441a5829e77120c269b6514418f4513a390b0499b0987f2ff1c"}, + {file = "black-22.6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:074458dc2f6e0d3dab7928d4417bb6957bb834434516f21514138437accdbe90"}, + {file = "black-22.6.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a218d7e5856f91d20f04e931b6f16d15356db1c846ee55f01bac297a705ca24f"}, + {file = "black-22.6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:568ac3c465b1c8b34b61cd7a4e349e93f91abf0f9371eda1cf87194663ab684e"}, + {file = "black-22.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6c1734ab264b8f7929cef8ae5f900b85d579e6cbfde09d7387da8f04771b51c6"}, + {file = "black-22.6.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9a3ac16efe9ec7d7381ddebcc022119794872abce99475345c5a61aa18c45ad"}, + {file = "black-22.6.0-cp38-cp38-win_amd64.whl", hash = "sha256:b9fd45787ba8aa3f5e0a0a98920c1012c884622c6c920dbe98dbd05bc7c70fbf"}, + {file = "black-22.6.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7ba9be198ecca5031cd78745780d65a3f75a34b2ff9be5837045dce55db83d1c"}, + {file = "black-22.6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a3db5b6409b96d9bd543323b23ef32a1a2b06416d525d27e0f67e74f1446c8f2"}, + {file = "black-22.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:560558527e52ce8afba936fcce93a7411ab40c7d5fe8c2463e279e843c0328ee"}, + {file = "black-22.6.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b154e6bbde1e79ea3260c4b40c0b7b3109ffcdf7bc4ebf8859169a6af72cd70b"}, + {file = "black-22.6.0-cp39-cp39-win_amd64.whl", hash = "sha256:4af5bc0e1f96be5ae9bd7aaec219c901a94d6caa2484c21983d043371c733fc4"}, + {file = "black-22.6.0-py3-none-any.whl", hash = "sha256:ac609cf8ef5e7115ddd07d85d988d074ed00e10fbc3445aee393e70164a2219c"}, + {file = "black-22.6.0.tar.gz", hash = "sha256:6c6d39e28aed379aec40da1c65434c77d75e65bb59a1e1c283de545fb4e7c6c9"}, ] -cashu = [ - {file = "cashu-0.1.11-py3-none-any.whl", hash = "sha256:d2c5a72648fa4487fdf694e5669dfaa8d62445d83cced33b5bc63eccbce6a00c"}, -] -Cerberus = [ +cerberus = [ {file = "Cerberus-1.3.4.tar.gz", hash = "sha256:d1b21b3954b2498d9a79edf16b3170a3ac1021df88d197dc2ce5928ba519237c"}, ] certifi = [ - {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"}, - {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"}, + {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, + {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, ] cffi = [ - {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, - {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, - {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, - {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, - {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, - {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, - {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, - {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, - {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, - {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, - {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, - {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, - {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, - {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, - {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, - {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, - {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, - {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, - {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, - {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, - {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, - {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, - {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, - {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, - {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, - {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, - {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, - {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, - {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, - {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, - {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, - {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, - {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, + {file = "cffi-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:c2502a1a03b6312837279c8c1bd3ebedf6c12c4228ddbad40912d671ccc8a962"}, + {file = "cffi-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:23cfe892bd5dd8941608f93348c0737e369e51c100d03718f108bf1add7bd6d0"}, + {file = "cffi-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:41d45de54cd277a7878919867c0f08b0cf817605e4eb94093e7516505d3c8d14"}, + {file = "cffi-1.15.0-cp27-cp27m-win32.whl", hash = "sha256:4a306fa632e8f0928956a41fa8e1d6243c71e7eb59ffbd165fc0b41e316b2474"}, + {file = "cffi-1.15.0-cp27-cp27m-win_amd64.whl", hash = "sha256:e7022a66d9b55e93e1a845d8c9eba2a1bebd4966cd8bfc25d9cd07d515b33fa6"}, + {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:14cd121ea63ecdae71efa69c15c5543a4b5fbcd0bbe2aad864baca0063cecf27"}, + {file = "cffi-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:d4d692a89c5cf08a8557fdeb329b82e7bf609aadfaed6c0d79f5a449a3c7c023"}, + {file = "cffi-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0104fb5ae2391d46a4cb082abdd5c69ea4eab79d8d44eaaf79f1b1fd806ee4c2"}, + {file = "cffi-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:91ec59c33514b7c7559a6acda53bbfe1b283949c34fe7440bcf917f96ac0723e"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f5c7150ad32ba43a07c4479f40241756145a1f03b43480e058cfd862bf5041c7"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:00c878c90cb53ccfaae6b8bc18ad05d2036553e6d9d1d9dbcf323bbe83854ca3"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abb9a20a72ac4e0fdb50dae135ba5e77880518e742077ced47eb1499e29a443c"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5263e363c27b653a90078143adb3d076c1a748ec9ecc78ea2fb916f9b861962"}, + {file = "cffi-1.15.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f54a64f8b0c8ff0b64d18aa76675262e1700f3995182267998c31ae974fbc382"}, + {file = "cffi-1.15.0-cp310-cp310-win32.whl", hash = "sha256:c21c9e3896c23007803a875460fb786118f0cdd4434359577ea25eb556e34c55"}, + {file = "cffi-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:5e069f72d497312b24fcc02073d70cb989045d1c91cbd53979366077959933e0"}, + {file = "cffi-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:64d4ec9f448dfe041705426000cc13e34e6e5bb13736e9fd62e34a0b0c41566e"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2756c88cbb94231c7a147402476be2c4df2f6078099a6f4a480d239a8817ae39"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b96a311ac60a3f6be21d2572e46ce67f09abcf4d09344c49274eb9e0bf345fc"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75e4024375654472cc27e91cbe9eaa08567f7fbdf822638be2814ce059f58032"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:59888172256cac5629e60e72e86598027aca6bf01fa2465bdb676d37636573e8"}, + {file = "cffi-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:27c219baf94952ae9d50ec19651a687b826792055353d07648a5695413e0c605"}, + {file = "cffi-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:4958391dbd6249d7ad855b9ca88fae690783a6be9e86df65865058ed81fc860e"}, + {file = "cffi-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f6f824dc3bce0edab5f427efcfb1d63ee75b6fcb7282900ccaf925be84efb0fc"}, + {file = "cffi-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:06c48159c1abed75c2e721b1715c379fa3200c7784271b3c46df01383b593636"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2051981a968d7de9dd2d7b87bcb9c939c74a34626a6e2f8181455dd49ed69e4"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91d77d2a782be4274da750752bb1650a97bfd8f291022b379bb8e01c66b4e96b"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:45db3a33139e9c8f7c09234b5784a5e33d31fd6907800b316decad50af323ff2"}, + {file = "cffi-1.15.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:263cc3d821c4ab2213cbe8cd8b355a7f72a8324577dc865ef98487c1aeee2bc7"}, + {file = "cffi-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:17771976e82e9f94976180f76468546834d22a7cc404b17c22df2a2c81db0c66"}, + {file = "cffi-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:3415c89f9204ee60cd09b235810be700e993e343a408693e80ce7f6a40108029"}, + {file = "cffi-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4238e6dab5d6a8ba812de994bbb0a79bddbdf80994e4ce802b6f6f3142fcc880"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0808014eb713677ec1292301ea4c81ad277b6cdf2fdd90fd540af98c0b101d20"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:57e9ac9ccc3101fac9d6014fba037473e4358ef4e89f8e181f8951a2c0162024"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b6c2ea03845c9f501ed1313e78de148cd3f6cad741a75d43a29b43da27f2e1e"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:10dffb601ccfb65262a27233ac273d552ddc4d8ae1bf93b21c94b8511bffe728"}, + {file = "cffi-1.15.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:786902fb9ba7433aae840e0ed609f45c7bcd4e225ebb9c753aa39725bb3e6ad6"}, + {file = "cffi-1.15.0-cp38-cp38-win32.whl", hash = "sha256:da5db4e883f1ce37f55c667e5c0de439df76ac4cb55964655906306918e7363c"}, + {file = "cffi-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:181dee03b1170ff1969489acf1c26533710231c58f95534e3edac87fff06c443"}, + {file = "cffi-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:45e8636704eacc432a206ac7345a5d3d2c62d95a507ec70d62f23cd91770482a"}, + {file = "cffi-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:31fb708d9d7c3f49a60f04cf5b119aeefe5644daba1cd2a0fe389b674fd1de37"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6dc2737a3674b3e344847c8686cf29e500584ccad76204efea14f451d4cc669a"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:74fdfdbfdc48d3f47148976f49fab3251e550a8720bebc99bf1483f5bfb5db3e"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f7d084648d77af029acb79a0ff49a0ad7e9d09057a9bf46596dac9514dc07df"}, + {file = "cffi-1.15.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef1f279350da2c586a69d32fc8733092fd32cc8ac95139a00377841f59a3f8d8"}, + {file = "cffi-1.15.0-cp39-cp39-win32.whl", hash = "sha256:2a23af14f408d53d5e6cd4e3d9a24ff9e05906ad574822a10563efcef137979a"}, + {file = "cffi-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:3773c4d81e6e818df2efbc7dd77325ca0dcb688116050fb2b3011218eda36139"}, + {file = "cffi-1.15.0.tar.gz", hash = "sha256:920f0d66a896c2d99f0adbb391f990a84091179542c205fa53ce5787aff87954"}, ] charset-normalizer = [ - {file = "charset-normalizer-2.0.12.tar.gz", hash = "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597"}, - {file = "charset_normalizer-2.0.12-py3-none-any.whl", hash = "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df"}, + {file = "charset-normalizer-2.0.6.tar.gz", hash = "sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f"}, + {file = "charset_normalizer-2.0.6-py3-none-any.whl", hash = "sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6"}, ] click = [ - {file = "click-8.0.4-py3-none-any.whl", hash = "sha256:6a7a62563bbfabfda3a38f3023a1db4a35978c0abd76f6c9605ecd6554d6d9b1"}, - {file = "click-8.0.4.tar.gz", hash = "sha256:8458d7b1287c5fb128c90e23381cf99dcde74beaf6c7ff6384ce84d6fe090adb"}, -] -coincurve = [ - {file = "coincurve-17.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac8c87d6fd080faa74e7ecf64a6ed20c11a254863238759eb02c3f13ad12b0c4"}, - {file = "coincurve-17.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:25dfa105beba24c8de886f8ed654bb1133866e4e22cfd7ea5ad8438cae6ed924"}, - {file = "coincurve-17.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:698efdd53e4fe1bbebaee9b75cbc851be617974c1c60098e9145cb7198ae97fb"}, - {file = "coincurve-17.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30dd44d1039f1d237aaa2da6d14a455ca88df3bcb00610b41f3253fdca1be97b"}, - {file = "coincurve-17.0.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d154e2eb5711db8c5ef52fcd80935b5a0e751c057bc6ffb215a7bb409aedef03"}, - {file = "coincurve-17.0.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c71caffb97dd3d0c243beb62352669b1e5dafa3a4bccdbb27d36bd82f5e65d20"}, - {file = "coincurve-17.0.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:747215254e51dd4dfbe6dded9235491263da5d88fe372d66541ca16b51ea078f"}, - {file = "coincurve-17.0.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad2f6df39ba1e2b7b14bb984505ffa7d0a0ecdd697e8d7dbd19e04bc245c87ed"}, - {file = "coincurve-17.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0503326963916c85b61d16f611ea0545f03c9e418fa8007c233c815429e381e8"}, - {file = "coincurve-17.0.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1013c1597b65684ae1c3e42497f9ef5a04527fa6136a84a16b34602606428c74"}, - {file = "coincurve-17.0.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4beef321fd6434448aab03a0c245f31c4e77f43b54b82108c0948d29852ac7e"}, - {file = "coincurve-17.0.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f47806527d3184da3e8b146fac92a8ed567bbd225194f4517943d8cdc85f9542"}, - {file = "coincurve-17.0.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:51e56373ac79f4ec1cfc5da53d72c55f5e5ac28d848b0849ef5e687ace857888"}, - {file = "coincurve-17.0.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:3d694ad194bee9e8792e2e75879dc5238d8a184010cde36c5ad518fcfe2cd8f2"}, - {file = "coincurve-17.0.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:74cedb3d3a1dc5abe0c9c2396e1b82cc64496babc5b42e007e72e185cb1edad8"}, - {file = "coincurve-17.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:db874c5c1dcb1f3a19379773b5e8cffc777625a7a7a60dd9a67206e31e62e2e9"}, - {file = "coincurve-17.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:896b01941254f0a218cf331a9bddfe2d43892f7f1ba10d6e372e2eb744a744c2"}, - {file = "coincurve-17.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6aec70238dbe7a5d66b5f9438ff45b08eb5e0990d49c32ebb65247c5d5b89d7a"}, - {file = "coincurve-17.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d24284d17162569df917a640f19d9654ba3b43cf560ced8864f270da903f73a5"}, - {file = "coincurve-17.0.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ea057f777842396d387103c606babeb3a1b4c6126769cc0a12044312fc6c465"}, - {file = "coincurve-17.0.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b88642edf7f281649b0c0b6ffade051945ccceae4b885e40445634877d0b3049"}, - {file = "coincurve-17.0.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a80a207131813b038351c5bdae8f20f5f774bbf53622081f208d040dd2b7528f"}, - {file = "coincurve-17.0.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f1ef72574aa423bc33665ef4be859164a478bad24d48442da874ef3dc39a474d"}, - {file = "coincurve-17.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dfd4fab857bcd975edc39111cb5f5c104f138dac2e9ace35ea8434d37bcea3be"}, - {file = "coincurve-17.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:73f39579dd651a9fc29da5a8fc0d8153d872bcbc166f876457baced1a1c01501"}, - {file = "coincurve-17.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8852dc01af4f0fe941ffd04069f7e4fecdce9b867a016f823a02286a1a1f07b5"}, - {file = "coincurve-17.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b1bef812da1da202cdd601a256825abcf26d86e8634fac3ec3e615e3bb3ff08c"}, - {file = "coincurve-17.0.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abbefc9ccb170cb255a31df32457c2e43084b9f37589d0694dacc2dea6ddaf7c"}, - {file = "coincurve-17.0.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:abbd9d017a7638dc38a3b9bb4851f8801b7818d4e5ac22e0c75e373b3c1dbff0"}, - {file = "coincurve-17.0.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e2c2e8a1f0b1f8e48049c891af4ae3cad65d115d358bde72f6b8abdbb8a23170"}, - {file = "coincurve-17.0.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c571445b166c714af4f8155e38a894376c16c0431e88963f2fff474a9985d87"}, - {file = "coincurve-17.0.0-py3-none-win32.whl", hash = "sha256:b956b0b2c85e25a7d00099970ff5d8338254b45e46f0a940f4a2379438ce0dde"}, - {file = "coincurve-17.0.0-py3-none-win_amd64.whl", hash = "sha256:630388080da3026e0b0176cc6762eaabecba857ee3fc85767577dea063ea7c6e"}, - {file = "coincurve-17.0.0.tar.gz", hash = "sha256:68da55aff898702952fda3ee04fd6ed60bb6b91f919c69270786ed766b548b93"}, + {file = "click-8.0.1-py3-none-any.whl", hash = "sha256:fba402a4a47334742d782209a7c79bc448911afe1149d07bdabdf480b3e2f4b6"}, + {file = "click-8.0.1.tar.gz", hash = "sha256:8c04c11192119b1ef78ea049e0a6f0463e4c48ef00a30160c704337586f3ad7a"}, ] colorama = [ {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, ] coverage = [ - {file = "coverage-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e7b4da9bafad21ea45a714d3ea6f3e1679099e420c8741c74905b92ee9bfa7cc"}, - {file = "coverage-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fde17bc42e0716c94bf19d92e4c9f5a00c5feb401f5bc01101fdf2a8b7cacf60"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdbb0d89923c80dbd435b9cf8bba0ff55585a3cdb28cbec65f376c041472c60d"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67f9346aeebea54e845d29b487eb38ec95f2ecf3558a3cffb26ee3f0dcc3e760"}, - {file = "coverage-6.4.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42c499c14efd858b98c4e03595bf914089b98400d30789511577aa44607a1b74"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c35cca192ba700979d20ac43024a82b9b32a60da2f983bec6c0f5b84aead635c"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9cc4f107009bca5a81caef2fca843dbec4215c05e917a59dec0c8db5cff1d2aa"}, - {file = "coverage-6.4.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f444627b3664b80d078c05fe6a850dd711beeb90d26731f11d492dcbadb6973"}, - {file = "coverage-6.4.4-cp310-cp310-win32.whl", hash = "sha256:66e6df3ac4659a435677d8cd40e8eb1ac7219345d27c41145991ee9bf4b806a0"}, - {file = "coverage-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:35ef1f8d8a7a275aa7410d2f2c60fa6443f4a64fae9be671ec0696a68525b875"}, - {file = "coverage-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c1328d0c2f194ffda30a45f11058c02410e679456276bfa0bbe0b0ee87225fac"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:61b993f3998ee384935ee423c3d40894e93277f12482f6e777642a0141f55782"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5dd4b8e9cd0deb60e6fcc7b0647cbc1da6c33b9e786f9c79721fd303994832f"}, - {file = "coverage-6.4.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7026f5afe0d1a933685d8f2169d7c2d2e624f6255fb584ca99ccca8c0e966fd7"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9c7b9b498eb0c0d48b4c2abc0e10c2d78912203f972e0e63e3c9dc21f15abdaa"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:ee2b2fb6eb4ace35805f434e0f6409444e1466a47f620d1d5763a22600f0f892"}, - {file = "coverage-6.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ab066f5ab67059d1f1000b5e1aa8bbd75b6ed1fc0014559aea41a9eb66fc2ce0"}, - {file = "coverage-6.4.4-cp311-cp311-win32.whl", hash = "sha256:9d6e1f3185cbfd3d91ac77ea065d85d5215d3dfa45b191d14ddfcd952fa53796"}, - {file = "coverage-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e3d3c4cc38b2882f9a15bafd30aec079582b819bec1b8afdbde8f7797008108a"}, - {file = "coverage-6.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a095aa0a996ea08b10580908e88fbaf81ecf798e923bbe64fb98d1807db3d68a"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef6f44409ab02e202b31a05dd6666797f9de2aa2b4b3534e9d450e42dea5e817"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b7101938584d67e6f45f0015b60e24a95bf8dea19836b1709a80342e01b472f"}, - {file = "coverage-6.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a32ec68d721c3d714d9b105c7acf8e0f8a4f4734c811eda75ff3718570b5e3"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:6a864733b22d3081749450466ac80698fe39c91cb6849b2ef8752fd7482011f3"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:08002f9251f51afdcc5e3adf5d5d66bb490ae893d9e21359b085f0e03390a820"}, - {file = "coverage-6.4.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a3b2752de32c455f2521a51bd3ffb53c5b3ae92736afde67ce83477f5c1dd928"}, - {file = "coverage-6.4.4-cp37-cp37m-win32.whl", hash = "sha256:f855b39e4f75abd0dfbcf74a82e84ae3fc260d523fcb3532786bcbbcb158322c"}, - {file = "coverage-6.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:ee6ae6bbcac0786807295e9687169fba80cb0617852b2fa118a99667e8e6815d"}, - {file = "coverage-6.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:564cd0f5b5470094df06fab676c6d77547abfdcb09b6c29c8a97c41ad03b103c"}, - {file = "coverage-6.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cbbb0e4cd8ddcd5ef47641cfac97d8473ab6b132dd9a46bacb18872828031685"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6113e4df2fa73b80f77663445be6d567913fb3b82a86ceb64e44ae0e4b695de1"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8d032bfc562a52318ae05047a6eb801ff31ccee172dc0d2504614e911d8fa83e"}, - {file = "coverage-6.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e431e305a1f3126477abe9a184624a85308da8edf8486a863601d58419d26ffa"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cf2afe83a53f77aec067033199797832617890e15bed42f4a1a93ea24794ae3e"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:783bc7c4ee524039ca13b6d9b4186a67f8e63d91342c713e88c1865a38d0892a"}, - {file = "coverage-6.4.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ff934ced84054b9018665ca3967fc48e1ac99e811f6cc99ea65978e1d384454b"}, - {file = "coverage-6.4.4-cp38-cp38-win32.whl", hash = "sha256:e1fabd473566fce2cf18ea41171d92814e4ef1495e04471786cbc943b89a3781"}, - {file = "coverage-6.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:4179502f210ebed3ccfe2f78bf8e2d59e50b297b598b100d6c6e3341053066a2"}, - {file = "coverage-6.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:98c0b9e9b572893cdb0a00e66cf961a238f8d870d4e1dc8e679eb8bdc2eb1b86"}, - {file = "coverage-6.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fc600f6ec19b273da1d85817eda339fb46ce9eef3e89f220055d8696e0a06908"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7a98d6bf6d4ca5c07a600c7b4e0c5350cd483c85c736c522b786be90ea5bac4f"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01778769097dbd705a24e221f42be885c544bb91251747a8a3efdec6eb4788f2"}, - {file = "coverage-6.4.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dfa0b97eb904255e2ab24166071b27408f1f69c8fbda58e9c0972804851e0558"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:fcbe3d9a53e013f8ab88734d7e517eb2cd06b7e689bedf22c0eb68db5e4a0a19"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:15e38d853ee224e92ccc9a851457fb1e1f12d7a5df5ae44544ce7863691c7a0d"}, - {file = "coverage-6.4.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6913dddee2deff8ab2512639c5168c3e80b3ebb0f818fed22048ee46f735351a"}, - {file = "coverage-6.4.4-cp39-cp39-win32.whl", hash = "sha256:354df19fefd03b9a13132fa6643527ef7905712109d9c1c1903f2133d3a4e145"}, - {file = "coverage-6.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:1238b08f3576201ebf41f7c20bf59baa0d05da941b123c6656e42cdb668e9827"}, - {file = "coverage-6.4.4-pp36.pp37.pp38-none-any.whl", hash = "sha256:f67cf9f406cf0d2f08a3515ce2db5b82625a7257f88aad87904674def6ddaec1"}, - {file = "coverage-6.4.4.tar.gz", hash = "sha256:e16c45b726acb780e1e6f88b286d3c10b3914ab03438f32117c4aa52d7f30d58"}, -] -cryptography = [ - {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:4e2dddd38a5ba733be6a025a1475a9f45e4e41139d1321f412c6b360b19070b6"}, - {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:4881d09298cd0b669bb15b9cfe6166f16fc1277b4ed0d04a22f3d6430cb30f1d"}, - {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea634401ca02367c1567f012317502ef3437522e2fc44a3ea1844de028fa4b84"}, - {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7be666cc4599b415f320839e36367b273db8501127b38316f3b9f22f17a0b815"}, - {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8241cac0aae90b82d6b5c443b853723bcc66963970c67e56e71a2609dc4b5eaf"}, - {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2d54e787a884ffc6e187262823b6feb06c338084bbe80d45166a1cb1c6c5bf"}, - {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:c2c5250ff0d36fd58550252f54915776940e4e866f38f3a7866d92b32a654b86"}, - {file = "cryptography-36.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ec6597aa85ce03f3e507566b8bcdf9da2227ec86c4266bd5e6ab4d9e0cc8dab2"}, - {file = "cryptography-36.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ca9f686517ec2c4a4ce930207f75c00bf03d94e5063cbc00a1dc42531511b7eb"}, - {file = "cryptography-36.0.2-cp36-abi3-win32.whl", hash = "sha256:f64b232348ee82f13aac22856515ce0195837f6968aeaa94a3d0353ea2ec06a6"}, - {file = "cryptography-36.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:53e0285b49fd0ab6e604f4c5d9c5ddd98de77018542e88366923f152dbeb3c29"}, - {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:32db5cc49c73f39aac27574522cecd0a4bb7384e71198bc65a0d23f901e89bb7"}, - {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b3d199647468d410994dbeb8cec5816fb74feb9368aedf300af709ef507e3e"}, - {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:da73d095f8590ad437cd5e9faf6628a218aa7c387e1fdf67b888b47ba56a17f0"}, - {file = "cryptography-36.0.2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:0a3bf09bb0b7a2c93ce7b98cb107e9170a90c51a0162a20af1c61c765b90e60b"}, - {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8897b7b7ec077c819187a123174b645eb680c13df68354ed99f9b40a50898f77"}, - {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82740818f2f240a5da8dfb8943b360e4f24022b093207160c77cadade47d7c85"}, - {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:1f64a62b3b75e4005df19d3b5235abd43fa6358d5516cfc43d87aeba8d08dd51"}, - {file = "cryptography-36.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e167b6b710c7f7bc54e67ef593f8731e1f45aa35f8a8a7b72d6e42ec76afd4b3"}, - {file = "cryptography-36.0.2.tar.gz", hash = "sha256:70f8f4f7bb2ac9f340655cbac89d68c527af5bb4387522a8413e841e3e6628c9"}, + {file = "coverage-6.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a9032f9b7d38bdf882ac9f66ebde3afb8145f0d4c24b2e600bc4c6304aafb87e"}, + {file = "coverage-6.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e0524adb49c716ca763dbc1d27bedce36b14f33e6b8af6dba56886476b42957c"}, + {file = "coverage-6.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4548be38a1c810d79e097a38107b6bf2ff42151900e47d49635be69943763d8"}, + {file = "coverage-6.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f23876b018dfa5d3e98e96f5644b109090f16a4acb22064e0f06933663005d39"}, + {file = "coverage-6.4.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fe75dcfcb889b6800f072f2af5a331342d63d0c1b3d2bf0f7b4f6c353e8c9c0"}, + {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2f8553878a24b00d5ab04b7a92a2af50409247ca5c4b7a2bf4eabe94ed20d3ee"}, + {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:d774d9e97007b018a651eadc1b3970ed20237395527e22cbeb743d8e73e0563d"}, + {file = "coverage-6.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d56f105592188ce7a797b2bd94b4a8cb2e36d5d9b0d8a1d2060ff2a71e6b9bbc"}, + {file = "coverage-6.4.2-cp310-cp310-win32.whl", hash = "sha256:d230d333b0be8042ac34808ad722eabba30036232e7a6fb3e317c49f61c93386"}, + {file = "coverage-6.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:5ef42e1db047ca42827a85e34abe973971c635f83aed49611b7f3ab49d0130f0"}, + {file = "coverage-6.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:25b7ec944f114f70803d6529394b64f8749e93cbfac0fe6c5ea1b7e6c14e8a46"}, + {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bb00521ab4f99fdce2d5c05a91bddc0280f0afaee0e0a00425e28e209d4af07"}, + {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2dff52b3e7f76ada36f82124703f4953186d9029d00d6287f17c68a75e2e6039"}, + {file = "coverage-6.4.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:147605e1702d996279bb3cc3b164f408698850011210d133a2cb96a73a2f7996"}, + {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:422fa44070b42fef9fb8dabd5af03861708cdd6deb69463adc2130b7bf81332f"}, + {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8af6c26ba8df6338e57bedbf916d76bdae6308e57fc8f14397f03b5da8622b4e"}, + {file = "coverage-6.4.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:5336e0352c0b12c7e72727d50ff02557005f79a0b8dcad9219c7c4940a930083"}, + {file = "coverage-6.4.2-cp37-cp37m-win32.whl", hash = "sha256:0f211df2cba951ffcae210ee00e54921ab42e2b64e0bf2c0befc977377fb09b7"}, + {file = "coverage-6.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a13772c19619118903d65a91f1d5fea84be494d12fd406d06c849b00d31bf120"}, + {file = "coverage-6.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f7bd0ffbcd03dc39490a1f40b2669cc414fae0c4e16b77bb26806a4d0b7d1452"}, + {file = "coverage-6.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0895ea6e6f7f9939166cc835df8fa4599e2d9b759b02d1521b574e13b859ac32"}, + {file = "coverage-6.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d4e7ced84a11c10160c0697a6cc0b214a5d7ab21dfec1cd46e89fbf77cc66fae"}, + {file = "coverage-6.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:80db4a47a199c4563d4a25919ff29c97c87569130375beca3483b41ad5f698e8"}, + {file = "coverage-6.4.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3def6791adf580d66f025223078dc84c64696a26f174131059ce8e91452584e1"}, + {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:4f89d8e03c8a3757aae65570d14033e8edf192ee9298303db15955cadcff0c63"}, + {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6d0b48aff8e9720bdec315d67723f0babd936a7211dc5df453ddf76f89c59933"}, + {file = "coverage-6.4.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2b20286c2b726f94e766e86a3fddb7b7e37af5d0c635bdfa7e4399bc523563de"}, + {file = "coverage-6.4.2-cp38-cp38-win32.whl", hash = "sha256:d714af0bdba67739598849c9f18efdcc5a0412f4993914a0ec5ce0f1e864d783"}, + {file = "coverage-6.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:5f65e5d3ff2d895dab76b1faca4586b970a99b5d4b24e9aafffc0ce94a6022d6"}, + {file = "coverage-6.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a697977157adc052284a7160569b36a8bbec09db3c3220642e6323b47cec090f"}, + {file = "coverage-6.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c77943ef768276b61c96a3eb854eba55633c7a3fddf0a79f82805f232326d33f"}, + {file = "coverage-6.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54d8d0e073a7f238f0666d3c7c0d37469b2aa43311e4024c925ee14f5d5a1cbe"}, + {file = "coverage-6.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f22325010d8824594820d6ce84fa830838f581a7fd86a9235f0d2ed6deb61e29"}, + {file = "coverage-6.4.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24b04d305ea172ccb21bee5bacd559383cba2c6fcdef85b7701cf2de4188aa55"}, + {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:866ebf42b4c5dbafd64455b0a1cd5aa7b4837a894809413b930026c91e18090b"}, + {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e36750fbbc422c1c46c9d13b937ab437138b998fe74a635ec88989afb57a3978"}, + {file = "coverage-6.4.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:79419370d6a637cb18553ecb25228893966bd7935a9120fa454e7076f13b627c"}, + {file = "coverage-6.4.2-cp39-cp39-win32.whl", hash = "sha256:b5e28db9199dd3833cc8a07fa6cf429a01227b5d429facb56eccd765050c26cd"}, + {file = "coverage-6.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:edfdabe7aa4f97ed2b9dd5dde52d2bb29cb466993bb9d612ddd10d0085a683cf"}, + {file = "coverage-6.4.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:e2618cb2cf5a7cc8d698306e42ebcacd02fb7ef8cfc18485c59394152c70be97"}, + {file = "coverage-6.4.2.tar.gz", hash = "sha256:6c3ccfe89c36f3e5b9837b9ee507472310164f352c9fe332120b764c9d60adbe"}, ] ecdsa = [ - {file = "ecdsa-0.18.0-py2.py3-none-any.whl", hash = "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd"}, - {file = "ecdsa-0.18.0.tar.gz", hash = "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49"}, + {file = "ecdsa-0.17.0-py2.py3-none-any.whl", hash = "sha256:5cf31d5b33743abe0dfc28999036c849a69d548f994b535e527ee3cb7f3ef676"}, + {file = "ecdsa-0.17.0.tar.gz", hash = "sha256:b9f500bb439e4153d0330610f5d26baaf18d17b8ced1bc54410d189385ea68aa"}, ] embit = [ {file = "embit-0.4.9.tar.gz", hash = "sha256:992332bd89af6e2d027e26fe437eb14aa33997db08c882c49064d49c3e6f4ab9"}, ] -enum34 = [ - {file = "enum34-1.1.10-py2-none-any.whl", hash = "sha256:a98a201d6de3f2ab3db284e70a33b0f896fbf35f8086594e8c9e74b909058d53"}, - {file = "enum34-1.1.10-py3-none-any.whl", hash = "sha256:c3858660960c984d6ab0ebad691265180da2b43f07e061c0f8dca9ef3cffd328"}, - {file = "enum34-1.1.10.tar.gz", hash = "sha256:cce6a7477ed816bd2542d03d53db9f0db935dd013b70f336a95c73979289f248"}, -] environs = [ - {file = "environs-9.5.0-py2.py3-none-any.whl", hash = "sha256:1e549569a3de49c05f856f40bce86979e7d5ffbbc4398e7f338574c220189124"}, - {file = "environs-9.5.0.tar.gz", hash = "sha256:a76307b36fbe856bdca7ee9161e6c466fd7fcffc297109a118c59b54e27e30c9"}, + {file = "environs-9.3.3-py2.py3-none-any.whl", hash = "sha256:ee5466156b50fe03aa9fec6e720feea577b5bf515d7f21b2c46608272557ba26"}, + {file = "environs-9.3.3.tar.gz", hash = "sha256:72b867ff7b553076cdd90f3ee01ecc1cf854987639c9c459f0ed0d3d44ae490c"}, ] fastapi = [ - {file = "fastapi-0.83.0-py3-none-any.whl", hash = "sha256:694a2b6c2607a61029a4be1c6613f84d74019cb9f7a41c7a475dca8e715f9368"}, - {file = "fastapi-0.83.0.tar.gz", hash = "sha256:96eb692350fe13d7a9843c3c87a874f0d45102975257dd224903efd6c0fde3bd"}, -] -grpcio = [ - {file = "grpcio-1.49.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:fd86040232e805b8e6378b2348c928490ee595b058ce9aaa27ed8e4b0f172b20"}, - {file = "grpcio-1.49.1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:6fd0c9cede9552bf00f8c5791d257d5bf3790d7057b26c59df08be5e7a1e021d"}, - {file = "grpcio-1.49.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:d0d402e158d4e84e49c158cb5204119d55e1baf363ee98d6cb5dce321c3a065d"}, - {file = "grpcio-1.49.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:822ceec743d42a627e64ea266059a62d214c5a3cdfcd0d7fe2b7a8e4e82527c7"}, - {file = "grpcio-1.49.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2106d9c16527f0a85e2eea6e6b91a74fc99579c60dd810d8690843ea02bc0f5f"}, - {file = "grpcio-1.49.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:52dd02b7e7868233c571b49bc38ebd347c3bb1ff8907bb0cb74cb5f00c790afc"}, - {file = "grpcio-1.49.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:120fecba2ec5d14b5a15d11063b39783fda8dc8d24addd83196acb6582cabd9b"}, - {file = "grpcio-1.49.1-cp310-cp310-win32.whl", hash = "sha256:f1a3b88e3c53c1a6e6bed635ec1bbb92201bb6a1f2db186179f7f3f244829788"}, - {file = "grpcio-1.49.1-cp310-cp310-win_amd64.whl", hash = "sha256:a7d0017b92d3850abea87c1bdec6ea41104e71c77bca44c3e17f175c6700af62"}, - {file = "grpcio-1.49.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:9fb17ff8c0d56099ac6ebfa84f670c5a62228d6b5c695cf21c02160c2ac1446b"}, - {file = "grpcio-1.49.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:075f2d06e3db6b48a2157a1bcd52d6cbdca980dd18988fe6afdb41795d51625f"}, - {file = "grpcio-1.49.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:46d93a1b4572b461a227f1db6b8d35a88952db1c47e5fadcf8b8a2f0e1dd9201"}, - {file = "grpcio-1.49.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dc79b2b37d779ac42341ddef40ad5bf0966a64af412c89fc2b062e3ddabb093f"}, - {file = "grpcio-1.49.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:5f8b3a971c7820ea9878f3fd70086240a36aeee15d1b7e9ecbc2743b0e785568"}, - {file = "grpcio-1.49.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49b301740cf5bc8fed4fee4c877570189ae3951432d79fa8e524b09353659811"}, - {file = "grpcio-1.49.1-cp311-cp311-win32.whl", hash = "sha256:1c66a25afc6c71d357867b341da594a5587db5849b48f4b7d5908d236bb62ede"}, - {file = "grpcio-1.49.1-cp311-cp311-win_amd64.whl", hash = "sha256:6b6c3a95d27846f4145d6967899b3ab25fffc6ae99544415e1adcacef84842d2"}, - {file = "grpcio-1.49.1-cp37-cp37m-linux_armv7l.whl", hash = "sha256:1cc400c8a2173d1c042997d98a9563e12d9bb3fb6ad36b7f355bc77c7663b8af"}, - {file = "grpcio-1.49.1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:34f736bd4d0deae90015c0e383885b431444fe6b6c591dea288173df20603146"}, - {file = "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_aarch64.whl", hash = "sha256:196082b9c89ebf0961dcd77cb114bed8171964c8e3063b9da2fb33536a6938ed"}, - {file = "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c9f89c42749890618cd3c2464e1fbf88446e3d2f67f1e334c8e5db2f3272bbd"}, - {file = "grpcio-1.49.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64419cb8a5b612cdb1550c2fd4acbb7d4fb263556cf4625f25522337e461509e"}, - {file = "grpcio-1.49.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:8a5272061826e6164f96e3255405ef6f73b88fd3e8bef464c7d061af8585ac62"}, - {file = "grpcio-1.49.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ea9d0172445241ad7cb49577314e39d0af2c5267395b3561d7ced5d70458a9f3"}, - {file = "grpcio-1.49.1-cp37-cp37m-win32.whl", hash = "sha256:2070e87d95991473244c72d96d13596c751cb35558e11f5df5414981e7ed2492"}, - {file = "grpcio-1.49.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fcedcab49baaa9db4a2d240ac81f2d57eb0052b1c6a9501b46b8ae912720fbf"}, - {file = "grpcio-1.49.1-cp38-cp38-linux_armv7l.whl", hash = "sha256:afbb3475cf7f4f7d380c2ca37ee826e51974f3e2665613996a91d6a58583a534"}, - {file = "grpcio-1.49.1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a4f9ba141380abde6c3adc1727f21529137a2552002243fa87c41a07e528245c"}, - {file = "grpcio-1.49.1-cp38-cp38-manylinux_2_17_aarch64.whl", hash = "sha256:cf0a1fb18a7204b9c44623dfbd1465b363236ce70c7a4ed30402f9f60d8b743b"}, - {file = "grpcio-1.49.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:17bb6fe72784b630728c6cff9c9d10ccc3b6d04e85da6e0a7b27fb1d135fac62"}, - {file = "grpcio-1.49.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18305d5a082d1593b005a895c10041f833b16788e88b02bb81061f5ebcc465df"}, - {file = "grpcio-1.49.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:b6a1b39e59ac5a3067794a0e498911cf2e37e4b19ee9e9977dc5e7051714f13f"}, - {file = "grpcio-1.49.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0e20d59aafc086b1cc68400463bddda6e41d3e5ed30851d1e2e0f6a2e7e342d3"}, - {file = "grpcio-1.49.1-cp38-cp38-win32.whl", hash = "sha256:e1e83233d4680863a421f3ee4a7a9b80d33cd27ee9ed7593bc93f6128302d3f2"}, - {file = "grpcio-1.49.1-cp38-cp38-win_amd64.whl", hash = "sha256:221d42c654d2a41fa31323216279c73ed17d92f533bc140a3390cc1bd78bf63c"}, - {file = "grpcio-1.49.1-cp39-cp39-linux_armv7l.whl", hash = "sha256:fa9e6e61391e99708ac87fc3436f6b7b9c6b845dc4639b406e5e61901e1aacde"}, - {file = "grpcio-1.49.1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9b449e966ef518ce9c860d21f8afe0b0f055220d95bc710301752ac1db96dd6a"}, - {file = "grpcio-1.49.1-cp39-cp39-manylinux_2_17_aarch64.whl", hash = "sha256:aa34d2ad9f24e47fa9a3172801c676e4037d862247e39030165fe83821a7aafd"}, - {file = "grpcio-1.49.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5207f4eed1b775d264fcfe379d8541e1c43b878f2b63c0698f8f5c56c40f3d68"}, - {file = "grpcio-1.49.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b24a74651438d45619ac67004638856f76cc13d78b7478f2457754cbcb1c8ad"}, - {file = "grpcio-1.49.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:fe763781669790dc8b9618e7e677c839c87eae6cf28b655ee1fa69ae04eea03f"}, - {file = "grpcio-1.49.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2f2ff7ba0f8f431f32d4b4bc3a3713426949d3533b08466c4ff1b2b475932ca8"}, - {file = "grpcio-1.49.1-cp39-cp39-win32.whl", hash = "sha256:08ff74aec8ff457a89b97152d36cb811dcc1d17cd5a92a65933524e363327394"}, - {file = "grpcio-1.49.1-cp39-cp39-win_amd64.whl", hash = "sha256:274ffbb39717918c514b35176510ae9be06e1d93121e84d50b350861dcb9a705"}, - {file = "grpcio-1.49.1.tar.gz", hash = "sha256:d4725fc9ec8e8822906ae26bb26f5546891aa7fbc3443de970cc556d43a5c99f"}, + {file = "fastapi-0.78.0-py3-none-any.whl", hash = "sha256:15fcabd5c78c266fa7ae7d8de9b384bfc2375ee0503463a6febbe3bab69d6f65"}, + {file = "fastapi-0.78.0.tar.gz", hash = "sha256:3233d4a789ba018578658e2af1a4bb5e38bdd122ff722b313666a9b2c6786a83"}, ] h11 = [ {file = "h11-0.12.0-py3-none-any.whl", hash = "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6"}, @@ -1503,12 +1131,12 @@ httpx = [ {file = "httpx-0.23.0.tar.gz", hash = "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef"}, ] idna = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.2-py3-none-any.whl", hash = "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a"}, + {file = "idna-3.2.tar.gz", hash = "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3"}, ] importlib-metadata = [ - {file = "importlib_metadata-4.12.0-py3-none-any.whl", hash = "sha256:7401a975809ea1fdc658c3aa4f78cc2195a0e019c5cbc4c06122884e9ae80c23"}, - {file = "importlib_metadata-4.12.0.tar.gz", hash = "sha256:637245b8bab2b6502fcbc752cc4b7a6f6243bb02b31c5c26156ad103d3d45670"}, + {file = "importlib_metadata-4.8.1-py3-none-any.whl", hash = "sha256:b618b6d2d5ffa2f16add5697cf57a46c76a56229b0ed1c438322e4e95645bd15"}, + {file = "importlib_metadata-4.8.1.tar.gz", hash = "sha256:f284b3e11256ad1e5d03ab86bb2ccd6f5339688ff17a4d797a0fe7df326f23b1"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -1518,63 +1146,92 @@ isort = [ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"}, {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"}, ] -Jinja2 = [ - {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"}, - {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"}, +jinja2 = [ + {file = "Jinja2-3.0.1-py3-none-any.whl", hash = "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4"}, + {file = "Jinja2-3.0.1.tar.gz", hash = "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4"}, ] lnurl = [ {file = "lnurl-0.3.6-py3-none-any.whl", hash = "sha256:579982fd8c4d25bc84c61c74ec45cb7999fa1fa2426f5d5aeb0160ba333b9c92"}, {file = "lnurl-0.3.6.tar.gz", hash = "sha256:8af07460115a48f3122a5a9c9a6062bee3897d5f6ab4c9a60f6561a83a8234f6"}, ] loguru = [ - {file = "loguru-0.6.0-py3-none-any.whl", hash = "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3"}, - {file = "loguru-0.6.0.tar.gz", hash = "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c"}, + {file = "loguru-0.5.3-py3-none-any.whl", hash = "sha256:f8087ac396b5ee5f67c963b495d615ebbceac2796379599820e324419d53667c"}, + {file = "loguru-0.5.3.tar.gz", hash = "sha256:b28e72ac7a98be3d28ad28570299a393dfcd32e5e3f6a353dec94675767b6319"}, ] -MarkupSafe = [ - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win32.whl", hash = "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6"}, - {file = "MarkupSafe-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win32.whl", hash = "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff"}, - {file = "MarkupSafe-2.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win32.whl", hash = "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1"}, - {file = "MarkupSafe-2.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win32.whl", hash = "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c"}, - {file = "MarkupSafe-2.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247"}, - {file = "MarkupSafe-2.1.1.tar.gz", hash = "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b"}, +markupsafe = [ + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win32.whl", hash = "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28"}, + {file = "MarkupSafe-2.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, ] marshmallow = [ - {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.17.0-py3-none-any.whl", hash = "sha256:00040ab5ea0c608e8787137627a8efae97fabd60552a05dc889c888f814e75eb"}, + {file = "marshmallow-3.17.0.tar.gz", hash = "sha256:635fb65a3285a31a30f276f30e958070f5214c7196202caa5c7ecf28f5274bc7"}, ] mock = [ {file = "mock-4.0.3-py3-none-any.whl", hash = "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62"}, @@ -1610,20 +1267,16 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] outcome = [ - {file = "outcome-1.2.0-py2.py3-none-any.whl", hash = "sha256:c4ab89a56575d6d38a05aa16daeaa333109c1f96167aba8901ab18b6b5e0f7f5"}, - {file = "outcome-1.2.0.tar.gz", hash = "sha256:6f82bd3de45da303cf1f771ecafa1633750a358436a8bb60e06a1ceb745d2672"}, + {file = "outcome-1.1.0-py2.py3-none-any.whl", hash = "sha256:c7dd9375cfd3c12db9801d080a3b63d4b0a261aa996c4c13152380587288d958"}, + {file = "outcome-1.1.0.tar.gz", hash = "sha256:e862f01d4e626e63e8f92c38d1f8d5546d3f9cce989263c521b2e7990d186967"}, ] packaging = [ {file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"}, {file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"}, ] -pathlib2 = [ - {file = "pathlib2-2.3.7.post1-py2.py3-none-any.whl", hash = "sha256:5266a0fd000452f1b3467d782f079a4343c63aaa119221fbdc4e39577489ca5b"}, - {file = "pathlib2-2.3.7.post1.tar.gz", hash = "sha256:9fe0edad898b83c0c3e199c842b27ed216645d2e177757b2dd67384d4113c641"}, -] pathspec = [ - {file = "pathspec-0.10.1-py3-none-any.whl", hash = "sha256:46846318467efc4556ccfd27816e004270a9eeeeb4d062ce5e6fc7a87c573f93"}, - {file = "pathspec-0.10.1.tar.gz", hash = "sha256:7ace6161b621d31e7902eb6b5ae148d12cfd23f4a249b9ffb6b9fee12084323d"}, + {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, + {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, ] platformdirs = [ {file = "platformdirs-2.5.2-py3-none-any.whl", hash = "sha256:027d8e83a2d7de06bbac4e5ef7e023c02b863d7ea5d079477e722bb41ab25788"}, @@ -1633,79 +1286,43 @@ pluggy = [ {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, ] -protobuf = [ - {file = "protobuf-4.21.6-cp310-abi3-win32.whl", hash = "sha256:49f88d56a9180dbb7f6199c920f5bb5c1dd0172f672983bb281298d57c2ac8eb"}, - {file = "protobuf-4.21.6-cp310-abi3-win_amd64.whl", hash = "sha256:7a6cc8842257265bdfd6b74d088b829e44bcac3cca234c5fdd6052730017b9ea"}, - {file = "protobuf-4.21.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:ba596b9ffb85c909fcfe1b1a23136224ed678af3faf9912d3fa483d5f9813c4e"}, - {file = "protobuf-4.21.6-cp37-abi3-manylinux2014_aarch64.whl", hash = "sha256:4143513c766db85b9d7c18dbf8339673c8a290131b2a0fe73855ab20770f72b0"}, - {file = "protobuf-4.21.6-cp37-abi3-manylinux2014_x86_64.whl", hash = "sha256:b6cea204865595a92a7b240e4b65bcaaca3ad5d2ce25d9db3756eba06041138e"}, - {file = "protobuf-4.21.6-cp37-cp37m-win32.whl", hash = "sha256:9666da97129138585b26afcb63ad4887f602e169cafe754a8258541c553b8b5d"}, - {file = "protobuf-4.21.6-cp37-cp37m-win_amd64.whl", hash = "sha256:308173d3e5a3528787bb8c93abea81d5a950bdce62840d9760effc84127fb39c"}, - {file = "protobuf-4.21.6-cp38-cp38-win32.whl", hash = "sha256:aa29113ec901281f29d9d27b01193407a98aa9658b8a777b0325e6d97149f5ce"}, - {file = "protobuf-4.21.6-cp38-cp38-win_amd64.whl", hash = "sha256:8f9e60f7d44592c66e7b332b6a7b4b6e8d8b889393c79dbc3a91f815118f8eac"}, - {file = "protobuf-4.21.6-cp39-cp39-win32.whl", hash = "sha256:80e6540381080715fddac12690ee42d087d0d17395f8d0078dfd6f1181e7be4c"}, - {file = "protobuf-4.21.6-cp39-cp39-win_amd64.whl", hash = "sha256:77b355c8604fe285536155286b28b0c4cbc57cf81b08d8357bf34829ea982860"}, - {file = "protobuf-4.21.6-py2.py3-none-any.whl", hash = "sha256:07a0bb9cc6114f16a39c866dc28b6e3d96fa4ffb9cc1033057412547e6e75cb9"}, - {file = "protobuf-4.21.6-py3-none-any.whl", hash = "sha256:c7c864148a237f058c739ae7a05a2b403c0dfa4ce7d1f3e5213f352ad52d57c6"}, - {file = "protobuf-4.21.6.tar.gz", hash = "sha256:6b1040a5661cd5f6e610cbca9cfaa2a17d60e2bb545309bc1b278bb05be44bdd"}, -] psycopg2-binary = [ - {file = "psycopg2-binary-2.9.3.tar.gz", hash = "sha256:761df5313dc15da1502b21453642d7599d26be88bff659382f8f9747c7ebea4e"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:539b28661b71da7c0e428692438efbcd048ca21ea81af618d845e06ebfd29478"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e82d38390a03da28c7985b394ec3f56873174e2c88130e6966cb1c946508e65"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57804fc02ca3ce0dbfbef35c4b3a4a774da66d66ea20f4bda601294ad2ea6092"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:083a55275f09a62b8ca4902dd11f4b33075b743cf0d360419e2051a8a5d5ff76"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:0a29729145aaaf1ad8bafe663131890e2111f13416b60e460dae0a96af5905c9"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a79d622f5206d695d7824cbf609a4f5b88ea6d6dab5f7c147fc6d333a8787e4"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:090f3348c0ab2cceb6dfbe6bf721ef61262ddf518cd6cc6ecc7d334996d64efa"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a9e1f75f96ea388fbcef36c70640c4efbe4650658f3d6a2967b4cc70e907352e"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c3ae8e75eb7160851e59adc77b3a19a976e50622e44fd4fd47b8b18208189d42"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-win32.whl", hash = "sha256:7b1e9b80afca7b7a386ef087db614faebbf8839b7f4db5eb107d0f1a53225029"}, - {file = "psycopg2_binary-2.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:8b344adbb9a862de0c635f4f0425b7958bf5a4b927c8594e6e8d261775796d53"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:e847774f8ffd5b398a75bc1c18fbb56564cda3d629fe68fd81971fece2d3c67e"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:68641a34023d306be959101b345732360fc2ea4938982309b786f7be1b43a4a1"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3303f8807f342641851578ee7ed1f3efc9802d00a6f83c101d21c608cb864460"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_24_aarch64.whl", hash = "sha256:e3699852e22aa68c10de06524a3721ade969abf382da95884e6a10ff798f9281"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-manylinux_2_24_ppc64le.whl", hash = "sha256:526ea0378246d9b080148f2d6681229f4b5964543c170dd10bf4faaab6e0d27f"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:b1c8068513f5b158cf7e29c43a77eb34b407db29aca749d3eb9293ee0d3103ca"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:15803fa813ea05bef089fa78835118b5434204f3a17cb9f1e5dbfd0b9deea5af"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:152f09f57417b831418304c7f30d727dc83a12761627bb826951692cc6491e57"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:404224e5fef3b193f892abdbf8961ce20e0b6642886cfe1fe1923f41aaa75c9d"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-win32.whl", hash = "sha256:1f6b813106a3abdf7b03640d36e24669234120c72e91d5cbaeb87c5f7c36c65b"}, - {file = "psycopg2_binary-2.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:2d872e3c9d5d075a2e104540965a1cf898b52274a5923936e5bfddb58c59c7c2"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:10bb90fb4d523a2aa67773d4ff2b833ec00857f5912bafcfd5f5414e45280fb1"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:874a52ecab70af13e899f7847b3e074eeb16ebac5615665db33bce8a1009cf33"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a29b3ca4ec9defec6d42bf5feb36bb5817ba3c0230dd83b4edf4bf02684cd0ae"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:12b11322ea00ad8db8c46f18b7dfc47ae215e4df55b46c67a94b4effbaec7094"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:53293533fcbb94c202b7c800a12c873cfe24599656b341f56e71dd2b557be063"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c381bda330ddf2fccbafab789d83ebc6c53db126e4383e73794c74eedce855ef"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d29409b625a143649d03d0fd7b57e4b92e0ecad9726ba682244b73be91d2fdb"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:183a517a3a63503f70f808b58bfbf962f23d73b6dccddae5aa56152ef2bcb232"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:15c4e4cfa45f5a60599d9cec5f46cd7b1b29d86a6390ec23e8eebaae84e64554"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-win32.whl", hash = "sha256:adf20d9a67e0b6393eac162eb81fb10bc9130a80540f4df7e7355c2dd4af9fba"}, - {file = "psycopg2_binary-2.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:2f9ffd643bc7349eeb664eba8864d9e01f057880f510e4681ba40a6532f93c71"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:def68d7c21984b0f8218e8a15d514f714d96904265164f75f8d3a70f9c295667"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dffc08ca91c9ac09008870c9eb77b00a46b3378719584059c034b8945e26b272"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:280b0bb5cbfe8039205c7981cceb006156a675362a00fe29b16fbc264e242834"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:af9813db73395fb1fc211bac696faea4ca9ef53f32dc0cfa27e4e7cf766dcf24"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:63638d875be8c2784cfc952c9ac34e2b50e43f9f0a0660b65e2a87d656b3116c"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ffb7a888a047696e7f8240d649b43fb3644f14f0ee229077e7f6b9f9081635bd"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:0c9d5450c566c80c396b7402895c4369a410cab5a82707b11aee1e624da7d004"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:d1c1b569ecafe3a69380a94e6ae09a4789bbb23666f3d3a08d06bbd2451f5ef1"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8fc53f9af09426a61db9ba357865c77f26076d48669f2e1bb24d85a22fb52307"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-win32.whl", hash = "sha256:6472a178e291b59e7f16ab49ec8b4f3bdada0a879c68d3817ff0963e722a82ce"}, - {file = "psycopg2_binary-2.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:35168209c9d51b145e459e05c31a9eaeffa9a6b0fd61689b48e07464ffd1a83e"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:47133f3f872faf28c1e87d4357220e809dfd3fa7c64295a4a148bcd1e6e34ec9"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:91920527dea30175cc02a1099f331aa8c1ba39bf8b7762b7b56cbf54bc5cce42"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:887dd9aac71765ac0d0bac1d0d4b4f2c99d5f5c1382d8b770404f0f3d0ce8a39"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:1f14c8b0942714eb3c74e1e71700cbbcb415acbc311c730370e70c578a44a25c"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:7af0dd86ddb2f8af5da57a976d27cd2cd15510518d582b478fbb2292428710b4"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:93cd1967a18aa0edd4b95b1dfd554cf15af657cb606280996d393dadc88c3c35"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bda845b664bb6c91446ca9609fc69f7db6c334ec5e4adc87571c34e4f47b7ddb"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:01310cf4cf26db9aea5158c217caa92d291f0500051a6469ac52166e1a16f5b7"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:99485cab9ba0fa9b84f1f9e1fef106f44a46ef6afdeec8885e0b88d0772b49e8"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-win32.whl", hash = "sha256:46f0e0a6b5fa5851bbd9ab1bc805eef362d3a230fbdfbc209f4a236d0a7a990d"}, - {file = "psycopg2_binary-2.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:accfe7e982411da3178ec690baaceaad3c278652998b2c45828aaac66cd8285f"}, + {file = "psycopg2-binary-2.9.1.tar.gz", hash = "sha256:b0221ca5a9837e040ebf61f48899926b5783668b7807419e4adae8175a31f773"}, + {file = "psycopg2_binary-2.9.1-cp310-cp310-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:24b0b6688b9f31a911f2361fe818492650795c9e5d3a1bc647acbd7440142a4f"}, + {file = "psycopg2_binary-2.9.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:542875f62bc56e91c6eac05a0deadeae20e1730be4c6334d8f04c944fcd99759"}, + {file = "psycopg2_binary-2.9.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:661509f51531ec125e52357a489ea3806640d0ca37d9dada461ffc69ee1e7b6e"}, + {file = "psycopg2_binary-2.9.1-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:d92272c7c16e105788efe2cfa5d680f07e34e0c29b03c1908f8636f55d5f915a"}, + {file = "psycopg2_binary-2.9.1-cp310-cp310-manylinux_2_24_ppc64le.whl", hash = "sha256:736b8797b58febabb85494142c627bd182b50d2a7ec65322983e71065ad3034c"}, + {file = "psycopg2_binary-2.9.1-cp310-cp310-win32.whl", hash = "sha256:ebccf1123e7ef66efc615a68295bf6fdba875a75d5bba10a05073202598085fc"}, + {file = "psycopg2_binary-2.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:1f6ca4a9068f5c5c57e744b4baa79f40e83e3746875cac3c45467b16326bab45"}, + {file = "psycopg2_binary-2.9.1-cp36-cp36m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:c250a7ec489b652c892e4f0a5d122cc14c3780f9f643e1a326754aedf82d9a76"}, + {file = "psycopg2_binary-2.9.1-cp36-cp36m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aef9aee84ec78af51107181d02fe8773b100b01c5dfde351184ad9223eab3698"}, + {file = "psycopg2_binary-2.9.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:123c3fb684e9abfc47218d3784c7b4c47c8587951ea4dd5bc38b6636ac57f616"}, + {file = "psycopg2_binary-2.9.1-cp36-cp36m-manylinux_2_24_aarch64.whl", hash = "sha256:995fc41ebda5a7a663a254a1dcac52638c3e847f48307b5416ee373da15075d7"}, + {file = "psycopg2_binary-2.9.1-cp36-cp36m-manylinux_2_24_ppc64le.whl", hash = "sha256:fbb42a541b1093385a2d8c7eec94d26d30437d0e77c1d25dae1dcc46741a385e"}, + {file = "psycopg2_binary-2.9.1-cp36-cp36m-win32.whl", hash = "sha256:20f1ab44d8c352074e2d7ca67dc00843067788791be373e67a0911998787ce7d"}, + {file = "psycopg2_binary-2.9.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f6fac64a38f6768e7bc7b035b9e10d8a538a9fadce06b983fb3e6fa55ac5f5ce"}, + {file = "psycopg2_binary-2.9.1-cp37-cp37m-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:1e3a362790edc0a365385b1ac4cc0acc429a0c0d662d829a50b6ce743ae61b5a"}, + {file = "psycopg2_binary-2.9.1-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f8559617b1fcf59a9aedba2c9838b5b6aa211ffedecabca412b92a1ff75aac1a"}, + {file = "psycopg2_binary-2.9.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a36c7eb6152ba5467fb264d73844877be8b0847874d4822b7cf2d3c0cb8cdcb0"}, + {file = "psycopg2_binary-2.9.1-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:2f62c207d1740b0bde5c4e949f857b044818f734a3d57f1d0d0edc65050532ed"}, + {file = "psycopg2_binary-2.9.1-cp37-cp37m-manylinux_2_24_ppc64le.whl", hash = "sha256:cfc523edecddaef56f6740d7de1ce24a2fdf94fd5e704091856a201872e37f9f"}, + {file = "psycopg2_binary-2.9.1-cp37-cp37m-win32.whl", hash = "sha256:1e85b74cbbb3056e3656f1cc4781294df03383127a8114cbc6531e8b8367bf1e"}, + {file = "psycopg2_binary-2.9.1-cp37-cp37m-win_amd64.whl", hash = "sha256:1473c0215b0613dd938db54a653f68251a45a78b05f6fc21af4326f40e8360a2"}, + {file = "psycopg2_binary-2.9.1-cp38-cp38-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:35c4310f8febe41f442d3c65066ca93cccefd75013df3d8c736c5b93ec288140"}, + {file = "psycopg2_binary-2.9.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8c13d72ed6af7fd2c8acbd95661cf9477f94e381fce0792c04981a8283b52917"}, + {file = "psycopg2_binary-2.9.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14db1752acdd2187d99cb2ca0a1a6dfe57fc65c3281e0f20e597aac8d2a5bd90"}, + {file = "psycopg2_binary-2.9.1-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:aed4a9a7e3221b3e252c39d0bf794c438dc5453bc2963e8befe9d4cd324dff72"}, + {file = "psycopg2_binary-2.9.1-cp38-cp38-manylinux_2_24_ppc64le.whl", hash = "sha256:da113b70f6ec40e7d81b43d1b139b9db6a05727ab8be1ee559f3a69854a69d34"}, + {file = "psycopg2_binary-2.9.1-cp38-cp38-win32.whl", hash = "sha256:4235f9d5ddcab0b8dbd723dca56ea2922b485ea00e1dafacf33b0c7e840b3d32"}, + {file = "psycopg2_binary-2.9.1-cp38-cp38-win_amd64.whl", hash = "sha256:988b47ac70d204aed01589ed342303da7c4d84b56c2f4c4b8b00deda123372bf"}, + {file = "psycopg2_binary-2.9.1-cp39-cp39-macosx_10_14_x86_64.macosx_10_9_intel.macosx_10_9_x86_64.macosx_10_10_intel.macosx_10_10_x86_64.whl", hash = "sha256:7360647ea04db2e7dff1648d1da825c8cf68dc5fbd80b8fb5b3ee9f068dcd21a"}, + {file = "psycopg2_binary-2.9.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca86db5b561b894f9e5f115d6a159fff2a2570a652e07889d8a383b5fae66eb4"}, + {file = "psycopg2_binary-2.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ced67f1e34e1a450cdb48eb53ca73b60aa0af21c46b9b35ac3e581cf9f00e31"}, + {file = "psycopg2_binary-2.9.1-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:0f2e04bd2a2ab54fa44ee67fe2d002bb90cee1c0f1cc0ebc3148af7b02034cbd"}, + {file = "psycopg2_binary-2.9.1-cp39-cp39-manylinux_2_24_ppc64le.whl", hash = "sha256:3242b9619de955ab44581a03a64bdd7d5e470cc4183e8fcadd85ab9d3756ce7a"}, + {file = "psycopg2_binary-2.9.1-cp39-cp39-win32.whl", hash = "sha256:0b7dae87f0b729922e06f85f667de7bf16455d411971b2043bbd9577af9d1975"}, + {file = "psycopg2_binary-2.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:b4d7679a08fea64573c969f6994a2631908bb2c0e69a7235648642f3d2e39a68"}, ] py = [ {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, @@ -1745,54 +1362,28 @@ pycryptodomex = [ {file = "pycryptodomex-3.14.1.tar.gz", hash = "sha256:2ce76ed0081fd6ac8c74edc75b9d14eca2064173af79843c24fa62573263c1f2"}, ] pydantic = [ - {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"}, -] -pyln-bolt7 = [ - {file = "pyln-bolt7-1.0.246.tar.gz", hash = "sha256:2b53744fa21c1b12d2c9c9df153651b122e38fa65d4a5c3f2957317ee148e089"}, - {file = "pyln_bolt7-1.0.246-py3-none-any.whl", hash = "sha256:54d48ec27fdc8751762cb068b0a9f2757a58fb57933c6d8f8255d02c27eb63c5"}, -] -pyln-client = [ - {file = "pyln-client-0.12.1.tar.gz", hash = "sha256:f14fa7947b65ecde2753984452441cf41b7b25b1a0ba7beced48786fa54d2bfe"}, - {file = "pyln_client-0.12.1-py3-none-any.whl", hash = "sha256:6b500bcc49e4028d50692b962d9c9f7e9ede920d718f9b9412f04f7db0aa0e63"}, -] -pyln-proto = [ - {file = "pyln-proto-0.12.0.tar.gz", hash = "sha256:3214d99d8385f2135a94937f0dc1da626a33b257e9ebc320841656edaefabbe5"}, - {file = "pyln_proto-0.12.0-py3-none-any.whl", hash = "sha256:dedef5d8e476a9ade5a0b2eb919ccc37e4a57f2a78fdc399f1c5e0de17e41604"}, + {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, + {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, + {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, + {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, + {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, + {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, + {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, + {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, + {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, + {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, ] pyparsing = [ {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, @@ -1801,21 +1392,16 @@ pyparsing = [ pypng = [ {file = "pypng-0.0.21-py3-none-any.whl", hash = "sha256:76f8a1539ec56451da7ab7121f12a361969fe0f2d48d703d198ce2a99d6c5afd"}, ] -PyQRCode = [ +pyqrcode = [ {file = "PyQRCode-1.2.1.tar.gz", hash = "sha256:fdbf7634733e56b72e27f9bce46e4550b75a3a2c420414035cae9d9d26b234d5"}, {file = "PyQRCode-1.2.1.zip", hash = "sha256:1b2812775fa6ff5c527977c4cd2ccb07051ca7d0bc0aecf937a43864abe5eff6"}, ] -pyScss = [ - {file = "pyScss-1.4.0.tar.gz", hash = "sha256:8f35521ffe36afa8b34c7d6f3195088a7057c185c2b8f15ee459ab19748669ff"}, -] -PySocks = [ - {file = "PySocks-1.7.1-py27-none-any.whl", hash = "sha256:08e69f092cc6dbe92a0fdd16eeb9b9ffbc13cadfe5ca4c7bd92ffb078b293299"}, - {file = "PySocks-1.7.1-py3-none-any.whl", hash = "sha256:2725bd0a9925919b9b51739eea5f9e2bae91e83288108a9ad338b2e3a4435ee5"}, - {file = "PySocks-1.7.1.tar.gz", hash = "sha256:3f8804571ebe159c380ac6de37643bb4685970655d3bba243530d6558b799aa0"}, +pyscss = [ + {file = "pyScss-1.3.7.tar.gz", hash = "sha256:f1df571569021a23941a538eb154405dde80bed35dc1ea7c5f3e18e0144746bf"}, ] pytest = [ - {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.1.2-py3-none-any.whl", hash = "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c"}, + {file = "pytest-7.1.2.tar.gz", hash = "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45"}, ] pytest-asyncio = [ {file = "pytest-asyncio-0.19.0.tar.gz", hash = "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed"}, @@ -1826,10 +1412,10 @@ pytest-cov = [ {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, ] python-dotenv = [ - {file = "python-dotenv-0.21.0.tar.gz", hash = "sha256:b77d08274639e3d34145dfa6c7008e66df0f04b7be7a75fd0d5292c191d79045"}, - {file = "python_dotenv-0.21.0-py3-none-any.whl", hash = "sha256:1684eb44636dd462b66c3ee016599815514527ad99965de77f43e0944634a7e5"}, + {file = "python-dotenv-0.19.0.tar.gz", hash = "sha256:f521bc2ac9a8e03c736f62911605c5d83970021e3fa95b37d769e2bbbe9b6172"}, + {file = "python_dotenv-0.19.0-py2.py3-none-any.whl", hash = "sha256:aae25dc1ebe97c420f50b81fb0e5c949659af713f31fdb63c749ca68748f34b1"}, ] -PyYAML = [ +pyyaml = [ {file = "PyYAML-5.4.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:3b2b1824fe7112845700f815ff6a489360226a5609b96ec2190a45e62a9fc922"}, {file = "PyYAML-5.4.1-cp27-cp27m-win32.whl", hash = "sha256:129def1b7c1bf22faffd67b8f3724645203b79d8f4cc81f674654d9902cb4393"}, {file = "PyYAML-5.4.1-cp27-cp27m-win_amd64.whl", hash = "sha256:4465124ef1b18d9ace298060f4eccc64b0850899ac4ac53294547536533800c8"}, @@ -1860,14 +1446,10 @@ PyYAML = [ {file = "PyYAML-5.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:c20cfa2d49991c8b4147af39859b167664f2ad4561704ee74c1de03318e898db"}, {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] -Represent = [ +represent = [ {file = "Represent-1.6.0.post0-py2.py3-none-any.whl", hash = "sha256:99142650756ef1998ce0661568f54a47dac8c638fb27e3816c02536575dbba8c"}, {file = "Represent-1.6.0.post0.tar.gz", hash = "sha256:026c0de2ee8385d1255b9c2426cd4f03fe9177ac94c09979bc601946c8493aa0"}, ] -requests = [ - {file = "requests-2.27.1-py2.py3-none-any.whl", hash = "sha256:f22fa1e554c9ddfd16e6e41ac79759e17be9e492b3587efa038054674760e72d"}, - {file = "requests-2.27.1.tar.gz", hash = "sha256:68d7c56fd5a8999887728ef304a6d12edc7be74f1cfa47714fc8b414525c9a61"}, -] rfc3986 = [ {file = "rfc3986-1.5.0-py2.py3-none-any.whl", hash = "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97"}, {file = "rfc3986-1.5.0.tar.gz", hash = "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835"}, @@ -1897,10 +1479,6 @@ secp256k1 = [ {file = "secp256k1-0.14.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c9e7c024ff17e9b9d7c392bb2a917da231d6cb40ab119389ff1f51dca10339a4"}, {file = "secp256k1-0.14.0.tar.gz", hash = "sha256:82c06712d69ef945220c8b53c1a0d424c2ff6a1f64aee609030df79ad8383397"}, ] -setuptools = [ - {file = "setuptools-65.4.0-py3-none-any.whl", hash = "sha256:c2d2709550f15aab6c9110196ea312f468f41cd546bceb24127a1be6fdcaeeb1"}, - {file = "setuptools-65.4.0.tar.gz", hash = "sha256:a8f6e213b4b0661f590ccf40de95d28a177cd747d098624ad3f69c40287297e9"}, -] shortuuid = [ {file = "shortuuid-1.0.1-py3-none-any.whl", hash = "sha256:492c7402ff91beb1342a5898bd61ea953985bf24a41cd9f247409aa2e03c8f77"}, {file = "shortuuid-1.0.1.tar.gz", hash = "sha256:3c11d2007b915c43bee3e10625f068d8a349e04f0d81f08f5fa08507427ebf1f"}, @@ -1910,44 +1488,48 @@ six = [ {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] sniffio = [ - {file = "sniffio-1.3.0-py3-none-any.whl", hash = "sha256:eecefdce1e5bbfb7ad2eeaabf7c1eeb404d7757c379bd1f7e5cce9d8bf425384"}, - {file = "sniffio-1.3.0.tar.gz", hash = "sha256:e60305c5e5d314f5389259b7f22aaa33d8f7dee49763119234af3755c55b9101"}, + {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, + {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, ] -SQLAlchemy = [ - {file = "SQLAlchemy-1.3.24-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:87a2725ad7d41cd7376373c15fd8bf674e9c33ca56d0b8036add2d634dba372e"}, - {file = "SQLAlchemy-1.3.24-cp27-cp27m-win32.whl", hash = "sha256:f597a243b8550a3a0b15122b14e49d8a7e622ba1c9d29776af741f1845478d79"}, - {file = "SQLAlchemy-1.3.24-cp27-cp27m-win_amd64.whl", hash = "sha256:fc4cddb0b474b12ed7bdce6be1b9edc65352e8ce66bc10ff8cbbfb3d4047dbf4"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:f1149d6e5c49d069163e58a3196865e4321bad1803d7886e07d8710de392c548"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:14f0eb5db872c231b20c18b1e5806352723a3a89fb4254af3b3e14f22eaaec75"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:e98d09f487267f1e8d1179bf3b9d7709b30a916491997137dd24d6ae44d18d79"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:fc1f2a5a5963e2e73bac4926bdaf7790c4d7d77e8fc0590817880e22dd9d0b8b"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-win32.whl", hash = "sha256:f3c5c52f7cb8b84bfaaf22d82cb9e6e9a8297f7c2ed14d806a0f5e4d22e83fb7"}, - {file = "SQLAlchemy-1.3.24-cp35-cp35m-win_amd64.whl", hash = "sha256:0352db1befcbed2f9282e72843f1963860bf0e0472a4fa5cf8ee084318e0e6ab"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:2ed6343b625b16bcb63c5b10523fd15ed8934e1ed0f772c534985e9f5e73d894"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:34fcec18f6e4b24b4a5f6185205a04f1eab1e56f8f1d028a2a03694ebcc2ddd4"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e47e257ba5934550d7235665eee6c911dc7178419b614ba9e1fbb1ce6325b14f"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:816de75418ea0953b5eb7b8a74933ee5a46719491cd2b16f718afc4b291a9658"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-win32.whl", hash = "sha256:26155ea7a243cbf23287f390dba13d7927ffa1586d3208e0e8d615d0c506f996"}, - {file = "SQLAlchemy-1.3.24-cp36-cp36m-win_amd64.whl", hash = "sha256:f03bd97650d2e42710fbe4cf8a59fae657f191df851fc9fc683ecef10746a375"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:a006d05d9aa052657ee3e4dc92544faae5fcbaafc6128217310945610d862d39"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1e2f89d2e5e3c7a88e25a3b0e43626dba8db2aa700253023b82e630d12b37109"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:0d5d862b1cfbec5028ce1ecac06a3b42bc7703eb80e4b53fceb2738724311443"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:0172423a27fbcae3751ef016663b72e1a516777de324a76e30efa170dbd3dd2d"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-win32.whl", hash = "sha256:d37843fb8df90376e9e91336724d78a32b988d3d20ab6656da4eb8ee3a45b63c"}, - {file = "SQLAlchemy-1.3.24-cp37-cp37m-win_amd64.whl", hash = "sha256:c10ff6112d119f82b1618b6dc28126798481b9355d8748b64b9b55051eb4f01b"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:861e459b0e97673af6cc5e7f597035c2e3acdfb2608132665406cded25ba64c7"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5de2464c254380d8a6c20a2746614d5a436260be1507491442cf1088e59430d2"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d375d8ccd3cebae8d90270f7aa8532fe05908f79e78ae489068f3b4eee5994e8"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:014ea143572fee1c18322b7908140ad23b3994036ef4c0d630110faf942652f8"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-win32.whl", hash = "sha256:6607ae6cd3a07f8a4c3198ffbf256c261661965742e2b5265a77cd5c679c9bba"}, - {file = "SQLAlchemy-1.3.24-cp38-cp38-win_amd64.whl", hash = "sha256:fcb251305fa24a490b6a9ee2180e5f8252915fb778d3dafc70f9cc3f863827b9"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:01aa5f803db724447c1d423ed583e42bf5264c597fd55e4add4301f163b0be48"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:4d0e3515ef98aa4f0dc289ff2eebb0ece6260bbf37c2ea2022aad63797eacf60"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:bce28277f308db43a6b4965734366f533b3ff009571ec7ffa583cb77539b84d6"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:8110e6c414d3efc574543109ee618fe2c1f96fa31833a1ff36cc34e968c4f233"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-win32.whl", hash = "sha256:ee5f5188edb20a29c1cc4a039b074fdc5575337c9a68f3063449ab47757bb064"}, - {file = "SQLAlchemy-1.3.24-cp39-cp39-win_amd64.whl", hash = "sha256:09083c2487ca3c0865dc588e07aeaa25416da3d95f7482c07e92f47e080aa17b"}, - {file = "SQLAlchemy-1.3.24.tar.gz", hash = "sha256:ebbb777cbf9312359b897bf81ba00dae0f5cb69fba2a18265dcc18a6f5ef7519"}, +sqlalchemy = [ + {file = "SQLAlchemy-1.3.23-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:fd3b96f8c705af8e938eaa99cbd8fd1450f632d38cad55e7367c33b263bf98ec"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:29cccc9606750fe10c5d0e8bd847f17a97f3850b8682aef1f56f5d5e1a5a64b1"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:927ce09e49bff3104459e1451ce82983b0a3062437a07d883a4c66f0b344c9b5"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27m-win32.whl", hash = "sha256:b4b0e44d586cd64b65b507fa116a3814a1a53d55dce4836d7c1a6eb2823ff8d1"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27m-win_amd64.whl", hash = "sha256:6b8b8c80c7f384f06825612dd078e4a31f0185e8f1f6b8c19e188ff246334205"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:9e9c25522933e569e8b53ccc644dc993cab87e922fb7e142894653880fdd419d"}, + {file = "SQLAlchemy-1.3.23-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:a0e306e9bb76fd93b29ae3a5155298e4c1b504c7cbc620c09c20858d32d16234"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:6c9e6cc9237de5660bcddea63f332428bb83c8e2015c26777281f7ffbd2efb84"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:94f667d86be82dd4cb17d08de0c3622e77ca865320e0b95eae6153faa7b4ecaf"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:751934967f5336a3e26fc5993ccad1e4fee982029f9317eb6153bc0bc3d2d2da"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:63677d0c08524af4c5893c18dbe42141de7178001360b3de0b86217502ed3601"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-win32.whl", hash = "sha256:ddfb511e76d016c3a160910642d57f4587dc542ce5ee823b0d415134790eeeb9"}, + {file = "SQLAlchemy-1.3.23-cp35-cp35m-win_amd64.whl", hash = "sha256:040bdfc1d76a9074717a3f43455685f781c581f94472b010cd6c4754754e1862"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:d1a85dfc5dee741bf49cb9b6b6b8d2725a268e4992507cf151cba26b17d97c37"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:639940bbe1108ac667dcffc79925db2966826c270112e9159439ab6bb14f8d80"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:e8a1750b44ad6422ace82bf3466638f1aa0862dbb9689690d5f2f48cce3476c8"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:e5bb3463df697279e5459a7316ad5a60b04b0107f9392e88674d0ece70e9cf70"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-win32.whl", hash = "sha256:e273367f4076bd7b9a8dc2e771978ef2bfd6b82526e80775a7db52bff8ca01dd"}, + {file = "SQLAlchemy-1.3.23-cp36-cp36m-win_amd64.whl", hash = "sha256:ac2244e64485c3778f012951fdc869969a736cd61375fde6096d08850d8be729"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:23927c3981d1ec6b4ea71eb99d28424b874d9c696a21e5fbd9fa322718be3708"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:d90010304abb4102123d10cbad2cdf2c25a9f2e66a50974199b24b468509bad5"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a8bfc1e1afe523e94974132d7230b82ca7fa2511aedde1f537ec54db0399541a"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:269990b3ab53cb035d662dcde51df0943c1417bdab707dc4a7e4114a710504b4"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-win32.whl", hash = "sha256:fdd2ed7395df8ac2dbb10cefc44737b66c6a5cd7755c92524733d7a443e5b7e2"}, + {file = "SQLAlchemy-1.3.23-cp37-cp37m-win_amd64.whl", hash = "sha256:6a939a868fdaa4b504e8b9d4a61f21aac11e3fecc8a8214455e144939e3d2aea"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:24f9569e82a009a09ce2d263559acb3466eba2617203170e4a0af91e75b4f075"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2578dbdbe4dbb0e5126fb37ffcd9793a25dcad769a95f171a2161030bea850ff"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1fe5d8d39118c2b018c215c37b73fd6893c3e1d4895be745ca8ff6eb83333ed3"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:c7dc052432cd5d060d7437e217dd33c97025287f99a69a50e2dc1478dd610d64"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-win32.whl", hash = "sha256:ecce8c021894a77d89808222b1ff9687ad84db54d18e4bd0500ca766737faaf6"}, + {file = "SQLAlchemy-1.3.23-cp38-cp38-win_amd64.whl", hash = "sha256:37b83bf81b4b85dda273aaaed5f35ea20ad80606f672d94d2218afc565fb0173"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8be835aac18ec85351385e17b8665bd4d63083a7160a017bef3d640e8e65cadb"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:6ec1044908414013ebfe363450c22f14698803ce97fbb47e53284d55c5165848"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:eab063a70cca4a587c28824e18be41d8ecc4457f8f15b2933584c6c6cccd30f0"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:baeb451ee23e264de3f577fee5283c73d9bbaa8cb921d0305c0bbf700094b65b"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-win32.whl", hash = "sha256:94208867f34e60f54a33a37f1c117251be91a47e3bfdb9ab8a7847f20886ad06"}, + {file = "SQLAlchemy-1.3.23-cp39-cp39-win_amd64.whl", hash = "sha256:f4d972139d5000105fcda9539a76452039434013570d6059993120dc2a65e447"}, + {file = "SQLAlchemy-1.3.23.tar.gz", hash = "sha256:6fca33672578666f657c131552c4ef8979c1606e494f78cd5199742dfb26918b"}, ] sqlalchemy-aio = [ {file = "sqlalchemy_aio-0.17.0-py3-none-any.whl", hash = "sha256:3f4aa392c38f032d6734826a4138a0f02ed3122d442ed142be1e5964f2a33b60"}, @@ -1991,20 +1573,17 @@ typed-ast = [ {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, ] types-protobuf = [ - {file = "types-protobuf-3.20.4.tar.gz", hash = "sha256:0dad3a5009895c985a56e2837f61902bad9594151265ac0ee907bb16d0b01eb7"}, - {file = "types_protobuf-3.20.4-py3-none-any.whl", hash = "sha256:5082437afe64ce3b31c8db109eae86e02fda11e4d5f9ac59cb8578a8a138aa70"}, + {file = "types-protobuf-3.19.22.tar.gz", hash = "sha256:d2b26861b0cb46a3c8669b0df507b7ef72e487da66d61f9f3576aa76ce028a83"}, + {file = "types_protobuf-3.19.22-py3-none-any.whl", hash = "sha256:d291388678af91bb045fafa864f142dc4ac22f5d4cdca097c7d8d8a32fa9b3ab"}, ] typing-extensions = [ - {file = "typing_extensions-4.3.0-py3-none-any.whl", hash = "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02"}, - {file = "typing_extensions-4.3.0.tar.gz", hash = "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6"}, -] -urllib3 = [ - {file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"}, - {file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"}, + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, ] uvicorn = [ - {file = "uvicorn-0.18.3-py3-none-any.whl", hash = "sha256:0abd429ebb41e604ed8d2be6c60530de3408f250e8d2d84967d85ba9e86fe3af"}, - {file = "uvicorn-0.18.3.tar.gz", hash = "sha256:9a66e7c42a2a95222f76ec24a4b754c158261c4696e683b9dadc72b590e0311b"}, + {file = "uvicorn-0.18.1-py3-none-any.whl", hash = "sha256:013c4ea0787cc2dc456ef4368e18c01982e6be57903e4d3183218e543eb889b7"}, + {file = "uvicorn-0.18.1.tar.gz", hash = "sha256:35703e6518105cfe53f16a5a9435db3e2e227d0784f1fd8fbc1214b1fdc108df"}, ] uvloop = [ {file = "uvloop-0.16.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6224f1401025b748ffecb7a6e2652b17768f30b1a6a3f7b44660e5b5b690b12d"}, @@ -2064,6 +1643,6 @@ win32-setctime = [ {file = "win32_setctime-1.1.0.tar.gz", hash = "sha256:15cf5750465118d6929ae4de4eb46e8edae9a5634350c01ba582df868e932cb2"}, ] zipp = [ - {file = "zipp-3.8.1-py3-none-any.whl", hash = "sha256:47c40d7fe183a6f21403a199b3e4192cca5774656965b0a4988ad2f8feb5f009"}, - {file = "zipp-3.8.1.tar.gz", hash = "sha256:05b45f1ee8f807d0cc928485ca40a07cb491cf092ff587c0df9cb1fd154848d2"}, + {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, + {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, ] diff --git a/pyproject.toml b/pyproject.toml index f106350c..1ae8c1fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,59 +11,55 @@ script = "build.py" [tool.poetry.dependencies] python = "^3.9 | ^3.8 | ^3.7" aiofiles = "0.8.0" -asgiref = "^3.4.1" -attrs = "22.1.0" +asgiref = "3.4.1" +attrs = "21.2.0" bech32 = "1.2.0" bitstring = "3.1.9" cerberus = "1.3.4" -certifi = "2022.9.24" -charset-normalizer = "2.0.12" -click = "8.0.4" -ecdsa = "0.18.0" +certifi = "2021.5.30" +charset-normalizer = "2.0.6" +click = "8.0.1" +ecdsa = "0.17.0" embit = "0.4.9" -environs = "9.5.0" -fastapi = "0.83.0" +environs = "9.3.3" +fastapi = "0.78.0" h11 = "0.12.0" +httpcore = "0.15.0" httptools = "0.4.0" httpx = "0.23.0" -idna = "3.4" -importlib-metadata = "^4.8.1" -jinja2 = "3.0.3" +idna = "3.2" +importlib-metadata = "4.8.1" +jinja2 = "3.0.1" lnurl = "0.3.6" -markupsafe = "2.1.1" -marshmallow = "3.18.0" -outcome = "1.2.0" -psycopg2-binary = "2.9.3" +markupsafe = "2.0.1" +marshmallow = "3.17.0" +outcome = "1.1.0" +psycopg2-binary = "2.9.1" pycryptodomex = "3.14.1" -pydantic = "1.10.2" +pydantic = "1.8.2" pypng = "0.0.21" pyqrcode = "1.2.1" -pyScss = "1.4.0" -python-dotenv = "0.21.0" +pyscss = "1.3.7" +python-dotenv = "0.19.0" pyyaml = "5.4.1" represent = "1.6.0.post0" rfc3986 = "1.5.0" secp256k1 = "0.14.0" shortuuid = "1.0.1" six = "1.16.0" -sniffio = "1.3.0" -sqlalchemy = "1.3.24" +sniffio = "1.2.0" +sqlalchemy = "1.3.23" sqlalchemy-aio = "0.17.0" sse-starlette = "0.6.2" -typing-extensions = "4.3.0" -uvicorn = "0.18.3" +typing-extensions = "3.10.0.2" +uvicorn = "0.18.1" uvloop = "0.16.0" watchgod = "0.7" websockets = "10.0" -zipp = "^3.5.0" -loguru = "0.6.0" -cffi = "1.15.1" +zipp = "3.5.0" +loguru = "0.5.3" +cffi = "1.15.0" websocket-client = "1.3.3" -grpcio = "^1.49.1" -protobuf = "^4.21.6" -pyln-client = "^0.12.0" -httpcore = "0.15.0" -cashu = {path = "../cashu/dist/cashu-0.1.11-py3-none-any.whl"} [tool.poetry.dev-dependencies] isort = "^5.10.1" From 45f2fffe90cc30b18e8ea7c510c1f3c36734d7cf Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 30 Sep 2022 12:25:48 +0100 Subject: [PATCH 0015/1058] Added the cashu router --- lnbits/extensions/cashu/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lnbits/extensions/cashu/__init__.py b/lnbits/extensions/cashu/__init__.py index fa549ad2..ed67b134 100644 --- a/lnbits/extensions/cashu/__init__.py +++ b/lnbits/extensions/cashu/__init__.py @@ -6,20 +6,20 @@ from lnbits.db import Database from lnbits.helpers import template_renderer from lnbits.tasks import catch_everything_and_restart +from cashu.mint.router import router as cashu_router + db = Database("ext_cashu") -cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["TPoS"]) - +cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["cashu"]) +cashu_ext.include_router(router=cashu_router) def cashu_renderer(): return template_renderer(["lnbits/extensions/cashu/templates"]) - from .tasks import wait_for_paid_invoices from .views import * # noqa from .views_api import * # noqa - def cashu_start(): loop = asyncio.get_event_loop() loop.create_task(catch_everything_and_restart(wait_for_paid_invoices)) From a6ddc0b335a5909b81b8700654f9814e0dafcb8d Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 30 Sep 2022 12:26:50 +0100 Subject: [PATCH 0016/1058] Extension authors --- lnbits/extensions/cashu/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/cashu/config.json b/lnbits/extensions/cashu/config.json index c688b22c..4f097e8b 100644 --- a/lnbits/extensions/cashu/config.json +++ b/lnbits/extensions/cashu/config.json @@ -2,5 +2,5 @@ "name": "Cashu Ecash", "short_description": "Ecash mints with LN peg in/out", "icon": "approval", - "contributors": ["shinobi", "arcbtc", "calle"] + "contributors": ["arcbtc", "calle"] } From b09dbc4b85d5cd0cd69ea6ea00f100f7d334baf4 Mon Sep 17 00:00:00 2001 From: ben Date: Fri, 30 Sep 2022 14:23:03 +0100 Subject: [PATCH 0017/1058] started adding mint stuff --- lnbits/extensions/cashu/crud.py | 59 ++++++ lnbits/extensions/cashu/ledger.py | 282 +++++++++++++++++++++++++++ lnbits/extensions/cashu/models.py | 105 +++++++++- lnbits/extensions/cashu/views_api.py | 67 ++++++- 4 files changed, 510 insertions(+), 3 deletions(-) create mode 100644 lnbits/extensions/cashu/ledger.py diff --git a/lnbits/extensions/cashu/crud.py b/lnbits/extensions/cashu/crud.py index f50da111..e1cdaf4e 100644 --- a/lnbits/extensions/cashu/crud.py +++ b/lnbits/extensions/cashu/crud.py @@ -68,3 +68,62 @@ async def get_cashus(wallet_ids: Union[str, List[str]]) -> List[Cashu]: async def delete_cashu(cashu_id: str) -> None: await db.execute("DELETE FROM cashu.cashu WHERE id = ?", (cashu_id,)) + + + +###############MINT STUFF################# + +async def store_promise( + amount: int, + B_: str, + C_: str, + db: Database, + conn: Optional[Connection] = None, +): + + await (conn or db).execute( + """ + INSERT INTO promises + (amount, B_b, C_b) + VALUES (?, ?, ?) + """, + ( + amount, + str(B_), + str(C_), + ), + ) + + +async def get_proofs_used( + db: Database, + conn: Optional[Connection] = None, +): + + rows = await (conn or db).fetchall( + """ + SELECT secret from proofs_used + """ + ) + return [row[0] for row in rows] + + +async def invalidate_proof( + proof: Proof, + db: Database, + conn: Optional[Connection] = None, +): + + # we add the proof and secret to the used list + await (conn or db).execute( + """ + INSERT INTO proofs_used + (amount, C, secret) + VALUES (?, ?, ?) + """, + ( + proof.amount, + str(proof.C), + str(proof.secret), + ), + ) \ No newline at end of file diff --git a/lnbits/extensions/cashu/ledger.py b/lnbits/extensions/cashu/ledger.py new file mode 100644 index 00000000..cc5ef924 --- /dev/null +++ b/lnbits/extensions/cashu/ledger.py @@ -0,0 +1,282 @@ +import hashlib +from typing import List, Set + +from models import BlindedMessage, BlindedSignature, Invoice, Proof +from secp256k1 import PublicKey, PrivateKey + +from lnbits.core.services import check_transaction_status, create_invoice + +class Ledger: + def __init__(self, secret_key: str, db: str, MAX_ORDER: int = Query(64)): + self.proofs_used: Set[str] = set() + + self.master_key: str = secret_key + self.keys: List[PrivateKey] = self._derive_keys(self.master_key) + self.pub_keys: List[PublicKey] = self._derive_pubkeys(self.keys) + self.db: Database = Database("mint", db) + + async def load_used_proofs(self): + self.proofs_used = set(await get_proofs_used(db=self.db)) + + @staticmethod + def _derive_keys(master_key: str): + """Deterministic derivation of keys for 2^n values.""" + return { + 2 + ** i: PrivateKey( + hashlib.sha256((str(master_key) + str(i)).encode("utf-8")) + .hexdigest() + .encode("utf-8")[:32], + raw=True, + ) + for i in range(MAX_ORDER) + } + + @staticmethod + def _derive_pubkeys(keys: List[PrivateKey]): + return {amt: keys[amt].pubkey for amt in [2**i for i in range(MAX_ORDER)]} + + async def _generate_promises(self, amounts: List[int], B_s: List[str]): + """Generates promises that sum to the given amount.""" + return [ + await self._generate_promise(amount, PublicKey(bytes.fromhex(B_), raw=True)) + for (amount, B_) in zip(amounts, B_s) + ] + + async def _generate_promise(self, amount: int, B_: PublicKey): + """Generates a promise for given amount and returns a pair (amount, C').""" + secret_key = self.keys[amount] # Get the correct key + C_ = step2_bob(B_, secret_key) + await store_promise( + amount, B_=B_.serialize().hex(), C_=C_.serialize().hex(), db=self.db + ) + return BlindedSignature(amount=amount, C_=C_.serialize().hex()) + + def _check_spendable(self, proof: Proof): + """Checks whether the proof was already spent.""" + return not proof.secret in self.proofs_used + + def _verify_proof(self, proof: Proof): + """Verifies that the proof of promise was issued by this ledger.""" + if not self._check_spendable(proof): + raise Exception(f"tokens already spent. Secret: {proof.secret}") + secret_key = self.keys[proof.amount] # Get the correct key to check against + C = PublicKey(bytes.fromhex(proof.C), raw=True) + return verify(secret_key, C, proof.secret) + + def _verify_outputs( + self, total: int, amount: int, output_data: List[BlindedMessage] + ): + """Verifies the expected split was correctly computed""" + fst_amt, snd_amt = total - amount, amount # we have two amounts to split to + fst_outputs = amount_split(fst_amt) + snd_outputs = amount_split(snd_amt) + expected = fst_outputs + snd_outputs + given = [o.amount for o in output_data] + return given == expected + + def _verify_no_duplicates( + self, proofs: List[Proof], output_data: List[BlindedMessage] + ): + secrets = [p.secret for p in proofs] + if len(secrets) != len(list(set(secrets))): + return False + B_s = [od.B_ for od in output_data] + if len(B_s) != len(list(set(B_s))): + return False + return True + + def _verify_split_amount(self, amount: int): + """Split amount like output amount can't be negative or too big.""" + try: + self._verify_amount(amount) + except: + # For better error message + raise Exception("invalid split amount: " + str(amount)) + + def _verify_amount(self, amount: int): + """Any amount used should be a positive integer not larger than 2^MAX_ORDER.""" + valid = isinstance(amount, int) and amount > 0 and amount < 2**MAX_ORDER + if not valid: + raise Exception("invalid amount: " + str(amount)) + return amount + + def _verify_equation_balanced( + self, proofs: List[Proof], outs: List[BlindedMessage] + ): + """Verify that Σoutputs - Σinputs = 0.""" + sum_inputs = sum(self._verify_amount(p.amount) for p in proofs) + sum_outputs = sum(self._verify_amount(p.amount) for p in outs) + assert sum_outputs - sum_inputs == 0 + + def _get_output_split(self, amount: int): + """Given an amount returns a list of amounts returned e.g. 13 is [1, 4, 8].""" + self._verify_amount(amount) + bits_amt = bin(amount)[::-1][:-2] + rv = [] + for (pos, bit) in enumerate(bits_amt): + if bit == "1": + rv.append(2**pos) + return rv + + async def _invalidate_proofs(self, proofs: List[Proof]): + """Adds secrets of proofs to the list of knwon secrets and stores them in the db.""" + # Mark proofs as used and prepare new promises + proof_msgs = set([p.secret for p in proofs]) + self.proofs_used |= proof_msgs + # store in db + for p in proofs: + await invalidate_proof(p, db=self.db) + + # Public methods + def get_pubkeys(self): + """Returns public keys for possible amounts.""" + return {a: p.serialize().hex() for a, p in self.pub_keys.items()} + + async def request_mint(self, amount): + """Returns Lightning invoice and stores it in the db.""" + payment_request, payment_hash = payment_hash, payment_request = await create_invoice( + wallet_id=link.wallet, + amount=amount, + memo=link.description, + unhashed_description=link.description.encode("utf-8"), + extra={ + "tag": "Cashu" + }, + ) + + invoice = Invoice( + amount=amount, pr=payment_request, hash=payment_hash, issued=False + ) + if not payment_request or not payment_hash: + raise Exception(f"Could not create Lightning invoice.") + await store_lightning_invoice(invoice, db=self.db) + return payment_request, payment_hash + + async def mint(self, B_s: List[PublicKey], amounts: List[int], payment_hash=None): + """Mints a promise for coins for B_.""" + # check if lightning invoice was paid + if payment_hash and not await check_transaction_status(ayment_hash) + raise Exception("Lightning invoice not paid yet.") + + for amount in amounts: + if amount not in [2**i for i in range(MAX_ORDER)]: + raise Exception(f"Can only mint amounts up to {2**MAX_ORDER}.") + + promises = [ + await self._generate_promise(amount, B_) for B_, amount in zip(B_s, amounts) + ] + return promises + + async def melt(self, proofs: List[Proof], amount: int, invoice: str): + """Invalidates proofs and pays a Lightning invoice.""" + # if not LIGHTNING: + total = sum([p["amount"] for p in proofs]) + # check that lightning fees are included + assert total + fee_reserve(amount * 1000) >= amount, Exception( + "provided proofs not enough for Lightning payment." + ) + + status, payment_hash = await pay_invoice( + wallet_id=link.wallet, + payment_request=invoice, + max_sat=amount, + extra={"tag": "Ecash melt"}, + ) + + if status == True: + await self._invalidate_proofs(proofs) + return status, payment_hash + + async def check_spendable(self, proofs: List[Proof]): + """Checks if all provided proofs are valid and still spendable (i.e. have not been spent).""" + return {i: self._check_spendable(p) for i, p in enumerate(proofs)} + + async def split( + self, proofs: List[Proof], amount: int, output_data: List[BlindedMessage] + ): + """Consumes proofs and prepares new promises based on the amount split.""" + self._verify_split_amount(amount) + # Verify proofs are valid + if not all([self._verify_proof(p) for p in proofs]): + return False + + total = sum([p.amount for p in proofs]) + + if not self._verify_no_duplicates(proofs, output_data): + raise Exception("duplicate proofs or promises") + if amount > total: + raise Exception("split amount is higher than the total sum") + if not self._verify_outputs(total, amount, output_data): + raise Exception("split of promises is not as expected") + + # Mark proofs as used and prepare new promises + await self._invalidate_proofs(proofs) + + outs_fst = amount_split(total - amount) + outs_snd = amount_split(amount) + B_fst = [od.B_ for od in output_data[: len(outs_fst)]] + B_snd = [od.B_ for od in output_data[len(outs_fst) :]] + prom_fst, prom_snd = await self._generate_promises( + outs_fst, B_fst + ), await self._generate_promises(outs_snd, B_snd) + self._verify_equation_balanced(proofs, prom_fst + prom_snd) + return prom_fst, prom_snd + + +#######FUNCTIONS############### +def fee_reserve(amount_msat: int) -> int: + """Function for calculating the Lightning fee reserve""" + return max( + int(LIGHTNING_RESERVE_FEE_MIN), int(amount_msat * LIGHTNING_FEE_PERCENT / 100.0) + ) + +def amount_split(amount): + """Given an amount returns a list of amounts returned e.g. 13 is [1, 4, 8].""" + bits_amt = bin(amount)[::-1][:-2] + rv = [] + for (pos, bit) in enumerate(bits_amt): + if bit == "1": + rv.append(2**pos) + return rv + +def hash_to_point(secret_msg): + """Generates x coordinate from the message hash and checks if the point lies on the curve. + If it does not, it tries computing again a new x coordinate from the hash of the coordinate.""" + point = None + msg = secret_msg + while point is None: + _hash = hashlib.sha256(msg).hexdigest().encode("utf-8") + try: + # We construct compressed pub which has x coordinate encoded with even y + _hash = list(_hash[:33]) # take the 33 bytes and get a list of bytes + _hash[0] = 0x02 # set first byte to represent even y coord + _hash = bytes(_hash) + point = PublicKey(_hash, raw=True) + except: + msg = _hash + + return point + + +def step1_alice(secret_msg): + secret_msg = secret_msg.encode("utf-8") + Y = hash_to_point(secret_msg) + r = PrivateKey() + B_ = Y + r.pubkey + return B_, r + + +def step2_bob(B_, a): + C_ = B_.mult(a) + return C_ + + +def step3_alice(C_, r, A): + C = C_ - A.mult(r) + return C + + +def verify(a, C, secret_msg): + Y = hash_to_point(secret_msg.encode("utf-8")) + return C == Y.mult(a) diff --git a/lnbits/extensions/cashu/models.py b/lnbits/extensions/cashu/models.py index 892abdf1..ba9303c5 100644 --- a/lnbits/extensions/cashu/models.py +++ b/lnbits/extensions/cashu/models.py @@ -31,5 +31,106 @@ class Pegs(BaseModel): def from_row(cls, row: Row) -> "TPoS": return cls(**dict(row)) -class PayLnurlWData(BaseModel): - lnurl: str \ No newline at end of file + +class Proof(BaseModel): + amount: int + secret: str + C: str + reserved: bool = False # whether this proof is reserved for sending + send_id: str = "" # unique ID of send attempt + time_created: str = "" + time_reserved: str = "" + + @classmethod + def from_row(cls, row: Row): + return cls( + amount=row[0], + C=row[1], + secret=row[2], + reserved=row[3] or False, + send_id=row[4] or "", + time_created=row[5] or "", + time_reserved=row[6] or "", + ) + + @classmethod + def from_dict(cls, d: dict): + assert "secret" in d, "no secret in proof" + assert "amount" in d, "no amount in proof" + return cls( + amount=d.get("amount"), + C=d.get("C"), + secret=d.get("secret"), + reserved=d.get("reserved") or False, + send_id=d.get("send_id") or "", + time_created=d.get("time_created") or "", + time_reserved=d.get("time_reserved") or "", + ) + + def to_dict(self): + return dict(amount=self.amount, secret=self.secret, C=self.C) + + def __getitem__(self, key): + return self.__getattribute__(key) + + def __setitem__(self, key, val): + self.__setattr__(key, val) + + +class Proofs(BaseModel): + """TODO: Use this model""" + + proofs: List[Proof] + + +class Invoice(BaseModel): + amount: int + pr: str + hash: str + issued: bool = False + + @classmethod + def from_row(cls, row: Row): + return cls( + amount=int(row[0]), + pr=str(row[1]), + hash=str(row[2]), + issued=bool(row[3]), + ) + + +class BlindedMessage(BaseModel): + amount: int + B_: str + + +class BlindedSignature(BaseModel): + amount: int + C_: str + + @classmethod + def from_dict(cls, d: dict): + return cls( + amount=d["amount"], + C_=d["C_"], + ) + + +class MintPayloads(BaseModel): + blinded_messages: List[BlindedMessage] = [] + + +class SplitPayload(BaseModel): + proofs: List[Proof] + amount: int + output_data: MintPayloads + + +class CheckPayload(BaseModel): + proofs: List[Proof] + + +class MeltPayload(BaseModel): + proofs: List[Proof] + amount: int + invoice: str \ No newline at end of file diff --git a/lnbits/extensions/cashu/views_api.py b/lnbits/extensions/cashu/views_api.py index 49383945..5a1c500e 100644 --- a/lnbits/extensions/cashu/views_api.py +++ b/lnbits/extensions/cashu/views_api.py @@ -1,4 +1,6 @@ from http import HTTPStatus +from secp256k1 import PublicKey +from typing import Union import httpx from fastapi import Query @@ -14,8 +16,9 @@ from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key from . import cashu_ext from .crud import create_cashu, delete_cashu, get_cashu, get_cashus, update_cashu_keys -from .models import Cashu, Pegs, PayLnurlWData +from .models import Cashu, Pegs, CheckPayload, MeltPayload, MintPayloads, SplitPayload +import .ledger @cashu_ext.get("/api/v1/cashus", status_code=HTTPStatus.OK) async def api_cashus( @@ -168,3 +171,65 @@ async def api_cashu_check_invoice(cashu_id: str, payment_hash: str): logger.error(exc) return {"paid": False} return status + + +#################CASHU STUFF################### + +@cashu_ext.get("/keys") +def keys(): + """Get the public keys of the mint""" + return ledger.get_pubkeys() + + +@cashu_ext.get("/mint") +async def request_mint(amount: int = 0): + """Request minting of tokens. Server responds with a Lightning invoice.""" + payment_request, payment_hash = await ledger.request_mint(amount) + print(f"Lightning invoice: {payment_request}") + return {"pr": payment_request, "hash": payment_hash} + + +@cashu_ext.post("/mint") +async def mint(payloads: MintPayloads, payment_hash: Union[str, None] = None): + amounts = [] + B_s = [] + for payload in payloads.blinded_messages: + amounts.append(payload.amount) + B_s.append(PublicKey(bytes.fromhex(payload.B_), raw=True)) + try: + promises = await ledger.mint(B_s, amounts, payment_hash=payment_hash) + return promises + except Exception as exc: + return {"error": str(exc)} + + +@cashu_ext.post("/melt") +async def melt(payload: MeltPayload): + + ok, preimage = await ledger.melt(payload.proofs, payload.amount, payload.invoice) + return {"paid": ok, "preimage": preimage} + + +@cashu_ext.post("/check") +async def check_spendable(payload: CheckPayload): + return await ledger.check_spendable(payload.proofs) + + +@cashu_ext.post("/split") +async def split(payload: SplitPayload): + """ + Requetst a set of tokens with amount "total" to be split into two + newly minted sets with amount "split" and "total-split". + """ + proofs = payload.proofs + amount = payload.amount + output_data = payload.output_data.blinded_messages + try: + split_return = await ledger.split(proofs, amount, output_data) + except Exception as exc: + return {"error": str(exc)} + if not split_return: + """There was a problem with the split""" + raise Exception("could not split tokens.") + fst_promises, snd_promises = split_return + return {"fst": fst_promises, "snd": snd_promises} \ No newline at end of file From 77269ad0a7b05127a917738e52d8119ab8f1d57c Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 3 Oct 2022 10:45:13 +0100 Subject: [PATCH 0018/1058] Booting --- lnbits/extensions/cashu/__init__.py | 3 --- lnbits/extensions/cashu/crud.py | 15 ++++----------- lnbits/extensions/cashu/ledger.py | 19 ++++++++++--------- lnbits/extensions/cashu/models.py | 4 +++- lnbits/extensions/cashu/views_api.py | 4 ++-- 5 files changed, 19 insertions(+), 26 deletions(-) diff --git a/lnbits/extensions/cashu/__init__.py b/lnbits/extensions/cashu/__init__.py index ed67b134..cf277664 100644 --- a/lnbits/extensions/cashu/__init__.py +++ b/lnbits/extensions/cashu/__init__.py @@ -6,12 +6,9 @@ from lnbits.db import Database from lnbits.helpers import template_renderer from lnbits.tasks import catch_everything_and_restart -from cashu.mint.router import router as cashu_router - db = Database("ext_cashu") cashu_ext: APIRouter = APIRouter(prefix="/cashu", tags=["cashu"]) -cashu_ext.include_router(router=cashu_router) def cashu_renderer(): return template_renderer(["lnbits/extensions/cashu/templates"]) diff --git a/lnbits/extensions/cashu/crud.py b/lnbits/extensions/cashu/crud.py index e1cdaf4e..2892e6a4 100644 --- a/lnbits/extensions/cashu/crud.py +++ b/lnbits/extensions/cashu/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 Cashu, Pegs +from .models import Cashu, Pegs, Proof from embit import script from embit import ec @@ -76,9 +76,7 @@ async def delete_cashu(cashu_id: str) -> None: async def store_promise( amount: int, B_: str, - C_: str, - db: Database, - conn: Optional[Connection] = None, + C_: str ): await (conn or db).execute( @@ -95,10 +93,7 @@ async def store_promise( ) -async def get_proofs_used( - db: Database, - conn: Optional[Connection] = None, -): +async def get_proofs_used(): rows = await (conn or db).fetchall( """ @@ -109,9 +104,7 @@ async def get_proofs_used( async def invalidate_proof( - proof: Proof, - db: Database, - conn: Optional[Connection] = None, + proof: Proof ): # we add the proof and secret to the used list diff --git a/lnbits/extensions/cashu/ledger.py b/lnbits/extensions/cashu/ledger.py index cc5ef924..59cc3b92 100644 --- a/lnbits/extensions/cashu/ledger.py +++ b/lnbits/extensions/cashu/ledger.py @@ -1,22 +1,23 @@ import hashlib from typing import List, Set -from models import BlindedMessage, BlindedSignature, Invoice, Proof +from .models import BlindedMessage, BlindedSignature, Invoice, Proof from secp256k1 import PublicKey, PrivateKey +from fastapi import Query + from lnbits.core.services import check_transaction_status, create_invoice class Ledger: - def __init__(self, secret_key: str, db: str, MAX_ORDER: int = Query(64)): + def __init__(self, secret_key: str, MAX_ORDER: int = Query(64)): self.proofs_used: Set[str] = set() self.master_key: str = secret_key self.keys: List[PrivateKey] = self._derive_keys(self.master_key) self.pub_keys: List[PublicKey] = self._derive_pubkeys(self.keys) - self.db: Database = Database("mint", db) async def load_used_proofs(self): - self.proofs_used = set(await get_proofs_used(db=self.db)) + self.proofs_used = set(await get_proofs_used) @staticmethod def _derive_keys(master_key: str): @@ -48,7 +49,7 @@ class Ledger: secret_key = self.keys[amount] # Get the correct key C_ = step2_bob(B_, secret_key) await store_promise( - amount, B_=B_.serialize().hex(), C_=C_.serialize().hex(), db=self.db + amount, B_=B_.serialize().hex(), C_=C_.serialize().hex() ) return BlindedSignature(amount=amount, C_=C_.serialize().hex()) @@ -126,7 +127,7 @@ class Ledger: self.proofs_used |= proof_msgs # store in db for p in proofs: - await invalidate_proof(p, db=self.db) + await invalidate_proof(p) # Public methods def get_pubkeys(self): @@ -150,13 +151,13 @@ class Ledger: ) if not payment_request or not payment_hash: raise Exception(f"Could not create Lightning invoice.") - await store_lightning_invoice(invoice, db=self.db) + await store_lightning_invoice(invoice) return payment_request, payment_hash async def mint(self, B_s: List[PublicKey], amounts: List[int], payment_hash=None): """Mints a promise for coins for B_.""" # check if lightning invoice was paid - if payment_hash and not await check_transaction_status(ayment_hash) + if payment_hash and not await check_transaction_status(payment_hash): raise Exception("Lightning invoice not paid yet.") for amount in amounts: @@ -224,7 +225,7 @@ class Ledger: return prom_fst, prom_snd -#######FUNCTIONS############### +##############FUNCTIONS############### def fee_reserve(amount_msat: int) -> int: """Function for calculating the Lightning fee reserve""" return max( diff --git a/lnbits/extensions/cashu/models.py b/lnbits/extensions/cashu/models.py index ba9303c5..a673dfe7 100644 --- a/lnbits/extensions/cashu/models.py +++ b/lnbits/extensions/cashu/models.py @@ -1,5 +1,5 @@ from sqlite3 import Row -from typing import Optional +from typing import Optional, List from fastapi import Query from pydantic import BaseModel @@ -31,6 +31,8 @@ class Pegs(BaseModel): def from_row(cls, row: Row) -> "TPoS": return cls(**dict(row)) +class PayLnurlWData(BaseModel): + lnurl: str class Proof(BaseModel): amount: int diff --git a/lnbits/extensions/cashu/views_api.py b/lnbits/extensions/cashu/views_api.py index 5a1c500e..5cc6e271 100644 --- a/lnbits/extensions/cashu/views_api.py +++ b/lnbits/extensions/cashu/views_api.py @@ -16,9 +16,9 @@ from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key from . import cashu_ext from .crud import create_cashu, delete_cashu, get_cashu, get_cashus, update_cashu_keys -from .models import Cashu, Pegs, CheckPayload, MeltPayload, MintPayloads, SplitPayload +from .models import Cashu, Pegs, CheckPayload, MeltPayload, MintPayloads, SplitPayload, PayLnurlWData -import .ledger +from .ledger import Ledger, fee_reserve, amount_split, hash_to_point, step1_alice, step2_bob, step3_alice, verify @cashu_ext.get("/api/v1/cashus", status_code=HTTPStatus.OK) async def api_cashus( From d51103e7e8e4052081fa5a944a75828bb6674d40 Mon Sep 17 00:00:00 2001 From: ben Date: Mon, 3 Oct 2022 14:43:02 +0100 Subject: [PATCH 0019/1058] Working through, getting functions working --- lnbits/extensions/cashu/crud.py | 85 ++-- lnbits/extensions/cashu/ledger.py | 426 +++++++++--------- lnbits/extensions/cashu/migrations.py | 31 +- lnbits/extensions/cashu/models.py | 9 +- lnbits/extensions/cashu/tasks.py | 1 - .../cashu/templates/cashu/index.html | 7 +- lnbits/extensions/cashu/views.py | 1 - lnbits/extensions/cashu/views_api.py | 51 ++- 8 files changed, 354 insertions(+), 257 deletions(-) diff --git a/lnbits/extensions/cashu/crud.py b/lnbits/extensions/cashu/crud.py index 2892e6a4..7a9c25c3 100644 --- a/lnbits/extensions/cashu/crud.py +++ b/lnbits/extensions/cashu/crud.py @@ -1,24 +1,37 @@ +import os + from typing import List, Optional, Union from lnbits.helpers import urlsafe_short_hash from . import db -from .models import Cashu, Pegs, Proof +from .models import Cashu, Pegs, Proof, Promises from embit import script from embit import ec from embit.networks import NETWORKS +from embit import bip32 +from embit import bip39 from binascii import unhexlify, hexlify +import random + +from loguru import logger async def create_cashu(wallet_id: str, data: Cashu) -> Cashu: cashu_id = urlsafe_short_hash() - prv = ec.PrivateKey.from_wif(urlsafe_short_hash()) - pub = prv.get_public_key() + + entropy = bytes([random.getrandbits(8) for i in range(16)]) + mnemonic = bip39.mnemonic_from_bytes(entropy) + seed = bip39.mnemonic_to_seed(mnemonic) + root = bip32.HDKey.from_seed(seed, version=NETWORKS["main"]["xprv"]) + + bip44_xprv = root.derive("m/44h/1h/0h") + bip44_xpub = bip44_xprv.to_public() await db.execute( """ INSERT INTO cashu.cashu (id, wallet, name, tickershort, fraction, maxsats, coins, prvkey, pubkey) - VALUES (?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( cashu_id, @@ -28,8 +41,8 @@ async def create_cashu(wallet_id: str, data: Cashu) -> Cashu: data.fraction, data.maxsats, data.coins, - prv, - pub + bip44_xprv.to_base58(), + bip44_xpub.to_base58() ), ) @@ -39,17 +52,20 @@ async def create_cashu(wallet_id: str, data: Cashu) -> Cashu: async def update_cashu_keys(cashu_id, wif: str = None) -> Optional[Cashu]: - if not wif: - prv = ec.PrivateKey.from_wif(urlsafe_short_hash()) - else: - prv = ec.PrivateKey.from_wif(wif) - pub = prv.get_public_key() - await db.execute("UPDATE cashu.cashu SET prv = ?, pub = ? WHERE id = ?", (hexlify(prv.serialize()), hexlify(pub.serialize()), cashu_id)) + entropy = bytes([random.getrandbits(8) for i in range(16)]) + mnemonic = bip39.mnemonic_from_bytes(entropy) + seed = bip39.mnemonic_to_seed(mnemonic) + root = bip32.HDKey.from_seed(seed, version=NETWORKS["main"]["xprv"]) + + bip44_xprv = root.derive("m/44h/1h/0h") + bip44_xpub = bip44_xprv.to_public() + + await db.execute("UPDATE cashu.cashu SET prv = ?, pub = ? WHERE id = ?", bip44_xprv.to_base58(), bip44_xpub.to_base58(), cashu_id) row = await db.fetchone("SELECT * FROM cashu.cashu WHERE id = ?", (cashu_id,)) return Cashu(**row) if row else None -async def get_cashu(cashu_id: str) -> Optional[Cashu]: +async def get_cashu(cashu_id) -> Optional[Cashu]: row = await db.fetchone("SELECT * FROM cashu.cashu WHERE id = ?", (cashu_id,)) return Cashu(**row) if row else None @@ -66,57 +82,62 @@ async def get_cashus(wallet_ids: Union[str, List[str]]) -> List[Cashu]: return [Cashu(**row) for row in rows] -async def delete_cashu(cashu_id: str) -> None: +async def delete_cashu(cashu_id) -> None: await db.execute("DELETE FROM cashu.cashu WHERE id = ?", (cashu_id,)) - +########################################## ###############MINT STUFF################# +########################################## async def store_promise( amount: int, B_: str, - C_: str + C_: str, + cashu_id ): + promise_id = urlsafe_short_hash() await (conn or db).execute( """ - INSERT INTO promises - (amount, B_b, C_b) - VALUES (?, ?, ?) + INSERT INTO cashu.promises + (id, amount, B_b, C_b, cashu_id) + VALUES (?, ?, ?, ?, ?) """, ( + promise_id, amount, str(B_), str(C_), + cashu_id ), ) +async def get_promises(cashu_id) -> Optional[Cashu]: + row = await db.fetchall("SELECT * FROM cashu.promises WHERE cashu_id = ?", (promises_id,)) + return Promises(**row) if row else None -async def get_proofs_used(): - - rows = await (conn or db).fetchall( - """ - SELECT secret from proofs_used - """ - ) +async def get_proofs_used(cashu_id): + rows = await db.fetchall("SELECT secret from cashu.proofs_used WHERE id = ?", (cashu_id,)) return [row[0] for row in rows] async def invalidate_proof( - proof: Proof + proof: Proof, + cashu_id ): - - # we add the proof and secret to the used list + invalidate_proof_id = urlsafe_short_hash() await (conn or db).execute( """ - INSERT INTO proofs_used - (amount, C, secret) - VALUES (?, ?, ?) + INSERT INTO cashu.proofs_used + (id, amount, C, secret, cashu_id) + VALUES (?, ?, ?, ?, ?) """, ( + invalidate_proof_id, proof.amount, str(proof.C), str(proof.secret), + cashu_id ), ) \ No newline at end of file diff --git a/lnbits/extensions/cashu/ledger.py b/lnbits/extensions/cashu/ledger.py index 59cc3b92..404f7ee8 100644 --- a/lnbits/extensions/cashu/ledger.py +++ b/lnbits/extensions/cashu/ledger.py @@ -5,234 +5,239 @@ from .models import BlindedMessage, BlindedSignature, Invoice, Proof from secp256k1 import PublicKey, PrivateKey from fastapi import Query - +from .crud import get_cashu from lnbits.core.services import check_transaction_status, create_invoice -class Ledger: - def __init__(self, secret_key: str, MAX_ORDER: int = Query(64)): - self.proofs_used: Set[str] = set() - - self.master_key: str = secret_key - self.keys: List[PrivateKey] = self._derive_keys(self.master_key) - self.pub_keys: List[PublicKey] = self._derive_pubkeys(self.keys) - - async def load_used_proofs(self): - self.proofs_used = set(await get_proofs_used) - - @staticmethod - def _derive_keys(master_key: str): - """Deterministic derivation of keys for 2^n values.""" - return { - 2 - ** i: PrivateKey( - hashlib.sha256((str(master_key) + str(i)).encode("utf-8")) - .hexdigest() - .encode("utf-8")[:32], - raw=True, - ) - for i in range(MAX_ORDER) - } - - @staticmethod - def _derive_pubkeys(keys: List[PrivateKey]): - return {amt: keys[amt].pubkey for amt in [2**i for i in range(MAX_ORDER)]} - - async def _generate_promises(self, amounts: List[int], B_s: List[str]): - """Generates promises that sum to the given amount.""" - return [ - await self._generate_promise(amount, PublicKey(bytes.fromhex(B_), raw=True)) - for (amount, B_) in zip(amounts, B_s) - ] - - async def _generate_promise(self, amount: int, B_: PublicKey): - """Generates a promise for given amount and returns a pair (amount, C').""" - secret_key = self.keys[amount] # Get the correct key - C_ = step2_bob(B_, secret_key) - await store_promise( - amount, B_=B_.serialize().hex(), C_=C_.serialize().hex() +def _derive_keys(master_key: str, cashu_id: str = Query(None)): + """Deterministic derivation of keys for 2^n values.""" + return { + 2 + ** i: PrivateKey( + hashlib.sha256((str(master_key) + str(i)).encode("utf-8")) + .hexdigest() + .encode("utf-8")[:32], + raw=True, ) - return BlindedSignature(amount=amount, C_=C_.serialize().hex()) + for i in range(MAX_ORDER) + } - def _check_spendable(self, proof: Proof): - """Checks whether the proof was already spent.""" - return not proof.secret in self.proofs_used +def _derive_pubkeys(keys: List[PrivateKey], cashu_id: str = Query(None)): + return {amt: keys[amt].pubkey for amt in [2**i for i in range(MAX_ORDER)]} - def _verify_proof(self, proof: Proof): - """Verifies that the proof of promise was issued by this ledger.""" - if not self._check_spendable(proof): - raise Exception(f"tokens already spent. Secret: {proof.secret}") - secret_key = self.keys[proof.amount] # Get the correct key to check against - C = PublicKey(bytes.fromhex(proof.C), raw=True) - return verify(secret_key, C, proof.secret) +async def _generate_promises(amounts: List[int], B_s: List[str], cashu_id: str = Query(None)): + """Generates promises that sum to the given amount.""" + return [ + await self._generate_promise(amount, PublicKey(bytes.fromhex(B_), raw=True)) + for (amount, B_) in zip(amounts, B_s) + ] - def _verify_outputs( - self, total: int, amount: int, output_data: List[BlindedMessage] - ): - """Verifies the expected split was correctly computed""" - fst_amt, snd_amt = total - amount, amount # we have two amounts to split to - fst_outputs = amount_split(fst_amt) - snd_outputs = amount_split(snd_amt) - expected = fst_outputs + snd_outputs - given = [o.amount for o in output_data] - return given == expected +async def _generate_promise(amount: int, B_: PublicKey, cashu_id: str = Query(None)): + """Generates a promise for given amount and returns a pair (amount, C').""" + secret_key = self.keys[amount] # Get the correct key + C_ = step2_bob(B_, secret_key) + await store_promise( + amount, B_=B_.serialize().hex(), C_=C_.serialize().hex() + ) + return BlindedSignature(amount=amount, C_=C_.serialize().hex()) - def _verify_no_duplicates( - self, proofs: List[Proof], output_data: List[BlindedMessage] - ): - secrets = [p.secret for p in proofs] - if len(secrets) != len(list(set(secrets))): - return False - B_s = [od.B_ for od in output_data] - if len(B_s) != len(list(set(B_s))): - return False - return True +def _check_spendable(proof: Proof, cashu_id: str = Query(None)): + """Checks whether the proof was already spent.""" + return not proof.secret in self.proofs_used - def _verify_split_amount(self, amount: int): - """Split amount like output amount can't be negative or too big.""" - try: - self._verify_amount(amount) - except: - # For better error message - raise Exception("invalid split amount: " + str(amount)) +def _verify_proof(proof: Proof, cashu_id: str = Query(None)): + """Verifies that the proof of promise was issued by this ledger.""" + if not self._check_spendable(proof): + raise Exception(f"tokens already spent. Secret: {proof.secret}") + secret_key = self.keys[proof.amount] # Get the correct key to check against + C = PublicKey(bytes.fromhex(proof.C), raw=True) + return verify(secret_key, C, proof.secret) - def _verify_amount(self, amount: int): - """Any amount used should be a positive integer not larger than 2^MAX_ORDER.""" - valid = isinstance(amount, int) and amount > 0 and amount < 2**MAX_ORDER - if not valid: - raise Exception("invalid amount: " + str(amount)) - return amount +def _verify_outputs(total: int, amount: int, output_data: List[BlindedMessage], cashu_id: str = Query(None)): + """Verifies the expected split was correctly computed""" + fst_amt, snd_amt = total - amount, amount # we have two amounts to split to + fst_outputs = amount_split(fst_amt) + snd_outputs = amount_split(snd_amt) + expected = fst_outputs + snd_outputs + given = [o.amount for o in output_data] + return given == expected - def _verify_equation_balanced( - self, proofs: List[Proof], outs: List[BlindedMessage] - ): - """Verify that Σoutputs - Σinputs = 0.""" - sum_inputs = sum(self._verify_amount(p.amount) for p in proofs) - sum_outputs = sum(self._verify_amount(p.amount) for p in outs) - assert sum_outputs - sum_inputs == 0 +def _verify_no_duplicates(proofs: List[Proof], output_data: List[BlindedMessage], cashu_id: str = Query(None)): + secrets = [p.secret for p in proofs] + if len(secrets) != len(list(set(secrets))): + return False + B_s = [od.B_ for od in output_data] + if len(B_s) != len(list(set(B_s))): + return False + return True - def _get_output_split(self, amount: int): - """Given an amount returns a list of amounts returned e.g. 13 is [1, 4, 8].""" +def _verify_split_amount(amount: int, cashu_id: str = Query(None)): + """Split amount like output amount can't be negative or too big.""" + try: self._verify_amount(amount) - bits_amt = bin(amount)[::-1][:-2] - rv = [] - for (pos, bit) in enumerate(bits_amt): - if bit == "1": - rv.append(2**pos) - return rv + except: + # For better error message + raise Exception("invalid split amount: " + str(amount)) - async def _invalidate_proofs(self, proofs: List[Proof]): - """Adds secrets of proofs to the list of knwon secrets and stores them in the db.""" - # Mark proofs as used and prepare new promises - proof_msgs = set([p.secret for p in proofs]) - self.proofs_used |= proof_msgs - # store in db - for p in proofs: - await invalidate_proof(p) +def _verify_amount(amount: int, cashu_id: str = Query(None)): + """Any amount used should be a positive integer not larger than 2^MAX_ORDER.""" + valid = isinstance(amount, int) and amount > 0 and amount < 2**MAX_ORDER + if not valid: + raise Exception("invalid amount: " + str(amount)) + return amount - # Public methods - def get_pubkeys(self): - """Returns public keys for possible amounts.""" - return {a: p.serialize().hex() for a, p in self.pub_keys.items()} +def _verify_equation_balanced(proofs: List[Proof], outs: List[BlindedMessage], cashu_id: str = Query(None)): + """Verify that Σoutputs - Σinputs = 0.""" + sum_inputs = sum(self._verify_amount(p.amount) for p in proofs) + sum_outputs = sum(self._verify_amount(p.amount) for p in outs) + assert sum_outputs - sum_inputs == 0 - async def request_mint(self, amount): - """Returns Lightning invoice and stores it in the db.""" - payment_request, payment_hash = payment_hash, payment_request = await create_invoice( - wallet_id=link.wallet, - amount=amount, - memo=link.description, - unhashed_description=link.description.encode("utf-8"), - extra={ - "tag": "Cashu" - }, - ) +def _get_output_split(amount: int, cashu_id: str): + """Given an amount returns a list of amounts returned e.g. 13 is [1, 4, 8].""" + self._verify_amount(amount) + bits_amt = bin(amount)[::-1][:-2] + rv = [] + for (pos, bit) in enumerate(bits_amt): + if bit == "1": + rv.append(2**pos) + return rv - invoice = Invoice( - amount=amount, pr=payment_request, hash=payment_hash, issued=False - ) - if not payment_request or not payment_hash: - raise Exception(f"Could not create Lightning invoice.") - await store_lightning_invoice(invoice) - return payment_request, payment_hash +async def _invalidate_proofs(proofs: List[Proof], cashu_id: str = Query(None)): + """Adds secrets of proofs to the list of knwon secrets and stores them in the db.""" + # Mark proofs as used and prepare new promises + proof_msgs = set([p.secret for p in proofs]) + self.proofs_used |= proof_msgs + # store in db + for p in proofs: + await invalidate_proof(p) - async def mint(self, B_s: List[PublicKey], amounts: List[int], payment_hash=None): - """Mints a promise for coins for B_.""" - # check if lightning invoice was paid - if payment_hash and not await check_transaction_status(payment_hash): +def get_pubkeys(cashu_id: str = Query(None)): + """Returns public keys for possible amounts.""" + return {a: p.serialize().hex() for a, p in self.pub_keys.items()} + +async def request_mint(amount, cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + + """Returns Lightning invoice and stores it in the db.""" + payment_hash, payment_request = await create_invoice( + wallet_id=cashu.wallet, + amount=amount, + memo=cashu.name, + unhashed_description=cashu.name.encode("utf-8"), + extra={ + "tag": "Cashu" + }, + ) + + invoice = Invoice( + amount=amount, pr=payment_request, hash=payment_hash, issued=False + ) + if not payment_request or not payment_hash: + raise Exception(f"Could not create Lightning invoice.") + return payment_request, payment_hash + +async def mint(B_s: List[PublicKey], amounts: List[int], payment_hash: str = Query(None), cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + + """Mints a promise for coins for B_.""" + # check if lightning invoice was paid + if payment_hash: + if not await check_transaction_status(wallet_id=cashu.wallet, payment_hash=payment_hash): raise Exception("Lightning invoice not paid yet.") - for amount in amounts: - if amount not in [2**i for i in range(MAX_ORDER)]: - raise Exception(f"Can only mint amounts up to {2**MAX_ORDER}.") + for amount in amounts: + if amount not in [2**i for i in range(MAX_ORDER)]: + raise Exception(f"Can only mint amounts up to {2**MAX_ORDER}.") - promises = [ - await self._generate_promise(amount, B_) for B_, amount in zip(B_s, amounts) - ] - return promises + promises = [ + await self._generate_promise(amount, B_) for B_, amount in zip(B_s, amounts) + ] + return promises - async def melt(self, proofs: List[Proof], amount: int, invoice: str): - """Invalidates proofs and pays a Lightning invoice.""" - # if not LIGHTNING: - total = sum([p["amount"] for p in proofs]) - # check that lightning fees are included - assert total + fee_reserve(amount * 1000) >= amount, Exception( - "provided proofs not enough for Lightning payment." - ) +async def melt(proofs: List[Proof], amount: int, invoice: str, cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + + """Invalidates proofs and pays a Lightning invoice.""" + # if not LIGHTNING: + total = sum([p["amount"] for p in proofs]) + # check that lightning fees are included + assert total + fee_reserve(amount * 1000) >= amount, Exception( + "provided proofs not enough for Lightning payment." + ) - status, payment_hash = await pay_invoice( - wallet_id=link.wallet, - payment_request=invoice, - max_sat=amount, - extra={"tag": "Ecash melt"}, - ) + status, payment_hash = await pay_invoice( + wallet_id=link.wallet, + payment_request=invoice, + max_sat=amount, + extra={"tag": "Ecash melt"}, + ) - if status == True: - await self._invalidate_proofs(proofs) - return status, payment_hash - - async def check_spendable(self, proofs: List[Proof]): - """Checks if all provided proofs are valid and still spendable (i.e. have not been spent).""" - return {i: self._check_spendable(p) for i, p in enumerate(proofs)} - - async def split( - self, proofs: List[Proof], amount: int, output_data: List[BlindedMessage] - ): - """Consumes proofs and prepares new promises based on the amount split.""" - self._verify_split_amount(amount) - # Verify proofs are valid - if not all([self._verify_proof(p) for p in proofs]): - return False - - total = sum([p.amount for p in proofs]) - - if not self._verify_no_duplicates(proofs, output_data): - raise Exception("duplicate proofs or promises") - if amount > total: - raise Exception("split amount is higher than the total sum") - if not self._verify_outputs(total, amount, output_data): - raise Exception("split of promises is not as expected") - - # Mark proofs as used and prepare new promises + if status == True: await self._invalidate_proofs(proofs) + return status, payment_hash - outs_fst = amount_split(total - amount) - outs_snd = amount_split(amount) - B_fst = [od.B_ for od in output_data[: len(outs_fst)]] - B_snd = [od.B_ for od in output_data[len(outs_fst) :]] - prom_fst, prom_snd = await self._generate_promises( - outs_fst, B_fst - ), await self._generate_promises(outs_snd, B_snd) - self._verify_equation_balanced(proofs, prom_fst + prom_snd) - return prom_fst, prom_snd +async def check_spendable(proofs: List[Proof], cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + + """Checks if all provided proofs are valid and still spendable (i.e. have not been spent).""" + return {i: self._check_spendable(p) for i, p in enumerate(proofs)} + +async def split(proofs: List[Proof], amount: int, output_data: List[BlindedMessage], cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + + """Consumes proofs and prepares new promises based on the amount split.""" + self._verify_split_amount(amount) + # Verify proofs are valid + if not all([self._verify_proof(p) for p in proofs]): + return False + + total = sum([p.amount for p in proofs]) + + if not self._verify_no_duplicates(proofs, output_data): + raise Exception("duplicate proofs or promises") + if amount > total: + raise Exception("split amount is higher than the total sum") + if not self._verify_outputs(total, amount, output_data): + raise Exception("split of promises is not as expected") + + # Mark proofs as used and prepare new promises + await self._invalidate_proofs(proofs) + + outs_fst = amount_split(total - amount) + outs_snd = amount_split(amount) + B_fst = [od.B_ for od in output_data[: len(outs_fst)]] + B_snd = [od.B_ for od in output_data[len(outs_fst) :]] + prom_fst, prom_snd = await self._generate_promises( + outs_fst, B_fst + ), await self._generate_promises(outs_snd, B_snd) + self._verify_equation_balanced(proofs, prom_fst + prom_snd) + return prom_fst, prom_snd -##############FUNCTIONS############### -def fee_reserve(amount_msat: int) -> int: +async def fee_reserve(amount_msat: int, cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + """Function for calculating the Lightning fee reserve""" return max( int(LIGHTNING_RESERVE_FEE_MIN), int(amount_msat * LIGHTNING_FEE_PERCENT / 100.0) ) -def amount_split(amount): +async def amount_split(amount, cashu_id: str): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + """Given an amount returns a list of amounts returned e.g. 13 is [1, 4, 8].""" bits_amt = bin(amount)[::-1][:-2] rv = [] @@ -241,7 +246,11 @@ def amount_split(amount): rv.append(2**pos) return rv -def hash_to_point(secret_msg): +async def hash_to_point(secret_msg, cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + """Generates x coordinate from the message hash and checks if the point lies on the curve. If it does not, it tries computing again a new x coordinate from the hash of the coordinate.""" point = None @@ -260,24 +269,39 @@ def hash_to_point(secret_msg): return point -def step1_alice(secret_msg): +async def step1_alice(secret_msg, cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + secret_msg = secret_msg.encode("utf-8") Y = hash_to_point(secret_msg) r = PrivateKey() B_ = Y + r.pubkey return B_, r +async def step2_bob(B_, a, cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") -def step2_bob(B_, a): C_ = B_.mult(a) return C_ -def step3_alice(C_, r, A): +async def step3_alice(C_, r, A, cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + C = C_ - A.mult(r) return C -def verify(a, C, secret_msg): +async def verify(a, C, secret_msg, cashu_id: str = Query(None)): + cashu = await get_cashu(cashu_id) + if not cashu: + raise Exception(f"Could not find Cashu") + Y = hash_to_point(secret_msg.encode("utf-8")) return C == Y.mult(a) diff --git a/lnbits/extensions/cashu/migrations.py b/lnbits/extensions/cashu/migrations.py index 53420062..f7d8f4f0 100644 --- a/lnbits/extensions/cashu/migrations.py +++ b/lnbits/extensions/cashu/migrations.py @@ -8,7 +8,7 @@ async def m001_initial(db): id TEXT PRIMARY KEY, wallet TEXT NOT NULL, name TEXT NOT NULL, - tickershort TEXT NOT NULL, + tickershort TEXT DEFAULT 'sats', fraction BOOL, maxsats INT, coins INT, @@ -32,3 +32,32 @@ async def m001_initial(db): """ ) + """ + Initial cashus table. + """ + await db.execute( + """ + CREATE TABLE cashu.promises ( + id TEXT PRIMARY KEY, + amount INT, + B_b TEXT NOT NULL, + C_b TEXT NOT NULL, + cashu_id TEXT NOT NULL + ); + """ + ) + + """ + Initial cashus table. + """ + await db.execute( + """ + CREATE TABLE cashu.proofs_used ( + id TEXT PRIMARY KEY, + amount INT, + C TEXT NOT NULL, + secret TEXT NOT NULL, + cashu_id TEXT NOT NULL + ); + """ + ) \ No newline at end of file diff --git a/lnbits/extensions/cashu/models.py b/lnbits/extensions/cashu/models.py index a673dfe7..094966ff 100644 --- a/lnbits/extensions/cashu/models.py +++ b/lnbits/extensions/cashu/models.py @@ -9,7 +9,7 @@ class Cashu(BaseModel): id: str = Query(None) name: str = Query(None) wallet: str = Query(None) - tickershort: str + tickershort: str = Query(None) fraction: bool = Query(None) maxsats: int = Query(0) coins: int = Query(0) @@ -34,6 +34,13 @@ class Pegs(BaseModel): class PayLnurlWData(BaseModel): lnurl: str +class Promises(BaseModel): + id: str + amount: int + B_b: str + C_b: str + cashu_id: str + class Proof(BaseModel): amount: int secret: str diff --git a/lnbits/extensions/cashu/tasks.py b/lnbits/extensions/cashu/tasks.py index fe00a591..5fbdde8e 100644 --- a/lnbits/extensions/cashu/tasks.py +++ b/lnbits/extensions/cashu/tasks.py @@ -9,7 +9,6 @@ from lnbits.tasks import internal_invoice_queue, register_invoice_listener from .crud import get_cashu - async def wait_for_paid_invoices(): invoice_queue = asyncio.Queue() register_invoice_listener(invoice_queue) diff --git a/lnbits/extensions/cashu/templates/cashu/index.html b/lnbits/extensions/cashu/templates/cashu/index.html index 17b2a919..3cd57d45 100644 --- a/lnbits/extensions/cashu/templates/cashu/index.html +++ b/lnbits/extensions/cashu/templates/cashu/index.html @@ -80,13 +80,10 @@ -
-
@@ -96,6 +93,8 @@
+
Create Mint + :disable="formDialog.data.wallet == null || formDialog.data.name == null" type="submit">Create Mint Cancel
diff --git a/lnbits/extensions/cashu/views.py b/lnbits/extensions/cashu/views.py index 4ac1f1ce..655ed028 100644 --- a/lnbits/extensions/cashu/views.py +++ b/lnbits/extensions/cashu/views.py @@ -22,7 +22,6 @@ async def index(request: Request, user: User = Depends(check_user_exists)): "cashu/index.html", {"request": request, "user": user.dict()} ) - @cashu_ext.get("/wallet") async def cashu(request: Request): return cashu_renderer().TemplateResponse("cashu/wallet.html",{"request": request}) diff --git a/lnbits/extensions/cashu/views_api.py b/lnbits/extensions/cashu/views_api.py index 5cc6e271..391aeda1 100644 --- a/lnbits/extensions/cashu/views_api.py +++ b/lnbits/extensions/cashu/views_api.py @@ -15,10 +15,25 @@ from lnbits.core.views.api import api_payment from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key from . import cashu_ext -from .crud import create_cashu, delete_cashu, get_cashu, get_cashus, update_cashu_keys -from .models import Cashu, Pegs, CheckPayload, MeltPayload, MintPayloads, SplitPayload, PayLnurlWData +from .ledger import get_pubkeys, request_mint, mint -from .ledger import Ledger, fee_reserve, amount_split, hash_to_point, step1_alice, step2_bob, step3_alice, verify +from .crud import ( + create_cashu, + delete_cashu, + get_cashu, + get_cashus, + update_cashu_keys +) + +from .models import ( + Cashu, + Pegs, + CheckPayload, + MeltPayload, + MintPayloads, + SplitPayload, + PayLnurlWData +) @cashu_ext.get("/api/v1/cashus", status_code=HTTPStatus.OK) async def api_cashus( @@ -173,50 +188,54 @@ async def api_cashu_check_invoice(cashu_id: str, payment_hash: str): return status -#################CASHU STUFF################### +######################################## +#################MINT################### +######################################## @cashu_ext.get("/keys") -def keys(): +def keys(cashu_id: str): """Get the public keys of the mint""" - return ledger.get_pubkeys() + return get_pubkeys(cashu_id) @cashu_ext.get("/mint") -async def request_mint(amount: int = 0): +async def mint_pay_request(amount: int = 0, cashu_id: str = Query(None)): """Request minting of tokens. Server responds with a Lightning invoice.""" - payment_request, payment_hash = await ledger.request_mint(amount) + payment_request, payment_hash = await request_mint(amount, cashu_id) print(f"Lightning invoice: {payment_request}") return {"pr": payment_request, "hash": payment_hash} @cashu_ext.post("/mint") -async def mint(payloads: MintPayloads, payment_hash: Union[str, None] = None): +async def mint_coins(payloads: MintPayloads, payment_hash: Union[str, None] = None, cashu_id: str = Query(None)): amounts = [] B_s = [] for payload in payloads.blinded_messages: amounts.append(payload.amount) B_s.append(PublicKey(bytes.fromhex(payload.B_), raw=True)) + promises = await mint(B_s, amounts, payment_hash, cashu_id) + logger.debug(promises) try: - promises = await ledger.mint(B_s, amounts, payment_hash=payment_hash) + promises = await mint(B_s, amounts, payment_hash, cashu_id) return promises except Exception as exc: return {"error": str(exc)} @cashu_ext.post("/melt") -async def melt(payload: MeltPayload): +async def melt_coins(payload: MeltPayload, cashu_id: str = Query(None)): - ok, preimage = await ledger.melt(payload.proofs, payload.amount, payload.invoice) + ok, preimage = await melt(payload.proofs, payload.amount, payload.invoice, cashu_id) return {"paid": ok, "preimage": preimage} @cashu_ext.post("/check") -async def check_spendable(payload: CheckPayload): - return await ledger.check_spendable(payload.proofs) +async def check_spendable_coins(payload: CheckPayload, cashu_id: str = Query(None)): + return await check_spendable(payload.proofs, cashu_id) @cashu_ext.post("/split") -async def split(payload: SplitPayload): +async def spli_coinst(payload: SplitPayload, cashu_id: str = Query(None)): """ Requetst a set of tokens with amount "total" to be split into two newly minted sets with amount "split" and "total-split". @@ -225,7 +244,7 @@ async def split(payload: SplitPayload): amount = payload.amount output_data = payload.output_data.blinded_messages try: - split_return = await ledger.split(proofs, amount, output_data) + split_return = await split(proofs, amount, output_data) except Exception as exc: return {"error": str(exc)} if not split_return: From 3b70d45091e6d69aac04a207c59e1115eba8c76f Mon Sep 17 00:00:00 2001 From: callebtc <93376500+callebtc@users.noreply.github.com> Date: Tue, 4 Oct 2022 09:56:15 +0200 Subject: [PATCH 0020/1058] .env variable for STARTUP_INVOICE_EXPIRY_CHECK --- .env.example | 2 ++ lnbits/settings.py | 1 + lnbits/tasks.py | 4 ++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 93b82325..1c7d1529 100644 --- a/.env.example +++ b/.env.example @@ -32,6 +32,8 @@ LNBITS_SERVICE_FEE="0.0" LNBITS_RESERVE_FEE_MIN=2000 # value in percent LNBITS_RESERVE_FEE_PERCENT=1.0 +# check invoice expiry on every startup (can be slow on large instances) +STARTUP_INVOICE_EXPIRY_CHECK=True # Change theme LNBITS_SITE_TITLE="LNbits" diff --git a/lnbits/settings.py b/lnbits/settings.py index 3f4e31cc..9fc3c197 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -64,6 +64,7 @@ PREFER_SECURE_URLS = env.bool("LNBITS_FORCE_HTTPS", default=True) RESERVE_FEE_MIN = env.int("LNBITS_RESERVE_FEE_MIN", default=2000) RESERVE_FEE_PERCENT = env.float("LNBITS_RESERVE_FEE_PERCENT", default=1.0) SERVICE_FEE = env.float("LNBITS_SERVICE_FEE", default=0.0) +STARTUP_INVOICE_EXPIRY_CHECK = env.bool("STARTUP_INVOICE_EXPIRY_CHECK", default=True) try: LNBITS_COMMIT = ( diff --git a/lnbits/tasks.py b/lnbits/tasks.py index 94e43dcf..26758303 100644 --- a/lnbits/tasks.py +++ b/lnbits/tasks.py @@ -15,7 +15,7 @@ from lnbits.core.crud import ( get_standalone_payment, ) from lnbits.core.services import redeem_lnurl_withdraw -from lnbits.settings import WALLET +from lnbits.settings import WALLET, STARTUP_INVOICE_EXPIRY_CHECK from .core import db @@ -144,7 +144,7 @@ async def check_pending_payments(): f"Task: pending check finished for {len(pending_payments)} payments (took {time.time() - start_time:0.3f} s)" ) # we delete expired invoices once upon the first pending check - if incoming: + if incoming and STARTUP_INVOICE_EXPIRY_CHECK: logger.debug("Task: deleting all expired invoices") start_time: float = time.time() await delete_expired_invoices(conn=conn) From 166530eb0c985575a140124fb4c9e5a23ee9e5a7 Mon Sep 17 00:00:00 2001 From: benarc Date: Mon, 7 Mar 2022 05:03:32 +0000 Subject: [PATCH 0021/1058] Added old admin extension --- .env.example | 12 +- lnbits/extensions/admin/README.md | 11 + lnbits/extensions/admin/__init__.py | 10 + lnbits/extensions/admin/config.json | 6 + lnbits/extensions/admin/crud.py | 59 ++ lnbits/extensions/admin/migrations.py | 256 ++++++++ lnbits/extensions/admin/models.py | 38 ++ .../admin/templates/admin/index.html | 565 ++++++++++++++++++ lnbits/extensions/admin/views.py | 20 + lnbits/extensions/admin/views_api.py | 41 ++ 10 files changed, 1013 insertions(+), 5 deletions(-) create mode 100644 lnbits/extensions/admin/README.md create mode 100644 lnbits/extensions/admin/__init__.py create mode 100644 lnbits/extensions/admin/config.json create mode 100644 lnbits/extensions/admin/crud.py create mode 100644 lnbits/extensions/admin/migrations.py create mode 100644 lnbits/extensions/admin/models.py create mode 100644 lnbits/extensions/admin/templates/admin/index.html create mode 100644 lnbits/extensions/admin/views.py create mode 100644 lnbits/extensions/admin/views_api.py diff --git a/.env.example b/.env.example index 93b82325..68e25ad1 100644 --- a/.env.example +++ b/.env.example @@ -3,10 +3,12 @@ PORT=5000 DEBUG=false -LNBITS_ALLOWED_USERS="" -LNBITS_ADMIN_USERS="" -# Extensions only admin can access -LNBITS_ADMIN_EXTENSIONS="ngrok" +LNBITS_ADMIN_USERS="" # User IDs seperated by comma +LNBITS_ADMIN_EXTENSIONS="ngrok" # Extensions only admin can access +LNBITS_ADMIN_UI=false # Extensions only admin can access + +LNBITS_ALLOWED_USERS="" # Restricts access, User IDs seperated by comma + LNBITS_DEFAULT_WALLET_NAME="LNbits wallet" # csv ad image filepaths or urls, extensions can choose to honor @@ -91,4 +93,4 @@ LNBITS_DENOMINATION=sats # EclairWallet ECLAIR_URL=http://127.0.0.1:8283 -ECLAIR_PASS=eclairpw \ No newline at end of file +ECLAIR_PASS=eclairpw diff --git a/lnbits/extensions/admin/README.md b/lnbits/extensions/admin/README.md new file mode 100644 index 00000000..27729459 --- /dev/null +++ b/lnbits/extensions/admin/README.md @@ -0,0 +1,11 @@ +

Example Extension

+

*tagline*

+This is an example extension to help you organise and build you own. + +Try to include an image + + + +

If your extension has API endpoints, include useful ones here

+ +curl -H "Content-type: application/json" -X POST https://YOUR-LNBITS/YOUR-EXTENSION/api/v1/EXAMPLE -d '{"amount":"100","memo":"example"}' -H "X-Api-Key: YOUR_WALLET-ADMIN/INVOICE-KEY" diff --git a/lnbits/extensions/admin/__init__.py b/lnbits/extensions/admin/__init__.py new file mode 100644 index 00000000..d5f26c90 --- /dev/null +++ b/lnbits/extensions/admin/__init__.py @@ -0,0 +1,10 @@ +from quart import Blueprint +from lnbits.db import Database + +db = Database("ext_admin") + +admin_ext: Blueprint = Blueprint("admin", __name__, static_folder="static", template_folder="templates") + + +from .views_api import * # noqa +from .views import * # noqa diff --git a/lnbits/extensions/admin/config.json b/lnbits/extensions/admin/config.json new file mode 100644 index 00000000..69661733 --- /dev/null +++ b/lnbits/extensions/admin/config.json @@ -0,0 +1,6 @@ +{ + "name": "Admin", + "short_description": "Manage your LNbits install", + "icon": "build", + "contributors": ["benarc"] +} diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py new file mode 100644 index 00000000..cb8f9b5b --- /dev/null +++ b/lnbits/extensions/admin/crud.py @@ -0,0 +1,59 @@ +from typing import List, Optional + +from . import db +from .models import Admin, Funding +from lnbits.settings import * +from lnbits.helpers import urlsafe_short_hash +from lnbits.core.crud import create_payment +from lnbits.db import Connection + + +def update_wallet_balance(wallet_id: str, amount: int) -> str: + temp_id = f"temp_{urlsafe_short_hash()}" + internal_id = f"internal_{urlsafe_short_hash()}" + create_payment( + wallet_id=wallet_id, + checking_id=internal_id, + payment_request="admin_internal", + payment_hash="admin_internal", + amount=amount * 1000, + memo="Admin top up", + pending=False, + ) + return "success" + + +async def update_admin( +) -> Optional[Admin]: + if not CLightningWallet: + print("poo") + await db.execute( + """ + UPDATE admin + SET user = ?, site_title = ?, site_tagline = ?, site_description = ?, allowed_users = ?, default_wallet_name = ?, data_folder = ?, disabled_ext = ?, force_https = ?, service_fee = ?, funding_source = ? + WHERE 1 + """, + ( + + ), + ) + row = await db.fetchone("SELECT * FROM admin WHERE 1") + return Admin.from_row(row) if row else None + +async def update_admin(admin_id: str, **kwargs) -> Optional[Admin]: + q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) + await db.execute( + f"UPDATE jukebox.jukebox SET {q} WHERE id = ?", (*kwargs.values(), juke_id) + ) + row = await db.fetchone("SELECT * FROM jukebox.jukebox WHERE id = ?", (juke_id,)) + return Jukebox(**row) if row else None + +async def get_admin() -> List[Admin]: + row = await db.fetchone("SELECT * FROM admin WHERE 1") + return Admin.from_row(row) if row else None + + +async def get_funding() -> List[Funding]: + rows = await db.fetchall("SELECT * FROM funding") + + return [Funding.from_row(row) for row in rows] diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py new file mode 100644 index 00000000..82d934cb --- /dev/null +++ b/lnbits/extensions/admin/migrations.py @@ -0,0 +1,256 @@ +from sqlalchemy.exc import OperationalError # type: ignore +from os import getenv +from lnbits.helpers import urlsafe_short_hash + + +async def m001_create_admin_table(db): + user = None + site_title = None + site_tagline = None + site_description = None + allowed_users = None + admin_user = None + default_wallet_name = None + data_folder = None + disabled_ext = None + force_https = True + service_fee = 0 + funding_source = "" + + if getenv("LNBITS_SITE_TITLE"): + site_title = getenv("LNBITS_SITE_TITLE") + + if getenv("LNBITS_SITE_TAGLINE"): + site_tagline = getenv("LNBITS_SITE_TAGLINE") + + if getenv("LNBITS_SITE_DESCRIPTION"): + site_description = getenv("LNBITS_SITE_DESCRIPTION") + + if getenv("LNBITS_ALLOWED_USERS"): + allowed_users = getenv("LNBITS_ALLOWED_USERS") + + if getenv("LNBITS_ADMIN_USER"): + admin_user = getenv("LNBITS_ADMIN_USER") + + if getenv("LNBITS_DEFAULT_WALLET_NAME"): + default_wallet_name = getenv("LNBITS_DEFAULT_WALLET_NAME") + + if getenv("LNBITS_DATA_FOLDER"): + data_folder = getenv("LNBITS_DATA_FOLDER") + + if getenv("LNBITS_DISABLED_EXTENSIONS"): + disabled_ext = getenv("LNBITS_DISABLED_EXTENSIONS") + + if getenv("LNBITS_FORCE_HTTPS"): + force_https = getenv("LNBITS_FORCE_HTTPS") + + if getenv("LNBITS_SERVICE_FEE"): + service_fee = getenv("LNBITS_SERVICE_FEE") + + if getenv("LNBITS_BACKEND_WALLET_CLASS"): + funding_source = getenv("LNBITS_BACKEND_WALLET_CLASS") + + await db.execute( + """ + CREATE TABLE IF NOT EXISTS admin ( + user TEXT, + site_title TEXT, + site_tagline TEXT, + site_description TEXT, + admin_user TEXT, + allowed_users TEXT, + default_wallet_name TEXT, + data_folder TEXT, + disabled_ext TEXT, + force_https BOOLEAN, + service_fee INT, + funding_source TEXT + ); + """ + ) + await db.execute( + """ + INSERT INTO admin (user, site_title, site_tagline, site_description, admin_user, allowed_users, default_wallet_name, data_folder, disabled_ext, force_https, service_fee, funding_source) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, + ( + user, + site_title, + site_tagline, + site_description, + admin_user, + allowed_users, + default_wallet_name, + data_folder, + disabled_ext, + force_https, + service_fee, + funding_source, + ), + ) + + +async def m001_create_funding_table(db): + + funding_wallet = getenv("LNBITS_BACKEND_WALLET_CLASS") + + # Make the funding table, if it does not already exist + await db.execute( + """ + CREATE TABLE IF NOT EXISTS funding ( + id TEXT PRIMARY KEY, + backend_wallet TEXT, + endpoint TEXT, + port INT, + read_key TEXT, + invoice_key TEXT, + admin_key TEXT, + cert TEXT, + balance INT, + selected INT + ); + """ + ) + + await db.execute( + """ + INSERT INTO funding (id, backend_wallet, endpoint, selected) + VALUES (?, ?, ?, ?) + """, + ( + urlsafe_short_hash(), + "CLightningWallet", + getenv("CLIGHTNING_RPC"), + 1 if funding_wallet == "CLightningWallet" else 0, + ), + ) + await db.execute( + """ + INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + VALUES (?, ?, ?, ?, ?) + """, + ( + urlsafe_short_hash(), + "SparkWallet", + getenv("SPARK_URL"), + getenv("SPARK_TOKEN"), + 1 if funding_wallet == "SparkWallet" else 0, + ), + ) + + await db.execute( + """ + INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + VALUES (?, ?, ?, ?, ?) + """, + ( + urlsafe_short_hash(), + "LnbitsWallet", + getenv("LNBITS_ENDPOINT"), + getenv("LNBITS_KEY"), + 1 if funding_wallet == "LnbitsWallet" else 0, + ), + ) + + await db.execute( + """ + INSERT INTO funding (id, backend_wallet, endpoint, port, admin_key, cert, selected) + VALUES (?, ?, ?, ?, ?, ?, ?) + """, + ( + urlsafe_short_hash(), + "LndWallet", + getenv("LND_GRPC_ENDPOINT"), + getenv("LND_GRPC_PORT"), + getenv("LND_GRPC_MACAROON"), + getenv("LND_GRPC_CERT"), + 1 if funding_wallet == "LndWallet" else 0, + ), + ) + + await db.execute( + """ + INSERT INTO funding (id, backend_wallet, endpoint, admin_key, cert, selected) + VALUES (?, ?, ?, ?, ?, ?) + """, + ( + urlsafe_short_hash(), + "LndRestWallet", + getenv("LND_REST_ENDPOINT"), + getenv("LND_REST_MACAROON"), + getenv("LND_REST_CERT"), + 1 if funding_wallet == "LndWallet" else 0, + ), + ) + + await db.execute( + """ + INSERT INTO funding (id, backend_wallet, endpoint, admin_key, cert, selected) + VALUES (?, ?, ?, ?, ?, ?) + """, + ( + urlsafe_short_hash(), + "LNPayWallet", + getenv("LNPAY_API_ENDPOINT"), + getenv("LNPAY_WALLET_KEY"), + getenv("LNPAY_API_KEY"), # this is going in as the cert + 1 if funding_wallet == "LNPayWallet" else 0, + ), + ) + + await db.execute( + """ + INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + VALUES (?, ?, ?, ?, ?) + """, + ( + urlsafe_short_hash(), + "LntxbotWallet", + getenv("LNTXBOT_API_ENDPOINT"), + getenv("LNTXBOT_KEY"), + 1 if funding_wallet == "LntxbotWallet" else 0, + ), + ) + + await db.execute( + """ + INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + VALUES (?, ?, ?, ?, ?) + """, + ( + urlsafe_short_hash(), + "OpenNodeWallet", + getenv("OPENNODE_API_ENDPOINT"), + getenv("OPENNODE_KEY"), + 1 if funding_wallet == "OpenNodeWallet" else 0, + ), + ) + + await db.execute( + """ + INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + VALUES (?, ?, ?, ?, ?) + """, + ( + urlsafe_short_hash(), + "SparkWallet", + getenv("SPARK_URL"), + getenv("SPARK_TOKEN"), + 1 if funding_wallet == "SparkWallet" else 0, + ), + ) + + ## PLACEHOLDER FOR ECLAIR WALLET + # await db.execute( + # """ + # INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + # VALUES (?, ?, ?, ?, ?) + # """, + # ( + # urlsafe_short_hash(), + # "EclairWallet", + # getenv("ECLAIR_URL"), + # getenv("ECLAIR_PASS"), + # 1 if funding_wallet == "EclairWallet" else 0, + # ), + # ) diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py new file mode 100644 index 00000000..c38f17f4 --- /dev/null +++ b/lnbits/extensions/admin/models.py @@ -0,0 +1,38 @@ +from typing import NamedTuple +from sqlite3 import Row + +class Admin(NamedTuple): + user: str + site_title: str + site_tagline: str + site_description:str + allowed_users: str + admin_user: str + default_wallet_name: str + data_folder: str + disabled_ext: str + force_https: str + service_fee: str + funding_source: str + + @classmethod + def from_row(cls, row: Row) -> "Admin": + data = dict(row) + return cls(**data) + +class Funding(NamedTuple): + id: str + backend_wallet: str + endpoint: str + port: str + read_key: str + invoice_key: str + admin_key: str + cert: str + balance: int + selected: int + + @classmethod + def from_row(cls, row: Row) -> "Funding": + data = dict(row) + return cls(**data) diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html new file mode 100644 index 00000000..87cf09ef --- /dev/null +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -0,0 +1,565 @@ +{% extends "base.html" %} {% from "macros.jinja" import window_vars with context +%} {% block page %} + +

Admin

+

+ +
+
+ + +
Settings
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+ + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+

+
+
+ +
+
+
+
+ +
+ + +
Wallet topup
+
+
+ +
+
+ +
+
+
+ +
+
+
+
+
+ +{% endblock %} {% block scripts %} {{ window_vars(user) }} + +{% endblock %} diff --git a/lnbits/extensions/admin/views.py b/lnbits/extensions/admin/views.py new file mode 100644 index 00000000..5e17919c --- /dev/null +++ b/lnbits/extensions/admin/views.py @@ -0,0 +1,20 @@ +from quart import g, render_template, request, jsonify +import json + +from lnbits.decorators import check_user_exists, validate_uuids +from lnbits.extensions.admin import admin_ext +from lnbits.core.crud import get_user, create_account +from .crud import get_admin, get_funding +from lnbits.settings import WALLET + + +@admin_ext.route("/") +@validate_uuids(["usr"], required=True) +@check_user_exists() +async def index(): + user_id = g.user + admin = await get_admin() + + funding = [{**funding._asdict()} for funding in await get_funding()] + + return await render_template("admin/index.html", user=g.user, admin=admin, funding=funding) diff --git a/lnbits/extensions/admin/views_api.py b/lnbits/extensions/admin/views_api.py new file mode 100644 index 00000000..2a61b6f5 --- /dev/null +++ b/lnbits/extensions/admin/views_api.py @@ -0,0 +1,41 @@ +from quart import jsonify, g, request +from http import HTTPStatus +from .crud import update_wallet_balance +from lnbits.extensions.admin import admin_ext +from lnbits.decorators import api_check_wallet_key, api_validate_post_request +from lnbits.core.crud import get_wallet +from .crud import get_admin,update_admin +import json + +@admin_ext.route("/api/v1/admin//", methods=["GET"]) +@api_check_wallet_key("admin") +async def api_update_balance(wallet_id, topup_amount): + print(g.data.wallet) + try: + wallet = await get_wallet(wallet_id) + except: + return ( + jsonify({"error": "Not allowed: not an admin"}), + HTTPStatus.FORBIDDEN, + ) + print(wallet) + print(topup_amount) + return jsonify({"status": "Success"}), HTTPStatus.OK + + +@admin_ext.route("/api/v1/admin/", methods=["POST"]) +@api_check_wallet_key("admin") +@api_validate_post_request(schema={}) +async def api_update_admin(): + body = await request.get_json() + admin = await get_admin() + print(g.wallet[2]) + print(body["admin_user"]) + if not admin.admin_user == g.wallet[2] and admin.admin_user != None: + return ( + jsonify({"error": "Not allowed: not an admin"}), + HTTPStatus.FORBIDDEN, + ) + updated = await update_admin(body) + print(updated) + return jsonify({"status": "Success"}), HTTPStatus.OK \ No newline at end of file From 68eee00b45170db4e35fa6fdafba85373958e9fa Mon Sep 17 00:00:00 2001 From: benarc Date: Mon, 7 Mar 2022 05:11:55 +0000 Subject: [PATCH 0022/1058] old admin setup UI --- lnbits/core/templates/core/admin.html | 717 ++++++++++++++++++++++++++ 1 file changed, 717 insertions(+) create mode 100644 lnbits/core/templates/core/admin.html diff --git a/lnbits/core/templates/core/admin.html b/lnbits/core/templates/core/admin.html new file mode 100644 index 00000000..e8176555 --- /dev/null +++ b/lnbits/core/templates/core/admin.html @@ -0,0 +1,717 @@ +{% extends "public.html" %} {% from "macros.jinja" import window_vars with +context %} {% block page %} +
+
+ + +

+
Welcome to LNbits
+

+
+ Fill in the information below to setup your LNbits instance. Details + can be changed later. +
+

+ + +
+ +
Branding
+
+
+ +
+
+ +
+
+
+
+ + + +
+
+ + + +
+
+ +
Service settings
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+ Funding source information (at least one required)
*if installed through RaspiBlitz, MyNode, etc, details + should be filled in for you
+
+ + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+
+
+
+
+ +
+ + +
+
+
+
+ View project in GitHub + Donate +
+
+
+
+
+{% endblock %} {% block scripts %} {{ window_vars(funding) }} + +{% endblock %} From 65e1f19ed1124340d2a9ba97b4420c099896488c Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Sat, 12 Mar 2022 14:18:09 +0000 Subject: [PATCH 0023/1058] convert to FastAPI --- lnbits/extensions/admin/__init__.py | 11 +++- lnbits/extensions/admin/crud.py | 50 +++++++-------- lnbits/extensions/admin/migrations.py | 23 ++++--- lnbits/extensions/admin/models.py | 51 ++++++++++------ .../admin/templates/admin/index.html | 23 +++++-- lnbits/extensions/admin/views.py | 39 ++++++++---- lnbits/extensions/admin/views_api.py | 61 ++++++++++--------- 7 files changed, 151 insertions(+), 107 deletions(-) diff --git a/lnbits/extensions/admin/__init__.py b/lnbits/extensions/admin/__init__.py index d5f26c90..6a56b2bb 100644 --- a/lnbits/extensions/admin/__init__.py +++ b/lnbits/extensions/admin/__init__.py @@ -1,10 +1,15 @@ -from quart import Blueprint +from fastapi import APIRouter + from lnbits.db import Database +from lnbits.helpers import template_renderer db = Database("ext_admin") -admin_ext: Blueprint = Blueprint("admin", __name__, static_folder="static", template_folder="templates") +admin_ext: APIRouter = APIRouter(prefix="/admin", tags=["admin"]) + +def admin_renderer(): + return template_renderer(["lnbits/extensions/admin/templates"]) -from .views_api import * # noqa from .views import * # noqa +from .views_api import * # noqa diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py index cb8f9b5b..872d6c97 100644 --- a/lnbits/extensions/admin/crud.py +++ b/lnbits/extensions/admin/crud.py @@ -1,11 +1,11 @@ from typing import List, Optional +from lnbits.core.crud import create_payment +from lnbits.helpers import urlsafe_short_hash +from lnbits.settings import * + from . import db from .models import Admin, Funding -from lnbits.settings import * -from lnbits.helpers import urlsafe_short_hash -from lnbits.core.crud import create_payment -from lnbits.db import Connection def update_wallet_balance(wallet_id: str, amount: int) -> str: @@ -22,38 +22,30 @@ def update_wallet_balance(wallet_id: str, amount: int) -> str: ) return "success" - -async def update_admin( -) -> Optional[Admin]: - if not CLightningWallet: - print("poo") - await db.execute( - """ - UPDATE admin - SET user = ?, site_title = ?, site_tagline = ?, site_description = ?, allowed_users = ?, default_wallet_name = ?, data_folder = ?, disabled_ext = ?, force_https = ?, service_fee = ?, funding_source = ? - WHERE 1 - """, - ( - - ), - ) - row = await db.fetchone("SELECT * FROM admin WHERE 1") - return Admin.from_row(row) if row else None - -async def update_admin(admin_id: str, **kwargs) -> Optional[Admin]: +async def update_admin(user: str, **kwargs) -> Admin: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) + print("UPDATE", q) await db.execute( - f"UPDATE jukebox.jukebox SET {q} WHERE id = ?", (*kwargs.values(), juke_id) + f'UPDATE admin SET {q} WHERE "user" = ?', (*kwargs.values(), user) ) - row = await db.fetchone("SELECT * FROM jukebox.jukebox WHERE id = ?", (juke_id,)) - return Jukebox(**row) if row else None + row = await db.fetchone('SELECT * FROM admin WHERE "user" = ?', (user,)) + assert row, "Newly updated settings couldn't be retrieved" + return Admin(**row) if row else None + +# async def update_admin(user: str, **kwargs) -> Optional[Admin]: +# q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) +# await db.execute( +# f"UPDATE admin SET {q} WHERE user = ?", (*kwargs.values(), user) +# ) +# new_settings = await get_admin() +# return new_settings async def get_admin() -> List[Admin]: - row = await db.fetchone("SELECT * FROM admin WHERE 1") - return Admin.from_row(row) if row else None + row = await db.fetchone("SELECT * FROM admin") + return Admin(**row) if row else None async def get_funding() -> List[Funding]: rows = await db.fetchall("SELECT * FROM funding") - return [Funding.from_row(row) for row in rows] + return [Funding(**row) for row in rows] diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index 82d934cb..13b76923 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -1,5 +1,7 @@ -from sqlalchemy.exc import OperationalError # type: ignore from os import getenv + +from sqlalchemy.exc import OperationalError # type: ignore + from lnbits.helpers import urlsafe_short_hash @@ -9,7 +11,7 @@ async def m001_create_admin_table(db): site_tagline = None site_description = None allowed_users = None - admin_user = None + admin_users = None default_wallet_name = None data_folder = None disabled_ext = None @@ -29,8 +31,9 @@ async def m001_create_admin_table(db): if getenv("LNBITS_ALLOWED_USERS"): allowed_users = getenv("LNBITS_ALLOWED_USERS") - if getenv("LNBITS_ADMIN_USER"): - admin_user = getenv("LNBITS_ADMIN_USER") + if getenv("LNBITS_ADMIN_USERS"): + admin_users = "".join(getenv("LNBITS_ADMIN_USERS").split()) + user = admin_users.split(',')[0] if getenv("LNBITS_DEFAULT_WALLET_NAME"): default_wallet_name = getenv("LNBITS_DEFAULT_WALLET_NAME") @@ -53,32 +56,32 @@ async def m001_create_admin_table(db): await db.execute( """ CREATE TABLE IF NOT EXISTS admin ( - user TEXT, + "user" TEXT, site_title TEXT, site_tagline TEXT, site_description TEXT, - admin_user TEXT, + admin_users TEXT, allowed_users TEXT, default_wallet_name TEXT, data_folder TEXT, disabled_ext TEXT, force_https BOOLEAN, - service_fee INT, + service_fee REAL, funding_source TEXT ); """ ) await db.execute( """ - INSERT INTO admin (user, site_title, site_tagline, site_description, admin_user, allowed_users, default_wallet_name, data_folder, disabled_ext, force_https, service_fee, funding_source) + INSERT INTO admin ("user", site_title, site_tagline, site_description, admin_users, allowed_users, default_wallet_name, data_folder, disabled_ext, force_https, service_fee, funding_source) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( - user, + user.strip(), site_title, site_tagline, site_description, - admin_user, + admin_users[1:], allowed_users, default_wallet_name, data_folder, diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py index c38f17f4..4080ff01 100644 --- a/lnbits/extensions/admin/models.py +++ b/lnbits/extensions/admin/models.py @@ -1,18 +1,35 @@ -from typing import NamedTuple from sqlite3 import Row +from typing import List, Optional -class Admin(NamedTuple): +from fastapi import Query +from pydantic import BaseModel + + +class UpdateAdminSettings(BaseModel): + site_title: Optional[str] + site_tagline: Optional[str] + site_description: Optional[str] + allowed_users: Optional[str] + admin_users: Optional[str] + default_wallet_name: Optional[str] + data_folder: Optional[str] + disabled_ext: Optional[str] + force_https: Optional[bool] + service_fee: Optional[float] + funding_source: Optional[str] + +class Admin(BaseModel): user: str - site_title: str - site_tagline: str - site_description:str - allowed_users: str - admin_user: str + site_title: Optional[str] + site_tagline: Optional[str] + site_description: Optional[str] + allowed_users: Optional[str] + admin_users: str default_wallet_name: str data_folder: str disabled_ext: str - force_https: str - service_fee: str + force_https: Optional[bool] = Query(True) + service_fee: float funding_source: str @classmethod @@ -20,16 +37,16 @@ class Admin(NamedTuple): data = dict(row) return cls(**data) -class Funding(NamedTuple): +class Funding(BaseModel): id: str backend_wallet: str - endpoint: str - port: str - read_key: str - invoice_key: str - admin_key: str - cert: str - balance: int + endpoint: str = Query(None) + port: str = Query(None) + read_key: str = Query(None) + invoice_key: str = Query(None) + admin_key: str = Query(None) + cert: str = Query(None) + balance: int = Query(None) selected: int @classmethod diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index 87cf09ef..a6b45625 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -87,7 +87,7 @@ @@ -442,13 +442,14 @@ site_title: '{{admin.site_title}}', tagline: '{{admin.site_tagline}}', description: '{{admin.site_description}}', - admin_user: '{{admin.admin_user}}', - service_fee: parseInt('{{admin.service_fee}}'), + admin_users: '{{admin.admin_users}}', + service_fee: parseFloat('{{admin.service_fee}}'), default_wallet_name: '{{admin.default_wallet_name}}', data_folder: '{{admin.data_folder}}', funding_source_primary: '{{admin.funding_source}}', disabled_ext: '{{admin.disabled_ext}}'.split(','), edited: [], + funding: {}, senddata: {} } }, @@ -528,15 +529,27 @@ }, UpdateLNbits: function () { var self = this - console.log(self.data.admin) + let {site_title, admin_users, default_wallet_name, data_folder, disabled_ext, service_fee, funding_source_primary} = this.data.admin + let data = { + site_title, + site_tagline: this.data.admin.tagline, + site_description: this.data.admin.description, + admin_users: admin_users.toString(), + default_wallet_name, + data_folder, + disabled_ext: disabled_ext.toString(), + service_fee, + funding_source: funding_source_primary} + console.log(data) LNbits.api .request( 'POST', '/admin/api/v1/admin/', self.g.user.wallets[0].adminkey, - self.data.admin + data ) .then(function (response) { + console.log(response.data) self.$q.notify({ type: 'positive', message: diff --git a/lnbits/extensions/admin/views.py b/lnbits/extensions/admin/views.py index 5e17919c..00a0c99f 100644 --- a/lnbits/extensions/admin/views.py +++ b/lnbits/extensions/admin/views.py @@ -1,20 +1,33 @@ -from quart import g, render_template, request, jsonify -import json +from email.policy import default +from os import getenv -from lnbits.decorators import check_user_exists, validate_uuids +from fastapi import Request +from fastapi.params import Depends +from fastapi.templating import Jinja2Templates +from starlette.responses import HTMLResponse + +from lnbits.core.models import User +from lnbits.decorators import check_user_exists from lnbits.extensions.admin import admin_ext -from lnbits.core.crud import get_user, create_account +from lnbits.requestvars import g + +from . import admin_ext, admin_renderer from .crud import get_admin, get_funding -from lnbits.settings import WALLET +templates = Jinja2Templates(directory="templates") -@admin_ext.route("/") -@validate_uuids(["usr"], required=True) -@check_user_exists() -async def index(): - user_id = g.user +@admin_ext.get("/", response_class=HTMLResponse) +async def index(request: Request, user: User = Depends(check_user_exists)): admin = await get_admin() + print(g()) + funding = [f.dict() for f in await get_funding()] - funding = [{**funding._asdict()} for funding in await get_funding()] - - return await render_template("admin/index.html", user=g.user, admin=admin, funding=funding) + print("ADMIN", admin.dict()) + return admin_renderer().TemplateResponse( + "admin/index.html", { + "request": request, + "user": user.dict(), + "admin": admin.dict(), + "funding": funding + } + ) diff --git a/lnbits/extensions/admin/views_api.py b/lnbits/extensions/admin/views_api.py index 2a61b6f5..b2c65be2 100644 --- a/lnbits/extensions/admin/views_api.py +++ b/lnbits/extensions/admin/views_api.py @@ -1,41 +1,42 @@ -from quart import jsonify, g, request from http import HTTPStatus -from .crud import update_wallet_balance -from lnbits.extensions.admin import admin_ext -from lnbits.decorators import api_check_wallet_key, api_validate_post_request -from lnbits.core.crud import get_wallet -from .crud import get_admin,update_admin -import json -@admin_ext.route("/api/v1/admin//", methods=["GET"]) -@api_check_wallet_key("admin") -async def api_update_balance(wallet_id, topup_amount): - print(g.data.wallet) +from fastapi import Body, Depends, Request +from starlette.exceptions import HTTPException + +from lnbits.core.crud import get_wallet +from lnbits.decorators import WalletTypeInfo, require_admin_key +from lnbits.extensions.admin import admin_ext +from lnbits.extensions.admin.models import Admin, UpdateAdminSettings + +from .crud import get_admin, update_admin, update_wallet_balance + + +@admin_ext.get("/api/v1/admin/{wallet_id}/{topup_amount}", status_code=HTTPStatus.OK) +async def api_update_balance(wallet_id, topup_amount, g: WalletTypeInfo = Depends(require_admin_key)): + print(g.wallet) try: wallet = await get_wallet(wallet_id) except: - return ( - jsonify({"error": "Not allowed: not an admin"}), - HTTPStatus.FORBIDDEN, - ) + raise HTTPException( + status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" + ) print(wallet) print(topup_amount) - return jsonify({"status": "Success"}), HTTPStatus.OK + return {"status": "Success"} -@admin_ext.route("/api/v1/admin/", methods=["POST"]) -@api_check_wallet_key("admin") -@api_validate_post_request(schema={}) -async def api_update_admin(): - body = await request.get_json() +@admin_ext.post("/api/v1/admin/", status_code=HTTPStatus.OK) +async def api_update_admin( + request: Request, + data: UpdateAdminSettings = Body(...), + g: WalletTypeInfo = Depends(require_admin_key) + ): admin = await get_admin() - print(g.wallet[2]) - print(body["admin_user"]) - if not admin.admin_user == g.wallet[2] and admin.admin_user != None: - return ( - jsonify({"error": "Not allowed: not an admin"}), - HTTPStatus.FORBIDDEN, - ) - updated = await update_admin(body) + print(data) + if not admin.user == g.wallet.user: + raise HTTPException( + status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" + ) + updated = await update_admin(user=g.wallet.user, **data.dict()) print(updated) - return jsonify({"status": "Success"}), HTTPStatus.OK \ No newline at end of file + return {"status": "Success"} From 23d770a07489c3d74cc0c4c4d3b4a3b4b00fc393 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Sat, 12 Mar 2022 14:18:58 +0000 Subject: [PATCH 0024/1058] remove core admin html (renamed for now) --- lnbits/core/templates/core/core_admin.html | 717 +++++++++++++++++++++ 1 file changed, 717 insertions(+) create mode 100644 lnbits/core/templates/core/core_admin.html diff --git a/lnbits/core/templates/core/core_admin.html b/lnbits/core/templates/core/core_admin.html new file mode 100644 index 00000000..835fc00a --- /dev/null +++ b/lnbits/core/templates/core/core_admin.html @@ -0,0 +1,717 @@ +{% extends "public.html" %} {% from "macros.jinja" import window_vars with +context %} {% block page %} +
+
+ + +

+
Welcome to LNbits
+

+
+ Fill in the information below to setup your LNbits instance. Details + can be changed later. +
+

+ + +
+ +
Branding
+
+
+ +
+
+ +
+
+
+
+ + + +
+
+ + + +
+
+ +
Service settings
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+ Funding source information (at least one required)
*if installed through RaspiBlitz, MyNode, etc, details + should be filled in for you
+
+ + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+
+
+
+
+ +
+ + +
+
+
+
+ View project in GitHub + Donate +
+
+
+
+
+{% endblock %} {% block scripts %} {{ window_vars(funding) }} + +{% endblock %} From 165ab6d0b50b49cad69b46100bce0f87fd6f7257 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Sat, 12 Mar 2022 14:21:38 +0000 Subject: [PATCH 0025/1058] typo --- .env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.example b/.env.example index 68e25ad1..bd189484 100644 --- a/.env.example +++ b/.env.example @@ -5,7 +5,7 @@ DEBUG=false LNBITS_ADMIN_USERS="" # User IDs seperated by comma LNBITS_ADMIN_EXTENSIONS="ngrok" # Extensions only admin can access -LNBITS_ADMIN_UI=false # Extensions only admin can access +LNBITS_ADMIN_UI=false # Enable Admin GUI, available for the first user in LNBITS_ADMIN_USERS LNBITS_ALLOWED_USERS="" # Restricts access, User IDs seperated by comma From 844e11edeb441fd2e7c7b40d11c25cc4019471bf Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Sat, 12 Mar 2022 14:22:23 +0000 Subject: [PATCH 0026/1058] add admin_ui env --- lnbits/settings.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lnbits/settings.py b/lnbits/settings.py index 3f4e31cc..43cb87cb 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -1,5 +1,6 @@ import importlib import subprocess +from email.policy import default from os import path from typing import List @@ -27,6 +28,7 @@ LNBITS_DATABASE_URL = env.str("LNBITS_DATABASE_URL", default=None) LNBITS_ALLOWED_USERS: List[str] = [ x.strip(" ") for x in env.list("LNBITS_ALLOWED_USERS", default=[], subcast=str) ] +LNBITS_ADMIN_UI = env.bool("LNBITS_ADMIN_UI", default=False) LNBITS_ADMIN_USERS: List[str] = [ x.strip(" ") for x in env.list("LNBITS_ADMIN_USERS", default=[], subcast=str) ] From 4336613028e05dae5b6adf3b543903f6fc365a44 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Sat, 12 Mar 2022 14:23:16 +0000 Subject: [PATCH 0027/1058] add db config at startup --- lnbits/commands.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lnbits/commands.py b/lnbits/commands.py index 0f7454f2..8c39c338 100644 --- a/lnbits/commands.py +++ b/lnbits/commands.py @@ -52,6 +52,25 @@ def bundle_vendored(): with open(outputpath, "w") as f: f.write(output) +async def get_admin_settings(): + from lnbits.extensions.admin.models import Admin + + async with core_db.connect() as conn: + + if conn.type == SQLITE: + exists = await conn.fetchone( + "SELECT * FROM sqlite_master WHERE type='table' AND name='admin'" + ) + elif conn.type in {POSTGRES, COCKROACH}: + exists = await conn.fetchone( + "SELECT * FROM information_schema.tables WHERE table_name = 'admin'" + ) + if not exists: + return False + + row = await conn.fetchone("SELECT * from admin") + + return Admin(**row) if row else None async def migrate_databases(): """Creates the necessary databases if they don't exist already; or migrates them.""" From 32a6a6ae2fb9fa3ba01c24f31067a5115feca4e3 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Sat, 12 Mar 2022 14:23:53 +0000 Subject: [PATCH 0028/1058] get admin settings at startup --- lnbits/app.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/lnbits/app.py b/lnbits/app.py index 51482538..6a66b99e 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -18,6 +18,7 @@ from loguru import logger import lnbits.settings from lnbits.core.tasks import register_task_listeners +from .commands import get_admin_settings from .core import core_app from .core.views.generic import core_html_routes from .helpers import ( @@ -42,6 +43,7 @@ def create_app(config_object="lnbits.settings") -> FastAPI: """Create application factory. :param config_object: The configuration object to use. """ +<<<<<<< HEAD configure_logger() app = FastAPI( @@ -53,6 +55,14 @@ def create_app(config_object="lnbits.settings") -> FastAPI: }, ) app.mount("/static", StaticFiles(packages=[("lnbits", "static")]), name="static") +======= + app = FastAPI() + + if lnbits.settings.LNBITS_ADMIN_UI: + check_settings(app) + + app.mount("/static", StaticFiles(directory="lnbits/static"), name="static") +>>>>>>> e3a1b3ae (get admin settings at startup) app.mount( "/core/static", StaticFiles(packages=[("lnbits.core", "static")]), @@ -64,7 +74,6 @@ def create_app(config_object="lnbits.settings") -> FastAPI: app.add_middleware( CORSMiddleware, allow_origins=origins, allow_methods=["*"], allow_headers=["*"] ) - g().config = lnbits.settings g().base_url = f"http://{lnbits.settings.HOST}:{lnbits.settings.PORT}" @@ -102,6 +111,18 @@ def create_app(config_object="lnbits.settings") -> FastAPI: return app +def check_settings(app: FastAPI): + @app.on_event("startup") + async def check_settings_admin(): + while True: + admin_set = await get_admin_settings() + if admin_set : + break + print("ERROR:", admin_set) + await asyncio.sleep(5) + # admin_set = await get_admin_settings() + g().admin_conf = admin_set + def check_funding_source(app: FastAPI) -> None: @app.on_event("startup") async def check_wallet_status(): From f245f3188b7f35b6f9388e9caa12d3d6a0b20c3e Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Sat, 12 Mar 2022 14:24:11 +0000 Subject: [PATCH 0029/1058] remove core admin.html --- lnbits/core/templates/core/admin.html | 717 -------------------------- 1 file changed, 717 deletions(-) delete mode 100644 lnbits/core/templates/core/admin.html diff --git a/lnbits/core/templates/core/admin.html b/lnbits/core/templates/core/admin.html deleted file mode 100644 index e8176555..00000000 --- a/lnbits/core/templates/core/admin.html +++ /dev/null @@ -1,717 +0,0 @@ -{% extends "public.html" %} {% from "macros.jinja" import window_vars with -context %} {% block page %} -
-
- - -

-
Welcome to LNbits
-

-
- Fill in the information below to setup your LNbits instance. Details - can be changed later. -
-

- - -
- -
Branding
-
-
- -
-
- -
-
-
-
- - - -
-
- - - -
-
- -
Service settings
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
- Funding source information (at least one required)
*if installed through RaspiBlitz, MyNode, etc, details - should be filled in for you
-
- - - - - - - - - - - - - -
-
- -
-
-
-
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
-
- - - - -
-
- -
-
- -
-
- -
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
-
- - - - -
-
- -
-
- -
-
-
-
-
- - - - -
-
- -
-
- -
-
-
-
- -
-
- -
-
-
-
-
- - - - -
-
- -
-
-
-
-
- -
-
- -
-
-
-
-
- - - - -
-
- -
-
- -
-
-
-
-
-
- -
- - -
-
-
-
- View project in GitHub - Donate -
-
-
-
-
-{% endblock %} {% block scripts %} {{ window_vars(funding) }} - -{% endblock %} From de21f0216161ac9f45cf17f42f5be708404156d0 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Fri, 18 Mar 2022 16:55:31 +0000 Subject: [PATCH 0030/1058] refactor ui --- .../admin/templates/admin/index.html | 727 +++++++++++++++++- 1 file changed, 712 insertions(+), 15 deletions(-) diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index a6b45625..65ac9f33 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -1,6 +1,670 @@ {% extends "base.html" %} {% from "macros.jinja" import window_vars with context %} {% block page %} +
+
+ +
+
+ + + + + + +
+
+ + + + +
Wallets Management
+
+
+
+
+

Funding Source Info

+
    + {%raw%} +
  • Funding Source: {{data.admin.funding_source}}
  • +
  • Balance: {{data.admin.balance / 1000}} sats
  • + {%endraw%} +
+
+
+
+
+
+

Active Funding

+ +
+
+
+ +

TopUp a wallet

+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+
+

Funding Sources

+ + + + + + + + + + + + +
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+
+ + + + +
+
+ +
+
+ +
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+ +
+
+
+
+
+
+ + + + +
+
+ +
+
+
+
+
+
+
+ +
+ Save +
+
+
+ + +
User Management
+
+

+ Super Admin: {% raw + %}{{this.data.admin.user}}{% endraw %} +

+
+
+

Admin Users

+ + + +
+ {% raw %} + + {{ user }} + + {% endraw %} +
+
+
+
+

Allowed Users

+ + + +
+ {% raw %} + + {{ user }} + + {% endraw %} +
+
+
+
+
+

Admin Extensions

+ +
+
+
+

Disabled Extensions

+ +
+
+
+
+ Save +
+
+
+ + +
Server Management
+
+
+
+
+

Server Info

+
    + {%raw%} +
  • SQlite: {{data.admin.data_folder}}
  • +
  • Postgres: {{data.admin.database_url}}
  • + {%endraw%} +
+
+
+
+
+
+

Service Fee

+ +
+
+
+

Miscelaneous

+ + + Force HTTPS + Prefer secure URLs + + + + + + + + Hide API + Hides wallet api, extensions can choose to honor + + + + + +
+
+
+
+ +
+ Save +
+
+
+ + +
UI Management
+
+
+
+
+

Site Title

+ +
+
+
+

Site Tagline

+ +
+
+
+
+

Site Description

+ +
+
+
+
+

Default Wallet Name

+ +
+
+
+

Denomination

+ +
+
+
+
+
+

Themes

+ +
+
+
+

Advertisement Slots

+ + + +
+ {% raw %} + + {{ space.slice(0, 8) + " ... " + space.slice(-8) }} + + {% endraw %} +
+
+
+
+
+ +
+ Save +
+
+
+
+
+
+
+
+

Admin

-
+
@@ -426,6 +1090,7 @@ return { wallet: {data: {}}, cancel: {}, + tab: 'funding', data: { funding_source: [ 'CLightningWallet', @@ -436,24 +1101,14 @@ 'LnbitsWallet', 'OpenNodeWallet' ], - + admin: { - user: '{{ user.id }}', - site_title: '{{admin.site_title}}', - tagline: '{{admin.site_tagline}}', - description: '{{admin.site_description}}', - admin_users: '{{admin.admin_users}}', - service_fee: parseFloat('{{admin.service_fee}}'), - default_wallet_name: '{{admin.default_wallet_name}}', - data_folder: '{{admin.data_folder}}', - funding_source_primary: '{{admin.funding_source}}', - disabled_ext: '{{admin.disabled_ext}}'.split(','), edited: [], funding: {}, senddata: {} } }, - + themes: ['classic', 'bitcoin', 'flamingo', 'mint', 'autumn', 'monochrome', 'salvador'], options: [ 'bleskomat', 'captcha', @@ -489,9 +1144,51 @@ for (i = 0; i < funding.length; i++) { self.data.admin.funding[funding[i].backend_wallet] = funding[i] } - console.log(self.data.admin) + let settings = JSON.parse('{{ settings | tojson|safe }}') + settings.balance = '{{ balance }}' + this.data.admin = {...this.data.admin, ...settings} + console.log(this.g.user) }, methods: { + addAdminUser(){ + let addUser = this.data.admin_users_add + let admin_users = this.data.admin.admin_users + if(addUser.length && !admin_users.includes(addUser)){ + admin_users.push(addUser) + this.data.admin.admin_users = admin_users + this.data.admin_users_add = "" + } + }, + removeAdminUser(user){ + let admin_users = this.data.admin.admin_users + this.data.admin.admin_users = admin_users.filter(u => u !== user) + }, + addAllowedUser(){ + let addUser = this.data.allowed_users_add + let allowed_users = this.data.admin.allowed_users + if(addUser.length && !allowed_users.includes(addUser)){ + allowed_users.push(addUser) + this.data.admin.allowed_users = allowed_users + this.data.allowed_users_add = "" + } + }, + removeAllowedUser(user){ + let allowed_users = this.data.admin.allowed_users + this.data.admin.allowed_users = allowed_users.filter(u => u !== user) + }, + addAdSpace(){ + let adSpace = this.data.ad_space_add + let spaces = this.data.admin.ad_space + if(adSpace.length && !spaces.includes(adSpace)){ + spaces.push(adSpace) + this.data.admin.ad_space = spaces + this.data.ad_space_add = "" + } + }, + removeAdSpace(ad){ + let spaces = this.data.admin.ad_space + this.data.admin.ad_space = spaces.filter(s => s !== ad) + }, topupWallet: function () { var self = this LNbits.api From 582cc52ac61236ca7ae219b49e20d0954e983411 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Fri, 18 Mar 2022 16:59:06 +0000 Subject: [PATCH 0031/1058] make it work from g() --- lnbits/app.py | 34 +++--- lnbits/config.py | 62 ++++++++++ lnbits/extensions/admin/crud.py | 2 +- lnbits/extensions/admin/migrations.py | 162 +++++++++++++++++--------- lnbits/extensions/admin/models.py | 27 +++-- lnbits/extensions/admin/views.py | 8 +- lnbits/settings.py | 2 +- 7 files changed, 218 insertions(+), 79 deletions(-) create mode 100644 lnbits/config.py diff --git a/lnbits/app.py b/lnbits/app.py index 6a66b99e..ccac1e00 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -19,6 +19,7 @@ import lnbits.settings from lnbits.core.tasks import register_task_listeners from .commands import get_admin_settings +from .config import WALLET, conf from .core import core_app from .core.views.generic import core_html_routes from .helpers import ( @@ -29,7 +30,8 @@ from .helpers import ( url_for_vendored, ) from .requestvars import g -from .settings import WALLET + +# from .settings import WALLET from .tasks import ( catch_everything_and_restart, check_pending_payments, @@ -43,7 +45,6 @@ def create_app(config_object="lnbits.settings") -> FastAPI: """Create application factory. :param config_object: The configuration object to use. """ -<<<<<<< HEAD configure_logger() app = FastAPI( @@ -55,20 +56,18 @@ def create_app(config_object="lnbits.settings") -> FastAPI: }, ) app.mount("/static", StaticFiles(packages=[("lnbits", "static")]), name="static") -======= - app = FastAPI() - - if lnbits.settings.LNBITS_ADMIN_UI: - check_settings(app) - - app.mount("/static", StaticFiles(directory="lnbits/static"), name="static") ->>>>>>> e3a1b3ae (get admin settings at startup) app.mount( "/core/static", StaticFiles(packages=[("lnbits.core", "static")]), name="core_static", ) + if lnbits.settings.LNBITS_ADMIN_UI: + g().admin_conf = conf + check_settings(app) + + g().WALLET = WALLET + origins = ["*"] app.add_middleware( @@ -110,18 +109,27 @@ def create_app(config_object="lnbits.settings") -> FastAPI: return app - def check_settings(app: FastAPI): @app.on_event("startup") async def check_settings_admin(): + + def removeEmptyString(arr): + return list(filter(None, arr)) + while True: admin_set = await get_admin_settings() if admin_set : break print("ERROR:", admin_set) await asyncio.sleep(5) - # admin_set = await get_admin_settings() - g().admin_conf = admin_set + + admin_set.admin_users = removeEmptyString(admin_set.admin_users.split(',')) + admin_set.allowed_users = removeEmptyString(admin_set.allowed_users.split(',')) + admin_set.admin_ext = removeEmptyString(admin_set.admin_ext.split(',')) + admin_set.disabled_ext = removeEmptyString(admin_set.disabled_ext.split(',')) + admin_set.theme = removeEmptyString(admin_set.theme.split(',')) + admin_set.ad_space = removeEmptyString(admin_set.ad_space.split(',')) + g().admin_conf = conf.copy(update=admin_set.dict()) def check_funding_source(app: FastAPI) -> None: @app.on_event("startup") diff --git a/lnbits/config.py b/lnbits/config.py new file mode 100644 index 00000000..02e8cf53 --- /dev/null +++ b/lnbits/config.py @@ -0,0 +1,62 @@ +import importlib +import json +from os import getenv, path +from typing import List, Optional + +from pydantic import BaseSettings, Field, validator + +wallets_module = importlib.import_module("lnbits.wallets") +wallet_class = getattr( + wallets_module, getenv("LNBITS_BACKEND_WALLET_CLASS", "VoidWallet") +) + +WALLET = wallet_class() + +def list_parse_fallback(v): + try: + return json.loads(v) + except Exception as e: + return v.replace(' ','').split(',') + +class Settings(BaseSettings): + # users + admin_users: List[str] = Field(default_factory=list, env="LNBITS_ADMIN_USERS") + allowed_users: List[str] = Field(default_factory=list, env="LNBITS_ALLOWED_USERS") + admin_ext: List[str] = Field(default_factory=list, env="LNBITS_ADMIN_EXTENSIONS") + disabled_ext: List[str] = Field(default_factory=list, env="LNBITS_DISABLED_EXTENSIONS") + funding_source: str = Field(default="VoidWallet", env="LNBITS_BACKEND_WALLET_CLASS") + # ops + data_folder: str = Field(default=None, env="LNBITS_DATA_FOLDER") + database_url: str = Field(default=None, env="LNBITS_DATABASE_URL") + force_https: bool = Field(default=True, env="LNBITS_FORCE_HTTPS") + service_fee: float = Field(default=0, env="LNBITS_SERVICE_FEE") + hide_api: bool = Field(default=False, env="LNBITS_HIDE_API") + denomination: str = Field(default="sats", env="LNBITS_DENOMINATION") + # Change theme + site_title: str = Field(default=None, env="LNBITS_SITE_TITLE") + site_tagline: str = Field(default=None, env="LNBITS_SITE_TAGLINE") + site_description: str = Field(default=None, env="LNBITS_SITE_DESCRIPTION") + default_wallet_name: str = Field(default=None, env="LNBITS_DEFAULT_WALLET_NAME") + theme: List[str] = Field(default="classic, flamingo, mint, salvador, monochrome, autumn", env="LNBITS_THEME_OPTIONS") + ad_space: List[str] = Field(default_factory=list, env="LNBITS_AD_SPACE") + # .env + env: Optional[str] + debug: Optional[str] + host: Optional[str] + port: Optional[str] + lnbits_path: Optional[str] = path.dirname(path.realpath(__file__)) + + # @validator('admin_users', 'allowed_users', 'admin_ext', 'disabled_ext', pre=True) + # def validate(cls, val): + # print(val) + # return val.split(',') + + class Config: + env_file = ".env" + env_file_encoding = "utf-8" + case_sensitive = False + json_loads = list_parse_fallback + + +conf = Settings() +WALLET = wallet_class() diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py index 872d6c97..6fccb8ee 100644 --- a/lnbits/extensions/admin/crud.py +++ b/lnbits/extensions/admin/crud.py @@ -40,7 +40,7 @@ async def update_admin(user: str, **kwargs) -> Admin: # new_settings = await get_admin() # return new_settings -async def get_admin() -> List[Admin]: +async def get_admin() -> Admin: row = await db.fetchone("SELECT * FROM admin") return Admin(**row) if row else None diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index 13b76923..574f772d 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -2,93 +2,151 @@ from os import getenv from sqlalchemy.exc import OperationalError # type: ignore +from lnbits.config import conf from lnbits.helpers import urlsafe_short_hash async def m001_create_admin_table(db): - user = None - site_title = None - site_tagline = None - site_description = None - allowed_users = None - admin_users = None - default_wallet_name = None - data_folder = None - disabled_ext = None - force_https = True - service_fee = 0 - funding_source = "" + # users/server + user = conf.admin_users[0] + admin_users = ",".join(conf.admin_users) + allowed_users = ",".join(conf.allowed_users) + admin_ext = ",".join(conf.admin_ext) + disabled_ext = ",".join(conf.disabled_ext) + funding_source = conf.funding_source + #operational + data_folder = conf.data_folder + database_url = conf.database_url + force_https = conf.force_https + service_fee = conf.service_fee + hide_api = conf.hide_api + denomination = conf.denomination + # Theme'ing + site_title = conf.site_title + site_tagline = conf.site_tagline + site_description = conf.site_description + default_wallet_name = conf.default_wallet_name + theme = ",".join(conf.theme) + ad_space = ",".join(conf.ad_space) - if getenv("LNBITS_SITE_TITLE"): - site_title = getenv("LNBITS_SITE_TITLE") + # if getenv("LNBITS_ADMIN_EXTENSIONS"): + # admin_ext = getenv("LNBITS_ADMIN_EXTENSIONS") - if getenv("LNBITS_SITE_TAGLINE"): - site_tagline = getenv("LNBITS_SITE_TAGLINE") + # if getenv("LNBITS_DATABASE_URL"): + # database_url = getenv("LNBITS_DATABASE_URL") - if getenv("LNBITS_SITE_DESCRIPTION"): - site_description = getenv("LNBITS_SITE_DESCRIPTION") + # if getenv("LNBITS_HIDE_API"): + # hide_api = getenv("LNBITS_HIDE_API") - if getenv("LNBITS_ALLOWED_USERS"): - allowed_users = getenv("LNBITS_ALLOWED_USERS") + # if getenv("LNBITS_THEME_OPTIONS"): + # theme = getenv("LNBITS_THEME_OPTIONS") - if getenv("LNBITS_ADMIN_USERS"): - admin_users = "".join(getenv("LNBITS_ADMIN_USERS").split()) - user = admin_users.split(',')[0] + # if getenv("LNBITS_AD_SPACE"): + # ad_space = getenv("LNBITS_AD_SPACE") - if getenv("LNBITS_DEFAULT_WALLET_NAME"): - default_wallet_name = getenv("LNBITS_DEFAULT_WALLET_NAME") + # if getenv("LNBITS_SITE_TITLE"): + # site_title = getenv("LNBITS_SITE_TITLE") - if getenv("LNBITS_DATA_FOLDER"): - data_folder = getenv("LNBITS_DATA_FOLDER") + # if getenv("LNBITS_SITE_TAGLINE"): + # site_tagline = getenv("LNBITS_SITE_TAGLINE") - if getenv("LNBITS_DISABLED_EXTENSIONS"): - disabled_ext = getenv("LNBITS_DISABLED_EXTENSIONS") + # if getenv("LNBITS_SITE_DESCRIPTION"): + # site_description = getenv("LNBITS_SITE_DESCRIPTION") - if getenv("LNBITS_FORCE_HTTPS"): - force_https = getenv("LNBITS_FORCE_HTTPS") + # if getenv("LNBITS_ALLOWED_USERS"): + # allowed_users = getenv("LNBITS_ALLOWED_USERS") - if getenv("LNBITS_SERVICE_FEE"): - service_fee = getenv("LNBITS_SERVICE_FEE") + # if getenv("LNBITS_ADMIN_USERS"): + # admin_users = "".join(getenv("LNBITS_ADMIN_USERS").split()) + # user = admin_users.split(',')[0] + + # if getenv("LNBITS_DEFAULT_WALLET_NAME"): + # default_wallet_name = getenv("LNBITS_DEFAULT_WALLET_NAME") - if getenv("LNBITS_BACKEND_WALLET_CLASS"): - funding_source = getenv("LNBITS_BACKEND_WALLET_CLASS") + # if getenv("LNBITS_DATA_FOLDER"): + # data_folder = getenv("LNBITS_DATA_FOLDER") + + # if getenv("LNBITS_DISABLED_EXTENSIONS"): + # disabled_ext = getenv("LNBITS_DISABLED_EXTENSIONS") + + # if getenv("LNBITS_FORCE_HTTPS"): + # force_https = getenv("LNBITS_FORCE_HTTPS") + + # if getenv("LNBITS_SERVICE_FEE"): + # service_fee = getenv("LNBITS_SERVICE_FEE") + + # if getenv("LNBITS_DENOMINATION"): + # denomination = getenv("LNBITS_DENOMINATION", "sats") + + # if getenv("LNBITS_BACKEND_WALLET_CLASS"): + # funding_source = getenv("LNBITS_BACKEND_WALLET_CLASS") await db.execute( """ CREATE TABLE IF NOT EXISTS admin ( - "user" TEXT, + "user" TEXT PRIMARY KEY, + admin_users TEXT, + allowed_users TEXT, + admin_ext TEXT, + disabled_ext TEXT, + funding_source TEXT, + data_folder TEXT, + database_url TEXT, + force_https BOOLEAN, + service_fee REAL, + hide_api BOOLEAN, + denomination TEXT, site_title TEXT, site_tagline TEXT, site_description TEXT, - admin_users TEXT, - allowed_users TEXT, default_wallet_name TEXT, - data_folder TEXT, - disabled_ext TEXT, - force_https BOOLEAN, - service_fee REAL, - funding_source TEXT + theme TEXT, + ad_space TEXT ); """ ) await db.execute( """ - INSERT INTO admin ("user", site_title, site_tagline, site_description, admin_users, allowed_users, default_wallet_name, data_folder, disabled_ext, force_https, service_fee, funding_source) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - user.strip(), + INSERT INTO admin ( + "user", + admin_users, + allowed_users, + admin_ext, + disabled_ext, + funding_source, + data_folder, + database_url, + force_https, + service_fee, + hide_api, + denomination, site_title, site_tagline, site_description, - admin_users[1:], - allowed_users, default_wallet_name, - data_folder, + theme, + ad_space) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + """, + ( + user, + admin_users, + allowed_users, + admin_ext, disabled_ext, + funding_source, + data_folder, + database_url, force_https, service_fee, - funding_source, + hide_api, + denomination, + site_title, + site_tagline, + site_description, + default_wallet_name, + theme, + ad_space, ), ) diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py index 4080ff01..f7c64de5 100644 --- a/lnbits/extensions/admin/models.py +++ b/lnbits/extensions/admin/models.py @@ -2,7 +2,7 @@ from sqlite3 import Row from typing import List, Optional from fastapi import Query -from pydantic import BaseModel +from pydantic import BaseModel, Field class UpdateAdminSettings(BaseModel): @@ -19,18 +19,27 @@ class UpdateAdminSettings(BaseModel): funding_source: Optional[str] class Admin(BaseModel): + # users user: str + admin_users: Optional[str] + allowed_users: Optional[str] + admin_ext: Optional[str] + disabled_ext: Optional[str] + funding_source: Optional[str] + # ops + data_folder: Optional[str] + database_url: Optional[str] + force_https: bool = Field(default=True) + service_fee: float = Field(default=0) + hide_api: bool = Field(default=False) + # Change theme site_title: Optional[str] site_tagline: Optional[str] site_description: Optional[str] - allowed_users: Optional[str] - admin_users: str - default_wallet_name: str - data_folder: str - disabled_ext: str - force_https: Optional[bool] = Query(True) - service_fee: float - funding_source: str + default_wallet_name: Optional[str] + denomination: str = Field(default="sats") + theme: Optional[str] + ad_space: Optional[str] @classmethod def from_row(cls, row: Row) -> "Admin": diff --git a/lnbits/extensions/admin/views.py b/lnbits/extensions/admin/views.py index 00a0c99f..105f05a1 100644 --- a/lnbits/extensions/admin/views.py +++ b/lnbits/extensions/admin/views.py @@ -19,15 +19,17 @@ templates = Jinja2Templates(directory="templates") @admin_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): admin = await get_admin() - print(g()) funding = [f.dict() for f in await get_funding()] - + error, balance = await g().WALLET.status() print("ADMIN", admin.dict()) + print(g().admin_conf) return admin_renderer().TemplateResponse( "admin/index.html", { "request": request, "user": user.dict(), "admin": admin.dict(), - "funding": funding + "funding": funding, + "settings": g().admin_conf.dict(), + "balance": balance } ) diff --git a/lnbits/settings.py b/lnbits/settings.py index 43cb87cb..ed5c77f7 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -4,7 +4,7 @@ from email.policy import default from os import path from typing import List -from environs import Env # type: ignore +from environs import Env env = Env() env.read_env() From 66a7f53b976ae98a1e18cff8305da1299e524b69 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Tue, 22 Mar 2022 10:28:07 +0000 Subject: [PATCH 0032/1058] topup wallet endpoint --- lnbits/extensions/admin/crud.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py index 6fccb8ee..683558f9 100644 --- a/lnbits/extensions/admin/crud.py +++ b/lnbits/extensions/admin/crud.py @@ -1,26 +1,31 @@ +import json from typing import List, Optional from lnbits.core.crud import create_payment from lnbits.helpers import urlsafe_short_hash from lnbits.settings import * +from lnbits.tasks import internal_invoice_queue from . import db from .models import Admin, Funding -def update_wallet_balance(wallet_id: str, amount: int) -> str: +async def update_wallet_balance(wallet_id: str, amount: int) -> str: temp_id = f"temp_{urlsafe_short_hash()}" internal_id = f"internal_{urlsafe_short_hash()}" - create_payment( + + payment = await create_payment( wallet_id=wallet_id, checking_id=internal_id, payment_request="admin_internal", payment_hash="admin_internal", - amount=amount * 1000, + amount=amount*1000, memo="Admin top up", pending=False, ) - return "success" + # manually send this for now + await internal_invoice_queue.put(internal_id) + return payment async def update_admin(user: str, **kwargs) -> Admin: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) From 663c7ebd2f52c4cc0ea57839d921e3730d4decef Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Tue, 22 Mar 2022 10:28:44 +0000 Subject: [PATCH 0033/1058] update admin settings in db --- lnbits/extensions/admin/models.py | 29 +++++++++++++++++----------- lnbits/extensions/admin/views_api.py | 8 ++++---- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py index f7c64de5..36d9b815 100644 --- a/lnbits/extensions/admin/models.py +++ b/lnbits/extensions/admin/models.py @@ -6,17 +6,24 @@ from pydantic import BaseModel, Field class UpdateAdminSettings(BaseModel): - site_title: Optional[str] - site_tagline: Optional[str] - site_description: Optional[str] - allowed_users: Optional[str] - admin_users: Optional[str] - default_wallet_name: Optional[str] - data_folder: Optional[str] - disabled_ext: Optional[str] - force_https: Optional[bool] - service_fee: Optional[float] - funding_source: Optional[str] + # users + admin_users: str = Query(None) + allowed_users: str = Query(None) + admin_ext: str = Query(None) + disabled_ext: str = Query(None) + funding_source: str = Query(None) + # ops + force_https: bool = Query(None) + service_fee: float = Query(None, ge=0) + hide_api: bool = Query(None) + # Change theme + site_title: str = Query(None) + site_tagline: str = Query(None) + site_description: str = Query(None) + default_wallet_name: str = Query(None) + denomination: str = Query(None) + theme: str = Query(None) + ad_space: str = Query(None) class Admin(BaseModel): # users diff --git a/lnbits/extensions/admin/views_api.py b/lnbits/extensions/admin/views_api.py index b2c65be2..cb526aa5 100644 --- a/lnbits/extensions/admin/views_api.py +++ b/lnbits/extensions/admin/views_api.py @@ -12,16 +12,16 @@ from .crud import get_admin, update_admin, update_wallet_balance @admin_ext.get("/api/v1/admin/{wallet_id}/{topup_amount}", status_code=HTTPStatus.OK) -async def api_update_balance(wallet_id, topup_amount, g: WalletTypeInfo = Depends(require_admin_key)): - print(g.wallet) +async def api_update_balance(wallet_id, topup_amount: int, g: WalletTypeInfo = Depends(require_admin_key)): try: wallet = await get_wallet(wallet_id) except: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" ) - print(wallet) - print(topup_amount) + + await update_wallet_balance(wallet_id=wallet_id, amount=int(topup_amount)) + return {"status": "Success"} From bc090190fca9a170566e1d605bdbdbd3536c70f5 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Tue, 22 Mar 2022 10:29:18 +0000 Subject: [PATCH 0034/1058] update settings and topup logic --- .../admin/templates/admin/index.html | 91 ++++++++++++------- 1 file changed, 57 insertions(+), 34 deletions(-) diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index 65ac9f33..e9ddc7c4 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -30,7 +30,7 @@
- + @@ -61,7 +61,7 @@
- +

TopUp a wallet

@@ -87,13 +87,13 @@
- +
@@ -577,7 +577,6 @@

Site Description

s !== ad) }, - topupWallet: function () { - var self = this + topupWallet() { LNbits.api .request( 'GET', '/admin/api/v1/admin/' + - self.wallet.id + + this.wallet.data.id + '/' + - self.wallet.data.amount, - self.g.user.wallets[0].adminkey + this.wallet.data.amount, + this.g.user.wallets[0].adminkey ) - .then(function (response) { - self.$q.notify({ + .then((response) => { + this.$q.notify({ type: 'positive', message: - 'Success! Added ' + - self.wallet.amount + - ' to ' + - self.wallet.id, + 'Success! Added ' + + this.wallet.data.amount + + ' to ' + + this.wallet.data.id, icon: null }) + this.wallet.data = {} }) .catch(function (error) { LNbits.utils.notifyApiError(error) @@ -1224,36 +1224,59 @@ self.data.admin.edited.push(source) console.log(self.data.admin.edited) }, - UpdateLNbits: function () { - var self = this - let {site_title, admin_users, default_wallet_name, data_folder, disabled_ext, service_fee, funding_source_primary} = this.data.admin + UpdateLNbits() { + let { + admin_users, + allowed_users, + admin_ext, + disabled_ext, + funding_source, + force_https, + service_fee, + hide_api, + site_title, + site_tagline, + site_description, + default_wallet_name, + denomination, + theme, + ad_space + } = this.data.admin + //console.log("this", this.data.admin) let data = { - site_title, - site_tagline: this.data.admin.tagline, - site_description: this.data.admin.description, - admin_users: admin_users.toString(), - default_wallet_name, - data_folder, + admin_users: admin_users.toString(), + allowed_users: allowed_users.toString(), + admin_ext: admin_ext.toString(), disabled_ext: disabled_ext.toString(), - service_fee, - funding_source: funding_source_primary} + funding_source, + force_https, + service_fee, + hide_api, + site_title, + site_tagline, + site_description, + default_wallet_name, + denomination, + theme: theme.toString(), + ad_space: ad_space.toString() + } console.log(data) LNbits.api .request( 'POST', '/admin/api/v1/admin/', - self.g.user.wallets[0].adminkey, + this.g.user.wallets[0].adminkey, data ) - .then(function (response) { + .then(response => { console.log(response.data) - self.$q.notify({ + this.$q.notify({ type: 'positive', message: 'Success! Added ' + - self.wallet.amount + + this.wallet.amount + ' to ' + - self.wallet.id, + this.wallet.id, icon: null }) }) From 313574df1991c47b6a0dbc390f8d839278e200d4 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Tue, 22 Mar 2022 11:34:47 +0000 Subject: [PATCH 0035/1058] make removeEmptyString fn as helper fn --- lnbits/app.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lnbits/app.py b/lnbits/app.py index ccac1e00..5df439dc 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -26,6 +26,7 @@ from .helpers import ( get_css_vendored, get_js_vendored, get_valid_extensions, + removeEmptyString, template_renderer, url_for_vendored, ) @@ -113,9 +114,6 @@ def check_settings(app: FastAPI): @app.on_event("startup") async def check_settings_admin(): - def removeEmptyString(arr): - return list(filter(None, arr)) - while True: admin_set = await get_admin_settings() if admin_set : From edfa98f00e7111096321d259fca4cd2eb36ac3d5 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Tue, 22 Mar 2022 11:35:15 +0000 Subject: [PATCH 0036/1058] add some defaults --- lnbits/config.py | 6 +++--- lnbits/extensions/admin/models.py | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lnbits/config.py b/lnbits/config.py index 02e8cf53..b2fbfff1 100644 --- a/lnbits/config.py +++ b/lnbits/config.py @@ -33,10 +33,10 @@ class Settings(BaseSettings): hide_api: bool = Field(default=False, env="LNBITS_HIDE_API") denomination: str = Field(default="sats", env="LNBITS_DENOMINATION") # Change theme - site_title: str = Field(default=None, env="LNBITS_SITE_TITLE") - site_tagline: str = Field(default=None, env="LNBITS_SITE_TAGLINE") + site_title: str = Field(default="LNbits", env="LNBITS_SITE_TITLE") + site_tagline: str = Field(default="free and open-source lightning wallet", env="LNBITS_SITE_TAGLINE") site_description: str = Field(default=None, env="LNBITS_SITE_DESCRIPTION") - default_wallet_name: str = Field(default=None, env="LNBITS_DEFAULT_WALLET_NAME") + default_wallet_name: str = Field(default="LNbits wallet", env="LNBITS_DEFAULT_WALLET_NAME") theme: List[str] = Field(default="classic, flamingo, mint, salvador, monochrome, autumn", env="LNBITS_THEME_OPTIONS") ad_space: List[str] = Field(default_factory=list, env="LNBITS_AD_SPACE") # .env diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py index 36d9b815..0f25679d 100644 --- a/lnbits/extensions/admin/models.py +++ b/lnbits/extensions/admin/models.py @@ -17,11 +17,11 @@ class UpdateAdminSettings(BaseModel): service_fee: float = Query(None, ge=0) hide_api: bool = Query(None) # Change theme - site_title: str = Query(None) - site_tagline: str = Query(None) + site_title: str = Query("LNbits") + site_tagline: str = Query("free and open-source lightning wallet") site_description: str = Query(None) - default_wallet_name: str = Query(None) - denomination: str = Query(None) + default_wallet_name: str = Query("LNbits wallet") + denomination: str = Query("sats") theme: str = Query(None) ad_space: str = Query(None) From ba6bda39ab4a6c50631658d9bee85329c4784950 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Tue, 22 Mar 2022 11:36:04 +0000 Subject: [PATCH 0037/1058] removeEmtpy sting as helper fn --- lnbits/helpers.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lnbits/helpers.py b/lnbits/helpers.py index e213240c..e456f715 100644 --- a/lnbits/helpers.py +++ b/lnbits/helpers.py @@ -154,8 +154,20 @@ def url_for(endpoint: str, external: Optional[bool] = False, **params: Any) -> s url = f"{base}{endpoint}{url_params}" return url +def removeEmptyString(arr): + return list(filter(None, arr)) def template_renderer(additional_folders: List = []) -> Jinja2Templates: + if(settings.LNBITS_ADMIN_UI): + _ = g().admin_conf + settings.LNBITS_AD_SPACE = _.ad_space + settings.LNBITS_HIDE_API = _.hide_api + settings.LNBITS_SITE_TITLE = _.site_title + settings.LNBITS_DENOMINATION = _.denomination + settings.LNBITS_SITE_TAGLINE = _.site_tagline + settings.LNBITS_SITE_DESCRIPTION = _.site_description + settings.LNBITS_THEME_OPTIONS = _.theme + t = Jinja2Templates( loader=jinja2.FileSystemLoader( ["lnbits/templates", "lnbits/core/templates", *additional_folders] From 0a211a2fb2d1fdf7c135cf637b768c8fc2855a64 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Tue, 22 Mar 2022 11:41:11 +0000 Subject: [PATCH 0038/1058] cleanup --- lnbits/extensions/admin/crud.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py index 683558f9..e14ad194 100644 --- a/lnbits/extensions/admin/crud.py +++ b/lnbits/extensions/admin/crud.py @@ -1,9 +1,7 @@ -import json -from typing import List, Optional +from typing import List from lnbits.core.crud import create_payment from lnbits.helpers import urlsafe_short_hash -from lnbits.settings import * from lnbits.tasks import internal_invoice_queue from . import db @@ -37,14 +35,6 @@ async def update_admin(user: str, **kwargs) -> Admin: assert row, "Newly updated settings couldn't be retrieved" return Admin(**row) if row else None -# async def update_admin(user: str, **kwargs) -> Optional[Admin]: -# q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) -# await db.execute( -# f"UPDATE admin SET {q} WHERE user = ?", (*kwargs.values(), user) -# ) -# new_settings = await get_admin() -# return new_settings - async def get_admin() -> Admin: row = await db.fetchone("SELECT * FROM admin") return Admin(**row) if row else None From 5ec7f21650897699f39723bbe93edd3d53da1fd2 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Tue, 22 Mar 2022 11:42:28 +0000 Subject: [PATCH 0039/1058] make string to list --- lnbits/extensions/admin/views_api.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/lnbits/extensions/admin/views_api.py b/lnbits/extensions/admin/views_api.py index cb526aa5..1d4e6a9c 100644 --- a/lnbits/extensions/admin/views_api.py +++ b/lnbits/extensions/admin/views_api.py @@ -1,5 +1,6 @@ from http import HTTPStatus +# from config import conf from fastapi import Body, Depends, Request from starlette.exceptions import HTTPException @@ -7,6 +8,8 @@ from lnbits.core.crud import get_wallet from lnbits.decorators import WalletTypeInfo, require_admin_key from lnbits.extensions.admin import admin_ext from lnbits.extensions.admin.models import Admin, UpdateAdminSettings +from lnbits.helpers import removeEmptyString +from lnbits.requestvars import g from .crud import get_admin, update_admin, update_wallet_balance @@ -19,7 +22,7 @@ async def api_update_balance(wallet_id, topup_amount: int, g: WalletTypeInfo = D raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" ) - + await update_wallet_balance(wallet_id=wallet_id, amount=int(topup_amount)) return {"status": "Success"} @@ -29,14 +32,24 @@ async def api_update_balance(wallet_id, topup_amount: int, g: WalletTypeInfo = D async def api_update_admin( request: Request, data: UpdateAdminSettings = Body(...), - g: WalletTypeInfo = Depends(require_admin_key) + w: WalletTypeInfo = Depends(require_admin_key) ): admin = await get_admin() print(data) - if not admin.user == g.wallet.user: + if not admin.user == w.wallet.user: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" ) - updated = await update_admin(user=g.wallet.user, **data.dict()) - print(updated) + updated = await update_admin(user=w.wallet.user, **data.dict()) + + updated.admin_users = removeEmptyString(updated.admin_users.split(',')) + updated.allowed_users = removeEmptyString(updated.allowed_users.split(',')) + updated.admin_ext = removeEmptyString(updated.admin_ext.split(',')) + updated.disabled_ext = removeEmptyString(updated.disabled_ext.split(',')) + updated.theme = removeEmptyString(updated.theme.split(',')) + updated.ad_space = removeEmptyString(updated.ad_space.split(',')) + + g().admin_conf = g().admin_conf.copy(update=updated.dict()) + + print(g().admin_conf) return {"status": "Success"} From 4d16c296aa1d8b8375e3f131e459a2f2f80f0d3b Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Tue, 22 Mar 2022 11:42:47 +0000 Subject: [PATCH 0040/1058] success message --- lnbits/extensions/admin/templates/admin/index.html | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index e9ddc7c4..9aa4f12a 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -1273,10 +1273,7 @@ this.$q.notify({ type: 'positive', message: - 'Success! Added ' + - this.wallet.amount + - ' to ' + - this.wallet.id, + 'Success! Settings changed!', icon: null }) }) From 2c48e3aa5f1e561e4106c60bfe0e4266a86711b3 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Thu, 14 Apr 2022 10:42:26 +0100 Subject: [PATCH 0041/1058] allow html to be passed to description --- lnbits/core/templates/core/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/core/templates/core/index.html b/lnbits/core/templates/core/index.html index f769b44f..03cf706f 100644 --- a/lnbits/core/templates/core/index.html +++ b/lnbits/core/templates/core/index.html @@ -82,7 +82,7 @@ >
-

{{SITE_DESCRIPTION}}

+

{{SITE_DESCRIPTION | safe}}

From f16ead4f7303787d945ab9dc39550ae3bc0ec611 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Thu, 14 Apr 2022 16:37:13 +0100 Subject: [PATCH 0042/1058] update funding wallets --- lnbits/extensions/admin/crud.py | 12 + .../admin/templates/admin/index.html | 523 ++++++++++-------- lnbits/extensions/admin/views.py | 3 +- lnbits/extensions/admin/views_api.py | 19 +- 4 files changed, 315 insertions(+), 242 deletions(-) diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py index e14ad194..dd39e8e4 100644 --- a/lnbits/extensions/admin/crud.py +++ b/lnbits/extensions/admin/crud.py @@ -39,6 +39,18 @@ async def get_admin() -> Admin: row = await db.fetchone("SELECT * FROM admin") return Admin(**row) if row else None +async def update_funding(data: Funding) -> Funding: + await db.execute( + """ + UPDATE funding + SET backend_wallet = ?, endpoint = ?, port = ?, read_key = ?, invoice_key = ?, admin_key = ?, cert = ?, balance = ?, selected = ? + WHERE id = ? + """, + (data.backend_wallet, data.endpoint, data.port, data.read_key, data.invoice_key, data.admin_key, data.cert, data.balance, data.selected, data.id,), + ) + row = await db.fetchone('SELECT * FROM funding WHERE "id" = ?', (data.id,)) + assert row, "Newly updated settings couldn't be retrieved" + return Funding(**row) if row else None async def get_funding() -> List[Funding]: rows = await db.fetchall("SELECT * FROM funding") diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index 9aa4f12a..d56b3d79 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -31,11 +31,11 @@
- - - -
Wallets Management
-
+ + + +
Wallets Management
+
@@ -62,43 +62,96 @@
-

TopUp a wallet

-
-
- -
-
-
- -
+

TopUp a wallet

+
+
+ +
-
- +
+
+
+
+ +

Funding Sources

- + {% raw %} + + + + + + + + + + + + + + {% endraw %} + +
+ + + + +
User Management
+
+

+ Super Admin: {% raw %}{{this.data.admin.user}}{% endraw %} +

+

Admin Users

+ hint="Users with admin privileges" + >
{% raw %} -
-
-
-

Allowed Users

- - - +
- {% raw %} - Allowed Users

+ - {{ user }} -
- {% endraw %} + + +
+ {% raw %} + + {{ user }} + + {% endraw %} +
+
+
+
+

Admin Extensions

+ +
+
+
+

Disabled Extensions

+ +
+
+
+
+ Save +
+ + + + +
Server Management

-
-
-
-

Admin Extensions

- -
-
-
-

Disabled Extensions

- -
-
-
-
- Save -
-
-
- - -
Server Management
-

Server Info

    {%raw%} -
  • SQlite: {{data.admin.data_folder}}
  • -
  • Postgres: {{data.admin.database_url}}
  • +
  • + SQlite: {{data.admin.data_folder}} +
  • +
  • + Postgres: {{data.admin.database_url}} +
  • {%endraw%}

@@ -520,7 +576,10 @@ Hide API - Hides wallet api, extensions can choose to honor + Hides wallet api, extensions can choose to + honor
-
- -
- Save -
-
-
- - -
UI Management
-
+
+ +
+ Save +
+ + + + +
UI Management
+
@@ -575,15 +629,15 @@
-

Site Description

- -
-
+

Site Description

+ +
+

Default Wallet Name

@@ -628,12 +682,15 @@ @keydown.enter="addAdSpace" type="text" label="Ad image URL" - hint="Ad image filepaths or urls, extensions can choose to honor"> + hint="Ad image filepaths or urls, extensions can choose to honor" + >
{% raw %} -
-
- -
- Save -
-
-
- - +
+ +
+ Save +
+
+
+
+
- - -

Admin

-

+ + - -
- - -
Wallet topup
-
-
- -
-
- -
-
-
- -
-
-
-
{% endblock %} {% block scripts %} {{ window_vars(user) }} @@ -1100,14 +1114,22 @@ 'LnbitsWallet', 'OpenNodeWallet' ], - + admin: { edited: [], - funding: {}, + funding: [], senddata: {} } }, - themes: ['classic', 'bitcoin', 'flamingo', 'mint', 'autumn', 'monochrome', 'salvador'], + themes: [ + 'classic', + 'bitcoin', + 'flamingo', + 'mint', + 'autumn', + 'monochrome', + 'salvador' + ], options: [ 'bleskomat', 'captcha', @@ -1139,10 +1161,13 @@ self.cancel.on = true } funding = JSON.parse(String('{{ funding | tojson|safe }}')) - var i + funding.map(f => { + this.data.admin.funding.push(f) + }) + /*var i for (i = 0; i < funding.length; i++) { self.data.admin.funding[funding[i].backend_wallet] = funding[i] - } + }*/ let settings = JSON.parse('{{ settings | tojson|safe }}') settings.balance = '{{ balance }}' this.data.admin = {...this.data.admin, ...settings} @@ -1150,42 +1175,42 @@ console.log(settings) }, methods: { - addAdminUser(){ + addAdminUser() { let addUser = this.data.admin_users_add let admin_users = this.data.admin.admin_users - if(addUser.length && !admin_users.includes(addUser)){ + if (addUser.length && !admin_users.includes(addUser)) { admin_users.push(addUser) this.data.admin.admin_users = admin_users - this.data.admin_users_add = "" + this.data.admin_users_add = '' } }, - removeAdminUser(user){ + removeAdminUser(user) { let admin_users = this.data.admin.admin_users this.data.admin.admin_users = admin_users.filter(u => u !== user) }, - addAllowedUser(){ + addAllowedUser() { let addUser = this.data.allowed_users_add let allowed_users = this.data.admin.allowed_users - if(addUser.length && !allowed_users.includes(addUser)){ + if (addUser.length && !allowed_users.includes(addUser)) { allowed_users.push(addUser) this.data.admin.allowed_users = allowed_users - this.data.allowed_users_add = "" + this.data.allowed_users_add = '' } }, - removeAllowedUser(user){ + removeAllowedUser(user) { let allowed_users = this.data.admin.allowed_users this.data.admin.allowed_users = allowed_users.filter(u => u !== user) }, - addAdSpace(){ + addAdSpace() { let adSpace = this.data.ad_space_add let spaces = this.data.admin.ad_space - if(adSpace.length && !spaces.includes(adSpace)){ + if (adSpace.length && !spaces.includes(adSpace)) { spaces.push(adSpace) this.data.admin.ad_space = spaces - this.data.ad_space_add = "" + this.data.ad_space_add = '' } }, - removeAdSpace(ad){ + removeAdSpace(ad) { let spaces = this.data.admin.ad_space this.data.admin.ad_space = spaces.filter(s => s !== ad) }, @@ -1199,14 +1224,14 @@ this.wallet.data.amount, this.g.user.wallets[0].adminkey ) - .then((response) => { + .then(response => { this.$q.notify({ type: 'positive', message: - 'Success! Added ' + - this.wallet.data.amount + - ' to ' + - this.wallet.data.id, + 'Success! Added ' + + this.wallet.data.amount + + ' to ' + + this.wallet.data.id, icon: null }) this.wallet.data = {} @@ -1224,6 +1249,29 @@ self.data.admin.edited.push(source) console.log(self.data.admin.edited) }, + updateFunding(fund) { + let data = this.data.admin.funding.find(v => v.backend_wallet == fund) + + LNbits.api + .request( + 'POST', + '/admin/api/v1/admin/funding', + this.g.user.wallets[0].adminkey, + data + ) + .then(response => { + //let wallet = response.data.backend_wallet + //this.data.admin.funding[wallet] = response.data + //this.data.admin.funding[wallet].endpoint = response.data.endpoint + //console.log(this.data.admin.funding) + //console.log(this.data.admin) + this.$q.notify({ + type: 'positive', + message: `Success! ${response.data.backend_wallet} changed!`, + icon: null + }) + }) + }, UpdateLNbits() { let { admin_users, @@ -1272,8 +1320,7 @@ console.log(response.data) this.$q.notify({ type: 'positive', - message: - 'Success! Settings changed!', + message: 'Success! Settings changed!', icon: null }) }) diff --git a/lnbits/extensions/admin/views.py b/lnbits/extensions/admin/views.py index 105f05a1..24b8ca85 100644 --- a/lnbits/extensions/admin/views.py +++ b/lnbits/extensions/admin/views.py @@ -21,8 +21,7 @@ async def index(request: Request, user: User = Depends(check_user_exists)): admin = await get_admin() funding = [f.dict() for f in await get_funding()] error, balance = await g().WALLET.status() - print("ADMIN", admin.dict()) - print(g().admin_conf) + return admin_renderer().TemplateResponse( "admin/index.html", { "request": request, diff --git a/lnbits/extensions/admin/views_api.py b/lnbits/extensions/admin/views_api.py index 1d4e6a9c..b797dc2d 100644 --- a/lnbits/extensions/admin/views_api.py +++ b/lnbits/extensions/admin/views_api.py @@ -7,11 +7,11 @@ from starlette.exceptions import HTTPException from lnbits.core.crud import get_wallet from lnbits.decorators import WalletTypeInfo, require_admin_key from lnbits.extensions.admin import admin_ext -from lnbits.extensions.admin.models import Admin, UpdateAdminSettings +from lnbits.extensions.admin.models import Admin, Funding, UpdateAdminSettings from lnbits.helpers import removeEmptyString from lnbits.requestvars import g -from .crud import get_admin, update_admin, update_wallet_balance +from .crud import get_admin, update_admin, update_funding, update_wallet_balance @admin_ext.get("/api/v1/admin/{wallet_id}/{topup_amount}", status_code=HTTPStatus.OK) @@ -53,3 +53,18 @@ async def api_update_admin( print(g().admin_conf) return {"status": "Success"} + +@admin_ext.post("/api/v1/admin/funding/", status_code=HTTPStatus.OK) +async def api_update_funding( + request: Request, + data: Funding = Body(...), + w: WalletTypeInfo = Depends(require_admin_key) + ): + admin = await get_admin() + + if not admin.user == w.wallet.user: + raise HTTPException( + status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" + ) + funding = await update_funding(data=data) + return funding From 5a3ad81c315f42a7b482714e943a1b0a72028e93 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Mon, 18 Apr 2022 14:25:06 +0100 Subject: [PATCH 0043/1058] allow user settings without restart --- lnbits/core/views/generic.py | 7 ++++++- lnbits/decorators.py | 8 ++++++++ lnbits/helpers.py | 3 +++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index 31a7b030..83648c44 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -15,7 +15,9 @@ from lnbits.core import db from lnbits.core.models import User from lnbits.decorators import check_user_exists from lnbits.helpers import template_renderer, url_for +from lnbits.requestvars import g from lnbits.settings import ( + LNBITS_ADMIN_UI, LNBITS_ADMIN_USERS, LNBITS_ALLOWED_USERS, LNBITS_CUSTOM_LOGO, @@ -37,7 +39,6 @@ from ..services import pay_invoice, redeem_lnurl_withdraw core_html_routes: APIRouter = APIRouter(tags=["Core NON-API Website Routes"]) - @core_html_routes.get("/favicon.ico", response_class=FileResponse) async def favicon(): return FileResponse("lnbits/core/static/favicon.ico") @@ -119,6 +120,10 @@ async def wallet( wallet_name = nme service_fee = int(SERVICE_FEE) if int(SERVICE_FEE) == SERVICE_FEE else SERVICE_FEE + if LNBITS_ADMIN_UI: + LNBITS_ADMIN_USERS = g().admin_conf.admin_users + LNBITS_ALLOWED_USERS = g().admin_conf.allowed_users + if not user_id: user = await get_user((await create_account()).id) logger.info(f"Create user {user.id}") # type: ignore diff --git a/lnbits/decorators.py b/lnbits/decorators.py index d4aa63ae..f951163f 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -16,6 +16,7 @@ from lnbits.core.models import User, Wallet from lnbits.requestvars import g from lnbits.settings import ( LNBITS_ADMIN_EXTENSIONS, + LNBITS_ADMIN_UI, LNBITS_ADMIN_USERS, LNBITS_ALLOWED_USERS, ) @@ -138,6 +139,9 @@ async def get_key_type( detail="Invoice (or Admin) key required.", ) + if LNBITS_ADMIN_UI: + LNBITS_ADMIN_USERS = g().admin_conf.admin_users + for typenr, WalletChecker in zip( [0, 1], [WalletAdminKeyChecker, WalletInvoiceKeyChecker] ): @@ -231,6 +235,10 @@ async def check_user_exists(usr: UUID4) -> User: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) + + if LNBITS_ADMIN_UI: + LNBITS_ADMIN_USERS = g().admin_conf.admin_users + LNBITS_ALLOWED_USERS = g().admin_conf.allowed_users if LNBITS_ALLOWED_USERS and g().user.id not in LNBITS_ALLOWED_USERS: raise HTTPException( diff --git a/lnbits/helpers.py b/lnbits/helpers.py index e456f715..1167143f 100644 --- a/lnbits/helpers.py +++ b/lnbits/helpers.py @@ -24,6 +24,9 @@ class Extension(NamedTuple): class ExtensionManager: def __init__(self): + if settings.LNBITS_ADMIN_UI: + settings.LNBITS_DISABLED_EXTENSIONS = g().admin_conf.disabled_ext + settings.LNBITS_ADMIN_EXTENSIONS = g().admin_conf.admin_ext self._disabled: List[str] = settings.LNBITS_DISABLED_EXTENSIONS self._admin_only: List[str] = [ x.strip(" ") for x in settings.LNBITS_ADMIN_EXTENSIONS From 1ff8a9fce5c15d421a8c37a3f8bc908a4b249510 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Mon, 18 Apr 2022 14:25:26 +0100 Subject: [PATCH 0044/1058] advert for server restart option --- lnbits/extensions/admin/templates/admin/index.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index d56b3d79..089c5f1c 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -51,7 +51,9 @@
-

Active Funding

+

+ Active Funding (Requires server restart) +

Date: Thu, 21 Apr 2022 11:08:26 +0100 Subject: [PATCH 0045/1058] cleanup prints and console logs --- lnbits/extensions/admin/crud.py | 2 +- lnbits/extensions/admin/templates/admin/index.html | 4 ++-- lnbits/extensions/admin/views_api.py | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py index dd39e8e4..f866bc1a 100644 --- a/lnbits/extensions/admin/crud.py +++ b/lnbits/extensions/admin/crud.py @@ -27,7 +27,7 @@ async def update_wallet_balance(wallet_id: str, amount: int) -> str: async def update_admin(user: str, **kwargs) -> Admin: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) - print("UPDATE", q) + # print("UPDATE", q) await db.execute( f'UPDATE admin SET {q} WHERE "user" = ?', (*kwargs.values(), user) ) diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index 089c5f1c..584d3a33 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -1310,7 +1310,7 @@ theme: theme.toString(), ad_space: ad_space.toString() } - console.log(data) + //console.log(data) LNbits.api .request( 'POST', @@ -1319,7 +1319,7 @@ data ) .then(response => { - console.log(response.data) + //console.log(response.data) this.$q.notify({ type: 'positive', message: 'Success! Settings changed!', diff --git a/lnbits/extensions/admin/views_api.py b/lnbits/extensions/admin/views_api.py index b797dc2d..c0650c8a 100644 --- a/lnbits/extensions/admin/views_api.py +++ b/lnbits/extensions/admin/views_api.py @@ -35,7 +35,7 @@ async def api_update_admin( w: WalletTypeInfo = Depends(require_admin_key) ): admin = await get_admin() - print(data) + # print(data) if not admin.user == w.wallet.user: raise HTTPException( status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" @@ -51,7 +51,7 @@ async def api_update_admin( g().admin_conf = g().admin_conf.copy(update=updated.dict()) - print(g().admin_conf) + # print(g().admin_conf) return {"status": "Success"} @admin_ext.post("/api/v1/admin/funding/", status_code=HTTPStatus.OK) From b0f9c82e1b0b16e3e1d499f5173a0368e5d9c93e Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Mon, 16 May 2022 10:49:21 +0100 Subject: [PATCH 0046/1058] create first user on fresh install --- .env.example | 4 ++-- lnbits/config.py | 3 ++- lnbits/extensions/admin/README.md | 15 ++++++++------- lnbits/extensions/admin/migrations.py | 15 ++++++++++++++- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/.env.example b/.env.example index bd189484..7a49d5c5 100644 --- a/.env.example +++ b/.env.example @@ -4,8 +4,8 @@ PORT=5000 DEBUG=false LNBITS_ADMIN_USERS="" # User IDs seperated by comma -LNBITS_ADMIN_EXTENSIONS="ngrok" # Extensions only admin can access -LNBITS_ADMIN_UI=false # Enable Admin GUI, available for the first user in LNBITS_ADMIN_USERS +LNBITS_ADMIN_EXTENSIONS="ngrok, admin" # Extensions only admin can access +LNBITS_ADMIN_UI=false # Enable Admin GUI, available for the first user in LNBITS_ADMIN_USERS if available LNBITS_ALLOWED_USERS="" # Restricts access, User IDs seperated by comma diff --git a/lnbits/config.py b/lnbits/config.py index b2fbfff1..3ce51c3c 100644 --- a/lnbits/config.py +++ b/lnbits/config.py @@ -19,6 +19,7 @@ def list_parse_fallback(v): return v.replace(' ','').split(',') class Settings(BaseSettings): + admin_ui: bool = Field(default=True, env="LNBITS_ADMIN_UI") # users admin_users: List[str] = Field(default_factory=list, env="LNBITS_ADMIN_USERS") allowed_users: List[str] = Field(default_factory=list, env="LNBITS_ALLOWED_USERS") @@ -37,7 +38,7 @@ class Settings(BaseSettings): site_tagline: str = Field(default="free and open-source lightning wallet", env="LNBITS_SITE_TAGLINE") site_description: str = Field(default=None, env="LNBITS_SITE_DESCRIPTION") default_wallet_name: str = Field(default="LNbits wallet", env="LNBITS_DEFAULT_WALLET_NAME") - theme: List[str] = Field(default="classic, flamingo, mint, salvador, monochrome, autumn", env="LNBITS_THEME_OPTIONS") + theme: List[str] = Field(default=["classic, flamingo, mint, salvador, monochrome, autumn"], env="LNBITS_THEME_OPTIONS") ad_space: List[str] = Field(default_factory=list, env="LNBITS_AD_SPACE") # .env env: Optional[str] diff --git a/lnbits/extensions/admin/README.md b/lnbits/extensions/admin/README.md index 27729459..6cf073a1 100644 --- a/lnbits/extensions/admin/README.md +++ b/lnbits/extensions/admin/README.md @@ -1,11 +1,12 @@ -

Example Extension

-

*tagline*

-This is an example extension to help you organise and build you own. +# Admin Extension -Try to include an image - +## Dashboard to manage LNbits from the UI +With AdminUI you can manage your LNbits from the UI -

If your extension has API endpoints, include useful ones here

+![AdminUI](https://i.imgur.com/BIyLkyG.png) -curl -H "Content-type: application/json" -X POST https://YOUR-LNBITS/YOUR-EXTENSION/api/v1/EXAMPLE -d '{"amount":"100","memo":"example"}' -H "X-Api-Key: YOUR_WALLET-ADMIN/INVOICE-KEY" +## Before you start + +**This extension doesn't discard the need for the `.env` file!** +In the .env file, set the `LNBITS_ADMIN_USERS` variable to include at least your user id. diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index 574f772d..0e22e667 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -6,9 +6,22 @@ from lnbits.config import conf from lnbits.helpers import urlsafe_short_hash +async def get_admin_user(): + if(conf.admin_users[0]): + return conf.admin_users[0] + from lnbits.core.crud import create_account, get_user + print("Seems like there's no admin users yet. Let's create an account for you!") + account = await create_account() + user = account.id + assert user, "Newly created user couldn't be retrieved" + print(f"Your newly created account/user id is: {user}. This will be the Super Admin user.") + return user + + + async def m001_create_admin_table(db): # users/server - user = conf.admin_users[0] + user = await get_admin_user() admin_users = ",".join(conf.admin_users) allowed_users = ",".join(conf.allowed_users) admin_ext = ",".join(conf.admin_ext) From 2f2d70f9a8cdd3edc59cb3c71b841b6823309dcf Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Mon, 16 May 2022 12:29:58 +0100 Subject: [PATCH 0047/1058] fix schemas for admin --- lnbits/commands.py | 11 ++++++++--- lnbits/extensions/admin/crud.py | 12 ++++++------ lnbits/extensions/admin/migrations.py | 26 +++++++++++++------------- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/lnbits/commands.py b/lnbits/commands.py index 8c39c338..7d9b49e2 100644 --- a/lnbits/commands.py +++ b/lnbits/commands.py @@ -55,8 +55,12 @@ def bundle_vendored(): async def get_admin_settings(): from lnbits.extensions.admin.models import Admin - async with core_db.connect() as conn: + try: + ext_db = importlib.import_module(f"lnbits.extensions.admin").db + except: + return False + async with ext_db.connect() as conn: if conn.type == SQLITE: exists = await conn.fetchone( "SELECT * FROM sqlite_master WHERE type='table' AND name='admin'" @@ -65,11 +69,12 @@ async def get_admin_settings(): exists = await conn.fetchone( "SELECT * FROM information_schema.tables WHERE table_name = 'admin'" ) + print("EXISTS", exists) if not exists: return False - row = await conn.fetchone("SELECT * from admin") - + row = await conn.fetchone("SELECT * from admin.admin") + return Admin(**row) if row else None async def migrate_databases(): diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py index f866bc1a..67fbc614 100644 --- a/lnbits/extensions/admin/crud.py +++ b/lnbits/extensions/admin/crud.py @@ -29,30 +29,30 @@ async def update_admin(user: str, **kwargs) -> Admin: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) # print("UPDATE", q) await db.execute( - f'UPDATE admin SET {q} WHERE "user" = ?', (*kwargs.values(), user) + f'UPDATE admin.admin SET {q} WHERE "user" = ?', (*kwargs.values(), user) ) - row = await db.fetchone('SELECT * FROM admin WHERE "user" = ?', (user,)) + row = await db.fetchone('SELECT * FROM admin.admin WHERE "user" = ?', (user,)) assert row, "Newly updated settings couldn't be retrieved" return Admin(**row) if row else None async def get_admin() -> Admin: - row = await db.fetchone("SELECT * FROM admin") + row = await db.fetchone("SELECT * FROM admin.admin") return Admin(**row) if row else None async def update_funding(data: Funding) -> Funding: await db.execute( """ - UPDATE funding + UPDATE admin.funding SET backend_wallet = ?, endpoint = ?, port = ?, read_key = ?, invoice_key = ?, admin_key = ?, cert = ?, balance = ?, selected = ? WHERE id = ? """, (data.backend_wallet, data.endpoint, data.port, data.read_key, data.invoice_key, data.admin_key, data.cert, data.balance, data.selected, data.id,), ) - row = await db.fetchone('SELECT * FROM funding WHERE "id" = ?', (data.id,)) + row = await db.fetchone('SELECT * FROM admin.funding WHERE "id" = ?', (data.id,)) assert row, "Newly updated settings couldn't be retrieved" return Funding(**row) if row else None async def get_funding() -> List[Funding]: - rows = await db.fetchall("SELECT * FROM funding") + rows = await db.fetchall("SELECT * FROM admin.funding") return [Funding(**row) for row in rows] diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index 0e22e667..c94d140b 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -96,7 +96,7 @@ async def m001_create_admin_table(db): await db.execute( """ - CREATE TABLE IF NOT EXISTS admin ( + CREATE TABLE IF NOT EXISTS admin.admin ( "user" TEXT PRIMARY KEY, admin_users TEXT, allowed_users TEXT, @@ -120,7 +120,7 @@ async def m001_create_admin_table(db): ) await db.execute( """ - INSERT INTO admin ( + INSERT INTO admin.admin ( "user", admin_users, allowed_users, @@ -171,7 +171,7 @@ async def m001_create_funding_table(db): # Make the funding table, if it does not already exist await db.execute( """ - CREATE TABLE IF NOT EXISTS funding ( + CREATE TABLE IF NOT EXISTS admin.funding ( id TEXT PRIMARY KEY, backend_wallet TEXT, endpoint TEXT, @@ -188,7 +188,7 @@ async def m001_create_funding_table(db): await db.execute( """ - INSERT INTO funding (id, backend_wallet, endpoint, selected) + INSERT INTO admin.funding (id, backend_wallet, endpoint, selected) VALUES (?, ?, ?, ?) """, ( @@ -200,7 +200,7 @@ async def m001_create_funding_table(db): ) await db.execute( """ - INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) VALUES (?, ?, ?, ?, ?) """, ( @@ -214,7 +214,7 @@ async def m001_create_funding_table(db): await db.execute( """ - INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) VALUES (?, ?, ?, ?, ?) """, ( @@ -228,7 +228,7 @@ async def m001_create_funding_table(db): await db.execute( """ - INSERT INTO funding (id, backend_wallet, endpoint, port, admin_key, cert, selected) + INSERT INTO admin.funding (id, backend_wallet, endpoint, port, admin_key, cert, selected) VALUES (?, ?, ?, ?, ?, ?, ?) """, ( @@ -244,7 +244,7 @@ async def m001_create_funding_table(db): await db.execute( """ - INSERT INTO funding (id, backend_wallet, endpoint, admin_key, cert, selected) + INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, cert, selected) VALUES (?, ?, ?, ?, ?, ?) """, ( @@ -259,7 +259,7 @@ async def m001_create_funding_table(db): await db.execute( """ - INSERT INTO funding (id, backend_wallet, endpoint, admin_key, cert, selected) + INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, cert, selected) VALUES (?, ?, ?, ?, ?, ?) """, ( @@ -274,7 +274,7 @@ async def m001_create_funding_table(db): await db.execute( """ - INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) VALUES (?, ?, ?, ?, ?) """, ( @@ -288,7 +288,7 @@ async def m001_create_funding_table(db): await db.execute( """ - INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) VALUES (?, ?, ?, ?, ?) """, ( @@ -302,7 +302,7 @@ async def m001_create_funding_table(db): await db.execute( """ - INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) VALUES (?, ?, ?, ?, ?) """, ( @@ -317,7 +317,7 @@ async def m001_create_funding_table(db): ## PLACEHOLDER FOR ECLAIR WALLET # await db.execute( # """ - # INSERT INTO funding (id, backend_wallet, endpoint, admin_key, selected) + # INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) # VALUES (?, ?, ?, ?, ?) # """, # ( From 08e54de99b72eec2c8f7850ef0d346c15bf64705 Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Mon, 16 May 2022 12:53:47 +0100 Subject: [PATCH 0048/1058] fix sqlite and show user account --- lnbits/app.py | 1 + lnbits/commands.py | 2 +- lnbits/extensions/admin/migrations.py | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lnbits/app.py b/lnbits/app.py index 5df439dc..f066163f 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -117,6 +117,7 @@ def check_settings(app: FastAPI): while True: admin_set = await get_admin_settings() if admin_set : + print(f"Access admin user account at: http://{lnbits.settings.HOST}:{lnbits.settings.PORT}/wallet?usr={admin_set.user}") break print("ERROR:", admin_set) await asyncio.sleep(5) diff --git a/lnbits/commands.py b/lnbits/commands.py index 7d9b49e2..763a5b90 100644 --- a/lnbits/commands.py +++ b/lnbits/commands.py @@ -69,7 +69,7 @@ async def get_admin_settings(): exists = await conn.fetchone( "SELECT * FROM information_schema.tables WHERE table_name = 'admin'" ) - print("EXISTS", exists) + if not exists: return False diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index c94d140b..6c5b507d 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -15,6 +15,7 @@ async def get_admin_user(): user = account.id assert user, "Newly created user couldn't be retrieved" print(f"Your newly created account/user id is: {user}. This will be the Super Admin user.") + conf.admin_users.insert(0, user) return user From 1adfb674ccb6bf44ad6e3680c795ed085bd20d8e Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Mon, 16 May 2022 15:35:04 +0100 Subject: [PATCH 0049/1058] cleanup and info to user on startup --- lnbits/app.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lnbits/app.py b/lnbits/app.py index f066163f..950b6140 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -113,13 +113,11 @@ def create_app(config_object="lnbits.settings") -> FastAPI: def check_settings(app: FastAPI): @app.on_event("startup") async def check_settings_admin(): - while True: admin_set = await get_admin_settings() if admin_set : - print(f"Access admin user account at: http://{lnbits.settings.HOST}:{lnbits.settings.PORT}/wallet?usr={admin_set.user}") break - print("ERROR:", admin_set) + print("Waiting for admin settings... retrying in 5 seconds!") await asyncio.sleep(5) admin_set.admin_users = removeEmptyString(admin_set.admin_users.split(',')) @@ -129,6 +127,7 @@ def check_settings(app: FastAPI): admin_set.theme = removeEmptyString(admin_set.theme.split(',')) admin_set.ad_space = removeEmptyString(admin_set.ad_space.split(',')) g().admin_conf = conf.copy(update=admin_set.dict()) + print(f" ✔️ Access admin user account at: http://{lnbits.settings.HOST}:{lnbits.settings.PORT}/wallet?usr={admin_set.user}") def check_funding_source(app: FastAPI) -> None: @app.on_event("startup") From 363bc85e3b73967c26b9809f1d71664ec8719d8d Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Wed, 8 Jun 2022 11:00:43 +0100 Subject: [PATCH 0050/1058] add custom logo --- lnbits/config.py | 1 + lnbits/extensions/admin/migrations.py | 58 ++----------------- lnbits/extensions/admin/models.py | 2 + .../admin/templates/admin/index.html | 20 +++++-- lnbits/helpers.py | 3 +- 5 files changed, 26 insertions(+), 58 deletions(-) diff --git a/lnbits/config.py b/lnbits/config.py index 3ce51c3c..d07ca044 100644 --- a/lnbits/config.py +++ b/lnbits/config.py @@ -39,6 +39,7 @@ class Settings(BaseSettings): site_description: str = Field(default=None, env="LNBITS_SITE_DESCRIPTION") default_wallet_name: str = Field(default="LNbits wallet", env="LNBITS_DEFAULT_WALLET_NAME") theme: List[str] = Field(default=["classic, flamingo, mint, salvador, monochrome, autumn"], env="LNBITS_THEME_OPTIONS") + custom_logo: str = Field(default=None, env="LNBITS_CUSTOM_LOGO") ad_space: List[str] = Field(default_factory=list, env="LNBITS_AD_SPACE") # .env env: Optional[str] diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index 6c5b507d..aad66f02 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -41,60 +41,9 @@ async def m001_create_admin_table(db): site_description = conf.site_description default_wallet_name = conf.default_wallet_name theme = ",".join(conf.theme) + custom_logo = conf.custom_logo ad_space = ",".join(conf.ad_space) - # if getenv("LNBITS_ADMIN_EXTENSIONS"): - # admin_ext = getenv("LNBITS_ADMIN_EXTENSIONS") - - # if getenv("LNBITS_DATABASE_URL"): - # database_url = getenv("LNBITS_DATABASE_URL") - - # if getenv("LNBITS_HIDE_API"): - # hide_api = getenv("LNBITS_HIDE_API") - - # if getenv("LNBITS_THEME_OPTIONS"): - # theme = getenv("LNBITS_THEME_OPTIONS") - - # if getenv("LNBITS_AD_SPACE"): - # ad_space = getenv("LNBITS_AD_SPACE") - - # if getenv("LNBITS_SITE_TITLE"): - # site_title = getenv("LNBITS_SITE_TITLE") - - # if getenv("LNBITS_SITE_TAGLINE"): - # site_tagline = getenv("LNBITS_SITE_TAGLINE") - - # if getenv("LNBITS_SITE_DESCRIPTION"): - # site_description = getenv("LNBITS_SITE_DESCRIPTION") - - # if getenv("LNBITS_ALLOWED_USERS"): - # allowed_users = getenv("LNBITS_ALLOWED_USERS") - - # if getenv("LNBITS_ADMIN_USERS"): - # admin_users = "".join(getenv("LNBITS_ADMIN_USERS").split()) - # user = admin_users.split(',')[0] - - # if getenv("LNBITS_DEFAULT_WALLET_NAME"): - # default_wallet_name = getenv("LNBITS_DEFAULT_WALLET_NAME") - - # if getenv("LNBITS_DATA_FOLDER"): - # data_folder = getenv("LNBITS_DATA_FOLDER") - - # if getenv("LNBITS_DISABLED_EXTENSIONS"): - # disabled_ext = getenv("LNBITS_DISABLED_EXTENSIONS") - - # if getenv("LNBITS_FORCE_HTTPS"): - # force_https = getenv("LNBITS_FORCE_HTTPS") - - # if getenv("LNBITS_SERVICE_FEE"): - # service_fee = getenv("LNBITS_SERVICE_FEE") - - # if getenv("LNBITS_DENOMINATION"): - # denomination = getenv("LNBITS_DENOMINATION", "sats") - - # if getenv("LNBITS_BACKEND_WALLET_CLASS"): - # funding_source = getenv("LNBITS_BACKEND_WALLET_CLASS") - await db.execute( """ CREATE TABLE IF NOT EXISTS admin.admin ( @@ -115,6 +64,7 @@ async def m001_create_admin_table(db): site_description TEXT, default_wallet_name TEXT, theme TEXT, + custom_logo TEXT, ad_space TEXT ); """ @@ -139,8 +89,9 @@ async def m001_create_admin_table(db): site_description, default_wallet_name, theme, + custom_logo, ad_space) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( user, @@ -160,6 +111,7 @@ async def m001_create_admin_table(db): site_description, default_wallet_name, theme, + custom_logo, ad_space, ), ) diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py index 0f25679d..3b17e720 100644 --- a/lnbits/extensions/admin/models.py +++ b/lnbits/extensions/admin/models.py @@ -23,6 +23,7 @@ class UpdateAdminSettings(BaseModel): default_wallet_name: str = Query("LNbits wallet") denomination: str = Query("sats") theme: str = Query(None) + custom_logo: str = Query(None) ad_space: str = Query(None) class Admin(BaseModel): @@ -46,6 +47,7 @@ class Admin(BaseModel): default_wallet_name: Optional[str] denomination: str = Field(default="sats") theme: Optional[str] + custom_logo: Optional[str] ad_space: Optional[str] @classmethod diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index 584d3a33..d9790051 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -705,6 +705,19 @@
+
+
+

Custom Logo

+ +
+
+
@@ -718,10 +731,7 @@
- +
@@ -1292,6 +1323,8 @@ disabled_ext, funding_source, force_https, + reserve_fee_min, + reserve_fee_pct, service_fee, hide_api, site_title, @@ -1311,6 +1344,8 @@ disabled_ext: disabled_ext.toString(), funding_source, force_https, + reserve_fee_min, + reserve_fee_pct, service_fee, hide_api, site_title, diff --git a/lnbits/settings.py b/lnbits/settings.py index ed5c77f7..8e5c321a 100644 --- a/lnbits/settings.py +++ b/lnbits/settings.py @@ -1,6 +1,5 @@ import importlib import subprocess -from email.policy import default from os import path from typing import List From fcf05a7dd19b831ee986578efad9b2d9094e69bd Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Wed, 8 Jun 2022 15:38:28 +0100 Subject: [PATCH 0052/1058] calle's semantics --- lnbits/extensions/admin/templates/admin/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index 832629bc..d34b9068 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -67,7 +67,7 @@
-

Minimum wallet reserve

+

Fee reserve

From faab389e3fa21671313b66236e66fccbf1f70a1d Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Tue, 5 Jul 2022 16:25:02 +0100 Subject: [PATCH 0053/1058] blacked --- lnbits/extensions/admin/__init__.py | 1 + lnbits/extensions/admin/crud.py | 23 ++++++++++++--- lnbits/extensions/admin/migrations.py | 10 ++++--- lnbits/extensions/admin/models.py | 2 ++ lnbits/extensions/admin/views.py | 10 ++++--- lnbits/extensions/admin/views_api.py | 41 ++++++++++++++------------- 6 files changed, 56 insertions(+), 31 deletions(-) diff --git a/lnbits/extensions/admin/__init__.py b/lnbits/extensions/admin/__init__.py index 6a56b2bb..24b91fe2 100644 --- a/lnbits/extensions/admin/__init__.py +++ b/lnbits/extensions/admin/__init__.py @@ -7,6 +7,7 @@ db = Database("ext_admin") admin_ext: APIRouter = APIRouter(prefix="/admin", tags=["admin"]) + def admin_renderer(): return template_renderer(["lnbits/extensions/admin/templates"]) diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py index 67fbc614..0d7019cc 100644 --- a/lnbits/extensions/admin/crud.py +++ b/lnbits/extensions/admin/crud.py @@ -11,13 +11,13 @@ from .models import Admin, Funding async def update_wallet_balance(wallet_id: str, amount: int) -> str: temp_id = f"temp_{urlsafe_short_hash()}" internal_id = f"internal_{urlsafe_short_hash()}" - + payment = await create_payment( wallet_id=wallet_id, checking_id=internal_id, payment_request="admin_internal", payment_hash="admin_internal", - amount=amount*1000, + amount=amount * 1000, memo="Admin top up", pending=False, ) @@ -25,6 +25,7 @@ async def update_wallet_balance(wallet_id: str, amount: int) -> str: await internal_invoice_queue.put(internal_id) return payment + async def update_admin(user: str, **kwargs) -> Admin: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) # print("UPDATE", q) @@ -35,23 +36,37 @@ async def update_admin(user: str, **kwargs) -> Admin: assert row, "Newly updated settings couldn't be retrieved" return Admin(**row) if row else None + async def get_admin() -> Admin: row = await db.fetchone("SELECT * FROM admin.admin") return Admin(**row) if row else None + async def update_funding(data: Funding) -> Funding: await db.execute( """ UPDATE admin.funding SET backend_wallet = ?, endpoint = ?, port = ?, read_key = ?, invoice_key = ?, admin_key = ?, cert = ?, balance = ?, selected = ? WHERE id = ? - """, - (data.backend_wallet, data.endpoint, data.port, data.read_key, data.invoice_key, data.admin_key, data.cert, data.balance, data.selected, data.id,), + """, + ( + data.backend_wallet, + data.endpoint, + data.port, + data.read_key, + data.invoice_key, + data.admin_key, + data.cert, + data.balance, + data.selected, + data.id, + ), ) row = await db.fetchone('SELECT * FROM admin.funding WHERE "id" = ?', (data.id,)) assert row, "Newly updated settings couldn't be retrieved" return Funding(**row) if row else None + async def get_funding() -> List[Funding]: rows = await db.fetchall("SELECT * FROM admin.funding") diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index f3663435..388f5ec6 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -7,19 +7,21 @@ from lnbits.helpers import urlsafe_short_hash async def get_admin_user(): - if(conf.admin_users[0]): + if conf.admin_users[0]: return conf.admin_users[0] from lnbits.core.crud import create_account, get_user + print("Seems like there's no admin users yet. Let's create an account for you!") account = await create_account() user = account.id assert user, "Newly created user couldn't be retrieved" - print(f"Your newly created account/user id is: {user}. This will be the Super Admin user.") + print( + f"Your newly created account/user id is: {user}. This will be the Super Admin user." + ) conf.admin_users.insert(0, user) return user - async def m001_create_admin_table(db): # users/server user = await get_admin_user() @@ -28,7 +30,7 @@ async def m001_create_admin_table(db): admin_ext = ",".join(conf.admin_ext) disabled_ext = ",".join(conf.disabled_ext) funding_source = conf.funding_source - #operational + # operational data_folder = conf.data_folder database_url = conf.database_url force_https = conf.force_https diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py index 3d8efdcd..6e95d68f 100644 --- a/lnbits/extensions/admin/models.py +++ b/lnbits/extensions/admin/models.py @@ -28,6 +28,7 @@ class UpdateAdminSettings(BaseModel): custom_logo: str = Query(None) ad_space: str = Query(None) + class Admin(BaseModel): # users user: str @@ -59,6 +60,7 @@ class Admin(BaseModel): data = dict(row) return cls(**data) + class Funding(BaseModel): id: str backend_wallet: str diff --git a/lnbits/extensions/admin/views.py b/lnbits/extensions/admin/views.py index 24b8ca85..ceda5192 100644 --- a/lnbits/extensions/admin/views.py +++ b/lnbits/extensions/admin/views.py @@ -16,19 +16,21 @@ from .crud import get_admin, get_funding templates = Jinja2Templates(directory="templates") + @admin_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): admin = await get_admin() funding = [f.dict() for f in await get_funding()] error, balance = await g().WALLET.status() - + return admin_renderer().TemplateResponse( - "admin/index.html", { + "admin/index.html", + { "request": request, "user": user.dict(), "admin": admin.dict(), "funding": funding, "settings": g().admin_conf.dict(), - "balance": balance - } + "balance": balance, + }, ) diff --git a/lnbits/extensions/admin/views_api.py b/lnbits/extensions/admin/views_api.py index c0650c8a..784ad97f 100644 --- a/lnbits/extensions/admin/views_api.py +++ b/lnbits/extensions/admin/views_api.py @@ -15,16 +15,18 @@ from .crud import get_admin, update_admin, update_funding, update_wallet_balance @admin_ext.get("/api/v1/admin/{wallet_id}/{topup_amount}", status_code=HTTPStatus.OK) -async def api_update_balance(wallet_id, topup_amount: int, g: WalletTypeInfo = Depends(require_admin_key)): +async def api_update_balance( + wallet_id, topup_amount: int, g: WalletTypeInfo = Depends(require_admin_key) +): try: wallet = await get_wallet(wallet_id) except: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" - ) + status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" + ) await update_wallet_balance(wallet_id=wallet_id, amount=int(topup_amount)) - + return {"status": "Success"} @@ -32,39 +34,40 @@ async def api_update_balance(wallet_id, topup_amount: int, g: WalletTypeInfo = D async def api_update_admin( request: Request, data: UpdateAdminSettings = Body(...), - w: WalletTypeInfo = Depends(require_admin_key) - ): + w: WalletTypeInfo = Depends(require_admin_key), +): admin = await get_admin() # print(data) if not admin.user == w.wallet.user: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" - ) + status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" + ) updated = await update_admin(user=w.wallet.user, **data.dict()) - updated.admin_users = removeEmptyString(updated.admin_users.split(',')) - updated.allowed_users = removeEmptyString(updated.allowed_users.split(',')) - updated.admin_ext = removeEmptyString(updated.admin_ext.split(',')) - updated.disabled_ext = removeEmptyString(updated.disabled_ext.split(',')) - updated.theme = removeEmptyString(updated.theme.split(',')) - updated.ad_space = removeEmptyString(updated.ad_space.split(',')) + updated.admin_users = removeEmptyString(updated.admin_users.split(",")) + updated.allowed_users = removeEmptyString(updated.allowed_users.split(",")) + updated.admin_ext = removeEmptyString(updated.admin_ext.split(",")) + updated.disabled_ext = removeEmptyString(updated.disabled_ext.split(",")) + updated.theme = removeEmptyString(updated.theme.split(",")) + updated.ad_space = removeEmptyString(updated.ad_space.split(",")) g().admin_conf = g().admin_conf.copy(update=updated.dict()) - + # print(g().admin_conf) return {"status": "Success"} + @admin_ext.post("/api/v1/admin/funding/", status_code=HTTPStatus.OK) async def api_update_funding( request: Request, data: Funding = Body(...), - w: WalletTypeInfo = Depends(require_admin_key) - ): + w: WalletTypeInfo = Depends(require_admin_key), +): admin = await get_admin() if not admin.user == w.wallet.user: raise HTTPException( - status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" - ) + status_code=HTTPStatus.FORBIDDEN, detail="Not allowed: not an admin" + ) funding = await update_funding(data=data) return funding From c319b84d7299eb5f7d942214fab2f21deffb38f6 Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 21 Sep 2022 15:28:13 +0100 Subject: [PATCH 0054/1058] Had to add a couple of tries --- lnbits/core/views/generic.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index 83648c44..63f7af68 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -133,12 +133,19 @@ async def wallet( return template_renderer().TemplateResponse( "error.html", {"request": request, "err": "User does not exist."} ) - if LNBITS_ALLOWED_USERS and user_id not in LNBITS_ALLOWED_USERS: - return template_renderer().TemplateResponse( - "error.html", {"request": request, "err": "User not authorized."} - ) - if LNBITS_ADMIN_USERS and user_id in LNBITS_ADMIN_USERS: - user.admin = True + try: + if LNBITS_ALLOWED_USERS and user_id not in LNBITS_ALLOWED_USERS: + return template_renderer().TemplateResponse( + "error.html", {"request": request, "err": "User not authorized."} + ) + except: + pass + + try: + if LNBITS_ADMIN_USERS and user_id in LNBITS_ADMIN_USERS: + user.admin = True + except: + pass if not wallet_id: if user.wallets and not wallet_name: # type: ignore wallet = user.wallets[0] # type: ignore From d8a13ed29d323f5233c6d9ba5cb59f9ef352d90c Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 21 Sep 2022 15:31:31 +0100 Subject: [PATCH 0055/1058] Added couple more tries --- lnbits/decorators.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lnbits/decorators.py b/lnbits/decorators.py index f951163f..a810892d 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -239,13 +239,16 @@ async def check_user_exists(usr: UUID4) -> User: if LNBITS_ADMIN_UI: LNBITS_ADMIN_USERS = g().admin_conf.admin_users LNBITS_ALLOWED_USERS = g().admin_conf.allowed_users - - if LNBITS_ALLOWED_USERS and g().user.id not in LNBITS_ALLOWED_USERS: - raise HTTPException( - status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized." - ) - - if LNBITS_ADMIN_USERS and g().user.id in LNBITS_ADMIN_USERS: - g().user.admin = True - + try: + if LNBITS_ALLOWED_USERS and g().user.id not in LNBITS_ALLOWED_USERS: + raise HTTPException( + status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized." + ) + except: + pass + try: + if LNBITS_ADMIN_USERS and g().user.id in LNBITS_ADMIN_USERS: + g().user.admin = True + except: + pass return g().user From 55a44030283b34b6d61c0d441b779b135b449c3a Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 21 Sep 2022 15:35:06 +0100 Subject: [PATCH 0056/1058] Reverted try --- lnbits/decorators.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/lnbits/decorators.py b/lnbits/decorators.py index a810892d..904ca1c2 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -239,16 +239,12 @@ async def check_user_exists(usr: UUID4) -> User: if LNBITS_ADMIN_UI: LNBITS_ADMIN_USERS = g().admin_conf.admin_users LNBITS_ALLOWED_USERS = g().admin_conf.allowed_users - try: - if LNBITS_ALLOWED_USERS and g().user.id not in LNBITS_ALLOWED_USERS: - raise HTTPException( - status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized." - ) - except: - pass - try: - if LNBITS_ADMIN_USERS and g().user.id in LNBITS_ADMIN_USERS: - g().user.admin = True + if LNBITS_ALLOWED_USERS and g().user.id not in LNBITS_ALLOWED_USERS: + raise HTTPException( + status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized." + ) + if LNBITS_ADMIN_USERS and g().user.id in LNBITS_ADMIN_USERS: + g().user.admin = True except: pass return g().user From a932f8a3d0c43692f6ec2b1ae9284c279ab7396c Mon Sep 17 00:00:00 2001 From: ben Date: Wed, 21 Sep 2022 15:37:07 +0100 Subject: [PATCH 0057/1058] reverted other try --- lnbits/core/views/generic.py | 19 ++++++------------- lnbits/decorators.py | 2 -- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index 63f7af68..83648c44 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -133,19 +133,12 @@ async def wallet( return template_renderer().TemplateResponse( "error.html", {"request": request, "err": "User does not exist."} ) - try: - if LNBITS_ALLOWED_USERS and user_id not in LNBITS_ALLOWED_USERS: - return template_renderer().TemplateResponse( - "error.html", {"request": request, "err": "User not authorized."} - ) - except: - pass - - try: - if LNBITS_ADMIN_USERS and user_id in LNBITS_ADMIN_USERS: - user.admin = True - except: - pass + if LNBITS_ALLOWED_USERS and user_id not in LNBITS_ALLOWED_USERS: + return template_renderer().TemplateResponse( + "error.html", {"request": request, "err": "User not authorized."} + ) + if LNBITS_ADMIN_USERS and user_id in LNBITS_ADMIN_USERS: + user.admin = True if not wallet_id: if user.wallets and not wallet_name: # type: ignore wallet = user.wallets[0] # type: ignore diff --git a/lnbits/decorators.py b/lnbits/decorators.py index 904ca1c2..dd26d8fe 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -245,6 +245,4 @@ async def check_user_exists(usr: UUID4) -> User: ) if LNBITS_ADMIN_USERS and g().user.id in LNBITS_ADMIN_USERS: g().user.admin = True - except: - pass return g().user From c32e0cbecb147918b2c95ad29bcaf8876855ac0b Mon Sep 17 00:00:00 2001 From: Tiago vasconcelos Date: Wed, 21 Sep 2022 18:40:46 +0100 Subject: [PATCH 0058/1058] fix main merge missing settings --- lnbits/app.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lnbits/app.py b/lnbits/app.py index 950b6140..49ef3d1b 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -56,6 +56,11 @@ def create_app(config_object="lnbits.settings") -> FastAPI: "url": "https://raw.githubusercontent.com/lnbits/lnbits-legend/main/LICENSE", }, ) + if lnbits.settings.LNBITS_ADMIN_UI: + g().admin_conf = conf + check_settings(app) + + g().WALLET = WALLET app.mount("/static", StaticFiles(packages=[("lnbits", "static")]), name="static") app.mount( "/core/static", From e4c310d197fbb6ddb9a7d5528aab66fe60608313 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 22 Sep 2022 10:46:11 +0200 Subject: [PATCH 0059/1058] format --- lnbits/app.py | 22 +++++++++++++--------- lnbits/commands.py | 6 +++++- lnbits/config.py | 25 ++++++++++++++++++------- lnbits/core/views/generic.py | 1 + lnbits/decorators.py | 2 +- lnbits/helpers.py | 8 +++++--- 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/lnbits/app.py b/lnbits/app.py index 49ef3d1b..00ed6d8d 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -115,24 +115,28 @@ def create_app(config_object="lnbits.settings") -> FastAPI: return app + def check_settings(app: FastAPI): @app.on_event("startup") async def check_settings_admin(): while True: admin_set = await get_admin_settings() - if admin_set : + if admin_set: break print("Waiting for admin settings... retrying in 5 seconds!") await asyncio.sleep(5) - - admin_set.admin_users = removeEmptyString(admin_set.admin_users.split(',')) - admin_set.allowed_users = removeEmptyString(admin_set.allowed_users.split(',')) - admin_set.admin_ext = removeEmptyString(admin_set.admin_ext.split(',')) - admin_set.disabled_ext = removeEmptyString(admin_set.disabled_ext.split(',')) - admin_set.theme = removeEmptyString(admin_set.theme.split(',')) - admin_set.ad_space = removeEmptyString(admin_set.ad_space.split(',')) + + admin_set.admin_users = removeEmptyString(admin_set.admin_users.split(",")) + admin_set.allowed_users = removeEmptyString(admin_set.allowed_users.split(",")) + admin_set.admin_ext = removeEmptyString(admin_set.admin_ext.split(",")) + admin_set.disabled_ext = removeEmptyString(admin_set.disabled_ext.split(",")) + admin_set.theme = removeEmptyString(admin_set.theme.split(",")) + admin_set.ad_space = removeEmptyString(admin_set.ad_space.split(",")) g().admin_conf = conf.copy(update=admin_set.dict()) - print(f" ✔️ Access admin user account at: http://{lnbits.settings.HOST}:{lnbits.settings.PORT}/wallet?usr={admin_set.user}") + print( + f" ✔️ Access admin user account at: http://{lnbits.settings.HOST}:{lnbits.settings.PORT}/wallet?usr={admin_set.user}" + ) + def check_funding_source(app: FastAPI) -> None: @app.on_event("startup") diff --git a/lnbits/commands.py b/lnbits/commands.py index 763a5b90..86868f1f 100644 --- a/lnbits/commands.py +++ b/lnbits/commands.py @@ -5,6 +5,7 @@ import re import warnings import click +from genericpath import exists from loguru import logger from .core import db as core_db @@ -52,6 +53,7 @@ def bundle_vendored(): with open(outputpath, "w") as f: f.write(output) + async def get_admin_settings(): from lnbits.extensions.admin.models import Admin @@ -61,6 +63,7 @@ async def get_admin_settings(): return False async with ext_db.connect() as conn: + if conn.type == SQLITE: exists = await conn.fetchone( "SELECT * FROM sqlite_master WHERE type='table' AND name='admin'" @@ -69,7 +72,7 @@ async def get_admin_settings(): exists = await conn.fetchone( "SELECT * FROM information_schema.tables WHERE table_name = 'admin'" ) - + if not exists: return False @@ -77,6 +80,7 @@ async def get_admin_settings(): return Admin(**row) if row else None + async def migrate_databases(): """Creates the necessary databases if they don't exist already; or migrates them.""" diff --git a/lnbits/config.py b/lnbits/config.py index 37b700fd..cf26ad21 100644 --- a/lnbits/config.py +++ b/lnbits/config.py @@ -6,17 +6,19 @@ from typing import List, Optional from pydantic import BaseSettings, Field wallets_module = importlib.import_module("lnbits.wallets") -wallet_class = getattr( +wallet_class = getattr( wallets_module, getenv("LNBITS_BACKEND_WALLET_CLASS", "VoidWallet") ) WALLET = wallet_class() + def list_parse_fallback(v): try: return json.loads(v) except Exception as e: - return v.replace(' ','').split(',') + return v.replace(" ", "").split(",") + class Settings(BaseSettings): admin_ui: bool = Field(default=True, env="LNBITS_ADMIN_UI") @@ -24,7 +26,9 @@ class Settings(BaseSettings): admin_users: List[str] = Field(default_factory=list, env="LNBITS_ADMIN_USERS") allowed_users: List[str] = Field(default_factory=list, env="LNBITS_ALLOWED_USERS") admin_ext: List[str] = Field(default_factory=list, env="LNBITS_ADMIN_EXTENSIONS") - disabled_ext: List[str] = Field(default_factory=list, env="LNBITS_DISABLED_EXTENSIONS") + disabled_ext: List[str] = Field( + default_factory=list, env="LNBITS_DISABLED_EXTENSIONS" + ) funding_source: str = Field(default="VoidWallet", env="LNBITS_BACKEND_WALLET_CLASS") # ops data_folder: str = Field(default=None, env="LNBITS_DATA_FOLDER") @@ -37,10 +41,17 @@ class Settings(BaseSettings): denomination: str = Field(default="sats", env="LNBITS_DENOMINATION") # Change theme site_title: str = Field(default="LNbits", env="LNBITS_SITE_TITLE") - site_tagline: str = Field(default="free and open-source lightning wallet", env="LNBITS_SITE_TAGLINE") + site_tagline: str = Field( + default="free and open-source lightning wallet", env="LNBITS_SITE_TAGLINE" + ) site_description: str = Field(default=None, env="LNBITS_SITE_DESCRIPTION") - default_wallet_name: str = Field(default="LNbits wallet", env="LNBITS_DEFAULT_WALLET_NAME") - theme: List[str] = Field(default=["classic, flamingo, mint, salvador, monochrome, autumn"], env="LNBITS_THEME_OPTIONS") + default_wallet_name: str = Field( + default="LNbits wallet", env="LNBITS_DEFAULT_WALLET_NAME" + ) + theme: List[str] = Field( + default=["classic, flamingo, mint, salvador, monochrome, autumn"], + env="LNBITS_THEME_OPTIONS", + ) custom_logo: str = Field(default=None, env="LNBITS_CUSTOM_LOGO") ad_space: List[str] = Field(default_factory=list, env="LNBITS_AD_SPACE") # .env @@ -48,7 +59,7 @@ class Settings(BaseSettings): debug: Optional[str] host: Optional[str] port: Optional[str] - lnbits_path: Optional[str] = path.dirname(path.realpath(__file__)) + lnbits_path: Optional[str] = path.dirname(path.realpath(__file__)) # @validator('admin_users', 'allowed_users', 'admin_ext', 'disabled_ext', pre=True) # def validate(cls, val): diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index 83648c44..3a1fbdfc 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -39,6 +39,7 @@ from ..services import pay_invoice, redeem_lnurl_withdraw core_html_routes: APIRouter = APIRouter(tags=["Core NON-API Website Routes"]) + @core_html_routes.get("/favicon.ico", response_class=FileResponse) async def favicon(): return FileResponse("lnbits/core/static/favicon.ico") diff --git a/lnbits/decorators.py b/lnbits/decorators.py index dd26d8fe..58b025aa 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -235,7 +235,7 @@ async def check_user_exists(usr: UUID4) -> User: raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) - + if LNBITS_ADMIN_UI: LNBITS_ADMIN_USERS = g().admin_conf.admin_users LNBITS_ALLOWED_USERS = g().admin_conf.allowed_users diff --git a/lnbits/helpers.py b/lnbits/helpers.py index 7bd1b54a..f4255c86 100644 --- a/lnbits/helpers.py +++ b/lnbits/helpers.py @@ -157,11 +157,13 @@ def url_for(endpoint: str, external: Optional[bool] = False, **params: Any) -> s url = f"{base}{endpoint}{url_params}" return url + def removeEmptyString(arr): return list(filter(None, arr)) + def template_renderer(additional_folders: List = []) -> Jinja2Templates: - if(settings.LNBITS_ADMIN_UI): + if settings.LNBITS_ADMIN_UI: _ = g().admin_conf settings.LNBITS_AD_SPACE = _.ad_space settings.LNBITS_HIDE_API = _.hide_api @@ -170,8 +172,8 @@ def template_renderer(additional_folders: List = []) -> Jinja2Templates: settings.LNBITS_SITE_TAGLINE = _.site_tagline settings.LNBITS_SITE_DESCRIPTION = _.site_description settings.LNBITS_THEME_OPTIONS = _.theme - settings.LNBITS_CUSTOM_LOGO = _.custom_logo - + settings.LNBITS_CUSTOM_LOGO = _.custom_logo + t = Jinja2Templates( loader=jinja2.FileSystemLoader( ["lnbits/templates", "lnbits/core/templates", *additional_folders] From 6c2a9b2258087302487716e3d35b1b2387bb58ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 22 Sep 2022 11:47:24 +0200 Subject: [PATCH 0060/1058] format black --- lnbits/app.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lnbits/app.py b/lnbits/app.py index 00ed6d8d..6ae75d7a 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -56,6 +56,7 @@ def create_app(config_object="lnbits.settings") -> FastAPI: "url": "https://raw.githubusercontent.com/lnbits/lnbits-legend/main/LICENSE", }, ) + if lnbits.settings.LNBITS_ADMIN_UI: g().admin_conf = conf check_settings(app) From 7c05d4c354be10d502b7c453f96902f76f9c15d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 22 Sep 2022 15:29:12 +0200 Subject: [PATCH 0061/1058] fix AD_SPACE --- lnbits/core/templates/core/wallet.html | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lnbits/core/templates/core/wallet.html b/lnbits/core/templates/core/wallet.html index bccdc2b4..189b060b 100644 --- a/lnbits/core/templates/core/wallet.html +++ b/lnbits/core/templates/core/wallet.html @@ -385,12 +385,9 @@ - {% endif %} {% if AD_SPACE %} {% for ADS in AD_SPACE %} {% set AD = - ADS.split(';') %} + {% endif %} {% if AD_SPACE %} {% for AD in AD_SPACE %} - {% endfor %} {% endif %}
From 415165c6fe7ec2affda20078c81e12b4fc2944de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 22 Sep 2022 15:55:37 +0200 Subject: [PATCH 0062/1058] fix some javascript errors when adding users --- lnbits/extensions/admin/templates/admin/index.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index d34b9068..1e881cb6 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -1221,7 +1221,7 @@ addAdminUser() { let addUser = this.data.admin_users_add let admin_users = this.data.admin.admin_users - if (addUser.length && !admin_users.includes(addUser)) { + if (addUser && addUser.length && !admin_users.includes(addUser)) { admin_users.push(addUser) this.data.admin.admin_users = admin_users this.data.admin_users_add = '' @@ -1234,7 +1234,7 @@ addAllowedUser() { let addUser = this.data.allowed_users_add let allowed_users = this.data.admin.allowed_users - if (addUser.length && !allowed_users.includes(addUser)) { + if (addUser && addUser.length && !allowed_users.includes(addUser)) { allowed_users.push(addUser) this.data.admin.allowed_users = allowed_users this.data.allowed_users_add = '' @@ -1336,7 +1336,6 @@ custom_logo, ad_space } = this.data.admin - //console.log("this", this.data.admin) let data = { admin_users: admin_users.toString(), allowed_users: allowed_users.toString(), From 850ed85311fea5c5e10bca8cdeaaa0a3dffbe71f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 22 Sep 2022 16:04:55 +0200 Subject: [PATCH 0063/1058] fix ADMIN_UI=false errors --- lnbits/core/views/generic.py | 3 +++ lnbits/decorators.py | 6 ++++++ 2 files changed, 9 insertions(+) diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index 3a1fbdfc..db4fac43 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -124,6 +124,9 @@ async def wallet( if LNBITS_ADMIN_UI: LNBITS_ADMIN_USERS = g().admin_conf.admin_users LNBITS_ALLOWED_USERS = g().admin_conf.allowed_users + else: + LNBITS_ADMIN_USERS = [] + LNBITS_ALLOWED_USERS = [] if not user_id: user = await get_user((await create_account()).id) diff --git a/lnbits/decorators.py b/lnbits/decorators.py index 58b025aa..5a3c0a5c 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -141,6 +141,8 @@ async def get_key_type( if LNBITS_ADMIN_UI: LNBITS_ADMIN_USERS = g().admin_conf.admin_users + else: + LNBITS_ADMIN_USERS = [] for typenr, WalletChecker in zip( [0, 1], [WalletAdminKeyChecker, WalletInvoiceKeyChecker] @@ -239,6 +241,10 @@ async def check_user_exists(usr: UUID4) -> User: if LNBITS_ADMIN_UI: LNBITS_ADMIN_USERS = g().admin_conf.admin_users LNBITS_ALLOWED_USERS = g().admin_conf.allowed_users + else: + LNBITS_ADMIN_USERS = [] + LNBITS_ALLOWED_USERS = [] + if LNBITS_ALLOWED_USERS and g().user.id not in LNBITS_ALLOWED_USERS: raise HTTPException( status_code=HTTPStatus.UNAUTHORIZED, detail="User not authorized." From 393d1a8204f04498aca712604f5646dcb30d7746 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 22 Sep 2022 16:14:17 +0200 Subject: [PATCH 0064/1058] prettier --- lnbits/core/templates/core/wallet.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lnbits/core/templates/core/wallet.html b/lnbits/core/templates/core/wallet.html index 189b060b..22c65bf3 100644 --- a/lnbits/core/templates/core/wallet.html +++ b/lnbits/core/templates/core/wallet.html @@ -386,8 +386,7 @@ {% endif %} {% if AD_SPACE %} {% for AD in AD_SPACE %} - - {% endfor %} {% endif %} From 622d0f50da4b319765175c97613ab31e5e1dd722 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Thu, 22 Sep 2022 18:35:47 +0200 Subject: [PATCH 0065/1058] fix migration tests --- lnbits/extensions/admin/migrations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index 388f5ec6..196c9fc0 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -7,7 +7,7 @@ from lnbits.helpers import urlsafe_short_hash async def get_admin_user(): - if conf.admin_users[0]: + if len(conf.admin_users) > 0: return conf.admin_users[0] from lnbits.core.crud import create_account, get_user From 26769d94984c5d7c4f56b1bd06ca4ce3e376453c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 26 Sep 2022 16:54:19 +0200 Subject: [PATCH 0066/1058] change comments to use multiple lines --- .env.example | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/.env.example b/.env.example index 7a49d5c5..c1ac7497 100644 --- a/.env.example +++ b/.env.example @@ -3,11 +3,15 @@ PORT=5000 DEBUG=false -LNBITS_ADMIN_USERS="" # User IDs seperated by comma -LNBITS_ADMIN_EXTENSIONS="ngrok, admin" # Extensions only admin can access -LNBITS_ADMIN_UI=false # Enable Admin GUI, available for the first user in LNBITS_ADMIN_USERS if available +# User IDs seperated by comma +LNBITS_ADMIN_USERS="" +# Extensions only admin can access +LNBITS_ADMIN_EXTENSIONS="ngrok, admin" +# Enable Admin GUI, available for the first user in LNBITS_ADMIN_USERS if available +LNBITS_ADMIN_UI=false -LNBITS_ALLOWED_USERS="" # Restricts access, User IDs seperated by comma +# Restricts access, User IDs seperated by comma +LNBITS_ALLOWED_USERS="" LNBITS_DEFAULT_WALLET_NAME="LNbits wallet" From cadb6b21617c77fac36ea55937a03c223ec5aa56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 26 Sep 2022 16:59:30 +0200 Subject: [PATCH 0067/1058] fix merge error --- lnbits/app.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lnbits/app.py b/lnbits/app.py index 6ae75d7a..60c09038 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -57,10 +57,6 @@ def create_app(config_object="lnbits.settings") -> FastAPI: }, ) - if lnbits.settings.LNBITS_ADMIN_UI: - g().admin_conf = conf - check_settings(app) - g().WALLET = WALLET app.mount("/static", StaticFiles(packages=[("lnbits", "static")]), name="static") app.mount( From a78ebbacd700c7975662424e07bb042a2da380f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Tue, 27 Sep 2022 14:14:36 +0200 Subject: [PATCH 0068/1058] use logger in app.py --- lnbits/app.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lnbits/app.py b/lnbits/app.py index 60c09038..d7bd3ea6 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -31,8 +31,6 @@ from .helpers import ( url_for_vendored, ) from .requestvars import g - -# from .settings import WALLET from .tasks import ( catch_everything_and_restart, check_pending_payments, @@ -120,7 +118,7 @@ def check_settings(app: FastAPI): admin_set = await get_admin_settings() if admin_set: break - print("Waiting for admin settings... retrying in 5 seconds!") + logger.info("Waiting for admin settings... retrying in 5 seconds!") await asyncio.sleep(5) admin_set.admin_users = removeEmptyString(admin_set.admin_users.split(",")) @@ -130,7 +128,7 @@ def check_settings(app: FastAPI): admin_set.theme = removeEmptyString(admin_set.theme.split(",")) admin_set.ad_space = removeEmptyString(admin_set.ad_space.split(",")) g().admin_conf = conf.copy(update=admin_set.dict()) - print( + logger.info( f" ✔️ Access admin user account at: http://{lnbits.settings.HOST}:{lnbits.settings.PORT}/wallet?usr={admin_set.user}" ) From 8be9b950fdff51e8c9d94d4123cae0dfb650dd3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Tue, 27 Sep 2022 14:14:57 +0200 Subject: [PATCH 0069/1058] fix config --- lnbits/config.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lnbits/config.py b/lnbits/config.py index cf26ad21..874effae 100644 --- a/lnbits/config.py +++ b/lnbits/config.py @@ -17,7 +17,11 @@ def list_parse_fallback(v): try: return json.loads(v) except Exception as e: - return v.replace(" ", "").split(",") + replaced = v.replace(" ", "") + if replaced: + return replaced.split(",") + else: + return [] class Settings(BaseSettings): @@ -48,10 +52,7 @@ class Settings(BaseSettings): default_wallet_name: str = Field( default="LNbits wallet", env="LNBITS_DEFAULT_WALLET_NAME" ) - theme: List[str] = Field( - default=["classic, flamingo, mint, salvador, monochrome, autumn"], - env="LNBITS_THEME_OPTIONS", - ) + theme: List[str] = Field(default_factory=list, env="LNBITS_THEME_OPTIONS") custom_logo: str = Field(default=None, env="LNBITS_CUSTOM_LOGO") ad_space: List[str] = Field(default_factory=list, env="LNBITS_AD_SPACE") # .env @@ -74,4 +75,5 @@ class Settings(BaseSettings): conf = Settings() +print(conf) WALLET = wallet_class() From f2e494384e96587b0b0fb2a9de8825aa9115ee21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Tue, 27 Sep 2022 14:17:20 +0200 Subject: [PATCH 0070/1058] concatenate first migrations script fixup --- lnbits/config.py | 1 - lnbits/extensions/admin/migrations.py | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lnbits/config.py b/lnbits/config.py index 874effae..fe8dabf9 100644 --- a/lnbits/config.py +++ b/lnbits/config.py @@ -75,5 +75,4 @@ class Settings(BaseSettings): conf = Settings() -print(conf) WALLET = wallet_class() diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index 196c9fc0..2d48a8e4 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -23,6 +23,8 @@ async def get_admin_user(): async def m001_create_admin_table(db): + + # users/server user = await get_admin_user() admin_users = ",".join(conf.admin_users) @@ -78,7 +80,7 @@ async def m001_create_admin_table(db): await db.execute( """ INSERT INTO admin.admin ( - "user", + "user", admin_users, allowed_users, admin_ext, @@ -126,9 +128,6 @@ async def m001_create_admin_table(db): ), ) - -async def m001_create_funding_table(db): - funding_wallet = getenv("LNBITS_BACKEND_WALLET_CLASS") # Make the funding table, if it does not already exist From 9757fad8684d166ce9ac04e6a69b0ff820c4de61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Tue, 27 Sep 2022 16:37:08 +0200 Subject: [PATCH 0071/1058] add restart button to frontend --- .../admin/templates/admin/index.html | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index 1e881cb6..319ca3f0 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -65,6 +65,14 @@ :options="data.funding_source" >
+
+ +

Fee reserve

@@ -89,7 +97,7 @@ >
-
+ @@ -1257,6 +1265,24 @@ let spaces = this.data.admin.ad_space this.data.admin.ad_space = spaces.filter(s => s !== ad) }, + restartServer() { + LNbits.api + .request( + 'GET', + '/admin/api/v1/admin/restart/', + this.g.user.wallets[0].adminkey + ) + .then(response => { + this.$q.notify({ + type: 'positive', + message: 'Success! Restarted Server', + icon: null + }) + }) + .catch(function (error) { + LNbits.utils.notifyApiError(error) + }) + }, topupWallet() { LNbits.api .request( From 66739f4246bdc6d3b347f54f675c00937601935e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 3 Oct 2022 16:34:52 +0200 Subject: [PATCH 0072/1058] make extension use new settings --- lnbits/extensions/boltz/boltz.py | 14 ++++++-------- lnbits/extensions/boltz/mempool.py | 15 ++++++--------- lnbits/extensions/boltz/views_api.py | 4 ++-- lnbits/extensions/lndhub/views_api.py | 4 ++-- lnbits/extensions/tpos/views.py | 14 +++++++------- 5 files changed, 23 insertions(+), 28 deletions(-) diff --git a/lnbits/extensions/boltz/boltz.py b/lnbits/extensions/boltz/boltz.py index ac99d4f4..424d0bf7 100644 --- a/lnbits/extensions/boltz/boltz.py +++ b/lnbits/extensions/boltz/boltz.py @@ -12,7 +12,7 @@ from loguru import logger from lnbits.core.services import create_invoice, pay_invoice from lnbits.helpers import urlsafe_short_hash -from lnbits.settings import BOLTZ_NETWORK, BOLTZ_URL +from lnbits.settings import settings from .crud import update_swap_status from .mempool import ( @@ -33,9 +33,7 @@ from .models import ( ) from .utils import check_balance, get_timestamp, req_wrap -net = NETWORKS[BOLTZ_NETWORK] -logger.trace(f"BOLTZ_URL: {BOLTZ_URL}") -logger.trace(f"Bitcoin Network: {net['name']}") +net = NETWORKS[settings.boltz_network] async def create_swap(data: CreateSubmarineSwap) -> SubmarineSwap: @@ -62,7 +60,7 @@ async def create_swap(data: CreateSubmarineSwap) -> SubmarineSwap: res = req_wrap( "post", - f"{BOLTZ_URL}/createswap", + f"{settings.boltz_url}/createswap", json={ "type": "submarine", "pairId": "BTC/BTC", @@ -129,7 +127,7 @@ async def create_reverse_swap( res = req_wrap( "post", - f"{BOLTZ_URL}/createswap", + f"{settings.boltz_url}/createswap", json={ "type": "reversesubmarine", "pairId": "BTC/BTC", @@ -409,7 +407,7 @@ def check_boltz_limits(amount): def get_boltz_pairs(): res = req_wrap( "get", - f"{BOLTZ_URL}/getpairs", + f"{settings.boltz_url}/getpairs", headers={"Content-Type": "application/json"}, ) return res.json() @@ -418,7 +416,7 @@ def get_boltz_pairs(): def get_boltz_status(boltzid): res = req_wrap( "post", - f"{BOLTZ_URL}/swapstatus", + f"{settings.boltz_url}/swapstatus", json={"id": boltzid}, ) return res.json() diff --git a/lnbits/extensions/boltz/mempool.py b/lnbits/extensions/boltz/mempool.py index a44c0f02..a64cadad 100644 --- a/lnbits/extensions/boltz/mempool.py +++ b/lnbits/extensions/boltz/mempool.py @@ -7,14 +7,11 @@ import websockets from embit.transaction import Transaction from loguru import logger -from lnbits.settings import BOLTZ_MEMPOOL_SPACE_URL, BOLTZ_MEMPOOL_SPACE_URL_WS +from lnbits.settings import settings from .utils import req_wrap -logger.trace(f"BOLTZ_MEMPOOL_SPACE_URL: {BOLTZ_MEMPOOL_SPACE_URL}") -logger.trace(f"BOLTZ_MEMPOOL_SPACE_URL_WS: {BOLTZ_MEMPOOL_SPACE_URL_WS}") - -websocket_url = f"{BOLTZ_MEMPOOL_SPACE_URL_WS}/api/v1/ws" +websocket_url = f"{settings.boltz_mempool_space_url_ws}/api/v1/ws" async def wait_for_websocket_message(send, message_string): @@ -33,7 +30,7 @@ async def wait_for_websocket_message(send, message_string): def get_mempool_tx(address): res = req_wrap( "get", - f"{BOLTZ_MEMPOOL_SPACE_URL}/api/address/{address}/txs", + f"{settings.boltz_mempool_space_url}/api/address/{address}/txs", headers={"Content-Type": "text/plain"}, ) txs = res.json() @@ -70,7 +67,7 @@ def get_fee_estimation() -> int: def get_mempool_fees() -> int: res = req_wrap( "get", - f"{BOLTZ_MEMPOOL_SPACE_URL}/api/v1/fees/recommended", + f"{settings.boltz_mempool_space_url}/api/v1/fees/recommended", headers={"Content-Type": "text/plain"}, ) fees = res.json() @@ -80,7 +77,7 @@ def get_mempool_fees() -> int: def get_mempool_blockheight() -> int: res = req_wrap( "get", - f"{BOLTZ_MEMPOOL_SPACE_URL}/api/blocks/tip/height", + f"{settings.boltz_mempool_space_url}/api/blocks/tip/height", headers={"Content-Type": "text/plain"}, ) return int(res.text) @@ -91,7 +88,7 @@ async def send_onchain_tx(tx: Transaction): logger.debug(f"Boltz - mempool sending onchain tx...") req_wrap( "post", - f"{BOLTZ_MEMPOOL_SPACE_URL}/api/tx", + f"{settings.boltz_mempool_space_url}/api/tx", headers={"Content-Type": "text/plain"}, content=raw, ) diff --git a/lnbits/extensions/boltz/views_api.py b/lnbits/extensions/boltz/views_api.py index a4b7d318..18ca14cb 100644 --- a/lnbits/extensions/boltz/views_api.py +++ b/lnbits/extensions/boltz/views_api.py @@ -14,7 +14,7 @@ from starlette.requests import Request from lnbits.core.crud import get_user from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key -from lnbits.settings import BOLTZ_MEMPOOL_SPACE_URL +from lnbits.settings import settings from . import boltz_ext from .boltz import ( @@ -55,7 +55,7 @@ from .utils import check_balance response_model=str, ) async def api_mempool_url(): - return BOLTZ_MEMPOOL_SPACE_URL + return settings.boltz_mempool_space_url # NORMAL SWAP diff --git a/lnbits/extensions/lndhub/views_api.py b/lnbits/extensions/lndhub/views_api.py index 8cbe5a6b..b2328c39 100644 --- a/lnbits/extensions/lndhub/views_api.py +++ b/lnbits/extensions/lndhub/views_api.py @@ -12,7 +12,7 @@ from lnbits import bolt11 from lnbits.core.crud import delete_expired_invoices, get_payments from lnbits.core.services import create_invoice, pay_invoice from lnbits.decorators import WalletTypeInfo -from lnbits.settings import LNBITS_SITE_TITLE, WALLET +from lnbits.settings import WALLET, settings from . import lndhub_ext from .decorators import check_wallet, require_admin_key @@ -56,7 +56,7 @@ async def lndhub_addinvoice( _, pr = await create_invoice( wallet_id=wallet.wallet.id, amount=int(data.amt), - memo=data.memo or LNBITS_SITE_TITLE, + memo=data.memo or settings.lnbits_site_title, extra={"tag": "lndhub"}, ) except: diff --git a/lnbits/extensions/tpos/views.py b/lnbits/extensions/tpos/views.py index e1f1d21e..dac129a9 100644 --- a/lnbits/extensions/tpos/views.py +++ b/lnbits/extensions/tpos/views.py @@ -8,7 +8,7 @@ from starlette.responses import HTMLResponse from lnbits.core.models import User from lnbits.decorators import check_user_exists -from lnbits.settings import LNBITS_CUSTOM_LOGO, LNBITS_SITE_TITLE +from lnbits.settings import settings from . import tpos_ext, tpos_renderer from .crud import get_tpos @@ -50,12 +50,12 @@ async def manifest(tpos_id: str): ) return { - "short_name": LNBITS_SITE_TITLE, - "name": tpos.name + " - " + LNBITS_SITE_TITLE, + "short_name": settings.lnbits_site_title, + "name": tpos.name + " - " + settings.lnbits_site_title, "icons": [ { - "src": LNBITS_CUSTOM_LOGO - if LNBITS_CUSTOM_LOGO + "src": settings.lnbits_custom_logo + if settings.lnbits_custom_logo else "https://cdn.jsdelivr.net/gh/lnbits/lnbits@0.3.0/docs/logos/lnbits.png", "type": "image/png", "sizes": "900x900", @@ -69,9 +69,9 @@ async def manifest(tpos_id: str): "theme_color": "#1F2234", "shortcuts": [ { - "name": tpos.name + " - " + LNBITS_SITE_TITLE, + "name": tpos.name + " - " + settings.lnbits_site_title, "short_name": tpos.name, - "description": tpos.name + " - " + LNBITS_SITE_TITLE, + "description": tpos.name + " - " + settings.lnbits_site_title, "url": "/tpos/" + tpos_id, } ], From 2b2884142fd9c2ac6fbfa3cbd8916aaf2225068a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 3 Oct 2022 16:35:26 +0200 Subject: [PATCH 0073/1058] remove enviroms --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 19dac860..7a69ec43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,6 @@ charset-normalizer = "2.0.6" click = "8.0.1" ecdsa = "0.17.0" embit = "0.4.9" -environs = "9.3.3" fastapi = "0.78.0" h11 = "0.12.0" httpcore = "0.15.0" From 840ede1bd66fd437e342bbefc0880de6fc2f216c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dni=20=E2=9A=A1?= Date: Mon, 3 Oct 2022 16:36:14 +0200 Subject: [PATCH 0074/1058] fix admin --- lnbits/extensions/admin/crud.py | 24 +- lnbits/extensions/admin/migrations.py | 337 +---- lnbits/extensions/admin/models.py | 58 +- .../admin/templates/admin/_tab_funding.html | 158 +++ .../admin/templates/admin/_tab_server.html | 78 ++ .../admin/templates/admin/_tab_theme.html | 122 ++ .../admin/templates/admin/_tab_users.html | 96 ++ .../admin/templates/admin/index.html | 1133 +---------------- lnbits/extensions/admin/views.py | 16 +- lnbits/extensions/admin/views_api.py | 28 +- 10 files changed, 576 insertions(+), 1474 deletions(-) create mode 100644 lnbits/extensions/admin/templates/admin/_tab_funding.html create mode 100644 lnbits/extensions/admin/templates/admin/_tab_server.html create mode 100644 lnbits/extensions/admin/templates/admin/_tab_theme.html create mode 100644 lnbits/extensions/admin/templates/admin/_tab_users.html diff --git a/lnbits/extensions/admin/crud.py b/lnbits/extensions/admin/crud.py index 0d7019cc..e4cb5d77 100644 --- a/lnbits/extensions/admin/crud.py +++ b/lnbits/extensions/admin/crud.py @@ -2,10 +2,11 @@ from typing import List from lnbits.core.crud import create_payment from lnbits.helpers import urlsafe_short_hash +from lnbits.settings import Settings from lnbits.tasks import internal_invoice_queue from . import db -from .models import Admin, Funding +from .models import Funding async def update_wallet_balance(wallet_id: str, amount: int) -> str: @@ -23,26 +24,26 @@ async def update_wallet_balance(wallet_id: str, amount: int) -> str: ) # manually send this for now await internal_invoice_queue.put(internal_id) - return payment -async def update_admin(user: str, **kwargs) -> Admin: +async def update_settings(user: str, **kwargs) -> Settings: q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()]) # print("UPDATE", q) await db.execute( - f'UPDATE admin.admin SET {q} WHERE "user" = ?', (*kwargs.values(), user) + f'UPDATE admin.settings SET {q} WHERE "user" = ?', (*kwargs.values(), user) ) - row = await db.fetchone('SELECT * FROM admin.admin WHERE "user" = ?', (user,)) + row = await db.fetchone('SELECT * FROM admin.settings WHERE "user" = ?', (user,)) assert row, "Newly updated settings couldn't be retrieved" - return Admin(**row) if row else None - - -async def get_admin() -> Admin: - row = await db.fetchone("SELECT * FROM admin.admin") - return Admin(**row) if row else None + return Settings(**row) if row else None async def update_funding(data: Funding) -> Funding: + await db.execute( + """ + UPDATE admin.settings SET funding_source = ? WHERE user = ? + """, + (data.backend_wallet, data.user), + ) await db.execute( """ UPDATE admin.funding @@ -69,5 +70,4 @@ async def update_funding(data: Funding) -> Funding: async def get_funding() -> List[Funding]: rows = await db.fetchall("SELECT * FROM admin.funding") - return [Funding(**row) for row in rows] diff --git a/lnbits/extensions/admin/migrations.py b/lnbits/extensions/admin/migrations.py index 2d48a8e4..8f6c76a0 100644 --- a/lnbits/extensions/admin/migrations.py +++ b/lnbits/extensions/admin/migrations.py @@ -1,292 +1,57 @@ -from os import getenv - -from sqlalchemy.exc import OperationalError # type: ignore - -from lnbits.config import conf -from lnbits.helpers import urlsafe_short_hash - - -async def get_admin_user(): - if len(conf.admin_users) > 0: - return conf.admin_users[0] - from lnbits.core.crud import create_account, get_user - - print("Seems like there's no admin users yet. Let's create an account for you!") - account = await create_account() - user = account.id - assert user, "Newly created user couldn't be retrieved" - print( - f"Your newly created account/user id is: {user}. This will be the Super Admin user." - ) - conf.admin_users.insert(0, user) - return user - - -async def m001_create_admin_table(db): - - - # users/server - user = await get_admin_user() - admin_users = ",".join(conf.admin_users) - allowed_users = ",".join(conf.allowed_users) - admin_ext = ",".join(conf.admin_ext) - disabled_ext = ",".join(conf.disabled_ext) - funding_source = conf.funding_source - # operational - data_folder = conf.data_folder - database_url = conf.database_url - force_https = conf.force_https - reserve_fee_min = conf.reserve_fee_min - reserve_fee_pct = conf.reserve_fee_pct - service_fee = conf.service_fee - hide_api = conf.hide_api - denomination = conf.denomination - # Theme'ing - site_title = conf.site_title - site_tagline = conf.site_tagline - site_description = conf.site_description - default_wallet_name = conf.default_wallet_name - theme = ",".join(conf.theme) - custom_logo = conf.custom_logo - ad_space = ",".join(conf.ad_space) - +async def m001_create_admin_settings_table(db): await db.execute( """ - CREATE TABLE IF NOT EXISTS admin.admin ( - "user" TEXT PRIMARY KEY, - admin_users TEXT, - allowed_users TEXT, - admin_ext TEXT, - disabled_ext TEXT, - funding_source TEXT, - data_folder TEXT, - database_url TEXT, - force_https BOOLEAN, - reserve_fee_min INT, - reserve_fee_pct REAL, - service_fee REAL, - hide_api BOOLEAN, - denomination TEXT, - site_title TEXT, - site_tagline TEXT, - site_description TEXT, - default_wallet_name TEXT, - theme TEXT, - custom_logo TEXT, - ad_space TEXT - ); - """ - ) - await db.execute( - """ - INSERT INTO admin.admin ( - "user", - admin_users, - allowed_users, - admin_ext, - disabled_ext, - funding_source, - data_folder, - database_url, - force_https, - reserve_fee_min, - reserve_fee_pct, - service_fee, - hide_api, - denomination, - site_title, - site_tagline, - site_description, - default_wallet_name, - theme, - custom_logo, - ad_space) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) - """, - ( - user, - admin_users, - allowed_users, - admin_ext, - disabled_ext, - funding_source, - data_folder, - database_url, - force_https, - reserve_fee_min, - reserve_fee_pct, - service_fee, - hide_api, - denomination, - site_title, - site_tagline, - site_description, - default_wallet_name, - theme, - custom_logo, - ad_space, - ), - ) - - funding_wallet = getenv("LNBITS_BACKEND_WALLET_CLASS") - - # Make the funding table, if it does not already exist - await db.execute( - """ - CREATE TABLE IF NOT EXISTS admin.funding ( - id TEXT PRIMARY KEY, - backend_wallet TEXT, - endpoint TEXT, + CREATE TABLE IF NOT EXISTS admin.settings ( + lnbits_admin_ui TEXT, + debug TEXT, + host TEXT, port INT, - read_key TEXT, - invoice_key TEXT, - admin_key TEXT, - cert TEXT, - balance INT, - selected INT + lnbits_path TEXT, + lnbits_commit TEXT, + lnbits_admin_users TEXT, + lnbits_allowed_users TEXT, + lnbits_allowed_funding_sources TEXT, + lnbits_admin_extensions TEXT, + lnbits_disabled_extensions TEXT, + lnbits_site_title TEXT, + lnbits_site_tagline TEXT, + lnbits_site_description TEXT, + lnbits_default_wallet_name TEXT, + lnbits_theme_options TEXT, + lnbits_custom_logo TEXT, + lnbits_ad_space TEXT, + lnbits_data_folder TEXT, + lnbits_database_url TEXT, + lnbits_force_https TEXT, + lnbits_reserve_fee_min TEXT, + lnbits_reserve_fee_percent TEXT, + lnbits_service_fee TEXT, + lnbits_hide_api TEXT, + lnbits_denomination TEXT, + lnbits_backend_wallet_class TEXT, + fake_wallet_secret TEXT, + lnbits_endpoint TEXT, + lnbits_key TEXT, + cliche_endpoint TEXT, + corelightning_rpc TEXT, + eclair_url TEXT, + eclair_pass TEXT, + lnd_rest_endpoint TEXT, + lnd_rest_cert TEXT, + lnd_rest_macaroon TEXT, + lnpay_api_endpoint TEXT, + lnpay_api_key TEXT, + lnpay_wallet_key TEXT, + lntxbot_api_endpoint TEXT, + lntxbot_key TEXT, + opennode_api_endpoint TEXT, + opennode_key TEXT, + spark_url TEXT, + spark_token TEXT, + boltz_network TEXT, + boltz_url TEXT, + boltz_mempool_space_url TEXT, + boltz_mempool_space_url_ws TEXT ); """ ) - - await db.execute( - """ - INSERT INTO admin.funding (id, backend_wallet, endpoint, selected) - VALUES (?, ?, ?, ?) - """, - ( - urlsafe_short_hash(), - "CLightningWallet", - getenv("CLIGHTNING_RPC"), - 1 if funding_wallet == "CLightningWallet" else 0, - ), - ) - await db.execute( - """ - INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) - VALUES (?, ?, ?, ?, ?) - """, - ( - urlsafe_short_hash(), - "SparkWallet", - getenv("SPARK_URL"), - getenv("SPARK_TOKEN"), - 1 if funding_wallet == "SparkWallet" else 0, - ), - ) - - await db.execute( - """ - INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) - VALUES (?, ?, ?, ?, ?) - """, - ( - urlsafe_short_hash(), - "LnbitsWallet", - getenv("LNBITS_ENDPOINT"), - getenv("LNBITS_KEY"), - 1 if funding_wallet == "LnbitsWallet" else 0, - ), - ) - - await db.execute( - """ - INSERT INTO admin.funding (id, backend_wallet, endpoint, port, admin_key, cert, selected) - VALUES (?, ?, ?, ?, ?, ?, ?) - """, - ( - urlsafe_short_hash(), - "LndWallet", - getenv("LND_GRPC_ENDPOINT"), - getenv("LND_GRPC_PORT"), - getenv("LND_GRPC_MACAROON"), - getenv("LND_GRPC_CERT"), - 1 if funding_wallet == "LndWallet" else 0, - ), - ) - - await db.execute( - """ - INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, cert, selected) - VALUES (?, ?, ?, ?, ?, ?) - """, - ( - urlsafe_short_hash(), - "LndRestWallet", - getenv("LND_REST_ENDPOINT"), - getenv("LND_REST_MACAROON"), - getenv("LND_REST_CERT"), - 1 if funding_wallet == "LndWallet" else 0, - ), - ) - - await db.execute( - """ - INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, cert, selected) - VALUES (?, ?, ?, ?, ?, ?) - """, - ( - urlsafe_short_hash(), - "LNPayWallet", - getenv("LNPAY_API_ENDPOINT"), - getenv("LNPAY_WALLET_KEY"), - getenv("LNPAY_API_KEY"), # this is going in as the cert - 1 if funding_wallet == "LNPayWallet" else 0, - ), - ) - - await db.execute( - """ - INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) - VALUES (?, ?, ?, ?, ?) - """, - ( - urlsafe_short_hash(), - "LntxbotWallet", - getenv("LNTXBOT_API_ENDPOINT"), - getenv("LNTXBOT_KEY"), - 1 if funding_wallet == "LntxbotWallet" else 0, - ), - ) - - await db.execute( - """ - INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) - VALUES (?, ?, ?, ?, ?) - """, - ( - urlsafe_short_hash(), - "OpenNodeWallet", - getenv("OPENNODE_API_ENDPOINT"), - getenv("OPENNODE_KEY"), - 1 if funding_wallet == "OpenNodeWallet" else 0, - ), - ) - - await db.execute( - """ - INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) - VALUES (?, ?, ?, ?, ?) - """, - ( - urlsafe_short_hash(), - "SparkWallet", - getenv("SPARK_URL"), - getenv("SPARK_TOKEN"), - 1 if funding_wallet == "SparkWallet" else 0, - ), - ) - - ## PLACEHOLDER FOR ECLAIR WALLET - # await db.execute( - # """ - # INSERT INTO admin.funding (id, backend_wallet, endpoint, admin_key, selected) - # VALUES (?, ?, ?, ?, ?) - # """, - # ( - # urlsafe_short_hash(), - # "EclairWallet", - # getenv("ECLAIR_URL"), - # getenv("ECLAIR_PASS"), - # 1 if funding_wallet == "EclairWallet" else 0, - # ), - # ) diff --git a/lnbits/extensions/admin/models.py b/lnbits/extensions/admin/models.py index 6e95d68f..ef57cadd 100644 --- a/lnbits/extensions/admin/models.py +++ b/lnbits/extensions/admin/models.py @@ -29,36 +29,36 @@ class UpdateAdminSettings(BaseModel): ad_space: str = Query(None) -class Admin(BaseModel): - # users - user: str - admin_users: Optional[str] - allowed_users: Optional[str] - admin_ext: Optional[str] - disabled_ext: Optional[str] - funding_source: Optional[str] - # ops - data_folder: Optional[str] - database_url: Optional[str] - force_https: bool = Field(default=True) - reserve_fee_min: Optional[int] - reserve_fee_pct: Optional[float] - service_fee: float = Optional[float] - hide_api: bool = Field(default=False) - # Change theme - site_title: Optional[str] - site_tagline: Optional[str] - site_description: Optional[str] - default_wallet_name: Optional[str] - denomination: str = Field(default="sats") - theme: Optional[str] - custom_logo: Optional[str] - ad_space: Optional[str] +# class Admin(BaseModel): +# # users +# user: str +# admin_users: Optional[str] +# allowed_users: Optional[str] +# admin_ext: Optional[str] +# disabled_ext: Optional[str] +# funding_source: Optional[str] +# # ops +# data_folder: Optional[str] +# database_url: Optional[str] +# force_https: bool = Field(default=True) +# reserve_fee_min: Optional[int] +# reserve_fee_pct: Optional[float] +# service_fee: float = Optional[float] +# hide_api: bool = Field(default=False) +# # Change theme +# site_title: Optional[str] +# site_tagline: Optional[str] +# site_description: Optional[str] +# default_wallet_name: Optional[str] +# denomination: str = Field(default="sats") +# theme: Optional[str] +# custom_logo: Optional[str] +# ad_space: Optional[str] - @classmethod - def from_row(cls, row: Row) -> "Admin": - data = dict(row) - return cls(**data) +# @classmethod +# def from_row(cls, row: Row) -> "Admin": +# data = dict(row) +# return cls(**data) class Funding(BaseModel): diff --git a/lnbits/extensions/admin/templates/admin/_tab_funding.html b/lnbits/extensions/admin/templates/admin/_tab_funding.html new file mode 100644 index 00000000..2ed0aae2 --- /dev/null +++ b/lnbits/extensions/admin/templates/admin/_tab_funding.html @@ -0,0 +1,158 @@ + + +
Wallets Management
+
+
+
+
+

Funding Source Info

+
    + {%raw%} +
  • + Funding Source: {{data.settings.lnbits_backend_wallet_class}} +
  • +
  • Balance: {{data.balance / 1000}} sats
  • + {%endraw%} +
+
+
+
+
+
+
+
+

Active Funding (Requires server restart)

+ +
+
+ +
+
+
+

Fee reserve

+
+
+ +
+
+ +
+
+
+
+
+
+

TopUp a wallet

+
+
+ +
+
+
+ +
+
+
+ +
+
+
+
+

Funding Sources

+ {% raw %} + + + + + + + + + + + + + + {% endraw %} +
+
+
diff --git a/lnbits/extensions/admin/templates/admin/_tab_server.html b/lnbits/extensions/admin/templates/admin/_tab_server.html new file mode 100644 index 00000000..2924e6a4 --- /dev/null +++ b/lnbits/extensions/admin/templates/admin/_tab_server.html @@ -0,0 +1,78 @@ + + +
Server Management
+
+
+
+
+

Server Info

+
    + {%raw%} +
  • + SQlite: {{data.settings.lnbits_data_folder}} +
  • +
  • + Postgres: {{data.settings.lnbits_database_url}} +
  • + {%endraw%} +
+
+
+
+
+
+

Service Fee

+ +
+
+
+

Miscelaneous

+ + + Force HTTPS + Prefer secure URLs + + + + + + + + Hide API + Hides wallet api, extensions can choose to honor + + + + + +
+
+
+
+ +
+ Save +
+
+
diff --git a/lnbits/extensions/admin/templates/admin/_tab_theme.html b/lnbits/extensions/admin/templates/admin/_tab_theme.html new file mode 100644 index 00000000..41dc0447 --- /dev/null +++ b/lnbits/extensions/admin/templates/admin/_tab_theme.html @@ -0,0 +1,122 @@ + + +
UI Management
+
+
+
+
+

Site Title

+ +
+
+
+

Site Tagline

+ +
+
+
+
+

Site Description

+ +
+
+
+
+

Default Wallet Name

+ +
+
+
+

Denomination

+ +
+
+
+
+
+

Themes

+ +
+
+
+

Advertisement Slots

+ + + +
+ {% raw %} + + {{ space.slice(0, 8) + " ... " + space.slice(-8) }} + + {% endraw %} +
+
+
+
+
+
+

Custom Logo

+ +
+
+
+
+ +
+ Save +
+
+
diff --git a/lnbits/extensions/admin/templates/admin/_tab_users.html b/lnbits/extensions/admin/templates/admin/_tab_users.html new file mode 100644 index 00000000..3eb53ac4 --- /dev/null +++ b/lnbits/extensions/admin/templates/admin/_tab_users.html @@ -0,0 +1,96 @@ + + +
User Management
+
+

+ Super Admin: {% raw %}{{this.data.settings.lnbits_admin_users[0]}}{% + endraw %} +

+
+
+

Admin Users

+ + + +
+ {% raw %} + + {{ user }} + + {% endraw %} +
+
+
+
+

Allowed Users

+ + + +
+ {% raw %} + + {{ user }} + + {% endraw %} +
+
+
+
+
+

Admin Extensions

+ +
+
+
+

Disabled Extensions

+ +
+
+
+
+ Save +
+
+
diff --git a/lnbits/extensions/admin/templates/admin/index.html b/lnbits/extensions/admin/templates/admin/index.html index 319ca3f0..87e89321 100644 --- a/lnbits/extensions/admin/templates/admin/index.html +++ b/lnbits/extensions/admin/templates/admin/index.html @@ -29,1118 +29,16 @@ - - - -
Wallets Management
-
-
-
-
-

Funding Source Info

-
    - {%raw%} -
  • Funding Source: {{data.admin.funding_source}}
  • -
  • Balance: {{data.admin.balance / 1000}} sats
  • - {%endraw%} -
-
-
-
-
-
-
-
-

- Active Funding - (Requires server restart) -

- -
-
- -
-
-
-

Fee reserve

-
-
- -
-
- -
-
- -
-
-
-
- -

TopUp a wallet

-
-
- -
-
-
- -
-
-
- -
- -
-
-
-

Funding Sources

- {% raw %} - - - - - - - - - - - - - - {% endraw %} - -
-
-
- - -
User Management
-
-

- Super Admin: {% raw %}{{this.data.admin.user}}{% endraw %} -

-
-
-

Admin Users

- - - -
- {% raw %} - - {{ user }} - - {% endraw %} -
-
-
-
-

Allowed Users

- - - -
- {% raw %} - - {{ user }} - - {% endraw %} -
-
-
-
-
-

Admin Extensions

- -
-
-
-

Disabled Extensions

- -
-
-
-
- Save -
-
-
- - -
Server Management
-
-
-
-
-

Server Info

-
    - {%raw%} -
  • - SQlite: {{data.admin.data_folder}} -
  • -
  • - Postgres: {{data.admin.database_url}} -
  • - {%endraw%} -
-
-
-
-
-
-

Service Fee

- -
-
-
-

Miscelaneous

- - - Force HTTPS - Prefer secure URLs - - - - - - - - Hide API - Hides wallet api, extensions can choose to - honor - - - - - -
-
-
-
- -
- Save -
-
-
- - -
UI Management
-
-
-
-
-

Site Title

- -
-
-
-

Site Tagline

- -
-
-
-
-

Site Description

- -
-
-
-
-

Default Wallet Name

- -
-
-
-

Denomination

- -
-
-
-
-
-

Themes

- -
-
-
-

Advertisement Slots

- - - -
- {% raw %} - - {{ space.slice(0, 8) + " ... " + space.slice(-8) }} - - {% endraw %} -
-
-
-
-
-
-

Custom Logo

- -
-
-
-
- -
- Save -
-
-
+ {% include "admin/_tab_funding.html" %} {% include + "admin/_tab_users.html" %} {% include "admin/_tab_server.html" %} {% + include "admin/_tab_theme.html" %}
- - -
- -
{% endblock %} {% block scripts %} {{ window_vars(user) }} -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/lnbits/extensions/cashu/templates/cashu/mint.html b/lnbits/extensions/cashu/templates/cashu/mint.html index 0f3e0e09..3c0998b5 100644 --- a/lnbits/extensions/cashu/templates/cashu/mint.html +++ b/lnbits/extensions/cashu/templates/cashu/mint.html @@ -5,14 +5,17 @@
+ name="account_balance" + class="text-grey" + style="font-size: 10rem" + >

{{ mint_name }}


-
Some data about mint here:
* whether its online
* Who to contact for support
* etc...
+
+ Some data about mint here:
* whether its online
* Who to + contact for support
* etc... +
diff --git a/lnbits/extensions/cashu/templates/cashu/wallet.html b/lnbits/extensions/cashu/templates/cashu/wallet.html index a5d5f371..75dff22e 100644 --- a/lnbits/extensions/cashu/templates/cashu/wallet.html +++ b/lnbits/extensions/cashu/templates/cashu/wallet.html @@ -1,41 +1,69 @@ -{% extends "public.html" %} {% block toolbar_title %} {% raw %} {{name}} Wallet {% endraw %} - -{% endblock %} {% block footer %}{% endblock %} {% block page_container %} +{% extends "public.html" %} {% block toolbar_title %} {% raw %} {{name}} Wallet +{% endraw %} {% endblock %} {% block footer %}{% endblock %} {% block +page_container %}
- - -
+

-
{% raw %} {{balanceAmount}} - {{tickershort}}{% endraw %}
+
+ {% raw %} {{balanceAmount}} {{tickershort}}{% + endraw %} +

-
- -
+
- Receive + Receive
- Send + Send
- Peg in/out + Peg in/out
- scan + scan
- -
- +
@@ -43,42 +71,99 @@
Transactions
-
{% raw %} - {% endraw %} +
+ {% raw %} + {% endraw %} Mint details - Export to CSV + Export to CSV - + Show chart
- + - + {% raw %}