fix: chunked processing, concat sql statements with parameters
This commit is contained in:
parent
b3e3eb7270
commit
55e33a87b1
5 changed files with 231 additions and 292 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -182,6 +182,12 @@ version = "0.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.12.4"
|
||||
|
@ -495,6 +501,7 @@ dependencies = [
|
|||
"base64",
|
||||
"console_error_panic_hook",
|
||||
"ctr",
|
||||
"hex",
|
||||
"hkdf",
|
||||
"hmac",
|
||||
"js-sys",
|
||||
|
|
|
@ -22,6 +22,7 @@ prost = "0.11"
|
|||
prost-types = "0.11"
|
||||
serde_bytes = "0.11.15"
|
||||
console_error_panic_hook = "0.1.7"
|
||||
hex = "0.4.3"
|
||||
|
||||
[build-dependencies]
|
||||
prost-build = "0.11"
|
||||
|
|
303
src/lib.rs
303
src/lib.rs
|
@ -39,12 +39,12 @@ pub mod signal {
|
|||
include!(concat!(env!("OUT_DIR"), "/signal.rs"));
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum AttachmentType {
|
||||
Attachment,
|
||||
Sticker,
|
||||
Avatar,
|
||||
}
|
||||
// #[derive(Debug)]
|
||||
// enum AttachmentType {
|
||||
// Attachment,
|
||||
// Sticker,
|
||||
// Avatar,
|
||||
// }
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub struct DecryptionResult {
|
||||
|
@ -90,14 +90,6 @@ impl ByteReader {
|
|||
self.remaining_data().len()
|
||||
}
|
||||
|
||||
fn get_position(&self) -> usize {
|
||||
self.position
|
||||
}
|
||||
|
||||
fn set_position(&mut self, position: usize) {
|
||||
self.position = position;
|
||||
}
|
||||
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
|
||||
let available = self.remaining_data();
|
||||
|
||||
|
@ -139,6 +131,74 @@ struct Keys {
|
|||
hmac_key: Vec<u8>,
|
||||
}
|
||||
|
||||
fn parameter_to_string(parameter: &signal::sql_statement::SqlParameter) -> Result<String, JsValue> {
|
||||
if let Some(s) = ¶meter.string_paramter {
|
||||
Ok(format!("'{}'", s.replace("'", "''")))
|
||||
} else if let Some(i) = parameter.integer_parameter {
|
||||
let signed_i = if i & (1 << 63) != 0 {
|
||||
i | (-1_i64 << 63) as u64
|
||||
} else {
|
||||
i
|
||||
};
|
||||
Ok(signed_i.to_string())
|
||||
} else if let Some(d) = parameter.double_parameter {
|
||||
Ok(d.to_string())
|
||||
} else if let Some(b) = ¶meter.blob_parameter {
|
||||
Ok(format!("X'{}'", hex::encode(b)))
|
||||
} else if parameter.nullparameter.is_some() {
|
||||
Ok("NULL".to_string())
|
||||
} else {
|
||||
Ok("NULL".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
fn process_parameter_placeholders(sql: &str, params: &[String]) -> Result<String, JsValue> {
|
||||
let mut result = sql.to_string();
|
||||
let mut param_index = 0;
|
||||
|
||||
// Handle different types of parameter placeholders
|
||||
while param_index < params.len() {
|
||||
let rest = &result[param_index..];
|
||||
|
||||
// Find the next placeholder
|
||||
let next_placeholder = rest.find('?').map(|i| (i, 1)); // ? style
|
||||
|
||||
match next_placeholder {
|
||||
Some((pos, len)) => {
|
||||
// Replace the placeholder with the parameter value
|
||||
if param_index < params.len() {
|
||||
let before = &result[..param_index + pos];
|
||||
let after = &result[param_index + pos + len..];
|
||||
result = format!("{}{}{}", before, params[param_index], after);
|
||||
param_index += 1;
|
||||
} else {
|
||||
return Err(JsValue::from_str(
|
||||
"Not enough parameters provided for SQL statement",
|
||||
));
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// No more placeholders found
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have unused parameters
|
||||
if param_index < params.len() {
|
||||
web_sys::console::warn_1(
|
||||
&format!(
|
||||
"Warning: {} parameters were provided but not all were used in SQL: {}",
|
||||
params.len(),
|
||||
sql
|
||||
)
|
||||
.into(),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
fn derive_keys(passphrase: &str, salt: &[u8]) -> Result<Keys, JsValue> {
|
||||
let passphrase_bytes = passphrase.replace(" ", "").as_bytes().to_vec();
|
||||
|
||||
|
@ -203,31 +263,18 @@ fn io_err_to_js(e: io::Error) -> JsValue {
|
|||
JsValue::from_str(&format!("IO Error: {}", e))
|
||||
}
|
||||
|
||||
fn decrypt_frame(
|
||||
fn get_frame_length(
|
||||
reader: &mut ByteReader,
|
||||
hmac_key: &[u8],
|
||||
cipher_key: &[u8],
|
||||
initialisation_vector: &[u8],
|
||||
hmac: &mut HmacSha256,
|
||||
ctr: &mut Ctr32BE<Aes256>,
|
||||
header_version: Option<u32>,
|
||||
ciphertext_buf: &mut Vec<u8>,
|
||||
plaintext_buf: &mut Vec<u8>,
|
||||
should_update_hmac: bool,
|
||||
) -> Result<Option<signal::BackupFrame>, JsValue> {
|
||||
) -> Result<Option<u32>, JsValue> {
|
||||
if reader.remaining_length() < 4 {
|
||||
web_sys::console::log_1(&"too less data to decrypt frame length".into());
|
||||
|
||||
return Ok(None); // Not enough data to read the frame length
|
||||
}
|
||||
|
||||
let initial_position = reader.get_position();
|
||||
|
||||
let mut hmac = <HmacSha256 as Mac>::new_from_slice(hmac_key)
|
||||
.map_err(|_| JsValue::from_str("Invalid HMAC key"))?;
|
||||
|
||||
let mut ctr =
|
||||
<Ctr32BE<Aes256> as KeyIvInit>::new_from_slices(cipher_key, initialisation_vector)
|
||||
.map_err(|_| JsValue::from_str("Invalid CTR parameters"))?;
|
||||
|
||||
let length = match header_version {
|
||||
None => {
|
||||
let mut length_bytes = [0u8; 4];
|
||||
|
@ -245,11 +292,9 @@ fn decrypt_frame(
|
|||
// &format!("encrypted length bytes: {:02x?}", encrypted_length).into(),
|
||||
// );
|
||||
|
||||
if should_update_hmac == true {
|
||||
// web_sys::console::log_1(&"updating hmac".into());
|
||||
// web_sys::console::log_1(&"updating hmac".into());
|
||||
|
||||
Mac::update(&mut hmac, &encrypted_length);
|
||||
}
|
||||
Mac::update(hmac, &encrypted_length);
|
||||
|
||||
let mut decrypted_length = encrypted_length;
|
||||
ctr.apply_keystream(&mut decrypted_length);
|
||||
|
@ -265,11 +310,20 @@ fn decrypt_frame(
|
|||
Some(v) => return Err(JsValue::from_str(&format!("Unsupported version: {}", v))),
|
||||
};
|
||||
|
||||
Ok(Some(length))
|
||||
}
|
||||
|
||||
fn decrypt_frame(
|
||||
reader: &mut ByteReader,
|
||||
mut hmac: HmacSha256,
|
||||
ctr: &mut Ctr32BE<Aes256>,
|
||||
ciphertext_buf: &mut Vec<u8>,
|
||||
plaintext_buf: &mut Vec<u8>,
|
||||
length: u32,
|
||||
) -> Result<Option<signal::BackupFrame>, JsValue> {
|
||||
if reader.remaining_length() < length as usize {
|
||||
// web_sys::console::log_1(&"remaining data is too less".into());
|
||||
|
||||
// reset the buffer for the next iteration
|
||||
reader.set_position(initial_position);
|
||||
return Ok(None); // Not =enough data to read the frame
|
||||
}
|
||||
|
||||
|
@ -392,14 +446,14 @@ pub struct BackupDecryptor {
|
|||
database_bytes: Vec<u8>,
|
||||
preferences: HashMap<String, HashMap<String, HashMap<String, serde_json::Value>>>,
|
||||
key_values: HashMap<String, HashMap<String, serde_json::Value>>,
|
||||
attachments: HashMap<String, Vec<u8>>,
|
||||
stickers: HashMap<String, Vec<u8>>,
|
||||
avatars: HashMap<String, Vec<u8>>,
|
||||
// attachments: HashMap<String, Vec<u8>>,
|
||||
// stickers: HashMap<String, Vec<u8>>,
|
||||
// avatars: HashMap<String, Vec<u8>>,
|
||||
ciphertext_buf: Vec<u8>,
|
||||
plaintext_buf: Vec<u8>,
|
||||
total_bytes_received: usize,
|
||||
is_initialized: bool,
|
||||
should_update_hmac_next_run: bool,
|
||||
current_backup_frame_length: Option<u32>,
|
||||
current_backup_frame: Option<signal::BackupFrame>,
|
||||
}
|
||||
|
||||
|
@ -416,14 +470,14 @@ impl BackupDecryptor {
|
|||
database_bytes: Vec::new(),
|
||||
preferences: HashMap::new(),
|
||||
key_values: HashMap::new(),
|
||||
attachments: HashMap::new(),
|
||||
stickers: HashMap::new(),
|
||||
avatars: HashMap::new(),
|
||||
// attachments: HashMap::new(),
|
||||
// stickers: HashMap::new(),
|
||||
// avatars: HashMap::new(),
|
||||
ciphertext_buf: Vec::new(),
|
||||
plaintext_buf: Vec::new(),
|
||||
total_bytes_received: 0,
|
||||
is_initialized: false,
|
||||
should_update_hmac_next_run: true,
|
||||
current_backup_frame_length: None,
|
||||
current_backup_frame: None,
|
||||
}
|
||||
}
|
||||
|
@ -475,28 +529,39 @@ impl BackupDecryptor {
|
|||
|
||||
let backup_frame_cloned = self.current_backup_frame.clone().unwrap();
|
||||
|
||||
let (filename, length, attachment_type) =
|
||||
if let Some(attachment) = backup_frame_cloned.attachment {
|
||||
(
|
||||
format!("{}.bin", attachment.row_id.unwrap_or(0)),
|
||||
attachment.length.unwrap_or(0),
|
||||
AttachmentType::Attachment,
|
||||
)
|
||||
} else if let Some(sticker) = backup_frame_cloned.sticker {
|
||||
(
|
||||
format!("{}.bin", sticker.row_id.unwrap_or(0)),
|
||||
sticker.length.unwrap_or(0),
|
||||
AttachmentType::Sticker,
|
||||
)
|
||||
} else if let Some(avatar) = backup_frame_cloned.avatar {
|
||||
(
|
||||
format!("{}.bin", avatar.recipient_id.unwrap_or_default()),
|
||||
avatar.length.unwrap_or(0),
|
||||
AttachmentType::Avatar,
|
||||
)
|
||||
} else {
|
||||
return Err(JsValue::from_str("Invalid field type found"));
|
||||
};
|
||||
// let (filename, length, attachment_type) =
|
||||
// if let Some(attachment) = backup_frame_cloned.attachment {
|
||||
// (
|
||||
// format!("{}.bin", attachment.row_id.unwrap_or(0)),
|
||||
// attachment.length.unwrap_or(0),
|
||||
// AttachmentType::Attachment,
|
||||
// )
|
||||
// } else if let Some(sticker) = backup_frame_cloned.sticker {
|
||||
// (
|
||||
// format!("{}.bin", sticker.row_id.unwrap_or(0)),
|
||||
// sticker.length.unwrap_or(0),
|
||||
// AttachmentType::Sticker,
|
||||
// )
|
||||
// } else if let Some(avatar) = backup_frame_cloned.avatar {
|
||||
// (
|
||||
// format!("{}.bin", avatar.recipient_id.unwrap_or_default()),
|
||||
// avatar.length.unwrap_or(0),
|
||||
// AttachmentType::Avatar,
|
||||
// )
|
||||
// } else {
|
||||
// return Err(JsValue::from_str("Invalid field type found"));
|
||||
// };
|
||||
//
|
||||
|
||||
let length = if let Some(attachment) = backup_frame_cloned.attachment {
|
||||
attachment.length.unwrap_or(0)
|
||||
} else if let Some(sticker) = backup_frame_cloned.sticker {
|
||||
sticker.length.unwrap_or(0)
|
||||
} else if let Some(avatar) = backup_frame_cloned.avatar {
|
||||
avatar.length.unwrap_or(0)
|
||||
} else {
|
||||
return Err(JsValue::from_str("Invalid field type found"));
|
||||
};
|
||||
|
||||
match decrypt_frame_payload(
|
||||
&mut self.reader,
|
||||
|
@ -511,7 +576,7 @@ impl BackupDecryptor {
|
|||
// no need to assign newly here, can stay the same as we need to load even more data
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(Some(payload)) => {
|
||||
Ok(Some(_payload)) => {
|
||||
self.current_backup_frame = None;
|
||||
|
||||
// match attachment_type {
|
||||
|
@ -534,24 +599,37 @@ impl BackupDecryptor {
|
|||
return Ok(false);
|
||||
}
|
||||
|
||||
let mut hmac = <HmacSha256 as Mac>::new_from_slice(&keys.hmac_key)
|
||||
.map_err(|_| JsValue::from_str("Invalid HMAC key"))?;
|
||||
|
||||
let mut ctr = <Ctr32BE<Aes256> as KeyIvInit>::new_from_slices(&keys.cipher_key, iv)
|
||||
.map_err(|_| JsValue::from_str("Invalid CTR parameters"))?;
|
||||
|
||||
let frame_length =
|
||||
match get_frame_length(&mut self.reader, &mut hmac, &mut ctr, header_data.version) {
|
||||
Ok(None) => {
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(Some(length)) => length,
|
||||
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,
|
||||
&keys.hmac_key,
|
||||
&keys.cipher_key,
|
||||
iv,
|
||||
header_data.version,
|
||||
hmac,
|
||||
&mut ctr,
|
||||
&mut self.ciphertext_buf,
|
||||
&mut self.plaintext_buf,
|
||||
self.should_update_hmac_next_run,
|
||||
frame_length,
|
||||
) {
|
||||
Ok(None) => {
|
||||
self.should_update_hmac_next_run = false;
|
||||
self.current_backup_frame_length = Some(frame_length);
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(Some(backup_frame)) => {
|
||||
self.should_update_hmac_next_run = true;
|
||||
self.current_backup_frame_length = None;
|
||||
|
||||
// can not assign right here because of borrowing issues
|
||||
let mut new_iv = increment_initialisation_vector(iv);
|
||||
|
@ -574,8 +652,25 @@ impl BackupDecryptor {
|
|||
&& !sql.contains("sms_fts_")
|
||||
&& !sql.contains("mms_fts_")
|
||||
{
|
||||
self.database_bytes.extend_from_slice(sql.as_bytes());
|
||||
let processed_sql = if !statement.parameters.is_empty() {
|
||||
let params: Vec<String> = statement
|
||||
.parameters
|
||||
.iter()
|
||||
.map(|param| parameter_to_string(param))
|
||||
.collect::<Result<_, _>>()?;
|
||||
|
||||
process_parameter_placeholders(&sql, ¶ms)?
|
||||
} else {
|
||||
sql
|
||||
};
|
||||
|
||||
// Add to concatenated string
|
||||
self.database_bytes
|
||||
.extend_from_slice(processed_sql.as_bytes());
|
||||
self.database_bytes.push(b';');
|
||||
|
||||
// Store individual statement
|
||||
// self.database_statements.push(processed_sql);
|
||||
}
|
||||
}
|
||||
} else if let Some(preference) = backup_frame.preference {
|
||||
|
@ -657,28 +752,38 @@ impl BackupDecryptor {
|
|||
} else {
|
||||
let backup_frame_cloned = backup_frame.clone();
|
||||
|
||||
let (filename, length, attachment_type) =
|
||||
if let Some(attachment) = backup_frame_cloned.attachment {
|
||||
(
|
||||
format!("{}.bin", attachment.row_id.unwrap_or(0)),
|
||||
attachment.length.unwrap_or(0),
|
||||
AttachmentType::Attachment,
|
||||
)
|
||||
} else if let Some(sticker) = backup_frame_cloned.sticker {
|
||||
(
|
||||
format!("{}.bin", sticker.row_id.unwrap_or(0)),
|
||||
sticker.length.unwrap_or(0),
|
||||
AttachmentType::Sticker,
|
||||
)
|
||||
} else if let Some(avatar) = backup_frame_cloned.avatar {
|
||||
(
|
||||
format!("{}.bin", avatar.recipient_id.unwrap_or_default()),
|
||||
avatar.length.unwrap_or(0),
|
||||
AttachmentType::Avatar,
|
||||
)
|
||||
} else {
|
||||
return Err(JsValue::from_str("Invalid field type found"));
|
||||
};
|
||||
// let (filename, length, attachment_type) =
|
||||
// if let Some(attachment) = backup_frame_cloned.attachment {
|
||||
// (
|
||||
// format!("{}.bin", attachment.row_id.unwrap_or(0)),
|
||||
// attachment.length.unwrap_or(0),
|
||||
// AttachmentType::Attachment,
|
||||
// )
|
||||
// } else if let Some(sticker) = backup_frame_cloned.sticker {
|
||||
// (
|
||||
// format!("{}.bin", sticker.row_id.unwrap_or(0)),
|
||||
// sticker.length.unwrap_or(0),
|
||||
// AttachmentType::Sticker,
|
||||
// )
|
||||
// } else if let Some(avatar) = backup_frame_cloned.avatar {
|
||||
// (
|
||||
// format!("{}.bin", avatar.recipient_id.unwrap_or_default()),
|
||||
// avatar.length.unwrap_or(0),
|
||||
// AttachmentType::Avatar,
|
||||
// )
|
||||
// } else {
|
||||
// return Err(JsValue::from_str("Invalid field type found"));
|
||||
// };
|
||||
//
|
||||
let length = if let Some(attachment) = backup_frame_cloned.attachment {
|
||||
attachment.length.unwrap_or(0)
|
||||
} else if let Some(sticker) = backup_frame_cloned.sticker {
|
||||
sticker.length.unwrap_or(0)
|
||||
} else if let Some(avatar) = backup_frame_cloned.avatar {
|
||||
avatar.length.unwrap_or(0)
|
||||
} else {
|
||||
return Err(JsValue::from_str("Invalid field type found"));
|
||||
};
|
||||
|
||||
match decrypt_frame_payload(
|
||||
&mut self.reader,
|
||||
|
@ -698,7 +803,7 @@ impl BackupDecryptor {
|
|||
|
||||
return Ok(true);
|
||||
}
|
||||
Ok(Some(payload)) => {
|
||||
Ok(Some(_payload)) => {
|
||||
// match attachment_type {
|
||||
// AttachmentType::Attachment => {
|
||||
// self.attachments.insert(filename, payload);
|
||||
|
|
175
test/.gitignore
vendored
175
test/.gitignore
vendored
|
@ -1,175 +0,0 @@
|
|||
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||
|
||||
# Logs
|
||||
|
||||
logs
|
||||
_.log
|
||||
npm-debug.log_
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
.pnpm-debug.log*
|
||||
|
||||
# Caches
|
||||
|
||||
.cache
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
|
||||
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||
|
||||
# Runtime data
|
||||
|
||||
pids
|
||||
_.pid
|
||||
_.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Snowpack dependency directory (https://snowpack.dev/)
|
||||
|
||||
web_modules/
|
||||
|
||||
# TypeScript cache
|
||||
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
|
||||
.eslintcache
|
||||
|
||||
# Optional stylelint cache
|
||||
|
||||
.stylelintcache
|
||||
|
||||
# Microbundle cache
|
||||
|
||||
.rpt2_cache/
|
||||
.rts2_cache_cjs/
|
||||
.rts2_cache_es/
|
||||
.rts2_cache_umd/
|
||||
|
||||
# Optional REPL history
|
||||
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variable files
|
||||
|
||||
.env
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
.env.local
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
|
||||
.parcel-cache
|
||||
|
||||
# Next.js build output
|
||||
|
||||
.next
|
||||
out
|
||||
|
||||
# Nuxt.js build / generate output
|
||||
|
||||
.nuxt
|
||||
|
||||
|
||||
# Gatsby files
|
||||
|
||||
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||
|
||||
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||
|
||||
# public
|
||||
|
||||
# vuepress build output
|
||||
|
||||
.vuepress/dist
|
||||
|
||||
# vuepress v2.x temp and cache directory
|
||||
|
||||
.temp
|
||||
|
||||
# Docusaurus cache and generated files
|
||||
|
||||
.docusaurus
|
||||
|
||||
# Serverless directories
|
||||
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
|
||||
.dynamodb/
|
||||
|
||||
# TernJS port file
|
||||
|
||||
.tern-port
|
||||
|
||||
# Stores VSCode versions used for testing VSCode extensions
|
||||
|
||||
.vscode-test
|
||||
|
||||
# yarn v2
|
||||
|
||||
.yarn/cache
|
||||
.yarn/unplugged
|
||||
.yarn/build-state.yml
|
||||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
# IntelliJ based IDEs
|
||||
.idea
|
||||
|
||||
# Finder (MacOS) folder config
|
||||
.DS_Store
|
37
test/dist/index.js
vendored
37
test/dist/index.js
vendored
|
@ -29,7 +29,7 @@ export async function decryptBackup(file, passphrase, progressCallback) {
|
|||
console.info(`${percent}% done`);
|
||||
}
|
||||
|
||||
console.log(`Processing chunk at offset ${offset}`);
|
||||
// console.log(`Processing chunk at offset ${offset}`);
|
||||
const chunk = file.slice(offset, offset + chunkSize);
|
||||
const arrayBuffer = await chunk.arrayBuffer();
|
||||
const uint8Array = new Uint8Array(arrayBuffer);
|
||||
|
@ -47,19 +47,18 @@ export async function decryptBackup(file, passphrase, progressCallback) {
|
|||
}
|
||||
|
||||
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(`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");
|
||||
console.log(window.performance.measureUserAgentSpecificMemory());
|
||||
// console.log("All chunks processed, finishing up");
|
||||
return decryptor.finish();
|
||||
} catch (e) {
|
||||
console.error("Decryption failed:", e);
|
||||
|
@ -71,13 +70,15 @@ async function decrypt(file, passphrase) {
|
|||
try {
|
||||
const result = await decryptBackup(file, passphrase);
|
||||
|
||||
console.log("Database bytes length:", result.databaseBytes.length);
|
||||
console.log("Preferences:", result.preferences);
|
||||
console.log("Key values:", result.keyValues);
|
||||
console.log(result, result.database_bytes);
|
||||
|
||||
// Example: Convert database bytes to SQL statements
|
||||
const sqlStatements = new TextDecoder().decode(result.databaseBytes);
|
||||
console.log("SQL statements:", sqlStatements);
|
||||
// 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("Preferences:", result.preferences);
|
||||
// console.log("Key values:", result.keyValues);
|
||||
} catch (error) {
|
||||
console.error("Decryption failed:", error);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue