[fix] Small bandit changes (#3241)

This commit is contained in:
Vlad Stan 2025-07-04 17:29:16 +03:00 committed by dni ⚡
parent 0529ee2835
commit e0749e186e
No known key found for this signature in database
GPG key ID: D1F416F29AD26E87
16 changed files with 125 additions and 34 deletions

View file

@ -248,7 +248,8 @@ async def m007_set_invoice_expiries(db: Connection):
""", """,
{"expiry": expiration_date, "checking_id": checking_id}, {"expiry": expiration_date, "checking_id": checking_id},
) )
except Exception: except Exception as exc:
logger.debug(exc)
continue continue
except OperationalError: except OperationalError:
# this is necessary now because it may be the case that this migration will # this is necessary now because it may be the case that this migration will
@ -371,7 +372,8 @@ async def m014_set_deleted_wallets(db: Connection):
"wallet": row.get("id"), "wallet": row.get("id"),
}, },
) )
except Exception: except Exception as exc:
logger.debug(exc)
continue continue
except OperationalError: except OperationalError:
# this is necessary now because it may be the case that this migration will # this is necessary now because it may be the case that this migration will

View file

@ -67,16 +67,16 @@ async def redeem_lnurl_withdraw(
external=True, external=True,
wal=wallet_id, wal=wallet_id,
) )
except Exception: except Exception as exc:
pass logger.debug(exc)
headers = {"User-Agent": settings.user_agent} headers = {"User-Agent": settings.user_agent}
async with httpx.AsyncClient(headers=headers) as client: async with httpx.AsyncClient(headers=headers) as client:
try: try:
check_callback_url(res["callback"]) check_callback_url(res["callback"])
await client.get(res["callback"], params=params) await client.get(res["callback"], params=params)
except Exception: except Exception as exc:
pass logger.debug(exc)
async def perform_lnurlauth( async def perform_lnurlauth(

View file

@ -557,8 +557,8 @@ def _find_auth_provider_class(provider: str) -> Callable:
provider_class = getattr(provider_module, f"{provider.title()}SSO") provider_class = getattr(provider_module, f"{provider.title()}SSO")
if provider_class: if provider_class:
return provider_class return provider_class
except Exception: except Exception as exc:
pass logger.debug(exc)
raise ValueError(f"No SSO provider found for '{provider}'.") raise ValueError(f"No SSO provider found for '{provider}'.")

View file

@ -306,8 +306,11 @@ def check_callback_url(url: str):
) )
def download_url(url, save_path): def download_url(url: str, save_path: Path):
with request.urlopen(url, timeout=60) as dl_file: if not url.startswith(("http:", "https:")):
raise ValueError(f"Invalid URL: {url}. Must start with 'http' or 'https'.")
with request.urlopen(url, timeout=60) as dl_file: # noqa: S310
with open(save_path, "wb") as out_file: with open(save_path, "wb") as out_file:
out_file.write(dl_file.read()) out_file.write(dl_file.read())

View file

@ -683,7 +683,7 @@ class NodeUISettings(LNbitsSettings):
class AuthMethods(Enum): class AuthMethods(Enum):
user_id_only = "user-id-only" user_id_only = "user-id-only"
username_and_password = "username-password" username_and_password = "username-password" # noqa: S105
nostr_auth_nip98 = "nostr-auth-nip98" nostr_auth_nip98 = "nostr-auth-nip98"
google_auth = "google-auth" google_auth = "google-auth"
github_auth = "github-auth" github_auth = "github-auth"

View file

@ -57,8 +57,8 @@ else:
# else convert from base64 # else convert from base64
try: try:
return base64.b64decode(source) return base64.b64decode(source)
except Exception: except Exception as exc:
pass logger.debug(exc)
return None return None
def load_greenlight_credentials() -> ( def load_greenlight_credentials() -> (

View file

@ -182,7 +182,8 @@ class ClicheWallet(Wallet):
try: try:
if data["result"]["status"]: if data["result"]["status"]:
yield data["result"]["payment_hash"] yield data["result"]["payment_hash"]
except Exception: except Exception as exc:
logger.debug(exc)
continue continue
except Exception as exc: except Exception as exc:
logger.error( logger.error(

View file

@ -1,6 +1,6 @@
import asyncio import asyncio
import random
from collections.abc import AsyncGenerator from collections.abc import AsyncGenerator
from secrets import token_urlsafe
from typing import Any, Optional from typing import Any, Optional
from bolt11.decode import decode as bolt11_decode from bolt11.decode import decode as bolt11_decode
@ -92,7 +92,7 @@ class CoreLightningWallet(Wallet):
unhashed_description: Optional[bytes] = None, unhashed_description: Optional[bytes] = None,
**kwargs, **kwargs,
) -> InvoiceResponse: ) -> InvoiceResponse:
label = kwargs.get("label", f"lbl{random.random()}") label = kwargs.get("label", f"lbl{token_urlsafe(16)}")
msat: int = int(amount * 1000) msat: int = int(amount * 1000)
try: try:
if description_hash and not unhashed_description: if description_hash and not unhashed_description:

View file

@ -1,7 +1,7 @@
import asyncio import asyncio
import json import json
import random
from collections.abc import AsyncGenerator from collections.abc import AsyncGenerator
from secrets import token_urlsafe
from typing import Optional from typing import Optional
import httpx import httpx
@ -111,7 +111,7 @@ class CoreLightningRestWallet(Wallet):
unhashed_description: Optional[bytes] = None, unhashed_description: Optional[bytes] = None,
**kwargs, **kwargs,
) -> InvoiceResponse: ) -> InvoiceResponse:
label = kwargs.get("label", f"lbl{random.random()}") label = kwargs.get("label", f"lbl{token_urlsafe(16)}")
data: dict = { data: dict = {
"amount": amount * 1000, "amount": amount * 1000,
"description": memo, "description": memo,
@ -298,7 +298,8 @@ class CoreLightningRestWallet(Wallet):
self.last_pay_index = inv["pay_index"] self.last_pay_index = inv["pay_index"]
if not paid: if not paid:
continue continue
except Exception: except Exception as exc:
logger.debug(exc)
continue continue
logger.trace(f"paid invoice: {inv}") logger.trace(f"paid invoice: {inv}")

View file

@ -292,7 +292,8 @@ class LndRestWallet(Wallet):
) )
else: else:
return PaymentPendingStatus() return PaymentPendingStatus()
except Exception: except Exception as exc:
logger.debug(exc)
continue continue
return PaymentPendingStatus() return PaymentPendingStatus()
@ -307,7 +308,8 @@ class LndRestWallet(Wallet):
inv = json.loads(line)["result"] inv = json.loads(line)["result"]
if not inv["settled"]: if not inv["settled"]:
continue continue
except Exception: except Exception as exc:
logger.debug(exc)
continue continue
payment_hash = base64.b64decode(inv["r_hash"]).hex() payment_hash = base64.b64decode(inv["r_hash"]).hex()

View file

@ -173,11 +173,12 @@ class LnTipsWallet(Wallet):
inv = json.loads(data) inv = json.loads(data)
if not inv.get("payment_hash"): if not inv.get("payment_hash"):
continue continue
except Exception: except Exception as exc:
logger.debug(exc)
continue continue
yield inv["payment_hash"] yield inv["payment_hash"]
except Exception: except Exception as exc:
pass logger.debug(exc)
# do not sleep if the connection was active for more than 10s # do not sleep if the connection was active for more than 10s
# since the backend is expected to drop the connection after 90s # since the backend is expected to drop the connection after 90s

View file

