Options.ts 12 KB

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