diff --git a/Cargo.lock b/Cargo.lock index f1bf5a0..17ab6a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1029,6 +1029,7 @@ version = "0.1.0" dependencies = [ "anyhow", "askama", + "async-trait", "axum", "axum-macros", "bollard", diff --git a/fl-server/Cargo.toml b/fl-server/Cargo.toml index 2111174..2859e90 100644 --- a/fl-server/Cargo.toml +++ b/fl-server/Cargo.toml @@ -49,3 +49,4 @@ thiserror = "1.0.63" hostname-validator = "1.1.1" walkdir = "2.5.0" sha256 = "1.5.0" +async-trait = "0.1.53" diff --git a/fl-server/src/auth.rs b/fl-server/src/auth.rs index 9cb96e6..efb097e 100644 --- a/fl-server/src/auth.rs +++ b/fl-server/src/auth.rs @@ -55,7 +55,7 @@ pub async fn sign_in_handler( Extension(cfg): Extension, Json(user_data): Json, ) -> impl IntoResponse { - let user = match get_user_by_username(cfg.users, &user_data.username) { + let user = match get_user_by_username(&cfg.users, &user_data.username) { Some(user) => user, None => { return Err(ResponseError::Unauthorized( @@ -70,7 +70,7 @@ pub async fn sign_in_handler( )); } - let token = encode_jwt(user.username, cfg.jwt_secret, cfg.jwt_expire_hours) + let token = encode_jwt(user.username.clone(), cfg.jwt_secret, cfg.jwt_expire_hours) .map_err(|_| ResponseError::InternalServerError)?; Ok(ResponseResult::SignedIn(SignInResponse { @@ -78,9 +78,9 @@ pub async fn sign_in_handler( })) } -pub fn get_user_by_username(users: Vec, username: &str) -> Option { +pub fn get_user_by_username<'a>(users: &'a [User], username: &str) -> Option<&'a User> { let user = users.iter().find(|u| u.username == username)?; - Some(user.clone()) + Some(user) } pub fn encode_jwt( @@ -138,7 +138,7 @@ pub async fn authorize( } }; - let current_user = match get_user_by_username(cfg.users, &token_data.claims.username) { + let current_user = match get_user_by_username(&cfg.users, &token_data.claims.username) { Some(user) => user, None => { return Err(ResponseError::Unauthorized( @@ -147,6 +147,6 @@ pub async fn authorize( } }; - req.extensions_mut().insert(current_user.username); + req.extensions_mut().insert(current_user.username.clone()); Ok(next.run(req).await) } diff --git a/fl-server/src/handlers.rs b/fl-server/src/handlers.rs index 50474a7..568254f 100644 --- a/fl-server/src/handlers.rs +++ b/fl-server/src/handlers.rs @@ -10,8 +10,6 @@ use std::{ fs, sync::{mpsc, Arc}, }; -use tokio::io; -use walkdir::WalkDir; use bollard::auth::DockerCredentials; use serde::{Deserialize, Serialize}; @@ -25,10 +23,7 @@ use crate::{ response::{FileInfo, ResponseError, ResponseResult}, serve_flists::visit_dir_one_level, }; -use rfs::{ - cache, - fungi::{Reader, Writer}, -}; +use rfs::fungi::{Reader, Writer}; use utoipa::{OpenApi, ToSchema}; use uuid::Uuid; @@ -126,16 +121,8 @@ pub async fn create_flist_handler( let fl_name = docker_image.replace([':', '/'], "-") + ".fl"; let username_dir = format!("{}/{}", cfg.flist_dir, username); - match flist_exists(std::path::Path::new(&username_dir), &fl_name).await { - Ok(exists) => { - if exists { - return Err(ResponseError::Conflict("flist already exists".to_string())); - } - } - Err(e) => { - log::error!("failed to check flist existence with error {:?}", e); - return Err(ResponseError::InternalServerError); - } + if std::path::Path::new(&username_dir).join(&fl_name).exists() { + return Err(ResponseError::Conflict("flist already exists".to_string())); } let created = fs::create_dir_all(&username_dir); @@ -397,7 +384,7 @@ pub async fn preview_flist_handler( Err(err) => return Err(ResponseError::BadRequest(err.to_string())), }; - let content = match unpack_flist(&fl_path).await { + let content = match get_flist_content(&fl_path).await { Ok(paths) => paths, Err(_) => return Err(ResponseError::InternalServerError), }; @@ -421,20 +408,6 @@ pub async fn preview_flist_handler( })) } -async fn flist_exists(dir_path: &std::path::Path, flist_name: &String) -> io::Result { - let mut dir = tokio::fs::read_dir(dir_path).await?; - - while let Some(child) = dir.next_entry().await? { - let file_name = child.file_name().to_string_lossy().to_string(); - - if file_name.eq(flist_name) { - return Ok(true); - } - } - - Ok(false) -} - async fn validate_flist_path( users: Vec, flist_dir: &String, @@ -466,7 +439,7 @@ async fn validate_flist_path( } // validate username - match get_user_by_username(users, parts[1]) { + match get_user_by_username(&users, parts[1]) { Some(_) => (), None => { return Err(anyhow::anyhow!( @@ -494,22 +467,17 @@ async fn validate_flist_path( // validate flist existence let username_dir = format!("{}/{}", parts[0], parts[1]); - match flist_exists(std::path::Path::new(&username_dir), &fl_name).await { - Ok(exists) => { - if !exists { - return Err(anyhow::anyhow!("flist '{}' doesn't exist", fl_path)); - } - } - Err(e) => { - log::error!("failed to check flist existence with error {:?}", e); - return Err(anyhow::anyhow!("Internal server error")); - } + if !std::path::Path::new(&username_dir).join(&fl_name).exists() { + return Err(anyhow::anyhow!("flist '{}' doesn't exist", fl_path)); } Ok(()) } -async fn unpack_flist(fl_path: &String) -> Result, Error> { +async fn get_flist_content(fl_path: &String) -> Result, Error> { + let mut content = Vec::new(); + let mut visitor = ReadVisitor::new(&mut content); + let meta = match Reader::new(&fl_path).await { Ok(reader) => reader, Err(err) => { @@ -522,43 +490,37 @@ async fn unpack_flist(fl_path: &String) -> Result, Erro } }; - let router = match rfs::store::get_router(&meta).await { - Ok(r) => r, + match meta.walk(&mut visitor).await { + Ok(()) => return Ok(visitor.content.to_vec()), Err(err) => { - log::error!("failed to get router with error {}", err); - return Err(anyhow::anyhow!("Internal server error")); - } - }; - - let cache = cache::Cache::new(String::from("/tmp/cache"), router); - let tmp_target = match tempdir::TempDir::new("target") { - Ok(dir) => dir, - Err(err) => { - log::error!("failed to create tmp dir with error {}", err); + log::error!( + "failed to walk through metadata for flist `{}` with error {}", + fl_path, + err + ); return Err(anyhow::anyhow!("Internal server error")); } }; - let tmp_target_path = tmp_target.path().to_owned(); +} - match rfs::unpack(&meta, &cache, &tmp_target_path, false).await { - Ok(_) => (), - Err(err) => { - log::error!("failed to unpack flist {} with error {}", fl_path, err); - return Err(anyhow::anyhow!("Internal server error")); - } - }; +struct ReadVisitor<'a> { + pub content: &'a mut Vec, +} - let mut paths = Vec::new(); - for file in WalkDir::new(tmp_target_path.clone()) - .into_iter() - .filter_map(|file| file.ok()) - { - let path = file.path().to_string_lossy().to_string(); - match path.strip_prefix(&tmp_target_path.to_string_lossy().to_string()) { - Some(p) => paths.push(p.to_string()), - None => return Err(anyhow::anyhow!("Internal server error")), - }; +impl<'a> ReadVisitor<'a> { + pub fn new(content: &'a mut Vec) -> Self { + Self { content } } +} - Ok(paths) +#[async_trait::async_trait] +impl<'a> rfs::fungi::meta::WalkVisitor for ReadVisitor<'a> { + async fn visit( + &mut self, + path: &std::path::Path, + _node: &rfs::fungi::meta::Inode, + ) -> rfs::fungi::meta::Result { + self.content.push(path.to_string_lossy().to_string()); + Ok(rfs::fungi::meta::Walk::Continue) + } }