@ -2,6 +2,8 @@ import base64
from getpass import getpass from getpass import getpass
from typing import Optional from typing import Optional
from loguru import logger
from lnbits.utils.crypto import AESCipher from lnbits.utils.crypto import AESCipher
@ -39,7 +41,7 @@ def load_macaroon(
try: try:
macaroon = base64.b64decode(macaroon).hex() macaroon = base64.b64decode(macaroon).hex()
return macaroon return macaroon
except Exception: except Exception as exc:
pass logger.debug(exc)
return macaroon return macaroon

View file

@ -390,7 +390,7 @@ class NWCConnection:
n = max_length - len(subid) n = max_length - len(subid)
if n > 0: if n > 0:
for _ in range(n): for _ in range(n):
subid += chars[random.randint(0, len(chars) - 1)] subid += chars[random.randint(0, len(chars) - 1)] # noqa: S311
return subid return subid
async def _close_subscription_by_subid( async def _close_subscription_by_subid(

View file

@ -1,8 +1,8 @@
import asyncio import asyncio
import hashlib import hashlib
import json import json
import random
from collections.abc import AsyncGenerator from collections.abc import AsyncGenerator
from secrets import token_urlsafe
from typing import Optional from typing import Optional
import httpx import httpx
@ -116,7 +116,7 @@ class SparkWallet(Wallet):
unhashed_description: Optional[bytes] = None, unhashed_description: Optional[bytes] = None,
**kwargs, **kwargs,
) -> InvoiceResponse: ) -> InvoiceResponse:
label = f"lbs{random.random()}" label = f"lbs{token_urlsafe(16)}"
try: try:
if description_hash: if description_hash:
r = await self.invoicewithdescriptionhash( r = await self.invoicewithdescriptionhash(

63
poetry.lock generated
View file

@ -363,6 +363,31 @@ files = [
{file = "backports_datetime_fromisoformat-2.0.3.tar.gz", hash = "sha256:b58edc8f517b66b397abc250ecc737969486703a66eb97e01e6d51291b1a139d"}, {file = "backports_datetime_fromisoformat-2.0.3.tar.gz", hash = "sha256:b58edc8f517b66b397abc250ecc737969486703a66eb97e01e6d51291b1a139d"},
] ]
[[package]]
name = "bandit"
version = "1.8.5"
description = "Security oriented static analyser for python code."
optional = false
python-versions = ">=3.9"
groups = ["dev"]
files = [
{file = "bandit-1.8.5-py3-none-any.whl", hash = "sha256:cb2e57524e99e33ced48833c6cc9c12ac78ae970bb6a450a83c4b506ecc1e2f9"},
{file = "bandit-1.8.5.tar.gz", hash = "sha256:db812e9c39b8868c0fed5278b77fffbbaba828b4891bc80e34b9c50373201cfd"},
]
[package.dependencies]
colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""}
PyYAML = ">=5.3.1"
rich = "*"
stevedore = ">=1.20.0"
[package.extras]
baseline = ["GitPython (>=3.1.30)"]
sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"]
test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"]
toml = ["tomli (>=1.1.0) ; python_version < \"3.11\""]
yaml = ["PyYAML"]
[[package]] [[package]]
name = "base58" name = "base58"
version = "2.1.1" version = "2.1.1"
@ -2094,7 +2119,7 @@ version = "3.0.0"
description = "Python port of markdown-it. Markdown parsing, done right!" description = "Python port of markdown-it. Markdown parsing, done right!"
optional = false optional = false
python-versions = ">=3.8" python-versions = ">=3.8"
groups = ["main"] groups = ["main", "dev"]
files = [ files = [
{file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"},
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
@ -2211,7 +2236,7 @@ version = "0.1.2"
description = "Markdown URL utilities" description = "Markdown URL utilities"
optional = false optional = false
python-versions = ">=3.7" python-versions = ">=3.7"
groups = ["main"] groups = ["main", "dev"]
files = [ files = [
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
@ -2581,6 +2606,21 @@ files = [
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
] ]
[[package]]
name = "pbr"
version = "6.1.1"
description = "Python Build Reasonableness"
optional = false
python-versions = ">=2.6"
groups = ["dev"]
files = [
{file = "pbr-6.1.1-py2.py3-none-any.whl", hash = "sha256:38d4daea5d9fa63b3f626131b9d34947fd0c8be9b05a29276870580050a25a76"},
{file = "pbr-6.1.1.tar.gz", hash = "sha256:93ea72ce6989eb2eed99d0f75721474f69ad88128afdef5ac377eb797c4bf76b"},
]
[package.dependencies]
setuptools = "*"
[[package]] [[package]]
name = "platformdirs" name = "platformdirs"
version = "4.3.8" version = "4.3.8"
@ -3344,7 +3384,7 @@ version = "14.0.0"
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
optional = false optional = false
python-versions = ">=3.8.0" python-versions = ">=3.8.0"
groups = ["main"] groups = ["main", "dev"]
files = [ files = [
{file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"}, {file = "rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0"},
{file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"}, {file = "rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725"},
@ -3753,6 +3793,21 @@ anyio = ">=3.4.0,<5"
[package.extras] [package.extras]
full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"] full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7)", "pyyaml"]
[[package]]
name = "stevedore"
version = "5.4.1"
description = "Manage dynamic plugins for Python applications"
optional = false
python-versions = ">=3.9"
groups = ["dev"]
files = [
{file = "stevedore-5.4.1-py3-none-any.whl", hash = "sha256:d10a31c7b86cba16c1f6e8d15416955fc797052351a56af15e608ad20811fcfe"},
{file = "stevedore-5.4.1.tar.gz", hash = "sha256:3135b5ae50fe12816ef291baff420acb727fcd356106e3e9cbfa9e5985cd6f4b"},
]
[package.dependencies]
pbr = ">=2.0.0"
[[package]] [[package]]
name = "tlv8" name = "tlv8"
version = "0.10.0" version = "0.10.0"
@ -4420,4 +4475,4 @@ liquid = ["wallycore"]
[metadata] [metadata]
lock-version = "2.1" lock-version = "2.1"
python-versions = "~3.12 | ~3.11 | ~3.10" python-versions = "~3.12 | ~3.11 | ~3.10"
content-hash = "53f582a8079540033939ccd1bbd93b8ec1e8190ee26be0c0b8d64d57edb5cdac" content-hash = "17a61e0f0d45c02d99c398f8ddfd68f7bd55a04183cad7d615e170813be43348"

View file

@ -70,6 +70,7 @@ breez = ["breez-sdk", "breez-sdk-liquid"]
liquid = ["wallycore"] liquid = ["wallycore"]
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
bandit = "^1.8.5"
black = "^25.1.0" black = "^25.1.0"
mypy = "^1.11.2" mypy = "^1.11.2"
types-protobuf = "^6.30.2.20250516" types-protobuf = "^6.30.2.20250516"
@ -192,7 +193,8 @@ extend-exclude = [
# UP - pyupgrade # UP - pyupgrade
# RUF - ruff specific rules # RUF - ruff specific rules
# B - bugbear # B - bugbear
select = ["F", "E", "W", "I", "A", "C", "N", "UP", "RUF", "B"] # S - bandit
select = ["F", "E", "W", "I", "A", "C", "N", "UP", "RUF", "B", "S"]
# UP007: pyupgrade: use X | Y instead of Optional. (python3.10) # UP007: pyupgrade: use X | Y instead of Optional. (python3.10)
# RUF012: mutable-class-default # RUF012: mutable-class-default
ignore = ["RUF012"] ignore = ["RUF012"]
@ -211,6 +213,28 @@ classmethod-decorators = [
"validator", "validator",
] ]
[tool.ruff.lint.per-file-ignores]
# S101: Use of assert detected. mostly for tests...
# S105: Use of hard-coded password. mostly for tests...
# S106: Possible hardcoded password: 'password'.
# S307 Use of possibly insecure function; consider using `ast.literal_eval
# S602 `subprocess` call with `shell=True` identified, security issue
# S603 `subprocess` call: check for execution of untrusted input
# S607: Starting a process with a partial executable path
# TODO: do not skip S608:
# S608: Possible SQL injection vector through string-based query construction
# S324 Probable use of insecure hash functions in `hashlib`: `md5`
"lnbits/*" = ["S101", "S608"]
"lnbits/core/views/admin_api.py" = ["S602", "S603", "S607"]
"crypto.py" = ["S324"]
"test*.py" = ["S101", "S105", "S106", "S307"]
"tools*.py" = ["S101", "S608"]
"tests/*" = ["S311"]
"tests/regtest/helpers.py" = ["S603"]
[tool.bandit]
skips = ["B101", "B404"]
[tool.ruff.lint.mccabe] [tool.ruff.lint.mccabe]
max-complexity = 10 max-complexity = 10