use axum::Router;
use axum::body::Body;
use axum::http::{Request, StatusCode, header};
use axum::routing::get;
use tower::ServiceExt;
use crate::headers::{install_csp, security_headers};
const POLICY: &str = "default-src 'self'; script-src 'self'";
fn app() -> Router {
install_csp(POLICY);
Router::new()
.route("/", get(|| async { "the page" }))
.route(
"/strict",
get(|| async {
(
[(header::CONTENT_SECURITY_POLICY, "default-src 'none'")],
"a page with its own policy",
)
}),
)
.layer(axum::middleware::from_fn(security_headers))
}
async fn headers_of(path: &str) -> axum::http::HeaderMap {
let response = app()
.oneshot(Request::builder().uri(path).body(Body::empty()).unwrap())
.await
.expect("a response");
assert_eq!(response.status(), StatusCode::OK);
response.headers().clone()
}
#[tokio::test]
async fn every_response_carries_the_policy() {
let headers = headers_of("/").await;
assert_eq!(headers[header::CONTENT_SECURITY_POLICY], POLICY);
}
#[tokio::test]
async fn a_page_that_set_its_own_policy_keeps_it() {
let headers = headers_of("/strict").await;
assert_eq!(
headers[header::CONTENT_SECURITY_POLICY],
"default-src 'none'"
);
}
#[tokio::test]
async fn sniffing_and_referrers_are_turned_off() {
let headers = headers_of("/").await;
assert_eq!(headers[header::X_CONTENT_TYPE_OPTIONS], "nosniff");
assert_eq!(headers[header::REFERRER_POLICY], "no-referrer");
}
#[test]
fn the_default_policy_covers_what_a_rahti_page_actually_loads() {
let csp = crate::config::NativeConfig::new("A", "com.example.a", "1.0.0", &["windows"])
.security
.csp;
assert!(csp.contains("script-src 'self'"), "{csp}");
assert!(
csp.contains("'unsafe-eval'"),
"the default policy would stop PulsePoint compiling any binding: {csp}"
);
assert!(csp.contains("connect-src"), "{csp}");
assert!(csp.contains("ws:"), "{csp}");
assert!(csp.contains("frame-ancestors 'none'"), "{csp}");
assert!(csp.contains("base-uri 'self'"), "{csp}");
assert!(csp.contains("object-src 'none'"), "{csp}");
}