JavaScriptObfuscatorCLI.spec.ts 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065
  1. import * as fs from 'fs';
  2. import * as mkdirp from 'mkdirp';
  3. import * as path from 'path';
  4. import * as rimraf from 'rimraf';
  5. import * as sinon from 'sinon';
  6. import { assert } from 'chai';
  7. import { StdoutWriteMock } from '../../mocks/StdoutWriteMock';
  8. import { JavaScriptObfuscatorCLI } from '../../../src/JavaScriptObfuscatorCLIFacade';
  9. describe('JavaScriptObfuscatorCLI', function (): void {
  10. this.timeout(100000);
  11. const expectedError: RegExp = /Given input path must be a valid/;
  12. const fixturesDirName: string = path.join('test', 'fixtures');
  13. const fixtureFileName: string = 'sample.js';
  14. const fixtureFilePath: string = path.join(fixturesDirName, fixtureFileName);
  15. const outputDirName: string = path.join('test', 'tmp');
  16. const outputFileName: string = 'sample-obfuscated.js';
  17. const outputFilePath: string = path.join(outputDirName, outputFileName);
  18. const configDirName: string = path.join('test', 'fixtures');
  19. const configFileName: string = 'config.js';
  20. const configFilePath: string = path.join(configDirName, configFileName);
  21. describe('run', () => {
  22. before(() => {
  23. mkdirp.sync(outputDirName);
  24. });
  25. describe('Variant #1: obfuscation of single file', () => {
  26. describe('--output` option is set', () => {
  27. describe('Variant #1: input file path is before options', () => {
  28. let isFileExist: boolean;
  29. before(() => {
  30. JavaScriptObfuscatorCLI.obfuscate([
  31. 'node',
  32. 'javascript-obfuscator',
  33. fixtureFilePath,
  34. '--output',
  35. outputFilePath,
  36. '--compact',
  37. 'true',
  38. '--self-defending',
  39. '0'
  40. ]);
  41. isFileExist = fs.existsSync(outputFilePath);
  42. });
  43. it('should create file with obfuscated code in `--output` directory', () => {
  44. assert.equal(isFileExist, true);
  45. });
  46. after(() => {
  47. fs.unlinkSync(outputFilePath);
  48. });
  49. });
  50. describe('Variant #2: input file path is after options', () => {
  51. let isFileExist: boolean;
  52. before(() => {
  53. JavaScriptObfuscatorCLI.obfuscate([
  54. 'node',
  55. 'javascript-obfuscator',
  56. '--output',
  57. outputFilePath,
  58. '--compact',
  59. 'true',
  60. '--self-defending',
  61. '0',
  62. fixtureFilePath
  63. ]);
  64. isFileExist = fs.existsSync(outputFilePath);
  65. });
  66. it('should create file with obfuscated code in `--output` directory', () => {
  67. assert.equal(isFileExist, true);
  68. });
  69. after(() => {
  70. fs.unlinkSync(outputFilePath);
  71. });
  72. });
  73. });
  74. describe('`--output` option isn\'t set', () => {
  75. describe('Variant #1: default behaviour', () => {
  76. let outputFixturesFilePath: string,
  77. isFileExist: boolean;
  78. before(() => {
  79. outputFixturesFilePath = path.join(fixturesDirName, outputFileName);
  80. JavaScriptObfuscatorCLI.obfuscate([
  81. 'node',
  82. 'javascript-obfuscator',
  83. fixtureFilePath
  84. ]);
  85. isFileExist = fs.existsSync(outputFixturesFilePath);
  86. });
  87. it(`should create file \`${outputFileName}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  88. assert.equal(isFileExist, true);
  89. });
  90. after(() => {
  91. fs.unlinkSync(outputFixturesFilePath);
  92. });
  93. });
  94. describe('Variant #2: invalid input file path', () => {
  95. let testFunc: () => void;
  96. before(() => {
  97. testFunc = () => JavaScriptObfuscatorCLI.obfuscate([
  98. 'node',
  99. 'javascript-obfuscator',
  100. path.join('wrong', 'file', 'path')
  101. ]);
  102. });
  103. it(`should throw an error`, () => {
  104. assert.throws(testFunc, expectedError);
  105. });
  106. });
  107. describe('Variant #3: input file extension isn\'t `.js`', () => {
  108. const expectedError: RegExp = /Given input path must be a valid/;
  109. const outputFileName: string = 'sample-obfuscated.ts';
  110. const outputFilePath: string = path.join(outputDirName, outputFileName);
  111. let testFunc: () => void;
  112. before(() => {
  113. fs.writeFileSync(outputFilePath, 'data');
  114. testFunc = () => JavaScriptObfuscatorCLI.obfuscate([
  115. 'node',
  116. 'javascript-obfuscator',
  117. outputFilePath
  118. ]);
  119. });
  120. it(`should throw an error`, () => {
  121. assert.throws(testFunc, expectedError);
  122. });
  123. after(() => {
  124. fs.unlinkSync(outputFilePath);
  125. });
  126. });
  127. });
  128. describe('--exclude option', () => {
  129. describe('Variant #1: --exclude option is pointed on different file', () => {
  130. let isFileExist: boolean;
  131. before(() => {
  132. JavaScriptObfuscatorCLI.obfuscate([
  133. 'node',
  134. 'javascript-obfuscator',
  135. fixtureFilePath,
  136. '--output',
  137. outputFilePath,
  138. '--exclude',
  139. path.join('**', 'foo.js')
  140. ]);
  141. isFileExist = fs.existsSync(outputFilePath);
  142. });
  143. it('should create file with obfuscated code in `--output` directory', () => {
  144. assert.equal(isFileExist, true);
  145. });
  146. });
  147. describe('Variant #2: --exclude option is pointed on input file', () => {
  148. let testFunc: () => void;
  149. before(() => {
  150. testFunc = () => JavaScriptObfuscatorCLI.obfuscate([
  151. 'node',
  152. 'javascript-obfuscator',
  153. fixtureFilePath,
  154. '--output',
  155. outputFilePath,
  156. '--exclude',
  157. path.join('**', 'sample.js')
  158. ]);
  159. });
  160. it('should throw an error', () => {
  161. assert.throws(testFunc, expectedError);
  162. });
  163. after(() => {
  164. fs.unlinkSync(outputFilePath);
  165. });
  166. });
  167. });
  168. });
  169. describe('Variant #2: obfuscation of directory', () => {
  170. describe(`Variant #1: default behaviour`, () => {
  171. const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
  172. const outputFileName1: string = 'foo-obfuscated.js';
  173. const outputFileName2: string = 'bar-obfuscated.js';
  174. const outputFileName3: string = 'baz-obfuscated.js';
  175. const readFileEncoding = 'utf8';
  176. const regExp1: RegExp = /^var a1_0x(\w){4,6} *= *0x1;$/;
  177. const regExp2: RegExp = /^var a0_0x(\w){4,6} *= *0x2;$/;
  178. let outputFixturesFilePath1: string,
  179. outputFixturesFilePath2: string,
  180. outputFixturesFilePath3: string,
  181. isFileExist1: boolean,
  182. isFileExist2: boolean,
  183. isFileExist3: boolean,
  184. fileContent1: string,
  185. fileContent2: string;
  186. before(() => {
  187. outputFixturesFilePath1 = path.join(directoryPath, outputFileName1);
  188. outputFixturesFilePath2 = path.join(directoryPath, outputFileName2);
  189. outputFixturesFilePath3 = path.join(directoryPath, outputFileName3);
  190. JavaScriptObfuscatorCLI.obfuscate([
  191. 'node',
  192. 'javascript-obfuscator',
  193. directoryPath,
  194. '--rename-globals',
  195. 'true'
  196. ]);
  197. isFileExist1 = fs.existsSync(outputFixturesFilePath1);
  198. isFileExist2 = fs.existsSync(outputFixturesFilePath2);
  199. isFileExist3 = fs.existsSync(outputFixturesFilePath3);
  200. fileContent1 = fs.readFileSync(outputFixturesFilePath1, readFileEncoding);
  201. fileContent2 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
  202. });
  203. it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  204. assert.equal(isFileExist1, true);
  205. });
  206. it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  207. assert.equal(isFileExist2, true);
  208. });
  209. it(`shouldn't create file \`${outputFileName3}\` in \`${fixturesDirName}\` directory`, () => {
  210. assert.equal(isFileExist3, false);
  211. });
  212. it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
  213. assert.match(fileContent1, regExp1);
  214. });
  215. it(`match #2: should create file with obfuscated code with prefixed identifier`, () => {
  216. assert.match(fileContent2, regExp2);
  217. });
  218. after(() => {
  219. rimraf.sync(outputFixturesFilePath1);
  220. rimraf.sync(outputFixturesFilePath2);
  221. });
  222. });
  223. describe('Variant #2: obfuscation of directory with `identifiersPrefix` option value', () => {
  224. const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
  225. const identifiersPrefix: string = 'foo';
  226. const outputFileName1: string = 'foo-obfuscated.js';
  227. const outputFileName2: string = 'bar-obfuscated.js';
  228. const readFileEncoding = 'utf8';
  229. const regExp1: RegExp = /^var foo1_0x(\w){4,6} *= *0x1;$/;
  230. const regExp2: RegExp = /^var foo0_0x(\w){4,6} *= *0x2;$/;
  231. let outputFixturesFilePath1: string,
  232. outputFixturesFilePath2: string,
  233. isFileExist1: boolean,
  234. isFileExist2: boolean,
  235. fileContent1: string,
  236. fileContent2: string;
  237. before(() => {
  238. outputFixturesFilePath1 = path.join(directoryPath, outputFileName1);
  239. outputFixturesFilePath2 = path.join(directoryPath, outputFileName2);
  240. JavaScriptObfuscatorCLI.obfuscate([
  241. 'node',
  242. 'javascript-obfuscator',
  243. directoryPath,
  244. '--identifiers-prefix',
  245. identifiersPrefix,
  246. '--rename-globals',
  247. 'true'
  248. ]);
  249. isFileExist1 = fs.existsSync(outputFixturesFilePath1);
  250. isFileExist2 = fs.existsSync(outputFixturesFilePath2);
  251. fileContent1 = fs.readFileSync(outputFixturesFilePath1, readFileEncoding);
  252. fileContent2 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
  253. });
  254. it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  255. assert.equal(isFileExist1, true);
  256. });
  257. it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  258. assert.equal(isFileExist2, true);
  259. });
  260. it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
  261. assert.match(fileContent1, regExp1);
  262. });
  263. it(`match #2: should create file with obfuscated code with prefixed identifier`, () => {
  264. assert.match(fileContent2, regExp2);
  265. });
  266. after(() => {
  267. rimraf.sync(outputFixturesFilePath1);
  268. rimraf.sync(outputFixturesFilePath2);
  269. });
  270. });
  271. describe('Variant #3: obfuscation of directory with `output` option', () => {
  272. const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
  273. const outputDirectoryName: string = 'obfuscated';
  274. const outputDirectoryPath: string = path.join(directoryPath, outputDirectoryName);
  275. const outputFileName1: string = 'foo.js';
  276. const outputFileName2: string = 'bar.js';
  277. const outputFileName3: string = 'baz.js';
  278. let outputFixturesFilePath1: string,
  279. outputFixturesFilePath2: string,
  280. outputFixturesFilePath3: string,
  281. isFileExist1: boolean,
  282. isFileExist2: boolean,
  283. isFileExist3: boolean;
  284. before(() => {
  285. outputFixturesFilePath1 = path.join(outputDirectoryPath, outputFileName1);
  286. outputFixturesFilePath2 = path.join(outputDirectoryPath, outputFileName2);
  287. outputFixturesFilePath3 = path.join(outputDirectoryPath, outputFileName3);
  288. JavaScriptObfuscatorCLI.obfuscate([
  289. 'node',
  290. 'javascript-obfuscator',
  291. directoryPath,
  292. '--output',
  293. outputDirectoryPath
  294. ]);
  295. isFileExist1 = fs.existsSync(outputFixturesFilePath1);
  296. isFileExist2 = fs.existsSync(outputFixturesFilePath2);
  297. isFileExist3 = fs.existsSync(outputFixturesFilePath3);
  298. });
  299. it(
  300. `should create file \`${outputFileName1}\` with obfuscated code in ` +
  301. `\`${path.join(fixturesDirName, outputDirectoryName)}\` directory`,
  302. () => {
  303. assert.equal(isFileExist1, true);
  304. }
  305. );
  306. it(
  307. `should create file \`${outputFileName2}\` with obfuscated code in ` +
  308. `\`${path.join(fixturesDirName, outputDirectoryName)}\` directory`,
  309. () => {
  310. assert.equal(isFileExist2, true);
  311. }
  312. );
  313. it(
  314. `shouldn't create file \`${outputFileName3}\` in ` +
  315. `\`${path.join(fixturesDirName, outputDirectoryName)}\` directory`,
  316. () => {
  317. assert.equal(isFileExist3, false);
  318. }
  319. );
  320. after(() => {
  321. rimraf.sync(outputDirectoryPath);
  322. });
  323. });
  324. describe('Variant #4: --exclude option', () => {
  325. describe('Variant #1: --exclude option is pointed on different file', () => {
  326. const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
  327. const outputFileName1: string = 'foo-obfuscated.js';
  328. const outputFileName2: string = 'bar-obfuscated.js';
  329. const outputFileName3: string = 'baz-obfuscated.js';
  330. const readFileEncoding = 'utf8';
  331. const regExp1: RegExp = /^var a1_0x(\w){4,6} *= *0x1;$/;
  332. const regExp2: RegExp = /^var a0_0x(\w){4,6} *= *0x2;$/;
  333. let outputFixturesFilePath1: string,
  334. outputFixturesFilePath2: string,
  335. outputFixturesFilePath3: string,
  336. isFileExist1: boolean,
  337. isFileExist2: boolean,
  338. isFileExist3: boolean,
  339. fileContent1: string,
  340. fileContent2: string;
  341. before(() => {
  342. outputFixturesFilePath1 = path.join(directoryPath, outputFileName1);
  343. outputFixturesFilePath2 = path.join(directoryPath, outputFileName2);
  344. outputFixturesFilePath3 = path.join(directoryPath, outputFileName3);
  345. JavaScriptObfuscatorCLI.obfuscate([
  346. 'node',
  347. 'javascript-obfuscator',
  348. directoryPath,
  349. '--exclude',
  350. path.join('**', 'bark.js'),
  351. '--rename-globals',
  352. 'true'
  353. ]);
  354. isFileExist1 = fs.existsSync(outputFixturesFilePath1);
  355. isFileExist2 = fs.existsSync(outputFixturesFilePath2);
  356. isFileExist3 = fs.existsSync(outputFixturesFilePath3);
  357. fileContent1 = fs.readFileSync(outputFixturesFilePath1, readFileEncoding);
  358. fileContent2 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
  359. });
  360. it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  361. assert.equal(isFileExist1, true);
  362. });
  363. it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  364. assert.equal(isFileExist2, true);
  365. });
  366. it(`shouldn't create file \`${outputFileName3}\` in \`${fixturesDirName}\` directory`, () => {
  367. assert.equal(isFileExist3, false);
  368. });
  369. it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
  370. assert.match(fileContent1, regExp1);
  371. });
  372. it(`match #2: should create file with obfuscated code with prefixed identifier`, () => {
  373. assert.match(fileContent2, regExp2);
  374. });
  375. after(() => {
  376. rimraf.sync(outputFixturesFilePath1);
  377. rimraf.sync(outputFixturesFilePath2);
  378. });
  379. });
  380. describe('Variant #2: --exclude option is pointed on file under obfuscating directory', () => {
  381. const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
  382. const outputFileName1: string = 'foo-obfuscated.js';
  383. const outputFileName2: string = 'bar-obfuscated.js';
  384. const outputFileName3: string = 'baz-obfuscated.js';
  385. const readFileEncoding = 'utf8';
  386. const regExp1: RegExp = /^var a0_0x(\w){4,6} *= *0x2;$/;
  387. let outputFixturesFilePath1: string,
  388. outputFixturesFilePath2: string,
  389. outputFixturesFilePath3: string,
  390. isFileExist1: boolean,
  391. isFileExist2: boolean,
  392. isFileExist3: boolean,
  393. fileContent1: string;
  394. before(() => {
  395. outputFixturesFilePath1 = path.join(directoryPath, outputFileName1);
  396. outputFixturesFilePath2 = path.join(directoryPath, outputFileName2);
  397. outputFixturesFilePath3 = path.join(directoryPath, outputFileName3);
  398. JavaScriptObfuscatorCLI.obfuscate([
  399. 'node',
  400. 'javascript-obfuscator',
  401. directoryPath,
  402. '--exclude',
  403. path.join('**', 'foo.js'),
  404. '--rename-globals',
  405. 'true'
  406. ]);
  407. isFileExist1 = fs.existsSync(outputFixturesFilePath1);
  408. isFileExist2 = fs.existsSync(outputFixturesFilePath2);
  409. isFileExist3 = fs.existsSync(outputFixturesFilePath3);
  410. fileContent1 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
  411. });
  412. it(`shouldn't create file \`${outputFileName1}\` in \`${fixturesDirName}\` directory`, () => {
  413. assert.equal(isFileExist1, false);
  414. });
  415. it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  416. assert.equal(isFileExist2, true);
  417. });
  418. it(`shouldn't create file \`${outputFileName3}\` in \`${fixturesDirName}\` directory`, () => {
  419. assert.equal(isFileExist3, false);
  420. });
  421. it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
  422. assert.match(fileContent1, regExp1);
  423. });
  424. after(() => {
  425. rimraf.sync(outputFixturesFilePath1);
  426. rimraf.sync(outputFixturesFilePath2);
  427. });
  428. });
  429. });
  430. });
  431. describe('`--sourceMap` option is set', () => {
  432. const outputSourceMapPath: string = `${outputFilePath}.map`;
  433. describe('Variant #1: `--sourceMapMode` option value is `separate`', () => {
  434. describe('Variant #1: default behaviour', () => {
  435. const expectedSourceMapSourceName: string = path.basename(fixtureFileName);
  436. let isFileExist: boolean,
  437. sourceMapObject: any;
  438. before(() => {
  439. JavaScriptObfuscatorCLI.obfuscate([
  440. 'node',
  441. 'javascript-obfuscator',
  442. fixtureFilePath,
  443. '--output',
  444. outputFilePath,
  445. '--compact',
  446. 'true',
  447. '--self-defending',
  448. '0',
  449. '--source-map',
  450. 'true'
  451. ]);
  452. try {
  453. const content: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' });
  454. isFileExist = true;
  455. sourceMapObject = JSON.parse(content);
  456. } catch (e) {
  457. isFileExist = false;
  458. }
  459. });
  460. it('should create file with source map in the same directory as output file', () => {
  461. assert.equal(isFileExist, true);
  462. });
  463. it('source map from created file should contains property `version`', () => {
  464. assert.property(sourceMapObject, 'version');
  465. });
  466. it('source map from created file should contains property `sources`', () => {
  467. assert.property(sourceMapObject, 'sources');
  468. });
  469. it('source map source should has correct name', () => {
  470. assert.equal(sourceMapObject.sources[0], expectedSourceMapSourceName);
  471. });
  472. it('source map from created file should contains property `names`', () => {
  473. assert.property(sourceMapObject, 'names');
  474. });
  475. after(() => {
  476. rimraf.sync(outputFilePath);
  477. rimraf.sync(outputSourceMapPath);
  478. });
  479. });
  480. describe('Variant #2: `sourceMapBaseUrl` option is set', () => {
  481. const expectedSourceMapSourceName: string = path.basename(fixtureFileName);
  482. let isFileExist: boolean,
  483. sourceMapObject: any;
  484. before(() => {
  485. JavaScriptObfuscatorCLI.obfuscate([
  486. 'node',
  487. 'javascript-obfuscator',
  488. fixtureFilePath,
  489. '--output',
  490. outputFilePath,
  491. '--compact',
  492. 'true',
  493. '--self-defending',
  494. '0',
  495. '--source-map',
  496. 'true',
  497. '--source-map-base-url',
  498. 'http://localhost:9000/'
  499. ]);
  500. try {
  501. const content: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' });
  502. isFileExist = true;
  503. sourceMapObject = JSON.parse(content);
  504. } catch (e) {
  505. isFileExist = false;
  506. }
  507. });
  508. it('should create file with source map in the same directory as output file', () => {
  509. assert.equal(isFileExist, true);
  510. });
  511. it('source map from created file should contains property `version`', () => {
  512. assert.property(sourceMapObject, 'version');
  513. });
  514. it('source map from created file should contains property `sources`', () => {
  515. assert.property(sourceMapObject, 'sources');
  516. });
  517. it('source map source should has correct name', () => {
  518. assert.equal(sourceMapObject.sources[0], expectedSourceMapSourceName);
  519. });
  520. it('source map from created file should contains property `names`', () => {
  521. assert.property(sourceMapObject, 'names');
  522. });
  523. after(() => {
  524. fs.unlinkSync(outputFilePath);
  525. fs.unlinkSync(outputSourceMapPath);
  526. });
  527. });
  528. describe('Variant #3: `--sourceMapFileName` option is set', () => {
  529. const expectedSourceMapSourceName: string = path.basename(fixtureFileName);
  530. const sourceMapFileName: string = 'test';
  531. const sourceMapFilePath: string = `${sourceMapFileName}.js.map`;
  532. const outputSourceMapFilePath: string = path.join(outputDirName, sourceMapFilePath);
  533. let isFileExist: boolean,
  534. sourceMapObject: any;
  535. before(() => {
  536. JavaScriptObfuscatorCLI.obfuscate([
  537. 'node',
  538. 'javascript-obfuscator',
  539. fixtureFilePath,
  540. '--output',
  541. outputFilePath,
  542. '--compact',
  543. 'true',
  544. '--self-defending',
  545. '0',
  546. '--source-map',
  547. 'true',
  548. '--source-map-file-name',
  549. sourceMapFileName
  550. ]);
  551. try {
  552. const content: string = fs.readFileSync(outputSourceMapFilePath, { encoding: 'utf8' });
  553. isFileExist = true;
  554. sourceMapObject = JSON.parse(content);
  555. } catch (e) {
  556. isFileExist = false;
  557. }
  558. });
  559. it('should create source map file with given name in the same directory as output file', () => {
  560. assert.equal(isFileExist, true);
  561. });
  562. it('source map from created file should contains property `version`', () => {
  563. assert.property(sourceMapObject, 'version');
  564. });
  565. it('source map from created file should contains property `sources`', () => {
  566. assert.property(sourceMapObject, 'sources');
  567. });
  568. it('source map source should has correct name', () => {
  569. assert.equal(sourceMapObject.sources[0], expectedSourceMapSourceName);
  570. });
  571. it('source map from created file should contains property `names`', () => {
  572. assert.property(sourceMapObject, 'names');
  573. });
  574. after(() => {
  575. fs.unlinkSync(outputFilePath);
  576. fs.unlinkSync(outputSourceMapFilePath);
  577. });
  578. });
  579. });
  580. describe('Variant #2: `--sourceMapMode` option is `inline`', () => {
  581. let isFileExist: boolean;
  582. before(() => {
  583. JavaScriptObfuscatorCLI.obfuscate([
  584. 'node',
  585. 'javascript-obfuscator',
  586. fixtureFilePath,
  587. '--output',
  588. outputFilePath,
  589. '--compact',
  590. 'true',
  591. '--self-defending',
  592. '0',
  593. '--source-map',
  594. 'true',
  595. '--source-map-mode',
  596. 'inline'
  597. ]);
  598. isFileExist = fs.existsSync(outputSourceMapPath);
  599. });
  600. it('shouldn\'t create file with source map', () => {
  601. assert.equal(isFileExist, false);
  602. });
  603. after(() => {
  604. fs.unlinkSync(outputFilePath);
  605. });
  606. });
  607. });
  608. describe('help output', () => {
  609. let callback: sinon.SinonSpy<any, void>,
  610. stdoutWriteMock: StdoutWriteMock,
  611. stubExit: sinon.SinonStub;
  612. beforeEach(() => {
  613. stubExit = sinon.stub(process, 'exit');
  614. callback = sinon.spy(console, 'log');
  615. stdoutWriteMock = new StdoutWriteMock(process.stdout.write);
  616. });
  617. describe('`--help` option is set without any additional parameters', () => {
  618. let isConsoleLogCalled: boolean;
  619. beforeEach(() => {
  620. stdoutWriteMock.mute();
  621. JavaScriptObfuscatorCLI.obfuscate([
  622. 'node',
  623. 'javascript-obfuscator',
  624. '--help'
  625. ]);
  626. stdoutWriteMock.restore();
  627. isConsoleLogCalled = callback.called;
  628. });
  629. it('should print `console.log` help', () => {
  630. assert.equal(isConsoleLogCalled, true);
  631. });
  632. });
  633. describe('`--help` option is set before file path', () => {
  634. let isConsoleLogCalled: boolean;
  635. beforeEach(() => {
  636. stdoutWriteMock.mute();
  637. JavaScriptObfuscatorCLI.obfuscate([
  638. 'node',
  639. 'javascript-obfuscator',
  640. '--help',
  641. fixtureFilePath
  642. ]);
  643. stdoutWriteMock.restore();
  644. isConsoleLogCalled = callback.called;
  645. });
  646. it('should print `console.log` help', () => {
  647. assert.equal(isConsoleLogCalled, true);
  648. });
  649. });
  650. describe('`--help` option is set after file path', () => {
  651. let isConsoleLogCalled: boolean;
  652. beforeEach(() => {
  653. stdoutWriteMock.mute();
  654. JavaScriptObfuscatorCLI.obfuscate([
  655. 'node',
  656. 'javascript-obfuscator',
  657. fixtureFilePath,
  658. '--help'
  659. ]);
  660. stdoutWriteMock.restore();
  661. isConsoleLogCalled = callback.called;
  662. });
  663. it('should print `console.log` help', () => {
  664. assert.equal(isConsoleLogCalled, true);
  665. });
  666. });
  667. describe('no arguments passed', () => {
  668. let isConsoleLogCalled: boolean;
  669. beforeEach(() => {
  670. stdoutWriteMock.mute();
  671. JavaScriptObfuscatorCLI.obfuscate([
  672. 'node',
  673. 'javascript-obfuscator'
  674. ]);
  675. stdoutWriteMock.restore();
  676. isConsoleLogCalled = callback.called;
  677. });
  678. it('should print `console.log` help', () => {
  679. assert.equal(isConsoleLogCalled, true);
  680. });
  681. });
  682. afterEach(() => {
  683. stubExit.restore();
  684. callback.restore();
  685. });
  686. });
  687. describe('`--config` option is set', () => {
  688. describe('Base options', () => {
  689. const outputSourceMapPath: string = `${outputFilePath}.map`;
  690. let isFileExist: boolean,
  691. sourceMapObject: any;
  692. before(() => {
  693. JavaScriptObfuscatorCLI.obfuscate([
  694. 'node',
  695. 'javascript-obfuscator',
  696. fixtureFilePath,
  697. '--output',
  698. outputFilePath,
  699. '--config',
  700. configFilePath
  701. ]);
  702. try {
  703. const content: string = fs.readFileSync(outputSourceMapPath, {encoding: 'utf8'});
  704. isFileExist = true;
  705. sourceMapObject = JSON.parse(content);
  706. } catch (e) {
  707. isFileExist = false;
  708. }
  709. });
  710. it('should create file with source map in the same directory as output file', () => {
  711. assert.equal(isFileExist, true);
  712. });
  713. it('source map from created file should contains property `version`', () => {
  714. assert.property(sourceMapObject, 'version');
  715. });
  716. it('source map from created file should contains property `sources`', () => {
  717. assert.property(sourceMapObject, 'sources');
  718. });
  719. it('source map from created file should contains property `names`', () => {
  720. assert.property(sourceMapObject, 'names');
  721. });
  722. after(() => {
  723. fs.unlinkSync(outputFilePath);
  724. fs.unlinkSync(outputSourceMapPath);
  725. });
  726. });
  727. describe('`--exclude` option', () => {
  728. const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
  729. const outputFileName1: string = 'foo-obfuscated.js';
  730. const outputFileName2: string = 'bar-obfuscated.js';
  731. let outputFixturesFilePath1: string,
  732. outputFixturesFilePath2: string,
  733. isFileExist1: boolean,
  734. isFileExist2: boolean;
  735. before(() => {
  736. outputFixturesFilePath1 = path.join(directoryPath, outputFileName1);
  737. outputFixturesFilePath2 = path.join(directoryPath, outputFileName2);
  738. JavaScriptObfuscatorCLI.obfuscate([
  739. 'node',
  740. 'javascript-obfuscator',
  741. directoryPath,
  742. '--config',
  743. configFilePath
  744. ]);
  745. isFileExist1 = fs.existsSync(outputFixturesFilePath1);
  746. isFileExist2 = fs.existsSync(outputFixturesFilePath2);
  747. });
  748. it(`shouldn't create file \`${outputFileName1}\` in \`${fixturesDirName}\` directory`, () => {
  749. assert.equal(isFileExist1, false);
  750. });
  751. it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  752. assert.equal(isFileExist2, true);
  753. });
  754. after(() => {
  755. rimraf.sync(outputFixturesFilePath1);
  756. rimraf.sync(outputFixturesFilePath2);
  757. });
  758. });
  759. });
  760. describe('`--config` option is set but overridden by CLI option', () => {
  761. const outputSourceMapPath: string = `${outputFilePath}.map`;
  762. let isFileExist: boolean;
  763. before(() => {
  764. JavaScriptObfuscatorCLI.obfuscate([
  765. 'node',
  766. 'javascript-obfuscator',
  767. fixtureFilePath,
  768. '--output',
  769. outputFilePath,
  770. '--config',
  771. configFilePath,
  772. '--source-map',
  773. 'false',
  774. ]);
  775. try {
  776. fs.readFileSync(outputSourceMapPath, {encoding: 'utf8'});
  777. isFileExist = true;
  778. } catch (e) {
  779. isFileExist = false;
  780. }
  781. });
  782. it('should create file without source map in the same directory as output file', () => {
  783. assert.equal(isFileExist, false);
  784. });
  785. after(() => {
  786. fs.unlinkSync(outputFilePath);
  787. });
  788. });
  789. describe('Logging', () => {
  790. describe('Obfuscating file message', () => {
  791. const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation');
  792. const inputFileName1: string = 'foo.js';
  793. const inputFileName2: string = 'bar.js';
  794. const inputFilePath1: string = path.join(directoryPath, inputFileName1);
  795. const inputFilePath2: string = path.join(directoryPath, inputFileName2);
  796. const outputFileName1: string = 'foo-obfuscated.js';
  797. const outputFileName2: string = 'bar-obfuscated.js';
  798. const outputFilePath1: string = path.join(directoryPath, outputFileName1);
  799. const outputFilePath2: string = path.join(directoryPath, outputFileName2);
  800. const expectedLoggingMessage1: string = `[javascript-obfuscator-cli] Obfuscating file: ${inputFilePath1}...`;
  801. const expectedLoggingMessage2: string = `[javascript-obfuscator-cli] Obfuscating file: ${inputFilePath2}...`;
  802. let consoleLogSpy: sinon.SinonSpy<any, void>,
  803. loggingMessageResult1: string,
  804. loggingMessageResult2: string;
  805. before(() => {
  806. consoleLogSpy = sinon.spy(console, 'log');
  807. JavaScriptObfuscatorCLI.obfuscate([
  808. 'node',
  809. 'javascript-obfuscator',
  810. directoryPath,
  811. '--rename-globals',
  812. 'true'
  813. ]);
  814. loggingMessageResult1 = consoleLogSpy.getCall(1).args[0];
  815. loggingMessageResult2 = consoleLogSpy.getCall(0).args[0];
  816. });
  817. it('Variant #1: should log file name to the console', () => {
  818. assert.include(loggingMessageResult1, expectedLoggingMessage1);
  819. });
  820. it('Variant #2: should log file name to the console', () => {
  821. assert.include(loggingMessageResult2, expectedLoggingMessage2);
  822. });
  823. after(() => {
  824. rimraf.sync(outputFilePath1);
  825. rimraf.sync(outputFilePath2);
  826. consoleLogSpy.restore();
  827. });
  828. });
  829. describe('Error message', () => {
  830. const directoryPath: string = path.join(fixturesDirName, 'directory-obfuscation-error');
  831. const inputFileName: string = 'foo.js';
  832. const inputFilePath: string = path.join(directoryPath, inputFileName);
  833. const expectedLoggingMessage1: string = `[javascript-obfuscator-cli] Error in file: ${inputFilePath}...`;
  834. let consoleLogSpy: sinon.SinonSpy<any, void>,
  835. loggingMessageResult: string
  836. before(() => {
  837. consoleLogSpy = sinon.spy(console, 'log');
  838. try {
  839. JavaScriptObfuscatorCLI.obfuscate([
  840. 'node',
  841. 'javascript-obfuscator',
  842. directoryPath,
  843. '--rename-globals',
  844. 'true'
  845. ]);
  846. } catch {}
  847. loggingMessageResult = consoleLogSpy.getCall(1).args[0];
  848. });
  849. it('Should log file name to the console', () => {
  850. assert.include(loggingMessageResult, expectedLoggingMessage1);
  851. });
  852. after(() => {
  853. consoleLogSpy.restore();
  854. });
  855. });
  856. });
  857. after(() => {
  858. rimraf.sync(outputDirName);
  859. });
  860. });
  861. });