use std::collections::HashMap; use serde::{Serialize, Deserialize}; //use serde_json::value::{to_value, Value}; use log::error; use std::io::{Error, ErrorKind, Result}; use pasetoken_lib::ConfigPaSeToken; use pasetors::footer::Footer; use crate::{ CFG_FILE_EXTENSION, FILE_SCHEME, defs::{ Local, TotpAlgorithm, TotpMode, deserialize_totp_algorithm, deserialize_totp_mode, FromFile, load_dict_from_file, VecFromFile, load_vec_from_file, }, }; use std::path::Path; pub type WebSubMenuItems = Vec; // use crate::tools::generate_uuid; // fn default_config_empty() -> String { // "".to_string() // } // fn default_config_items() -> HashMap { // HashMap::new() // } fn default_config_resource() -> String { "/".to_string() } fn default_config_array_resource() -> Vec { Vec::new() } fn default_config_serv_paths()-> Vec { Vec::new() } fn default_config_dflt_lang() -> String { "en".to_string() } // fn default_server_uid() -> String { // generate_uuid(String::from("abcdef0123456789")) // } fn default_config_org() -> String { "".to_string() } fn default_config_empty() -> String { "".to_string() } fn default_config_locales() -> HashMap { HashMap::new() } fn default_config_tpls() -> HashMap { HashMap::new() } fn default_is_restricted() -> bool { false } fn default_config_use_mail() -> bool { false } fn default_config_use_token() -> bool { false } fn default_config_invite_expire() -> u64 { 300 } fn default_config_web_menu_items() -> Vec { Vec::new() } fn default_web_menu_item_roles() -> Vec { Vec::new() } fn default_auth_roles() -> Vec { Vec::new() } fn default_sub_menu_items() -> Vec { Vec::new() } fn default_config_totp_digits() -> usize { 6 } fn default_config_totp_algorithm() -> TotpAlgorithm { TotpAlgorithm::default() } fn default_config_totp_mode() -> TotpMode { TotpMode::default() } fn default_config_password_score() -> u8 { 0 } fn default_config_trace_level() -> u8 { 1 } #[derive(Debug, Clone, Serialize, Deserialize,Default)] pub struct SubMenuItem { #[serde(default = "default_config_empty")] pub typ: String, #[serde(default = "default_config_empty")] pub srctyp: String, #[serde(default = "default_config_empty")] pub text: String, #[serde(default = "default_config_empty")] pub url: String, #[serde(default = "default_web_menu_item_roles")] pub roles: Vec, } #[derive(Debug, Clone, Serialize, Deserialize,Default)] pub struct WebMenuItem { #[serde(default = "default_config_resource")] pub root_path: String, #[serde(default = "default_config_empty")] pub typ: String, #[serde(default = "default_config_empty")] pub srctyp: String, #[serde(default = "default_config_empty")] pub text: String, #[serde(default = "default_config_empty")] pub url: String, #[serde(default = "default_web_menu_item_roles")] pub roles: Vec, #[serde(default = "default_sub_menu_items")] pub items: Vec, } impl VecFromFile for WebMenuItem { fn fix_root_path(&mut self, _root_path: String ) { } } // impl WebMenuItem { // pub fn load_items(path_items: String) -> Vec { // if !path_items.is_empty() { // load_vec_from_file(&path_items.to_owned(), "web_menu.items").unwrap_or_else(|e|{ // print!("Error loading sid_settings from {}: {}",&path_items,e); // error!("Error loading sid_settings from {}: {}",&path_items,e); // Vec::new() // }) // } else { // Vec::new() // } // } //} #[derive(Debug, Clone, Serialize, Deserialize,Default)] pub struct UiConfig { #[serde(default = "default_config_empty")] pub css_link: String, #[serde(default = "default_config_empty")] pub js_link: String, #[serde(default = "default_config_empty")] pub other_css_link: String, #[serde(default = "default_config_empty")] pub other_js_link: String, #[serde(default = "default_config_empty")] pub main_js_link: String, #[serde(default = "default_config_empty")] pub utils_js_link: String, #[serde(default = "default_config_web_menu_items")] pub web_menu_items: Vec, } /// ServPath collects dir path to server as static content #[derive(Debug, Clone, Serialize, Deserialize,Default)] pub struct ServPath { #[serde(default = "default_config_empty")] pub src_path: String, #[serde(default = "default_config_empty")] pub url_path: String, #[serde(default = "default_config_empty")] pub not_found: String, #[serde(default = "default_config_empty")] pub not_auth: String, #[serde(default = "default_is_restricted")] pub is_restricted: bool, #[serde(default = "default_config_empty")] pub redirect_to: String, } /// Config collects config values. #[derive(Debug, Clone, Serialize, Deserialize,Default)] pub struct Config { pub hostport: String, pub bind: String, pub port: u16, pub protocol: String, #[serde(default = "default_config_org")] pub org: String, pub name: String, pub verbose: u8, pub prefix: String, pub resources_path: String, pub cert_file: String, pub key_file: String, //pub certs_store_path: String, //pub cert_file_sufix: String, #[serde(default = "default_config_array_resource")] pub allow_origin: Vec, #[serde(default = "default_config_array_resource")] pub langs: Vec, #[serde(default = "default_config_dflt_lang")] pub dflt_lang: String, #[serde(default = "default_config_empty")] pub path_locales_config: String, #[serde(default = "default_config_locales")] pub locales: HashMap, // Some paths #[serde(default = "default_config_resource")] pub root_path: String, #[serde(default = "default_config_resource")] pub defaults_path: String, #[serde(default = "default_config_serv_paths")] pub serv_paths: Vec, #[serde(default = "default_config_resource")] pub docs_index: String, #[serde(default = "default_config_resource")] pub templates_path: String, #[serde(default = "default_config_resource")] pub html_url: String, #[serde(default = "default_config_resource")] pub assets_url: String, #[serde(default = "default_config_resource")] pub users_store_uri: String, #[serde(default = "default_config_empty")] pub user_store_access: String, #[serde(default = "default_auth_roles")] pub auth_roles: Vec, #[serde(default = "default_config_empty")] pub trace_store_uri: String, #[serde(default = "default_config_trace_level")] pub trace_level: u8, #[serde(default = "default_config_empty")] pub signup_mode: String, #[serde(default = "default_config_invite_expire")] pub invite_expire: u64, #[serde(default = "default_config_use_token")] pub use_token: bool, #[serde(default = "default_config_totp_digits")] pub totp_digits: usize, #[serde(default = "default_config_totp_mode", deserialize_with = "deserialize_totp_mode")] pub totp_mode: TotpMode, #[serde(default = "default_config_totp_algorithm", deserialize_with = "deserialize_totp_algorithm")] pub totp_algorithm: TotpAlgorithm, #[serde(default = "default_config_password_score")] pub password_score: u8, #[serde(default = "default_config_empty")] pub admin_fields: String, #[serde(default = "default_config_empty")] pub mail_from: String, #[serde(default = "default_config_empty")] pub mail_reply_to: String, #[serde(default = "default_config_use_mail")] pub use_mail: bool, #[serde(default = "default_config_empty")] pub smtp: String, #[serde(default = "default_config_empty")] pub smtp_auth: String, // #[cfg(feature = "authstore")] #[serde(default = "default_config_resource")] pub authz_store_uri: String, // #[cfg(feature = "casbin")] #[serde(default = "default_config_empty")] pub authz_model_path: String, // #[cfg(feature = "casbin")] #[serde(default = "default_config_empty")] pub authz_policy_path: String, #[serde(default = "default_config_empty")] pub session_store_uri: String, #[serde(default = "default_config_empty")] pub session_store_file: String, pub session_expire: u64, pub paseto: ConfigPaSeToken, pub ui: UiConfig, #[serde(default = "default_config_tpls")] pub tpls: HashMap, #[serde(default = "default_config_resource")] pub path_menu_items: String, #[serde(default = "default_config_resource")] pub path_serv_paths: String, } // impl FromFile for Config { // fn fix_root_path(&mut self, root_path: String ) { // if root_path != self.root_path { // self.root_path = root_path.to_owned(); // } // if self.root_path.is_empty() || ! Path::new(&self.root_path).exists() { // return; // } // } // } impl Config { fn fix_item_path(&mut self, item: String ) -> String { if !item.is_empty() && ! Path::new(&item).exists() { format!("{}/{}",&self.root_path,&item) } else { item } } pub fn load_items(&mut self) { // self.fix_root_path::(self.root_path.to_owned()); if !self.path_menu_items.is_empty() { self.path_menu_items = self.fix_item_path(self.path_menu_items.to_owned()); self.ui.web_menu_items = load_vec_from_file(&self.path_menu_items.to_owned(), "menu_items").unwrap_or_else(|e|{ error!("Error loading menu_items from {}: {}",&self.path_menu_items,e); Vec::new() }); } if !self.path_locales_config.is_empty() { self.path_locales_config = self.fix_item_path(self.path_locales_config.to_owned()); self.locales = load_dict_from_file(&self.path_locales_config.to_owned(), "locales").unwrap_or_else(|e|{ error!("Error loading locales from {}: {}",&self.path_locales_config,e); HashMap::new() }); } if self.users_store_uri.starts_with(FILE_SCHEME) { self.users_store_uri = format!("{}{}", FILE_SCHEME, self.fix_item_path(self.users_store_uri.replace(FILE_SCHEME,""))); } if self.session_store_uri.starts_with(FILE_SCHEME) { self.session_store_uri = format!("{}{}", FILE_SCHEME, self.fix_item_path(self.session_store_uri.replace(FILE_SCHEME,""))); } if self.trace_store_uri.starts_with(FILE_SCHEME) { self.trace_store_uri = format!("{}{}", FILE_SCHEME, self.fix_item_path(self.trace_store_uri.replace(FILE_SCHEME,""))); } self.cert_file = self.fix_item_path(self.cert_file.to_owned()); self.key_file = self.fix_item_path(self.key_file.to_owned()); self.templates_path = self.fix_item_path(self.templates_path.to_owned()); self.defaults_path = self.fix_item_path(self.defaults_path.to_owned()); #[cfg(feature = "authstore")] if self.authz_store_uri.starts_with(FILE_SCHEME) { self.authz_store_uri = format!("{}{}", FILE_SCHEME, self.fix_item_path(self.authz_store_uri.replace(FILE_SCHEME,""))); } #[cfg(feature = "casbin")] { self.authz_model_path = self.fix_item_path(self.authz_model_path.to_owned()); self.authz_policy_path = self.fix_item_path(self.authz_policy_path.to_owned()); } self.paseto.public_path = self.fix_item_path(self.paseto.public_path.to_owned()); self.paseto.secret_path = self.fix_item_path(self.paseto.secret_path.to_owned()); // Loading paseto (self.paseto.public_data, self.paseto.secret_data) = self.paseto.load_data(); self.paseto.footer = ConfigPaSeToken::make_footer( self.paseto.map_footer.to_owned() ).unwrap_or(Footer::new()); } #[allow(dead_code)] pub fn to_json(&self) -> String { serde_json::to_string(self).unwrap_or_else(|e|{ println!("Error to convert Config to json: {}",e); String::from("") }) } // #[allow(dead_code)] // pub fn st_html_path(&self) -> &'static str { // Box::leak(self.html_path.to_owned().into_boxed_str()) // } #[allow(dead_code)] pub fn full_html_url(&self, url: &str) -> String { format!("{}://{}:{}/{}", &self.protocol,&self.bind,&self.port, url ) } pub fn load_from_file<'a>(file_cfg: &str, name: &str) -> Result { let item_cfg: Self; let file_path: String; if file_cfg.contains(CFG_FILE_EXTENSION) { file_path = file_cfg.to_string(); } else { file_path = format!("{}{}",file_cfg.to_string(),CFG_FILE_EXTENSION); } let config_content: &'a str; match std::fs::read_to_string(&file_path) { Ok(cfgcontent) => config_content = Box::leak(cfgcontent.into_boxed_str()), Err(e) => return Err(Error::new( ErrorKind::InvalidInput, format!("Error read {}: {}",&file_path,e) )), }; // match toml::from_str::(&config_content) { match toml::from_str::(&config_content) { Ok(cfg) => item_cfg = cfg, Err(e) => return Err(Error::new( ErrorKind::InvalidInput, format!("Error loading config {}: {}",&file_path,e) )), }; log::info!("Loaded {} config from: {}", &name, &file_path); Ok(item_cfg) } }