chore(server): small changes
This commit is contained in:
parent
1d36af0bcb
commit
ec04360f6c
|
@ -6,8 +6,8 @@
|
|||
//! [code-size]: https://img.shields.io/github/languages/code-size/MedzikUser/HomeDisk?style=for-the-badge&color=c8df52&logo=github
|
||||
//! [ci]: https://img.shields.io/github/workflow/status/MedzikUser/HomeDisk/Rust/main?style=for-the-badge
|
||||
//!
|
||||
//! [home-screenshot]: https://cdn.medzik.xyz/x4Glw7w.png
|
||||
//! [login-screenshot]: https://cdn.medzik.xyz/KpwY4nb.png
|
||||
//! [home-screenshot]: https://i.imgur.com/x4Glw7w.png
|
||||
//! [login-screenshot]: https://i.imgur.com/KpwY4nb.png
|
||||
//!
|
||||
//! [![github]](https://github.com/MedzikUser/HomeDisk)
|
||||
//! [![docs-rs]](https://homedisk-doc.vercel.app)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use tracing::level_filters::LevelFilter;
|
||||
|
||||
/// Max Logger Level on debug build
|
||||
// Max Logger Level on debug build
|
||||
#[cfg(debug_assertions)]
|
||||
const MAX_LEVEL: LevelFilter = LevelFilter::DEBUG;
|
||||
|
||||
/// Max Logger Level on release build
|
||||
// Max Logger Level on release build
|
||||
#[cfg(not(debug_assertions))]
|
||||
const MAX_LEVEL: LevelFilter = LevelFilter::INFO;
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ pub async fn handle(
|
|||
request: Result<Json<Request>, JsonRejection>,
|
||||
) -> Result<Json<Response>, ServerError> {
|
||||
// validate json request
|
||||
let request = validate_json::<Request>(request)?;
|
||||
let request = validate_json(request)?;
|
||||
|
||||
// create `User` type
|
||||
let user = User::new(&request.username, &request.password);
|
||||
|
@ -42,5 +42,6 @@ pub async fn handle(
|
|||
},
|
||||
};
|
||||
|
||||
// send response
|
||||
Ok(Json(response))
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ mod login;
|
|||
mod register;
|
||||
mod whoami;
|
||||
|
||||
/// Handle `/api/auth/*` requests
|
||||
pub fn app() -> axum::Router {
|
||||
use axum::routing::{get, post};
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ pub async fn handle(
|
|||
request: Result<Json<Request>, JsonRejection>,
|
||||
) -> Result<Json<Response>, ServerError> {
|
||||
// validate json request
|
||||
let request = validate_json::<Request>(request)?;
|
||||
let request = validate_json(request)?;
|
||||
|
||||
// username must contain at least 4 characters
|
||||
if request.username.len() < 4 {
|
||||
|
@ -33,10 +33,12 @@ pub async fn handle(
|
|||
return Err(ServerError::AuthError(AuthError::PasswordTooShort));
|
||||
}
|
||||
|
||||
// create `User` type and hash password
|
||||
let user = User::new(&request.username, &request.password);
|
||||
|
||||
// create user in the database
|
||||
let response = match db.create_user(&user).await {
|
||||
Ok(_) => {
|
||||
Ok(_result) => {
|
||||
let token = create_token(&user, config.jwt.secret.as_bytes(), config.jwt.expires)?;
|
||||
|
||||
Response::LoggedIn {
|
||||
|
@ -56,14 +58,10 @@ pub async fn handle(
|
|||
},
|
||||
};
|
||||
|
||||
// create directory for user files
|
||||
let user_dir = format!(
|
||||
"{storage}/{username}",
|
||||
storage = config.storage.path,
|
||||
username = user.username,
|
||||
);
|
||||
fs::create_dir_all(&user_dir)
|
||||
// create directory for the user files
|
||||
fs::create_dir_all(&format!("{}/{}", config.storage.path, user.username,))
|
||||
.map_err(|e| ServerError::FsError(FsError::CreateDirectory(e.to_string())))?;
|
||||
|
||||
// send response
|
||||
Ok(Json(response))
|
||||
}
|
||||
|
|
|
@ -19,8 +19,8 @@ pub async fn handle(
|
|||
|
||||
// search for a user in database
|
||||
let response = match db.find_user_by_id(&token.claims.sub).await {
|
||||
Ok(res) => Response {
|
||||
username: res.username,
|
||||
Ok(user) => Response {
|
||||
username: user.username,
|
||||
},
|
||||
|
||||
// error while searching for a user
|
||||
|
@ -32,5 +32,6 @@ pub async fn handle(
|
|||
},
|
||||
};
|
||||
|
||||
// send response
|
||||
Ok(Json(response))
|
||||
}
|
||||
|
|
|
@ -15,21 +15,18 @@ pub enum Error {
|
|||
/// Custom Result
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// axum::Error
|
||||
impl From<axum::Error> for Error {
|
||||
fn from(err: axum::Error) -> Self {
|
||||
Error::Axum(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// hyper::Error
|
||||
impl From<hyper::Error> for Error {
|
||||
fn from(err: hyper::Error) -> Self {
|
||||
Error::Hyper(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// std::net::AddrParseError
|
||||
impl From<std::net::AddrParseError> for Error {
|
||||
fn from(err: std::net::AddrParseError) -> Self {
|
||||
Error::AddrParseError(err)
|
||||
|
|
|
@ -9,9 +9,7 @@ use homedisk_types::{
|
|||
fs::create_dir::Request,
|
||||
};
|
||||
|
||||
use crate::middleware::{find_user, validate_json, validate_jwt};
|
||||
|
||||
use super::validate_path;
|
||||
use crate::middleware::{find_user, validate_json, validate_jwt, validate_path};
|
||||
|
||||
pub async fn handle(
|
||||
Extension(db): Extension<Database>,
|
||||
|
@ -20,7 +18,7 @@ pub async fn handle(
|
|||
request: Result<Json<Request>, JsonRejection>,
|
||||
) -> Result<(), ServerError> {
|
||||
// validate json request
|
||||
let Json(request) = validate_json::<Request>(request)?;
|
||||
let Json(request) = validate_json(request)?;
|
||||
|
||||
// validate user token
|
||||
let token = validate_jwt(config.jwt.secret.as_bytes(), &token)?;
|
||||
|
@ -42,6 +40,6 @@ pub async fn handle(
|
|||
fs::create_dir_all(path)
|
||||
.map_err(|err| ServerError::FsError(FsError::CreateDirectory(err.to_string())))?;
|
||||
|
||||
// send aan empty Response
|
||||
// send an empty response
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -9,9 +9,7 @@ use homedisk_types::{
|
|||
fs::delete::Request,
|
||||
};
|
||||
|
||||
use crate::middleware::{find_user, validate_jwt};
|
||||
|
||||
use super::validate_path;
|
||||
use crate::middleware::{find_user, validate_jwt, validate_path};
|
||||
|
||||
pub async fn handle(
|
||||
Extension(db): Extension<Database>,
|
||||
|
@ -53,6 +51,6 @@ pub async fn handle(
|
|||
.map_err(|err| ServerError::FsError(FsError::DeleteDirectory(err.to_string())))?;
|
||||
}
|
||||
|
||||
// send an empty Response
|
||||
// send an empty response
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -7,9 +7,7 @@ use homedisk_types::errors::FsError;
|
|||
use homedisk_types::fs::upload::Pagination;
|
||||
use homedisk_types::{config::Config, errors::ServerError};
|
||||
|
||||
use crate::middleware::{find_user, validate_jwt};
|
||||
|
||||
use super::validate_path;
|
||||
use crate::middleware::{find_user, validate_jwt, validate_path};
|
||||
|
||||
pub async fn handle(
|
||||
Extension(db): Extension<Database>,
|
||||
|
@ -37,6 +35,6 @@ pub async fn handle(
|
|||
let content =
|
||||
fs::read(path).map_err(|err| ServerError::FsError(FsError::ReadFile(err.to_string())))?;
|
||||
|
||||
// send file content in Response
|
||||
// send file content in response
|
||||
Ok(content)
|
||||
}
|
||||
|
|
|
@ -11,9 +11,7 @@ use homedisk_types::{
|
|||
fs::list::{DirInfo, FileInfo, Request, Response},
|
||||
};
|
||||
|
||||
use crate::middleware::{find_user, validate_json, validate_jwt};
|
||||
|
||||
use super::validate_path;
|
||||
use crate::middleware::{find_user, validate_json, validate_jwt, validate_path};
|
||||
|
||||
/// Get directory size on disk (size of all files in directory).
|
||||
fn dir_size(path: impl Into<PathBuf>) -> io::Result<u64> {
|
||||
|
@ -94,6 +92,8 @@ pub async fn handle(
|
|||
.get_appropriate_unit(true)
|
||||
.to_string();
|
||||
|
||||
// TODO: fix modification time
|
||||
|
||||
// check how long it has been since the file was last modified
|
||||
let elapsed = metadata.modified().unwrap().elapsed().unwrap();
|
||||
|
||||
|
@ -123,5 +123,6 @@ pub async fn handle(
|
|||
}
|
||||
}
|
||||
|
||||
// send response
|
||||
Ok(Json(Response { files, dirs }))
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ mod download;
|
|||
mod list;
|
||||
mod upload;
|
||||
|
||||
/// Handle `/api/fs/*` requests
|
||||
pub fn app() -> axum::Router {
|
||||
use axum::routing::{delete, get, post};
|
||||
|
||||
|
@ -15,25 +14,3 @@ pub fn app() -> axum::Router {
|
|||
.route("/download", get(download::handle))
|
||||
.route("/createdir", post(create_dir::handle))
|
||||
}
|
||||
|
||||
pub fn validate_path(path: &str) -> Result<(), homedisk_types::errors::ServerError> {
|
||||
use homedisk_types::errors::{FsError, ServerError};
|
||||
|
||||
// `path` can't contain `..`
|
||||
// to prevent attack attempts because by using a `..` you can access the previous folder
|
||||
if path.contains("..") {
|
||||
return Err(ServerError::FsError(FsError::ReadDirectory(
|
||||
"the `path` must not contain `..`".to_string(),
|
||||
)));
|
||||
}
|
||||
|
||||
// `path` can't contain `~`
|
||||
// to prevent attack attempts because `~` can get up a directory on `$HOME`
|
||||
if path.contains('~') {
|
||||
return Err(ServerError::FsError(FsError::ReadDirectory(
|
||||
"the `path` must not contain `~`".to_string(),
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -14,9 +14,7 @@ use homedisk_types::{
|
|||
fs::upload::Pagination,
|
||||
};
|
||||
|
||||
use crate::middleware::{find_user, validate_jwt};
|
||||
|
||||
use super::validate_path;
|
||||
use crate::middleware::{find_user, validate_jwt, validate_path};
|
||||
|
||||
pub async fn handle(
|
||||
Extension(db): Extension<Database>,
|
||||
|
@ -76,6 +74,6 @@ pub async fn handle(
|
|||
.await
|
||||
.map_err(|err| ServerError::FsError(FsError::WriteFile(err.to_string())))?;
|
||||
|
||||
// send an empty Response
|
||||
// send an empty response
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
mod auth;
|
||||
mod jwt;
|
||||
mod validate_json;
|
||||
mod validate_path;
|
||||
|
||||
pub use auth::*;
|
||||
pub use jwt::*;
|
||||
pub use validate_json::*;
|
||||
pub use validate_path::*;
|
||||
|
|
|
@ -2,9 +2,9 @@ use axum::{extract::rejection::JsonRejection, Json};
|
|||
use homedisk_types::errors::ServerError;
|
||||
|
||||
/// Validate json request
|
||||
pub fn validate_json<Typ>(
|
||||
payload: Result<Json<Typ>, JsonRejection>,
|
||||
) -> Result<Json<Typ>, ServerError> {
|
||||
pub fn validate_json<T>(
|
||||
payload: Result<Json<T>, JsonRejection>,
|
||||
) -> Result<Json<T>, ServerError> {
|
||||
match payload {
|
||||
// if success return payload
|
||||
Ok(payload) => Ok(payload),
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
use homedisk_types::errors::{FsError, ServerError};
|
||||
|
||||
/// Validate path param provided in the request
|
||||
pub fn validate_path(path: &str) -> Result<(), ServerError> {
|
||||
// `path` can't contain `..`
|
||||
// to prevent attack attempts because by using a `..` you can access the previous folder
|
||||
if path.contains("..") {
|
||||
return Err(ServerError::FsError(FsError::ReadDirectory(
|
||||
"the `path` can't contain `..`".to_string(),
|
||||
)));
|
||||
}
|
||||
|
||||
// `path` can't contain `~`
|
||||
// to prevent attack attempts because `~` can get up a directory on `$HOME`
|
||||
if path.contains('~') {
|
||||
return Err(ServerError::FsError(FsError::ReadDirectory(
|
||||
"the `path` can't not contain `~`".to_string(),
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_validate_path() {
|
||||
// Successfully
|
||||
assert!(validate_path("Directory/path/to/test.png").is_ok());
|
||||
assert!(validate_path("/test.png").is_ok()); // `/` doesn't point to the system root
|
||||
assert!(validate_path("./test.png").is_ok());
|
||||
|
||||
// Errors
|
||||
assert!(validate_path("../../test.png").is_err());
|
||||
assert!(validate_path("../test.png").is_err());
|
||||
assert!(validate_path("~/test.png").is_err());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue