124 lines
4.2 KiB
Rust
124 lines
4.2 KiB
Rust
use std::{
|
|
io::{Cursor, Read},
|
|
ops::Deref,
|
|
};
|
|
|
|
use napi::bindgen_prelude::Uint8Array;
|
|
use napi_derive::*;
|
|
|
|
use crate::into_err;
|
|
|
|
/// A type to encrypt and to decrypt anything that can fit in an
|
|
/// `Uint8Array`, usually big buffer.
|
|
#[napi]
|
|
pub struct Attachment;
|
|
|
|
#[napi]
|
|
impl Attachment {
|
|
/// Encrypt the content of the `Uint8Array`.
|
|
///
|
|
/// It produces an `EncryptedAttachment`, which can be used to
|
|
/// retrieve the media encryption information, or the encrypted
|
|
/// data.
|
|
#[napi]
|
|
pub fn encrypt(array: Uint8Array) -> napi::Result<EncryptedAttachment> {
|
|
let buffer: &[u8] = array.deref();
|
|
|
|
let mut cursor = Cursor::new(buffer);
|
|
let mut encryptor = matrix_sdk_crypto::AttachmentEncryptor::new(&mut cursor);
|
|
|
|
let mut encrypted_data = Vec::new();
|
|
encryptor.read_to_end(&mut encrypted_data).map_err(into_err)?;
|
|
|
|
let media_encryption_info = Some(encryptor.finish());
|
|
|
|
Ok(EncryptedAttachment {
|
|
encrypted_data: Uint8Array::new(encrypted_data),
|
|
media_encryption_info,
|
|
})
|
|
}
|
|
|
|
/// Decrypt an `EncryptedAttachment`.
|
|
///
|
|
/// The encrypted attachment can be created manually, or from the
|
|
/// `encrypt` method.
|
|
///
|
|
/// **Warning**: The encrypted attachment can be used only
|
|
/// **once**! The encrypted data will still be present, but the
|
|
/// media encryption info (which contain secrets) will be
|
|
/// destroyed. It is still possible to get a JSON-encoded backup
|
|
/// by calling `EncryptedAttachment.mediaEncryptionInfo`.
|
|
#[napi]
|
|
pub fn decrypt(attachment: &mut EncryptedAttachment) -> napi::Result<Uint8Array> {
|
|
let Some(media_encryption_info) = attachment.media_encryption_info.take() else {
|
|
return Err(napi::Error::from_reason(
|
|
"The media encryption info are absent from the given encrypted attachment"
|
|
.to_owned(),
|
|
));
|
|
};
|
|
|
|
let encrypted_data: &[u8] = attachment.encrypted_data.deref();
|
|
|
|
let mut cursor = Cursor::new(encrypted_data);
|
|
let mut decryptor =
|
|
matrix_sdk_crypto::AttachmentDecryptor::new(&mut cursor, media_encryption_info)
|
|
.map_err(into_err)?;
|
|
|
|
let mut decrypted_data = Vec::new();
|
|
decryptor.read_to_end(&mut decrypted_data).map_err(into_err)?;
|
|
|
|
Ok(Uint8Array::new(decrypted_data))
|
|
}
|
|
}
|
|
|
|
/// An encrypted attachment, usually created from `Attachment.encrypt`.
|
|
#[napi]
|
|
pub struct EncryptedAttachment {
|
|
media_encryption_info: Option<matrix_sdk_crypto::MediaEncryptionInfo>,
|
|
|
|
/// The actual encrypted data.
|
|
pub encrypted_data: Uint8Array,
|
|
}
|
|
|
|
#[napi]
|
|
impl EncryptedAttachment {
|
|
/// Create a new encrypted attachment manually.
|
|
///
|
|
/// It needs encrypted data, stored in an `Uint8Array`, and a
|
|
/// [media encryption
|
|
/// information](https://docs.rs/matrix-sdk-crypto/latest/matrix_sdk_crypto/struct.MediaEncryptionInfo.html),
|
|
/// as a JSON-encoded string.
|
|
///
|
|
/// The media encryption information aren't stored as a string:
|
|
/// they are parsed, validated and fully deserialized.
|
|
///
|
|
/// See [the specification to learn
|
|
/// more](https://spec.matrix.org/unstable/client-server-api/#extensions-to-mroommessage-msgtypes).
|
|
#[napi(constructor)]
|
|
pub fn new(encrypted_data: Uint8Array, media_encryption_info: String) -> napi::Result<Self> {
|
|
Ok(Self {
|
|
encrypted_data,
|
|
media_encryption_info: Some(
|
|
serde_json::from_str(media_encryption_info.as_str()).map_err(into_err)?,
|
|
),
|
|
})
|
|
}
|
|
|
|
/// Return the media encryption info as a JSON-encoded string. The
|
|
/// structure is fully valid.
|
|
///
|
|
/// If the media encryption info have been consumed already, it
|
|
/// will return `null`.
|
|
#[napi(getter)]
|
|
pub fn media_encryption_info(&self) -> Option<String> {
|
|
serde_json::to_string(self.media_encryption_info.as_ref()?).ok()
|
|
}
|
|
|
|
/// Check whether the media encryption info has been consumed by
|
|
/// `Attachment.decrypt` already.
|
|
#[napi(getter)]
|
|
pub fn has_media_encryption_info_been_consumed(&self) -> bool {
|
|
self.media_encryption_info.is_none()
|
|
}
|
|
}
|