JavaScriptObfuscatorCLI.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import { Command } from 'commander';
  2. import * as fs from 'fs';
  3. import * as mkdirp from 'mkdirp';
  4. import * as path from 'path';
  5. import { execSync } from "child_process";
  6. import { IOptionsPreset } from "../interfaces/IOptionsPreset";
  7. import { DEFAULT_PRESET } from "../preset-options/DefaultPreset";
  8. import { JavaScriptObfuscator } from "../JavaScriptObfuscator";
  9. import { Utils } from "../Utils";
  10. export class JavaScriptObfuscatorCLI {
  11. /**
  12. * @type {string[]}
  13. */
  14. private static availableInputExtensions: string[] = [
  15. '.js'
  16. ];
  17. /**
  18. * @type {BufferEncoding}
  19. */
  20. private static encoding: BufferEncoding = 'utf8';
  21. /**
  22. * @type {string}
  23. */
  24. private static packageName: string = 'javascript-obfuscator';
  25. /**
  26. * @type {string[]}
  27. */
  28. private arguments: string[];
  29. /**
  30. * @type {commander.ICommand}
  31. */
  32. private commands: commander.ICommand;
  33. /**
  34. * @type {string[]}
  35. */
  36. private rawArguments: string[];
  37. /**
  38. * @type {string}
  39. */
  40. private data: string = '';
  41. /**
  42. * @type {string}
  43. */
  44. private inputPath: string;
  45. /**
  46. * @param argv
  47. */
  48. constructor (argv: string[]) {
  49. this.rawArguments = argv;
  50. this.arguments = this.rawArguments.slice(2);
  51. }
  52. /**
  53. * @returns {string}
  54. */
  55. private static getBuildVersion (): string {
  56. return execSync(`npm info ${JavaScriptObfuscatorCLI.packageName} version`, {
  57. encoding: JavaScriptObfuscatorCLI.encoding
  58. });
  59. }
  60. /**
  61. * @param filePath
  62. */
  63. private static isFilePath (filePath: string): boolean {
  64. try {
  65. return fs.statSync(filePath).isFile();
  66. } catch (e) {
  67. return false;
  68. }
  69. }
  70. /**
  71. * @param value
  72. * @returns {boolean}
  73. */
  74. private static parseBoolean (value: string): boolean {
  75. return value === 'true' || value === '1';
  76. }
  77. public run (): void {
  78. this.configureCommands();
  79. if (!this.arguments.length || Utils.arrayContains(this.arguments, '--help')) {
  80. this.commands.outputHelp();
  81. return;
  82. }
  83. this.inputPath = this.getInputPath();
  84. this.getData();
  85. this.processData();
  86. }
  87. /**
  88. * @returns {IOptionsPreset}
  89. */
  90. private buildOptions (): IOptionsPreset {
  91. let options: IOptionsPreset = {},
  92. availableOptions: string[] = Object.keys(DEFAULT_PRESET);
  93. for (let option in this.commands) {
  94. if (!this.commands.hasOwnProperty(option)) {
  95. continue;
  96. }
  97. if (!Utils.arrayContains(availableOptions, option)) {
  98. continue;
  99. }
  100. options[option] = (<any>this.commands)[option];
  101. }
  102. return Object.assign({}, DEFAULT_PRESET, options);
  103. }
  104. private configureCommands (): void {
  105. this.commands = new Command()
  106. .version(JavaScriptObfuscatorCLI.getBuildVersion(), '-v, --version')
  107. .usage('<inputPath> [options]')
  108. .option('-o, --output <path>', 'Output path for obfuscated code')
  109. .option('--compact <boolean>', 'Disable one line output code compacting', JavaScriptObfuscatorCLI.parseBoolean)
  110. .option('--debugProtection <boolean>', 'Disable browser Debug panel (can cause DevTools enabled browser freeze)', JavaScriptObfuscatorCLI.parseBoolean)
  111. .option('--debugProtectionInterval <boolean>', 'Disable browser Debug panel even after page was loaded (can cause DevTools enabled browser freeze)', JavaScriptObfuscatorCLI.parseBoolean)
  112. .option('--disableConsoleOutput <boolean>', 'Allow console.log, console.info, console.error and console.warn messages output into browser console', JavaScriptObfuscatorCLI.parseBoolean)
  113. .option('--encodeUnicodeLiterals <boolean>', 'All literals in Unicode array become encoded in Base64 (this option can slightly slow down your code speed)', JavaScriptObfuscatorCLI.parseBoolean)
  114. .option('--reservedNames <list>', 'Disable obfuscation of variable names, function names and names of function parameters that match the passed RegExp patterns (comma separated)', (val: string) => val.split(','))
  115. .option('--rotateUnicodeArray <boolean>', 'Disable rotation of unicode array values during obfuscation', JavaScriptObfuscatorCLI.parseBoolean)
  116. .option('--selfDefending <boolean>', 'Disables self-defending for obfuscated code', JavaScriptObfuscatorCLI.parseBoolean)
  117. .option('--unicodeArray <boolean>', 'Disables gathering of all literal strings into an array and replacing every literal string with an array call', JavaScriptObfuscatorCLI.parseBoolean)
  118. .option('--unicodeArrayThreshold <number>', 'The probability that the literal string will be inserted into unicodeArray (Default: 0.8, Min: 0, Max: 1)', parseFloat)
  119. .option('--wrapUnicodeArrayCalls <boolean>', 'Disables usage of special access function instead of direct array call', JavaScriptObfuscatorCLI.parseBoolean)
  120. .parse(this.rawArguments);
  121. this.commands.on('--help', () => {
  122. console.log(' Examples:\n');
  123. console.log(' %> javascript-obfuscator in.js --compact true --selfDefending false');
  124. console.log(' %> javascript-obfuscator in.js --output out.js --compact true --selfDefending false');
  125. console.log('');
  126. });
  127. }
  128. private getData (): void {
  129. this.data = fs.readFileSync(this.inputPath, JavaScriptObfuscatorCLI.encoding);
  130. }
  131. /**
  132. * @returns {string}
  133. */
  134. private getInputPath (): string {
  135. let inputPath: string = this.arguments[0];
  136. if (!JavaScriptObfuscatorCLI.isFilePath(inputPath)) {
  137. throw new ReferenceError(`First argument must be a valid file path`);
  138. }
  139. if (!Utils.arrayContains(JavaScriptObfuscatorCLI.availableInputExtensions, path.extname(inputPath))) {
  140. throw new ReferenceError(`Input file must have .js extension`);
  141. }
  142. return inputPath;
  143. }
  144. /**
  145. * @returns {string}
  146. */
  147. private getOutputPath (): string {
  148. let outputPath: string = (<any>this.commands).output;
  149. if (outputPath) {
  150. return outputPath;
  151. }
  152. return this.inputPath
  153. .split('.')
  154. .map<string>((value: string, index: number) => {
  155. return index === 0 ? `${value}-obfuscated` : value;
  156. })
  157. .join('.');
  158. }
  159. private processData (): void {
  160. let outputPath: string = this.getOutputPath(),
  161. dirName: string = path.dirname(outputPath);
  162. mkdirp.sync(dirName);
  163. fs.writeFileSync(
  164. this.getOutputPath(),
  165. JavaScriptObfuscator.obfuscate(this.data, this.buildOptions()),
  166. {
  167. encoding: JavaScriptObfuscatorCLI.encoding
  168. }
  169. );
  170. }
  171. }