feat: check permission on move/copy destination (#93)

This commit is contained in:
sigoden 2022-07-04 23:25:05 +08:00 committed by GitHub
parent c6541b1c36
commit 604cbb7412
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 67 additions and 20 deletions

View file

@ -239,7 +239,7 @@ impl Server {
} else if is_miss {
status_not_found(&mut res);
} else {
self.handle_copy(path, headers, &mut res).await?
self.handle_copy(path, &req, &mut res).await?
}
}
"MOVE" => {
@ -248,7 +248,7 @@ impl Server {
} else if is_miss {
status_not_found(&mut res);
} else {
self.handle_move(path, headers, &mut res).await?
self.handle_move(path, &req, &mut res).await?
}
}
"LOCK" => {
@ -643,16 +643,10 @@ impl Server {
Ok(())
}
async fn handle_copy(
&self,
path: &Path,
headers: &HeaderMap<HeaderValue>,
res: &mut Response,
) -> BoxResult<()> {
let dest = match self.extract_dest(headers) {
async fn handle_copy(&self, path: &Path, req: &Request, res: &mut Response) -> BoxResult<()> {
let dest = match self.extract_dest(req, res) {
Some(dest) => dest,
None => {
*res.status_mut() = StatusCode::BAD_REQUEST;
return Ok(());
}
};
@ -671,16 +665,10 @@ impl Server {
Ok(())
}
async fn handle_move(
&self,
path: &Path,
headers: &HeaderMap<HeaderValue>,
res: &mut Response,
) -> BoxResult<()> {
let dest = match self.extract_dest(headers) {
async fn handle_move(&self, path: &Path, req: &Request, res: &mut Response) -> BoxResult<()> {
let dest = match self.extract_dest(req, res) {
Some(dest) => dest,
None => {
*res.status_mut() = StatusCode::BAD_REQUEST;
return Ok(());
}
};
@ -799,10 +787,43 @@ DATA = {}
.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 uri: Uri = dest.parse().ok()?;
self.extract_path(uri.path())
Some(uri.path().to_string())
}
fn extract_path(&self, path: &str) -> Option<PathBuf> {

View file

@ -95,3 +95,29 @@ fn auth_basic(
assert_eq!(resp.status(), 201);
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(())
}