aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Fischer <martin@push-f.com>2021-06-24 21:07:45 +0200
committerMartin Fischer <martin@push-f.com>2021-06-24 23:14:15 +0200
commitd43543440e5d3f0e93ed1cf197601d778541c3ae (patch)
treed966b40936d7ef8cb559e2b556d3b9e01a5f824b
parentb019d39957bd644d9b6b856738b57eb87e0506de (diff)
generate <script> tags and CSP from Page vectors
-rw-r--r--src/controller.rs10
-rw-r--r--src/forms.rs12
-rw-r--r--src/get_routes.rs11
-rw-r--r--src/main.rs29
-rw-r--r--src/static/edit_script.js.sha1
-rw-r--r--src/static/edit_script.js.sha2561
-rw-r--r--src/static/style.css.sha1
-rw-r--r--src/static/style.css.sha2561
-rwxr-xr-xsrc/static/update_hashes.sh2
9 files changed, 38 insertions, 30 deletions
diff --git a/src/controller.rs b/src/controller.rs
index f912d74..168bc76 100644
--- a/src/controller.rs
+++ b/src/controller.rs
@@ -286,8 +286,7 @@ fn multi_user_startpage(
// TODO: add domain name to title?
let mut page = Page {
title: "GitPad".into(),
- body: String::new(),
- header: None,
+ ..Default::default()
};
let branches: Vec<_> = repo.branches(Some(BranchType::Local))?.collect();
@@ -354,12 +353,7 @@ impl Controller for MultiUserController {
if unsanitized_path.is_empty() {
let username = username_from_parts(&parts).unwrap();
if username != rev.0 {
- let mut page = Page {
- title: "".into(),
- header: None,
- body: String::new(),
- };
-
+ let mut page = Page::default();
self.list_shares(repo, &rev, username, &mut page.body);
return Err(Ok(page.into()));
}
diff --git a/src/forms.rs b/src/forms.rs
index 240d300..c827ccb 100644
--- a/src/forms.rs
+++ b/src/forms.rs
@@ -36,7 +36,9 @@ pub fn edit_text_form<'a, C: Controller>(
.oid
.is_some()
.then(|| action_links("edit", controller, ctx, parts)),
- body: String::new(),
+ scripts: vec![include_str!("static/edit_script.js")],
+ script_src: vec![include_str!("static/edit_script.js.sha")],
+ ..Default::default()
};
if let Some(access_info_html) = controller.access_info_html(&ctx, parts) {
page.body.push_str(&access_info_html);
@@ -70,11 +72,6 @@ pub fn edit_text_form<'a, C: Controller>(
"<input name=msg placeholder=Message value='{}' autocomplete=off></div></form>",
html_escape(data.msg.as_deref().unwrap_or_default())
));
-
- page.body.push_str(&format!(
- "<script>{}</script>",
- include_str!("static/edit_script.js")
- ));
page
}
@@ -94,8 +91,8 @@ pub fn move_form<C: Controller>(
) -> Result<Response, Error> {
let mut page = Page {
title: format!("Move {}", filename),
- body: String::new(),
header: Some(action_links("move", controller, ctx, parts)),
+ ..Default::default()
};
if let Some(error) = error {
@@ -131,5 +128,6 @@ pub fn upload_form<'a, C: Controller>(
</form>"
.into(),
header: file_exists.then(|| action_links("edit", controller, &ctx, parts)),
+ ..Default::default()
}
}
diff --git a/src/get_routes.rs b/src/get_routes.rs
index 3661896..b9ad933 100644
--- a/src/get_routes.rs
+++ b/src/get_routes.rs
@@ -56,8 +56,8 @@ fn view_blob<C: Controller>(
) -> Result<Response, Error> {
let mut page = Page {
title: ctx.file_name().unwrap().to_owned(),
- body: String::new(),
header: Some(action_links(&params.action, controller, &ctx, parts)),
+ ..Default::default()
};
if let Some(access_info_html) = controller.access_info_html(&ctx, parts) {
@@ -135,8 +135,8 @@ fn log_blob<C: Controller>(
let mut page = Page {
title: format!("Log for {}", filename),
- body: String::new(),
header: Some(action_links(&params.action, controller, &ctx, parts)),
+ ..Default::default()
};
let mut walk = ctx.repo.revwalk()?;
@@ -256,6 +256,7 @@ fn diff_blob<C: Controller>(
title: format!("Commit for {}", ctx.file_name().unwrap()),
body: "file removed".into(),
header: Some(action_links(&action_param.action, controller, &ctx, parts)),
+ ..Default::default()
}
.into());
};
@@ -279,7 +280,7 @@ fn diff_blob<C: Controller>(
ctx.file_name().unwrap()
),
header: Some(action_links(&action_param.action, controller, &ctx, parts)),
- body: String::new(),
+ ..Default::default()
};
page.body.push_str("<div>");
if params.oldid.is_none() {
@@ -400,6 +401,7 @@ fn remove_blob<C: Controller>(
<label>Message <input name=msg autofocus></label>\
<button>Remove</button></form>"
.into(),
+ ..Default::default()
};
Ok(page.into())
@@ -413,8 +415,7 @@ pub fn view_tree<C: Controller>(
) -> Result<Response, Error> {
let mut page = Page {
title: ctx.path.to_string_lossy().to_string(),
- body: String::new(),
- header: None,
+ ..Default::default()
};
page.body.push_str("<ul>");
diff --git a/src/main.rs b/src/main.rs
index 5c9f10c..4d0c1b3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -214,14 +214,21 @@ async fn service<C: Controller>(
) -> Result<HyperResponse, Infallible> {
let (mut parts, body) = request.into_parts();
+ let mut script_csp = "'none'".into();
+
let mut resp = build_response(args, &*controller, &mut parts, body)
.await
.map(|resp| match resp {
Response::Raw(resp) => resp,
- Response::Page(page) => Builder::new()
- .content_type(mime::TEXT_HTML)
- .body(render_page(&page, &*controller, &parts).into())
- .unwrap(),
+ Response::Page(page) => {
+ if !page.script_src.is_empty() {
+ script_csp = page.script_src.join(" ");
+ }
+ Builder::new()
+ .content_type(mime::TEXT_HTML)
+ .body(render_page(&page, &*controller, &parts).into())
+ .unwrap()
+ }
})
.unwrap_or_else(|err| {
let (status, message) = match err {
@@ -257,9 +264,9 @@ async fn service<C: Controller>(
resp.headers_mut().insert(
header::CONTENT_SECURITY_POLICY,
format!(
- "default-src 'self'; frame-src 'none'; script-src 'sha256-{}'; style-src 'sha256-{}'",
- include_str!("static/edit_script.js.sha256"),
- include_str!("static/style.css.sha256"),
+ "default-src 'self'; frame-src 'none'; script-src {}; style-src {}",
+ script_csp,
+ include_str!("static/style.css.sha"),
)
.parse()
.unwrap(),
@@ -267,10 +274,15 @@ async fn service<C: Controller>(
Ok(resp)
}
+#[derive(Default)]
pub struct Page {
title: String,
header: Option<String>,
body: String,
+ /// will be embedded as inline <script> tags
+ scripts: Vec<&'static str>,
+ /// for the Content Security Policy
+ script_src: Vec<&'static str>,
}
fn render_page<C: Controller>(page: &Page, controller: &C, parts: &Parts) -> String {
@@ -289,6 +301,9 @@ fn render_page<C: Controller>(page: &Page, controller: &C, parts: &Parts) -> Str
);
out.push_str("</header>");
out.push_str(&page.body);
+ for script in &page.scripts {
+ out.push_str(&format!("<script>{}</script>", script));
+ }
out.push_str("</body></html>");
out
}
diff --git a/src/static/edit_script.js.sha b/src/static/edit_script.js.sha
new file mode 100644
index 0000000..055c251
--- /dev/null
+++ b/src/static/edit_script.js.sha
@@ -0,0 +1 @@
+'sha256-O/Q67ZO/c2t0OEnZQIJtx/2VGvvdDEBTB8ol44aaUIo=' \ No newline at end of file
diff --git a/src/static/edit_script.js.sha256 b/src/static/edit_script.js.sha256
deleted file mode 100644
index c03887e..0000000
--- a/src/static/edit_script.js.sha256
+++ /dev/null
@@ -1 +0,0 @@
-O/Q67ZO/c2t0OEnZQIJtx/2VGvvdDEBTB8ol44aaUIo= \ No newline at end of file
diff --git a/src/static/style.css.sha b/src/static/style.css.sha
new file mode 100644
index 0000000..774a743
--- /dev/null
+++ b/src/static/style.css.sha
@@ -0,0 +1 @@
+'sha256-9xIJ8fFnUyBYBKBAR6JWlmi39sUqyIqzUt1PnrkDE/c=' \ No newline at end of file
diff --git a/src/static/style.css.sha256 b/src/static/style.css.sha256
deleted file mode 100644
index cb45c3f..0000000
--- a/src/static/style.css.sha256
+++ /dev/null
@@ -1 +0,0 @@
-9xIJ8fFnUyBYBKBAR6JWlmi39sUqyIqzUt1PnrkDE/c= \ No newline at end of file
diff --git a/src/static/update_hashes.sh b/src/static/update_hashes.sh
index 31f63bd..ac6c6a1 100755
--- a/src/static/update_hashes.sh
+++ b/src/static/update_hashes.sh
@@ -1,5 +1,5 @@
#/bin/sh
cd "$(dirname "$0")"
for script in *.css *.js; do
- shasum -a 256 < $script | cut -d' ' -f1 | xxd -r -p | base64 -w 0 > $script.sha256
+ printf "'sha256-%s'" $(shasum -a 256 < $script | cut -d' ' -f1 | xxd -r -p | base64 -w 0) > $script.sha
done