diff --git a/Cargo.lock b/Cargo.lock index 6c62503..43a606a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -495,7 +495,7 @@ dependencies = [ [[package]] name = "signal-decrypt-backup-wasm" -version = "0.3.0" +version = "0.1.1" dependencies = [ "aes", "base64", diff --git a/Cargo.toml b/Cargo.toml index 5f8111a..1d3e272 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "signal-decrypt-backup-wasm" -version = "0.3.0" +version = "0.1.1" edition = "2021" description = "Get the raw database from your Signal backup. Written for webassembly" repository = "https://git.duskflower.dev/duskflower/signal-decrypt-backup-wasm" diff --git a/build.sh b/build.sh index 321e22c..8f41923 100755 --- a/build.sh +++ b/build.sh @@ -1,3 +1,3 @@ #!/bin/bash -wasm-pack build --scope duskflower --release --weak-refs --target bundler +wasm-pack build --scope duskflower --release --target bundler jq '. |= . + {"publishConfig": {"registry": "https://git.duskflower.dev/api/packages/duskflower/npm/"}}' pkg/package.json > pkg/package.json.tmp && mv pkg/package.json.tmp pkg/package.json diff --git a/src/lib.rs b/src/lib.rs index dbf8972..3b4614d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,19 @@ pub mod signal { type HmacSha256 = Hmac; +#[wasm_bindgen] +pub struct DecryptionResult { + database_statements: Vec, +} + +#[wasm_bindgen] +impl DecryptionResult { + #[wasm_bindgen(getter)] + pub fn database_statements(&self) -> Vec { + self.database_statements.clone() + } +} + // Add position field to ByteReader struct ByteReader { data: Vec, @@ -343,8 +356,6 @@ pub struct BackupDecryptor { header_data: Option, initialisation_vector: Option>, database_statements: Vec, - // how many statements were already passed back to JS for partial passing - returned_database_statements_length: usize, ciphertext_buf: Vec, plaintext_buf: Vec, total_file_size: usize, @@ -369,7 +380,6 @@ impl BackupDecryptor { header_data: None, initialisation_vector: None, database_statements: Vec::new(), - returned_database_statements_length: 0, ciphertext_buf: Vec::new(), plaintext_buf: Vec::new(), total_file_size: 0, @@ -503,6 +513,8 @@ impl BackupDecryptor { Err(e) => return Err(e), }; + // if we got to an attachment, but there we demand more data, it will be faulty, because we try to decrypt the frame although we would need + // to decrypt the attachment match decrypt_frame( &mut self.reader, hmac, @@ -512,8 +524,6 @@ impl BackupDecryptor { frame_length, ) { Ok(None) => { - // here we have to reset as well because the hmac depends on the length decryption which should therefore happen next time on the correct bits - self.reader.set_position(initial_reader_position); return Ok(true); } Ok(Some(backup_frame)) => { @@ -612,17 +622,9 @@ impl BackupDecryptor { } #[wasm_bindgen] - pub fn get_new_decrypted_statements(&mut self) -> Result, JsValue> { - let result = - Ok(self.database_statements[self.returned_database_statements_length..].to_vec()); - - self.returned_database_statements_length = self.database_statements.len(); - - result - } - - #[wasm_bindgen] - pub fn finish(self) -> Result, JsValue> { - Ok(self.database_statements.clone()) + pub fn finish(self) -> Result { + Ok(DecryptionResult { + database_statements: self.database_statements, + }) } } diff --git a/test/src/App.tsx b/test/src/App.tsx index 1f562ff..934806f 100644 --- a/test/src/App.tsx +++ b/test/src/App.tsx @@ -6,8 +6,7 @@ import { db } from "./db"; export async function decryptBackup( file: File, passphrase: string, - progressCallback: (progress: number) => void, - statementsCallback?: (statements: string[]) => void, + progressCallback: (progres: number) => void, ) { const fileSize = file.size; console.log("Starting decryption of file size:", fileSize); @@ -31,30 +30,53 @@ export async function decryptBackup( while (!done) { try { done = decryptor.process_chunk(passphrase); - } catch (error) { - console.error("Error processing chunk:", error); - throw error; + } catch (e) { + console.error("Error processing chunk:", e); + throw e; } } - statementsCallback?.(decryptor.get_new_decrypted_statements()); - offset += chunkSize; + // console.log(`Completed chunk, new offset: ${offset}`); + // if (performance.memory) { + // const memoryInfo = performance.memory; + // console.log(`Total JS Heap Size: ${memoryInfo.totalJSHeapSize} bytes`); + // console.log(`Used JS Heap Size: ${memoryInfo.usedJSHeapSize} bytes`); + // console.log(`JS Heap Size Limit: ${memoryInfo.jsHeapSizeLimit} bytes`); + // } else { + // console.log("Memory information is not available in this environment."); + // } } + // console.log("All chunks processed, finishing up"); const result = decryptor.finish(); + // decryptor.free(); + return result; - } catch (error) { - console.error("Decryption failed:", error); - throw error; + } catch (e) { + console.error("Decryption failed:", e); + throw e; } } async function decrypt(file: File, passphrase: string) { try { const result = await decryptBackup(file, passphrase, console.info); + + // console.log(result, result.database_bytes); + + // console.log("Database bytes length:", result.databaseBytes.length); + // console.log( + // "Database bytes as string (partly)", + // new TextDecoder().decode(result.database_bytes.slice(0, 1024 * 50)), + // ); + + // console.log(result.database_statements); + return result; + // console.log("Preferences:", result.preferences); + // console.log("Key values:", result.keyValues); } catch (error) { console.error("Decryption failed:", error); } @@ -64,19 +86,14 @@ const App: Component = () => { const [passphrase, setPassphrase] = createSignal(""); const [backupFile, setBackupFile] = createSignal(); - let executed = 0; - createEffect( on( backupFile, (currentBackupFile) => { if (currentBackupFile) { - decryptBackup( - currentBackupFile, - passphrase(), - console.info, - (statements) => { - for (const statement of statements) { + decrypt(currentBackupFile, passphrase()).then((result) => { + if (result) { + for (const statement of result.database_statements) { try { console.log("executing"); db.exec(statement); @@ -87,11 +104,7 @@ const App: Component = () => { } } - executed += statements.length; - }, - ).then((result) => { - if (result) { - console.log("All statements executed: ", result.length, executed); + console.log("All statements executed"); console.log( db.exec("SELECT * from message", { @@ -120,7 +133,6 @@ const App: Component = () => { { setBackupFile(event.currentTarget.files?.[0]); }}