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