bambuddy/requirements.txt
maziggy 09b739b95d fix(cloud): stop reporting an expired Bambu Cloud sign-in as connected (issue #2562)
An expired token was indistinguishable from a working one. set_token()
stamped token_expiry = now + 30 days every time a stored token was loaded,
so the expiry reset on every request and is_authenticated could never
return False. /cloud/status answered "connected" for as long as any token
existed, while every cloud call 401'd — and the user was shown Bambu's own
{"error": "Please login."} verbatim.

Bambu is now the authority: /cloud/status validates the token upstream
(cached 5m), and any 401 from any authenticated call durably records the
credential as dead via users.cloud_token_invalid_at, so MakerWorld, cloud
profiles, slicer presets and firmware checks all agree at once. An
unreachable Bambu is treated as unknown, never as expired, so an outage
cannot sign a working session out.

The user-facing message now names the Profiles page, where the Bambu Cloud
sign-in actually lives; the old text pointed at a Settings page that does
not exist. Same stale path corrected in the wiki.
2026-07-14 11:29:56 +02:00

167 lines
6.6 KiB
Text

# Web Framework
# fastapi 0.136.x ships an undocumented `fastar` dep in its [standard]
# extras group (MAL-2026-4750, surfaced by Amazon Inspector). `fastar`
# is a Rust-tar binding package — no plausible reason for a web
# framework to depend on it. Even if `fastar` is benign today, the
# advisory's framing as a namespace-abuse / supply-chain vector is
# valid: anyone controlling the `fastar` PyPI namespace gains code
# execution at install time across every fastapi[standard] install.
# Bambuddy doesn't request [standard], so we don't pull `fastar` in
# practice, but pip-audit flags the package itself and breaks CI.
# Hold to 0.135.x (which has all features we use, including SSE)
# until upstream removes the dep or explains the rationale.
fastapi>=0.109.0,<0.136.0
uvicorn[standard]>=0.27.0
# Database
# 2.0.38 is a hard floor, not a preference: it changed the aiosqlite dialect's
# default pool for file databases from NullPool to AsyncAdaptedQueuePool.
# core/database._create_engine() passes pool_size/max_overflow on the SQLite
# branch, which NullPool rejects — on <=2.0.37 every SQLite install (and the
# test suite, which imports the module-level engine) dies at import with
# "Invalid argument(s) 'pool_size','max_overflow' sent to create_engine()".
sqlalchemy>=2.0.38
aiosqlite>=0.19.0
asyncpg>=0.29.0
greenlet>=3.0.0
# Pydantic
pydantic>=2.0.0
# 2.14.2 patches GHSA-4xgf-cpjx-pc3j (NestedSecretsSettingsSource follows
# symlinks out of secrets_dir). Bambuddy does not use that source — pin
# is precautionary so the audit stays clean.
pydantic-settings>=2.14.2
# Transitive of pydantic-settings, floor-pinned to patch CVE-2026-28684 (dotenv 1.2.1)
python-dotenv>=1.2.2
# Bambu Lab Printer Communication
paho-mqtt>=2.0.0
aioftp>=0.22.0
# Virtual Printer (emulates Bambu printer for slicer uploads)
pyftpdlib>=2.0.0
# 46.x line has GHSA-537c-gmf6-5ccf; 48.0.1 is the fix release. Upstream's
# X.509 / PKCS#7 surface is in our trust path via asyncssh, pyOpenSSL,
# py-vapid, http_ece, pywebpush.
cryptography>=48.0.1
# Transitive of asyncssh / pywebpush. pyopenssl<26.3.0 caps `cryptography<47`
# so without this floor the resolver either downgrades cryptography below
# the GHSA-537c-gmf6-5ccf fix line or installs an inconsistent pair.
pyopenssl>=26.3.0
# SpoolBuddy remote SSH updates (pure-Python SSH client; avoids the
# OpenSSH `ssh` binary which calls getpwuid() and fails in Docker when
# the container UID isn't in /etc/passwd)
asyncssh>=2.18.0
# 3MF Processing (standard zipfile is sufficient for Bambu 3MF files)
defusedxml>=0.7.0 # Safe XML parsing (prevents XXE attacks)
# Excel Export
openpyxl>=3.1.0
# Notifications
pywebpush>=2.0.0
# Utilities
# 0.0.27 → 0.0.31 clears three CVEs in the parser surface that FastAPI
# uses for multipart form bodies (CVE-2026-53538/53539/53540).
python-multipart>=0.0.31
aiofiles>=23.0.0
# QR Code generation
qrcode[pil]>=7.4.0
# PDF generation (spool label printing — #809)
reportlab>=4.0.0
# STL Thumbnail Generation
trimesh>=4.0.0
matplotlib>=3.8.0
fast-simplification>=0.1.0
# trimesh's 3MF loader uses networkx for scene-graph traversal and lxml
# for the model.xml parse. Required by plate_thumbnail.py to render the
# model out of a sliced .gcode.3mf when the BS/Orca CLI didn't embed
# Metadata/plate_N.png. Not strictly transitive — trimesh imports both
# lazily inside the 3MF code path, so the load call fails at runtime
# ("No module named 'networkx'" / "No module named 'lxml'") if absent.
networkx>=3.0
lxml>=5.0
# System monitoring
psutil>=6.0.0
# IANA tz database for Windows. The stdlib ``zoneinfo`` module reads the
# system tz database on Linux/macOS, but Windows has none — and the
# embedded Python in our Windows installer doesn't carry one either, so
# even ``ZoneInfo("UTC")`` raises ``ZoneInfoNotFoundError`` and any
# endpoint that resolves a tz (e.g. /api/local-backup/status) 500s.
# ``tzdata`` is the official PyPI package that fills the gap.
tzdata>=2024.1; sys_platform == "win32"
# Authentication
PyJWT>=2.13.0
passlib[bcrypt]>=1.7.4
ldap3>=2.9.0
pyotp>=2.9.0
# Transitive dep pin: idna<3.15 has CVE-2026-45409 (ReDoS on encode() with
# crafted Unicode). Pulled in by anyio/httpx/requests/yarl; pin the floor
# so we don't regress when a downstream loosens its constraint.
idna>=3.15
# HTTP client (used for OIDC token exchange)
httpx>=0.26.0
# CA bundle. Already a transitive dep of httpx, but services/makerworld.py
# imports it directly to pin the S3 presigned download's urllib opener to the
# same trust store httpx uses — the Windows OS store lacks the Amazon root
# until CryptoAPI lazily caches it (#2562). Declared explicitly so a future
# httpx release that drops certifi can't silently break that import.
certifi>=2024.2.2
# HTTP client with browser TLS-fingerprint impersonation. Used only for
# the bambulab.com firmware-download page in services/firmware_check.py:
# Bambu's Cloudflare WAF gates the page behind a JA3/TLS-fingerprint
# challenge that plain httpx/requests can't pass (#1666). curl_cffi
# replays Chrome's ClientHello bytes so the TLS handshake clears CF;
# the HTTP-layer User-Agent stays honest Bambuddy/1.0 per our compliance
# commitment. Soft dependency — if it fails to import (rare platforms,
# constrained installs), firmware_check degrades gracefully to wiki-only
# version detection and logs a warning at startup.
curl_cffi>=0.7.0
# Transitive pin: urllib3 2.6.3 has CVE-2026-44431 and CVE-2026-44432;
# 2.7.0+ is the fixed release. Direct pin here because none of our
# top-level deps require >=2.7.0 yet, so without this the resolver
# would silently keep installing the vulnerable 2.6.x line.
urllib3>=2.7.0
# Transitive of fastapi. starlette 1.0.0 has PYSEC-2026-161; 1.1.x has
# CVE-2026-54282/54283; 1.3.1 is the fixed release. fastapi's range still
# admits the vulnerable builds, so we pin the floor directly to stop the
# resolver from picking them.
starlette>=1.3.1
# Transitive of pywebpush (unpinned `aiohttp` requirement). aiohttp 3.13.5
# has CVE-2026-34993 and CVE-2026-47265, both fixed in 3.14.0. pywebpush
# doesn't declare an upper bound either way, so without this pin the
# resolver keeps installing the vulnerable 3.13.x line. Our direct usage
# in services/external_camera.py (ClientSession, ClientTimeout, ClientError,
# iter_chunked) is unaffected by 3.14.0.
aiohttp>=3.14.0
# Plate Detection (optional - enables build plate empty detection)
opencv-python-headless>=4.8.0
numpy>=1.24.0
# Development
pytest>=9.0.3
pytest-asyncio>=0.23.0
httpx>=0.26.0
# Lint/format is pinned exactly in requirements-dev.txt — that file is the
# source of truth for the version CI enforces. This floor only keeps `ruff`
# importable for anyone who installs the runtime file alone.
ruff>=0.8.0
pillow>=12.2.0