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}