Added additional self defending mechanisms. Updated tests

This commit is contained in:
sanex
2021-08-01 16:58:04 +03:00
parent 9da81caf3d
commit c4abec8c2a
31 changed files with 785 additions and 320 deletions
+2 -1
View File
@@ -37,7 +37,8 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
stringArrayEncoding: ['rc4', 'base64'],
stringArrayWrappersCount: 5,
rotateStringArray: true,
identifierNamesGenerator: 'mangled'
identifierNamesGenerator: 'mangled',
selfDefending: true
}
).getObfuscatedCode();
@@ -2,6 +2,7 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
@@ -59,8 +60,8 @@ describe('HashbangOperatorTransformer', () => {
describe('Variant #3: `stringArray` option enabled', () => {
const regExp: RegExp = new RegExp(
`^#!\/usr\/bin\/env node${lineSeparator}` +
`var _0x(\\w){4} *= *\\['abc'];`
`^#!\/usr\/bin\/env node${lineSeparator}.*` +
`${getStringArrayRegExp(['abc']).source}`
);
let obfuscatedCode: string;
@@ -56,9 +56,10 @@ describe('StringArrayCallsWrapperCodeHelper', () => {
describe('Preserve string array name', () => {
const callsWrapperRegExp: RegExp = new RegExp(`` +
`function *b *\\(c, *d\\) *{ *` +
`b *= *function *\\(e, *f\\) *{` +
`e *= *e *- *0x0; *` +
`var g *= *a\\[e]; *` +
`var e *= *a\\(\\); *` +
`b *= *function *\\(f, *g\\) *{` +
`f *= *f *- *0x0; *` +
`var h *= *e\\[f]; *` +
``);
let obfuscatedCode: string;
@@ -2,12 +2,13 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../src/options/presets/NoCustomNodes';
import { getStringArrayRegExp } from '../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscatorFacade';
describe('StringArrayCodeHelper', () => {
const regExp: RegExp = /^var _0x([a-f0-9]){4} *= *\[/;
const regExp: RegExp = getStringArrayRegExp(['test']);
describe('`stringArray` option is set', () => {
let obfuscatedCode: string;
@@ -84,8 +84,8 @@ describe('StringArrayRotateFunctionCodeHelper', () => {
});
describe('Preserve string array name', () => {
const arrayRotateRegExp: RegExp = /c\['push']\(c\['shift']\(\)\);/;
const comparisonRegExp: RegExp = /if *\(e *=== *d\) *{/;
const arrayRotateRegExp: RegExp = /e\['push']\(e\['shift']\(\)\);/;
const comparisonRegExp: RegExp = /if *\(f *=== *d\) *{/;
let obfuscatedCode: string;
@@ -5,41 +5,59 @@ import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/id
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { getRegExpMatch } from '../../../../helpers/getRegExpMatch';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
describe('StringArrayCodeHelperGroup', () => {
const regExp: RegExp = new RegExp(
'function *b *\\(\\w, *\\w\\) *{.*return \\w;}.*' +
'function *c *\\(\\w, *\\w\\) *{.*return \\w;}.*' +
'function *d *\\(\\w, *\\w\\) *{.*return \\w;}'
'function *\\w *\\(\\w, *\\w\\) *{.*return \\w;}.*' +
'function *\\w *\\(\\w, *\\w\\) *{.*return \\w;}.*' +
'function *\\w *\\(\\w, *\\w\\) *{.*return \\w;}'
);
const stringArrayCallsWrapperRegExp: RegExp = new RegExp(
`function *(\\w) *\\(\\w, *\\w\\) *{.*return \\w;}.*`
);
describe('StringArrayCallsWrapper code helper names', () => {
const stringArrayCallsWrapperNames: Set<string> = new Set();
const samplesCount: number = 30;
let obfuscatedCode: string;
const expectedUniqStringArrayCallsWrapperNamesCount: number = 3;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
stringArray: true,
stringArrayThreshold: 1,
stringArrayEncoding: [
StringArrayEncoding.None,
StringArrayEncoding.Base64,
StringArrayEncoding.Rc4
]
}
).getObfuscatedCode();
for (let i = 0; i < samplesCount; i++) {
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
stringArray: true,
stringArrayThreshold: 1,
stringArrayEncoding: [
StringArrayEncoding.None,
StringArrayEncoding.Base64,
StringArrayEncoding.Rc4
]
}
).getObfuscatedCode();
const callsWrapperName: string = getRegExpMatch(obfuscatedCode, stringArrayCallsWrapperRegExp);
stringArrayCallsWrapperNames.add(callsWrapperName);
}
});
it('should place multiple StringArrayCallsWrapper code helper names in the correct order', () => {
it('should correct place all StringArrayCallsWrapper code helpers', () => {
assert.match(obfuscatedCode, regExp);
});
it('should place multiple StringArrayCallsWrapper code helper names in the random order', () => {
assert.equal(stringArrayCallsWrapperNames.size, expectedUniqStringArrayCallsWrapperNamesCount);
});
});
});
@@ -16,16 +16,19 @@ import { Rc4Template } from '../../../../../../src/custom-code-helpers/string-ar
import { StringArrayBase64DecodeTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayBase64DecodeTemplate';
import { StringArrayCallsWrapperTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayCallsWrapperTemplate';
import { StringArrayRC4DecodeTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayRC4DecodeTemplate';
import { StringArrayTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array/StringArrayTemplate';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes';
import { InversifyContainerFacade } from '../../../../../../src/container/InversifyContainerFacade';
import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade';
import { minimizeCode } from '../../../../../helpers/minimizeCode';
import { readFileAsString } from '../../../../../helpers/readFileAsString';
import { swapLettersCase } from '../../../../../helpers/swapLettersCase';
describe('StringArrayCallsWrapperTemplate', () => {
const stringArrayName: string = 'stringArrayName';
const stringArrayFunctionName: string = 'stringArrayFunctionName';
const stringArrayCallsWrapperName: string = 'stringArrayCallsWrapperName';
const stringArrayCacheName: string = 'stringArrayCache';
const atobFunctionName: string = 'atob';
@@ -45,243 +48,510 @@ describe('StringArrayCallsWrapperTemplate', () => {
});
describe('Variant #1: `base64` encoding', () => {
describe('Variant #1: index shift amount is `0`', () => {
const index: string = '0x0';
describe('Variant #1: `selfDefending` option is disabled', () => {
const selfDefendingEnabled: boolean = false;
const indexShiftAmount: number = 0;
describe('Variant #1: index shift amount is `0`', () => {
const index: string = '0x0';
const expectedDecodedValue: string = 'test1';
const indexShiftAmount: number = 0;
let decodedValue: string;
const expectedDecodedValue: string = 'test1';
before(() => {
const atobPolyfill = format(AtobTemplate(), {
atobFunctionName
});
const atobDecodeTemplate: string = format(
StringArrayBase64DecodeTemplate(randomGenerator),
{
atobPolyfill,
atobFunctionName,
selfDefendingCode: '',
let decodedValue: string;
before(() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('test1')}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const atobDecodeTemplate: string = format(
StringArrayBase64DecodeTemplate(randomGenerator),
{
atobPolyfill,
atobFunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: atobDecodeTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: atobDecodeTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayName
stringArrayCallsWrapperName,
stringArrayFunctionName
});
decodedValue = Function(`
${stringArrayTemplate}
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}(${index});
`)();
});
decodedValue = Function(`
var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa('test1')}'];
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}(${index});
`)();
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
describe('Variant #2: index shift amount is `5`', () => {
const index: string = '0x5';
const indexShiftAmount: number = 5;
const expectedDecodedValue: string = 'test1';
let decodedValue: string;
before(() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('test1')}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const atobDecodeTemplate: string = format(
StringArrayBase64DecodeTemplate(randomGenerator),
{
atobPolyfill,
atobFunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: atobDecodeTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayFunctionName
});
decodedValue = Function(`
${stringArrayTemplate}
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}(${index});
`)();
});
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});
describe('Variant #3: no regexp inside atob template', () => {
const indexShiftAmount: number = 0;
const expectedRegExpTestValue: string = '12345';
let decodedValue: string;
before(() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${swapLettersCase('c3RyaQ==')}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const atobDecodeTemplate: string = format(
StringArrayBase64DecodeTemplate(randomGenerator),
{
atobPolyfill,
atobFunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: atobDecodeTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayFunctionName
});
decodedValue = Function(`
${stringArrayTemplate}
${stringArrayCallsWrapperTemplate}
/(.+)/.test("12345");
${stringArrayCallsWrapperName}(0x0);
return RegExp.$1;
`)();
});
it('should correctly return RegExp.$1 match without mutation by atob template', () => {
assert.deepEqual(decodedValue, expectedRegExpTestValue);
});
});
});
describe('Variant #2: index shift amount is `5`', () => {
const index: string = '0x5';
describe('Variant #2: `selfDefending` option is enabled', () => {
const selfDefendingEnabled: boolean = true;
const indexShiftAmount: number = 5;
describe('Variant #1: correct code evaluation for single-line code', () => {
describe('Variant #1: index shift amount is `0`', () => {
const index: string = '0x0';
const expectedDecodedValue: string = 'test1';
const indexShiftAmount: number = 0;
let decodedValue: string;
const expectedDecodedValue: string = 'test1test1';
before(() => {
const atobPolyfill = format(AtobTemplate(), {
atobFunctionName
let decodedValue: string;
before(async() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('test1test1')}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const atobDecodeTemplate: string = format(
StringArrayBase64DecodeTemplate(randomGenerator),
{
atobPolyfill,
atobFunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = await minimizeCode(
format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: atobDecodeTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayFunctionName
})
);
decodedValue = Function(`
${stringArrayTemplate}
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}(${index});
`)();
});
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});
const atobDecodeTemplate: string = format(
StringArrayBase64DecodeTemplate(randomGenerator),
{
atobPolyfill,
atobFunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: atobDecodeTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayName
});
decodedValue = Function(`
var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa('test1')}'];
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}(${index});
`)();
});
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});
describe('Variant #2: invalid code evaluation for multi-line code', () => {
describe('Variant #1: index shift amount is `0`', () => {
const index: string = '0x0';
describe('Variant #3: no regexp inside atob template', () => {
const indexShiftAmount: number = 0;
const indexShiftAmount: number = 0;
const expectedRegExpTestValue: string = '12345';
const expectedDecodedValue: string = 'test18est1';
let decodedValue: string;
let decodedValue: string;
before(() => {
const atobPolyfill = format(AtobTemplate(), {
atobFunctionName
before(() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('test1test1')}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const atobDecodeTemplate: string = format(
StringArrayBase64DecodeTemplate(randomGenerator),
{
atobPolyfill,
atobFunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: atobDecodeTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayFunctionName
});
decodedValue = Function(`
${stringArrayTemplate}
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}(${index});
`)();
});
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});
const atobDecodeTemplate: string = format(
StringArrayBase64DecodeTemplate(randomGenerator),
{
atobPolyfill,
atobFunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: atobDecodeTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayName
});
decodedValue = Function(`
var ${stringArrayName} = ['${swapLettersCase('c3RyaQ==')}'];
${stringArrayCallsWrapperTemplate}
/(.+)/.test("12345");
${stringArrayCallsWrapperName}(0x0);
return RegExp.$1;
`)();
});
it('should correctly return RegExp.$1 match without mutation by atob template', () => {
assert.deepEqual(decodedValue, expectedRegExpTestValue);
});
});
});
describe('Variant #2: `rc4` encoding', () => {
describe('Variant #1: index shift amount is `0`', () => {
const index: string = '0x0';
const key: string = 'key';
describe('Variant #1: `selfDefending` option is disabled', () => {
const selfDefendingEnabled: boolean = false;
const indexShiftAmount: number = 0;
describe('Variant #1: index shift amount is `0`', () => {
const index: string = '0x0';
const key: string = 'key';
const expectedDecodedValue: string = 'test1';
const indexShiftAmount: number = 0;
let decodedValue: string;
const expectedDecodedValue: string = 'test1';
before(() => {
const atobPolyfill = format(AtobTemplate(), {
atobFunctionName
});
const rc4Polyfill = format(Rc4Template(), {
atobFunctionName,
rc4FunctionName
});
const rc4decodeCodeHelperTemplate: string = format(
StringArrayRC4DecodeTemplate(randomGenerator),
{
atobPolyfill,
rc4Polyfill,
rc4FunctionName,
selfDefendingCode: '',
let decodedValue: string;
before(() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const rc4Polyfill = format(Rc4Template(), {
atobFunctionName,
rc4FunctionName
});
const rc4decodeCodeHelperTemplate: string = format(
StringArrayRC4DecodeTemplate(randomGenerator),
{
atobPolyfill,
rc4Polyfill,
rc4FunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayName
stringArrayCallsWrapperName,
stringArrayFunctionName
});
decodedValue = Function(`
${stringArrayTemplate}
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}('${index}', '${key}');
`)();
});
decodedValue = Function(`
var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'];
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}('${index}', '${key}');
`)();
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
describe('Variant #2: index shift amount is `5`', () => {
const index: string = '0x5';
const key: string = 'key';
const indexShiftAmount: number = 5;
const expectedDecodedValue: string = 'test1';
let decodedValue: string;
before(() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const rc4Polyfill = format(Rc4Template(), {
atobFunctionName,
rc4FunctionName
});
const rc4decodeCodeHelperTemplate: string = format(
StringArrayRC4DecodeTemplate(randomGenerator),
{
atobPolyfill,
rc4Polyfill,
rc4FunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayFunctionName
});
decodedValue = Function(`
${stringArrayTemplate}
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}('${index}', '${key}');
`)();
});
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});
});
describe('Variant #2: index shift amount is `5`', () => {
const index: string = '0x5';
const key: string = 'key';
describe('Variant #2: `selfDefending` option is enabled', () => {
const selfDefendingEnabled: boolean = true;
const indexShiftAmount: number = 5;
describe('Variant #1: correct code evaluation for single-line code', () => {
describe('Variant #1: index shift amount is `0`', () => {
const index: string = '0x0';
const key: string = 'key';
const expectedDecodedValue: string = 'test1';
const indexShiftAmount: number = 0;
let decodedValue: string;
const expectedDecodedValue: string = 'test1';
before(() => {
const atobPolyfill = format(AtobTemplate(), {
atobFunctionName
let decodedValue: string;
before(async() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const rc4Polyfill = format(Rc4Template(), {
atobFunctionName,
rc4FunctionName
});
const rc4decodeCodeHelperTemplate: string = format(
StringArrayRC4DecodeTemplate(randomGenerator),
{
atobPolyfill,
rc4Polyfill,
rc4FunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = await minimizeCode(
format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayFunctionName
})
);
console.log(stringArrayCallsWrapperTemplate);
decodedValue = Function(`
${stringArrayTemplate}
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}('${index}', '${key}');
`)();
});
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});
const rc4Polyfill = format(Rc4Template(), {
atobFunctionName,
rc4FunctionName
});
const rc4decodeCodeHelperTemplate: string = format(
StringArrayRC4DecodeTemplate(randomGenerator),
{
atobPolyfill,
rc4Polyfill,
rc4FunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayName
});
decodedValue = Function(`
var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'];
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}('${index}', '${key}');
`)();
});
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
describe('Variant #2: invalid code evaluation for multi-line code', () => {
describe('Variant #1: index shift amount is `0`', () => {
const index: string = '0x0';
const key: string = 'key';
const indexShiftAmount: number = 0;
const expectedDecodedValue: string = 'test\u001c';
let decodedValue: string;
before(() => {
const stringArrayTemplate = format(StringArrayTemplate(), {
stringArrayName,
stringArrayFunctionName,
stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'`
});
const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), {
atobFunctionName
});
const rc4Polyfill = format(Rc4Template(), {
atobFunctionName,
rc4FunctionName
});
const rc4decodeCodeHelperTemplate: string = format(
StringArrayRC4DecodeTemplate(randomGenerator),
{
atobPolyfill,
rc4Polyfill,
rc4FunctionName,
selfDefendingCode: '',
stringArrayCacheName,
stringArrayCallsWrapperName
}
);
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
indexShiftAmount,
stringArrayCacheName,
stringArrayCallsWrapperName,
stringArrayFunctionName
});
decodedValue = Function(`
${stringArrayTemplate}
${stringArrayCallsWrapperTemplate}
return ${stringArrayCallsWrapperName}('${index}', '${key}');
`)();
});
it('should correctly return decoded value', () => {
assert.deepEqual(decodedValue, expectedDecodedValue);
});
});
});
});
});
@@ -7,13 +7,14 @@ import { IObfuscationResult } from '../../../../../../src/interfaces/source-code
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes';
import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade';
import { getStringArrayRegExp } from '../../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../../helpers/readFileAsString';
describe('StringArrayTemplate', () => {
describe('Prevailing kind of variables', () => {
describe('`var` kind', () => {
let obfuscatedCode: string,
stringArrayRegExp: RegExp = /var (_0x(\w){4}) *= *\['.*'];/;
stringArrayRegExp: RegExp = getStringArrayRegExp(['foo'], {kind: 'var'});
beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-var.js');
@@ -40,7 +41,7 @@ describe('StringArrayTemplate', () => {
describe('`const` kind', () => {
let obfuscatedCode: string,
stringArrayRegExp: RegExp = /const (_0x(\w){4}) *= *\['.*'];/;
stringArrayRegExp: RegExp = getStringArrayRegExp(['foo'], {kind: 'const'});
beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-const.js');
@@ -67,7 +68,7 @@ describe('StringArrayTemplate', () => {
describe('`let` kind', () => {
let obfuscatedCode: string,
stringArrayRegExp: RegExp = /const (_0x(\w){4}) *= *\['.*'];/;
stringArrayRegExp: RegExp = getStringArrayRegExp(['foo'], {kind: 'const'});
beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-let.js');
@@ -4,8 +4,9 @@ import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/id
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { getRegExpMatch } from '../../../../helpers/getRegExpMatch';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
@@ -13,10 +14,19 @@ describe('DictionaryIdentifierNamesGenerator', () => {
describe('generateWithPrefix', () => {
describe('Variant #1: should not generate same name for string array as existing name in code', () => {
describe('Variant #1: `renameGlobals` option is disabled', () => {
const stringArrayStorageRegExp: RegExp = /const a[cABC] *= *\['_aa', *'_ab'];/;
const variableDeclarationIdentifierNameRegExp1: RegExp = /const aa *= *a[cABC]\(0x0\);/;
const variableDeclarationIdentifierNameRegExp2: RegExp = /const ab *= *a[cABC]\(0x1\);/;
const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(
['_aa', '_ab'],
{
name: '\\w*',
kind: 'const'
}
);
const variableDeclarationIdentifierNameRegExp1: RegExp = /const (\w*) *= *\w*\(0x0\);/;
const variableDeclarationIdentifierNameRegExp2: RegExp = /const (\w*) *= *\w*\(0x1\);/;
let stringArrayName: string = '';
let variableDeclarationIdentifierName1: string = '';
let variableDeclarationIdentifierName2: string = '';
let obfuscatedCode: string;
before(() => {
@@ -34,26 +44,45 @@ describe('DictionaryIdentifierNamesGenerator', () => {
stringArrayThreshold: 1
}
).getObfuscatedCode();
stringArrayName = getRegExpMatch(obfuscatedCode, stringArrayStorageRegExp);
variableDeclarationIdentifierName1 = getRegExpMatch(
obfuscatedCode,
variableDeclarationIdentifierNameRegExp1
);
variableDeclarationIdentifierName2 = getRegExpMatch(
obfuscatedCode,
variableDeclarationIdentifierNameRegExp2
);
});
it('Match #1: should generate correct identifier for string array', () => {
it('Should generate correct identifier for string array', () => {
assert.match(obfuscatedCode, stringArrayStorageRegExp);
});
it('Match #2: should keep identifier name for existing variable declaration', () => {
assert.match(obfuscatedCode, variableDeclarationIdentifierNameRegExp1);
it('Should keep identifier name for existing variable declaration #1', () => {
assert.notEqual(stringArrayName, variableDeclarationIdentifierName1);
});
it('Match #3: should keep identifier name for existing variable declaration', () => {
assert.match(obfuscatedCode, variableDeclarationIdentifierNameRegExp2);
it('Should keep identifier name for existing variable declaration #2', () => {
assert.notEqual(stringArrayName, variableDeclarationIdentifierName2);
});
});
describe('Variant #2: `renameGlobals` option is enabled', () => {
const stringArrayStorageRegExp: RegExp = /const a[cABC] *= *\['_aa', *'_ab'];/;
const lastVariableDeclarationIdentifierNameRegExp1: RegExp = /const a[cABC] *= *a[cABC]\(0x0\);/;
const lastVariableDeclarationIdentifierNameRegExp2: RegExp = /const a[cABC] *= *a[cABC]\(0x1\);/;
const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(
['_aa', '_ab'],
{
name: '\\w*',
kind: 'const'
}
);
const variableDeclarationIdentifierNameRegExp1: RegExp = /const (\w*) *= *\w*\(0x0\);/;
const variableDeclarationIdentifierNameRegExp2: RegExp = /const (\w*) *= *\w*\(0x1\);/;
let stringArrayName: string = '';
let variableDeclarationIdentifierName1: string = '';
let variableDeclarationIdentifierName2: string = '';
let obfuscatedCode: string;
before(() => {
@@ -64,7 +93,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator,
identifiersDictionary: ['a', 'b', 'c'],
identifiersDictionary: ['a', 'b', 'c', 'd'],
identifiersPrefix: 'a',
renameGlobals: true,
transformObjectKeys: true,
@@ -72,18 +101,28 @@ describe('DictionaryIdentifierNamesGenerator', () => {
stringArrayThreshold: 1
}
).getObfuscatedCode();
stringArrayName = getRegExpMatch(obfuscatedCode, stringArrayStorageRegExp);
variableDeclarationIdentifierName1 = getRegExpMatch(
obfuscatedCode,
variableDeclarationIdentifierNameRegExp1
);
variableDeclarationIdentifierName2 = getRegExpMatch(
obfuscatedCode,
variableDeclarationIdentifierNameRegExp2
);
});
it('Match #1: should generate correct identifier for string array', () => {
it('Should generate correct identifier for string array', () => {
assert.match(obfuscatedCode, stringArrayStorageRegExp);
});
it('Match #2: should keep identifier name for existing variable declaration', () => {
assert.match(obfuscatedCode, lastVariableDeclarationIdentifierNameRegExp1);
it('Should keep identifier name for existing variable declaration #1', () => {
assert.notEqual(stringArrayName, variableDeclarationIdentifierName1);
});
it('Match #3: should keep identifier name for existing variable declaration', () => {
assert.match(obfuscatedCode, lastVariableDeclarationIdentifierNameRegExp2);
it('Should keep identifier name for existing variable declaration #2', () => {
assert.notEqual(stringArrayName, variableDeclarationIdentifierName2);
});
});
});
@@ -91,11 +130,17 @@ describe('DictionaryIdentifierNamesGenerator', () => {
describe('Variant #2: should not generate same prefixed name for identifier in code as prefixed name of string array', function () {
this.timeout(10000);
const samplesCount: number = 20;
const samplesCount: number = 30;
describe('Variant #1: `renameGlobals` option is disabled', () => {
const stringArrayStorageRegExp: RegExp = /const ([abAB]{1,3}) *= *\['first', *'abc'];/;
const variableDeclarationIdentifierNameRegExp: RegExp = /const ([abAB]{1,3}){1,2} *= *[abAB]{1,3}\(0x0\);/;
const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(
['first', 'abc'],
{
name: '\\w*',
kind: 'const'
}
);
const variableDeclarationIdentifierNameRegExp: RegExp = /const (\w*) *= *\w*\(0x0\);/;
let isIdentifiersAreConflicted: boolean = false;
@@ -133,8 +178,14 @@ describe('DictionaryIdentifierNamesGenerator', () => {
});
describe('Variant #2: `renameGlobals` option is enabled', () => {
const stringArrayStorageRegExp: RegExp = /const ([abAB]{1,3}) *= *\['first', *'abc'];/;
const variableDeclarationIdentifierNameRegExp: RegExp = /const ([abAB]{1,3}){1,2} *= *[abAB]{1,3}\(0x0\);/;
const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(
['first', 'abc'],
{
name: '\\w*',
kind: 'const'
}
);
const variableDeclarationIdentifierNameRegExp: RegExp = /const (\w*) *= *\w*\(0x0\);/;
let isIdentifiersAreConflicted: boolean = false;
@@ -1,5 +1,4 @@
function foo () {
const testA = 'first';
const testB = 'abc';
const testC = 'abc';
}
@@ -4,6 +4,7 @@ import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/id
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
@@ -12,7 +13,10 @@ describe('MangledIdentifierNamesGenerator', () => {
describe('generateWithPrefix', () => {
describe('Variant #1: should not generate same name for string array as existing name in code', () => {
describe('Variant #1: `renameGlobals` option is disabled', () => {
const stringArrayStorageRegExp: RegExp = /const ab *= *\['abc'];/;
const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(['abc'], {
kind: 'const',
name: 'ab'
});
const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const aa *= *ac\(0x0\);/;
let obfuscatedCode: string;
@@ -43,7 +47,10 @@ describe('MangledIdentifierNamesGenerator', () => {
});
describe('Variant #2: `renameGlobals` option is enabled', () => {
const stringArrayStorageRegExp: RegExp = /const ab *= *\['abc'];/;
const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(['abc'], {
kind: 'const',
name: 'ab'
});
const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const aB *= *ac\(0x0\);/;
let obfuscatedCode: string;
@@ -77,7 +84,10 @@ describe('MangledIdentifierNamesGenerator', () => {
describe('Variant #2: should not generate same prefixed name for identifier in code as prefixed name of string array', () => {
describe('Variant #1: `renameGlobals` option is disabled', () => {
const stringArrayStorageRegExp: RegExp = /const aa *= *\['abc', *'last'];/;
const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(['abc', 'last'], {
kind: 'const',
name: 'aa'
});
const functionDeclarationIdentifierNameRegExp: RegExp = /function foo *\(\) *{/;
const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ac *= *ab\(0x1\);/;
@@ -113,7 +123,10 @@ describe('MangledIdentifierNamesGenerator', () => {
});
describe('Variant #2: `renameGlobals` option is enabled', () => {
const stringArrayStorageRegExp: RegExp = /const aa *= *\['abc', *'last'];/;
const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(['abc', 'last'], {
kind: 'const',
name: 'aa'
});
const functionDeclarationIdentifierNameRegExp: RegExp = /function ac *\(\) *{/;
const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ad *= *ab\(0x1\);/;
@@ -221,7 +234,10 @@ describe('MangledIdentifierNamesGenerator', () => {
describe('Variant #2: Should generate different names set for different lexical scopes when string array is enabled', () => {
describe('Variant #1: `renameGlobals` option is disabled', () => {
const stringArrayIdentifierRegExp: RegExp = /var a *= *\['abc'];/;
const stringArrayIdentifierRegExp: RegExp = getStringArrayRegExp(['abc'], {
kind: 'var',
name: 'a'
});
const variableIdentifierRegExp: RegExp = /var foo *= *b\(0x0\);/;
const functionDeclarationRegExp1: RegExp = /function bar *\(c, *d\) *{}/;
const functionDeclarationRegExp2: RegExp = /function baz *\(c, *d\) *{}/;
@@ -260,7 +276,10 @@ describe('MangledIdentifierNamesGenerator', () => {
});
describe('Variant #2: `renameGlobals` option is enabled', () => {
const stringArrayIdentifierRegExp: RegExp = /var a *= *\['abc'];/;
const stringArrayIdentifierRegExp: RegExp = getStringArrayRegExp(['abc'], {
kind: 'var',
name: 'a'
});
const variableIdentifierRegExp: RegExp = /var c *= *b\(0x0\);/;
const functionDeclarationRegExp1: RegExp = /function d *\(f, *g\) *{}/;
const functionDeclarationRegExp2: RegExp = /function e *\(f, *g\) *{}/;
@@ -27,6 +27,7 @@ import { OptionsPreset } from '../../../src/enums/options/presets/OptionsPreset'
import { buildLargeCode } from '../../helpers/buildLargeCode';
import { getRegExpMatch } from '../../helpers/getRegExpMatch';
import { getStringArrayRegExp } from '../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../helpers/readFileAsString';
describe('JavaScriptObfuscator', () => {
@@ -444,7 +445,12 @@ describe('JavaScriptObfuscator', () => {
});
describe('Variant #4: with `stringArray`, `renameGlobals` and `identifiersPrefix` options', () => {
const stringArrayRegExp: RegExp = /^var foo_0x(\w){4} *= *\['abc'\];/;
const stringArrayRegExp: RegExp = new RegExp(
'function foo_0x([a-f0-9]){4} *\\(\\) *{' +
'var _0x([a-f0-9]){4,6} *= *\\[\'abc\'];.*' +
'return foo_0x([a-f0-9]){4}\\(\\); *' +
'}'
);
const stringArrayCallRegExp: RegExp = /var foo_0x(\w){4,6} *= *foo_0x(\w){4}\(0x0\);$/;
let obfuscatedCode: string;
@@ -536,7 +542,7 @@ describe('JavaScriptObfuscator', () => {
});
describe('latin literal variable value', () => {
const stringArrayLatinRegExp: RegExp = /^var _0x(\w){4} *= *\['abc'\];/;
const stringArrayLatinRegExp: RegExp = getStringArrayRegExp(['abc']);
const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\(0x0\);$/;
let obfuscatedCode: string;
@@ -564,7 +570,12 @@ describe('JavaScriptObfuscator', () => {
});
describe('cyrillic literal variable value', () => {
const stringArrayCyrillicRegExp: RegExp = /^var _0x(\w){4} *= *\['абц'\];/;
const stringArrayCyrillicRegExp: RegExp = new RegExp(
'function _0x(\\w){4} *\\(\\) *{' +
'var _0x([a-f0-9]){4,6} *= *\\[\'абц\'];.*' +
'return _0x(\\w){4}\\(\\); *' +
'}'
);
const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\(0x0\);$/;
let obfuscatedCode: string;
@@ -689,7 +700,12 @@ describe('JavaScriptObfuscator', () => {
const code1: string = readFileAsString(__dirname + '/fixtures/simple-input-cyrillic.js');
const code2: string = readFileAsString(__dirname + '/fixtures/simple-input-2.js');
const regExp: RegExp = /var (_0x(\w){4}) *= *\['.*'\];/;
const regExp: RegExp = new RegExp(
'function _0x(\\w){4} *\\(\\) *{' +
'var _0x([a-f0-9]){4,6} *= *\\[\'.*\'];.*' +
'return _0x(\\w){4}\\(\\); *' +
'}'
);
let match1: string,
match2: string;
@@ -2,6 +2,7 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
@@ -31,7 +32,7 @@ describe('ClassFieldTransformer', () => {
});
describe('Variant #2: `stringArray` option is enabled', () => {
const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['property', *'bar'\];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['property', 'bar']);
const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\(0x1\)\]\(\)\{\}/;
let obfuscatedCode: string;
@@ -103,7 +104,7 @@ describe('ClassFieldTransformer', () => {
});
describe('Variant #2: `stringArray` option is enabled', () => {
const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['property', *'constructor', *'bar'];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['property', 'constructor', 'bar']);
const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\(0x2\)\]\(\)\{\}/;
let obfuscatedCode: string;
@@ -203,7 +204,7 @@ describe('ClassFieldTransformer', () => {
});
describe('Variant #2: `stringArray` option is enabled', () => {
const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['property', *'bar'\];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['property', 'bar']);
const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\(0x0\)\] *= *0x1;/;
let obfuscatedCode: string;
@@ -254,7 +255,7 @@ describe('ClassFieldTransformer', () => {
});
describe('Variant #2: `stringArray` option is enabled', () => {
const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['property', *'constructor', *'bar'];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['property', 'constructor', 'bar']);
const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\(0x0\)\] *= *0x1;/;
let obfuscatedCode: string;
@@ -2,6 +2,7 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
@@ -30,7 +31,7 @@ describe('MemberExpressionTransformer', () => {
});
describe('`stringArray` option is enabled', () => {
const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log'\];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['log']);
const stringArrayCallRegExp: RegExp = /var test *= *console\[_0x([a-f0-9]){4}\(0x0\)\];/;
let obfuscatedCode: string;
@@ -60,7 +61,7 @@ describe('MemberExpressionTransformer', () => {
describe('transformation of member expression node with square brackets', () => {
describe('Variant #1: square brackets literal ', () => {
const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log'\];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['log']);
const stringArrayCallRegExp: RegExp = /var test *= *console\[_0x([a-f0-9]){4}\(0x0\)\];/;
let obfuscatedCode: string;
@@ -2,6 +2,7 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
@@ -11,7 +12,10 @@ describe('DirectivePlacementTransformer', function () {
describe('Variant #1: program scope', () => {
describe('Variant #1: directive at the top of program scope', () => {
const directiveRegExp: RegExp = /^'use strict'; *var _0x([a-f0-9]){4} *= *\['test'];/;
const directiveRegExp: RegExp = new RegExp(
'^\'use strict\';.*' +
getStringArrayRegExp(['test']).source
);
let obfuscatedCode: string;
@@ -34,9 +38,8 @@ describe('DirectivePlacementTransformer', function () {
});
describe('Variant #2: directive-like string literal at the middle of program scope', () => {
const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(['test', 'use\\\\x20strict']);
const directiveRegExp: RegExp = new RegExp(
'^var _0x([a-f0-9]){4} *= *\\[\'test\', *\'use\\\\x20strict\']; *' +
'.*?' +
'var test *= *_0x([a-f0-9]){4}\\(0x0\\);.*' +
'_0x([a-f0-9]){4}\\(0x1\\);'
);
@@ -56,7 +59,11 @@ describe('DirectivePlacementTransformer', function () {
).getObfuscatedCode();
});
it('should keep directive-like string literal at the middle of program scope', () => {
it('should add directive-like string literal to the string array', () => {
assert.match(obfuscatedCode, stringArrayStorageRegExp);
});
it('should add call to the directive-like string literal from the string array', () => {
assert.match(obfuscatedCode, directiveRegExp);
});
});
@@ -5,6 +5,7 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/N
import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
import { StringArrayIndexesType } from '../../../../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
@@ -57,7 +58,7 @@ describe('EscapeSequenceTransformer', function () {
});
describe('Variant #3: `unicodeEscapeSequence` and `stringArray` options are enabled', () => {
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['\\x74\\x65\\x73\\x74'\];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['\\\\x74\\\\x65\\\\x73\\\\x74']);
const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('\\x30\\x78\\x30'\);/;
let obfuscatedCode: string;
@@ -5,6 +5,7 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/N
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
describe('CommentsTransformer', () => {
const lineSeparatorEscaped: string = '\\r?\\n';
@@ -142,7 +143,10 @@ describe('CommentsTransformer', () => {
describe('Variant #7: simple comment with preserved words and additional code helper is inserted', () => {
describe('Variant #1: `stringArray` code helper', () => {
const regExp: RegExp = /^\/\/ *@license *test *comment *\n*var _0x([a-f0-9]){4} *= *\['abc'];/;
const regExp: RegExp = new RegExp(
'^\\/\\/ *@license *test *comment *\\n*.*' +
getStringArrayRegExp(['abc']).source
);
let obfuscatedCode: string;
@@ -4,10 +4,11 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/N
import { StringArrayIndexesType } from '../../../../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType';
import { getRegExpMatch } from '../../../../helpers/getRegExpMatch';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
import { getRegExpMatch } from '../../../../helpers/getRegExpMatch';
describe('EvalCallExpressionTransformer', () => {
describe('Variant #1: identifier reference', () => {
@@ -95,7 +96,7 @@ describe('EvalCallExpressionTransformer', () => {
describe('Variant #4: string array calls wrapper call', () => {
describe('Variant #1: hexadecimal number indexes type', () => {
const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log', *'bar'];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['log', 'bar']);
const stringArrayCallsWrapperRegExp: RegExp = /eval *\('console\[_0x([a-f0-9]){4,6}\(0\)]\(_0x([a-f0-9]){4,6}\(1\)\);'\);/;
let obfuscatedCode: string;
@@ -126,7 +127,7 @@ describe('EvalCallExpressionTransformer', () => {
});
describe('Variant #1: hexadecimal numeric string indexes type', () => {
const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log', *'bar'];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['log', 'bar']);
const stringArrayCallsWrapperRegExp: RegExp = /eval *\('console\[_0x([a-f0-9]){4,6}\(\\'0x0\\'\)]\(_0x([a-f0-9]){4,6}\(\\'0x1\\'\)\);'\);/;
let obfuscatedCode: string;
@@ -4,13 +4,14 @@ import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscator
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes';
import { getStringArrayRegExp } from '../../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../../helpers/readFileAsString';
describe('BlackListObfuscatingGuard', () => {
describe('check', () => {
describe('`\'use strict\';` operator', () => {
const useStrictOperatorRegExp: RegExp = /'use *strict';/;
const stringArrayLatinRegExp: RegExp = /var _0x(\w){4} *= *\['abc'\];/;
const stringArrayLatinRegExp: RegExp = getStringArrayRegExp(['abc']);
const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\(0x0\);$/;
let obfuscatedCode: string;
@@ -10,9 +10,9 @@ describe('ConditionalCommentObfuscatingGuard', () => {
describe('check', () => {
describe('Variant #1: `disable` conditional comment', () => {
const disableConditionalCommentRegExp: RegExp = /\/\/ *javascript-obfuscator:disable/;
const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x1;/;
const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x1;/;
const ignoredVariableDeclarationRegExp: RegExp = /var bar *= *2;/;
const consoleLogRegExp: RegExp = /console.log\(_0x([a-f0-9]){4,6}\);/;
const consoleLogRegExp: RegExp = /console.log\(_0x([a-f0-9]){5,6}\);/;
let obfuscatedCode: string;
@@ -47,8 +47,8 @@ describe('ConditionalCommentObfuscatingGuard', () => {
describe('Variant #2: `disable` and `enable` conditional comments #1', () => {
const disableConditionalCommentRegExp: RegExp = /\/\/ *javascript-obfuscator:disable/;
const enableConditionalCommentRegExp: RegExp = /\/\/ *javascript-obfuscator:enable/;
const obfuscatedVariableDeclaration1RegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x1;/;
const obfuscatedVariableDeclaration2RegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x3;/;
const obfuscatedVariableDeclaration1RegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x1;/;
const obfuscatedVariableDeclaration2RegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x3;/;
const ignoredVariableDeclarationRegExp: RegExp = /var bar *= *2;/;
let obfuscatedCode: string;
@@ -87,7 +87,7 @@ describe('ConditionalCommentObfuscatingGuard', () => {
describe('Variant #3: `disable` and `enable` conditional comments #2', () => {
const ignoredVariableDeclarationRegExp: RegExp = /var foo *= *1;/;
const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x2;/;
const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x2;/;
let obfuscatedCode: string;
@@ -139,13 +139,13 @@ describe('ConditionalCommentObfuscatingGuard', () => {
});
describe('Variant #5: `disable` and `enable` conditional comments with dead code injection', () => {
const obfuscatedFunctionExpressionRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *function *\(_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}\) *{/g;
const obfuscatedFunctionExpressionRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *function *\(_0x([a-f0-9]){5,6}, *_0x([a-f0-9]){5,6}, *_0x([a-f0-9]){5,6}\) *{/g;
const expectedObfuscatedFunctionExpressionLength: number = 3;
const ignoredFunctionExpression1RegExp: RegExp = /var bar *= *function *\(a, *b, *c\) *{/;
const ignoredFunctionExpression2RegExp: RegExp = /var baz *= *function *\(a, *b, *c\) *{/;
const obfuscatedFunctionCallRegExp: RegExp = /_0x([a-f0-9]){4,6}\( *\);/g;
const obfuscatedFunctionCallRegExp: RegExp = /_0x([a-f0-9]){5,6}\( *\);/g;
const expectedObfuscatedFunctionCallsLength: number = 3;
const ignoredFunctionCall1RegExp: RegExp = /bar\( *\);/;
@@ -209,7 +209,7 @@ describe('ConditionalCommentObfuscatingGuard', () => {
});
describe('Variant #6: `disable` and `enable` conditional comments with control flow flattening', () => {
const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\['[a-zA-Z0-9]{1,5}'];/;
const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *_0x([a-f0-9]){5,6}\['[a-zA-Z0-9]{1,5}'];/;
const ignoredVariableDeclarationRegExp: RegExp = /var bar *= *'bar';/;
let obfuscatedCode: string;
@@ -2,6 +2,7 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { stubNodeTransformers } from '../../../../helpers/stubNodeTransformers';
@@ -11,7 +12,10 @@ import { ObjectPatternPropertiesTransformer } from '../../../../../src/node-tran
describe('VariablePreserveTransformer', () => {
describe('Variant #1: string array storage name conflicts with identifier name', () => {
describe('Variant #1: `renameGlobals` option is disabled', () => {
const stringArrayStorageNameRegExp: RegExp = /const b *= *\['abc'];/;
const stringArrayStorageNameRegExp: RegExp = getStringArrayRegExp(['abc'], {
kind: 'const',
name: 'b'
});
const identifierNameRegExp: RegExp = /const a *= *c\(0x0\);/;
let obfuscatedCode: string;
@@ -40,7 +44,10 @@ describe('VariablePreserveTransformer', () => {
});
describe('Variant #2: `renameGlobals` option is enabled', () => {
const stringArrayStorageNameRegExp: RegExp = /const b *= *\['abc'];/;
const stringArrayStorageNameRegExp: RegExp = getStringArrayRegExp(['abc'], {
kind: 'const',
name: 'b'
});
const identifierNameRegExp: RegExp = /const d *= *c\(0x0\);/;
let obfuscatedCode: string;
@@ -651,11 +651,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
'}';
const stringArrayScopeCallsWrapperRegExp1: RegExp = new RegExp(
'const a *= *\\[.*?];.*?' +
getStringArrayCallsWrapperMatch('f')
);
const stringArrayScopeCallsWrapperRegExp2: RegExp = new RegExp(
'const a *= *\\[.*?];.*?' +
'function test *\\( *\\) *{.*' +
`${getStringArrayCallsWrapperMatch('g')}.*?` +
'}'
@@ -723,11 +721,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
'}';
const stringArrayScopeCallsWrapperRegExp1: RegExp = new RegExp(
'const a *= *\\[.*?];.*?' +
getStringArrayCallsWrapperMatch('f')
);
const stringArrayScopeCallsWrapperRegExp2: RegExp = new RegExp(
'const a *= *\\[.*?];.*?' +
'function test *\\( *\\) *{.*' +
`${getStringArrayCallsWrapperMatch('g')}.*?` +
'}'
@@ -791,13 +787,11 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
describe('Variant #2: correct chained calls', () => {
const stringArrayScopeCallsWrapperRegExp1: RegExp = new RegExp(
'const a *= *\\[.*?];.*?' +
'function *f *\\(c, *d\\) *{' +
`return b\\([cd] *-(?: -)?${hexadecimalIndexMatch}, *[cd]\\);` +
'}.*'
);
const stringArrayScopeCallsWrapperRegExp2: RegExp = new RegExp(
'const a *= *\\[.*?];.*?' +
'function test *\\( *\\) *{.*' +
'function *g *\\(c, *d\\) *{' +
`return f\\(` +
@@ -863,7 +857,6 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
describe('Variant #3: no wrappers on a root scope', () => {
const stringArrayScopeCallsWrapperRegExp: RegExp = new RegExp(
'const a *= *\\[.*?];.*' +
'function test *\\( *\\) *{.*' +
'function *f*\\(c, *d\\) *{' +
`return b\\([cd] *-(?: -)?${hexadecimalIndexMatch}, *[cd]\\);` +
@@ -1088,13 +1081,11 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
.join(', *');
const stringArrayScopeCallsWrapperRegExp1: RegExp = new RegExp(
'const a *= *\\[.*?];.*?' +
'function *f *\\(c, *d, *e, *h, *i\\) *{' +
`return b\\([cdehi] *-(?: -)?${hexadecimalIndexMatch}, *[cdehi]\\);` +
'}.*'
);
const stringArrayScopeCallsWrapperRegExp2: RegExp = new RegExp(
'const a *= *\\[.*?];.*?' +
'function test *\\( *\\) *{.*' +
'function *g *\\(c, *d, *e, *h, *i\\) *{' +
`return f\\(` +
@@ -1169,13 +1160,11 @@ describe('StringArrayScopeCallsWrapperTransformer', function () {
.join(', *');
const stringArrayScopeCallsWrapperRegExp1: RegExp = new RegExp(
'const a *= *\\[.*?];.*?' +
'function *f *\\(c, *d, *e, *h, *i\\) *{' +
`return b\\([cdehi] *-(?: -)?${hexadecimalIndexMatch}, *[cdehi]\\);` +
'}.*'
);
const stringArrayScopeCallsWrapperRegExp2: RegExp = new RegExp(
'const a *= *\\[.*?];.*?' +
'function test *\\( *\\) *{.*' +
'function *g *\\(c, *d, *e, *h, *i\\) *{' +
`return f\\(` +
@@ -7,6 +7,7 @@ import { StringArrayWrappersType } from '../../../../../src/enums/node-transform
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { getRegExpMatch } from '../../../../helpers/getRegExpMatch';
import { swapLettersCase } from '../../../../helpers/swapLettersCase';
@@ -17,7 +18,7 @@ describe('StringArrayTransformer', function () {
this.timeout(120000);
describe('Variant #1: default behaviour', () => {
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['test']);
const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/;
let obfuscatedCode: string;
@@ -355,7 +356,7 @@ describe('StringArrayTransformer', function () {
});
describe('Variant #5: same literal node values', () => {
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['test']);
const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/;
let obfuscatedCode: string;
@@ -406,7 +407,12 @@ describe('StringArrayTransformer', function () {
});
describe('Variant #7: base64 encoding', () => {
const stringArrayRegExp: RegExp = new RegExp(`^var _0x([a-f0-9]){4} *= *\\['${swapLettersCase('dGVzdA')}'];`);
const stringArrayRegExp: RegExp = new RegExp(
'function _0x([a-f0-9]){4} *\\(\\) *{' +
`var _0x([a-f0-9]){4,6} *= *\\[\'${swapLettersCase('dGVzdA')}\'];.*` +
'return _0x([a-f0-9]){4}\\(\\); *' +
'}'
);
const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/;
let obfuscatedCode: string;
@@ -506,8 +512,8 @@ describe('StringArrayTransformer', function () {
const expectedMatchesChance: number = 0.5;
const expectedMatchesDelta: number = 0.15;
const noneEncodingRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/;
const base64EncodingRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['DgvZDa'\];/;
const noneEncodingRegExp: RegExp = getStringArrayRegExp(['test']);
const base64EncodingRegExp: RegExp = getStringArrayRegExp(['DgvZDa']);
let noneEncodingMatchesCount: number = 0;
let base64EncodingMatchesCount: number = 0;
@@ -1080,7 +1086,7 @@ describe('StringArrayTransformer', function () {
describe('Variant #16: object expression key literal', () => {
describe('Variant #1: base key literal', () => {
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['bar'];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['bar'])
const objectExpressionRegExp: RegExp = /var test *= *{'foo' *: *_0x([a-f0-9]){4}\(0x0\)};/;
let obfuscatedCode: string;
@@ -1108,7 +1114,7 @@ describe('StringArrayTransformer', function () {
});
describe('Variant #2: computed key literal', () => {
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['foo', *'bar'];/;
const stringArrayRegExp: RegExp = getStringArrayRegExp(['foo', 'bar'])
const objectExpressionRegExp: RegExp = /var test *= *{\[_0x([a-f0-9]){4}\(0x0\)] *: *_0x([a-f0-9]){4}\(0x1\)};/;
let obfuscatedCode: string;
@@ -2,6 +2,7 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
@@ -15,7 +16,7 @@ describe('StringArrayStorage', () => {
const delta: number = 0.1;
const expectedVariantProbability: number = 1;
const stringArrayVariantRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\[(?:'.*?', *)?'test'(?:, *'.*?')?];/g;
const stringArrayVariantRegExp: RegExp = /var.*= *\[(?:'.*?', *)?'test'(?:, *'.*?')?];.*/;
const literalNodeVariantRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x.\);/g;
let stringArrayVariantProbability: number,
@@ -74,8 +75,8 @@ describe('StringArrayStorage', () => {
const literalNodeVariantsCount: number = 1;
const stringArrayVariantRegExps: RegExp[] = [
/var _0x([a-f0-9]){4} *= *\['foo', *'bar', *'baz'(?:, *'.*?')+];/g,
/var _0x([a-f0-9]){4} *= *\[(?:'.*?', *)+'foo', *'bar', *'baz'];/g
/var.*= *\['foo', *'bar', *'baz'(?:, *'.*?')+];.*/,
/var.*= *\[(?:'.*?', *)+'foo', *'bar', *'baz'];.*/,
];
const literalNodeVariantRegExps: RegExp[] = [
new RegExp(
@@ -155,7 +156,7 @@ describe('StringArrayStorage', () => {
const delta: number = 0.1;
const expectedVariantProbability: number = 1;
const stringArrayVariantRegExp1: RegExp = /var _0x([a-f0-9]){4} *= *\['test'];/g;
const stringArrayVariantRegExp1: RegExp = getStringArrayRegExp(['test']);
const literalNodeVariant1RegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/g;
let stringArrayVariant1Probability: number,
@@ -212,12 +213,12 @@ describe('StringArrayStorage', () => {
const variantsCount: number = 6;
const stringArrayVariantRegExps: RegExp[] = [
/var _0x([a-f0-9]){4} *= *\['foo', *'bar', *'baz'];/g,
/var _0x([a-f0-9]){4} *= *\['foo', *'baz', *'bar'];/g,
/var _0x([a-f0-9]){4} *= *\['bar', *'foo', *'baz'];/g,
/var _0x([a-f0-9]){4} *= *\['bar', *'baz', *'foo'];/g,
/var _0x([a-f0-9]){4} *= *\['baz', *'foo', *'bar'];/g,
/var _0x([a-f0-9]){4} *= *\['baz', *'bar', *'foo'];/g
getStringArrayRegExp(['foo', 'bar', 'baz']),
getStringArrayRegExp(['foo', 'baz', 'bar']),
getStringArrayRegExp(['bar', 'foo', 'baz']),
getStringArrayRegExp(['bar', 'baz', 'foo']),
getStringArrayRegExp(['baz', 'foo', 'bar']),
getStringArrayRegExp(['baz', 'bar', 'foo'])
];
const literalNodeVariantRegExps: RegExp[] = [
+28
View File
@@ -0,0 +1,28 @@
const defaultOptions = {
name: '_0x([a-f0-9]){4}',
kind: 'var'
}
/**
* Returns string array RegExp
*
* @returns {RegExp}
*/
export function getStringArrayRegExp(
stringArrayItems: string[],
options: Partial<typeof defaultOptions> = {}
): RegExp {
const mergedOptions = {
...defaultOptions,
...options
};
const {name, kind} = mergedOptions;
return new RegExp(
`function (${name}) *\\(\\) *{` +
`${kind}.*= *\\[${stringArrayItems.map((item: string) => `\'${item}\'`).join(',')}];.*` +
`return ${name}\\(\\); *` +
'}'
);
}
+13
View File
@@ -0,0 +1,13 @@
import {minify} from 'terser';
/**
* Minimizes code
*
* @param {string} code
* @returns {string}
*/
export async function minimizeCode (code: string): Promise<string> {
const result = await minify(code);
return result.code ?? '';
}