diff options
author | Martin Fischer <martin@push-f.com> | 2021-06-24 21:07:45 +0200 |
---|---|---|
committer | Martin Fischer <martin@push-f.com> | 2021-06-24 23:14:15 +0200 |
commit | d43543440e5d3f0e93ed1cf197601d778541c3ae (patch) | |
tree | d966b40936d7ef8cb559e2b556d3b9e01a5f824b | |
parent | b019d39957bd644d9b6b856738b57eb87e0506de (diff) |
generate <script> tags and CSP from Page vectors
-rw-r--r-- | src/controller.rs | 10 | ||||
-rw-r--r-- | src/forms.rs | 12 | ||||
-rw-r--r-- | src/get_routes.rs | 11 | ||||
-rw-r--r-- | src/main.rs | 29 | ||||
-rw-r--r-- | src/static/edit_script.js.sha | 1 | ||||
-rw-r--r-- | src/static/edit_script.js.sha256 | 1 | ||||
-rw-r--r-- | src/static/style.css.sha | 1 | ||||
-rw-r--r-- | src/static/style.css.sha256 | 1 | ||||
-rwxr-xr-x | src/static/update_hashes.sh | 2 |
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(¶ms.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(¶ms.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 |