use std::io::Read;
use clap::Parser;
use js_deobfuscator::engine::api::JSDeobfuscator;
#[derive(Parser)]
#[command(name = "deob", about = "Universal JavaScript deobfuscator")]
struct Cli {
input: Option<String>,
#[arg(short, long)]
output: Option<String>,
#[arg(short, long, default_value = "50")]
max_iterations: usize,
#[arg(long)]
no_fold: bool,
#[arg(long)]
no_transforms: bool,
#[arg(short, long)]
globals: Option<String>,
#[arg(short, long)]
stats: bool,
}
fn main() {
let cli = Cli::parse();
let source = match &cli.input {
Some(path) => std::fs::read_to_string(path).unwrap_or_else(|e| {
eprintln!("error reading {path}: {e}");
std::process::exit(1);
}),
None => {
let mut buf = String::new();
std::io::stdin().read_to_string(&mut buf).unwrap_or_else(|e| {
eprintln!("error reading stdin: {e}");
std::process::exit(1);
});
buf
}
};
let mut deob = JSDeobfuscator::new()
.max_iterations(cli.max_iterations)
.static_eval(!cli.no_fold)
.transforms(!cli.no_transforms);
if let Some(globals_json) = &cli.globals {
match serde_json::from_str::<serde_json::Value>(globals_json) {
Ok(val) => {
if let Some(obj) = val.as_object() {
for (k, v) in obj {
deob = deob.global(k, v.clone());
}
}
}
Err(e) => {
eprintln!("error parsing --globals JSON: {e}");
std::process::exit(1);
}
}
}
let result = match deob.deobfuscate(&source) {
Ok(r) => r,
Err(e) => {
eprintln!("error: {e}");
std::process::exit(1);
}
};
match &cli.output {
Some(path) => std::fs::write(path, &result.code).unwrap_or_else(|e| {
eprintln!("error writing {path}: {e}");
std::process::exit(1);
}),
None => print!("{}", result.code),
}
if cli.stats {
eprintln!(
"iterations: {}, modifications: {}, converged: {}",
result.iterations, result.modifications, result.converged
);
}
}