use std::prelude::v1::*;
use csp::{CSP, Directive, Sources, Source, ReportUris, SriFor, SandboxAllowedList, SandboxAllow, Plugins};
use product_os_security::CSPConfig;
pub struct ContentSecurityPolicy {
policy: CSPConfig
}
impl ContentSecurityPolicy {
pub fn from_csp_config(csp_config: &CSPConfig) -> Self {
Self {
policy: csp_config.clone()
}
}
fn build_sources(sources: &[String]) -> Sources<'_> {
let mut sources_list = Sources::new();
for value in sources {
if value == "self" {
sources_list.push_borrowed(Source::Self_);
} else {
sources_list.push_borrowed(Source::Host(value.as_str()));
}
}
sources_list
}
pub fn get_csp(&self) -> String {
let csp_config = &self.policy;
let mut policy = CSP::new();
if let Some(sources) = &csp_config.base_uri {
if !sources.is_empty() {
policy.push_borrowed(Directive::BaseUri(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.child_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::ChildSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.connect_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::ConnectSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.default_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::DefaultSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.font_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::FontSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.form_action {
if !sources.is_empty() {
policy.push_borrowed(Directive::FormAction(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.frame_ancestors {
if !sources.is_empty() {
policy.push_borrowed(Directive::FrameAncestors(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.frame_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::FrameSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.img_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::ImgSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.manifest_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::ManifestSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.media_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::MediaSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.navigate_to {
if !sources.is_empty() {
policy.push_borrowed(Directive::NavigateTo(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.object_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::ObjectSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.prefetch_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::PrefetchSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.script_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::ScriptSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.script_src_attr {
if !sources.is_empty() {
policy.push_borrowed(Directive::ScriptSrcAttr(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.script_src_elem {
if !sources.is_empty() {
policy.push_borrowed(Directive::ScriptSrcElem(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.style_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::StyleSrc(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.style_src_attr {
if !sources.is_empty() {
policy.push_borrowed(Directive::StyleSrcAttr(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.style_src_elem {
if !sources.is_empty() {
policy.push_borrowed(Directive::StyleSrcElem(Self::build_sources(sources)));
}
}
if let Some(sources) = &csp_config.worker_src {
if !sources.is_empty() {
policy.push_borrowed(Directive::WorkerSrc(Self::build_sources(sources)));
}
}
if let Some(values) = &csp_config.block_all_mixed_content {
if values.iter().any(|v| v == "true") {
policy.push_borrowed(Directive::BlockAllMixedContent);
}
}
if let Some(plugin_types) = &csp_config.plugin_types {
if !plugin_types.is_empty() {
let mut plugins = Plugins::new();
for value in plugin_types {
if value.len() == 2 {
plugins = plugins.push((value[0].as_str(), value[1].as_str()));
}
}
policy.push_borrowed(Directive::PluginTypes(plugins));
}
}
if let Some(report_to) = &csp_config.report_to {
for value in report_to {
policy.push_borrowed(Directive::ReportTo(value.as_str()));
}
}
if let Some(report_uri) = &csp_config.report_uri {
if !report_uri.is_empty() {
let mut report_uris = ReportUris::new();
for value in report_uri {
report_uris.push_borrowed(value.as_str());
}
policy.push_borrowed(Directive::ReportUri(report_uris));
}
}
if let Some(values) = &csp_config.require_sri_for {
if values.iter().any(|v| v == "true") {
policy.push_borrowed(Directive::RequireSriFor(SriFor::ScriptStyle));
}
}
if let Some(sandbox_allow) = &csp_config.sandbox_allow {
if !sandbox_allow.is_empty() {
let mut sandbox_list = SandboxAllowedList::new();
for value in sandbox_allow {
let allow = match value.as_str() {
"downloads_without_user_activation" => SandboxAllow::DownloadsWithoutUserActivation,
"forms" => SandboxAllow::Forms,
"modals" => SandboxAllow::Modals,
"orientation_lock" => SandboxAllow::OrientationLock,
"popups" => SandboxAllow::Popups,
"popups_to_escape_sandbox" => SandboxAllow::PopupsToEscapeSandbox,
"pointer_lock" => SandboxAllow::PointerLock,
"presentation" => SandboxAllow::Presentation,
"same_origin" => SandboxAllow::SameOrigin,
"scripts" => SandboxAllow::Scripts,
"storage_access_by_user_activation" => SandboxAllow::StorageAccessByUserActivation,
"top_navigation" => SandboxAllow::TopNavigation,
"top_navigation_by_user_activation" => SandboxAllow::TopNavigationByUserActivation,
_ => SandboxAllow::SameOrigin,
};
sandbox_list.push_borrowed(allow);
}
policy.push_borrowed(Directive::Sandbox(sandbox_list));
}
}
if let Some(trusted_types) = &csp_config.trusted_types {
if !trusted_types.is_empty() {
let types: Vec<&str> = trusted_types.iter().map(|s| s.as_str()).collect();
policy.push_borrowed(Directive::TrustedTypes(types));
}
}
if let Some(values) = &csp_config.upgrade_insecure_requests {
if values.iter().all(|v| v != "false") && !values.is_empty() {
policy.push_borrowed(Directive::UpgradeInsecureRequests);
}
}
policy.to_string()
}
}