Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Change Log

v5.8.1
---
* Fixed `transformObjectKeys` making default parameter objects shared across calls. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1455

v5.8.0
---
* Pro API: added support for custom presets. `optionsPreset` accepts the alias of a custom preset saved in the obfuscator.io dashboard; `obfuscatePro()` and the CLI (`--pro-api-token`) fetch it and merge its options
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "5.8.0",
"version": "5.8.1",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,19 +111,17 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {

/**
* @param {ObjectExpression} objectExpressionNode
* @param {Node} objectExpressionParentNode
* @param {Statement} objectExpressionHostStatement
* @returns {boolean}
*/
private static isProhibitedObjectExpressionNode(
objectExpressionNode: ESTree.ObjectExpression,
objectExpressionParentNode: ESTree.Node,
objectExpressionHostStatement: ESTree.Statement
): boolean {
if (
ObjectExpressionKeysTransformer.isProhibitedArrowFunctionExpression(
ObjectExpressionKeysTransformer.isProhibitedEvaluationBoundary(
objectExpressionNode,
objectExpressionParentNode
objectExpressionHostStatement
) ||
ObjectExpressionKeysTransformer.isProhibitedSequenceExpression(objectExpressionNode) ||
ObjectExpressionKeysTransformer.isProhibitedLoopBody(objectExpressionNode)
Expand Down Expand Up @@ -174,17 +172,28 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {

/**
* @param {ObjectExpression} objectExpressionNode
* @param {Node} objectExpressionNodeParentNode
* @param {Statement} objectExpressionHostStatement
* @returns {boolean}
*/
private static isProhibitedArrowFunctionExpression(
private static isProhibitedEvaluationBoundary(
objectExpressionNode: ESTree.ObjectExpression,
objectExpressionNodeParentNode: ESTree.Node
objectExpressionHostStatement: ESTree.Statement
): boolean {
return (
NodeGuards.isArrowFunctionExpressionNode(objectExpressionNodeParentNode) &&
objectExpressionNodeParentNode.body === objectExpressionNode
);
let currentNode: ESTree.Node | undefined = objectExpressionNode.parentNode;

while (currentNode) {
if (NodeGuards.isFunctionNode(currentNode) || NodeGuards.isPropertyDefinitionNode(currentNode)) {
return true;
}

if (currentNode === objectExpressionHostStatement) {
break;
}

currentNode = currentNode.parentNode;
}

return false;
}

/**
Expand Down Expand Up @@ -307,11 +316,7 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
const hostStatement: ESTree.Statement = NodeStatementUtils.getRootStatementOfNode(objectExpressionNode);

if (
ObjectExpressionKeysTransformer.isProhibitedObjectExpressionNode(
objectExpressionNode,
parentNode,
hostStatement
)
ObjectExpressionKeysTransformer.isProhibitedObjectExpressionNode(objectExpressionNode, hostStatement)
) {
return objectExpressionNode;
}
Expand Down
58 changes: 58 additions & 0 deletions test/functional-tests/issues/issue1455.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { assert } from 'chai';

import { NO_ADDITIONAL_NODES_PRESET } from '../../../src/options/presets/NoCustomNodes';

import { JavaScriptObfuscator } from '../../../src/JavaScriptObfuscatorFacade';

//
// https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1455
//
describe('Issue #1455', () => {
describe('`transformObjectKeys` should not share object expressions across function calls', () => {
const samples: { name: string; code: string }[] = [
{
name: 'Variant #1: function declaration default parameter',
code: 'function f(o = { a: 1 }) { return o; } f() === f();'
},
{
name: 'Variant #2: arrow function default parameter',
code: 'var f = (o = { a: 1 }) => o; f() === f();'
},
{
name: 'Variant #3: nested object inside default parameter',
code: 'function f(o = { a: { b: 1 } }) { return o.a; } f() === f();'
},
{
name: 'Variant #4: arrow function expression body',
code: 'var id = (x) => x; var f = () => id({ a: 1 }); f() === f();'
},
{
name: 'Variant #5: class method default parameter',
code: 'class A { m(o = { a: 1 }) { return o; } } var a = new A(); a.m() === a.m();'
},
{
name: 'Variant #6: class field initializer',
code: 'class A { x = { a: 1 }; } new A().x === new A().x;'
}
];

samples.forEach(({ name, code }) => {
describe(name, () => {
let result: boolean;

before(() => {
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(code, {
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true
}).getObfuscatedCode();

result = eval(obfuscatedCode);
});

it('should create a new object on every evaluation', () => {
assert.isFalse(result);
});
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -478,9 +478,7 @@ describe('ObjectExpressionKeysTransformer', () => {
describe('Variant #1: base', () => {
const match: string =
`` +
`var ${variableMatch} *= *{};` +
`${variableMatch}\\['value'] *= *0x1;` +
`function test *\\(${variableMatch} *= *0x1, *${variableMatch} *= *${variableMatch}\\) *{ *}` +
`^function test *\\(${variableMatch} *= *0x1, *${variableMatch} *= *{'value' *: *0x1}\\) *{ *}` +
``;
const regExp: RegExp = new RegExp(match);

Expand All @@ -495,16 +493,14 @@ describe('ObjectExpressionKeysTransformer', () => {
}).getObfuscatedCode();
});

it('shouldn ignore default parameter object if it references other parameter', () => {
it('shouldn ignore default parameter object', () => {
assert.match(obfuscatedCode, regExp);
});
});

describe('Variant #2: mangled name of object host node', () => {
const match1: string =
`` + `var a *= *{};` + `a\\['bar'] *= *0x1;` + `function foo *\\(c *= *a\\) *{ *}` + ``;
const match2: string =
`` + `var b *= *{};` + `b\\['bark'] *= *0x1;` + `function baz *\\(c *= *b\\) *{ *}` + ``;
describe('Variant #2: mangled identifier names', () => {
const match1: string = `` + `^function foo *\\(a *= *{'bar' *: *0x1}\\) *{ *}` + ``;
const match2: string = `` + `function baz *\\(a *= *{'bark' *: *0x1}\\) *{ *}$` + ``;
const regExp1: RegExp = new RegExp(match1);
const regExp2: RegExp = new RegExp(match2);

Expand All @@ -522,11 +518,11 @@ describe('ObjectExpressionKeysTransformer', () => {
}).getObfuscatedCode();
});

it('Match #1: shouldn generate correct name for object host node', () => {
it('Match #1: shouldn ignore default parameter object', () => {
assert.match(obfuscatedCode, regExp1);
});

it('Match #2: shouldn generate correct name for object host node', () => {
it('Match #2: shouldn ignore default parameter object', () => {
assert.match(obfuscatedCode, regExp2);
});
});
Expand Down
1 change: 1 addition & 0 deletions test/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ import './functional-tests/issues/issue437.spec';
import './functional-tests/issues/issue1419.spec';
import './functional-tests/issues/issue1437.spec';
import './functional-tests/issues/issue1448.spec';
import './functional-tests/issues/issue1455.spec';
import './functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec';
import './functional-tests/node-transformers/control-flow-transformers/block-statement-control-flow-transformer/BlockStatementControlFlowTransformer.spec';
import './functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/BinaryExpressionControlFlowReplacer.spec';
Expand Down
Loading