js_deobfuscator/core/
config.rs

1//! Configuration types for the deobfuscation engine.
2
3// ============================================================================
4// LogLevel
5// ============================================================================
6
7/// Log level for engine output.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9pub enum LogLevel {
10    /// No logging.
11    Off,
12    /// Errors only.
13    Error,
14    /// Warnings and errors.
15    Warn,
16    /// Informational messages.
17    #[default]
18    Info,
19    /// Debug messages.
20    Debug,
21    /// Trace-level messages.
22    Trace,
23}
24
25// ============================================================================
26// EcmaConfig
27// ============================================================================
28
29/// Fine-grained ECMA layer configuration.
30#[derive(Debug, Clone)]
31pub struct EcmaConfig {
32    /// Enable operator passes (+, -, *, /, etc.).
33    pub operators: bool,
34    /// Enable String.prototype method passes.
35    pub string: bool,
36    /// Enable Array.prototype method passes.
37    pub array: bool,
38    /// Enable Number method passes.
39    pub number: bool,
40    /// Enable Math method passes.
41    pub math: bool,
42    /// Enable Object method passes.
43    pub object: bool,
44    /// Enable JSON method passes.
45    pub json: bool,
46    /// Enable RegExp method passes.
47    pub regexp: bool,
48    /// Enable URI function passes.
49    pub uri: bool,
50    /// Enable type coercion passes (JSFuck patterns).
51    pub coercion: bool,
52    /// Enable syntax simplification passes.
53    pub syntax: bool,
54    /// Enable control flow simplification passes.
55    pub control: bool,
56    /// Enable dead code removal passes.
57    pub dead: bool,
58}
59
60impl Default for EcmaConfig {
61    fn default() -> Self {
62        Self::all()
63    }
64}
65
66impl EcmaConfig {
67    /// Enable all ECMA passes.
68    pub fn all() -> Self {
69        Self {
70            operators: true,
71            string: true,
72            array: true,
73            number: true,
74            math: true,
75            object: true,
76            json: true,
77            regexp: true,
78            uri: true,
79            coercion: true,
80            syntax: true,
81            control: true,
82            dead: true,
83        }
84    }
85
86    /// Disable all ECMA passes.
87    pub fn none() -> Self {
88        Self {
89            operators: false,
90            string: false,
91            array: false,
92            number: false,
93            math: false,
94            object: false,
95            json: false,
96            regexp: false,
97            uri: false,
98            coercion: false,
99            syntax: false,
100            control: false,
101            dead: false,
102        }
103    }
104}
105
106// ============================================================================
107// RuntimeConfig
108// ============================================================================
109
110/// Fine-grained Runtime layer configuration.
111#[derive(Debug, Clone)]
112pub struct RuntimeConfig {
113    /// Enable encoding passes (atob, btoa).
114    pub encoding: bool,
115    /// Enable deprecated API passes (escape, unescape).
116    pub deprecated: bool,
117}
118
119impl Default for RuntimeConfig {
120    fn default() -> Self {
121        Self::all()
122    }
123}
124
125impl RuntimeConfig {
126    /// Enable all Runtime passes.
127    pub fn all() -> Self {
128        Self {
129            encoding: true,
130            deprecated: true,
131        }
132    }
133
134    /// Disable all Runtime passes.
135    pub fn none() -> Self {
136        Self {
137            encoding: false,
138            deprecated: false,
139        }
140    }
141}
142
143// ============================================================================
144// ExtensionsConfig
145// ============================================================================
146
147/// Fine-grained Extensions layer configuration.
148#[derive(Debug, Clone, Default)]
149pub struct ExtensionsConfig {
150    /// Enable string array decoder.
151    pub string_array: bool,
152    /// Enable control flow deflattener.
153    pub control_flow: bool,
154    /// Enable proxy function inliner.
155    pub proxy: bool,
156}
157
158impl ExtensionsConfig {
159    /// Enable all extension patterns.
160    pub fn all() -> Self {
161        Self {
162            string_array: true,
163            control_flow: true,
164            proxy: true,
165        }
166    }
167
168    /// Disable all extension patterns.
169    pub fn none() -> Self {
170        Self {
171            string_array: false,
172            control_flow: false,
173            proxy: false,
174        }
175    }
176}
177
178// ============================================================================
179// LayerConfig
180// ============================================================================
181
182/// Layer enable/disable configuration.
183#[derive(Debug, Clone)]
184pub struct LayerConfig {
185    /// Enable ECMA layer (recommended: always true).
186    pub ecma: bool,
187    /// Enable Runtime layer (browser/Node APIs).
188    pub runtime: bool,
189    /// Enable Extensions layer (obfuscator patterns).
190    pub extensions: bool,
191    /// Fine-grained ECMA configuration.
192    pub ecma_config: EcmaConfig,
193    /// Fine-grained Runtime configuration.
194    pub runtime_config: RuntimeConfig,
195    /// Fine-grained Extensions configuration.
196    pub extensions_config: ExtensionsConfig,
197}
198
199impl Default for LayerConfig {
200    fn default() -> Self {
201        Self {
202            ecma: true,
203            runtime: true,
204            extensions: false, // Opt-in for obfuscator-specific patterns
205            ecma_config: EcmaConfig::default(),
206            runtime_config: RuntimeConfig::default(),
207            extensions_config: ExtensionsConfig::default(),
208        }
209    }
210}
211
212impl LayerConfig {
213    /// Create config with all layers enabled.
214    pub fn all() -> Self {
215        Self {
216            ecma: true,
217            runtime: true,
218            extensions: true,
219            ecma_config: EcmaConfig::all(),
220            runtime_config: RuntimeConfig::all(),
221            extensions_config: ExtensionsConfig::all(),
222        }
223    }
224
225    /// Create config with only ECMA layer (pure ECMAScript).
226    pub fn ecma_only() -> Self {
227        Self {
228            ecma: true,
229            runtime: false,
230            extensions: false,
231            ecma_config: EcmaConfig::all(),
232            runtime_config: RuntimeConfig::none(),
233            extensions_config: ExtensionsConfig::none(),
234        }
235    }
236}
237
238// ============================================================================
239// EngineConfig
240// ============================================================================
241
242/// Engine configuration.
243#[derive(Debug, Clone)]
244pub struct EngineConfig {
245    /// Maximum iterations before stopping.
246    pub max_iterations: usize,
247    /// Layer configuration.
248    pub layers: LayerConfig,
249    /// Log level.
250    pub log_level: LogLevel,
251}
252
253impl Default for EngineConfig {
254    fn default() -> Self {
255        Self {
256            max_iterations: 100,
257            layers: LayerConfig::default(),
258            log_level: LogLevel::Info,
259        }
260    }
261}
262
263impl EngineConfig {
264    /// Create minimal config (ECMA operators only).
265    pub fn minimal() -> Self {
266        Self {
267            layers: LayerConfig {
268                ecma: true,
269                runtime: false,
270                extensions: false,
271                ecma_config: EcmaConfig {
272                    operators: true,
273                    ..EcmaConfig::none()
274                },
275                runtime_config: RuntimeConfig::none(),
276                extensions_config: ExtensionsConfig::none(),
277            },
278            ..Default::default()
279        }
280    }
281
282    /// Create standard config (ECMA + Runtime).
283    pub fn standard() -> Self {
284        Self::default()
285    }
286
287    /// Create full config (all layers enabled).
288    pub fn full() -> Self {
289        Self {
290            layers: LayerConfig::all(),
291            ..Default::default()
292        }
293    }
294
295    /// Create aggressive config (full + high iterations).
296    pub fn aggressive() -> Self {
297        Self {
298            max_iterations: 200,
299            layers: LayerConfig::all(),
300            ..Default::default()
301        }
302    }
303
304    /// Set max iterations.
305    #[must_use]
306    pub fn with_max_iterations(mut self, max: usize) -> Self {
307        self.max_iterations = max;
308        self
309    }
310
311    /// Set layer configuration.
312    #[must_use]
313    pub fn with_layers(mut self, layers: LayerConfig) -> Self {
314        self.layers = layers;
315        self
316    }
317
318    /// Set log level.
319    #[must_use]
320    pub fn with_log_level(mut self, level: LogLevel) -> Self {
321        self.log_level = level;
322        self
323    }
324}