bitwarden_vault/cipher/
field.rs

1use bitwarden_api_api::models::CipherFieldModel;
2use bitwarden_core::{
3    key_management::{KeyIds, SymmetricKeyId},
4    require,
5};
6use bitwarden_crypto::{CryptoError, Decryptable, EncString, Encryptable, KeyStoreContext};
7use serde::{Deserialize, Serialize};
8use serde_repr::{Deserialize_repr, Serialize_repr};
9#[cfg(feature = "wasm")]
10use tsify_next::Tsify;
11#[cfg(feature = "wasm")]
12use wasm_bindgen::prelude::wasm_bindgen;
13
14use super::linked_id::LinkedIdType;
15use crate::VaultParseError;
16
17#[derive(Clone, Copy, Serialize_repr, Deserialize_repr, Debug)]
18#[repr(u8)]
19#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
20#[cfg_attr(feature = "wasm", wasm_bindgen)]
21pub enum FieldType {
22    Text = 0,
23    Hidden = 1,
24    Boolean = 2,
25    Linked = 3,
26}
27
28#[derive(Serialize, Deserialize, Debug, Clone)]
29#[serde(rename_all = "camelCase", deny_unknown_fields)]
30#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
31#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
32pub struct Field {
33    name: Option<EncString>,
34    value: Option<EncString>,
35    r#type: FieldType,
36
37    linked_id: Option<LinkedIdType>,
38}
39
40#[derive(Serialize, Deserialize, Debug, Clone)]
41#[serde(rename_all = "camelCase", deny_unknown_fields)]
42#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
43#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
44pub struct FieldView {
45    pub name: Option<String>,
46    pub value: Option<String>,
47    pub r#type: FieldType,
48
49    pub linked_id: Option<LinkedIdType>,
50}
51
52impl Encryptable<KeyIds, SymmetricKeyId, Field> for FieldView {
53    fn encrypt(
54        &self,
55        ctx: &mut KeyStoreContext<KeyIds>,
56        key: SymmetricKeyId,
57    ) -> Result<Field, CryptoError> {
58        Ok(Field {
59            name: self.name.encrypt(ctx, key)?,
60            value: self.value.encrypt(ctx, key)?,
61            r#type: self.r#type,
62            linked_id: self.linked_id,
63        })
64    }
65}
66
67impl Decryptable<KeyIds, SymmetricKeyId, FieldView> for Field {
68    fn decrypt(
69        &self,
70        ctx: &mut KeyStoreContext<KeyIds>,
71        key: SymmetricKeyId,
72    ) -> Result<FieldView, CryptoError> {
73        Ok(FieldView {
74            name: self.name.decrypt(ctx, key).ok().flatten(),
75            value: self.value.decrypt(ctx, key).ok().flatten(),
76            r#type: self.r#type,
77            linked_id: self.linked_id,
78        })
79    }
80}
81
82impl TryFrom<CipherFieldModel> for Field {
83    type Error = VaultParseError;
84
85    fn try_from(model: CipherFieldModel) -> Result<Self, Self::Error> {
86        Ok(Self {
87            name: EncString::try_from_optional(model.name)?,
88            value: EncString::try_from_optional(model.value)?,
89            r#type: require!(model.r#type).into(),
90            linked_id: model
91                .linked_id
92                .map(|id| (id as u32).try_into())
93                .transpose()?,
94        })
95    }
96}
97
98impl From<bitwarden_api_api::models::FieldType> for FieldType {
99    fn from(model: bitwarden_api_api::models::FieldType) -> Self {
100        match model {
101            bitwarden_api_api::models::FieldType::Text => FieldType::Text,
102            bitwarden_api_api::models::FieldType::Hidden => FieldType::Hidden,
103            bitwarden_api_api::models::FieldType::Boolean => FieldType::Boolean,
104            bitwarden_api_api::models::FieldType::Linked => FieldType::Linked,
105        }
106    }
107}