Options.ts 11 KB

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