Переглянути джерело

Fixed tests. Added `inputFileName` option validation

sanex 3 роки тому
батько
коміт
4ab4406f5e

+ 1 - 0
CHANGELOG.md

@@ -3,6 +3,7 @@ Change Log
 v2.17.0
 v2.17.0
 ---
 ---
 * **New option**: `sourceMapSourcesMode` allows to control `sources` and `sourcesContent` fields of the source map
 * **New option**: `sourceMapSourcesMode` allows to control `sources` and `sourcesContent` fields of the source map
+* `inputFileName` option now required when using NodeJS API and `sourceMapSourcesMode` option has `sources` value`.
 * Fixed some cases with wrong source map file name generation when `sourceMapFileName` option is set
 * Fixed some cases with wrong source map file name generation when `sourceMapFileName` option is set
 
 
 v2.16.0
 v2.16.0

+ 2 - 1
README.md

@@ -842,6 +842,7 @@ Prevents obfuscation of `require` imports. Could be helpful in some cases when f
 Type: `string` Default: `''`
 Type: `string` Default: `''`
 
 
 Allows to set name of the input file with source code. This name will be used internally for source map generation.
 Allows to set name of the input file with source code. This name will be used internally for source map generation.
+Required when using NodeJS API and `sourceMapSourcesMode` option has `sources` value`.
 
 
 ### `log`
 ### `log`
 Type: `boolean` Default: `false`
 Type: `boolean` Default: `false`
@@ -1078,7 +1079,7 @@ Type: `string` Default: `sources-content`
 
 
 Allows to control `sources` and `sourcesContent` fields of the source map:
 Allows to control `sources` and `sourcesContent` fields of the source map:
 * `sources-content` - adds dummy `sources` field, adds `sourcesContent` field with the original source code;
 * `sources-content` - adds dummy `sources` field, adds `sourcesContent` field with the original source code;
-* `sources` - adds `sources` field with a valid source description, does not add `sourcesContent` field.
+* `sources` - adds `sources` field with a valid source description, does not add `sourcesContent` field. When using NodeJS API it's required to define `inputFileName` option that will be used as `sources` field value.
 
 
 ### `splitStrings`
 ### `splitStrings`
 Type: `boolean` Default: `false`
 Type: `boolean` Default: `false`

Різницю між файлами не показано, бо вона завелика
+ 0 - 0
dist/index.browser.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 0
dist/index.cli.js


Різницю між файлами не показано, бо вона завелика
+ 0 - 0
dist/index.js


+ 1 - 1
src/JavaScriptObfuscator.ts

@@ -259,7 +259,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
                         sourceContent: sourceCode
                         sourceContent: sourceCode
                     }
                     }
                     : {
                     : {
-                        sourceMap: this.options.inputFileName
+                        sourceMap: this.options.inputFileName || 'sourceMap'
                     }
                     }
             }
             }
         };
         };

+ 2 - 1
src/options/Options.ts

@@ -49,6 +49,7 @@ import { ValidationErrorsFormatter } from './ValidationErrorsFormatter';
 import { IsAllowedForObfuscationTargets } from './validators/IsAllowedForObfuscationTargets';
 import { IsAllowedForObfuscationTargets } from './validators/IsAllowedForObfuscationTargets';
 import { IsDomainLockRedirectUrl } from './validators/IsDomainLockRedirectUrl';
 import { IsDomainLockRedirectUrl } from './validators/IsDomainLockRedirectUrl';
 import { IsIdentifierNamesCache } from './validators/IsIdentifierNamesCache';
 import { IsIdentifierNamesCache } from './validators/IsIdentifierNamesCache';
+import { IsInputFileName } from './validators/IsInputFileName';
 
 
 @injectable()
 @injectable()
 export class Options implements IOptions {
 export class Options implements IOptions {
@@ -195,7 +196,7 @@ export class Options implements IOptions {
     /**
     /**
      * @type {string}
      * @type {string}
      */
      */
-    @IsString()
+    @IsInputFileName()
     public readonly inputFileName!: string;
     public readonly inputFileName!: string;
 
 
     /**
     /**

+ 18 - 0
src/options/validators/IsInputFileName.ts

@@ -0,0 +1,18 @@
+import { IsNotEmpty, IsString, ValidateIf } from 'class-validator';
+
+import { TInputOptions } from '../../types/options/TInputOptions';
+
+import { SourceMapSourcesMode } from '../../enums/source-map/SourceMapSourcesMode';
+
+/**
+ * @returns {PropertyDecorator}
+ */
+export const IsInputFileName = (): PropertyDecorator => {
+    return (target: any, key: string | symbol): void => {
+        IsString()(target, key);
+        ValidateIf(({sourceMapSourcesMode}: TInputOptions) => {
+            return sourceMapSourcesMode === SourceMapSourcesMode.Sources;
+        })(target, key);
+        IsNotEmpty()(target, key);
+    };
+};

+ 123 - 0
test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts

@@ -12,6 +12,7 @@ import { IObfuscationResult } from '../../../src/interfaces/source-code/IObfusca
 import { ISourceMap } from '../../../src/interfaces/source-code/ISourceMap';
 import { ISourceMap } from '../../../src/interfaces/source-code/ISourceMap';
 
 
 import { SourceMapMode } from '../../../src/enums/source-map/SourceMapMode';
 import { SourceMapMode } from '../../../src/enums/source-map/SourceMapMode';
+import { SourceMapSourcesMode } from '../../../src/enums/source-map/SourceMapSourcesMode';
 import { StringArrayEncoding } from '../../../src/enums/node-transformers/string-array-transformers/StringArrayEncoding';
 import { StringArrayEncoding } from '../../../src/enums/node-transformers/string-array-transformers/StringArrayEncoding';
 import { StringArrayIndexesType } from '../../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 import { StringArrayIndexesType } from '../../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType';
 import { StringArrayWrappersType } from '../../../src/enums/node-transformers/string-array-transformers/StringArrayWrappersType';
 import { StringArrayWrappersType } from '../../../src/enums/node-transformers/string-array-transformers/StringArrayWrappersType';
@@ -251,6 +252,128 @@ describe('JavaScriptObfuscator', () => {
                     assert.isNotOk(sourceMapMappings);
                     assert.isNotOk(sourceMapMappings);
                 });
                 });
             });
             });
+
+            describe('`sourceMapSourceMode` is set', () => {
+                describe('`sourcesContent` value', () => {
+                    let code: string,
+                        obfuscatedCode: string,
+                        sourceMap: ISourceMap,
+                        resolvedSources: string;
+
+                    beforeEach((done) => {
+                        code = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
+                        const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                sourceMap: true,
+                                sourceMapSourcesMode: SourceMapSourcesMode.SourcesContent
+                            }
+                        );
+
+                        obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                        sourceMap = JSON.parse(obfuscationResult.getSourceMap());
+                        resolveSources(sourceMap, '/', fs.readFile, (error, result) => {
+                            resolvedSources = typeof result.sourcesContent[0] === 'string'
+                                ? result.sourcesContent[0]
+                                : '';
+                            done();
+                        });
+                    });
+
+                    it('should return correct obfuscated code', () => {
+                        assert.isOk(obfuscatedCode);
+                    });
+
+                    it('should return correct source map mappings', () => {
+                        assert.isOk(sourceMap.mappings);
+                    });
+
+                    it('should define `sources` field for source map', () => {
+                        assert.property(sourceMap, 'sources');
+                    });
+
+                    it('should define `sourcesContent` field for source map', () => {
+                        assert.property(sourceMap, 'sourcesContent');
+                    });
+
+                    it('should define placeholder `sources` field for source map', () => {
+                        assert.deepEqual(sourceMap.sources, ['sourceMap']);
+                    });
+
+                    it('should define `sourcesContent` value with source code', () => {
+                        assert.deepEqual(sourceMap.sourcesContent[0], code);
+                    });
+
+                    it('should resolve correct sources from source map', () => {
+                        assert.equal(resolvedSources, code);
+                    });
+                });
+
+                describe('`sources` value', () => {
+                    describe('`inputFileName` option is set', () => {
+                        let code: string,
+                            obfuscatedCode: string,
+                            sourceMap: ISourceMap;
+
+                        beforeEach(() => {
+                            code = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
+                            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                                code,
+                                {
+                                    ...NO_ADDITIONAL_NODES_PRESET,
+                                    inputFileName: 'someFile.js',
+                                    sourceMap: true,
+                                    sourceMapSourcesMode: SourceMapSourcesMode.Sources
+                                }
+                            );
+
+                            obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                            sourceMap = JSON.parse(obfuscationResult.getSourceMap());
+                        });
+
+                        it('should return correct obfuscated code', () => {
+                            assert.isOk(obfuscatedCode);
+                        });
+
+                        it('should return correct source map mappings', () => {
+                            assert.isOk(sourceMap.mappings);
+                        });
+
+                        it('should define `sources` field for source map', () => {
+                            assert.property(sourceMap, 'sources');
+                        });
+
+                        it('should not define `sourcesContent` field for source map', () => {
+                            assert.notProperty(sourceMap, 'sourcesContent');
+                        });
+
+                        it('should define placeholder `sources` field for source map', () => {
+                            assert.deepEqual(sourceMap.sources, ['someFile.js']);
+                        });
+                    })
+
+                    describe('`inputFileName` option is not set', () => {
+                        let testFunc: () => IObfuscationResult;
+
+                        beforeEach(() => {
+                            const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
+                            testFunc = () => JavaScriptObfuscator.obfuscate(
+                                code,
+                                {
+                                    ...NO_ADDITIONAL_NODES_PRESET,
+                                    sourceMap: true,
+                                    sourceMapSourcesMode: SourceMapSourcesMode.Sources
+                                }
+                            );
+                        });
+
+                        it('should throw an error', () => {
+                            assert.throws(testFunc, Error);
+                        });
+                    });
+                });
+            });
         });
         });
 
 
         describe('variable inside global scope', () => {
         describe('variable inside global scope', () => {

+ 72 - 0
test/functional-tests/options/input-file-name/Validation.spec.ts

@@ -0,0 +1,72 @@
+import { assert } from 'chai';
+
+import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscatorFacade';
+
+import { NO_ADDITIONAL_NODES_PRESET } from '../../../../src/options/presets/NoCustomNodes';
+import { SourceMapSourcesMode } from '../../../../src/enums/source-map/SourceMapSourcesMode';
+
+describe('`inputFileName` validation', () => {
+    describe('IsInputFileName', () => {
+        describe('Variant #1: positive validation', () => {
+            describe('Variant #1: empty string when `sourceMapSourcesMode: \'sources-content\'', () => {
+                let testFunc: () => string;
+
+                beforeEach(() => {
+                    testFunc = () => JavaScriptObfuscator.obfuscate(
+                        '',
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            inputFileName: '',
+                            sourceMapSourcesMode: SourceMapSourcesMode.SourcesContent
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('should pass validation', () => {
+                    assert.doesNotThrow(testFunc);
+                });
+            });
+
+            describe('Variant #2: string with input file name when `sourceMapSourcesMode: \'sources\'', () => {
+                let testFunc: () => string;
+
+                beforeEach(() => {
+                    testFunc = () => JavaScriptObfuscator.obfuscate(
+                        '',
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            inputFileName: 'some-file.js',
+                            sourceMapSourcesMode: SourceMapSourcesMode.Sources
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('should pass validation', () => {
+                    assert.doesNotThrow(testFunc);
+                });
+            });
+        });
+
+        describe('Variant #2: negative validation', () => {
+            describe('Variant #1: empty string when `sourceMapSourcesMode: \'sources\'', () => {
+                const expectedError: string = 'should not be empty';
+                let testFunc: () => string;
+
+                beforeEach(() => {
+                    testFunc = () => JavaScriptObfuscator.obfuscate(
+                        '',
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            inputFileName: '',
+                            sourceMapSourcesMode: SourceMapSourcesMode.Sources
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('should not pass validation', () => {
+                    assert.throws(testFunc, expectedError);
+                });
+            });
+        });
+    });
+});

+ 7 - 0
test/helpers/atob.ts

@@ -0,0 +1,7 @@
+/**
+ * @param {string} encodedString
+ * @returns {string}
+ */
+export function atob (encodedString: string): string {
+    return Buffer.from(encodedString, 'base64').toString();
+}

+ 0 - 15
test/helpers/cryptUtilsAtob.ts

@@ -1,15 +0,0 @@
-/**
- * @param {string} encodedString
- * @returns {string}
- */
-export function cryptUtilsAtob (encodedString: string): string {
-    const baseDecodedString = atob(encodedString);
-
-    var tempDecodedString = '';
-
-    for (let k = 0, length = baseDecodedString.length; k < length; k++) {
-        tempDecodedString += '%' + ('00' + baseDecodedString.charCodeAt(k).toString(16)).slice(-2);
-    }
-
-    return decodeURIComponent(tempDecodedString);
-}

+ 2 - 2
test/helpers/parseSourceMapFromObfuscatedCode.ts

@@ -1,11 +1,11 @@
 import { ISourceMap } from '../../src/interfaces/source-code/ISourceMap';
 import { ISourceMap } from '../../src/interfaces/source-code/ISourceMap';
 
 
-import { cryptUtilsAtob } from './cryptUtilsAtob';
+import { atob } from './atob';
 
 
 /**
 /**
  * @param {string} obfuscatedCodeWithInlineSourceMap
  * @param {string} obfuscatedCodeWithInlineSourceMap
  * @returns {ISourceMap}
  * @returns {ISourceMap}
  */
  */
 export function parseSourceMapFromObfuscatedCode (obfuscatedCodeWithInlineSourceMap: string): ISourceMap {
 export function parseSourceMapFromObfuscatedCode (obfuscatedCodeWithInlineSourceMap: string): ISourceMap {
-    return JSON.parse(cryptUtilsAtob(obfuscatedCodeWithInlineSourceMap.split('base64,')[1]));
+    return JSON.parse(atob(obfuscatedCodeWithInlineSourceMap.split('base64,')[1]));
 }
 }

+ 1 - 0
test/index.spec.ts

@@ -136,6 +136,7 @@ import './functional-tests/options/OptionsNormalizer.spec';
 import './functional-tests/options/domain-lock-destination/Validation.spec';
 import './functional-tests/options/domain-lock-destination/Validation.spec';
 import './functional-tests/options/domain-lock/Validation.spec';
 import './functional-tests/options/domain-lock/Validation.spec';
 import './functional-tests/options/identifier-names-cache/Validation.spec';
 import './functional-tests/options/identifier-names-cache/Validation.spec';
+import './functional-tests/options/input-file-name/Validation.spec';
 import './functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec';
 import './functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec';
 
 
 /**
 /**

+ 4 - 4
test/unit-tests/utils/CryptUtils.spec.ts

@@ -8,7 +8,7 @@ import { ICryptUtils } from '../../../src/interfaces/utils/ICryptUtils';
 import { IInversifyContainerFacade } from '../../../src/interfaces/container/IInversifyContainerFacade';
 import { IInversifyContainerFacade } from '../../../src/interfaces/container/IInversifyContainerFacade';
 
 
 import { InversifyContainerFacade } from '../../../src/container/InversifyContainerFacade';
 import { InversifyContainerFacade } from '../../../src/container/InversifyContainerFacade';
-import { cryptUtilsAtob } from '../../helpers/cryptUtilsAtob';
+import { atob } from '../../helpers/atob';
 
 
 describe('CryptUtils', () => {
 describe('CryptUtils', () => {
     let cryptUtils: ICryptUtils;
     let cryptUtils: ICryptUtils;
@@ -30,7 +30,7 @@ describe('CryptUtils', () => {
 
 
            before(() => {
            before(() => {
                encodedString = cryptUtils.btoa('string');
                encodedString = cryptUtils.btoa('string');
-               decodedString = cryptUtilsAtob(encodedString);
+               decodedString = atob(encodedString);
            });
            });
 
 
            it('should create a base-64 encoded string from a given string', () => {
            it('should create a base-64 encoded string from a given string', () => {
@@ -51,7 +51,7 @@ describe('CryptUtils', () => {
 
 
             before(() => {
             before(() => {
                 encodedString = cryptUtils.btoa('stri');
                 encodedString = cryptUtils.btoa('stri');
-                decodedString = cryptUtilsAtob(encodedString);
+                decodedString = atob(encodedString);
             });
             });
 
 
             it('should create a base-64 encoded string from a given string with padding characters', () => {
             it('should create a base-64 encoded string from a given string with padding characters', () => {
@@ -72,7 +72,7 @@ describe('CryptUtils', () => {
 
 
             before(() => {
             before(() => {
                 encodedString = cryptUtils.btoa('тест');
                 encodedString = cryptUtils.btoa('тест');
-                decodedString = cryptUtilsAtob(encodedString);
+                decodedString = atob(encodedString);
             });
             });
 
 
             it('should create a base-64 encoded string from a given string', () => {
             it('should create a base-64 encoded string from a given string', () => {

Деякі файли не було показано, через те що забагато файлів було змінено