bitwarden_vault/
collection_client.rs

1use std::collections::HashMap;
2
3use bitwarden_collections::{
4    collection::{Collection, CollectionId, CollectionView},
5    tree::{NodeItem, Tree},
6};
7use bitwarden_core::Client;
8#[cfg(feature = "wasm")]
9use serde::{Deserialize, Serialize};
10#[cfg(feature = "wasm")]
11use tsify::Tsify;
12#[cfg(feature = "wasm")]
13use wasm_bindgen::prelude::wasm_bindgen;
14
15use crate::DecryptError;
16
17#[allow(missing_docs)]
18#[cfg_attr(feature = "wasm", wasm_bindgen)]
19#[derive(Clone)]
20pub struct CollectionsClient {
21    pub(crate) client: Client,
22}
23
24#[cfg_attr(feature = "wasm", wasm_bindgen)]
25impl CollectionsClient {
26    #[allow(missing_docs)]
27    pub fn decrypt(&self, collection: Collection) -> Result<CollectionView, DecryptError> {
28        let key_store = self.client.internal.get_key_store();
29        let view = key_store.decrypt(&collection)?;
30        Ok(view)
31    }
32
33    #[allow(missing_docs)]
34    pub fn decrypt_list(
35        &self,
36        collections: Vec<Collection>,
37    ) -> Result<Vec<CollectionView>, DecryptError> {
38        let key_store = self.client.internal.get_key_store();
39        let views = key_store.decrypt_list(&collections)?;
40        Ok(views)
41    }
42
43    ///
44    /// Returns the vector of CollectionView objects in a tree structure based on its implemented
45    /// path().
46    pub fn get_collection_tree(&self, collections: Vec<CollectionView>) -> CollectionViewTree {
47        CollectionViewTree {
48            tree: Tree::from_items(collections),
49        }
50    }
51}
52
53#[cfg_attr(feature = "wasm", wasm_bindgen)]
54pub struct CollectionViewTree {
55    tree: Tree<CollectionView>,
56}
57
58#[cfg_attr(feature = "wasm", wasm_bindgen)]
59pub struct CollectionViewNodeItem {
60    node_item: NodeItem<CollectionView>,
61}
62
63#[cfg_attr(
64    feature = "wasm",
65    derive(Tsify, Serialize, Deserialize),
66    tsify(into_wasm_abi, from_wasm_abi)
67)]
68#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
69pub struct AncestorMap {
70    pub ancestors: HashMap<CollectionId, String>,
71}
72
73#[cfg_attr(feature = "wasm", wasm_bindgen)]
74impl CollectionViewNodeItem {
75    pub fn get_item(&self) -> CollectionView {
76        self.node_item.item.clone()
77    }
78
79    pub fn get_parent(&self) -> Option<CollectionView> {
80        self.node_item.parent.clone()
81    }
82
83    pub fn get_children(&self) -> Vec<CollectionView> {
84        self.node_item.children.clone()
85    }
86
87    pub fn get_ancestors(&self) -> AncestorMap {
88        AncestorMap {
89            ancestors: self
90                .node_item
91                .ancestors
92                .iter()
93                .map(|(&uuid, name)| (CollectionId::new(uuid), name.clone()))
94                .collect(),
95        }
96    }
97}
98
99#[cfg_attr(feature = "wasm", wasm_bindgen)]
100impl CollectionViewTree {
101    pub fn get_item_for_view(
102        &self,
103        collection_view: CollectionView,
104    ) -> Option<CollectionViewNodeItem> {
105        self.tree
106            .get_item_by_id(collection_view.id.unwrap_or_default().into())
107            .map(|n| CollectionViewNodeItem { node_item: n })
108    }
109
110    pub fn get_root_items(&self) -> Vec<CollectionViewNodeItem> {
111        self.tree
112            .get_root_items()
113            .into_iter()
114            .map(|n| CollectionViewNodeItem { node_item: n })
115            .collect()
116    }
117
118    pub fn get_flat_items(&self) -> Vec<CollectionViewNodeItem> {
119        self.tree
120            .get_flat_items()
121            .into_iter()
122            .map(|n| CollectionViewNodeItem { node_item: n })
123            .collect()
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use bitwarden_collections::collection::CollectionType;
130    use bitwarden_core::client::test_accounts::test_bitwarden_com_account;
131
132    use super::*;
133    use crate::VaultClientExt;
134
135    #[tokio::test]
136    async fn test_decrypt_list() {
137        let client = Client::init_test_account(test_bitwarden_com_account()).await;
138
139        let dec = client.vault().collections().decrypt_list(vec![Collection {
140            id: Some("66c5ca57-0868-4c7e-902f-b181009709c0".parse().unwrap()),
141            organization_id: "1bc9ac1e-f5aa-45f2-94bf-b181009709b8".parse().unwrap(),
142            name: "2.EI9Km5BfrIqBa1W+WCccfA==|laWxNnx+9H3MZww4zm7cBSLisjpi81zreaQntRhegVI=|x42+qKFf5ga6DIL0OW5pxCdLrC/gm8CXJvf3UASGteI=".parse().unwrap(),
143            external_id: None,
144            hide_passwords: false,
145            read_only: false,
146            manage: false,
147            default_user_collection_email: None,
148            r#type: CollectionType::SharedCollection,
149        }]).unwrap();
150
151        assert_eq!(dec[0].name, "Default collection");
152    }
153
154    #[tokio::test]
155    async fn test_decrypt() {
156        let client = Client::init_test_account(test_bitwarden_com_account()).await;
157
158        let dec = client.vault().collections().decrypt(Collection {
159            id: Some("66c5ca57-0868-4c7e-902f-b181009709c0".parse().unwrap()),
160            organization_id: "1bc9ac1e-f5aa-45f2-94bf-b181009709b8".parse().unwrap(),
161            name: "2.EI9Km5BfrIqBa1W+WCccfA==|laWxNnx+9H3MZww4zm7cBSLisjpi81zreaQntRhegVI=|x42+qKFf5ga6DIL0OW5pxCdLrC/gm8CXJvf3UASGteI=".parse().unwrap(),
162            external_id: None,
163            hide_passwords: false,
164            read_only: false,
165            manage: false,
166            default_user_collection_email: None,
167            r#type: CollectionType::SharedCollection,
168        }).unwrap();
169
170        assert_eq!(dec.name, "Default collection");
171    }
172}