mas_storage/user/registration.rs
1// Copyright 2025, 2026 Element Creations Ltd.
2// Copyright 2025 New Vector Ltd.
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 std::net::IpAddr;
8
9use async_trait::async_trait;
10use mas_data_model::{
11 Clock, UpstreamOAuthAuthorizationSession, UserEmailAuthentication, UserRegistration,
12 UserRegistrationToken,
13};
14use rand_core::RngCore;
15use ulid::Ulid;
16use url::Url;
17
18use crate::repository_impl;
19
20/// A [`UserRegistrationRepository`] helps interacting with [`UserRegistration`]
21/// saved in the storage backend
22#[async_trait]
23pub trait UserRegistrationRepository: Send + Sync {
24 /// The error type returned by the repository
25 type Error;
26
27 /// Lookup a [`UserRegistration`] by its ID
28 ///
29 /// Returns `None` if no [`UserRegistration`] was found
30 ///
31 /// # Parameters
32 ///
33 /// * `id`: The ID of the [`UserRegistration`] to lookup
34 ///
35 /// # Errors
36 ///
37 /// Returns [`Self::Error`] if the underlying repository fails
38 async fn lookup(&mut self, id: Ulid) -> Result<Option<UserRegistration>, Self::Error>;
39
40 /// Create a new [`UserRegistration`] session
41 ///
42 /// Returns the newly created [`UserRegistration`]
43 ///
44 /// # Parameters
45 ///
46 /// * `rng`: The random number generator to use
47 /// * `clock`: The clock used to generate timestamps
48 /// * `username`: The username of the user
49 /// * `ip_address`: The IP address of the user agent, if any
50 /// * `user_agent`: The user agent of the user agent, if any
51 /// * `post_auth_action`: The post auth action to execute after the
52 /// registration, if any
53 ///
54 /// # Errors
55 ///
56 /// Returns [`Self::Error`] if the underlying repository fails
57 async fn add(
58 &mut self,
59 rng: &mut (dyn RngCore + Send),
60 clock: &dyn Clock,
61 username: String,
62 ip_address: Option<IpAddr>,
63 user_agent: Option<String>,
64 post_auth_action: Option<serde_json::Value>,
65 ) -> Result<UserRegistration, Self::Error>;
66
67 /// Set the display name of a [`UserRegistration`]
68 ///
69 /// Returns the updated [`UserRegistration`]
70 ///
71 /// # Parameters
72 ///
73 /// * `user_registration`: The [`UserRegistration`] to update
74 /// * `display_name`: The display name to set
75 ///
76 /// # Errors
77 ///
78 /// Returns [`Self::Error`] if the underlying repository fails or if the
79 /// registration is already completed
80 async fn set_display_name(
81 &mut self,
82 user_registration: UserRegistration,
83 display_name: String,
84 ) -> Result<UserRegistration, Self::Error>;
85
86 /// Set the terms URL of a [`UserRegistration`]
87 ///
88 /// Returns the updated [`UserRegistration`]
89 ///
90 /// # Parameters
91 ///
92 /// * `user_registration`: The [`UserRegistration`] to update
93 /// * `terms_url`: The terms URL to set
94 ///
95 /// # Errors
96 ///
97 /// Returns [`Self::Error`] if the underlying repository fails or if the
98 /// registration is already completed
99 async fn set_terms_url(
100 &mut self,
101 user_registration: UserRegistration,
102 terms_url: Url,
103 ) -> Result<UserRegistration, Self::Error>;
104
105 /// Set the email authentication code of a [`UserRegistration`]
106 ///
107 /// Returns the updated [`UserRegistration`]
108 ///
109 /// # Parameters
110 ///
111 /// * `user_registration`: The [`UserRegistration`] to update
112 /// * `email_authentication`: The [`UserEmailAuthentication`] to set
113 ///
114 /// # Errors
115 ///
116 /// Returns [`Self::Error`] if the underlying repository fails or if the
117 /// registration is already completed
118 async fn set_email_authentication(
119 &mut self,
120 user_registration: UserRegistration,
121 email_authentication: &UserEmailAuthentication,
122 ) -> Result<UserRegistration, Self::Error>;
123
124 /// Set the password of a [`UserRegistration`]
125 ///
126 /// Returns the updated [`UserRegistration`]
127 ///
128 /// # Parameters
129 ///
130 /// * `user_registration`: The [`UserRegistration`] to update
131 /// * `hashed_password`: The hashed password to set
132 /// * `version`: The version of the hashing scheme
133 ///
134 /// # Errors
135 ///
136 /// Returns [`Self::Error`] if the underlying repository fails or if the
137 /// registration is already completed
138 async fn set_password(
139 &mut self,
140 user_registration: UserRegistration,
141 hashed_password: String,
142 version: u16,
143 ) -> Result<UserRegistration, Self::Error>;
144
145 /// Set the registration token of a [`UserRegistration`]
146 ///
147 /// Returns the updated [`UserRegistration`]
148 ///
149 /// # Parameters
150 ///
151 /// * `user_registration`: The [`UserRegistration`] to update
152 /// * `user_registration_token`: The [`UserRegistrationToken`] to set
153 ///
154 /// # Errors
155 ///
156 /// Returns [`Self::Error`] if the underlying repository fails or if the
157 /// registration is already completed
158 async fn set_registration_token(
159 &mut self,
160 user_registration: UserRegistration,
161 user_registration_token: &UserRegistrationToken,
162 ) -> Result<UserRegistration, Self::Error>;
163
164 /// Set an [`UpstreamOAuthAuthorizationSession`] to associate with a
165 /// [`UserRegistration`]
166 ///
167 /// Returns the updated [`UserRegistration`]
168 ///
169 /// # Parameters
170 ///
171 /// * `user_registration`: The [`UserRegistration`] to update
172 /// * `upstream_oauth_authorization_session`: The
173 /// [`UpstreamOAuthAuthorizationSession`] to set
174 ///
175 /// # Errors
176 ///
177 /// Returns [`Self::Error`] if the underlying repository fails or if the
178 /// registration is already completed
179 async fn set_upstream_oauth_authorization_session(
180 &mut self,
181 user_registration: UserRegistration,
182 upstream_oauth_authorization_session: &UpstreamOAuthAuthorizationSession,
183 ) -> Result<UserRegistration, Self::Error>;
184
185 /// Complete a [`UserRegistration`]
186 ///
187 /// Returns the updated [`UserRegistration`]
188 ///
189 /// # Parameters
190 ///
191 /// * `clock`: The clock used to generate timestamps
192 /// * `user_registration`: The [`UserRegistration`] to complete
193 ///
194 /// # Errors
195 ///
196 /// Returns [`Self::Error`] if the underlying repository fails or if the
197 /// registration is already completed
198 async fn complete(
199 &mut self,
200 clock: &dyn Clock,
201 user_registration: UserRegistration,
202 ) -> Result<UserRegistration, Self::Error>;
203
204 /// Cleanup [`UserRegistration`]s between the given IDs.
205 ///
206 /// Returns the number of registrations deleted, as well as the ID of the
207 /// last registration deleted.
208 ///
209 /// # Parameters
210 ///
211 /// * `since`: An optional ID to start from
212 /// * `until`: The ID until which to clean up registrations
213 /// * `limit`: The maximum number of registrations to clean up
214 ///
215 /// # Errors
216 ///
217 /// Returns [`Self::Error`] if the underlying repository fails
218 async fn cleanup(
219 &mut self,
220 since: Option<Ulid>,
221 until: Ulid,
222 limit: usize,
223 ) -> Result<(usize, Option<Ulid>), Self::Error>;
224}
225
226repository_impl!(UserRegistrationRepository:
227 async fn lookup(&mut self, id: Ulid) -> Result<Option<UserRegistration>, Self::Error>;
228 async fn add(
229 &mut self,
230 rng: &mut (dyn RngCore + Send),
231 clock: &dyn Clock,
232 username: String,
233 ip_address: Option<IpAddr>,
234 user_agent: Option<String>,
235 post_auth_action: Option<serde_json::Value>,
236 ) -> Result<UserRegistration, Self::Error>;
237 async fn set_display_name(
238 &mut self,
239 user_registration: UserRegistration,
240 display_name: String,
241 ) -> Result<UserRegistration, Self::Error>;
242 async fn set_terms_url(
243 &mut self,
244 user_registration: UserRegistration,
245 terms_url: Url,
246 ) -> Result<UserRegistration, Self::Error>;
247 async fn set_email_authentication(
248 &mut self,
249 user_registration: UserRegistration,
250 email_authentication: &UserEmailAuthentication,
251 ) -> Result<UserRegistration, Self::Error>;
252 async fn set_password(
253 &mut self,
254 user_registration: UserRegistration,
255 hashed_password: String,
256 version: u16,
257 ) -> Result<UserRegistration, Self::Error>;
258 async fn set_registration_token(
259 &mut self,
260 user_registration: UserRegistration,
261 user_registration_token: &UserRegistrationToken,
262 ) -> Result<UserRegistration, Self::Error>;
263 async fn set_upstream_oauth_authorization_session(
264 &mut self,
265 user_registration: UserRegistration,
266 upstream_oauth_authorization_session: &UpstreamOAuthAuthorizationSession,
267 ) -> Result<UserRegistration, Self::Error>;
268 async fn complete(
269 &mut self,
270 clock: &dyn Clock,
271 user_registration: UserRegistration,
272 ) -> Result<UserRegistration, Self::Error>;
273 async fn cleanup(
274 &mut self,
275 since: Option<Ulid>,
276 until: Ulid,
277 limit: usize,
278 ) -> Result<(usize, Option<Ulid>), Self::Error>;
279);