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/// See [MSC4312] for how to use this.
76///
77/// [MSC4312]: https://github.com/matrix-org/matrix-spec-proposals/pull/4312
78#[derive(Clone, Debug, Deserialize, Serialize)]
79#[cfg_attr(not(ruma_unstable_exhaustive_types), non_exhaustive)]
80pub struct OAuthParams {
81    /// A URL pointing to the homeserver’s OAuth 2.0 account management web UI where the user can
82    /// approve the action.
83    ///
84    /// Must be a valid URI with scheme `http://` or `https://`, the latter being recommended.
85    pub url: String,
86}
87
88impl OAuthParams {
89    /// Construct an `OAuthParams` with the given URL.
90    pub fn new(url: String) -> Self {
91        Self { url }
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use serde_json::{from_value as from_json_value, json, to_value as to_json_value};
98
99    use super::{LoginTermsParams, PolicyDefinition, PolicyTranslation};
100
101    #[test]
102    fn serialize_login_terms_params() {
103        let privacy_definition = PolicyDefinition::new(
104            "1".to_owned(),
105            [
106                (
107                    "en-US".to_owned(),
108                    PolicyTranslation::new(
109                        "Privacy Policy".to_owned(),
110                        "http://matrix.local/en-US/privacy".to_owned(),
111                    ),
112                ),
113                (
114                    "fr-FR".to_owned(),
115                    PolicyTranslation::new(
116                        "Politique de confidentialité".to_owned(),
117                        "http://matrix.local/fr-FR/privacy".to_owned(),
118                    ),
119                ),
120            ]
121            .into(),
122        );
123        let params = LoginTermsParams::new([("privacy".to_owned(), privacy_definition)].into());
124
125        assert_eq!(
126            to_json_value(&params).unwrap(),
127            json!({
128                "policies": {
129                    "privacy": {
130                        "en-US": {
131                            "name": "Privacy Policy",
132                            "url": "http://matrix.local/en-US/privacy",
133                        },
134                        "fr-FR": {
135                            "name": "Politique de confidentialité",
136                            "url": "http://matrix.local/fr-FR/privacy",
137                        },
138                        "version": "1",
139                    },
140                },
141            })
142        );
143    }
144
145    #[test]
146    fn deserialize_login_terms_params() {
147        // Missing version field in policy.
148        let json = json!({
149            "policies": {
150                "privacy": {
151                    "en-US": {
152                        "name": "Privacy Policy",
153                        "url": "http://matrix.local/en-US/privacy",
154                    },
155                    "fr-FR": {
156                        "name": "Politique de confidentialité",
157                        "url": "http://matrix.local/fr-FR/privacy",
158                    },
159                },
160            },
161        });
162
163        from_json_value::<LoginTermsParams>(json).unwrap_err();
164
165        // Valid params.
166        let json = json!({
167            "policies": {
168                "privacy_policy": {
169                    "en": {
170                        "name": "Privacy Policy",
171                        "url": "https://example.org/somewhere/privacy-1.2-en.html"
172                    },
173                    "fr": {
174                        "name": "Politique de confidentialité",
175                        "url": "https://example.org/somewhere/privacy-1.2-fr.html"
176                    },
177                    // Unsupported field will be ignored.
178                    "foo": "bar",
179                    "version": "1.2",
180                },
181                // No translations is fine.
182                "terms_of_service": {
183                    "version": "1.2",
184                }
185            }
186        });
187
188        let params = from_json_value::<LoginTermsParams>(json).unwrap();
189
190        assert_eq!(params.policies.len(), 2);
191
192        let policy = params.policies.get("privacy_policy").unwrap();
193        assert_eq!(policy.version, "1.2");
194        assert_eq!(policy.translations.len(), 2);
195        let translation = policy.translations.get("en").unwrap();
196        assert_eq!(translation.name, "Privacy Policy");
197        assert_eq!(translation.url, "https://example.org/somewhere/privacy-1.2-en.html");
198        let translation = policy.translations.get("fr").unwrap();
199        assert_eq!(translation.name, "Politique de confidentialité");
200        assert_eq!(translation.url, "https://example.org/somewhere/privacy-1.2-fr.html");
201
202        let policy = params.policies.get("terms_of_service").unwrap();
203        assert_eq!(policy.version, "1.2");
204        assert_eq!(policy.translations.len(), 0);
205    }
206}