JavaScriptObfuscatorCLI.ts 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. import * as commander from 'commander';
  2. import * as path from 'path';
  3. import { TStringArrayEncoding } from '../types/TStringArrayEncoding';
  4. import { IObfuscationResult } from '../interfaces/IObfuscationResult';
  5. import { IObfuscatorOptions } from '../interfaces/IObfuscatorOptions';
  6. import { SourceMapMode } from '../enums/SourceMapMode';
  7. import { StringArrayEncoding } from '../enums/StringArrayEncoding';
  8. import { DEFAULT_PRESET } from '../preset-options/DefaultPreset';
  9. import { CLIUtils } from './CLIUtils';
  10. import { JavaScriptObfuscator } from '../JavaScriptObfuscator';
  11. import { Utils } from '../Utils';
  12. export class JavaScriptObfuscatorCLI {
  13. /**
  14. * @type {string[]}
  15. */
  16. private arguments: string[];
  17. /**
  18. * @type {commander.ICommand}
  19. */
  20. private commands: commander.ICommand;
  21. /**
  22. * @type {string}
  23. */
  24. private data: string = '';
  25. /**
  26. * @type {string}
  27. */
  28. private inputPath: string;
  29. /**
  30. * @type {string[]}
  31. */
  32. private rawArguments: string[];
  33. /**
  34. * @param argv
  35. */
  36. constructor (argv: string[]) {
  37. this.rawArguments = argv;
  38. this.arguments = this.rawArguments.slice(2);
  39. }
  40. /**
  41. * @returns {string}
  42. */
  43. private static getBuildVersion (): string {
  44. return CLIUtils.getPackageConfig().version;
  45. }
  46. /**
  47. * @param value
  48. * @returns {boolean}
  49. */
  50. private static parseBoolean (value: string): boolean {
  51. return value === 'true' || value === '1';
  52. }
  53. /**
  54. * @param value
  55. * @returns {string}
  56. */
  57. private static parseSourceMapMode (value: string): string {
  58. let availableMode: boolean = Object
  59. .keys(SourceMapMode)
  60. .some((key: string): boolean => {
  61. return SourceMapMode[key] === value;
  62. });
  63. if (!availableMode) {
  64. throw new ReferenceError('Invalid value of `--sourceMapMode` option');
  65. }
  66. return value;
  67. }
  68. /**
  69. * @param value
  70. * @returns {TStringArrayEncoding}
  71. */
  72. private static parseStringArrayEncoding (value: string): TStringArrayEncoding {
  73. switch (value) {
  74. case 'true':
  75. case '1':
  76. case StringArrayEncoding.base64:
  77. return true;
  78. case StringArrayEncoding.rc4:
  79. return StringArrayEncoding.rc4;
  80. default:
  81. return false;
  82. }
  83. }
  84. public run (): void {
  85. this.configureCommands();
  86. if (!this.arguments.length || Utils.arrayContains(this.arguments, '--help')) {
  87. this.commands.outputHelp();
  88. return;
  89. }
  90. this.inputPath = this.arguments[0];
  91. CLIUtils.validateInputPath(this.inputPath);
  92. this.getData();
  93. this.processData();
  94. }
  95. /**
  96. * @returns {IObfuscatorOptions}
  97. */
  98. private buildOptions (): IObfuscatorOptions {
  99. let obfuscatorOptions: IObfuscatorOptions = {},
  100. availableOptions: string[] = Object.keys(DEFAULT_PRESET);
  101. for (const option in this.commands) {
  102. if (!this.commands.hasOwnProperty(option)) {
  103. continue;
  104. }
  105. if (!Utils.arrayContains(availableOptions, option)) {
  106. continue;
  107. }
  108. obfuscatorOptions[option] = (<any>this.commands)[option];
  109. }
  110. return Object.assign({}, DEFAULT_PRESET, obfuscatorOptions);
  111. }
  112. private configureCommands (): void {
  113. this.commands = new commander.Command()
  114. .version(JavaScriptObfuscatorCLI.getBuildVersion(), '-v, --version')
  115. .usage('<inputPath> [options]')
  116. .option('-o, --output <path>', 'Output path for obfuscated code')
  117. .option('--compact <boolean>', 'Disable one line output code compacting', JavaScriptObfuscatorCLI.parseBoolean)
  118. .option('--controlFlowFlattening <boolean>', 'Enables control flow flattening', JavaScriptObfuscatorCLI.parseBoolean)
  119. .option('--debugProtection <boolean>', 'Disable browser Debug panel (can cause DevTools enabled browser freeze)', JavaScriptObfuscatorCLI.parseBoolean)
  120. .option('--debugProtectionInterval <boolean>', 'Disable browser Debug panel even after page was loaded (can cause DevTools enabled browser freeze)', JavaScriptObfuscatorCLI.parseBoolean)
  121. .option('--disableConsoleOutput <boolean>', 'Allow console.log, console.info, console.error and console.warn messages output into browser console', JavaScriptObfuscatorCLI.parseBoolean)
  122. .option('--domainLock <list>', 'Blocks the execution of the code in domains that do not match the passed RegExp patterns (comma separated)', (val: string) => val.split(','))
  123. .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(','))
  124. .option('--rotateStringArray <boolean>', 'Disable rotation of unicode array values during obfuscation', JavaScriptObfuscatorCLI.parseBoolean)
  125. .option('--seed <number>', 'Sets seed for random generator. This is useful for creating repeatable results.', parseFloat)
  126. .option('--selfDefending <boolean>', 'Disables self-defending for obfuscated code', JavaScriptObfuscatorCLI.parseBoolean)
  127. .option('--sourceMap <boolean>', 'Enables source map generation', JavaScriptObfuscatorCLI.parseBoolean)
  128. .option('--sourceMapBaseUrl <string>', 'Sets base url to the source map import url when `--sourceMapMode=separate`')
  129. .option('--sourceMapFileName <string>', 'Sets file name for output source map when `--sourceMapMode=separate`')
  130. .option(
  131. '--sourceMapMode <string> [inline, separate]',
  132. 'Specify source map output mode',
  133. JavaScriptObfuscatorCLI.parseSourceMapMode
  134. )
  135. .option('--stringArray <boolean>', 'Disables gathering of all literal strings into an array and replacing every literal string with an array call', JavaScriptObfuscatorCLI.parseBoolean)
  136. .option('--stringArrayEncoding <boolean|string> [true, false, base64, rc4]', 'Encodes all strings in strings array using base64 or rc4 (this option can slow down your code speed', JavaScriptObfuscatorCLI.parseStringArrayEncoding)
  137. .option('--stringArrayThreshold <number>', 'The probability that the literal string will be inserted into stringArray (Default: 0.8, Min: 0, Max: 1)', parseFloat)
  138. .option('--unicodeEscapeSequence <boolean>', 'Allows to enable/disable string conversion to unicode escape sequence', JavaScriptObfuscatorCLI.parseBoolean)
  139. .parse(this.rawArguments);
  140. this.commands.on('--help', () => {
  141. console.log(' Examples:\n');
  142. console.log(' %> javascript-obfuscator in.js --compact true --selfDefending false');
  143. console.log(' %> javascript-obfuscator in.js --output out.js --compact true --selfDefending false');
  144. console.log('');
  145. });
  146. }
  147. private getData (): void {
  148. this.data = CLIUtils.readFile(this.inputPath);
  149. }
  150. private processData (): void {
  151. let options: IObfuscatorOptions = this.buildOptions(),
  152. outputCodePath: string = CLIUtils.getOutputCodePath((<any>this.commands).output, this.inputPath);
  153. if (options.sourceMap) {
  154. this.processDataWithSourceMap(outputCodePath, options);
  155. } else {
  156. this.processDataWithoutSourceMap(outputCodePath, options);
  157. }
  158. }
  159. /**
  160. * @param outputCodePath
  161. * @param options
  162. */
  163. private processDataWithoutSourceMap (outputCodePath: string, options: IObfuscatorOptions): void {
  164. let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(this.data, options).getObfuscatedCode();
  165. CLIUtils.writeFile(outputCodePath, obfuscatedCode);
  166. }
  167. /**
  168. * @param outputCodePath
  169. * @param options
  170. */
  171. private processDataWithSourceMap (outputCodePath: string, options: IObfuscatorOptions): void {
  172. let outputSourceMapPath: string = CLIUtils.getOutputSourceMapPath(
  173. outputCodePath,
  174. options.sourceMapFileName || ''
  175. );
  176. options.sourceMapFileName = path.basename(outputSourceMapPath);
  177. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(this.data, options);
  178. CLIUtils.writeFile(outputCodePath, obfuscationResult.getObfuscatedCode());
  179. if (options.sourceMapMode === 'separate' && obfuscationResult.getSourceMap()) {
  180. CLIUtils.writeFile(outputSourceMapPath, obfuscationResult.getSourceMap());
  181. }
  182. }
  183. }