bitwarden_core/auth/
register.rs

1use 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
32/// Half baked implementation of user registration
33pub(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, // TODO: Add
48            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, // TODO: Add
60        }),
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}