From 464660a274e6b64bc6c6fa118e2ffaaf7f0ea26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Gruszczy=C5=84ski?= Date: Sun, 2 Aug 2026 11:04:04 +0200 Subject: [PATCH] changesin headers --- src/api/files.rs | 17 ------------- src/app/mod.rs | 64 ++++++++++++++++++++++++++++++++++-------------- src/app/pages.rs | 2 +- 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/src/api/files.rs b/src/api/files.rs index 89f2c91..f4a9d12 100644 --- a/src/api/files.rs +++ b/src/api/files.rs @@ -524,23 +524,6 @@ pub async fn download_file( serve_token_file(&state, &token, &filename).await } -pub async fn download_legacy_file( - State(state): State, - Path((directory, filename)): Path<(String, String)>, -) -> Result { - let Some((id_part, token)) = directory.split_once('_') else { - return Err(ApiError::not_found_file()); - }; - let id: i64 = id_part.parse().map_err(|_| ApiError::not_found_file())?; - let owner = db::find_file_owner(&state.db, token) - .await? - .ok_or_else(ApiError::not_found_file)?; - if owner.id != id { - return Err(ApiError::not_found_file()); - } - serve_token_file(&state, token, &filename).await -} - async fn serve_token_file( state: &SharedState, token: &str, diff --git a/src/app/mod.rs b/src/app/mod.rs index 0b9c818..78d79eb 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -70,10 +70,6 @@ pub fn router( .route("/icons/favicon-32.png", get(favicon_png)) .route("/icons/apple-touch-icon.png", get(apple_touch_icon)) .route("/f/{token}/{filename}", get(api::download_file)) - .route( - "/files/{directory}/{filename}", - get(api::download_legacy_file), - ) .route("/api/auth/identity", post(auth::identity)) .route( "/api/security/csrf", @@ -245,7 +241,7 @@ async fn apply_response_header_policy(request: Request, next: Next) -> Response fn apply_response_headers(policy: ResponseHeaderPolicy, headers: &mut HeaderMap) { match policy { - ResponseHeaderPolicy::StaticAsset => { + ResponseHeaderPolicy::StaticAsset | ResponseHeaderPolicy::File => { headers .entry(header::X_CONTENT_TYPE_OPTIONS) .or_insert(HeaderValue::from_static("nosniff")); @@ -284,16 +280,23 @@ fn apply_response_headers(policy: ResponseHeaderPolicy, headers: &mut HeaderMap) enum ResponseHeaderPolicy { Application, StaticAsset, + File, } fn response_header_policy(path: &str) -> ResponseHeaderPolicy { - if is_asset_path(path) || is_icon_path(path) { + if is_file_path(path) { + ResponseHeaderPolicy::File + } else if is_asset_path(path) || is_icon_path(path) { ResponseHeaderPolicy::StaticAsset } else { ResponseHeaderPolicy::Application } } +fn is_file_path(path: &str) -> bool { + path == "/f" || path.starts_with("/f/") +} + fn is_asset_path(path: &str) -> bool { path == "/assets" || path.starts_with("/assets/") } @@ -329,23 +332,21 @@ mod tests { } #[test] - fn keeps_file_routes_on_the_application_policy() { - for path in [ - "/f", - "/f/token/image.png", - "/files", - "/files/legacy/image.png", - ] { - assert_eq!( - response_header_policy(path), - ResponseHeaderPolicy::Application - ); + fn classifies_file_routes_as_files() { + for path in ["/f", "/f/token/image.png"] { + assert_eq!(response_header_policy(path), ResponseHeaderPolicy::File); } } #[test] fn classifies_other_routes_as_application() { - for path in ["/", "/api/auth/me", "/static/missing.css", "/unknown"] { + for path in [ + "/", + "/api/auth/me", + "/static/missing.css", + "/files/legacy/image.png", + "/unknown", + ] { assert_eq!( response_header_policy(path), ResponseHeaderPolicy::Application @@ -372,6 +373,33 @@ mod tests { assert!(!headers.contains_key("permissions-policy")); } + #[test] + fn file_policy_keeps_file_headers_without_document_policies() { + let mut headers = HeaderMap::new(); + headers.insert( + "content-security-policy", + HeaderValue::from_static("default-src 'none'; sandbox"), + ); + headers.insert( + header::CONTENT_DISPOSITION, + HeaderValue::from_static("attachment; filename=\"manual.pdf\""), + ); + + apply_response_headers(ResponseHeaderPolicy::File, &mut headers); + + assert_eq!(headers[header::X_CONTENT_TYPE_OPTIONS], "nosniff"); + assert_eq!( + headers["content-security-policy"], + "default-src 'none'; sandbox" + ); + assert!(headers.contains_key(header::CONTENT_DISPOSITION)); + assert!(!headers.contains_key("x-frame-options")); + assert!(!headers.contains_key("cross-origin-opener-policy")); + assert!(!headers.contains_key("cross-origin-resource-policy")); + assert!(!headers.contains_key("referrer-policy")); + assert!(!headers.contains_key("permissions-policy")); + } + #[test] fn application_policy_preserves_handler_headers() { let mut headers = HeaderMap::new(); diff --git a/src/app/pages.rs b/src/app/pages.rs index 82d280d..2a1aaae 100644 --- a/src/app/pages.rs +++ b/src/app/pages.rs @@ -133,7 +133,7 @@ pub(super) async fn apple_touch_icon() -> Response { } pub(super) async fn robots_txt() -> Response { - let mut response = "User-agent: *\nDisallow: /f/\nDisallow: /files/\n".into_response(); + let mut response = "User-agent: *\nDisallow: /f/\n".into_response(); response.headers_mut().insert( header::CONTENT_TYPE, HeaderValue::from_static("text/plain; charset=utf-8"),