Skip to content

Commit c160ed3

Browse files
johan-smitsctron
authored andcommitted
Add a nonce to the script elements. This allows CSP to pick
up the nonce value and include it into the header.
1 parent cb2cf04 commit c160ed3

File tree

7 files changed

+32
-10
lines changed

7 files changed

+32
-10
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ once_cell = "1"
5050
open = "5"
5151
oxipng = "9"
5252
parking_lot = "0.12"
53+
rand = "0.8.5"
5354
remove_dir_all = "0.8"
5455
reqwest = { version = "0.12", default-features = false, features = ["stream", "trust-dns"] }
5556
sha2 = "0.10"

src/common/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ pub mod html_rewrite;
33

44
use anyhow::{anyhow, bail, Context, Result};
55
use async_recursion::async_recursion;
6+
use base64::{engine::general_purpose, Engine};
67
use console::Emoji;
78
use once_cell::sync::Lazy;
9+
use rand::RngCore;
810
use std::collections::HashSet;
911
use std::ffi::OsStr;
1012
use std::fmt::Debug;
@@ -262,3 +264,12 @@ pub fn path_to_href(path: impl AsRef<Path>) -> String {
262264
.collect::<Vec<_>>();
263265
path.join("/")
264266
}
267+
268+
/// A nonce random generator for script and style
269+
///
270+
/// https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/nonce
271+
pub fn nonce() -> String {
272+
let mut buffer = [0u8; 16];
273+
rand::rngs::OsRng.fill_bytes(&mut buffer);
274+
general_purpose::STANDARD.encode(buffer)
275+
}

src/pipelines/inline.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use super::{trunk_id_selector, AssetFile, Attrs, TrunkAssetPipelineOutput, ATTR_HREF, ATTR_TYPE};
44
use crate::common::html_rewrite::Document;
5+
use crate::common::nonce;
56
use anyhow::{bail, Context, Result};
67
use std::path::PathBuf;
78
use std::str::FromStr;
@@ -125,9 +126,13 @@ impl InlineOutput {
125126
pub async fn finalize(self, dom: &mut Document) -> Result<()> {
126127
let html = match self.content_type {
127128
ContentType::Html | ContentType::Svg => self.content,
128-
ContentType::Css => format!(r#"<style>{}</style>"#, self.content),
129-
ContentType::Js => format!(r#"<script>{}</script>"#, self.content),
130-
ContentType::Module => format!(r#"<script type="module">{}</script>"#, self.content),
129+
ContentType::Css => format!(r#"<style nonce="{}">{}</style>"#, nonce(), self.content),
130+
ContentType::Js => format!(r#"<script nonce="{}">{}</script>"#, nonce(), self.content),
131+
ContentType::Module => format!(
132+
r#"<script type="module" nonce="{}">{}</script>"#,
133+
nonce(),
134+
self.content
135+
),
131136
};
132137

133138
dom.replace_with_html(&trunk_id_selector(self.id), &html)

src/pipelines/rust/output.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use super::super::trunk_id_selector;
22
use crate::{
3-
common::html_rewrite::Document,
3+
common::{html_rewrite::Document, nonce},
44
config::{rt::RtcBuild, types::CrossOrigin},
55
pipelines::rust::{sri::SriBuilder, RustAppType},
66
};
@@ -130,6 +130,8 @@ window.{bindings} = bindings;
130130
false => ("", String::new()),
131131
};
132132

133+
let nonce = nonce();
134+
133135
// the code to fire the `TrunkApplicationStarted` event
134136
let fire = r#"
135137
dispatchEvent(new CustomEvent("TrunkApplicationStarted", {detail: {wasm}}));
@@ -138,7 +140,7 @@ dispatchEvent(new CustomEvent("TrunkApplicationStarted", {detail: {wasm}}));
138140
match &self.initializer {
139141
None => format!(
140142
r#"
141-
<script type="module">
143+
<script type="module" nonce="{nonce}">
142144
import init{import} from '{base}{js}';
143145
const wasm = await init('{base}{wasm}');
144146
@@ -148,7 +150,7 @@ const wasm = await init('{base}{wasm}');
148150
),
149151
Some(initializer) => format!(
150152
r#"
151-
<script type="module">
153+
<script type="module" nonce="{nonce}">
152154
{init}
153155
154156
import init{import} from '{base}{js}';

src/pipelines/sass.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::{
55
ATTR_INLINE, ATTR_NO_MINIFY,
66
};
77
use crate::{
8-
common::{self, dist_relative, html_rewrite::Document, target_path},
8+
common::{self, dist_relative, html_rewrite::Document, nonce, target_path},
99
config::rt::RtcBuild,
1010
processing::integrity::{IntegrityType, OutputDigest},
1111
tools::{self, Application},
@@ -206,7 +206,8 @@ impl SassOutput {
206206
let html = match self.css_ref {
207207
// Insert the inlined CSS into a `<style>` tag.
208208
CssRef::Inline(css) => format!(
209-
r#"<style {attrs}>{css}</style>"#,
209+
r#"<style {attrs} nonce="{}">{css}</style>"#,
210+
nonce(),
210211
attrs = AttrWriter::new(&self.attrs, AttrWriter::EXCLUDE_CSS_INLINE)
211212
),
212213
// Link to the CSS file.

src/pipelines/tailwind_css.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use super::{
55
ATTR_INLINE, ATTR_NO_MINIFY,
66
};
77
use crate::{
8-
common::{self, dist_relative, html_rewrite::Document, target_path},
8+
common::{self, dist_relative, html_rewrite::Document, nonce, target_path},
99
config::rt::RtcBuild,
1010
processing::integrity::{IntegrityType, OutputDigest},
1111
tools::{self, Application},
@@ -174,7 +174,8 @@ impl TailwindCssOutput {
174174
let html = match self.css_ref {
175175
// Insert the inlined CSS into a `<style>` tag.
176176
CssRef::Inline(css) => format!(
177-
r#"<style {attrs}>{css}</style>"#,
177+
r#"<style {attrs} nonce="{}">{css}</style>"#,
178+
nonce(),
178179
attrs = AttrWriter::new(&self.attrs, AttrWriter::EXCLUDE_CSS_INLINE)
179180
),
180181
// Link to the CSS file.

0 commit comments

Comments
 (0)