From 3c75a9c4ccb6b24bb7dc5b54c8c471282f014259 Mon Sep 17 00:00:00 2001 From: sigoden Date: Tue, 6 Feb 2024 17:23:18 +0800 Subject: [PATCH] fix: guard req and destination path (#359) --- src/server.rs | 41 +++++++++++++++++++++++++++++------------ tests/assets.rs | 23 ++++++++++++----------- 2 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/server.rs b/src/server.rs index 965da88..4ef237b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -71,7 +71,7 @@ pub struct Server { impl Server { pub fn init(args: Args, running: Arc) -> Result { - let assets_prefix = format!("{}__dufs_v{}_", args.uri_prefix, env!("CARGO_PKG_VERSION")); + let assets_prefix = format!("{}__dufs_v{}_/", args.uri_prefix, env!("CARGO_PKG_VERSION")); let single_file_req_paths = if args.path_is_file { vec![ args.uri_prefix.to_string(), @@ -144,6 +144,10 @@ impl Server { let headers = req.headers(); let method = req.method().clone(); + if guard_path(req_path, &mut res) { + return Ok(res); + } + if method == Method::GET && self.handle_assets(req_path, headers, &mut res).await? { return Ok(res); } @@ -713,7 +717,12 @@ impl Server { match self.args.assets.as_ref() { Some(assets_path) => { let path = assets_path.join(name); - self.handle_send_file(&path, headers, false, res).await?; + if path.exists() { + self.handle_send_file(&path, headers, false, res).await?; + } else { + status_not_found(res); + return Ok(true); + } } None => match name { "index.js" => { @@ -1153,7 +1162,10 @@ impl Server { fn extract_dest(&self, req: &Request, res: &mut Response) -> Option { let headers = req.headers(); - let dest_path = match self.extract_destination_header(headers) { + let dest_path = match self + .extract_destination_header(headers) + .and_then(|dest| self.resolve_path(&dest)) + { Some(dest) => dest, None => { *res.status_mut() = StatusCode::BAD_REQUEST; @@ -1161,19 +1173,15 @@ impl Server { } }; - let relative_path = match self.resolve_path(&dest_path) { - Some(v) => v, - None => { - *res.status_mut() = StatusCode::BAD_REQUEST; - return None; - } - }; + if guard_path(&dest_path, res) { + return None; + } let authorization = headers.get(AUTHORIZATION); let guard = self .args .auth - .guard(&relative_path, req.method(), authorization); + .guard(&dest_path, req.method(), authorization); match guard { (_, Some(_)) => {} @@ -1183,7 +1191,7 @@ impl Server { } }; - let dest = match self.join_path(&relative_path) { + let dest = match self.join_path(&dest_path) { Some(dest) => dest, None => { *res.status_mut() = StatusCode::BAD_REQUEST; @@ -1690,3 +1698,12 @@ fn parse_upload_offset(headers: &HeaderMap, size: u64) -> Result bool { + let path = Path::new(path); + if path.components().any(|v| v.as_os_str() == "..") { + status_bad_request(res, ""); + return true; + } + false +} diff --git a/tests/assets.rs b/tests/assets.rs index ea1821b..8482b2a 100644 --- a/tests/assets.rs +++ b/tests/assets.rs @@ -11,10 +11,11 @@ use std::process::{Command, Stdio}; fn assets(server: TestServer) -> Result<(), Error> { let ver = env!("CARGO_PKG_VERSION"); let resp = reqwest::blocking::get(server.url())?; - let index_js = format!("/__dufs_v{ver}_index.js"); - let index_css = format!("/__dufs_v{ver}_index.css"); - let favicon_ico = format!("/__dufs_v{ver}_favicon.ico"); + let index_js = format!("/__dufs_v{ver}_/index.js"); + let index_css = format!("/__dufs_v{ver}_/index.css"); + let favicon_ico = format!("/__dufs_v{ver}_/favicon.ico"); let text = resp.text()?; + println!("{text}"); assert!(text.contains(&format!(r#"href="{index_css}""#))); assert!(text.contains(&format!(r#"href="{favicon_ico}""#))); assert!(text.contains(&format!(r#"src="{index_js}""#))); @@ -24,7 +25,7 @@ fn assets(server: TestServer) -> Result<(), Error> { #[rstest] fn asset_js(server: TestServer) -> Result<(), Error> { let url = format!( - "{}__dufs_v{}_index.js", + "{}__dufs_v{}_/index.js", server.url(), env!("CARGO_PKG_VERSION") ); @@ -40,7 +41,7 @@ fn asset_js(server: TestServer) -> Result<(), Error> { #[rstest] fn asset_css(server: TestServer) -> Result<(), Error> { let url = format!( - "{}__dufs_v{}_index.css", + "{}__dufs_v{}_/index.css", server.url(), env!("CARGO_PKG_VERSION") ); @@ -56,7 +57,7 @@ fn asset_css(server: TestServer) -> Result<(), Error> { #[rstest] fn asset_ico(server: TestServer) -> Result<(), Error> { let url = format!( - "{}__dufs_v{}_favicon.ico", + "{}__dufs_v{}_/favicon.ico", server.url(), env!("CARGO_PKG_VERSION") ); @@ -70,9 +71,9 @@ fn asset_ico(server: TestServer) -> Result<(), Error> { fn assets_with_prefix(#[with(&["--path-prefix", "xyz"])] server: TestServer) -> Result<(), Error> { let ver = env!("CARGO_PKG_VERSION"); let resp = reqwest::blocking::get(format!("{}xyz/", server.url()))?; - let index_js = format!("/xyz/__dufs_v{ver}_index.js"); - let index_css = format!("/xyz/__dufs_v{ver}_index.css"); - let favicon_ico = format!("/xyz/__dufs_v{ver}_favicon.ico"); + let index_js = format!("/xyz/__dufs_v{ver}_/index.js"); + let index_css = format!("/xyz/__dufs_v{ver}_/index.css"); + let favicon_ico = format!("/xyz/__dufs_v{ver}_/favicon.ico"); let text = resp.text()?; assert!(text.contains(&format!(r#"href="{index_css}""#))); assert!(text.contains(&format!(r#"href="{favicon_ico}""#))); @@ -85,7 +86,7 @@ fn asset_js_with_prefix( #[with(&["--path-prefix", "xyz"])] server: TestServer, ) -> Result<(), Error> { let url = format!( - "{}xyz/__dufs_v{}_index.js", + "{}xyz/__dufs_v{}_/index.js", server.url(), env!("CARGO_PKG_VERSION") ); @@ -114,7 +115,7 @@ fn assets_override(tmpdir: TempDir, port: u16) -> Result<(), Error> { let url = format!("http://localhost:{port}"); let resp = reqwest::blocking::get(&url)?; assert!(resp.text()?.starts_with(&format!( - "/__dufs_v{}_index.js;DATA", + "/__dufs_v{}_/index.js;DATA", env!("CARGO_PKG_VERSION") ))); let resp = reqwest::blocking::get(&url)?;