diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 514520d4..00000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -**/static/vendor/** linguist-vendored diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 62311205..baa938c6 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,54 +1,28 @@ -name: "CodeQL" +name: codeql on: push: branches: [master, ] pull_request: - # The branches below must be a subset of the branches above branches: [master] schedule: - cron: '0 12 * * 5' jobs: - CodeQL-Build: - + analyze: runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v2 - with: - # We must fetch at least the immediate parents so that if this is - # a pull request then we can checkout the head. - fetch-depth: 2 - - # If this run was triggered by a pull request event, then checkout - # the head of the pull request instead of the merge commit. - - run: git checkout HEAD^2 - if: ${{ github.event_name == 'pull_request' }} - - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - # Override language selection by uncommenting this and choosing your languages - # with: - # languages: go, javascript, csharp, python, cpp, java - - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - - name: Autobuild - uses: github/codeql-action/autobuild@v1 - - # ℹī¸ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏ī¸ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 2 + - run: git checkout HEAD^2 + if: ${{ github.event_name == 'pull_request' }} + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: javascript, python + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 diff --git a/.github/workflows/linting.yml b/.github/workflows/formatting.yml similarity index 57% rename from .github/workflows/linting.yml rename to .github/workflows/formatting.yml index 57abd8ba..61f03a2b 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/formatting.yml @@ -1,4 +1,4 @@ -name: Linters +name: formatting on: push: @@ -21,13 +21,3 @@ jobs: - uses: actions/checkout@v2 - run: npm install - run: make checkprettier - mypy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - run: sudo apt-get install python3-venv - - run: sudo apt-get install libev-dev - - run: python3 -m venv venv - - run: ./venv/bin/pip install -r requirements.txt - - run: ./venv/bin/pip install mypy - - run: make mypy diff --git a/.github/workflows/mypy.yml b/.github/workflows/mypy.yml new file mode 100644 index 00000000..77d340c1 --- /dev/null +++ b/.github/workflows/mypy.yml @@ -0,0 +1,12 @@ +name: mypy + +on: [push, pull_request] + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: jpetrucciani/mypy-check@master + with: + path: lnbits diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index e2715129..e3d69070 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,15 +1,13 @@ -name: test suite +name: tests on: [push, pull_request] jobs: build: - runs-on: ubuntu-latest strategy: matrix: python-version: [3.8] - steps: - uses: actions/checkout@v2 - name: Set up Python ${{ matrix.python-version }} diff --git a/README.md b/README.md index 2eb48994..94f3c1eb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ LNbits ====== -[![github-actions-badge]][github-actions] +[![github-tests-badge]][github-tests] +[![github-mypy-badge]][github-mypy] [![codecov-badge]][codecov] [![license-badge]](LICENSE) [![docs-badge]][docs] @@ -70,8 +71,10 @@ If you like this project and might even use or extend it, why not [send some tip [docs]: https://lnbits.org/ [docs-badge]: https://img.shields.io/badge/docs-lnbits.org-673ab7.svg -[github-actions]: https://github.com/lnbits/lnbits/actions -[github-actions-badge]: https://github.com/lnbits/lnbits/workflows/test%20suite/badge.svg +[github-mypy]: https://github.com/lnbits/lnbits/actions?query=workflow%3Amypy +[github-mypy-badge]: https://github.com/lnbits/lnbits/workflows/mypy/badge.svg +[github-tests]: https://github.com/lnbits/lnbits/actions?query=workflow%3Atests +[github-tests-badge]: https://github.com/lnbits/lnbits/workflows/tests/badge.svg [codecov]: https://codecov.io/gh/lnbits/lnbits [codecov-badge]: https://codecov.io/gh/lnbits/lnbits/branch/master/graph/badge.svg [license-badge]: https://img.shields.io/badge/license-MIT-blue.svg diff --git a/lnbits/__init__.py b/lnbits/__init__.py index b2433760..228de131 100644 --- a/lnbits/__init__.py +++ b/lnbits/__init__.py @@ -29,7 +29,13 @@ Talisman( app, force_https=FORCE_HTTPS, content_security_policy={ - "default-src": ["'self'", "'unsafe-eval'", "'unsafe-inline'", "blob:", "api.opennode.co",] + "default-src": [ + "'self'", + "'unsafe-eval'", + "'unsafe-inline'", + "blob:", + "api.opennode.co", + ] }, ) diff --git a/lnbits/bolt11.py b/lnbits/bolt11.py index 417aa2f0..1be351be 100644 --- a/lnbits/bolt11.py +++ b/lnbits/bolt11.py @@ -2,7 +2,7 @@ import bitstring # type: ignore import re import hashlib from typing import List, NamedTuple, Optional -from bech32 import bech32_decode, CHARSET +from bech32 import bech32_decode, CHARSET # type: ignore from ecdsa import SECP256k1, VerifyingKey # type: ignore from ecdsa.util import sigdecode_string # type: ignore from binascii import unhexlify @@ -115,8 +115,7 @@ def decode(pr: str) -> Invoice: def _unshorten_amount(amount: str) -> int: - """ Given a shortened amount, return millisatoshis - """ + """Given a shortened amount, return millisatoshis""" # BOLT #11: # The following `multiplier` letters are defined: # diff --git a/lnbits/core/crud.py b/lnbits/core/crud.py index 4733a493..3023db95 100644 --- a/lnbits/core/crud.py +++ b/lnbits/core/crud.py @@ -268,7 +268,13 @@ def create_payment( def update_payment_status(checking_id: str, pending: bool) -> None: with open_db() as db: - db.execute("UPDATE apipayments SET pending = ? WHERE checking_id = ?", (int(pending), checking_id,)) + db.execute( + "UPDATE apipayments SET pending = ? WHERE checking_id = ?", + ( + int(pending), + checking_id, + ), + ) def delete_payment(checking_id: str) -> None: diff --git a/lnbits/core/services.py b/lnbits/core/services.py index 6f39111f..e4809775 100644 --- a/lnbits/core/services.py +++ b/lnbits/core/services.py @@ -9,7 +9,12 @@ from .crud import get_wallet, create_payment, delete_payment, check_internal, up def create_invoice( - *, wallet_id: str, amount: int, memo: str, description_hash: Optional[bytes] = None, extra: Optional[Dict] = None, + *, + wallet_id: str, + amount: int, + memo: str, + description_hash: Optional[bytes] = None, + extra: Optional[Dict] = None, ) -> Tuple[str, str]: invoice_memo = None if description_hash else memo storeable_memo = memo diff --git a/lnbits/decorators.py b/lnbits/decorators.py index 9298d1e7..ef86b7a1 100644 --- a/lnbits/decorators.py +++ b/lnbits/decorators.py @@ -16,7 +16,10 @@ def api_check_wallet_key(key_type: str = "invoice"): try: g.wallet = get_wallet_for_key(request.headers["X-Api-Key"], key_type) except KeyError: - return jsonify({"message": "`X-Api-Key` header missing."}), HTTPStatus.BAD_REQUEST + return ( + jsonify({"message": "`X-Api-Key` header missing."}), + HTTPStatus.BAD_REQUEST, + ) if not g.wallet: return jsonify({"message": "Wrong keys."}), HTTPStatus.UNAUTHORIZED @@ -33,13 +36,19 @@ def api_validate_post_request(*, schema: dict): @wraps(view) def wrapped_view(**kwargs): if "application/json" not in request.headers["Content-Type"]: - return jsonify({"message": "Content-Type must be `application/json`."}), HTTPStatus.BAD_REQUEST + return ( + jsonify({"message": "Content-Type must be `application/json`."}), + HTTPStatus.BAD_REQUEST, + ) v = Validator(schema) g.data = {key: request.json[key] for key in schema.keys() if key in request.json} if not v.validate(g.data): - return jsonify({"message": f"Errors in request data: {v.errors}"}), HTTPStatus.BAD_REQUEST + return ( + jsonify({"message": f"Errors in request data: {v.errors}"}), + HTTPStatus.BAD_REQUEST, + ) return view(**kwargs) diff --git a/lnbits/extensions/diagonalley/crud.py b/lnbits/extensions/diagonalley/crud.py index 0563f8ce..ff182d96 100644 --- a/lnbits/extensions/diagonalley/crud.py +++ b/lnbits/extensions/diagonalley/crud.py @@ -125,10 +125,22 @@ def get_diagonalleys_indexer(indexer_id: str) -> Optional[Indexers]: print(x) print("poo") with open_ext_db("diagonalley") as db: - db.execute("UPDATE indexers SET online = ? WHERE id = ?", (True, indexer_id,)) + db.execute( + "UPDATE indexers SET online = ? WHERE id = ?", + ( + True, + indexer_id, + ), + ) else: with open_ext_db("diagonalley") as db: - db.execute("UPDATE indexers SET online = ? WHERE id = ?", (False, indexer_id,)) + db.execute( + "UPDATE indexers SET online = ? WHERE id = ?", + ( + False, + indexer_id, + ), + ) except: print("An exception occurred") with open_ext_db("diagonalley") as db: @@ -149,10 +161,22 @@ def get_diagonalleys_indexers(wallet_ids: Union[str, List[str]]) -> List[Indexer x = requests.get(r["indexeraddress"] + "/" + r["ratingkey"]) if x.status_code == 200: with open_ext_db("diagonalley") as db: - db.execute("UPDATE indexers SET online = ? WHERE id = ?", (True, r["id"],)) + db.execute( + "UPDATE indexers SET online = ? WHERE id = ?", + ( + True, + r["id"], + ), + ) else: with open_ext_db("diagonalley") as db: - db.execute("UPDATE indexers SET online = ? WHERE id = ?", (False, r["id"],)) + db.execute( + "UPDATE indexers SET online = ? WHERE id = ?", + ( + False, + r["id"], + ), + ) except: print("An exception occurred") with open_ext_db("diagonalley") as db: @@ -213,7 +237,13 @@ def get_diagonalleys_orders(wallet_ids: Union[str, List[str]]) -> List[Orders]: PAID = WALLET.get_invoice_status(r["invoiceid"]).paid if PAID: with open_ext_db("diagonalley") as db: - db.execute("UPDATE orders SET paid = ? WHERE id = ?", (True, r["id"],)) + db.execute( + "UPDATE orders SET paid = ? WHERE id = ?", + ( + True, + r["id"], + ), + ) rows = db.fetchall(f"SELECT * FROM orders WHERE wallet IN ({q})", (*wallet_ids,)) return [Orders(**row) for row in rows] diff --git a/lnbits/extensions/diagonalley/views_api.py b/lnbits/extensions/diagonalley/views_api.py index e887eaa3..fbdc2a7b 100644 --- a/lnbits/extensions/diagonalley/views_api.py +++ b/lnbits/extensions/diagonalley/views_api.py @@ -198,7 +198,13 @@ def api_diagonalley_order_delete(order_id): @api_check_wallet_key(key_type="invoice") def api_diagonalleys_order_paid(order_id): with open_ext_db("diagonalley") as db: - db.execute("UPDATE orders SET paid = ? WHERE id = ?", (True, order_id,)) + db.execute( + "UPDATE orders SET paid = ? WHERE id = ?", + ( + True, + order_id, + ), + ) return "", HTTPStatus.OK @@ -206,7 +212,13 @@ def api_diagonalleys_order_paid(order_id): @api_check_wallet_key(key_type="invoice") def api_diagonalleys_order_shipped(order_id): with open_ext_db("diagonalley") as db: - db.execute("UPDATE orders SET shipped = ? WHERE id = ?", (True, order_id,)) + db.execute( + "UPDATE orders SET shipped = ? WHERE id = ?", + ( + True, + order_id, + ), + ) order = db.fetchone("SELECT * FROM orders WHERE id = ?", (order_id,)) return jsonify([order._asdict() for order in get_diagonalleys_orders(order["wallet"])]), HTTPStatus.OK diff --git a/lnbits/extensions/events/migrations.py b/lnbits/extensions/events/migrations.py index 7d2bd46a..851c4ae3 100644 --- a/lnbits/extensions/events/migrations.py +++ b/lnbits/extensions/events/migrations.py @@ -75,7 +75,15 @@ def m002_changed(db): ) VALUES (?, ?, ?, ?, ?, ?, ?) """, - (row[0], row[1], row[2], row[3], row[4], row[5], True,), + ( + row[0], + row[1], + row[2], + row[3], + row[4], + row[5], + True, + ), ) db.execute("DROP TABLE tickets") diff --git a/lnbits/extensions/example/views_api.py b/lnbits/extensions/example/views_api.py index 0cc00db9..84642849 100644 --- a/lnbits/extensions/example/views_api.py +++ b/lnbits/extensions/example/views_api.py @@ -18,9 +18,21 @@ from lnbits.extensions.example import example_ext def api_example(): """Try to add descriptions for others.""" tools = [ - {"name": "Flask", "url": "https://flask.palletsprojects.com/", "language": "Python",}, - {"name": "Vue.js", "url": "https://vuejs.org/", "language": "JavaScript",}, - {"name": "Quasar Framework", "url": "https://quasar.dev/", "language": "JavaScript",}, + { + "name": "Flask", + "url": "https://flask.palletsprojects.com/", + "language": "Python", + }, + { + "name": "Vue.js", + "url": "https://vuejs.org/", + "language": "JavaScript", + }, + { + "name": "Quasar Framework", + "url": "https://quasar.dev/", + "language": "JavaScript", + }, ] return jsonify(tools), HTTPStatus.OK diff --git a/lnbits/extensions/lnticket/migrations.py b/lnbits/extensions/lnticket/migrations.py index 842a7d33..4d8ab82d 100644 --- a/lnbits/extensions/lnticket/migrations.py +++ b/lnbits/extensions/lnticket/migrations.py @@ -74,7 +74,16 @@ def m002_changed(db): ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, - (row[0], row[1], row[2], row[3], row[4], row[5], row[6], True,), + ( + row[0], + row[1], + row[2], + row[3], + row[4], + row[5], + row[6], + True, + ), ) db.execute("DROP TABLE tickets") diff --git a/lnbits/extensions/lnurlp/views_api.py b/lnbits/extensions/lnurlp/views_api.py index 327310d9..47a53369 100644 --- a/lnbits/extensions/lnurlp/views_api.py +++ b/lnbits/extensions/lnurlp/views_api.py @@ -106,7 +106,10 @@ def api_lnurl_response(link_id): url = url_for("lnurlp.api_lnurl_callback", link_id=link.id, _external=True, _scheme=scheme) resp = LnurlPayResponse( - callback=url, min_sendable=link.amount * 1000, max_sendable=link.amount * 1000, metadata=link.lnurlpay_metadata, + callback=url, + min_sendable=link.amount * 1000, + max_sendable=link.amount * 1000, + metadata=link.lnurlpay_metadata, ) return jsonify(resp.dict()), HTTPStatus.OK diff --git a/lnbits/wallets/lnbits.py b/lnbits/wallets/lnbits.py index 8da7de7e..d7dfca0f 100644 --- a/lnbits/wallets/lnbits.py +++ b/lnbits/wallets/lnbits.py @@ -22,7 +22,11 @@ class LNbitsWallet(Wallet): else: data["memo"] = memo or "" - r = post(url=f"{self.endpoint}/api/v1/payments", headers=self.auth_invoice, json=data,) + r = post( + url=f"{self.endpoint}/api/v1/payments", + headers=self.auth_invoice, + json=data, + ) ok, checking_id, payment_request, error_message = r.ok, None, None, None if r.ok: diff --git a/lnbits/wallets/lndgrpc.py b/lnbits/wallets/lndgrpc.py index f1bf82bf..a2b836fa 100644 --- a/lnbits/wallets/lndgrpc.py +++ b/lnbits/wallets/lndgrpc.py @@ -55,7 +55,9 @@ class LndWallet(Wallet): grpc_port=self.port, ) - payinvoice = lnd_rpc.pay_invoice(payment_request=bolt11,) + payinvoice = lnd_rpc.pay_invoice( + payment_request=bolt11, + ) ok, checking_id, fee_msat, error_message = True, None, 0, None diff --git a/lnbits/wallets/lndrest.py b/lnbits/wallets/lndrest.py index d47b9f6b..a76a8995 100644 --- a/lnbits/wallets/lndrest.py +++ b/lnbits/wallets/lndrest.py @@ -30,7 +30,12 @@ class LndRestWallet(Wallet): else: data["memo"] = memo or "" - r = post(url=f"{self.endpoint}/v1/invoices", headers=self.auth_invoice, verify=self.auth_cert, json=data,) + r = post( + url=f"{self.endpoint}/v1/invoices", + headers=self.auth_invoice, + verify=self.auth_cert, + json=data, + ) ok, checking_id, payment_request, error_message = r.ok, None, None, None @@ -38,7 +43,11 @@ class LndRestWallet(Wallet): data = r.json() payment_request = data["payment_request"] - r = get(url=f"{self.endpoint}/v1/payreq/{payment_request}", headers=self.auth_read, verify=self.auth_cert,) + r = get( + url=f"{self.endpoint}/v1/payreq/{payment_request}", + headers=self.auth_read, + verify=self.auth_cert, + ) print(r) if r.ok: checking_id = r.json()["payment_hash"].replace("/", "_") @@ -56,7 +65,11 @@ class LndRestWallet(Wallet): json={"payment_request": bolt11}, ) ok, checking_id, fee_msat, error_message = r.ok, None, 0, None - r = get(url=f"{self.endpoint}/v1/payreq/{bolt11}", headers=self.auth_admin, verify=self.auth_cert,) + r = get( + url=f"{self.endpoint}/v1/payreq/{bolt11}", + headers=self.auth_admin, + verify=self.auth_cert, + ) if r.ok: checking_id = r.json()["payment_hash"] @@ -68,7 +81,11 @@ class LndRestWallet(Wallet): def get_invoice_status(self, checking_id: str) -> PaymentStatus: checking_id = checking_id.replace("_", "/") print(checking_id) - r = get(url=f"{self.endpoint}/v1/invoice/{checking_id}", headers=self.auth_invoice, verify=self.auth_cert,) + r = get( + url=f"{self.endpoint}/v1/invoice/{checking_id}", + headers=self.auth_invoice, + verify=self.auth_cert, + ) print(r.json()["settled"]) if not r or r.json()["settled"] == False: return PaymentStatus(None) diff --git a/lnbits/wallets/lnpay.py b/lnbits/wallets/lnpay.py index 271ceb45..db0d4171 100644 --- a/lnbits/wallets/lnpay.py +++ b/lnbits/wallets/lnpay.py @@ -25,7 +25,11 @@ class LNPayWallet(Wallet): else: data["memo"] = memo or "" - r = post(url=f"{self.endpoint}/user/wallet/{self.auth_invoice}/invoice", headers=self.auth_api, json=data,) + r = post( + url=f"{self.endpoint}/user/wallet/{self.auth_invoice}/invoice", + headers=self.auth_api, + json=data, + ) ok, checking_id, payment_request, error_message = r.status_code == 201, None, None, r.text if ok: diff --git a/lnbits/wallets/lntxbot.py b/lnbits/wallets/lntxbot.py index 64d38d0c..0c419da9 100644 --- a/lnbits/wallets/lntxbot.py +++ b/lnbits/wallets/lntxbot.py @@ -23,7 +23,11 @@ class LntxbotWallet(Wallet): else: data["memo"] = memo or "" - r = post(url=f"{self.endpoint}/addinvoice", headers=self.auth_invoice, json=data,) + r = post( + url=f"{self.endpoint}/addinvoice", + headers=self.auth_invoice, + json=data, + ) ok, checking_id, payment_request, error_message = r.ok, None, None, None if r.ok: diff --git a/lnbits/wallets/spark.py b/lnbits/wallets/spark.py index 6ad18fad..20216343 100644 --- a/lnbits/wallets/spark.py +++ b/lnbits/wallets/spark.py @@ -48,7 +48,9 @@ class SparkWallet(Wallet): try: if description_hash: r = self.invoicewithdescriptionhash( - msatoshi=amount * 1000, label=label, description_hash=description_hash.hex(), + msatoshi=amount * 1000, + label=label, + description_hash=description_hash.hex(), ) else: r = self.invoice(