omegaupload/web/src/decrypt.rs

111 lines
3.5 KiB
Rust
Raw Normal View History

2021-10-26 18:19:14 -07:00
use std::io::Cursor;
2021-10-24 02:25:42 -07:00
use std::sync::Arc;
2021-10-23 10:10:55 -07:00
use gloo_console::log;
use js_sys::{Array, Uint8Array};
2021-10-31 00:57:52 -07:00
use omegaupload_common::crypto::{open_in_place, Error, Key};
2021-10-30 21:00:09 -07:00
use omegaupload_common::secrecy::{Secret, SecretVec};
2021-10-26 18:19:14 -07:00
use serde::Serialize;
2021-10-27 01:49:06 -07:00
use wasm_bindgen::JsCast;
use web_sys::{Blob, BlobPropertyBag};
2021-10-26 18:19:14 -07:00
#[derive(Clone, Serialize)]
pub struct ArchiveMeta {
name: String,
file_size: usize,
}
2021-10-23 10:10:55 -07:00
2021-10-24 11:40:19 -07:00
#[derive(Clone)]
pub enum DecryptedData {
String(Arc<String>),
Blob(Arc<Blob>),
Image(Arc<Blob>, usize),
2021-10-24 11:40:19 -07:00
Audio(Arc<Blob>),
Video(Arc<Blob>),
2021-10-26 18:19:14 -07:00
Archive(Arc<Blob>, Vec<ArchiveMeta>),
2021-10-24 11:40:19 -07:00
}
2021-10-23 10:10:55 -07:00
2021-10-24 20:54:49 -07:00
fn now() -> f64 {
web_sys::window()
.expect("should have a Window")
.performance()
.expect("should have a Performance")
.now()
}
2021-10-24 02:25:42 -07:00
pub fn decrypt(
2021-10-23 10:10:55 -07:00
mut container: Vec<u8>,
2021-10-31 00:57:52 -07:00
key: &Secret<Key>,
2021-10-30 21:00:09 -07:00
maybe_password: Option<SecretVec<u8>>,
2021-10-31 00:57:52 -07:00
) -> Result<DecryptedData, Error> {
open_in_place(&mut container, key, maybe_password)?;
2021-10-23 10:10:55 -07:00
2021-10-27 02:23:28 -07:00
let mime_type = tree_magic_mini::from_u8(&container);
log!("Mimetype: ", mime_type);
2021-10-27 01:49:06 -07:00
2021-10-27 02:23:28 -07:00
log!("Blob conversion started.");
let start = now();
let blob_chunks = Array::new_with_length(container.chunks(65536).len().try_into().unwrap());
for (i, chunk) in container.chunks(65536).enumerate() {
let array = Uint8Array::new_with_length(chunk.len().try_into().unwrap());
array.copy_from(chunk);
blob_chunks.set(i.try_into().unwrap(), array.dyn_into().unwrap());
}
let mut blob_props = BlobPropertyBag::new();
blob_props.type_(mime_type);
let blob = Arc::new(
Blob::new_with_u8_array_sequence_and_options(blob_chunks.dyn_ref().unwrap(), &blob_props)
2021-10-27 01:49:06 -07:00
.unwrap(),
2021-10-27 02:23:28 -07:00
);
2021-10-30 18:38:55 -07:00
2021-10-27 02:23:28 -07:00
log!(format!("Blob conversion completed in {}ms", now() - start));
2021-10-23 10:10:55 -07:00
2021-10-27 02:23:28 -07:00
if mime_type.starts_with("text/") {
2021-10-31 00:57:52 -07:00
if let Ok(string) = String::from_utf8(container) {
Ok(DecryptedData::String(Arc::new(string)))
} else {
Ok(DecryptedData::Blob(blob))
}
} else if mime_type.starts_with("image/")
// application/x-riff is WebP
|| mime_type == "application/x-riff"
{
2021-10-27 02:23:28 -07:00
Ok(DecryptedData::Image(blob, container.len()))
} else if mime_type.starts_with("audio/") {
Ok(DecryptedData::Audio(blob))
2021-10-31 00:57:52 -07:00
} else if mime_type.starts_with("video/")
// application/x-matroska is mkv
|| mime_type == "application/x-matroska"
{
2021-10-27 02:23:28 -07:00
Ok(DecryptedData::Video(blob))
} else if mime_type == "application/zip" {
let mut entries = vec![];
let cursor = Cursor::new(container);
if let Ok(mut zip) = zip::ZipArchive::new(cursor) {
for i in 0..zip.len() {
match zip.by_index(i) {
Ok(file) => entries.push(ArchiveMeta {
name: file.name().to_string(),
file_size: file.size() as usize,
}),
Err(err) => match err {
zip::result::ZipError::UnsupportedArchive(s) => {
log!("Unsupported: ", s.to_string());
}
_ => {
log!(format!("Error: {}", err));
}
},
2021-10-26 18:19:14 -07:00
}
}
2021-10-23 10:10:55 -07:00
}
2021-10-27 17:45:36 -07:00
entries.sort_by(|a, b| a.name.cmp(&b.name));
2021-10-27 02:23:28 -07:00
Ok(DecryptedData::Archive(blob, entries))
} else if mime_type == "application/gzip" {
2021-10-27 17:45:36 -07:00
Ok(DecryptedData::Archive(blob, vec![]))
2021-10-27 02:23:28 -07:00
} else {
Ok(DecryptedData::Blob(blob))
2021-10-23 10:10:55 -07:00
}
}