Skip to content

Commit 76eed20

Browse files
authored
Merge pull request javascript-obfuscator#861 from javascript-obfuscator/simplify-single-line-statement-fix
Fixed behavior of `simplify` options when a node with a single-statement `body` is inside simplified `IfStatement` node
2 parents ee41f06 + 49ec0a6 commit 76eed20

18 files changed

+970
-8
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
Change Log
22

3+
v2.10.2
4+
---
5+
* Fixed behaviour of `simplify` options when node with a single-statement `body` is inside simplified `IfStatement` node. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/860
6+
37
v2.10.1
48
---
59
* Removed padding characters from all base64 encoded strings. Removed RegExp that trims padding characters from `base64` encoded strings from `atob` code helper to prevent mutation of `RegExp.$1` value during calls to the `stringArray`. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/829

dist/index.browser.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.cli.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "javascript-obfuscator",
3-
"version": "2.10.1",
3+
"version": "2.10.2",
44
"description": "JavaScript obfuscator",
55
"keywords": [
66
"obfuscator",

src/enums/node/NodeType.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export enum NodeType {
1414
ClassDeclaration = 'ClassDeclaration',
1515
ConditionalExpression = 'ConditionalExpression',
1616
ContinueStatement = 'ContinueStatement',
17+
DoWhileStatement = 'DoWhileStatement',
1718
ExportAllDeclaration = 'ExportAllDeclaration',
1819
ExportNamedDeclaration = 'ExportNamedDeclaration',
1920
ExportSpecifier = 'ExportSpecifier',
@@ -54,6 +55,7 @@ export enum NodeType {
5455
UpdateExpression = 'UpdateExpression',
5556
VariableDeclaration = 'VariableDeclaration',
5657
VariableDeclarator = 'VariableDeclarator',
58+
WithStatement = 'WithStatement',
5759
WhileStatement = 'WhileStatement',
5860
YieldExpression = 'YieldExpression'
5961
}

src/node-transformers/simplifying-transformers/IfStatementSimplifyTransformer.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ export class IfStatementSimplifyTransformer extends AbstractStatementSimplifyTra
286286
*/
287287
return NodeGuards.isFunctionDeclarationNode(statement)
288288
/**
289+
* Ignore any nodes with a single statement as a `body`
289290
* Without ignore it can break following code:
290291
* Input:
291292
* if (condition1) {
@@ -302,8 +303,10 @@ export class IfStatementSimplifyTransformer extends AbstractStatementSimplifyTra
302303
* var foo = bar();
303304
* else
304305
* var baz = bark();
306+
*
307+
* See issue: https://github.com/javascript-obfuscator/javascript-obfuscator/issues/860
305308
*/
306-
|| NodeGuards.isIfStatementNode(statement)
309+
|| NodeGuards.isNodeWithSingleStatementBody(statement)
307310

308311
/**
309312
* `let` and `const` variable declarations are not allowed outside of `IfStatement` block statement

src/node/NodeFactory.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,20 @@ export class NodeFactory {
167167
};
168168
}
169169

170+
/**
171+
* @param {Statement} body
172+
* @param {Expression} test
173+
* @returns {DoWhileStatement}
174+
*/
175+
public static doWhileStatementNode (body: ESTree.Statement, test: ESTree.Expression): ESTree.DoWhileStatement {
176+
return {
177+
type: NodeType.DoWhileStatement,
178+
body,
179+
test,
180+
metadata: { ignoredNode: false }
181+
};
182+
}
183+
170184
/**
171185
* @param {Literal} source
172186
* @returns {ExportAllDeclaration}
@@ -210,6 +224,72 @@ export class NodeFactory {
210224
};
211225
}
212226

227+
/**
228+
* @param {VariableDeclaration | Expression | null} init
229+
* @param {Expression | null} test
230+
* @param {Expression | null} update
231+
* @param {Statement} body
232+
* @returns {ForStatement}
233+
*/
234+
public static forStatementNode (
235+
init: ESTree.VariableDeclaration | ESTree.Expression | null,
236+
test: ESTree.Expression | null,
237+
update: ESTree.Expression | null,
238+
body: ESTree.Statement
239+
): ESTree.ForStatement {
240+
return {
241+
type: NodeType.ForStatement,
242+
init,
243+
test,
244+
update,
245+
body,
246+
metadata: { ignoredNode: false }
247+
};
248+
}
249+
250+
/**
251+
* @param {VariableDeclaration | Pattern} left
252+
* @param {Expression} right
253+
* @param {Statement} body
254+
* @returns {ForInStatement}
255+
*/
256+
public static forInStatementNode (
257+
left: ESTree.VariableDeclaration | ESTree.Pattern,
258+
right: ESTree.Expression,
259+
body: ESTree.Statement
260+
): ESTree.ForInStatement {
261+
return {
262+
type: NodeType.ForInStatement,
263+
left,
264+
right,
265+
body,
266+
metadata: { ignoredNode: false }
267+
};
268+
}
269+
270+
/**
271+
* @param {boolean} await
272+
* @param {VariableDeclaration | Pattern} left
273+
* @param {Expression} right
274+
* @param {Statement} body
275+
* @returns {ForOfStatement}
276+
*/
277+
public static forOfStatementNode (
278+
await: boolean,
279+
left: ESTree.VariableDeclaration | ESTree.Pattern,
280+
right: ESTree.Expression,
281+
body: ESTree.Statement
282+
): ESTree.ForOfStatement {
283+
return {
284+
type: NodeType.ForOfStatement,
285+
await,
286+
left,
287+
right,
288+
body,
289+
metadata: { ignoredNode: false }
290+
};
291+
}
292+
213293
/**
214294
* @param {string} functionName
215295
* @param {Identifier[]} params
@@ -298,6 +378,23 @@ export class NodeFactory {
298378
};
299379
}
300380

381+
/**
382+
* @param {Identifier} label
383+
* @param {Statement} body
384+
* @returns {LabeledStatement}
385+
*/
386+
public static labeledStatementNode (
387+
label: ESTree.Identifier,
388+
body: ESTree.Statement
389+
): ESTree.LabeledStatement {
390+
return {
391+
type: NodeType.LabeledStatement,
392+
label,
393+
body,
394+
metadata: { ignoredNode: false }
395+
};
396+
}
397+
301398
/**
302399
* @param {boolean | number | string} value
303400
* @param {string} raw

src/node/NodeGuards.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
1+
/* eslint-disable max-lines */
12
import * as ESTree from 'estree';
23

34
import { TNodeWithLexicalScope } from '../types/node/TNodeWithLexicalScope';
45
import { TNodeWithLexicalScopeStatements } from '../types/node/TNodeWithLexicalScopeStatements';
56
import { TNodeWithStatements } from '../types/node/TNodeWithStatements';
67

78
import { NodeType } from '../enums/node/NodeType';
9+
import { TNodeWithSingleStatementBody } from '../types/node/TNodeWithSingleStatementBody';
810

911
export class NodeGuards {
1012
/**
@@ -116,6 +118,14 @@ export class NodeGuards {
116118
&& 'directive' in node;
117119
}
118120

121+
/**
122+
* @param {Node} node
123+
* @returns {boolean}
124+
*/
125+
public static isDoWhileStatementNode (node: ESTree.Node): node is ESTree.DoWhileStatement {
126+
return node.type === NodeType.DoWhileStatement;
127+
}
128+
119129
/**
120130
* @param {Node} node
121131
* @returns {boolean}
@@ -149,6 +159,22 @@ export class NodeGuards {
149159
&& !('directive' in node);
150160
}
151161

162+
/**
163+
* @param {Node} node
164+
* @returns {boolean}
165+
*/
166+
public static isForStatementNode (node: ESTree.Node): node is ESTree.ForStatement {
167+
return node.type === NodeType.ForStatement;
168+
}
169+
170+
/**
171+
* @param {Node} node
172+
* @returns {boolean}
173+
*/
174+
public static isForInStatementNode (node: ESTree.Node): node is ESTree.ForInStatement {
175+
return node.type === NodeType.ForInStatement;
176+
}
177+
152178
/**
153179
* @param {Node} node
154180
* @returns {boolean}
@@ -201,6 +227,19 @@ export class NodeGuards {
201227
return node.type === NodeType.IfStatement;
202228
}
203229

230+
/**
231+
* @param {Node} node
232+
* @returns {boolean}
233+
*/
234+
public static isIfStatementNodeWithSingleStatementBody (node: ESTree.Node): node is ESTree.IfStatement {
235+
if (!NodeGuards.isIfStatementNode(node)) {
236+
return false;
237+
}
238+
239+
return !NodeGuards.isBlockStatementNode(node.consequent)
240+
|| (!!node.alternate && !NodeGuards.isBlockStatementNode(node.alternate));
241+
}
242+
204243
/**
205244
* @param {Node} node
206245
* @returns {boolean}
@@ -287,6 +326,35 @@ export class NodeGuards {
287326
return NodeGuards.isNodeWithLexicalScope(node) || NodeGuards.isBlockStatementNode(node);
288327
}
289328

329+
/**
330+
* Checks if a node is the node with single statement body, like:
331+
* while (true)
332+
* console.log(1);
333+
*
334+
* or:
335+
*
336+
*
337+
* @param {Node} node
338+
* @returns {boolean}
339+
*/
340+
public static isNodeWithSingleStatementBody (node: ESTree.Node): node is TNodeWithSingleStatementBody {
341+
// Different approach for `IfStatement` node because this node hasn't `body` property
342+
if (NodeGuards.isIfStatementNode(node)) {
343+
return NodeGuards.isIfStatementNodeWithSingleStatementBody(node);
344+
}
345+
346+
// All other nodes with `Statement` node as `body` property
347+
return (
348+
NodeGuards.isForStatementNode(node)
349+
|| NodeGuards.isForOfStatementNode(node)
350+
|| NodeGuards.isForInStatementNode(node)
351+
|| NodeGuards.isWhileStatementNode(node)
352+
|| NodeGuards.isDoWhileStatementNode(node)
353+
|| NodeGuards.isWithStatementNode(node)
354+
|| NodeGuards.isLabeledStatementNode(node)
355+
) && !NodeGuards.isBlockStatementNode(node.body);
356+
}
357+
290358
/**
291359
* @param {Node} node
292360
* @param {Node} parentNode
@@ -438,6 +506,14 @@ export class NodeGuards {
438506
return node.type === NodeType.VariableDeclarator;
439507
}
440508

509+
/**
510+
* @param {Node} node
511+
* @returns {boolean}
512+
*/
513+
public static isWithStatementNode (node: ESTree.Node): node is ESTree.WithStatement {
514+
return node.type === NodeType.WithStatement;
515+
}
516+
441517
/**
442518
* @param {Node} node
443519
* @returns {boolean}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as ESTree from 'estree';
2+
3+
export type TNodeWithSingleStatementBody = (
4+
ESTree.LabeledStatement
5+
| ESTree.WithStatement
6+
| ESTree.WhileStatement
7+
| ESTree.DoWhileStatement
8+
| ESTree.ForStatement
9+
| ESTree.ForInStatement
10+
| ESTree.ForOfStatement
11+
& {
12+
body: Exclude<ESTree.Statement, ESTree.BlockStatement>;
13+
}
14+
)
15+
| (
16+
ESTree.IfStatement
17+
& {
18+
consequent: Exclude<ESTree.Statement, ESTree.BlockStatement>;
19+
alternate?: Exclude<ESTree.Statement, ESTree.BlockStatement> | null;
20+
}
21+
);

0 commit comments

Comments
 (0)