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