systemprompt_api/services/middleware/
security_headers.rs1use axum::extract::Request;
7use axum::http::HeaderValue;
8use axum::middleware::Next;
9use axum::response::Response;
10use systemprompt_extension::FrameOptionsOverride;
11use systemprompt_models::profile::SecurityHeadersConfig;
12
13pub async fn inject_security_headers(
14 config: SecurityHeadersConfig,
15 request: Request,
16 next: Next,
17) -> Response {
18 let mut response = next.run(request).await;
19 let frame_override = response.extensions().get::<FrameOptionsOverride>().copied();
20 let headers = response.headers_mut();
21
22 if let Ok(value) = HeaderValue::from_str(&config.hsts) {
23 headers.insert("strict-transport-security", value);
24 }
25
26 if let Some(FrameOptionsOverride(frame_options)) = frame_override {
27 match frame_options.header_value() {
28 Some(value) => {
29 headers.insert("x-frame-options", HeaderValue::from_static(value));
30 },
31 None => {
32 headers.remove("x-frame-options");
33 },
34 }
35 if let Ok(value) = HeaderValue::from_str(&format!(
36 "frame-ancestors {}",
37 frame_options.frame_ancestors()
38 )) {
39 headers.insert("content-security-policy", value);
40 }
41 } else {
42 match config.frame_options.header_value() {
43 Some(value) => {
44 headers.insert("x-frame-options", HeaderValue::from_static(value));
45 },
46 None => {
47 headers.remove("x-frame-options");
48 },
49 }
50 }
51
52 if let Ok(value) = HeaderValue::from_str(&config.content_type_options) {
53 headers.insert("x-content-type-options", value);
54 }
55
56 headers.insert(
57 "referrer-policy",
58 HeaderValue::from_static(config.referrer_policy.header_value()),
59 );
60
61 if let Ok(value) = HeaderValue::from_str(&config.permissions_policy) {
62 headers.insert("permissions-policy", value);
63 }
64
65 if let Some(ref csp) = config.content_security_policy
66 && frame_override.is_none()
67 && let Ok(value) = HeaderValue::from_str(csp)
68 {
69 headers.insert("content-security-policy", value);
70 }
71
72 response
73}