diff --git a/server/src/fs/delete.rs b/server/src/fs/delete.rs new file mode 100644 index 0000000..ea06733 --- /dev/null +++ b/server/src/fs/delete.rs @@ -0,0 +1,56 @@ +use std::{fs, path::Path}; + +use axum::extract::Query; +use axum::Extension; +use axum_auth::AuthBearer; +use homedisk_database::Database; +use homedisk_types::{ + config::types::Config, + errors::{FsError, ServerError}, + fs::delete::Request, +}; + +use crate::fs::validate_path; +use crate::middleware::{find_user, validate_jwt}; + +pub async fn handle( + Extension(db): Extension, + Extension(config): Extension, + AuthBearer(token): AuthBearer, + query: Query, +) -> Result<(), ServerError> { + // validate user token + let token = validate_jwt(config.jwt.secret.as_bytes(), &token)?; + + // validate the `path` can be used + validate_path(&query.path)?; + + // search for a user by UUID from a token + let user = find_user(db, token.claims.sub).await?; + + // path to the file + let path = format!( + "{user_dir}/{request_path}", + user_dir = user.user_dir(&config.storage.path), + request_path = query.path + ); + let path = Path::new(&path); + + // if file does not exist return error + if !path.exists() { + return Err(ServerError::FsError(FsError::FileDoesNotExist)); + } + + // delete file + if path.is_file() { + fs::remove_file(&path) + .map_err(|err| ServerError::FsError(FsError::DeleteFile(err.to_string())))?; + } + // delete directory + else if path.is_dir() { + fs::remove_dir(&path) + .map_err(|err| ServerError::FsError(FsError::DeleteDirectory(err.to_string())))?; + } + + Ok(()) +} diff --git a/server/src/fs/download.rs b/server/src/fs/download.rs new file mode 100644 index 0000000..6c1f682 --- /dev/null +++ b/server/src/fs/download.rs @@ -0,0 +1,46 @@ +use std::path::PathBuf; +use std::{fs, io}; + +use crate::fs::validate_path; +use axum::extract::Query; +use axum::{extract::rejection::JsonRejection, Extension, Json}; +use axum_auth::AuthBearer; +use byte_unit::Byte; +use homedisk_database::Database; +use homedisk_types::fs::list::DirInfo; +use homedisk_types::fs::upload::Pagination; +use homedisk_types::{ + config::types::Config, + errors::{FsError, ServerError}, + fs::list::{FileInfo, Request, Response}, +}; + +use crate::middleware::{find_user, validate_json, validate_jwt}; + +pub async fn handle( + Extension(db): Extension, + Extension(config): Extension, + AuthBearer(token): AuthBearer, + query: Query, +) -> Result, ServerError> { + // validate token + let token = validate_jwt(config.jwt.secret.as_bytes(), &token)?; + + // validate the `path` can be used + validate_path(&query.path)?; + + // search for a user by UUID from a token + let user = find_user(db, token.claims.sub).await?; + + // directory where the file will be placed + let path = format!( + "{user_dir}/{req_dir}", + user_dir = user.user_dir(&config.storage.path), + req_dir = query.path + ); + + // read file content + let content = fs::read(path).unwrap(); + + Ok(content) +} diff --git a/server/src/fs/list.rs b/server/src/fs/list.rs index 1883ba2..e016564 100644 --- a/server/src/fs/list.rs +++ b/server/src/fs/list.rs @@ -59,10 +59,10 @@ pub async fn handle( let mut dirs = vec![]; for f in paths { - let f = f.map_err(|err| ServerError::FsError(FsError::UnknowError(err.to_string())))?; + let f = f.map_err(|err| ServerError::FsError(FsError::UnknownError(err.to_string())))?; let metadata = f .metadata() - .map_err(|err| ServerError::FsError(FsError::UnknowError(err.to_string())))?; + .map_err(|err| ServerError::FsError(FsError::UnknownError(err.to_string())))?; let name = f.path().display().to_string().replace(&path, ""); diff --git a/server/src/fs/mod.rs b/server/src/fs/mod.rs index aa1f494..fa7bb1c 100644 --- a/server/src/fs/mod.rs +++ b/server/src/fs/mod.rs @@ -1,12 +1,16 @@ +pub mod delete; +pub mod download; pub mod list; pub mod upload; pub fn app() -> axum::Router { - use axum::routing::post; + use axum::routing::{delete, get, post}; axum::Router::new() .route("/list", post(list::handle)) .route("/upload", post(upload::handle)) + .route("/delete", delete(upload::handle)) + .route("/download", get(download::handle)) } pub fn validate_path(path: &str) -> Result<(), homedisk_types::errors::ServerError> { diff --git a/types/src/errors/fs.rs b/types/src/errors/fs.rs index 2825685..fa9e591 100644 --- a/types/src/errors/fs.rs +++ b/types/src/errors/fs.rs @@ -5,12 +5,21 @@ pub enum Error { #[error("file already exists")] FileAlreadyExists, + #[error("file doesn't exists")] + FileDoesNotExist, + #[error("unexpected multipart error")] MultipartError, #[error("create file - {0}")] CreateFile(String), + #[error("delete file - {0}")] + DeleteFile(String), + + #[error("delete dir - {0}")] + DeleteDirectory(String), + #[error("write file - {0}")] WriteFile(String), @@ -20,6 +29,6 @@ pub enum Error { #[error("read dir - {0}")] ReadDir(String), - #[error("unknow error")] - UnknowError(String), + #[error("unknown error")] + UnknownError(String), } diff --git a/types/src/errors/mod.rs b/types/src/errors/mod.rs index f266c7f..4d411ff 100644 --- a/types/src/errors/mod.rs +++ b/types/src/errors/mod.rs @@ -51,13 +51,16 @@ impl axum::response::IntoResponse for ServerError { AuthError::UnknownError(_) => StatusCode::INTERNAL_SERVER_ERROR, }, Self::FsError(ref err) => match err { - FsError::MultipartError => StatusCode::BAD_REQUEST, FsError::FileAlreadyExists => StatusCode::BAD_REQUEST, + FsError::FileDoesNotExist => StatusCode::BAD_REQUEST, + FsError::MultipartError => StatusCode::BAD_REQUEST, FsError::CreateFile(_) => StatusCode::INTERNAL_SERVER_ERROR, + FsError::DeleteFile(_) => StatusCode::INTERNAL_SERVER_ERROR, + FsError::DeleteDirectory(_) => StatusCode::INTERNAL_SERVER_ERROR, FsError::WriteFile(_) => StatusCode::INTERNAL_SERVER_ERROR, FsError::Base64(_) => StatusCode::BAD_REQUEST, FsError::ReadDir(_) => StatusCode::BAD_REQUEST, - FsError::UnknowError(_) => StatusCode::INTERNAL_SERVER_ERROR, + FsError::UnknownError(_) => StatusCode::INTERNAL_SERVER_ERROR, }, Self::TooManyRequests => StatusCode::TOO_MANY_REQUESTS, Self::MissingJsonContentType => StatusCode::BAD_REQUEST, diff --git a/types/src/fs/delete.rs b/types/src/fs/delete.rs new file mode 100644 index 0000000..0f47ff1 --- /dev/null +++ b/types/src/fs/delete.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Request { + pub path: String, +} diff --git a/types/src/fs/download.rs b/types/src/fs/download.rs new file mode 100644 index 0000000..0f47ff1 --- /dev/null +++ b/types/src/fs/download.rs @@ -0,0 +1,6 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct Request { + pub path: String, +} diff --git a/types/src/fs/mod.rs b/types/src/fs/mod.rs index b3f8ba9..20c4358 100644 --- a/types/src/fs/mod.rs +++ b/types/src/fs/mod.rs @@ -1,2 +1,4 @@ +pub mod delete; +pub mod download; pub mod list; pub mod upload;