bitwarden_vault/
collection_client.rs1use 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 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}