diff --git a/file-service/src/handlers.rs b/file-service/src/handlers.rs index 96478df..82aaa11 100644 --- a/file-service/src/handlers.rs +++ b/file-service/src/handlers.rs @@ -88,21 +88,24 @@ pub async fn handle_auth( form: HashMap, ) -> Result, Error> { match form.get("token") { - Some(token) => match app.authenticate(AuthToken::from(token.clone())).await { - Ok(Some(session_token)) => Response::builder() - .header("location", "/") - .header( - "set-cookie", - format!( - "session={}; Secure; HttpOnly; SameSite=Strict", - *session_token - ), - ) - .status(StatusCode::SEE_OTHER) - .body("".to_owned()), - Ok(None) => render_auth_page(Some("no user found".to_owned())), - Err(_) => render_auth_page(Some("invalid auth token".to_owned())), - }, + Some(token) => { + println!("token: {:?}", token); + match app.authenticate(AuthToken::from(token.clone())).await { + Ok(Some(session_token)) => Response::builder() + .header("location", "/") + .header( + "set-cookie", + format!( + "session={}; Secure; HttpOnly; SameSite=Strict", + *session_token + ), + ) + .status(StatusCode::SEE_OTHER) + .body("".to_owned()), + Ok(None) => render_auth_page(Some("no user found".to_owned())), + Err(_) => render_auth_page(Some("invalid auth token".to_owned())), + } + } None => render_auth_page(Some("no token available".to_owned())), } } @@ -134,6 +137,25 @@ pub async fn handle_upload( } } +pub async fn handle_delete( + app: App, + token: SessionToken, + id: FileId, +) -> Result, Error> { + match app.validate_session(token).await { + Ok(Some(_)) => match app.delete_file(id).await { + Ok(_) => Response::builder() + .header("location", "/") + .status(StatusCode::SEE_OTHER) + .body("".to_owned()), + Err(_) => unimplemented!(), + }, + _ => Response::builder() + .status(StatusCode::UNAUTHORIZED) + .body("".to_owned()), + } +} + fn serve_file( info: FileInfo, file: F, diff --git a/file-service/src/lib.rs b/file-service/src/lib.rs index a19f54c..0325109 100644 --- a/file-service/src/lib.rs +++ b/file-service/src/lib.rs @@ -1,6 +1,6 @@ mod store; pub use store::{ - AuthDB, AuthError, AuthToken, FileHandle, FileId, FileInfo, ReadFileError, SessionToken, Store, - Username, WriteFileError, + AuthDB, AuthError, AuthToken, DeleteFileError, FileHandle, FileId, FileInfo, ReadFileError, + SessionToken, Store, Username, WriteFileError, }; diff --git a/file-service/src/main.rs b/file-service/src/main.rs index 88b69cc..c9d70df 100644 --- a/file-service/src/main.rs +++ b/file-service/src/main.rs @@ -1,7 +1,7 @@ extern crate log; use cookie::Cookie; -use handlers::{file, handle_auth, handle_css, handle_upload, thumbnail}; +use handlers::{file, handle_auth, handle_css, handle_delete, handle_upload, thumbnail}; use std::{ collections::{HashMap, HashSet}, convert::Infallible, @@ -19,8 +19,8 @@ mod pages; const MAX_UPLOAD: u64 = 15 * 1024 * 1024; pub use file_service::{ - AuthDB, AuthError, AuthToken, FileHandle, FileId, FileInfo, ReadFileError, SessionToken, Store, - Username, WriteFileError, + AuthDB, AuthError, AuthToken, DeleteFileError, FileHandle, FileId, FileInfo, ReadFileError, + SessionToken, Store, Username, WriteFileError, }; pub use handlers::handle_index; @@ -64,6 +64,11 @@ impl App { ) -> Result { self.store.write().await.add_file(filename, content) } + + pub async fn delete_file(&self, id: FileId) -> Result<(), DeleteFileError> { + self.store.write().await.delete_file(&id)?; + Ok(()) + } } fn with_app(app: App) -> impl Filter + Clone { @@ -134,6 +139,12 @@ pub async fn main() { .and(warp::multipart::form().max_length(MAX_UPLOAD)) .then(handle_upload); + let delete_via_form = warp::path!("delete" / String) + .and(warp::post()) + .and(with_app(app.clone())) + .and(with_session()) + .then(|id, app, token| handle_delete(app, token, FileId::from(id))); + let thumbnail = warp::path!(String / "tn") .and(warp::get()) .and(warp::header::optional::("if-none-match")) @@ -150,6 +161,7 @@ pub async fn main() { root.or(styles) .or(auth) .or(upload_via_form) + .or(delete_via_form) .or(thumbnail) .or(file) .with(log), diff --git a/file-service/src/store/mod.rs b/file-service/src/store/mod.rs index 5f07644..1f7ad05 100644 --- a/file-service/src/store/mod.rs +++ b/file-service/src/store/mod.rs @@ -53,9 +53,6 @@ pub enum ReadFileError { #[error("permission denied")] PermissionDenied, - #[error("invalid path")] - InvalidPath, - #[error("JSON error")] JSONError(#[from] serde_json::error::Error), @@ -63,6 +60,36 @@ pub enum ReadFileError { IOError(#[from] std::io::Error), } +#[derive(Debug, Error)] +pub enum DeleteFileError { + #[error("file not found")] + FileNotFound(PathBuf), + + #[error("metadata path is not a file")] + NotAFile, + + #[error("cannot read metadata")] + PermissionDenied, + + #[error("invalid metadata path")] + MetadataParseError(serde_json::error::Error), + + #[error("IO error")] + IOError(#[from] std::io::Error), +} + +impl From for DeleteFileError { + fn from(err: ReadFileError) -> Self { + match err { + ReadFileError::FileNotFound(path) => DeleteFileError::FileNotFound(path), + ReadFileError::NotAFile => DeleteFileError::NotAFile, + ReadFileError::PermissionDenied => DeleteFileError::PermissionDenied, + ReadFileError::JSONError(err) => DeleteFileError::MetadataParseError(err), + ReadFileError::IOError(err) => DeleteFileError::IOError(err), + } + } +} + #[derive(Debug, Error)] pub enum AuthError { #[error("authentication token is duplicated")] @@ -369,7 +396,7 @@ impl Store { FileHandle::load(id, &self.files_root) } - pub fn delete_file(&mut self, id: &FileId) -> Result<(), WriteFileError> { + pub fn delete_file(&mut self, id: &FileId) -> Result<(), DeleteFileError> { let handle = FileHandle::load(id, &self.files_root)?; handle.delete(); Ok(())