Gruntfile.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /* eslint-env node */
  2. module.exports = function(grunt) {
  3. grunt.file.defaultEncoding = "utf8";
  4. grunt.file.preserveBOM = false;
  5. // Tasks
  6. grunt.registerTask("dev",
  7. "A persistent task which creates a development build whenever source files are modified.",
  8. ["clean:dev", "concat:css", "concat:js", "copy:htmlDev", "copy:staticDev", "chmod:build", "watch"]);
  9. grunt.registerTask("test",
  10. "A task which runs all the tests in test/tests.",
  11. ["clean:test", "concat:jsTest", "copy:htmlTest", "chmod:build", "exec:tests"]);
  12. grunt.registerTask("prod",
  13. "Creates a production-ready build. Use the --msg flag to add a compile message.",
  14. ["eslint", "exec:stats", "clean", "jsdoc", "concat", "copy:htmlDev", "copy:htmlProd", "copy:htmlInline",
  15. "copy:staticDev", "copy:staticProd", "cssmin", "uglify:prod", "inline", "htmlmin", "chmod", "test"]);
  16. grunt.registerTask("docs",
  17. "Compiles documentation in the /docs directory.",
  18. ["clean:docs", "jsdoc", "chmod:docs"]);
  19. grunt.registerTask("stats",
  20. "Provides statistics about the code base such as how many lines there are as well as details of file sizes before and after compression.",
  21. ["concat:js", "uglify:prod", "exec:stats", "exec:repoSize", "exec:displayStats"]);
  22. grunt.registerTask("release",
  23. "Prepares and deploys a production version of CyberChef to the gh-pages branch.",
  24. ["copy:ghPages", "exec:deployGhPages"]);
  25. grunt.registerTask("default",
  26. "Lints the code base and shows stats",
  27. ["eslint", "exec:stats", "exec:displayStats"]);
  28. grunt.registerTask("doc", "docs");
  29. grunt.registerTask("lint", "eslint");
  30. // Load tasks provided by each plugin
  31. grunt.loadNpmTasks("grunt-eslint");
  32. grunt.loadNpmTasks("grunt-jsdoc");
  33. grunt.loadNpmTasks("grunt-contrib-clean");
  34. grunt.loadNpmTasks("grunt-contrib-concat");
  35. grunt.loadNpmTasks("grunt-contrib-copy");
  36. grunt.loadNpmTasks("grunt-contrib-uglify");
  37. grunt.loadNpmTasks("grunt-contrib-cssmin");
  38. grunt.loadNpmTasks("grunt-contrib-htmlmin");
  39. grunt.loadNpmTasks("grunt-inline-alt");
  40. grunt.loadNpmTasks("grunt-chmod");
  41. grunt.loadNpmTasks("grunt-exec");
  42. grunt.loadNpmTasks("grunt-contrib-watch");
  43. // JS includes
  44. var jsIncludes = [
  45. // Third party framework libraries
  46. "src/js/lib/jquery-2.1.1.js",
  47. "src/js/lib/bootstrap-3.3.6.js",
  48. "src/js/lib/split.js",
  49. "src/js/lib/bootstrap-switch.js",
  50. "src/js/lib/yahoo.js",
  51. "src/js/lib/snowfall.jquery.js",
  52. // Third party operation libraries
  53. "src/js/lib/cryptojs/core.js",
  54. "src/js/lib/cryptojs/x64-core.js",
  55. "src/js/lib/cryptojs/enc-base64.js",
  56. "src/js/lib/cryptojs/enc-utf16.js",
  57. "src/js/lib/cryptojs/md5.js",
  58. "src/js/lib/cryptojs/evpkdf.js",
  59. "src/js/lib/cryptojs/cipher-core.js",
  60. "src/js/lib/cryptojs/mode-cfb.js",
  61. "src/js/lib/cryptojs/mode-ctr-gladman.js",
  62. "src/js/lib/cryptojs/mode-ctr.js",
  63. "src/js/lib/cryptojs/mode-ecb.js",
  64. "src/js/lib/cryptojs/mode-ofb.js",
  65. "src/js/lib/cryptojs/format-hex.js",
  66. "src/js/lib/cryptojs/lib-typedarrays.js",
  67. "src/js/lib/cryptojs/pad-ansix923.js",
  68. "src/js/lib/cryptojs/pad-iso10126.js",
  69. "src/js/lib/cryptojs/pad-iso97971.js",
  70. "src/js/lib/cryptojs/pad-nopadding.js",
  71. "src/js/lib/cryptojs/pad-zeropadding.js",
  72. "src/js/lib/cryptojs/aes.js",
  73. "src/js/lib/cryptojs/hmac.js",
  74. "src/js/lib/cryptojs/rabbit-legacy.js",
  75. "src/js/lib/cryptojs/rabbit.js",
  76. "src/js/lib/cryptojs/ripemd160.js",
  77. "src/js/lib/cryptojs/sha1.js",
  78. "src/js/lib/cryptojs/sha256.js",
  79. "src/js/lib/cryptojs/sha224.js",
  80. "src/js/lib/cryptojs/sha512.js",
  81. "src/js/lib/cryptojs/sha384.js",
  82. "src/js/lib/cryptojs/sha3.js",
  83. "src/js/lib/cryptojs/tripledes.js",
  84. "src/js/lib/cryptojs/rc4.js",
  85. "src/js/lib/cryptojs/pbkdf2.js",
  86. "src/js/lib/cryptoapi/crypto-api.js",
  87. "src/js/lib/cryptoapi/hasher.md2.js",
  88. "src/js/lib/cryptoapi/hasher.md4.js",
  89. "src/js/lib/cryptoapi/hasher.sha0.js",
  90. "src/js/lib/jsbn/jsbn.js",
  91. "src/js/lib/jsbn/jsbn2.js",
  92. "src/js/lib/jsbn/base64.js",
  93. "src/js/lib/jsbn/ec.js",
  94. "src/js/lib/jsbn/prng4.js",
  95. "src/js/lib/jsbn/rng.js",
  96. "src/js/lib/jsbn/rsa.js",
  97. "src/js/lib/jsbn/sec.js",
  98. "src/js/lib/jsrasign/asn1-1.0.js",
  99. "src/js/lib/jsrasign/asn1hex-1.1.js",
  100. "src/js/lib/jsrasign/asn1x509-1.0.js",
  101. "src/js/lib/jsrasign/base64x-1.1.js",
  102. "src/js/lib/jsrasign/crypto-1.1.js",
  103. "src/js/lib/jsrasign/dsa-modified-1.0.js",
  104. "src/js/lib/jsrasign/ecdsa-modified-1.0.js",
  105. "src/js/lib/jsrasign/ecparam-1.0.js",
  106. "src/js/lib/jsrasign/keyutil-1.0.js",
  107. "src/js/lib/jsrasign/x509-1.1.js",
  108. "src/js/lib/blowfish.dojo.js",
  109. "src/js/lib/rawdeflate.js",
  110. "src/js/lib/rawinflate.js",
  111. "src/js/lib/zip.js",
  112. "src/js/lib/unzip.js",
  113. "src/js/lib/zlib_and_gzip.js",
  114. "src/js/lib/bzip2.js",
  115. "src/js/lib/punycode.js",
  116. "src/js/lib/uas_parser.js",
  117. "src/js/lib/esprima.js",
  118. "src/js/lib/escodegen.browser.js",
  119. "src/js/lib/esmangle.min.js",
  120. "src/js/lib/diff.js",
  121. "src/js/lib/moment.js",
  122. "src/js/lib/moment-timezone.js",
  123. "src/js/lib/prettify.js",
  124. "src/js/lib/vkbeautify.js",
  125. "src/js/lib/Sortable.js",
  126. "src/js/lib/bootstrap-colorpicker.js",
  127. "src/js/lib/es6-promise.auto.js",
  128. "src/js/lib/xpath.js",
  129. // Custom libraries
  130. "src/js/lib/canvascomponents.js",
  131. // Utility functions
  132. "src/js/core/Utils.js",
  133. // Operation objects
  134. "src/js/operations/*.js",
  135. // Core framework objects
  136. "src/js/core/*.js",
  137. "src/js/config/Categories.js",
  138. "src/js/config/OperationConfig.js",
  139. // HTML view objects
  140. "src/js/views/html/*.js",
  141. "!src/js/views/html/main.js",
  142. ];
  143. var jsAppFiles = [].concat(
  144. jsIncludes,
  145. [
  146. // Start the main app!
  147. "src/js/views/html/main.js",
  148. ]
  149. );
  150. var jsTestFiles = [].concat(
  151. jsIncludes,
  152. [
  153. "test/TestRegister.js",
  154. "test/tests/**/*.js",
  155. "test/TestRunner.js",
  156. ]
  157. );
  158. var banner = '/**\n\
  159. * CyberChef - The Cyber Swiss Army Knife\n\
  160. *\n\
  161. * @copyright Crown Copyright 2016\n\
  162. * @license Apache-2.0\n\
  163. *\n\
  164. * Copyright 2016 Crown Copyright\n\
  165. *\n\
  166. * Licensed under the Apache License, Version 2.0 (the "License");\n\
  167. * you may not use this file except in compliance with the License.\n\
  168. * You may obtain a copy of the License at\n\
  169. *\n\
  170. * http://www.apache.org/licenses/LICENSE-2.0\n\
  171. *\n\
  172. * Unless required by applicable law or agreed to in writing, software\n\
  173. * distributed under the License is distributed on an "AS IS" BASIS,\n\
  174. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\
  175. * See the License for the specific language governing permissions and\n\
  176. * limitations under the License.\n\
  177. */\n';
  178. var templateOptions = {
  179. data: {
  180. compileTime: grunt.template.today("dd/mm/yyyy HH:MM:ss") + " UTC",
  181. compileMsg: grunt.option("compile-msg") || grunt.option("msg") || "",
  182. codebaseStats: grunt.file.read("src/static/stats.txt").split("\n").join("<br>")
  183. }
  184. };
  185. // Project configuration
  186. grunt.initConfig({
  187. eslint: {
  188. options: {
  189. configFile: "src/js/.eslintrc.json"
  190. },
  191. gruntfile: ["Gruntfile.js"],
  192. core: ["src/js/core/**/*.js"],
  193. config: ["src/js/config/**/*.js"],
  194. views: ["src/js/views/**/*.js"],
  195. operations: ["src/js/operations/**/*.js"],
  196. tests: [
  197. "test/**/*.js",
  198. "!test/PhantomRunner.js",
  199. "!test/NodeRunner.js",
  200. ],
  201. },
  202. jsdoc: {
  203. options: {
  204. destination: "docs",
  205. template: "node_modules/ink-docstrap/template",
  206. recurse: true,
  207. readme: "./README.md",
  208. configure: "docs/jsdoc.conf.json"
  209. },
  210. all: {
  211. src: [
  212. "src/js/**/*.js",
  213. "!src/js/lib/**/*",
  214. ],
  215. }
  216. },
  217. clean: {
  218. dev: ["build/dev/*"],
  219. test: ["build/test/*"],
  220. prod: ["build/prod/*"],
  221. docs: ["docs/*", "!docs/*.conf.json", "!docs/*.ico"],
  222. },
  223. concat: {
  224. options: {
  225. process: templateOptions
  226. },
  227. css: {
  228. options: {
  229. banner: banner.replace(/\/\*\*/g, "/*!"),
  230. process: function(content, srcpath) {
  231. // Change special comments from /** to /*! to comply with cssmin
  232. content = content.replace(/^\/\*\* /g, "/*! ");
  233. return grunt.template.process(content);
  234. }
  235. },
  236. src: [
  237. "src/css/lib/**/*.css",
  238. "src/css/structure/**/*.css",
  239. "src/css/themes/classic.css"
  240. ],
  241. dest: "build/dev/styles.css"
  242. },
  243. js: {
  244. options: {
  245. banner: '"use strict";\n'
  246. },
  247. src: jsAppFiles,
  248. dest: "build/dev/scripts.js"
  249. },
  250. jsTest: {
  251. options: {
  252. banner: '"use strict";\n'
  253. },
  254. src: jsTestFiles,
  255. dest: "build/test/tests.js"
  256. }
  257. },
  258. copy: {
  259. htmlDev: {
  260. options: {
  261. process: function(content, srcpath) {
  262. return grunt.template.process(content, templateOptions);
  263. }
  264. },
  265. src: "src/html/index.html",
  266. dest: "build/dev/index.html"
  267. },
  268. htmlTest: {
  269. options: {
  270. process: function(content, srcpath) {
  271. return grunt.template.process(content, templateOptions);
  272. }
  273. },
  274. src: "src/html/test.html",
  275. dest: "build/test/index.html"
  276. },
  277. htmlProd: {
  278. options: {
  279. process: function(content, srcpath) {
  280. return grunt.template.process(content, templateOptions);
  281. }
  282. },
  283. src: "src/html/index.html",
  284. dest: "build/prod/index.html"
  285. },
  286. htmlInline: {
  287. options: {
  288. process: function(content, srcpath) {
  289. // TODO: Do all this in Jade
  290. content = content.replace(
  291. '<a href="cyberchef.htm" style="float: left; margin-left: 10px; margin-right: 80px;" download>Download CyberChef<img src="images/download-24x24.png" /></a>',
  292. '<span style="float: left; margin-left: 10px;">Compile time: ' + grunt.template.today("dd/mm/yyyy HH:MM:ss") + " UTC</span>");
  293. return grunt.template.process(content, templateOptions);
  294. }
  295. },
  296. src: "src/html/index.html",
  297. dest: "build/prod/cyberchef.htm"
  298. },
  299. staticDev: {
  300. files: [
  301. {
  302. expand: true,
  303. cwd: "src/static/",
  304. src: [
  305. "**/*",
  306. "**/.*",
  307. "!stats.txt",
  308. "!ga.html"
  309. ],
  310. dest: "build/dev/"
  311. }
  312. ]
  313. },
  314. staticProd: {
  315. files: [
  316. {
  317. expand: true,
  318. cwd: "src/static/",
  319. src: [
  320. "**/*",
  321. "**/.*",
  322. "!stats.txt",
  323. "!ga.html"
  324. ],
  325. dest: "build/prod/"
  326. }
  327. ]
  328. },
  329. ghPages: {
  330. options: {
  331. process: function(content, srcpath) {
  332. // Add Google Analytics code to index.html
  333. content = content.replace("</body></html>",
  334. grunt.file.read("src/static/ga.html") + "</body></html>");
  335. return grunt.template.process(content, templateOptions);
  336. }
  337. },
  338. src: "build/prod/index.html",
  339. dest: "build/prod/index.html"
  340. }
  341. },
  342. uglify: {
  343. options: {
  344. preserveComments: function(node, comment) {
  345. if (comment.value.indexOf("* @license") === 0) return true;
  346. return false;
  347. },
  348. screwIE8: true,
  349. ASCIIOnly: true,
  350. beautify: {
  351. beautify: false,
  352. inline_script: true, // eslint-disable-line camelcase
  353. ascii_only: true, // eslint-disable-line camelcase
  354. screw_ie8: true // eslint-disable-line camelcase
  355. },
  356. compress: {
  357. screw_ie8: true // eslint-disable-line camelcase
  358. },
  359. banner: banner
  360. },
  361. prod: {
  362. src: "build/dev/scripts.js",
  363. dest: "build/prod/scripts.js"
  364. }
  365. },
  366. cssmin: {
  367. prod: {
  368. src: "build/dev/styles.css",
  369. dest: "build/prod/styles.css"
  370. }
  371. },
  372. htmlmin: {
  373. prod: {
  374. options: {
  375. removeComments: true,
  376. collapseWhitespace: true,
  377. minifyJS: true,
  378. minifyCSS: true
  379. },
  380. src: "build/prod/index.html",
  381. dest: "build/prod/index.html"
  382. },
  383. inline: {
  384. options: {
  385. removeComments: true,
  386. collapseWhitespace: true,
  387. minifyJS: false,
  388. minifyCSS: false
  389. },
  390. src: "build/prod/cyberchef.htm",
  391. dest: "build/prod/cyberchef.htm"
  392. }
  393. },
  394. inline: {
  395. options: {
  396. tag: "",
  397. inlineTagAttributes: {
  398. js: "type='application/javascript'",
  399. css: "type='text/css'"
  400. }
  401. },
  402. compiled: {
  403. src: "build/prod/cyberchef.htm",
  404. dest: "build/prod/cyberchef.htm"
  405. },
  406. prod: {
  407. options: {
  408. tag: "__inline"
  409. },
  410. src: "build/prod/index.html",
  411. dest: "build/prod/index.html"
  412. }
  413. },
  414. chmod: {
  415. build: {
  416. options: {
  417. mode: "755",
  418. },
  419. src: ["build/**/*", "build/**/.htaccess", "build/"]
  420. },
  421. docs: {
  422. options: {
  423. mode: "755",
  424. },
  425. src: ["docs/**/*", "docs/"]
  426. }
  427. },
  428. exec: {
  429. tests: {
  430. command: "node test/NodeRunner.js",
  431. },
  432. repoSize: {
  433. command: [
  434. "git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
  435. "du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'"
  436. ].join(";"),
  437. stderr: false
  438. },
  439. stats: {
  440. command: "rm src/static/stats.txt;" +
  441. [
  442. "ls src/ -R1 | grep '^$' -v | grep ':$' -v | wc -l | xargs printf '%b\tsource files\n'",
  443. "find src/ -regex '.*\..*' -print | xargs cat | wc -l | xargs printf '%b\tlines\n'",
  444. "du -hs src/ | pcregrep -o '^[^\t]*' | xargs printf '%b\tsize\n'",
  445. "ls src/js/ -R1 | grep '\.js$' | wc -l | xargs printf '\n%b\tJavaScript source files\n'",
  446. "find src/js/ -regex '.*\.js' -print | xargs cat | wc -l | xargs printf '%b\tlines\n'",
  447. "find src/js/ -regex '.*\.js' -exec du -hcs {} \+ | tail -n1 | egrep -o '^[^\t]*' | xargs printf '%b\tsize\n'",
  448. "find src/js/ -regex '.*/lib/.*\.js' -print | wc -l | xargs printf '\n%b\tthird party JavaScript source files\n'",
  449. "find src/js/ -regex '.*/lib/.*\.js' -print | xargs cat | wc -l | xargs printf '%b\tlines\n'",
  450. "find src/js/ -regex '.*/lib/.*\.js' -exec du -hcs {} \+ | tail -n1 | egrep -o '^[^\t]*' | xargs printf '%b\tsize\n'",
  451. "find src/js/ -regex '.*\.js' -not -regex '.*/lib/.*' -print | wc -l | xargs printf '\n%b\tfirst party JavaScript source files\n'",
  452. "find src/js/ -regex '.*\.js' -not -regex '.*/lib/.*' -print | xargs cat | wc -l | xargs printf '%b\tlines\n'",
  453. "find src/js/ -regex '.*\.js' -not -regex '.*/lib/.*' -exec du -hcs {} \+ | tail -n1 | egrep -o '^[^\t]*' | xargs printf '%b\tsize\n'",
  454. "du build/dev/scripts.js -h | egrep -o '^[^\t]*' | xargs printf '\n%b\tuncompressed JavaScript size\n'",
  455. "du build/prod/scripts.js -h | egrep -o '^[^\t]*' | xargs printf '%b\tcompressed JavaScript size\n'",
  456. "grep -E '^\\s+name: ' src/js/config/Categories.js | wc -l | xargs printf '\n%b\tcategories\n'",
  457. "grep -E '^\\s+\"[A-Za-z0-9 \\-]+\": {' src/js/config/OperationConfig.js | wc -l | xargs printf '%b\toperations\n'",
  458. ].join(" >> src/static/stats.txt;") + " >> src/static/stats.txt;",
  459. stderr: false
  460. },
  461. displayStats: {
  462. command: "cat src/static/stats.txt"
  463. },
  464. cleanGit: {
  465. command: "git gc --prune=now --aggressive"
  466. },
  467. deployGhPages: {
  468. command: [
  469. "git add build/prod/index.html -v",
  470. "COMMIT_HASH=$(git rev-parse HEAD)",
  471. "git commit -m \"GitHub Pages release for ${COMMIT_HASH}\"",
  472. "git push origin `git subtree split --prefix build/prod master`:gh-pages --force",
  473. "git reset HEAD~",
  474. "git checkout build/prod/index.html"
  475. ].join(";")
  476. }
  477. },
  478. watch: {
  479. css: {
  480. files: "src/css/**/*.css",
  481. tasks: ["concat:css", "chmod:build"]
  482. },
  483. js: {
  484. files: "src/js/**/*.js",
  485. tasks: ["concat:js", "chmod:build"]
  486. },
  487. html: {
  488. files: "src/html/**/*.html",
  489. tasks: ["copy:htmlDev", "chmod:build"]
  490. },
  491. static: {
  492. files: ["src/static/**/*", "src/static/**/.*"],
  493. tasks: ["copy:staticDev", "chmod:build"]
  494. },
  495. grunt: {
  496. files: "Gruntfile.js",
  497. tasks: ["clean:dev", "concat:css", "concat:js", "copy:htmlDev", "copy:staticDev", "chmod:build"]
  498. }
  499. },
  500. });
  501. };