bitwarden_vault/
password_history.rs1use 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}