Skip to content
Snippets Groups Projects
mod.rs 33.5 KiB
Newer Older
  • Learn to ignore specific revisions
  • Jonas Platte's avatar
    Jonas Platte committed
    use std::{
    
    🥺's avatar
    🥺 committed
    	collections::BTreeMap,
    
    	net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
    
    	path::PathBuf,
    
    Jonas Platte's avatar
    Jonas Platte committed
    };
    
    Jason Volk's avatar
    Jason Volk committed
    use either::{
    	Either,
    	Either::{Left, Right},
    };
    
    use figment::providers::{Env, Format, Toml};
    pub use figment::{value::Value as FigmentValue, Figment};
    
    use itertools::Itertools;
    use regex::RegexSet;
    
    use ruma::{
    	api::client::discovery::discover_support::ContactRole, OwnedRoomId, OwnedServerName, OwnedUserId, RoomVersionId,
    };
    
    🥺's avatar
    🥺 committed
    use serde::{de::IgnoredAny, Deserialize};
    
    Jason Volk's avatar
    Jason Volk committed
    pub use self::check::check;
    use self::proxy::ProxyConfig;
    
    use crate::{error::Error, Err, Result};
    
    Jason Volk's avatar
    Jason Volk committed
    pub mod check;
    pub mod proxy;
    
    /// all the config options for conduwuit
    
    #[derive(Clone, Debug, Deserialize)]
    
    #[allow(clippy::struct_excessive_bools)]
    
    Jason Volk's avatar
    Jason Volk committed
    pub struct Config {
    
    	/// [`IpAddr`] conduwuit will listen on (can be IPv4 or IPv6)
    	#[serde(default = "default_address")]
    
    	/// default TCP port(s) conduwuit will listen on
    	#[serde(default = "default_port")]
    
    	port: ListeningPort,
    
    Jason Volk's avatar
    Jason Volk committed
    	pub tls: Option<TlsConfig>,
    	pub unix_socket_path: Option<PathBuf>,
    
    	#[serde(default = "default_unix_socket_perms")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub unix_socket_perms: u32,
    	pub server_name: OwnedServerName,
    
    	#[serde(default = "default_database_backend")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub database_backend: String,
    	pub database_path: PathBuf,
    	pub database_backup_path: Option<PathBuf>,
    
    	#[serde(default = "default_database_backups_to_keep")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub database_backups_to_keep: i16,
    
    	#[serde(default = "default_db_cache_capacity_mb")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub db_cache_capacity_mb: f64,
    
    	#[serde(default = "default_new_user_displayname_suffix")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub new_user_displayname_suffix: String,
    
    🥺's avatar
    🥺 committed
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_check_for_updates: bool,
    
    	#[serde(default = "default_pdu_cache_capacity")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub pdu_cache_capacity: u32,
    
    	#[serde(default = "default_cache_capacity_modifier", alias = "conduit_cache_capacity_modifier")]
    	pub cache_capacity_modifier: f64,
    
    	#[serde(default = "default_auth_chain_cache_capacity")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub auth_chain_cache_capacity: u32,
    
    	#[serde(default = "default_shorteventid_cache_capacity")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub shorteventid_cache_capacity: u32,
    
    	#[serde(default = "default_eventidshort_cache_capacity")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub eventidshort_cache_capacity: u32,
    
    	#[serde(default = "default_shortstatekey_cache_capacity")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub shortstatekey_cache_capacity: u32,
    
    	#[serde(default = "default_statekeyshort_cache_capacity")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub statekeyshort_cache_capacity: u32,
    
    	#[serde(default = "default_server_visibility_cache_capacity")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub server_visibility_cache_capacity: u32,
    
    	#[serde(default = "default_user_visibility_cache_capacity")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub user_visibility_cache_capacity: u32,
    
    	#[serde(default = "default_stateinfo_cache_capacity")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub stateinfo_cache_capacity: u32,
    
    	#[serde(default = "default_roomid_spacehierarchy_cache_capacity")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub roomid_spacehierarchy_cache_capacity: u32,
    
    	#[serde(default = "default_dns_cache_entries")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub dns_cache_entries: u32,
    
    	#[serde(default = "default_dns_min_ttl")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub dns_min_ttl: u64,
    
    	#[serde(default = "default_dns_min_ttl_nxdomain")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub dns_min_ttl_nxdomain: u64,
    
    	#[serde(default = "default_dns_attempts")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub dns_attempts: u16,
    
    	#[serde(default = "default_dns_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub dns_timeout: u64,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub dns_tcp_fallback: bool,
    
    🥺's avatar
    🥺 committed
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub query_all_nameservers: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub query_over_tcp_only: bool,
    
    	#[serde(default = "default_ip_lookup_strategy")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub ip_lookup_strategy: u8,
    
    	#[serde(default = "default_max_request_size")]
    
    	pub max_request_size: usize,
    
    	#[serde(default = "default_max_fetch_prev_events")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub max_fetch_prev_events: u16,
    
    	#[serde(default = "default_request_conn_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub request_conn_timeout: u64,
    
    	#[serde(default = "default_request_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub request_timeout: u64,
    
    	#[serde(default = "default_request_total_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub request_total_timeout: u64,
    
    	#[serde(default = "default_request_idle_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub request_idle_timeout: u64,
    
    	#[serde(default = "default_request_idle_per_host")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub request_idle_per_host: u16,
    
    	#[serde(default = "default_well_known_conn_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub well_known_conn_timeout: u64,
    
    	#[serde(default = "default_well_known_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub well_known_timeout: u64,
    
    	#[serde(default = "default_federation_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub federation_timeout: u64,
    
    	#[serde(default = "default_federation_idle_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub federation_idle_timeout: u64,
    
    	#[serde(default = "default_federation_idle_per_host")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub federation_idle_per_host: u16,
    
    	#[serde(default = "default_sender_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub sender_timeout: u64,
    
    	#[serde(default = "default_sender_idle_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub sender_idle_timeout: u64,
    
    	#[serde(default = "default_sender_retry_backoff_limit")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub sender_retry_backoff_limit: u64,
    
    	#[serde(default = "default_appservice_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub appservice_timeout: u64,
    
    	#[serde(default = "default_appservice_idle_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub appservice_idle_timeout: u64,
    
    	#[serde(default = "default_pusher_idle_timeout")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub pusher_idle_timeout: u64,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_registration: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub yes_i_am_very_very_sure_i_want_an_open_registration_server_prone_to_abuse: bool,
    	pub registration_token: Option<String>,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_encryption: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_federation: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_public_room_directory_over_federation: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_public_room_directory_without_auth: bool,
    
    	#[serde(default)]
    
    	pub turn_allow_guests: bool,
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub lockdown_public_room_directory: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_device_name_federation: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_profile_lookup_federation_requests: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_room_creation: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_unstable_room_versions: bool,
    
    	#[serde(default = "default_default_room_version")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub default_room_version: RoomVersionId,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub well_known: WellKnownConfig,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_jaeger: bool,
    
    	#[serde(default = "default_jaeger_filter")]
    	pub jaeger_filter: String,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub tracing_flame: bool,
    
    	#[serde(default = "default_tracing_flame_filter")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub tracing_flame_filter: String,
    
    	#[serde(default = "default_tracing_flame_output_path")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub tracing_flame_output_path: String,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub proxy: ProxyConfig,
    	pub jwt_secret: Option<String>,
    
    	#[serde(default = "default_trusted_servers")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub trusted_servers: Vec<OwnedServerName>,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub query_trusted_key_servers_first: bool,
    
    	#[serde(default = "default_log")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub log: String,
    
    	#[serde(default = "default_openid_token_ttl")]
    	pub openid_token_ttl: u64,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub turn_username: String,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub turn_password: String,
    
    	#[serde(default = "Vec::new")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub turn_uris: Vec<String>,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub turn_secret: String,
    
    	#[serde(default = "default_turn_ttl")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub turn_ttl: u64,
    
    	#[serde(default = "Vec::new")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub auto_join_rooms: Vec<OwnedRoomId>,
    
    Jason Volk's avatar
    Jason Volk committed
    	pub auto_deactivate_banned_room_attempts: bool,
    
    	#[serde(default = "default_rocksdb_log_level")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_log_level: String,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_log_stderr: bool,
    
    	#[serde(default = "default_rocksdb_max_log_file_size")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_max_log_file_size: usize,
    
    	#[serde(default = "default_rocksdb_log_time_to_roll")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_log_time_to_roll: usize,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_optimize_for_spinning_disks: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_direct_io: bool,
    
    	#[serde(default = "default_rocksdb_parallelism_threads")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_parallelism_threads: usize,
    
    	#[serde(default = "default_rocksdb_max_log_files")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_max_log_files: usize,
    
    	#[serde(default = "default_rocksdb_compression_algo")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_compression_algo: String,
    
    	#[serde(default = "default_rocksdb_compression_level")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_compression_level: i32,
    
    	#[serde(default = "default_rocksdb_bottommost_compression_level")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_bottommost_compression_level: i32,
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_bottommost_compression: bool,
    
    	#[serde(default = "default_rocksdb_recovery_mode")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_recovery_mode: u8,
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_repair: bool,
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_read_only: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_compaction_prio_idle: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub rocksdb_compaction_ioprio_idle: bool,
    
    	#[serde(default = "true_fn")]
    	pub rocksdb_compaction: bool,
    
    	#[serde(default = "default_rocksdb_stats_level")]
    	pub rocksdb_stats_level: u8,
    
    Jason Volk's avatar
    Jason Volk committed
    	pub emergency_password: Option<String>,
    
    
    	#[serde(default = "default_notification_push_path")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub notification_push_path: String,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_local_presence: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_incoming_presence: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_outgoing_presence: bool,
    
    	#[serde(default = "default_presence_idle_timeout_s")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub presence_idle_timeout_s: u64,
    
    	#[serde(default = "default_presence_offline_timeout_s")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub presence_offline_timeout_s: u64,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub presence_timeout_remote_users: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_incoming_read_receipts: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_outgoing_read_receipts: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_outgoing_typing: bool,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_incoming_typing: bool,
    
    	#[serde(default = "default_typing_federation_timeout_s")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub typing_federation_timeout_s: u64,
    
    	#[serde(default = "default_typing_client_timeout_min_s")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub typing_client_timeout_min_s: u64,
    
    	#[serde(default = "default_typing_client_timeout_max_s")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub typing_client_timeout_max_s: u64,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub zstd_compression: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub gzip_compression: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub brotli_compression: bool,
    
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_guest_registration: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub log_guest_registrations: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub allow_guests_auto_join_rooms: bool,
    
    Jason Volk's avatar
    Jason Volk committed
    	#[serde(default = "true_fn")]
    	pub media_startup_check: bool,
    
    Jason Volk's avatar
    Jason Volk committed
    	pub media_compat_file_link: bool,
    
    	#[serde(default = "Vec::new")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub prevent_media_downloads_from: Vec<OwnedServerName>,
    
    Jason Volk's avatar
    Jason Volk committed
    	pub forbidden_remote_server_names: Vec<OwnedServerName>,
    
    Jason Volk's avatar
    Jason Volk committed
    	pub forbidden_remote_room_directory_server_names: Vec<OwnedServerName>,
    
    
    	#[serde(default = "default_ip_range_denylist")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub ip_range_denylist: Vec<String>,
    
    
    	#[serde(default = "Vec::new")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub url_preview_domain_contains_allowlist: Vec<String>,
    
    	#[serde(default = "Vec::new")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub url_preview_domain_explicit_allowlist: Vec<String>,
    
    	#[serde(default = "Vec::new")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub url_preview_domain_explicit_denylist: Vec<String>,
    
    	#[serde(default = "Vec::new")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub url_preview_url_contains_allowlist: Vec<String>,
    
    	#[serde(default = "default_url_preview_max_spider_size")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub url_preview_max_spider_size: usize,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub url_preview_check_root_domain: bool,
    
    
    	#[serde(default = "RegexSet::empty")]
    	#[serde(with = "serde_regex")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub forbidden_alias_names: RegexSet,
    
    
    	#[serde(default = "RegexSet::empty")]
    	#[serde(with = "serde_regex")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub forbidden_usernames: RegexSet,
    
    	#[serde(default = "true_fn")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub startup_netburst: bool,
    
    	#[serde(default = "default_startup_netburst_keep")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub startup_netburst_keep: i64,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub block_non_admin_invites: bool,
    
    	#[serde(default = "true_fn")]
    	pub admin_escape_commands: bool,
    
    	#[serde(default)]
    	pub admin_console_automatic: bool,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub sentry: bool,
    
    🥺's avatar
    🥺 committed
    	#[serde(default = "default_sentry_endpoint")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub sentry_endpoint: Option<Url>,
    
    	#[serde(default)]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub sentry_send_server_name: bool,
    
    	#[serde(default = "default_sentry_traces_sample_rate")]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub sentry_traces_sample_rate: f32,
    
    	#[serde(default)]
    	pub sentry_attach_stacktrace: bool,
    
    	#[serde(default = "true_fn")]
    	pub sentry_send_panic: bool,
    	#[serde(default = "true_fn")]
    	pub sentry_send_error: bool,
    
    	#[serde(default = "default_sentry_filter")]
    	pub sentry_filter: String,
    
    	#[serde(default)]
    	pub tokio_console: bool,
    
    
    	#[serde(flatten)]
    
    🥺's avatar
    🥺 committed
    	#[allow(clippy::zero_sized_map_values)] // this is a catchall, the map shouldn't be zero at runtime
    
    	catchall: BTreeMap<String, IgnoredAny>,
    
    #[derive(Clone, Debug, Deserialize)]
    
    Jason Volk's avatar
    Jason Volk committed
    pub struct TlsConfig {
    	pub certs: String,
    	pub key: String,
    
    	#[serde(default)]
    	/// Whether to listen and allow for HTTP and HTTPS connections (insecure!)
    	/// Only works / does something if the `axum_dual_protocol` feature flag was
    	/// built
    
    Jason Volk's avatar
    Jason Volk committed
    	pub dual_protocol: bool,
    
    #[derive(Clone, Debug, Deserialize, Default)]
    
    Jason Volk's avatar
    Jason Volk committed
    pub struct WellKnownConfig {
    	pub client: Option<Url>,
    	pub server: Option<OwnedServerName>,
    	pub support_page: Option<Url>,
    	pub support_role: Option<ContactRole>,
    	pub support_email: Option<String>,
    	pub support_mxid: Option<OwnedUserId>,
    
    #[derive(Deserialize, Clone, Debug)]
    #[serde(transparent)]
    struct ListeningPort {
    	#[serde(with = "either::serde_untagged")]
    	ports: Either<u16, Vec<u16>>,
    }
    
    #[derive(Deserialize, Clone, Debug)]
    #[serde(transparent)]
    struct ListeningAddr {
    	#[serde(with = "either::serde_untagged")]
    	addrs: Either<IpAddr, Vec<IpAddr>>,
    }
    
    
    const DEPRECATED_KEYS: &[&str; 9] = &[
    
    	"conduit_cache_capacity_modifier",
    
    	"well_known_client",
    	"well_known_server",
    	"well_known_support_page",
    	"well_known_support_role",
    	"well_known_support_email",
    	"well_known_support_mxid",
    ];
    
    	/// Pre-initialize config
    	pub fn load(path: &Option<PathBuf>) -> Result<Figment> {
    
    Jason Volk's avatar
    Jason Volk committed
    		let raw_config = if let Some(config_file_env) = Env::var("CONDUIT_CONFIG") {
    			Figment::new()
    				.merge(Toml::file(config_file_env).nested())
    
    				.merge(Env::prefixed("CONDUIT_").global().split("__"))
    				.merge(Env::prefixed("CONDUWUIT_").global().split("__"))
    
    		} else if let Some(config_file_arg) = Env::var("CONDUWUIT_CONFIG") {
    			Figment::new()
    				.merge(Toml::file(config_file_arg).nested())
    
    				.merge(Env::prefixed("CONDUIT_").global().split("__"))
    				.merge(Env::prefixed("CONDUWUIT_").global().split("__"))
    
    Jason Volk's avatar
    Jason Volk committed
    		} else if let Some(config_file_arg) = path {
    			Figment::new()
    				.merge(Toml::file(config_file_arg).nested())
    
    				.merge(Env::prefixed("CONDUIT_").global().split("__"))
    				.merge(Env::prefixed("CONDUWUIT_").global().split("__"))
    
    Jason Volk's avatar
    Jason Volk committed
    		} else {
    
    			Figment::new()
    
    				.merge(Env::prefixed("CONDUIT_").global().split("__"))
    				.merge(Env::prefixed("CONDUWUIT_").global().split("__"))
    
    Jason Volk's avatar
    Jason Volk committed
    		};
    
    
    		Ok(raw_config)
    	}
    
    	/// Finalize config
    	pub fn new(raw_config: &Figment) -> Result<Self> {
    
    Jason Volk's avatar
    Jason Volk committed
    		let config = match raw_config.extract::<Self>() {
    
    Jason Volk's avatar
    Jason Volk committed
    			Err(e) => return Err!("There was a problem with your configuration file: {e}"),
    
    Jason Volk's avatar
    Jason Volk committed
    			Ok(config) => config,
    		};
    
    		// don't start if we're listening on both UNIX sockets and TCP at same time
    
    		check::is_dual_listening(raw_config)?;
    
    Jason Volk's avatar
    Jason Volk committed
    
    		Ok(config)
    	}
    
    	#[must_use]
    
    Jason Volk's avatar
    Jason Volk committed
    	pub fn get_bind_addrs(&self) -> Vec<SocketAddr> {
    
    		let mut addrs = Vec::new();
    		for host in &self.get_bind_hosts() {
    			for port in &self.get_bind_ports() {
    				addrs.push(SocketAddr::new(*host, *port));
    			}
    		}
    
    		addrs
    	}
    
    	fn get_bind_hosts(&self) -> Vec<IpAddr> {
    		match &self.address.addrs {
    			Left(addr) => vec![*addr],
    			Right(addrs) => addrs.clone(),
    		}
    	}
    
    	fn get_bind_ports(&self) -> Vec<u16> {
    
    Jason Volk's avatar
    Jason Volk committed
    		match &self.port.ports {
    
    			Left(port) => vec![*port],
    			Right(ports) => ports.clone(),
    
    Jason Volk's avatar
    Jason Volk committed
    		}
    	}
    
    Jason Volk's avatar
    Jason Volk committed
    	pub fn check(&self) -> Result<(), Error> { check(self) }
    
    impl fmt::Display for Config {
    
    	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    
    		writeln!(f, "Active config values:\n\n").expect("wrote line to formatter stream");
    		let mut line = |key: &str, val: &str| {
    			writeln!(f, "{key}: {val}").expect("wrote line to formatter stream");
    		};
    
    		line("Server name", self.server_name.host());
    		line("Database backend", &self.database_backend);
    		line("Database path", &self.database_path.to_string_lossy());
    		line(
    			"Database backup path",
    			self.database_backup_path
    				.as_ref()
    				.map_or("", |path| path.to_str().unwrap_or("")),
    		);
    		line("Database backups to keep", &self.database_backups_to_keep.to_string());
    		line("Database cache capacity (MB)", &self.db_cache_capacity_mb.to_string());
    
    		line("Cache capacity modifier", &self.cache_capacity_modifier.to_string());
    
    		line("PDU cache capacity", &self.pdu_cache_capacity.to_string());
    		line("Auth chain cache capacity", &self.auth_chain_cache_capacity.to_string());
    		line("Short eventid cache capacity", &self.shorteventid_cache_capacity.to_string());
    		line("Eventid short cache capacity", &self.eventidshort_cache_capacity.to_string());
    		line("Short statekey cache capacity", &self.shortstatekey_cache_capacity.to_string());
    		line("Statekey short cache capacity", &self.statekeyshort_cache_capacity.to_string());
    		line(
    			"Server visibility cache capacity",
    			&self.server_visibility_cache_capacity.to_string(),
    		);
    		line(
    			"User visibility cache capacity",
    			&self.user_visibility_cache_capacity.to_string(),
    		);
    		line("Stateinfo cache capacity", &self.stateinfo_cache_capacity.to_string());
    		line(
    			"Roomid space hierarchy cache capacity",
    			&self.roomid_spacehierarchy_cache_capacity.to_string(),
    		);
    		line("DNS cache entry limit", &self.dns_cache_entries.to_string());
    		line("DNS minimum TTL", &self.dns_min_ttl.to_string());
    		line("DNS minimum NXDOMAIN TTL", &self.dns_min_ttl_nxdomain.to_string());
    		line("DNS attempts", &self.dns_attempts.to_string());
    		line("DNS timeout", &self.dns_timeout.to_string());
    		line("DNS fallback to TCP", &self.dns_tcp_fallback.to_string());
    		line("DNS query over TCP only", &self.query_over_tcp_only.to_string());
    		line("Query all nameservers", &self.query_all_nameservers.to_string());
    		line("Maximum request size (bytes)", &self.max_request_size.to_string());
    		line("Sender retry backoff limit", &self.sender_retry_backoff_limit.to_string());
    		line("Request connect timeout", &self.request_conn_timeout.to_string());
    		line("Request timeout", &self.request_timeout.to_string());
    		line("Request total timeout", &self.request_total_timeout.to_string());
    		line("Idle connections per host", &self.request_idle_per_host.to_string());
    		line("Request pool idle timeout", &self.request_idle_timeout.to_string());
    		line("Well_known connect timeout", &self.well_known_conn_timeout.to_string());
    		line("Well_known timeout", &self.well_known_timeout.to_string());
    		line("Federation timeout", &self.federation_timeout.to_string());
    		line("Federation pool idle per host", &self.federation_idle_per_host.to_string());
    		line("Federation pool idle timeout", &self.federation_idle_timeout.to_string());
    		line("Sender timeout", &self.sender_timeout.to_string());
    		line("Sender pool idle timeout", &self.sender_idle_timeout.to_string());
    		line("Appservice timeout", &self.appservice_timeout.to_string());
    		line("Appservice pool idle timeout", &self.appservice_idle_timeout.to_string());
    		line("Pusher pool idle timeout", &self.pusher_idle_timeout.to_string());
    		line("Allow registration", &self.allow_registration.to_string());
    		line(
    			"Registration token",
    			if self.registration_token.is_some() {
    				"set"
    			} else {
    				"not set (open registration!)"
    			},
    		);
    		line(
    			"Allow guest registration (inherently false if allow registration is false)",
    			&self.allow_guest_registration.to_string(),
    		);
    		line(
    			"Log guest registrations in admin room",
    			&self.log_guest_registrations.to_string(),
    		);
    		line(
    			"Allow guests to auto join rooms",
    			&self.allow_guests_auto_join_rooms.to_string(),
    		);
    		line("New user display name suffix", &self.new_user_displayname_suffix);
    		line("Allow encryption", &self.allow_encryption.to_string());
    		line("Allow federation", &self.allow_federation.to_string());
    		line(
    			"Allow incoming federated presence requests (updates)",
    			&self.allow_incoming_presence.to_string(),
    		);
    		line(
    			"Allow outgoing federated presence requests (updates)",
    			&self.allow_outgoing_presence.to_string(),
    		);
    		line(
    			"Allow local presence requests (updates)",
    			&self.allow_local_presence.to_string(),
    		);
    		line(
    			"Allow incoming remote read receipts",
    			&self.allow_incoming_read_receipts.to_string(),
    		);
    		line(
    			"Allow outgoing remote read receipts",
    			&self.allow_outgoing_read_receipts.to_string(),
    		);
    		line(
    			"Block non-admin room invites (local and remote, admins can still send and receive invites)",
    			&self.block_non_admin_invites.to_string(),
    		);
    		line("Enable admin escape commands", &self.admin_escape_commands.to_string());
    
    		line(
    			"Activate admin console after startup",
    			&self.admin_console_automatic.to_string(),
    		);
    
    		line("Allow outgoing federated typing", &self.allow_outgoing_typing.to_string());
    		line("Allow incoming federated typing", &self.allow_incoming_typing.to_string());
    		line(
    			"Incoming federated typing timeout",
    			&self.typing_federation_timeout_s.to_string(),
    		);
    		line("Client typing timeout minimum", &self.typing_client_timeout_min_s.to_string());
    		line("Client typing timeout maxmimum", &self.typing_client_timeout_max_s.to_string());
    		line("Allow device name federation", &self.allow_device_name_federation.to_string());
    		line(
    			"Allow incoming profile lookup federation requests",
    			&self.allow_profile_lookup_federation_requests.to_string(),
    		);
    		line(
    			"Auto deactivate banned room join attempts",
    			&self.auto_deactivate_banned_room_attempts.to_string(),
    		);
    		line("Notification push path", &self.notification_push_path);
    		line("Allow room creation", &self.allow_room_creation.to_string());
    		line(
    			"Allow public room directory over federation",
    			&self.allow_public_room_directory_over_federation.to_string(),
    		);
    		line(
    			"Allow public room directory without authentication",
    			&self.allow_public_room_directory_without_auth.to_string(),
    		);
    		line(
    			"Lockdown public room directory (only allow admins to publish)",
    			&self.lockdown_public_room_directory.to_string(),
    		);
    		line(
    			"JWT secret",
    			match self.jwt_secret {
    				Some(_) => "set",
    				None => "not set",
    			},
    		);
    		line(
    			"Trusted key servers",
    			&self
    				.trusted_servers
    				.iter()
    				.map(|server| server.host())
    				.join(", "),
    		);
    		line(
    			"Query Trusted Key Servers First",
    			&self.query_trusted_key_servers_first.to_string(),
    		);
    		line("OpenID Token TTL", &self.openid_token_ttl.to_string());
    		line(
    			"TURN username",
    			if self.turn_username.is_empty() {
    				"not set"
    			} else {
    				&self.turn_username
    			},
    		);
    		line("TURN password", {
    			if self.turn_password.is_empty() {
    				"not set"
    			} else {
    				"set"
    			}
    		});
    		line("TURN secret", {
    			if self.turn_secret.is_empty() {
    				"not set"
    			} else {
    				"set"
    			}
    		});
    		line("Turn TTL", &self.turn_ttl.to_string());
    		line("Turn URIs", {
    			let mut lst = vec![];
    			for item in self.turn_uris.iter().cloned().enumerate() {
    				let (_, uri): (usize, String) = item;
    				lst.push(uri);
    			}
    			&lst.join(", ")
    		});
    		line("Auto Join Rooms", {
    			let mut lst = vec![];
    			for room in &self.auto_join_rooms {
    				lst.push(room);
    			}
    			&lst.into_iter().join(", ")
    		});
    		line("Zstd HTTP Compression", &self.zstd_compression.to_string());
    		line("Gzip HTTP Compression", &self.gzip_compression.to_string());
    		line("Brotli HTTP Compression", &self.brotli_compression.to_string());
    		line("RocksDB database LOG level", &self.rocksdb_log_level);
    		line("RocksDB database LOG to stderr", &self.rocksdb_log_stderr.to_string());
    		line("RocksDB database LOG time-to-roll", &self.rocksdb_log_time_to_roll.to_string());
    		line("RocksDB Max LOG Files", &self.rocksdb_max_log_files.to_string());
    		line(
    			"RocksDB database max LOG file size",
    			&self.rocksdb_max_log_file_size.to_string(),
    		);
    		line(
    			"RocksDB database optimize for spinning disks",
    			&self.rocksdb_optimize_for_spinning_disks.to_string(),
    		);
    		line("RocksDB Direct-IO", &self.rocksdb_direct_io.to_string());
    		line("RocksDB Parallelism Threads", &self.rocksdb_parallelism_threads.to_string());
    		line("RocksDB Compression Algorithm", &self.rocksdb_compression_algo);
    		line("RocksDB Compression Level", &self.rocksdb_compression_level.to_string());
    		line(
    			"RocksDB Bottommost Compression Level",
    			&self.rocksdb_bottommost_compression_level.to_string(),
    		);
    		line(
    			"RocksDB Bottommost Level Compression",
    			&self.rocksdb_bottommost_compression.to_string(),
    		);
    		line("RocksDB Recovery Mode", &self.rocksdb_recovery_mode.to_string());
    		line("RocksDB Repair Mode", &self.rocksdb_repair.to_string());
    		line("RocksDB Read-only Mode", &self.rocksdb_read_only.to_string());
    		line(
    			"RocksDB Compaction Idle Priority",
    			&self.rocksdb_compaction_prio_idle.to_string(),
    		);
    		line(
    			"RocksDB Compaction Idle IOPriority",
    			&self.rocksdb_compaction_ioprio_idle.to_string(),
    		);
    
    		line("RocksDB Compaction enabled", &self.rocksdb_compaction.to_string());
    
    		line("RocksDB Statistics level", &self.rocksdb_stats_level.to_string());
    
    		line("Media integrity checks on startup", &self.media_startup_check.to_string());
    		line("Media compatibility filesystem links", &self.media_compat_file_link.to_string());
    		line("Prevent Media Downloads From", {
    			let mut lst = vec![];
    			for domain in &self.prevent_media_downloads_from {
    				lst.push(domain.host());
    			}
    			&lst.join(", ")
    		});
    		line("Forbidden Remote Server Names (\"Global\" ACLs)", {
    			let mut lst = vec![];
    			for domain in &self.forbidden_remote_server_names {
    				lst.push(domain.host());
    			}
    			&lst.join(", ")
    		});
    		line("Forbidden Remote Room Directory Server Names", {
    			let mut lst = vec![];
    			for domain in &self.forbidden_remote_room_directory_server_names {
    				lst.push(domain.host());
    			}
    			&lst.join(", ")
    		});
    		line("Outbound Request IP Range Denylist", {
    			let mut lst = vec![];
    			for item in self.ip_range_denylist.iter().cloned().enumerate() {
    				let (_, ip): (usize, String) = item;
    				lst.push(ip);
    			}
    			&lst.join(", ")
    		});
    		line("Forbidden usernames", {
    			&self.forbidden_usernames.patterns().iter().join(", ")
    		});
    		line("Forbidden room aliases", {
    			&self.forbidden_alias_names.patterns().iter().join(", ")
    		});
    		line(
    			"URL preview domain contains allowlist",
    			&self.url_preview_domain_contains_allowlist.join(", "),
    		);
    		line(
    			"URL preview domain explicit allowlist",
    			&self.url_preview_domain_explicit_allowlist.join(", "),
    		);
    		line(
    			"URL preview domain explicit denylist",
    			&self.url_preview_domain_explicit_denylist.join(", "),
    		);
    		line(
    			"URL preview URL contains allowlist",
    			&self.url_preview_url_contains_allowlist.join(", "),
    		);
    		line("URL preview maximum spider size", &self.url_preview_max_spider_size.to_string());
    		line("URL preview check root domain", &self.url_preview_check_root_domain.to_string());
    		line(
    			"Allow check for updates / announcements check",
    			&self.allow_check_for_updates.to_string(),
    		);
    		line("Enable netburst on startup", &self.startup_netburst.to_string());
    		#[cfg(feature = "sentry_telemetry")]
    		line("Sentry.io reporting and tracing", &self.sentry.to_string());
    		#[cfg(feature = "sentry_telemetry")]
    		line("Sentry.io send server_name in logs", &self.sentry_send_server_name.to_string());
    		#[cfg(feature = "sentry_telemetry")]
    		line("Sentry.io tracing sample rate", &self.sentry_traces_sample_rate.to_string());
    		line("Sentry.io attach stacktrace", &self.sentry_attach_stacktrace.to_string());
    		line("Sentry.io send panics", &self.sentry_send_panic.to_string());
    		line("Sentry.io send errors", &self.sentry_send_error.to_string());
    
    		line("Sentry.io tracing filter", &self.sentry_filter);
    
    		line(
    			"Well-known server name",
    			self.well_known
    				.server
    				.as_ref()
    				.map_or("", |server| server.as_str()),
    		);
    		line(
    			"Well-known client URL",
    			self.well_known
    				.client
    				.as_ref()
    				.map_or("", |url| url.as_str()),
    		);
    		line(
    			"Well-known support email",
    			self.well_known
    				.support_email
    				.as_ref()
    				.map_or("", |str| str.as_ref()),
    		);
    		line(
    			"Well-known support Matrix ID",
    			self.well_known
    				.support_mxid
    				.as_ref()
    				.map_or("", |mxid| mxid.as_str()),
    		);
    		line(
    			"Well-known support role",
    			self.well_known
    				.support_role
    				.as_ref()
    				.map_or("", |role| role.as_str()),
    		);
    		line(
    			"Well-known support page/URL",
    			self.well_known
    				.support_page
    				.as_ref()
    				.map_or("", |url| url.as_str()),
    		);
    		line("Enable the tokio-console", &self.tokio_console.to_string());
    
    		Ok(())
    
    fn true_fn() -> bool { true }
    
    fn default_address() -> ListeningAddr {
    	ListeningAddr {
    		addrs: Right(vec![Ipv4Addr::LOCALHOST.into(), Ipv6Addr::LOCALHOST.into()]),
    	}
    }
    
    fn default_port() -> ListeningPort {
    
    	ListeningPort {
    
    Jason Volk's avatar
    Jason Volk committed
    		ports: Left(8008),
    
    fn default_unix_socket_perms() -> u32 { 660 }
    
    🥺's avatar
    🥺 committed
    
    
    fn default_database_backups_to_keep() -> i16 { 1 }
    
    
    fn default_database_backend() -> String { "rocksdb".to_owned() }
    
    fn default_db_cache_capacity_mb() -> f64 { 256.0 }
    
    fn default_pdu_cache_capacity() -> u32 { 150_000 }
    
    
    fn default_cache_capacity_modifier() -> f64 { 1.0 }
    
    fn default_auth_chain_cache_capacity() -> u32 { 100_000 }
    
    fn default_shorteventid_cache_capacity() -> u32 { 500_000 }
    
    fn default_eventidshort_cache_capacity() -> u32 { 100_000 }
    
    fn default_shortstatekey_cache_capacity() -> u32 { 100_000 }
    
    fn default_statekeyshort_cache_capacity() -> u32 { 100_000 }
    
    fn default_server_visibility_cache_capacity() -> u32 { 100 }
    
    fn default_user_visibility_cache_capacity() -> u32 { 100 }
    
    fn default_stateinfo_cache_capacity() -> u32 { 100 }
    
    fn default_roomid_spacehierarchy_cache_capacity() -> u32 { 100 }
    
    fn default_dns_cache_entries() -> u32 { 32768 }
    
    🥺's avatar
    🥺 committed
    fn default_dns_min_ttl() -> u64 { 60 * 180 }
    
    fn default_dns_min_ttl_nxdomain() -> u64 { 60 * 60 * 24 * 3 }
    
    🥺's avatar
    🥺 committed
    fn default_dns_attempts() -> u16 { 10 }
    
    🥺's avatar
    🥺 committed
    fn default_dns_timeout() -> u64 { 10 }
    
    fn default_ip_lookup_strategy() -> u8 { 5 }
    
    
    fn default_max_request_size() -> usize {
    
    	20 * 1024 * 1024 // Default to 20 MB
    
    fn default_request_conn_timeout() -> u64 { 10 }
    
    fn default_request_timeout() -> u64 { 35 }
    
    
    fn default_request_total_timeout() -> u64 { 320 }
    
    
    fn default_request_idle_timeout() -> u64 { 5 }
    
    
    fn default_request_idle_per_host() -> u16 { 1 }
    
    
    fn default_well_known_conn_timeout() -> u64 { 6 }
    
    fn default_well_known_timeout() -> u64 { 10 }
    
    fn default_federation_timeout() -> u64 { 300 }
    
    fn default_federation_idle_timeout() -> u64 { 25 }
    
    
    fn default_federation_idle_per_host() -> u16 { 1 }
    
    
    fn default_sender_timeout() -> u64 { 180 }
    
    
    fn default_sender_idle_timeout() -> u64 { 180 }
    
    
    fn default_sender_retry_backoff_limit() -> u64 { 86400 }
    
    
    fn default_appservice_timeout() -> u64 { 35 }
    
    
    fn default_appservice_idle_timeout() -> u64 { 300 }
    
    fn default_pusher_idle_timeout() -> u64 { 15 }
    
    
    fn default_max_fetch_prev_events() -> u16 { 100_u16 }
    
    fn default_tracing_flame_filter() -> String {
    	cfg!(debug_assertions)
    		.then_some("trace,h2=off")
    		.unwrap_or("info")
    		.to_owned()
    }
    
    fn default_jaeger_filter() -> String {
    	cfg!(debug_assertions)
    		.then_some("trace,h2=off")
    		.unwrap_or("info")
    		.to_owned()
    }
    
    
    fn default_tracing_flame_output_path() -> String { "./tracing.folded".to_owned() }
    
    
    fn default_trusted_servers() -> Vec<OwnedServerName> { vec![OwnedServerName::try_from("matrix.org").unwrap()] }
    
    Jason Volk's avatar
    Jason Volk committed
    /// do debug logging by default for debug builds
    
    #[must_use]
    pub fn default_log() -> String {
    
    Jason Volk's avatar
    Jason Volk committed
    	cfg!(debug_assertions)
    		.then_some("debug")
    		.unwrap_or("info")
    		.to_owned()
    
    fn default_notification_push_path() -> String { "/_matrix/push/v1/notify".to_owned() }
    
    fn default_openid_token_ttl() -> u64 { 60 * 60 }
    
    
    fn default_turn_ttl() -> u64 { 60 * 60 * 24 }
    
    fn default_presence_idle_timeout_s() -> u64 { 5 * 60 }
    
    fn default_presence_offline_timeout_s() -> u64 { 30 * 60 }
    
    fn default_typing_federation_timeout_s() -> u64 { 30 }
    
    fn default_typing_client_timeout_min_s() -> u64 { 15 }
    
    fn default_typing_client_timeout_max_s() -> u64 { 45 }
    
    
    fn default_rocksdb_recovery_mode() -> u8 { 1 }
    
    fn default_rocksdb_log_level() -> String { "error".to_owned() }
    
    fn default_rocksdb_log_time_to_roll() -> usize { 0 }
    
    fn default_rocksdb_max_log_files() -> usize { 3 }
    
    
    fn default_rocksdb_max_log_file_size() -> usize {
    	// 4 megabytes
    	4 * 1024 * 1024
    }
    
    
    fn default_rocksdb_parallelism_threads() -> usize { 0 }
    
    fn default_rocksdb_compression_algo() -> String { "zstd".to_owned() }
    
    
    /// Default RocksDB compression level is 32767, which is internally read by
    /// RocksDB as the default magic number and translated to the library's default
    /// compression level as they all differ. See their `kDefaultCompressionLevel`.
    
    #[allow(clippy::doc_markdown)]
    
    fn default_rocksdb_compression_level() -> i32 { 32767 }