1#[cfg(feature = "wasm")]
2use bitwarden_core::key_management::KeySlotIds;
3#[cfg(feature = "wasm")]
4use bitwarden_crypto::{CompositeEncryptable, KeyStore, SymmetricCryptoKey};
5#[cfg(feature = "wasm")]
6use bitwarden_encoding::B64;
7
8#[cfg(feature = "wasm")]
9use crate::{Send, SendView, send_client::SendClient, send_client::SendEncryptError};
10
11#[cfg(feature = "wasm")]
14fn encrypt_send_for_rotation(
15 key_store: &KeyStore<KeySlotIds>,
16 send_view: SendView,
17 new_key: B64,
18) -> Result<Send, SendEncryptError> {
19 let new_key = SymmetricCryptoKey::try_from(new_key)?;
20
21 let mut ctx = key_store.context();
22
23 let new_key_id = ctx.add_local_symmetric_key(new_key);
25
26 Ok(send_view.encrypt_composite(&mut ctx, new_key_id)?)
27}
28
29#[cfg(feature = "wasm")]
30#[bitwarden_ffi::wasm_export]
31impl SendClient {
32 #[allow(clippy::unused_async)]
40 pub async fn encrypt_send_for_rotation(
41 &self,
42 send_view: SendView,
43 new_key: B64,
44 ) -> Result<Send, SendEncryptError> {
45 let key_store = self.client.internal.get_key_store();
46
47 encrypt_send_for_rotation(key_store, send_view, new_key)
48 }
49}
50
51#[cfg(test)]
52#[cfg(feature = "wasm")]
53mod tests {
54 use bitwarden_core::key_management::create_test_crypto_with_user_key;
55 use bitwarden_crypto::{CryptoError, SymmetricCryptoKey, SymmetricKeyAlgorithm};
56
57 use super::*;
58 use crate::{AuthType, SendTextView, SendType};
59
60 fn test_send_view() -> SendView {
61 SendView {
62 id: "3d80dd72-2d14-4f26-812c-b0f0018aa144".parse().ok(),
63 access_id: Some("ct2APRQtJk-BLLDwAYqhRA".to_owned()),
64 name: "Test".to_string(),
65 notes: None,
66 key: Some("Pgui0FK85cNhBGWHAlBHBw".to_owned()),
67 new_password: None,
68 has_password: false,
69 r#type: SendType::Text,
70 file: None,
71 text: Some(SendTextView {
72 text: Some("This is a test".to_owned()),
73 hidden: false,
74 }),
75 data: None,
76 max_access_count: None,
77 access_count: 0,
78 disabled: false,
79 hide_email: false,
80 revision_date: "2024-01-07T23:56:48.207363Z".parse().unwrap(),
81 deletion_date: "2024-01-14T23:56:48Z".parse().unwrap(),
82 expiration_date: None,
83 emails: Vec::new(),
84 auth_type: AuthType::None,
85 }
86 }
87
88 #[test]
89 fn test_encrypt_send_for_rotation() {
90 let user_key = SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256CbcHmac);
91 let store = create_test_crypto_with_user_key(user_key);
92
93 let new_key = SymmetricCryptoKey::make(SymmetricKeyAlgorithm::Aes256CbcHmac);
94 let new_key_b64 = new_key.to_base64();
95
96 let send_view = test_send_view();
97
98 let rotated = encrypt_send_for_rotation(&store, send_view.clone(), new_key_b64).unwrap();
99
100 let new_store = create_test_crypto_with_user_key(new_key);
102 let decrypted: SendView = new_store.decrypt(&rotated).unwrap();
103 assert_eq!(decrypted.name, send_view.name);
104 assert_eq!(decrypted.text, send_view.text);
105
106 assert!(matches!(
108 store.decrypt::<_, Send, SendView>(&rotated).err(),
109 Some(CryptoError::Decrypt)
110 ));
111 }
112}