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