bitwarden_vault/
password_history.rs

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