fix: don't mark private-mode blobs as publicly cacheable

The immutable Cache-Control added for the reader preload work was
`public` unconditionally. Under PRIVATE_MODE, /files is auth-gated, so a
shared cache/CDN would store the blob and serve it to unauthenticated
clients, defeating the gate. Emit `private, ...` when private_mode is on,
`public, ...` otherwise.

Found in the security audit; regression from 0.124.3. Bump to 0.124.9.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-07 21:39:20 +02:00
parent 795eb76f9a
commit 61669aac3f
5 changed files with 64 additions and 4 deletions

View File

@@ -55,9 +55,19 @@ async fn serve(State(state): State<AppState>, Path(key): Path<String>) -> AppRes
// revalidation entirely — this is what lets the reader's page and
// next-chapter preloading hit cache instead of re-downloading (and
// re-proxying every byte through the SvelteKit node server in prod).
//
// BUT under PRIVATE_MODE these blobs are auth-gated (see
// `private_mode_guard`), so they must NOT be marked `public`: a shared
// cache / CDN in front of the app would store the object and then serve
// it to unauthenticated clients, defeating the gate. Use `private` so
// only the requesting user's browser caches it.
(
header::CACHE_CONTROL,
"public, max-age=31536000, immutable".to_string(),
if state.auth.private_mode {
"private, max-age=31536000, immutable".to_string()
} else {
"public, max-age=31536000, immutable".to_string()
},
),
];
Ok((headers, Body::from_stream(file.stream)).into_response())