bitwarden_vault/cipher/
card.rs

1use bitwarden_api_api::models::CipherCardModel;
2use bitwarden_core::key_management::{KeyIds, SymmetricKeyId};
3use bitwarden_crypto::{CryptoError, Decryptable, EncString, Encryptable, KeyStoreContext};
4use serde::{Deserialize, Serialize};
5#[cfg(feature = "wasm")]
6use tsify_next::Tsify;
7
8use crate::VaultParseError;
9
10#[derive(Serialize, Deserialize, Debug, Clone)]
11#[serde(rename_all = "camelCase", deny_unknown_fields)]
12#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
13#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
14pub struct Card {
15    pub cardholder_name: Option<EncString>,
16    pub exp_month: Option<EncString>,
17    pub exp_year: Option<EncString>,
18    pub code: Option<EncString>,
19    pub brand: Option<EncString>,
20    pub number: Option<EncString>,
21}
22
23#[derive(Serialize, Deserialize, Debug, Clone)]
24#[serde(rename_all = "camelCase", deny_unknown_fields)]
25#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
26#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
27pub struct CardView {
28    pub cardholder_name: Option<String>,
29    pub exp_month: Option<String>,
30    pub exp_year: Option<String>,
31    pub code: Option<String>,
32    pub brand: Option<String>,
33    pub number: Option<String>,
34}
35
36#[derive(Serialize, Deserialize)]
37pub enum CardBrand {
38    Visa,
39    Mastercard,
40    Amex,
41    Discover,
42    #[serde(rename = "Diners Club")]
43    DinersClub,
44    #[serde(rename = "JCB")]
45    Jcb,
46    Maestro,
47    UnionPay,
48    RuPay,
49    #[serde(untagged)]
50    Other,
51}
52
53impl Encryptable<KeyIds, SymmetricKeyId, Card> for CardView {
54    fn encrypt(
55        &self,
56        ctx: &mut KeyStoreContext<KeyIds>,
57        key: SymmetricKeyId,
58    ) -> Result<Card, CryptoError> {
59        Ok(Card {
60            cardholder_name: self.cardholder_name.encrypt(ctx, key)?,
61            exp_month: self.exp_month.encrypt(ctx, key)?,
62            exp_year: self.exp_year.encrypt(ctx, key)?,
63            code: self.code.encrypt(ctx, key)?,
64            brand: self.brand.encrypt(ctx, key)?,
65            number: self.number.encrypt(ctx, key)?,
66        })
67    }
68}
69
70impl Decryptable<KeyIds, SymmetricKeyId, CardView> for Card {
71    fn decrypt(
72        &self,
73        ctx: &mut KeyStoreContext<KeyIds>,
74        key: SymmetricKeyId,
75    ) -> Result<CardView, CryptoError> {
76        Ok(CardView {
77            cardholder_name: self.cardholder_name.decrypt(ctx, key).ok().flatten(),
78            exp_month: self.exp_month.decrypt(ctx, key).ok().flatten(),
79            exp_year: self.exp_year.decrypt(ctx, key).ok().flatten(),
80            code: self.code.decrypt(ctx, key).ok().flatten(),
81            brand: self.brand.decrypt(ctx, key).ok().flatten(),
82            number: self.number.decrypt(ctx, key).ok().flatten(),
83        })
84    }
85}
86
87impl TryFrom<CipherCardModel> for Card {
88    type Error = VaultParseError;
89
90    fn try_from(card: CipherCardModel) -> Result<Self, Self::Error> {
91        Ok(Self {
92            cardholder_name: EncString::try_from_optional(card.cardholder_name)?,
93            exp_month: EncString::try_from_optional(card.exp_month)?,
94            exp_year: EncString::try_from_optional(card.exp_year)?,
95            code: EncString::try_from_optional(card.code)?,
96            brand: EncString::try_from_optional(card.brand)?,
97            number: EncString::try_from_optional(card.number)?,
98        })
99    }
100}