bitwarden_vault/
collection_client.rs

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