Utils.js 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. import CryptoJS from "crypto-js";
  2. /**
  3. * Utility functions for use in operations, the core framework and the stage.
  4. *
  5. * @author n1474335 [n1474335@gmail.com]
  6. * @copyright Crown Copyright 2016
  7. * @license Apache-2.0
  8. *
  9. * @namespace
  10. */
  11. const Utils = {
  12. /**
  13. * Translates an ordinal into a character.
  14. *
  15. * @param {number} o
  16. * @returns {char}
  17. *
  18. * @example
  19. * // returns 'a'
  20. * Utils.chr(97);
  21. */
  22. chr: function(o) {
  23. // Detect astral symbols
  24. // Thanks to @mathiasbynens for this solution
  25. // https://mathiasbynens.be/notes/javascript-unicode
  26. if (o > 0xffff) {
  27. o -= 0x10000;
  28. const high = String.fromCharCode(o >>> 10 & 0x3ff | 0xd800);
  29. o = 0xdc00 | o & 0x3ff;
  30. return high + String.fromCharCode(o);
  31. }
  32. return String.fromCharCode(o);
  33. },
  34. /**
  35. * Translates a character into an ordinal.
  36. *
  37. * @param {char} c
  38. * @returns {number}
  39. *
  40. * @example
  41. * // returns 97
  42. * Utils.ord('a');
  43. */
  44. ord: function(c) {
  45. // Detect astral symbols
  46. // Thanks to @mathiasbynens for this solution
  47. // https://mathiasbynens.be/notes/javascript-unicode
  48. if (c.length === 2) {
  49. const high = c.charCodeAt(0);
  50. const low = c.charCodeAt(1);
  51. if (high >= 0xd800 && high < 0xdc00 &&
  52. low >= 0xdc00 && low < 0xe000) {
  53. return (high - 0xd800) * 0x400 + low - 0xdc00 + 0x10000;
  54. }
  55. }
  56. return c.charCodeAt(0);
  57. },
  58. /**
  59. * Adds leading zeros to strings
  60. *
  61. * @param {string} str - String to add leading characters to.
  62. * @param {number} max - Maximum width of the string.
  63. * @param {char} [chr='0'] - The character to pad with.
  64. * @returns {string}
  65. *
  66. * @example
  67. * // returns "0a"
  68. * Utils.padLeft("a", 2);
  69. *
  70. * // returns "000a"
  71. * Utils.padLeft("a", 4);
  72. *
  73. * // returns "xxxa"
  74. * Utils.padLeft("a", 4, "x");
  75. *
  76. * // returns "bcabchello"
  77. * Utils.padLeft("hello", 10, "abc");
  78. */
  79. padLeft: function(str, max, chr) {
  80. chr = chr || "0";
  81. let startIndex = chr.length - (max - str.length);
  82. startIndex = startIndex < 0 ? 0 : startIndex;
  83. return str.length < max ?
  84. Utils.padLeft(chr.slice(startIndex, chr.length) + str, max, chr) : str;
  85. },
  86. /**
  87. * Adds trailing spaces to strings.
  88. *
  89. * @param {string} str - String to add trailing characters to.
  90. * @param {number} max - Maximum width of the string.
  91. * @param {char} [chr='0'] - The character to pad with.
  92. * @returns {string}
  93. *
  94. * @example
  95. * // returns "a "
  96. * Utils.padRight("a", 4);
  97. *
  98. * // returns "axxx"
  99. * Utils.padRight("a", 4, "x");
  100. */
  101. padRight: function(str, max, chr) {
  102. chr = chr || " ";
  103. return str.length < max ?
  104. Utils.padRight(str + chr.slice(0, max-str.length), max, chr) : str;
  105. },
  106. /**
  107. * Adds trailing bytes to a byteArray.
  108. *
  109. * @author tlwr [toby@toby.codes]
  110. *
  111. * @param {byteArray} arr - byteArray to add trailing bytes to.
  112. * @param {number} numBytes - Maximum width of the array.
  113. * @param {Integer} [padByte=0] - The byte to pad with.
  114. * @returns {byteArray}
  115. *
  116. * @example
  117. * // returns ["a", 0, 0, 0]
  118. * Utils.padBytesRight("a", 4);
  119. *
  120. * // returns ["a", 1, 1, 1]
  121. * Utils.padBytesRight("a", 4, 1);
  122. *
  123. * // returns ["t", "e", "s", "t", 0, 0, 0, 0]
  124. * Utils.padBytesRight("test", 8);
  125. *
  126. * // returns ["t", "e", "s", "t", 1, 1, 1, 1]
  127. * Utils.padBytesRight("test", 8, 1);
  128. */
  129. padBytesRight: function(arr, numBytes, padByte) {
  130. padByte = padByte || 0;
  131. const paddedBytes = new Array(numBytes);
  132. paddedBytes.fill(padByte);
  133. Array.prototype.map.call(arr, function(b, i) {
  134. paddedBytes[i] = b;
  135. });
  136. return paddedBytes;
  137. },
  138. /**
  139. * @alias Utils.padLeft
  140. */
  141. pad: function(str, max, chr) {
  142. return Utils.padLeft(str, max, chr);
  143. },
  144. /**
  145. * Truncates a long string to max length and adds suffix.
  146. *
  147. * @param {string} str - String to truncate
  148. * @param {number} max - Maximum length of the final string
  149. * @param {string} [suffix='...'] - The string to add to the end of the final string
  150. * @returns {string}
  151. *
  152. * @example
  153. * // returns "A long..."
  154. * Utils.truncate("A long string", 9);
  155. *
  156. * // returns "A long s-"
  157. * Utils.truncate("A long string", 9, "-");
  158. */
  159. truncate: function(str, max, suffix) {
  160. suffix = suffix || "...";
  161. if (str.length > max) {
  162. str = str.slice(0, max - suffix.length) + suffix;
  163. }
  164. return str;
  165. },
  166. /**
  167. * Converts a character or number to its hex representation.
  168. *
  169. * @param {char|number} c
  170. * @param {number} [length=2] - The width of the resulting hex number.
  171. * @returns {string}
  172. *
  173. * @example
  174. * // returns "6e"
  175. * Utils.hex("n");
  176. *
  177. * // returns "6e"
  178. * Utils.hex(110);
  179. */
  180. hex: function(c, length) {
  181. c = typeof c == "string" ? Utils.ord(c) : c;
  182. length = length || 2;
  183. return Utils.pad(c.toString(16), length);
  184. },
  185. /**
  186. * Converts a character or number to its binary representation.
  187. *
  188. * @param {char|number} c
  189. * @param {number} [length=8] - The width of the resulting binary number.
  190. * @returns {string}
  191. *
  192. * @example
  193. * // returns "01101110"
  194. * Utils.bin("n");
  195. *
  196. * // returns "01101110"
  197. * Utils.bin(110);
  198. */
  199. bin: function(c, length) {
  200. c = typeof c == "string" ? Utils.ord(c) : c;
  201. length = length || 8;
  202. return Utils.pad(c.toString(2), length);
  203. },
  204. /**
  205. * Returns a string with all non-printable chars as dots, optionally preserving whitespace.
  206. *
  207. * @param {string} str - The input string to display.
  208. * @param {boolean} [preserveWs=false] - Whether or not to print whitespace.
  209. * @returns {string}
  210. */
  211. printable: function(str, preserveWs) {
  212. if (typeof window !== "undefined" && window.app && !window.app.options.treatAsUtf8) {
  213. str = Utils.byteArrayToChars(Utils.strToByteArray(str));
  214. }
  215. const re = /[\0-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uE000-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
  216. const wsRe = /[\x09-\x10\x0D\u2028\u2029]/g;
  217. str = str.replace(re, ".");
  218. if (!preserveWs) str = str.replace(wsRe, ".");
  219. return str;
  220. },
  221. /**
  222. * Parse a string entered by a user and replace escaped chars with the bytes they represent.
  223. *
  224. * @param {string} str
  225. * @returns {string}
  226. *
  227. * @example
  228. * // returns "\x00"
  229. * Utils.parseEscapedChars("\\x00");
  230. *
  231. * // returns "\n"
  232. * Utils.parseEscapedChars("\\n");
  233. */
  234. parseEscapedChars: function(str) {
  235. return str.replace(/(\\)?\\([nrtbf]|x[\da-f]{2})/g, function(m, a, b) {
  236. if (a === "\\") return "\\"+b;
  237. switch (b[0]) {
  238. case "n":
  239. return "\n";
  240. case "r":
  241. return "\r";
  242. case "t":
  243. return "\t";
  244. case "b":
  245. return "\b";
  246. case "f":
  247. return "\f";
  248. case "x":
  249. return Utils.chr(parseInt(b.substr(1), 16));
  250. }
  251. });
  252. },
  253. /**
  254. * Escape a string containing regex control characters so that it can be safely
  255. * used in a regex without causing unintended behaviours.
  256. *
  257. * @param {string} str
  258. * @returns {string}
  259. *
  260. * @example
  261. * // returns "\[example\]"
  262. * Utils.escapeRegex("[example]");
  263. */
  264. escapeRegex: function(str) {
  265. return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, "\\$1");
  266. },
  267. /**
  268. * Expand an alphabet range string into a list of the characters in that range.
  269. *
  270. * @param {string} alphStr
  271. * @returns {char[]}
  272. *
  273. * @example
  274. * // returns ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]
  275. * Utils.expandAlphRange("0-9");
  276. *
  277. * // returns ["a", "b", "c", "d", "0", "1", "2", "3", "+", "/"]
  278. * Utils.expandAlphRange("a-d0-3+/");
  279. *
  280. * // returns ["a", "b", "c", "d", "0", "-", "3"]
  281. * Utils.expandAlphRange("a-d0\\-3")
  282. */
  283. expandAlphRange: function(alphStr) {
  284. const alphArr = [];
  285. for (let i = 0; i < alphStr.length; i++) {
  286. if (i < alphStr.length - 2 &&
  287. alphStr[i+1] === "-" &&
  288. alphStr[i] !== "\\") {
  289. let start = Utils.ord(alphStr[i]),
  290. end = Utils.ord(alphStr[i+2]);
  291. for (let j = start; j <= end; j++) {
  292. alphArr.push(Utils.chr(j));
  293. }
  294. i += 2;
  295. } else if (i < alphStr.length - 2 &&
  296. alphStr[i] === "\\" &&
  297. alphStr[i+1] === "-") {
  298. alphArr.push("-");
  299. i++;
  300. } else {
  301. alphArr.push(alphStr[i]);
  302. }
  303. }
  304. return alphArr;
  305. },
  306. /**
  307. * Converts a string to a byte array.
  308. * Treats the string as UTF-8 if any values are over 255.
  309. *
  310. * @param {string} str
  311. * @returns {byteArray}
  312. *
  313. * @example
  314. * // returns [72,101,108,108,111]
  315. * Utils.strToByteArray("Hello");
  316. *
  317. * // returns [228,189,160,229,165,189]
  318. * Utils.strToByteArray("你好");
  319. */
  320. strToByteArray: function(str) {
  321. const byteArray = new Array(str.length);
  322. let i = str.length, b;
  323. while (i--) {
  324. b = str.charCodeAt(i);
  325. byteArray[i] = b;
  326. // If any of the bytes are over 255, read as UTF-8
  327. if (b > 255) return Utils.strToUtf8ByteArray(str);
  328. }
  329. return byteArray;
  330. },
  331. /**
  332. * Converts a string to a UTF-8 byte array.
  333. *
  334. * @param {string} str
  335. * @returns {byteArray}
  336. *
  337. * @example
  338. * // returns [72,101,108,108,111]
  339. * Utils.strToUtf8ByteArray("Hello");
  340. *
  341. * // returns [228,189,160,229,165,189]
  342. * Utils.strToUtf8ByteArray("你好");
  343. */
  344. strToUtf8ByteArray: function(str) {
  345. let wordArray = CryptoJS.enc.Utf8.parse(str),
  346. byteArray = Utils.wordArrayToByteArray(wordArray);
  347. if (typeof window !== "undefined" && str.length !== wordArray.sigBytes) {
  348. window.app.options.attemptHighlight = false;
  349. }
  350. return byteArray;
  351. },
  352. /**
  353. * Converts a string to a unicode charcode array
  354. *
  355. * @param {string} str
  356. * @returns {byteArray}
  357. *
  358. * @example
  359. * // returns [72,101,108,108,111]
  360. * Utils.strToCharcode("Hello");
  361. *
  362. * // returns [20320,22909]
  363. * Utils.strToCharcode("你好");
  364. */
  365. strToCharcode: function(str) {
  366. const charcode = new Array();
  367. for (let i = 0; i < str.length; i++) {
  368. let ord = str.charCodeAt(i);
  369. // Detect and merge astral symbols
  370. if (i < str.length - 1 && ord >= 0xd800 && ord < 0xdc00) {
  371. const low = str[i + 1].charCodeAt(0);
  372. if (low >= 0xdc00 && low < 0xe000) {
  373. ord = Utils.ord(str[i] + str[++i]);
  374. }
  375. }
  376. charcode.push(ord);
  377. }
  378. return charcode;
  379. },
  380. /**
  381. * Attempts to convert a byte array to a UTF-8 string.
  382. *
  383. * @param {byteArray} byteArray
  384. * @returns {string}
  385. *
  386. * @example
  387. * // returns "Hello"
  388. * Utils.byteArrayToUtf8([72,101,108,108,111]);
  389. *
  390. * // returns "你好"
  391. * Utils.byteArrayToUtf8([228,189,160,229,165,189]);
  392. */
  393. byteArrayToUtf8: function(byteArray) {
  394. try {
  395. // Try to output data as UTF-8 string
  396. const words = [];
  397. for (let i = 0; i < byteArray.length; i++) {
  398. words[i >>> 2] |= byteArray[i] << (24 - (i % 4) * 8);
  399. }
  400. let wordArray = new CryptoJS.lib.WordArray.init(words, byteArray.length),
  401. str = CryptoJS.enc.Utf8.stringify(wordArray);
  402. if (typeof window !== "undefined" && str.length !== wordArray.sigBytes)
  403. window.app.options.attemptHighlight = false;
  404. return str;
  405. } catch (err) {
  406. // If it fails, treat it as ANSI
  407. return Utils.byteArrayToChars(byteArray);
  408. }
  409. },
  410. /**
  411. * Converts a charcode array to a string.
  412. *
  413. * @param {byteArray} byteArray
  414. * @returns {string}
  415. *
  416. * @example
  417. * // returns "Hello"
  418. * Utils.byteArrayToChars([72,101,108,108,111]);
  419. *
  420. * // returns "你好"
  421. * Utils.byteArrayToChars([20320,22909]);
  422. */
  423. byteArrayToChars: function(byteArray) {
  424. if (!byteArray) return "";
  425. let str = "";
  426. for (let i = 0; i < byteArray.length;) {
  427. str += String.fromCharCode(byteArray[i++]);
  428. }
  429. return str;
  430. },
  431. /**
  432. * Converts a CryptoJS.lib.WordArray to a byteArray.
  433. *
  434. * @param {CryptoJS.lib.WordArray} wordArray
  435. * @returns {byteArray}
  436. *
  437. * @example
  438. * // returns [84, 101, 115, 116]
  439. * Utils.wordArrayToByteArray(CryptoJS.enc.Hex.parse("54657374"));
  440. */
  441. wordArrayToByteArray: function(wordArray) {
  442. if (wordArray.sigBytes <= 0) return [];
  443. let words = wordArray.words,
  444. byteArray = [];
  445. for (let i = 0; i < wordArray.sigBytes; i++) {
  446. byteArray.push((words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff);
  447. }
  448. return byteArray;
  449. },
  450. /**
  451. * Base64's the input byte array using the given alphabet, returning a string.
  452. *
  453. * @param {byteArray|string} data
  454. * @param {string} [alphabet]
  455. * @returns {string}
  456. *
  457. * @example
  458. * // returns "SGVsbG8="
  459. * Utils.toBase64([72, 101, 108, 108, 111]);
  460. *
  461. * // returns "SGVsbG8="
  462. * Utils.toBase64("Hello");
  463. */
  464. toBase64: function(data, alphabet) {
  465. if (!data) return "";
  466. if (typeof data == "string") {
  467. data = Utils.strToByteArray(data);
  468. }
  469. alphabet = alphabet ?
  470. Utils.expandAlphRange(alphabet).join("") :
  471. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  472. let output = "",
  473. chr1, chr2, chr3,
  474. enc1, enc2, enc3, enc4,
  475. i = 0;
  476. while (i < data.length) {
  477. chr1 = data[i++];
  478. chr2 = data[i++];
  479. chr3 = data[i++];
  480. enc1 = chr1 >> 2;
  481. enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  482. enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  483. enc4 = chr3 & 63;
  484. if (isNaN(chr2)) {
  485. enc3 = enc4 = 64;
  486. } else if (isNaN(chr3)) {
  487. enc4 = 64;
  488. }
  489. output += alphabet.charAt(enc1) + alphabet.charAt(enc2) +
  490. alphabet.charAt(enc3) + alphabet.charAt(enc4);
  491. }
  492. return output;
  493. },
  494. /**
  495. * UnBase64's the input string using the given alphabet, returning a byte array.
  496. *
  497. * @param {byteArray} data
  498. * @param {string} [alphabet]
  499. * @param {string} [returnType="string"] - Either "string" or "byteArray"
  500. * @param {boolean} [removeNonAlphChars=true]
  501. * @returns {byteArray}
  502. *
  503. * @example
  504. * // returns "Hello"
  505. * Utils.fromBase64("SGVsbG8=");
  506. *
  507. * // returns [72, 101, 108, 108, 111]
  508. * Utils.fromBase64("SGVsbG8=", null, "byteArray");
  509. */
  510. fromBase64: function(data, alphabet, returnType, removeNonAlphChars) {
  511. returnType = returnType || "string";
  512. if (!data) {
  513. return returnType === "string" ? "" : [];
  514. }
  515. alphabet = alphabet ?
  516. Utils.expandAlphRange(alphabet).join("") :
  517. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  518. if (removeNonAlphChars === undefined)
  519. removeNonAlphChars = true;
  520. let output = [],
  521. chr1, chr2, chr3,
  522. enc1, enc2, enc3, enc4,
  523. i = 0;
  524. if (removeNonAlphChars) {
  525. const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
  526. data = data.replace(re, "");
  527. }
  528. while (i < data.length) {
  529. enc1 = alphabet.indexOf(data.charAt(i++));
  530. enc2 = alphabet.indexOf(data.charAt(i++) || "=");
  531. enc3 = alphabet.indexOf(data.charAt(i++) || "=");
  532. enc4 = alphabet.indexOf(data.charAt(i++) || "=");
  533. enc2 = enc2 === -1 ? 64 : enc2;
  534. enc3 = enc3 === -1 ? 64 : enc3;
  535. enc4 = enc4 === -1 ? 64 : enc4;
  536. chr1 = (enc1 << 2) | (enc2 >> 4);
  537. chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
  538. chr3 = ((enc3 & 3) << 6) | enc4;
  539. output.push(chr1);
  540. if (enc3 !== 64) {
  541. output.push(chr2);
  542. }
  543. if (enc4 !== 64) {
  544. output.push(chr3);
  545. }
  546. }
  547. return returnType === "string" ? Utils.byteArrayToUtf8(output) : output;
  548. },
  549. /**
  550. * Convert a byte array into a hex string.
  551. *
  552. * @param {byteArray} data
  553. * @param {string} [delim=" "]
  554. * @param {number} [padding=2]
  555. * @returns {string}
  556. *
  557. * @example
  558. * // returns "0a 14 1e"
  559. * Utils.toHex([10,20,30]);
  560. *
  561. * // returns "0a:14:1e"
  562. * Utils.toHex([10,20,30], ":");
  563. */
  564. toHex: function(data, delim, padding) {
  565. if (!data) return "";
  566. delim = typeof delim == "string" ? delim : " ";
  567. padding = padding || 2;
  568. let output = "";
  569. for (let i = 0; i < data.length; i++) {
  570. output += Utils.pad(data[i].toString(16), padding) + delim;
  571. }
  572. // Add \x or 0x to beginning
  573. if (delim === "0x") output = "0x" + output;
  574. if (delim === "\\x") output = "\\x" + output;
  575. if (delim.length)
  576. return output.slice(0, -delim.length);
  577. else
  578. return output;
  579. },
  580. /**
  581. * Convert a byte array into a hex string as efficiently as possible with no options.
  582. *
  583. * @param {byteArray} data
  584. * @returns {string}
  585. *
  586. * @example
  587. * // returns "0a141e"
  588. * Utils.toHex([10,20,30]);
  589. */
  590. toHexFast: function(data) {
  591. if (!data) return "";
  592. const output = [];
  593. for (let i = 0; i < data.length; i++) {
  594. output.push((data[i] >>> 4).toString(16));
  595. output.push((data[i] & 0x0f).toString(16));
  596. }
  597. return output.join("");
  598. },
  599. /**
  600. * Convert a hex string into a byte array.
  601. *
  602. * @param {string} data
  603. * @param {string} [delim]
  604. * @param {number} [byteLen=2]
  605. * @returns {byteArray}
  606. *
  607. * @example
  608. * // returns [10,20,30]
  609. * Utils.fromHex("0a 14 1e");
  610. *
  611. * // returns [10,20,30]
  612. * Utils.fromHex("0a:14:1e", "Colon");
  613. */
  614. fromHex: function(data, delim, byteLen) {
  615. delim = delim || (data.indexOf(" ") >= 0 ? "Space" : "None");
  616. byteLen = byteLen || 2;
  617. if (delim !== "None") {
  618. const delimRegex = Utils.regexRep[delim];
  619. data = data.replace(delimRegex, "");
  620. }
  621. const output = [];
  622. for (let i = 0; i < data.length; i += byteLen) {
  623. output.push(parseInt(data.substr(i, byteLen), 16));
  624. }
  625. return output;
  626. },
  627. /**
  628. * Parses CSV data and returns it as a two dimensional array or strings.
  629. *
  630. * @param {string} data
  631. * @returns {string[][]}
  632. *
  633. * @example
  634. * // returns [["head1", "head2"], ["data1", "data2"]]
  635. * Utils.parseCSV("head1,head2\ndata1,data2");
  636. */
  637. parseCSV: function(data) {
  638. let b,
  639. ignoreNext = false,
  640. inString = false,
  641. cell = "",
  642. line = [],
  643. lines = [];
  644. for (let i = 0; i < data.length; i++) {
  645. b = data[i];
  646. if (ignoreNext) {
  647. cell += b;
  648. ignoreNext = false;
  649. } else if (b === "\\") {
  650. cell += b;
  651. ignoreNext = true;
  652. } else if (b === "\"" && !inString) {
  653. inString = true;
  654. } else if (b === "\"" && inString) {
  655. inString = false;
  656. } else if (b === "," && !inString) {
  657. line.push(cell);
  658. cell = "";
  659. } else if ((b === "\n" || b === "\r") && !inString) {
  660. line.push(cell);
  661. cell = "";
  662. lines.push(line);
  663. line = [];
  664. } else {
  665. cell += b;
  666. }
  667. }
  668. if (line.length) {
  669. line.push(cell);
  670. lines.push(line);
  671. }
  672. return lines;
  673. },
  674. /**
  675. * Removes all HTML (or XML) tags from the input string.
  676. *
  677. * @param {string} htmlStr
  678. * @param {boolean} removeScriptAndStyle - Flag to specify whether to remove entire script or style blocks
  679. * @returns {string}
  680. *
  681. * @example
  682. * // returns "Test"
  683. * Utils.stripHtmlTags("<div>Test</div>");
  684. */
  685. stripHtmlTags: function(htmlStr, removeScriptAndStyle) {
  686. if (removeScriptAndStyle) {
  687. htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
  688. }
  689. return htmlStr.replace(/<[^>]+>/g, "");
  690. },
  691. /**
  692. * Escapes HTML tags in a string to stop them being rendered.
  693. * https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
  694. *
  695. * @param {string} str
  696. * @returns string
  697. *
  698. * @example
  699. * // return "A &lt;script&gt; tag"
  700. * Utils.escapeHtml("A <script> tag");
  701. */
  702. escapeHtml: function(str) {
  703. const HTML_CHARS = {
  704. "&": "&amp;",
  705. "<": "&lt;",
  706. ">": "&gt;",
  707. '"': "&quot;",
  708. "'": "&#x27;", // &apos; not recommended because it's not in the HTML spec
  709. "/": "&#x2F;", // forward slash is included as it helps end an HTML entity
  710. "`": "&#x60;"
  711. };
  712. return str.replace(/[&<>"'/`]/g, function (match) {
  713. return HTML_CHARS[match];
  714. });
  715. },
  716. /**
  717. * Unescapes HTML tags in a string to make them render again.
  718. *
  719. * @param {string} str
  720. * @returns string
  721. *
  722. * @example
  723. * // return "A <script> tag"
  724. * Utils.unescapeHtml("A &lt;script&gt; tag");
  725. */
  726. unescapeHtml: function(str) {
  727. const HTML_CHARS = {
  728. "&amp;": "&",
  729. "&lt;": "<",
  730. "&gt;": ">",
  731. "&quot;": '"',
  732. "&#x27;": "'",
  733. "&#x2F;": "/",
  734. "&#x60;": "`"
  735. };
  736. return str.replace(/&#?x?[a-z0-9]{2,4};/ig, function (match) {
  737. return HTML_CHARS[match] || match;
  738. });
  739. },
  740. /**
  741. * Expresses a number of milliseconds in a human readable format.
  742. *
  743. * Range | Sample Output
  744. * -----------------------------|-------------------------------
  745. * 0 to 45 seconds | a few seconds ago
  746. * 45 to 90 seconds | a minute ago
  747. * 90 seconds to 45 minutes | 2 minutes ago ... 45 minutes ago
  748. * 45 to 90 minutes | an hour ago
  749. * 90 minutes to 22 hours | 2 hours ago ... 22 hours ago
  750. * 22 to 36 hours | a day ago
  751. * 36 hours to 25 days | 2 days ago ... 25 days ago
  752. * 25 to 45 days | a month ago
  753. * 45 to 345 days | 2 months ago ... 11 months ago
  754. * 345 to 545 days (1.5 years) | a year ago
  755. * 546 days+ | 2 years ago ... 20 years ago
  756. *
  757. * @param {number} ms
  758. * @returns {string}
  759. *
  760. * @example
  761. * // returns "3 minutes"
  762. * Utils.fuzzyTime(152435);
  763. *
  764. * // returns "5 days"
  765. * Utils.fuzzyTime(456851321);
  766. */
  767. fuzzyTime: function(ms) {
  768. return moment.duration(ms, "milliseconds").humanize();
  769. },
  770. /**
  771. * Adds the properties of one Object to another.
  772. *
  773. * @param {Object} a
  774. * @param {Object} b
  775. * @returns {Object}
  776. */
  777. extend: function(a, b){
  778. for (const key in b)
  779. if (b.hasOwnProperty(key))
  780. a[key] = b[key];
  781. return a;
  782. },
  783. /**
  784. * Formats a list of files or directories.
  785. * A File is an object with a "fileName" and optionally a "contents".
  786. * If the fileName ends with "/" and the contents is of length 0 then
  787. * it is considered a directory.
  788. *
  789. * @author tlwr [toby@toby.codes]
  790. *
  791. * @param {Object[]} files
  792. * @returns {html}
  793. */
  794. displayFilesAsHTML: function(files) {
  795. /* <NL> and <SP> used to denote newlines and spaces in HTML markup.
  796. * If a non-html operation is used, all markup will be removed but these
  797. * whitespace chars will remain for formatting purposes.
  798. */
  799. const formatDirectory = function(file) {
  800. const html = `<div class='panel panel-default' style='white-space: normal;'>
  801. <div class='panel-heading' role='tab'>
  802. <h4 class='panel-title'>
  803. <NL>${Utils.escapeHtml(file.fileName)}
  804. </h4>
  805. </div>
  806. </div>`;
  807. return html;
  808. };
  809. const formatFile = function(file, i) {
  810. const blob = new Blob(
  811. [new Uint8Array(file.bytes)],
  812. {type: "octet/stream"}
  813. );
  814. const blobUrl = URL.createObjectURL(blob);
  815. const viewFileElem = `<a href='#collapse${i}'
  816. class='collapsed'
  817. data-toggle='collapse'
  818. aria-expanded='true'
  819. aria-controls='collapse${i}'
  820. title="Show/hide contents of '${Utils.escapeHtml(file.fileName)}'">&#x1f441;&#xfe0f;</a>`;
  821. const downloadFileElem = `<a href='${blobUrl}'
  822. title='Download ${Utils.escapeHtml(file.fileName)}'
  823. download='${Utils.escapeHtml(file.fileName)}'>&#x1f4be;</a>`;
  824. const hexFileData = Utils.toHexFast(new Uint8Array(file.bytes));
  825. const switchToInputElem = `<a href='#switchFileToInput${i}'
  826. class='file-switch'
  827. title='Move file to input as hex'
  828. fileValue='${hexFileData}'>&#x21e7;</a>`;
  829. const html = `<div class='panel panel-default' style='white-space: normal;'>
  830. <div class='panel-heading' role='tab' id='heading${i}'>
  831. <h4 class='panel-title'>
  832. <div>
  833. ${Utils.escapeHtml(file.fileName)}<NL>
  834. ${viewFileElem}<SP>
  835. ${downloadFileElem}<SP>
  836. ${switchToInputElem}<SP>
  837. <span class='pull-right'>
  838. <NL>${file.size.toLocaleString()} bytes
  839. </span>
  840. </div>
  841. </h4>
  842. </div>
  843. <div id='collapse${i}' class='panel-collapse collapse'
  844. role='tabpanel' aria-labelledby='heading${i}'>
  845. <div class='panel-body'>
  846. <NL><NL><pre><code>${Utils.escapeHtml(file.contents)}</code></pre>
  847. </div>
  848. </div>
  849. </div>`;
  850. return html;
  851. };
  852. let html = `<div style='padding: 5px; white-space: normal;'>
  853. ${files.length} file(s) found<NL>
  854. </div>`;
  855. files.forEach(function(file, i) {
  856. if (typeof file.contents !== "undefined") {
  857. html += formatFile(file, i);
  858. } else {
  859. html += formatDirectory(file);
  860. }
  861. });
  862. return html.replace(/(?:(<pre>(?:\n|.)*<\/pre>)|\s{2,})/g, "$1") // Remove whitespace from markup
  863. .replace(/<NL>/g, "\n") // Replace <NP> with newlines
  864. .replace(/<SP>/g, " "); // Replace <SP> with spaces
  865. },
  866. /**
  867. * Parses URI parameters into a JSON object.
  868. *
  869. * @param {string} paramStr - The serialised query or hash section of a URI
  870. * @returns {object}
  871. *
  872. * @example
  873. * // returns {a: 'abc', b: '123'}
  874. * Utils.parseURIParams("?a=abc&b=123")
  875. * Utils.parseURIParams("#a=abc&b=123")
  876. */
  877. parseURIParams: function(paramStr) {
  878. if (paramStr === "") return {};
  879. // Cut off ? or # and split on &
  880. if (paramStr[0] === "?" ||
  881. paramStr[0] === "#") {
  882. paramStr = paramStr.substr(1);
  883. }
  884. const params = paramStr.split("&");
  885. const result = {};
  886. for (let i = 0; i < params.length; i++) {
  887. const param = params[i].split("=");
  888. if (param.length !== 2) {
  889. result[params[i]] = true;
  890. } else {
  891. result[param[0]] = decodeURIComponent(param[1].replace(/\+/g, " "));
  892. }
  893. }
  894. return result;
  895. },
  896. /**
  897. * Actual modulo function, since % is actually the remainder function in JS.
  898. *
  899. * @author Matt C [matt@artemisbot.uk]
  900. * @param {number} x
  901. * @param {number} y
  902. * @returns {number}
  903. */
  904. mod: function (x, y) {
  905. return ((x % y) + y) % y;
  906. },
  907. /**
  908. * Finds the greatest common divisor of two numbers.
  909. *
  910. * @author Matt C [matt@artemisbot.uk]
  911. * @param {number} x
  912. * @param {number} y
  913. * @returns {number}
  914. */
  915. gcd: function(x, y) {
  916. if (!y) {
  917. return x;
  918. }
  919. return Utils.gcd(y, x % y);
  920. },
  921. /**
  922. * Finds the modular inverse of two values.
  923. *
  924. * @author Matt C [matt@artemisbot.uk]
  925. * @param {number} x
  926. * @param {number} y
  927. * @returns {number}
  928. */
  929. modInv: function(x, y) {
  930. x %= y;
  931. for (let i = 1; i < y; i++) {
  932. if ((x * i) % 26 === 1) {
  933. return i;
  934. }
  935. }
  936. },
  937. /**
  938. * A mapping of names of delimiter characters to their symbols.
  939. * @constant
  940. */
  941. charRep: {
  942. "Space": " ",
  943. "Comma": ",",
  944. "Semi-colon": ";",
  945. "Colon": ":",
  946. "Line feed": "\n",
  947. "CRLF": "\r\n",
  948. "Forward slash": "/",
  949. "Backslash": "\\",
  950. "0x": "0x",
  951. "\\x": "\\x",
  952. "Nothing (separate chars)": "",
  953. "None": "",
  954. },
  955. /**
  956. * A mapping of names of delimiter characters to regular expressions which can select them.
  957. * @constant
  958. */
  959. regexRep: {
  960. "Space": /\s+/g,
  961. "Comma": /,/g,
  962. "Semi-colon": /;/g,
  963. "Colon": /:/g,
  964. "Line feed": /\n/g,
  965. "CRLF": /\r\n/g,
  966. "Forward slash": /\//g,
  967. "Backslash": /\\/g,
  968. "0x": /0x/g,
  969. "\\x": /\\x/g
  970. },
  971. /**
  972. * A mapping of string formats to their classes in the CryptoJS library.
  973. * @constant
  974. */
  975. format: {
  976. "Hex": CryptoJS.enc.Hex,
  977. "Base64": CryptoJS.enc.Base64,
  978. "UTF8": CryptoJS.enc.Utf8,
  979. "UTF16": CryptoJS.enc.Utf16,
  980. "UTF16LE": CryptoJS.enc.Utf16LE,
  981. "UTF16BE": CryptoJS.enc.Utf16BE,
  982. "Latin1": CryptoJS.enc.Latin1,
  983. },
  984. };
  985. export default Utils;
  986. /**
  987. * Removes all duplicates from an array.
  988. *
  989. * @returns {Array}
  990. *
  991. * @example
  992. * // returns [3,6,4,8,2]
  993. * [3,6,4,8,4,2,3].unique();
  994. *
  995. * // returns ["One", "Two", "Three"]
  996. * ["One", "Two", "Three", "One"].unique();
  997. */
  998. Array.prototype.unique = function() {
  999. let u = {}, a = [];
  1000. for (let i = 0, l = this.length; i < l; i++) {
  1001. if (u.hasOwnProperty(this[i])) {
  1002. continue;
  1003. }
  1004. a.push(this[i]);
  1005. u[this[i]] = 1;
  1006. }
  1007. return a;
  1008. };
  1009. /**
  1010. * Returns the largest value in the array.
  1011. *
  1012. * @returns {number}
  1013. *
  1014. * @example
  1015. * // returns 7
  1016. * [4,2,5,3,7].max();
  1017. */
  1018. Array.prototype.max = function() {
  1019. return Math.max.apply(null, this);
  1020. };
  1021. /**
  1022. * Returns the smallest value in the array.
  1023. *
  1024. * @returns {number}
  1025. *
  1026. * @example
  1027. * // returns 2
  1028. * [4,2,5,3,7].min();
  1029. */
  1030. Array.prototype.min = function() {
  1031. return Math.min.apply(null, this);
  1032. };
  1033. /**
  1034. * Sums all the values in an array.
  1035. *
  1036. * @returns {number}
  1037. *
  1038. * @example
  1039. * // returns 21
  1040. * [4,2,5,3,7].sum();
  1041. */
  1042. Array.prototype.sum = function() {
  1043. return this.reduce(function (a, b) {
  1044. return a + b;
  1045. }, 0);
  1046. };
  1047. /**
  1048. * Determine whether two arrays are equal or not.
  1049. *
  1050. * @param {Object[]} other
  1051. * @returns {boolean}
  1052. *
  1053. * @example
  1054. * // returns true
  1055. * [1,2,3].equals([1,2,3]);
  1056. *
  1057. * // returns false
  1058. * [1,2,3].equals([3,2,1]);
  1059. */
  1060. Array.prototype.equals = function(other) {
  1061. if (!other) return false;
  1062. let i = this.length;
  1063. if (i !== other.length) return false;
  1064. while (i--) {
  1065. if (this[i] !== other[i]) return false;
  1066. }
  1067. return true;
  1068. };
  1069. /**
  1070. * Counts the number of times a char appears in a string.
  1071. *
  1072. * @param {char} chr
  1073. * @returns {number}
  1074. *
  1075. * @example
  1076. * // returns 2
  1077. * "Hello".count("l");
  1078. */
  1079. String.prototype.count = function(chr) {
  1080. return this.split(chr).length - 1;
  1081. };
  1082. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1083. // Library overrides ///////////////////////////////////////////////////////////////////////////////
  1084. ////////////////////////////////////////////////////////////////////////////////////////////////////
  1085. /**
  1086. * Override for the CryptoJS Hex encoding parser to remove whitespace before attempting to parse
  1087. * the hex string.
  1088. *
  1089. * @param {string} hexStr
  1090. * @returns {CryptoJS.lib.WordArray}
  1091. */
  1092. CryptoJS.enc.Hex.parse = function (hexStr) {
  1093. // Remove whitespace
  1094. hexStr = hexStr.replace(/\s/g, "");
  1095. // Shortcut
  1096. const hexStrLength = hexStr.length;
  1097. // Convert
  1098. const words = [];
  1099. for (let i = 0; i < hexStrLength; i += 2) {
  1100. words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
  1101. }
  1102. return new CryptoJS.lib.WordArray.init(words, hexStrLength / 2);
  1103. };