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#[allow(missing_docs)]
41#[derive(Serialize, Deserialize, Debug, Clone)]
42#[serde(rename_all = "camelCase", deny_unknown_fields)]
43#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
44#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
45pub struct FieldView {
46    pub name: Option<String>,
47    pub value: Option<String>,
48    pub r#type: FieldType,
49
50    pub linked_id: Option<LinkedIdType>,
51}
52
53impl Encryptable<KeyIds, SymmetricKeyId, Field> for FieldView {
54    fn encrypt(
55        &self,
56        ctx: &mut KeyStoreContext<KeyIds>,
57        key: SymmetricKeyId,
58    ) -> Result<Field, CryptoError> {
59        Ok(Field {
60            name: self.name.encrypt(ctx, key)?,
61            value: self.value.encrypt(ctx, key)?,
62            r#type: self.r#type,
63            linked_id: self.linked_id,
64        })
65    }
66}
67
68impl Decryptable<KeyIds, SymmetricKeyId, FieldView> for Field {
69    fn decrypt(
70        &self,
71        ctx: &mut KeyStoreContext<KeyIds>,
72        key: SymmetricKeyId,
73    ) -> Result<FieldView, CryptoError> {
74        Ok(FieldView {
75            name: self.name.decrypt(ctx, key).ok().flatten(),
76            value: self.value.decrypt(ctx, key).ok().flatten(),
77            r#type: self.r#type,
78            linked_id: self.linked_id,
79        })
80    }
81}
82
83impl TryFrom<CipherFieldModel> for Field {
84    type Error = VaultParseError;
85
86    fn try_from(model: CipherFieldModel) -> Result<Self, Self::Error> {
87        Ok(Self {
88            name: EncString::try_from_optional(model.name)?,
89            value: EncString::try_from_optional(model.value)?,
90            r#type: require!(model.r#type).into(),
91            linked_id: model
92                .linked_id
93                .map(|id| (id as u32).try_into())
94                .transpose()?,
95        })
96    }
97}
98
99impl From<bitwarden_api_api::models::FieldType> for FieldType {
100    fn from(model: bitwarden_api_api::models::FieldType) -> Self {
101        match model {
102            bitwarden_api_api::models::FieldType::Text => FieldType::Text,
103            bitwarden_api_api::models::FieldType::Hidden => FieldType::Hidden,
104            bitwarden_api_api::models::FieldType::Boolean => FieldType::Boolean,
105            bitwarden_api_api::models::FieldType::Linked => FieldType::Linked,
106        }
107    }
108}