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, SymmetricKeyAlgorithm};
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 = create_test_crypto_with_user_key(SymmetricCryptoKey::make(
61            SymmetricKeyAlgorithm::Aes256CbcHmac,
62        ));
63        let repository = Arc::new(MemoryRepository::<Folder>::default());
64
65        FoldersClient {
66            key_store: store,
67            api_configurations: Arc::new(ApiConfigurations::from_api_client(
68                ApiClient::new_mocked(|_| {}),
69            )),
70            repository: Some(repository),
71        }
72    }
73
74    fn make_folder(client: &FoldersClient, id: FolderId, name: &str) -> Folder {
75        client
76            .key_store
77            .encrypt(FolderView {
78                id: Some(id),
79                name: name.to_string(),
80                revision_date: "2025-01-01T00:00:00Z".parse().unwrap(),
81            })
82            .unwrap()
83    }
84
85    #[tokio::test]
86    async fn test_get_folder() {
87        let client = create_client();
88        let folder_id = FolderId::new(uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1"));
89        let folder = make_folder(&client, folder_id, "Test Folder");
90
91        client
92            .repository
93            .as_ref()
94            .unwrap()
95            .set(folder_id, folder)
96            .await
97            .unwrap();
98
99        let result = client.get(folder_id).await.unwrap();
100
101        assert_eq!(
102            result,
103            FolderView {
104                id: Some(folder_id),
105                name: "Test Folder".to_string(),
106                revision_date: "2025-01-01T00:00:00Z".parse().unwrap(),
107            }
108        );
109    }
110
111    #[tokio::test]
112    async fn test_get_folder_not_found() {
113        let client = create_client();
114        let folder_id = FolderId::new(uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1"));
115
116        let result = client.get(folder_id).await;
117
118        assert!(result.is_err());
119        assert!(matches!(
120            result.unwrap_err(),
121            GetFolderError::ItemNotFound(_)
122        ));
123    }
124
125    #[tokio::test]
126    async fn test_list_folders() {
127        let client = create_client();
128        let id_a = FolderId::new(uuid!("25afb11c-9c95-4db5-8bac-c21cb204a3f1"));
129        let id_b = FolderId::new(uuid!("35afb11c-9c95-4db5-8bac-c21cb204a3f2"));
130
131        let repository = client.repository.as_ref().unwrap();
132        repository
133            .set(id_a, make_folder(&client, id_a, "Folder A"))
134            .await
135            .unwrap();
136        repository
137            .set(id_b, make_folder(&client, id_b, "Folder B"))
138            .await
139            .unwrap();
140
141        let mut result = client.list().await.unwrap();
142        result.sort_by(|a, b| a.name.cmp(&b.name));
143
144        assert_eq!(result.len(), 2);
145        assert_eq!(result[0].name, "Folder A");
146        assert_eq!(result[1].name, "Folder B");
147    }
148
149    #[tokio::test]
150    async fn test_list_folders_empty() {
151        let client = create_client();
152
153        let result = client.list().await.unwrap();
154
155        assert!(result.is_empty());
156    }
157}