interop/clients/cryptobox/
native.rs

1use crate::clients::{EmulatedClient, EmulatedClientProtocol, EmulatedClientType, EmulatedProteusClient};
2use color_eyre::eyre::{Result, eyre};
3use std::cell::Cell;
4
5pub(crate) struct CryptoboxNativeClient {
6    client_id: Vec<u8>,
7    last_prekey_id: Cell<u16>,
8    cbox: Option<cryptobox::CBox<cryptobox::store::file::FileStore>>,
9    tempdir: Option<tempfile::TempDir>,
10}
11
12impl CryptoboxNativeClient {
13    pub(crate) fn new() -> Self {
14        let client_id = uuid::Uuid::new_v4().into_bytes().to_vec();
15        Self {
16            client_id,
17            last_prekey_id: Cell::new(0),
18            cbox: None,
19            tempdir: None,
20        }
21    }
22}
23
24#[async_trait::async_trait(?Send)]
25impl EmulatedClient for CryptoboxNativeClient {
26    fn client_name(&self) -> &str {
27        "Cryptobox::native"
28    }
29
30    fn client_type(&self) -> EmulatedClientType {
31        EmulatedClientType::Native
32    }
33
34    fn client_id(&self) -> &[u8] {
35        &self.client_id
36    }
37
38    fn client_protocol(&self) -> EmulatedClientProtocol {
39        EmulatedClientProtocol::PROTEUS
40    }
41
42    async fn wipe(mut self) -> Result<()> {
43        let _ = self.cbox.take();
44        if let Some(tempdir) = self.tempdir.take() {
45            tempdir.close()?;
46        }
47
48        Ok(())
49    }
50}
51
52#[async_trait::async_trait(?Send)]
53impl EmulatedProteusClient for CryptoboxNativeClient {
54    async fn init(&mut self) -> Result<()> {
55        let tempdir = tempfile::tempdir()?;
56        self.cbox = Some(cryptobox::CBox::file_open(tempdir.path())?);
57        self.tempdir = Some(tempdir);
58        Ok(())
59    }
60
61    async fn get_prekey(&self) -> Result<Vec<u8>> {
62        let cbox = self.cbox.as_ref().ok_or(eyre!("Cryptobox isn't initialized"))?;
63        self.last_prekey_id.replace(self.last_prekey_id.get() + 1);
64        let prekey_bundle = cbox.new_prekey(proteus::keys::PreKeyId::new(self.last_prekey_id.get()))?;
65        Ok(prekey_bundle.serialise()?)
66    }
67
68    async fn session_from_prekey(&self, session_id: &str, prekey: &[u8]) -> Result<()> {
69        let cbox = self.cbox.as_ref().ok_or(eyre!("Cryptobox isn't initialized"))?;
70        let mut session = cbox.session_from_prekey(session_id.to_string(), prekey)?;
71        cbox.session_save(&mut session)?;
72        Ok(())
73    }
74
75    async fn session_from_message(&self, session_id: &str, message: &[u8]) -> Result<Vec<u8>> {
76        let cbox = self.cbox.as_ref().ok_or(eyre!("Cryptobox isn't initialized"))?;
77        let (mut session, message) = cbox.session_from_message(session_id.to_string(), message)?;
78        cbox.session_save(&mut session)?;
79        Ok(message)
80    }
81
82    async fn encrypt(&self, session_id: &str, plaintext: &[u8]) -> Result<Vec<u8>> {
83        let cbox = self.cbox.as_ref().ok_or(eyre!("Cryptobox isn't initialized"))?;
84        let mut session = cbox
85            .session_load(session_id.to_string())?
86            .ok_or(eyre!("session not found"))?;
87        let encrypted = session.encrypt(plaintext)?;
88        cbox.session_save(&mut session)?;
89        Ok(encrypted)
90    }
91
92    async fn decrypt(&self, session_id: &str, ciphertext: &[u8]) -> Result<Vec<u8>> {
93        let cbox = self.cbox.as_ref().ok_or(eyre!("Cryptobox isn't initialized"))?;
94        let mut session = cbox
95            .session_load(session_id.to_string())?
96            .ok_or(eyre!("session not found"))?;
97        let decrypted = session.decrypt(ciphertext)?;
98        cbox.session_save(&mut session)?;
99        Ok(decrypted)
100    }
101
102    async fn fingerprint(&self) -> Result<String> {
103        self.cbox
104            .as_ref()
105            .map(|cbox| cbox.fingerprint())
106            .ok_or(eyre!("Cryptobox isn't initialized"))
107    }
108}