From 55b3e9f52036f35f4b8ac741c2a59f9ca7b3cbad Mon Sep 17 00:00:00 2001 From: _ <_@_> Date: Fri, 30 Oct 2020 21:31:03 -0500 Subject: [PATCH] :construction: Working on handlebars for prettier directories --- Cargo.toml | 1 + ptth_handlebars/file_server_dir.html | 9 +++++++ ptth_handlebars/file_server_dir_entry.html | 5 ++++ src/bin/file_server.rs | 19 ++++++++----- src/server/file_server.rs | 31 +++++++++++++++++++--- src/server/mod.rs | 29 ++++++++++++-------- todo.md | 1 + 7 files changed, 74 insertions(+), 21 deletions(-) create mode 100644 ptth_handlebars/file_server_dir.html create mode 100644 ptth_handlebars/file_server_dir_entry.html diff --git a/Cargo.toml b/Cargo.toml index a008887..51005b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ edition = "2018" base64 = "0.12.3" blake3 = "0.3.7" futures = "0.3.7" +handlebars = "3.5.1" http = "0.2.1" hyper = "0.13.8" lazy_static = "1.4.0" diff --git a/ptth_handlebars/file_server_dir.html b/ptth_handlebars/file_server_dir.html new file mode 100644 index 0000000..7563912 --- /dev/null +++ b/ptth_handlebars/file_server_dir.html @@ -0,0 +1,9 @@ + diff --git a/ptth_handlebars/file_server_dir_entry.html b/ptth_handlebars/file_server_dir_entry.html new file mode 100644 index 0000000..200b99e --- /dev/null +++ b/ptth_handlebars/file_server_dir_entry.html @@ -0,0 +1,5 @@ +
  • + +{{file_name}}{{trailing_slash}} + +
  • diff --git a/src/bin/file_server.rs b/src/bin/file_server.rs index fda269d..356fa7c 100644 --- a/src/bin/file_server.rs +++ b/src/bin/file_server.rs @@ -18,9 +18,8 @@ use hyper::{ StatusCode, }; -#[derive (Default)] -struct ServerState { - // Pass +struct ServerState <'a> { + handlebars: Arc >, } fn status_reply > (status: StatusCode, b: B) @@ -39,7 +38,7 @@ fn prefix_match <'a> (hay: &'a str, needle: &str) -> Option <&'a str> } } -async fn handle_all (req: Request , _state: Arc ) +async fn handle_all (req: Request , state: Arc >) -> Result , Infallible> { use ptth::{ @@ -62,7 +61,7 @@ async fn handle_all (req: Request , _state: Arc ) _ => return Ok (status_reply (StatusCode::BAD_REQUEST, "Bad request")), }; - let ptth_resp = file_server::serve_all (&root, ptth_req).await; + let ptth_resp = file_server::serve_all (state.handlebars.clone (), &root, ptth_req).await; let mut resp = Response::builder () .status (StatusCode::from (ptth_resp.parts.status_code)); @@ -91,7 +90,15 @@ async fn handle_all (req: Request , _state: Arc ) async fn main () -> Result <(), Box > { let addr = SocketAddr::from(([0, 0, 0, 0], 4000)); - let state = Arc::new (ServerState::default ()); + let mut handlebars = handlebars::Handlebars::new (); + + handlebars.register_template_file ("file_server_dir_entry", "ptth_handlebars/file_server_dir_entry.html")?; + + let handlebars = Arc::new (handlebars); + + let state = Arc::new (ServerState { + handlebars, + }); let make_svc = make_service_fn (|_conn| { let state = state.clone (); diff --git a/src/server/file_server.rs b/src/server/file_server.rs index dd63ef5..4f4fd9f 100644 --- a/src/server/file_server.rs +++ b/src/server/file_server.rs @@ -5,8 +5,10 @@ use std::{ convert::{Infallible, TryInto}, io::SeekFrom, path::{Path, PathBuf}, + sync::Arc, }; +use handlebars::Handlebars; use tokio::{ fs::{ File, @@ -45,15 +47,21 @@ fn parse_range_header (range_str: &str) -> (Option , Option ) { (start, end) } -async fn serve_dir (mut dir: ReadDir) -> http_serde::Response { +async fn serve_dir ( + handlebars: Arc >, + mut dir: ReadDir +) -> http_serde::Response { let (tx, rx) = channel (2); + let handlebars = handlebars.clone (); tokio::spawn (async move { let mut tx = tx; tx.send (Ok::<_, Infallible> (String::from ("
      ").into_bytes ())).await.unwrap (); + let handlebars = handlebars.clone (); while let Ok (entry) = dir.next_entry ().await { + let handlebars = handlebars.clone (); let entry: tokio::fs::DirEntry = match entry { Some (x) => x, None => break, @@ -84,9 +92,23 @@ async fn serve_dir (mut dir: ReadDir) -> http_serde::Response { use std::borrow::Cow; use percent_encoding::*; - let percent_file_name: Cow = utf8_percent_encode (&file_name, CONTROLS).into (); + let encoded_file_name: Cow = utf8_percent_encode (&file_name, CONTROLS).into (); + + #[derive (serde::Serialize)] + struct TemplateDirEntry <'a> { + trailing_slash: &'a str, + file_name: &'a str, + encoded_file_name: Cow <'a, str>, + } + + let s = handlebars.render ( + "file_server_dir_entry", + &TemplateDirEntry { + trailing_slash: &trailing_slash, + file_name: &file_name, + encoded_file_name, + }).unwrap (); - let s = format! ("
    • {}{}
    • \n", percent_file_name, trailing_slash, file_name, trailing_slash); if tx.send (Ok::<_, Infallible> (s.into_bytes ())).await.is_err () { break; @@ -201,6 +223,7 @@ async fn serve_error ( } pub async fn serve_all ( + handlebars: Arc >, root: &Path, parts: http_serde::RequestParts ) @@ -238,7 +261,7 @@ pub async fn serve_all ( full_path.push (&*path); if let Ok (dir) = read_dir (&full_path).await { - serve_dir (dir).await + serve_dir (handlebars, dir).await } else if let Ok (file) = File::open (&full_path).await { serve_file ( diff --git a/src/server/mod.rs b/src/server/mod.rs index 7d9b42d..e60c8c7 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -5,6 +5,7 @@ use std::{ time::Duration, }; +use handlebars::Handlebars; use hyper::{ StatusCode, }; @@ -19,28 +20,29 @@ pub mod file_server; const SERVER_NAME: &str = "alien_wildlands"; -async fn handle_req_resp ( - opt: &Opt, - client: &Client, +async fn handle_req_resp <'a> ( + opt: &'a Opt, + handlebars: Arc >, + client: &'a Client, req_resp: reqwest::Response -) -> Result <(), Box > { +) { //println! ("Step 1"); if req_resp.status () != StatusCode::OK { // TODO: Error handling - return Ok (()); + return; } - let body = req_resp.bytes ().await?; + let body = req_resp.bytes ().await.unwrap (); let wrapped_req: http_serde::WrappedRequest = match rmp_serde::from_read_ref (&body) { Ok (x) => x, - _ => return Ok (()), + _ => return, }; let (req_id, parts) = (wrapped_req.id, wrapped_req.req); - let response = file_server::serve_all (&opt.file_server_root, parts).await; + let response = file_server::serve_all (handlebars, &opt.file_server_root, parts).await; let mut resp_req = client .post (&format! ("{}/http_response/{}", opt.relay_url, req_id)) @@ -54,8 +56,6 @@ async fn handle_req_resp ( if let Err (e) = resp_req.send ().await { println! ("Err: {:?}", e); } - - Ok (()) } pub struct Opt { @@ -67,6 +67,12 @@ pub async fn main (opt: Opt) -> Result <(), Box > { let client = Arc::new (Client::new ()); let opt = Arc::new (opt); + let mut handlebars = handlebars::Handlebars::new (); + + handlebars.register_template_file ("file_server_dir_entry", "ptth_handlebars/file_server_dir_entry.html")?; + + let handlebars = Arc::new (handlebars); + let mut backoff_delay = 0; loop { @@ -94,8 +100,9 @@ pub async fn main (opt: Opt) -> Result <(), Box > { let client = client.clone (); let opt = opt.clone (); + let handlebars = handlebars.clone (); tokio::spawn (async move { - match handle_req_resp (&opt, &client, req_resp).await { + match handle_req_resp (&opt, handlebars, &client, req_resp).await { _ => (), } }); diff --git a/todo.md b/todo.md index ce39f7c..6e11ad8 100644 --- a/todo.md +++ b/todo.md @@ -1,4 +1,5 @@ - Add ".." for parent directory +- Prevent directory traversal attacks - Set up tokens or something so clients can't trivially impersonate servers - Offer list of clients at server root