ruma_client_api/uiaa/
auth_params.rs

1//! Authentication parameters types for the different [`AuthType`]s.
2
3use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6
7mod params_serde;
8
9/// Parameters for the terms of service flow.
10///
11/// This type is only valid during account registration.
12///
13/// See [the spec] for how to use this.
14///
15/// [the spec]: https://spec.matrix.org/latest/client-server-api/#terms-of-service-at-registration
16#[derive(Clone, Debug, Default, Deserialize, Serialize)]
17#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
18pub struct LoginTermsParams {
19    /// A map from policy ID to the current definition of this policy document.
20    pub policies: BTreeMap<String, PolicyDefinition>,
21}
22
23impl LoginTermsParams {
24    /// Construct a new `LoginTermsParams` with the given policy documents.
25    pub fn new(policies: BTreeMap<String, PolicyDefinition>) -> Self {
26        Self { policies }
27    }
28}
29
30/// The definition of a policy document.
31#[derive(Clone, Debug, Serialize)]
32#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
33pub struct PolicyDefinition {
34    /// The version of this policy document.
35    pub version: String,
36
37    /// Map from language codes to details of the document in that language.
38    ///
39    /// Language codes SHOULD be formatted as per Section 2.2 of RFC 5646, though some
40    /// implementations may use an underscore instead of dash (for example, en_US instead of
41    /// en-US).
42    #[serde(flatten)]
43    pub translations: BTreeMap<String, PolicyTranslation>,
44}
45
46impl PolicyDefinition {
47    /// Construct a new `PolicyDefinition` with the given version and translations.
48    pub fn new(version: String, translations: BTreeMap<String, PolicyTranslation>) -> Self {
49        Self { version, translations }
50    }
51}
52
53/// Details about a translation of a policy document.
54#[derive(Clone, Debug, Deserialize, Serialize)]
55#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
56pub struct PolicyTranslation {
57    /// The name of this document, in the appropriate language.
58    pub name: String,
59
60    /// A link to the text of this document, in the appropriate language.
61    ///
62    /// MUST be a valid URI with scheme `https://` or `http://`. Insecure HTTP is discouraged..
63    pub url: String,
64}
65
66impl PolicyTranslation {
67    /// Construct a new `PolicyTranslation` with the given name and URL.
68    pub fn new(name: String, url: String) -> Self {
69        Self { name, url }
70    }
71}
72
73/// Parameters for an [OAuth 2.0-based] UIAA flow.
74///
75/// [OAuth 2.0-based]: https://spec.matrix.org/latest/client-server-api/#oauth-authentication
76#[derive(Clone, Debug, Deserialize, Serialize)]
77#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
78pub struct OAuthParams {
79    /// A URL pointing to the homeserver’s OAuth 2.0 account management web UI where the user can
80    /// approve the action.
81    ///
82    /// Must be a valid URI with scheme `http://` or `https://`, the latter being recommended.
83    pub url: String,
84}
85
86impl OAuthParams {
87    /// Construct an `OAuthParams` with the given URL.
88    pub fn new(url: String) -> Self {
89        Self { url }
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
96
97    use super::{LoginTermsParams, PolicyDefinition, PolicyTranslation};
98
99    #[test]
100    fn serialize_login_terms_params() {
101        let privacy_definition = PolicyDefinition::new(
102            "1".to_owned(),
103            [
104                (
105                    "en-US".to_owned(),
106                    PolicyTranslation::new(
107                        "Privacy Policy".to_owned(),
108                        "http://matrix.local/en-US/privacy".to_owned(),
109                    ),
110                ),
111                (
112                    "fr-FR".to_owned(),
113                    PolicyTranslation::new(
114                        "Politique de confidentialité".to_owned(),
115                        "http://matrix.local/fr-FR/privacy".to_owned(),
116                    ),
117                ),
118            ]
119            .into(),
120        );
121        let params = LoginTermsParams::new([("privacy".to_owned(), privacy_definition)].into());
122
123        assert_eq!(
124            to_json_value(&params).unwrap(),
125            json!({
126                "policies": {
127                    "privacy": {
128                        "en-US": {
129                            "name": "Privacy Policy",
130                            "url": "http://matrix.local/en-US/privacy",
131                        },
132                        "fr-FR": {
133                            "name": "Politique de confidentialité",
134                            "url": "http://matrix.local/fr-FR/privacy",
135                        },
136                        "version": "1",
137                    },
138                },
139            })
140        );
141    }
142
143    #[test]
144    fn deserialize_login_terms_params() {
145        // Missing version field in policy.
146        let json = json!({
147            "policies": {
148                "privacy": {
149                    "en-US": {
150                        "name": "Privacy Policy",
151                        "url": "http://matrix.local/en-US/privacy",
152                    },
153                    "fr-FR": {
154                        "name": "Politique de confidentialité",
155                        "url": "http://matrix.local/fr-FR/privacy",
156                    },
157                },
158            },
159        });
160
161        from_json_value::<LoginTermsParams>(json).unwrap_err();
162
163        // Valid params.
164        let json = json!({
165            "policies": {
166                "privacy_policy": {
167                    "en": {
168                        "name": "Privacy Policy",
169                        "url": "https://example.org/somewhere/privacy-1.2-en.html"
170                    },
171                    "fr": {
172                        "name": "Politique de confidentialité",
173                        "url": "https://example.org/somewhere/privacy-1.2-fr.html"
174                    },
175                    // Unsupported field will be ignored.
176                    "foo": "bar",
177                    "version": "1.2",
178                },
179                // No translations is fine.
180                "terms_of_service": {
181                    "version": "1.2",
182                }
183            }
184        });
185
186        let params = from_json_value::<LoginTermsParams>(json).unwrap();
187
188        assert_eq!(params.policies.len(), 2);
189
190        let policy = params.policies.get("privacy_policy").unwrap();
191        assert_eq!(policy.version, "1.2");
192        assert_eq!(policy.translations.len(), 2);
193        let translation = policy.translations.get("en").unwrap();
194        assert_eq!(translation.name, "Privacy Policy");
195        assert_eq!(translation.url, "https://example.org/somewhere/privacy-1.2-en.html");
196        let translation = policy.translations.get("fr").unwrap();
197        assert_eq!(translation.name, "Politique de confidentialité");
198        assert_eq!(translation.url, "https://example.org/somewhere/privacy-1.2-fr.html");
199
200        let policy = params.policies.get("terms_of_service").unwrap();
201        assert_eq!(policy.version, "1.2");
202        assert_eq!(policy.translations.len(), 0);
203    }
204}