use crate::users::{APITokenID, UserEmail}; use crate::utils::crypt_utils::sha256str; use clap::Parser; use std::path::{Path, PathBuf}; /// Matrix gateway backend API #[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, /// Website origin #[clap(short, long, env, default_value = "http://localhost:5173")] pub website_origin: String, /// Proxy IP, might end with a star "*" #[clap(short, long, env)] pub proxy_ip: Option, /// Unsecure : for development, bypass authentication, using the account with the given /// email address by default #[clap(long, env)] unsecure_auto_login_email: Option, /// Secret key, used to secure some resources. Must be randomly generated #[clap(short = 'S', long, env, default_value = "")] secret: String, /// Matrix homeserver origin #[clap(short, long, env, default_value = "http://127.0.0.1:8448")] pub matrix_homeserver: String, /// Redis connection hostname #[clap(long, env, default_value = "localhost")] redis_hostname: String, /// Redis connection port #[clap(long, env, default_value_t = 6379)] redis_port: u16, /// Redis database number #[clap(long, env, default_value_t = 0)] redis_db_number: i64, /// Redis username #[clap(long, env)] redis_username: Option, /// Redis password #[clap(long, env, default_value = "secretredis")] redis_password: String, /// URL where the OpenID configuration can be found #[arg( long, env, default_value = "http://localhost:9001/dex/.well-known/openid-configuration" )] pub oidc_configuration_url: String, /// OpenID provider name #[arg(long, env, default_value = "3rd party provider")] pub oidc_provider_name: String, /// OpenID client ID #[arg(long, env, default_value = "foo")] pub oidc_client_id: String, /// OpenID client secret #[arg(long, env, default_value = "bar")] pub oidc_client_secret: String, /// OpenID login redirect URL #[arg(long, env, default_value = "APP_ORIGIN/oidc_cb")] oidc_redirect_url: String, /// Application storage path #[arg(long, env, default_value = "app_storage")] storage_path: String, } lazy_static::lazy_static! { static ref ARGS: AppConfig = { AppConfig::parse() }; } impl AppConfig { /// Get parsed command line arguments pub fn get() -> &'static AppConfig { &ARGS } /// Get auto login email (if not empty) pub fn unsecure_auto_login_email(&self) -> Option { match self.unsecure_auto_login_email.as_deref() { None | Some("") => None, Some(s) => Some(UserEmail(s.to_owned())), } } /// Get app secret pub fn secret(&self) -> &str { let mut secret = self.secret.as_str(); if cfg!(debug_assertions) && secret.is_empty() { secret = "DEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEYDEBUGKEY"; } if secret.is_empty() { panic!("SECRET is undefined or too short (min 64 chars)!") } secret } /// Check if auth is disabled pub fn is_auth_disabled(&self) -> bool { self.unsecure_auto_login_email().is_some() } /// Get Redis connection configuration pub fn redis_connection_string(&self) -> String { format!( "redis://{}:{}@{}:{}/{}", self.redis_username.as_deref().unwrap_or(""), self.redis_password, self.redis_hostname, self.redis_port, self.redis_db_number ) } /// Get OpenID providers configuration pub fn openid_provider(&self) -> OIDCProvider<'_> { OIDCProvider { client_id: self.oidc_client_id.as_str(), client_secret: self.oidc_client_secret.as_str(), configuration_url: self.oidc_configuration_url.as_str(), name: self.oidc_provider_name.as_str(), redirect_url: self .oidc_redirect_url .replace("APP_ORIGIN", &self.website_origin), } } /// Get storage path pub fn storage_path(&self) -> &Path { Path::new(self.storage_path.as_str()) } /// User storage directory pub fn user_directory(&self, mail: &UserEmail) -> PathBuf { self.storage_path().join("users").join(sha256str(&mail.0)) } /// User metadata file pub fn user_metadata_file_path(&self, mail: &UserEmail) -> PathBuf { self.user_directory(mail).join("metadata.json") } /// User API tokens directory pub fn user_api_token_directory(&self, mail: &UserEmail) -> PathBuf { self.user_directory(mail).join("api-tokens") } /// User API token metadata file pub fn user_api_token_metadata_file(&self, mail: &UserEmail, id: &APITokenID) -> PathBuf { self.user_api_token_directory(mail).join(id.0.to_string()) } } #[derive(Debug, Clone, serde::Serialize)] pub struct OIDCProvider<'a> { pub name: &'a str, pub client_id: &'a str, pub client_secret: &'a str, pub configuration_url: &'a str, pub redirect_url: String, } #[cfg(test)] mod test { use crate::app_config::AppConfig; #[test] fn verify_cli() { use clap::CommandFactory; AppConfig::command().debug_assert() } }