fix: guard req and destination path (#359)
This commit is contained in:
parent
871e8276ff
commit
3c75a9c4cc
2 changed files with 41 additions and 23 deletions
|
@ -71,7 +71,7 @@ pub struct Server {
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub fn init(args: Args, running: Arc<AtomicBool>) -> Result<Self> {
|
pub fn init(args: Args, running: Arc<AtomicBool>) -> Result<Self> {
|
||||||
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 {
|
let single_file_req_paths = if args.path_is_file {
|
||||||
vec![
|
vec![
|
||||||
args.uri_prefix.to_string(),
|
args.uri_prefix.to_string(),
|
||||||
|
@ -144,6 +144,10 @@ impl Server {
|
||||||
let headers = req.headers();
|
let headers = req.headers();
|
||||||
let method = req.method().clone();
|
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? {
|
if method == Method::GET && self.handle_assets(req_path, headers, &mut res).await? {
|
||||||
return Ok(res);
|
return Ok(res);
|
||||||
}
|
}
|
||||||
|
@ -713,7 +717,12 @@ impl Server {
|
||||||
match self.args.assets.as_ref() {
|
match self.args.assets.as_ref() {
|
||||||
Some(assets_path) => {
|
Some(assets_path) => {
|
||||||
let path = assets_path.join(name);
|
let path = assets_path.join(name);
|
||||||
|
if path.exists() {
|
||||||
self.handle_send_file(&path, headers, false, res).await?;
|
self.handle_send_file(&path, headers, false, res).await?;
|
||||||
|
} else {
|
||||||
|
status_not_found(res);
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => match name {
|
None => match name {
|
||||||
"index.js" => {
|
"index.js" => {
|
||||||
|
@ -1153,7 +1162,10 @@ impl Server {
|
||||||
|
|
||||||
fn extract_dest(&self, req: &Request, res: &mut Response) -> Option<PathBuf> {
|
fn extract_dest(&self, req: &Request, res: &mut Response) -> Option<PathBuf> {
|
||||||
let headers = req.headers();
|
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,
|
Some(dest) => dest,
|
||||||
None => {
|
None => {
|
||||||
*res.status_mut() = StatusCode::BAD_REQUEST;
|
*res.status_mut() = StatusCode::BAD_REQUEST;
|
||||||
|
@ -1161,19 +1173,15 @@ impl Server {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let relative_path = match self.resolve_path(&dest_path) {
|
if guard_path(&dest_path, res) {
|
||||||
Some(v) => v,
|
|
||||||
None => {
|
|
||||||
*res.status_mut() = StatusCode::BAD_REQUEST;
|
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
let authorization = headers.get(AUTHORIZATION);
|
let authorization = headers.get(AUTHORIZATION);
|
||||||
let guard = self
|
let guard = self
|
||||||
.args
|
.args
|
||||||
.auth
|
.auth
|
||||||
.guard(&relative_path, req.method(), authorization);
|
.guard(&dest_path, req.method(), authorization);
|
||||||
|
|
||||||
match guard {
|
match guard {
|
||||||
(_, Some(_)) => {}
|
(_, 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,
|
Some(dest) => dest,
|
||||||
None => {
|
None => {
|
||||||
*res.status_mut() = StatusCode::BAD_REQUEST;
|
*res.status_mut() = StatusCode::BAD_REQUEST;
|
||||||
|
@ -1690,3 +1698,12 @@ fn parse_upload_offset(headers: &HeaderMap<HeaderValue>, size: u64) -> Result<Op
|
||||||
let (start, _) = parse_range(value, size).ok_or_else(err)?;
|
let (start, _) = parse_range(value, size).ok_or_else(err)?;
|
||||||
Ok(Some(start))
|
Ok(Some(start))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn guard_path(path: &str, res: &mut Response) -> bool {
|
||||||
|
let path = Path::new(path);
|
||||||
|
if path.components().any(|v| v.as_os_str() == "..") {
|
||||||
|
status_bad_request(res, "");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
|
@ -11,10 +11,11 @@ use std::process::{Command, Stdio};
|
||||||
fn assets(server: TestServer) -> Result<(), Error> {
|
fn assets(server: TestServer) -> Result<(), Error> {
|
||||||
let ver = env!("CARGO_PKG_VERSION");
|
let ver = env!("CARGO_PKG_VERSION");
|
||||||
let resp = reqwest::blocking::get(server.url())?;
|
let resp = reqwest::blocking::get(server.url())?;
|
||||||
let index_js = format!("/__dufs_v{ver}_index.js");
|
let index_js = format!("/__dufs_v{ver}_/index.js");
|
||||||
let index_css = format!("/__dufs_v{ver}_index.css");
|
let index_css = format!("/__dufs_v{ver}_/index.css");
|
||||||
let favicon_ico = format!("/__dufs_v{ver}_favicon.ico");
|
let favicon_ico = format!("/__dufs_v{ver}_/favicon.ico");
|
||||||
let text = resp.text()?;
|
let text = resp.text()?;
|
||||||
|
println!("{text}");
|
||||||
assert!(text.contains(&format!(r#"href="{index_css}""#)));
|
assert!(text.contains(&format!(r#"href="{index_css}""#)));
|
||||||
assert!(text.contains(&format!(r#"href="{favicon_ico}""#)));
|
assert!(text.contains(&format!(r#"href="{favicon_ico}""#)));
|
||||||
assert!(text.contains(&format!(r#"src="{index_js}""#)));
|
assert!(text.contains(&format!(r#"src="{index_js}""#)));
|
||||||
|
@ -24,7 +25,7 @@ fn assets(server: TestServer) -> Result<(), Error> {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn asset_js(server: TestServer) -> Result<(), Error> {
|
fn asset_js(server: TestServer) -> Result<(), Error> {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"{}__dufs_v{}_index.js",
|
"{}__dufs_v{}_/index.js",
|
||||||
server.url(),
|
server.url(),
|
||||||
env!("CARGO_PKG_VERSION")
|
env!("CARGO_PKG_VERSION")
|
||||||
);
|
);
|
||||||
|
@ -40,7 +41,7 @@ fn asset_js(server: TestServer) -> Result<(), Error> {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn asset_css(server: TestServer) -> Result<(), Error> {
|
fn asset_css(server: TestServer) -> Result<(), Error> {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"{}__dufs_v{}_index.css",
|
"{}__dufs_v{}_/index.css",
|
||||||
server.url(),
|
server.url(),
|
||||||
env!("CARGO_PKG_VERSION")
|
env!("CARGO_PKG_VERSION")
|
||||||
);
|
);
|
||||||
|
@ -56,7 +57,7 @@ fn asset_css(server: TestServer) -> Result<(), Error> {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn asset_ico(server: TestServer) -> Result<(), Error> {
|
fn asset_ico(server: TestServer) -> Result<(), Error> {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"{}__dufs_v{}_favicon.ico",
|
"{}__dufs_v{}_/favicon.ico",
|
||||||
server.url(),
|
server.url(),
|
||||||
env!("CARGO_PKG_VERSION")
|
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> {
|
fn assets_with_prefix(#[with(&["--path-prefix", "xyz"])] server: TestServer) -> Result<(), Error> {
|
||||||
let ver = env!("CARGO_PKG_VERSION");
|
let ver = env!("CARGO_PKG_VERSION");
|
||||||
let resp = reqwest::blocking::get(format!("{}xyz/", server.url()))?;
|
let resp = reqwest::blocking::get(format!("{}xyz/", server.url()))?;
|
||||||
let index_js = format!("/xyz/__dufs_v{ver}_index.js");
|
let index_js = format!("/xyz/__dufs_v{ver}_/index.js");
|
||||||
let index_css = format!("/xyz/__dufs_v{ver}_index.css");
|
let index_css = format!("/xyz/__dufs_v{ver}_/index.css");
|
||||||
let favicon_ico = format!("/xyz/__dufs_v{ver}_favicon.ico");
|
let favicon_ico = format!("/xyz/__dufs_v{ver}_/favicon.ico");
|
||||||
let text = resp.text()?;
|
let text = resp.text()?;
|
||||||
assert!(text.contains(&format!(r#"href="{index_css}""#)));
|
assert!(text.contains(&format!(r#"href="{index_css}""#)));
|
||||||
assert!(text.contains(&format!(r#"href="{favicon_ico}""#)));
|
assert!(text.contains(&format!(r#"href="{favicon_ico}""#)));
|
||||||
|
@ -85,7 +86,7 @@ fn asset_js_with_prefix(
|
||||||
#[with(&["--path-prefix", "xyz"])] server: TestServer,
|
#[with(&["--path-prefix", "xyz"])] server: TestServer,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let url = format!(
|
let url = format!(
|
||||||
"{}xyz/__dufs_v{}_index.js",
|
"{}xyz/__dufs_v{}_/index.js",
|
||||||
server.url(),
|
server.url(),
|
||||||
env!("CARGO_PKG_VERSION")
|
env!("CARGO_PKG_VERSION")
|
||||||
);
|
);
|
||||||
|
@ -114,7 +115,7 @@ fn assets_override(tmpdir: TempDir, port: u16) -> Result<(), Error> {
|
||||||
let url = format!("http://localhost:{port}");
|
let url = format!("http://localhost:{port}");
|
||||||
let resp = reqwest::blocking::get(&url)?;
|
let resp = reqwest::blocking::get(&url)?;
|
||||||
assert!(resp.text()?.starts_with(&format!(
|
assert!(resp.text()?.starts_with(&format!(
|
||||||
"/__dufs_v{}_index.js;DATA",
|
"/__dufs_v{}_/index.js;DATA",
|
||||||
env!("CARGO_PKG_VERSION")
|
env!("CARGO_PKG_VERSION")
|
||||||
)));
|
)));
|
||||||
let resp = reqwest::blocking::get(&url)?;
|
let resp = reqwest::blocking::get(&url)?;
|
||||||
|
|
Loading…
Reference in a new issue