bitwarden_vault/
password_history.rs1use bitwarden_api_api::models::CipherPasswordHistoryModel;
2use bitwarden_core::key_management::{KeyIds, SymmetricKeyId};
3use bitwarden_crypto::{
4 CompositeEncryptable, CryptoError, Decryptable, EncString, IdentifyKey, KeyStoreContext,
5 PrimitiveEncryptable,
6};
7use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9#[cfg(feature = "wasm")]
10use tsify::Tsify;
11
12use crate::VaultParseError;
13
14#[allow(missing_docs)]
15#[derive(Serialize, Deserialize, Debug, Clone)]
16#[serde(rename_all = "camelCase", deny_unknown_fields)]
17#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
18#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
19pub struct PasswordHistory {
20 password: EncString,
21 last_used_date: DateTime<Utc>,
22}
23
24#[allow(missing_docs)]
25#[derive(Serialize, Deserialize, Debug, Clone)]
26#[serde(rename_all = "camelCase", deny_unknown_fields)]
27#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
28#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
29pub struct PasswordHistoryView {
30 password: String,
31 last_used_date: DateTime<Utc>,
32}
33
34impl IdentifyKey<SymmetricKeyId> for PasswordHistory {
35 fn key_identifier(&self) -> SymmetricKeyId {
36 SymmetricKeyId::User
37 }
38}
39impl IdentifyKey<SymmetricKeyId> for PasswordHistoryView {
40 fn key_identifier(&self) -> SymmetricKeyId {
41 SymmetricKeyId::User
42 }
43}
44
45impl CompositeEncryptable<KeyIds, SymmetricKeyId, PasswordHistory> for PasswordHistoryView {
46 fn encrypt_composite(
47 &self,
48 ctx: &mut KeyStoreContext<KeyIds>,
49 key: SymmetricKeyId,
50 ) -> Result<PasswordHistory, CryptoError> {
51 Ok(PasswordHistory {
52 password: self.password.encrypt(ctx, key)?,
53 last_used_date: self.last_used_date,
54 })
55 }
56}
57
58impl Decryptable<KeyIds, SymmetricKeyId, PasswordHistoryView> for PasswordHistory {
59 fn decrypt(
60 &self,
61 ctx: &mut KeyStoreContext<KeyIds>,
62 key: SymmetricKeyId,
63 ) -> Result<PasswordHistoryView, CryptoError> {
64 Ok(PasswordHistoryView {
65 password: self.password.decrypt(ctx, key).ok().unwrap_or_default(),
66 last_used_date: self.last_used_date,
67 })
68 }
69}
70
71impl TryFrom<CipherPasswordHistoryModel> for PasswordHistory {
72 type Error = VaultParseError;
73
74 fn try_from(model: CipherPasswordHistoryModel) -> Result<Self, Self::Error> {
75 Ok(Self {
76 password: model.password.parse()?,
77 last_used_date: model.last_used_date.parse()?,
78 })
79 }
80}