bitwarden_vault/
password_history.rs

1use 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}