Rust implementation of OCI Distribution Spec with granular access control
at main 81 lines 2.1 kB view raw
1use serde::{Deserialize, Serialize}; 2use tokio::sync::Mutex; 3use utoipa::ToSchema; 4 5use std::{collections::HashSet, fmt, fs}; 6 7use crate::args::Args; 8 9#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] 10pub(crate) enum ServerStatus { 11 Starting, 12 Ready, 13} 14 15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, ToSchema)] 16pub struct Permission { 17 pub repository: String, 18 pub tag: String, 19 pub actions: Vec<String>, 20} 21 22#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash, ToSchema)] 23pub struct User { 24 pub username: String, 25 pub password: String, 26 #[serde(default)] 27 pub permissions: Vec<Permission>, 28} 29 30#[derive(Debug, Serialize, Deserialize, ToSchema)] 31pub struct UsersFile { 32 pub users: Vec<User>, 33} 34 35impl fmt::Display for ServerStatus { 36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 37 match self { 38 ServerStatus::Starting => write!(f, "Starting"), 39 ServerStatus::Ready => write!(f, "Ready"), 40 } 41 } 42} 43 44pub(crate) struct App { 45 pub(crate) server_status: Mutex<ServerStatus>, 46 pub(crate) users: Mutex<HashSet<User>>, 47 pub(crate) args: Args, 48} 49 50fn load_users_from_file(file_path: &str) -> HashSet<User> { 51 let file_content = match fs::read_to_string(file_path) { 52 Ok(content) => content, 53 Err(err) => { 54 log::error!("Failed to read users file {}: {}", file_path, err); 55 return HashSet::new(); 56 } 57 }; 58 59 let users_file: UsersFile = match serde_json::from_str(&file_content) { 60 Ok(users_file) => users_file, 61 Err(err) => { 62 log::error!( 63 "Failed to parse JSON from users file {}: {}", 64 file_path, 65 err 66 ); 67 return HashSet::new(); 68 } 69 }; 70 71 log::info!("Loaded {} users", users_file.users.len()); 72 HashSet::from_iter(users_file.users) 73} 74 75pub(crate) fn new_app(args: &Args) -> App { 76 App { 77 server_status: Mutex::new(ServerStatus::Starting), 78 users: Mutex::new(load_users_from_file(&args.users_file)), 79 args: args.clone(), 80 } 81}