@@ -70,18 +70,31 @@ pub fn routes() -> Vec<rocket::Route> {
70
70
#[ serde( rename_all = "camelCase" ) ]
71
71
pub struct RegisterData {
72
72
email : String ,
73
+
73
74
kdf : Option < i32 > ,
74
75
kdf_iterations : Option < i32 > ,
75
76
kdf_memory : Option < i32 > ,
76
77
kdf_parallelism : Option < i32 > ,
78
+
79
+ #[ serde( alias = "userSymmetricKey" ) ]
77
80
key : String ,
81
+ #[ serde( alias = "userAsymmetricKeys" ) ]
78
82
keys : Option < KeysData > ,
83
+
79
84
master_password_hash : String ,
80
85
master_password_hint : Option < String > ,
86
+
81
87
name : Option < String > ,
82
- token : Option < String > ,
88
+
83
89
#[ allow( dead_code) ]
84
90
organization_user_id : Option < MembershipId > ,
91
+
92
+ // Used only from the register/finish endpoint
93
+ email_verification_token : Option < String > ,
94
+ accept_emergency_access_id : Option < EmergencyAccessId > ,
95
+ accept_emergency_access_invite_token : Option < String > ,
96
+ #[ serde( alias = "token" ) ]
97
+ org_invite_token : Option < String > ,
85
98
}
86
99
87
100
#[ derive( Debug , Deserialize ) ]
@@ -124,13 +137,78 @@ async fn is_email_2fa_required(member_id: Option<MembershipId>, conn: &mut DbCon
124
137
125
138
#[ post( "/accounts/register" , data = "<data>" ) ]
126
139
async fn register ( data : Json < RegisterData > , conn : DbConn ) -> JsonResult {
127
- _register ( data, conn) . await
140
+ _register ( data, false , conn) . await
128
141
}
129
142
130
- pub async fn _register ( data : Json < RegisterData > , mut conn : DbConn ) -> JsonResult {
131
- let data: RegisterData = data. into_inner ( ) ;
143
+ pub async fn _register ( data : Json < RegisterData > , email_verification : bool , mut conn : DbConn ) -> JsonResult {
144
+ let mut data: RegisterData = data. into_inner ( ) ;
132
145
let email = data. email . to_lowercase ( ) ;
133
146
147
+ let mut email_verified = false ;
148
+
149
+ let mut pending_emergency_access = None ;
150
+
151
+ // First, validate the provided verification tokens
152
+ if email_verification {
153
+ match (
154
+ & data. email_verification_token ,
155
+ & data. accept_emergency_access_id ,
156
+ & data. accept_emergency_access_invite_token ,
157
+ & data. organization_user_id ,
158
+ & data. org_invite_token ,
159
+ ) {
160
+ // Normal user registration, when email verification is required
161
+ ( Some ( email_verification_token) , None , None , None , None ) => {
162
+ let claims = crate :: auth:: decode_register_verify ( email_verification_token) ?;
163
+ if claims. sub != data. email {
164
+ err ! ( "Email verification token does not match email" ) ;
165
+ }
166
+
167
+ // During this call we don't get the name, so extract it from the claims
168
+ if claims. name . is_some ( ) {
169
+ data. name = claims. name ;
170
+ }
171
+ email_verified = claims. verified ;
172
+ }
173
+ // Emergency access registration
174
+ ( None , Some ( accept_emergency_access_id) , Some ( accept_emergency_access_invite_token) , None , None ) => {
175
+ if !CONFIG . emergency_access_allowed ( ) {
176
+ err ! ( "Emergency access is not enabled." )
177
+ }
178
+
179
+ let claims = crate :: auth:: decode_emergency_access_invite ( accept_emergency_access_invite_token) ?;
180
+
181
+ if claims. email != data. email {
182
+ err ! ( "Claim email does not match email" )
183
+ }
184
+ if & claims. emer_id != accept_emergency_access_id {
185
+ err ! ( "Claim emer_id does not match accept_emergency_access_id" )
186
+ }
187
+
188
+ pending_emergency_access = Some ( ( accept_emergency_access_id, claims) ) ;
189
+ email_verified = true ;
190
+ }
191
+ // Org invite
192
+ ( None , None , None , Some ( organization_user_id) , Some ( org_invite_token) ) => {
193
+ let claims = decode_invite ( org_invite_token) ?;
194
+
195
+ if claims. email != data. email {
196
+ err ! ( "Claim email does not match email" )
197
+ }
198
+
199
+ if & claims. member_id != organization_user_id {
200
+ err ! ( "Claim org_user_id does not match organization_user_id" )
201
+ }
202
+
203
+ email_verified = true ;
204
+ }
205
+
206
+ _ => {
207
+ err ! ( "Registration is missing required parameters" )
208
+ }
209
+ }
210
+ }
211
+
134
212
// Check if the length of the username exceeds 50 characters (Same is Upstream Bitwarden)
135
213
// This also prevents issues with very long usernames causing to large JWT's. See #2419
136
214
if let Some ( ref name) = data. name {
@@ -144,20 +222,17 @@ pub async fn _register(data: Json<RegisterData>, mut conn: DbConn) -> JsonResult
144
222
let password_hint = clean_password_hint ( & data. master_password_hint ) ;
145
223
enforce_password_hint_setting ( & password_hint) ?;
146
224
147
- let mut verified_by_invite = false ;
148
-
149
225
let mut user = match User :: find_by_mail ( & email, & mut conn) . await {
150
- Some ( mut user) => {
226
+ Some ( user) => {
151
227
if !user. password_hash . is_empty ( ) {
152
228
err ! ( "Registration not allowed or user already exists" )
153
229
}
154
230
155
- if let Some ( token) = data. token {
231
+ if let Some ( token) = data. org_invite_token {
156
232
let claims = decode_invite ( & token) ?;
157
233
if claims. email == email {
158
234
// Verify the email address when signing up via a valid invite token
159
- verified_by_invite = true ;
160
- user. verified_at = Some ( Utc :: now ( ) . naive_utc ( ) ) ;
235
+ email_verified = true ;
161
236
user
162
237
} else {
163
238
err ! ( "Registration email does not match invite email" )
@@ -181,7 +256,10 @@ pub async fn _register(data: Json<RegisterData>, mut conn: DbConn) -> JsonResult
181
256
// Order is important here; the invitation check must come first
182
257
// because the vaultwarden admin can invite anyone, regardless
183
258
// of other signup restrictions.
184
- if Invitation :: take ( & email, & mut conn) . await || CONFIG . is_signup_allowed ( & email) {
259
+ if Invitation :: take ( & email, & mut conn) . await
260
+ || CONFIG . is_signup_allowed ( & email)
261
+ || pending_emergency_access. is_some ( )
262
+ {
185
263
User :: new ( email. clone ( ) )
186
264
} else {
187
265
err ! ( "Registration not allowed or user already exists" )
@@ -216,8 +294,12 @@ pub async fn _register(data: Json<RegisterData>, mut conn: DbConn) -> JsonResult
216
294
user. public_key = Some ( keys. public_key ) ;
217
295
}
218
296
297
+ if email_verified {
298
+ user. verified_at = Some ( Utc :: now ( ) . naive_utc ( ) ) ;
299
+ }
300
+
219
301
if CONFIG . mail_enabled ( ) {
220
- if CONFIG . signups_verify ( ) && !verified_by_invite {
302
+ if CONFIG . signups_verify ( ) && !email_verified {
221
303
if let Err ( e) = mail:: send_welcome_must_verify ( & user. email , & user. uuid ) . await {
222
304
error ! ( "Error sending welcome email: {:#?}" , e) ;
223
305
}
@@ -226,7 +308,7 @@ pub async fn _register(data: Json<RegisterData>, mut conn: DbConn) -> JsonResult
226
308
error ! ( "Error sending welcome email: {:#?}" , e) ;
227
309
}
228
310
229
- if verified_by_invite && is_email_2fa_required ( data. organization_user_id , & mut conn) . await {
311
+ if email_verified && is_email_2fa_required ( data. organization_user_id , & mut conn) . await {
230
312
email:: activate_email_2fa ( & user, & mut conn) . await . ok ( ) ;
231
313
}
232
314
}
0 commit comments