Skip to content

Commit

Permalink
Implement alternative login with device flow (#568)
Browse files Browse the repository at this point in the history
When approving from other devices we need to support the master key
flow. Also implements login with device for the CLI as a testing tool.
  • Loading branch information
Hinton authored Feb 1, 2024
1 parent 872a05b commit 2ac95f1
Show file tree
Hide file tree
Showing 16 changed files with 405 additions and 31 deletions.
4 changes: 4 additions & 0 deletions crates/bitwarden-crypto/src/keys/master_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ pub enum HashPurpose {
pub struct MasterKey(SymmetricCryptoKey);

impl MasterKey {
pub fn new(key: SymmetricCryptoKey) -> MasterKey {
Self(key)
}

/// Derives a users master key from their password, email and KDF.
pub fn derive(password: &[u8], email: &[u8], kdf: &Kdf) -> Result<Self> {
derive_key(password, email, kdf).map(Self)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use log::debug;
use serde::{Deserialize, Serialize};
use uuid::Uuid;

use crate::{
auth::api::response::IdentityTokenResponse,
client::{client_settings::DeviceType, ApiConfigurations},
error::Result,
};

#[derive(Serialize, Deserialize, Debug)]
pub struct AuthRequestTokenRequest {
scope: String,
client_id: String,
#[serde(rename = "deviceType")]
device_type: u8,
#[serde(rename = "deviceIdentifier")]
device_identifier: String,
#[serde(rename = "deviceName")]
device_name: String,
grant_type: String,
#[serde(rename = "username")]
email: String,
#[serde(rename = "authRequest")]
auth_request_id: Uuid,
#[serde(rename = "password")]
access_code: String,
}

impl AuthRequestTokenRequest {
pub fn new(
email: &str,
auth_request_id: &Uuid,
access_code: &str,
device_type: DeviceType,
device_identifier: &str,
) -> Self {
let obj = Self {
scope: "api offline_access".to_string(),
client_id: "web".to_string(),
device_type: device_type as u8,
device_identifier: device_identifier.to_string(),
device_name: "chrome".to_string(),
grant_type: "password".to_string(),
email: email.to_string(),
auth_request_id: *auth_request_id,
access_code: access_code.to_string(),
};
debug!("initializing {:?}", obj);
obj
}

pub(crate) async fn send(
&self,
configurations: &ApiConfigurations,
) -> Result<IdentityTokenResponse> {
super::send_identity_connect_request(configurations, Some(&self.email), &self).await
}
}
5 changes: 5 additions & 0 deletions crates/bitwarden/src/auth/api/request/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ pub(crate) use password_token_request::*;
#[cfg(feature = "internal")]
pub(crate) use renew_token_request::*;

#[cfg(feature = "mobile")]
mod auth_request_token_request;
#[cfg(feature = "mobile")]
pub(crate) use auth_request_token_request::*;

use crate::{
auth::api::response::{parse_identity_response, IdentityTokenResponse},
client::ApiConfigurations,
Expand Down
14 changes: 10 additions & 4 deletions crates/bitwarden/src/auth/api/request/password_token_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{
api::response::IdentityTokenResponse,
login::{TwoFactorProvider, TwoFactorRequest},
},
client::ApiConfigurations,
client::{client_settings::DeviceType, ApiConfigurations},
error::Result,
};

Expand Down Expand Up @@ -35,13 +35,19 @@ pub struct PasswordTokenRequest {
}

impl PasswordTokenRequest {
pub fn new(email: &str, password_hash: &String, two_factor: &Option<TwoFactorRequest>) -> Self {
pub fn new(
email: &str,
password_hash: &str,
device_type: DeviceType,
device_identifier: &str,
two_factor: &Option<TwoFactorRequest>,
) -> Self {
let tf = two_factor.as_ref();
let obj = Self {
scope: "api offline_access".to_string(),
client_id: "web".to_string(),
device_type: 10,
device_identifier: "b86dd6ab-4265-4ddf-a7f1-eb28d5677f33".to_string(),
device_type: device_type as u8,
device_identifier: device_identifier.to_string(),
device_name: "firefox".to_string(),
grant_type: "password".to_string(),
master_password_hash: password_hash.to_string(),
Expand Down
67 changes: 61 additions & 6 deletions crates/bitwarden/src/auth/auth_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bitwarden_crypto::{
fingerprint, AsymmetricCryptoKey, AsymmetricEncString, AsymmetricPublicCryptoKey,
};
#[cfg(feature = "mobile")]
use bitwarden_crypto::{KeyDecryptable, SymmetricCryptoKey};
use bitwarden_crypto::{EncString, KeyDecryptable, SymmetricCryptoKey};
use bitwarden_generators::{password, PasswordGeneratorRequest};

use crate::{error::Error, Client};
Expand Down Expand Up @@ -63,6 +63,22 @@ pub(crate) fn auth_request_decrypt_user_key(
Ok(SymmetricCryptoKey::try_from(key.as_mut_slice())?)
}

/// Decrypt the user key using the private key generated previously.
#[cfg(feature = "mobile")]
pub(crate) fn auth_request_decrypt_master_key(
private_key: String,
master_key: AsymmetricEncString,
user_key: EncString,
) -> Result<SymmetricCryptoKey, Error> {
use bitwarden_crypto::MasterKey;

let key = AsymmetricCryptoKey::from_der(&STANDARD.decode(private_key)?)?;
let mut master_key: Vec<u8> = master_key.decrypt_with_key(&key)?;
let master_key = MasterKey::new(SymmetricCryptoKey::try_from(master_key.as_mut_slice())?);

Ok(master_key.decrypt_user_key(user_key)?)
}

/// Approve an auth request.
///
/// Encrypts the user key with a public key.
Expand Down Expand Up @@ -113,14 +129,14 @@ mod tests {
use super::*;
use crate::{
client::{LoginMethod, UserLoginMethod},
mobile::crypto::{InitUserCryptoMethod, InitUserCryptoRequest},
mobile::crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest},
};

#[test]
fn test_approve() {
let mut client = Client::new(None);
client.set_login_method(LoginMethod::User(UserLoginMethod::Username {
client_id: "123".to_owned(),
client_id: "7b821276-e27c-400b-9853-606393c87f18".to_owned(),
email: "test@bitwarden.com".to_owned(),
kdf: Kdf::PBKDF2 {
iterations: NonZeroU32::new(600_000).unwrap(),
Expand All @@ -133,16 +149,53 @@ mod tests {
.initialize_user_crypto("asdfasdfasdf", user_key, private_key)
.unwrap();

let public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnRtpYLp9QLaEUkdPkWZX6TrMUKFoSaFamBKDL0NlS6xwtETTqYIxRVsvnHii3Dhz+fh3aHQVyBa1rBXogeH3MLERzNADwZhpWtBT9wKCXY5o0fIWYdZV/Nf0Y+0ZoKdImrGPLPmyHGfCqrvrK7g09q8+3kXUlkdAImlQqc5TiYwiHBfUQVTBq/Ae7a0FEpajx1NUM4h3edpCYxbvnpSTuzMgbmbUUS4gdCaheA2ibYxy/zkLzsaLygoibMyGNl9Y8J5n7dDrVXpUKZTihVfXwHfEZwtKNunWsmmt8rEJWVpguUDEDVSUogoxQcNaCi7KHn9ioSip76hg1jLpypO3WwIDAQAB";
let public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvyLRDUwXB4BfQ507D4meFPmwn5zwy3IqTPJO4plrrhnclWahXa240BzyFW9gHgYu+Jrgms5xBfRTBMcEsqqNm7+JpB6C1B6yvnik0DpJgWQw1rwvy4SUYidpR/AWbQi47n/hvnmzI/sQxGddVfvWu1iTKOlf5blbKYAXnUE5DZBGnrWfacNXwRRdtP06tFB0LwDgw+91CeLSJ9py6dm1qX5JIxoO8StJOQl65goLCdrTWlox+0Jh4xFUfCkb+s3px+OhSCzJbvG/hlrSRcUz5GnwlCEyF3v5lfUtV96MJD+78d8pmH6CfFAp2wxKRAbGdk+JccJYO6y6oIXd3Fm7twIDAQAB";

// Verify fingerprint
let pbkey = STANDARD.decode(public_key).unwrap();
let fingerprint = fingerprint("test@bitwarden.com", &pbkey).unwrap();
assert_eq!(fingerprint, "spill-applaud-sweep-habitable-shrunk");
assert_eq!(fingerprint, "childless-unfair-prowler-dropbox-designate");

approve_auth_request(&mut client, public_key.to_owned()).unwrap();
}

#[tokio::test]
async fn test_decrypt_user_key() {
let private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzLtEUdxfcLxDj84yaGFsVF5hZ8Hjlb08NMQDy1RnBma06I3ZESshLYzVz4r/gegMn9OOltfV/Yxlyvida8oW6qdlfJ7AVz6Oa8pV7BiL40C7b76+oqraQpyYw2HChANB1AhXL9SqWngKmLZwjA7qiCrmcc0kZHeOb4KnKtp9iVvPVs+8veFvKgYO4ba2AAOHKFdR0W55/agXfAy+fWUAkC8mc9ikyJdQWaPV6OZvC2XFkOseBQm9Rynudh3BQpoWiL6w620efe7t5k+02/EyOFJL9f/XEEjM/+Yo0t3LAfkuhHGeKiRST59Xc9hTEmyJTeVXROtz+0fjqOp3xkaObAgMBAAECggEACs4xhnO0HaZhh1/iH7zORMIRXKeyxP2LQiTR8xwN5JJ9wRWmGAR9VasS7EZFTDidIGVME2u/h4s5EqXnhxfO+0gGksVvgNXJ/qw87E8K2216g6ZNo6vSGA7H1GH2voWwejJ4/k/cJug6dz2S402rRAKh2Wong1arYHSkVlQp3diiMa5FHAOSE+Cy09O2ZsaF9IXQYUtlW6AVXFrBEPYH2kvkaPXchh8VETMijo6tbvoKLnUHe+wTaDMls7hy8exjtVyI59r3DNzjy1lNGaGb5QSnFMXR+eHhPZc844Wv02MxC15zKABADrl58gpJyjTl6XpDdHCYGsmGpVGH3X9TQQKBgQDz/9beFjzq59ve6rGwn+EtnQfSsyYT+jr7GN8lNEXb3YOFXBgPhfFIcHRh2R00Vm9w2ApfAx2cd8xm2I6HuvQ1Os7g26LWazvuWY0Qzb+KaCLQTEGH1RnTq6CCG+BTRq/a3J8M4t38GV5TWlzv8wr9U4dl6FR4efjb65HXs1GQ4QKBgQC7/uHfrOTEHrLeIeqEuSl0vWNqEotFKdKLV6xpOvNuxDGbgW4/r/zaxDqt0YBOXmRbQYSEhmO3oy9J6XfE1SUln0gbavZeW0HESCAmUIC88bDnspUwS9RxauqT5aF8ODKN/bNCWCnBM1xyonPOs1oT1nyparJVdQoG//Y7vkB3+wKBgBqLqPq8fKAp3XfhHLfUjREDVoiLyQa/YI9U42IOz9LdxKNLo6p8rgVthpvmnRDGnpUuS+KOWjhdqDVANjF6G3t3DG7WNl8Rh5Gk2H4NhFswfSkgQrjebFLlBy9gjQVCWXt8KSmjvPbiY6q52Aaa8IUjA0YJAregvXxfopxO+/7BAoGARicvEtDp7WWnSc1OPoj6N14VIxgYcI7SyrzE0d/1x3ffKzB5e7qomNpxKzvqrVP8DzG7ydh8jaKPmv1MfF8tpYRy3AhmN3/GYwCnPqT75YYrhcrWcVdax5gmQVqHkFtIQkRSCIftzPLlpMGKha/YBV8c1fvC4LD0NPh/Ynv0gtECgYEAyOZg95/kte0jpgUEgwuMrzkhY/AaUJULFuR5MkyvReEbtSBQwV5tx60+T95PHNiFooWWVXiLMsAgyI2IbkxVR1Pzdri3gWK5CTfqb7kLuaj/B7SGvBa2Sxo478KS5K8tBBBWkITqo+wLC0mn3uZi1dyMWO1zopTA+KtEGF2dtGQ=";

let enc_user_key = "4.dxbd5OMwi/Avy7DQxvLV+Z7kDJgHBtg/jAbgYNO7QU0Zii4rLFNco2lS5aS9z42LTZHc2p5HYwn2ZwkZNfHsQ6//d5q40MDgGYJMKBXOZP62ZHhct1XsvYBmtcUtIOm5j2HSjt2pjEuGAc1LbyGIWRJJQ3Lp1ULbL2m71I+P23GF36JyOM8SUWvpvxE/3+qqVhRFPG2VqMCYa2kLLxwVfUmpV+KKjX1TXsrq6pfJIwHNwHw4h7MSfD8xTy2bx4MiBt638Z9Vt1pGsSQkh9RgPvCbnhuCpZQloUgJ8ByLVEcrlKx3yaaxiQXvte+ZhuOI7rGdjmoVoOzisooje4JgYw==".parse().unwrap();
let dec = auth_request_decrypt_user_key(private_key.to_owned(), enc_user_key).unwrap();

assert_eq!(
dec.to_vec().as_ref(),
vec![
201, 37, 234, 213, 21, 75, 40, 70, 149, 213, 234, 16, 19, 251, 162, 245, 161, 74,
34, 245, 211, 151, 211, 192, 95, 10, 117, 50, 88, 223, 23, 157
]
);
}

#[tokio::test]
async fn test_decrypt_master_key() {
let private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCzLtEUdxfcLxDj84yaGFsVF5hZ8Hjlb08NMQDy1RnBma06I3ZESshLYzVz4r/gegMn9OOltfV/Yxlyvida8oW6qdlfJ7AVz6Oa8pV7BiL40C7b76+oqraQpyYw2HChANB1AhXL9SqWngKmLZwjA7qiCrmcc0kZHeOb4KnKtp9iVvPVs+8veFvKgYO4ba2AAOHKFdR0W55/agXfAy+fWUAkC8mc9ikyJdQWaPV6OZvC2XFkOseBQm9Rynudh3BQpoWiL6w620efe7t5k+02/EyOFJL9f/XEEjM/+Yo0t3LAfkuhHGeKiRST59Xc9hTEmyJTeVXROtz+0fjqOp3xkaObAgMBAAECggEACs4xhnO0HaZhh1/iH7zORMIRXKeyxP2LQiTR8xwN5JJ9wRWmGAR9VasS7EZFTDidIGVME2u/h4s5EqXnhxfO+0gGksVvgNXJ/qw87E8K2216g6ZNo6vSGA7H1GH2voWwejJ4/k/cJug6dz2S402rRAKh2Wong1arYHSkVlQp3diiMa5FHAOSE+Cy09O2ZsaF9IXQYUtlW6AVXFrBEPYH2kvkaPXchh8VETMijo6tbvoKLnUHe+wTaDMls7hy8exjtVyI59r3DNzjy1lNGaGb5QSnFMXR+eHhPZc844Wv02MxC15zKABADrl58gpJyjTl6XpDdHCYGsmGpVGH3X9TQQKBgQDz/9beFjzq59ve6rGwn+EtnQfSsyYT+jr7GN8lNEXb3YOFXBgPhfFIcHRh2R00Vm9w2ApfAx2cd8xm2I6HuvQ1Os7g26LWazvuWY0Qzb+KaCLQTEGH1RnTq6CCG+BTRq/a3J8M4t38GV5TWlzv8wr9U4dl6FR4efjb65HXs1GQ4QKBgQC7/uHfrOTEHrLeIeqEuSl0vWNqEotFKdKLV6xpOvNuxDGbgW4/r/zaxDqt0YBOXmRbQYSEhmO3oy9J6XfE1SUln0gbavZeW0HESCAmUIC88bDnspUwS9RxauqT5aF8ODKN/bNCWCnBM1xyonPOs1oT1nyparJVdQoG//Y7vkB3+wKBgBqLqPq8fKAp3XfhHLfUjREDVoiLyQa/YI9U42IOz9LdxKNLo6p8rgVthpvmnRDGnpUuS+KOWjhdqDVANjF6G3t3DG7WNl8Rh5Gk2H4NhFswfSkgQrjebFLlBy9gjQVCWXt8KSmjvPbiY6q52Aaa8IUjA0YJAregvXxfopxO+/7BAoGARicvEtDp7WWnSc1OPoj6N14VIxgYcI7SyrzE0d/1x3ffKzB5e7qomNpxKzvqrVP8DzG7ydh8jaKPmv1MfF8tpYRy3AhmN3/GYwCnPqT75YYrhcrWcVdax5gmQVqHkFtIQkRSCIftzPLlpMGKha/YBV8c1fvC4LD0NPh/Ynv0gtECgYEAyOZg95/kte0jpgUEgwuMrzkhY/AaUJULFuR5MkyvReEbtSBQwV5tx60+T95PHNiFooWWVXiLMsAgyI2IbkxVR1Pzdri3gWK5CTfqb7kLuaj/B7SGvBa2Sxo478KS5K8tBBBWkITqo+wLC0mn3uZi1dyMWO1zopTA+KtEGF2dtGQ=";

let enc_master_key = "4.dxbd5OMwi/Avy7DQxvLV+Z7kDJgHBtg/jAbgYNO7QU0Zii4rLFNco2lS5aS9z42LTZHc2p5HYwn2ZwkZNfHsQ6//d5q40MDgGYJMKBXOZP62ZHhct1XsvYBmtcUtIOm5j2HSjt2pjEuGAc1LbyGIWRJJQ3Lp1ULbL2m71I+P23GF36JyOM8SUWvpvxE/3+qqVhRFPG2VqMCYa2kLLxwVfUmpV+KKjX1TXsrq6pfJIwHNwHw4h7MSfD8xTy2bx4MiBt638Z9Vt1pGsSQkh9RgPvCbnhuCpZQloUgJ8ByLVEcrlKx3yaaxiQXvte+ZhuOI7rGdjmoVoOzisooje4JgYw==".parse().unwrap();
let enc_user_key = "2.Q/2PhzcC7GdeiMHhWguYAQ==|GpqzVdr0go0ug5cZh1n+uixeBC3oC90CIe0hd/HWA/pTRDZ8ane4fmsEIcuc8eMKUt55Y2q/fbNzsYu41YTZzzsJUSeqVjT8/iTQtgnNdpo=|dwI+uyvZ1h/iZ03VQ+/wrGEFYVewBUUl/syYgjsNMbE=".parse().unwrap();
let dec =
auth_request_decrypt_master_key(private_key.to_owned(), enc_master_key, enc_user_key)
.unwrap();

assert_eq!(
dec.to_vec().as_ref(),
vec![
109, 128, 172, 147, 206, 123, 134, 95, 16, 36, 155, 113, 201, 18, 186, 230, 216,
212, 173, 188, 74, 11, 134, 131, 137, 242, 105, 178, 105, 126, 52, 139, 248, 91,
215, 21, 128, 91, 226, 222, 165, 67, 251, 34, 83, 81, 77, 147, 225, 76, 13, 41,
102, 45, 183, 218, 106, 89, 254, 208, 251, 101, 130, 10,
]
);
}

#[tokio::test]
async fn test_device_login() {
let kdf = Kdf::PBKDF2 {
Expand Down Expand Up @@ -181,7 +234,9 @@ mod tests {
private_key: private_key.to_owned(),
method: InitUserCryptoMethod::AuthRequest {
request_private_key: auth_req.private_key,
protected_user_key: approved_req,
method: AuthRequestMethod::UserKey {
protected_user_key: approved_req,
},
},
})
.await
Expand Down
21 changes: 21 additions & 0 deletions crates/bitwarden/src/auth/client_auth.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#[cfg(feature = "internal")]
use bitwarden_crypto::{AsymmetricEncString, DeviceKey, TrustDeviceResponse};

#[cfg(feature = "mobile")]
use crate::auth::login::NewAuthRequestResponse;
#[cfg(feature = "secrets")]
use crate::auth::login::{login_access_token, AccessTokenLoginRequest, AccessTokenLoginResponse};
use crate::{auth::renew::renew_token, error::Result, Client};
Expand Down Expand Up @@ -116,6 +118,25 @@ impl<'a> ClientAuth<'a> {
}
}

#[cfg(feature = "mobile")]
impl<'a> ClientAuth<'a> {
pub async fn login_device(
&mut self,
email: String,
device_identifier: String,
) -> Result<NewAuthRequestResponse> {
use crate::auth::login::send_new_auth_request;

send_new_auth_request(self.client, email, device_identifier).await
}

pub async fn login_device_complete(&mut self, auth_req: NewAuthRequestResponse) -> Result<()> {
use crate::auth::login::complete_auth_request;

complete_auth_request(self.client, auth_req).await
}
}

#[cfg(feature = "internal")]
fn trust_device(client: &Client) -> Result<TrustDeviceResponse> {
let enc = client.get_encryption_settings()?;
Expand Down
131 changes: 131 additions & 0 deletions crates/bitwarden/src/auth/login/auth_request.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use std::num::NonZeroU32;

use bitwarden_api_api::{
apis::auth_requests_api::{auth_requests_id_response_get, auth_requests_post},
models::{AuthRequestCreateRequestModel, AuthRequestType},
};
use bitwarden_crypto::Kdf;
use uuid::Uuid;

use crate::{
auth::{
api::{request::AuthRequestTokenRequest, response::IdentityTokenResponse},
auth_request::new_auth_request,
},
client::{LoginMethod, UserLoginMethod},
error::Result,
mobile::crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest},
Client,
};

pub struct NewAuthRequestResponse {
pub fingerprint: String,
email: String,
device_identifier: String,
auth_request_id: Uuid,
access_code: String,
private_key: String,
}

pub(crate) async fn send_new_auth_request(
client: &mut Client,
email: String,
device_identifier: String,
) -> Result<NewAuthRequestResponse> {
let config = client.get_api_configurations().await;

let auth = new_auth_request(&email)?;

let req = AuthRequestCreateRequestModel {
email: email.clone(),
public_key: auth.public_key,
device_identifier: device_identifier.clone(),
access_code: auth.access_code.clone(),
r#type: AuthRequestType::Variant0, // AuthenticateAndUnlock
};

let res = auth_requests_post(&config.api, Some(req)).await?;

Ok(NewAuthRequestResponse {
fingerprint: auth.fingerprint,
email,
device_identifier,
auth_request_id: res.id.unwrap(),
access_code: auth.access_code,
private_key: auth.private_key,
})
}

pub(crate) async fn complete_auth_request(
client: &mut Client,
auth_req: NewAuthRequestResponse,
) -> Result<()> {
let config = client.get_api_configurations().await;

let res = auth_requests_id_response_get(
&config.api,
auth_req.auth_request_id,
Some(&auth_req.access_code),
)
.await?;

let approved = res.request_approved.unwrap_or(false);

if !approved {
return Err("Auth request was not approved".into());
}

let response = AuthRequestTokenRequest::new(
&auth_req.email,
&auth_req.auth_request_id,
&auth_req.access_code,
config.device_type,
&auth_req.device_identifier,
)
.send(config)
.await?;

if let IdentityTokenResponse::Authenticated(r) = response {
let kdf = Kdf::PBKDF2 {
iterations: NonZeroU32::new(600_000).unwrap(),
};

client.set_tokens(
r.access_token.clone(),
r.refresh_token.clone(),
r.expires_in,
);
client.set_login_method(LoginMethod::User(UserLoginMethod::Username {
client_id: "web".to_owned(),
email: auth_req.email.to_owned(),
kdf: kdf.clone(),
}));

let method = match res.master_password_hash {
Some(_) => AuthRequestMethod::MasterKey {
protected_master_key: res.key.unwrap().parse().unwrap(),
auth_request_key: r.key.unwrap().parse().unwrap(),
},
None => AuthRequestMethod::UserKey {
protected_user_key: res.key.unwrap().parse().unwrap(),
},
};

client
.crypto()
.initialize_user_crypto(InitUserCryptoRequest {
kdf_params: kdf,
email: auth_req.email,
private_key: r.private_key.unwrap(),
method: InitUserCryptoMethod::AuthRequest {
request_private_key: auth_req.private_key,
method,
},
})
.await?;

Ok(())
} else {
Err("Failed to authenticate".into())
}
}
Loading

0 comments on commit 2ac95f1

Please sign in to comment.