Jelajahi Sumber

Merge pull request #658 from javascript-obfuscator/mangled-shuffled-identifier-names-generator

Added `mangled-shuffled` identifier names generator
Timofey Kachalov 4 tahun lalu
induk
melakukan
83e493f8b1

+ 5 - 1
CHANGELOG.md

@@ -1,8 +1,12 @@
 Change Log
 
+v1.5.0
+---
+* New `mangled-shuffled` identifier names generator based on `mangled` identifier names generator
+
 v1.4.0
 ---
-* **New option:** `simplify` enables additional code obfuscation through simplification.
+* **New option:** `simplify` enables additional code obfuscation through simplification
 
 v1.3.0
 ---

+ 30 - 1
README.md

@@ -643,6 +643,7 @@ Available values:
 * `dictionary`: identifier names from [`identifiersDictionary`](#identifiersDictionary) list
 * `hexadecimal`: identifier names like `_0xabc123`
 * `mangled`: short identifier names like `a`, `b`, `c`
+* `mangled-shuffled`: same as `mangled` but with shuffled alphabet
 
 ### `identifiersDictionary`
 Type: `string[]` Default: `[]`
@@ -779,7 +780,35 @@ Type: `boolean` Default: `true`
 
 Enables additional code obfuscation through simplification.
 
-##### :warning: in the future releases obfuscation of `boolean` literals (`true` => `!![]`) will be moved under this option. 
+##### :warning: in future releases obfuscation of `boolean` literals (`true` => `!![]`) will be moved under this option. 
+
+Example:
+```ts
+// input
+if (condition1) {
+    const foo = 1;
+    const bar = 2;
+  
+    console.log(foo);
+  
+    return bar;
+} else if (condition2) {
+    console.log(1);
+    console.log(2);
+    console.log(3);
+  
+    return 4;
+} else {
+    return 5;
+}
+
+// output
+if (condition1) {
+    const foo = 0x1, bar = 0x2;
+    return console['log'](foo), bar;
+} else
+    return condition2 ? (console['log'](0x1), console['log'](0x2), console['log'](0x3), 0x4) : 0x5;
+```
 
 ### `sourceMap`
 Type: `boolean` Default: `false`

File diff ditekan karena terlalu besar
+ 0 - 0
dist/index.browser.js


File diff ditekan karena terlalu besar
+ 0 - 0
dist/index.cli.js


File diff ditekan karena terlalu besar
+ 0 - 0
dist/index.js


+ 5 - 5
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "1.4.0",
+  "version": "1.5.0",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",
@@ -54,7 +54,7 @@
     "@types/mkdirp": "1.0.1",
     "@types/mocha": "7.0.2",
     "@types/multimatch": "4.0.0",
-    "@types/node": "14.0.19",
+    "@types/node": "14.0.20",
     "@types/rimraf": "3.0.0",
     "@types/sinon": "9.0.4",
     "@types/string-template": "1.0.2",
@@ -65,7 +65,7 @@
     "coveralls": "3.1.0",
     "eslint": "7.4.0",
     "eslint-plugin-import": "2.22.0",
-    "eslint-plugin-jsdoc": "28.6.1",
+    "eslint-plugin-jsdoc": "29.1.2",
     "eslint-plugin-no-null": "1.0.2",
     "eslint-plugin-prefer-arrow": "1.2.1",
     "eslint-plugin-unicorn": "20.1.0",
@@ -78,12 +78,12 @@
     "rimraf": "3.0.2",
     "sinon": "9.0.2",
     "threads": "1.6.3",
-    "ts-loader": "7.0.5",
+    "ts-loader": "8.0.0",
     "ts-node": "8.10.2",
     "typescript": "3.9.6",
     "webpack": "4.43.0",
     "webpack-cli": "3.3.12",
-    "webpack-node-externals": "1.7.2"
+    "webpack-node-externals": "2.3.0"
   },
   "repository": {
     "type": "git",

+ 1 - 1
src/cli/JavaScriptObfuscatorCLI.ts

@@ -232,7 +232,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
             .option(
                 '--identifier-names-generator <string>',
                 'Sets identifier names generator. ' +
-                'Values: hexadecimal, mangled, dictionary. ' +
+                'Values: hexadecimal, mangled, mangled-shuffled, dictionary. ' +
                 'Default: hexadecimal',
                 IdentifierNamesGeneratorSanitizer
             )

+ 14 - 0
src/container/modules/generators/GeneratorsModule.ts

@@ -9,6 +9,7 @@ import { IdentifierNamesGenerator } from '../../../enums/generators/identifier-n
 import { DictionaryIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/DictionaryIdentifierNamesGenerator';
 import { HexadecimalIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator';
 import { MangledIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/MangledIdentifierNamesGenerator';
+import { MangledShuffledIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/MangledShuffledIdentifierNamesGenerator';
 
 export const generatorsModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
     // identifier name generators
@@ -27,6 +28,11 @@ export const generatorsModule: interfaces.ContainerModule = new ContainerModule(
         .inSingletonScope()
         .whenTargetNamed(IdentifierNamesGenerator.MangledIdentifierNamesGenerator);
 
+    bind<IIdentifierNamesGenerator>(ServiceIdentifiers.IIdentifierNamesGenerator)
+        .to(MangledShuffledIdentifierNamesGenerator)
+        .inSingletonScope()
+        .whenTargetNamed(IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator);
+
     // identifier name generator factory
     function identifierNameGeneratorFactory (): (context: interfaces.Context) => (options: IOptions) => IIdentifierNamesGenerator {
         let cachedIdentifierNamesGenerator: IIdentifierNamesGenerator | null = null;
@@ -55,6 +61,14 @@ export const generatorsModule: interfaces.ContainerModule = new ContainerModule(
 
                     break;
 
+                case IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator:
+                    identifierNamesGenerator = context.container.getNamed<IIdentifierNamesGenerator>(
+                        ServiceIdentifiers.IIdentifierNamesGenerator,
+                        IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator
+                    );
+
+                    break;
+
                 case IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator:
                 default:
                     identifierNamesGenerator = context.container.getNamed<IIdentifierNamesGenerator>(

+ 3 - 1
src/enums/generators/identifier-names-generators/IdentifierNamesGenerator.ts

@@ -4,8 +4,10 @@ export const IdentifierNamesGenerator: Readonly<{
     DictionaryIdentifierNamesGenerator: 'dictionary';
     HexadecimalIdentifierNamesGenerator: 'hexadecimal';
     MangledIdentifierNamesGenerator: 'mangled';
+    MangledShuffledIdentifierNamesGenerator: 'mangled-shuffled';
 }> = MakeEnum({
     DictionaryIdentifierNamesGenerator: 'dictionary',
     HexadecimalIdentifierNamesGenerator: 'hexadecimal',
-    MangledIdentifierNamesGenerator: 'mangled'
+    MangledIdentifierNamesGenerator: 'mangled',
+    MangledShuffledIdentifierNamesGenerator: 'mangled-shuffled'
 });

+ 6 - 6
src/generators/identifier-names-generators/MangledIdentifierNamesGenerator.ts

@@ -25,11 +25,6 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
      */
     private static readonly lastMangledNameInScopeMap: WeakMap <TNodeWithLexicalScope, string> = new WeakMap();
 
-    /**
-     * @type {string[]}
-     */
-    private static readonly nameSequence: string[] = `${numbersString}${alphabetString}${alphabetStringUppercase}`.split('');
-
     /**
      * Reserved JS words with length of 2-4 symbols that can be possible generated with this replacer
      *
@@ -41,6 +36,11 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
         'var', 'void', 'with'
     ]);
 
+    /**
+     * @type {string[]}
+     */
+    protected nameSequence: string[] = `${numbersString}${alphabetString}${alphabetStringUppercase}`.split('');
+
     /**
      * @type {string}
      */
@@ -134,7 +134,7 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
      */
     private generateNewMangledName (previousMangledName: string): string {
         const generateNewMangledName: (name: string) => string = (name: string): string => {
-            const nameSequence: string[] = MangledIdentifierNamesGenerator.nameSequence;
+            const nameSequence: string[] = this.nameSequence;
             const nameSequenceLength: number = nameSequence.length;
             const nameLength: number = name.length;
 

+ 39 - 0
src/generators/identifier-names-generators/MangledShuffledIdentifierNamesGenerator.ts

@@ -0,0 +1,39 @@
+import { inject, injectable } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
+import { IArrayUtils } from '../../interfaces/utils/IArrayUtils';
+import { IOptions } from '../../interfaces/options/IOptions';
+import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
+
+import { numbersString } from '../../constants/NumbersString';
+import { alphabetString } from '../../constants/AlphabetString';
+import { alphabetStringUppercase } from '../../constants/AlphabetStringUppercase';
+
+import { MangledIdentifierNamesGenerator } from './MangledIdentifierNamesGenerator';
+
+@injectable()
+export class MangledShuffledIdentifierNamesGenerator extends MangledIdentifierNamesGenerator {
+    /**
+     * @type {IArrayUtils}
+     */
+    private readonly arrayUtils: IArrayUtils;
+
+    /**
+     * @param {IArrayUtils} arrayUtils
+     * @param {IRandomGenerator} randomGenerator
+     * @param {IOptions} options
+     */
+    public constructor (
+        @inject(ServiceIdentifiers.IArrayUtils) arrayUtils: IArrayUtils,
+        @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(randomGenerator, options);
+
+        this.arrayUtils = arrayUtils;
+        this.nameSequence = [
+            ...`${numbersString}`,
+            ...this.arrayUtils.shuffle([...`${alphabetString}${alphabetStringUppercase}`])
+        ];
+    }
+}

+ 2 - 1
src/options/Options.ts

@@ -117,7 +117,8 @@ export class Options implements IOptions {
     @IsIn([
         IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator,
         IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
-        IdentifierNamesGenerator.MangledIdentifierNamesGenerator
+        IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
+        IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator
     ])
     public readonly identifierNamesGenerator!: TypeFromEnum<typeof IdentifierNamesGenerator>;
 

+ 4 - 10
test/dev/dev.ts

@@ -1,5 +1,6 @@
 'use strict';
 
+import { IdentifierNamesGenerator } from '../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
 import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNodes';
 
 (function () {
@@ -7,20 +8,13 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
 
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
-            function foo() {
-                if (true) {
-                    if (false) {
-                        var bar = baz();
-                    }
-                } else {
-                    var bark = hawk();
-                }
+            function foo (arg1, arg2, arg3) {
+                console.log(arg1, arg2, arg3);
             }
         `,
         {
             ...NO_ADDITIONAL_NODES_PRESET,
-            compact: false,
-            simplify: true
+            identifierNamesGenerator: IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator
         }
     ).getObfuscatedCode();
 

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

@@ -703,6 +703,27 @@ describe('JavaScriptObfuscator', () => {
             });
         });
 
+        describe('mangled shuffled identifier names generator', () => {
+            const regExp: RegExp = /var [a-zA-Z] *= *0x1/;
+
+            let obfuscatedCode: string;
+
+            beforeEach(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/mangle.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        identifierNamesGenerator: IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('should mangle obfuscated code', () => {
+                assert.match(obfuscatedCode, regExp);
+            });
+        });
+
         describe('dictionary identifier names generator', () => {
             const regExp1: RegExp = /var [abc] *= *0x1; *var [abc] *= *0x2; *var [abc] *= *0x3;/;
             const regExp2: RegExp = /var [ABC] *= *0x4; *var [ABC] *= *0x5; *var [ABC] *= *0x6;/;

+ 1 - 0
test/index.spec.ts

@@ -22,6 +22,7 @@ import './unit-tests/decorators/initializable/Initializable.spec';
 import './unit-tests/generators/identifier-names-generators/DictionarylIdentifierNamesGenerator.spec';
 import './unit-tests/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.spec';
 import './unit-tests/generators/identifier-names-generators/MangledlIdentifierNamesGenerator.spec';
+import './unit-tests/generators/identifier-names-generators/MangledShuffledlIdentifierNamesGenerator.spec';
 import './unit-tests/javascript-obfuscator/ASTParserFacade.spec';
 import './unit-tests/javascript-obfuscator/JavaScriptObfuscator.spec';
 import './unit-tests/logger/Logger.spec';

+ 115 - 0
test/unit-tests/generators/identifier-names-generators/MangledShuffledlIdentifierNamesGenerator.spec.ts

@@ -0,0 +1,115 @@
+import 'reflect-metadata';
+
+import { assert } from 'chai';
+
+import { ServiceIdentifiers } from '../../../../src/container/ServiceIdentifiers';
+
+import { IIdentifierNamesGenerator } from '../../../../src/interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
+import { IInversifyContainerFacade } from '../../../../src/interfaces/container/IInversifyContainerFacade';
+
+import { IdentifierNamesGenerator } from '../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
+
+import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
+
+describe('MangledShuffledIdentifierNamesGenerator', () => {
+    describe('generateNext', () => {
+        let identifierNamesGenerator: IIdentifierNamesGenerator,
+            mangledIdentifierName: string;
+
+        beforeEach(() => {
+            const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
+
+            inversifyContainerFacade.load('', '', {});
+            identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
+                ServiceIdentifiers.IIdentifierNamesGenerator,
+                IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator
+            );
+        });
+
+        describe('Variant #1: initial mangled name', () => {
+            const expectedMangledIdentifierNameRegExp: RegExp = /[a-zA-Z]/;
+
+            beforeEach(() => {
+                mangledIdentifierName = identifierNamesGenerator.generateNext();
+            });
+
+            it('should return mangled name', () => {
+                assert.match(mangledIdentifierName, expectedMangledIdentifierNameRegExp);
+            });
+        });
+
+        describe('Variant #2: second mangled name', () => {
+            const expectedMangledIdentifierNameRegExp: RegExp = /[a-zA-Z]/;
+            const expectedMangledIdentifierPosition: number = 1;
+
+            beforeEach(() => {
+                for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
+                    mangledIdentifierName = identifierNamesGenerator.generateNext();
+                }
+            });
+
+            it('should return mangled name', () => {
+                assert.match(mangledIdentifierName, expectedMangledIdentifierNameRegExp);
+            });
+        });
+
+        describe('Variant #3: correct increase of mangled name length', () => {
+            const expectedMangledIdentifierNameRegExp: RegExp = /[a-zA-Z]0/;
+            const expectedMangledIdentifierPosition: number = 52;
+
+            beforeEach(() => {
+                for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
+                    mangledIdentifierName = identifierNamesGenerator.generateNext();
+                }
+            });
+
+            it('should return mangled name', () => {
+                assert.match(mangledIdentifierName, expectedMangledIdentifierNameRegExp);
+            });
+        });
+
+        describe('Variant #4: correct increase of mangled name length #2', () => {
+            const expectedMangledIdentifierNameRegExp: RegExp = /[a-zA-Z][a-zA-Z]/;
+            const expectedMangledIdentifierPosition: number = 62;
+
+            beforeEach(() => {
+                for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
+                    mangledIdentifierName = identifierNamesGenerator.generateNext();
+                }
+            });
+
+            it('should return mangled name', () => {
+                assert.match(mangledIdentifierName, expectedMangledIdentifierNameRegExp);
+            });
+        });
+    });
+
+    describe('generateForGlobalScope', () => {
+        let identifierNamesGenerator: IIdentifierNamesGenerator,
+            mangledIdentifierName: string;
+
+        before(() => {
+            const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
+
+            inversifyContainerFacade.load('', '', {
+                identifiersPrefix: 'foo'
+            });
+            identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
+                ServiceIdentifiers.IIdentifierNamesGenerator,
+                IdentifierNamesGenerator.MangledIdentifierNamesGenerator
+            );
+        });
+
+        describe('Variant #1: initial mangled name', () => {
+            const expectedMangledIdentifierNameRegExp: RegExp = /foo[a-zA-Z]/;
+
+            beforeEach(() => {
+                mangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
+            });
+
+            it('should return mangled name with prefix', () => {
+                assert.match(mangledIdentifierName, expectedMangledIdentifierNameRegExp);
+            });
+        });
+    });
+});

+ 21 - 21
yarn.lock

@@ -369,10 +369,10 @@
   resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.3.tgz#6356df2647de9eac569f9a52eda3480fa9e70b4d"
   integrity sha512-01s+ac4qerwd6RHD+mVbOEsraDHSgUaefQlEdBbUolnQFjKwCr7luvAlEwW1RFojh67u0z4OUTjPn9LEl4zIkA==
 
-"@types/[email protected].19":
-  version "14.0.19"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.19.tgz#994d99708822bca643a2364f8aeed04a16e0f5a1"
-  integrity sha512-yf3BP/NIXF37BjrK5klu//asUWitOEoUP5xE1mhSUjazotwJ/eJDgEmMQNlOeWOVv72j24QQ+3bqXHE++CFGag==
+"@types/[email protected].20":
+  version "14.0.20"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.20.tgz#0da05cddbc761e1fa98af88a17244c8c1ff37231"
+  integrity sha512-MRn/NP3dee8yL5QhbSA6riuwkS+UOcsPUMOIOG3KMUQpuor/2TopdRBu8QaaB4fGU+gz/bzyDWt0FtUbeJ8H1A==
 
 "@types/normalize-package-data@^2.4.0":
   version "2.4.0"
@@ -1923,14 +1923,14 @@ [email protected]:
     resolve "^1.17.0"
     tsconfig-paths "^3.9.0"
 
-eslint-plugin-jsdoc@28.6.1:
-  version "28.6.1"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-28.6.1.tgz#c9e9da59d0d3cef4fb45ffb91c0acde43af4e418"
-  integrity sha512-Z3y7hcNPDuhL339D1KOf9SY8pMAxYxhaG4QLtu3KVn20k/hNF1u6WQv44wvuSCb6OfPJ4say37RUlSNqIjR+mw==
+eslint-plugin-jsdoc@29.1.2:
+  version "29.1.2"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-29.1.2.tgz#542beba99946cb8d184e5261ebc632b24673f825"
+  integrity sha512-s1uJcPcjZQ4Z5i98T3zWkp/gzJ9AtHGXXg0zxd0wCnFzX8RQU6awdUokUlBFMoWZJZxdCAXDtEIQBRfr/Lrsjw==
   dependencies:
     comment-parser "^0.7.5"
     debug "^4.1.1"
-    jsdoctypeparser "^7.0.0"
+    jsdoctypeparser "^8.0.0"
     lodash "^4.17.15"
     regextras "^0.7.1"
     semver "^7.3.2"
@@ -3156,10 +3156,10 @@ jsbn@~0.1.0:
   resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
   integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
 
-jsdoctypeparser@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/jsdoctypeparser/-/jsdoctypeparser-7.0.0.tgz#957192fbcb8c574240092cca4635383a6ed706eb"
-  integrity sha512-6vWPn5qSy+MbgCVjXsQKVkRywhs+IxFU7Chw72DKsWoGueYp6QX8eTc55+EA0yPGYfhmglb1gfi283asXirfGQ==
+jsdoctypeparser@^8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/jsdoctypeparser/-/jsdoctypeparser-8.0.0.tgz#a04a944539d3f86e30040c1ece6f6730f865f81a"
+  integrity sha512-eLCs6s4JqN8TjFJfgdiLHRvogLhOAJz+5RIA2FtoMe6ZDyuvghvppnlIToqAEnVbxRqLMrfnNXpW8FpmR6IMBw==
 
 jsesc@^2.5.1:
   version "2.5.2"
@@ -5166,10 +5166,10 @@ tough-cookie@~2.5.0:
     psl "^1.1.28"
     punycode "^2.1.1"
 
-ts-loader@7.0.5:
-  version "7.0.5"
-  resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-7.0.5.tgz#789338fb01cb5dc0a33c54e50558b34a73c9c4c5"
-  integrity sha512-zXypEIT6k3oTc+OZNx/cqElrsbBtYqDknf48OZos0NQ3RTt045fBIU8RRSu+suObBzYB355aIPGOe/3kj9h7Ig==
+ts-loader@8.0.0:
+  version "8.0.0"
+  resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.0.tgz#faf4b1617dcc4a24c2925d92c5b19e9c6621064d"
+  integrity sha512-giEW167rtK1V6eX/DnXEtOgcawwoIp6hqznqYNNSmraUZOq36zMhwBq12JMlYhxf50BC58bscsTSKKtE42zAuw==
   dependencies:
     chalk "^2.3.0"
     enhanced-resolve "^4.0.0"
@@ -5432,10 +5432,10 @@ [email protected]:
     v8-compile-cache "^2.1.1"
     yargs "^13.3.2"
 
-webpack-node-externals@1.7.2:
-  version "1.7.2"
-  resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-1.7.2.tgz#6e1ee79ac67c070402ba700ef033a9b8d52ac4e3"
-  integrity sha512-ajerHZ+BJKeCLviLUUmnyd5B4RavLF76uv3cs6KNuO8W+HuQaEs0y0L7o40NQxdPy5w0pcv8Ew7yPUAQG0UdCg==
+webpack-node-externals@2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-2.3.0.tgz#c884c07103de080284e17c195fe87c68e2b9c668"
+  integrity sha512-d1scCn/L5hv73GMOlqSTO6ykLWOiUrZfn54xQYf7u0yGLlUSf5trq6HV/Gw8JIpH2NEyXS7bJec1gk9YR/Qdqw==
 
 webpack-sources@^1.4.0, webpack-sources@^1.4.1:
   version "1.4.3"

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini