mas_storage/user/
registration.rs

1// Copyright 2025 New Vector Ltd.
2//
3// SPDX-License-Identifier: AGPL-3.0-only
4// Please see LICENSE in the repository root for full details.
5
6use std::net::IpAddr;
7
8use async_trait::async_trait;
9use mas_data_model::{UserAgent, UserEmailAuthentication, UserRegistration};
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<UserAgent>,
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    /// Complete a [`UserRegistration`]
142    ///
143    /// Returns the updated [`UserRegistration`]
144    ///
145    /// # Parameters
146    ///
147    /// * `clock`: The clock used to generate timestamps
148    /// * `user_registration`: The [`UserRegistration`] to complete
149    ///
150    /// # Errors
151    ///
152    /// Returns [`Self::Error`] if the underlying repository fails or if the
153    /// registration is already completed
154    async fn complete(
155        &mut self,
156        clock: &dyn Clock,
157        user_registration: UserRegistration,
158    ) -> Result<UserRegistration, Self::Error>;
159}
160
161repository_impl!(UserRegistrationRepository:
162    async fn lookup(&mut self, id: Ulid) -> Result<Option<UserRegistration>, Self::Error>;
163    async fn add(
164        &mut self,
165        rng: &mut (dyn RngCore + Send),
166        clock: &dyn Clock,
167        username: String,
168        ip_address: Option<IpAddr>,
169        user_agent: Option<UserAgent>,
170        post_auth_action: Option<serde_json::Value>,
171    ) -> Result<UserRegistration, Self::Error>;
172    async fn set_display_name(
173        &mut self,
174        user_registration: UserRegistration,
175        display_name: String,
176    ) -> Result<UserRegistration, Self::Error>;
177    async fn set_terms_url(
178        &mut self,
179        user_registration: UserRegistration,
180        terms_url: Url,
181    ) -> Result<UserRegistration, Self::Error>;
182    async fn set_email_authentication(
183        &mut self,
184        user_registration: UserRegistration,
185        email_authentication: &UserEmailAuthentication,
186    ) -> Result<UserRegistration, Self::Error>;
187    async fn set_password(
188        &mut self,
189        user_registration: UserRegistration,
190        hashed_password: String,
191        version: u16,
192    ) -> Result<UserRegistration, Self::Error>;
193    async fn complete(
194        &mut self,
195        clock: &dyn Clock,
196        user_registration: UserRegistration,
197    ) -> Result<UserRegistration, Self::Error>;
198);