From 377035ce88dad2fa96f5831c95bc420991829855 Mon Sep 17 00:00:00 2001 From: Brent Schroeter Date: Sat, 22 Mar 2025 01:03:04 -0700 Subject: [PATCH] set csp and cache-control headers appropriately --- Cargo.toml | 2 +- src/cli.rs | 14 +++++++++++--- src/router.rs | 27 +++++++++++++++++++++++++-- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c259a3..a5e8019 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,7 @@ serde = { version = "1.0.213", features = ["derive"] } serde_json = "1.0.132" tokio = { version = "1.42.0", features = ["full"] } tower = "0.5.2" -tower-http = { version = "0.6.2", features = ["compression-gzip", "fs", "normalize-path", "trace"] } +tower-http = { version = "0.6.2", features = ["compression-gzip", "fs", "normalize-path", "set-header", "trace"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.19", features = ["chrono", "env-filter"] } uuid = { version = "1.11.0", features = ["serde", "v4", "v7"] } diff --git a/src/cli.rs b/src/cli.rs index 2bdd50a..db5309f 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,11 +1,15 @@ use anyhow::Result; -use axum::middleware::map_request; +use axum::{ + http::{header::CONTENT_SECURITY_POLICY, HeaderValue}, + middleware::map_request, +}; use chrono::{TimeDelta, Utc}; use clap::{Parser, Subcommand}; use tokio::time::sleep; use tower::ServiceBuilder; use tower_http::{ - compression::CompressionLayer, normalize_path::NormalizePathLayer, trace::TraceLayer, + compression::CompressionLayer, normalize_path::NormalizePathLayer, + set_header::response::SetResponseHeaderLayer, trace::TraceLayer, }; use crate::{ @@ -42,7 +46,11 @@ pub async fn serve_command(state: AppState) -> Result<()> { .layer(map_request(lowercase_uri_path)) .layer(TraceLayer::new_for_http()) .layer(CompressionLayer::new()) - .layer(NormalizePathLayer::trim_trailing_slash()), + .layer(NormalizePathLayer::trim_trailing_slash()) + .layer(SetResponseHeaderLayer::if_not_present( + CONTENT_SECURITY_POLICY, + HeaderValue::from_static("frame-ancestors 'none'"), + )), ); let listener = diff --git a/src/router.rs b/src/router.rs index 184a2d7..664d5f9 100644 --- a/src/router.rs +++ b/src/router.rs @@ -1,10 +1,15 @@ use axum::{ extract::State, + http::{header::CACHE_CONTROL, HeaderValue}, response::{IntoResponse, Redirect}, routing::get, Router, }; -use tower_http::services::{ServeDir, ServeFile}; +use tower::ServiceBuilder; +use tower_http::{ + services::{ServeDir, ServeFile}, + set_header::SetResponseHeaderLayer, +}; use crate::{ app_state::AppState, auth, channels_router, projects_router, settings::Settings, teams_router, @@ -20,8 +25,26 @@ pub fn new_router(state: AppState) -> Router<()> { .merge(teams_router::new_router()) .merge(v0_router::new_router()) .nest("/auth", auth::new_router()) + .layer(SetResponseHeaderLayer::if_not_present( + CACHE_CONTROL, + HeaderValue::from_static("no-cache"), + )) .fallback_service( - ServeDir::new("static").not_found_service(ServeFile::new("static/_404.html")), + ServiceBuilder::new() + .layer(SetResponseHeaderLayer::if_not_present( + CACHE_CONTROL, + HeaderValue::from_static("max-age=21600, stale-while-revalidate=86400"), + )) + .service( + ServeDir::new("static").not_found_service( + ServiceBuilder::new() + .layer(SetResponseHeaderLayer::if_not_present( + CACHE_CONTROL, + HeaderValue::from_static("no-cache"), + )) + .service(ServeFile::new("static/_404.html")), + ), + ), ) .with_state(state); if base_path.is_empty() {