JavaScriptObfuscatorCLI.ts 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import * as commander from 'commander';
  2. import * as path from 'path';
  3. import { TInputOptions } from '../types/options/TInputOptions';
  4. import { IObfuscationResult } from '../interfaces/IObfuscationResult';
  5. import { DEFAULT_PRESET } from '../options/presets/Default';
  6. import { BooleanSanitizer } from './sanitizers/BooleanSanitizer';
  7. import { SourceMapModeSanitizer } from './sanitizers/SourceMapModeSanitizer';
  8. import { StringArrayEncodingSanitizer } from './sanitizers/StringArrayEncodingSanitizer';
  9. import { CLIUtils } from './utils/CLIUtils';
  10. import { JavaScriptObfuscator } from '../JavaScriptObfuscator';
  11. export class JavaScriptObfuscatorCLI {
  12. /**
  13. * @type {string[]}
  14. */
  15. private readonly arguments: string[];
  16. /**
  17. * @type {string[]}
  18. */
  19. private readonly rawArguments: string[];
  20. /**
  21. * @type {commander.CommanderStatic}
  22. */
  23. private commands: commander.CommanderStatic;
  24. /**
  25. * @type {string}
  26. */
  27. private inputPath: string;
  28. /**
  29. * @type {string}
  30. */
  31. private sourceCode: string = '';
  32. /**
  33. * @param {string[]} argv
  34. */
  35. constructor (argv: string[]) {
  36. this.rawArguments = argv;
  37. this.arguments = this.rawArguments.slice(2);
  38. this.commands = <commander.CommanderStatic>(new commander.Command());
  39. }
  40. public run (): void {
  41. this.configureCommands();
  42. this.configureHelp();
  43. if (!this.arguments.length || this.arguments.includes('--help')) {
  44. this.commands.outputHelp();
  45. return;
  46. }
  47. this.inputPath = this.arguments[0];
  48. CLIUtils.validateInputPath(this.inputPath);
  49. this.getData();
  50. this.processData();
  51. }
  52. /**
  53. * @returns {TInputOptions}
  54. */
  55. private buildOptions (): TInputOptions {
  56. const inputOptions: TInputOptions = {};
  57. const availableOptions: string[] = Object.keys(DEFAULT_PRESET);
  58. for (const option in this.commands) {
  59. if (!this.commands.hasOwnProperty(option)) {
  60. continue;
  61. }
  62. if (!availableOptions.includes(option)) {
  63. continue;
  64. }
  65. (<any>inputOptions)[option] = (<any>this.commands)[option];
  66. }
  67. return {
  68. ...DEFAULT_PRESET,
  69. ...inputOptions
  70. };
  71. }
  72. private configureCommands (): void {
  73. this.commands
  74. .version(CLIUtils.getPackageConfig().version, '-v, --version')
  75. .usage('<inputPath> [options]')
  76. .option(
  77. '-o, --output <path>',
  78. 'Output path for obfuscated code'
  79. )
  80. .option(
  81. '--compact <boolean>',
  82. 'Disable one line output code compacting',
  83. BooleanSanitizer
  84. )
  85. .option(
  86. '--controlFlowFlattening <boolean>',
  87. 'Enables control flow flattening',
  88. BooleanSanitizer
  89. )
  90. .option(
  91. '--controlFlowFlatteningThreshold <number>',
  92. 'The probability that the control flow flattening transformation will be applied to the node',
  93. parseFloat
  94. )
  95. .option(
  96. '--deadCodeInjection <boolean>',
  97. 'Enables dead code injection',
  98. BooleanSanitizer
  99. )
  100. .option(
  101. '--deadCodeInjectionThreshold <number>',
  102. 'The probability that the dead code injection transformation will be applied to the node',
  103. parseFloat
  104. )
  105. .option(
  106. '--debugProtection <boolean>',
  107. 'Disable browser Debug panel (can cause DevTools enabled browser freeze)',
  108. BooleanSanitizer
  109. )
  110. .option(
  111. '--debugProtectionInterval <boolean>',
  112. 'Disable browser Debug panel even after page was loaded (can cause DevTools enabled browser freeze)',
  113. BooleanSanitizer
  114. )
  115. .option(
  116. '--disableConsoleOutput <boolean>',
  117. 'Allow console.log, console.info, console.error and console.warn messages output into browser console',
  118. BooleanSanitizer
  119. )
  120. .option(
  121. '--domainLock <list>',
  122. 'Blocks the execution of the code in domains that do not match the passed RegExp patterns (comma separated)',
  123. (value: string) => value.split(',')
  124. )
  125. .option(
  126. '--mangle <boolean>', 'Enables mangling of variable names',
  127. BooleanSanitizer
  128. )
  129. .option(
  130. '--reservedNames <list>',
  131. 'Disable obfuscation of variable names, function names and names of function parameters that match the passed RegExp patterns (comma separated)',
  132. (value: string) => value.split(',')
  133. )
  134. .option(
  135. '--rotateStringArray <boolean>', 'Disable rotation of unicode array values during obfuscation',
  136. BooleanSanitizer
  137. )
  138. .option(
  139. '--seed <number>',
  140. 'Sets seed for random generator. This is useful for creating repeatable results.',
  141. parseFloat
  142. )
  143. .option(
  144. '--selfDefending <boolean>',
  145. 'Disables self-defending for obfuscated code',
  146. BooleanSanitizer
  147. )
  148. .option(
  149. '--sourceMap <boolean>',
  150. 'Enables source map generation',
  151. BooleanSanitizer
  152. )
  153. .option(
  154. '--sourceMapBaseUrl <string>',
  155. 'Sets base url to the source map import url when `--sourceMapMode=separate`'
  156. )
  157. .option(
  158. '--sourceMapFileName <string>',
  159. 'Sets file name for output source map when `--sourceMapMode=separate`'
  160. )
  161. .option(
  162. '--sourceMapMode <string> [inline, separate]',
  163. 'Specify source map output mode',
  164. SourceMapModeSanitizer
  165. )
  166. .option(
  167. '--stringArray <boolean>',
  168. 'Disables gathering of all literal strings into an array and replacing every literal string with an array call',
  169. BooleanSanitizer
  170. )
  171. .option(
  172. '--stringArrayEncoding <boolean|string> [true, false, base64, rc4]',
  173. 'Encodes all strings in strings array using base64 or rc4 (this option can slow down your code speed',
  174. StringArrayEncodingSanitizer
  175. )
  176. .option(
  177. '--stringArrayThreshold <number>',
  178. 'The probability that the literal string will be inserted into stringArray (Default: 0.8, Min: 0, Max: 1)',
  179. parseFloat
  180. )
  181. .option(
  182. '--unicodeEscapeSequence <boolean>',
  183. 'Allows to enable/disable string conversion to unicode escape sequence',
  184. BooleanSanitizer
  185. )
  186. .parse(this.rawArguments);
  187. }
  188. private configureHelp (): void {
  189. this.commands.on('--help', () => {
  190. console.log(' Examples:\n');
  191. console.log(' %> javascript-obfuscator in.js --compact true --selfDefending false');
  192. console.log(' %> javascript-obfuscator in.js --output out.js --compact true --selfDefending false');
  193. console.log('');
  194. });
  195. }
  196. private getData (): void {
  197. this.sourceCode = CLIUtils.readFile(this.inputPath);
  198. }
  199. private processData (): void {
  200. const options: TInputOptions = this.buildOptions();
  201. const outputCodePath: string = CLIUtils.getOutputCodePath((<any>this.commands).output, this.inputPath);
  202. if (options.sourceMap) {
  203. this.processDataWithSourceMap(outputCodePath, options);
  204. } else {
  205. this.processDataWithoutSourceMap(outputCodePath, options);
  206. }
  207. }
  208. /**
  209. * @param {string} outputCodePath
  210. * @param {TInputOptions} options
  211. */
  212. private processDataWithoutSourceMap (outputCodePath: string, options: TInputOptions): void {
  213. const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(this.sourceCode, options).getObfuscatedCode();
  214. CLIUtils.writeFile(outputCodePath, obfuscatedCode);
  215. }
  216. /**
  217. * @param {string} outputCodePath
  218. * @param {TInputOptions} options
  219. */
  220. private processDataWithSourceMap (outputCodePath: string, options: TInputOptions): void {
  221. const outputSourceMapPath: string = CLIUtils.getOutputSourceMapPath(
  222. outputCodePath,
  223. options.sourceMapFileName || ''
  224. );
  225. options = {
  226. ...options,
  227. sourceMapFileName: path.basename(outputSourceMapPath)
  228. };
  229. const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(this.sourceCode, options);
  230. CLIUtils.writeFile(outputCodePath, obfuscationResult.getObfuscatedCode());
  231. if (options.sourceMapMode === 'separate' && obfuscationResult.getSourceMap()) {
  232. CLIUtils.writeFile(outputSourceMapPath, obfuscationResult.getSourceMap());
  233. }
  234. }
  235. }