Merge branch 'main' into draggablecopilot
This commit is contained in:
commit
615734e4a9
34 changed files with 751 additions and 516 deletions
13
.env.example
13
.env.example
|
|
@ -54,8 +54,9 @@ LNBITS_SITE_DESCRIPTION="Some description about your service, will display if ti
|
|||
LNBITS_THEME_OPTIONS="classic, bitcoin, flamingo, freedom, mint, autumn, monochrome, salvador"
|
||||
# LNBITS_CUSTOM_LOGO="https://lnbits.com/assets/images/logo/logo.svg"
|
||||
|
||||
# Choose from LNPayWallet, OpenNodeWallet, LntxbotWallet, ClicheWallet, LnTipsWallet
|
||||
# LndRestWallet, CoreLightningWallet, LNbitsWallet, SparkWallet, FakeWallet, EclairWallet
|
||||
# Choose from LNPayWallet, OpenNodeWallet, LntxbotWallet, ClicheWallet,
|
||||
# LndWallet, LndRestWallet, CoreLightningWallet, EclairWallet,
|
||||
# LnTipsWallet, LNbitsWallet, SparkWallet, FakeWallet,
|
||||
LNBITS_BACKEND_WALLET_CLASS=VoidWallet
|
||||
# VoidWallet is just a fallback that works without any actual Lightning capabilities,
|
||||
# just so you can see the UI before dealing with this file.
|
||||
|
|
@ -76,6 +77,14 @@ CORELIGHTNING_RPC="/home/bob/.lightning/bitcoin/lightning-rpc"
|
|||
LNBITS_ENDPOINT=https://legend.lnbits.com
|
||||
LNBITS_KEY=LNBITS_ADMIN_KEY
|
||||
|
||||
# LndWallet
|
||||
LND_GRPC_ENDPOINT=127.0.0.1
|
||||
LND_GRPC_PORT=10009
|
||||
LND_GRPC_CERT="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/tls.cert"
|
||||
LND_GRPC_MACAROON="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/admin.macaroon or HEXSTRING"
|
||||
# To use an AES-encrypted macaroon, set
|
||||
# LND_GRPC_MACAROON="eNcRyPtEdMaCaRoOn"
|
||||
|
||||
# LndRestWallet
|
||||
LND_REST_ENDPOINT=https://127.0.0.1:8080/
|
||||
LND_REST_CERT="/home/bob/.config/Zap/lnd/bitcoin/mainnet/wallet-1/data/chain/bitcoin/mainnet/tls.cert"
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ By default, LNbits will use SQLite as its database. You can also use PostgreSQL
|
|||
If you have problems installing LNbits using these instructions, please have a look at the [Troubleshooting](#troubleshooting) section.
|
||||
|
||||
```sh
|
||||
git clone https://github.com/lnbits/lnbits-legend.git
|
||||
cd lnbits-legend/
|
||||
git clone https://github.com/lnbits/lnbits.git
|
||||
cd lnbits
|
||||
|
||||
# for making sure python 3.9 is installed, skip if installed. To check your installed version: python3 --version
|
||||
sudo apt update
|
||||
|
|
@ -50,9 +50,10 @@ poetry run lnbits
|
|||
#### Updating the server
|
||||
|
||||
```
|
||||
cd lnbits-legend/
|
||||
cd lnbits
|
||||
# Stop LNbits with `ctrl + x`
|
||||
git pull
|
||||
# Keep your poetry install up to date, this can be done with `poetry self update`
|
||||
poetry install --only main
|
||||
# Start LNbits with `poetry run lnbits`
|
||||
```
|
||||
|
|
@ -62,8 +63,8 @@ poetry install --only main
|
|||
> note: currently not supported while we make some architectural changes on the path to leave beta
|
||||
|
||||
```sh
|
||||
git clone https://github.com/lnbits/lnbits-legend.git
|
||||
cd lnbits-legend/
|
||||
git clone https://github.com/lnbits/lnbits.git
|
||||
cd lnbits
|
||||
# Modern debian distros usually include Nix, however you can install with:
|
||||
# 'sh <(curl -L https://nixos.org/nix/install) --daemon', or use setup here https://nixos.org/download.html#nix-verify-installation
|
||||
|
||||
|
|
@ -82,8 +83,8 @@ LNBITS_DATA_FOLDER=data LNBITS_BACKEND_WALLET_CLASS=LNbitsWallet LNBITS_ENDPOINT
|
|||
## Option 3: venv
|
||||
|
||||
```sh
|
||||
git clone https://github.com/lnbits/lnbits-legend.git
|
||||
cd lnbits-legend/
|
||||
git clone https://github.com/lnbits/lnbits.git
|
||||
cd lnbits
|
||||
# ensure you have virtualenv installed, on debian/ubuntu 'apt install python3.9-venv'
|
||||
python3.9 -m venv venv
|
||||
# If you have problems here, try `sudo apt install -y pkg-config libpq-dev`
|
||||
|
|
@ -105,9 +106,9 @@ If you want to host LNbits on the internet, run with the option `--host 0.0.0.0`
|
|||
## Option 4: Docker
|
||||
|
||||
```sh
|
||||
git clone https://github.com/lnbits/lnbits-legend.git
|
||||
cd lnbits-legend
|
||||
docker build -t lnbits-legend .
|
||||
git clone https://github.com/lnbits/lnbits.git
|
||||
cd lnbits
|
||||
docker build -t lnbits .
|
||||
cp .env.example .env
|
||||
mkdir data
|
||||
docker run --detach --publish 5000:5000 --name lnbits-legend --volume ${PWD}/.env:/app/.env --volume ${PWD}/data/:/app/data lnbits-legend
|
||||
|
|
@ -135,8 +136,8 @@ You can either run those commands, then `source ~/.bash_profile` or, if you don'
|
|||
Once installed, run the following commands.
|
||||
|
||||
```
|
||||
git clone https://github.com/lnbits/lnbits-legend.git
|
||||
cd lnbits-legend
|
||||
git clone https://github.com/lnbits/lnbits.git
|
||||
cd lnbits
|
||||
fly auth login
|
||||
[complete login process]
|
||||
fly launch
|
||||
|
|
@ -437,8 +438,8 @@ If you want to run LNbits on your Umbrel but want it to be reached through clear
|
|||
To install using docker you first need to build the docker image as:
|
||||
|
||||
```
|
||||
git clone https://github.com/lnbits/lnbits-legend.git
|
||||
cd lnbits-legend
|
||||
git clone https://github.com/lnbits/lnbits.git
|
||||
cd lnbits
|
||||
docker build -t lnbits-legend .
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@
|
|||
outline
|
||||
color="grey"
|
||||
type="a"
|
||||
href="https://github.com/lnbits/lnbits-legend"
|
||||
href="https://github.com/lnbits/lnbits"
|
||||
target="_blank"
|
||||
rel="noopener"
|
||||
>View project in GitHub</q-btn
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import json
|
||||
import os
|
||||
from typing import Callable, Dict, Union
|
||||
|
||||
import httpx
|
||||
|
||||
|
|
@ -12,7 +13,9 @@ fiat_currencies = json.load(
|
|||
)
|
||||
)
|
||||
|
||||
exchange_rate_providers = {
|
||||
exchange_rate_providers: dict[
|
||||
str, dict[str, Union[str, Callable[[dict, dict], str]]]
|
||||
] = {
|
||||
"bitfinex": {
|
||||
"name": "Bitfinex",
|
||||
"domain": "bitfinex.com",
|
||||
|
|
@ -65,17 +68,19 @@ async def fetch_fiat_exchange_rate(currency: str, provider: str):
|
|||
"to": currency.lower(),
|
||||
}
|
||||
|
||||
url = exchange_rate_providers[provider]["api_url"]
|
||||
if url:
|
||||
api_url_or_none = exchange_rate_providers[provider]["api_url"]
|
||||
if api_url_or_none is not None:
|
||||
api_url = str(api_url_or_none)
|
||||
for key in replacements.keys():
|
||||
url = url.replace("{" + key + "}", replacements[key])
|
||||
api_url = api_url.replace("{" + key + "}", replacements[key])
|
||||
async with httpx.AsyncClient() as client:
|
||||
r = await client.get(url)
|
||||
r = await client.get(api_url)
|
||||
r.raise_for_status()
|
||||
data = r.json()
|
||||
else:
|
||||
data = {}
|
||||
|
||||
getter = exchange_rate_providers[provider]["getter"]
|
||||
rate = float(getter(data, replacements))
|
||||
print(getter)
|
||||
if callable(getter):
|
||||
rate = float(getter(data, replacements))
|
||||
return rate
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import urllib
|
||||
from http import HTTPStatus
|
||||
from typing import Dict
|
||||
from urllib import parse
|
||||
|
||||
from starlette.requests import Request
|
||||
from fastapi import Request
|
||||
|
||||
|
||||
def generate_bleskomat_lnurl_hash(secret: str):
|
||||
|
|
@ -22,7 +22,7 @@ def generate_bleskomat_lnurl_signature(
|
|||
elif api_key_encoding == "base64":
|
||||
key = base64.b64decode(api_key_secret)
|
||||
else:
|
||||
key = bytes(f"{api_key_secret}")
|
||||
key = bytes.fromhex(api_key_secret)
|
||||
return hmac.new(key=key, msg=payload.encode(), digestmod=hashlib.sha256).hexdigest()
|
||||
|
||||
|
||||
|
|
@ -57,8 +57,8 @@ class LnurlValidationError(Exception):
|
|||
pass
|
||||
|
||||
|
||||
def prepare_lnurl_params(tag: str, query: Dict[str, str]):
|
||||
params = {}
|
||||
def prepare_lnurl_params(tag: str, query: dict) -> dict:
|
||||
params: dict = {}
|
||||
if not is_supported_lnurl_subprotocol(tag):
|
||||
raise LnurlValidationError(f'Unsupported subprotocol: "{tag}"')
|
||||
if tag == "withdrawRequest":
|
||||
|
|
@ -85,15 +85,15 @@ def query_to_signing_payload(query: Dict[str, str]) -> str:
|
|||
payload = []
|
||||
for key in sorted_keys:
|
||||
if not key == "signature":
|
||||
encoded_key = urllib.parse.quote(key, safe=encode_uri_component_safe_chars)
|
||||
encoded_value = urllib.parse.quote(
|
||||
encoded_key = parse.quote(key, safe=encode_uri_component_safe_chars)
|
||||
encoded_value = parse.quote(
|
||||
query[key], safe=encode_uri_component_safe_chars
|
||||
)
|
||||
payload.append(f"{encoded_key}={encoded_value}")
|
||||
return "&".join(payload)
|
||||
|
||||
|
||||
unshorten_rules = {
|
||||
unshorten_rules: dict[str, dict] = {
|
||||
"query": {"n": "nonce", "s": "signature", "t": "tag"},
|
||||
"tags": {
|
||||
"c": "channelRequest",
|
||||
|
|
@ -114,7 +114,7 @@ unshorten_rules = {
|
|||
}
|
||||
|
||||
|
||||
def unshorten_lnurl_query(query: Dict[str, str]) -> Dict[str, str]:
|
||||
def unshorten_lnurl_query(query: dict) -> Dict[str, str]:
|
||||
new_query = {}
|
||||
rules = unshorten_rules
|
||||
if "tag" in query:
|
||||
|
|
@ -131,9 +131,9 @@ def unshorten_lnurl_query(query: Dict[str, str]) -> Dict[str, str]:
|
|||
if not tag in rules["params"]:
|
||||
raise LnurlValidationError(f'Unknown tag: "{tag}"')
|
||||
for key in query:
|
||||
if key in rules["params"][tag]:
|
||||
if key in rules["params"][str(tag)]:
|
||||
short_param_key = key
|
||||
long_param_key = rules["params"][tag][short_param_key]
|
||||
long_param_key = rules["params"][str(tag)][short_param_key]
|
||||
if short_param_key in query:
|
||||
new_query[long_param_key] = query[short_param_key]
|
||||
else:
|
||||
|
|
@ -146,7 +146,7 @@ def unshorten_lnurl_query(query: Dict[str, str]) -> Dict[str, str]:
|
|||
if short_key in query:
|
||||
new_query[long_key] = query[short_key]
|
||||
else:
|
||||
new_query[long_key] = query[long_key]
|
||||
new_query[long_key] = query[str(long_key)]
|
||||
else:
|
||||
# Keep unknown key/value pairs unchanged:
|
||||
new_query[key] = query[key]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import json
|
||||
import math
|
||||
import traceback
|
||||
from http import HTTPStatus
|
||||
|
||||
from loguru import logger
|
||||
|
|
@ -28,7 +27,7 @@ from .helpers import (
|
|||
@bleskomat_ext.get("/u", name="bleskomat.api_bleskomat_lnurl")
|
||||
async def api_bleskomat_lnurl(req: Request):
|
||||
try:
|
||||
query = req.query_params
|
||||
query = dict(req.query_params)
|
||||
|
||||
# Unshorten query if "s" is used instead of "signature".
|
||||
if "s" in query:
|
||||
|
|
@ -89,11 +88,15 @@ async def api_bleskomat_lnurl(req: Request):
|
|||
# Convert to msats:
|
||||
params[key] = int(amount_sats_less_fee * 1e3)
|
||||
except LnurlValidationError as e:
|
||||
raise LnurlHttpError(e.message, HTTPStatus.BAD_REQUEST)
|
||||
raise LnurlHttpError(str(e), HTTPStatus.BAD_REQUEST)
|
||||
# Create a new LNURL using the query parameters provided in the signed URL.
|
||||
params = json.JSONEncoder().encode(params)
|
||||
json_params = json.JSONEncoder().encode(params)
|
||||
lnurl = await create_bleskomat_lnurl(
|
||||
bleskomat=bleskomat, secret=secret, tag=tag, params=params, uses=1
|
||||
bleskomat=bleskomat,
|
||||
secret=secret,
|
||||
tag=tag,
|
||||
params=json_params,
|
||||
uses=1,
|
||||
)
|
||||
|
||||
# Reply with LNURL response object.
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@ import json
|
|||
import time
|
||||
from typing import Dict
|
||||
|
||||
from fastapi.params import Query
|
||||
from fastapi import Query, Request
|
||||
from loguru import logger
|
||||
from pydantic import BaseModel, validator
|
||||
from starlette.requests import Request
|
||||
|
||||
from lnbits import bolt11
|
||||
from lnbits.core.services import PaymentFailure, pay_invoice
|
||||
|
|
@ -80,7 +79,7 @@ class BleskomatLnurl(BaseModel):
|
|||
response["k1"] = secret
|
||||
return response
|
||||
|
||||
def validate_action(self, query: Dict[str, str]) -> None:
|
||||
def validate_action(self, query) -> None:
|
||||
tag = self.tag
|
||||
params = json.loads(self.params)
|
||||
# Perform tag-specific checks.
|
||||
|
|
@ -109,7 +108,7 @@ class BleskomatLnurl(BaseModel):
|
|||
else:
|
||||
raise LnurlValidationError(f'Unknown subprotocol: "{tag}"')
|
||||
|
||||
async def execute_action(self, query: Dict[str, str]):
|
||||
async def execute_action(self, query):
|
||||
self.validate_action(query)
|
||||
used = False
|
||||
async with db.connect() as conn:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
from fastapi import Request
|
||||
from fastapi.params import Depends
|
||||
from fastapi import Depends, Request
|
||||
from fastapi.templating import Jinja2Templates
|
||||
from starlette.responses import HTMLResponse
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ from starlette.exceptions import HTTPException
|
|||
|
||||
from lnbits.core.crud import get_user
|
||||
from lnbits.decorators import WalletTypeInfo, require_admin_key
|
||||
from lnbits.extensions.bleskomat.models import CreateBleskomat
|
||||
|
||||
from . import bleskomat_ext
|
||||
from .crud import (
|
||||
|
|
@ -17,6 +16,7 @@ from .crud import (
|
|||
update_bleskomat,
|
||||
)
|
||||
from .exchange_rates import fetch_fiat_exchange_rate
|
||||
from .models import CreateBleskomat
|
||||
|
||||
|
||||
@bleskomat_ext.get("/api/v1/bleskomats")
|
||||
|
|
@ -27,7 +27,8 @@ async def api_bleskomats(
|
|||
wallet_ids = [wallet.wallet.id]
|
||||
|
||||
if all_wallets:
|
||||
wallet_ids = (await get_user(wallet.wallet.user)).wallet_ids
|
||||
user = await get_user(wallet.wallet.user)
|
||||
wallet_ids = user.wallet_ids if user else []
|
||||
|
||||
return [bleskomat.dict() for bleskomat in await get_bleskomats(wallet_ids)]
|
||||
|
||||
|
|
@ -54,9 +55,9 @@ async def api_bleskomat_create_or_update(
|
|||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||
bleskomat_id=None,
|
||||
):
|
||||
fiat_currency = data.fiat_currency
|
||||
exchange_rate_provider = data.exchange_rate_provider
|
||||
try:
|
||||
fiat_currency = data.fiat_currency
|
||||
exchange_rate_provider = data.exchange_rate_provider
|
||||
await fetch_fiat_exchange_rate(
|
||||
currency=fiat_currency, provider=exchange_rate_provider
|
||||
)
|
||||
|
|
@ -79,6 +80,7 @@ async def api_bleskomat_create_or_update(
|
|||
else:
|
||||
bleskomat = await create_bleskomat(wallet_id=wallet.wallet.id, data=data)
|
||||
|
||||
assert bleskomat
|
||||
return bleskomat.dict()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@
|
|||
<a
|
||||
class="text-secondary"
|
||||
target="_blank"
|
||||
href="https://github.com/lnbits/lnbits-legend/tree/main/lnbits/extensions/boltz"
|
||||
href="https://github.com/lnbits/lnbits/tree/main/lnbits/extensions/boltz"
|
||||
>More details</a
|
||||
>
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -4,18 +4,19 @@
|
|||
<q-card class="q-pa-lg q-mb-xl">
|
||||
<q-card-section class="q-pa-none">
|
||||
<center>
|
||||
<q-icon
|
||||
name="account_balance"
|
||||
class="text-grey"
|
||||
style="font-size: 10rem"
|
||||
></q-icon>
|
||||
<h4 class="q-mt-none q-mb-md">{{ mint_name }}</h4>
|
||||
<q-img
|
||||
src="/cashu/static/image/cashu.png"
|
||||
spinner-color="white"
|
||||
style="max-width: 20%"
|
||||
></q-img>
|
||||
<h4 class="q-mt-sm q-mb-md">{{ mint_name }}</h4>
|
||||
<!-- <a class="text-secondary">Mint URL: {{testfield}} </a> <br /> -->
|
||||
<a
|
||||
class="text-secondary"
|
||||
class="q-my-xl text-white"
|
||||
style="font-size: 1.5rem"
|
||||
href="../wallet?mint_id={{ mint_id }}"
|
||||
>Open wallet</a
|
||||
>click to open wallet</a
|
||||
>
|
||||
</center>
|
||||
</q-card-section>
|
||||
|
|
@ -58,24 +59,34 @@
|
|||
</p>
|
||||
<p>
|
||||
<strong>This service is in BETA</strong> <br />
|
||||
We hold no responsibility for people losing access to funds. Use at
|
||||
your own risk!
|
||||
Cashu is still experimental and in active development. There are
|
||||
likely bugs in this implementation so please use this with caution. We
|
||||
hold no responsibility for people losing access to funds. Use at your
|
||||
own risk!
|
||||
</p>
|
||||
</q-card-section>
|
||||
</q-card>
|
||||
</div>
|
||||
|
||||
{% endblock %} {% block scripts %}
|
||||
|
||||
<script>
|
||||
new Vue({
|
||||
el: '#vue',
|
||||
mixins: [windowMixin],
|
||||
data: function () {
|
||||
return {}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% endblock %} {% block scripts %}
|
||||
|
||||
<script>
|
||||
Vue.component(VueQrcode.name, VueQrcode)
|
||||
|
||||
new Vue({
|
||||
el: '#vue',
|
||||
mixins: [windowMixin],
|
||||
data: function () {
|
||||
return {
|
||||
testfield: 'asd',
|
||||
mintURL: {
|
||||
location: window.location,
|
||||
base_url: location.protocol + '//' + location.host + location.pathname
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1479,15 +1479,15 @@ page_container %}
|
|||
},
|
||||
|
||||
constructOutputs: async function (amounts, secrets) {
|
||||
const blindedMessages = []
|
||||
const outputs = []
|
||||
const rs = []
|
||||
for (let i = 0; i < amounts.length; i++) {
|
||||
const {B_, r} = await step1Alice(secrets[i])
|
||||
blindedMessages.push({amount: amounts[i], B_: B_})
|
||||
outputs.push({amount: amounts[i], B_: B_})
|
||||
rs.push(r)
|
||||
}
|
||||
return {
|
||||
blindedMessages,
|
||||
outputs,
|
||||
rs
|
||||
}
|
||||
},
|
||||
|
|
@ -1581,25 +1581,26 @@ page_container %}
|
|||
mintApi: async function (amounts, payment_hash, verbose = true) {
|
||||
/*
|
||||
asks the mint to check whether the invoice with payment_hash has been paid
|
||||
and requests signing of the attached outputs (blindedMessages)
|
||||
and requests signing of the attached outputs.
|
||||
*/
|
||||
console.log('### promises', payment_hash)
|
||||
try {
|
||||
let secrets = await this.generateSecrets(amounts)
|
||||
let {blindedMessages, rs} = await this.constructOutputs(
|
||||
amounts,
|
||||
secrets
|
||||
)
|
||||
let {outputs, rs} = await this.constructOutputs(amounts, secrets)
|
||||
const promises = await LNbits.api.request(
|
||||
'POST',
|
||||
`/cashu/api/v1/${this.mintId}/mint?payment_hash=${payment_hash}`,
|
||||
'',
|
||||
{
|
||||
blinded_messages: blindedMessages
|
||||
outputs
|
||||
}
|
||||
)
|
||||
console.log('### promises data', promises.data)
|
||||
let proofs = await this.constructProofs(promises.data, secrets, rs)
|
||||
console.log('### promises data', promises.data.promises)
|
||||
let proofs = await this.constructProofs(
|
||||
promises.data.promises,
|
||||
secrets,
|
||||
rs
|
||||
)
|
||||
return proofs
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
|
|
@ -1682,16 +1683,11 @@ page_container %}
|
|||
'number of secrets does not match number of outputs.'
|
||||
)
|
||||
}
|
||||
let {blindedMessages, rs} = await this.constructOutputs(
|
||||
amounts,
|
||||
secrets
|
||||
)
|
||||
let {outputs, rs} = await this.constructOutputs(amounts, secrets)
|
||||
const payload = {
|
||||
amount,
|
||||
proofs,
|
||||
outputs: {
|
||||
blinded_messages: blindedMessages
|
||||
}
|
||||
outputs
|
||||
}
|
||||
|
||||
console.log('payload', JSON.stringify(payload))
|
||||
|
|
@ -1881,10 +1877,7 @@ page_container %}
|
|||
'amount with fees',
|
||||
amount
|
||||
)
|
||||
// if (amount > balance()) {
|
||||
// LNbits.utils.notifyApiError('Balance too low')
|
||||
// return
|
||||
// }
|
||||
|
||||
let {fristProofs, scndProofs} = await this.splitToSend(
|
||||
this.proofs,
|
||||
amount
|
||||
|
|
@ -2132,6 +2125,19 @@ page_container %}
|
|||
return paid
|
||||
},
|
||||
|
||||
findTokenForAmount: function (amount) {
|
||||
for (const token of this.proofs) {
|
||||
const index = token.promises?.findIndex(p => p.amount === amount)
|
||||
if (index >= 0) {
|
||||
return {
|
||||
promise: token.promises[index],
|
||||
secret: token.secrets[index],
|
||||
r: token.rs[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
////////////// WORKERS //////////////
|
||||
|
||||
clearAllWorkers: function () {
|
||||
|
|
@ -2220,76 +2226,6 @@ page_container %}
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
findTokenForAmount: function (amount) {
|
||||
for (const token of this.proofs) {
|
||||
const index = token.promises?.findIndex(p => p.amount === amount)
|
||||
if (index >= 0) {
|
||||
return {
|
||||
promise: token.promises[index],
|
||||
secret: token.secrets[index],
|
||||
r: token.rs[index]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// checkInvoice: function () {
|
||||
// console.log('#### checkInvoice')
|
||||
// try {
|
||||
// const invoice = decode(this.payInvoiceData.data.request)
|
||||
|
||||
// const cleanInvoice = {
|
||||
// msat: invoice.human_readable_part.amount,
|
||||
// sat: invoice.human_readable_part.amount / 1000,
|
||||
// fsat: LNbits.utils.formatSat(
|
||||
// invoice.human_readable_part.amount / 1000
|
||||
// )
|
||||
// }
|
||||
|
||||
// _.each(invoice.data.tags, tag => {
|
||||
// if (_.isObject(tag) && _.has(tag, 'description')) {
|
||||
// if (tag.description === 'payment_hash') {
|
||||
// cleanInvoice.hash = tag.value
|
||||
// } else if (tag.description === 'description') {
|
||||
// cleanInvoice.description = tag.value
|
||||
// } else if (tag.description === 'expiry') {
|
||||
// var expireDate = new Date(
|
||||
// (invoice.data.time_stamp + tag.value) * 1000
|
||||
// )
|
||||
// cleanInvoice.expireDate = Quasar.utils.date.formatDate(
|
||||
// expireDate,
|
||||
// 'YYYY-MM-DDTHH:mm:ss.SSSZ'
|
||||
// )
|
||||
// cleanInvoice.expired = false // TODO
|
||||
// }
|
||||
// }
|
||||
|
||||
// this.payInvoiceData.invoice = cleanInvoice
|
||||
// })
|
||||
|
||||
// console.log(
|
||||
// '#### this.payInvoiceData.invoice',
|
||||
// this.payInvoiceData.invoice
|
||||
// )
|
||||
// } catch (error) {
|
||||
// this.$q.notify({
|
||||
// timeout: 5000,
|
||||
// type: 'warning',
|
||||
// message: 'Could not decode invoice',
|
||||
// caption: error + '',
|
||||
// position: 'top',
|
||||
// actions: [
|
||||
// {
|
||||
// icon: 'close',
|
||||
// color: 'white',
|
||||
// handler: () => {}
|
||||
// }
|
||||
// ]
|
||||
// })
|
||||
// throw error
|
||||
// }
|
||||
// },
|
||||
|
||||
////////////// STORAGE /////////////
|
||||
|
||||
getLocalstorageToFile: async function () {
|
||||
|
|
|
|||
|
|
@ -12,7 +12,8 @@ from cashu.core.base import (
|
|||
GetMintResponse,
|
||||
Invoice,
|
||||
MeltRequest,
|
||||
MintRequest,
|
||||
PostMintRequest,
|
||||
PostMintResponse,
|
||||
PostSplitResponse,
|
||||
SplitRequest,
|
||||
)
|
||||
|
|
@ -204,10 +205,10 @@ async def request_mint(cashu_id: str = Query(None), amount: int = 0) -> GetMintR
|
|||
|
||||
@cashu_ext.post("/api/v1/{cashu_id}/mint")
|
||||
async def mint(
|
||||
data: MintRequest,
|
||||
data: PostMintRequest,
|
||||
cashu_id: str = Query(None),
|
||||
payment_hash: str = Query(None),
|
||||
) -> List[BlindedSignature]:
|
||||
) -> PostMintResponse:
|
||||
"""
|
||||
Requests the minting of tokens belonging to a paid payment request.
|
||||
Call this endpoint after `GET /mint`.
|
||||
|
|
@ -245,7 +246,7 @@ async def mint(
|
|||
)
|
||||
|
||||
try:
|
||||
total_requested = sum([bm.amount for bm in data.blinded_messages])
|
||||
total_requested = sum([bm.amount for bm in data.outputs])
|
||||
if total_requested > invoice.amount:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.PAYMENT_REQUIRED,
|
||||
|
|
@ -257,10 +258,8 @@ async def mint(
|
|||
status_code=HTTPStatus.PAYMENT_REQUIRED, detail="Invoice not paid."
|
||||
)
|
||||
|
||||
promises = await ledger._generate_promises(
|
||||
B_s=data.blinded_messages, keyset=keyset
|
||||
)
|
||||
return promises
|
||||
promises = await ledger._generate_promises(B_s=data.outputs, keyset=keyset)
|
||||
return PostMintResponse(promises=promises)
|
||||
except (Exception, HTTPException) as e:
|
||||
logger.debug(f"Cashu: /melt {str(e) or getattr(e, 'detail')}")
|
||||
# unset issued flag because something went wrong
|
||||
|
|
@ -274,10 +273,8 @@ async def mint(
|
|||
)
|
||||
else:
|
||||
# only used for testing when LIGHTNING=false
|
||||
promises = await ledger._generate_promises(
|
||||
B_s=data.blinded_messages, keyset=keyset
|
||||
)
|
||||
return promises
|
||||
promises = await ledger._generate_promises(B_s=data.outputs, keyset=keyset)
|
||||
return PostMintResponse(promises=promises)
|
||||
|
||||
|
||||
@cashu_ext.post("/api/v1/{cashu_id}/melt")
|
||||
|
|
@ -421,7 +418,7 @@ async def split(
|
|||
)
|
||||
|
||||
amount = payload.amount
|
||||
outputs = payload.outputs.blinded_messages
|
||||
outputs = payload.outputs
|
||||
assert outputs, Exception("no outputs provided.")
|
||||
split_return = None
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<a
|
||||
class="text-secondary"
|
||||
href="https://github.com/lnbits/lnbits-legend/tree/main/lnbits/extensions/lnaddress"
|
||||
href="https://github.com/lnbits/lnbits/tree/main/lnbits/extensions/lnaddress"
|
||||
>More details</a
|
||||
>
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@
|
|||
Check extension
|
||||
<a
|
||||
class="text-secondary"
|
||||
href="https://github.com/lnbits/lnbits-legend/blob/main/lnbits/extensions/lnaddress/README.md"
|
||||
href="https://github.com/lnbits/lnbits/blob/main/lnbits/extensions/lnaddress/README.md"
|
||||
>documentation!</a
|
||||
>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from typing import List, Optional, Union
|
|||
from lnbits.helpers import urlsafe_short_hash
|
||||
|
||||
from . import db
|
||||
from .models import Address, CreateAddressData, CreateDomainData, Domain
|
||||
from .models import Address, CreateAddressData, CreateDomainData, Domain, EditDomainData
|
||||
|
||||
|
||||
async def get_domain(domain_id: str) -> Optional[Domain]:
|
||||
|
|
@ -170,6 +170,26 @@ async def create_address_internal(domain_id: str, data: CreateAddressData) -> Ad
|
|||
return address
|
||||
|
||||
|
||||
async def update_domain_internal(wallet_id: str, data: EditDomainData) -> Domain:
|
||||
if data.currency != "Satoshis":
|
||||
amount = data.amount * 100
|
||||
else:
|
||||
amount = data.amount
|
||||
print(data)
|
||||
await db.execute(
|
||||
"""
|
||||
UPDATE nostrnip5.domains
|
||||
SET amount = ?, currency = ?
|
||||
WHERE id = ?
|
||||
""",
|
||||
(int(amount), data.currency, data.id),
|
||||
)
|
||||
|
||||
domain = await get_domain(data.id)
|
||||
assert domain, "Domain couldn't be updated"
|
||||
return domain
|
||||
|
||||
|
||||
async def create_domain_internal(wallet_id: str, data: CreateDomainData) -> Domain:
|
||||
domain_id = urlsafe_short_hash()
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,16 @@ class CreateDomainData(BaseModel):
|
|||
domain: str
|
||||
|
||||
|
||||
class EditDomainData(BaseModel):
|
||||
id: str
|
||||
currency: str
|
||||
amount: float = Query(..., ge=0.01)
|
||||
|
||||
@classmethod
|
||||
def from_row(cls, row: Row) -> "EditDomainData":
|
||||
return cls(**dict(row))
|
||||
|
||||
|
||||
class Domain(BaseModel):
|
||||
id: str
|
||||
wallet: str
|
||||
|
|
|
|||
|
|
@ -73,6 +73,14 @@
|
|||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||
@click="deleteDomain(props.row.id)"
|
||||
></q-btn>
|
||||
<q-btn
|
||||
unelevated
|
||||
dense
|
||||
size="xs"
|
||||
icon="edit"
|
||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||
@click="editDomain(props.row.id)"
|
||||
></q-btn>
|
||||
</q-td>
|
||||
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||
{{ col.value }}
|
||||
|
|
@ -226,6 +234,39 @@
|
|||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog
|
||||
v-model="editFormDialog.show"
|
||||
position="top"
|
||||
@hide="closeFormDialog"
|
||||
>
|
||||
<q-card class="q-pa-lg q-pt-xl" style="width: 500px">
|
||||
<q-form @submit="saveEditedDomain" class="q-gutter-md">
|
||||
<q-select
|
||||
filled
|
||||
dense
|
||||
emit-value
|
||||
v-model="editFormDialog.data.currency"
|
||||
:options="currencyOptions"
|
||||
label="Currency *"
|
||||
></q-select>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="editFormDialog.data.amount"
|
||||
label="Amount"
|
||||
placeholder="How much do you want to charge?"
|
||||
></q-input>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn unelevated color="primary" type="submit">Update Amount</q-btn>
|
||||
<q-btn v-close-popup flat color="grey" class="q-ml-auto"
|
||||
>Cancel</q-btn
|
||||
>
|
||||
</div>
|
||||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
|
||||
<q-dialog
|
||||
v-model="addressFormDialog.show"
|
||||
position="top"
|
||||
|
|
@ -513,6 +554,10 @@
|
|||
show: false,
|
||||
data: {}
|
||||
},
|
||||
editFormDialog: {
|
||||
show: false,
|
||||
data: {}
|
||||
},
|
||||
addressFormDialog: {
|
||||
show: false,
|
||||
data: {}
|
||||
|
|
@ -578,6 +623,34 @@
|
|||
LNbits.utils.notifyApiError(error)
|
||||
})
|
||||
},
|
||||
saveEditedDomain: function () {
|
||||
var data = this.editFormDialog.data
|
||||
var self = this
|
||||
|
||||
LNbits.api
|
||||
.request(
|
||||
'PUT',
|
||||
'/nostrnip5/api/v1/domain',
|
||||
_.findWhere(this.g.user.wallets, {
|
||||
id: this.editFormDialog.data.wallet
|
||||
}).inkey,
|
||||
data
|
||||
)
|
||||
.then(function (response) {
|
||||
self.editFormDialog.show = false
|
||||
self.editFormDialog.data = {}
|
||||
})
|
||||
.catch(function (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
})
|
||||
},
|
||||
editDomain: function (domain_id) {
|
||||
var self = this
|
||||
var data = _.findWhere(this.domains, {id: domain_id})
|
||||
|
||||
self.editFormDialog.show = true
|
||||
self.editFormDialog.data = data
|
||||
},
|
||||
deleteDomain: function (domain_id) {
|
||||
var self = this
|
||||
var domain = _.findWhere(this.domains, {id: domain_id})
|
||||
|
|
|
|||
|
|
@ -26,8 +26,14 @@ from .crud import (
|
|||
get_domain_by_name,
|
||||
get_domains,
|
||||
rotate_address,
|
||||
update_domain_internal,
|
||||
)
|
||||
from .models import (
|
||||
CreateAddressData,
|
||||
CreateDomainData,
|
||||
EditDomainData,
|
||||
RotateAddressData,
|
||||
)
|
||||
from .models import CreateAddressData, CreateDomainData, RotateAddressData
|
||||
|
||||
|
||||
@nostrnip5_ext.get("/api/v1/domains", status_code=HTTPStatus.OK)
|
||||
|
|
@ -89,6 +95,16 @@ async def api_domain_create(
|
|||
return domain
|
||||
|
||||
|
||||
@nostrnip5_ext.put("/api/v1/domain", status_code=HTTPStatus.OK)
|
||||
async def api_domain_update(
|
||||
data: EditDomainData, wallet: WalletTypeInfo = Depends(get_key_type)
|
||||
):
|
||||
|
||||
domain = await update_domain_internal(wallet_id=wallet.wallet.id, data=data)
|
||||
|
||||
return domain
|
||||
|
||||
|
||||
@nostrnip5_ext.delete("/api/v1/domain/{domain_id}", status_code=HTTPStatus.CREATED)
|
||||
async def api_domain_delete(
|
||||
domain_id: str,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,15 @@ Vue.component(VueQrcode.name, VueQrcode)
|
|||
|
||||
const pica = window.pica()
|
||||
|
||||
function imgSizeFit(img, maxWidth = 1024, maxHeight = 768) {
|
||||
let ratio = Math.min(
|
||||
1,
|
||||
maxWidth / img.naturalWidth,
|
||||
maxHeight / img.naturalHeight
|
||||
)
|
||||
return {width: img.naturalWidth * ratio, height: img.naturalHeight * ratio}
|
||||
}
|
||||
|
||||
const defaultItemData = {
|
||||
unit: 'sat'
|
||||
}
|
||||
|
|
@ -23,6 +32,7 @@ new Vue({
|
|||
},
|
||||
itemDialog: {
|
||||
show: false,
|
||||
urlImg: true,
|
||||
data: {...defaultItemData},
|
||||
units: ['sat']
|
||||
}
|
||||
|
|
@ -41,6 +51,9 @@ new Vue({
|
|||
openUpdateDialog(itemId) {
|
||||
this.itemDialog.show = true
|
||||
let item = this.offlineshop.items.find(item => item.id === itemId)
|
||||
if (item.image.startsWith('data:')) {
|
||||
this.itemDialog.urlImg = false
|
||||
}
|
||||
this.itemDialog.data = item
|
||||
},
|
||||
imageAdded(file) {
|
||||
|
|
@ -48,17 +61,12 @@ new Vue({
|
|||
let image = new Image()
|
||||
image.src = blobURL
|
||||
image.onload = async () => {
|
||||
let fit = imgSizeFit(image, 100, 100)
|
||||
let canvas = document.createElement('canvas')
|
||||
canvas.setAttribute('width', 100)
|
||||
canvas.setAttribute('height', 100)
|
||||
await pica.resize(image, canvas, {
|
||||
quality: 0,
|
||||
alpha: true,
|
||||
unsharpAmount: 95,
|
||||
unsharpRadius: 0.9,
|
||||
unsharpThreshold: 70
|
||||
})
|
||||
this.itemDialog.data.image = canvas.toDataURL()
|
||||
canvas.setAttribute('width', fit.width)
|
||||
canvas.setAttribute('height', fit.height)
|
||||
output = await pica.resize(image, canvas)
|
||||
this.itemDialog.data.image = output.toDataURL('image/jpeg', 0.4)
|
||||
this.itemDialog = {...this.itemDialog}
|
||||
}
|
||||
},
|
||||
|
|
@ -155,6 +163,7 @@ new Vue({
|
|||
|
||||
this.loadShop()
|
||||
this.itemDialog.show = false
|
||||
this.itemDialog.urlImg = true
|
||||
this.itemDialog.data = {...defaultItemData}
|
||||
},
|
||||
toggleItem(itemId) {
|
||||
|
|
|
|||
|
|
@ -237,7 +237,7 @@
|
|||
<q-responsive v-if="itemDialog.data.id" :ratio="1">
|
||||
<qrcode
|
||||
:value="'lightning:' + itemDialog.data.lnurl"
|
||||
:options="{width: 800}"
|
||||
:options="{width: 300}"
|
||||
class="rounded-borders"
|
||||
></qrcode>
|
||||
</q-responsive>
|
||||
|
|
@ -266,7 +266,16 @@
|
|||
type="text"
|
||||
label="Brief description"
|
||||
></q-input>
|
||||
<q-input
|
||||
v-if="itemDialog.urlImg"
|
||||
filled
|
||||
dense
|
||||
v-model.trim="itemDialog.data.image"
|
||||
type="url"
|
||||
label="Image URL"
|
||||
></q-input>
|
||||
<q-file
|
||||
v-else
|
||||
filled
|
||||
dense
|
||||
capture="environment"
|
||||
|
|
@ -288,6 +297,10 @@
|
|||
/>
|
||||
</template>
|
||||
</q-file>
|
||||
<q-toggle
|
||||
:label="`${itemDialog.urlImg ? 'Insert image URL' : 'Upload image file'}`"
|
||||
v-model="itemDialog.urlImg"
|
||||
></q-toggle>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
|
|
|
|||
|
|
@ -60,6 +60,22 @@ async def api_add_or_update_item(
|
|||
):
|
||||
shop = await get_or_create_shop_by_wallet(wallet.wallet.id)
|
||||
assert shop
|
||||
if data.image:
|
||||
image_is_url = data.image.startswith("https://") or data.image.startswith(
|
||||
"http://"
|
||||
)
|
||||
|
||||
if not image_is_url:
|
||||
|
||||
def size(b64string):
|
||||
return int((len(b64string) * 3) / 4 - b64string.count("=", -2))
|
||||
|
||||
image_size = size(data.image) / 1024
|
||||
if image_size > 100:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail=f"Image size is too big, {int(image_size)}Kb. Max: 100kb, Compress the image at https://tinypng.com, or use an URL.",
|
||||
)
|
||||
if data.unit != "sat":
|
||||
data.price = data.price * 100
|
||||
if item_id == None:
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
from http import HTTPStatus
|
||||
from typing import List, Optional, Union
|
||||
|
||||
from lnbits.helpers import urlsafe_short_hash
|
||||
|
||||
from . import db
|
||||
from .models import CreateEmail, CreateEmailaddress, Emailaddresses, Emails
|
||||
from .models import CreateEmail, CreateEmailaddress, Email, Emailaddress
|
||||
from .smtp import send_mail
|
||||
|
||||
|
||||
|
|
@ -17,7 +16,7 @@ def get_test_mail(email, testemail):
|
|||
)
|
||||
|
||||
|
||||
async def create_emailaddress(data: CreateEmailaddress) -> Emailaddresses:
|
||||
async def create_emailaddress(data: CreateEmailaddress) -> Emailaddress:
|
||||
|
||||
emailaddress_id = urlsafe_short_hash()
|
||||
|
||||
|
|
@ -50,7 +49,7 @@ async def create_emailaddress(data: CreateEmailaddress) -> Emailaddresses:
|
|||
return new_emailaddress
|
||||
|
||||
|
||||
async def update_emailaddress(emailaddress_id: str, **kwargs) -> Emailaddresses:
|
||||
async def update_emailaddress(emailaddress_id: str, **kwargs) -> Emailaddress:
|
||||
q = ", ".join([f"{field[0]} = ?" for field in kwargs.items()])
|
||||
await db.execute(
|
||||
f"UPDATE smtp.emailaddress SET {q} WHERE id = ?",
|
||||
|
|
@ -65,30 +64,22 @@ async def update_emailaddress(emailaddress_id: str, **kwargs) -> Emailaddresses:
|
|||
await send_mail(row, email)
|
||||
|
||||
assert row, "Newly updated emailaddress couldn't be retrieved"
|
||||
return Emailaddresses(**row)
|
||||
return Emailaddress(**row)
|
||||
|
||||
|
||||
async def get_emailaddress(emailaddress_id: str) -> Optional[Emailaddresses]:
|
||||
async def get_emailaddress(emailaddress_id: str) -> Optional[Emailaddress]:
|
||||
row = await db.fetchone(
|
||||
"SELECT * FROM smtp.emailaddress WHERE id = ?", (emailaddress_id,)
|
||||
)
|
||||
return Emailaddresses(**row) if row else None
|
||||
return Emailaddress(**row) if row else None
|
||||
|
||||
|
||||
async def get_emailaddress_by_email(email: str) -> Optional[Emailaddresses]:
|
||||
async def get_emailaddress_by_email(email: str) -> Optional[Emailaddress]:
|
||||
row = await db.fetchone("SELECT * FROM smtp.emailaddress WHERE email = ?", (email,))
|
||||
return Emailaddresses(**row) if row else None
|
||||
return Emailaddress(**row) if row else None
|
||||
|
||||
|
||||
# async def get_emailAddressByEmail(email: str) -> Optional[Emails]:
|
||||
# row = await db.fetchone(
|
||||
# "SELECT s.*, d.emailaddress as emailaddress FROM smtp.email s INNER JOIN smtp.emailaddress d ON (s.emailaddress_id = d.id) WHERE s.emailaddress = ?",
|
||||
# (email,),
|
||||
# )
|
||||
# return Subdomains(**row) if row else None
|
||||
|
||||
|
||||
async def get_emailaddresses(wallet_ids: Union[str, List[str]]) -> List[Emailaddresses]:
|
||||
async def get_emailaddresses(wallet_ids: Union[str, List[str]]) -> List[Emailaddress]:
|
||||
if isinstance(wallet_ids, str):
|
||||
wallet_ids = [wallet_ids]
|
||||
|
||||
|
|
@ -97,21 +88,22 @@ async def get_emailaddresses(wallet_ids: Union[str, List[str]]) -> List[Emailadd
|
|||
f"SELECT * FROM smtp.emailaddress WHERE wallet IN ({q})", (*wallet_ids,)
|
||||
)
|
||||
|
||||
return [Emailaddresses(**row) for row in rows]
|
||||
return [Emailaddress(**row) for row in rows]
|
||||
|
||||
|
||||
async def delete_emailaddress(emailaddress_id: str) -> None:
|
||||
await db.execute("DELETE FROM smtp.emailaddress WHERE id = ?", (emailaddress_id,))
|
||||
|
||||
|
||||
## create emails
|
||||
async def create_email(payment_hash, wallet, data: CreateEmail) -> Emails:
|
||||
async def create_email(wallet: str, data: CreateEmail, payment_hash: str = "") -> Email:
|
||||
id = urlsafe_short_hash()
|
||||
await db.execute(
|
||||
"""
|
||||
INSERT INTO smtp.email (id, wallet, emailaddress_id, subject, receiver, message, paid)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
INSERT INTO smtp.email (id, payment_hash, wallet, emailaddress_id, subject, receiver, message, paid)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
""",
|
||||
(
|
||||
id,
|
||||
payment_hash,
|
||||
wallet,
|
||||
data.emailaddress_id,
|
||||
|
|
@ -122,36 +114,34 @@ async def create_email(payment_hash, wallet, data: CreateEmail) -> Emails:
|
|||
),
|
||||
)
|
||||
|
||||
new_email = await get_email(payment_hash)
|
||||
new_email = await get_email(id)
|
||||
assert new_email, "Newly created email couldn't be retrieved"
|
||||
return new_email
|
||||
|
||||
|
||||
async def set_email_paid(payment_hash: str) -> Emails:
|
||||
email = await get_email(payment_hash)
|
||||
async def set_email_paid(payment_hash: str) -> bool:
|
||||
email = await get_email_by_payment_hash(payment_hash)
|
||||
if email and email.paid == False:
|
||||
await db.execute(
|
||||
"""
|
||||
UPDATE smtp.email
|
||||
SET paid = true
|
||||
WHERE id = ?
|
||||
""",
|
||||
(payment_hash,),
|
||||
f"UPDATE smtp.email SET paid = true WHERE payment_hash = ?", (payment_hash,)
|
||||
)
|
||||
new_email = await get_email(payment_hash)
|
||||
assert new_email, "Newly paid email couldn't be retrieved"
|
||||
return new_email
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
async def get_email(email_id: str) -> Optional[Emails]:
|
||||
async def get_email_by_payment_hash(payment_hash: str) -> Optional[Email]:
|
||||
row = await db.fetchone(
|
||||
"SELECT s.*, d.email as emailaddress FROM smtp.email s INNER JOIN smtp.emailaddress d ON (s.emailaddress_id = d.id) WHERE s.id = ?",
|
||||
(email_id,),
|
||||
f"SELECT * FROM smtp.email WHERE payment_hash = ?", (payment_hash,)
|
||||
)
|
||||
return Emails(**row) if row else None
|
||||
return Email(**row) if row else None
|
||||
|
||||
|
||||
async def get_emails(wallet_ids: Union[str, List[str]]) -> List[Emails]:
|
||||
async def get_email(id: str) -> Optional[Email]:
|
||||
row = await db.fetchone(f"SELECT * FROM smtp.email WHERE id = ?", (id,))
|
||||
return Email(**row) if row else None
|
||||
|
||||
|
||||
async def get_emails(wallet_ids: Union[str, List[str]]) -> List[Email]:
|
||||
if isinstance(wallet_ids, str):
|
||||
wallet_ids = [wallet_ids]
|
||||
|
||||
|
|
@ -161,7 +151,7 @@ async def get_emails(wallet_ids: Union[str, List[str]]) -> List[Emails]:
|
|||
(*wallet_ids,),
|
||||
)
|
||||
|
||||
return [Emails(**row) for row in rows]
|
||||
return [Email(**row) for row in rows]
|
||||
|
||||
|
||||
async def delete_email(email_id: str) -> None:
|
||||
|
|
|
|||
|
|
@ -33,3 +33,7 @@ async def m001_initial(db):
|
|||
);
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
async def m002_add_payment_hash(db):
|
||||
await db.execute(f"ALTER TABLE smtp.email ADD COLUMN payment_hash TEXT;")
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class CreateEmailaddress(BaseModel):
|
|||
cost: int = Query(..., ge=0)
|
||||
|
||||
|
||||
class Emailaddresses(BaseModel):
|
||||
class Emailaddress(BaseModel):
|
||||
id: str
|
||||
wallet: str
|
||||
email: str
|
||||
|
|
@ -36,7 +36,7 @@ class CreateEmail(BaseModel):
|
|||
message: str = Query(...)
|
||||
|
||||
|
||||
class Emails(BaseModel):
|
||||
class Email(BaseModel):
|
||||
id: str
|
||||
wallet: str
|
||||
emailaddress_id: str
|
||||
|
|
|
|||
|
|
@ -4,83 +4,107 @@ import time
|
|||
from email.mime.multipart import MIMEMultipart
|
||||
from email.mime.text import MIMEText
|
||||
from email.utils import formatdate
|
||||
from http import HTTPStatus
|
||||
from smtplib import SMTP_SSL as SMTP
|
||||
from typing import Union
|
||||
|
||||
from loguru import logger
|
||||
from starlette.exceptions import HTTPException
|
||||
|
||||
from .models import CreateEmail, CreateEmailaddress, Email, Emailaddress
|
||||
|
||||
|
||||
async def send_mail(
|
||||
emailaddress: Union[Emailaddress, CreateEmailaddress],
|
||||
email: Union[Email, CreateEmail],
|
||||
):
|
||||
smtp_client = SmtpService(emailaddress)
|
||||
message = smtp_client.create_message(email)
|
||||
await smtp_client.send_mail(email.receiver, message)
|
||||
|
||||
|
||||
def valid_email(s):
|
||||
# https://regexr.com/2rhq7
|
||||
pat = "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
|
||||
pat = r"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
|
||||
if re.match(pat, s):
|
||||
return True
|
||||
msg = f"SMTP - invalid email: {s}."
|
||||
logger.error(msg)
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=msg)
|
||||
log = f"SMTP - invalid email: {s}."
|
||||
logger.error(log)
|
||||
raise Exception(log)
|
||||
|
||||
|
||||
async def send_mail(emailaddress, email):
|
||||
valid_email(emailaddress.email)
|
||||
valid_email(email.receiver)
|
||||
class SmtpService:
|
||||
def __init__(self, emailaddress: Union[Emailaddress, CreateEmailaddress]) -> None:
|
||||
self.sender = emailaddress.email
|
||||
self.smtp_server = emailaddress.smtp_server
|
||||
self.smtp_port = emailaddress.smtp_port
|
||||
self.smtp_user = emailaddress.smtp_user
|
||||
self.smtp_password = emailaddress.smtp_password
|
||||
|
||||
ts = time.time()
|
||||
date = formatdate(ts, True)
|
||||
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg["Date"] = date
|
||||
msg["Subject"] = email.subject
|
||||
msg["From"] = emailaddress.email
|
||||
msg["To"] = email.receiver
|
||||
|
||||
signature = "Email sent anonymiously by LNbits Sendmail extension."
|
||||
text = f"""
|
||||
{email.message}
|
||||
|
||||
{signature}
|
||||
"""
|
||||
|
||||
html = f"""
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<p>{email.message}<p>
|
||||
<br>
|
||||
<p>{signature}</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
part1 = MIMEText(text, "plain")
|
||||
part2 = MIMEText(html, "html")
|
||||
msg.attach(part1)
|
||||
msg.attach(part2)
|
||||
|
||||
try:
|
||||
conn = SMTP(
|
||||
host=emailaddress.smtp_server, port=emailaddress.smtp_port, timeout=10
|
||||
def render_email(self, email: Union[Email, CreateEmail]):
|
||||
signature: str = "Email sent by LNbits SMTP extension."
|
||||
text = f"{email.message}\n\n{signature}"
|
||||
html = (
|
||||
"""
|
||||
<html>
|
||||
<head></head>
|
||||
<body>
|
||||
<p>"""
|
||||
+ email.message
|
||||
+ """</p>
|
||||
<p>"""
|
||||
+ signature
|
||||
+ """</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
)
|
||||
logger.debug("SMTP - connected to smtp server.")
|
||||
# conn.set_debuglevel(True)
|
||||
except:
|
||||
msg = f"SMTP - error connecting to smtp server: {emailaddress.smtp_server}:{emailaddress.smtp_port}."
|
||||
logger.error(msg)
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=msg)
|
||||
try:
|
||||
conn.login(emailaddress.smtp_user, emailaddress.smtp_password)
|
||||
logger.debug("SMTP - successful login to smtp server.")
|
||||
except:
|
||||
msg = f"SMTP - error login into smtp {emailaddress.smtp_user}."
|
||||
logger.error(msg)
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=msg)
|
||||
try:
|
||||
conn.sendmail(emailaddress.email, email.receiver, msg.as_string())
|
||||
logger.debug("SMTP - successfully send email.")
|
||||
except socket.error as e:
|
||||
msg = f"SMTP - error sending email: {str(e)}."
|
||||
logger.error(msg)
|
||||
raise HTTPException(status_code=HTTPStatus.BAD_REQUEST, detail=msg)
|
||||
finally:
|
||||
conn.quit()
|
||||
return text, html
|
||||
|
||||
def create_message(self, email: Union[Email, CreateEmail]):
|
||||
ts = time.time()
|
||||
date = formatdate(ts, True)
|
||||
|
||||
msg = MIMEMultipart("alternative")
|
||||
msg["Date"] = date
|
||||
msg["Subject"] = email.subject
|
||||
msg["From"] = self.sender
|
||||
msg["To"] = email.receiver
|
||||
|
||||
text, html = self.render_email(email)
|
||||
|
||||
part1 = MIMEText(text, "plain")
|
||||
part2 = MIMEText(html, "html")
|
||||
msg.attach(part1)
|
||||
msg.attach(part2)
|
||||
return msg
|
||||
|
||||
async def send_mail(self, receiver, msg: MIMEMultipart):
|
||||
|
||||
valid_email(self.sender)
|
||||
valid_email(receiver)
|
||||
|
||||
try:
|
||||
conn = SMTP(host=self.smtp_server, port=int(self.smtp_port), timeout=10)
|
||||
logger.debug("SMTP - connected to smtp server.")
|
||||
# conn.set_debuglevel(True)
|
||||
except:
|
||||
log = f"SMTP - error connecting to smtp server: {self.smtp_server}:{self.smtp_port}."
|
||||
logger.debug(log)
|
||||
raise Exception(log)
|
||||
|
||||
try:
|
||||
conn.login(self.smtp_user, self.smtp_password)
|
||||
logger.debug("SMTP - successful login to smtp server.")
|
||||
except:
|
||||
log = f"SMTP - error login into smtp {self.smtp_user}."
|
||||
logger.error(log)
|
||||
raise Exception(log)
|
||||
|
||||
try:
|
||||
conn.sendmail(self.sender, receiver, msg.as_string())
|
||||
logger.debug("SMTP - successfully send email.")
|
||||
except socket.error as e:
|
||||
log = f"SMTP - error sending email: {str(e)}."
|
||||
logger.error(log)
|
||||
raise Exception(log)
|
||||
finally:
|
||||
conn.quit()
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from loguru import logger
|
|||
from lnbits.core.models import Payment
|
||||
from lnbits.tasks import register_invoice_listener
|
||||
|
||||
from .crud import get_email, get_emailaddress, set_email_paid
|
||||
from .crud import get_email_by_payment_hash, get_emailaddress, set_email_paid
|
||||
from .smtp import send_mail
|
||||
|
||||
|
||||
|
|
@ -21,7 +21,7 @@ async def on_invoice_paid(payment: Payment) -> None:
|
|||
if payment.extra.get("tag") != "smtp":
|
||||
return
|
||||
|
||||
email = await get_email(payment.checking_id)
|
||||
email = await get_email_by_payment_hash(payment.checking_id)
|
||||
if not email:
|
||||
logger.error("SMTP: email can not by fetched")
|
||||
return
|
||||
|
|
|
|||
|
|
@ -57,6 +57,14 @@
|
|||
:href="props.row.displayUrl"
|
||||
target="_blank"
|
||||
></q-btn>
|
||||
<q-btn
|
||||
unelevated
|
||||
dense
|
||||
size="xs"
|
||||
icon="email"
|
||||
:color="($q.dark.isActive) ? 'grey-7' : 'grey-5'"
|
||||
@click="showEmailDialog(props.row.id)"
|
||||
></q-btn>
|
||||
</q-td>
|
||||
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
||||
{{ col.value }}
|
||||
|
|
@ -154,6 +162,42 @@
|
|||
</q-card>
|
||||
</div>
|
||||
|
||||
<q-dialog v-model="emailDialog.show" position="top">
|
||||
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
||||
<q-form @submit="sendEmail()" class="q-gutter-md">
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="emailDialog.data.receiver"
|
||||
type="text"
|
||||
label="Receiver"
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="emailDialog.data.subject"
|
||||
type="text"
|
||||
label="Subject"
|
||||
></q-input>
|
||||
<q-input
|
||||
filled
|
||||
dense
|
||||
v-model.trim="emailDialog.data.message"
|
||||
type="textarea"
|
||||
label="Message "
|
||||
></q-input>
|
||||
<div class="row q-mt-lg">
|
||||
<q-btn
|
||||
unelevated
|
||||
color="primary"
|
||||
:disable="emailDialog.data.receiver == '' || emailDialog.data.subject == '' || emailDialog.data.message == ''"
|
||||
type="submit"
|
||||
>Submit</q-btn
|
||||
>
|
||||
</div>
|
||||
</q-form>
|
||||
</q-card>
|
||||
</q-dialog>
|
||||
<q-dialog v-model="emailaddressDialog.show" position="top">
|
||||
<q-card class="q-pa-lg q-pt-xl lnbits__dialog-card">
|
||||
<q-form @submit="sendFormData" class="q-gutter-md">
|
||||
|
|
@ -316,10 +360,10 @@
|
|||
emailsTable: {
|
||||
columns: [
|
||||
{
|
||||
name: 'emailaddress',
|
||||
name: 'emailaddress_id',
|
||||
align: 'left',
|
||||
label: 'From',
|
||||
field: 'emailaddress'
|
||||
field: 'emailaddress_id'
|
||||
},
|
||||
{
|
||||
name: 'receiver',
|
||||
|
|
@ -350,6 +394,10 @@
|
|||
rowsPerPage: 10
|
||||
}
|
||||
},
|
||||
emailDialog: {
|
||||
show: false,
|
||||
data: {}
|
||||
},
|
||||
emailaddressDialog: {
|
||||
show: false,
|
||||
data: {}
|
||||
|
|
@ -453,6 +501,33 @@
|
|||
LNbits.utils.notifyApiError(error)
|
||||
})
|
||||
},
|
||||
sendEmail: function () {
|
||||
var self = this
|
||||
var emailaddress = _.findWhere(this.emailaddresses, {
|
||||
id: self.emailDialog.data.emailaddress_id
|
||||
})
|
||||
var wallet = _.findWhere(this.g.user.wallets, {
|
||||
id: emailaddress.wallet
|
||||
})
|
||||
LNbits.api
|
||||
.request(
|
||||
'POST',
|
||||
'/smtp/api/v1/email/' + emailaddress.id + '/send',
|
||||
wallet.adminkey,
|
||||
self.emailDialog.data
|
||||
)
|
||||
.then(function (response) {
|
||||
self.emailDialog.show = false
|
||||
self.emailDialog.data = {}
|
||||
})
|
||||
.catch(function (error) {
|
||||
LNbits.utils.notifyApiError(error)
|
||||
})
|
||||
},
|
||||
showEmailDialog: function (emailaddress_id) {
|
||||
this.emailDialog.data.emailaddress_id = emailaddress_id
|
||||
this.emailDialog.show = true
|
||||
},
|
||||
updateEmailaddressDialog: function (formId) {
|
||||
var link = _.findWhere(this.emailaddresses, {id: formId})
|
||||
this.emailaddressDialog.data = _.clone(link)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from fastapi import Depends, HTTPException, Query
|
|||
|
||||
from lnbits.core.crud import get_user
|
||||
from lnbits.core.services import check_transaction_status, create_invoice
|
||||
from lnbits.decorators import WalletTypeInfo, get_key_type
|
||||
from lnbits.decorators import WalletTypeInfo, get_key_type, require_admin_key
|
||||
|
||||
from . import smtp_ext
|
||||
from .crud import (
|
||||
|
|
@ -13,13 +13,14 @@ from .crud import (
|
|||
delete_email,
|
||||
delete_emailaddress,
|
||||
get_email,
|
||||
get_email_by_payment_hash,
|
||||
get_emailaddress,
|
||||
get_emailaddresses,
|
||||
get_emails,
|
||||
update_emailaddress,
|
||||
)
|
||||
from .models import CreateEmail, CreateEmailaddress
|
||||
from .smtp import valid_email
|
||||
from .smtp import send_mail, valid_email
|
||||
|
||||
|
||||
## EMAILS
|
||||
|
|
@ -37,13 +38,14 @@ async def api_email(
|
|||
|
||||
@smtp_ext.get("/api/v1/email/{payment_hash}")
|
||||
async def api_smtp_send_email(payment_hash):
|
||||
email = await get_email(payment_hash)
|
||||
email = await get_email_by_payment_hash(payment_hash)
|
||||
if not email:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST, detail="paymenthash is wrong"
|
||||
)
|
||||
|
||||
emailaddress = await get_emailaddress(email.emailaddress_id)
|
||||
assert emailaddress
|
||||
|
||||
try:
|
||||
status = await check_transaction_status(email.wallet, payment_hash)
|
||||
|
|
@ -59,11 +61,9 @@ async def api_smtp_send_email(payment_hash):
|
|||
|
||||
@smtp_ext.post("/api/v1/email/{emailaddress_id}")
|
||||
async def api_smtp_make_email(emailaddress_id, data: CreateEmail):
|
||||
|
||||
valid_email(data.receiver)
|
||||
|
||||
emailaddress = await get_emailaddress(emailaddress_id)
|
||||
# If the request is coming for the non-existant emailaddress
|
||||
if not emailaddress:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
|
|
@ -94,6 +94,26 @@ async def api_smtp_make_email(emailaddress_id, data: CreateEmail):
|
|||
return {"payment_hash": payment_hash, "payment_request": payment_request}
|
||||
|
||||
|
||||
@smtp_ext.post(
|
||||
"/api/v1/email/{emailaddress_id}/send", dependencies=[Depends(require_admin_key)]
|
||||
)
|
||||
async def api_smtp_make_email_send(emailaddress_id, data: CreateEmail):
|
||||
valid_email(data.receiver)
|
||||
emailaddress = await get_emailaddress(emailaddress_id)
|
||||
if not emailaddress:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.BAD_REQUEST,
|
||||
detail="Emailaddress address does not exist.",
|
||||
)
|
||||
email = await create_email(wallet=emailaddress.wallet, data=data)
|
||||
if not email:
|
||||
raise HTTPException(
|
||||
status_code=HTTPStatus.NOT_FOUND, detail="Email could not be fetched."
|
||||
)
|
||||
await send_mail(emailaddress, email)
|
||||
return {"sent": True}
|
||||
|
||||
|
||||
@smtp_ext.delete("/api/v1/email/{email_id}")
|
||||
async def api_email_delete(email_id, g: WalletTypeInfo = Depends(get_key_type)):
|
||||
email = await get_email(email_id)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
<a
|
||||
class="text-secondary"
|
||||
href="https://github.com/lnbits/lnbits-legend/tree/main/lnbits/extensions/subdomains"
|
||||
href="https://github.com/lnbits/lnbits/tree/main/lnbits/extensions/subdomains"
|
||||
>More details</a
|
||||
>
|
||||
<br />
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from typing import AsyncGenerator, Dict, Optional
|
|||
import httpx
|
||||
from loguru import logger
|
||||
|
||||
# TODO: https://github.com/lnbits/lnbits-legend/issues/764
|
||||
# TODO: https://github.com/lnbits/lnbits/issues/764
|
||||
# mypy https://github.com/aaugustin/websockets/issues/940
|
||||
from websockets import connect # type: ignore
|
||||
from websockets.exceptions import (
|
||||
|
|
|
|||
340
poetry.lock
generated
340
poetry.lock
generated
|
|
@ -81,21 +81,22 @@ typing-extensions = {version = ">=3.6.5", markers = "python_version < \"3.8\""}
|
|||
|
||||
[[package]]
|
||||
name = "attrs"
|
||||
version = "22.1.0"
|
||||
version = "22.2.0"
|
||||
description = "Classes Without Boilerplate"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.5"
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"},
|
||||
{file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"},
|
||||
{file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"},
|
||||
{file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"]
|
||||
docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"]
|
||||
tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"]
|
||||
tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"]
|
||||
cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"]
|
||||
dev = ["attrs[docs,tests]"]
|
||||
docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"]
|
||||
tests = ["attrs[tests-no-zope]", "zope.interface"]
|
||||
tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"]
|
||||
|
||||
[[package]]
|
||||
name = "base58"
|
||||
|
|
@ -176,61 +177,65 @@ uvloop = ["uvloop (>=0.15.2)"]
|
|||
|
||||
[[package]]
|
||||
name = "cashu"
|
||||
version = "0.6.0"
|
||||
description = "Ecash wallet and mint with Bitcoin Lightning support"
|
||||
version = "0.8.2"
|
||||
description = "Ecash wallet and mint for Bitcoin Lightning"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "cashu-0.6.0-py3-none-any.whl", hash = "sha256:54096af145643aab45943b235f95a3357b0ec697835c1411e66523049ffb81f6"},
|
||||
{file = "cashu-0.6.0.tar.gz", hash = "sha256:503a90c4ca8d25d0b2c3f78a11b163c32902a726ea5b58e5337dc00eca8e96ad"},
|
||||
{file = "cashu-0.8.2-py3-none-any.whl", hash = "sha256:53893911763c424255bc7112aaba356e0a265e850d770338c70b2d282f67bf99"},
|
||||
{file = "cashu-0.8.2.tar.gz", hash = "sha256:4cdd34a50d14960d2dcc6f5b6120f462688090dd084387860f7a59d16aa102ff"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
anyio = {version = "3.6.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
attrs = {version = "22.1.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
attrs = {version = "22.2.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
bech32 = {version = "1.2.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
bitstring = {version = "3.1.9", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
certifi = {version = "2022.9.24", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
certifi = {version = "2022.12.7", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
cffi = {version = "1.15.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
charset-normalizer = {version = "2.0.12", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
click = {version = "8.0.4", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
colorama = {version = "0.4.5", markers = "python_version >= \"3.7\" and python_version < \"4.0\" and platform_system == \"Windows\" or python_version >= \"3.7\" and python_version < \"4.0\" and sys_platform == \"win32\""}
|
||||
colorama = {version = "0.4.6", markers = "python_version >= \"3.7\" and python_version < \"4.0\" and platform_system == \"Windows\" or python_version >= \"3.7\" and python_version < \"4.0\" and sys_platform == \"win32\""}
|
||||
cryptography = {version = "36.0.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
ecdsa = {version = "0.18.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
environs = {version = "9.5.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
exceptiongroup = {version = "1.1.0", markers = "python_version >= \"3.7\" and python_version < \"3.11\""}
|
||||
fastapi = {version = "0.83.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
h11 = {version = "0.12.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
idna = {version = "3.4", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
importlib-metadata = {version = "5.0.0", markers = "python_version >= \"3.7\" and python_version < \"3.8\""}
|
||||
iniconfig = {version = "1.1.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
importlib-metadata = {version = "5.2.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
iniconfig = {version = "2.0.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
loguru = {version = "0.6.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
marshmallow = {version = "3.18.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
marshmallow = {version = "3.19.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
outcome = {version = "1.2.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
packaging = {version = "21.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
packaging = {version = "23.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
pluggy = {version = "1.0.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
py = {version = "1.11.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
pycparser = {version = "2.21", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
pydantic = {version = "1.10.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
pyparsing = {version = "3.0.9", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
pycryptodomex = {version = "3.16.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
pydantic = {version = "1.10.4", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
pysocks = {version = "1.7.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
pytest = {version = "7.1.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
pytest = {version = "7.2.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
pytest-asyncio = {version = "0.19.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
python-bitcoinlib = {version = "0.11.2", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
python-dotenv = {version = "0.21.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
represent = {version = "1.6.0.post0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
requests = {version = "2.27.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
secp256k1 = {version = "0.14.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
setuptools = {version = "65.7.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
six = {version = "1.16.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
sniffio = {version = "1.3.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
sqlalchemy = {version = "1.3.24", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
sqlalchemy-aio = {version = "0.17.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
starlette = {version = "0.19.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
tomli = {version = "2.0.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
tomli = {version = "2.0.1", markers = "python_version >= \"3.7\" and python_version < \"3.11\""}
|
||||
typing-extensions = {version = "4.4.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
urllib3 = {version = "1.26.12", markers = "python_version >= \"3.7\" and python_version < \"4\""}
|
||||
urllib3 = {version = "1.26.14", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
uvicorn = {version = "0.18.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
websocket-client = {version = "1.3.3", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
wheel = {version = "0.38.4", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
win32-setctime = {version = "1.1.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\" and sys_platform == \"win32\""}
|
||||
zipp = {version = "3.9.0", markers = "python_version >= \"3.7\" and python_version < \"3.8\""}
|
||||
zipp = {version = "3.11.0", markers = "python_version >= \"3.7\" and python_version < \"4.0\""}
|
||||
|
||||
[[package]]
|
||||
name = "cerberus"
|
||||
|
|
@ -248,14 +253,14 @@ setuptools = "*"
|
|||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2022.9.24"
|
||||
version = "2022.12.7"
|
||||
description = "Python package for providing Mozilla's CA Bundle."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
{file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"},
|
||||
{file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"},
|
||||
{file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"},
|
||||
{file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -416,14 +421,14 @@ cffi = ">=1.3.0"
|
|||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.5"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
files = [
|
||||
{file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"},
|
||||
{file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"},
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -527,10 +532,10 @@ files = [
|
|||
cffi = ">=1.12"
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx_rtd_theme"]
|
||||
docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"]
|
||||
docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"]
|
||||
pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"]
|
||||
sdist = ["setuptools_rust (>=0.11.4)"]
|
||||
sdist = ["setuptools-rust (>=0.11.4)"]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"]
|
||||
|
||||
|
|
@ -599,6 +604,21 @@ django = ["dj-database-url", "dj-email-url", "django-cache-url"]
|
|||
lint = ["flake8 (==4.0.1)", "flake8-bugbear (==21.9.2)", "mypy (==0.910)", "pre-commit (>=2.4,<3.0)"]
|
||||
tests = ["dj-database-url", "dj-email-url", "django-cache-url", "pytest"]
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.1.0"
|
||||
description = "Backport of PEP 654 (exception groups)"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"},
|
||||
{file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest (>=6)"]
|
||||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
version = "0.83.0"
|
||||
|
|
@ -798,14 +818,14 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "importlib-metadata"
|
||||
version = "5.0.0"
|
||||
version = "5.2.0"
|
||||
description = "Read metadata from Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "importlib_metadata-5.0.0-py3-none-any.whl", hash = "sha256:ddb0e35065e8938f867ed4928d0ae5bf2a53b7773871bfe6bcc7e4fcdc7dea43"},
|
||||
{file = "importlib_metadata-5.0.0.tar.gz", hash = "sha256:da31db32b304314d044d3c12c79bd59e307889b287ad12ff387b3500835fc2ab"},
|
||||
{file = "importlib_metadata-5.2.0-py3-none-any.whl", hash = "sha256:0eafa39ba42bf225fc00e67f701d71f85aead9f878569caf13c3724f704b970f"},
|
||||
{file = "importlib_metadata-5.2.0.tar.gz", hash = "sha256:404d48d62bba0b7a77ff9d405efd91501bef2e67ff4ace0bed40a0cf28c3c7cd"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
|
|
@ -813,20 +833,20 @@ typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""}
|
|||
zipp = ">=0.5"
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"]
|
||||
perf = ["ipython"]
|
||||
testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "1.1.1"
|
||||
description = "iniconfig: brain-dead simple config-ini parsing"
|
||||
version = "2.0.0"
|
||||
description = "brain-dead simple config-ini parsing"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"},
|
||||
{file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"},
|
||||
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
|
||||
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -982,23 +1002,23 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "marshmallow"
|
||||
version = "3.18.0"
|
||||
version = "3.19.0"
|
||||
description = "A lightweight library for converting complex datatypes to and from native Python datatypes."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "marshmallow-3.18.0-py3-none-any.whl", hash = "sha256:35e02a3a06899c9119b785c12a22f4cda361745d66a71ab691fd7610202ae104"},
|
||||
{file = "marshmallow-3.18.0.tar.gz", hash = "sha256:6804c16114f7fce1f5b4dadc31f4674af23317fcc7f075da21e35c1a35d781f7"},
|
||||
{file = "marshmallow-3.19.0-py3-none-any.whl", hash = "sha256:93f0958568da045b0021ec6aeb7ac37c81bfcccbb9a0e7ed8559885070b3a19b"},
|
||||
{file = "marshmallow-3.19.0.tar.gz", hash = "sha256:90032c0fd650ce94b6ec6dc8dfeb0e3ff50c144586462c389b81a07205bedb78"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
packaging = ">=17.0"
|
||||
|
||||
[package.extras]
|
||||
dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.9.11)", "mypy (==0.971)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"]
|
||||
docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.1.1)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"]
|
||||
lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.9.11)", "mypy (==0.971)", "pre-commit (>=2.4,<3.0)"]
|
||||
dev = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)", "pytest", "pytz", "simplejson", "tox"]
|
||||
docs = ["alabaster (==0.7.12)", "autodocsumm (==0.2.9)", "sphinx (==5.3.0)", "sphinx-issues (==3.0.1)", "sphinx-version-warning (==1.1.2)"]
|
||||
lint = ["flake8 (==5.0.4)", "flake8-bugbear (==22.10.25)", "mypy (==0.990)", "pre-commit (>=2.4,<3.0)"]
|
||||
tests = ["pytest", "pytz", "simplejson"]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1091,19 +1111,16 @@ attrs = ">=19.2.0"
|
|||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "21.3"
|
||||
version = "23.0"
|
||||
description = "Core utilities for Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
|
||||
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
|
||||
{file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"},
|
||||
{file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
|
||||
|
||||
[[package]]
|
||||
name = "pathlib2"
|
||||
version = "2.3.7.post1"
|
||||
|
|
@ -1239,18 +1256,6 @@ files = [
|
|||
{file = "psycopg2_binary-2.9.1-cp39-cp39-win_amd64.whl", hash = "sha256:b4d7679a08fea64573c969f6994a2631908bb2c0e69a7235648642f3d2e39a68"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "py"
|
||||
version = "1.11.0"
|
||||
description = "library with cross-python path, ini-parsing, io, code, log facilities"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
{file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"},
|
||||
{file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pycparser"
|
||||
version = "2.21"
|
||||
|
|
@ -1265,89 +1270,88 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "pycryptodomex"
|
||||
version = "3.14.1"
|
||||
version = "3.16.0"
|
||||
description = "Cryptographic library for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
files = [
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca88f2f7020002638276439a01ffbb0355634907d1aa5ca91f3dc0c2e44e8f3b"},
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:8536bc08d130cae6dcba1ea689f2913dfd332d06113904d171f2f56da6228e89"},
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:406ec8cfe0c098fadb18d597dc2ee6de4428d640c0ccafa453f3d9b2e58d29e2"},
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:da8db8374295fb532b4b0c467e66800ef17d100e4d5faa2bbbd6df35502da125"},
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:d709572d64825d8d59ea112e11cc7faf6007f294e9951324b7574af4251e4de8"},
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27m-win32.whl", hash = "sha256:3da13c2535b7aea94cc2a6d1b1b37746814c74b6e80790daddd55ca5c120a489"},
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27m-win_amd64.whl", hash = "sha256:298c00ea41a81a491d5b244d295d18369e5aac4b61b77b2de5b249ca61cd6659"},
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:77931df40bb5ce5e13f4de2bfc982b2ddc0198971fbd947776c8bb5050896eb2"},
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:c5dd3ffa663c982d7f1be9eb494a8924f6d40e2e2f7d1d27384cfab1b2ac0662"},
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2aa887683eee493e015545bd69d3d21ac8d5ad582674ec98f4af84511e353e45"},
|
||||
{file = "pycryptodomex-3.14.1-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:8085bd0ad2034352eee4d4f3e2da985c2749cb7344b939f4d95ead38c2520859"},
|
||||
{file = "pycryptodomex-3.14.1-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:e95a4a6c54d27a84a4624d2af8bb9ee178111604653194ca6880c98dcad92f48"},
|
||||
{file = "pycryptodomex-3.14.1-cp35-abi3-manylinux1_i686.whl", hash = "sha256:a4d412eba5679ede84b41dbe48b1bed8f33131ab9db06c238a235334733acc5e"},
|
||||
{file = "pycryptodomex-3.14.1-cp35-abi3-manylinux1_x86_64.whl", hash = "sha256:d2cce1c82a7845d7e2e8a0956c6b7ed3f1661c9acf18eb120fc71e098ab5c6fe"},
|
||||
{file = "pycryptodomex-3.14.1-cp35-abi3-manylinux2010_i686.whl", hash = "sha256:f75009715dcf4a3d680c2338ab19dac5498f8121173a929872950f4fb3a48fbf"},
|
||||
{file = "pycryptodomex-3.14.1-cp35-abi3-manylinux2010_x86_64.whl", hash = "sha256:1ca8e1b4c62038bb2da55451385246f51f412c5f5eabd64812c01766a5989b4a"},
|
||||
{file = "pycryptodomex-3.14.1-cp35-abi3-win32.whl", hash = "sha256:ee835def05622e0c8b1435a906491760a43d0c462f065ec9143ec4b8d79f8bff"},
|
||||
{file = "pycryptodomex-3.14.1-cp35-abi3-win_amd64.whl", hash = "sha256:b5a185ae79f899b01ca49f365bdf15a45d78d9856f09b0de1a41b92afce1a07f"},
|
||||
{file = "pycryptodomex-3.14.1-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:797a36bd1f69df9e2798e33edb4bd04e5a30478efc08f9428c087f17f65a7045"},
|
||||
{file = "pycryptodomex-3.14.1-pp27-pypy_73-manylinux1_x86_64.whl", hash = "sha256:aebecde2adc4a6847094d3bd6a8a9538ef3438a5ea84ac1983fcb167db614461"},
|
||||
{file = "pycryptodomex-3.14.1-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:f8524b8bc89470cec7ac51734907818d3620fb1637f8f8b542d650ebec42a126"},
|
||||
{file = "pycryptodomex-3.14.1-pp27-pypy_73-win32.whl", hash = "sha256:4d0db8df9ffae36f416897ad184608d9d7a8c2b46c4612c6bc759b26c073f750"},
|
||||
{file = "pycryptodomex-3.14.1-pp36-pypy36_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b276cc4deb4a80f9dfd47a41ebb464b1fe91efd8b1b8620cf5ccf8b824b850d6"},
|
||||
{file = "pycryptodomex-3.14.1-pp36-pypy36_pp73-manylinux1_x86_64.whl", hash = "sha256:e36c7e3b5382cd5669cf199c4a04a0279a43b2a3bdd77627e9b89778ac9ec08c"},
|
||||
{file = "pycryptodomex-3.14.1-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:c4d8977ccda886d88dc3ca789de2f1adc714df912ff3934b3d0a3f3d777deafb"},
|
||||
{file = "pycryptodomex-3.14.1-pp36-pypy36_pp73-win32.whl", hash = "sha256:530756d2faa40af4c1f74123e1d889bd07feae45bac2fd32f259a35f7aa74151"},
|
||||
{file = "pycryptodomex-3.14.1.tar.gz", hash = "sha256:2ce76ed0081fd6ac8c74edc75b9d14eca2064173af79843c24fa62573263c1f2"},
|
||||
{file = "pycryptodomex-3.16.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:b3d04c00d777c36972b539fb79958790126847d84ec0129fce1efef250bfe3ce"},
|
||||
{file = "pycryptodomex-3.16.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:e5a670919076b71522c7d567a9043f66f14b202414a63c3a078b5831ae342c03"},
|
||||
{file = "pycryptodomex-3.16.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:ce338a9703f54b2305a408fc9890eb966b727ce72b69f225898bb4e9d9ed3f1f"},
|
||||
{file = "pycryptodomex-3.16.0-cp27-cp27m-manylinux2014_aarch64.whl", hash = "sha256:a1c0ae7123448ecb034c75c713189cb00ebe2d415b11682865b6c54d200d9c93"},
|
||||
{file = "pycryptodomex-3.16.0-cp27-cp27m-win32.whl", hash = "sha256:8851585ff19871e5d69e1790f4ca5f6fd1699d6b8b14413b472a4c0dbc7ea780"},
|
||||
{file = "pycryptodomex-3.16.0-cp27-cp27m-win_amd64.whl", hash = "sha256:8dd2d9e3c617d0712ed781a77efd84ea579e76c5f9b2a4bc0b684ebeddf868b2"},
|
||||
{file = "pycryptodomex-3.16.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:2ad9bb86b355b6104796567dd44c215b3dc953ef2fae5e0bdfb8516731df92cf"},
|
||||
{file = "pycryptodomex-3.16.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:e25a2f5667d91795f9417cb856f6df724ccdb0cdd5cbadb212ee9bf43946e9f8"},
|
||||
{file = "pycryptodomex-3.16.0-cp27-cp27mu-manylinux2014_aarch64.whl", hash = "sha256:b0789a8490114a2936ed77c87792cfe77582c829cb43a6d86ede0f9624ba8aa3"},
|
||||
{file = "pycryptodomex-3.16.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0da835af786fdd1c9930994c78b23e88d816dc3f99aa977284a21bbc26d19735"},
|
||||
{file = "pycryptodomex-3.16.0-cp35-abi3-manylinux2014_aarch64.whl", hash = "sha256:22aed0868622d95179217c298e37ed7410025c7b29dac236d3230617d1e4ed56"},
|
||||
{file = "pycryptodomex-3.16.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1619087fb5b31510b0b0b058a54f001a5ffd91e6ffee220d9913064519c6a69d"},
|
||||
{file = "pycryptodomex-3.16.0-cp35-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:70288d9bfe16b2fd0d20b6c365db614428f1bcde7b20d56e74cf88ade905d9eb"},
|
||||
{file = "pycryptodomex-3.16.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7993d26dae4d83b8f4ce605bb0aecb8bee330bb3c95475ef06f3694403621e71"},
|
||||
{file = "pycryptodomex-3.16.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:1cda60207be8c1cf0b84b9138f9e3ca29335013d2b690774a5e94678ff29659a"},
|
||||
{file = "pycryptodomex-3.16.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:04610536921c1ec7adba158ef570348550c9f3a40bc24be9f8da2ef7ab387981"},
|
||||
{file = "pycryptodomex-3.16.0-cp35-abi3-win32.whl", hash = "sha256:daa67f5ebb6fbf1ee9c90decaa06ca7fc88a548864e5e484d52b0920a57fe8a5"},
|
||||
{file = "pycryptodomex-3.16.0-cp35-abi3-win_amd64.whl", hash = "sha256:231dc8008cbdd1ae0e34645d4523da2dbc7a88c325f0d4a59635a86ee25b41dd"},
|
||||
{file = "pycryptodomex-3.16.0-pp27-pypy_73-macosx_10_9_x86_64.whl", hash = "sha256:4dbbe18cc232b5980c7633972ae5417d0df76fe89e7db246eefd17ef4d8e6d7a"},
|
||||
{file = "pycryptodomex-3.16.0-pp27-pypy_73-manylinux2010_x86_64.whl", hash = "sha256:893f8a97d533c66cc3a56e60dd3ed40a3494ddb4aafa7e026429a08772f8a849"},
|
||||
{file = "pycryptodomex-3.16.0-pp27-pypy_73-win32.whl", hash = "sha256:6a465e4f856d2a4f2a311807030c89166529ccf7ccc65bef398de045d49144b6"},
|
||||
{file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ba57ac7861fd2c837cdb33daf822f2a052ff57dd769a2107807f52a36d0e8d38"},
|
||||
{file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f2b971a7b877348a27dcfd0e772a0343fb818df00b74078e91c008632284137d"},
|
||||
{file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e2453162f473c1eae4826eb10cd7bce19b5facac86d17fb5f29a570fde145abd"},
|
||||
{file = "pycryptodomex-3.16.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0ba28aa97cdd3ff5ed1a4f2b7f5cd04e721166bd75bd2b929e2734433882b583"},
|
||||
{file = "pycryptodomex-3.16.0.tar.gz", hash = "sha256:e9ba9d8ed638733c9e95664470b71d624a6def149e2db6cc52c1aca5a6a2df1d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pydantic"
|
||||
version = "1.10.2"
|
||||
version = "1.10.4"
|
||||
description = "Data validation and settings management using python type hints"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pydantic-1.10.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bb6ad4489af1bac6955d38ebcb95079a836af31e4c4f74aba1ca05bb9f6027bd"},
|
||||
{file = "pydantic-1.10.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a1f5a63a6dfe19d719b1b6e6106561869d2efaca6167f84f5ab9347887d78b98"},
|
||||
{file = "pydantic-1.10.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:352aedb1d71b8b0736c6d56ad2bd34c6982720644b0624462059ab29bd6e5912"},
|
||||
{file = "pydantic-1.10.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19b3b9ccf97af2b7519c42032441a891a5e05c68368f40865a90eb88833c2559"},
|
||||
{file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e9069e1b01525a96e6ff49e25876d90d5a563bc31c658289a8772ae186552236"},
|
||||
{file = "pydantic-1.10.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:355639d9afc76bcb9b0c3000ddcd08472ae75318a6eb67a15866b87e2efa168c"},
|
||||
{file = "pydantic-1.10.2-cp310-cp310-win_amd64.whl", hash = "sha256:ae544c47bec47a86bc7d350f965d8b15540e27e5aa4f55170ac6a75e5f73b644"},
|
||||
{file = "pydantic-1.10.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4c805731c33a8db4b6ace45ce440c4ef5336e712508b4d9e1aafa617dc9907f"},
|
||||
{file = "pydantic-1.10.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d49f3db871575e0426b12e2f32fdb25e579dea16486a26e5a0474af87cb1ab0a"},
|
||||
{file = "pydantic-1.10.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:37c90345ec7dd2f1bcef82ce49b6235b40f282b94d3eec47e801baf864d15525"},
|
||||
{file = "pydantic-1.10.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b5ba54d026c2bd2cb769d3468885f23f43710f651688e91f5fb1edcf0ee9283"},
|
||||
{file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05e00dbebbe810b33c7a7362f231893183bcc4251f3f2ff991c31d5c08240c42"},
|
||||
{file = "pydantic-1.10.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2d0567e60eb01bccda3a4df01df677adf6b437958d35c12a3ac3e0f078b0ee52"},
|
||||
{file = "pydantic-1.10.2-cp311-cp311-win_amd64.whl", hash = "sha256:c6f981882aea41e021f72779ce2a4e87267458cc4d39ea990729e21ef18f0f8c"},
|
||||
{file = "pydantic-1.10.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c4aac8e7103bf598373208f6299fa9a5cfd1fc571f2d40bf1dd1955a63d6eeb5"},
|
||||
{file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81a7b66c3f499108b448f3f004801fcd7d7165fb4200acb03f1c2402da73ce4c"},
|
||||
{file = "pydantic-1.10.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bedf309630209e78582ffacda64a21f96f3ed2e51fbf3962d4d488e503420254"},
|
||||
{file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9300fcbebf85f6339a02c6994b2eb3ff1b9c8c14f502058b5bf349d42447dcf5"},
|
||||
{file = "pydantic-1.10.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:216f3bcbf19c726b1cc22b099dd409aa371f55c08800bcea4c44c8f74b73478d"},
|
||||
{file = "pydantic-1.10.2-cp37-cp37m-win_amd64.whl", hash = "sha256:dd3f9a40c16daf323cf913593083698caee97df2804aa36c4b3175d5ac1b92a2"},
|
||||
{file = "pydantic-1.10.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b97890e56a694486f772d36efd2ba31612739bc6f3caeee50e9e7e3ebd2fdd13"},
|
||||
{file = "pydantic-1.10.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9cabf4a7f05a776e7793e72793cd92cc865ea0e83a819f9ae4ecccb1b8aa6116"},
|
||||
{file = "pydantic-1.10.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06094d18dd5e6f2bbf93efa54991c3240964bb663b87729ac340eb5014310624"},
|
||||
{file = "pydantic-1.10.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cc78cc83110d2f275ec1970e7a831f4e371ee92405332ebfe9860a715f8336e1"},
|
||||
{file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ee433e274268a4b0c8fde7ad9d58ecba12b069a033ecc4645bb6303c062d2e9"},
|
||||
{file = "pydantic-1.10.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7c2abc4393dea97a4ccbb4ec7d8658d4e22c4765b7b9b9445588f16c71ad9965"},
|
||||
{file = "pydantic-1.10.2-cp38-cp38-win_amd64.whl", hash = "sha256:0b959f4d8211fc964772b595ebb25f7652da3f22322c007b6fed26846a40685e"},
|
||||
{file = "pydantic-1.10.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c33602f93bfb67779f9c507e4d69451664524389546bacfe1bee13cae6dc7488"},
|
||||
{file = "pydantic-1.10.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:5760e164b807a48a8f25f8aa1a6d857e6ce62e7ec83ea5d5c5a802eac81bad41"},
|
||||
{file = "pydantic-1.10.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6eb843dcc411b6a2237a694f5e1d649fc66c6064d02b204a7e9d194dff81eb4b"},
|
||||
{file = "pydantic-1.10.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4b8795290deaae348c4eba0cebb196e1c6b98bdbe7f50b2d0d9a4a99716342fe"},
|
||||
{file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e0bedafe4bc165ad0a56ac0bd7695df25c50f76961da29c050712596cf092d6d"},
|
||||
{file = "pydantic-1.10.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2e05aed07fa02231dbf03d0adb1be1d79cabb09025dd45aa094aa8b4e7b9dcda"},
|
||||
{file = "pydantic-1.10.2-cp39-cp39-win_amd64.whl", hash = "sha256:c1ba1afb396148bbc70e9eaa8c06c1716fdddabaf86e7027c5988bae2a829ab6"},
|
||||
{file = "pydantic-1.10.2-py3-none-any.whl", hash = "sha256:1b6ee725bd6e83ec78b1aa32c5b1fa67a3a65badddde3976bca5fe4568f27709"},
|
||||
{file = "pydantic-1.10.2.tar.gz", hash = "sha256:91b8e218852ef6007c2b98cd861601c6a09f1aa32bbbb74fab5b1c33d4a1e410"},
|
||||
{file = "pydantic-1.10.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b5635de53e6686fe7a44b5cf25fcc419a0d5e5c1a1efe73d49d48fe7586db854"},
|
||||
{file = "pydantic-1.10.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6dc1cc241440ed7ca9ab59d9929075445da6b7c94ced281b3dd4cfe6c8cff817"},
|
||||
{file = "pydantic-1.10.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51bdeb10d2db0f288e71d49c9cefa609bca271720ecd0c58009bd7504a0c464c"},
|
||||
{file = "pydantic-1.10.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:78cec42b95dbb500a1f7120bdf95c401f6abb616bbe8785ef09887306792e66e"},
|
||||
{file = "pydantic-1.10.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8775d4ef5e7299a2f4699501077a0defdaac5b6c4321173bcb0f3c496fbadf85"},
|
||||
{file = "pydantic-1.10.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:572066051eeac73d23f95ba9a71349c42a3e05999d0ee1572b7860235b850cc6"},
|
||||
{file = "pydantic-1.10.4-cp310-cp310-win_amd64.whl", hash = "sha256:7feb6a2d401f4d6863050f58325b8d99c1e56f4512d98b11ac64ad1751dc647d"},
|
||||
{file = "pydantic-1.10.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39f4a73e5342b25c2959529f07f026ef58147249f9b7431e1ba8414a36761f53"},
|
||||
{file = "pydantic-1.10.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:983e720704431a6573d626b00662eb78a07148c9115129f9b4351091ec95ecc3"},
|
||||
{file = "pydantic-1.10.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75d52162fe6b2b55964fbb0af2ee58e99791a3138588c482572bb6087953113a"},
|
||||
{file = "pydantic-1.10.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdf8d759ef326962b4678d89e275ffc55b7ce59d917d9f72233762061fd04a2d"},
|
||||
{file = "pydantic-1.10.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:05a81b006be15655b2a1bae5faa4280cf7c81d0e09fcb49b342ebf826abe5a72"},
|
||||
{file = "pydantic-1.10.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d88c4c0e5c5dfd05092a4b271282ef0588e5f4aaf345778056fc5259ba098857"},
|
||||
{file = "pydantic-1.10.4-cp311-cp311-win_amd64.whl", hash = "sha256:6a05a9db1ef5be0fe63e988f9617ca2551013f55000289c671f71ec16f4985e3"},
|
||||
{file = "pydantic-1.10.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:887ca463c3bc47103c123bc06919c86720e80e1214aab79e9b779cda0ff92a00"},
|
||||
{file = "pydantic-1.10.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdf88ab63c3ee282c76d652fc86518aacb737ff35796023fae56a65ced1a5978"},
|
||||
{file = "pydantic-1.10.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a48f1953c4a1d9bd0b5167ac50da9a79f6072c63c4cef4cf2a3736994903583e"},
|
||||
{file = "pydantic-1.10.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a9f2de23bec87ff306aef658384b02aa7c32389766af3c5dee9ce33e80222dfa"},
|
||||
{file = "pydantic-1.10.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:cd8702c5142afda03dc2b1ee6bc358b62b3735b2cce53fc77b31ca9f728e4bc8"},
|
||||
{file = "pydantic-1.10.4-cp37-cp37m-win_amd64.whl", hash = "sha256:6e7124d6855b2780611d9f5e1e145e86667eaa3bd9459192c8dc1a097f5e9903"},
|
||||
{file = "pydantic-1.10.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b53e1d41e97063d51a02821b80538053ee4608b9a181c1005441f1673c55423"},
|
||||
{file = "pydantic-1.10.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:55b1625899acd33229c4352ce0ae54038529b412bd51c4915349b49ca575258f"},
|
||||
{file = "pydantic-1.10.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:301d626a59edbe5dfb48fcae245896379a450d04baeed50ef40d8199f2733b06"},
|
||||
{file = "pydantic-1.10.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b6f9d649892a6f54a39ed56b8dfd5e08b5f3be5f893da430bed76975f3735d15"},
|
||||
{file = "pydantic-1.10.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:d7b5a3821225f5c43496c324b0d6875fde910a1c2933d726a743ce328fbb2a8c"},
|
||||
{file = "pydantic-1.10.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f2f7eb6273dd12472d7f218e1fef6f7c7c2f00ac2e1ecde4db8824c457300416"},
|
||||
{file = "pydantic-1.10.4-cp38-cp38-win_amd64.whl", hash = "sha256:4b05697738e7d2040696b0a66d9f0a10bec0efa1883ca75ee9e55baf511909d6"},
|
||||
{file = "pydantic-1.10.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a9a6747cac06c2beb466064dda999a13176b23535e4c496c9d48e6406f92d42d"},
|
||||
{file = "pydantic-1.10.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:eb992a1ef739cc7b543576337bebfc62c0e6567434e522e97291b251a41dad7f"},
|
||||
{file = "pydantic-1.10.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:990406d226dea0e8f25f643b370224771878142155b879784ce89f633541a024"},
|
||||
{file = "pydantic-1.10.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e82a6d37a95e0b1b42b82ab340ada3963aea1317fd7f888bb6b9dfbf4fff57c"},
|
||||
{file = "pydantic-1.10.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9193d4f4ee8feca58bc56c8306bcb820f5c7905fd919e0750acdeeeef0615b28"},
|
||||
{file = "pydantic-1.10.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2b3ce5f16deb45c472dde1a0ee05619298c864a20cded09c4edd820e1454129f"},
|
||||
{file = "pydantic-1.10.4-cp39-cp39-win_amd64.whl", hash = "sha256:9cbdc268a62d9a98c56e2452d6c41c0263d64a2009aac69246486f01b4f594c4"},
|
||||
{file = "pydantic-1.10.4-py3-none-any.whl", hash = "sha256:4948f264678c703f3877d1c8877c4e3b2e12e549c57795107f08cf70c6ec7774"},
|
||||
{file = "pydantic-1.10.4.tar.gz", hash = "sha256:b9a3859f24eb4e097502a3be1fb4b2abb79b6103dd9e2e0edb70613a4459a648"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
typing-extensions = ">=4.1.0"
|
||||
typing-extensions = ">=4.2.0"
|
||||
|
||||
[package.extras]
|
||||
dotenv = ["python-dotenv (>=0.10.4)"]
|
||||
|
|
@ -1400,21 +1404,6 @@ coincurve = ">=17.0.0,<18.0.0"
|
|||
cryptography = ">=36.0.1,<37.0.0"
|
||||
PySocks = ">=1.7.1,<2.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "pyparsing"
|
||||
version = "3.0.9"
|
||||
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.6.8"
|
||||
files = [
|
||||
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
|
||||
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pypng"
|
||||
version = "0.0.21"
|
||||
|
|
@ -1472,25 +1461,25 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "7.1.3"
|
||||
version = "7.2.1"
|
||||
description = "pytest: simple powerful testing with Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "pytest-7.1.3-py3-none-any.whl", hash = "sha256:1377bda3466d70b55e3f5cecfa55bb7cfcf219c7964629b967c37cf0bda818b7"},
|
||||
{file = "pytest-7.1.3.tar.gz", hash = "sha256:4f365fec2dff9c1162f834d9f18af1ba13062db0c708bf7b946f8a5c76180c39"},
|
||||
{file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"},
|
||||
{file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
attrs = ">=19.2.0"
|
||||
colorama = {version = "*", markers = "sys_platform == \"win32\""}
|
||||
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
|
||||
importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""}
|
||||
iniconfig = "*"
|
||||
packaging = "*"
|
||||
pluggy = ">=0.12,<2.0"
|
||||
py = ">=1.8.2"
|
||||
tomli = ">=1.0.0"
|
||||
tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
|
||||
|
||||
[package.extras]
|
||||
testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"]
|
||||
|
|
@ -1695,18 +1684,18 @@ cffi = ">=1.3.0"
|
|||
|
||||
[[package]]
|
||||
name = "setuptools"
|
||||
version = "65.6.3"
|
||||
version = "65.7.0"
|
||||
description = "Easily download, build, install, upgrade, and uninstall Python packages"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "setuptools-65.6.3-py3-none-any.whl", hash = "sha256:57f6f22bde4e042978bcd50176fdb381d7c21a9efa4041202288d3737a0c6a54"},
|
||||
{file = "setuptools-65.6.3.tar.gz", hash = "sha256:a7620757bf984b58deaf32fc8a4577a9bbc0850cf92c20e1ce41c38c19e5fb75"},
|
||||
{file = "setuptools-65.7.0-py3-none-any.whl", hash = "sha256:8ab4f1dbf2b4a65f7eec5ad0c620e84c34111a68d3349833494b9088212214dd"},
|
||||
{file = "setuptools-65.7.0.tar.gz", hash = "sha256:4d3c92fac8f1118bb77a22181355e29c239cabfe2b9effdaa665c66b711136d7"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
||||
docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
|
||||
testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
|
||||
testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"]
|
||||
|
||||
|
|
@ -1795,7 +1784,7 @@ mssql = ["pyodbc"]
|
|||
mssql-pymssql = ["pymssql"]
|
||||
mssql-pyodbc = ["pyodbc"]
|
||||
mysql = ["mysqlclient"]
|
||||
oracle = ["cx_oracle"]
|
||||
oracle = ["cx-oracle"]
|
||||
postgresql = ["psycopg2"]
|
||||
postgresql-pg8000 = ["pg8000 (<1.16.6)"]
|
||||
postgresql-psycopg2binary = ["psycopg2-binary"]
|
||||
|
|
@ -1926,14 +1915,14 @@ files = [
|
|||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "1.26.12"
|
||||
version = "1.26.14"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4"
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
|
||||
files = [
|
||||
{file = "urllib3-1.26.12-py2.py3-none-any.whl", hash = "sha256:b930dd878d5a8afb066a637fbb35144fe7901e3b209d1cd4f524bd0e9deee997"},
|
||||
{file = "urllib3-1.26.12.tar.gz", hash = "sha256:3fa96cf423e6987997fc326ae8df396db2a8b7c667747d47ddd8ecba91f4a74e"},
|
||||
{file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"},
|
||||
{file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
|
@ -2056,6 +2045,21 @@ files = [
|
|||
{file = "websockets-10.0.tar.gz", hash = "sha256:c4fc9a1d242317892590abe5b61a9127f1a61740477bfb121743f290b8054002"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wheel"
|
||||
version = "0.38.4"
|
||||
description = "A built-package format for Python"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "wheel-0.38.4-py3-none-any.whl", hash = "sha256:b60533f3f5d530e971d6737ca6d58681ee434818fab630c83a734bb10c083ce8"},
|
||||
{file = "wheel-0.38.4.tar.gz", hash = "sha256:965f5259b566725405b05e7cf774052044b1ed30119b5d586b2703aafe8719ac"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
test = ["pytest (>=3.0.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "win32-setctime"
|
||||
version = "1.1.0"
|
||||
|
|
@ -2073,14 +2077,14 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
|
|||
|
||||
[[package]]
|
||||
name = "zipp"
|
||||
version = "3.9.0"
|
||||
version = "3.11.0"
|
||||
description = "Backport of pathlib-compatible object wrapper for zip files"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
{file = "zipp-3.9.0-py3-none-any.whl", hash = "sha256:972cfa31bc2fedd3fa838a51e9bc7e64b7fb725a8c00e7431554311f180e9980"},
|
||||
{file = "zipp-3.9.0.tar.gz", hash = "sha256:3a7af91c3db40ec72dd9d154ae18e008c69efe8ca88dde4f9a731bb82fe2f9eb"},
|
||||
{file = "zipp-3.11.0-py3-none-any.whl", hash = "sha256:83a28fcb75844b5c0cdaf5aa4003c2d728c77e05f5aeabe8e95e56727005fbaa"},
|
||||
{file = "zipp-3.11.0.tar.gz", hash = "sha256:a7a22e05929290a67401440b39690ae6563279bced5f314609d9d03798f56766"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
|
|
@ -2090,4 +2094,4 @@ testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools"
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10 | ^3.9 | ^3.8 | ^3.7"
|
||||
content-hash = "73e1443abc1eed24639a5297a66b2eb16e80491f8849b8008e065f153de215c7"
|
||||
content-hash = "9daf94dd600a7e23dcefcc8752fae1694e0084e56553dc578a63272776a8fe53"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
[tool.poetry]
|
||||
name = "lnbits"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["matthewcroughan <matt@croughan.sh>"]
|
||||
version = "0.9.5.3"
|
||||
description = "LNbits, free and open-source Lightning wallet and accounts system."
|
||||
authors = ["Alan Bits <alan@lnbits.com>"]
|
||||
|
||||
[tool.poetry.build]
|
||||
generate-setup-file = false
|
||||
|
|
@ -12,10 +12,10 @@ script = "build.py"
|
|||
python = "^3.10 | ^3.9 | ^3.8 | ^3.7"
|
||||
aiofiles = "0.8.0"
|
||||
asgiref = "3.4.1"
|
||||
attrs = "22.1.0"
|
||||
attrs = "22.2.0"
|
||||
bech32 = "1.2.0"
|
||||
bitstring = "3.1.9"
|
||||
certifi = "2022.9.24"
|
||||
certifi = "2022.12.7"
|
||||
charset-normalizer = "2.0.12"
|
||||
click = "8.0.4"
|
||||
ecdsa = "0.18.0"
|
||||
|
|
@ -26,15 +26,15 @@ httpcore = "0.15.0"
|
|||
httptools = "0.4.0"
|
||||
httpx = "0.23.0"
|
||||
idna = "3.4"
|
||||
importlib-metadata = "5.0.0"
|
||||
importlib-metadata = "5.2.0"
|
||||
jinja2 = "3.0.1"
|
||||
lnurl = "0.3.6"
|
||||
markupsafe = "2.0.1"
|
||||
marshmallow = "3.18.0"
|
||||
marshmallow = "3.19.0"
|
||||
outcome = "1.2.0"
|
||||
psycopg2-binary = "2.9.1"
|
||||
pycryptodomex = "3.14.1"
|
||||
pydantic = "1.10.2"
|
||||
pycryptodomex = "3.16.0"
|
||||
pydantic = "1.10.4"
|
||||
pypng = "0.0.21"
|
||||
pyqrcode = "1.2.1"
|
||||
pyScss = "1.4.0"
|
||||
|
|
@ -53,7 +53,7 @@ uvicorn = "0.18.3"
|
|||
uvloop = "0.16.0"
|
||||
watchgod = "0.7"
|
||||
websockets = "10.0"
|
||||
zipp = "3.9.0"
|
||||
zipp = "3.11.0"
|
||||
loguru = "0.6.0"
|
||||
cffi = "1.15.1"
|
||||
websocket-client = "1.3.3"
|
||||
|
|
@ -62,7 +62,7 @@ protobuf = "^4.21.6"
|
|||
Cerberus = "^1.3.4"
|
||||
async-timeout = "^4.0.2"
|
||||
pyln-client = "0.11.1"
|
||||
cashu = "^0.6.0"
|
||||
cashu = "0.8.2"
|
||||
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
|
@ -88,8 +88,7 @@ profile = "black"
|
|||
[tool.mypy]
|
||||
files = "lnbits"
|
||||
exclude = """(?x)(
|
||||
^lnbits/extensions/bleskomat.
|
||||
| ^lnbits/extensions/boltz.
|
||||
^lnbits/extensions/boltz.
|
||||
| ^lnbits/wallets/lnd_grpc_files.
|
||||
)"""
|
||||
|
||||
|
|
|
|||
|
|
@ -3,57 +3,56 @@ anyio==3.6.2 ; python_version >= "3.7" and python_version < "4.0"
|
|||
asgiref==3.4.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
asn1crypto==1.5.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
async-timeout==4.0.2 ; python_version >= "3.7" and python_version < "4.0"
|
||||
attrs==22.1.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
attrs==22.2.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
base58==2.1.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
bech32==1.2.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
bitstring==3.1.9 ; python_version >= "3.7" and python_version < "4.0"
|
||||
cashu==0.6.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
cashu==0.8.2 ; python_version >= "3.7" and python_version < "4.0"
|
||||
cerberus==1.3.4 ; python_version >= "3.7" and python_version < "4.0"
|
||||
certifi==2022.9.24 ; python_version >= "3.7" and python_version < "4.0"
|
||||
certifi==2022.12.7 ; python_version >= "3.7" and python_version < "4.0"
|
||||
cffi==1.15.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
charset-normalizer==2.0.12 ; python_version >= "3.7" and python_version < "4.0"
|
||||
click==8.0.4 ; python_version >= "3.7" and python_version < "4.0"
|
||||
coincurve==17.0.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
colorama==0.4.5 ; python_version >= "3.7" and python_version < "4.0" and platform_system == "Windows" or python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32"
|
||||
colorama==0.4.6 ; python_version >= "3.7" and python_version < "4.0" and platform_system == "Windows" or python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32"
|
||||
cryptography==36.0.2 ; python_version >= "3.7" and python_version < "4.0"
|
||||
ecdsa==0.18.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
embit==0.4.9 ; python_version >= "3.7" and python_version < "4.0"
|
||||
enum34==1.1.10 ; python_version >= "3.7" and python_version < "4.0"
|
||||
environs==9.5.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
exceptiongroup==1.1.0 ; python_version >= "3.7" and python_version < "3.11"
|
||||
fastapi==0.83.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
grpcio==1.50.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
grpcio==1.51.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
h11==0.12.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
httpcore==0.15.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
httptools==0.4.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
httpx==0.23.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
idna==3.4 ; python_version >= "3.7" and python_version < "4.0"
|
||||
importlib-metadata==5.0.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
iniconfig==1.1.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
importlib-metadata==5.2.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
iniconfig==2.0.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
jinja2==3.0.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
lnurl==0.3.6 ; python_version >= "3.7" and python_version < "4.0"
|
||||
loguru==0.6.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
markupsafe==2.0.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
marshmallow==3.18.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
marshmallow==3.19.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
outcome==1.2.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
packaging==21.3 ; python_version >= "3.7" and python_version < "4.0"
|
||||
packaging==23.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pathlib2==2.3.7.post1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pluggy==1.0.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
protobuf==4.21.9 ; python_version >= "3.7" and python_version < "4.0"
|
||||
protobuf==4.21.12 ; python_version >= "3.7" and python_version < "4.0"
|
||||
psycopg2-binary==2.9.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
py==1.11.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pycparser==2.21 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pycryptodomex==3.14.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pydantic==1.10.2 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pycryptodomex==3.16.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pydantic==1.10.4 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pyln-bolt7==1.0.246 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pyln-client==0.11.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pyln-proto==0.11.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pyparsing==3.0.9 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pypng==0.0.21 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pyqrcode==1.2.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pyscss==1.4.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pysocks==1.7.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pytest-asyncio==0.19.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pytest==7.1.3 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pytest==7.2.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
python-bitcoinlib==0.11.2 ; python_version >= "3.7" and python_version < "4.0"
|
||||
python-dotenv==0.21.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
pyyaml==5.4.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
|
|
@ -62,7 +61,7 @@ requests==2.27.1 ; python_version >= "3.7" and python_version < "4.0"
|
|||
rfc3986==1.5.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
rfc3986[idna2008]==1.5.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
secp256k1==0.14.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
setuptools==65.6.3 ; python_version >= "3.7" and python_version < "4.0"
|
||||
setuptools==65.7.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
shortuuid==1.0.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
six==1.16.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
sniffio==1.3.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
|
|
@ -70,13 +69,14 @@ sqlalchemy-aio==0.17.0 ; python_version >= "3.7" and python_version < "4.0"
|
|||
sqlalchemy==1.3.24 ; python_version >= "3.7" and python_version < "4.0"
|
||||
sse-starlette==0.6.2 ; python_version >= "3.7" and python_version < "4.0"
|
||||
starlette==0.19.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
tomli==2.0.1 ; python_version >= "3.7" and python_version < "4.0"
|
||||
tomli==2.0.1 ; python_version >= "3.7" and python_version < "3.11"
|
||||
typing-extensions==4.4.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
urllib3==1.26.12 ; python_version >= "3.7" and python_version < "4"
|
||||
urllib3==1.26.14 ; python_version >= "3.7" and python_version < "4.0"
|
||||
uvicorn==0.18.3 ; python_version >= "3.7" and python_version < "4.0"
|
||||
uvloop==0.16.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
watchgod==0.7 ; python_version >= "3.7" and python_version < "4.0"
|
||||
websocket-client==1.3.3 ; python_version >= "3.7" and python_version < "4.0"
|
||||
websockets==10.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
wheel==0.38.4 ; python_version >= "3.7" and python_version < "4.0"
|
||||
win32-setctime==1.1.0 ; python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32"
|
||||
zipp==3.9.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
zipp==3.11.0 ; python_version >= "3.7" and python_version < "4.0"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue