Explorar o código

Random identifiers prefix generation

sanex3339 %!s(int64=7) %!d(string=hai) anos
pai
achega
6de55d27f3

+ 2 - 2
README.md

@@ -573,9 +573,9 @@ Available values:
 * `mangled`: short identifier names like `a`, `b`, `c`
 
 ### `identifiersPrefix`
-Type: `string` Default: ``
+Type: `string|boolean` Default: `false`
 
-Sets prefix for all generated identifiers.
+Sets prefix for all generated identifiers. If prefix sets to `true` - random prefix will generated. If prefix sets to `false` or empty string - prefix won't generated.
 
 Use this option when you want to obfuscate multiple files. This option helps to avoid conflicts between identifiers of these files. Prefix should be different for every file.
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
dist/index.js


+ 1 - 1
package.json

@@ -60,7 +60,7 @@
     "chai": "4.1.2",
     "coveralls": "3.0.0",
     "istanbul": "1.1.0-alpha.1",
-    "mocha": "4.1.0",
+    "mocha": "5.0.0",
     "pre-commit": "1.2.2",
     "rimraf": "2.6.2",
     "sinon": "4.1.6",

+ 4 - 2
src/cli/JavaScriptObfuscatorCLI.ts

@@ -18,6 +18,7 @@ import { DEFAULT_PRESET } from '../options/presets/Default';
 import { ArraySanitizer } from './sanitizers/ArraySanitizer';
 import { BooleanSanitizer } from './sanitizers/BooleanSanitizer';
 import { IdentifierNamesGeneratorSanitizer } from './sanitizers/IdentifierNamesGeneratorSanitizer';
+import { IdentifiersPrefixSanitizer } from './sanitizers/IdentifiersPrefixSanitizer';
 import { ObfuscationTargetSanitizer } from './sanitizers/ObfuscatingTargetSanitizer';
 import { SourceMapModeSanitizer } from './sanitizers/SourceMapModeSanitizer';
 import { StringArrayEncodingSanitizer } from './sanitizers/StringArrayEncodingSanitizer';
@@ -245,8 +246,9 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
                 IdentifierNamesGeneratorSanitizer
             )
             .option(
-                '--identifiers-prefix <string>',
+                '--identifiers-prefix <string|boolean>',
                 'Sets prefix for all generated identifiers.',
+                IdentifiersPrefixSanitizer
             )
             .option(
                 '--log <boolean>', 'Enables logging of the information to the console',
@@ -299,7 +301,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
                 BooleanSanitizer
             )
             .option(
-                '--string-array-encoding <boolean|string> [true, false, base64, rc4]',
+                '--string-array-encoding <string|boolean> [true, false, base64, rc4]',
                 'Encodes all strings in strings array using base64 or rc4 (this option can slow down your code speed',
                 StringArrayEncodingSanitizer
             )

+ 21 - 0
src/cli/sanitizers/IdentifiersPrefixSanitizer.ts

@@ -0,0 +1,21 @@
+import { TCLISanitizer } from '../../types/cli/TCLISanitizer';
+
+/**
+ * @param {string} value
+ * @returns {string | boolean}
+ * @constructor
+ */
+export const IdentifiersPrefixSanitizer: TCLISanitizer = (value: string): string | boolean => {
+    switch (value) {
+        case 'true':
+        case '1':
+            return true;
+
+        case 'false':
+        case '0':
+            return false;
+
+        default:
+            return value;
+    }
+};

+ 9 - 0
src/generators/identifier-names-generators/AbstractIdentifierNamesGenerator.ts

