mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
More complex object keys transformation + some string literal transformations refactoring
This commit is contained in:
Vendored
+6
-6
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -12,6 +12,7 @@ import { IStringArrayStorageItemData } from '../../interfaces/storages/string-ar
|
||||
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { NodeMetadata } from '../../node/NodeMetadata';
|
||||
import { NodeLiteralUtils } from '../../node/NodeLiteralUtils';
|
||||
|
||||
/**
|
||||
* Adds values of literal nodes to the string array storage
|
||||
@@ -67,7 +68,11 @@ export class StringArrayStorageAnalyzer implements IStringArrayStorageAnalyzer {
|
||||
}
|
||||
|
||||
estraverse.traverse(astTree, {
|
||||
enter: (node: ESTree.Node): estraverse.VisitorOption | void => {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): estraverse.VisitorOption | void => {
|
||||
if (!parentNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NodeMetadata.isIgnoredNode(node)) {
|
||||
return estraverse.VisitorOption.Skip;
|
||||
}
|
||||
@@ -76,7 +81,7 @@ export class StringArrayStorageAnalyzer implements IStringArrayStorageAnalyzer {
|
||||
return;
|
||||
}
|
||||
|
||||
this.analyzeLiteralNode(node);
|
||||
this.analyzeLiteralNode(node, parentNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -91,12 +96,17 @@ export class StringArrayStorageAnalyzer implements IStringArrayStorageAnalyzer {
|
||||
|
||||
/**
|
||||
* @param {Literal} literalNode
|
||||
* @param {Node} parentNode
|
||||
*/
|
||||
private analyzeLiteralNode (literalNode: ESTree.Literal): void {
|
||||
private analyzeLiteralNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): void {
|
||||
if (typeof literalNode.value !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NodeLiteralUtils.isProhibitedLiteralNode(literalNode, parentNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.shouldAddValueToStringArray(literalNode.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
||||
switch (transformationStage) {
|
||||
case TransformationStage.Converting:
|
||||
return {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
||||
leave: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
||||
if (
|
||||
parentNode
|
||||
&& NodeGuards.isObjectExpressionNode(node)
|
||||
|
||||
@@ -12,7 +12,6 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { NodeFactory } from '../../node/NodeFactory';
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEncoder';
|
||||
|
||||
/**
|
||||
* replaces:
|
||||
@@ -24,23 +23,14 @@ import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEn
|
||||
@injectable()
|
||||
export class ObjectExpressionTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {IEscapeSequenceEncoder}
|
||||
*/
|
||||
private readonly escapeSequenceEncoder: IEscapeSequenceEncoder;
|
||||
|
||||
/**
|
||||
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder,
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.escapeSequenceEncoder = escapeSequenceEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,7 +83,7 @@ export class ObjectExpressionTransformer extends AbstractNodeTransformer {
|
||||
return;
|
||||
}
|
||||
|
||||
property.key = NodeFactory.literalNode(this.getPropertyKeyValue(property.key.value));
|
||||
property.key = NodeFactory.literalNode(property.key.value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,16 +98,6 @@ export class ObjectExpressionTransformer extends AbstractNodeTransformer {
|
||||
return;
|
||||
}
|
||||
|
||||
property.key = NodeFactory.literalNode(this.getPropertyKeyValue(property.key.name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} inputValue
|
||||
* @returns {string}
|
||||
*/
|
||||
private getPropertyKeyValue (inputValue: string): string {
|
||||
return this.options.unicodeEscapeSequence
|
||||
? this.escapeSequenceEncoder.encode(inputValue, true)
|
||||
: inputValue;
|
||||
property.key = NodeFactory.literalNode(property.key.name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import * as ESTree from 'estree';
|
||||
|
||||
import { TLiteralObfuscatingReplacerFactory } from '../../types/container/node-transformers/TLiteralObfuscatingReplacerFactory';
|
||||
|
||||
import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEncoder';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IStringArrayStorageAnalyzer } from '../../interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
|
||||
@@ -14,12 +15,19 @@ import { LiteralObfuscatingReplacer } from '../../enums/node-transformers/obfusc
|
||||
import { TransformationStage } from '../../enums/node-transformers/TransformationStage';
|
||||
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { NodeFactory } from '../../node/NodeFactory';
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { NodeLiteralUtils } from '../../node/NodeLiteralUtils';
|
||||
import { NodeMetadata } from '../../node/NodeMetadata';
|
||||
import { NodeUtils } from '../../node/NodeUtils';
|
||||
|
||||
@injectable()
|
||||
export class LiteralTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {IEscapeSequenceEncoder}
|
||||
*/
|
||||
private readonly escapeSequenceEncoder: IEscapeSequenceEncoder;
|
||||
|
||||
/**
|
||||
* @type {TLiteralObfuscatingReplacerFactory}
|
||||
*/
|
||||
@@ -35,18 +43,21 @@ export class LiteralTransformer extends AbstractNodeTransformer {
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
* @param {IStringArrayStorageAnalyzer} stringArrayStorageAnalyzer
|
||||
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.Factory__IObfuscatingReplacer)
|
||||
literalObfuscatingReplacerFactory: TLiteralObfuscatingReplacerFactory,
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions,
|
||||
@inject(ServiceIdentifiers.IStringArrayStorageAnalyzer) stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer
|
||||
@inject(ServiceIdentifiers.IStringArrayStorageAnalyzer) stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer,
|
||||
@inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.literalObfuscatingReplacerFactory = literalObfuscatingReplacerFactory;
|
||||
this.stringArrayStorageAnalyzer = stringArrayStorageAnalyzer;
|
||||
this.escapeSequenceEncoder = escapeSequenceEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,6 +79,15 @@ export class LiteralTransformer extends AbstractNodeTransformer {
|
||||
}
|
||||
};
|
||||
|
||||
case TransformationStage.Finalizing:
|
||||
return {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
||||
if (parentNode && NodeGuards.isLiteralNode(node)) {
|
||||
return this.encodeLiteralNodeToEscapeSequence(node, parentNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -83,7 +103,7 @@ export class LiteralTransformer extends AbstractNodeTransformer {
|
||||
* @returns {NodeGuards}
|
||||
*/
|
||||
public transformNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): ESTree.Node {
|
||||
if (this.isProhibitedNode(literalNode, parentNode)) {
|
||||
if (NodeLiteralUtils.isProhibitedLiteralNode(literalNode, parentNode)) {
|
||||
return literalNode;
|
||||
}
|
||||
|
||||
@@ -123,17 +143,18 @@ export class LiteralTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @param {Literal} literalNode
|
||||
* @param {Node} parentNode
|
||||
* @returns {boolean}
|
||||
* @returns {Literal}
|
||||
*/
|
||||
private isProhibitedNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): boolean {
|
||||
if (NodeGuards.isPropertyNode(parentNode) && parentNode.key === literalNode) {
|
||||
return true;
|
||||
private encodeLiteralNodeToEscapeSequence (
|
||||
literalNode: ESTree.Literal,
|
||||
parentNode: ESTree.Node
|
||||
): ESTree.Literal {
|
||||
if (typeof literalNode.value !== 'string') {
|
||||
return literalNode;
|
||||
}
|
||||
|
||||
if (NodeGuards.isImportDeclarationNode(parentNode)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return NodeFactory.literalNode(
|
||||
this.escapeSequenceEncoder.encode(literalNode.value, this.options.unicodeEscapeSequence)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-15
@@ -3,7 +3,6 @@ import { ServiceIdentifiers } from '../../../../container/ServiceIdentifiers';
|
||||
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { IEscapeSequenceEncoder } from '../../../../interfaces/utils/IEscapeSequenceEncoder';
|
||||
import { IInitializable } from '../../../../interfaces/IInitializable';
|
||||
import { IOptions } from '../../../../interfaces/options/IOptions';
|
||||
import { IStringArrayStorage } from '../../../../interfaces/storages/string-array-storage/IStringArrayStorage';
|
||||
@@ -22,11 +21,6 @@ import { Utils } from '../../../../utils/Utils';
|
||||
|
||||
@injectable()
|
||||
export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplacer implements IInitializable {
|
||||
/**
|
||||
* @type {IEscapeSequenceEncoder}
|
||||
*/
|
||||
private readonly escapeSequenceEncoder: IEscapeSequenceEncoder;
|
||||
|
||||
/**
|
||||
* @type {Map<string, ESTree.Node>}
|
||||
*/
|
||||
@@ -51,20 +45,17 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
|
||||
/**
|
||||
* @param {IStringArrayStorage} stringArrayStorage
|
||||
* @param {IStringArrayStorageAnalyzer} stringArrayStorageAnalyzer
|
||||
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
|
||||
* @param {IOptions} options
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.TStringArrayStorage) stringArrayStorage: IStringArrayStorage,
|
||||
@inject(ServiceIdentifiers.IStringArrayStorageAnalyzer) stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer,
|
||||
@inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions
|
||||
) {
|
||||
super(options);
|
||||
|
||||
this.stringArrayStorage = stringArrayStorage;
|
||||
this.stringArrayStorageAnalyzer = stringArrayStorageAnalyzer;
|
||||
this.escapeSequenceEncoder = escapeSequenceEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,9 +129,7 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
|
||||
* @returns {Node}
|
||||
*/
|
||||
private replaceWithLiteralNode (value: string): ESTree.Node {
|
||||
return NodeFactory.literalNode(
|
||||
this.escapeSequenceEncoder.encode(value, this.options.unicodeEscapeSequence)
|
||||
);
|
||||
return NodeFactory.literalNode(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,9 +145,7 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
|
||||
];
|
||||
|
||||
if (decodeKey) {
|
||||
callExpressionArgs.push(StringLiteralObfuscatingReplacer.getRc4KeyLiteralNode(
|
||||
this.escapeSequenceEncoder.encode(decodeKey, this.options.unicodeEscapeSequence)
|
||||
));
|
||||
callExpressionArgs.push(StringLiteralObfuscatingReplacer.getRc4KeyLiteralNode(decodeKey));
|
||||
}
|
||||
|
||||
const stringArrayIdentifierNode: ESTree.Identifier = NodeFactory.identifierNode(this.stringArrayStorageCallsWrapperName);
|
||||
|
||||
@@ -228,6 +228,23 @@ export class NodeFactory {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier)[]} specifiers
|
||||
* @param {Literal} source
|
||||
* @returns {ImportDeclaration}
|
||||
*/
|
||||
public static importDeclarationNode (
|
||||
specifiers: (ESTree.ImportSpecifier | ESTree.ImportDefaultSpecifier | ESTree.ImportNamespaceSpecifier)[],
|
||||
source: ESTree.Literal
|
||||
): ESTree.ImportDeclaration {
|
||||
return {
|
||||
type: NodeType.ImportDeclaration,
|
||||
specifiers,
|
||||
source,
|
||||
metadata: { ignoredNode: false }
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean | number | string} value
|
||||
* @param {string} raw
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { NodeGuards } from './NodeGuards';
|
||||
|
||||
export class NodeLiteralUtils {
|
||||
/**
|
||||
* @param {Literal} literalNode
|
||||
* @param {Node} parentNode
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isProhibitedLiteralNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): boolean {
|
||||
if (NodeGuards.isPropertyNode(parentNode) && !parentNode.computed && parentNode.key === literalNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NodeGuards.isImportDeclarationNode(parentNode)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -218,6 +218,7 @@ export class StringArrayStorage extends MapStorage <string, IStringArrayStorageI
|
||||
return Array
|
||||
.from(this.storage.values())
|
||||
.map((stringArrayStorageItemData: IStringArrayStorageItemData) => {
|
||||
// we have to encode here, because of possible errors during `parse` of StringArrayCustomNode
|
||||
return `'${this.escapeSequenceEncoder.encode(
|
||||
stringArrayStorageItemData.encodedValue,
|
||||
this.options.unicodeEscapeSequence
|
||||
|
||||
+5
-3
@@ -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();
|
||||
|
||||
|
||||
+22
-14
@@ -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};` +
|
||||
``;
|
||||
|
||||
+7
-9
@@ -1,10 +1,8 @@
|
||||
(function(){
|
||||
var object = {
|
||||
foo: 'bar',
|
||||
inner: {
|
||||
inner1: {
|
||||
baz: 'bark'
|
||||
}
|
||||
var object = {
|
||||
foo: 'bar',
|
||||
inner: {
|
||||
inner1: {
|
||||
baz: 'bark'
|
||||
}
|
||||
};
|
||||
})();
|
||||
}
|
||||
};
|
||||
+11
-13
@@ -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',
|
||||
};
|
||||
+60
-2
@@ -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', () => {
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
var test = {['foo']: 'bar'};
|
||||
+1
@@ -0,0 +1 @@
|
||||
var test = {'foo': 'bar'};
|
||||
+49
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user