More complex object keys transformation + some string literal transformations refactoring

This commit is contained in:
sanex3339
2020-01-25 13:50:00 +03:00
parent f333b9d425
commit fc2cf933d9
20 changed files with 390 additions and 101 deletions
+5 -3
View File
@@ -7,12 +7,14 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
var foo = {foo: 1};
var foo = {['foo']: 1};
`,
{
...NO_ADDITIONAL_NODES_PRESET,
transformObjectKeys: true,
compact: false
compact: false,
unicodeEscapeSequence: true,
stringArray: true,
stringArrayThreshold: 1
}
).getObfuscatedCode();
@@ -152,11 +152,14 @@ describe('ObjectExpressionKeysTransformer', () => {
describe('Variant #6: nested objects #1', () => {
const match: string = `` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['baz'] *= *'bark';` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['inner1'] *= *${variableMatch};` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['foo'] *= *'bar';` +
`${variableMatch}\\['inner'] *= *{};` +
`${variableMatch}\\['inner']\\['inner1'] *= *{};` +
`${variableMatch}\\['inner']\\['inner1']\\['baz'] *= *'bark';` +
`${variableMatch}\\['inner'] *= *${variableMatch};` +
`var object *= *${variableMatch};` +
``;
const regExp: RegExp = new RegExp(match);
@@ -181,14 +184,17 @@ describe('ObjectExpressionKeysTransformer', () => {
describe('Variant #7: nested objects #2', () => {
const match: string = `` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['hawk'] *= *'geek';` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['baz'] *= *'bark';` +
`${variableMatch}\\['inner1'] *= *${variableMatch};` +
`${variableMatch}\\['cow'] *= *'bear';` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['foo'] *= *'bar';` +
`${variableMatch}\\['inner'] *= *{};` +
`${variableMatch}\\['inner'] *= *${variableMatch};` +
`${variableMatch}\\['ball'] *= *'door';` +
`${variableMatch}\\['inner']\\['baz'] *= *'bark';` +
`${variableMatch}\\['inner']\\['inner1'] *= *{};` +
`${variableMatch}\\['inner']\\['cow'] *= *'bear';` +
`${variableMatch}\\['inner']\\['inner1']\\['hawk'] *= *'geek';` +
`var *object *= *${variableMatch};` +
``;
const regExp: RegExp = new RegExp(match);
@@ -213,14 +219,16 @@ describe('ObjectExpressionKeysTransformer', () => {
describe('Variant #8: nested objects #3', () => {
const match: string = `` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['hawk'] *= *'geek';` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['baz'] *= *'bark';` +
`${variableMatch}\\['inner1'] *= *${variableMatch};` +
`${variableMatch}\\['cow'] *= *'bear';` +
`var *${variableMatch} *= *{};` +
`${variableMatch}\\['foo'] *= *'bar';` +
`${variableMatch}\\['inner'] *= *{};` +
`${variableMatch}\\['inner'] *= *${variableMatch};` +
`${variableMatch}\\['ball'] *= *'door';` +
`${variableMatch}\\['inner']\\['baz'] *= *'bark';` +
`${variableMatch}\\['inner']\\['inner1'] *= *{};` +
`${variableMatch}\\['inner']\\['cow'] *= *'bear';` +
`${variableMatch}\\['inner']\\['inner1']\\['hawk'] *= *'geek';` +
`return ${variableMatch};` +
``;
const regExp: RegExp = new RegExp(match);
@@ -1394,7 +1402,7 @@ describe('ObjectExpressionKeysTransformer', () => {
`var ${variableMatch} *= *{};` +
`${variableMatch}\\['foo'] *= *'test';` +
`var foo *= *${variableMatch};` +
`var ${variableMatch} *= *{\\[foo.foo] *: *'1'};` +
`var ${variableMatch} *= *{\\[foo\\['foo']] *: *'1'};` +
`${variableMatch}\\['bar'] *= *'2';` +
`var bar *= *${variableMatch};` +
``;
@@ -1,10 +1,8 @@
(function(){
var object = {
foo: 'bar',
inner: {
inner1: {
baz: 'bark'
}
var object = {
foo: 'bar',
inner: {
inner1: {
baz: 'bark'
}
};
})();
}
};
@@ -1,14 +1,12 @@
(function(){
var object = {
foo: 'bar',
inner: {
baz: 'bark',
inner1: {
hawk: 'geek'
},
cow: 'bear',
var object = {
foo: 'bar',
inner: {
baz: 'bark',
inner1: {
hawk: 'geek'
},
ball: 'door',
};
})();
cow: 'bear',
},
ball: 'door',
};
@@ -135,7 +135,7 @@ describe('LiteralTransformer', () => {
describe('Variant #6: `unicodeEscapeSequence` and `stringArray` options are enabled', () => {
const stringArrayRegExp: RegExp = /^var *_0x([a-f0-9]){4} *= *\['\\x74\\x65\\x73\\x74'\];/;
const stringArrayCallRegExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/;
const stringArrayCallRegExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('\\x30\\x78\\x30'\);/;
let obfuscatedCode: string;
@@ -157,7 +157,7 @@ describe('LiteralTransformer', () => {
assert.match(obfuscatedCode, stringArrayRegExp);
});
it('match #1: should replace literal node value with unicode escape sequence from string array', () => {
it('match #2: should replace literal node value with unicode escape sequence from string array', () => {
assert.match(obfuscatedCode, stringArrayCallRegExp);
});
});
@@ -518,6 +518,64 @@ describe('LiteralTransformer', () => {
});
});
});
describe('Variant #13: object expression key literal', () => {
describe('Variant #1: base key literal', () => {
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['bar'];/;
const objectExpressionRegExp: RegExp = /var test *= *{'foo' *: *_0x([a-f0-9]){4}\('0x0'\)};/;
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/object-expression-key-literal.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
stringArray: true,
stringArrayThreshold: 1
}
).getObfuscatedCode();
});
it('match #1: should not add object expression key literal to the string array', () => {
assert.match(obfuscatedCode, stringArrayRegExp);
});
it('match #2: should keep object expression key literal', () => {
assert.match(obfuscatedCode, objectExpressionRegExp);
});
});
describe('Variant #2: computed key literal', () => {
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['foo', *'bar'];/;
const objectExpressionRegExp: RegExp = /var test *= *{\[_0x([a-f0-9]){4}\('0x0'\)] *: *_0x([a-f0-9]){4}\('0x1'\)};/;
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/object-expression-computed-key-literal.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
stringArray: true,
stringArrayThreshold: 1
}
).getObfuscatedCode();
});
it('match #1: should add object expression computed key literal to the string array', () => {
assert.match(obfuscatedCode, stringArrayRegExp);
});
it('match #2: should replace object expression computed key literal on call to the string array', () => {
assert.match(obfuscatedCode, objectExpressionRegExp);
});
});
});
});
describe('transformation of literal node with boolean value', () => {
@@ -157,6 +157,55 @@ describe('StringArrayStorageAnalyzer', () => {
});
});
describe('Analyzes of the AST tree with prohibited string literal nodes', () => {
const literalNode1: ESTree.Literal = NodeFactory.literalNode('foo');
const literalNode2: ESTree.Literal = NodeFactory.literalNode('bar');
const expectedStringArrayStorageItemData1: IStringArrayStorageItemData = {
encodedValue: 'foo',
decodeKey: null,
index: 0,
value: 'foo'
};
const expectedStringArrayStorageItemData2: undefined = undefined;
let stringArrayStorageItemData1: IStringArrayStorageItemData | undefined;
let stringArrayStorageItemData2: IStringArrayStorageItemData | undefined;
before(() => {
stringArrayStorageAnalyzer = getStringArrayStorageAnalyzer({
stringArrayThreshold: 1
});
const astTree: ESTree.Program = NodeFactory.programNode([
NodeFactory.expressionStatementNode(literalNode1),
NodeFactory.variableDeclarationNode([
NodeFactory.variableDeclaratorNode(
NodeFactory.identifierNode('bar'),
NodeFactory.objectExpressionNode([
NodeFactory.propertyNode(
literalNode2,
NodeFactory.literalNode(1)
)
])
)
])
]);
stringArrayStorageAnalyzer.analyze(astTree);
stringArrayStorageItemData1 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode1);
stringArrayStorageItemData2 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode2);
});
it('Variant #1: should return correct string array storage item data for literal node #1', () => {
assert.deepEqual(stringArrayStorageItemData1, expectedStringArrayStorageItemData1);
});
it('Variant #2: should return correct string array storage item data for literal node #1', () => {
assert.deepEqual(stringArrayStorageItemData2, expectedStringArrayStorageItemData2);
});
});
describe('Analyzes of the AST tree with ignored nodes', () => {
const literalNode1: ESTree.Literal = NodeFactory.literalNode('foo');
const literalNode2: ESTree.Literal = NodeFactory.literalNode('bar');
@@ -0,0 +1,136 @@
import * as ESTree from 'estree';
import { assert } from 'chai';
import { NodeFactory } from '../../../../src/node/NodeFactory';
import { NodeLiteralUtils } from '../../../../src/node/NodeLiteralUtils';
describe('NodeLiteralUtils', () => {
describe('isProhibitedLiteralNode', () => {
describe('String literal node', () => {
describe('Variant #1: base string literal node', () => {
const literalNode: ESTree.Literal = NodeFactory.literalNode('foo');
let statementNode: ESTree.Statement;
before(() => {
statementNode = NodeFactory.expressionStatementNode(
literalNode
);
literalNode.parentNode = statementNode;
});
it('should return false for base string literal node', () => {
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, statementNode), false);
});
});
describe('Variant #2: property literal node', () => {
describe('Variant #1: property key literal node', () => {
const literalNode: ESTree.Literal = NodeFactory.literalNode('foo');
let propertyNode: ESTree.Property;
before(() => {
propertyNode = NodeFactory.propertyNode(
literalNode,
NodeFactory.literalNode(1)
);
literalNode.parentNode = propertyNode;
});
it('should return false for property key literal node', () => {
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, propertyNode), true);
});
});
describe('Variant #2: computed property key literal node', () => {
const literalNode: ESTree.Literal = NodeFactory.literalNode('foo');
let propertyNode: ESTree.Property;
before(() => {
propertyNode = NodeFactory.propertyNode(
literalNode,
NodeFactory.literalNode(1),
true
);
literalNode.parentNode = propertyNode;
});
it('should return false for computed property key literal node', () => {
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, propertyNode), false);
});
});
describe('Variant #3: property value literal node', () => {
const literalNode: ESTree.Literal = NodeFactory.literalNode('foo');
let propertyNode: ESTree.Property;
before(() => {
propertyNode = NodeFactory.propertyNode(
NodeFactory.literalNode(1),
literalNode
);
literalNode.parentNode = propertyNode;
});
it('should return false for property value literal node', () => {
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, propertyNode), false);
});
});
});
describe('Variant #3: import declaration node', () => {
describe('Variant #1: base import declaration literal node', () => {
const literalNode: ESTree.Literal = NodeFactory.literalNode('foo');
let importDeclarationNode: ESTree.ImportDeclaration;
before(() => {
importDeclarationNode = NodeFactory.importDeclarationNode(
[],
literalNode
);
literalNode.parentNode = importDeclarationNode;
});
it('should return false for import declaration literal node', () => {
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, importDeclarationNode), true);
});
});
});
});
describe('Number literal node', () => {
describe('Variant #1: base number literal node', () => {
const literalNode: ESTree.Literal = NodeFactory.literalNode(1);
let statementNode: ESTree.Statement;
before(() => {
statementNode = NodeFactory.expressionStatementNode(
literalNode
);
const blockStatementNode: ESTree.BlockStatement = NodeFactory.blockStatementNode([
statementNode
]);
statementNode.parentNode = blockStatementNode;
literalNode.parentNode = statementNode;
});
it('should return false for base number literal node', () => {
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, statementNode), false);
});
});
});
});
});