bitwarden_core/auth/
register.rs1use bitwarden_api_identity::{
2 apis::accounts_api::accounts_register_post,
3 models::{KeysRequestModel, RegisterRequestModel},
4};
5use bitwarden_crypto::{
6 default_pbkdf2_iterations, CryptoError, EncString, HashPurpose, Kdf, MasterKey, RsaKeyPair,
7};
8use serde::{Deserialize, Serialize};
9use thiserror::Error;
10
11use crate::{ApiError, Client};
12
13#[allow(missing_docs)]
14#[derive(Serialize, Deserialize, Debug)]
15#[serde(rename_all = "camelCase", deny_unknown_fields)]
16pub struct RegisterRequest {
17 pub email: String,
18 pub name: Option<String>,
19 pub password: String,
20 pub password_hint: Option<String>,
21}
22
23#[allow(missing_docs)]
24#[derive(Debug, Error)]
25pub enum RegisterError {
26 #[error(transparent)]
27 Crypto(#[from] CryptoError),
28 #[error(transparent)]
29 Api(#[from] ApiError),
30}
31
32pub(super) async fn register(client: &Client, req: &RegisterRequest) -> Result<(), RegisterError> {
34 let config = client.internal.get_api_configurations().await;
35
36 let kdf = Kdf::default();
37
38 let keys = make_register_keys(req.email.to_owned(), req.password.to_owned(), kdf)?;
39
40 accounts_register_post(
41 &config.identity,
42 Some(RegisterRequestModel {
43 name: req.name.to_owned(),
44 email: req.email.to_owned(),
45 master_password_hash: keys.master_password_hash,
46 master_password_hint: req.password_hint.to_owned(),
47 captcha_response: None, key: Some(keys.encrypted_user_key.to_string()),
49 keys: Some(Box::new(KeysRequestModel {
50 public_key: keys.keys.public,
51 encrypted_private_key: keys.keys.private.to_string(),
52 })),
53 token: None,
54 organization_user_id: None,
55 kdf: Some(bitwarden_api_identity::models::KdfType::PBKDF2_SHA256),
56 kdf_iterations: Some(default_pbkdf2_iterations().get() as i32),
57 kdf_memory: None,
58 kdf_parallelism: None,
59 reference_data: None, }),
61 )
62 .await
63 .map_err(ApiError::from)?;
64
65 Ok(())
66}
67
68pub(super) fn make_register_keys(
69 email: String,
70 password: String,
71 kdf: Kdf,
72) -> Result<RegisterKeyResponse, CryptoError> {
73 let master_key = MasterKey::derive(&password, &email, &kdf)?;
74 let master_password_hash =
75 master_key.derive_master_key_hash(password.as_bytes(), HashPurpose::ServerAuthorization)?;
76 let (user_key, encrypted_user_key) = master_key.make_user_key()?;
77 let keys = user_key.make_key_pair()?;
78
79 Ok(RegisterKeyResponse {
80 master_password_hash,
81 encrypted_user_key,
82 keys,
83 })
84}
85
86#[allow(missing_docs)]
87#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
88pub struct RegisterKeyResponse {
89 pub master_password_hash: String,
90 pub encrypted_user_key: EncString,
91 pub keys: RsaKeyPair,
92}