Skip to main content

bitwarden_vault/folder/
get_list.rs

1use bitwarden_crypto::CryptoError;
2use bitwarden_error::bitwarden_error;
3use bitwarden_state::repository::{RepositoryError, RepositoryOption};
4use thiserror::Error;
5#[cfg(feature = "wasm")]
6use wasm_bindgen::prelude::*;
7
8use crate::{FolderId, FolderView, FoldersClient, ItemNotFoundError};
9
10#[allow(missing_docs)]
11#[bitwarden_error(flat)]
12#[derive(Debug, Error)]
13pub enum GetFolderError {
14    #[error(transparent)]
15    ItemNotFound(#[from] ItemNotFoundError),
16    #[error(transparent)]
17    Crypto(#[from] CryptoError),
18    #[error(transparent)]
19    Repository(#[from] RepositoryError),
20}
21
22#[cfg_attr(feature = "wasm", wasm_bindgen)]
23impl FoldersClient {
24    /// Get a specific [crate::Folder] by its ID from state and decrypt it to a [FolderView].
25    pub async fn get(&self, folder_id: FolderId) -> Result<FolderView, GetFolderError> {
26        let folder = self
27            .repository
28            .require()?
29            .get(folder_id)
30            .await?
31            .ok_or(ItemNotFoundError)?;
32
33        Ok(self.key_store.decrypt(&folder)?)
34    }
35
36    /// Get all folders from state and decrypt them to a list of [FolderView].
37    pub async fn list(&self) -> Result<Vec<FolderView>, GetFolderError> {
38        let folders = self.repository.require()?.list().await?;
39        let views = self.key_store.decrypt_list(&folders)?;
40        Ok(views)
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use std::sync::Arc;
47
48    use bitwarden_api_api::apis::ApiClient;
49    use bitwarden_core::{
50        client::ApiConfigurations, key_management::create_test_crypto_with_user_key,
51    };
52    use bitwarden_crypto::SymmetricCryptoKey;
53    use bitwarden_test::MemoryRepository;
54    use uuid::uuid;
55
56    use super::*;
57    use crate::Folder;
58
59    fn create_client() -> FoldersClient {
60        let store =
61            create_test_crypto_with_user_key(SymmetricCryptoKey::make_aes256_cbc_hmac_key());
62        let repository = Arc::new(MemoryRepository::<Folder>::default());
63
64        FoldersClient {
65            key_store: store,
66            api_configurations: Arc::new(ApiConfigurations::from_api_client(
67                ApiClient::new_mocked(|_| {}),
68            )),
69            repository: Some(repository),
70        }
71    }
72
73    fn make_folder(client: &FoldersClient, id: FolderId, name: &str) -> Folder {
74        client
75            .key_store
76            .encrypt(FolderView {
77                id: Some(id),
78                name: name.to_string(),
79                revision_date: "2025-01-01T00:00:00Z".parse().unwrap(),
80            })
81            .unwrap()
82    }
83
84    #[tokio::test]
85    async fn test_get_folder() {
86        let client = create_client();
87        let folder_id = FolderId::new(uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1"));
88        let folder = make_folder(&client, folder_id, "Test Folder");
89
90        client
91            .repository
92            .as_ref()
93            .unwrap()
94            .set(folder_id, folder)
95            .await
96            .unwrap();
97
98        let result = client.get(folder_id).await.unwrap();
99
100        assert_eq!(
101            result,
102            FolderView {
103                id: Some(folder_id),
104                name: "Test Folder".to_string(),
105                revision_date: "2025-01-01T00:00:00Z".parse().unwrap(),
106            }
107        );
108    }
109
110    #[tokio::test]
111    async fn test_get_folder_not_found() {
112        let client = create_client();
113        let folder_id = FolderId::new(uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1"));
114
115        let result = client.get(folder_id).await;
116
117        assert!(result.is_err());
118        assert!(matches!(
119            result.unwrap_err(),
120            GetFolderError::ItemNotFound(_)
121        ));
122    }
123
124    #[tokio::test]
125    async fn test_list_folders() {
126        let client = create_client();
127        let id_a = FolderId::new(uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1"));
128        let id_b = FolderId::new(uuid!("35afb11c-9c95-4db5-8bac-c21cb204a3f2"));
129
130        let repository = client.repository.as_ref().unwrap();
131        repository
132            .set(id_a, make_folder(&client, id_a, "Folder A"))
133            .await
134            .unwrap();
135        repository
136            .set(id_b, make_folder(&client, id_b, "Folder B"))
137            .await
138            .unwrap();
139
140        let mut result = client.list().await.unwrap();
141        result.sort_by(|a, b| a.name.cmp(&b.name));
142
143        assert_eq!(result.len(), 2);
144        assert_eq!(result[0].name, "Folder A");
145        assert_eq!(result[1].name, "Folder B");
146    }
147
148    #[tokio::test]
149    async fn test_list_folders_empty() {
150        let client = create_client();
151
152        let result = client.list().await.unwrap();
153
154        assert!(result.is_empty());
155    }
156}