changesin headers
This commit is contained in:
@@ -524,23 +524,6 @@ pub async fn download_file(
|
|||||||
serve_token_file(&state, &token, &filename).await
|
serve_token_file(&state, &token, &filename).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn download_legacy_file(
|
|
||||||
State(state): State<SharedState>,
|
|
||||||
Path((directory, filename)): Path<(String, String)>,
|
|
||||||
) -> Result<Response, ApiError> {
|
|
||||||
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(
|
async fn serve_token_file(
|
||||||
state: &SharedState,
|
state: &SharedState,
|
||||||
token: &str,
|
token: &str,
|
||||||
|
|||||||
+46
-18
@@ -70,10 +70,6 @@ pub fn router(
|
|||||||
.route("/icons/favicon-32.png", get(favicon_png))
|
.route("/icons/favicon-32.png", get(favicon_png))
|
||||||
.route("/icons/apple-touch-icon.png", get(apple_touch_icon))
|
.route("/icons/apple-touch-icon.png", get(apple_touch_icon))
|
||||||
.route("/f/{token}/{filename}", get(api::download_file))
|
.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/auth/identity", post(auth::identity))
|
||||||
.route(
|
.route(
|
||||||
"/api/security/csrf",
|
"/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) {
|
fn apply_response_headers(policy: ResponseHeaderPolicy, headers: &mut HeaderMap) {
|
||||||
match policy {
|
match policy {
|
||||||
ResponseHeaderPolicy::StaticAsset => {
|
ResponseHeaderPolicy::StaticAsset | ResponseHeaderPolicy::File => {
|
||||||
headers
|
headers
|
||||||
.entry(header::X_CONTENT_TYPE_OPTIONS)
|
.entry(header::X_CONTENT_TYPE_OPTIONS)
|
||||||
.or_insert(HeaderValue::from_static("nosniff"));
|
.or_insert(HeaderValue::from_static("nosniff"));
|
||||||
@@ -284,16 +280,23 @@ fn apply_response_headers(policy: ResponseHeaderPolicy, headers: &mut HeaderMap)
|
|||||||
enum ResponseHeaderPolicy {
|
enum ResponseHeaderPolicy {
|
||||||
Application,
|
Application,
|
||||||
StaticAsset,
|
StaticAsset,
|
||||||
|
File,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn response_header_policy(path: &str) -> ResponseHeaderPolicy {
|
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
|
ResponseHeaderPolicy::StaticAsset
|
||||||
} else {
|
} else {
|
||||||
ResponseHeaderPolicy::Application
|
ResponseHeaderPolicy::Application
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_file_path(path: &str) -> bool {
|
||||||
|
path == "/f" || path.starts_with("/f/")
|
||||||
|
}
|
||||||
|
|
||||||
fn is_asset_path(path: &str) -> bool {
|
fn is_asset_path(path: &str) -> bool {
|
||||||
path == "/assets" || path.starts_with("/assets/")
|
path == "/assets" || path.starts_with("/assets/")
|
||||||
}
|
}
|
||||||
@@ -329,23 +332,21 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn keeps_file_routes_on_the_application_policy() {
|
fn classifies_file_routes_as_files() {
|
||||||
for path in [
|
for path in ["/f", "/f/token/image.png"] {
|
||||||
"/f",
|
assert_eq!(response_header_policy(path), ResponseHeaderPolicy::File);
|
||||||
"/f/token/image.png",
|
|
||||||
"/files",
|
|
||||||
"/files/legacy/image.png",
|
|
||||||
] {
|
|
||||||
assert_eq!(
|
|
||||||
response_header_policy(path),
|
|
||||||
ResponseHeaderPolicy::Application
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn classifies_other_routes_as_application() {
|
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!(
|
assert_eq!(
|
||||||
response_header_policy(path),
|
response_header_policy(path),
|
||||||
ResponseHeaderPolicy::Application
|
ResponseHeaderPolicy::Application
|
||||||
@@ -372,6 +373,33 @@ mod tests {
|
|||||||
assert!(!headers.contains_key("permissions-policy"));
|
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]
|
#[test]
|
||||||
fn application_policy_preserves_handler_headers() {
|
fn application_policy_preserves_handler_headers() {
|
||||||
let mut headers = HeaderMap::new();
|
let mut headers = HeaderMap::new();
|
||||||
|
|||||||
+1
-1
@@ -133,7 +133,7 @@ pub(super) async fn apple_touch_icon() -> Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn robots_txt() -> 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(
|
response.headers_mut().insert(
|
||||||
header::CONTENT_TYPE,
|
header::CONTENT_TYPE,
|
||||||
HeaderValue::from_static("text/plain; charset=utf-8"),
|
HeaderValue::from_static("text/plain; charset=utf-8"),
|
||||||
|
|||||||
Reference in New Issue
Block a user