From 2dd6f91b7ff03e9acfec67727ee0186b8b541f77 Mon Sep 17 00:00:00 2001 From: sanex3339 Date: Sun, 18 Sep 2016 13:33:29 +0300 Subject: [PATCH] `sourceMapBaseUrl` wip implementation --- README.md | 7 ++ dist/index.js | 84 +++++++++++++++++-- package.json | 2 +- src/JavaScriptObfuscatorInternal.ts | 4 + src/Utils.ts | 72 +++++++++------- src/cli/JavaScriptObfuscatorCLI.ts | 1 + src/interfaces/IObfuscatorOptions.d.ts | 1 + src/interfaces/IOptions.d.ts | 1 + src/options/Options.ts | 25 +++++- src/options/OptionsNormalizer.ts | 43 ++++++++++ src/preset-options/DefaultPreset.ts | 1 + src/preset-options/NoCustomNodesPreset.ts | 1 + .../JavaScriptObfuscatorCLI.spec.ts | 27 ++++++ .../JavaScriptObfuscatorInternal.spec.ts | 28 ++++++- test/unit-tests/OptionsNormalizer.spec.ts | 6 ++ test/unit-tests/Utils.spec.ts | 10 +++ 16 files changed, 273 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index b847c398..f33e5557 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ Following options available for the JS Obfuscator: rotateUnicodeArray: true, selfDefending: true, sourceMap: false, + sourceMapBaseUrl: '', sourceMapMode: 'separate', unicodeArray: true, unicodeArrayThreshold: 0.8, @@ -137,6 +138,7 @@ Following options available for the JS Obfuscator: --rotateUnicodeArray --selfDefending --sourceMap + --sourceMapBaseUrl --sourceMapMode [inline, separate] --unicodeArray --unicodeArrayThreshold @@ -220,6 +222,11 @@ Type: `boolean` Default: `false` Enables source map generation for obfuscated code. +### `sourceMapBaseUrl` +Type: `string` Default: `` + +Inserts custom Url for source map + ### `sourceMapMode` Type: `string` Default: `separate` diff --git a/dist/index.js b/dist/index.js index 01ebd910..e158075a 100644 --- a/dist/index.js +++ b/dist/index.js @@ -145,6 +145,18 @@ var Utils = function () { var radix = 16; return Number(dec).toString(radix); } + }, { + key: 'extractDomainFromUrl', + value: function extractDomainFromUrl(url) { + var domain = void 0; + if (url.indexOf('://') > -1 || url.indexOf('//') === 0) { + domain = url.split('/')[2]; + } else { + domain = url.split('/')[0]; + } + domain = domain.split(':')[0]; + return domain; + } }, { key: 'getRandomGenerator', value: function getRandomGenerator() { @@ -183,9 +195,9 @@ var Utils = function () { return result; }; var customPool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - var randomString = Utils.randomGenerator.string({ length: length, pool: customPool }); - var randomStringDiff = randomString.replace(new RegExp('[' + escapeRegExp(str) + ']', 'g'), ''); - var randomStringDiffArray = randomStringDiff.split(''); + var randomString = Utils.randomGenerator.string({ length: length, pool: customPool }), + randomStringDiff = randomString.replace(new RegExp('[' + escapeRegExp(str) + ']', 'g'), ''), + randomStringDiffArray = randomStringDiff.split(''); Utils.randomGenerator.shuffle(randomStringDiffArray); randomStringDiff = randomStringDiffArray.join(''); return [randomMerge(str, randomStringDiff), randomStringDiff]; @@ -883,6 +895,7 @@ exports.NO_CUSTOM_NODES_PRESET = Object.freeze({ rotateUnicodeArray: false, selfDefending: false, sourceMap: false, + sourceMapBaseUrl: '', sourceMapMode: SourceMapMode_1.SourceMapMode.Separate, unicodeArray: false, unicodeArrayThreshold: 0, @@ -921,6 +934,9 @@ var JavaScriptObfuscatorInternal = function () { _createClass(JavaScriptObfuscatorInternal, [{ key: 'getObfuscationResult', value: function getObfuscationResult() { + if (this.options.sourceMapBaseUrl) { + this.setSourceMapUrl(this.options.sourceMapBaseUrl); + } return new SourceMapCorrector_1.SourceMapCorrector(new ObfuscationResult_1.ObfuscationResult(this.generatorOutput.code, this.generatorOutput.map), this.sourceMapUrl, this.options.sourceMapMode).correct(); } }, { @@ -1132,6 +1148,7 @@ exports.DEFAULT_PRESET = Object.freeze({ rotateUnicodeArray: true, selfDefending: true, sourceMap: false, + sourceMapBaseUrl: '', sourceMapMode: SourceMapMode_1.SourceMapMode.Separate, unicodeArray: true, unicodeArrayThreshold: 0.8, @@ -1528,7 +1545,7 @@ var JavaScriptObfuscatorCLI = function () { value: function configureCommands() { this.commands = new commander.Command().version(JavaScriptObfuscatorCLI.getBuildVersion(), '-v, --version').usage(' [options]').option('-o, --output ', 'Output path for obfuscated code').option('--compact ', 'Disable one line output code compacting', JavaScriptObfuscatorCLI.parseBoolean).option('--debugProtection ', 'Disable browser Debug panel (can cause DevTools enabled browser freeze)', JavaScriptObfuscatorCLI.parseBoolean).option('--debugProtectionInterval ', 'Disable browser Debug panel even after page was loaded (can cause DevTools enabled browser freeze)', JavaScriptObfuscatorCLI.parseBoolean).option('--disableConsoleOutput ', 'Allow console.log, console.info, console.error and console.warn messages output into browser console', JavaScriptObfuscatorCLI.parseBoolean).option('--encodeUnicodeLiterals ', 'All literals in Unicode array become encoded in Base64 (this option can slightly slow down your code speed)', JavaScriptObfuscatorCLI.parseBoolean).option('--reservedNames ', 'Disable obfuscation of variable names, function names and names of function parameters that match the passed RegExp patterns (comma separated)', function (val) { return val.split(','); - }).option('--rotateUnicodeArray ', 'Disable rotation of unicode array values during obfuscation', JavaScriptObfuscatorCLI.parseBoolean).option('--selfDefending ', 'Disables self-defending for obfuscated code', JavaScriptObfuscatorCLI.parseBoolean).option('--sourceMap ', 'Enables source map generation', JavaScriptObfuscatorCLI.parseBoolean).option('--sourceMapMode [inline, separate]', 'Specify source map output mode', JavaScriptObfuscatorCLI.parseSourceMapMode).option('--unicodeArray ', 'Disables gathering of all literal strings into an array and replacing every literal string with an array call', JavaScriptObfuscatorCLI.parseBoolean).option('--unicodeArrayThreshold ', 'The probability that the literal string will be inserted into unicodeArray (Default: 0.8, Min: 0, Max: 1)', parseFloat).option('--wrapUnicodeArrayCalls ', 'Disables usage of special access function instead of direct array call', JavaScriptObfuscatorCLI.parseBoolean).option('--domainLock ', 'Blocks the execution of the code in domains that do not match the passed RegExp patterns (comma separated)', function (val) { + }).option('--rotateUnicodeArray ', 'Disable rotation of unicode array values during obfuscation', JavaScriptObfuscatorCLI.parseBoolean).option('--selfDefending ', 'Disables self-defending for obfuscated code', JavaScriptObfuscatorCLI.parseBoolean).option('--sourceMap ', 'Enables source map generation', JavaScriptObfuscatorCLI.parseBoolean).option('--sourceMapBaseUrl ', 'Inserts custom Url for source map').option('--sourceMapMode [inline, separate]', 'Specify source map output mode', JavaScriptObfuscatorCLI.parseSourceMapMode).option('--unicodeArray ', 'Disables gathering of all literal strings into an array and replacing every literal string with an array call', JavaScriptObfuscatorCLI.parseBoolean).option('--unicodeArrayThreshold ', 'The probability that the literal string will be inserted into unicodeArray (Default: 0.8, Min: 0, Max: 1)', parseFloat).option('--wrapUnicodeArrayCalls ', 'Disables usage of special access function instead of direct array call', JavaScriptObfuscatorCLI.parseBoolean).option('--domainLock ', 'Blocks the execution of the code in domains that do not match the passed RegExp patterns (comma separated)', function (val) { return val.split(','); }).parse(this.rawArguments); this.commands.on('--help', function () { @@ -3213,6 +3230,12 @@ __decorate([class_validator_1.IsString({ __decorate([class_validator_1.IsBoolean(), __metadata('design:type', Boolean)], Options.prototype, "rotateUnicodeArray", void 0); __decorate([class_validator_1.IsBoolean(), __metadata('design:type', Boolean)], Options.prototype, "selfDefending", void 0); __decorate([class_validator_1.IsBoolean(), __metadata('design:type', Boolean)], Options.prototype, "sourceMap", void 0); +__decorate([class_validator_1.IsString(), class_validator_1.ValidateIf(function (options) { + return Boolean(options.sourceMapBaseUrl); +}), class_validator_1.IsUrl({ + require_protocol: false, + require_valid_protocol: true +}), __metadata('design:type', String)], Options.prototype, "sourceMapBaseUrl", void 0); __decorate([class_validator_1.IsIn(['inline', 'separate']), __metadata('design:type', String)], Options.prototype, "sourceMapMode", void 0); __decorate([class_validator_1.IsBoolean(), __metadata('design:type', Boolean)], Options.prototype, "unicodeArray", void 0); __decorate([class_validator_1.IsNumber(), class_validator_1.Min(0), class_validator_1.Max(1), __metadata('design:type', Number)], Options.prototype, "unicodeArrayThreshold", void 0); @@ -3221,7 +3244,7 @@ exports.Options = Options; /***/ }, /* 55 */ -/***/ function(module, exports) { +/***/ function(module, exports, __webpack_require__) { "use strict"; "use strict"; @@ -3230,6 +3253,8 @@ var _createClass = function () { function defineProperties(target, props) { for function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } +var Utils_1 = __webpack_require__(0); + var OptionsNormalizer = function () { function OptionsNormalizer() { _classCallCheck(this, OptionsNormalizer); @@ -3266,6 +3291,42 @@ var OptionsNormalizer = function () { return normalizedOptions; } + }, { + key: "domainLockRule", + value: function domainLockRule(options) { + if (options.domainLock.length) { + var normalizedDomains = []; + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = options.domainLock[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var domain = _step2.value; + + normalizedDomains.push(Utils_1.Utils.extractDomainFromUrl(domain)); + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + Object.assign(options, { + domainLock: normalizedDomains + }); + } + return options; + } }, { key: "encodeUnicodeLiteralsRule", value: function encodeUnicodeLiteralsRule(options) { @@ -3282,6 +3343,14 @@ var OptionsNormalizer = function () { } return options; } + }, { + key: "sourceMapBaseUrl", + value: function sourceMapBaseUrl(options) { + if (options.sourceMapBaseUrl) { + Object.assign(options, OptionsNormalizer.SOURCE_MAP_BASE_URL_OPTIONS); + } + return options; + } }, { key: "unicodeArrayRule", value: function unicodeArrayRule(options) { @@ -3318,7 +3387,10 @@ OptionsNormalizer.SELF_DEFENDING_OPTIONS = { compact: true, selfDefending: true }; -OptionsNormalizer.normalizerRules = [OptionsNormalizer.unicodeArrayRule, OptionsNormalizer.unicodeArrayThresholdRule, OptionsNormalizer.encodeUnicodeLiteralsRule, OptionsNormalizer.selfDefendingRule]; +OptionsNormalizer.SOURCE_MAP_BASE_URL_OPTIONS = { + sourceMapMode: 'separate' +}; +OptionsNormalizer.normalizerRules = [OptionsNormalizer.domainLockRule, OptionsNormalizer.unicodeArrayRule, OptionsNormalizer.unicodeArrayThresholdRule, OptionsNormalizer.encodeUnicodeLiteralsRule, OptionsNormalizer.sourceMapBaseUrl, OptionsNormalizer.selfDefendingRule]; exports.OptionsNormalizer = OptionsNormalizer; /***/ }, diff --git a/package.json b/package.json index a9d26512..23cc3680 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "dependencies": { "babel-polyfill": "^6.13.0", "chance": "^1.0.4", - "class-validator": "^0.5.0", + "class-validator": "next", "commander": "^2.9.0", "escodegen": "^1.8.1", "esprima": "^3.0.0", diff --git a/src/JavaScriptObfuscatorInternal.ts b/src/JavaScriptObfuscatorInternal.ts index 951c14f4..73ff8f58 100644 --- a/src/JavaScriptObfuscatorInternal.ts +++ b/src/JavaScriptObfuscatorInternal.ts @@ -84,6 +84,10 @@ export class JavaScriptObfuscatorInternal { * @returns {IObfuscationResult} */ public getObfuscationResult (): IObfuscationResult { + if (this.options.sourceMapBaseUrl) { + this.setSourceMapUrl(this.options.sourceMapBaseUrl); + } + return new SourceMapCorrector( new ObfuscationResult( this.generatorOutput.code, diff --git a/src/Utils.ts b/src/Utils.ts index 1a55555a..c891c92f 100644 --- a/src/Utils.ts +++ b/src/Utils.ts @@ -62,6 +62,24 @@ export class Utils { return Number(dec).toString(radix); } + /** + * @param url + * @returns {string} + */ + public static extractDomainFromUrl (url: string): string { + let domain: string; + + if (url.indexOf('://') > -1 || url.indexOf('//') === 0) { + domain = url.split('/')[2]; + } else { + domain = url.split('/')[0]; + } + + domain = domain.split(':')[0]; + + return domain; + } + /** * @returns {Chance.Chance} */ @@ -71,7 +89,7 @@ export class Utils { /** * @param length - * @returns any + * @returns {string} */ public static getRandomVariableName (length: number = 6): string { const rangeMinInteger: number = 10000, @@ -89,42 +107,40 @@ export class Utils { } /** + * @param str * @param length - * @param charSet - * @returns string + * @returns {string[]} */ public static hideString(str: string, length: number): [string, string] { + const escapeRegExp = (s: string) => + s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - // from http://stackoverflow.com/a/3561711 - const escapeRegExp = (s: string) => - s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); + const randomMerge = function (s1: string, s2: string): string { + let i1 = -1, i2 = -1, result = ''; - const randomMerge = function (s1: string, s2: string): string { - let i1 = -1, i2 = -1, result = ''; - while (i1 < s1.length || i2 < s2.length) { - if (Math.random() < 0.5 && i2 < s2.length) { - result += s2.charAt(++i2); - } else { - result += s1.charAt(++i1); - } - } - return result; - } + while (i1 < s1.length || i2 < s2.length) { + if (Math.random() < 0.5 && i2 < s2.length) { + result += s2.charAt(++i2); + } else { + result += s1.charAt(++i1); + } + } - // here we need a custom pool parameter because the default on from Change.string - // can return chars that break the RegExp - const customPool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - let randomString = Utils.randomGenerator.string({length: length, pool: customPool}); + return result; + }; - let randomStringDiff = randomString.replace( - new RegExp('[' + escapeRegExp(str) + ']', 'g'), - ''); + const customPool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; - let randomStringDiffArray = randomStringDiff.split(''); - Utils.randomGenerator.shuffle(randomStringDiffArray); - randomStringDiff = randomStringDiffArray.join(''); + let randomString = Utils.randomGenerator.string({length: length, pool: customPool}), + randomStringDiff = randomString.replace( + new RegExp('[' + escapeRegExp(str) + ']', 'g'), + ''), + randomStringDiffArray = randomStringDiff.split(''); - return [randomMerge(str, randomStringDiff), randomStringDiff]; + Utils.randomGenerator.shuffle(randomStringDiffArray); + randomStringDiff = randomStringDiffArray.join(''); + + return [randomMerge(str, randomStringDiff), randomStringDiff]; } diff --git a/src/cli/JavaScriptObfuscatorCLI.ts b/src/cli/JavaScriptObfuscatorCLI.ts index 9f550da6..ebe7e550 100644 --- a/src/cli/JavaScriptObfuscatorCLI.ts +++ b/src/cli/JavaScriptObfuscatorCLI.ts @@ -132,6 +132,7 @@ export class JavaScriptObfuscatorCLI { .option('--rotateUnicodeArray ', 'Disable rotation of unicode array values during obfuscation', JavaScriptObfuscatorCLI.parseBoolean) .option('--selfDefending ', 'Disables self-defending for obfuscated code', JavaScriptObfuscatorCLI.parseBoolean) .option('--sourceMap ', 'Enables source map generation', JavaScriptObfuscatorCLI.parseBoolean) + .option('--sourceMapBaseUrl ', 'Inserts custom Url for source map') .option( '--sourceMapMode [inline, separate]', 'Specify source map output mode', diff --git a/src/interfaces/IObfuscatorOptions.d.ts b/src/interfaces/IObfuscatorOptions.d.ts index a6671830..751100e8 100644 --- a/src/interfaces/IObfuscatorOptions.d.ts +++ b/src/interfaces/IObfuscatorOptions.d.ts @@ -10,6 +10,7 @@ export interface IObfuscatorOptions { rotateUnicodeArray?: boolean; selfDefending?: boolean; sourceMap?: boolean; + sourceMapBaseUrl?: string; sourceMapMode?: TSourceMapMode; unicodeArray?: boolean; unicodeArrayThreshold?: number; diff --git a/src/interfaces/IOptions.d.ts b/src/interfaces/IOptions.d.ts index 7e078265..509af4db 100644 --- a/src/interfaces/IOptions.d.ts +++ b/src/interfaces/IOptions.d.ts @@ -10,6 +10,7 @@ export interface IOptions { readonly rotateUnicodeArray: boolean; readonly selfDefending: boolean; readonly sourceMap: boolean; + readonly sourceMapBaseUrl: string; readonly sourceMapMode: TSourceMapMode; readonly unicodeArray: boolean; readonly unicodeArrayThreshold: number; diff --git a/src/options/Options.ts b/src/options/Options.ts index cc7133f3..740cbd18 100644 --- a/src/options/Options.ts +++ b/src/options/Options.ts @@ -1,4 +1,16 @@ -import { IsBoolean, IsIn, IsNumber, IsString, Min, Max, validateSync, ValidationError, ValidatorOptions } from 'class-validator'; +import { + IsBoolean, + IsIn, + IsNumber, + IsString, + IsUrl, + Min, + Max, + ValidateIf, + validateSync, + ValidationError, + ValidatorOptions +} from 'class-validator'; import { IObfuscatorOptions } from "../interfaces/IObfuscatorOptions"; import { IOptions } from "../interfaces/IOptions"; @@ -84,6 +96,17 @@ export class Options implements IOptions { @IsBoolean() public readonly sourceMap: boolean; + /** + * @type {boolean} + */ + @IsString() + @ValidateIf((options: IOptions) => Boolean(options.sourceMapBaseUrl)) + @IsUrl({ + require_protocol: false, + require_valid_protocol: true + }) + public readonly sourceMapBaseUrl: string; + /** * @type {TSourceMapMode} */ diff --git a/src/options/OptionsNormalizer.ts b/src/options/OptionsNormalizer.ts index 08cc401d..caec3a04 100644 --- a/src/options/OptionsNormalizer.ts +++ b/src/options/OptionsNormalizer.ts @@ -3,6 +3,8 @@ import { IOptions } from "../interfaces/IOptions"; import { TOptionsNormalizerRule } from "../types/TOptionsNormalizerRule"; +import { Utils } from "../Utils"; + export class OptionsNormalizer { /** * @type {IObfuscatorOptions} @@ -31,13 +33,22 @@ export class OptionsNormalizer { selfDefending: true }; + /** + * @type {IObfuscatorOptions} + */ + private static SOURCE_MAP_BASE_URL_OPTIONS: IObfuscatorOptions = { + sourceMapMode: 'separate' + }; + /** * @type {TOptionsNormalizerRule[]} */ private static normalizerRules: TOptionsNormalizerRule[] = [ + OptionsNormalizer.domainLockRule, OptionsNormalizer.unicodeArrayRule, OptionsNormalizer.unicodeArrayThresholdRule, OptionsNormalizer.encodeUnicodeLiteralsRule, + OptionsNormalizer.sourceMapBaseUrl, OptionsNormalizer.selfDefendingRule ]; @@ -55,6 +66,26 @@ export class OptionsNormalizer { return normalizedOptions; } + /** + * @param options + * @returns {IOptions} + */ + private static domainLockRule (options: IOptions): IOptions { + if (options.domainLock.length) { + let normalizedDomains: string[] = []; + + for (let domain of options.domainLock) { + normalizedDomains.push(Utils.extractDomainFromUrl(domain)); + } + + Object.assign(options, { + domainLock: normalizedDomains + }); + } + + return options; + } + /** * @param options * @returns {IOptions} @@ -79,6 +110,18 @@ export class OptionsNormalizer { return options; } + /** + * @param options + * @returns {IOptions} + */ + private static sourceMapBaseUrl (options: IOptions): IOptions { + if (options.sourceMapBaseUrl) { + Object.assign(options, OptionsNormalizer.SOURCE_MAP_BASE_URL_OPTIONS); + } + + return options; + } + /** * @param options * @returns {IOptions} diff --git a/src/preset-options/DefaultPreset.ts b/src/preset-options/DefaultPreset.ts index dde82d4a..d6427ba7 100644 --- a/src/preset-options/DefaultPreset.ts +++ b/src/preset-options/DefaultPreset.ts @@ -13,6 +13,7 @@ export const DEFAULT_PRESET: IObfuscatorOptions = Object.freeze({ rotateUnicodeArray: true, selfDefending: true, sourceMap: false, + sourceMapBaseUrl: '', sourceMapMode: SourceMapMode.Separate, unicodeArray: true, unicodeArrayThreshold: 0.8, diff --git a/src/preset-options/NoCustomNodesPreset.ts b/src/preset-options/NoCustomNodesPreset.ts index 2232c1a3..4cf59083 100644 --- a/src/preset-options/NoCustomNodesPreset.ts +++ b/src/preset-options/NoCustomNodesPreset.ts @@ -13,6 +13,7 @@ export const NO_CUSTOM_NODES_PRESET: IObfuscatorOptions = Object.freeze({ rotateUnicodeArray: false, selfDefending: false, sourceMap: false, + sourceMapBaseUrl: '', sourceMapMode: SourceMapMode.Separate, unicodeArray: false, unicodeArrayThreshold: 0, diff --git a/test/functional-tests/JavaScriptObfuscatorCLI.spec.ts b/test/functional-tests/JavaScriptObfuscatorCLI.spec.ts index 094df58b..19ef7707 100644 --- a/test/functional-tests/JavaScriptObfuscatorCLI.spec.ts +++ b/test/functional-tests/JavaScriptObfuscatorCLI.spec.ts @@ -112,6 +112,33 @@ describe('JavaScriptObfuscatorCLI', function (): void { assert.property(sourceMap, 'names'); }); + it('should creates file with source map in the same directory as output file if `sourceMapBaseUrl` is set', () => { + JavaScriptObfuscator.runCLI([ + 'node', + 'javascript-obfuscator', + fixtureFilePath, + '--output', + outputFilePath, + '--compact', + 'true', + '--selfDefending', + '0', + '--sourceMap', + 'true', + '--sourceMapBaseUrl', + 'http://localhost:9000/' + ]); + + assert.equal(fs.existsSync(outputSourceMapPath), true); + + const content: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' }), + sourceMap: any = JSON.parse(content); + + assert.property(sourceMap, 'version'); + assert.property(sourceMap, 'sources'); + assert.property(sourceMap, 'names'); + }); + afterEach(() => { fs.unlinkSync(outputFilePath); fs.unlinkSync(outputSourceMapPath); diff --git a/test/functional-tests/JavaScriptObfuscatorInternal.spec.ts b/test/functional-tests/JavaScriptObfuscatorInternal.spec.ts index 5df61fbb..1ff2372f 100644 --- a/test/functional-tests/JavaScriptObfuscatorInternal.spec.ts +++ b/test/functional-tests/JavaScriptObfuscatorInternal.spec.ts @@ -10,9 +10,10 @@ describe('JavaScriptObfuscatorInternal', () => { describe(`setSourceMapUrl (url: string)`, () => { let javaScriptObfuscator: JavaScriptObfuscatorInternal, obfuscationResult: IObfuscationResult, - sourceMapUrl: string = 'test.map.js'; + sourceMapUrl: string; - beforeEach(() => { + it('should link obfuscated code with source map', () => { + sourceMapUrl = 'test.map.js'; javaScriptObfuscator = new JavaScriptObfuscatorInternal( `var test = 1;`, Object.assign({}, NO_CUSTOM_NODES_PRESET, { @@ -24,14 +25,33 @@ describe('JavaScriptObfuscatorInternal', () => { javaScriptObfuscator.setSourceMapUrl(sourceMapUrl); obfuscationResult = javaScriptObfuscator.getObfuscationResult(); - }); - it('should link obfuscated code with source map', () => { assert.match( obfuscationResult.getObfuscatedCode(), new RegExp(`sourceMappingURL=${sourceMapUrl}`)) ; assert.isOk(JSON.parse(obfuscationResult.getSourceMap()).mappings); }); + + it('should properly add source map import to the obfuscated code if `sourceMapBaseUrl` is set', () => { + sourceMapUrl = 'http://localhost:9000/'; + javaScriptObfuscator = new JavaScriptObfuscatorInternal( + `var test = 1;`, + Object.assign({}, NO_CUSTOM_NODES_PRESET, { + sourceMap: true, + sourceMapBaseUrl: sourceMapUrl + }) + ); + + javaScriptObfuscator.obfuscate(); + + obfuscationResult = javaScriptObfuscator.getObfuscationResult(); + + assert.match( + obfuscationResult.getObfuscatedCode(), + new RegExp(`sourceMappingURL=${sourceMapUrl}$`)) + ; + assert.isOk(JSON.parse(obfuscationResult.getSourceMap()).mappings); + }); }); }); diff --git a/test/unit-tests/OptionsNormalizer.spec.ts b/test/unit-tests/OptionsNormalizer.spec.ts index 590a4bd1..6c9c6de4 100644 --- a/test/unit-tests/OptionsNormalizer.spec.ts +++ b/test/unit-tests/OptionsNormalizer.spec.ts @@ -30,11 +30,14 @@ describe('OptionsNormalizer', () => { }); optionsPreset2 = Object.assign({}, DEFAULT_PRESET, { rotateUnicodeArray: true, + sourceMapBaseUrl: 'http://localhost:9000', + sourceMapMode: 'inline', unicodeArray: true, unicodeArrayThreshold: 0, wrapUnicodeArrayCalls: true }); optionsPreset3 = Object.assign({}, DEFAULT_PRESET, { + domainLock: ['//localhost:9000', 'https://google.ru/abc?cde=fgh'], unicodeArray: true, encodeUnicodeLiterals: true, wrapUnicodeArrayCalls: false @@ -49,11 +52,14 @@ describe('OptionsNormalizer', () => { }); expectedOptionsPreset2 = Object.assign({}, DEFAULT_PRESET, { rotateUnicodeArray: false, + sourceMapBaseUrl: 'http://localhost:9000', + sourceMapMode: 'separate', unicodeArray: false, unicodeArrayThreshold: 0, wrapUnicodeArrayCalls: false }); expectedOptionsPreset3 = Object.assign({}, DEFAULT_PRESET, { + domainLock: ['localhost', 'google.ru'], unicodeArray: true, encodeUnicodeLiterals: true, wrapUnicodeArrayCalls: true diff --git a/test/unit-tests/Utils.spec.ts b/test/unit-tests/Utils.spec.ts index 5d59bf71..43cdb53e 100644 --- a/test/unit-tests/Utils.spec.ts +++ b/test/unit-tests/Utils.spec.ts @@ -50,6 +50,16 @@ describe('Utils', () => { }); }); + describe('extractDomainFromUrl (url: string): string', () => { + it('should extract domain from the given URL', () => { + assert.equal(Utils.extractDomainFromUrl('http://google.ru'), 'google.ru'); + assert.equal(Utils.extractDomainFromUrl('http://www.google.ru'), 'www.google.ru'); + assert.equal(Utils.extractDomainFromUrl('https://www.google.ru:9000'), 'www.google.ru'); + assert.equal(Utils.extractDomainFromUrl('//google.ru/abc'), 'google.ru'); + assert.equal(Utils.extractDomainFromUrl('//localhost:9000'), 'localhost'); + }); + }); + describe('getRandomVariableName (length: number = 6): string', () => { it('should return a string of given length with random variable name', () => { assert.match(Utils.getRandomVariableName(4), /^_0x(\w){4}$/);