Skip to content

Commit 4e00b57

Browse files
committed
gateway: split up the csp lines
Signed-off-by: Younes Khoudli <[email protected]>
1 parent 65476a9 commit 4e00b57

File tree

3 files changed

+90
-8
lines changed

3 files changed

+90
-8
lines changed

front/public/netzgrafik-frontend/index.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
<!DOCTYPE html>
1+
<!doctype html>
22
<html class="sbb-lean sbb-light">
33
<head>
4-
<base href="/netzgrafik-frontend/">
5-
<link rel="stylesheet" href="/netzgrafik-frontend/assets/styles.css">
4+
<base href="/netzgrafik-frontend/" />
5+
<link rel="stylesheet" href="/netzgrafik-frontend/assets/styles.css" />
66
<script type="module" src="/netzgrafik-frontend/assets/runtime.js"></script>
77
<script type="module" src="/netzgrafik-frontend/assets/polyfills.js"></script>
88
<script type="module" src="/netzgrafik-frontend/assets/vendor.js"></script>

gateway/src/csp.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use std::{
2+
future::{Future, Ready, ready},
3+
pin::Pin,
4+
};
5+
6+
use actix_web::{
7+
Error,
8+
dev::{Service, ServiceRequest, ServiceResponse, Transform, forward_ready},
9+
web,
10+
};
11+
12+
use actix_web::http::header::CONTENT_SECURITY_POLICY;
13+
14+
pub struct CSP;
15+
16+
// `S` - type of the next service
17+
// `B` - type of response's body
18+
impl<S, B> Transform<S, ServiceRequest> for CSP
19+
where
20+
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
21+
S::Future: 'static,
22+
B: 'static,
23+
{
24+
type Response = ServiceResponse<B>;
25+
type Error = Error;
26+
type InitError = ();
27+
type Transform = CSPMiddleware<S>;
28+
type Future = Ready<Result<Self::Transform, Self::InitError>>;
29+
30+
fn new_transform(&self, service: S) -> Self::Future {
31+
ready(Ok(CSPMiddleware { service }))
32+
}
33+
}
34+
35+
pub struct CSPMiddleware<S> {
36+
/// The next service to call
37+
service: S,
38+
}
39+
40+
// This future doesn't have the requirement of being `Send`.
41+
// See: futures_util::future::LocalBoxFuture
42+
type LocalBoxFuture<T> = Pin<Box<dyn Future<Output = T> + 'static>>;
43+
44+
// `S`: type of the wrapped service
45+
// `B`: type of the body - try to be generic over the body where possible
46+
impl<S, B> Service<ServiceRequest> for CSPMiddleware<S>
47+
where
48+
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
49+
S::Future: 'static,
50+
B: 'static,
51+
{
52+
type Response = ServiceResponse<B>;
53+
type Error = Error;
54+
type Future = LocalBoxFuture<Result<Self::Response, Self::Error>>;
55+
56+
// This service is ready when its next service is ready
57+
forward_ready!(service);
58+
59+
fn call(&self, req: ServiceRequest) -> Self::Future {
60+
let csp_string = if req.path().starts_with("/netzgrafik-frontend") {
61+
// FIXME: add unsafe-inline for scripts if we don't keep the next commit
62+
// or, ideally, fix NGE to not require it.
63+
concat!(
64+
"default-src 'self'; form-action 'self'; frame-ancestors 'self'; ",
65+
"connect-src 'self' https://icons.app.sbb.ch; img-src 'self' data:; ",
66+
"font-src 'self' https://cdn.app.sbb.ch/fonts/ data:; style-src 'self' 'unsafe-inline';"
67+
)
68+
} else {
69+
"default-src 'self'; frame-ancestors 'self'; form-action 'self'; img-src 'self' data:; font-src 'self' data:; style-src 'self';"
70+
};
71+
let fut = self.service.call(req);
72+
73+
Box::pin(async move {
74+
let mut res = fut.await?;
75+
if !res.headers().contains_key(CONTENT_SECURITY_POLICY) {
76+
res.headers_mut().insert(
77+
CONTENT_SECURITY_POLICY,
78+
actix_web::http::header::HeaderValue::from_static(csp_string),
79+
);
80+
}
81+
Ok(res)
82+
})
83+
}
84+
}

gateway/src/main.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ use actix_auth::AuthMiddleware;
2222

2323
mod config;
2424
mod config_parser;
25+
mod csp;
2526
mod request_modifier;
2627

2728
#[actix_web::main]
@@ -86,13 +87,10 @@ async fn main() -> std::io::Result<()> {
8687
actix_cors::Cors::default()
8788
};
8889

89-
let default_headers = actix_web::middleware::DefaultHeaders::new().add((
90-
"Content-Security-Policy",
91-
"default-src 'self'; connect-src 'self' https://icons.app.sbb.ch; frame-ancestors 'self'; form-action 'self'; img-src 'self' data:; font-src 'self' https://cdn.app.sbb.ch/fonts/ data:; style-src 'self' 'unsafe-inline';",
92-
));
90+
let csp = csp::CSP;
9391

9492
let mut app = App::new()
95-
.wrap(default_headers)
93+
.wrap(csp)
9694
.wrap(cors)
9795
.wrap(RequestTracing::new())
9896
.wrap(Compress::default()) // enable compress

0 commit comments

Comments
 (0)