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:
@@ -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())
|
||||
|
||||
Reference in New Issue
Block a user