mas_config/sections/
mod.rs

1// Copyright 2024, 2025 New Vector Ltd.
2// Copyright 2022-2024 The Matrix.org Foundation C.I.C.
3//
4// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
5// Please see LICENSE files in the repository root for full details.
6
7use 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        PkceMethod as UpstreamOAuth2PkceMethod, Provider as UpstreamOAuth2Provider,
58        ResponseMode as UpstreamOAuth2ResponseMode,
59        TokenAuthMethod as UpstreamOAuth2TokenAuthMethod, UpstreamOAuth2Config,
60    },
61};
62use crate::util::ConfigurationSection;
63
64/// Application configuration root
65#[derive(Debug, Serialize, Deserialize, JsonSchema)]
66pub struct RootConfig {
67    /// List of OAuth 2.0/OIDC clients config
68    #[serde(default, skip_serializing_if = "ClientsConfig::is_default")]
69    pub clients: ClientsConfig,
70
71    /// Configuration of the HTTP server
72    #[serde(default)]
73    pub http: HttpConfig,
74
75    /// Database connection configuration
76    #[serde(default)]
77    pub database: DatabaseConfig,
78
79    /// Configuration related to sending monitoring data
80    #[serde(default, skip_serializing_if = "TelemetryConfig::is_default")]
81    pub telemetry: TelemetryConfig,
82
83    /// Configuration related to templates
84    #[serde(default, skip_serializing_if = "TemplatesConfig::is_default")]
85    pub templates: TemplatesConfig,
86
87    /// Configuration related to sending emails
88    #[serde(default)]
89    pub email: EmailConfig,
90
91    /// Application secrets
92    pub secrets: SecretsConfig,
93
94    /// Configuration related to user passwords
95    #[serde(default)]
96    pub passwords: PasswordsConfig,
97
98    /// Configuration related to the homeserver
99    pub matrix: MatrixConfig,
100
101    /// Configuration related to the OPA policies
102    #[serde(default, skip_serializing_if = "PolicyConfig::is_default")]
103    pub policy: PolicyConfig,
104
105    /// Configuration related to limiting the rate of user actions to prevent
106    /// abuse
107    #[serde(default, skip_serializing_if = "RateLimitingConfig::is_default")]
108    pub rate_limiting: RateLimitingConfig,
109
110    /// Configuration related to upstream OAuth providers
111    #[serde(default, skip_serializing_if = "UpstreamOAuth2Config::is_default")]
112    pub upstream_oauth2: UpstreamOAuth2Config,
113
114    /// Configuration section for tweaking the branding of the service
115    #[serde(default, skip_serializing_if = "BrandingConfig::is_default")]
116    pub branding: BrandingConfig,
117
118    /// Configuration section to setup CAPTCHA protection on a few operations
119    #[serde(default, skip_serializing_if = "CaptchaConfig::is_default")]
120    pub captcha: CaptchaConfig,
121
122    /// Configuration section to configure features related to account
123    /// management
124    #[serde(default, skip_serializing_if = "AccountConfig::is_default")]
125    pub account: AccountConfig,
126
127    /// Experimental configuration options
128    #[serde(default, skip_serializing_if = "ExperimentalConfig::is_default")]
129    pub experimental: ExperimentalConfig,
130}
131
132impl ConfigurationSection for RootConfig {
133    fn validate(&self, figment: &figment::Figment) -> Result<(), figment::Error> {
134        self.clients.validate(figment)?;
135        self.http.validate(figment)?;
136        self.database.validate(figment)?;
137        self.telemetry.validate(figment)?;
138        self.templates.validate(figment)?;
139        self.email.validate(figment)?;
140        self.passwords.validate(figment)?;
141        self.secrets.validate(figment)?;
142        self.matrix.validate(figment)?;
143        self.policy.validate(figment)?;
144        self.rate_limiting.validate(figment)?;
145        self.upstream_oauth2.validate(figment)?;
146        self.branding.validate(figment)?;
147        self.captcha.validate(figment)?;
148        self.account.validate(figment)?;
149        self.experimental.validate(figment)?;
150
151        Ok(())
152    }
153}
154
155impl RootConfig {
156    /// Generate a new configuration with random secrets
157    ///
158    /// # Errors
159    ///
160    /// Returns an error if the secrets could not be generated
161    pub async fn generate<R>(mut rng: R) -> anyhow::Result<Self>
162    where
163        R: Rng + Send,
164    {
165        Ok(Self {
166            clients: ClientsConfig::default(),
167            http: HttpConfig::default(),
168            database: DatabaseConfig::default(),
169            telemetry: TelemetryConfig::default(),
170            templates: TemplatesConfig::default(),
171            email: EmailConfig::default(),
172            passwords: PasswordsConfig::default(),
173            secrets: SecretsConfig::generate(&mut rng).await?,
174            matrix: MatrixConfig::generate(&mut rng),
175            policy: PolicyConfig::default(),
176            rate_limiting: RateLimitingConfig::default(),
177            upstream_oauth2: UpstreamOAuth2Config::default(),
178            branding: BrandingConfig::default(),
179            captcha: CaptchaConfig::default(),
180            account: AccountConfig::default(),
181            experimental: ExperimentalConfig::default(),
182        })
183    }
184
185    /// Configuration used in tests
186    #[must_use]
187    pub fn test() -> Self {
188        Self {
189            clients: ClientsConfig::default(),
190            http: HttpConfig::default(),
191            database: DatabaseConfig::default(),
192            telemetry: TelemetryConfig::default(),
193            templates: TemplatesConfig::default(),
194            passwords: PasswordsConfig::default(),
195            email: EmailConfig::default(),
196            secrets: SecretsConfig::test(),
197            matrix: MatrixConfig::test(),
198            policy: PolicyConfig::default(),
199            rate_limiting: RateLimitingConfig::default(),
200            upstream_oauth2: UpstreamOAuth2Config::default(),
201            branding: BrandingConfig::default(),
202            captcha: CaptchaConfig::default(),
203            account: AccountConfig::default(),
204            experimental: ExperimentalConfig::default(),
205        }
206    }
207}
208
209/// Partial configuration actually used by the server
210#[allow(missing_docs)]
211#[derive(Debug, Deserialize)]
212pub struct AppConfig {
213    #[serde(default)]
214    pub http: HttpConfig,
215
216    #[serde(default)]
217    pub database: DatabaseConfig,
218
219    #[serde(default)]
220    pub templates: TemplatesConfig,
221
222    #[serde(default)]
223    pub email: EmailConfig,
224
225    pub secrets: SecretsConfig,
226
227    #[serde(default)]
228    pub passwords: PasswordsConfig,
229
230    pub matrix: MatrixConfig,
231
232    #[serde(default)]
233    pub policy: PolicyConfig,
234
235    #[serde(default)]
236    pub rate_limiting: RateLimitingConfig,
237
238    #[serde(default)]
239    pub branding: BrandingConfig,
240
241    #[serde(default)]
242    pub captcha: CaptchaConfig,
243
244    #[serde(default)]
245    pub account: AccountConfig,
246
247    #[serde(default)]
248    pub experimental: ExperimentalConfig,
249}
250
251impl ConfigurationSection for AppConfig {
252    fn validate(&self, figment: &figment::Figment) -> Result<(), figment::Error> {
253        self.http.validate(figment)?;
254        self.database.validate(figment)?;
255        self.templates.validate(figment)?;
256        self.email.validate(figment)?;
257        self.passwords.validate(figment)?;
258        self.secrets.validate(figment)?;
259        self.matrix.validate(figment)?;
260        self.policy.validate(figment)?;
261        self.rate_limiting.validate(figment)?;
262        self.branding.validate(figment)?;
263        self.captcha.validate(figment)?;
264        self.account.validate(figment)?;
265        self.experimental.validate(figment)?;
266
267        Ok(())
268    }
269}
270
271/// Partial config used by the `mas-cli config sync` command
272#[allow(missing_docs)]
273#[derive(Debug, Deserialize)]
274pub struct SyncConfig {
275    #[serde(default)]
276    pub database: DatabaseConfig,
277
278    pub secrets: SecretsConfig,
279
280    #[serde(default)]
281    pub clients: ClientsConfig,
282
283    #[serde(default)]
284    pub upstream_oauth2: UpstreamOAuth2Config,
285}
286
287impl ConfigurationSection for SyncConfig {
288    fn validate(&self, figment: &figment::Figment) -> Result<(), figment::Error> {
289        self.database.validate(figment)?;
290        self.secrets.validate(figment)?;
291        self.clients.validate(figment)?;
292        self.upstream_oauth2.validate(figment)?;
293
294        Ok(())
295    }
296}