mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Merge pull request #810 from javascript-obfuscator/string-array-index-shift-option
New option: `stringArrayIndexShift`
This commit is contained in:
@@ -1,5 +1,9 @@
|
||||
Change Log
|
||||
|
||||
v2.9.0
|
||||
---
|
||||
* New option: `stringArrayIndexShift` enables additional index shift for all string array calls
|
||||
|
||||
v2.8.1
|
||||
---
|
||||
* Fixed incorrect rename of the identifiers of the added helpers in some rare cases. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/804
|
||||
|
||||
@@ -365,6 +365,7 @@ Following options are available for the JS Obfuscator:
|
||||
splitStringsChunkLength: 10,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [],
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayWrappersCount: 1,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersType: 'variable',
|
||||
@@ -418,6 +419,7 @@ Following options are available for the JS Obfuscator:
|
||||
--split-strings-chunk-length <number>
|
||||
--string-array <boolean>
|
||||
--string-array-encoding '<list>' (comma separated) [none, base64, rc4]
|
||||
--string-array-index-shift <boolean>
|
||||
--string-array-wrappers-count <number>
|
||||
--string-array-wrappers-chained-calls <boolean>
|
||||
--string-array-wrappers-type <string> [variable, function]
|
||||
@@ -987,6 +989,13 @@ stringArrayEncoding: [
|
||||
]
|
||||
```
|
||||
|
||||
### `stringArrayIndexShift`
|
||||
Type: `boolean` Default: `true`
|
||||
|
||||
##### :warning: `stringArray` option must be enabled
|
||||
|
||||
Enables additional index shift for all string array calls
|
||||
|
||||
### `stringArrayWrappersCount`
|
||||
Type: `number` Default: `1`
|
||||
|
||||
@@ -1236,6 +1245,7 @@ Performance will 50-100% slower than without obfuscation
|
||||
splitStringsChunkLength: 5,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: ['rc4'],
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayWrappersCount: 5,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersType: 'function',
|
||||
@@ -1271,6 +1281,7 @@ Performance will 30-35% slower than without obfuscation
|
||||
splitStringsChunkLength: 10,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: ['base64'],
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayWrappersCount: 2,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersType: 'variable',
|
||||
@@ -1303,6 +1314,7 @@ Performance will slightly slower than without obfuscation
|
||||
splitStrings: false,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [],
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayWrappersCount: 1,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersType: 'variable',
|
||||
@@ -1332,6 +1344,7 @@ Performance will slightly slower than without obfuscation
|
||||
splitStrings: false,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [],
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayWrappersCount: 1,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersType: 'variable',
|
||||
|
||||
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
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+3
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "javascript-obfuscator",
|
||||
"version": "2.8.1",
|
||||
"version": "2.9.0",
|
||||
"description": "JavaScript obfuscator",
|
||||
"keywords": [
|
||||
"obfuscator",
|
||||
@@ -56,7 +56,7 @@
|
||||
"@types/js-string-escape": "1.0.0",
|
||||
"@types/md5": "2.2.1",
|
||||
"@types/mkdirp": "1.0.1",
|
||||
"@types/mocha": "8.0.3",
|
||||
"@types/mocha": "8.0.4",
|
||||
"@types/multimatch": "4.0.0",
|
||||
"@types/node": "14.14.7",
|
||||
"@types/rimraf": "3.0.0",
|
||||
@@ -71,7 +71,7 @@
|
||||
"cross-env": "7.0.2",
|
||||
"eslint": "7.13.0",
|
||||
"eslint-plugin-import": "2.22.1",
|
||||
"eslint-plugin-jsdoc": "30.7.7",
|
||||
"eslint-plugin-jsdoc": "30.7.8",
|
||||
"eslint-plugin-no-null": "1.0.2",
|
||||
"eslint-plugin-prefer-arrow": "1.2.2",
|
||||
"eslint-plugin-unicorn": "23.0.0",
|
||||
|
||||
@@ -350,6 +350,11 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
|
||||
`Default: ${StringArrayEncoding.None}`,
|
||||
ArraySanitizer
|
||||
)
|
||||
.option(
|
||||
'--string-array-index-shift <boolean>',
|
||||
'Enables additional index shift for all string array calls',
|
||||
BooleanSanitizer
|
||||
)
|
||||
.option(
|
||||
'--string-array-wrappers-count <number>',
|
||||
'Sets the count of wrappers for the string array inside each root or function scope',
|
||||
|
||||
@@ -20,6 +20,12 @@ import { NodeUtils } from '../../node/NodeUtils';
|
||||
|
||||
@injectable()
|
||||
export class StringArrayCallsWrapperCodeHelper extends AbstractCustomCodeHelper {
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
@initializable()
|
||||
protected indexShiftAmount!: number;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
@@ -68,13 +74,16 @@ export class StringArrayCallsWrapperCodeHelper extends AbstractCustomCodeHelper
|
||||
/**
|
||||
* @param {string} stringArrayName
|
||||
* @param {string} stringArrayCallsWrapperName
|
||||
* @param {number} indexShiftAmount
|
||||
*/
|
||||
public initialize (
|
||||
stringArrayName: string,
|
||||
stringArrayCallsWrapperName: string
|
||||
stringArrayCallsWrapperName: string,
|
||||
indexShiftAmount: number
|
||||
): void {
|
||||
this.stringArrayName = stringArrayName;
|
||||
this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
|
||||
this.indexShiftAmount = indexShiftAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,7 +106,8 @@ export class StringArrayCallsWrapperCodeHelper extends AbstractCustomCodeHelper
|
||||
this.customCodeHelperFormatter.formatTemplate(StringArrayCallsWrapperTemplate(), {
|
||||
decodeCodeHelperTemplate,
|
||||
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
|
||||
stringArrayName: this.stringArrayName
|
||||
stringArrayName: this.stringArrayName,
|
||||
indexShiftAmount: this.indexShiftAmount
|
||||
}),
|
||||
{
|
||||
reservedNames: preservedNames
|
||||
|
||||
@@ -142,7 +142,8 @@ export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup {
|
||||
|
||||
stringArrayCallsWrapperCodeHelper.initialize(
|
||||
stringArrayName,
|
||||
stringArrayCallsWrapperName
|
||||
stringArrayCallsWrapperName,
|
||||
this.stringArrayStorage.getIndexShiftAmount()
|
||||
);
|
||||
|
||||
this.customCodeHelpers.set(stringArrayCallsWrapperCodeHelperName, stringArrayCallsWrapperCodeHelper);
|
||||
@@ -151,9 +152,11 @@ export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup {
|
||||
// stringArrayRotateFunction helper initialize
|
||||
const stringArrayRotateFunctionCodeHelper: ICustomCodeHelper<TInitialData<StringArrayRotateFunctionCodeHelper>> =
|
||||
this.customCodeHelperFactory(CustomCodeHelper.StringArrayRotateFunction);
|
||||
const stringArrayRotationAmount: number = this.stringArrayStorage.getRotationAmount();
|
||||
|
||||
stringArrayRotateFunctionCodeHelper.initialize(stringArrayName, stringArrayRotationAmount);
|
||||
stringArrayRotateFunctionCodeHelper.initialize(
|
||||
stringArrayName,
|
||||
this.stringArrayStorage.getRotationAmount()
|
||||
);
|
||||
|
||||
if (this.options.rotateStringArray) {
|
||||
this.customCodeHelpers.set(CustomCodeHelper.StringArrayRotateFunction, stringArrayRotateFunctionCodeHelper);
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
export function StringArrayCallsWrapperTemplate (): string {
|
||||
return `
|
||||
const {stringArrayCallsWrapperName} = function (index, key) {
|
||||
index = index - 0;
|
||||
index = index - {indexShiftAmount};
|
||||
|
||||
let value = {stringArrayName}[index];
|
||||
|
||||
|
||||
@@ -30,6 +30,12 @@ export class StringArrayCallNode extends AbstractStringArrayCallNode {
|
||||
@initializable()
|
||||
private index!: number;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
@initializable()
|
||||
private indexShiftAmount!: number;
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
@@ -60,15 +66,18 @@ export class StringArrayCallNode extends AbstractStringArrayCallNode {
|
||||
/**
|
||||
* @param {string} stringArrayCallsWrapperName
|
||||
* @param {number} index
|
||||
* @param {number} indexShiftAmount
|
||||
* @param {string | null} decodeKey
|
||||
*/
|
||||
public initialize (
|
||||
stringArrayCallsWrapperName: string,
|
||||
index: number,
|
||||
indexShiftAmount: number,
|
||||
decodeKey: string | null
|
||||
): void {
|
||||
this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
|
||||
this.index = index;
|
||||
this.indexShiftAmount = indexShiftAmount;
|
||||
this.decodeKey = decodeKey;
|
||||
}
|
||||
|
||||
@@ -77,7 +86,7 @@ export class StringArrayCallNode extends AbstractStringArrayCallNode {
|
||||
*/
|
||||
protected getNodeStructure (): TStatement[] {
|
||||
const callExpressionArgs: ESTree.Expression[] = [
|
||||
this.getHexadecimalNode(this.index)
|
||||
this.getHexadecimalNode(this.indexShiftAmount + this.index)
|
||||
];
|
||||
|
||||
if (this.decodeKey) {
|
||||
|
||||
@@ -43,6 +43,7 @@ export interface IOptions {
|
||||
readonly splitStringsChunkLength: number;
|
||||
readonly stringArray: boolean;
|
||||
readonly stringArrayEncoding: TStringArrayEncoding[];
|
||||
readonly stringArrayIndexShift: boolean;
|
||||
readonly stringArrayWrappersChainedCalls: boolean;
|
||||
readonly stringArrayWrappersCount: number;
|
||||
readonly stringArrayWrappersType: TStringArrayWrappersType;
|
||||
|
||||
@@ -4,6 +4,11 @@ import { IMapStorage } from '../IMapStorage';
|
||||
import { IStringArrayStorageItemData } from './IStringArrayStorageItem';
|
||||
|
||||
export interface IStringArrayStorage extends IMapStorage <string, IStringArrayStorageItemData> {
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
getIndexShiftAmount (): number;
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
|
||||
@@ -204,16 +204,21 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
|
||||
|
||||
/**
|
||||
* @param {IStringArrayStorageItemData} stringArrayStorageItemData
|
||||
* @returns {Node}
|
||||
* @returns {Expression}
|
||||
*/
|
||||
private getStringArrayCallNode (stringArrayStorageItemData: IStringArrayStorageItemData): ESTree.Node {
|
||||
private getStringArrayCallNode (stringArrayStorageItemData: IStringArrayStorageItemData): ESTree.Expression {
|
||||
const [stringArrayCallsWrapperName, index] = this.getStringArrayCallsWrapperData(stringArrayStorageItemData);
|
||||
const {decodeKey } = stringArrayStorageItemData;
|
||||
|
||||
const stringArrayCallCustomNode: ICustomNode<TInitialData<StringArrayCallNode>> =
|
||||
this.stringArrayTransformerCustomNodeFactory(StringArrayCustomNode.StringArrayCallNode);
|
||||
|
||||
stringArrayCallCustomNode.initialize(stringArrayCallsWrapperName, index, decodeKey);
|
||||
stringArrayCallCustomNode.initialize(
|
||||
stringArrayCallsWrapperName,
|
||||
index,
|
||||
this.stringArrayStorage.getIndexShiftAmount(),
|
||||
decodeKey
|
||||
);
|
||||
|
||||
const statementNode: TStatement = stringArrayCallCustomNode.getNode()[0];
|
||||
|
||||
|
||||
@@ -314,6 +314,12 @@ export class Options implements IOptions {
|
||||
@IsIn([StringArrayEncoding.None, StringArrayEncoding.Base64, StringArrayEncoding.Rc4], { each: true })
|
||||
public readonly stringArrayEncoding!: TStringArrayEncoding[];
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
@IsBoolean()
|
||||
public readonly stringArrayIndexShift!: boolean;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,7 @@ export const StringArrayRule: TOptionsNormalizerRule = (options: IOptions): IOpt
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None
|
||||
],
|
||||
stringArrayIndexShift: false,
|
||||
stringArrayWrappersChainedCalls: false,
|
||||
stringArrayWrappersCount: 0,
|
||||
stringArrayThreshold: 0
|
||||
|
||||
@@ -47,6 +47,7 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None
|
||||
],
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 1,
|
||||
stringArrayWrappersType: StringArrayWrappersType.Variable,
|
||||
|
||||
@@ -44,6 +44,7 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None
|
||||
],
|
||||
stringArrayIndexShift: false,
|
||||
stringArrayWrappersChainedCalls: false,
|
||||
stringArrayWrappersCount: 0,
|
||||
stringArrayWrappersType: StringArrayWrappersType.Variable,
|
||||
|
||||
@@ -29,6 +29,16 @@ export class StringArrayStorage extends MapStorage <string, IStringArrayStorageI
|
||||
*/
|
||||
private static readonly maximumRotationAmount: number = 500;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
private static readonly minimumIndexShiftAmount: number = 100;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
private static readonly maximumIndexShiftAmount: number = 500;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
@@ -69,6 +79,11 @@ export class StringArrayStorage extends MapStorage <string, IStringArrayStorageI
|
||||
*/
|
||||
private readonly rc4EncodedValuesSourcesCache: Map<string, string[]> = new Map();
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
private indexShiftAmount: number = 0;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
@@ -118,6 +133,12 @@ export class StringArrayStorage extends MapStorage <string, IStringArrayStorageI
|
||||
public initialize (): void {
|
||||
super.initialize();
|
||||
|
||||
this.indexShiftAmount = this.options.stringArrayIndexShift
|
||||
? this.randomGenerator.getRandomInteger(
|
||||
StringArrayStorage.minimumIndexShiftAmount,
|
||||
StringArrayStorage.maximumIndexShiftAmount
|
||||
)
|
||||
: 0;
|
||||
this.rotationAmount = this.options.rotateStringArray
|
||||
? this.randomGenerator.getRandomInteger(
|
||||
StringArrayStorage.minimumRotationAmount,
|
||||
@@ -133,6 +154,13 @@ export class StringArrayStorage extends MapStorage <string, IStringArrayStorageI
|
||||
return this.getOrSetIfDoesNotExist(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
public getIndexShiftAmount (): number {
|
||||
return this.indexShiftAmount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
|
||||
+28
-10
@@ -7,20 +7,38 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
|
||||
|
||||
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
`
|
||||
const foo = {
|
||||
baz: 1
|
||||
};
|
||||
const bar = {
|
||||
baz: 2,
|
||||
bark: 3,
|
||||
...foo,
|
||||
};
|
||||
console.log(bar);
|
||||
const foo = 'foo';
|
||||
const bar = 'bar';
|
||||
|
||||
function test1 () {
|
||||
const baz = 'baz';
|
||||
|
||||
function test2() {
|
||||
const bark = 'bark';
|
||||
|
||||
console.log(bark);
|
||||
}
|
||||
|
||||
console.log(baz);
|
||||
|
||||
test2();
|
||||
}
|
||||
|
||||
console.log(foo, bar);
|
||||
|
||||
test1();
|
||||
`,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
compact: false,
|
||||
transformObjectKeys: true
|
||||
rotateStringArray: true,
|
||||
shuffleStringArray: true,
|
||||
stringArray: true,
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersType: 'function'
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
|
||||
+154
-52
@@ -42,84 +42,186 @@ describe('StringArrayCallsWrapperTemplate', () => {
|
||||
});
|
||||
|
||||
describe('Variant #1: `base64` encoding', () => {
|
||||
const index: string = '0x0';
|
||||
const expectedDecodedValue: string = 'test1';
|
||||
describe('Variant #1: index shift amount is `0`', () => {
|
||||
const index: string = '0x0';
|
||||
|
||||
let decodedValue: string;
|
||||
const indexShiftAmount: number = 0;
|
||||
|
||||
before(() => {
|
||||
const atobPolyfill = format(AtobTemplate(), {
|
||||
atobFunctionName
|
||||
});
|
||||
const atobDecodeTemplate: string = format(
|
||||
StringArrayBase64DecodeTemplate(randomGenerator),
|
||||
{
|
||||
atobPolyfill,
|
||||
atobFunctionName,
|
||||
selfDefendingCode: '',
|
||||
stringArrayCallsWrapperName
|
||||
}
|
||||
);
|
||||
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
|
||||
decodeCodeHelperTemplate: atobDecodeTemplate,
|
||||
stringArrayCallsWrapperName,
|
||||
stringArrayName
|
||||
});
|
||||
const expectedDecodedValue: string = 'test1';
|
||||
|
||||
decodedValue = Function(`
|
||||
let decodedValue: string;
|
||||
|
||||
before(() => {
|
||||
const atobPolyfill = format(AtobTemplate(), {
|
||||
atobFunctionName
|
||||
});
|
||||
const atobDecodeTemplate: string = format(
|
||||
StringArrayBase64DecodeTemplate(randomGenerator),
|
||||
{
|
||||
atobPolyfill,
|
||||
atobFunctionName,
|
||||
selfDefendingCode: '',
|
||||
stringArrayCallsWrapperName
|
||||
}
|
||||
);
|
||||
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
|
||||
decodeCodeHelperTemplate: atobDecodeTemplate,
|
||||
indexShiftAmount,
|
||||
stringArrayCallsWrapperName,
|
||||
stringArrayName
|
||||
});
|
||||
|
||||
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 atobPolyfill = format(AtobTemplate(), {
|
||||
atobFunctionName
|
||||
});
|
||||
const atobDecodeTemplate: string = format(
|
||||
StringArrayBase64DecodeTemplate(randomGenerator),
|
||||
{
|
||||
atobPolyfill,
|
||||
atobFunctionName,
|
||||
selfDefendingCode: '',
|
||||
stringArrayCallsWrapperName
|
||||
}
|
||||
);
|
||||
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
|
||||
decodeCodeHelperTemplate: atobDecodeTemplate,
|
||||
indexShiftAmount,
|
||||
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: `rc4` encoding', () => {
|
||||
const index: string = '0x0';
|
||||
const key: string = 'key';
|
||||
const expectedDecodedValue: string = 'test1';
|
||||
describe('Variant #1: index shift amount is `0`', () => {
|
||||
const index: string = '0x0';
|
||||
const key: string = 'key';
|
||||
|
||||
let decodedValue: string;
|
||||
const indexShiftAmount: number = 0;
|
||||
|
||||
before(() => {
|
||||
const atobPolyfill = format(AtobTemplate(), {
|
||||
atobFunctionName
|
||||
});
|
||||
const rc4Polyfill = format(Rc4Template(), {
|
||||
atobFunctionName
|
||||
});
|
||||
const rc4decodeCodeHelperTemplate: string = format(
|
||||
StringArrayRC4DecodeTemplate(randomGenerator),
|
||||
{
|
||||
atobPolyfill,
|
||||
rc4Polyfill,
|
||||
selfDefendingCode: '',
|
||||
stringArrayCallsWrapperName
|
||||
}
|
||||
);
|
||||
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
|
||||
decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
|
||||
stringArrayCallsWrapperName,
|
||||
stringArrayName
|
||||
});
|
||||
const expectedDecodedValue: string = 'test1';
|
||||
|
||||
decodedValue = Function(`
|
||||
let decodedValue: string;
|
||||
|
||||
before(() => {
|
||||
const atobPolyfill = format(AtobTemplate(), {
|
||||
atobFunctionName
|
||||
});
|
||||
const rc4Polyfill = format(Rc4Template(), {
|
||||
atobFunctionName
|
||||
});
|
||||
const rc4decodeCodeHelperTemplate: string = format(
|
||||
StringArrayRC4DecodeTemplate(randomGenerator),
|
||||
{
|
||||
atobPolyfill,
|
||||
rc4Polyfill,
|
||||
selfDefendingCode: '',
|
||||
stringArrayCallsWrapperName
|
||||
}
|
||||
);
|
||||
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
|
||||
decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
|
||||
indexShiftAmount,
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
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 atobPolyfill = format(AtobTemplate(), {
|
||||
atobFunctionName
|
||||
});
|
||||
const rc4Polyfill = format(Rc4Template(), {
|
||||
atobFunctionName
|
||||
});
|
||||
const rc4decodeCodeHelperTemplate: string = format(
|
||||
StringArrayRC4DecodeTemplate(randomGenerator),
|
||||
{
|
||||
atobPolyfill,
|
||||
rc4Polyfill,
|
||||
selfDefendingCode: '',
|
||||
stringArrayCallsWrapperName
|
||||
}
|
||||
);
|
||||
const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), {
|
||||
decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate,
|
||||
indexShiftAmount,
|
||||
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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -918,6 +918,7 @@ describe('JavaScriptObfuscator', () => {
|
||||
StringArrayEncoding.Base64,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 10,
|
||||
stringArrayWrappersType: StringArrayWrappersType.Function,
|
||||
|
||||
+210
-15
@@ -2,6 +2,7 @@ import { assert } from 'chai';
|
||||
|
||||
import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
|
||||
import { StringArrayEncoding } from '../../../../../src/enums/node-transformers/string-array-transformers/StringArrayEncoding';
|
||||
import { StringArrayWrappersType } from '../../../../../src/enums/node-transformers/string-array-transformers/StringArrayWrappersType';
|
||||
|
||||
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
|
||||
|
||||
@@ -63,7 +64,201 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: same literal node values', () => {
|
||||
describe('Variant #3: `stringArrayIndexShift` option is enabled', () => {
|
||||
const stringArrayIndexShiftRegExp: RegExp = /_0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4,6} *- *(0x[a-z0-9]{1,3});/;
|
||||
const stringArrayCallRegExp1: RegExp = /var _0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4}\('(0x[a-z0-9]{1,3})'\) *\+ *0x1;/;
|
||||
const stringArrayCallRegExp2: RegExp = /var _0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4}\('(0x[a-z0-9]{1,3})'\) *\+ *0x2;/;
|
||||
const stringArrayCallRegExp3: RegExp = /var _0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4}\('(0x[a-z0-9]{1,3})'\) *\+ *0x3;/;
|
||||
|
||||
const expectedEvaluationResult: string = 'foo1bar2baz3';
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
let stringArrayIndexShiftIndexValue: number;
|
||||
let stringArrayCallIndexValue1: number;
|
||||
let stringArrayCallIndexValue2: number;
|
||||
let stringArrayCallIndexValue3: number;
|
||||
|
||||
let evaluationResult: string;
|
||||
|
||||
describe('Variant #1: simple', () => {
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-index-shift.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayIndexShift: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
stringArrayIndexShiftIndexValue = parseInt(getRegExpMatch(obfuscatedCode, stringArrayIndexShiftRegExp), 16);
|
||||
stringArrayCallIndexValue1 = parseInt(getRegExpMatch(obfuscatedCode, stringArrayCallRegExp1), 16);
|
||||
stringArrayCallIndexValue2 = parseInt(getRegExpMatch(obfuscatedCode, stringArrayCallRegExp2), 16);
|
||||
stringArrayCallIndexValue3 = parseInt(getRegExpMatch(obfuscatedCode, stringArrayCallRegExp3), 16);
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should shift string array index in calls wrapper', () => {
|
||||
assert.match(obfuscatedCode, stringArrayIndexShiftRegExp);
|
||||
});
|
||||
|
||||
it('Match #1: should create string array call with shifted index', () => {
|
||||
assert.equal(stringArrayIndexShiftIndexValue, stringArrayCallIndexValue1);
|
||||
});
|
||||
|
||||
it('Match #2: should create string array call with shifted index', () => {
|
||||
assert.equal(stringArrayIndexShiftIndexValue, stringArrayCallIndexValue2 - 1);
|
||||
});
|
||||
|
||||
it('Match #3: should create string array call with shifted index', () => {
|
||||
assert.equal(stringArrayIndexShiftIndexValue, stringArrayCallIndexValue3 - 2);
|
||||
});
|
||||
|
||||
it('should correctly evaluate code', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `rotateStringArray` option is enabled', () => {
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-index-shift.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayIndexShift: true,
|
||||
rotateStringArray: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
stringArrayIndexShiftIndexValue = parseInt(getRegExpMatch(obfuscatedCode, stringArrayIndexShiftRegExp), 16);
|
||||
stringArrayCallIndexValue1 = parseInt(getRegExpMatch(obfuscatedCode, stringArrayCallRegExp1), 16);
|
||||
stringArrayCallIndexValue2 = parseInt(getRegExpMatch(obfuscatedCode, stringArrayCallRegExp2), 16);
|
||||
stringArrayCallIndexValue3 = parseInt(getRegExpMatch(obfuscatedCode, stringArrayCallRegExp3), 16);
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should shift string array index in calls wrapper', () => {
|
||||
assert.match(obfuscatedCode, stringArrayIndexShiftRegExp);
|
||||
});
|
||||
|
||||
it('Match #1: should create string array call with shifted index', () => {
|
||||
assert.equal(stringArrayIndexShiftIndexValue, stringArrayCallIndexValue1);
|
||||
});
|
||||
|
||||
it('Match #2: should create string array call with shifted index', () => {
|
||||
assert.equal(stringArrayIndexShiftIndexValue, stringArrayCallIndexValue2 - 1);
|
||||
});
|
||||
|
||||
it('Match #3: should create string array call with shifted index', () => {
|
||||
assert.equal(stringArrayIndexShiftIndexValue, stringArrayCallIndexValue3 - 2);
|
||||
});
|
||||
|
||||
it('should correctly evaluate code', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: `shuffleStringArray` option is enabled', () => {
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-index-shift.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayIndexShift: true,
|
||||
shuffleStringArray: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should shift string array index in calls wrapper', () => {
|
||||
assert.match(obfuscatedCode, stringArrayIndexShiftRegExp);
|
||||
});
|
||||
|
||||
it('should correctly evaluate code', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: `stringArrayWrappersCount` option is enabled and type is `function`', () => {
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-index-shift.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayWrappersCount: 1,
|
||||
stringArrayWrappersType: StringArrayWrappersType.Function
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should shift string array index in calls wrapper', () => {
|
||||
assert.match(obfuscatedCode, stringArrayIndexShiftRegExp);
|
||||
});
|
||||
|
||||
it('should correctly evaluate code', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #5: all string array options are enabled', () => {
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-index-shift.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
rotateStringArray: true,
|
||||
shuffleStringArray: true,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersType: 'function'
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should shift string array index in calls wrapper', () => {
|
||||
assert.match(obfuscatedCode, stringArrayIndexShiftRegExp);
|
||||
});
|
||||
|
||||
it('should correctly evaluate code', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: same literal node values', () => {
|
||||
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/;
|
||||
const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/;
|
||||
|
||||
@@ -91,7 +286,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: short literal node value', () => {
|
||||
describe('Variant #5: short literal node value', () => {
|
||||
const regExp: RegExp = /var test *= *'te';/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -114,7 +309,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #5: base64 encoding', () => {
|
||||
describe('Variant #6: base64 encoding', () => {
|
||||
const stringArrayRegExp: RegExp = new RegExp(`^var _0x([a-f0-9]){4} *= *\\['${swapLettersCase('dGVzdA==')}'];`);
|
||||
const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/;
|
||||
|
||||
@@ -143,7 +338,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #6: rc4 encoding', () => {
|
||||
describe('Variant #7: rc4 encoding', () => {
|
||||
describe('Variant #1: single string literal', () => {
|
||||
const regExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0', *'.{4}'\);/;
|
||||
|
||||
@@ -209,7 +404,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #7: none and base64 encoding', () => {
|
||||
describe('Variant #8: none and base64 encoding', () => {
|
||||
describe('Variant #1: string array values', () => {
|
||||
const samplesCount: number = 300;
|
||||
const expectedMatchesChance: number = 0.5;
|
||||
@@ -265,7 +460,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #8: none and rc4 encoding', () => {
|
||||
describe('Variant #9: none and rc4 encoding', () => {
|
||||
describe('Variant #1: string array calls wrapper call', () => {
|
||||
const samplesCount: number = 300;
|
||||
const expectedMatchesChance: number = 0.5;
|
||||
@@ -321,7 +516,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #9: base64 and rc4 encoding', () => {
|
||||
describe('Variant #10: base64 and rc4 encoding', () => {
|
||||
describe('Variant #1: single string literal', () => {
|
||||
const samplesCount: number = 300;
|
||||
const expectedMatchesChance: number = 0.5;
|
||||
@@ -377,7 +572,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #10: `stringArrayThreshold` option value', () => {
|
||||
describe('Variant #11: `stringArrayThreshold` option value', () => {
|
||||
const samples: number = 1000;
|
||||
const stringArrayThreshold: number = 0.5;
|
||||
const delta: number = 0.1;
|
||||
@@ -420,7 +615,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #11: string array calls wrapper name', () => {
|
||||
describe('Variant #12: string array calls wrapper name', () => {
|
||||
const regExp: RegExp = /console\[b\('0x0'\)]\('a'\);/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -444,7 +639,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #12: `reservedStrings` option is enabled', () => {
|
||||
describe('Variant #13: `reservedStrings` option is enabled', () => {
|
||||
describe('Variant #1: base `reservedStrings` values', () => {
|
||||
describe('Variant #1: single reserved string value', () => {
|
||||
const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
|
||||
@@ -566,7 +761,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #13: `forceTransformStrings` option is enabled', () => {
|
||||
describe('Variant #14: `forceTransformStrings` option is enabled', () => {
|
||||
describe('Variant #1: base `forceTransformStrings` values', () => {
|
||||
describe('Variant #1: single force transform string value', () => {
|
||||
const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
|
||||
@@ -787,7 +982,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #14: object expression key literal', () => {
|
||||
describe('Variant #15: 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'\)};/;
|
||||
@@ -845,7 +1040,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #15: import declaration source literal', () => {
|
||||
describe('Variant #16: import declaration source literal', () => {
|
||||
const importDeclarationRegExp: RegExp = /import *{ *bar *} *from *'foo';/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -868,7 +1063,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #16: export all declaration source literal', () => {
|
||||
describe('Variant #17: export all declaration source literal', () => {
|
||||
const exportAllDeclarationRegExp: RegExp = /export *\* *from *'foo';/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -891,7 +1086,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #17: export named declaration source literal', () => {
|
||||
describe('Variant #18: export named declaration source literal', () => {
|
||||
const exportNamedDeclarationRegExp: RegExp = /export *{ *bar *} *from *'foo';/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
function test () {
|
||||
var foo = 'foo' + 1;
|
||||
var bar = 'bar' + 2;
|
||||
var baz = 'baz' + 3;
|
||||
|
||||
return foo + bar + baz;
|
||||
}
|
||||
|
||||
test();
|
||||
@@ -544,6 +544,7 @@ describe('OptionsNormalizer', () => {
|
||||
shuffleStringArray: true,
|
||||
stringArray: false,
|
||||
stringArrayEncoding: [StringArrayEncoding.Rc4],
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 5,
|
||||
stringArrayThreshold: 0.5,
|
||||
@@ -555,6 +556,7 @@ describe('OptionsNormalizer', () => {
|
||||
shuffleStringArray: false,
|
||||
stringArray: false,
|
||||
stringArrayEncoding: [StringArrayEncoding.None],
|
||||
stringArrayIndexShift: false,
|
||||
stringArrayWrappersChainedCalls: false,
|
||||
stringArrayWrappersCount: 0,
|
||||
stringArrayThreshold: 0,
|
||||
|
||||
@@ -40,6 +40,7 @@ describe('JavaScriptObfuscator runtime eval', function () {
|
||||
StringArrayEncoding.Base64,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayIndexShift: true,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 5,
|
||||
stringArrayWrappersType: StringArrayWrappersType.Function,
|
||||
|
||||
+1
-1
@@ -434,7 +434,7 @@ describe('StringArrayStorageAnalyzer', () => {
|
||||
before(() => {
|
||||
stringArrayStorageAnalyzer = getStringArrayStorageAnalyzer({
|
||||
stringArrayThreshold: 0.5,
|
||||
seed: 1
|
||||
seed: 3
|
||||
});
|
||||
|
||||
const astTree: ESTree.Program = NodeFactory.programNode([
|
||||
|
||||
@@ -513,10 +513,10 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/mocha@8.0.3":
|
||||
version "8.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.0.3.tgz#51b21b6acb6d1b923bbdc7725c38f9f455166402"
|
||||
integrity sha512-vyxR57nv8NfcU0GZu8EUXZLTbCMupIUwy95LJ6lllN+JRPG25CwMHoB1q5xKh8YKhQnHYRAn4yW2yuHbf/5xgg==
|
||||
"@types/mocha@8.0.4":
|
||||
version "8.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-8.0.4.tgz#b840c2dce46bacf286e237bfb59a29e843399148"
|
||||
integrity sha512-M4BwiTJjHmLq6kjON7ZoI2JMlBvpY3BYSdiP6s/qCT3jb1s9/DeJF0JELpAxiVSIxXDzfNKe+r7yedMIoLbknQ==
|
||||
|
||||
"@types/multimatch@4.0.0":
|
||||
version "4.0.0"
|
||||
@@ -1813,10 +1813,10 @@ eslint-plugin-import@2.22.1:
|
||||
resolve "^1.17.0"
|
||||
tsconfig-paths "^3.9.0"
|
||||
|
||||
eslint-plugin-jsdoc@30.7.7:
|
||||
version "30.7.7"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.7.7.tgz#2af2c68e5adaf8a59fc3c72081a4b137098268bb"
|
||||
integrity sha512-DmVMJC2AbpYX7X1KhnVT1a9ex1AUvG+q9G8i6hzjp3cpjW8vmKQTUmZnRS0//W+7HvMqeb+eXPANdCOzGVVZBQ==
|
||||
eslint-plugin-jsdoc@30.7.8:
|
||||
version "30.7.8"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.7.8.tgz#4a678c25ddb2c5732163f0258bb1d05edf34f61c"
|
||||
integrity sha512-OWm2AYvXjCl7nRbpcw5xisfSVkpVAyp4lGqL9T+DeK4kaPm6ecnmTc/G5s1PtcRrwbaI8bIWGzwScqv5CdGyxA==
|
||||
dependencies:
|
||||
comment-parser "^0.7.6"
|
||||
debug "^4.2.0"
|
||||
|
||||
Reference in New Issue
Block a user