diff --git a/.dockerignore b/.dockerignore index ebac296a..51cee13c 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,21 @@ .git -docs +data docker +docs +tests +venv +tools -# ignore all the markdown *.md +*.log + +.env + +.gitignore +.prettierrc +LICENSE +Makefile +mypy.ini +package-lock.json +package.json +pytest.ini diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index b6a0d721..00000000 --- a/.editorconfig +++ /dev/null @@ -1,16 +0,0 @@ -root = true - -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true -indent_size = 2 -indent_style = space - -[*.md] -trim_trailing_whitespace = false - -[*.py] -indent_size = 4 -indent_style = space diff --git a/.env.example b/.env.example index 4d2241e3..6ef60bc1 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,7 @@ HOST=127.0.0.1 PORT=5000 -DEBUG=true +DEBUG=false LNBITS_ALLOWED_USERS="" LNBITS_ADMIN_USERS="" diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index ad72b9d5..696d1aa2 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -custom: https://lnbits.com/paywall/GAqKguK5S8f6w5VNjS9DfK +custom: https://legend.lnbits.com/paywall/GAqKguK5S8f6w5VNjS9DfK diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml index 18c8d5d6..23d7ae3e 100644 --- a/.github/workflows/formatting.yml +++ b/.github/workflows/formatting.yml @@ -15,6 +15,16 @@ jobs: - run: python3 -m venv venv - run: ./venv/bin/pip install black - run: make checkblack + isort: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + - run: sudo apt-get install python3-venv + - run: python3 -m venv venv + - run: ./venv/bin/pip install isort + - run: make checkisort + prettier: runs-on: ubuntu-latest steps: @@ -23,4 +33,4 @@ jobs: - run: sudo apt-get install python3-venv - run: python3 -m venv venv - run: npm install prettier - - run: ./node_modules/.bin/prettier --check lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js \ No newline at end of file + - run: ./node_modules/.bin/prettier --check lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js diff --git a/.github/workflows/migrations.yml b/.github/workflows/migrations.yml new file mode 100644 index 00000000..45de9727 --- /dev/null +++ b/.github/workflows/migrations.yml @@ -0,0 +1,49 @@ +name: migrations + +on: [pull_request] + +jobs: + sqlite-to-postgres: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:latest + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: postgres + ports: + # maps tcp port 5432 on service container to the host + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + strategy: + matrix: + python-version: [3.8] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + env: + VIRTUAL_ENV: ./venv + PATH: ${{ env.VIRTUAL_ENV }}/bin:${{ env.PATH }} + run: | + python -m venv ${{ env.VIRTUAL_ENV }} + ./venv/bin/python -m pip install --upgrade pip + ./venv/bin/pip install -r requirements.txt + ./venv/bin/pip install pytest pytest-asyncio pytest-cov requests mock + - name: Run migrations + run: | + rm -rf ./data + mkdir -p ./data + export LNBITS_DATA_FOLDER="./data" + timeout 5s ./venv/bin/uvicorn lnbits.__main__:app --host 0.0.0.0 --port 5001 || code=$?; if [[ $code -ne 124 && $code -ne 0 ]]; then exit $code; fi + export LNBITS_DATABASE_URL="postgres://postgres:postgres@0.0.0.0:5432/postgres" + timeout 5s ./venv/bin/uvicorn lnbits.__main__:app --host 0.0.0.0 --port 5001 || code=$?; if [[ $code -ne 124 && $code -ne 0 ]]; then exit $code; fi + ./venv/bin/python tools/conv.py --dont-ignore-missing diff --git a/.github/workflows/regtest.yml b/.github/workflows/regtest.yml new file mode 100644 index 00000000..7883cf19 --- /dev/null +++ b/.github/workflows/regtest.yml @@ -0,0 +1,97 @@ +name: regtest + +on: [push, pull_request] + +jobs: + LndRestWallet: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.8] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Setup Regtest + run: | + docker build -t lnbits-legend . + git clone https://github.com/lnbits/legend-regtest-enviroment.git docker + cd docker + source docker-scripts.sh + lnbits-regtest-start + echo "sleeping 60 seconds" + sleep 60 + echo "continue" + lnbits-regtest-init + bitcoin-cli-sim -generate 1 + lncli-sim 1 listpeers + sudo chmod -R a+rwx . + - name: Install dependencies + env: + VIRTUAL_ENV: ./venv + PATH: ${{ env.VIRTUAL_ENV }}/bin:${{ env.PATH }} + run: | + python -m venv ${{ env.VIRTUAL_ENV }} + ./venv/bin/python -m pip install --upgrade pip + ./venv/bin/pip install -r requirements.txt + ./venv/bin/pip install pylightning + ./venv/bin/pip install pytest pytest-asyncio pytest-cov requests mock + - name: Run tests + env: + PYTHONUNBUFFERED: 1 + PORT: 5123 + LNBITS_DATA_FOLDER: ./data + LNBITS_BACKEND_WALLET_CLASS: LndRestWallet + LND_REST_ENDPOINT: https://localhost:8081/ + LND_REST_CERT: docker/data/lnd-1/tls.cert + LND_REST_MACAROON: docker/data/lnd-1/data/chain/bitcoin/regtest/admin.macaroon + run: | + sudo chmod -R a+rwx . && rm -rf ./data && mkdir -p ./data + make test-real-wallet + CLightningWallet: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.8] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Setup Regtest + run: | + docker build -t lnbits-legend . + git clone https://github.com/lnbits/legend-regtest-enviroment.git docker + cd docker + source docker-scripts.sh + lnbits-regtest-start + echo "sleeping 60 seconds" + sleep 60 + echo "continue" + lnbits-regtest-init + bitcoin-cli-sim -generate 1 + lncli-sim 1 listpeers + sudo chmod -R a+rwx . + - name: Install dependencies + env: + VIRTUAL_ENV: ./venv + PATH: ${{ env.VIRTUAL_ENV }}/bin:${{ env.PATH }} + run: | + python -m venv ${{ env.VIRTUAL_ENV }} + ./venv/bin/python -m pip install --upgrade pip + ./venv/bin/pip install -r requirements.txt + ./venv/bin/pip install pylightning + ./venv/bin/pip install pytest pytest-asyncio pytest-cov requests mock + - name: Run tests + env: + PYTHONUNBUFFERED: 1 + PORT: 5123 + LNBITS_DATA_FOLDER: ./data + LNBITS_BACKEND_WALLET_CLASS: CLightningWallet + CLIGHTNING_RPC: docker/data/clightning-1/regtest/lightning-rpc + run: | + sudo chmod -R a+rwx . && rm -rf ./data && mkdir -p ./data + make test-real-wallet \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2683b45e..218a557b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -3,19 +3,17 @@ name: tests on: [push, pull_request] jobs: - sqlite: + venv-sqlite: runs-on: ubuntu-latest strategy: matrix: - python-version: [3.7, 3.8] + python-version: [3.7, 3.8, 3.9] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - name: psycopg2 prerequisites - run: sudo apt-get install python-dev libpq-dev - name: Install dependencies env: VIRTUAL_ENV: ./venv @@ -27,7 +25,7 @@ jobs: ./venv/bin/pip install pytest pytest-asyncio pytest-cov requests mock - name: Run tests run: make test - postgres: + venv-postgres: runs-on: ubuntu-latest services: postgres: @@ -46,15 +44,13 @@ jobs: --health-retries 5 strategy: matrix: - python-version: [3.7, 3.8] + python-version: [3.8] steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - - name: psycopg2 prerequisites - run: sudo apt-get install python-dev libpq-dev - name: Install dependencies env: VIRTUAL_ENV: ./venv @@ -72,34 +68,21 @@ jobs: uses: codecov/codecov-action@v3 with: file: ./coverage.xml - # build: - # runs-on: ubuntu-latest - # strategy: - # matrix: - # python-version: [3.7, 3.8] - # steps: - # - uses: actions/checkout@v2 - # - name: Set up Python ${{ matrix.python-version }} - # uses: actions/setup-python@v1 - # with: - # python-version: ${{ matrix.python-version }} - # - name: Install dependencies - # run: | - # python -m pip install --upgrade pip - # pip install -r requirements.txt - # - name: Test with pytest - # env: - # LNBITS_BACKEND_WALLET_CLASS: LNPayWallet - # LNBITS_FORCE_HTTPS: 0 - # LNPAY_API_ENDPOINT: https://api.lnpay.co/v1/ - # LNPAY_API_KEY: sak_gG5pSFZhFgOLHm26a8hcWvXKt98yd - # LNPAY_ADMIN_KEY: waka_HqWfOoNE0TPqmQHSYErbF4n9 - # LNPAY_INVOICE_KEY: waki_ZqFEbhrTyopuPlOZButZUw - # LNPAY_READ_KEY: wakr_6IyTaNrvSeu3jbojSWt4ou6h - # run: | - # pip install pytest pytest-cov - # pytest --cov=lnbits --cov-report=xml - # - name: Upload coverage to Codecov - # uses: codecov/codecov-action@v1 - # with: - # file: ./coverage.xml + pipenv-sqlite: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.7, 3.8, 3.9] + steps: + - uses: actions/checkout@v2 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install pipenv + pipenv install --dev + pipenv install importlib-metadata + - name: Run tests + run: make test-pipenv \ No newline at end of file diff --git a/Makefile b/Makefile index 0ace3da0..5cc3f050 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ all: format check requirements.txt -format: prettier black +format: prettier isort black check: mypy checkprettier checkblack @@ -17,12 +17,18 @@ mypy: $(shell find lnbits -name "*.py") ./venv/bin/mypy lnbits/core ./venv/bin/mypy lnbits/extensions/* +isort: $(shell find lnbits -name "*.py") + ./venv/bin/isort --profile black lnbits + checkprettier: $(shell find lnbits -name "*.js" -name ".html") ./node_modules/.bin/prettier --check lnbits/static/js/*.js lnbits/core/static/js/*.js lnbits/extensions/*/templates/*/*.html ./lnbits/core/templates/core/*.html lnbits/templates/*.html lnbits/extensions/*/static/js/*.js checkblack: $(shell find lnbits -name "*.py") ./venv/bin/black --check lnbits +checkisort: $(shell find lnbits -name "*.py") + ./venv/bin/isort --profile black --check-only lnbits + Pipfile.lock: Pipfile ./venv/bin/pipenv lock @@ -32,10 +38,27 @@ requirements.txt: Pipfile.lock test: rm -rf ./tests/data mkdir -p ./tests/data + LNBITS_BACKEND_WALLET_CLASS="FakeWallet" \ FAKE_WALLET_SECRET="ToTheMoon1" \ LNBITS_DATA_FOLDER="./tests/data" \ PYTHONUNBUFFERED=1 \ - ./venv/bin/pytest --durations=1 -s --cov=lnbits --cov-report=xml + ./venv/bin/pytest --durations=1 -s --cov=lnbits --cov-report=xml tests + +test-real-wallet: + rm -rf ./tests/data + mkdir -p ./tests/data + LNBITS_DATA_FOLDER="./tests/data" \ + PYTHONUNBUFFERED=1 \ + ./venv/bin/pytest --durations=1 -s --cov=lnbits --cov-report=xml tests + +test-pipenv: + rm -rf ./tests/data + mkdir -p ./tests/data + LNBITS_BACKEND_WALLET_CLASS="FakeWallet" \ + FAKE_WALLET_SECRET="ToTheMoon1" \ + LNBITS_DATA_FOLDER="./tests/data" \ + PYTHONUNBUFFERED=1 \ + pipenv run pytest --durations=1 -s --cov=lnbits --cov-report=xml tests bak: # LNBITS_DATABASE_URL=postgres://postgres:postgres@0.0.0.0:5432/postgres diff --git a/Pipfile b/Pipfile index 7d676984..f8c42a9d 100644 --- a/Pipfile +++ b/Pipfile @@ -4,7 +4,7 @@ url = "https://pypi.org/simple" verify_ssl = true [requires] -python_version = "3.7" +python_version = "3.8" [packages] bitstring = "*" @@ -28,13 +28,17 @@ asyncio = "*" fastapi = "*" uvicorn = {extras = ["standard"], version = "*"} sse-starlette = "*" -jinja2 = "3.0.1" +jinja2 = "==3.0.1" pyngrok = "*" -secp256k1 = "*" +secp256k1 = "==0.14.0" +cffi = "==1.15.0" pycryptodomex = "*" [dev-packages] black = "==20.8b1" pytest = "*" pytest-cov = "*" -mypy = "latest" +mypy = "*" +pytest-asyncio = "*" +requests = "*" +mock = "*" diff --git a/Pipfile.lock b/Pipfile.lock index e77de500..42d471c6 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "3e19364434fd2db3748162ccc1f3b6bddcf7a382473069d15cee6eda5e07eef1" + "sha256": "503e9942306106e40621c59f37a3ab866b483f8c5f27b879c1c6783dca30949f" }, "pipfile-spec": 6, "requires": { - "python_version": "3.7" + "python_version": "3.8" }, "sources": [ { @@ -26,19 +26,10 @@ }, "anyio": { "hashes": [ - "sha256:a0aeffe2fb1fdf374a8e4b471444f0f3ac4fb9f5a5b542b48824475e0042a5a6", - "sha256:b5fa16c5ff93fa1046f2eeb5bbff2dad4d3514d6cda61d02816dba34fa8c3c2e" + "sha256:413adf95f93886e442aea925f3ee43baa5a765a64a0f52c6081894f9992fdd0b", + "sha256:cb29b9c70620506a9a8f87a309591713446953302d7d995344d0d7c6c0c9a7be" ], - "markers": "python_full_version >= '3.6.2'", - "version": "==3.5.0" - }, - "asgiref": { - "hashes": [ - "sha256:2f8abc20f7248433085eda803936d98992f1343ddb022065779f37c5da0181d0", - "sha256:88d59c13d634dcffe0510be048210188edd79aeccb6a6c9028cdad6f31d730a9" - ], - "markers": "python_version >= '3.7'", - "version": "==3.5.0" + "version": "==3.6.1" }, "asyncio": { "hashes": [ @@ -55,7 +46,6 @@ "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==21.4.0" }, "bech32": { @@ -63,7 +53,6 @@ "sha256:7d6db8214603bd7871fcfa6c0826ef68b85b0abd90fa21c285a9c5e21d2bd899", "sha256:990dc8e5a5e4feabbdf55207b5315fdd9b73db40be294a19b3752cde9e79d981" ], - "markers": "python_version >= '3.5'", "version": "==1.2.0" }, "bitstring": { @@ -84,10 +73,10 @@ }, "certifi": { "hashes": [ - "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872", - "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569" + "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d", + "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412" ], - "version": "==2021.10.8" + "version": "==2022.6.15" }, "cffi": { "hashes": [ @@ -142,38 +131,30 @@ "sha256:fd8a250edc26254fe5b33be00402e6d287f562b6a5b2152dec302fa15bb3e997", "sha256:ffaa5c925128e29efbde7301d8ecaf35c8c60ffbcd6a1ffd3a552177c8e5e796" ], + "index": "pypi", "version": "==1.15.0" }, - "charset-normalizer": { - "hashes": [ - "sha256:2857e29ff0d34db842cd7ca3230549d1a697f96ee6d3fb071cfa6c7393832597", - "sha256:6881edbebdb17b39b4eaaa821b438bf6eddffb4468cf344f09f89def34a8b1df" - ], - "markers": "python_version >= '3.5'", - "version": "==2.0.12" - }, "click": { "hashes": [ - "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3", - "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b" + "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", + "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" ], - "markers": "python_version >= '3.6'", - "version": "==8.0.3" + "version": "==8.1.3" }, "ecdsa": { "hashes": [ - "sha256:5cf31d5b33743abe0dfc28999036c849a69d548f994b535e527ee3cb7f3ef676", - "sha256:b9f500bb439e4153d0330610f5d26baaf18d17b8ced1bc54410d189385ea68aa" + "sha256:190348041559e21b22a1d65cee485282ca11a6f81d503fddb84d5017e9ed1e49", + "sha256:80600258e7ed2f16b9aa1d7c295bd70194109ad5a30fdee0eaeefef1d4c559dd" ], "index": "pypi", - "version": "==0.17.0" + "version": "==0.18.0" }, "embit": { "hashes": [ - "sha256:d340107dc1604581df59f844d4eb76ec34b0219c2ac2cbc1837c14938a4730ee" + "sha256:5644ae6ed07bb71bf7fb15daf7f5af73d889180e623f5ff1f35a20ad01f0405e" ], "index": "pypi", - "version": "==0.4.12" + "version": "==0.5.0" }, "environs": { "hashes": [ @@ -185,64 +166,72 @@ }, "fastapi": { "hashes": [ - "sha256:dcfee92a7f9a72b5d4b7ca364bd2b009f8fc10d95ed5769be20e94f39f7e5a15", - "sha256:f0a618aff5f6942862f2d3f20f39b1c037e33314d1b8207fd1c3a2cca76dfd8c" + "sha256:cf0ff6db25b91d321050c4112baab0908c90f19b40bf257f9591d2f9780d1f22", + "sha256:d337563424ceada23857f73d5abe8dae0c28e4cccb53b2af06e78b7bb4a1c7d7" ], "index": "pypi", - "version": "==0.73.0" + "version": "==0.79.0" }, "h11": { "hashes": [ "sha256:36a3cb8c0a032f56e2da7084577878a035d3b61d104230d4bd49c0c6b555a9c6", "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042" ], - "markers": "python_version >= '3.6'", "version": "==0.12.0" }, "httpcore": { "hashes": [ - "sha256:47d772f754359e56dd9d892d9593b6f9870a37aeb8ba51e9a88b09b3d68cfade", - "sha256:7503ec1c0f559066e7e39bc4003fd2ce023d01cf51793e3c173b864eb456ead1" + "sha256:1105b8b73c025f23ff7c36468e4432226cbb959176eab66864b8e31c4ee27fa6", + "sha256:18b68ab86a3ccf3e7dc0f43598eaddcf472b602aba29f9aa6ab85fe2ada3980b" ], - "markers": "python_version >= '3.6'", - "version": "==0.14.7" + "version": "==0.15.0" }, "httptools": { "hashes": [ - "sha256:04114db99605c9b56ea22a8ec4d7b1485b908128ed4f4a8f6438489c428da794", - "sha256:074afd8afdeec0fa6786cd4a1676e0c0be23dc9a017a86647efa6b695168104f", - "sha256:113816f9af7dcfc4aa71ebb5354d77365f666ecf96ac7ff2aa1d24b6bca44165", - "sha256:1a8f26327023fa1a947d36e60a0582149e182fbbc949c8a65ec8665754dbbe69", - "sha256:2119fa619a4c53311f594f25c0205d619350fcb32140ec5057f861952e9b2b4f", - "sha256:21e948034f70e47c8abfa2d5e6f1a5661f87a2cddc7bcc70f61579cc87897c70", - "sha256:32a10a5903b5bc0eb647d01cd1e95bec3bb614a9bf53f0af1e01360b2debdf81", - "sha256:3787c1f46e9722ef7f07ea5c76b0103037483d1b12e34a02c53ceca5afa4e09a", - "sha256:3f82eb106e1474c63dba36a176067e65b48385f4cecddf3616411aa5d1fbdfec", - "sha256:3f9b4856d46ba1f0c850f4e84b264a9a8b4460acb20e865ec00978ad9fbaa4cf", - "sha256:4137137de8976511a392e27bfdcf231bd926ac13d375e0414e927b08217d779e", - "sha256:4687dfc116a9f1eb22a7d797f0dc6f6e17190d406ca4e729634b38aa98044b17", - "sha256:47dba2345aaa01b87e4981e8756af441349340708d5b60712c98c55a4d28f4af", - "sha256:5a836bd85ae1fb4304f674808488dae403e136d274aa5bafd0e6ee456f11c371", - "sha256:6e676bc3bb911b11f3d7e2144b9a53600bf6b9b21e0e4437aa308e1eef094d97", - "sha256:72ee0e3fb9c6437ab3ae34e9abee67fcee6876f4f58504e3f613dd5882aafdb7", - "sha256:79717080dc3f8b1eeb7f820b9b81528acbc04be6041f323fdd97550da2062575", - "sha256:8ac842df4fc3952efa7820b277961ea55e068bbc54cb59a0820400de7ae358d8", - "sha256:9f475b642c48b1b78584bdd12a5143e2c512485664331eade9c29ef769a17598", - "sha256:b8ac7dee63af4346e02b1e6d32202e3b5b3706a9928bec6da6d7a5b066217422", - "sha256:c0ac2e0ce6733c55858932e7d37fcc7b67ba6bb23e9648593c55f663de031b93", - "sha256:c14576b737d9e6e4f2a86af04918dbe9b62f57ce8102a8695c9a382dbe405c7f", - "sha256:cdc3975db86c29817e6d13df14e037c931fc893a710fb71097777a4147090068", - "sha256:eda95634027200f4b2a6d499e7c2e7fa9b8ee57e045dfda26958ea0af27c070b" + "sha256:1a99346ebcb801b213c591540837340bdf6fd060a8687518d01c607d338b7424", + "sha256:1ee0b459257e222b878a6c09ccf233957d3a4dcb883b0847640af98d2d9aac23", + "sha256:20a45bcf22452a10fa8d58b7dbdb474381f6946bf5b8933e3662d572bc61bae4", + "sha256:29bf97a5c532da9c7a04de2c7a9c31d1d54f3abd65a464119b680206bbbb1055", + "sha256:2c9a930c378b3d15d6b695fb95ebcff81a7395b4f9775c4f10a076beb0b2c1ff", + "sha256:2db44a0b294d317199e9f80123e72c6b005c55b625b57fae36de68670090fa48", + "sha256:3194f6d6443befa8d4db16c1946b2fc428a3ceb8ab32eb6f09a59f86104dc1a0", + "sha256:34d2903dd2a3dd85d33705b6fde40bf91fc44411661283763fd0746723963c83", + "sha256:48e48530d9b995a84d1d89ae6b3ec4e59ea7d494b150ac3bbc5e2ac4acce92cd", + "sha256:54bbd295f031b866b9799dd39cb45deee81aca036c9bff9f58ca06726f6494f1", + "sha256:5d1fe6b6661022fd6cac541f54a4237496b246e6f1c0a6b41998ee08a1135afe", + "sha256:645373c070080e632480a3d251d892cb795be3d3a15f86975d0f1aca56fd230d", + "sha256:6a1a7dfc1f9c78a833e2c4904757a0f47ce25d08634dd2a52af394eefe5f9777", + "sha256:701e66b59dd21a32a274771238025d58db7e2b6ecebbab64ceff51b8e31527ae", + "sha256:72aa3fbe636b16d22e04b5a9d24711b043495e0ecfe58080addf23a1a37f3409", + "sha256:7af6bdbd21a2a25d6784f6d67f44f5df33ef39b6159543b9f9064d365c01f919", + "sha256:7ee9f226acab9085037582c059d66769862706e8e8cd2340470ceb8b3850873d", + "sha256:7f7bfb74718f52d5ed47d608d507bf66d3bc01d4a8b3e6dd7134daaae129357b", + "sha256:8e2eb957787cbb614a0f006bfc5798ff1d90ac7c4dd24854c84edbdc8c02369e", + "sha256:903f739c9fb78dab8970b0f3ea51f21955b24b45afa77b22ff0e172fc11ef111", + "sha256:98993805f1e3cdb53de4eed02b55dcc953cdf017ba7bbb2fd89226c086a6d855", + "sha256:9967d9758df505975913304c434cb9ab21e2c609ad859eb921f2f615a038c8de", + "sha256:a113789e53ac1fa26edf99856a61e4c493868e125ae0dd6354cf518948fbbd5c", + "sha256:a522d12e2ddbc2e91842ffb454a1aeb0d47607972c7d8fc88bd0838d97fb8a2a", + "sha256:abe829275cdd4174b4c4e65ad718715d449e308d59793bf3a931ee1bf7e7b86c", + "sha256:c286985b5e194ca0ebb2908d71464b9be8f17cc66d6d3e330e8d5407248f56ad", + "sha256:cd1295f52971097f757edfbfce827b6dbbfb0f7a74901ee7d4933dff5ad4c9af", + "sha256:ceafd5e960b39c7e0d160a1936b68eb87c5e79b3979d66e774f0c77d4d8faaed", + "sha256:d1f27bb0f75bef722d6e22dc609612bfa2f994541621cd2163f8c943b6463dfe", + "sha256:d3a4e165ca6204f34856b765d515d558dc84f1352033b8721e8d06c3e44930c3", + "sha256:d9b90bf58f3ba04e60321a23a8723a1ff2a9377502535e70495e5ada8e6e6722", + "sha256:f72b5d24d6730035128b238decdc4c0f2104b7056a7ca55cf047c106842ec890", + "sha256:fcddfe70553be717d9745990dfdb194e22ee0f60eb8f48c0794e7bfeda30d2d5", + "sha256:fdb9f9ed79bc6f46b021b3319184699ba1a22410a82204e6e89c774530069683" ], - "version": "==0.3.0" + "version": "==0.4.0" }, "httpx": { "hashes": [ - "sha256:d8e778f76d9bbd46af49e7f062467e3157a5a3d2ae4876a4bbfd8a51ed9c9cb4", - "sha256:e35e83d1d2b9b2a609ef367cc4c1e66fd80b750348b20cc9e19d1952fc2ca3f6" + "sha256:42974f577483e1e932c3cdc3cd2303e883cbfba17fe228b0f63589764d7b9c4b", + "sha256:f28eac771ec9eb4866d3fb4ab65abd42d38c424739e80c08d8d20570de60b0ef" ], "index": "pypi", - "version": "==0.22.0" + "version": "==0.23.0" }, "idna": { "hashes": [ @@ -253,11 +242,11 @@ }, "jinja2": { "hashes": [ - "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8", - "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7" + "sha256:1f06f2da51e7b56b8f238affdd6b4e2c61e39598a378cc49345bc1bd42a978a4", + "sha256:703f484b47a6af502e743c9122595cc812b0271f661722403114f71a79d0f5a4" ], "index": "pypi", - "version": "==3.0.3" + "version": "==3.0.1" }, "lnurl": { "hashes": [ @@ -267,96 +256,79 @@ "index": "pypi", "version": "==0.3.6" }, + "loguru": { + "hashes": [ + "sha256:066bd06758d0a513e9836fd9c6b5a75bfb3fd36841f4b996bc60b547a309d41c", + "sha256:4e2414d534a2ab57573365b3e6d0234dfb1d84b68b7f3b948e6fb743860a77c3" + ], + "index": "pypi", + "version": "==0.6.0" + }, "markupsafe": { "hashes": [ - "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298", - "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64", - "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b", - "sha256:04635854b943835a6ea959e948d19dcd311762c5c0c6e1f0e16ee57022669194", - "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567", - "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff", - "sha256:0d4b31cc67ab36e3392bbf3862cfbadac3db12bdd8b02a2731f509ed5b829724", - "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74", - "sha256:168cd0a3642de83558a5153c8bd34f175a9a6e7f6dc6384b9655d2697312a646", - "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35", - "sha256:1f2ade76b9903f39aa442b4aadd2177decb66525062db244b35d71d0ee8599b6", - "sha256:20dca64a3ef2d6e4d5d615a3fd418ad3bde77a47ec8a23d984a12b5b4c74491a", - "sha256:2a7d351cbd8cfeb19ca00de495e224dea7e7d919659c2841bbb7f420ad03e2d6", - "sha256:2d7d807855b419fc2ed3e631034685db6079889a1f01d5d9dac950f764da3dad", - "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26", - "sha256:36bc903cbb393720fad60fc28c10de6acf10dc6cc883f3e24ee4012371399a38", - "sha256:37205cac2a79194e3750b0af2a5720d95f786a55ce7df90c3af697bfa100eaac", - "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7", - "sha256:3dd007d54ee88b46be476e293f48c85048603f5f516008bee124ddd891398ed6", - "sha256:4296f2b1ce8c86a6aea78613c34bb1a672ea0e3de9c6ba08a960efe0b0a09047", - "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75", - "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f", - "sha256:4dc8f9fb58f7364b63fd9f85013b780ef83c11857ae79f2feda41e270468dd9b", - "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135", - "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8", - "sha256:5855f8438a7d1d458206a2466bf82b0f104a3724bf96a1c781ab731e4201731a", - "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a", - "sha256:5b6d930f030f8ed98e3e6c98ffa0652bdb82601e7a016ec2ab5d7ff23baa78d1", - "sha256:5bb28c636d87e840583ee3adeb78172efc47c8b26127267f54a9c0ec251d41a9", - "sha256:60bf42e36abfaf9aff1f50f52644b336d4f0a3fd6d8a60ca0d054ac9f713a864", - "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914", - "sha256:6300b8454aa6930a24b9618fbb54b5a68135092bc666f7b06901f897fa5c2fee", - "sha256:63f3268ba69ace99cab4e3e3b5840b03340efed0948ab8f78d2fd87ee5442a4f", - "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18", - "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8", - "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2", - "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d", - "sha256:6fcf051089389abe060c9cd7caa212c707e58153afa2c649f00346ce6d260f1b", - "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b", - "sha256:89c687013cb1cd489a0f0ac24febe8c7a666e6e221b783e53ac50ebf68e45d86", - "sha256:8d206346619592c6200148b01a2142798c989edcb9c896f9ac9722a99d4e77e6", - "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f", - "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb", - "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833", - "sha256:99df47edb6bda1249d3e80fdabb1dab8c08ef3975f69aed437cb69d0a5de1e28", - "sha256:9f02365d4e99430a12647f09b6cc8bab61a6564363f313126f775eb4f6ef798e", - "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415", - "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902", - "sha256:aca6377c0cb8a8253e493c6b451565ac77e98c2951c45f913e0b52facdcff83f", - "sha256:add36cb2dbb8b736611303cd3bfcee00afd96471b09cda130da3581cbdc56a6d", - "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9", - "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d", - "sha256:baa1a4e8f868845af802979fcdbf0bb11f94f1cb7ced4c4b8a351bb60d108145", - "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066", - "sha256:bf5d821ffabf0ef3533c39c518f3357b171a1651c1ff6827325e4489b0e46c3c", - "sha256:c47adbc92fc1bb2b3274c4b3a43ae0e4573d9fbff4f54cd484555edbf030baf1", - "sha256:cdfba22ea2f0029c9261a4bd07e830a8da012291fbe44dc794e488b6c9bb353a", - "sha256:d6c7ebd4e944c85e2c3421e612a7057a2f48d478d79e61800d81468a8d842207", - "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f", - "sha256:d8446c54dc28c01e5a2dbac5a25f071f6653e6e40f3a8818e8b45d790fe6ef53", - "sha256:deb993cacb280823246a026e3b2d81c493c53de6acfd5e6bfe31ab3402bb37dd", - "sha256:e0f138900af21926a02425cf736db95be9f4af72ba1bb21453432a07f6082134", - "sha256:e9936f0b261d4df76ad22f8fee3ae83b60d7c3e871292cd42f40b81b70afae85", - "sha256:f0567c4dc99f264f49fe27da5f735f414c4e7e7dd850cfd8e69f0862d7c74ea9", - "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5", - "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94", - "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509", - "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51", - "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872" + "sha256:0212a68688482dc52b2d45013df70d169f542b7394fc744c02a57374a4207003", + "sha256:089cf3dbf0cd6c100f02945abeb18484bd1ee57a079aefd52cffd17fba910b88", + "sha256:10c1bfff05d95783da83491be968e8fe789263689c02724e0c691933c52994f5", + "sha256:33b74d289bd2f5e527beadcaa3f401e0df0a89927c1559c8566c066fa4248ab7", + "sha256:3799351e2336dc91ea70b034983ee71cf2f9533cdff7c14c90ea126bfd95d65a", + "sha256:3ce11ee3f23f79dbd06fb3d63e2f6af7b12db1d46932fe7bd8afa259a5996603", + "sha256:421be9fbf0ffe9ffd7a378aafebbf6f4602d564d34be190fc19a193232fd12b1", + "sha256:43093fb83d8343aac0b1baa75516da6092f58f41200907ef92448ecab8825135", + "sha256:46d00d6cfecdde84d40e572d63735ef81423ad31184100411e6e3388d405e247", + "sha256:4a33dea2b688b3190ee12bd7cfa29d39c9ed176bda40bfa11099a3ce5d3a7ac6", + "sha256:4b9fe39a2ccc108a4accc2676e77da025ce383c108593d65cc909add5c3bd601", + "sha256:56442863ed2b06d19c37f94d999035e15ee982988920e12a5b4ba29b62ad1f77", + "sha256:671cd1187ed5e62818414afe79ed29da836dde67166a9fac6d435873c44fdd02", + "sha256:694deca8d702d5db21ec83983ce0bb4b26a578e71fbdbd4fdcd387daa90e4d5e", + "sha256:6a074d34ee7a5ce3effbc526b7083ec9731bb3cbf921bbe1d3005d4d2bdb3a63", + "sha256:6d0072fea50feec76a4c418096652f2c3238eaa014b2f94aeb1d56a66b41403f", + "sha256:6fbf47b5d3728c6aea2abb0589b5d30459e369baa772e0f37a0320185e87c980", + "sha256:7f91197cc9e48f989d12e4e6fbc46495c446636dfc81b9ccf50bb0ec74b91d4b", + "sha256:86b1f75c4e7c2ac2ccdaec2b9022845dbb81880ca318bb7a0a01fbf7813e3812", + "sha256:8dc1c72a69aa7e082593c4a203dcf94ddb74bb5c8a731e4e1eb68d031e8498ff", + "sha256:8e3dcf21f367459434c18e71b2a9532d96547aef8a871872a5bd69a715c15f96", + "sha256:8e576a51ad59e4bfaac456023a78f6b5e6e7651dcd383bcc3e18d06f9b55d6d1", + "sha256:96e37a3dc86e80bf81758c152fe66dbf60ed5eca3d26305edf01892257049925", + "sha256:97a68e6ada378df82bc9f16b800ab77cbf4b2fada0081794318520138c088e4a", + "sha256:99a2a507ed3ac881b975a2976d59f38c19386d128e7a9a18b7df6fff1fd4c1d6", + "sha256:a49907dd8420c5685cfa064a1335b6754b74541bbb3706c259c02ed65b644b3e", + "sha256:b09bf97215625a311f669476f44b8b318b075847b49316d3e28c08e41a7a573f", + "sha256:b7bd98b796e2b6553da7225aeb61f447f80a1ca64f41d83612e6139ca5213aa4", + "sha256:b87db4360013327109564f0e591bd2a3b318547bcef31b468a92ee504d07ae4f", + "sha256:bcb3ed405ed3222f9904899563d6fc492ff75cce56cba05e32eff40e6acbeaa3", + "sha256:d4306c36ca495956b6d568d276ac11fdd9c30a36f1b6eb928070dc5360b22e1c", + "sha256:d5ee4f386140395a2c818d149221149c54849dfcfcb9f1debfe07a8b8bd63f9a", + "sha256:dda30ba7e87fbbb7eab1ec9f58678558fd9a6b8b853530e176eabd064da81417", + "sha256:e04e26803c9c3851c931eac40c695602c6295b8d432cbe78609649ad9bd2da8a", + "sha256:e1c0b87e09fa55a220f058d1d49d3fb8df88fbfab58558f1198e08c1e1de842a", + "sha256:e72591e9ecd94d7feb70c1cbd7be7b3ebea3f548870aa91e2732960fa4d57a37", + "sha256:e8c843bbcda3a2f1e3c2ab25913c80a3c5376cd00c6e8c4a86a89a28c8dc5452", + "sha256:efc1913fd2ca4f334418481c7e595c00aad186563bbc1ec76067848c7ca0a933", + "sha256:f121a1420d4e173a5d96e47e9a0c0dcff965afdf1626d28de1460815f7c4ee7a", + "sha256:fc7b548b17d238737688817ab67deebb30e8073c95749d55538ed473130ec0c7" ], - "markers": "python_version >= '3.6'", - "version": "==2.0.1" + "version": "==2.1.1" }, "marshmallow": { "hashes": [ - "sha256:04438610bc6dadbdddb22a4a55bcc7f6f8099e69580b2e67f5a681933a1f4400", - "sha256:4c05c1684e0e97fe779c62b91878f173b937fe097b356cd82f793464f5bc6138" + "sha256:00040ab5ea0c608e8787137627a8efae97fabd60552a05dc889c888f814e75eb", + "sha256:635fb65a3285a31a30f276f30e958070f5214c7196202caa5c7ecf28f5274bc7" ], - "markers": "python_version >= '3.6'", - "version": "==3.14.1" + "version": "==3.17.0" }, "outcome": { "hashes": [ - "sha256:c7dd9375cfd3c12db9801d080a3b63d4b0a261aa996c4c13152380587288d958", - "sha256:e862f01d4e626e63e8f92c38d1f8d5546d3f9cce989263c521b2e7990d186967" + "sha256:6f82bd3de45da303cf1f771ecafa1633750a358436a8bb60e06a1ceb745d2672", + "sha256:c4ab89a56575d6d38a05aa16daeaa333109c1f96167aba8901ab18b6b5e0f7f5" ], - "markers": "python_version >= '3.6'", - "version": "==1.1.0" + "version": "==1.2.0" + }, + "packaging": { + "hashes": [ + "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", + "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" + ], + "version": "==21.3" }, "psycopg2-binary": { "hashes": [ @@ -429,77 +401,79 @@ }, "pycryptodomex": { "hashes": [ - "sha256:1ca8e1b4c62038bb2da55451385246f51f412c5f5eabd64812c01766a5989b4a", - "sha256:298c00ea41a81a491d5b244d295d18369e5aac4b61b77b2de5b249ca61cd6659", - "sha256:2aa887683eee493e015545bd69d3d21ac8d5ad582674ec98f4af84511e353e45", - "sha256:2ce76ed0081fd6ac8c74edc75b9d14eca2064173af79843c24fa62573263c1f2", - "sha256:3da13c2535b7aea94cc2a6d1b1b37746814c74b6e80790daddd55ca5c120a489", - "sha256:406ec8cfe0c098fadb18d597dc2ee6de4428d640c0ccafa453f3d9b2e58d29e2", - "sha256:4d0db8df9ffae36f416897ad184608d9d7a8c2b46c4612c6bc759b26c073f750", - "sha256:530756d2faa40af4c1f74123e1d889bd07feae45bac2fd32f259a35f7aa74151", - "sha256:77931df40bb5ce5e13f4de2bfc982b2ddc0198971fbd947776c8bb5050896eb2", - "sha256:797a36bd1f69df9e2798e33edb4bd04e5a30478efc08f9428c087f17f65a7045", - "sha256:8085bd0ad2034352eee4d4f3e2da985c2749cb7344b939f4d95ead38c2520859", - "sha256:8536bc08d130cae6dcba1ea689f2913dfd332d06113904d171f2f56da6228e89", - "sha256:a4d412eba5679ede84b41dbe48b1bed8f33131ab9db06c238a235334733acc5e", - "sha256:aebecde2adc4a6847094d3bd6a8a9538ef3438a5ea84ac1983fcb167db614461", - "sha256:b276cc4deb4a80f9dfd47a41ebb464b1fe91efd8b1b8620cf5ccf8b824b850d6", - "sha256:b5a185ae79f899b01ca49f365bdf15a45d78d9856f09b0de1a41b92afce1a07f", - "sha256:c4d8977ccda886d88dc3ca789de2f1adc714df912ff3934b3d0a3f3d777deafb", - "sha256:c5dd3ffa663c982d7f1be9eb494a8924f6d40e2e2f7d1d27384cfab1b2ac0662", - "sha256:ca88f2f7020002638276439a01ffbb0355634907d1aa5ca91f3dc0c2e44e8f3b", - "sha256:d2cce1c82a7845d7e2e8a0956c6b7ed3f1661c9acf18eb120fc71e098ab5c6fe", - "sha256:d709572d64825d8d59ea112e11cc7faf6007f294e9951324b7574af4251e4de8", - "sha256:da8db8374295fb532b4b0c467e66800ef17d100e4d5faa2bbbd6df35502da125", - "sha256:e36c7e3b5382cd5669cf199c4a04a0279a43b2a3bdd77627e9b89778ac9ec08c", - "sha256:e95a4a6c54d27a84a4624d2af8bb9ee178111604653194ca6880c98dcad92f48", - "sha256:ee835def05622e0c8b1435a906491760a43d0c462f065ec9143ec4b8d79f8bff", - "sha256:f75009715dcf4a3d680c2338ab19dac5498f8121173a929872950f4fb3a48fbf", - "sha256:f8524b8bc89470cec7ac51734907818d3620fb1637f8f8b542d650ebec42a126" + "sha256:04cc393045a8f19dd110c975e30f38ed7ab3faf21ede415ea67afebd95a22380", + "sha256:0776bfaf2c48154ab54ea45392847c1283d2fcf64e232e85565f858baedfc1fa", + "sha256:0fadb9f7fa3150577800eef35f62a8a24b9ddf1563ff060d9bd3af22d3952c8c", + "sha256:18e2ab4813883ae63396c0ffe50b13554b32bb69ec56f0afaf052e7a7ae0d55b", + "sha256:191e73bc84a8064ad1874dba0ebadedd7cce4dedee998549518f2c74a003b2e1", + "sha256:35a8f7afe1867118330e2e0e0bf759c409e28557fb1fc2fbb1c6c937297dbe9a", + "sha256:3709f13ca3852b0b07fc04a2c03b379189232b24007c466be0f605dd4723e9d4", + "sha256:4540904c09704b6f831059c0dfb38584acb82cb97b0125cd52688c1f1e3fffa6", + "sha256:463119d7d22d0fc04a0f9122e9d3e6121c6648bcb12a052b51bd1eed1b996aa2", + "sha256:46b3f05f2f7ac7841053da4e0f69616929ca3c42f238c405f6c3df7759ad2780", + "sha256:48697790203909fab02a33226fda546604f4e2653f9d47bc5d3eb40879fa7c64", + "sha256:5676a132169a1c1a3712edf25250722ebc8c9102aa9abd814df063ca8362454f", + "sha256:65204412d0c6a8e3c41e21e93a5e6054a74fea501afa03046a388cf042e3377a", + "sha256:67e1e6a92151023ccdfcfbc0afb3314ad30080793b4c27956ea06ab1fb9bcd8a", + "sha256:6f5b6ba8aefd624834bc177a2ac292734996bb030f9d1b388e7504103b6fcddf", + "sha256:7341f1bb2dadb0d1a0047f34c3a58208a92423cdbd3244d998e4b28df5eac0ed", + "sha256:78d9621cf0ea35abf2d38fa2ca6d0634eab6c991a78373498ab149953787e5e5", + "sha256:8eecdf9cdc7343001d047f951b9cc805cd68cb6cd77b20ea46af5bffc5bd3dfb", + "sha256:94c7b60e1f52e1a87715571327baea0733708ab4723346598beca4a3b6879794", + "sha256:996e1ba717077ce1e6d4849af7a1426f38b07b3d173b879e27d5e26d2e958beb", + "sha256:a07a64709e366c2041cd5cfbca592b43998bf4df88f7b0ca73dca37071ccf1bd", + "sha256:b6306403228edde6e289f626a3908a2f7f67c344e712cf7c0a508bab3ad9e381", + "sha256:b9279adc16e4b0f590ceff581f53a80179b02cba9056010d733eb4196134a870", + "sha256:c4cb9cb492ea7dcdf222a8d19a1d09002798ea516aeae8877245206d27326d86", + "sha256:dd452a5af7014e866206d41751886c9b4bf379a339fdf2dbfc7dd16c0fb4f8e0", + "sha256:e2b12968522a0358b8917fc7b28865acac002f02f4c4c6020fcb264d76bfd06d", + "sha256:e3164a18348bd53c69b4435ebfb4ac8a4076291ffa2a70b54f0c4b80c7834b1d", + "sha256:e47bf8776a7e15576887f04314f5228c6527b99946e6638cf2f16da56d260cab", + "sha256:f8be976cec59b11f011f790b88aca67b4ea2bd286578d0bd3e31bcd19afcd3e4", + "sha256:fc9bc7a9b79fe5c750fc81a307052f8daabb709bdaabb0fb18fb136b66b653b5" ], "index": "pypi", - "version": "==3.14.1" + "version": "==3.15.0" }, "pydantic": { "hashes": [ - "sha256:085ca1de245782e9b46cefcf99deecc67d418737a1fd3f6a4f511344b613a5b3", - "sha256:086254884d10d3ba16da0588604ffdc5aab3f7f09557b998373e885c690dd398", - "sha256:0b6037175234850ffd094ca77bf60fb54b08b5b22bc85865331dd3bda7a02fa1", - "sha256:0fe476769acaa7fcddd17cadd172b156b53546ec3614a4d880e5d29ea5fbce65", - "sha256:1d5278bd9f0eee04a44c712982343103bba63507480bfd2fc2790fa70cd64cf4", - "sha256:2cc6a4cb8a118ffec2ca5fcb47afbacb4f16d0ab8b7350ddea5e8ef7bcc53a16", - "sha256:2ee7e3209db1e468341ef41fe263eb655f67f5c5a76c924044314e139a1103a2", - "sha256:3011b975c973819883842c5ab925a4e4298dffccf7782c55ec3580ed17dc464c", - "sha256:3c3b035103bd4e2e4a28da9da7ef2fa47b00ee4a9cf4f1a735214c1bcd05e0f6", - "sha256:4c68c3bc88dbda2a6805e9a142ce84782d3930f8fdd9655430d8576315ad97ce", - "sha256:574936363cd4b9eed8acdd6b80d0143162f2eb654d96cb3a8ee91d3e64bf4cf9", - "sha256:5a79330f8571faf71bf93667d3ee054609816f10a259a109a0738dac983b23c3", - "sha256:5e48ef4a8b8c066c4a31409d91d7ca372a774d0212da2787c0d32f8045b1e034", - "sha256:6c5b77947b9e85a54848343928b597b4f74fc364b70926b3c4441ff52620640c", - "sha256:742645059757a56ecd886faf4ed2441b9c0cd406079c2b4bee51bcc3fbcd510a", - "sha256:7bdfdadb5994b44bd5579cfa7c9b0e1b0e540c952d56f627eb227851cda9db77", - "sha256:815ddebb2792efd4bba5488bc8fde09c29e8ca3227d27cf1c6990fc830fd292b", - "sha256:8b5ac0f1c83d31b324e57a273da59197c83d1bb18171e512908fe5dc7278a1d6", - "sha256:96f240bce182ca7fe045c76bcebfa0b0534a1bf402ed05914a6f1dadff91877f", - "sha256:a733965f1a2b4090a5238d40d983dcd78f3ecea221c7af1497b845a9709c1721", - "sha256:ab624700dc145aa809e6f3ec93fb8e7d0f99d9023b713f6a953637429b437d37", - "sha256:b2571db88c636d862b35090ccf92bf24004393f85c8870a37f42d9f23d13e032", - "sha256:bbbc94d0c94dd80b3340fc4f04fd4d701f4b038ebad72c39693c794fd3bc2d9d", - "sha256:c0727bda6e38144d464daec31dff936a82917f431d9c39c39c60a26567eae3ed", - "sha256:c556695b699f648c58373b542534308922c46a1cda06ea47bc9ca45ef5b39ae6", - "sha256:c86229333cabaaa8c51cf971496f10318c4734cf7b641f08af0a6fbf17ca3054", - "sha256:c8d7da6f1c1049eefb718d43d99ad73100c958a5367d30b9321b092771e96c25", - "sha256:c8e9dcf1ac499679aceedac7e7ca6d8641f0193c591a2d090282aaf8e9445a46", - "sha256:cb23bcc093697cdea2708baae4f9ba0e972960a835af22560f6ae4e7e47d33f5", - "sha256:d1e4c28f30e767fd07f2ddc6f74f41f034d1dd6bc526cd59e63a82fe8bb9ef4c", - "sha256:d9c9bdb3af48e242838f9f6e6127de9be7063aad17b32215ccc36a09c5cf1070", - "sha256:dee5ef83a76ac31ab0c78c10bd7d5437bfdb6358c95b91f1ba7ff7b76f9996a1", - "sha256:e0896200b6a40197405af18828da49f067c2fa1f821491bc8f5bde241ef3f7d7", - "sha256:f5a64b64ddf4c99fe201ac2724daada8595ada0d102ab96d019c1555c2d6441d", - "sha256:f947352c3434e8b937e3aa8f96f47bdfe6d92779e44bb3f41e4c213ba6a32145" + "sha256:02eefd7087268b711a3ff4db528e9916ac9aa18616da7bca69c1871d0b7a091f", + "sha256:059b6c1795170809103a1538255883e1983e5b831faea6558ef873d4955b4a74", + "sha256:0bf07cab5b279859c253d26a9194a8906e6f4a210063b84b433cf90a569de0c1", + "sha256:1542636a39c4892c4f4fa6270696902acb186a9aaeac6f6cf92ce6ae2e88564b", + "sha256:177071dfc0df6248fd22b43036f936cfe2508077a72af0933d0c1fa269b18537", + "sha256:18f3e912f9ad1bdec27fb06b8198a2ccc32f201e24174cec1b3424dda605a310", + "sha256:1dd8fecbad028cd89d04a46688d2fcc14423e8a196d5b0a5c65105664901f810", + "sha256:1ed987c3ff29fff7fd8c3ea3a3ea877ad310aae2ef9889a119e22d3f2db0691a", + "sha256:447d5521575f18e18240906beadc58551e97ec98142266e521c34968c76c8761", + "sha256:494f7c8537f0c02b740c229af4cb47c0d39840b829ecdcfc93d91dcbb0779892", + "sha256:4988c0f13c42bfa9ddd2fe2f569c9d54646ce84adc5de84228cfe83396f3bd58", + "sha256:4ce9ae9e91f46c344bec3b03d6ee9612802682c1551aaf627ad24045ce090761", + "sha256:5d93d4e95eacd313d2c765ebe40d49ca9dd2ed90e5b37d0d421c597af830c195", + "sha256:61b6760b08b7c395975d893e0b814a11cf011ebb24f7d869e7118f5a339a82e1", + "sha256:72ccb318bf0c9ab97fc04c10c37683d9eea952ed526707fabf9ac5ae59b701fd", + "sha256:79b485767c13788ee314669008d01f9ef3bc05db9ea3298f6a50d3ef596a154b", + "sha256:7eb57ba90929bac0b6cc2af2373893d80ac559adda6933e562dcfb375029acee", + "sha256:8bc541a405423ce0e51c19f637050acdbdf8feca34150e0d17f675e72d119580", + "sha256:969dd06110cb780da01336b281f53e2e7eb3a482831df441fb65dd30403f4608", + "sha256:985ceb5d0a86fcaa61e45781e567a59baa0da292d5ed2e490d612d0de5796918", + "sha256:9bcf8b6e011be08fb729d110f3e22e654a50f8a826b0575c7196616780683380", + "sha256:9ce157d979f742a915b75f792dbd6aa63b8eccaf46a1005ba03aa8a986bde34a", + "sha256:9f659a5ee95c8baa2436d392267988fd0f43eb774e5eb8739252e5a7e9cf07e0", + "sha256:a4a88dcd6ff8fd47c18b3a3709a89adb39a6373f4482e04c1b765045c7e282fd", + "sha256:a955260d47f03df08acf45689bd163ed9df82c0e0124beb4251b1290fa7ae728", + "sha256:a9af62e9b5b9bc67b2a195ebc2c2662fdf498a822d62f902bf27cccb52dbbf49", + "sha256:ae72f8098acb368d877b210ebe02ba12585e77bd0db78ac04a1ee9b9f5dd2166", + "sha256:b83ba3825bc91dfa989d4eed76865e71aea3a6ca1388b59fc801ee04c4d8d0d6", + "sha256:c11951b404e08b01b151222a1cb1a9f0a860a8153ce8334149ab9199cd198131", + "sha256:c320c64dd876e45254bdd350f0179da737463eea41c43bacbee9d8c9d1021f11", + "sha256:c8098a724c2784bf03e8070993f6d46aa2eeca031f8d8a048dff277703e6e193", + "sha256:d12f96b5b64bec3f43c8e82b4aab7599d0157f11c798c9f9c528a72b9e0b339a", + "sha256:e565a785233c2d03724c4dc55464559639b1ba9ecf091288dd47ad9c629433bd", + "sha256:f0f047e11febe5c3198ed346b507e1d010330d56ad615a7e0a89fae604065a0e", + "sha256:fe4670cb32ea98ffbf5a1262f14c3e102cccd92b1869df3bb09538158ba90fe6" ], - "markers": "python_full_version >= '3.6.1'", - "version": "==1.9.0" + "version": "==1.9.1" }, "pyngrok": { "hashes": [ @@ -508,12 +482,20 @@ "index": "pypi", "version": "==5.1.0" }, + "pyparsing": { + "hashes": [ + "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", + "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" + ], + "version": "==3.0.9" + }, "pypng": { "hashes": [ - "sha256:76f8a1539ec56451da7ab7121f12a361969fe0f2d48d703d198ce2a99d6c5afd" + "sha256:4a43e969b8f5aaafb2a415536c1a8ec7e341cd6a3f957fd5b5f32a4cfeed902c", + "sha256:739c433ba96f078315de54c0db975aee537cbc3e1d0ae4ed9aab0ca1e427e2c1" ], "index": "pypi", - "version": "==0.0.21" + "version": "==0.20220715.0" }, "pyqrcode": { "hashes": [ @@ -525,18 +507,17 @@ }, "pyscss": { "hashes": [ - "sha256:f1df571569021a23941a538eb154405dde80bed35dc1ea7c5f3e18e0144746bf" + "sha256:8f35521ffe36afa8b34c7d6f3195088a7057c185c2b8f15ee459ab19748669ff" ], "index": "pypi", - "version": "==1.3.7" + "version": "==1.4.0" }, "python-dotenv": { "hashes": [ - "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3", - "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f" + "sha256:b7e3b04a59693c42c36f9ab1cc2acc46fa5df8c78e178fc33a8d4cd05c8d498f", + "sha256:d92a187be61fe482e4fd675b6d52200e7be63a12b724abbf931a40ce4fa92938" ], - "markers": "python_full_version >= '3.5.0'", - "version": "==0.19.2" + "version": "==0.20.0" }, "pyyaml": { "hashes": [ @@ -581,13 +562,9 @@ "sha256:026c0de2ee8385d1255b9c2426cd4f03fe9177ac94c09979bc601946c8493aa0", "sha256:99142650756ef1998ce0661568f54a47dac8c638fb27e3816c02536575dbba8c" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.6.0.post0" }, "rfc3986": { - "extras": [ - "idna2008" - ], "hashes": [ "sha256:270aaf10d87d0d4e095063c65bf3ddbc6ee3d0b226328ce21e036f946e421835", "sha256:a86d6e1f5b1dc238b218b012df0aa79409667bb209e58da56d0b94704e712a97" @@ -625,18 +602,17 @@ }, "shortuuid": { "hashes": [ - "sha256:44a7a86bcf24dbaba2e626cf80c779926b7c3a0d31a3a013e0d3cd1077707d23", - "sha256:9435e87e5a64f3b92f7110c81f989a3b7bdb9358e22d2359829167da476cfc23" + "sha256:459f12fa1acc34ff213b1371467c0325169645a31ed989e268872339af7563d5", + "sha256:b2bb9eb7773170e253bb7ba25971023acb473517a8b76803d9618668cb1dd46f" ], "index": "pypi", - "version": "==1.0.8" + "version": "==1.0.9" }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, "sniffio": { @@ -644,7 +620,6 @@ "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663", "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de" ], - "markers": "python_version >= '3.5'", "version": "==1.2.0" }, "sqlalchemy": { @@ -693,11 +668,11 @@ }, "sqlalchemy-aio": { "hashes": [ - "sha256:7f77366f55d34891c87386dd0962a28b948b684e8ea5edb7daae4187c0b291bf", - "sha256:f767320427c22c66fa5840a1f17f3261110a8ddc8560558f4fbf12d31a66b17b" + "sha256:3f4aa392c38f032d6734826a4138a0f02ed3122d442ed142be1e5964f2a33b60", + "sha256:f531c7982662d71dfc0b117e77bb2ed544e25cd5361e76cf9f5208edcfb71f7b" ], "index": "pypi", - "version": "==0.16.0" + "version": "==0.17.0" }, "sse-starlette": { "hashes": [ @@ -709,30 +684,26 @@ }, "starlette": { "hashes": [ - "sha256:26a18cbda5e6b651c964c12c88b36d9898481cd428ed6e063f5f29c418f73050", - "sha256:57eab3cc975a28af62f6faec94d355a410634940f10b30d68d31cb5ec1b44ae8" + "sha256:5a60c5c2d051f3a8eb546136aa0c9399773a689595e099e0877704d5888279bf", + "sha256:c6d21096774ecb9639acad41b86b7706e52ba3bf1dc13ea4ed9ad593d47e24c7" ], - "markers": "python_version >= '3.6'", - "version": "==0.17.1" + "version": "==0.19.1" }, "typing-extensions": { "hashes": [ - "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42", - "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2" + "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", + "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" ], "index": "pypi", - "version": "==4.1.1" + "version": "==4.3.0" }, "uvicorn": { - "extras": [ - "standard" - ], "hashes": [ - "sha256:25850bbc86195a71a6477b3e4b3b7b4c861fb687fb96912972ce5324472b1011", - "sha256:e85872d84fb651cccc4c5d2a71cf7ead055b8fb4d8f1e78e36092282c0cf2aec" + "sha256:c19a057deb1c5bb060946e2e5c262fc01590c6529c0af2c3d9ce941e89bc30e0", + "sha256:cade07c403c397f9fe275492a48c1b869efd175d5d8a692df649e6e7e2ed8f4e" ], "index": "pypi", - "version": "==0.17.4" + "version": "==0.18.2" }, "uvloop": { "hashes": [ @@ -755,65 +726,80 @@ ], "version": "==0.16.0" }, - "watchgod": { + "watchfiles": { "hashes": [ - "sha256:48140d62b0ebe9dd9cf8381337f06351e1f2e70b2203fa9c6eff4e572ca84f29", - "sha256:d6c1ea21df37847ac0537ca0d6c2f4cdf513562e95f77bb93abbcf05573407b7" + "sha256:059bd9596429f8c13604b2eb30888a5661b3c79099edc506f11b63be7afe3ca4", + "sha256:09490d258be8fdd7f5141a39b468dede0b4aa4a52f2b2dbfb0f3835ae7c23eca", + "sha256:1bb5f0117c8b93f8e1b22ac0be60cfeb00332959a72e6bbe2073fea27ed086e5", + "sha256:3d3f0397c9128971398a5cbb0fb45852ab2fa4472ac9724c031071e1e39970c0", + "sha256:43d1d517faffa8955c2da0e6f64268e38442d43b50ca73cb686df25f891e49a1", + "sha256:4f712dbe9d8c0365bf46ffe0dd9c6a62cc0acf05ba951f1a53de2b4d5bb63299", + "sha256:59498853d3214d1e4d9b1cb3a06b0011a11f24d31708b1734d9cd7f5a30fe1af", + "sha256:5e3d4c92091d16bca1d61920575dab5d6dcbceda76dccd5fb91da0b7390b4ee9", + "sha256:5fa786d102e7eabef22b2147af531aa70194aabcb35335be81c07c26382b0050", + "sha256:750e40db5efcf3f5f11602dbc6fdf8e96a0eefdbccd271093efe9fa2e9d02ed2", + "sha256:7c80e3907d21ca3f1689f42632d239fdc40ffc1d5f32f564997480f85e94c474", + "sha256:8d635dcba3aab2909bf568765547696d7465d30e2e9c6f5ab99da877b58d29bb", + "sha256:a5f64674559fac56a6bf2f5e086cb3758740140c80711fe3e016f5443b84ef15", + "sha256:bcd085980389bc64fe509188a9caffa4fe13b2616e2e3e674cde58f916b2a8ee", + "sha256:c9e3756cd2ba17e5042e8c9399a08e4bdbe1a366156a164e8373bda30ca096d0", + "sha256:cbdb7814ca43f85ab8569206ab2c3bcd51dd5d1ba582914246784414e6ada62e", + "sha256:d5fb4f3b5c884d4f22f643b0697edbb04942bcad961a8f9a9bfadb73e7a1e229" ], - "version": "==0.7" + "version": "==0.16.0" }, "websockets": { "hashes": [ - "sha256:002071169d2e44ce8eb9e5ebac9fbce142ba4b5146eef1cfb16b177a27662657", - "sha256:05e7f098c76b0a4743716590bb8f9706de19f1ef5148d61d0cf76495ec3edb9c", - "sha256:08a42856158307e231b199671c4fce52df5786dd3d703f36b5d8ac76b206c485", - "sha256:0d93b7cadc761347d98da12ec1930b5c71b2096f1ceed213973e3cda23fead9c", - "sha256:10edd9d7d3581cfb9ff544ac09fc98cab7ee8f26778a5a8b2d5fd4b0684c5ba5", - "sha256:14e9cf68a08d1a5d42109549201aefba473b1d925d233ae19035c876dd845da9", - "sha256:181d2b25de5a437b36aefedaf006ecb6fa3aa1328ec0236cdde15f32f9d3ff6d", - "sha256:189ed478395967d6a98bb293abf04e8815349e17456a0a15511f1088b6cb26e4", - "sha256:1d858fb31e5ac992a2cdf17e874c95f8a5b1e917e1fb6b45ad85da30734b223f", - "sha256:1dafe98698ece09b8ccba81b910643ff37198e43521d977be76caf37709cf62b", - "sha256:3477146d1f87ead8df0f27e8960249f5248dceb7c2741e8bbec9aa5338d0c053", - "sha256:38db6e2163b021642d0a43200ee2dec8f4980bdbda96db54fde72b283b54cbfc", - "sha256:3a02ab91d84d9056a9ee833c254895421a6333d7ae7fff94b5c68e4fa8095519", - "sha256:3bbf080f3892ba1dc8838786ec02899516a9d227abe14a80ef6fd17d4fb57127", - "sha256:3ef6f73854cded34e78390dbdf40dfdcf0b89b55c0e282468ef92646fce8d13a", - "sha256:468f0031fdbf4d643f89403a66383247eb82803430b14fa27ce2d44d2662ca37", - "sha256:483edee5abed738a0b6a908025be47f33634c2ad8e737edd03ffa895bd600909", - "sha256:531d8eb013a9bc6b3ad101588182aa9b6dd994b190c56df07f0d84a02b85d530", - "sha256:5560558b0dace8312c46aa8915da977db02738ac8ecffbc61acfbfe103e10155", - "sha256:5bb6256de5a4fb1d42b3747b4e2268706c92965d75d0425be97186615bf2f24f", - "sha256:667c41351a6d8a34b53857ceb8343a45c85d438ee4fd835c279591db8aeb85be", - "sha256:6b014875fae19577a392372075e937ebfebf53fd57f613df07b35ab210f31534", - "sha256:6fdec1a0b3e5630c58e3d8704d2011c678929fce90b40908c97dfc47de8dca72", - "sha256:7bdd3d26315db0a9cf8a0af30ca95e0aa342eda9c1377b722e71ccd86bc5d1dd", - "sha256:7c9407719f42cb77049975410490c58a705da6af541adb64716573e550e5c9db", - "sha256:7d6673b2753f9c5377868a53445d0c321ef41ff3c8e3b6d57868e72054bfce5f", - "sha256:816ae7dac2c6522cfa620947ead0ca95ac654916eebf515c94d7c28de5601a6e", - "sha256:882c0b8bdff3bf1bd7f024ce17c6b8006042ec4cceba95cf15df57e57efa471c", - "sha256:8877861e3dee38c8d302eee0d5dbefa6663de3b46dc6a888f70cd7e82562d1f7", - "sha256:888a5fa2a677e0c2b944f9826c756475980f1b276b6302e606f5c4ff5635be9e", - "sha256:89e985d40d407545d5f5e2e58e1fdf19a22bd2d8cd54d20a882e29f97e930a0a", - "sha256:97b4b68a2ddaf5c4707ae79c110bfd874c5be3c6ac49261160fb243fa45d8bbb", - "sha256:98de71f86bdb29430fd7ba9997f47a6b10866800e3ea577598a786a785701bb0", - "sha256:9f304a22ece735a3da8a51309bc2c010e23961a8f675fae46fdf62541ed62123", - "sha256:9fd62c6dc83d5d35fb6a84ff82ec69df8f4657fff05f9cd6c7d9bec0dd57f0f6", - "sha256:a249139abc62ef333e9e85064c27fefb113b16ffc5686cefc315bdaef3eefbc8", - "sha256:b66e6d514f12c28d7a2d80bb2a48ef223342e99c449782d9831b0d29a9e88a17", - "sha256:b68b6caecb9a0c6db537aa79750d1b592a841e4f1a380c6196091e65b2ad35f9", - "sha256:baa83174390c0ff4fc1304fbe24393843ac7a08fdd59295759c4b439e06b1536", - "sha256:bb01ea7b5f52e7125bdc3c5807aeaa2d08a0553979cf2d96a8b7803ea33e15e7", - "sha256:cfae282c2aa7f0c4be45df65c248481f3509f8c40ca8b15ed96c35668ae0ff69", - "sha256:d0d81b46a5c87d443e40ce2272436da8e6092aa91f5fbeb60d1be9f11eff5b4c", - "sha256:d9b245db5a7e64c95816e27d72830e51411c4609c05673d1ae81eb5d23b0be54", - "sha256:ddab2dc69ee5ae27c74dbfe9d7bb6fee260826c136dca257faa1a41d1db61a89", - "sha256:e1b60fd297adb9fc78375778a5220da7f07bf54d2a33ac781319650413fc6a60", - "sha256:e259be0863770cb91b1a6ccf6907f1ac2f07eff0b7f01c249ed751865a70cb0d", - "sha256:e3872ae57acd4306ecf937d36177854e218e999af410a05c17168cd99676c512", - "sha256:e4819c6fb4f336fd5388372cb556b1f3a165f3f68e66913d1a2fc1de55dc6f58" + "sha256:07cdc0a5b2549bcfbadb585ad8471ebdc7bdf91e32e34ae3889001c1c106a6af", + "sha256:210aad7fdd381c52e58777560860c7e6110b6174488ef1d4b681c08b68bf7f8c", + "sha256:28dd20b938a57c3124028680dc1600c197294da5db4292c76a0b48efb3ed7f76", + "sha256:2f94fa3ae454a63ea3a19f73b95deeebc9f02ba2d5617ca16f0bbdae375cda47", + "sha256:31564a67c3e4005f27815634343df688b25705cccb22bc1db621c781ddc64c69", + "sha256:347974105bbd4ea068106ec65e8e8ebd86f28c19e529d115d89bd8cc5cda3079", + "sha256:379e03422178436af4f3abe0aa8f401aa77ae2487843738542a75faf44a31f0c", + "sha256:3eda1cb7e9da1b22588cefff09f0951771d6ee9fa8dbe66f5ae04cc5f26b2b55", + "sha256:51695d3b199cd03098ae5b42833006a0f43dc5418d3102972addc593a783bc02", + "sha256:54c000abeaff6d8771a4e2cef40900919908ea7b6b6a30eae72752607c6db559", + "sha256:5b936bf552e4f6357f5727579072ff1e1324717902127ffe60c92d29b67b7be3", + "sha256:6075fd24df23133c1b078e08a9b04a3bc40b31a8def4ee0b9f2c8865acce913e", + "sha256:661f641b44ed315556a2fa630239adfd77bd1b11cb0b9d96ed8ad90b0b1e4978", + "sha256:6ea6b300a6bdd782e49922d690e11c3669828fe36fc2471408c58b93b5535a98", + "sha256:6ed1d6f791eabfd9808afea1e068f5e59418e55721db8b7f3bfc39dc831c42ae", + "sha256:7934e055fd5cd9dee60f11d16c8d79c4567315824bacb1246d0208a47eca9755", + "sha256:7ab36e17af592eec5747c68ef2722a74c1a4a70f3772bc661079baf4ae30e40d", + "sha256:7f6d96fdb0975044fdd7953b35d003b03f9e2bcf85f2d2cf86285ece53e9f991", + "sha256:83e5ca0d5b743cde3d29fda74ccab37bdd0911f25bd4cdf09ff8b51b7b4f2fa1", + "sha256:85506b3328a9e083cc0a0fb3ba27e33c8db78341b3eb12eb72e8afd166c36680", + "sha256:8af75085b4bc0b5c40c4a3c0e113fa95e84c60f4ed6786cbb675aeb1ee128247", + "sha256:8b1359aba0ff810d5830d5ab8e2c4a02bebf98a60aa0124fb29aa78cfdb8031f", + "sha256:8fbd7d77f8aba46d43245e86dd91a8970eac4fb74c473f8e30e9c07581f852b2", + "sha256:907e8247480f287aa9bbc9391bd6de23c906d48af54c8c421df84655eef66af7", + "sha256:93d5ea0b5da8d66d868b32c614d2b52d14304444e39e13a59566d4acb8d6e2e4", + "sha256:97bc9d41e69a7521a358f9b8e44871f6cdeb42af31815c17aed36372d4eec667", + "sha256:994cdb1942a7a4c2e10098d9162948c9e7b235df755de91ca33f6e0481366fdb", + "sha256:a141de3d5a92188234afa61653ed0bbd2dde46ad47b15c3042ffb89548e77094", + "sha256:a1e15b230c3613e8ea82c9fc6941b2093e8eb939dd794c02754d33980ba81e36", + "sha256:aad5e300ab32036eb3fdc350ad30877210e2f51bceaca83fb7fef4d2b6c72b79", + "sha256:b529fdfa881b69fe563dbd98acce84f3e5a67df13de415e143ef053ff006d500", + "sha256:b9c77f0d1436ea4b4dc089ed8335fa141e6a251a92f75f675056dac4ab47a71e", + "sha256:bb621ec2dbbbe8df78a27dbd9dd7919f9b7d32a73fafcb4d9252fc4637343582", + "sha256:c7250848ce69559756ad0086a37b82c986cd33c2d344ab87fea596c5ac6d9442", + "sha256:c8d1d14aa0f600b5be363077b621b1b4d1eb3fbf90af83f9281cda668e6ff7fd", + "sha256:d1655a6fc7aecd333b079d00fb3c8132d18988e47f19740c69303bf02e9883c6", + "sha256:d6353ba89cfc657a3f5beabb3b69be226adbb5c6c7a66398e17809b0ce3c4731", + "sha256:da4377904a3379f0c1b75a965fff23b28315bcd516d27f99a803720dfebd94d4", + "sha256:e49ea4c1a9543d2bd8a747ff24411509c29e4bdcde05b5b0895e2120cb1a761d", + "sha256:e4e08305bfd76ba8edab08dcc6496f40674f44eb9d5e23153efa0a35750337e8", + "sha256:e6fa05a680e35d0fcc1470cb070b10e6fe247af54768f488ed93542e71339d6f", + "sha256:e7e6f2d6fd48422071cc8a6f8542016f350b79cc782752de531577d35e9bd677", + "sha256:e904c0381c014b914136c492c8fa711ca4cced4e9b3d110e5e7d436d0fc289e8", + "sha256:ec2b0ab7edc8cd4b0eb428b38ed89079bdc20c6bdb5f889d353011038caac2f9", + "sha256:ef5ce841e102278c1c2e98f043db99d6755b1c58bde475516aef3a008ed7f28e", + "sha256:f351c7d7d92f67c0609329ab2735eee0426a03022771b00102816a72715bb00b", + "sha256:fab7c640815812ed5f10fbee7abbf58788d602046b7bb3af9b1ac753a6d5e916", + "sha256:fc06cc8073c8e87072138ba1e431300e2d408f054b27047d047b549455066ff4" ], - "version": "==10.1" + "version": "==10.3" } }, "develop": { @@ -829,7 +815,6 @@ "sha256:2d27e3784d7a565d36ab851fe94887c5eccd6a463168875832a1be79c82828b4", "sha256:626ba8234211db98e869df76230a137c4c40a12d72445c45d5f5b716f076e2fd" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==21.4.0" }, "black": { @@ -839,63 +824,79 @@ "index": "pypi", "version": "==20.8b1" }, + "certifi": { + "hashes": [ + "sha256:84c85a9078b11105f04f3036a9482ae10e4621616db313fe045dd24743a0820d", + "sha256:fe86415d55e84719d75f8b69414f6438ac3547d2078ab91b67e779ef69378412" + ], + "version": "==2022.6.15" + }, + "charset-normalizer": { + "hashes": [ + "sha256:5189b6f22b01957427f35b6a08d9a0bc45b46d3788ef5a92e978433c7a35f8a5", + "sha256:575e708016ff3a5e3681541cb9d79312c416835686d054a23accb873b254f413" + ], + "version": "==2.1.0" + }, "click": { "hashes": [ - "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3", - "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b" + "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e", + "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48" ], - "markers": "python_version >= '3.6'", - "version": "==8.0.3" + "version": "==8.1.3" }, "coverage": { - "extras": [ - "toml" - ], "hashes": [ - "sha256:1245ab82e8554fa88c4b2ab1e098ae051faac5af829efdcf2ce6b34dccd5567c", - "sha256:1bc6d709939ff262fd1432f03f080c5042dc6508b6e0d3d20e61dd045456a1a0", - "sha256:25e73d4c81efa8ea3785274a2f7f3bfbbeccb6fcba2a0bdd3be9223371c37554", - "sha256:276b13cc085474e482566c477c25ed66a097b44c6e77132f3304ac0b039f83eb", - "sha256:2aed4761809640f02e44e16b8b32c1a5dee5e80ea30a0ff0912158bde9c501f2", - "sha256:2dd70a167843b4b4b2630c0c56f1b586fe965b4f8ac5da05b6690344fd065c6b", - "sha256:352c68e233409c31048a3725c446a9e48bbff36e39db92774d4f2380d630d8f8", - "sha256:3f2b05757c92ad96b33dbf8e8ec8d4ccb9af6ae3c9e9bd141c7cc44d20c6bcba", - "sha256:448d7bde7ceb6c69e08474c2ddbc5b4cd13c9e4aa4a717467f716b5fc938a734", - "sha256:463e52616ea687fd323888e86bf25e864a3cc6335a043fad6bbb037dbf49bbe2", - "sha256:482fb42eea6164894ff82abbcf33d526362de5d1a7ed25af7ecbdddd28fc124f", - "sha256:56c4a409381ddd7bbff134e9756077860d4e8a583d310a6f38a2315b9ce301d0", - "sha256:56d296cbc8254a7dffdd7bcc2eb70be5a233aae7c01856d2d936f5ac4e8ac1f1", - "sha256:5e15d424b8153756b7c903bde6d4610be0c3daca3986173c18dd5c1a1625e4cd", - "sha256:618eeba986cea7f621d8607ee378ecc8c2504b98b3fdc4952b30fe3578304687", - "sha256:61d47a897c1e91f33f177c21de897267b38fbb45f2cd8e22a710bcef1df09ac1", - "sha256:621f6ea7260ea2ffdaec64fe5cb521669984f567b66f62f81445221d4754df4c", - "sha256:6a5cdc3adb4f8bb8d8f5e64c2e9e282bc12980ef055ec6da59db562ee9bdfefa", - "sha256:6c3f6158b02ac403868eea390930ae64e9a9a2a5bbfafefbb920d29258d9f2f8", - "sha256:704f89b87c4f4737da2860695a18c852b78ec7279b24eedacab10b29067d3a38", - "sha256:72128176fea72012063200b7b395ed8a57849282b207321124d7ff14e26988e8", - "sha256:78fbb2be068a13a5d99dce9e1e7d168db880870f7bc73f876152130575bd6167", - "sha256:7bff3a98f63b47464480de1b5bdd80c8fade0ba2832c9381253c9b74c4153c27", - "sha256:84f2436d6742c01136dd940ee158bfc7cf5ced3da7e4c949662b8703b5cd8145", - "sha256:9976fb0a5709988778ac9bc44f3d50fccd989987876dfd7716dee28beed0a9fa", - "sha256:9ad0a117b8dc2061ce9461ea4c1b4799e55edceb236522c5b8f958ce9ed8fa9a", - "sha256:9e3dd806f34de38d4c01416344e98eab2437ac450b3ae39c62a0ede2f8b5e4ed", - "sha256:9eb494070aa060ceba6e4bbf44c1bc5fa97bfb883a0d9b0c9049415f9e944793", - "sha256:9fde6b90889522c220dd56a670102ceef24955d994ff7af2cb786b4ba8fe11e4", - "sha256:9fff3ff052922cb99f9e52f63f985d4f7a54f6b94287463bc66b7cdf3eb41217", - "sha256:a06c358f4aed05fa1099c39decc8022261bb07dfadc127c08cfbd1391b09689e", - "sha256:a4f923b9ab265136e57cc14794a15b9dcea07a9c578609cd5dbbfff28a0d15e6", - "sha256:c5b81fb37db76ebea79aa963b76d96ff854e7662921ce742293463635a87a78d", - "sha256:d5ed164af5c9078596cfc40b078c3b337911190d3faeac830c3f1274f26b8320", - "sha256:d651fde74a4d3122e5562705824507e2f5b2d3d57557f1916c4b27635f8fbe3f", - "sha256:de73fca6fb403dd72d4da517cfc49fcf791f74eee697d3219f6be29adf5af6ce", - "sha256:e647a0be741edbb529a72644e999acb09f2ad60465f80757da183528941ff975", - "sha256:e92c7a5f7d62edff50f60a045dc9542bf939758c95b2fcd686175dd10ce0ed10", - "sha256:eeffd96882d8c06d31b65dddcf51db7c612547babc1c4c5db6a011abe9798525", - "sha256:f5a4551dfd09c3bd12fca8144d47fe7745275adf3229b7223c2f9e29a975ebda", - "sha256:fac0bcc5b7e8169bffa87f0dcc24435446d329cbc2b5486d155c2e0f3b493ae1" + "sha256:0895ea6e6f7f9939166cc835df8fa4599e2d9b759b02d1521b574e13b859ac32", + "sha256:0f211df2cba951ffcae210ee00e54921ab42e2b64e0bf2c0befc977377fb09b7", + "sha256:147605e1702d996279bb3cc3b164f408698850011210d133a2cb96a73a2f7996", + "sha256:24b04d305ea172ccb21bee5bacd559383cba2c6fcdef85b7701cf2de4188aa55", + "sha256:25b7ec944f114f70803d6529394b64f8749e93cbfac0fe6c5ea1b7e6c14e8a46", + "sha256:2b20286c2b726f94e766e86a3fddb7b7e37af5d0c635bdfa7e4399bc523563de", + "sha256:2dff52b3e7f76ada36f82124703f4953186d9029d00d6287f17c68a75e2e6039", + "sha256:2f8553878a24b00d5ab04b7a92a2af50409247ca5c4b7a2bf4eabe94ed20d3ee", + "sha256:3def6791adf580d66f025223078dc84c64696a26f174131059ce8e91452584e1", + "sha256:422fa44070b42fef9fb8dabd5af03861708cdd6deb69463adc2130b7bf81332f", + "sha256:4f89d8e03c8a3757aae65570d14033e8edf192ee9298303db15955cadcff0c63", + "sha256:5336e0352c0b12c7e72727d50ff02557005f79a0b8dcad9219c7c4940a930083", + "sha256:54d8d0e073a7f238f0666d3c7c0d37469b2aa43311e4024c925ee14f5d5a1cbe", + "sha256:5ef42e1db047ca42827a85e34abe973971c635f83aed49611b7f3ab49d0130f0", + "sha256:5f65e5d3ff2d895dab76b1faca4586b970a99b5d4b24e9aafffc0ce94a6022d6", + "sha256:6c3ccfe89c36f3e5b9837b9ee507472310164f352c9fe332120b764c9d60adbe", + "sha256:6d0b48aff8e9720bdec315d67723f0babd936a7211dc5df453ddf76f89c59933", + "sha256:6fe75dcfcb889b6800f072f2af5a331342d63d0c1b3d2bf0f7b4f6c353e8c9c0", + "sha256:79419370d6a637cb18553ecb25228893966bd7935a9120fa454e7076f13b627c", + "sha256:7bb00521ab4f99fdce2d5c05a91bddc0280f0afaee0e0a00425e28e209d4af07", + "sha256:80db4a47a199c4563d4a25919ff29c97c87569130375beca3483b41ad5f698e8", + "sha256:866ebf42b4c5dbafd64455b0a1cd5aa7b4837a894809413b930026c91e18090b", + "sha256:8af6c26ba8df6338e57bedbf916d76bdae6308e57fc8f14397f03b5da8622b4e", + "sha256:a13772c19619118903d65a91f1d5fea84be494d12fd406d06c849b00d31bf120", + "sha256:a697977157adc052284a7160569b36a8bbec09db3c3220642e6323b47cec090f", + "sha256:a9032f9b7d38bdf882ac9f66ebde3afb8145f0d4c24b2e600bc4c6304aafb87e", + "sha256:b5e28db9199dd3833cc8a07fa6cf429a01227b5d429facb56eccd765050c26cd", + "sha256:c77943ef768276b61c96a3eb854eba55633c7a3fddf0a79f82805f232326d33f", + "sha256:d230d333b0be8042ac34808ad722eabba30036232e7a6fb3e317c49f61c93386", + "sha256:d4548be38a1c810d79e097a38107b6bf2ff42151900e47d49635be69943763d8", + "sha256:d4e7ced84a11c10160c0697a6cc0b214a5d7ab21dfec1cd46e89fbf77cc66fae", + "sha256:d56f105592188ce7a797b2bd94b4a8cb2e36d5d9b0d8a1d2060ff2a71e6b9bbc", + "sha256:d714af0bdba67739598849c9f18efdcc5a0412f4993914a0ec5ce0f1e864d783", + "sha256:d774d9e97007b018a651eadc1b3970ed20237395527e22cbeb743d8e73e0563d", + "sha256:e0524adb49c716ca763dbc1d27bedce36b14f33e6b8af6dba56886476b42957c", + "sha256:e2618cb2cf5a7cc8d698306e42ebcacd02fb7ef8cfc18485c59394152c70be97", + "sha256:e36750fbbc422c1c46c9d13b937ab437138b998fe74a635ec88989afb57a3978", + "sha256:edfdabe7aa4f97ed2b9dd5dde52d2bb29cb466993bb9d612ddd10d0085a683cf", + "sha256:f22325010d8824594820d6ce84fa830838f581a7fd86a9235f0d2ed6deb61e29", + "sha256:f23876b018dfa5d3e98e96f5644b109090f16a4acb22064e0f06933663005d39", + "sha256:f7bd0ffbcd03dc39490a1f40b2669cc414fae0c4e16b77bb26806a4d0b7d1452" ], - "markers": "python_version >= '3.7'", - "version": "==6.3.1" + "version": "==6.4.2" + }, + "idna": { + "hashes": [ + "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff", + "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d" + ], + "version": "==3.3" }, "iniconfig": { "hashes": [ @@ -904,31 +905,42 @@ ], "version": "==1.1.1" }, - "mypy": { + "mock": { "hashes": [ - "sha256:0038b21890867793581e4cb0d810829f5fd4441aa75796b53033af3aa30430ce", - "sha256:1171f2e0859cfff2d366da2c7092b06130f232c636a3f7301e3feb8b41f6377d", - "sha256:1b06268df7eb53a8feea99cbfff77a6e2b205e70bf31743e786678ef87ee8069", - "sha256:1b65714dc296a7991000b6ee59a35b3f550e0073411ac9d3202f6516621ba66c", - "sha256:1bf752559797c897cdd2c65f7b60c2b6969ffe458417b8d947b8340cc9cec08d", - "sha256:300717a07ad09525401a508ef5d105e6b56646f7942eb92715a1c8d610149714", - "sha256:3c5b42d0815e15518b1f0990cff7a705805961613e701db60387e6fb663fe78a", - "sha256:4365c60266b95a3f216a3047f1d8e3f895da6c7402e9e1ddfab96393122cc58d", - "sha256:50c7346a46dc76a4ed88f3277d4959de8a2bd0a0fa47fa87a4cde36fe247ac05", - "sha256:5b56154f8c09427bae082b32275a21f500b24d93c88d69a5e82f3978018a0266", - "sha256:74f7eccbfd436abe9c352ad9fb65872cc0f1f0a868e9d9c44db0893440f0c697", - "sha256:7b3f6f557ba4afc7f2ce6d3215d5db279bcf120b3cfd0add20a5d4f4abdae5bc", - "sha256:8c11003aaeaf7cc2d0f1bc101c1cc9454ec4cc9cb825aef3cafff8a5fdf4c799", - "sha256:8ca7f8c4b1584d63c9a0f827c37ba7a47226c19a23a753d52e5b5eddb201afcd", - "sha256:c89702cac5b302f0c5d33b172d2b55b5df2bede3344a2fbed99ff96bddb2cf00", - "sha256:d8f1ff62f7a879c9fe5917b3f9eb93a79b78aad47b533911b853a757223f72e7", - "sha256:d9d2b84b2007cea426e327d2483238f040c49405a6bf4074f605f0156c91a47a", - "sha256:e839191b8da5b4e5d805f940537efcaa13ea5dd98418f06dc585d2891d228cf0", - "sha256:f9fe20d0872b26c4bba1c1be02c5340de1019530302cf2dcc85c7f9fc3252ae0", - "sha256:ff3bf387c14c805ab1388185dd22d6b210824e164d4bb324b195ff34e322d166" + "sha256:122fcb64ee37cfad5b3f48d7a7d51875d7031aaf3d8be7c42e2bee25044eee62", + "sha256:7d3fbbde18228f4ff2f1f119a45cdffa458b4c0dee32eb4d2bb2f82554bac7bc" ], "index": "pypi", - "version": "==0.931" + "version": "==4.0.3" + }, + "mypy": { + "hashes": [ + "sha256:02ef476f6dcb86e6f502ae39a16b93285fef97e7f1ff22932b657d1ef1f28655", + "sha256:0d054ef16b071149917085f51f89555a576e2618d5d9dd70bd6eea6410af3ac9", + "sha256:19830b7dba7d5356d3e26e2427a2ec91c994cd92d983142cbd025ebe81d69cf3", + "sha256:1f7656b69974a6933e987ee8ffb951d836272d6c0f81d727f1d0e2696074d9e6", + "sha256:23488a14a83bca6e54402c2e6435467a4138785df93ec85aeff64c6170077fb0", + "sha256:23c7ff43fff4b0df93a186581885c8512bc50fc4d4910e0f838e35d6bb6b5e58", + "sha256:25c5750ba5609a0c7550b73a33deb314ecfb559c350bb050b655505e8aed4103", + "sha256:2ad53cf9c3adc43cf3bea0a7d01a2f2e86db9fe7596dfecb4496a5dda63cbb09", + "sha256:3fa7a477b9900be9b7dd4bab30a12759e5abe9586574ceb944bc29cddf8f0417", + "sha256:40b0f21484238269ae6a57200c807d80debc6459d444c0489a102d7c6a75fa56", + "sha256:4b21e5b1a70dfb972490035128f305c39bc4bc253f34e96a4adf9127cf943eb2", + "sha256:5a361d92635ad4ada1b1b2d3630fc2f53f2127d51cf2def9db83cba32e47c856", + "sha256:77a514ea15d3007d33a9e2157b0ba9c267496acf12a7f2b9b9f8446337aac5b0", + "sha256:855048b6feb6dfe09d3353466004490b1872887150c5bb5caad7838b57328cc8", + "sha256:9796a2ba7b4b538649caa5cecd398d873f4022ed2333ffde58eaf604c4d2cb27", + "sha256:98e02d56ebe93981c41211c05adb630d1d26c14195d04d95e49cd97dbc046dc5", + "sha256:b793b899f7cf563b1e7044a5c97361196b938e92f0a4343a5d27966a53d2ec71", + "sha256:d1ea5d12c8e2d266b5fb8c7a5d2e9c0219fedfeb493b7ed60cd350322384ac27", + "sha256:d2022bfadb7a5c2ef410d6a7c9763188afdb7f3533f22a0a32be10d571ee4bbe", + "sha256:d3348e7eb2eea2472db611486846742d5d52d1290576de99d59edeb7cd4a42ca", + "sha256:d744f72eb39f69312bc6c2abf8ff6656973120e2eb3f3ec4f758ed47e414a4bf", + "sha256:ef943c72a786b0f8d90fd76e9b39ce81fb7171172daf84bf43eaf937e9f220a9", + "sha256:f2899a3cbd394da157194f913a931edfd4be5f274a88041c9dc2d9cdcb1c315c" + ], + "index": "pypi", + "version": "==0.971" }, "mypy-extensions": { "hashes": [ @@ -942,7 +954,6 @@ "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb", "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522" ], - "markers": "python_version >= '3.6'", "version": "==21.3" }, "pathspec": { @@ -957,7 +968,6 @@ "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159", "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3" ], - "markers": "python_version >= '3.6'", "version": "==1.0.0" }, "py": { @@ -965,24 +975,30 @@ "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719", "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==1.11.0" }, "pyparsing": { "hashes": [ - "sha256:18ee9022775d270c55187733956460083db60b37d0d0fb357445f3094eed3eea", - "sha256:a6c06a88f252e6c322f65faf8f418b16213b51bdfaece0524c1c1bc30c63c484" + "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb", + "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc" ], - "markers": "python_version >= '3.6'", - "version": "==3.0.7" + "version": "==3.0.9" }, "pytest": { "hashes": [ - "sha256:9ce3ff477af913ecf6321fe337b93a2c0dcf2a0a1439c43f5452112c1e4280db", - "sha256:e30905a0c131d3d94b89624a1cc5afec3e0ba2fbdb151867d8e0ebd49850f171" + "sha256:13d0e3ccfc2b6e26be000cb6568c832ba67ba32e719443bfe725814d3c42433c", + "sha256:a06a0425453864a270bc45e71f783330a7428defb4230fb5e6a731fde06ecd45" ], "index": "pypi", - "version": "==7.0.1" + "version": "==7.1.2" + }, + "pytest-asyncio": { + "hashes": [ + "sha256:7a97e37cfe1ed296e2e84941384bdd37c376453912d397ed39293e0916f521fa", + "sha256:ac4ebf3b6207259750bc32f4c1d8fcd7e79739edbc67ad0c58dd150b1d072fed" + ], + "index": "pypi", + "version": "==0.19.0" }, "pytest-cov": { "hashes": [ @@ -994,89 +1010,96 @@ }, "regex": { "hashes": [ - "sha256:04611cc0f627fc4a50bc4a9a2e6178a974c6a6a4aa9c1cca921635d2c47b9c87", - "sha256:0b5d6f9aed3153487252d00a18e53f19b7f52a1651bc1d0c4b5844bc286dfa52", - "sha256:0d2f5c3f7057530afd7b739ed42eb04f1011203bc5e4663e1e1d01bb50f813e3", - "sha256:11772be1eb1748e0e197a40ffb82fb8fd0d6914cd147d841d9703e2bef24d288", - "sha256:1333b3ce73269f986b1fa4d5d395643810074dc2de5b9d262eb258daf37dc98f", - "sha256:16f81025bb3556eccb0681d7946e2b35ff254f9f888cff7d2120e8826330315c", - "sha256:1a171eaac36a08964d023eeff740b18a415f79aeb212169080c170ec42dd5184", - "sha256:1d6301f5288e9bdca65fab3de6b7de17362c5016d6bf8ee4ba4cbe833b2eda0f", - "sha256:1e031899cb2bc92c0cf4d45389eff5b078d1936860a1be3aa8c94fa25fb46ed8", - "sha256:1f8c0ae0a0de4e19fddaaff036f508db175f6f03db318c80bbc239a1def62d02", - "sha256:2245441445099411b528379dee83e56eadf449db924648e5feb9b747473f42e3", - "sha256:22709d701e7037e64dae2a04855021b62efd64a66c3ceed99dfd684bfef09e38", - "sha256:24c89346734a4e4d60ecf9b27cac4c1fee3431a413f7aa00be7c4d7bbacc2c4d", - "sha256:25716aa70a0d153cd844fe861d4f3315a6ccafce22b39d8aadbf7fcadff2b633", - "sha256:2dacb3dae6b8cc579637a7b72f008bff50a94cde5e36e432352f4ca57b9e54c4", - "sha256:34316bf693b1d2d29c087ee7e4bb10cdfa39da5f9c50fa15b07489b4ab93a1b5", - "sha256:36b2d700a27e168fa96272b42d28c7ac3ff72030c67b32f37c05616ebd22a202", - "sha256:37978254d9d00cda01acc1997513f786b6b971e57b778fbe7c20e30ae81a97f3", - "sha256:38289f1690a7e27aacd049e420769b996826f3728756859420eeee21cc857118", - "sha256:385ccf6d011b97768a640e9d4de25412204fbe8d6b9ae39ff115d4ff03f6fe5d", - "sha256:3c7ea86b9ca83e30fa4d4cd0eaf01db3ebcc7b2726a25990966627e39577d729", - "sha256:49810f907dfe6de8da5da7d2b238d343e6add62f01a15d03e2195afc180059ed", - "sha256:519c0b3a6fbb68afaa0febf0d28f6c4b0a1074aefc484802ecb9709faf181607", - "sha256:51f02ca184518702975b56affde6c573ebad4e411599005ce4468b1014b4786c", - "sha256:552a39987ac6655dad4bf6f17dd2b55c7b0c6e949d933b8846d2e312ee80005a", - "sha256:596f5ae2eeddb79b595583c2e0285312b2783b0ec759930c272dbf02f851ff75", - "sha256:6014038f52b4b2ac1fa41a58d439a8a00f015b5c0735a0cd4b09afe344c94899", - "sha256:61ebbcd208d78658b09e19c78920f1ad38936a0aa0f9c459c46c197d11c580a0", - "sha256:6213713ac743b190ecbf3f316d6e41d099e774812d470422b3a0f137ea635832", - "sha256:637e27ea1ebe4a561db75a880ac659ff439dec7f55588212e71700bb1ddd5af9", - "sha256:6aa427c55a0abec450bca10b64446331b5ca8f79b648531138f357569705bc4a", - "sha256:6ca45359d7a21644793de0e29de497ef7f1ae7268e346c4faf87b421fea364e6", - "sha256:6db1b52c6f2c04fafc8da17ea506608e6be7086715dab498570c3e55e4f8fbd1", - "sha256:752e7ddfb743344d447367baa85bccd3629c2c3940f70506eb5f01abce98ee68", - "sha256:760c54ad1b8a9b81951030a7e8e7c3ec0964c1cb9fee585a03ff53d9e531bb8e", - "sha256:768632fd8172ae03852e3245f11c8a425d95f65ff444ce46b3e673ae5b057b74", - "sha256:7a0b9f6a1a15d494b35f25ed07abda03209fa76c33564c09c9e81d34f4b919d7", - "sha256:7e070d3aef50ac3856f2ef5ec7214798453da878bb5e5a16c16a61edf1817cc3", - "sha256:7e12949e5071c20ec49ef00c75121ed2b076972132fc1913ddf5f76cae8d10b4", - "sha256:7e26eac9e52e8ce86f915fd33380f1b6896a2b51994e40bb094841e5003429b4", - "sha256:85ffd6b1cb0dfb037ede50ff3bef80d9bf7fa60515d192403af6745524524f3b", - "sha256:8618d9213a863c468a865e9d2ec50221015f7abf52221bc927152ef26c484b4c", - "sha256:8acef4d8a4353f6678fd1035422a937c2170de58a2b29f7da045d5249e934101", - "sha256:8d2f355a951f60f0843f2368b39970e4667517e54e86b1508e76f92b44811a8a", - "sha256:90b6840b6448203228a9d8464a7a0d99aa8fa9f027ef95fe230579abaf8a6ee1", - "sha256:9187500d83fd0cef4669385cbb0961e227a41c0c9bc39219044e35810793edf7", - "sha256:93c20777a72cae8620203ac11c4010365706062aa13aaedd1a21bb07adbb9d5d", - "sha256:93cce7d422a0093cfb3606beae38a8e47a25232eea0f292c878af580a9dc7605", - "sha256:94c623c331a48a5ccc7d25271399aff29729fa202c737ae3b4b28b89d2b0976d", - "sha256:97f32dc03a8054a4c4a5ab5d761ed4861e828b2c200febd4e46857069a483916", - "sha256:9a2bf98ac92f58777c0fafc772bf0493e67fcf677302e0c0a630ee517a43b949", - "sha256:a602bdc8607c99eb5b391592d58c92618dcd1537fdd87df1813f03fed49957a6", - "sha256:a9d24b03daf7415f78abc2d25a208f234e2c585e5e6f92f0204d2ab7b9ab48e3", - "sha256:abfcb0ef78df0ee9df4ea81f03beea41849340ce33a4c4bd4dbb99e23ec781b6", - "sha256:b013f759cd69cb0a62de954d6d2096d648bc210034b79b1881406b07ed0a83f9", - "sha256:b02e3e72665cd02afafb933453b0c9f6c59ff6e3708bd28d0d8580450e7e88af", - "sha256:b52cc45e71657bc4743a5606d9023459de929b2a198d545868e11898ba1c3f59", - "sha256:ba37f11e1d020969e8a779c06b4af866ffb6b854d7229db63c5fdddfceaa917f", - "sha256:bb804c7d0bfbd7e3f33924ff49757de9106c44e27979e2492819c16972ec0da2", - "sha256:bf594cc7cc9d528338d66674c10a5b25e3cde7dd75c3e96784df8f371d77a298", - "sha256:c38baee6bdb7fe1b110b6b3aaa555e6e872d322206b7245aa39572d3fc991ee4", - "sha256:c73d2166e4b210b73d1429c4f1ca97cea9cc090e5302df2a7a0a96ce55373f1c", - "sha256:c9099bf89078675c372339011ccfc9ec310310bf6c292b413c013eb90ffdcafc", - "sha256:cf0db26a1f76aa6b3aa314a74b8facd586b7a5457d05b64f8082a62c9c49582a", - "sha256:d19a34f8a3429bd536996ad53597b805c10352a8561d8382e05830df389d2b43", - "sha256:da80047524eac2acf7c04c18ac7a7da05a9136241f642dd2ed94269ef0d0a45a", - "sha256:de2923886b5d3214be951bc2ce3f6b8ac0d6dfd4a0d0e2a4d2e5523d8046fdfb", - "sha256:defa0652696ff0ba48c8aff5a1fac1eef1ca6ac9c660b047fc8e7623c4eb5093", - "sha256:e54a1eb9fd38f2779e973d2f8958fd575b532fe26013405d1afb9ee2374e7ab8", - "sha256:e5c31d70a478b0ca22a9d2d76d520ae996214019d39ed7dd93af872c7f301e52", - "sha256:ebaeb93f90c0903233b11ce913a7cb8f6ee069158406e056f884854c737d2442", - "sha256:ecfe51abf7f045e0b9cdde71ca9e153d11238679ef7b5da6c82093874adf3338", - "sha256:f99112aed4fb7cee00c7f77e8b964a9b10f69488cdff626ffd797d02e2e4484f", - "sha256:fd914db437ec25bfa410f8aa0aa2f3ba87cdfc04d9919d608d02330947afaeab" + "sha256:00d2e907d3c5e4f85197c8d2263a9cc2d34bf234a9c6236ae42a3fb0bc09b759", + "sha256:0186edcda692c38381db8ac257c2d023fd2e08818d45dc5bee4ed84212045f51", + "sha256:06c509bd7dcb7966bdb03974457d548e54d8327bad5b0c917e87248edc43e2eb", + "sha256:0a3f3f45c5902eb4d90266002ccb035531ae9b9278f6d5e8028247c34d192099", + "sha256:0c1821146b429e6fdbd13ea10f26765e48d5284bc79749468cfbfe3ceb929f0d", + "sha256:0d93167b7d7731fa9ff9fdc1bae84ec9c7133b01a35f8cc04e926d48da6ce1f7", + "sha256:0fd8c3635fa03ef79d07c7b3ed693b3f3930ccb52c0c51761c3296a7525b135c", + "sha256:119091c675e6ad19da8770f89aa1d52f4ad2a2018d631956f3e90c45882df880", + "sha256:121981ba84309dabefd5e1debd49be6d51624e54b4d44bfc184cd8d555ff1df1", + "sha256:1244e9b9b4b81c9c34e8a84273ffaeebdc78abc98a5b02dcdd49845eb3c63bd7", + "sha256:12e1404dfb4e928d3273a10e3468877fe84bdcd3c50b655a2c9613cfc5d9fe63", + "sha256:13d74951c14708f00700bb29475129ecbc40e01b4029c62ee7bfe9d1f59f31ce", + "sha256:162a5939a6fdf48658d3565eeff35acdd207e07367bf5caaff3d9ea7cb77d7a9", + "sha256:1703490c5b850fa9cef1af00c58966756042e6ca22f4fb5bb857345cd535834f", + "sha256:18e6203cfd81df42a987175aaeed7ba46bcb42130cd81763e2d5edcff0006d5d", + "sha256:192c2784833aea6fc7b004730bf1b91b8b8c6b998b30271aaf3bd8adfef20a96", + "sha256:1948d3ceac5b2d55bc93159c1e0679a256a87a54c735be5cef4543a9e692dbb9", + "sha256:206a327e628bc529d64b21ff79a5e2564f5aec7dc7abcd4b2e8a4b271ec10550", + "sha256:2e5db20412f0db8798ff72473d16da5f13ec808e975b49188badb2462f529fa9", + "sha256:2f94b0befc811fe74a972b1739fffbf74c0dc1a91102aca8e324aa4f2c6991bd", + "sha256:303676797c4c7978726e74eb8255d68f7125a3a29da71ff453448f2117290e9a", + "sha256:34ae4f35db30caa4caf85c55069fcb7a05966a3a5ba6e9e1dab5477d84fbb08a", + "sha256:3c6df8be7d1dd35a0d9a200fbc29f888c4452c8882d284f87608046152e049e6", + "sha256:402fa998c5988d11ed34585eb65740dcebd0fd11844d12eb0a6b4be178eb9c64", + "sha256:40a28759d345c0bb1f5b0ac74ac04f5d48136019522c95c0ec4b07786f67ce20", + "sha256:414ae507ba88264444baf771fec43ce0adcd4c5dbb304d3e0716f3f4d4499d2e", + "sha256:42da079e31ae9818ffa7a35cdd16ab7104e3f7eca9c0958040aede827b2e55c6", + "sha256:473a7d21932ce7c314953b33c32e63df690181860edcdf14bba1278cdf71b07f", + "sha256:49fcb45931a693b0e901972c5e077ea2cf30ec39da699645c43cb8b1542c6e14", + "sha256:4c5913cb9769038bd03e42318955c2f15a688384a6a0b807bcfc8271603d9277", + "sha256:4cfeb71095c8d8380a5df5a38ff94d27a3f483717e509130a822b4d6400b7991", + "sha256:4dc74f0171eede67d79a79c06eca0fe5b7b280dbb8c27ad1fae4ced2ad66268f", + "sha256:5b1cffff2d9f832288fe516021cb81c95c57c0067b13a82f1d2daabdbc2f4270", + "sha256:601c99ac775b6c89699a48976f3dbb000b47d3ca59362c8abc9582e6d0780d91", + "sha256:667a06bb8d72b6da3d9cf38dac4ba969688868ed2279a692e993d2c0e1c30aba", + "sha256:673549a0136c7893f567ed71ab5225ed3701c79b17c0a7faee846c645fc24010", + "sha256:67bd3bdd27db7a6460384869dd4b9c54267d805b67d70b20495bb5767f8e051c", + "sha256:727edff0a4eaff3b6d26cbb50216feac9055aba7e6290eec23c061c2fe2fab55", + "sha256:782627a1cb8fbb1c78d8e841f5b71c2c683086c038f975bebdac7cce7678a96f", + "sha256:7d462ba84655abeddae4dfc517fe1afefb5430b3b5acb0a954de12a47aea7183", + "sha256:8ab39aa445d00902c43a1e951871bedc7f18d095a21eccba153d594faac34aea", + "sha256:8e2075ed4ea2e231e2e98b16cfa5dae87e9a6045a71104525e1efc29aa8faa8e", + "sha256:9daeccb2764bf4cc280c40c6411ae176bb0876948e536590a052b3d647254c95", + "sha256:9e4006942334fa954ebd32fa0728718ec870f95f4ba7cda9edc46dd49c294f22", + "sha256:9f1c8fffd4def0b76c0947b8cb261b266e31041785dc2dc2db7569407a2f54fe", + "sha256:a00cd58a30a1041c193777cb1bc090200b05ff4b073d5935738afd1023e63069", + "sha256:a0220a7a16fd4bfc700661f920510defd31ef7830ce992d5cc51777aa8ccd724", + "sha256:a048f91823862270905cb22ef88038b08aac852ce48e0ecc4b4bf1b895ec37d9", + "sha256:a3c47c71fde0c5d584402e67546c81af9951540f1f622d821e9c20761556473a", + "sha256:a6d9ea727fd1233ee746bf44dd37e7d4320b3ed8ff09e73d7638c969b28d280f", + "sha256:ab0709daedc1099bbd4371ae17eeedd4efc1cf70fcdcfe5de1374a0944b61f80", + "sha256:ab1cb36b411f16da6e057ef8e6657dd0af36f59a667f07e0b4b617e44e53d7b2", + "sha256:ae1c5b435d44aa91d48cc710f20c3485e0584a3ad3565d5ae031d61a35f674f4", + "sha256:b279b9bb401af41130fd2a09427105100bc8c624ed45da1c81c1c0d0aa639734", + "sha256:b72a4ec79a15f6066d14ae1c472b743af4b4ecee14420e8d6e4a336b49b8f21c", + "sha256:c2cd93725911c0159d597b90c96151070ef7e0e67604637e2f2abe06c34bf079", + "sha256:c7c5f914b0eb5242c09f91058b80295525897e873b522575ab235b48db125597", + "sha256:d07d849c9e2eca80adb85d3567302a47195a603ad7b1f0a07508e253c041f954", + "sha256:d2672d68cf6c8452b6758fc3cd2d8feac966d511eed79a68182a5297b473af9c", + "sha256:d35bbcbf70d14f724e7489746cf68efe122796578addd98f91428e144d0ad266", + "sha256:d40b4447784dbe0896a6d10a178f6724598161f942c56f5a60dc0ef7fe63f7a1", + "sha256:d561dcb0fb0ab858291837d51330696a45fd3ba6912a332a4ee130e5484b9e47", + "sha256:d7f5ccfff648093152cadf6d886c7bd922047532f72024c953a79c7553aac2fe", + "sha256:dce6b2ad817e3eb107f8704782b091b0631dd3adf47f14bdc086165d05b528b0", + "sha256:e1fdda3ec7e9785065b67941693995cab95b54023a21db9bf39e54cc7b2c3526", + "sha256:e2a262ec85c595fc8e1f3162cafc654d2219125c00ea3a190c173cea70d2cc7a", + "sha256:e2fc1e3928c1189c0382c547c17717c6d9f425fffe619ef94270fe4c6c8be0a6", + "sha256:ea27acd97a752cfefa9907da935e583efecb302e6e9866f37565968c8407ad58", + "sha256:ee769a438827e443ed428e66d0aa7131c653ecd86ddc5d4644a81ed1d93af0e7", + "sha256:f32e0d1c7e7b0b9c3cac76f3d278e7ee6b99c95672d2c1c6ea625033431837c0", + "sha256:f355caec5bbce20421dc26e53787b10e32fd0df68db2b795435217210c08d69c", + "sha256:f87e9108bb532f8a1fc6bf7e69b930a35c7b0267b8fef0a3ede0bcb4c5aaa531", + "sha256:f8a2fd2f62a77536e4e3193303bec380df40d99e253b1c8f9b6eafa07eaeff67", + "sha256:fbdf4fc6adf38fab1091c579ece3fe9f493bd0f1cfc3d2c76d2e52461ca4f8a9" ], - "version": "==2022.1.18" + "version": "==2022.7.9" + }, + "requests": { + "hashes": [ + "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983", + "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349" + ], + "index": "pypi", + "version": "==2.28.1" }, "toml": { "hashes": [ "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" ], - "markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==0.10.2" }, "tomli": { @@ -1088,41 +1111,47 @@ }, "typed-ast": { "hashes": [ - "sha256:0eb77764ea470f14fcbb89d51bc6bbf5e7623446ac4ed06cbd9ca9495b62e36e", - "sha256:1098df9a0592dd4c8c0ccfc2e98931278a6c6c53cb3a3e2cf7e9ee3b06153344", - "sha256:183b183b7771a508395d2cbffd6db67d6ad52958a5fdc99f450d954003900266", - "sha256:18fe320f354d6f9ad3147859b6e16649a0781425268c4dde596093177660e71a", - "sha256:26a432dc219c6b6f38be20a958cbe1abffcc5492821d7e27f08606ef99e0dffd", - "sha256:294a6903a4d087db805a7656989f613371915fc45c8cc0ddc5c5a0a8ad9bea4d", - "sha256:31d8c6b2df19a777bc8826770b872a45a1f30cfefcfd729491baa5237faae837", - "sha256:33b4a19ddc9fc551ebabca9765d54d04600c4a50eda13893dadf67ed81d9a098", - "sha256:42c47c3b43fe3a39ddf8de1d40dbbfca60ac8530a36c9b198ea5b9efac75c09e", - "sha256:525a2d4088e70a9f75b08b3f87a51acc9cde640e19cc523c7e41aa355564ae27", - "sha256:58ae097a325e9bb7a684572d20eb3e1809802c5c9ec7108e85da1eb6c1a3331b", - "sha256:676d051b1da67a852c0447621fdd11c4e104827417bf216092ec3e286f7da596", - "sha256:74cac86cc586db8dfda0ce65d8bcd2bf17b58668dfcc3652762f3ef0e6677e76", - "sha256:8c08d6625bb258179b6e512f55ad20f9dfef019bbfbe3095247401e053a3ea30", - "sha256:90904d889ab8e81a956f2c0935a523cc4e077c7847a836abee832f868d5c26a4", - "sha256:963a0ccc9a4188524e6e6d39b12c9ca24cc2d45a71cfdd04a26d883c922b4b78", - "sha256:bbebc31bf11762b63bf61aaae232becb41c5bf6b3461b80a4df7e791fabb3aca", - "sha256:bc2542e83ac8399752bc16e0b35e038bdb659ba237f4222616b4e83fb9654985", - "sha256:c29dd9a3a9d259c9fa19d19738d021632d673f6ed9b35a739f48e5f807f264fb", - "sha256:c7407cfcad702f0b6c0e0f3e7ab876cd1d2c13b14ce770e412c0c4b9728a0f88", - "sha256:da0a98d458010bf4fe535f2d1e367a2e2060e105978873c04c04212fb20543f7", - "sha256:df05aa5b241e2e8045f5f4367a9f6187b09c4cdf8578bb219861c4e27c443db5", - "sha256:f290617f74a610849bd8f5514e34ae3d09eafd521dceaa6cf68b3f4414266d4e", - "sha256:f30ddd110634c2d7534b2d4e0e22967e88366b0d356b24de87419cc4410c41b7" + "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2", + "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1", + "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6", + "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62", + "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac", + "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d", + "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc", + "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2", + "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97", + "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35", + "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6", + "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1", + "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4", + "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c", + "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e", + "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec", + "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f", + "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72", + "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47", + "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72", + "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe", + "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6", + "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3", + "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66" ], - "markers": "python_version >= '3.6'", - "version": "==1.5.2" + "version": "==1.5.4" }, "typing-extensions": { "hashes": [ - "sha256:1a9462dcc3347a79b1f1c0271fbe79e844580bb598bafa1ed208b94da3cdcd42", - "sha256:21c85e0fe4b9a155d0799430b0ad741cdce7e359660ccbd8b530613e8df88ce2" + "sha256:25642c956049920a5aa49edcdd6ab1e06d7e5d467fc00e0506c44ac86fbfca02", + "sha256:e6d2677a32f47fc7eb2795db1dd15c1f34eff616bcaf2cfb5e997f854fa1c4a6" ], "index": "pypi", - "version": "==4.1.1" + "version": "==4.3.0" + }, + "urllib3": { + "hashes": [ + "sha256:8298d6d56d39be0e3bc13c1c97d133f9b45d797169a0e11cdd0e0489d786f7ec", + "sha256:879ba4d1e89654d9769ce13121e0f94310ea32e8d2f8cf587b77c08bbcdb30d6" + ], + "version": "==1.26.10" } } } diff --git a/Procfile b/Procfile deleted file mode 100644 index c0ca4887..00000000 --- a/Procfile +++ /dev/null @@ -1 +0,0 @@ -web: hypercorn -k trio --bind 0.0.0.0:5000 'lnbits.app:create_app()' diff --git a/README.md b/README.md index 020f617c..f0f9df62 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ LNbits (LNbits is beta, for responsible disclosure of any concerns please contact lnbits@pm.me) -Use [lnbits.com](https://lnbits.com), or run your own LNbits server! +Use [legend.lnbits.com](https://legend.lnbits.com), or run your own LNbits server! LNbits is a very simple Python server that sits on top of any funding source, and can be used as: @@ -33,7 +33,7 @@ LNbits is inspired by all the great work of [opennode.com](https://www.opennode. ## Running LNbits -See the [install guide](docs/devs/installation.md) for details on installation and setup. +See the [install guide](docs/guide/installation.md) for details on installation and setup. ## LNbits as an account system @@ -67,7 +67,7 @@ Wallets can be easily generated and given out to people at events (one click mul ## Tip us -If you like this project and might even use or extend it, why not [send some tip love](https://lnbits.com/paywall/GAqKguK5S8f6w5VNjS9DfK)! +If you like this project and might even use or extend it, why not [send some tip love](https://legend.lnbits.com/paywall/GAqKguK5S8f6w5VNjS9DfK)! [docs]: https://lnbits.org/ diff --git a/app.json b/app.json deleted file mode 100644 index 5f5d5bb1..00000000 --- a/app.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "scripts": { - "dokku": { - "predeploy": "quart migrate && quart assets" - } - } -} diff --git a/docs/devs/extensions.md b/docs/devs/extensions.md index 70e599e9..8c9a30a4 100644 --- a/docs/devs/extensions.md +++ b/docs/devs/extensions.md @@ -15,6 +15,7 @@ cp lnbits/extensions/example lnbits/extensions/mysuperplugin -r # Let's not use cd lnbits/extensions/mysuperplugin find . -type f -print0 | xargs -0 sed -i 's/example/mysuperplugin/g' # Change all occurrences of 'example' to your plugin name 'mysuperplugin'. ``` +- if you are on macOS and having difficulty with 'sed', consider `brew install gnu-sed` and use 'gsed', without -0 option after xargs. Going over the example extension's structure: * views_api.py: This is where your public API would go. It will be exposed at "$DOMAIN/$PLUGIN/$ROUTE". For example: https://lnbits.com/mysuperplugin/api/v1/tools. diff --git a/docs/devs/installation.md b/docs/devs/installation.md index cbf234cc..f4d6b145 100644 --- a/docs/devs/installation.md +++ b/docs/devs/installation.md @@ -7,46 +7,10 @@ nav_order: 1 # Installation -LNbits uses [Pipenv][pipenv] to manage Python packages. +This guide has been moved to the [installation guide](../guide/installation.md). +To install the developer packages, use `pipenv install --dev`. -```sh -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend/ +## Notes: -sudo apt-get install pipenv -pipenv shell -# pipenv --python 3.9 shell (if you wish to use a version of Python higher than 3.7) -pipenv install --dev -# pipenv --python 3.9 install --dev (if you wish to use a version of Python higher than 3.7) - -# If any of the modules fails to install, try checking and upgrading your setupTool module -# pip install -U setuptools - -# install libffi/libpq in case "pipenv install" fails -# sudo apt-get install -y libffi-dev libpq-dev -``` -## Running the server - -Create the data folder and edit the .env file: - - mkdir data - cp .env.example .env - sudo nano .env - -To then run the server for development purposes (includes hot-reload), use: - - pipenv run python -m uvicorn lnbits.__main__:app --host 0.0.0.0 --reload - -For production, use: - - pipenv run python -m uvicorn lnbits.__main__:app --host 0.0.0.0 - -You might also need to install additional packages, depending on the [backend wallet](../guide/wallets.md) you use. -E.g. when you want to use LND you have to `pipenv run pip install lndgrpc` and `pipenv run pip install purerpc`. - -Take a look at [Polar][polar] for an excellent way of spinning up a Lightning Network dev environment. - -**Notes**: - -* We reccomend using Caddy for a reverse-proxy if you want to serve your install through a domain, alternatively you can use [ngrok](https://ngrok.com/). +* We recommend using Caddy for a reverse-proxy if you want to serve your install through a domain, alternatively you can use [ngrok](https://ngrok.com/). * Screen works well if you want LNbits to continue running when you close your terminal session. diff --git a/docs/guide/installation.md b/docs/guide/installation.md index b458c3f1..591516f1 100644 --- a/docs/guide/installation.md +++ b/docs/guide/installation.md @@ -4,8 +4,88 @@ title: Basic installation nav_order: 2 --- + + # Basic installation -Install Postgres and setup a database for LNbits: + +You can choose between two python package managers, `venv` and `pipenv`. Both are fine but if you don't know what you're doing, just go for the first option. + +By default, LNbits will use SQLite as its database. You can also use PostgreSQL which is recommended for applications with a high load (see guide below). + +## Option 1: pipenv + +You can also use Pipenv to manage your python packages. + +```sh +git clone https://github.com/lnbits/lnbits-legend.git +cd lnbits-legend/ + +sudo apt update && sudo apt install -y pipenv +pipenv install --dev +# pipenv --python 3.9 install --dev (if you wish to use a version of Python higher than 3.7) +pipenv shell +# pipenv --python 3.9 shell (if you wish to use a version of Python higher than 3.7) + +# If any of the modules fails to install, try checking and upgrading your setupTool module +# pip install -U setuptools wheel + +# install libffi/libpq in case "pipenv install" fails +# sudo apt-get install -y libffi-dev libpq-dev + + mkdir data && cp .env.example .env +``` + +#### Running the server + +```sh +pipenv run python -m uvicorn lnbits.__main__:app --port 5000 --host 0.0.0.0 +``` + +Add the flag `--reload` for development (includes hot-reload). + + +## Option 2: venv + +Download this repo and install the dependencies: + +```sh +git clone https://github.com/lnbits/lnbits-legend.git +cd lnbits-legend/ +# ensure you have virtualenv installed, on debian/ubuntu 'apt install python3-venv' +python3 -m venv venv +# If you have problems here, try `sudo apt install -y pkg-config libpq-dev` +./venv/bin/pip install -r requirements.txt +# create the data folder and the .env file +mkdir data && cp .env.example .env +``` + +#### Running the server + +```sh +./venv/bin/uvicorn lnbits.__main__:app --port 5000 +``` + +If you want to host LNbits on the internet, run with the option `--host 0.0.0.0`. + +### Troubleshooting + +Problems installing? These commands have helped us install LNbits. + +```sh +sudo apt install pkg-config libffi-dev libpq-dev + +# if the secp256k1 build fails: +# if you used pipenv (option 1) +pipenv install setuptools wheel +# if you used venv (option 2) +./venv/bin/pip install setuptools wheel +# build essentials for debian/ubuntu +sudo apt install python3-dev gcc build-essential +``` + +### Optional: PostgreSQL database + +If you want to use LNbits at scale, we recommend using PostgreSQL as the backend database. Install Postgres and setup a database for LNbits: ```sh # on debian/ubuntu 'sudo apt-get -y install postgresql' @@ -22,34 +102,35 @@ createdb lnbits exit ``` -Download this repo and install the dependencies: +You need to edit the `.env` file. ```sh -git clone https://github.com/lnbits/lnbits-legend.git -cd lnbits-legend/ -# ensure you have virtualenv installed, on debian/ubuntu 'apt install python3-venv' should work -python3 -m venv venv -./venv/bin/pip install -r requirements.txt -cp .env.example .env # add the database connection string to .env 'nano .env' LNBITS_DATABASE_URL= # postgres://:@/ - alter line bellow with your user, password and db name LNBITS_DATABASE_URL="postgres://postgres:postgres@localhost/lnbits" # save and exit -./venv/bin/uvicorn lnbits.__main__:app --port 5000 ``` +# Using LNbits + Now you can visit your LNbits at http://localhost:5000/. -Now modify the `.env` file with any settings you prefer and add a proper [funding source](./wallets.md) by modifying the value of `LNBITS_BACKEND_WALLET_CLASS` and providing the extra information and credentials related to the chosen funding source. +Now modify the `.env` file with any settings you prefer and add a proper [funding source](./wallets.md) by modifying the value of `LNBITS_BACKEND_WALLET_CLASS` and providing the extra information and credentials related to the chosen funding source. Then you can restart it and it will be using the new settings. -You might also need to install additional packages or perform additional setup steps, depending on the chosen backend. See [the short guide](./wallets.md) on each different funding source. +You might also need to install additional packages or perform additional setup steps, depending on the chosen backend. See [the short guide](./wallets.md) on each different funding source. -## Important note -If you already have LNbits installed and running, on an SQLite database, we **HIGHLY** recommend you migrate to postgres! +Take a look at [Polar](https://lightningpolar.com/) for an excellent way of spinning up a Lightning Network dev environment. -There's a script included that can do the migration easy. You should have Postgres already installed and there should be a password for the user, check the guide above. Additionally, your lnbits instance should run once on postgres to implement the database schema before the migration works: + + +# Additional guides + +## SQLite to PostgreSQL migration +If you already have LNbits installed and running, on an SQLite database, we **highly** recommend you migrate to postgres if you are planning to run LNbits on scale. + +There's a script included that can do the migration easy. You should have Postgres already installed and there should be a password for the user (see Postgres install guide above). Additionally, your LNbits instance should run once on postgres to implement the database schema before the migration works: ```sh # STOP LNbits @@ -61,17 +142,14 @@ LNBITS_DATABASE_URL="postgres://postgres:postgres@localhost/lnbits" # START LNbits # STOP LNbits -# on the LNBits folder, locate and edit 'conv.py' with the relevant credentials -python3 conv.py +# on the LNBits folder, locate and edit 'tools/conv.py' with the relevant credentials +python3 tools/conv.py ``` Hopefully, everything works and get migrated... Launch LNbits again and check if everything is working properly. - -# Additional guides - -### LNbits as a systemd service +## LNbits as a systemd service Systemd is great for taking care of your LNbits instance. It will start it on boot and restart it in case it crashes. If you want to run LNbits as a systemd service on your Debian/Ubuntu/Raspbian server, create a file at `/etc/systemd/system/lnbits.service` with the following content: @@ -110,11 +188,40 @@ sudo systemctl enable lnbits.service sudo systemctl start lnbits.service ``` -### LNbits running on Umbrel behind Tor +## Using https without reverse proxy +The most common way of using LNbits via https is to use a reverse proxy such as Caddy, nginx, or ngriok. However, you can also run LNbits via https without additional software. This is useful for development purposes or if you want to use LNbits in your local network. + +We have to create a self-signed certificate using `mkcert`. Note that this certiciate is not "trusted" by most browsers but that's fine (since you know that you have created it) and encryption is always better than clear text. + +#### Install mkcert +You can find the install instructions for `mkcert` [here](https://github.com/FiloSottile/mkcert). + +Install mkcert on Ubuntu: +```sh +sudo apt install libnss3-tools +curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64" +chmod +x mkcert-v*-linux-amd64 +sudo cp mkcert-v*-linux-amd64 /usr/local/bin/mkcert +``` +#### Create certificate +To create a certificate, first `cd` into your lnbits folder and execute the following command ([more info](https://kifarunix.com/how-to-create-self-signed-ssl-certificate-with-mkcert-on-ubuntu-18-04/)) +```sh +# add your local IP (192.x.x.x) as well if you want to use it in your local network +mkcert localhost 127.0.0.1 ::1 +``` + +This will create two new files (`localhost-key.pem` and `localhost.pem `) which you can then pass to uvicorn when you start LNbits: + +```sh +./venv/bin/uvicorn lnbits.__main__:app --host 0.0.0.0 --port 5000 --ssl-keyfile ./localhost-key.pem --ssl-certfile ./localhost.pem +``` + + +## LNbits running on Umbrel behind Tor If you want to run LNbits on your Umbrel but want it to be reached through clearnet, _Uxellodunum_ made an extensive [guide](https://community.getumbrel.com/t/guide-lnbits-without-tor/604) on how to do it. -### Docker installation +## Docker installation To install using docker you first need to build the docker image as: @@ -146,9 +253,3 @@ docker run --detach --publish 5000:5000 --name lnbits --volume ${PWD}/.env:/app/ ``` Finally you can access your lnbits on your machine at port 5000. - -# Additional guides - -## LNbits running on Umbrel behind Tor - -If you want to run LNbits on your Umbrel but want it to be reached through clearnet, _Uxellodunum_ made an extensive [guide](https://community.getumbrel.com/t/guide-lnbits-without-tor/604) on how to do it. diff --git a/lnbits/__main__.py b/lnbits/__main__.py index aa652899..90cb1997 100644 --- a/lnbits/__main__.py +++ b/lnbits/__main__.py @@ -1,21 +1,19 @@ import asyncio import uvloop -from starlette.requests import Request - from loguru import logger +from starlette.requests import Request from .commands import migrate_databases from .settings import ( DEBUG, + HOST, LNBITS_COMMIT, LNBITS_DATA_FOLDER, + LNBITS_DATABASE_URL, LNBITS_SITE_TITLE, - HOST, PORT, WALLET, - LNBITS_DATABASE_URL, - LNBITS_DATA_FOLDER, ) uvloop.install() diff --git a/lnbits/app.py b/lnbits/app.py index 84df250f..83a9749b 100644 --- a/lnbits/app.py +++ b/lnbits/app.py @@ -1,11 +1,9 @@ import asyncio import importlib +import logging import sys import traceback import warnings - -from loguru import logger - from http import HTTPStatus from fastapi import FastAPI, Request @@ -14,6 +12,7 @@ from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.gzip import GZipMiddleware from fastapi.responses import JSONResponse from fastapi.staticfiles import StaticFiles +from loguru import logger import lnbits.settings from lnbits.core.tasks import register_task_listeners @@ -199,8 +198,33 @@ def register_exception_handlers(app: FastAPI): def configure_logger() -> None: logger.remove() log_level: str = "DEBUG" if lnbits.settings.DEBUG else "INFO" - if lnbits.settings.DEBUG: - fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level: <6} | {name}:{function}:{line} | {message}" - else: - fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level} | {message}" - logger.add(sys.stderr, level=log_level, format=fmt) + formatter = Formatter() + logger.add(sys.stderr, level=log_level, format=formatter.format) + + logging.getLogger("uvicorn").handlers = [InterceptHandler()] + logging.getLogger("uvicorn.access").handlers = [InterceptHandler()] + + +class Formatter: + def __init__(self): + self.padding = 0 + self.minimal_fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level} | {message}\n" + if lnbits.settings.DEBUG: + self.fmt: str = "{time:YYYY-MM-DD HH:mm:ss.SS} | {level: <4} | {name}:{function}:{line} | {message}\n" + else: + self.fmt: str = self.minimal_fmt + + def format(self, record): + function = "{function}".format(**record) + if function == "emit": # uvicorn logs + return self.minimal_fmt + return self.fmt + + +class InterceptHandler(logging.Handler): + def emit(self, record): + try: + level = logger.level(record.levelname).name + except ValueError: + level = record.levelno + logger.log(level, record.getMessage()) diff --git a/lnbits/bolt11.py b/lnbits/bolt11.py index e5221984..cc841585 100644 --- a/lnbits/bolt11.py +++ b/lnbits/bolt11.py @@ -1,15 +1,16 @@ -import bitstring # type: ignore -import re import hashlib -from typing import List, NamedTuple, Optional -from bech32 import bech32_encode, bech32_decode, CHARSET -from ecdsa import SECP256k1, VerifyingKey # type: ignore -from ecdsa.util import sigdecode_string # type: ignore -from binascii import unhexlify +import re import time +from binascii import unhexlify from decimal import Decimal +from typing import List, NamedTuple, Optional + +import bitstring # type: ignore import embit import secp256k1 +from bech32 import CHARSET, bech32_decode, bech32_encode +from ecdsa import SECP256k1, VerifyingKey # type: ignore +from ecdsa.util import sigdecode_string # type: ignore class Route(NamedTuple): diff --git a/lnbits/commands.py b/lnbits/commands.py index 13e926e8..0f7454f2 100644 --- a/lnbits/commands.py +++ b/lnbits/commands.py @@ -1,18 +1,19 @@ import asyncio -import warnings -import click import importlib -import re import os +import re +import warnings +import click from loguru import logger -from .db import SQLITE, POSTGRES, COCKROACH -from .core import db as core_db, migrations as core_migrations +from .core import db as core_db +from .core import migrations as core_migrations +from .db import COCKROACH, POSTGRES, SQLITE from .helpers import ( - get_valid_extensions, get_css_vendored, get_js_vendored, + get_valid_extensions, url_for_vendored, ) from .settings import LNBITS_PATH diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index 1493d4e4..770e2906 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -1,15 +1,15 @@ -import json import datetime -from uuid import uuid4 -from typing import List, Optional, Dict, Any +import json +from typing import Any, Dict, List, Optional from urllib.parse import urlparse +from uuid import uuid4 from lnbits import bolt11 -from lnbits.db import Connection, POSTGRES, COCKROACH +from lnbits.db import COCKROACH, POSTGRES, Connection from lnbits.settings import DEFAULT_WALLET_NAME, LNBITS_ADMIN_USERS from . import db -from .models import User, Wallet, Payment, BalanceCheck +from .models import BalanceCheck, Payment, User, Wallet # accounts # -------- diff --git a/lnbits/core/models.py b/lnbits/core/models.py index a6cdb23b..ab73b702 100644 --- a/lnbits/core/models.py +++ b/lnbits/core/models.py @@ -1,15 +1,15 @@ -import json -import hmac import hashlib -from lnbits.helpers import url_for +import hmac +import json +from sqlite3 import Row +from typing import Dict, List, NamedTuple, Optional + from ecdsa import SECP256k1, SigningKey # type: ignore from lnurl import encode as lnurl_encode # type: ignore -from typing import List, NamedTuple, Optional, Dict -from sqlite3 import Row +from loguru import logger from pydantic import BaseModel -from loguru import logger - +from lnbits.helpers import url_for from lnbits.settings import WALLET diff --git a/lnbits/core/services.py b/lnbits/core/services.py index 6a24348e..0b565ebb 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -3,20 +3,25 @@ import json from binascii import unhexlify from io import BytesIO from typing import Dict, Optional, Tuple - -from loguru import logger - from urllib.parse import parse_qs, urlparse import httpx +from fastapi import Depends from lnurl import LnurlErrorResponse from lnurl import decode as decode_lnurl # type: ignore +from loguru import logger from lnbits import bolt11 from lnbits.db import Connection +from lnbits.decorators import ( + WalletTypeInfo, + get_key_type, + require_admin_key, + require_invoice_key, +) from lnbits.helpers import url_for, urlsafe_short_hash from lnbits.requestvars import g -from lnbits.settings import WALLET +from lnbits.settings import FAKE_WALLET, WALLET from lnbits.wallets.base import PaymentResponse, PaymentStatus from . import db @@ -51,15 +56,19 @@ async def create_invoice( description_hash: Optional[bytes] = None, extra: Optional[Dict] = None, webhook: Optional[str] = None, + internal: Optional[bool] = False, conn: Optional[Connection] = None, ) -> Tuple[str, str]: invoice_memo = None if description_hash else memo - ok, checking_id, payment_request, error_message = await WALLET.create_invoice( + # use the fake wallet if the invoice is for internal use only + wallet = FAKE_WALLET if internal else WALLET + + ok, checking_id, payment_request, error_message = await wallet.create_invoice( amount=amount, memo=invoice_memo, description_hash=description_hash ) if not ok: - raise InvoiceFailure(error_message or "Unexpected backend error.") + raise InvoiceFailure(error_message or "unexpected backend error.") invoice = bolt11.decode(payment_request) @@ -229,7 +238,7 @@ async def redeem_lnurl_withdraw( conn=conn, ) except: - logger.warn( + logger.warning( f"failed to create invoice on redeem_lnurl_withdraw from {lnurl}. params: {res}" ) return None @@ -256,12 +265,14 @@ async def redeem_lnurl_withdraw( async def perform_lnurlauth( - callback: str, conn: Optional[Connection] = None + callback: str, + wallet: WalletTypeInfo = Depends(require_admin_key), + conn: Optional[Connection] = None, ) -> Optional[LnurlErrorResponse]: cb = urlparse(callback) k1 = unhexlify(parse_qs(cb.query)["k1"][0]) - key = g().wallet.lnurlauth_key(cb.netloc) + key = wallet.wallet.lnurlauth_key(cb.netloc) def int_to_bytes_suitable_der(x: int) -> bytes: """for strict DER we need to encode the integer with some quirks""" diff --git a/lnbits/core/static/js/extensions.js b/lnbits/core/static/js/extensions.js index 85ace775..ec8f811c 100644 --- a/lnbits/core/static/js/extensions.js +++ b/lnbits/core/static/js/extensions.js @@ -1,4 +1,36 @@ new Vue({ el: '#vue', + data: function () { + return { + searchTerm: '', + filteredExtensions: null + } + }, + mounted() { + this.filteredExtensions = this.g.extensions + }, + watch: { + searchTerm(term) { + // Reset the filter + this.filteredExtensions = this.g.extensions + if (term !== '') { + // Filter the extensions list + function extensionNameContains(searchTerm) { + return function (extension) { + return ( + extension.name.toLowerCase().includes(searchTerm.toLowerCase()) || + extension.shortDescription + .toLowerCase() + .includes(searchTerm.toLowerCase()) + ) + } + } + + this.filteredExtensions = this.filteredExtensions.filter( + extensionNameContains(term) + ) + } + } + }, mixins: [windowMixin] }) diff --git a/lnbits/core/tasks.py b/lnbits/core/tasks.py index bb258958..5fea769d 100644 --- a/lnbits/core/tasks.py +++ b/lnbits/core/tasks.py @@ -1,7 +1,7 @@ import asyncio -import httpx from typing import List +import httpx from loguru import logger from lnbits.tasks import register_invoice_listener diff --git a/lnbits/core/templates/core/_api_docs.html b/lnbits/core/templates/core/_api_docs.html index 271568d4..383f2b12 100644 --- a/lnbits/core/templates/core/_api_docs.html +++ b/lnbits/core/templates/core/_api_docs.html @@ -49,7 +49,8 @@
Body (application/json)
{"out": false, "amount": <int>, "memo": <string>, "unit": - <string>, "webhook": <url:string>}
Returns 201 CREATED (application/json) diff --git a/lnbits/core/templates/core/extensions.html b/lnbits/core/templates/core/extensions.html index daeb660f..1b527903 100644 --- a/lnbits/core/templates/core/extensions.html +++ b/lnbits/core/templates/core/extensions.html @@ -2,10 +2,23 @@ %} {% block scripts %} {{ window_vars(user) }} {% endblock %} {% block page %} +
+
+ + + +
+
+
diff --git a/lnbits/core/views/api.py b/lnbits/core/views/api.py index 2a4cc3e8..9fee6063 100644 --- a/lnbits/core/views/api.py +++ b/lnbits/core/views/api.py @@ -7,30 +7,23 @@ from typing import Dict, List, Optional, Union from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse import httpx - -from loguru import logger - -from fastapi import Header, Query, Request +from fastapi import Depends, Header, Query, Request from fastapi.exceptions import HTTPException -from fastapi.param_functions import Depends from fastapi.params import Body +from loguru import logger from pydantic import BaseModel from pydantic.fields import Field from sse_starlette.sse import EventSourceResponse from lnbits import bolt11, lnurl -from lnbits.bolt11 import Invoice from lnbits.core.models import Payment, Wallet from lnbits.decorators import ( - WalletAdminKeyChecker, - WalletInvoiceKeyChecker, WalletTypeInfo, get_key_type, require_admin_key, require_invoice_key, ) from lnbits.helpers import url_for, urlsafe_short_hash -from lnbits.requestvars import g from lnbits.settings import LNBITS_ADMIN_USERS, LNBITS_SITE_TITLE from lnbits.utils.exchange_rates import ( currencies, @@ -149,6 +142,7 @@ class CreateInvoiceData(BaseModel): lnurl_balance_check: Optional[str] = None extra: Optional[dict] = None webhook: Optional[str] = None + internal: Optional[bool] = False bolt11: Optional[str] = None @@ -175,6 +169,7 @@ async def api_payments_create_invoice(data: CreateInvoiceData, wallet: Wallet): description_hash=description_hash, extra=data.extra, webhook=data.webhook, + internal=data.internal, conn=conn, ) except InvoiceFailure as e: @@ -395,7 +390,7 @@ async def api_payment(payment_hash, X_Api_Key: Optional[str] = Header(None)): wallet = None try: if X_Api_Key.extra: - logger.warn("No key") + logger.warning("No key") except: wallet = await get_wallet_for_key(X_Api_Key) payment = await get_standalone_payment( @@ -435,10 +430,8 @@ async def api_payment(payment_hash, X_Api_Key: Optional[str] = Header(None)): return {"paid": not payment.pending, "preimage": payment.preimage} -@core_app.get( - "/api/v1/lnurlscan/{code}", dependencies=[Depends(WalletInvoiceKeyChecker())] -) -async def api_lnurlscan(code: str): +@core_app.get("/api/v1/lnurlscan/{code}") +async def api_lnurlscan(code: str, wallet: WalletTypeInfo = Depends(get_key_type)): try: url = lnurl.decode(code) domain = urlparse(url).netloc @@ -466,7 +459,7 @@ async def api_lnurlscan(code: str): params.update(kind="auth") params.update(callback=url) # with k1 already in it - lnurlauth_key = g().wallet.lnurlauth_key(domain) + lnurlauth_key = wallet.wallet.lnurlauth_key(domain) params.update(pubkey=lnurlauth_key.verifying_key.to_string("compressed").hex()) else: async with httpx.AsyncClient() as client: @@ -582,14 +575,19 @@ async def api_payments_decode(data: DecodePayment): return {"message": "Failed to decode"} -@core_app.post("/api/v1/lnurlauth", dependencies=[Depends(WalletAdminKeyChecker())]) -async def api_perform_lnurlauth(callback: str): - err = await perform_lnurlauth(callback) +class Callback(BaseModel): + callback: str = Query(...) + + +@core_app.post("/api/v1/lnurlauth") +async def api_perform_lnurlauth( + callback: Callback, wallet: WalletTypeInfo = Depends(require_admin_key) +): + err = await perform_lnurlauth(callback.callback, wallet=wallet) if err: raise HTTPException( status_code=HTTPStatus.SERVICE_UNAVAILABLE, detail=err.reason ) - return "" diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py index b6750c95..86f7ecff 100644 --- a/lnbits/core/views/generic.py +++ b/lnbits/core/views/generic.py @@ -7,11 +7,10 @@ from fastapi.exceptions import HTTPException from fastapi.params import Depends, Query from fastapi.responses import FileResponse, RedirectResponse from fastapi.routing import APIRouter +from loguru import logger from pydantic.types import UUID4 from starlette.responses import HTMLResponse, JSONResponse -from loguru import logger - from lnbits.core import db from lnbits.core.models import User from lnbits.decorators import check_user_exists @@ -113,7 +112,7 @@ async def wallet( if not user_id: user = await get_user((await create_account()).id) - logger.info(f"Created new account for user {user.id}") + logger.info(f"Create user {user.id}") else: user = await get_user(user_id) if not user: @@ -140,7 +139,7 @@ async def wallet( status_code=status.HTTP_307_TEMPORARY_REDIRECT, ) - logger.info(f"Access wallet {wallet_name} of user {user.id}") + logger.debug(f"Access wallet {wallet_name}{'of user '+ user.id if user else ''}") wallet = user.get_wallet(wallet_id) if not wallet: return template_renderer().TemplateResponse( diff --git a/lnbits/core/views/public_api.py b/lnbits/core/views/public_api.py index 0b84243e..2d2cdd66 100644 --- a/lnbits/core/views/public_api.py +++ b/lnbits/core/views/public_api.py @@ -4,11 +4,10 @@ from http import HTTPStatus from urllib.parse import urlparse from fastapi import HTTPException +from loguru import logger from starlette.requests import Request from starlette.responses import HTMLResponse -from loguru import logger - from lnbits import bolt11 from .. import core_app diff --git a/lnbits/db.py b/lnbits/db.py index bed9397f..66981784 100644 --- a/lnbits/db.py +++ b/lnbits/db.py @@ -6,7 +6,6 @@ from contextlib import asynccontextmanager from typing import Optional from loguru import logger - from sqlalchemy import create_engine from sqlalchemy_aio.base import AsyncConnection from sqlalchemy_aio.strategy import ASYNCIO_STRATEGY # type: ignore diff --git a/lnbits/decorators.py b/lnbits/decorators.py index d6f73f40..e65b9041 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -14,9 +14,9 @@ from lnbits.core.crud import get_user, get_wallet_for_key from lnbits.core.models import User, Wallet from lnbits.requestvars import g from lnbits.settings import ( - LNBITS_ALLOWED_USERS, - LNBITS_ADMIN_USERS, LNBITS_ADMIN_EXTENSIONS, + LNBITS_ADMIN_USERS, + LNBITS_ALLOWED_USERS, ) diff --git a/lnbits/extensions/bleskomat/exchange_rates.py b/lnbits/extensions/bleskomat/exchange_rates.py index dcdaa220..e5eb843f 100644 --- a/lnbits/extensions/bleskomat/exchange_rates.py +++ b/lnbits/extensions/bleskomat/exchange_rates.py @@ -1,7 +1,8 @@ -import httpx import json import os +import httpx + fiat_currencies = json.load( open( os.path.join( diff --git a/lnbits/extensions/bleskomat/lnurl_api.py b/lnbits/extensions/bleskomat/lnurl_api.py index 212f9b4a..33e33a70 100644 --- a/lnbits/extensions/bleskomat/lnurl_api.py +++ b/lnbits/extensions/bleskomat/lnurl_api.py @@ -3,9 +3,8 @@ import math import traceback from http import HTTPStatus -from starlette.requests import Request - from loguru import logger +from starlette.requests import Request from . import bleskomat_ext from .crud import ( diff --git a/lnbits/extensions/bleskomat/models.py b/lnbits/extensions/bleskomat/models.py index ab952b55..364cbe22 100644 --- a/lnbits/extensions/bleskomat/models.py +++ b/lnbits/extensions/bleskomat/models.py @@ -3,13 +3,12 @@ import time from typing import Dict from fastapi.params import Query +from loguru import logger from pydantic import BaseModel, validator from starlette.requests import Request -from loguru import logger - from lnbits import bolt11 -from lnbits.core.services import pay_invoice, PaymentFailure +from lnbits.core.services import PaymentFailure, pay_invoice from . import db from .exchange_rates import exchange_rate_providers, fiat_currencies diff --git a/lnbits/extensions/bleskomat/views_api.py b/lnbits/extensions/bleskomat/views_api.py index 81efa4ab..e29e3fe7 100644 --- a/lnbits/extensions/bleskomat/views_api.py +++ b/lnbits/extensions/bleskomat/views_api.py @@ -1,9 +1,8 @@ from http import HTTPStatus from fastapi import Depends, Query -from starlette.exceptions import HTTPException - from loguru import logger +from starlette.exceptions import HTTPException from lnbits.core.crud import get_user from lnbits.decorators import WalletTypeInfo, require_admin_key diff --git a/lnbits/extensions/copilot/models.py b/lnbits/extensions/copilot/models.py index a279879d..b9b43ccf 100644 --- a/lnbits/extensions/copilot/models.py +++ b/lnbits/extensions/copilot/models.py @@ -1,12 +1,14 @@ -from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult -from starlette.requests import Request -from fastapi.param_functions import Query -from typing import Optional, Dict -from lnbits.lnurl import encode as lnurl_encode # type: ignore -from lnurl.types import LnurlPayMetadata # type: ignore -from pydantic import BaseModel import json from sqlite3 import Row +from typing import Dict, Optional +from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse + +from fastapi.param_functions import Query +from lnurl.types import LnurlPayMetadata # type: ignore +from pydantic import BaseModel +from starlette.requests import Request + +from lnbits.lnurl import encode as lnurl_encode # type: ignore class CreateCopilotData(BaseModel): diff --git a/lnbits/extensions/copilot/tasks.py b/lnbits/extensions/copilot/tasks.py index 351eb24b..f3c5cff8 100644 --- a/lnbits/extensions/copilot/tasks.py +++ b/lnbits/extensions/copilot/tasks.py @@ -25,7 +25,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: webhook = None data = None - if "copilot" != payment.extra.get("tag"): + if payment.extra.get("tag") != "copilot": # not an copilot invoice return diff --git a/lnbits/extensions/discordbot/models.py b/lnbits/extensions/discordbot/models.py index 985eb096..8b9cd822 100644 --- a/lnbits/extensions/discordbot/models.py +++ b/lnbits/extensions/discordbot/models.py @@ -1,8 +1,8 @@ from sqlite3 import Row +from typing import Optional from fastapi.param_functions import Query from pydantic import BaseModel -from typing import Optional class CreateUserData(BaseModel): diff --git a/lnbits/extensions/jukebox/models.py b/lnbits/extensions/jukebox/models.py index 093961e4..90984b03 100644 --- a/lnbits/extensions/jukebox/models.py +++ b/lnbits/extensions/jukebox/models.py @@ -1,9 +1,9 @@ -from typing import NamedTuple from sqlite3 import Row +from typing import NamedTuple, Optional + from fastapi.param_functions import Query -from pydantic.main import BaseModel from pydantic import BaseModel -from typing import Optional +from pydantic.main import BaseModel class CreateJukeLinkData(BaseModel): diff --git a/lnbits/extensions/jukebox/tasks.py b/lnbits/extensions/jukebox/tasks.py index 02241c7b..70a2e65d 100644 --- a/lnbits/extensions/jukebox/tasks.py +++ b/lnbits/extensions/jukebox/tasks.py @@ -16,7 +16,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "jukebox" != payment.extra.get("tag"): + if payment.extra.get("tag") != "jukebox": # not a jukebox invoice return await update_jukebox_payment(payment.payment_hash, paid=True) diff --git a/lnbits/extensions/jukebox/templates/jukebox/index.html b/lnbits/extensions/jukebox/templates/jukebox/index.html index 9b4efbd5..a67767fb 100644 --- a/lnbits/extensions/jukebox/templates/jukebox/index.html +++ b/lnbits/extensions/jukebox/templates/jukebox/index.html @@ -117,7 +117,7 @@ > @@ -170,16 +170,25 @@
- + To use this extension you need a Spotify client ID and client secret. - You get these by creating an app in the Spotify developers dashboard - +
+ here
. + >Open the Spotify Developer Dashboard +
- + - In the app go to edit-settings, set the redirect URI to this link +

+ In the app go to edit-settings, set the redirect URI to this link +

+ + + {% raw %}{{ locationcb }}{{ jukeboxDialog.data.sp_id }}{% endraw + %} + + Click to copy URL +
{% raw %}{{ locationcb }}{{ jukeboxDialog.data.sp_id }}{% endraw - %} Click to copy URL - -
- Settings can be found - here. + >Open the Spotify Application Settings +

+

+ After adding the redirect URI, click the "Authorise access" button + below. +

@@ -281,7 +301,7 @@ None: - if "livestream" != payment.extra.get("tag"): + if payment.extra.get("tag") != "livestream": # not a livestream invoice return diff --git a/lnbits/extensions/livestream/views.py b/lnbits/extensions/livestream/views.py index ef035431..97f803a3 100644 --- a/lnbits/extensions/livestream/views.py +++ b/lnbits/extensions/livestream/views.py @@ -1,7 +1,5 @@ from http import HTTPStatus -# from mmap import MAP_DENYWRITE - from fastapi.param_functions import Depends from fastapi.params import Query from starlette.exceptions import HTTPException @@ -15,6 +13,8 @@ from lnbits.decorators import check_user_exists from . import livestream_ext, livestream_renderer from .crud import get_livestream_by_track, get_track +# from mmap import MAP_DENYWRITE + @livestream_ext.get("/", response_class=HTMLResponse) async def index(request: Request, user: User = Depends(check_user_exists)): diff --git a/lnbits/extensions/lnaddress/lnurl.py b/lnbits/extensions/lnaddress/lnurl.py index 2b064e0a..e6a1ff48 100644 --- a/lnbits/extensions/lnaddress/lnurl.py +++ b/lnbits/extensions/lnaddress/lnurl.py @@ -3,15 +3,13 @@ import json from datetime import datetime, timedelta import httpx - -from loguru import logger - from fastapi.params import Query from lnurl import ( # type: ignore LnurlErrorResponse, LnurlPayActionResponse, LnurlPayResponse, ) +from loguru import logger from starlette.requests import Request from starlette.responses import HTMLResponse diff --git a/lnbits/extensions/lnaddress/tasks.py b/lnbits/extensions/lnaddress/tasks.py index 9702c70b..9abe10c3 100644 --- a/lnbits/extensions/lnaddress/tasks.py +++ b/lnbits/extensions/lnaddress/tasks.py @@ -43,13 +43,13 @@ async def call_webhook_on_paid(payment_hash): async def on_invoice_paid(payment: Payment) -> None: - if "lnaddress" == payment.extra.get("tag"): + if payment.extra.get("tag") == "lnaddress": await payment.set_pending(False) await set_address_paid(payment_hash=payment.payment_hash) await call_webhook_on_paid(payment_hash=payment.payment_hash) - elif "renew lnaddress" == payment.extra.get("tag"): + elif payment.extra.get("tag") == "renew lnaddress": await payment.set_pending(False) await set_address_renewed( diff --git a/lnbits/extensions/lndhub/decorators.py b/lnbits/extensions/lndhub/decorators.py index 14931164..4698e9b9 100644 --- a/lnbits/extensions/lndhub/decorators.py +++ b/lnbits/extensions/lndhub/decorators.py @@ -1,14 +1,12 @@ from base64 import b64decode -from fastapi.param_functions import Security - -from fastapi.security.api_key import APIKeyHeader from fastapi import Request, status +from fastapi.param_functions import Security +from fastapi.security.api_key import APIKeyHeader from starlette.exceptions import HTTPException from lnbits.decorators import WalletTypeInfo, get_key_type # type: ignore - api_key_header_auth = APIKeyHeader( name="AUTHORIZATION", auto_error=False, diff --git a/lnbits/extensions/lndhub/views.py b/lnbits/extensions/lndhub/views.py index 4b015c09..38a33a34 100644 --- a/lnbits/extensions/lndhub/views.py +++ b/lnbits/extensions/lndhub/views.py @@ -1,8 +1,10 @@ -from lnbits.decorators import check_user_exists -from . import lndhub_ext, lndhub_renderer from fastapi import Request from fastapi.params import Depends + from lnbits.core.models import User +from lnbits.decorators import check_user_exists + +from . import lndhub_ext, lndhub_renderer @lndhub_ext.get("/") diff --git a/lnbits/extensions/lndhub/views_api.py b/lnbits/extensions/lndhub/views_api.py index 8cbf5b01..a3160fa9 100644 --- a/lnbits/extensions/lndhub/views_api.py +++ b/lnbits/extensions/lndhub/views_api.py @@ -1,6 +1,5 @@ -import time import asyncio - +import time from base64 import urlsafe_b64encode from http import HTTPStatus @@ -13,7 +12,7 @@ from lnbits import bolt11 from lnbits.core.crud import delete_expired_invoices, get_payments from lnbits.core.services import create_invoice, pay_invoice from lnbits.decorators import WalletTypeInfo -from lnbits.settings import WALLET, LNBITS_SITE_TITLE +from lnbits.settings import LNBITS_SITE_TITLE, WALLET from . import lndhub_ext from .decorators import check_wallet, require_admin_key diff --git a/lnbits/extensions/lnticket/crud.py b/lnbits/extensions/lnticket/crud.py index 8fe17090..3254ad43 100644 --- a/lnbits/extensions/lnticket/crud.py +++ b/lnbits/extensions/lnticket/crud.py @@ -1,11 +1,12 @@ -from lnbits.core.models import Wallet from typing import List, Optional, Union +import httpx + +from lnbits.core.models import Wallet from lnbits.helpers import urlsafe_short_hash from . import db -from .models import CreateFormData, CreateTicketData, Tickets, Forms -import httpx +from .models import CreateFormData, CreateTicketData, Forms, Tickets async def create_ticket( diff --git a/lnbits/extensions/lnticket/models.py b/lnbits/extensions/lnticket/models.py index 50ffc1e1..a7a3cf8c 100644 --- a/lnbits/extensions/lnticket/models.py +++ b/lnbits/extensions/lnticket/models.py @@ -1,4 +1,5 @@ from typing import Optional + from fastapi.param_functions import Query from pydantic import BaseModel diff --git a/lnbits/extensions/lnticket/tasks.py b/lnbits/extensions/lnticket/tasks.py index 23d485b4..7e672115 100644 --- a/lnbits/extensions/lnticket/tasks.py +++ b/lnbits/extensions/lnticket/tasks.py @@ -18,7 +18,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "lnticket" != payment.extra.get("tag"): + if payment.extra.get("tag") != "lnticket": # not a lnticket invoice return diff --git a/lnbits/extensions/lnurldevice/lnurl.py b/lnbits/extensions/lnurldevice/lnurl.py index 26a127f1..5e25dadb 100644 --- a/lnbits/extensions/lnurldevice/lnurl.py +++ b/lnbits/extensions/lnurldevice/lnurl.py @@ -1,30 +1,26 @@ import base64 import hashlib +import hmac from http import HTTPStatus +from io import BytesIO from typing import Optional -from embit import bech32 -from embit import compact -import base64 -from io import BytesIO -import hmac - +from embit import bech32, compact from fastapi import Request from fastapi.param_functions import Query from starlette.exceptions import HTTPException from lnbits.core.services import create_invoice -from lnbits.utils.exchange_rates import fiat_amount_as_satoshis from lnbits.core.views.api import pay_invoice - +from lnbits.utils.exchange_rates import fiat_amount_as_satoshis from . import lnurldevice_ext from .crud import ( create_lnurldevicepayment, get_lnurldevice, get_lnurldevicepayment, - update_lnurldevicepayment, get_lnurlpayload, + update_lnurldevicepayment, ) diff --git a/lnbits/extensions/lnurldevice/migrations.py b/lnbits/extensions/lnurldevice/migrations.py index 67065347..c7899282 100644 --- a/lnbits/extensions/lnurldevice/migrations.py +++ b/lnbits/extensions/lnurldevice/migrations.py @@ -38,7 +38,7 @@ async def m001_initial(db): async def m002_redux(db): """ - Moves everything from lnurlpos to lnurldevices + Moves everything from lnurlpos to lnurldevice """ try: for row in [ diff --git a/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html b/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html index d5b4b5b8..940d4691 100644 --- a/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html +++ b/lnbits/extensions/lnurldevice/templates/lnurldevice/_api_docs.html @@ -120,7 +120,7 @@ GET - /lnurldevice/api/v1/lnurlposs
Headers
{"X-Api-Key": <invoice_key>}
diff --git a/lnbits/extensions/lnurlp/crud.py b/lnbits/extensions/lnurlp/crud.py index c7046588..9cb01fde 100644 --- a/lnbits/extensions/lnurlp/crud.py +++ b/lnbits/extensions/lnurlp/crud.py @@ -1,8 +1,9 @@ from typing import List, Optional, Union from lnbits.db import SQLITE + from . import db -from .models import PayLink, CreatePayLinkData +from .models import CreatePayLinkData, PayLink async def create_pay_link(data: CreatePayLinkData, wallet_id: str) -> PayLink: diff --git a/lnbits/extensions/lnurlp/models.py b/lnbits/extensions/lnurlp/models.py index bd121cc8..4bd438a4 100644 --- a/lnbits/extensions/lnurlp/models.py +++ b/lnbits/extensions/lnurlp/models.py @@ -1,12 +1,14 @@ import json -from urllib.parse import urlparse, urlunparse, parse_qs, urlencode, ParseResult -from starlette.requests import Request -from fastapi.param_functions import Query -from typing import Optional, Dict -from lnbits.lnurl import encode as lnurl_encode # type: ignore -from lnurl.types import LnurlPayMetadata # type: ignore from sqlite3 import Row +from typing import Dict, Optional +from urllib.parse import ParseResult, parse_qs, urlencode, urlparse, urlunparse + +from fastapi.param_functions import Query +from lnurl.types import LnurlPayMetadata # type: ignore from pydantic import BaseModel +from starlette.requests import Request + +from lnbits.lnurl import encode as lnurl_encode # type: ignore class CreatePayLinkData(BaseModel): diff --git a/lnbits/extensions/lnurlp/static/js/index.js b/lnbits/extensions/lnurlp/static/js/index.js index e18d6161..1713e77f 100644 --- a/lnbits/extensions/lnurlp/static/js/index.js +++ b/lnbits/extensions/lnurlp/static/js/index.js @@ -35,6 +35,7 @@ new Vue({ rowsPerPage: 10 } }, + nfcTagWriting: false, formDialog: { show: false, fixedAmount: true, @@ -205,6 +206,42 @@ new Vue({ .catch(err => { LNbits.utils.notifyApiError(err) }) + }, + writeNfcTag: async function (lnurl) { + try { + if (typeof NDEFReader == 'undefined') { + throw { + toString: function () { + return 'NFC not supported on this device or browser.' + } + } + } + + const ndef = new NDEFReader() + + this.nfcTagWriting = true + this.$q.notify({ + message: 'Tap your NFC tag to write the LNURL-pay link to it.' + }) + + await ndef.write({ + records: [{recordType: 'url', data: 'lightning:' + lnurl, lang: 'en'}] + }) + + this.nfcTagWriting = false + this.$q.notify({ + type: 'positive', + message: 'NFC tag written successfully.' + }) + } catch (error) { + this.nfcTagWriting = false + this.$q.notify({ + type: 'negative', + message: error + ? error.toString() + : 'An unexpected error has occurred.' + }) + } } }, created() { diff --git a/lnbits/extensions/lnurlp/tasks.py b/lnbits/extensions/lnurlp/tasks.py index b632fa13..525d36ce 100644 --- a/lnbits/extensions/lnurlp/tasks.py +++ b/lnbits/extensions/lnurlp/tasks.py @@ -1,5 +1,6 @@ import asyncio import json + import httpx from lnbits.core import db as core_db @@ -19,7 +20,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "lnurlp" != payment.extra.get("tag"): + if payment.extra.get("tag") != "lnurlp": # not an lnurlp invoice return diff --git a/lnbits/extensions/lnurlp/templates/lnurlp/display.html b/lnbits/extensions/lnurlp/templates/lnurlp/display.html index 08e4de15..944e764b 100644 --- a/lnbits/extensions/lnurlp/templates/lnurlp/display.html +++ b/lnbits/extensions/lnurlp/templates/lnurlp/display.html @@ -14,10 +14,17 @@
-
+
Copy LNURL +
diff --git a/lnbits/extensions/lnurlp/templates/lnurlp/index.html b/lnbits/extensions/lnurlp/templates/lnurlp/index.html index c535f2fb..9677a027 100644 --- a/lnbits/extensions/lnurlp/templates/lnurlp/index.html +++ b/lnbits/extensions/lnurlp/templates/lnurlp/index.html @@ -99,7 +99,8 @@ @click="openUpdateDialog(props.row.id)" icon="edit" color="light-blue" - > + > + + > +
+ > +
@@ -200,7 +203,8 @@ type="number" label="Comment maximum characters" hint="Tell wallets to prompt users for a comment that will be sent along with the payment. LNURLp will store the comment and send it in the webhook." - > + > + + > +
Shareable link + + int: diff --git a/lnbits/extensions/offlineshop/helpers.py b/lnbits/extensions/offlineshop/helpers.py index 6b56cf55..86a653aa 100644 --- a/lnbits/extensions/offlineshop/helpers.py +++ b/lnbits/extensions/offlineshop/helpers.py @@ -1,6 +1,6 @@ import base64 -import struct import hmac +import struct import time diff --git a/lnbits/extensions/offlineshop/models.py b/lnbits/extensions/offlineshop/models.py index 06225351..0128fdb8 100644 --- a/lnbits/extensions/offlineshop/models.py +++ b/lnbits/extensions/offlineshop/models.py @@ -1,14 +1,15 @@ -import json import base64 import hashlib +import json from collections import OrderedDict +from typing import Dict, List, Optional -from typing import Optional, List, Dict from lnurl import encode as lnurl_encode # type: ignore -from lnurl.types import LnurlPayMetadata # type: ignore from lnurl.models import LnurlPaySuccessAction, UrlAction # type: ignore +from lnurl.types import LnurlPayMetadata # type: ignore from pydantic import BaseModel from starlette.requests import Request + from .helpers import totp shop_counters: Dict = {} diff --git a/lnbits/extensions/offlineshop/views.py b/lnbits/extensions/offlineshop/views.py index e1d3a66e..34bb7a03 100644 --- a/lnbits/extensions/offlineshop/views.py +++ b/lnbits/extensions/offlineshop/views.py @@ -3,18 +3,18 @@ from datetime import datetime from http import HTTPStatus from typing import List +from fastapi import HTTPException, Request from fastapi.params import Depends, Query from starlette.responses import HTMLResponse -from lnbits.decorators import check_user_exists -from lnbits.core.models import Payment, User from lnbits.core.crud import get_standalone_payment +from lnbits.core.models import Payment, User from lnbits.core.views.api import api_payment +from lnbits.decorators import check_user_exists from . import offlineshop_ext, offlineshop_renderer -from .models import Item from .crud import get_item, get_shop -from fastapi import Request, HTTPException +from .models import Item @offlineshop_ext.get("/", response_class=HTMLResponse) diff --git a/lnbits/extensions/satspay/tasks.py b/lnbits/extensions/satspay/tasks.py index 7ee6298c..d325405b 100644 --- a/lnbits/extensions/satspay/tasks.py +++ b/lnbits/extensions/satspay/tasks.py @@ -19,7 +19,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "charge" != payment.extra.get("tag"): + if payment.extra.get("tag") != "charge": # not a charge invoice return diff --git a/lnbits/extensions/splitpayments/migrations.py b/lnbits/extensions/splitpayments/migrations.py index 735afc6c..b3921c42 100644 --- a/lnbits/extensions/splitpayments/migrations.py +++ b/lnbits/extensions/splitpayments/migrations.py @@ -14,3 +14,41 @@ async def m001_initial(db): ); """ ) + + +async def m002_float_percent(db): + """ + Add float percent and migrates the existing data. + """ + await db.execute("ALTER TABLE splitpayments.targets RENAME TO splitpayments_old") + await db.execute( + """ + CREATE TABLE splitpayments.targets ( + wallet TEXT NOT NULL, + source TEXT NOT NULL, + percent REAL NOT NULL CHECK (percent >= 0 AND percent <= 100), + alias TEXT, + + UNIQUE (source, wallet) + ); + """ + ) + + for row in [ + list(row) + for row in await db.fetchall("SELECT * FROM splitpayments.splitpayments_old") + ]: + await db.execute( + """ + INSERT INTO splitpayments.targets ( + wallet, + source, + percent, + alias + ) + VALUES (?, ?, ?, ?) + """, + (row[0], row[1], row[2], row[3]), + ) + + await db.execute("DROP TABLE splitpayments.splitpayments_old") diff --git a/lnbits/extensions/splitpayments/models.py b/lnbits/extensions/splitpayments/models.py index 3264bca7..4b95ed18 100644 --- a/lnbits/extensions/splitpayments/models.py +++ b/lnbits/extensions/splitpayments/models.py @@ -7,14 +7,14 @@ from pydantic import BaseModel class Target(BaseModel): wallet: str source: str - percent: int + percent: float alias: Optional[str] class TargetPutList(BaseModel): wallet: str = Query(...) alias: str = Query("") - percent: int = Query(..., ge=1) + percent: float = Query(..., ge=0.01) class TargetPut(BaseModel): diff --git a/lnbits/extensions/splitpayments/static/js/index.js b/lnbits/extensions/splitpayments/static/js/index.js index d9750bef..5d326231 100644 --- a/lnbits/extensions/splitpayments/static/js/index.js +++ b/lnbits/extensions/splitpayments/static/js/index.js @@ -105,7 +105,7 @@ new Vue({ if (currentTotal > 100 && isPercent) { let diff = (currentTotal - 100) / (100 - this.targets[index].percent) this.targets.forEach((target, t) => { - if (t !== index) target.percent -= Math.round(diff * target.percent) + if (t !== index) target.percent -= +(diff * target.percent).toFixed(2) }) } diff --git a/lnbits/extensions/splitpayments/tasks.py b/lnbits/extensions/splitpayments/tasks.py index 914e9bd2..0948e849 100644 --- a/lnbits/extensions/splitpayments/tasks.py +++ b/lnbits/extensions/splitpayments/tasks.py @@ -22,7 +22,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "splitpayments" == payment.extra.get("tag") or payment.extra.get("splitted"): + if payment.extra.get("tag") == "splitpayments" or payment.extra.get("splitted"): # already splitted, ignore return diff --git a/lnbits/extensions/splitpayments/templates/splitpayments/index.html b/lnbits/extensions/splitpayments/templates/splitpayments/index.html index 1aae4e33..5862abc1 100644 --- a/lnbits/extensions/splitpayments/templates/splitpayments/index.html +++ b/lnbits/extensions/splitpayments/templates/splitpayments/index.html @@ -58,14 +58,14 @@ >
- - +
+
Clear - +
- +
Save Targets - - +
+
diff --git a/lnbits/extensions/subdomains/cloudflare.py b/lnbits/extensions/subdomains/cloudflare.py index 8ada2a90..679ca843 100644 --- a/lnbits/extensions/subdomains/cloudflare.py +++ b/lnbits/extensions/subdomains/cloudflare.py @@ -1,5 +1,8 @@ +import json + +import httpx + from lnbits.extensions.subdomains.models import Domains -import httpx, json async def cloudflare_create_subdomain( diff --git a/lnbits/extensions/subdomains/tasks.py b/lnbits/extensions/subdomains/tasks.py index 75223e82..d8f35161 100644 --- a/lnbits/extensions/subdomains/tasks.py +++ b/lnbits/extensions/subdomains/tasks.py @@ -19,7 +19,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "lnsubdomain" != payment.extra.get("tag"): + if payment.extra.get("tag") != "lnsubdomain": # not an lnurlp invoice return diff --git a/lnbits/extensions/tpos/__init__.py b/lnbits/extensions/tpos/__init__.py index 1aed95ba..3ce618aa 100644 --- a/lnbits/extensions/tpos/__init__.py +++ b/lnbits/extensions/tpos/__init__.py @@ -16,8 +16,8 @@ def tpos_renderer(): from .tasks import wait_for_paid_invoices -from .views_api import * # noqa from .views import * # noqa +from .views_api import * # noqa def tpos_start(): diff --git a/lnbits/extensions/tpos/tasks.py b/lnbits/extensions/tpos/tasks.py index 0bb8dff9..01c11428 100644 --- a/lnbits/extensions/tpos/tasks.py +++ b/lnbits/extensions/tpos/tasks.py @@ -20,7 +20,7 @@ async def wait_for_paid_invoices(): async def on_invoice_paid(payment: Payment) -> None: - if "tpos" == payment.extra.get("tag") and payment.extra.get("tipSplitted"): + if payment.extra.get("tag") == "tpos" and payment.extra.get("tipSplitted"): # already splitted, ignore return diff --git a/lnbits/extensions/tpos/views.py b/lnbits/extensions/tpos/views.py index 21a471c4..e1f1d21e 100644 --- a/lnbits/extensions/tpos/views.py +++ b/lnbits/extensions/tpos/views.py @@ -8,10 +8,7 @@ from starlette.responses import HTMLResponse from lnbits.core.models import User from lnbits.decorators import check_user_exists -from lnbits.settings import ( - LNBITS_CUSTOM_LOGO, - LNBITS_SITE_TITLE, -) +from lnbits.settings import LNBITS_CUSTOM_LOGO, LNBITS_SITE_TITLE from . import tpos_ext, tpos_renderer from .crud import get_tpos diff --git a/lnbits/extensions/tpos/views_api.py b/lnbits/extensions/tpos/views_api.py index 6a4e5c43..9567f98a 100644 --- a/lnbits/extensions/tpos/views_api.py +++ b/lnbits/extensions/tpos/views_api.py @@ -2,9 +2,8 @@ from http import HTTPStatus from fastapi import Query from fastapi.params import Depends -from starlette.exceptions import HTTPException - from loguru import logger +from starlette.exceptions import HTTPException from lnbits.core.crud import get_user from lnbits.core.services import create_invoice diff --git a/lnbits/extensions/usermanager/models.py b/lnbits/extensions/usermanager/models.py index 67facec6..15f50e28 100644 --- a/lnbits/extensions/usermanager/models.py +++ b/lnbits/extensions/usermanager/models.py @@ -1,8 +1,8 @@ from sqlite3 import Row +from typing import Optional from fastapi.param_functions import Query from pydantic import BaseModel -from typing import Optional class CreateUserData(BaseModel): diff --git a/lnbits/extensions/usermanager/views_api.py b/lnbits/extensions/usermanager/views_api.py index a36b36bb..7e7b7653 100644 --- a/lnbits/extensions/usermanager/views_api.py +++ b/lnbits/extensions/usermanager/views_api.py @@ -75,7 +75,7 @@ async def api_usermanager_activate_extension( raise HTTPException( status_code=HTTPStatus.NOT_FOUND, detail="User does not exist." ) - update_user_extension(user_id=userid, extension=extension, active=active) + await update_user_extension(user_id=userid, extension=extension, active=active) return {"extension": "updated"} diff --git a/lnbits/extensions/withdraw/lnurl.py b/lnbits/extensions/withdraw/lnurl.py index 05b3908c..18a99599 100644 --- a/lnbits/extensions/withdraw/lnurl.py +++ b/lnbits/extensions/withdraw/lnurl.py @@ -1,15 +1,13 @@ import json import traceback -import httpx - from datetime import datetime from http import HTTPStatus -from loguru import logger - +import httpx import shortuuid # type: ignore from fastapi import HTTPException from fastapi.param_functions import Query +from loguru import logger from starlette.requests import Request from starlette.responses import HTMLResponse # type: ignore diff --git a/lnbits/extensions/withdraw/static/js/index.js b/lnbits/extensions/withdraw/static/js/index.js index e54005c6..3f484deb 100644 --- a/lnbits/extensions/withdraw/static/js/index.js +++ b/lnbits/extensions/withdraw/static/js/index.js @@ -53,6 +53,7 @@ new Vue({ rowsPerPage: 10 } }, + nfcTagWriting: false, formDialog: { show: false, secondMultiplier: 'seconds', @@ -231,6 +232,42 @@ new Vue({ }) }) }, + writeNfcTag: async function (lnurl) { + try { + if (typeof NDEFReader == 'undefined') { + throw { + toString: function () { + return 'NFC not supported on this device or browser.' + } + } + } + + const ndef = new NDEFReader() + + this.nfcTagWriting = true + this.$q.notify({ + message: 'Tap your NFC tag to write the LNURL-withdraw link to it.' + }) + + await ndef.write({ + records: [{recordType: 'url', data: 'lightning:' + lnurl, lang: 'en'}] + }) + + this.nfcTagWriting = false + this.$q.notify({ + type: 'positive', + message: 'NFC tag written successfully.' + }) + } catch (error) { + this.nfcTagWriting = false + this.$q.notify({ + type: 'negative', + message: error + ? error.toString() + : 'An unexpected error has occurred.' + }) + } + }, exportCSV: function () { LNbits.utils.exportCSV(this.paywallsTable.columns, this.paywalls) } diff --git a/lnbits/extensions/withdraw/templates/withdraw/display.html b/lnbits/extensions/withdraw/templates/withdraw/display.html index 5552c77f..1e632741 100644 --- a/lnbits/extensions/withdraw/templates/withdraw/display.html +++ b/lnbits/extensions/withdraw/templates/withdraw/display.html @@ -13,14 +13,22 @@ :value="this.here + '/?lightning={{lnurl }}'" :options="{width: 800}" class="rounded-borders" - > + > +
-
+
Copy LNURL +
@@ -51,7 +59,8 @@ mixins: [windowMixin], data: function () { return { - here: location.protocol + '//' + location.host + here: location.protocol + '//' + location.host, + nfcTagWriting: false } } }) diff --git a/lnbits/extensions/withdraw/templates/withdraw/index.html b/lnbits/extensions/withdraw/templates/withdraw/index.html index 6d3ab374..99aa03b2 100644 --- a/lnbits/extensions/withdraw/templates/withdraw/index.html +++ b/lnbits/extensions/withdraw/templates/withdraw/index.html @@ -369,6 +369,13 @@ @click="copyText(qrCodeDialog.data.withdraw_url, 'Link copied to clipboard!')" >Shareable link + b.name + const nameA = a.name.toUpperCase() + const nameB = b.name.toUpperCase() + return nameA < nameB ? -1 : nameA > nameB ? 1 : 0 }) ) + + this.g.extensions = extensions } } } diff --git a/lnbits/tasks.py b/lnbits/tasks.py index 69aa1906..86863f98 100644 --- a/lnbits/tasks.py +++ b/lnbits/tasks.py @@ -1,22 +1,20 @@ -import time import asyncio +import time import traceback from http import HTTPStatus -from typing import List, Callable - -from loguru import logger +from typing import Callable, List from fastapi.exceptions import HTTPException +from loguru import logger -from lnbits.settings import WALLET from lnbits.core.crud import ( - get_payments, - get_standalone_payment, delete_expired_invoices, get_balance_checks, + get_payments, + get_standalone_payment, ) from lnbits.core.services import redeem_lnurl_withdraw - +from lnbits.settings import WALLET deferred_async: List[Callable] = [] diff --git a/lnbits/templates/base.html b/lnbits/templates/base.html index 6ab1ec84..acca92e7 100644 --- a/lnbits/templates/base.html +++ b/lnbits/templates/base.html @@ -228,7 +228,6 @@