@@ -7,6 +7,11 @@ import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 
 @injectable()
 export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNamesGenerator {
+    /**
+     * @type {string}
+     */
+    protected readonly identifiersPrefix: string;
+
     /**
      * @type {IOptions}
      */
@@ -27,6 +32,10 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
     ) {
         this.randomGenerator = randomGenerator;
         this.options = options;
+
+        this.identifiersPrefix = this.options.identifiersPrefix === true
+            ? this.randomGenerator.getRandomString(3)
+            : this.options.identifiersPrefix || '';
     }
 
     /**

+ 1 - 1
src/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.ts

@@ -30,7 +30,7 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
      * @returns {string}
      */
     public generate (length: number): string {
-        const prefix: string = `${this.options.identifiersPrefix}_${Utils.hexadecimalPrefix}`;
+        const prefix: string = `${this.identifiersPrefix}_${Utils.hexadecimalPrefix}`;
         const rangeMinInteger: number = 10000;
         const rangeMaxInteger: number = 99999999;
         const randomInteger: number = this.randomGenerator.getRandomInteger(rangeMinInteger, rangeMaxInteger);

+ 1 - 1
src/interfaces/options/IOptions.d.ts

@@ -15,7 +15,7 @@ export interface IOptions {
     readonly disableConsoleOutput: boolean;
     readonly domainLock: string[];
     readonly identifierNamesGenerator: IdentifierNamesGenerator;
-    readonly identifiersPrefix: string;
+    readonly identifiersPrefix: string | boolean;
     readonly log: boolean;
     readonly renameGlobals: boolean;
     readonly reservedNames: string[];

+ 4 - 2
src/options/Options.ts

@@ -113,10 +113,12 @@ export class Options implements IOptions {
     public readonly identifierNamesGenerator: IdentifierNamesGenerator;
 
     /**
+     * We won't validate this field, because of missing support of multiple types validation in `class-validator`.
+     * Value of this field will transformed to the string in `OptionsNormalizer`
+     *
      * @type {string}
      */
-    @IsString()
-    public readonly identifiersPrefix: string;
+    public readonly identifiersPrefix: string | boolean;
 
     /**
      * @type {boolean}

+ 2 - 0
src/options/OptionsNormalizer.ts

@@ -9,6 +9,7 @@ import { ControlFlowFlatteningThresholdRule } from './normalizer-rules/ControlFl
 import { DeadCodeInjectionRule } from './normalizer-rules/DeadCodeInjectionRule';
 import { DeadCodeInjectionThresholdRule } from './normalizer-rules/DeadCodeInjectionThresholdRule';
 import { DomainLockRule } from './normalizer-rules/DomainLockRule';
+import { IdentifiersPrefixRule } from './normalizer-rules/IdentifiersPrefixRule';
 import { SelfDefendingRule } from './normalizer-rules/SelfDefendingRule';
 import { SourceMapBaseUrlRule } from './normalizer-rules/SourceMapBaseUrlRule';
 import { SourceMapFileNameRule } from './normalizer-rules/SourceMapFileNameRule';
@@ -26,6 +27,7 @@ export class OptionsNormalizer implements IOptionsNormalizer {
         DeadCodeInjectionRule,
         DeadCodeInjectionThresholdRule,
         DomainLockRule,
+        IdentifiersPrefixRule,
         SelfDefendingRule,
         SourceMapBaseUrlRule,
         SourceMapFileNameRule,

+ 26 - 0
src/options/normalizer-rules/IdentifiersPrefixRule.ts

@@ -0,0 +1,26 @@
+import { TOptionsNormalizerRule } from '../../types/options/TOptionsNormalizerRule';
+
+import { IOptions } from '../../interfaces/options/IOptions';
+
+/**
+ * @param {IOptions} options
+ * @returns {IOptions}
+ */
+export const IdentifiersPrefixRule: TOptionsNormalizerRule = (options: IOptions): IOptions => {
+    const { identifiersPrefix }: { identifiersPrefix: string | boolean } = options;
+    const isStringPrefix: boolean = !!identifiersPrefix && typeof identifiersPrefix === 'string';
+    const isRandomPrefix: boolean = identifiersPrefix === true;
+
+    if (isStringPrefix || isRandomPrefix) {
+        return options;
+    }
+
+    const normalizedIdentifiersPrefix: string | boolean = typeof identifiersPrefix === 'number'
+        ? String(identifiersPrefix)
+        : false;
+
+    return {
+        ...options,
+        identifiersPrefix: normalizedIdentifiersPrefix
+    };
+};

+ 1 - 1
src/options/presets/Default.ts

@@ -16,7 +16,7 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({
     disableConsoleOutput: false,
     domainLock: [],
     identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
-    identifiersPrefix: '',
+    identifiersPrefix: false,
     log: false,
     renameGlobals: false,
     reservedNames: [],

+ 1 - 1
src/options/presets/NoCustomNodes.ts

@@ -15,7 +15,7 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
     disableConsoleOutput: false,
     domainLock: [],
     identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
-    identifiersPrefix: '',
+    identifiersPrefix: false,
     log: false,
     renameGlobals: false,
     reservedNames: [],

+ 128 - 0
test/functional-tests/options/OptionsNormalizer.spec.ts

@@ -176,6 +176,134 @@ describe('OptionsNormalizer', () => {
             });
         });
 
+        describe('identifiersPrefixRule', () => {
+            describe('variant #1: string option value', () => {
+                before(() => {
+                    optionsPreset = getNormalizedOptions({
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: 'foo',
+                    });
+
+                    expectedOptionsPreset = {
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: 'foo',
+                    };
+                });
+
+                it('should normalize options preset', () => {
+                    assert.deepEqual(optionsPreset, expectedOptionsPreset);
+                });
+            });
+
+            describe('variant #2: empty string option value', () => {
+                before(() => {
+                    optionsPreset = getNormalizedOptions({
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: '',
+                    });
+
+                    expectedOptionsPreset = {
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: false,
+                    };
+                });
+
+                it('should normalize options preset', () => {
+                    assert.deepEqual(optionsPreset, expectedOptionsPreset);
+                });
+            });
+
+            describe('variant #3: option value is `true`', () => {
+                before(() => {
+                    optionsPreset = getNormalizedOptions({
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: true,
+                    });
+
+                    expectedOptionsPreset = {
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: true,
+                    };
+                });
+
+                it('should normalize options preset', () => {
+                    assert.deepEqual(optionsPreset, expectedOptionsPreset);
+                });
+            });
+
+            describe('variant #4: option value is `false`', () => {
+                before(() => {
+                    optionsPreset = getNormalizedOptions({
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: false,
+                    });
+
+                    expectedOptionsPreset = {
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: false,
+                    };
+                });
+
+                it('should normalize options preset', () => {
+                    assert.deepEqual(optionsPreset, expectedOptionsPreset);
+                });
+            });
+
+            describe('variant #5: option value is object', () => {
+                before(() => {
+                    optionsPreset = getNormalizedOptions({
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: <any>{},
+                    });
+
+                    expectedOptionsPreset = {
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: false,
+                    };
+                });
+
+                it('should normalize options preset', () => {
+                    assert.deepEqual(optionsPreset, expectedOptionsPreset);
+                });
+            });
+
+            describe('variant #6: option value is function', () => {
+                before(() => {
+                    optionsPreset = getNormalizedOptions({
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: <any>{},
+                    });
+
+                    expectedOptionsPreset = {
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: false,
+                    };
+                });
+
+                it('should normalize options preset', () => {
+                    assert.deepEqual(optionsPreset, expectedOptionsPreset);
+                });
+            });
+
+            describe('variant #7: option value is number', () => {
+                before(() => {
+                    optionsPreset = getNormalizedOptions({
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: <any>123,
+                    });
+
+                    expectedOptionsPreset = {
+                        ...DEFAULT_PRESET,
+                        identifiersPrefix: '123',
+                    };
+                });
+
+                it('should normalize options preset', () => {
+                    assert.deepEqual(optionsPreset, expectedOptionsPreset);
+                });
+            });
+        });
+
         describe('selfDefendingRule', () => {
             before(() => {
                 optionsPreset = getNormalizedOptions({

+ 1 - 0
test/index.spec.ts

@@ -9,6 +9,7 @@ import './unit-tests/analyzers/stack-trace-analyzer/StackTraceAnalyzer.spec';
 import './unit-tests/cli/sanitizers/ArraySanitizer.spec';
 import './unit-tests/cli/sanitizers/BooleanSanitizer.spec';
 import './unit-tests/cli/sanitizers/IdentifierNamesGeneratorSanitizer.spec';
+import './unit-tests/cli/sanitizers/IdentifiersPrefixSanitizer.spec';
 import './unit-tests/cli/sanitizers/ObfuscationTargetSanitizer.spec';
 import './unit-tests/cli/sanitizers/SourceMapModeSanitizer.spec';
 import './unit-tests/cli/sanitizers/StringArrayEncodingSanitizer.spec';

+ 82 - 0
test/unit-tests/cli/sanitizers/IdentifiersPrefixSanitizer.spec.ts

@@ -0,0 +1,82 @@
+import { assert } from 'chai';
+
+import { IdentifiersPrefixSanitizer } from '../../../../src/cli/sanitizers/IdentifiersPrefixSanitizer';
+
+describe('IdentifiersPrefixSanitizer', () => {
+    describe('IdentifiersPrefixSanitizer: TCLISanitizer = (value: string): string | boolean', () => {
+        describe('variant #1: identifiers prefix `true`', () => {
+            const inputValue: string = 'true';
+            const expectedValue: boolean = true;
+
+            let value: boolean | string;
+
+            before(() => {
+                value = IdentifiersPrefixSanitizer(inputValue);
+            });
+
+            it('should sanitize value', () => {
+                assert.equal(value, expectedValue);
+            });
+        });
+
+        describe('variant #2: identifiers prefix `1`', () => {
+            const inputValue: string = '1';
+            const expectedValue: boolean = true;
+
+            let value: boolean | string;
+
+            before(() => {
+                value = IdentifiersPrefixSanitizer(inputValue);
+            });
+
+            it('should sanitize value', () => {
+                assert.equal(value, expectedValue);
+            });
+        });
+
+        describe('variant #3: identifiers prefix `false`', () => {
+            const inputValue: string = 'false';
+            const expectedValue: boolean = false;
+
+            let value: boolean | string;
+
+            before(() => {
+                value = IdentifiersPrefixSanitizer(inputValue);
+            });
+
+            it('should sanitize value', () => {
+                assert.equal(value, expectedValue);
+            });
+        });
+
+        describe('variant #4: identifiers prefix `0`', () => {
+            const inputValue: string = '0';
+            const expectedValue: boolean = false;
+
+            let value: boolean | string;
+
+            before(() => {
+                value = IdentifiersPrefixSanitizer(inputValue);
+            });
+
+            it('should sanitize value', () => {
+                assert.equal(value, expectedValue);
+            });
+        });
+
+        describe('variant #5: string identifiers prefix', () => {
+            const inputValue: string = 'foo';
+            const expectedValue: string = 'foo';
+
+            let value: boolean | string;
+
+            before(() => {
+                value = IdentifiersPrefixSanitizer(inputValue);
+            });
+
+            it('should sanitize value', () => {
+                assert.equal(value, expectedValue);
+            });
+        });
+    });
+});

+ 31 - 10
test/unit-tests/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.spec.ts

@@ -52,9 +52,10 @@ describe('HexadecimalIdentifierNamesGenerator', () => {
         });
 
         describe('Hexadecimal name with prefix', () => {
+            const regExp: RegExp = /^foo_0x(\w){4,6}$/;
+
             let identifierNamesGenerator: IIdentifierNamesGenerator,
-                hexadecimalIdentifierName: string,
-                regExp: RegExp;
+                hexadecimalIdentifierName: string;
 
             before(() => {
                 const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
@@ -65,19 +66,39 @@ describe('HexadecimalIdentifierNamesGenerator', () => {
                 identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
                     ServiceIdentifiers.IIdentifierNamesGenerator,
                     IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
-                )
+                );
+
+                hexadecimalIdentifierName = identifierNamesGenerator.generate(6);
             });
 
-            describe('variant #1: hexadecimal name with prefix', () => {
-                before(() => {
-                    hexadecimalIdentifierName = identifierNamesGenerator.generate(6);
-                    regExp = /^foo_0x(\w){4,6}$/;
+            it('should return hexadecimal name with prefix', () => {
+                assert.match(hexadecimalIdentifierName, regExp);
+            })
+        });
+
+        describe('Hexadecimal name with random prefix', () => {
+            const regExp: RegExp = /^(\w){3}_0x(\w){4,6}$/;
+
+            let identifierNamesGenerator: IIdentifierNamesGenerator,
+                hexadecimalIdentifierName: string;
+
+            before(() => {
+                const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
+
+                inversifyContainerFacade.load('', {
+                    identifiersPrefix: true
                 });
+                identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
+                    ServiceIdentifiers.IIdentifierNamesGenerator,
+                    IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
+                );
 
-                it('should return hexadecimal name', () => {
-                    assert.match(hexadecimalIdentifierName, regExp);
-                })
+                hexadecimalIdentifierName = identifierNamesGenerator.generate(6);
             });
+
+            it('should return hexadecimal name with prefix', () => {
+                assert.match(hexadecimalIdentifierName, regExp);
+            })
         });
     });
 });

+ 55 - 2
test/unit-tests/generators/identifier-names-generators/MangledlIdentifierNamesGenerator.spec.ts

@@ -134,7 +134,7 @@ describe('MangledIdentifierNamesGenerator', () => {
             let identifierNamesGenerator: IIdentifierNamesGenerator,
                 mangledIdentifierName: string;
 
-            beforeEach(() => {
+            before(() => {
                 const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
 
                 inversifyContainerFacade.load('', {
@@ -153,10 +153,63 @@ describe('MangledIdentifierNamesGenerator', () => {
                     mangledIdentifierName = identifierNamesGenerator.generate(4);
                 });
 
-                it('should return mangled name', () => {
+                it('should return mangled name with prefix', () => {
+                    assert.equal(mangledIdentifierName, expectedMangledIdentifierName);
+                });
+            });
+
+            describe('variant #2: second mangled name', () => {
+                const expectedMangledIdentifierName: string = 'foo_b';
+
+                beforeEach(() => {
+                    mangledIdentifierName = identifierNamesGenerator.generate(4);
+                });
+
+                it('should return mangled name with prefix', () => {
                     assert.equal(mangledIdentifierName, expectedMangledIdentifierName);
                 });
             });
         });
+
+        describe('Mangled name with random prefix', () => {
+            let identifierNamesGenerator: IIdentifierNamesGenerator,
+                mangledIdentifierName: string;
+
+            before(() => {
+                const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
+
+                inversifyContainerFacade.load('', {
+                    identifiersPrefix: true
+                });
+                identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
+                    ServiceIdentifiers.IIdentifierNamesGenerator,
+                    IdentifierNamesGenerator.MangledIdentifierNamesGenerator
+                );
+            });
+
+            describe('variant #1: initial mangled name', () => {
+                const expectedMangledIdentifierNameRegExp: RegExp = /(?:\w){3}_a/;
+
+                beforeEach(() => {
+                    mangledIdentifierName = identifierNamesGenerator.generate(4);
+                });
+
+                it('should return mangled name with prefix', () => {
+                    assert.match(mangledIdentifierName, expectedMangledIdentifierNameRegExp);
+                });
+            });
+
+            describe('variant #2: second mangled name', () => {
+                const expectedMangledIdentifierNameRegExp: RegExp = /(?:\w){3}_b/;
+
+                beforeEach(() => {
+                    mangledIdentifierName = identifierNamesGenerator.generate(4);
+                });
+
+                it('should return mangled name with prefix', () => {
+                    assert.match(mangledIdentifierName, expectedMangledIdentifierNameRegExp);
+                });
+            });
+        });
     });
 });

+ 6 - 6
yarn.lock

@@ -2,9 +2,9 @@
 # yarn lockfile v1
 
 
-"@types/[email protected].0":
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.0.tgz#d9008fa4c06f6801f93396d121f0227cd4244ac6"
+"@types/[email protected].1":
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.1.tgz#15f1257fab17b7acb9c413f9f88d3d87f834d11e"
 
 "@types/[email protected]":
   version "0.7.36"
@@ -2566,9 +2566,9 @@ [email protected], [email protected], "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
   dependencies:
     minimist "0.0.8"
 
-mocha@4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794"
+mocha@5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.0.tgz#cccac988b0bc5477119cba0e43de7af6d6ad8f4e"
   dependencies:
     browser-stdout "1.3.0"
     commander "2.11.0"

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio