All checks were successful
		
		
	
	continuous-integration/drone/push Build is passing
				
			
		
			
				
	
	
		
			152 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use std::path::{Path, PathBuf};
 | |
| 
 | |
| use clap::Parser;
 | |
| 
 | |
| use crate::constants::{
 | |
|     APP_NAME, CLIENTS_LIST_FILE, OIDC_PROVIDER_CB_URI, PROVIDERS_LIST_FILE, USERS_LIST_FILE,
 | |
| };
 | |
| 
 | |
| /// Action logger format
 | |
| #[derive(Copy, Clone, Eq, PartialEq, Debug, clap::ValueEnum, Default)]
 | |
| pub enum ActionLoggerFormat {
 | |
|     #[default]
 | |
|     Text,
 | |
|     Json,
 | |
|     None,
 | |
| }
 | |
| 
 | |
| /// Basic OIDC provider
 | |
| #[derive(Parser, Debug, Clone)]
 | |
| #[clap(author, version, about, long_about = None)]
 | |
| pub struct AppConfig {
 | |
|     /// Listen address
 | |
|     #[clap(short, long, env, default_value = "0.0.0.0:8000")]
 | |
|     pub listen_address: String,
 | |
| 
 | |
|     /// Storage path
 | |
|     #[clap(short, long, env)]
 | |
|     pub storage_path: String,
 | |
| 
 | |
|     /// Overwrite clients list file path, if the file is not to be found in storage path
 | |
|     #[clap(long, env)]
 | |
|     pub clients_list_file_path: Option<String>,
 | |
| 
 | |
|     /// Overwrite providers list file path, if the file is not to be found in storage path
 | |
|     #[clap(long, env)]
 | |
|     pub providers_list_file_path: Option<String>,
 | |
| 
 | |
|     /// App token token
 | |
|     #[clap(short, long, env, default_value = "")]
 | |
|     pub token_key: String,
 | |
| 
 | |
|     /// Website origin
 | |
|     #[clap(short, long, env, default_value = "http://localhost:8000")]
 | |
|     pub website_origin: String,
 | |
| 
 | |
|     /// Proxy IP, might end with a star "*"
 | |
|     #[clap(short, long, env)]
 | |
|     pub proxy_ip: Option<String>,
 | |
| 
 | |
|     /// IP location service API
 | |
|     ///
 | |
|     /// Operating instance of IP location service : https://gitlab.com/pierre42100/iplocationserver
 | |
|     ///
 | |
|     /// Example: "https://api.geoip.rs"
 | |
|     #[arg(long, short, env)]
 | |
|     pub ip_location_service: Option<String>,
 | |
| 
 | |
|     /// Action logger output format
 | |
|     #[arg(long, env, default_value_t, value_enum)]
 | |
|     pub action_logger_format: ActionLoggerFormat,
 | |
| 
 | |
|     /// Login background image
 | |
|     #[arg(long, env, default_value = "/assets/img/forest.jpg")]
 | |
|     pub login_background_image: String,
 | |
| 
 | |
|     /// Disable local login. If this option is set without any upstream providers set, it will be impossible
 | |
|     /// to authenticate
 | |
|     #[arg(long, env)]
 | |
|     pub disable_local_login: bool,
 | |
| }
 | |
| 
 | |
| lazy_static::lazy_static! {
 | |
|     static ref ARGS: AppConfig = {
 | |
|         let mut config = AppConfig::parse();
 | |
| 
 | |
|         // In debug mode only, use dummy token
 | |
|         if cfg!(debug_assertions) && config.token_key.is_empty() {
 | |
|             config.token_key = String::from_utf8_lossy(&[32; 64]).to_string();
 | |
|         }
 | |
| 
 | |
|         config
 | |
|     };
 | |
| }
 | |
| 
 | |
| impl AppConfig {
 | |
|     /// Get parsed command line arguments
 | |
|     pub fn get() -> &'static AppConfig {
 | |
|         &ARGS
 | |
|     }
 | |
| 
 | |
|     pub fn secure_cookie(&self) -> bool {
 | |
|         self.website_origin.starts_with("https:")
 | |
|     }
 | |
| 
 | |
|     pub fn storage_path(&self) -> &Path {
 | |
|         self.storage_path.as_ref()
 | |
|     }
 | |
| 
 | |
|     pub fn users_file(&self) -> PathBuf {
 | |
|         self.storage_path().join(USERS_LIST_FILE)
 | |
|     }
 | |
| 
 | |
|     pub fn clients_file(&self) -> PathBuf {
 | |
|         match &self.clients_list_file_path {
 | |
|             None => self.storage_path().join(CLIENTS_LIST_FILE),
 | |
|             Some(p) => Path::new(p).to_path_buf(),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn providers_file(&self) -> PathBuf {
 | |
|         match &self.providers_list_file_path {
 | |
|             None => self.storage_path().join(PROVIDERS_LIST_FILE),
 | |
|             Some(p) => Path::new(p).to_path_buf(),
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn full_url(&self, uri: &str) -> String {
 | |
|         if uri.starts_with('/') {
 | |
|             format!("{}{}", self.website_origin, uri)
 | |
|         } else {
 | |
|             format!("{}/{}", self.website_origin, uri)
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /// Get the URL where a upstream OpenID provider should redirect
 | |
|     /// the user after an authentication
 | |
|     pub fn oidc_provider_redirect_url(&self) -> String {
 | |
|         AppConfig::get().full_url(OIDC_PROVIDER_CB_URI)
 | |
|     }
 | |
| 
 | |
|     pub fn domain_name(&self) -> &str {
 | |
|         self.website_origin.split('/').nth(2).unwrap_or(APP_NAME)
 | |
|     }
 | |
| 
 | |
|     /// Get the domain without the port
 | |
|     pub fn domain_name_without_port(&self) -> &str {
 | |
|         let domain = self.domain_name();
 | |
|         domain.split_once(':').map(|i| i.0).unwrap_or(domain)
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[cfg(test)]
 | |
| mod test {
 | |
|     use crate::data::app_config::AppConfig;
 | |
| 
 | |
|     #[test]
 | |
|     fn verify_cli() {
 | |
|         use clap::CommandFactory;
 | |
|         AppConfig::command().debug_assert()
 | |
|     }
 | |
| }
 |