Skip to content

Commit a31de88

Browse files
committed
Add CSP
1 parent f976b97 commit a31de88

File tree

5 files changed

+30
-3
lines changed

5 files changed

+30
-3
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.

browser/data-browser/vite.config.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import { defineConfig } from 'vite';
1+
import { defineConfig, type PluginOption } from 'vite';
22
import react from '@vitejs/plugin-react';
33
import { VitePWA } from 'vite-plugin-pwa';
44
import webfontDownload from 'vite-plugin-webfont-dl';
55
import prismjs from 'vite-plugin-prismjs';
6+
67
export default defineConfig({
78
plugins: [
89
webfontDownload(),
@@ -165,6 +166,9 @@ export default defineConfig({
165166
},
166167
},
167168
},
169+
html: {
170+
cspNonce: 'ATOMICSERVER_NONCE',
171+
},
168172
server: {
169173
strictPort: true,
170174
host: true,

lib/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ kuchikiki = { version = "0.8.2", optional = true }
2626
lol_html = { version = "1", optional = true }
2727
rand = { version = "0.8" }
2828
regex = "1"
29-
ring = "0.17.6"
29+
ring = "0.17.14"
3030
rio_api = { version = "0.8", optional = true }
3131
rio_turtle = { version = "0.8", optional = true }
3232
serde = { version = "1", features = ["derive"] }

server/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ tracing-chrome = "0.7"
5252
tracing-log = "0.2"
5353
ureq = "2"
5454
urlencoding = "2"
55+
ring = "0.17.14"
5556

5657
[dependencies.instant-acme]
5758
optional = true

server/src/handlers/single_page_app.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub async fn single_page(
1111
path: actix_web::web::Path<String>,
1212
) -> AtomicServerResult<HttpResponse> {
1313
let template = include_str!("../../assets_tmp/index.html");
14+
let csp_nonce = generate_nonce().map_err(|_e| "Failed to generate nonce")?;
1415
let subject = format!("{}/{}", appstate.store.get_server_url()?, path);
1516
let meta_tags: MetaTags = if let Ok(resource_response) =
1617
appstate
@@ -22,8 +23,13 @@ pub async fn single_page(
2223
MetaTags::default()
2324
};
2425

25-
let script = format!("<script>{}</script>", appstate.config.opts.script);
26+
let script = format!(
27+
"<script nonce=\"{}\">{}</script>",
28+
csp_nonce, appstate.config.opts.script
29+
);
30+
2631
let body = template
32+
.replace("ATOMICSERVER_NONCE", &csp_nonce)
2733
.replace("<!-- { inject_html_head } -->", &meta_tags.to_string())
2834
.replace("<!-- { inject_script } -->", &script);
2935

@@ -35,6 +41,10 @@ pub async fn single_page(
3541
"Cache-Control",
3642
"no-store, no-cache, must-revalidate, private",
3743
))
44+
.insert_header((
45+
"Content-Security-Policy",
46+
format!("script-src 'nonce-{}'; worker-src 'self'", csp_nonce),
47+
))
3848
.body(body);
3949

4050
Ok(resp)
@@ -159,6 +169,17 @@ fn escape_html(s: &str) -> String {
159169
.replace('/', "&#x2F;")
160170
}
161171

172+
fn generate_nonce() -> Result<String, ring::error::Unspecified> {
173+
use base64::{engine::general_purpose, Engine as _};
174+
use ring::rand::{SecureRandom, SystemRandom};
175+
176+
let mut nonce_bytes = [0u8; 32];
177+
let rng = SystemRandom::new();
178+
rng.fill(&mut nonce_bytes)?;
179+
180+
Ok(general_purpose::URL_SAFE_NO_PAD.encode(nonce_bytes))
181+
}
182+
162183
#[cfg(test)]
163184
mod test {
164185
use super::MetaTags;

0 commit comments

Comments
 (0)