-
Notifications
You must be signed in to change notification settings - Fork 15
[PM-24051] MasterPasswordUnlockData model with response mapping and adds it to identity success response model #376
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
44773f7
0712878
8ca20a8
28a8423
b089ea0
0d35393
a08179d
b3647f2
36d3136
7c8664d
9c7d50d
70ad9d3
110f4db
ff86adf
fa253a3
4a95dc5
cd37e31
3bf880f
93a3d0c
f0c4f2a
3e6a46a
7c34725
042678c
9676069
7973f12
5a4f314
7e425ca
c9aaa8c
2591773
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
use bitwarden_api_api::models::MasterPasswordUnlockResponseModel; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Serialize, Deserialize, Debug, PartialEq)] | ||
pub struct IdentityUserDecryptionOptionsResponseModel { | ||
#[serde( | ||
rename = "masterPasswordUnlock", | ||
skip_serializing_if = "Option::is_none" | ||
)] | ||
pub master_password_unlock: Option<MasterPasswordUnlockResponseModel>, | ||
} |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,316 @@ | ||||||||||||||||||||||||||||||
use std::num::NonZeroU32; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
use bitwarden_api_api::models::{ | ||||||||||||||||||||||||||||||
master_password_unlock_response_model::MasterPasswordUnlockResponseModel, KdfType, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
use bitwarden_crypto::{EncString, Kdf}; | ||||||||||||||||||||||||||||||
use bitwarden_error::bitwarden_error; | ||||||||||||||||||||||||||||||
use serde::{Deserialize, Serialize}; | ||||||||||||||||||||||||||||||
#[cfg(feature = "wasm")] | ||||||||||||||||||||||||||||||
use wasm_bindgen::prelude::*; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
use crate::{require, MissingFieldError}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/// Error for master password related operations. | ||||||||||||||||||||||||||||||
#[bitwarden_error(flat)] | ||||||||||||||||||||||||||||||
#[derive(Debug, thiserror::Error)] | ||||||||||||||||||||||||||||||
pub enum MasterPasswordError { | ||||||||||||||||||||||||||||||
/// The wrapped encryption key could not be parsed because the encstring is malformed | ||||||||||||||||||||||||||||||
#[error("Wrapped encryption key is malformed")] | ||||||||||||||||||||||||||||||
EncryptionKeyMalformed, | ||||||||||||||||||||||||||||||
/// The KDF data could not be parsed, because it is missing values or has an invalid value | ||||||||||||||||||||||||||||||
#[error("KDF is malformed")] | ||||||||||||||||||||||||||||||
KdfMalformed, | ||||||||||||||||||||||||||||||
/// The wrapped encryption key or salt fields are missing or KDF data is malformed | ||||||||||||||||||||||||||||||
#[error(transparent)] | ||||||||||||||||||||||||||||||
MissingField(#[from] MissingFieldError), | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
/// Represents the data required to unlock with the master password. | ||||||||||||||||||||||||||||||
#[derive(Serialize, Deserialize, Debug)] | ||||||||||||||||||||||||||||||
#[serde(rename_all = "camelCase", deny_unknown_fields)] | ||||||||||||||||||||||||||||||
#[cfg_attr(feature = "uniffi", derive(uniffi::Record))] | ||||||||||||||||||||||||||||||
#[cfg_attr( | ||||||||||||||||||||||||||||||
feature = "wasm", | ||||||||||||||||||||||||||||||
derive(tsify::Tsify), | ||||||||||||||||||||||||||||||
tsify(into_wasm_abi, from_wasm_abi) | ||||||||||||||||||||||||||||||
)] | ||||||||||||||||||||||||||||||
pub struct MasterPasswordUnlockData { | ||||||||||||||||||||||||||||||
/// The key derivation function used to derive the master key | ||||||||||||||||||||||||||||||
pub kdf: Kdf, | ||||||||||||||||||||||||||||||
/// The master key wrapped user key | ||||||||||||||||||||||||||||||
pub master_key_wrapped_user_key: EncString, | ||||||||||||||||||||||||||||||
/// The salt used in the KDF, typically the user's email | ||||||||||||||||||||||||||||||
pub salt: String, | ||||||||||||||||||||||||||||||
quexten marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
impl TryFrom<MasterPasswordUnlockResponseModel> for MasterPasswordUnlockData { | ||||||||||||||||||||||||||||||
type Error = MasterPasswordError; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
fn try_from(response: MasterPasswordUnlockResponseModel) -> Result<Self, Self::Error> { | ||||||||||||||||||||||||||||||
let kdf = match response.kdf.kdf_type { | ||||||||||||||||||||||||||||||
mzieniukbw marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||
KdfType::PBKDF2_SHA256 => Kdf::PBKDF2 { | ||||||||||||||||||||||||||||||
iterations: kdf_parse_nonzero_u32(response.kdf.iterations)?, | ||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
KdfType::Argon2id => Kdf::Argon2id { | ||||||||||||||||||||||||||||||
iterations: kdf_parse_nonzero_u32(response.kdf.iterations)?, | ||||||||||||||||||||||||||||||
memory: kdf_parse_nonzero_u32( | ||||||||||||||||||||||||||||||
response | ||||||||||||||||||||||||||||||
.kdf | ||||||||||||||||||||||||||||||
.memory | ||||||||||||||||||||||||||||||
.ok_or(MasterPasswordError::KdfMalformed)?, | ||||||||||||||||||||||||||||||
)?, | ||||||||||||||||||||||||||||||
parallelism: kdf_parse_nonzero_u32( | ||||||||||||||||||||||||||||||
response | ||||||||||||||||||||||||||||||
.kdf | ||||||||||||||||||||||||||||||
.parallelism | ||||||||||||||||||||||||||||||
.ok_or(MasterPasswordError::KdfMalformed)?, | ||||||||||||||||||||||||||||||
)?, | ||||||||||||||||||||||||||||||
Comment on lines
+57
to
+68
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: Is there a reason for not just using
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @quexten pointed out, that it might be better to consolidate all KDF related verification into the |
||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let master_key_encrypted_user_key = require!(response.master_key_encrypted_user_key); | ||||||||||||||||||||||||||||||
let salt = require!(response.salt); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
Ok(MasterPasswordUnlockData { | ||||||||||||||||||||||||||||||
kdf, | ||||||||||||||||||||||||||||||
master_key_wrapped_user_key: master_key_encrypted_user_key | ||||||||||||||||||||||||||||||
.parse() | ||||||||||||||||||||||||||||||
.map_err(|_| MasterPasswordError::EncryptionKeyMalformed)?, | ||||||||||||||||||||||||||||||
salt, | ||||||||||||||||||||||||||||||
}) | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
fn kdf_parse_nonzero_u32(value: impl TryInto<u32>) -> Result<NonZeroU32, MasterPasswordError> { | ||||||||||||||||||||||||||||||
value | ||||||||||||||||||||||||||||||
.try_into() | ||||||||||||||||||||||||||||||
.ok() | ||||||||||||||||||||||||||||||
.and_then(NonZeroU32::new) | ||||||||||||||||||||||||||||||
.ok_or(MasterPasswordError::KdfMalformed) | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[cfg(test)] | ||||||||||||||||||||||||||||||
mod tests { | ||||||||||||||||||||||||||||||
use bitwarden_api_api::models::{KdfType, MasterPasswordUnlockKdfResponseModel}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
use super::*; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
const TEST_USER_KEY: &str = "2.Q/2PhzcC7GdeiMHhWguYAQ==|GpqzVdr0go0ug5cZh1n+uixeBC3oC90CIe0hd/HWA/pTRDZ8ane4fmsEIcuc8eMKUt55Y2q/fbNzsYu41YTZzzsJUSeqVjT8/iTQtgnNdpo=|dwI+uyvZ1h/iZ03VQ+/wrGEFYVewBUUl/syYgjsNMbE="; | ||||||||||||||||||||||||||||||
const TEST_INVALID_USER_KEY: &str = "-1.8UClLa8IPE1iZT7chy5wzQ==|6PVfHnVk5S3XqEtQemnM5yb4JodxmPkkWzmDRdfyHtjORmvxqlLX40tBJZ+CKxQWmS8tpEB5w39rbgHg/gqs0haGdZG4cPbywsgGzxZ7uNI="; | ||||||||||||||||||||||||||||||
const TEST_SALT: &str = "[email protected]"; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
fn create_pbkdf2_response( | ||||||||||||||||||||||||||||||
master_key_encrypted_user_key: Option<String>, | ||||||||||||||||||||||||||||||
salt: Option<String>, | ||||||||||||||||||||||||||||||
iterations: i32, | ||||||||||||||||||||||||||||||
) -> MasterPasswordUnlockResponseModel { | ||||||||||||||||||||||||||||||
MasterPasswordUnlockResponseModel { | ||||||||||||||||||||||||||||||
kdf: Box::new(MasterPasswordUnlockKdfResponseModel { | ||||||||||||||||||||||||||||||
kdf_type: KdfType::PBKDF2_SHA256, | ||||||||||||||||||||||||||||||
iterations, | ||||||||||||||||||||||||||||||
memory: None, | ||||||||||||||||||||||||||||||
parallelism: None, | ||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||
master_key_encrypted_user_key, | ||||||||||||||||||||||||||||||
salt, | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_pbkdf2_success() { | ||||||||||||||||||||||||||||||
let response = create_pbkdf2_response( | ||||||||||||||||||||||||||||||
Some(TEST_USER_KEY.to_string()), | ||||||||||||||||||||||||||||||
Some(TEST_SALT.to_string()), | ||||||||||||||||||||||||||||||
600_000, | ||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let data = MasterPasswordUnlockData::try_from(response).unwrap(); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if let Kdf::PBKDF2 { iterations } = data.kdf { | ||||||||||||||||||||||||||||||
assert_eq!(iterations.get(), 600_000); | ||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||
panic!("Expected PBKDF2 KDF") | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
assert_eq!(data.salt, TEST_SALT); | ||||||||||||||||||||||||||||||
assert_eq!(data.master_key_wrapped_user_key.to_string(), TEST_USER_KEY); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_argon2id_success() { | ||||||||||||||||||||||||||||||
let response = MasterPasswordUnlockResponseModel { | ||||||||||||||||||||||||||||||
kdf: Box::new(MasterPasswordUnlockKdfResponseModel { | ||||||||||||||||||||||||||||||
kdf_type: KdfType::Argon2id, | ||||||||||||||||||||||||||||||
iterations: 3, | ||||||||||||||||||||||||||||||
memory: Some(64), | ||||||||||||||||||||||||||||||
parallelism: Some(4), | ||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||
master_key_encrypted_user_key: Some(TEST_USER_KEY.to_string()), | ||||||||||||||||||||||||||||||
salt: Some(TEST_SALT.to_string()), | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let data = MasterPasswordUnlockData::try_from(response).unwrap(); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
if let Kdf::Argon2id { | ||||||||||||||||||||||||||||||
iterations, | ||||||||||||||||||||||||||||||
memory, | ||||||||||||||||||||||||||||||
parallelism, | ||||||||||||||||||||||||||||||
} = data.kdf | ||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||
assert_eq!(iterations.get(), 3); | ||||||||||||||||||||||||||||||
assert_eq!(memory.get(), 64); | ||||||||||||||||||||||||||||||
assert_eq!(parallelism.get(), 4); | ||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||
panic!("Expected Argon2id KDF") | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
assert_eq!(data.salt, TEST_SALT); | ||||||||||||||||||||||||||||||
assert_eq!(data.master_key_wrapped_user_key.to_string(), TEST_USER_KEY); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_invalid_user_key_encryption_key_malformed_error( | ||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||
let response = create_pbkdf2_response( | ||||||||||||||||||||||||||||||
Some(TEST_INVALID_USER_KEY.to_string()), | ||||||||||||||||||||||||||||||
Some(TEST_SALT.to_string()), | ||||||||||||||||||||||||||||||
600_000, | ||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let result = MasterPasswordUnlockData::try_from(response); | ||||||||||||||||||||||||||||||
assert!(matches!( | ||||||||||||||||||||||||||||||
result, | ||||||||||||||||||||||||||||||
Err(MasterPasswordError::EncryptionKeyMalformed) | ||||||||||||||||||||||||||||||
)); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_user_key_none_missing_field_error() { | ||||||||||||||||||||||||||||||
let response = create_pbkdf2_response(None, Some(TEST_SALT.to_string()), 600_000); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let result = MasterPasswordUnlockData::try_from(response); | ||||||||||||||||||||||||||||||
assert!(matches!( | ||||||||||||||||||||||||||||||
result, | ||||||||||||||||||||||||||||||
Err(MasterPasswordError::MissingField(MissingFieldError( | ||||||||||||||||||||||||||||||
"response.master_key_encrypted_user_key" | ||||||||||||||||||||||||||||||
))) | ||||||||||||||||||||||||||||||
)); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_salt_none_missing_field_error() { | ||||||||||||||||||||||||||||||
let response = create_pbkdf2_response(Some(TEST_USER_KEY.to_string()), None, 600_000); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let result = MasterPasswordUnlockData::try_from(response); | ||||||||||||||||||||||||||||||
assert!(matches!( | ||||||||||||||||||||||||||||||
result, | ||||||||||||||||||||||||||||||
Err(MasterPasswordError::MissingField(MissingFieldError( | ||||||||||||||||||||||||||||||
"response.salt" | ||||||||||||||||||||||||||||||
))) | ||||||||||||||||||||||||||||||
)); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_argon2id_kdf_memory_none_kdf_malformed_error( | ||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||
let response = MasterPasswordUnlockResponseModel { | ||||||||||||||||||||||||||||||
kdf: Box::new(MasterPasswordUnlockKdfResponseModel { | ||||||||||||||||||||||||||||||
kdf_type: KdfType::Argon2id, | ||||||||||||||||||||||||||||||
iterations: 3, | ||||||||||||||||||||||||||||||
memory: None, | ||||||||||||||||||||||||||||||
parallelism: Some(4), | ||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||
master_key_encrypted_user_key: Some(TEST_USER_KEY.to_string()), | ||||||||||||||||||||||||||||||
salt: Some(TEST_SALT.to_string()), | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let result = MasterPasswordUnlockData::try_from(response); | ||||||||||||||||||||||||||||||
assert!(matches!(result, Err(MasterPasswordError::KdfMalformed))); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_argon2id_kdf_memory_zero_kdf_malformed_error( | ||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||
let response = MasterPasswordUnlockResponseModel { | ||||||||||||||||||||||||||||||
kdf: Box::new(MasterPasswordUnlockKdfResponseModel { | ||||||||||||||||||||||||||||||
kdf_type: KdfType::Argon2id, | ||||||||||||||||||||||||||||||
iterations: 3, | ||||||||||||||||||||||||||||||
memory: Some(0), | ||||||||||||||||||||||||||||||
parallelism: Some(4), | ||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||
master_key_encrypted_user_key: Some(TEST_USER_KEY.to_string()), | ||||||||||||||||||||||||||||||
salt: Some(TEST_SALT.to_string()), | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let result = MasterPasswordUnlockData::try_from(response); | ||||||||||||||||||||||||||||||
assert!(matches!(result, Err(MasterPasswordError::KdfMalformed))); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_argon2id_kdf_parallelism_kdf_malformed_error( | ||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||
let response = MasterPasswordUnlockResponseModel { | ||||||||||||||||||||||||||||||
kdf: Box::new(MasterPasswordUnlockKdfResponseModel { | ||||||||||||||||||||||||||||||
kdf_type: KdfType::Argon2id, | ||||||||||||||||||||||||||||||
iterations: 3, | ||||||||||||||||||||||||||||||
memory: Some(64), | ||||||||||||||||||||||||||||||
parallelism: None, | ||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||
master_key_encrypted_user_key: Some(TEST_USER_KEY.to_string()), | ||||||||||||||||||||||||||||||
salt: Some(TEST_SALT.to_string()), | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let result = MasterPasswordUnlockData::try_from(response); | ||||||||||||||||||||||||||||||
assert!(matches!(result, Err(MasterPasswordError::KdfMalformed))); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_argon2id_kdf_parallelism_zero_kdf_malformed_error( | ||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||
let response = MasterPasswordUnlockResponseModel { | ||||||||||||||||||||||||||||||
kdf: Box::new(MasterPasswordUnlockKdfResponseModel { | ||||||||||||||||||||||||||||||
kdf_type: KdfType::Argon2id, | ||||||||||||||||||||||||||||||
iterations: 3, | ||||||||||||||||||||||||||||||
memory: Some(64), | ||||||||||||||||||||||||||||||
parallelism: Some(0), | ||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||
master_key_encrypted_user_key: Some(TEST_USER_KEY.to_string()), | ||||||||||||||||||||||||||||||
salt: Some(TEST_SALT.to_string()), | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let result = MasterPasswordUnlockData::try_from(response); | ||||||||||||||||||||||||||||||
assert!(matches!(result, Err(MasterPasswordError::KdfMalformed))); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_pbkdf2_kdf_iterations_zero_kdf_malformed_error( | ||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||
let response = create_pbkdf2_response( | ||||||||||||||||||||||||||||||
Some(TEST_USER_KEY.to_string()), | ||||||||||||||||||||||||||||||
Some(TEST_SALT.to_string()), | ||||||||||||||||||||||||||||||
0, | ||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let result = MasterPasswordUnlockData::try_from(response); | ||||||||||||||||||||||||||||||
assert!(matches!(result, Err(MasterPasswordError::KdfMalformed))); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||
fn test_try_from_master_password_unlock_response_model_argon2id_kdf_iterations_zero_kdf_malformed_error( | ||||||||||||||||||||||||||||||
) { | ||||||||||||||||||||||||||||||
let response = MasterPasswordUnlockResponseModel { | ||||||||||||||||||||||||||||||
kdf: Box::new(MasterPasswordUnlockKdfResponseModel { | ||||||||||||||||||||||||||||||
kdf_type: KdfType::Argon2id, | ||||||||||||||||||||||||||||||
iterations: 0, | ||||||||||||||||||||||||||||||
memory: Some(64), | ||||||||||||||||||||||||||||||
parallelism: Some(4), | ||||||||||||||||||||||||||||||
}), | ||||||||||||||||||||||||||||||
master_key_encrypted_user_key: Some(TEST_USER_KEY.to_string()), | ||||||||||||||||||||||||||||||
salt: Some(TEST_SALT.to_string()), | ||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||
let result = MasterPasswordUnlockData::try_from(response); | ||||||||||||||||||||||||||||||
assert!(matches!(result, Err(MasterPasswordError::KdfMalformed))); | ||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||
} |
Uh oh!
There was an error while loading. Please reload this page.