bugfix: SSRF allowlist, image size cap, robust session detect (0.34.1)

Four crawler defences in one PR (all four threats the review flagged
in §3 of REVIEW.md):

- New crawler::safety module with is_safe_url + accumulate_capped +
  fetch_bytes_capped. Rejects non-http(s) schemes, RFC1918 / loopback
  / link-local / CGNAT / ULA / IPv6-link-local hosts, and any host
  not on the operator's allowlist (defaults to CRAWLER_START_URL host
  + CRAWLER_CDN_HOST + CRAWLER_DOWNLOAD_ALLOWLIST extras).
- Streaming size cap (CRAWLER_MAX_IMAGE_BYTES, default 32 MiB) so a
  10 GiB \"image\" can't fill memory before disk.
- looks_like_image() reject path: non-image bytes fail the chapter or
  cover instead of being stored as .bin and served as
  application/octet-stream.
- session::classify_chapter_probe: three-way classifier replaces the
  binary #avatar_menu check at content.rs:115. A transient hiccup
  (broken-page body, or logged-in-but-no-reader) now retries with
  backoff instead of falsely freezing every worker on
  session_expired.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-05-28 08:07:59 +02:00
parent e7662d18d6
commit c33f30972e
12 changed files with 807 additions and 43 deletions

18
backend/Cargo.lock generated
View File

@@ -1470,7 +1470,7 @@ checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4"
[[package]]
name = "mangalord"
version = "0.34.0"
version = "0.34.1"
dependencies = [
"anyhow",
"argon2",
@@ -2324,6 +2324,7 @@ dependencies = [
"cookie",
"cookie_store",
"futures-core",
"futures-util",
"http",
"http-body",
"http-body-util",
@@ -2343,12 +2344,14 @@ dependencies = [
"sync_wrapper",
"tokio",
"tokio-rustls",
"tokio-util",
"tower",
"tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"webpki-roots",
]
@@ -3527,6 +3530,19 @@ dependencies = [
"wasmparser",
]
[[package]]
name = "wasm-streams"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65"
dependencies = [
"futures-util",
"js-sys",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "wasmparser"
version = "0.244.0"