Skip to content

Commit 8e913b8

Browse files
committed
parse the content-security-policy just once
1 parent f08fa57 commit 8e913b8

File tree

3 files changed

+23
-12
lines changed

3 files changed

+23
-12
lines changed

src/app_config.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::webserver::content_security_policy::DEFAULT_CONTENT_SECURITY_POLICY;
1+
use crate::webserver::content_security_policy::ContentSecurityPolicyTemplate;
22
use crate::webserver::routing::RoutingConfig;
33
use anyhow::Context;
44
use clap::Parser;
@@ -266,8 +266,8 @@ pub struct AppConfig {
266266

267267
/// Content-Security-Policy header to send to the client.
268268
/// If not set, a default policy allowing scripts from the same origin is used and from jsdelivr.net
269-
#[serde(default = "default_content_security_policy")]
270-
pub content_security_policy: String,
269+
#[serde(default)]
270+
pub content_security_policy: ContentSecurityPolicyTemplate,
271271

272272
/// Whether `sqlpage.fetch` should load trusted certificates from the operating system's certificate store
273273
/// By default, it loads Mozilla's root certificates that are embedded in the `SQLPage` binary, or the ones pointed to by the
@@ -533,10 +533,6 @@ fn default_compress_responses() -> bool {
533533
true
534534
}
535535

536-
fn default_content_security_policy() -> String {
537-
String::from(DEFAULT_CONTENT_SECURITY_POLICY)
538-
}
539-
540536
fn default_system_root_ca_certificates() -> bool {
541537
std::env::var("SSL_CERT_FILE").is_ok_and(|x| !x.is_empty())
542538
|| std::env::var("SSL_CERT_DIR").is_ok_and(|x| !x.is_empty())

src/webserver/content_security_policy.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use actix_web::http::header::{
44
use actix_web::HttpResponseBuilder;
55
use awc::http::header::InvalidHeaderValue;
66
use rand::random;
7+
use serde::Deserialize;
78
use std::fmt::{Display, Formatter};
89
use std::sync::Arc;
910

@@ -19,12 +20,18 @@ pub struct ContentSecurityPolicy {
1920
/// The template is a string that contains the nonce placeholder.
2021
/// The nonce placeholder is replaced with the nonce value when the Content Security Policy is applied to a response.
2122
/// This struct is cheap to clone.
22-
#[derive(Debug, Clone)]
23+
#[derive(Debug, Clone, PartialEq, Eq)]
2324
pub struct ContentSecurityPolicyTemplate {
2425
pub before_nonce: Arc<str>,
2526
pub after_nonce: Option<Arc<str>>,
2627
}
2728

29+
impl Default for ContentSecurityPolicyTemplate {
30+
fn default() -> Self {
31+
Self::from(DEFAULT_CONTENT_SECURITY_POLICY)
32+
}
33+
}
34+
2835
impl From<&str> for ContentSecurityPolicyTemplate {
2936
fn from(s: &str) -> Self {
3037
if let Some((before, after)) = s.split_once("{NONCE}") {
@@ -41,6 +48,16 @@ impl From<&str> for ContentSecurityPolicyTemplate {
4148
}
4249
}
4350

51+
impl<'de> Deserialize<'de> for ContentSecurityPolicyTemplate {
52+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
53+
where
54+
D: serde::Deserializer<'de>,
55+
{
56+
let s: &str = Deserialize::deserialize(deserializer)?;
57+
Ok(Self::from(s))
58+
}
59+
}
60+
4461
impl ContentSecurityPolicy {
4562
pub fn new(template: ContentSecurityPolicyTemplate) -> Self {
4663
Self {
@@ -56,7 +73,7 @@ impl ContentSecurityPolicy {
5673
}
5774

5875
fn is_enabled(&self) -> bool {
59-
!self.template.before_nonce.is_empty()
76+
!self.template.before_nonce.is_empty() || self.template.after_nonce.is_some()
6077
}
6178
}
6279

src/webserver/http.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,7 @@ async fn render_sql(
178178
let request_context = RequestContext {
179179
is_embedded: req_param.get_variables.contains_key("_sqlpage_embed"),
180180
content_security_policy: ContentSecurityPolicy::new(
181-
crate::webserver::content_security_policy::ContentSecurityPolicyTemplate::from(
182-
app_state.config.content_security_policy.as_str(),
183-
),
181+
app_state.config.content_security_policy.clone(),
184182
),
185183
};
186184
let mut conn = None;

0 commit comments

Comments
 (0)