1use rand::Rng;
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10
11mod account;
12mod branding;
13mod captcha;
14mod clients;
15mod database;
16mod email;
17mod experimental;
18mod http;
19mod matrix;
20mod passwords;
21mod policy;
22mod rate_limiting;
23mod secrets;
24mod telemetry;
25mod templates;
26mod upstream_oauth2;
27
28pub use self::{
29    account::AccountConfig,
30    branding::BrandingConfig,
31    captcha::{CaptchaConfig, CaptchaServiceKind},
32    clients::{ClientAuthMethodConfig, ClientConfig, ClientsConfig},
33    database::{DatabaseConfig, PgSslMode},
34    email::{EmailConfig, EmailSmtpMode, EmailTransportKind},
35    experimental::ExperimentalConfig,
36    http::{
37        BindConfig as HttpBindConfig, HttpConfig, ListenerConfig as HttpListenerConfig,
38        Resource as HttpResource, TlsConfig as HttpTlsConfig, UnixOrTcp,
39    },
40    matrix::{HomeserverKind, MatrixConfig},
41    passwords::{
42        Algorithm as PasswordAlgorithm, HashingScheme as PasswordHashingScheme, PasswordsConfig,
43    },
44    policy::PolicyConfig,
45    rate_limiting::RateLimitingConfig,
46    secrets::SecretsConfig,
47    telemetry::{
48        MetricsConfig, MetricsExporterKind, Propagator, TelemetryConfig, TracingConfig,
49        TracingExporterKind,
50    },
51    templates::TemplatesConfig,
52    upstream_oauth2::{
53        ClaimsImports as UpstreamOAuth2ClaimsImports, DiscoveryMode as UpstreamOAuth2DiscoveryMode,
54        EmailImportPreference as UpstreamOAuth2EmailImportPreference,
55        ImportAction as UpstreamOAuth2ImportAction, PkceMethod as UpstreamOAuth2PkceMethod,
56        Provider as UpstreamOAuth2Provider, ResponseMode as UpstreamOAuth2ResponseMode,
57        TokenAuthMethod as UpstreamOAuth2TokenAuthMethod, UpstreamOAuth2Config,
58    },
59};
60use crate::util::ConfigurationSection;
61
62#[derive(Debug, Serialize, Deserialize, JsonSchema)]
64pub struct RootConfig {
65    #[serde(default, skip_serializing_if = "ClientsConfig::is_default")]
67    pub clients: ClientsConfig,
68
69    #[serde(default)]
71    pub http: HttpConfig,
72
73    #[serde(default)]
75    pub database: DatabaseConfig,
76
77    #[serde(default, skip_serializing_if = "TelemetryConfig::is_default")]
79    pub telemetry: TelemetryConfig,
80
81    #[serde(default, skip_serializing_if = "TemplatesConfig::is_default")]
83    pub templates: TemplatesConfig,
84
85    #[serde(default)]
87    pub email: EmailConfig,
88
89    pub secrets: SecretsConfig,
91
92    #[serde(default)]
94    pub passwords: PasswordsConfig,
95
96    pub matrix: MatrixConfig,
98
99    #[serde(default, skip_serializing_if = "PolicyConfig::is_default")]
101    pub policy: PolicyConfig,
102
103    #[serde(default, skip_serializing_if = "RateLimitingConfig::is_default")]
106    pub rate_limiting: RateLimitingConfig,
107
108    #[serde(default, skip_serializing_if = "UpstreamOAuth2Config::is_default")]
110    pub upstream_oauth2: UpstreamOAuth2Config,
111
112    #[serde(default, skip_serializing_if = "BrandingConfig::is_default")]
114    pub branding: BrandingConfig,
115
116    #[serde(default, skip_serializing_if = "CaptchaConfig::is_default")]
118    pub captcha: CaptchaConfig,
119
120    #[serde(default, skip_serializing_if = "AccountConfig::is_default")]
123    pub account: AccountConfig,
124
125    #[serde(default, skip_serializing_if = "ExperimentalConfig::is_default")]
127    pub experimental: ExperimentalConfig,
128}
129
130impl ConfigurationSection for RootConfig {
131    fn validate(&self, figment: &figment::Figment) -> Result<(), figment::Error> {
132        self.clients.validate(figment)?;
133        self.http.validate(figment)?;
134        self.database.validate(figment)?;
135        self.telemetry.validate(figment)?;
136        self.templates.validate(figment)?;
137        self.email.validate(figment)?;
138        self.passwords.validate(figment)?;
139        self.secrets.validate(figment)?;
140        self.matrix.validate(figment)?;
141        self.policy.validate(figment)?;
142        self.rate_limiting.validate(figment)?;
143        self.upstream_oauth2.validate(figment)?;
144        self.branding.validate(figment)?;
145        self.captcha.validate(figment)?;
146        self.account.validate(figment)?;
147        self.experimental.validate(figment)?;
148
149        Ok(())
150    }
151}
152
153impl RootConfig {
154    pub async fn generate<R>(mut rng: R) -> anyhow::Result<Self>
160    where
161        R: Rng + Send,
162    {
163        Ok(Self {
164            clients: ClientsConfig::default(),
165            http: HttpConfig::default(),
166            database: DatabaseConfig::default(),
167            telemetry: TelemetryConfig::default(),
168            templates: TemplatesConfig::default(),
169            email: EmailConfig::default(),
170            passwords: PasswordsConfig::default(),
171            secrets: SecretsConfig::generate(&mut rng).await?,
172            matrix: MatrixConfig::generate(&mut rng),
173            policy: PolicyConfig::default(),
174            rate_limiting: RateLimitingConfig::default(),
175            upstream_oauth2: UpstreamOAuth2Config::default(),
176            branding: BrandingConfig::default(),
177            captcha: CaptchaConfig::default(),
178            account: AccountConfig::default(),
179            experimental: ExperimentalConfig::default(),
180        })
181    }
182
183    #[must_use]
185    pub fn test() -> Self {
186        Self {
187            clients: ClientsConfig::default(),
188            http: HttpConfig::default(),
189            database: DatabaseConfig::default(),
190            telemetry: TelemetryConfig::default(),
191            templates: TemplatesConfig::default(),
192            passwords: PasswordsConfig::default(),
193            email: EmailConfig::default(),
194            secrets: SecretsConfig::test(),
195            matrix: MatrixConfig::test(),
196            policy: PolicyConfig::default(),
197            rate_limiting: RateLimitingConfig::default(),
198            upstream_oauth2: UpstreamOAuth2Config::default(),
199            branding: BrandingConfig::default(),
200            captcha: CaptchaConfig::default(),
201            account: AccountConfig::default(),
202            experimental: ExperimentalConfig::default(),
203        }
204    }
205}
206
207#[allow(missing_docs)]
209#[derive(Debug, Deserialize)]
210pub struct AppConfig {
211    #[serde(default)]
212    pub http: HttpConfig,
213
214    #[serde(default)]
215    pub database: DatabaseConfig,
216
217    #[serde(default)]
218    pub templates: TemplatesConfig,
219
220    #[serde(default)]
221    pub email: EmailConfig,
222
223    pub secrets: SecretsConfig,
224
225    #[serde(default)]
226    pub passwords: PasswordsConfig,
227
228    pub matrix: MatrixConfig,
229
230    #[serde(default)]
231    pub policy: PolicyConfig,
232
233    #[serde(default)]
234    pub rate_limiting: RateLimitingConfig,
235
236    #[serde(default)]
237    pub branding: BrandingConfig,
238
239    #[serde(default)]
240    pub captcha: CaptchaConfig,
241
242    #[serde(default)]
243    pub account: AccountConfig,
244
245    #[serde(default)]
246    pub experimental: ExperimentalConfig,
247}
248
249impl ConfigurationSection for AppConfig {
250    fn validate(&self, figment: &figment::Figment) -> Result<(), figment::Error> {
251        self.http.validate(figment)?;
252        self.database.validate(figment)?;
253        self.templates.validate(figment)?;
254        self.email.validate(figment)?;
255        self.passwords.validate(figment)?;
256        self.secrets.validate(figment)?;
257        self.matrix.validate(figment)?;
258        self.policy.validate(figment)?;
259        self.rate_limiting.validate(figment)?;
260        self.branding.validate(figment)?;
261        self.captcha.validate(figment)?;
262        self.account.validate(figment)?;
263        self.experimental.validate(figment)?;
264
265        Ok(())
266    }
267}
268
269#[allow(missing_docs)]
271#[derive(Debug, Deserialize)]
272pub struct SyncConfig {
273    #[serde(default)]
274    pub database: DatabaseConfig,
275
276    pub secrets: SecretsConfig,
277
278    #[serde(default)]
279    pub clients: ClientsConfig,
280
281    #[serde(default)]
282    pub upstream_oauth2: UpstreamOAuth2Config,
283}
284
285impl ConfigurationSection for SyncConfig {
286    fn validate(&self, figment: &figment::Figment) -> Result<(), figment::Error> {
287        self.database.validate(figment)?;
288        self.secrets.validate(figment)?;
289        self.clients.validate(figment)?;
290        self.upstream_oauth2.validate(figment)?;
291
292        Ok(())
293    }
294}