fix(server): inert proxy responses, API-call header, image-only uploads; origin check by host
From the final review: proxied archived HTML could run on our origin and read a remembered token; /api/upload accepted any Wayback URL and GIF-prefixed bytes; the origin check broke behind a TLS proxy; one unreadable snapshot could fail a run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
5084f8c557
commit
baa3476b73
16 files changed
+183
-26
No files matched your search
@@ -58,6 +58,8 @@ Put it behind a reverse proxy that terminates TLS and **appends** the client add
|
||||
no file is deleted before its 30 days.
|
||||
- Nothing is uploaded or submitted without an explicit user action; saves use `save_mode: "review"`.
|
||||
- `/api/fetch` only fetches allowlisted hosts; `/api/upload` only takes a source URL, never bytes.
|
||||
- Proxied bodies are inert (`application/octet-stream`, sandbox CSP, attachment), and `/api/*` fetch/upload need
|
||||
the `x-mbseed: 1` header; `/api/upload` only rehosts from source image hosts or their Wayback copies.
|
||||
|
||||
## Known rough edges
|
||||
See the open questions in spec §7 and [`TODO.md`](TODO.md).
|
||||
@@ -16,6 +16,24 @@ the repo every session — measurably slower and more tokens).
|
||||
**Consequences:** Rule changes happen in one file; pointer files must stay thin. Plans are working
|
||||
artefacts: kept after merge they go stale and contradict the code, so the spec is the record.
|
||||
|
||||
## 2026-10-15 — Harden the server proxy and uploads (final review)
|
||||
**Status:** accepted (amends "Implementation details: server API" below)
|
||||
**Context:** The whole-branch review found that `/api/fetch` passed the upstream content type through. Anyone can
|
||||
archive an HTML page on Wayback and link a user to our `/api/fetch?url=…` for it: the script would run on our origin
|
||||
and could read a MangaBaka token saved with "remember on this device". `/api/upload` also accepted any Wayback URL
|
||||
and any bytes starting with `GIF`, so our domain could be used as a 30-day file drop and the store filled.
|
||||
**Decision:**
|
||||
- Proxied bodies are always `application/octet-stream` with `nosniff`, `Content-Security-Policy: sandbox;
|
||||
default-src 'none'` and `Content-Disposition: attachment`. Nothing in our clients reads the content type.
|
||||
- `/api/fetch` and `/api/upload` require the header `x-mbseed: 1`, which our page and userscript send and a link or
|
||||
form cannot.
|
||||
- `/api/upload` rehosts only from a source's image hosts (`Source.imageHosts`) or Wayback's copy of one, and only
|
||||
images 1–10 000 px a side.
|
||||
- The origin check compares hosts, so `https://host` passes behind a TLS proxy that Bun sees as `http://host`.
|
||||
**Alternatives:** A session cookie or the password gate (deferred, spec §4.11); serving the page and the proxy on
|
||||
different origins (more deployment work).
|
||||
**Consequences:** A new source must list its image hosts. Clients other than ours must send `x-mbseed: 1`.
|
||||
|
||||
## 2026-10-14 — Implementation details: server API, Webtoons fetch forms
|
||||
**Status:** accepted
|
||||
**Context:** Decisions made while implementing plan 001 that the spec leaves open.
|
||||
|
||||
@@ -18,6 +18,10 @@ Design: [specs/001-webtoons-covers.md](specs/001-webtoons-covers.md).
|
||||
submitted with its hash on MangaBaka. If it doesn't, "already on MangaBaka" never matches.
|
||||
- [ ] Userscript: fill MangaBaka's cover form for users without a token (spec §4.9) — needs the logged-in
|
||||
form's markup and a check that it accepts programmatic input (spec §7.5). The panel offers copy-and-paste instead.
|
||||
- [ ] Small fixes from the final review (deferred as minor): a malformed `Location` on a proxied redirect gives 500
|
||||
instead of 502; cap the `/api/upload` JSON body size (`maxRequestBodySize`); after Preview, re-run `draw()`
|
||||
so the button respects an unconfirmed link mismatch and the counts refresh after a partial upload;
|
||||
label the "direct" host's URL as "Source URL", not "Rehosted".
|
||||
- [ ] Mobile layout (the user deferred it, 2026-10-15): the page stacks under 1000px but was only checked at 760px.
|
||||
|
||||
## Verify with real services (once possible)
|
||||
|
||||
Reference in new issue
Block a user