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#[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}