mas_storage/user/
registration.rs

1// Copyright 2025 New Vector Ltd.
2//
3// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
4// Please see LICENSE files in the repository root for full details.
5
6use std::net::IpAddr;
7
8use async_trait::async_trait;
9use mas_data_model::{UserEmailAuthentication, UserRegistration, UserRegistrationToken};
10use rand_core::RngCore;
11use ulid::Ulid;
12use url::Url;
13
14use crate::{Clock, repository_impl};
15
16/// A [`UserRegistrationRepository`] helps interacting with [`UserRegistration`]
17/// saved in the storage backend
18#[async_trait]
19pub trait UserRegistrationRepository: Send + Sync {
20    /// The error type returned by the repository
21    type Error;
22
23    /// Lookup a [`UserRegistration`] by its ID
24    ///
25    /// Returns `None` if no [`UserRegistration`] was found
26    ///
27    /// # Parameters
28    ///
29    /// * `id`: The ID of the [`UserRegistration`] to lookup
30    ///
31    /// # Errors
32    ///
33    /// Returns [`Self::Error`] if the underlying repository fails
34    async fn lookup(&mut self, id: Ulid) -> Result<Option<UserRegistration>, Self::Error>;
35
36    /// Create a new [`UserRegistration`] session
37    ///
38    /// Returns the newly created [`UserRegistration`]
39    ///
40    /// # Parameters
41    ///
42    /// * `rng`: The random number generator to use
43    /// * `clock`: The clock used to generate timestamps
44    /// * `username`: The username of the user
45    /// * `ip_address`: The IP address of the user agent, if any
46    /// * `user_agent`: The user agent of the user agent, if any
47    /// * `post_auth_action`: The post auth action to execute after the
48    ///   registration, if any
49    ///
50    /// # Errors
51    ///
52    /// Returns [`Self::Error`] if the underlying repository fails
53    async fn add(
54        &mut self,
55        rng: &mut (dyn RngCore + Send),
56        clock: &dyn Clock,
57        username: String,
58        ip_address: Option<IpAddr>,
59        user_agent: Option<String>,
60        post_auth_action: Option<serde_json::Value>,
61    ) -> Result<UserRegistration, Self::Error>;
62
63    /// Set the display name of a [`UserRegistration`]
64    ///
65    /// Returns the updated [`UserRegistration`]
66    ///
67    /// # Parameters
68    ///
69    /// * `user_registration`: The [`UserRegistration`] to update
70    /// * `display_name`: The display name to set
71    ///
72    /// # Errors
73    ///
74    /// Returns [`Self::Error`] if the underlying repository fails or if the
75    /// registration is already completed
76    async fn set_display_name(
77        &mut self,
78        user_registration: UserRegistration,
79        display_name: String,
80    ) -> Result<UserRegistration, Self::Error>;
81
82    /// Set the terms URL of a [`UserRegistration`]
83    ///
84    /// Returns the updated [`UserRegistration`]
85    ///
86    /// # Parameters
87    ///
88    /// * `user_registration`: The [`UserRegistration`] to update
89    /// * `terms_url`: The terms URL to set
90    ///
91    /// # Errors
92    ///
93    /// Returns [`Self::Error`] if the underlying repository fails or if the
94    /// registration is already completed
95    async fn set_terms_url(
96        &mut self,
97        user_registration: UserRegistration,
98        terms_url: Url,
99    ) -> Result<UserRegistration, Self::Error>;
100
101    /// Set the email authentication code of a [`UserRegistration`]
102    ///
103    /// Returns the updated [`UserRegistration`]
104    ///
105    /// # Parameters
106    ///
107    /// * `user_registration`: The [`UserRegistration`] to update
108    /// * `email_authentication`: The [`UserEmailAuthentication`] to set
109    ///
110    /// # Errors
111    ///
112    /// Returns [`Self::Error`] if the underlying repository fails or if the
113    /// registration is already completed
114    async fn set_email_authentication(
115        &mut self,
116        user_registration: UserRegistration,
117        email_authentication: &UserEmailAuthentication,
118    ) -> Result<UserRegistration, Self::Error>;
119
120    /// Set the password of a [`UserRegistration`]
121    ///
122    /// Returns the updated [`UserRegistration`]
123    ///
124    /// # Parameters
125    ///
126    /// * `user_registration`: The [`UserRegistration`] to update
127    /// * `hashed_password`: The hashed password to set
128    /// * `version`: The version of the hashing scheme
129    ///
130    /// # Errors
131    ///
132    /// Returns [`Self::Error`] if the underlying repository fails or if the
133    /// registration is already completed
134    async fn set_password(
135        &mut self,
136        user_registration: UserRegistration,
137        hashed_password: String,
138        version: u16,
139    ) -> Result<UserRegistration, Self::Error>;
140
141    /// Set the registration token of a [`UserRegistration`]
142    ///
143    /// Returns the updated [`UserRegistration`]
144    ///
145    /// # Parameters
146    ///
147    /// * `user_registration`: The [`UserRegistration`] to update
148    /// * `user_registration_token`: The [`UserRegistrationToken`] to set
149    ///
150    /// # Errors
151    ///
152    /// Returns [`Self::Error`] if the underlying repository fails or if the
153    /// registration is already completed
154    async fn set_registration_token(
155        &mut self,
156        user_registration: UserRegistration,
157        user_registration_token: &UserRegistrationToken,
158    ) -> Result<UserRegistration, Self::Error>;
159
160    /// Complete a [`UserRegistration`]
161    ///
162    /// Returns the updated [`UserRegistration`]
163    ///
164    /// # Parameters
165    ///
166    /// * `clock`: The clock used to generate timestamps
167    /// * `user_registration`: The [`UserRegistration`] to complete
168    ///
169    /// # Errors
170    ///
171    /// Returns [`Self::Error`] if the underlying repository fails or if the
172    /// registration is already completed
173    async fn complete(
174        &mut self,
175        clock: &dyn Clock,
176        user_registration: UserRegistration,
177    ) -> Result<UserRegistration, Self::Error>;
178}
179
180repository_impl!(UserRegistrationRepository:
181    async fn lookup(&mut self, id: Ulid) -> Result<Option<UserRegistration>, Self::Error>;
182    async fn add(
183        &mut self,
184        rng: &mut (dyn RngCore + Send),
185        clock: &dyn Clock,
186        username: String,
187        ip_address: Option<IpAddr>,
188        user_agent: Option<String>,
189        post_auth_action: Option<serde_json::Value>,
190    ) -> Result<UserRegistration, Self::Error>;
191    async fn set_display_name(
192        &mut self,
193        user_registration: UserRegistration,
194        display_name: String,
195    ) -> Result<UserRegistration, Self::Error>;
196    async fn set_terms_url(
197        &mut self,
198        user_registration: UserRegistration,
199        terms_url: Url,
200    ) -> Result<UserRegistration, Self::Error>;
201    async fn set_email_authentication(
202        &mut self,
203        user_registration: UserRegistration,
204        email_authentication: &UserEmailAuthentication,
205    ) -> Result<UserRegistration, Self::Error>;
206    async fn set_password(
207        &mut self,
208        user_registration: UserRegistration,
209        hashed_password: String,
210        version: u16,
211    ) -> Result<UserRegistration, Self::Error>;
212    async fn set_registration_token(
213        &mut self,
214        user_registration: UserRegistration,
215        user_registration_token: &UserRegistrationToken,
216    ) -> Result<UserRegistration, Self::Error>;
217    async fn complete(
218        &mut self,
219        clock: &dyn Clock,
220        user_registration: UserRegistration,
221    ) -> Result<UserRegistration, Self::Error>;
222);