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,
56 OnBackchannelLogout as UpstreamOAuth2OnBackchannelLogout,
57 OnConflict as UpstreamOAuth2OnConflict, PkceMethod as UpstreamOAuth2PkceMethod,
58 Provider as UpstreamOAuth2Provider, ResponseMode as UpstreamOAuth2ResponseMode,
59 TokenAuthMethod as UpstreamOAuth2TokenAuthMethod, UpstreamOAuth2Config,
60 },
61};
62use crate::util::ConfigurationSection;
63
64#[derive(Debug, Serialize, Deserialize, JsonSchema)]
66pub struct RootConfig {
67 #[serde(default, skip_serializing_if = "ClientsConfig::is_default")]
69 pub clients: ClientsConfig,
70
71 #[serde(default)]
73 pub http: HttpConfig,
74
75 #[serde(default)]
77 pub database: DatabaseConfig,
78
79 #[serde(default, skip_serializing_if = "TelemetryConfig::is_default")]
81 pub telemetry: TelemetryConfig,
82
83 #[serde(default, skip_serializing_if = "TemplatesConfig::is_default")]
85 pub templates: TemplatesConfig,
86
87 #[serde(default)]
89 pub email: EmailConfig,
90
91 pub secrets: SecretsConfig,
93
94 #[serde(default)]
96 pub passwords: PasswordsConfig,
97
98 pub matrix: MatrixConfig,
100
101 #[serde(default, skip_serializing_if = "PolicyConfig::is_default")]
103 pub policy: PolicyConfig,
104
105 #[serde(default, skip_serializing_if = "RateLimitingConfig::is_default")]
108 pub rate_limiting: RateLimitingConfig,
109
110 #[serde(default, skip_serializing_if = "UpstreamOAuth2Config::is_default")]
112 pub upstream_oauth2: UpstreamOAuth2Config,
113
114 #[serde(default, skip_serializing_if = "BrandingConfig::is_default")]
116 pub branding: BrandingConfig,
117
118 #[serde(default, skip_serializing_if = "CaptchaConfig::is_default")]
120 pub captcha: CaptchaConfig,
121
122 #[serde(default, skip_serializing_if = "AccountConfig::is_default")]
125 pub account: AccountConfig,
126
127 #[serde(default, skip_serializing_if = "ExperimentalConfig::is_default")]
129 pub experimental: ExperimentalConfig,
130}
131
132impl ConfigurationSection for RootConfig {
133 fn validate(
134 &self,
135 figment: &figment::Figment,
136 ) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
137 self.clients.validate(figment)?;
138 self.http.validate(figment)?;
139 self.database.validate(figment)?;
140 self.telemetry.validate(figment)?;
141 self.templates.validate(figment)?;
142 self.email.validate(figment)?;
143 self.passwords.validate(figment)?;
144 self.secrets.validate(figment)?;
145 self.matrix.validate(figment)?;
146 self.policy.validate(figment)?;
147 self.rate_limiting.validate(figment)?;
148 self.upstream_oauth2.validate(figment)?;
149 self.branding.validate(figment)?;
150 self.captcha.validate(figment)?;
151 self.account.validate(figment)?;
152 self.experimental.validate(figment)?;
153
154 Ok(())
155 }
156}
157
158impl RootConfig {
159 pub async fn generate<R>(mut rng: R) -> anyhow::Result<Self>
165 where
166 R: Rng + Send,
167 {
168 Ok(Self {
169 clients: ClientsConfig::default(),
170 http: HttpConfig::default(),
171 database: DatabaseConfig::default(),
172 telemetry: TelemetryConfig::default(),
173 templates: TemplatesConfig::default(),
174 email: EmailConfig::default(),
175 passwords: PasswordsConfig::default(),
176 secrets: SecretsConfig::generate(&mut rng).await?,
177 matrix: MatrixConfig::generate(&mut rng),
178 policy: PolicyConfig::default(),
179 rate_limiting: RateLimitingConfig::default(),
180 upstream_oauth2: UpstreamOAuth2Config::default(),
181 branding: BrandingConfig::default(),
182 captcha: CaptchaConfig::default(),
183 account: AccountConfig::default(),
184 experimental: ExperimentalConfig::default(),
185 })
186 }
187
188 #[must_use]
190 pub fn test() -> Self {
191 Self {
192 clients: ClientsConfig::default(),
193 http: HttpConfig::default(),
194 database: DatabaseConfig::default(),
195 telemetry: TelemetryConfig::default(),
196 templates: TemplatesConfig::default(),
197 passwords: PasswordsConfig::default(),
198 email: EmailConfig::default(),
199 secrets: SecretsConfig::test(),
200 matrix: MatrixConfig::test(),
201 policy: PolicyConfig::default(),
202 rate_limiting: RateLimitingConfig::default(),
203 upstream_oauth2: UpstreamOAuth2Config::default(),
204 branding: BrandingConfig::default(),
205 captcha: CaptchaConfig::default(),
206 account: AccountConfig::default(),
207 experimental: ExperimentalConfig::default(),
208 }
209 }
210}
211
212#[allow(missing_docs)]
214#[derive(Debug, Deserialize)]
215pub struct AppConfig {
216 #[serde(default)]
217 pub http: HttpConfig,
218
219 #[serde(default)]
220 pub database: DatabaseConfig,
221
222 #[serde(default)]
223 pub templates: TemplatesConfig,
224
225 #[serde(default)]
226 pub email: EmailConfig,
227
228 pub secrets: SecretsConfig,
229
230 #[serde(default)]
231 pub passwords: PasswordsConfig,
232
233 pub matrix: MatrixConfig,
234
235 #[serde(default)]
236 pub policy: PolicyConfig,
237
238 #[serde(default)]
239 pub rate_limiting: RateLimitingConfig,
240
241 #[serde(default)]
242 pub branding: BrandingConfig,
243
244 #[serde(default)]
245 pub captcha: CaptchaConfig,
246
247 #[serde(default)]
248 pub account: AccountConfig,
249
250 #[serde(default)]
251 pub experimental: ExperimentalConfig,
252}
253
254impl ConfigurationSection for AppConfig {
255 fn validate(
256 &self,
257 figment: &figment::Figment,
258 ) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
259 self.http.validate(figment)?;
260 self.database.validate(figment)?;
261 self.templates.validate(figment)?;
262 self.email.validate(figment)?;
263 self.passwords.validate(figment)?;
264 self.secrets.validate(figment)?;
265 self.matrix.validate(figment)?;
266 self.policy.validate(figment)?;
267 self.rate_limiting.validate(figment)?;
268 self.branding.validate(figment)?;
269 self.captcha.validate(figment)?;
270 self.account.validate(figment)?;
271 self.experimental.validate(figment)?;
272
273 Ok(())
274 }
275}
276
277#[allow(missing_docs)]
279#[derive(Debug, Deserialize)]
280pub struct SyncConfig {
281 #[serde(default)]
282 pub database: DatabaseConfig,
283
284 pub secrets: SecretsConfig,
285
286 #[serde(default)]
287 pub clients: ClientsConfig,
288
289 #[serde(default)]
290 pub upstream_oauth2: UpstreamOAuth2Config,
291}
292
293impl ConfigurationSection for SyncConfig {
294 fn validate(
295 &self,
296 figment: &figment::Figment,
297 ) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
298 self.database.validate(figment)?;
299 self.secrets.validate(figment)?;
300 self.clients.validate(figment)?;
301 self.upstream_oauth2.validate(figment)?;
302
303 Ok(())
304 }
305}