JavaScriptObfuscatorCLI.spec.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. import * as fs from 'fs';
  2. import * as mkdirp from 'mkdirp';
  3. import * as sinon from 'sinon';
  4. import { assert } from 'chai';
  5. import { StdoutWriteMock } from '../../mocks/StdoutWriteMock';
  6. import { JavaScriptObfuscator } from '../../../src/JavaScriptObfuscatorFacade';
  7. describe('JavaScriptObfuscatorCLI', function (): void {
  8. this.timeout(100000);
  9. const fixturesDirName: string = 'test/fixtures';
  10. const fixtureFileName: string = 'sample.js';
  11. const fixtureFilePath: string = `${fixturesDirName}/${fixtureFileName}`;
  12. const outputDirName: string = 'test/tmp';
  13. const outputFileName: string = 'sample-obfuscated.js';
  14. const outputFilePath: string = `${outputDirName}/${outputFileName}`;
  15. const configDirName: string = 'test/fixtures';
  16. const configFileName: string = 'config.js';
  17. const configFilePath: string = `${configDirName}/${configFileName}`;
  18. describe('run (): void', () => {
  19. before(() => {
  20. mkdirp.sync(outputDirName);
  21. });
  22. describe('Variant #1: obfuscation of single file', () => {
  23. describe('`--output` option is set', () => {
  24. let isFileExist: boolean;
  25. before(() => {
  26. JavaScriptObfuscator.runCLI([
  27. 'node',
  28. 'javascript-obfuscator',
  29. fixtureFilePath,
  30. '--output',
  31. outputFilePath,
  32. '--compact',
  33. 'true',
  34. '--self-defending',
  35. '0'
  36. ]);
  37. isFileExist = fs.existsSync(outputFilePath);
  38. });
  39. it('should create file with obfuscated code in `--output` directory', () => {
  40. assert.equal(isFileExist, true);
  41. });
  42. after(() => {
  43. fs.unlinkSync(outputFilePath);
  44. });
  45. });
  46. describe('`--output` option isn\'t set', () => {
  47. describe('variant #1: default behaviour', () => {
  48. let outputFixturesFilePath: string,
  49. isFileExist: boolean;
  50. before(() => {
  51. outputFixturesFilePath = `${fixturesDirName}/${outputFileName}`;
  52. JavaScriptObfuscator.runCLI([
  53. 'node',
  54. 'javascript-obfuscator',
  55. fixtureFilePath
  56. ]);
  57. isFileExist = fs.existsSync(outputFixturesFilePath);
  58. });
  59. it(`should create file \`${outputFileName}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  60. assert.equal(isFileExist, true);
  61. });
  62. after(() => {
  63. fs.unlinkSync(outputFixturesFilePath);
  64. });
  65. });
  66. describe('variant #2: invalid input file path', () => {
  67. const expectedError: ReferenceErrorConstructor = ReferenceError;
  68. let testFunc: () => void;
  69. before(() => {
  70. testFunc = () => JavaScriptObfuscator.runCLI([
  71. 'node',
  72. 'javascript-obfuscator',
  73. 'wrong/file/path'
  74. ]);
  75. });
  76. it(`should throw an error`, () => {
  77. assert.throws(testFunc, expectedError);
  78. });
  79. });
  80. describe('variant #3: input file extension isn\'t `.js`', () => {
  81. const expectedError: ReferenceErrorConstructor = ReferenceError;
  82. const outputFileName: string = 'sample-obfuscated.ts';
  83. const outputFilePath: string = `${outputDirName}/${outputFileName}`;
  84. let testFunc: () => void;
  85. before(() => {
  86. fs.writeFileSync(outputFilePath, 'data');
  87. testFunc = () => JavaScriptObfuscator.runCLI([
  88. 'node',
  89. 'javascript-obfuscator',
  90. outputFilePath
  91. ]);
  92. });
  93. it(`should throw an error`, () => {
  94. assert.throws(testFunc, expectedError);
  95. });
  96. after(() => {
  97. fs.unlinkSync(outputFilePath);
  98. });
  99. });
  100. });
  101. });
  102. describe('Variant #2: obfuscation of directory', () => {
  103. const directoryPath: string = `${fixturesDirName}/directory-obfuscation`;
  104. const outputFileName1: string = 'foo-obfuscated.js';
  105. const outputFileName2: string = 'bar-obfuscated.js';
  106. const outputFileName3: string = 'baz-obfuscated.js';
  107. let outputFixturesFilePath1: string,
  108. outputFixturesFilePath2: string,
  109. outputFixturesFilePath3: string,
  110. isFileExist1: boolean,
  111. isFileExist2: boolean,
  112. isFileExist3: boolean;
  113. before(() => {
  114. outputFixturesFilePath1 = `${directoryPath}/${outputFileName1}`;
  115. outputFixturesFilePath2 = `${directoryPath}/${outputFileName2}`;
  116. outputFixturesFilePath3 = `${directoryPath}/${outputFileName3}`;
  117. JavaScriptObfuscator.runCLI([
  118. 'node',
  119. 'javascript-obfuscator',
  120. directoryPath
  121. ]);
  122. isFileExist1 = fs.existsSync(outputFixturesFilePath1);
  123. isFileExist2 = fs.existsSync(outputFixturesFilePath2);
  124. isFileExist3 = fs.existsSync(outputFixturesFilePath3);
  125. });
  126. it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  127. assert.equal(isFileExist1, true);
  128. });
  129. it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
  130. assert.equal(isFileExist2, true);
  131. });
  132. it(`shouldn't create file \`${outputFileName3}\` in \`${fixturesDirName}\` directory`, () => {
  133. assert.equal(isFileExist3, false);
  134. });
  135. after(() => {
  136. fs.unlinkSync(outputFixturesFilePath1);
  137. fs.unlinkSync(outputFixturesFilePath2);
  138. });
  139. });
  140. describe('`--sourceMap` option is set', () => {
  141. const outputSourceMapPath: string = `${outputFilePath}.map`;
  142. describe('variant #1: `--sourceMapMode` option value is `separate`', () => {
  143. describe('variant #1: default behaviour', () => {
  144. let isFileExist: boolean,
  145. sourceMapObject: any;
  146. before(() => {
  147. JavaScriptObfuscator.runCLI([
  148. 'node',
  149. 'javascript-obfuscator',
  150. fixtureFilePath,
  151. '--output',
  152. outputFilePath,
  153. '--compact',
  154. 'true',
  155. '--self-defending',
  156. '0',
  157. '--source-map',
  158. 'true'
  159. ]);
  160. try {
  161. const content: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' });
  162. isFileExist = true;
  163. sourceMapObject = JSON.parse(content);
  164. } catch (e) {
  165. isFileExist = false;
  166. }
  167. });
  168. it('should create file with source map in the same directory as output file', () => {
  169. assert.equal(isFileExist, true);
  170. });
  171. it('source map from created file should contains property `version`', () => {
  172. assert.property(sourceMapObject, 'version');
  173. });
  174. it('source map from created file should contains property `sources`', () => {
  175. assert.property(sourceMapObject, 'sources');
  176. });
  177. it('source map from created file should contains property `names`', () => {
  178. assert.property(sourceMapObject, 'names');
  179. });
  180. after(() => {
  181. fs.unlinkSync(outputFilePath);
  182. fs.unlinkSync(outputSourceMapPath);
  183. });
  184. });
  185. describe('variant #2: `sourceMapBaseUrl` option is set', () => {
  186. let isFileExist: boolean,
  187. sourceMapObject: any;
  188. before(() => {
  189. JavaScriptObfuscator.runCLI([
  190. 'node',
  191. 'javascript-obfuscator',
  192. fixtureFilePath,
  193. '--output',
  194. outputFilePath,
  195. '--compact',
  196. 'true',
  197. '--self-defending',
  198. '0',
  199. '--source-map',
  200. 'true',
  201. '--source-map-base-url',
  202. 'http://localhost:9000/'
  203. ]);
  204. try {
  205. const content: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' });
  206. isFileExist = true;
  207. sourceMapObject = JSON.parse(content);
  208. } catch (e) {
  209. isFileExist = false;
  210. }
  211. });
  212. it('should create file with source map in the same directory as output file', () => {
  213. assert.equal(isFileExist, true);
  214. });
  215. it('source map from created file should contains property `version`', () => {
  216. assert.property(sourceMapObject, 'version');
  217. });
  218. it('source map from created file should contains property `sources`', () => {
  219. assert.property(sourceMapObject, 'sources');
  220. });
  221. it('source map from created file should contains property `names`', () => {
  222. assert.property(sourceMapObject, 'names');
  223. });
  224. after(() => {
  225. fs.unlinkSync(outputFilePath);
  226. fs.unlinkSync(outputSourceMapPath);
  227. });
  228. });
  229. describe('variant #3: `--sourceMapFileName` option is set', () => {
  230. const sourceMapFileName: string = 'test';
  231. const sourceMapFilePath: string = `${sourceMapFileName}.js.map`;
  232. const outputSourceMapFilePath: string = `${outputDirName}/${sourceMapFilePath}`;
  233. let isFileExist: boolean,
  234. sourceMapObject: any;
  235. before(() => {
  236. JavaScriptObfuscator.runCLI([
  237. 'node',
  238. 'javascript-obfuscator',
  239. fixtureFilePath,
  240. '--output',
  241. outputFilePath,
  242. '--compact',
  243. 'true',
  244. '--self-defending',
  245. '0',
  246. '--source-map',
  247. 'true',
  248. '--source-map-file-name',
  249. sourceMapFileName
  250. ]);
  251. try {
  252. const content: string = fs.readFileSync(outputSourceMapFilePath, { encoding: 'utf8' });
  253. isFileExist = true;
  254. sourceMapObject = JSON.parse(content);
  255. } catch (e) {
  256. isFileExist = false;
  257. }
  258. });
  259. it('should create source map file with given name in the same directory as output file', () => {
  260. assert.equal(isFileExist, true);
  261. });
  262. it('source map from created file should contains property `version`', () => {
  263. assert.property(sourceMapObject, 'version');
  264. });
  265. it('source map from created file should contains property `sources`', () => {
  266. assert.property(sourceMapObject, 'sources');
  267. });
  268. it('source map from created file should contains property `names`', () => {
  269. assert.property(sourceMapObject, 'names');
  270. });
  271. after(() => {
  272. fs.unlinkSync(outputFilePath);
  273. fs.unlinkSync(outputSourceMapFilePath);
  274. });
  275. });
  276. });
  277. describe('variant #2: `--sourceMapMode` option is `inline`', () => {
  278. let isFileExist: boolean;
  279. before(() => {
  280. JavaScriptObfuscator.runCLI([
  281. 'node',
  282. 'javascript-obfuscator',
  283. fixtureFilePath,
  284. '--output',
  285. outputFilePath,
  286. '--compact',
  287. 'true',
  288. '--self-defending',
  289. '0',
  290. '--source-map',
  291. 'true',
  292. '--source-map-mode',
  293. 'inline'
  294. ]);
  295. isFileExist = fs.existsSync(outputSourceMapPath);
  296. });
  297. it('shouldn\'t create file with source map', () => {
  298. assert.equal(isFileExist, false);
  299. });
  300. after(() => {
  301. fs.unlinkSync(outputFilePath);
  302. });
  303. });
  304. });
  305. describe('help output', () => {
  306. let callback: sinon.SinonSpy,
  307. stdoutWriteMock: StdoutWriteMock;
  308. beforeEach(() => {
  309. callback = sinon.spy(console, 'log');
  310. stdoutWriteMock = new StdoutWriteMock(process.stdout.write);
  311. });
  312. describe('`--help` option is set', () => {
  313. let isConsoleLogCalled: boolean;
  314. beforeEach(() => {
  315. stdoutWriteMock.mute();
  316. JavaScriptObfuscator.runCLI([
  317. 'node',
  318. 'javascript-obfuscator',
  319. fixtureFilePath,
  320. '--help'
  321. ]);
  322. stdoutWriteMock.restore();
  323. isConsoleLogCalled = callback.called;
  324. });
  325. it('should print `console.log` help', () => {
  326. assert.equal(isConsoleLogCalled, true);
  327. });
  328. });
  329. describe('no arguments passed', () => {
  330. let isConsoleLogCalled: boolean;
  331. beforeEach(() => {
  332. stdoutWriteMock.mute();
  333. JavaScriptObfuscator.runCLI([
  334. 'node',
  335. 'javascript-obfuscator'
  336. ]);
  337. stdoutWriteMock.restore();
  338. isConsoleLogCalled = callback.called;
  339. });
  340. it('should print `console.log` help', () => {
  341. assert.equal(isConsoleLogCalled, true);
  342. });
  343. });
  344. afterEach(() => {
  345. callback.restore();
  346. });
  347. });
  348. describe('`--config` option is set', () => {
  349. const outputSourceMapPath: string = `${outputFilePath}.map`;
  350. let isFileExist: boolean,
  351. sourceMapObject: any;
  352. before(() => {
  353. JavaScriptObfuscator.runCLI([
  354. 'node',
  355. 'javascript-obfuscator',
  356. fixtureFilePath,
  357. '--output',
  358. outputFilePath,
  359. '--config',
  360. configFilePath
  361. ]);
  362. try {
  363. const content: string = fs.readFileSync(outputSourceMapPath, {encoding: 'utf8'});
  364. isFileExist = true;
  365. sourceMapObject = JSON.parse(content);
  366. } catch (e) {
  367. isFileExist = false;
  368. }
  369. });
  370. it('should create file with source map in the same directory as output file', () => {
  371. assert.equal(isFileExist, true);
  372. });
  373. it('source map from created file should contains property `version`', () => {
  374. assert.property(sourceMapObject, 'version');
  375. });
  376. it('source map from created file should contains property `sources`', () => {
  377. assert.property(sourceMapObject, 'sources');
  378. });
  379. it('source map from created file should contains property `names`', () => {
  380. assert.property(sourceMapObject, 'names');
  381. });
  382. after(() => {
  383. fs.unlinkSync(outputFilePath);
  384. fs.unlinkSync(outputSourceMapPath);
  385. });
  386. });
  387. describe('`--config` option is set but overridden by CLI option', () => {
  388. const outputSourceMapPath: string = `${outputFilePath}.map`;
  389. let isFileExist: boolean;
  390. before(() => {
  391. JavaScriptObfuscator.runCLI([
  392. 'node',
  393. 'javascript-obfuscator',
  394. fixtureFilePath,
  395. '--output',
  396. outputFilePath,
  397. '--config',
  398. configFilePath,
  399. '--source-map',
  400. 'false',
  401. ]);
  402. try {
  403. fs.readFileSync(outputSourceMapPath, {encoding: 'utf8'});
  404. isFileExist = true;
  405. } catch (e) {
  406. isFileExist = false;
  407. }
  408. });
  409. it('should create file without source map in the same directory as output file', () => {
  410. assert.equal(isFileExist, false);
  411. });
  412. after(() => {
  413. fs.unlinkSync(outputFilePath);
  414. });
  415. });
  416. after(() => {
  417. fs.rmdirSync(outputDirName);
  418. });
  419. });
  420. });