From af69755e5b276133f649ee0f6aa4bc1e075e5291 Mon Sep 17 00:00:00 2001 From: Johan Smits Date: Wed, 5 Jun 2024 10:31:46 +0200 Subject: [PATCH] Add a nonce to the script elements. This allows CSP to pick up the nonce value and include it into the header. --- Cargo.lock | 1 + Cargo.toml | 1 + src/common/mod.rs | 11 +++++++++++ src/pipelines/inline.rs | 11 ++++++++--- src/pipelines/rust/output.rs | 8 +++++--- src/pipelines/sass.rs | 5 +++-- src/pipelines/tailwind_css.rs | 5 +++-- 7 files changed, 32 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19c4066e..118b280a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3759,6 +3759,7 @@ dependencies = [ "open", "oxipng", "parking_lot", + "rand 0.8.5", "remove_dir_all", "reqwest", "rstest", diff --git a/Cargo.toml b/Cargo.toml index 55ac8b51..5b0dd0ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ once_cell = "1" open = "5" oxipng = "9" parking_lot = "0.12" +rand = "0.8.5" remove_dir_all = "0.8" reqwest = { version = "0.12", default-features = false, features = ["stream", "trust-dns"] } sha2 = "0.10" diff --git a/src/common/mod.rs b/src/common/mod.rs index f1484eb8..5a91739e 100644 --- a/src/common/mod.rs +++ b/src/common/mod.rs @@ -3,8 +3,10 @@ pub mod html_rewrite; use anyhow::{anyhow, bail, Context, Result}; use async_recursion::async_recursion; +use base64::{engine::general_purpose, Engine}; use console::Emoji; use once_cell::sync::Lazy; +use rand::RngCore; use std::collections::HashSet; use std::ffi::OsStr; use std::fmt::Debug; @@ -262,3 +264,12 @@ pub fn path_to_href(path: impl AsRef) -> String { .collect::>(); path.join("/") } + +/// A nonce random generator for script and style +/// +/// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce +pub fn nonce() -> String { + let mut buffer = [0u8; 16]; + rand::rngs::OsRng.fill_bytes(&mut buffer); + general_purpose::STANDARD.encode(buffer) +} diff --git a/src/pipelines/inline.rs b/src/pipelines/inline.rs index 482aff0f..3ec781c8 100644 --- a/src/pipelines/inline.rs +++ b/src/pipelines/inline.rs @@ -2,6 +2,7 @@ use super::{trunk_id_selector, AssetFile, Attrs, TrunkAssetPipelineOutput, ATTR_HREF, ATTR_TYPE}; use crate::common::html_rewrite::Document; +use crate::common::nonce; use anyhow::{bail, Context, Result}; use std::path::PathBuf; use std::str::FromStr; @@ -125,9 +126,13 @@ impl InlineOutput { pub async fn finalize(self, dom: &mut Document) -> Result<()> { let html = match self.content_type { ContentType::Html | ContentType::Svg => self.content, - ContentType::Css => format!(r#""#, self.content), - ContentType::Js => format!(r#""#, self.content), - ContentType::Module => format!(r#""#, self.content), + ContentType::Css => format!(r#""#, nonce(), self.content), + ContentType::Js => format!(r#""#, nonce(), self.content), + ContentType::Module => format!( + r#""#, + nonce(), + self.content + ), }; dom.replace_with_html(&trunk_id_selector(self.id), &html) diff --git a/src/pipelines/rust/output.rs b/src/pipelines/rust/output.rs index e9df2f6c..ddbd733c 100644 --- a/src/pipelines/rust/output.rs +++ b/src/pipelines/rust/output.rs @@ -1,6 +1,6 @@ use super::super::trunk_id_selector; use crate::{ - common::html_rewrite::Document, + common::{html_rewrite::Document, nonce}, config::{rt::RtcBuild, types::CrossOrigin}, pipelines::rust::{sri::SriBuilder, RustAppType}, }; @@ -130,6 +130,8 @@ window.{bindings} = bindings; false => ("", String::new()), }; + let nonce = nonce(); + // the code to fire the `TrunkApplicationStarted` event let fire = r#" dispatchEvent(new CustomEvent("TrunkApplicationStarted", {detail: {wasm}})); @@ -138,7 +140,7 @@ dispatchEvent(new CustomEvent("TrunkApplicationStarted", {detail: {wasm}})); match &self.initializer { None => format!( r#" -