JavaScriptObfuscatorCLI.spec.ts 42 KB

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