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