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 ruma_common::canonical_json::assert_to_canonical_json_eq;
96    use serde_json::{from_value as from_json_value, json};
97
98    use super::{LoginTermsParams, PolicyDefinition, PolicyTranslation};
99
100    #[test]
101    fn serialize_login_terms_params() {
102        let privacy_definition = PolicyDefinition::new(
103            "1".to_owned(),
104            [
105                (
106                    "en-US".to_owned(),
107                    PolicyTranslation::new(
108                        "Privacy Policy".to_owned(),
109                        "http://matrix.local/en-US/privacy".to_owned(),
110                    ),
111                ),
112                (
113                    "fr-FR".to_owned(),
114                    PolicyTranslation::new(
115                        "Politique de confidentialité".to_owned(),
116                        "http://matrix.local/fr-FR/privacy".to_owned(),
117                    ),
118                ),
119            ]
120            .into(),
121        );
122        let params = LoginTermsParams::new([("privacy".to_owned(), privacy_definition)].into());
123
124        assert_to_canonical_json_eq!(
125            params,
126            json!({
127                "policies": {
128                    "privacy": {
129                        "en-US": {
130                            "name": "Privacy Policy",
131                            "url": "http://matrix.local/en-US/privacy",
132                        },
133                        "fr-FR": {
134                            "name": "Politique de confidentialité",
135                            "url": "http://matrix.local/fr-FR/privacy",
136                        },
137                        "version": "1",
138                    },
139                },
140            })
141        );
142    }
143
144    #[test]
145    fn deserialize_login_terms_params() {
146        // Missing version field in policy.
147        let json = json!({
148            "policies": {
149                "privacy": {
150                    "en-US": {
151                        "name": "Privacy Policy",
152                        "url": "http://matrix.local/en-US/privacy",
153                    },
154                    "fr-FR": {
155                        "name": "Politique de confidentialité",
156                        "url": "http://matrix.local/fr-FR/privacy",
157                    },
158                },
159            },
160        });
161
162        from_json_value::<LoginTermsParams>(json).unwrap_err();
163
164        // Valid params.
165        let json = json!({
166            "policies": {
167                "privacy_policy": {
168                    "en": {
169                        "name": "Privacy Policy",
170                        "url": "https://example.org/somewhere/privacy-1.2-en.html"
171                    },
172                    "fr": {
173                        "name": "Politique de confidentialité",
174                        "url": "https://example.org/somewhere/privacy-1.2-fr.html"
175                    },
176                    // Unsupported field will be ignored.
177                    "foo": "bar",
178                    "version": "1.2",
179                },
180                // No translations is fine.
181                "terms_of_service": {
182                    "version": "1.2",
183                }
184            }
185        });
186
187        let params = from_json_value::<LoginTermsParams>(json).unwrap();
188
189        assert_eq!(params.policies.len(), 2);
190
191        let policy = params.policies.get("privacy_policy").unwrap();
192        assert_eq!(policy.version, "1.2");
193        assert_eq!(policy.translations.len(), 2);
194        let translation = policy.translations.get("en").unwrap();
195        assert_eq!(translation.name, "Privacy Policy");
196        assert_eq!(translation.url, "https://example.org/somewhere/privacy-1.2-en.html");
197        let translation = policy.translations.get("fr").unwrap();
198        assert_eq!(translation.name, "Politique de confidentialité");
199        assert_eq!(translation.url, "https://example.org/somewhere/privacy-1.2-fr.html");
200
201        let policy = params.policies.get("terms_of_service").unwrap();
202        assert_eq!(policy.version, "1.2");
203        assert_eq!(policy.translations.len(), 0);
204    }
205}