Options.ts 11 KB

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