use crate::config::SecurityHeaders;
use crate::policy::*;
use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Preset {
Strict,
Balanced,
Relaxed,
}
impl Preset {
pub fn build(self) -> SecurityHeaders {
match self {
Self::Strict => self.build_strict(),
Self::Balanced => self.build_balanced(),
Self::Relaxed => self.build_relaxed(),
}
}
fn build_strict(self) -> SecurityHeaders {
let csp = ContentSecurityPolicy::new()
.default_src(vec!["'self'"])
.object_src(vec!["'none'"])
.base_uri(vec!["'self'"])
.frame_ancestors(vec!["'none'"]);
SecurityHeaders::builder()
.content_security_policy(csp)
.strict_transport_security(Duration::from_secs(31536000), true, false)
.x_frame_options_deny()
.x_content_type_options_nosniff()
.referrer_policy_no_referrer()
.cross_origin_opener_policy(CrossOriginOpenerPolicy::SameOrigin)
.cross_origin_embedder_policy(CrossOriginEmbedderPolicy::RequireCorp)
.cross_origin_resource_policy(CrossOriginResourcePolicy::SameOrigin)
.build()
.expect("strict preset should always be valid")
}
fn build_balanced(self) -> SecurityHeaders {
let csp = ContentSecurityPolicy::new()
.default_src(vec!["'self'"])
.script_src(vec!["'self'", "'unsafe-inline'"])
.object_src(vec!["'none'"]);
SecurityHeaders::builder()
.content_security_policy(csp)
.strict_transport_security(Duration::from_secs(31536000), true, false)
.x_frame_options_sameorigin()
.x_content_type_options_nosniff()
.referrer_policy_strict_origin_when_cross_origin()
.cross_origin_opener_policy(CrossOriginOpenerPolicy::SameOriginAllowPopups)
.build()
.expect("balanced preset should always be valid")
}
fn build_relaxed(self) -> SecurityHeaders {
SecurityHeaders::builder()
.strict_transport_security(Duration::from_secs(15552000), false, false) .x_frame_options_sameorigin()
.x_content_type_options_nosniff()
.referrer_policy_strict_origin_when_cross_origin()
.build()
.expect("relaxed preset should always be valid")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_strict_preset() {
let headers = Preset::Strict.build();
assert!(headers.content_security_policy().is_some());
assert!(headers.strict_transport_security().is_some());
assert_eq!(headers.x_frame_options(), Some(XFrameOptions::Deny));
assert!(headers.x_content_type_options_enabled());
assert_eq!(headers.referrer_policy(), Some(ReferrerPolicy::NoReferrer));
assert_eq!(
headers.cross_origin_opener_policy(),
Some(CrossOriginOpenerPolicy::SameOrigin)
);
assert_eq!(
headers.cross_origin_embedder_policy(),
Some(CrossOriginEmbedderPolicy::RequireCorp)
);
assert_eq!(
headers.cross_origin_resource_policy(),
Some(CrossOriginResourcePolicy::SameOrigin)
);
}
#[test]
fn test_balanced_preset() {
let headers = Preset::Balanced.build();
assert!(headers.content_security_policy().is_some());
assert!(headers.strict_transport_security().is_some());
assert_eq!(headers.x_frame_options(), Some(XFrameOptions::SameOrigin));
assert!(headers.x_content_type_options_enabled());
assert_eq!(
headers.referrer_policy(),
Some(ReferrerPolicy::StrictOriginWhenCrossOrigin)
);
assert_eq!(
headers.cross_origin_opener_policy(),
Some(CrossOriginOpenerPolicy::SameOriginAllowPopups)
);
}
#[test]
fn test_relaxed_preset() {
let headers = Preset::Relaxed.build();
assert!(headers.content_security_policy().is_none());
assert!(headers.strict_transport_security().is_some());
assert_eq!(headers.x_frame_options(), Some(XFrameOptions::SameOrigin));
assert!(headers.x_content_type_options_enabled());
assert_eq!(
headers.referrer_policy(),
Some(ReferrerPolicy::StrictOriginWhenCrossOrigin)
);
let hsts = headers.strict_transport_security().unwrap();
assert_eq!(hsts.max_age(), Duration::from_secs(15552000)); }
}