feat: check permission on move/copy destination (#93)
This commit is contained in:
parent
c6541b1c36
commit
604cbb7412
2 changed files with 67 additions and 20 deletions
|
@ -239,7 +239,7 @@ impl Server {
|
||||||
} else if is_miss {
|
} else if is_miss {
|
||||||
status_not_found(&mut res);
|
status_not_found(&mut res);
|
||||||
} else {
|
} else {
|
||||||
self.handle_copy(path, headers, &mut res).await?
|
self.handle_copy(path, &req, &mut res).await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"MOVE" => {
|
"MOVE" => {
|
||||||
|
@ -248,7 +248,7 @@ impl Server {
|
||||||
} else if is_miss {
|
} else if is_miss {
|
||||||
status_not_found(&mut res);
|
status_not_found(&mut res);
|
||||||
} else {
|
} else {
|
||||||
self.handle_move(path, headers, &mut res).await?
|
self.handle_move(path, &req, &mut res).await?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"LOCK" => {
|
"LOCK" => {
|
||||||
|
@ -643,16 +643,10 @@ impl Server {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_copy(
|
async fn handle_copy(&self, path: &Path, req: &Request, res: &mut Response) -> BoxResult<()> {
|
||||||
&self,
|
let dest = match self.extract_dest(req, res) {
|
||||||
path: &Path,
|
|
||||||
headers: &HeaderMap<HeaderValue>,
|
|
||||||
res: &mut Response,
|
|
||||||
) -> BoxResult<()> {
|
|
||||||
let dest = match self.extract_dest(headers) {
|
|
||||||
Some(dest) => dest,
|
Some(dest) => dest,
|
||||||
None => {
|
None => {
|
||||||
*res.status_mut() = StatusCode::BAD_REQUEST;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -671,16 +665,10 @@ impl Server {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_move(
|
async fn handle_move(&self, path: &Path, req: &Request, res: &mut Response) -> BoxResult<()> {
|
||||||
&self,
|
let dest = match self.extract_dest(req, res) {
|
||||||
path: &Path,
|
|
||||||
headers: &HeaderMap<HeaderValue>,
|
|
||||||
res: &mut Response,
|
|
||||||
) -> BoxResult<()> {
|
|
||||||
let dest = match self.extract_dest(headers) {
|
|
||||||
Some(dest) => dest,
|
Some(dest) => dest,
|
||||||
None => {
|
None => {
|
||||||
*res.status_mut() = StatusCode::BAD_REQUEST;
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -799,10 +787,43 @@ DATA = {}
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_dest(&self, headers: &HeaderMap<HeaderValue>) -> Option<PathBuf> {
|
fn extract_dest(&self, req: &Request, res: &mut Response) -> Option<PathBuf> {
|
||||||
|
let headers = req.headers();
|
||||||
|
let dest_path = match self.extract_destination_header(headers) {
|
||||||
|
Some(dest) => dest,
|
||||||
|
None => {
|
||||||
|
*res.status_mut() = StatusCode::BAD_REQUEST;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let authorization = headers.get(AUTHORIZATION);
|
||||||
|
let guard_type = self.args.auth.guard(
|
||||||
|
&dest_path,
|
||||||
|
req.method(),
|
||||||
|
authorization,
|
||||||
|
self.args.auth_method.clone(),
|
||||||
|
);
|
||||||
|
if guard_type.is_reject() {
|
||||||
|
*res.status_mut() = StatusCode::FORBIDDEN;
|
||||||
|
*res.body_mut() = Body::from("Forbidden");
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let dest = match self.extract_path(&dest_path) {
|
||||||
|
Some(dest) => dest,
|
||||||
|
None => {
|
||||||
|
*res.status_mut() = StatusCode::BAD_REQUEST;
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(dest)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extract_destination_header(&self, headers: &HeaderMap<HeaderValue>) -> Option<String> {
|
||||||
let dest = headers.get("Destination")?.to_str().ok()?;
|
let dest = headers.get("Destination")?.to_str().ok()?;
|
||||||
let uri: Uri = dest.parse().ok()?;
|
let uri: Uri = dest.parse().ok()?;
|
||||||
self.extract_path(uri.path())
|
Some(uri.path().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extract_path(&self, path: &str) -> Option<PathBuf> {
|
fn extract_path(&self, path: &str) -> Option<PathBuf> {
|
||||||
|
|
|
@ -95,3 +95,29 @@ fn auth_basic(
|
||||||
assert_eq!(resp.status(), 201);
|
assert_eq!(resp.status(), 201);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn auth_webdav_move(
|
||||||
|
#[with(&["--auth", "/@user:pass@*", "--auth", "/dira@user3:pass3", "-A"])] server: TestServer,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let origin_url = format!("{}dira/test.html", server.url());
|
||||||
|
let new_url = format!("{}test2.html", server.url());
|
||||||
|
let resp = fetch!(b"MOVE", &origin_url)
|
||||||
|
.header("Destination", &new_url)
|
||||||
|
.send_with_digest_auth("user3", "pass3")?;
|
||||||
|
assert_eq!(resp.status(), 403);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn auth_webdav_copy(
|
||||||
|
#[with(&["--auth", "/@user:pass@*", "--auth", "/dira@user3:pass3", "-A"])] server: TestServer,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
let origin_url = format!("{}dira/test.html", server.url());
|
||||||
|
let new_url = format!("{}test2.html", server.url());
|
||||||
|
let resp = fetch!(b"COPY", &origin_url)
|
||||||
|
.header("Destination", &new_url)
|
||||||
|
.send_with_digest_auth("user3", "pass3")?;
|
||||||
|
assert_eq!(resp.status(), 403);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue