1use bitwarden_api_api::models::CipherIdentityModel;
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 Identity {
15 pub title: Option<EncString>,
16 pub first_name: Option<EncString>,
17 pub middle_name: Option<EncString>,
18 pub last_name: Option<EncString>,
19 pub address1: Option<EncString>,
20 pub address2: Option<EncString>,
21 pub address3: Option<EncString>,
22 pub city: Option<EncString>,
23 pub state: Option<EncString>,
24 pub postal_code: Option<EncString>,
25 pub country: Option<EncString>,
26 pub company: Option<EncString>,
27 pub email: Option<EncString>,
28 pub phone: Option<EncString>,
29 pub ssn: Option<EncString>,
30 pub username: Option<EncString>,
31 pub passport_number: Option<EncString>,
32 pub license_number: Option<EncString>,
33}
34
35#[derive(Serialize, Deserialize, Debug, Clone)]
36#[serde(rename_all = "camelCase", deny_unknown_fields)]
37#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
38#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
39pub struct IdentityView {
40 pub title: Option<String>,
41 pub first_name: Option<String>,
42 pub middle_name: Option<String>,
43 pub last_name: Option<String>,
44 pub address1: Option<String>,
45 pub address2: Option<String>,
46 pub address3: Option<String>,
47 pub city: Option<String>,
48 pub state: Option<String>,
49 pub postal_code: Option<String>,
50 pub country: Option<String>,
51 pub company: Option<String>,
52 pub email: Option<String>,
53 pub phone: Option<String>,
54 pub ssn: Option<String>,
55 pub username: Option<String>,
56 pub passport_number: Option<String>,
57 pub license_number: Option<String>,
58}
59
60impl Encryptable<KeyIds, SymmetricKeyId, Identity> for IdentityView {
61 fn encrypt(
62 &self,
63 ctx: &mut KeyStoreContext<KeyIds>,
64 key: SymmetricKeyId,
65 ) -> Result<Identity, CryptoError> {
66 Ok(Identity {
67 title: self.title.encrypt(ctx, key)?,
68 first_name: self.first_name.encrypt(ctx, key)?,
69 middle_name: self.middle_name.encrypt(ctx, key)?,
70 last_name: self.last_name.encrypt(ctx, key)?,
71 address1: self.address1.encrypt(ctx, key)?,
72 address2: self.address2.encrypt(ctx, key)?,
73 address3: self.address3.encrypt(ctx, key)?,
74 city: self.city.encrypt(ctx, key)?,
75 state: self.state.encrypt(ctx, key)?,
76 postal_code: self.postal_code.encrypt(ctx, key)?,
77 country: self.country.encrypt(ctx, key)?,
78 company: self.company.encrypt(ctx, key)?,
79 email: self.email.encrypt(ctx, key)?,
80 phone: self.phone.encrypt(ctx, key)?,
81 ssn: self.ssn.encrypt(ctx, key)?,
82 username: self.username.encrypt(ctx, key)?,
83 passport_number: self.passport_number.encrypt(ctx, key)?,
84 license_number: self.license_number.encrypt(ctx, key)?,
85 })
86 }
87}
88
89impl Decryptable<KeyIds, SymmetricKeyId, IdentityView> for Identity {
90 fn decrypt(
91 &self,
92 ctx: &mut KeyStoreContext<KeyIds>,
93 key: SymmetricKeyId,
94 ) -> Result<IdentityView, CryptoError> {
95 Ok(IdentityView {
96 title: self.title.decrypt(ctx, key).ok().flatten(),
97 first_name: self.first_name.decrypt(ctx, key).ok().flatten(),
98 middle_name: self.middle_name.decrypt(ctx, key).ok().flatten(),
99 last_name: self.last_name.decrypt(ctx, key).ok().flatten(),
100 address1: self.address1.decrypt(ctx, key).ok().flatten(),
101 address2: self.address2.decrypt(ctx, key).ok().flatten(),
102 address3: self.address3.decrypt(ctx, key).ok().flatten(),
103 city: self.city.decrypt(ctx, key).ok().flatten(),
104 state: self.state.decrypt(ctx, key).ok().flatten(),
105 postal_code: self.postal_code.decrypt(ctx, key).ok().flatten(),
106 country: self.country.decrypt(ctx, key).ok().flatten(),
107 company: self.company.decrypt(ctx, key).ok().flatten(),
108 email: self.email.decrypt(ctx, key).ok().flatten(),
109 phone: self.phone.decrypt(ctx, key).ok().flatten(),
110 ssn: self.ssn.decrypt(ctx, key).ok().flatten(),
111 username: self.username.decrypt(ctx, key).ok().flatten(),
112 passport_number: self.passport_number.decrypt(ctx, key).ok().flatten(),
113 license_number: self.license_number.decrypt(ctx, key).ok().flatten(),
114 })
115 }
116}
117
118impl TryFrom<CipherIdentityModel> for Identity {
119 type Error = VaultParseError;
120
121 fn try_from(identity: CipherIdentityModel) -> Result<Self, Self::Error> {
122 Ok(Self {
123 title: EncString::try_from_optional(identity.title)?,
124 first_name: EncString::try_from_optional(identity.first_name)?,
125 middle_name: EncString::try_from_optional(identity.middle_name)?,
126 last_name: EncString::try_from_optional(identity.last_name)?,
127 address1: EncString::try_from_optional(identity.address1)?,
128 address2: EncString::try_from_optional(identity.address2)?,
129 address3: EncString::try_from_optional(identity.address3)?,
130 city: EncString::try_from_optional(identity.city)?,
131 state: EncString::try_from_optional(identity.state)?,
132 postal_code: EncString::try_from_optional(identity.postal_code)?,
133 country: EncString::try_from_optional(identity.country)?,
134 company: EncString::try_from_optional(identity.company)?,
135 email: EncString::try_from_optional(identity.email)?,
136 phone: EncString::try_from_optional(identity.phone)?,
137 ssn: EncString::try_from_optional(identity.ssn)?,
138 username: EncString::try_from_optional(identity.username)?,
139 passport_number: EncString::try_from_optional(identity.passport_number)?,
140 license_number: EncString::try_from_optional(identity.license_number)?,
141 })
142 }
143}