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