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