@ -1,5 +1,6 @@ 
			
		
	
		
		
			
				
					use   std ::{ use   std ::{  
			
		
	
		
		
			
				
					     env ::consts ::EXE_SUFFIX ,      env ::consts ::EXE_SUFFIX ,  
			
		
	
		
		
			
				
					     fmt ,  
			
		
	
		
		
			
				
					     process ::exit ,      process ::exit ,  
			
		
	
		
		
			
				
					     sync ::{      sync ::{  
			
		
	
		
		
			
				
					         atomic ::{ AtomicBool ,   Ordering } ,          atomic ::{ AtomicBool ,   Ordering } ,  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -8,8 +9,8 @@ use std::{ 
			
		
	
		
		
			
				
					} ; } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					use   job_scheduler_ng ::Schedule ; use   job_scheduler_ng ::Schedule ;  
			
		
	
		
		
			
				
					use   once_cell ::sync ::Lazy ;  
			
		
	
		
		
			
				
					use   reqwest ::Url ; use   reqwest ::Url ;  
			
		
	
		
		
			
				
					use   serde ::de ::{ self ,   Deserialize ,   Deserializer ,   MapAccess ,   Visitor } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					use   crate ::{ use   crate ::{  
			
		
	
		
		
			
				
					     db ::DbConnType ,      db ::DbConnType ,  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -17,7 +18,7 @@ use crate::{ 
			
		
	
		
		
			
				
					     util ::{ get_env ,   get_env_bool ,   get_web_vault_version ,   is_valid_email ,   parse_experimental_client_feature_flags } ,      util ::{ get_env ,   get_env_bool ,   get_web_vault_version ,   is_valid_email ,   parse_experimental_client_feature_flags } ,  
			
		
	
		
		
			
				
					} ; } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					static   CONFIG_FILE : Lazy < String >   =   Lazy ::new ( | |   { static   CONFIG_FILE : LazyLock  < String >   =   LazyLock  ::new ( | |   {  
			
				
				
			
		
	
		
		
	
		
		
			
				
					     let   data_folder   =   get_env ( "DATA_FOLDER" ) . unwrap_or_else ( | |   String ::from ( "data" ) ) ;      let   data_folder   =   get_env ( "DATA_FOLDER" ) . unwrap_or_else ( | |   String ::from ( "data" ) ) ;  
			
		
	
		
		
			
				
					     get_env ( "CONFIG_FILE" ) . unwrap_or_else ( | |   format ! ( "{data_folder}/config.json" ) )      get_env ( "CONFIG_FILE" ) . unwrap_or_else ( | |   format ! ( "{data_folder}/config.json" ) )  
			
		
	
		
		
			
				
					} ) ; } ) ;  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -34,7 +35,7 @@ static CONFIG_FILENAME: LazyLock<String> = LazyLock::new(|| { 
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					pub   static   SKIP_CONFIG_VALIDATION : AtomicBool   =   AtomicBool ::new ( false ) ; pub   static   SKIP_CONFIG_VALIDATION : AtomicBool   =   AtomicBool ::new ( false ) ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					pub   static   CONFIG : Lazy < Config >   =   Lazy ::new ( | |   { pub   static   CONFIG : LazyLock  < Config >   =   LazyLock  ::new ( | |   {  
			
				
				
			
		
	
		
		
	
		
		
			
				
					     std ::thread ::spawn ( | |   {      std ::thread ::spawn ( | |   {  
			
		
	
		
		
			
				
					         let   rt   =   tokio ::runtime ::Builder ::new_current_thread ( ) . enable_all ( ) . build ( ) . unwrap_or_else ( | e |   {          let   rt   =   tokio ::runtime ::Builder ::new_current_thread ( ) . enable_all ( ) . build ( ) . unwrap_or_else ( | e |   {  
			
		
	
		
		
			
				
					             println ! ( "Error loading config:\n  {e:?}\n" ) ;              println ! ( "Error loading config:\n  {e:?}\n" ) ;  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -56,6 +57,41 @@ pub static CONFIG: Lazy<Config> = Lazy::new(|| { 
			
		
	
		
		
			
				
					pub   type  Pass   =   String ; pub   type  Pass   =   String ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					macro_rules !   make_config   { macro_rules !   make_config   {  
			
		
	
		
		
			
				
					     // Support string print
  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   Pass ,   option   )   = >   {   serde_json ::to_value ( & $value . as_ref ( ) . map ( | _ |   String ::from ( "***" ) ) ) . unwrap ( )   } ;   // Optional pass, we map to an Option<String> with "***"
  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   Pass ,   $none_action :ident   )   = >   {   "***" . into ( )   } ;   // Required pass, we return "***"
  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   $ty :ty ,   option   )   = >   {   serde_json ::to_value ( & $value ) . unwrap ( )   } ;   // Optional other or string, we convert to json
  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   String ,   $none_action :ident   )   = >   {   $value . as_str ( ) . into ( )   } ;   // Required string value, we convert to json
  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   $ty :ty ,   $none_action :ident   )   = >   {   ( $value ) . into ( )   } ;   // Required other value, we return as is or convert to json
  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					     // Group or empty string
  
			
		
	
		
		
			
				
					     (   @ show   )   = >   {   ""   } ;  
			
		
	
		
		
			
				
					     (   @ show   $lit :literal   )   = >   {   $lit   } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					     // Wrap the optionals in an Option type
  
			
		
	
		
		
			
				
					     (   @ type  $ty :ty ,   option )   = >   {   Option < $ty >   } ;  
			
		
	
		
		
			
				
					     (   @ type  $ty :ty ,   $id :ident )   = >   {   $ty   } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					     // Generate the values depending on none_action
  
			
		
	
		
		
			
				
					     (   @ build   $value :expr ,   $config :expr ,   option ,   )   = >   {   $value   } ;  
			
		
	
		
		
			
				
					     (   @ build   $value :expr ,   $config :expr ,   def ,   $default :expr   )   = >   {   $value . unwrap_or ( $default )   } ;  
			
		
	
		
		
			
				
					     (   @ build   $value :expr ,   $config :expr ,   auto ,   $default_fn :expr   )   = >   { {  
			
		
	
		
		
			
				
					         match   $value   {  
			
		
	
		
		
			
				
					             Some ( v )   = >   v ,  
			
		
	
		
		
			
				
					             None   = >   {  
			
		
	
		
		
			
				
					                 let   f : & dyn   Fn ( & ConfigItems )   -> _   =   & $default_fn ;  
			
		
	
		
		
			
				
					                 f ( $config )  
			
		
	
		
		
			
				
					             }  
			
		
	
		
		
			
				
					         }  
			
		
	
		
		
			
				
					     } } ;  
			
		
	
		
		
			
				
					     (   @ build   $value :expr ,   $config :expr ,   generated ,   $default_fn :expr   )   = >   { {  
			
		
	
		
		
			
				
					         let   f : & dyn   Fn ( & ConfigItems )   -> _   =   & $default_fn ;  
			
		
	
		
		
			
				
					         f ( $config )  
			
		
	
		
		
			
				
					     } } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					     (   @ getenv   $name :expr ,   bool   )   = >   {   get_env_bool ( $name )   } ;  
			
		
	
		
		
			
				
					     (   @ getenv   $name :expr ,   $ty :ident   )   = >   {   get_env ( $name )   } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					     ( $(      ( $(  
			
		
	
		
		
			
				
					         $( #[ doc = $groupdoc:literal ] ) ?          $( #[ doc = $groupdoc:literal ] ) ?  
			
		
	
		
		
			
				
					         $group :ident   $( : $group_enabled :ident ) ?   {          $group :ident   $( : $group_enabled :ident ) ?   {  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -75,10 +111,103 @@ macro_rules! make_config { 
			
		
	
		
		
			
				
					             _env : ConfigBuilder ,              _env : ConfigBuilder ,  
			
		
	
		
		
			
				
					             _usr : ConfigBuilder ,              _usr : ConfigBuilder ,  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					             _overrides : Vec < String > ,              _overrides : Vec < & 'static   str > ,  
			
				
				
			
		
	
		
		
	
		
		
			
				
					         }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					         // Custom Deserialize for ConfigBuilder, mainly based upon https://serde.rs/deserialize-struct.html
  
			
		
	
		
		
			
				
					         // This deserialize doesn't care if there are keys missing, or if there are duplicate keys
  
			
		
	
		
		
			
				
					         // In case of duplicate keys (which should never be possible unless manually edited), the last value is used!
  
			
		
	
		
		
			
				
					         // Main reason for this is removing the `visit_seq` function, which causes a lot of code generation not needed or used for this struct.
  
			
		
	
		
		
			
				
					         impl < 'de >   Deserialize < 'de >   for   ConfigBuilder   {  
			
		
	
		
		
			
				
					             fn  deserialize < D > ( deserializer : D )   -> Result < Self ,   D ::Error >  
			
		
	
		
		
			
				
					             where  
			
		
	
		
		
			
				
					                 D : Deserializer < 'de > ,  
			
		
	
		
		
			
				
					             {  
			
		
	
		
		
			
				
					                 const   FIELDS : & [ & str ]   =   & [  
			
		
	
		
		
			
				
					                 $( $(  
			
		
	
		
		
			
				
					                     stringify ! ( $name ) ,  
			
		
	
		
		
			
				
					                 ) + ) +  
			
		
	
		
		
			
				
					                 ] ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                 #[ allow(non_camel_case_types) ]  
			
		
	
		
		
			
				
					                 enum  Field   {  
			
		
	
		
		
			
				
					                 $( $(  
			
		
	
		
		
			
				
					                     $name ,  
			
		
	
		
		
			
				
					                 ) + ) +  
			
		
	
		
		
			
				
					                     __ignore ,  
			
		
	
		
		
			
				
					                 }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                 impl < 'de >   Deserialize < 'de >   for   Field   {  
			
		
	
		
		
			
				
					                     fn  deserialize < D > ( deserializer : D )   -> Result < Self ,   D ::Error >  
			
		
	
		
		
			
				
					                     where  
			
		
	
		
		
			
				
					                         D : Deserializer < 'de > ,  
			
		
	
		
		
			
				
					                     {  
			
		
	
		
		
			
				
					                         struct  FieldVisitor ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                         impl   Visitor < '_ >   for   FieldVisitor   {  
			
		
	
		
		
			
				
					                             type  Value   =   Field ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                             fn  expecting ( & self ,   formatter : & mut   fmt ::Formatter < '_ > )   -> fmt ::Result   {  
			
		
	
		
		
			
				
					                                 formatter . write_str ( "ConfigBuilder field identifier" )  
			
		
	
		
		
			
				
					                             }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                             #[ inline ]  
			
		
	
		
		
			
				
					                             fn  visit_str < E > ( self ,   value : & str )   -> Result < Field ,   E >  
			
		
	
		
		
			
				
					                             where  
			
		
	
		
		
			
				
					                                 E : de ::Error ,  
			
		
	
		
		
			
				
					                             {  
			
		
	
		
		
			
				
					                                 match   value   {  
			
		
	
		
		
			
				
					                                 $( $(  
			
		
	
		
		
			
				
					                                     stringify ! ( $name )   = >   Ok ( Field ::$name ) ,  
			
		
	
		
		
			
				
					                                 ) + ) +  
			
		
	
		
		
			
				
					                                     _   = >   Ok ( Field ::__ignore ) ,  
			
		
	
		
		
			
				
					                                 }  
			
		
	
		
		
			
				
					                             }  
			
		
	
		
		
			
				
					                         }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                         deserializer . deserialize_identifier ( FieldVisitor )  
			
		
	
		
		
			
				
					                     }                      }  
			
		
	
		
		
			
				
					                 }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                 struct  ConfigBuilderVisitor ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					         #[ derive(Clone, Default, Deserialize, Serialize) ]                  impl < 'de >   Visitor < 'de >   for   ConfigBuilderVisitor   {  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                     type  Value   =   ConfigBuilder ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                     fn  expecting ( & self ,   formatter : & mut   fmt ::Formatter < '_ > )   -> fmt ::Result   {  
			
		
	
		
		
			
				
					                         formatter . write_str ( "struct ConfigBuilder" )  
			
		
	
		
		
			
				
					                     }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                     #[ inline ]  
			
		
	
		
		
			
				
					                     fn  visit_map < A > ( self ,   mut   map : A )   -> Result < Self ::Value ,   A ::Error >  
			
		
	
		
		
			
				
					                     where  
			
		
	
		
		
			
				
					                         A : MapAccess < 'de > ,  
			
		
	
		
		
			
				
					                     {  
			
		
	
		
		
			
				
					                         let   mut   builder   =   ConfigBuilder ::default ( ) ;  
			
		
	
		
		
			
				
					                         while   let   Some ( key )   =   map . next_key ( ) ?   {  
			
		
	
		
		
			
				
					                             match   key   {  
			
		
	
		
		
			
				
					                             $( $(  
			
		
	
		
		
			
				
					                                 Field ::$name   = >   {  
			
		
	
		
		
			
				
					                                     if   builder . $name . is_some ( )   {  
			
		
	
		
		
			
				
					                                         return   Err ( de ::Error ::duplicate_field ( stringify ! ( $name ) ) ) ;  
			
		
	
		
		
			
				
					                                     }  
			
		
	
		
		
			
				
					                                     builder . $name   =   map . next_value ( ) ? ;  
			
		
	
		
		
			
				
					                                 }  
			
		
	
		
		
			
				
					                             ) + ) +  
			
		
	
		
		
			
				
					                                 Field ::__ignore   = >   {  
			
		
	
		
		
			
				
					                                     let   _   =   map . next_value ::< de ::IgnoredAny > ( ) ? ;  
			
		
	
		
		
			
				
					                                 }  
			
		
	
		
		
			
				
					                             }  
			
		
	
		
		
			
				
					                         }  
			
		
	
		
		
			
				
					                         Ok ( builder )  
			
		
	
		
		
			
				
					                     }  
			
		
	
		
		
			
				
					                 }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                 deserializer . deserialize_struct ( "ConfigBuilder" ,   FIELDS ,   ConfigBuilderVisitor )  
			
		
	
		
		
			
				
					             }  
			
		
	
		
		
			
				
					         }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					         #[ derive(Clone, Default, Serialize) ]  
			
		
	
		
		
			
				
					         pub   struct  ConfigBuilder   {          pub   struct  ConfigBuilder   {  
			
		
	
		
		
			
				
					             $( $(              $( $(  
			
		
	
		
		
			
				
					                 #[ serde(skip_serializing_if =  " Option::is_none " ) ]                  #[ serde(skip_serializing_if =  " Option::is_none " ) ]  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -87,7 +216,6 @@ macro_rules! make_config { 
			
		
	
		
		
			
				
					         }          }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					         impl   ConfigBuilder   {          impl   ConfigBuilder   {  
			
		
	
		
		
			
				
					             #[ allow(clippy::field_reassign_with_default) ]  
			
		
	
		
		
			
				
					             fn  from_env ( )   -> Self   {              fn  from_env ( )   -> Self   {  
			
		
	
		
		
			
				
					                 let   env_file   =   get_env ( "ENV_FILE" ) . unwrap_or_else ( | |   String ::from ( ".env" ) ) ;                  let   env_file   =   get_env ( "ENV_FILE" ) . unwrap_or_else ( | |   String ::from ( ".env" ) ) ;  
			
		
	
		
		
			
				
					                 match   dotenvy ::from_path ( & env_file )   {                  match   dotenvy ::from_path ( & env_file )   {  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -149,14 +277,14 @@ macro_rules! make_config { 
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					             /// Merges the values of both builders into a new builder.
              /// Merges the values of both builders into a new builder.
  
			
		
	
		
		
			
				
					             /// If both have the same element, `other` wins.
              /// If both have the same element, `other` wins.
  
			
		
	
		
		
			
				
					
					             fn  merge ( & self ,   other : & Self ,   show_overrides : bool ,   overrides : & mut   Vec < String > )   -> Self   {              fn  merge ( & self ,   other : & Self ,   show_overrides : bool ,   overrides : & mut   Vec < & str > )   -> Self   {  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                 let   mut   builder   =   self . clone ( ) ;                  let   mut   builder   =   self . clone ( ) ;  
			
		
	
		
		
			
				
					                 $( $(                  $( $(  
			
		
	
		
		
			
				
					                     if   let   v   @ Some ( _ )   =   & other . $name   {                      if   let   v   @ Some ( _ )   =   & other . $name   {  
			
		
	
		
		
			
				
					                         builder . $name   =   v . clone ( ) ;                          builder . $name   =   v . clone ( ) ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                         if   self . $name . is_some ( )   {                          if   self . $name . is_some ( )   {  
			
		
	
		
		
			
				
					
					                             overrides . push ( pastey ::paste ! ( stringify ! ( [ < $name :upper > ] ) ) . into ( ) ) ;                              overrides . push ( pastey ::paste ! ( stringify ! ( [ < $name :upper > ] ) ) ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                         }                          }  
			
		
	
		
		
			
				
					                     }                      }  
			
		
	
		
		
			
				
					                 ) + ) +                  ) + ) +  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -197,6 +325,32 @@ macro_rules! make_config { 
			
		
	
		
		
			
				
					         #[ derive(Clone, Default) ]          #[ derive(Clone, Default) ]  
			
		
	
		
		
			
				
					         struct  ConfigItems   {   $( $(   $name : make_config ! { @ type  $ty ,   $none_action } ,   ) + ) +   }          struct  ConfigItems   {   $( $(   $name : make_config ! { @ type  $ty ,   $none_action } ,   ) + ) +   }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					         #[ derive(Serialize) ]  
			
		
	
		
		
			
				
					         struct  ElementDoc   {  
			
		
	
		
		
			
				
					             name : & 'static   str ,  
			
		
	
		
		
			
				
					             description : & 'static   str ,  
			
		
	
		
		
			
				
					         }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					         #[ derive(Serialize) ]  
			
		
	
		
		
			
				
					         struct  ElementData   {  
			
		
	
		
		
			
				
					             editable : bool ,  
			
		
	
		
		
			
				
					             name : & 'static   str ,  
			
		
	
		
		
			
				
					             value : serde_json ::Value ,  
			
		
	
		
		
			
				
					             default : serde_json ::Value ,  
			
		
	
		
		
			
				
					             #[ serde(rename =  " type " ) ]  
			
		
	
		
		
			
				
					             r#type : & 'static   str ,  
			
		
	
		
		
			
				
					             doc : ElementDoc ,  
			
		
	
		
		
			
				
					             overridden : bool ,  
			
		
	
		
		
			
				
					         }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					         #[ derive(Serialize) ]  
			
		
	
		
		
			
				
					         pub   struct  GroupData   {  
			
		
	
		
		
			
				
					             group : & 'static   str ,  
			
		
	
		
		
			
				
					             grouptoggle : & 'static   str ,  
			
		
	
		
		
			
				
					             groupdoc : & 'static   str ,  
			
		
	
		
		
			
				
					             elements : Vec < ElementData > ,  
			
		
	
		
		
			
				
					         }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					         #[ allow(unused) ]          #[ allow(unused) ]  
			
		
	
		
		
			
				
					         impl   Config   {          impl   Config   {  
			
		
	
		
		
			
				
					             $( $(              $( $(  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -208,11 +362,12 @@ macro_rules! make_config { 
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					             pub   fn  prepare_json ( & self )   -> serde_json ::Value   {              pub   fn  prepare_json ( & self )   -> serde_json ::Value   {  
			
		
	
		
		
			
				
					                 let   ( def ,   cfg ,   overridden )   =   {                  let   ( def ,   cfg ,   overridden )   =   {  
			
		
	
		
		
			
				
					                     // Lock the inner as short as possible and clone what is needed to prevent deadlocks
  
			
		
	
		
		
			
				
					                     let   inner   =   & self . inner . read ( ) . unwrap ( ) ;                      let   inner   =   & self . inner . read ( ) . unwrap ( ) ;  
			
		
	
		
		
			
				
					                     ( inner . _env . build ( ) ,   inner . config . clone ( ) ,   inner . _overrides . clone ( ) )                      ( inner . _env . build ( ) ,   inner . config . clone ( ) ,   inner . _overrides . clone ( ) )  
			
		
	
		
		
			
				
					                 } ;                  } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					                 fn  _get_form_type ( rust_type : & str )   -> & 'static   str   {                  fn  _get_form_type ( rust_type : & 'static   str )   -> & 'static   str   {  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                     match   rust_type   {                      match   rust_type   {  
			
		
	
		
		
			
				
					                         "Pass"   = >   "password" ,                          "Pass"   = >   "password" ,  
			
		
	
		
		
			
				
					                         "String"   = >   "text" ,                          "String"   = >   "text" ,  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -221,48 +376,36 @@ macro_rules! make_config { 
			
		
	
		
		
			
				
					                     }                      }  
			
		
	
		
		
			
				
					                 }                  }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					                 fn  _get_doc ( doc : & str )   -> serde_json ::Value   {                  fn  _get_doc ( doc_str : & 'static   str )   -> ElementDoc   {  
			
				
				
			
		
	
		
		
			
				
					
					                     let   mut   split   =   doc . split ( "|>" ) . map ( str ::trim ) ;                      let   mut   split   =   doc_str . split ( "|>" ) . map ( str ::trim ) ;  
			
				
				
			
		
	
		
		
			
				
					
					
                     ElementDoc   {  
			
				
				
			
		
	
		
		
			
				
					
					                     // We do not use the json!() macro here since that causes a lot of macro recursion.
                          name : split . next ( ) . unwrap_or_default ( ) ,  
			
				
				
			
		
	
		
		
			
				
					
					                     // This slows down compile time and it also causes issues with rust-analyzer
                          description : split . next ( ) . unwrap_or_default ( ) ,  
			
				
				
			
		
	
		
		
			
				
					
					                     serde_json ::Value ::Object ( {                      }  
			
				
				
			
		
	
		
		
			
				
					                         let   mut   doc_json   =   serde_json ::Map ::new ( ) ;  
			
		
	
		
		
			
				
					                         doc_json . insert ( "name" . into ( ) ,   serde_json ::to_value ( split . next ( ) ) . unwrap ( ) ) ;  
			
		
	
		
		
			
				
					                         doc_json . insert ( "description" . into ( ) ,   serde_json ::to_value ( split . next ( ) ) . unwrap ( ) ) ;  
			
		
	
		
		
			
				
					                         doc_json  
			
		
	
		
		
			
				
					                     } )  
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					                 }                  }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					                 // We do not use the json!() macro here since that causes a lot of macro recursion.
                  let   data : Vec < GroupData >   =   vec ! [  
			
				
				
			
		
	
		
		
			
				
					
					                 // This slows down compile time and it also causes issues with rust-analyzer
                  $(   // This repetition is for each group
  
			
				
				
			
		
	
		
		
			
				
					
					                 serde_json ::Value ::Array ( < [ _ ] > ::into_vec ( Box ::new ( [                      GroupData   {  
			
				
				
			
		
	
		
		
			
				
					
					                 $(                          group : stringify ! ( $group ) ,  
			
				
				
			
		
	
		
		
			
				
					
					                     serde_json ::Value ::Object ( {                          grouptoggle : stringify ! ( $( $group_enabled ) ? ) ,  
			
				
				
			
		
	
		
		
			
				
					
					                         let   mut   group   =   serde_json ::Map ::new ( ) ;                          groupdoc : ( make_config ! {   @ show   $( $groupdoc ) ?   } ) ,  
			
				
				
			
		
	
		
		
			
				
					                         group . insert ( "group" . into ( ) ,   ( stringify ! ( $group ) ) . into ( ) ) ;  
			
		
	
		
		
			
				
					                         group . insert ( "grouptoggle" . into ( ) ,   ( stringify ! ( $( $group_enabled ) ? ) ) . into ( ) ) ;  
			
		
	
		
		
			
				
					                         group . insert ( "groupdoc" . into ( ) ,   ( make_config ! {   @ show   $( $groupdoc ) ?   } ) . into ( ) ) ;  
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					                         group . insert ( "elements" . into ( ) ,   serde_json ::Value ::Array ( < [ _ ] > ::into_vec ( Box ::new ( [                          elements : vec ! [  
			
				
				
			
		
	
		
		
			
				
					
					                         $(                          $(   // This repetition is for each element within a group
  
			
				
				
			
		
	
		
		
			
				
					
					                             serde_json ::Value ::Object ( {                              ElementData   {  
			
				
				
			
		
	
		
		
			
				
					
					                                 let   mut   element   =   serde_json ::Map ::new ( ) ;                                  editable : $editable ,  
			
				
				
			
		
	
		
		
			
				
					
					                                 element . insert ( "editable" . into ( ) ,   ( $editable ) . into ( ) ) ;                                  name : stringify ! ( $name ) ,  
			
				
				
			
		
	
		
		
			
				
					
					                                 element . insert ( "name" . into ( ) ,   ( stringify ! ( $name ) ) . into ( ) ) ;                                  value : serde_json ::to_value ( & cfg . $name ) . unwrap_or_default ( ) ,  
			
				
				
			
		
	
		
		
			
				
					
					                                 element . insert ( "value" . into ( ) ,   serde_json ::to_value ( cfg . $name ) . unwrap ( ) ) ;                                  default : serde_json ::to_value ( & def . $name ) . unwrap_or_default ( ) ,  
			
				
				
			
		
	
		
		
			
				
					
					                                 element . insert ( "default" . into ( ) ,   serde_json ::to_value ( def . $name ) . unwrap ( ) ) ;                                  r#type : _get_form_type ( stringify ! ( $ty ) ) ,  
			
				
				
			
		
	
		
		
			
				
					
					                                 element . insert ( "type" . into ( ) ,   ( _get_form_type ( stringify ! ( $ty ) ) ) . into ( ) ) ;                                  doc : _get_doc ( concat ! ( $( $doc ) , + ) ) ,  
			
				
				
			
		
	
		
		
			
				
					
					                                 element . insert ( "doc" . into ( ) ,   ( _get_doc ( concat ! ( $( $doc ) , + ) ) ) . into ( ) ) ;                                  overridden : overridden . contains ( & pastey ::paste ! ( stringify ! ( [ < $name :upper > ] ) ) ) ,  
			
				
				
			
		
	
		
		
			
				
					
					                                 element . insert ( "overridden" . into ( ) ,   ( overridden . contains ( & pastey ::paste ! ( stringify ! ( [ < $name :upper > ] ) ) . into ( ) ) ) . into ( ) ) ;                              } ,  
			
				
				
			
		
	
		
		
			
				
					
					                                 element                          ) + ] ,   // End of elements repetition
  
			
				
				
			
		
	
		
		
			
				
					
					                             } ) ,                      } ,  
			
				
				
			
		
	
		
		
			
				
					
					                         ) +                  ) + ] ;   // End of groups repetition
  
			
				
				
			
		
	
		
		
			
				
					
					                         ] ) ) ) ) ;                  serde_json ::to_value ( data ) . unwrap ( )  
			
				
				
			
		
	
		
		
			
				
					                         group  
			
		
	
		
		
			
				
					                     } ) ,  
			
		
	
		
		
			
				
					                 ) +  
			
		
	
		
		
			
				
					                 ] ) ) )  
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					             }              }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					             pub   fn  get_support_json ( & self )   -> serde_json ::Value   {              pub   fn  get_support_json ( & self )   -> serde_json ::Value   {  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -270,8 +413,8 @@ macro_rules! make_config { 
			
		
	
		
		
			
				
					                 // Pass types will always be masked and no need to put them in the list.
                  // Pass types will always be masked and no need to put them in the list.
  
			
		
	
		
		
			
				
					                 // Besides Pass, only String types will be masked via _privacy_mask.
                  // Besides Pass, only String types will be masked via _privacy_mask.
  
			
		
	
		
		
			
				
					                 const   PRIVACY_CONFIG : & [ & str ]   =   & [                  const   PRIVACY_CONFIG : & [ & str ]   =   & [  
			
		
	
		
		
			
				
					                     "allowed_iframe_ancestors" ,  
			
		
	
		
		
			
				
					                     "allowed_connect_src" ,                      "allowed_connect_src" ,  
			
		
	
		
		
			
				
					                     "allowed_iframe_ancestors" ,  
			
		
	
		
		
			
				
					                     "database_url" ,                      "database_url" ,  
			
		
	
		
		
			
				
					                     "domain_origin" ,                      "domain_origin" ,  
			
		
	
		
		
			
				
					                     "domain_path" ,                      "domain_path" ,  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -279,16 +422,18 @@ macro_rules! make_config { 
			
		
	
		
		
			
				
					                     "helo_name" ,                      "helo_name" ,  
			
		
	
		
		
			
				
					                     "org_creation_users" ,                      "org_creation_users" ,  
			
		
	
		
		
			
				
					                     "signups_domains_whitelist" ,                      "signups_domains_whitelist" ,  
			
		
	
		
		
			
				
					                     "_smtp_img_src" ,  
			
		
	
		
		
			
				
					                     "smtp_from_name" ,  
			
		
	
		
		
			
				
					                     "smtp_from" ,                      "smtp_from" ,  
			
		
	
		
		
			
				
					                     "smtp_host" ,                      "smtp_host" ,  
			
		
	
		
		
			
				
					                     "smtp_username" ,                      "smtp_username" ,  
			
		
	
		
		
			
				
					                     "_smtp_img_src" ,  
			
		
	
		
		
			
				
					                     "sso_client_id" ,  
			
		
	
		
		
			
				
					                     "sso_authority" ,                      "sso_authority" ,  
			
		
	
		
		
			
				
					                     "sso_callback_path" ,                      "sso_callback_path" ,  
			
		
	
		
		
			
				
					                     "sso_client_id" ,  
			
		
	
		
		
			
				
					                 ] ;                  ] ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					                 let   cfg   =   {                  let   cfg   =   {  
			
		
	
		
		
			
				
					                     // Lock the inner as short as possible and clone what is needed to prevent deadlocks
  
			
		
	
		
		
			
				
					                     let   inner   =   & self . inner . read ( ) . unwrap ( ) ;                      let   inner   =   & self . inner . read ( ) . unwrap ( ) ;  
			
		
	
		
		
			
				
					                     inner . config . clone ( )                      inner . config . clone ( )  
			
		
	
		
		
			
				
					                 } ;                  } ;  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -318,13 +463,21 @@ macro_rules! make_config { 
			
		
	
		
		
			
				
					                 serde_json ::Value ::Object ( {                  serde_json ::Value ::Object ( {  
			
		
	
		
		
			
				
					                     let   mut   json   =   serde_json ::Map ::new ( ) ;                      let   mut   json   =   serde_json ::Map ::new ( ) ;  
			
		
	
		
		
			
				
					                     $( $(                      $( $(  
			
		
	
		
		
			
				
					
					                         json . insert ( stringify ! ( $name ) . into ( ) ,   make_config ! {   @ supportstr   $name ,   cfg . $name ,   $ty ,   $none_action   } ) ;                          json . insert ( String ::from ( stringify ! ( $name ) ) ,   make_config ! {   @ supportstr   $name ,   cfg . $name ,   $ty ,   $none_action   } ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                     ) + ) + ;                      ) + ) + ;  
			
		
	
		
		
			
				
					                     // Loop through all privacy sensitive keys and mask them
  
			
		
	
		
		
			
				
					                     for   mask_key   in   PRIVACY_CONFIG   {  
			
		
	
		
		
			
				
					                         if   let   Some ( value )   =   json . get_mut ( * mask_key )   {  
			
		
	
		
		
			
				
					                             if   let   Some ( s )   =   value . as_str ( )   {  
			
		
	
		
		
			
				
					                                 * value   =   _privacy_mask ( s ) . into ( ) ;  
			
		
	
		
		
			
				
					                             }  
			
		
	
		
		
			
				
					                         }  
			
		
	
		
		
			
				
					                     }  
			
		
	
		
		
			
				
					                     json                      json  
			
		
	
		
		
			
				
					                 } )                  } )  
			
		
	
		
		
			
				
					             }              }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					             pub   fn  get_overrides ( & self )   -> Vec < String >   {              pub   fn  get_overrides ( & self )   -> Vec < & 'static   str >   {  
			
				
				
			
		
	
		
		
	
		
		
			
				
					                 let   overrides   =   {                  let   overrides   =   {  
			
		
	
		
		
			
				
					                     let   inner   =   & self . inner . read ( ) . unwrap ( ) ;                      let   inner   =   & self . inner . read ( ) . unwrap ( ) ;  
			
		
	
		
		
			
				
					                     inner . _overrides . clone ( )                      inner . _overrides . clone ( )  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -333,55 +486,6 @@ macro_rules! make_config { 
			
		
	
		
		
			
				
					             }              }  
			
		
	
		
		
			
				
					         }          }  
			
		
	
		
		
			
				
					     } ;      } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					     // Support string print
  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   Pass ,   option   )   = >   {   serde_json ::to_value ( $value . as_ref ( ) . map ( | _ |   String ::from ( "***" ) ) ) . unwrap ( )   } ;   // Optional pass, we map to an Option<String> with "***"
  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   Pass ,   $none_action :ident   )   = >   {   "***" . into ( )   } ;   // Required pass, we return "***"
  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   String ,   option   )   = >   {   // Optional other value, we return as is or convert to string to apply the privacy config
  
			
		
	
		
		
			
				
					         if   PRIVACY_CONFIG . contains ( & stringify ! ( $name ) )   {  
			
		
	
		
		
			
				
					             serde_json ::to_value ( $value . as_ref ( ) . map ( | x |   _privacy_mask ( x )   ) ) . unwrap ( )  
			
		
	
		
		
			
				
					         }   else   {  
			
		
	
		
		
			
				
					             serde_json ::to_value ( $value ) . unwrap ( )  
			
		
	
		
		
			
				
					         }  
			
		
	
		
		
			
				
					     } ;  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   String ,   $none_action :ident   )   = >   {   // Required other value, we return as is or convert to string to apply the privacy config
  
			
		
	
		
		
			
				
					         if   PRIVACY_CONFIG . contains ( & stringify ! ( $name ) )   {  
			
		
	
		
		
			
				
					             _privacy_mask ( & $value ) . into ( )  
			
		
	
		
		
			
				
					         }   else   {  
			
		
	
		
		
			
				
					             ( $value ) . into ( )  
			
		
	
		
		
			
				
					         }  
			
		
	
		
		
			
				
					     } ;  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   $ty :ty ,   option   )   = >   {   serde_json ::to_value ( $value ) . unwrap ( )   } ;   // Optional other value, we return as is or convert to string to apply the privacy config
  
			
		
	
		
		
			
				
					     (   @ supportstr   $name :ident ,   $value :expr ,   $ty :ty ,   $none_action :ident   )   = >   {   ( $value ) . into ( )   } ;   // Required other value, we return as is or convert to string to apply the privacy config
  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					     // Group or empty string
  
			
		
	
		
		
			
				
					     (   @ show   )   = >   {   ""   } ;  
			
		
	
		
		
			
				
					     (   @ show   $lit :literal   )   = >   {   $lit   } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					     // Wrap the optionals in an Option type
  
			
		
	
		
		
			
				
					     (   @ type  $ty :ty ,   option )   = >   {   Option < $ty >   } ;  
			
		
	
		
		
			
				
					     (   @ type  $ty :ty ,   $id :ident )   = >   {   $ty   } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					     // Generate the values depending on none_action
  
			
		
	
		
		
			
				
					     (   @ build   $value :expr ,   $config :expr ,   option ,   )   = >   {   $value   } ;  
			
		
	
		
		
			
				
					     (   @ build   $value :expr ,   $config :expr ,   def ,   $default :expr   )   = >   {   $value . unwrap_or ( $default )   } ;  
			
		
	
		
		
			
				
					     (   @ build   $value :expr ,   $config :expr ,   auto ,   $default_fn :expr   )   = >   { {  
			
		
	
		
		
			
				
					         match   $value   {  
			
		
	
		
		
			
				
					             Some ( v )   = >   v ,  
			
		
	
		
		
			
				
					             None   = >   {  
			
		
	
		
		
			
				
					                 let   f : & dyn   Fn ( & ConfigItems )   -> _   =   & $default_fn ;  
			
		
	
		
		
			
				
					                 f ( $config )  
			
		
	
		
		
			
				
					             }  
			
		
	
		
		
			
				
					         }  
			
		
	
		
		
			
				
					     } } ;  
			
		
	
		
		
			
				
					     (   @ build   $value :expr ,   $config :expr ,   generated ,   $default_fn :expr   )   = >   { {  
			
		
	
		
		
			
				
					         let   f : & dyn   Fn ( & ConfigItems )   -> _   =   & $default_fn ;  
			
		
	
		
		
			
				
					         f ( $config )  
			
		
	
		
		
			
				
					     } } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					     (   @ getenv   $name :expr ,   bool   )   = >   {   get_env_bool ( $name )   } ;  
			
		
	
		
		
			
				
					     (   @ getenv   $name :expr ,   $ty :ident   )   = >   {   get_env ( $name )   } ;  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					} }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					//STRUCTURE:
 //STRUCTURE:
  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -1512,7 +1616,7 @@ impl Config { 
			
		
	
		
		
			
				
					         if   let   Some ( akey )   =   self . _duo_akey ( )   {          if   let   Some ( akey )   =   self . _duo_akey ( )   {  
			
		
	
		
		
			
				
					             akey              akey  
			
		
	
		
		
			
				
					         }   else   {          }   else   {  
			
		
	
		
		
			
				
					
					             let   akey_s   =   crate ::crypto ::encode_random_bytes ::< 64 > ( data_encoding ::BASE64 ) ;              let   akey_s   =   crate ::crypto ::encode_random_bytes ::< 64 > ( & data_encoding ::BASE64 ) ;  
			
				
				
			
		
	
		
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					             // Save the new value
              // Save the new value
  
			
		
	
		
		
			
				
					             let   builder   =   ConfigBuilder   {              let   builder   =   ConfigBuilder   {  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -1536,7 +1640,7 @@ impl Config { 
			
		
	
		
		
			
				
					         token . is_some ( )   & &   ! token . unwrap ( ) . trim ( ) . is_empty ( )          token . is_some ( )   & &   ! token . unwrap ( ) . trim ( ) . is_empty ( )  
			
		
	
		
		
			
				
					     }      }  
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					
					     pub   fn  opendal_operator_for_path_type ( & self ,   path_type : PathType )   -> Result < opendal ::Operator ,   Error >   {      pub   fn  opendal_operator_for_path_type ( & self ,   path_type : & PathType )   -> Result < opendal ::Operator ,   Error >   {  
			
				
				
			
		
	
		
		
	
		
		
			
				
					         let   path   =   match   path_type   {          let   path   =   match   path_type   {  
			
		
	
		
		
			
				
					             PathType ::Data   = >   self . data_folder ( ) ,              PathType ::Data   = >   self . data_folder ( ) ,  
			
		
	
		
		
			
				
					             PathType ::IconCache   = >   self . icon_cache_folder ( ) ,              PathType ::IconCache   = >   self . icon_cache_folder ( ) ,  
			
		
	
	
		
		
			
				
					
						
							
								 
						
						
							
								 
						
						
					 
					@ -1729,7 +1833,7 @@ fn to_json<'reg, 'rc>( 
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					// Configure the web-vault version as an integer so it can be used as a comparison smaller or greater then.
 // Configure the web-vault version as an integer so it can be used as a comparison smaller or greater then.
  
			
		
	
		
		
			
				
					// The default is based upon the version since this feature is added.
 // The default is based upon the version since this feature is added.
  
			
		
	
		
		
			
				
					
					static   WEB_VAULT_VERSION : Lazy < semver ::Version >   =   Lazy ::new ( | |   { static   WEB_VAULT_VERSION : LazyLock  < semver ::Version >   =   LazyLock  ::new ( | |   {  
			
				
				
			
		
	
		
		
	
		
		
			
				
					     let   vault_version   =   get_web_vault_version ( ) ;      let   vault_version   =   get_web_vault_version ( ) ;  
			
		
	
		
		
			
				
					     // Use a single regex capture to extract version components
      // Use a single regex capture to extract version components
  
			
		
	
		
		
			
				
					     let   re   =   regex ::Regex ::new ( r"(\d{4})\.(\d{1,2})\.(\d{1,2})" ) . unwrap ( ) ;      let   re   =   regex ::Regex ::new ( r"(\d{4})\.(\d{1,2})\.(\d{1,2})" ) . unwrap ( ) ;  
			
		
	
	
		
		
			
				
					
						
						
						
							
								 
						
					 
					@ -1745,7 +1849,7 @@ static WEB_VAULT_VERSION: Lazy<semver::Version> = Lazy::new(|| { 
			
		
	
		
		
			
				
					
 
			
		
	
		
		
			
				
					// Configure the Vaultwarden version as an integer so it can be used as a comparison smaller or greater then.
 // Configure the Vaultwarden version as an integer so it can be used as a comparison smaller or greater then.
  
			
		
	
		
		
			
				
					// The default is based upon the version since this feature is added.
 // The default is based upon the version since this feature is added.
  
			
		
	
		
		
			
				
					
					static   VW_VERSION : Lazy < semver ::Version >   =   Lazy ::new ( | |   { static   VW_VERSION : LazyLock  < semver ::Version >   =   LazyLock  ::new ( | |   {  
			
				
				
			
		
	
		
		
	
		
		
			
				
					     let   vw_version   =   crate ::VERSION . unwrap_or ( "1.32.5" ) ;      let   vw_version   =   crate ::VERSION . unwrap_or ( "1.32.5" ) ;  
			
		
	
		
		
			
				
					     // Use a single regex capture to extract version components
      // Use a single regex capture to extract version components
  
			
		
	
		
		
			
				
					     let   re   =   regex ::Regex ::new ( r"(\d{1})\.(\d{1,2})\.(\d{1,2})" ) . unwrap ( ) ;      let   re   =   regex ::Regex ::new ( r"(\d{1})\.(\d{1,2})\.(\d{1,2})" ) . unwrap ( ) ;