Options.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. import { inject, injectable } from 'inversify';
  2. import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
  3. import {
  4. ArrayNotEmpty,
  5. ArrayUnique,
  6. IsArray,
  7. IsBoolean,
  8. IsIn,
  9. IsNumber,
  10. IsString,
  11. IsUrl,
  12. Max,
  13. Min,
  14. ValidateIf,
  15. validateSync,
  16. ValidationError,
  17. ValidatorOptions
  18. } from 'class-validator';
  19. import { TInputOptions } from '../types/options/TInputOptions';
  20. import { TOptionsPreset } from '../types/options/TOptionsPreset';
  21. import { TStringArrayIndexesType } from '../types/options/TStringArrayIndexesType';
  22. import { TStringArrayEncoding } from '../types/options/TStringArrayEncoding';
  23. import { TStringArrayWrappersType } from '../types/options/TStringArrayWrappersType';
  24. import { TTypeFromEnum } from '../types/utils/TTypeFromEnum';
  25. import { IOptions } from '../interfaces/options/IOptions';
  26. import { IOptionsNormalizer } from '../interfaces/options/IOptionsNormalizer';
  27. import { IdentifierNamesGenerator } from '../enums/generators/identifier-names-generators/IdentifierNamesGenerator';
  28. import { ObfuscationTarget } from '../enums/ObfuscationTarget';
  29. import { OptionsPreset } from '../enums/options/presets/OptionsPreset';
  30. import { SourceMapMode } from '../enums/source-map/SourceMapMode';
  31. import { StringArrayIndexesType } from '../enums/node-transformers/string-array-transformers/StringArrayIndexesType';
  32. import { StringArrayEncoding } from '../enums/node-transformers/string-array-transformers/StringArrayEncoding';
  33. import { StringArrayWrappersType } from '../enums/node-transformers/string-array-transformers/StringArrayWrappersType';
  34. import { DEFAULT_PRESET } from './presets/Default';
  35. import { LOW_OBFUSCATION_PRESET } from './presets/LowObfuscation';
  36. import { MEDIUM_OBFUSCATION_PRESET } from './presets/MediumObfuscation';
  37. import { HIGH_OBFUSCATION_PRESET } from './presets/HighObfuscation';
  38. import { ValidationErrorsFormatter } from './ValidationErrorsFormatter';
  39. import { IsAllowedForObfuscationTargets } from './validators/IsAllowedForObfuscationTargets';
  40. @injectable()
  41. export class Options implements IOptions {
  42. /**
  43. * @type {Map<TOptionsPreset, TInputOptions>}
  44. */
  45. private static readonly optionPresetsMap: Map<TOptionsPreset, TInputOptions> = new Map([
  46. [OptionsPreset.Default, DEFAULT_PRESET],
  47. [OptionsPreset.LowObfuscation, LOW_OBFUSCATION_PRESET],
  48. [OptionsPreset.MediumObfuscation, MEDIUM_OBFUSCATION_PRESET],
  49. [OptionsPreset.HighObfuscation, HIGH_OBFUSCATION_PRESET]
  50. ]);
  51. /**
  52. * @type {ValidatorOptions}
  53. */
  54. private static readonly validatorOptions: ValidatorOptions = {
  55. forbidUnknownValues: true,
  56. validationError: {
  57. target: false
  58. }
  59. };
  60. /**
  61. * @type {boolean}
  62. */
  63. @IsBoolean()
  64. public readonly compact!: boolean;
  65. /**
  66. * @type {boolean}
  67. */
  68. @IsBoolean()
  69. public readonly controlFlowFlattening!: boolean;
  70. /**
  71. * @type {boolean}
  72. */
  73. @IsNumber()
  74. @Min(0)
  75. @Max(1)
  76. public readonly controlFlowFlatteningThreshold!: number;
  77. /**
  78. * @type {boolean}
  79. */
  80. @IsBoolean()
  81. public readonly deadCodeInjection!: boolean;
  82. /**
  83. * @type {number}
  84. */
  85. @IsNumber()
  86. public readonly deadCodeInjectionThreshold!: number;
  87. /**
  88. * @type {boolean}
  89. */
  90. @IsBoolean()
  91. public readonly debugProtection!: boolean;
  92. /**
  93. * @type {boolean}
  94. */
  95. @IsBoolean()
  96. public readonly debugProtectionInterval!: boolean;
  97. /**
  98. * @type {boolean}
  99. */
  100. @IsBoolean()
  101. public readonly disableConsoleOutput!: boolean;
  102. /**
  103. * @type {string[]}
  104. */
  105. @IsArray()
  106. @ArrayUnique()
  107. @IsString({
  108. each: true
  109. })
  110. @IsAllowedForObfuscationTargets([
  111. ObfuscationTarget.Browser,
  112. ObfuscationTarget.BrowserNoEval,
  113. ])
  114. public readonly domainLock!: string[];
  115. /**
  116. * @type {string[]}
  117. */
  118. @IsArray()
  119. @ArrayUnique()
  120. @IsString({
  121. each: true
  122. })
  123. public readonly forceTransformStrings!: string[];
  124. /**
  125. * @type {IdentifierNamesGenerator}
  126. */
  127. @IsIn([
  128. IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator,
  129. IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
  130. IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
  131. IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator
  132. ])
  133. public readonly identifierNamesGenerator!: TTypeFromEnum<typeof IdentifierNamesGenerator>;
  134. /**
  135. * @type {string}
  136. */
  137. @IsString()
  138. public readonly identifiersPrefix!: string;
  139. @IsArray()
  140. @ArrayUnique()
  141. @IsString({
  142. each: true
  143. })
  144. @ValidateIf((options: IOptions) =>
  145. options.identifierNamesGenerator === IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
  146. )
  147. @ArrayNotEmpty()
  148. public readonly identifiersDictionary!: string[];
  149. /**
  150. * @type {boolean}
  151. */
  152. @IsBoolean()
  153. public readonly ignoreRequireImports!: boolean;
  154. /**
  155. * @type {string}
  156. */
  157. @IsString()
  158. public readonly inputFileName!: string;
  159. /**
  160. * @type {boolean}
  161. */
  162. @IsBoolean()
  163. public readonly log!: boolean;
  164. /**
  165. * @type {boolean}
  166. */
  167. @IsBoolean()
  168. public readonly numbersToExpressions!: boolean;
  169. /**
  170. * @type {TOptionsPreset}
  171. */
  172. @IsIn([
  173. OptionsPreset.Default,
  174. OptionsPreset.LowObfuscation,
  175. OptionsPreset.MediumObfuscation,
  176. OptionsPreset.HighObfuscation
  177. ])
  178. public readonly optionsPreset!: TOptionsPreset;
  179. /**
  180. * @type {boolean}
  181. */
  182. @IsBoolean()
  183. public readonly renameGlobals!: boolean;
  184. /**
  185. * @type {boolean}
  186. */
  187. @IsBoolean()
  188. public readonly renameProperties!: boolean;
  189. /**
  190. * @type {string[]}
  191. */
  192. @IsArray()
  193. @ArrayUnique()
  194. @IsString({
  195. each: true
  196. })
  197. public readonly reservedNames!: string[];
  198. /**
  199. * @type {string[]}
  200. */
  201. @IsArray()
  202. @ArrayUnique()
  203. @IsString({
  204. each: true
  205. })
  206. public readonly reservedStrings!: string[];
  207. /**
  208. * @type {boolean}
  209. */
  210. @IsBoolean()
  211. public readonly rotateStringArray!: boolean;
  212. /**
  213. * @type {boolean}
  214. */
  215. @IsBoolean()
  216. public readonly selfDefending!: boolean;
  217. /**
  218. * @type {boolean}
  219. */
  220. @IsBoolean()
  221. public readonly shuffleStringArray!: boolean;
  222. /**
  223. * @type {boolean}
  224. */
  225. @IsBoolean()
  226. public readonly simplify!: boolean;
  227. /**
  228. * @type {boolean}
  229. */
  230. @IsBoolean()
  231. public readonly sourceMap!: boolean;
  232. /**
  233. * @type {string}
  234. */
  235. @IsString()
  236. @ValidateIf((options: IOptions) => Boolean(options.sourceMapBaseUrl))
  237. @IsUrl({
  238. require_protocol: true,
  239. require_tld: false,
  240. require_valid_protocol: true
  241. })
  242. public readonly sourceMapBaseUrl!: string;
  243. /**
  244. * @type {string}
  245. */
  246. @IsString()
  247. public readonly sourceMapFileName!: string;
  248. /**
  249. * @type {SourceMapMode}
  250. */
  251. @IsIn([SourceMapMode.Inline, SourceMapMode.Separate])
  252. public readonly sourceMapMode!: TTypeFromEnum<typeof SourceMapMode>;
  253. /**
  254. * @type {boolean}
  255. */
  256. @IsBoolean()
  257. public readonly splitStrings!: boolean;
  258. /**
  259. * @type {number}
  260. */
  261. @IsNumber()
  262. @ValidateIf((options: IOptions) => Boolean(options.splitStrings))
  263. @Min(1)
  264. public readonly splitStringsChunkLength!: number;
  265. /**
  266. * @type {boolean}
  267. */
  268. @IsBoolean()
  269. public readonly stringArray!: boolean;
  270. /**
  271. * @type {TStringArrayEncoding[]}
  272. */
  273. @IsArray()
  274. @ArrayUnique()
  275. @IsIn([StringArrayEncoding.None, StringArrayEncoding.Base64, StringArrayEncoding.Rc4], { each: true })
  276. public readonly stringArrayEncoding!: TStringArrayEncoding[];
  277. /**
  278. * @type {TStringArrayIndexesType[]}
  279. */
  280. @IsArray()
  281. @ArrayNotEmpty()
  282. @ArrayUnique()
  283. @IsIn([StringArrayIndexesType.HexadecimalNumber, StringArrayIndexesType.HexadecimalNumericString], { each: true })
  284. public readonly stringArrayIndexesType!: TStringArrayIndexesType[];
  285. /**
  286. * @type {boolean}
  287. */
  288. @IsBoolean()
  289. public readonly stringArrayIndexShift!: boolean;
  290. /**
  291. * @type {boolean}
  292. */
  293. @IsBoolean()
  294. public readonly stringArrayWrappersChainedCalls!: boolean;
  295. /**
  296. * @type {boolean}
  297. */
  298. @IsNumber()
  299. @Min(0)
  300. public readonly stringArrayWrappersCount!: number;
  301. /**
  302. * @type {boolean}
  303. */
  304. @IsNumber()
  305. @Min(2)
  306. public readonly stringArrayWrappersParametersMaxCount!: number;
  307. /**
  308. * @type {TStringArrayWrappersType}
  309. */
  310. @IsIn([StringArrayWrappersType.Variable, StringArrayWrappersType.Function])
  311. public readonly stringArrayWrappersType!: TStringArrayWrappersType;
  312. /**
  313. * @type {number}
  314. */
  315. @IsNumber()
  316. @Min(0)
  317. @Max(1)
  318. public readonly stringArrayThreshold!: number;
  319. /**
  320. * @type {ObfuscationTarget}
  321. */
  322. @IsIn([ObfuscationTarget.Browser, ObfuscationTarget.BrowserNoEval, ObfuscationTarget.Node])
  323. public readonly target!: TTypeFromEnum<typeof ObfuscationTarget>;
  324. /**
  325. * @type {boolean}
  326. */
  327. @IsBoolean()
  328. public readonly transformObjectKeys!: boolean;
  329. /**
  330. * @type {boolean}
  331. */
  332. @IsBoolean()
  333. public readonly unicodeEscapeSequence!: boolean;
  334. /**
  335. * @type {string | number}
  336. */
  337. public readonly seed!: string | number;
  338. /**
  339. * @param {TInputOptions} inputOptions
  340. * @param {IOptionsNormalizer} optionsNormalizer
  341. */
  342. public constructor (
  343. @inject(ServiceIdentifiers.TInputOptions) inputOptions: TInputOptions,
  344. @inject(ServiceIdentifiers.IOptionsNormalizer) optionsNormalizer: IOptionsNormalizer
  345. ) {
  346. const optionsPreset: TInputOptions = Options.getOptionsByPreset(
  347. inputOptions.optionsPreset ?? OptionsPreset.Default
  348. );
  349. Object.assign(this, optionsPreset, inputOptions);
  350. const errors: ValidationError[] = validateSync(this, Options.validatorOptions);
  351. if (errors.length) {
  352. throw new ReferenceError(`Validation failed. errors:\n${ValidationErrorsFormatter.format(errors)}`);
  353. }
  354. Object.assign(this, optionsNormalizer.normalize(this));
  355. }
  356. /**
  357. * @param {TOptionsPreset} optionsPreset
  358. * @returns {TInputOptions}
  359. */
  360. public static getOptionsByPreset (optionsPreset: TOptionsPreset): TInputOptions {
  361. const options: TInputOptions | null = Options.optionPresetsMap.get(optionsPreset) ?? null;
  362. if (!options) {
  363. throw new Error(`Options for preset name \`${optionsPreset}\` are not found`);
  364. }
  365. return options;
  366. }
  367. }