mas_config/sections/
mod.rs

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