mas_config/sections/
matrix.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::{
8    Rng,
9    distributions::{Alphanumeric, DistString},
10};
11use schemars::JsonSchema;
12use serde::{Deserialize, Serialize};
13use serde_with::serde_as;
14use url::Url;
15
16use super::ConfigurationSection;
17
18fn default_homeserver() -> String {
19    "localhost:8008".to_owned()
20}
21
22fn default_endpoint() -> Url {
23    Url::parse("http://localhost:8008/").unwrap()
24}
25
26/// The kind of homeserver it is.
27#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Default)]
28#[serde(rename_all = "snake_case")]
29pub enum HomeserverKind {
30    /// Homeserver is Synapse, version 1.135.0 or newer
31    #[default]
32    Synapse,
33
34    /// Homeserver is Synapse, version 1.135.0 or newer, in read-only mode
35    ///
36    /// This is meant for testing rolling out Matrix Authentication Service with
37    /// no risk of writing data to the homeserver.
38    SynapseReadOnly,
39
40    /// Homeserver is Synapse, using the legacy API
41    SynapseLegacy,
42
43    /// Homeserver is Synapse, with the modern API available (>= 1.135.0)
44    SynapseModern,
45}
46
47/// Configuration related to the Matrix homeserver
48#[serde_as]
49#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
50pub struct MatrixConfig {
51    /// The kind of homeserver it is.
52    #[serde(default)]
53    pub kind: HomeserverKind,
54
55    /// The server name of the homeserver.
56    #[serde(default = "default_homeserver")]
57    pub homeserver: String,
58
59    /// Shared secret to use for calls to the admin API
60    pub secret: String,
61
62    /// The base URL of the homeserver's client API
63    #[serde(default = "default_endpoint")]
64    pub endpoint: Url,
65}
66
67impl ConfigurationSection for MatrixConfig {
68    const PATH: Option<&'static str> = Some("matrix");
69}
70
71impl MatrixConfig {
72    pub(crate) fn generate<R>(mut rng: R) -> Self
73    where
74        R: Rng + Send,
75    {
76        Self {
77            kind: HomeserverKind::default(),
78            homeserver: default_homeserver(),
79            secret: Alphanumeric.sample_string(&mut rng, 32),
80            endpoint: default_endpoint(),
81        }
82    }
83
84    pub(crate) fn test() -> Self {
85        Self {
86            kind: HomeserverKind::default(),
87            homeserver: default_homeserver(),
88            secret: "test".to_owned(),
89            endpoint: default_endpoint(),
90        }
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use figment::{
97        Figment, Jail,
98        providers::{Format, Yaml},
99    };
100
101    use super::*;
102
103    #[test]
104    fn load_config() {
105        Jail::expect_with(|jail| {
106            jail.create_file(
107                "config.yaml",
108                r"
109                    matrix:
110                      homeserver: matrix.org
111                      secret: test
112                ",
113            )?;
114
115            let config = Figment::new()
116                .merge(Yaml::file("config.yaml"))
117                .extract_inner::<MatrixConfig>("matrix")?;
118
119            assert_eq!(&config.homeserver, "matrix.org");
120            assert_eq!(&config.secret, "test");
121
122            Ok(())
123        });
124    }
125}