-
Notifications
You must be signed in to change notification settings - Fork 0
/
Node-RED-TOTP
1 lines (1 loc) · 10.3 KB
/
Node-RED-TOTP
1
[{"id":"f36b3d5c.974d08","type":"subflow","name":"TOTP","info":"INPUT\nmsg.payload is totp string (6 decimal digits)\n\nOUTPUT\nmsg.payload is true or false","in":[{"x":60,"y":60,"wires":[{"id":"b58c3011.ebc0a"}]}],"out":[{"x":400,"y":60,"wires":[{"id":"b58c3011.ebc0a","port":0}]}]},{"id":"b58c3011.ebc0a","type":"function","z":"f36b3d5c.974d08","name":"TOTP (HMAC + TRUNC)","func":"// website to generate a random key in hex (copy exactly 40 characters from the first box):\n// https://www.grc.com/passwords.htm\n// paste this is the code below in line 245. No, I don't use that key! :-)\n//\n// website to convert said key to BASE32\n// http://tomeko.net/online_tools/hex_to_base32.php\n//\n// website to make a QR barcode for Google Authenticator (add base32 code at the end)\n// http://qrickit.com/api/qr?qrsize=200&d=otpauth://totp/nodered?secret=\n//\n\n/*\n A JavaScript implementation of the SHA family of hashes, as\n defined in FIPS PUB 180-2 as well as the corresponding HMAC implementation\n as defined in FIPS PUB 198a\n Copyright Brian Turek 2008-2013\n Distributed under the BSD License\n See http://caligatio.github.com/jsSHA/ for more information\n Several functions taken from Paul Johnston\n*/\n(function(A) {\n function q(a, d, b) {\n var f = 0,\n e = [0],\n c = \"\",\n g = null,\n c = b || \"UTF8\";\n if (\"UTF8\" !== c && \"UTF16\" !== c) throw \"encoding must be UTF8 or UTF16\";\n if (\"HEX\" === d) {\n if (0 !== a.length % 2) throw \"srcString of HEX type must be in byte increments\";\n g = t(a);\n f = g.binLen;\n e = g.value\n } else if (\"ASCII\" === d || \"TEXT\" === d) g = v(a, c), f = g.binLen, e = g.value;\n else if (\"B64\" === d) g = w(a), f = g.binLen, e = g.value;\n else throw \"inputFormat must be HEX, TEXT, ASCII, or B64\";\n this.getHash = function(a, b, c, d) {\n var g = null,\n h = e.slice(),\n k = f,\n m;\n 3 === arguments.length ? \"number\" !==\n typeof c && (d = c, c = 1) : 2 === arguments.length && (c = 1);\n if (c !== parseInt(c, 10) || 1 > c) throw \"numRounds must a integer >= 1\";\n switch (b) {\n case \"HEX\":\n g = x;\n break;\n case \"B64\":\n g = y;\n break;\n default:\n throw \"format must be HEX or B64\";\n }\n if (\"SHA-1\" === a)\n for (m = 0; m < c; m++) h = s(h, k), k = 160;\n else throw \"Chosen SHA variant is not supported\";\n return g(h, z(d))\n };\n this.getHMAC = function(a, b, d, g, q) {\n var h, k, m, l, r = [],\n u = [];\n h = null;\n switch (g) {\n case \"HEX\":\n g = x;\n break;\n case \"B64\":\n g = y;\n break;\n default:\n throw \"outputFormat must be HEX or B64\";\n }\n if (\"SHA-1\" === d) k = 64, l =\n 160;\n else throw \"Chosen SHA variant is not supported\";\n if (\"HEX\" === b) h = t(a), m = h.binLen, h = h.value;\n else if (\"ASCII\" === b || \"TEXT\" === b) h = v(a, c), m = h.binLen, h = h.value;\n else if (\"B64\" === b) h = w(a), m = h.binLen, h = h.value;\n else throw \"inputFormat must be HEX, TEXT, ASCII, or B64\";\n a = 8 * k;\n b = k / 4 - 1;\n if (k < m / 8) {\n if (\"SHA-1\" === d) h = s(h, m);\n else throw \"Unexpected error in HMAC implementation\";\n h[b] &= 4294967040\n } else k > m / 8 && (h[b] &= 4294967040);\n for (k = 0; k <= b; k += 1) r[k] = h[k] ^ 909522486, u[k] = h[k] ^ 1549556828;\n if (\"SHA-1\" === d) d = s(u.concat(s(r.concat(e),\n a + f)), a + l);\n else throw \"Unexpected error in HMAC implementation\";\n return g(d, z(q))\n }\n }\n\n function v(a, d) {\n var b = [],\n f, e = [],\n c = 0,\n g;\n if (\"UTF8\" === d)\n for (g = 0; g < a.length; g += 1)\n for (f = a.charCodeAt(g), e = [], 2048 < f ? (e[0] = 224 | (f & 61440) >>> 12, e[1] = 128 | (f & 4032) >>> 6, e[2] = 128 | f & 63) : 128 < f ? (e[0] = 192 | (f & 1984) >>> 6, e[1] = 128 | f & 63) : e[0] = f, f = 0; f < e.length; f += 1) b[c >>> 2] |= e[f] << 24 - c % 4 * 8, c += 1;\n else if (\"UTF16\" === d)\n for (g = 0; g < a.length; g += 1) b[c >>> 2] |= a.charCodeAt(g) << 16 - c % 4 * 8, c += 2;\n return {\n value: b,\n binLen: 8 * c\n }\n }\n\n function t(a) {\n var d = [],\n b = a.length,\n f,\n e;\n if (0 !== b % 2) throw \"String of HEX type must be in byte increments\";\n for (f = 0; f < b; f += 2) {\n e = parseInt(a.substr(f, 2), 16);\n if (isNaN(e)) throw \"String of HEX type contains invalid characters\";\n d[f >>> 3] |= e << 24 - f % 8 * 4\n }\n return {\n value: d,\n binLen: 4 * b\n }\n }\n\n function w(a) {\n var d = [],\n b = 0,\n f, e, c, g, p;\n if (-1 === a.search(/^[a-zA-Z0-9=+\\/]+$/)) throw \"Invalid character in base-64 string\";\n f = a.indexOf(\"=\");\n a = a.replace(/\\=/g, \"\");\n if (-1 !== f && f < a.length) throw \"Invalid '=' found in base-64 string\";\n for (e = 0; e < a.length; e += 4) {\n p = a.substr(e, 4);\n for (c = g = 0; c <\n p.length; c += 1) f = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\".indexOf(p[c]), g |= f << 18 - 6 * c;\n for (c = 0; c < p.length - 1; c += 1) d[b >> 2] |= (g >>> 16 - 8 * c & 255) << 24 - b % 4 * 8, b += 1\n }\n return {\n value: d,\n binLen: 8 * b\n }\n }\n\n function x(a, d) {\n var b = \"\",\n f = 4 * a.length,\n e, c;\n for (e = 0; e < f; e += 1) c = a[e >>> 2] >>> 8 * (3 - e % 4), b += \"0123456789abcdef\".charAt(c >>> 4 & 15) + \"0123456789abcdef\".charAt(c & 15);\n return d.outputUpper ? b.toUpperCase() : b\n }\n\n function y(a, d) {\n var b = \"\",\n f = 4 * a.length,\n e, c, g;\n for (e = 0; e < f; e += 3)\n for (g = (a[e >>> 2] >>> 8 * (3 - e % 4) & 255) << 16 | (a[e + 1 >>>\n 2] >>> 8 * (3 - (e + 1) % 4) & 255) << 8 | a[e + 2 >>> 2] >>> 8 * (3 - (e + 2) % 4) & 255, c = 0; 4 > c; c += 1) b = 8 * e + 6 * c <= 32 * a.length ? b + \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\".charAt(g >>> 6 * (3 - c) & 63) : b + d.b64Pad;\n return b\n }\n\n function z(a) {\n var d = {\n outputUpper: !1,\n b64Pad: \"=\"\n };\n try {\n a.hasOwnProperty(\"outputUpper\") && (d.outputUpper = a.outputUpper), a.hasOwnProperty(\"b64Pad\") && (d.b64Pad = a.b64Pad)\n } catch (b) {}\n if (\"boolean\" !== typeof d.outputUpper) throw \"Invalid outputUpper formatting option\";\n if (\"string\" !== typeof d.b64Pad) throw \"Invalid b64Pad formatting option\";\n return d\n }\n\n function B(a, d) {\n return a << d | a >>> 32 - d\n }\n\n function C(a, d, b) {\n return a ^ d ^ b\n }\n\n function D(a, d, b) {\n return a & d ^ ~a & b\n }\n\n function E(a, d, b) {\n return a & d ^ a & b ^ d & b\n }\n\n function F(a, d) {\n var b = (a & 65535) + (d & 65535);\n return ((a >>> 16) + (d >>> 16) + (b >>> 16) & 65535) << 16 | b & 65535\n }\n\n function G(a, d, b, f, e) {\n var c = (a & 65535) + (d & 65535) + (b & 65535) + (f & 65535) + (e & 65535);\n return ((a >>> 16) + (d >>> 16) + (b >>> 16) + (f >>> 16) + (e >>> 16) + (c >>> 16) & 65535) << 16 | c & 65535\n }\n\n function s(a, d) {\n var b = [],\n f, e, c, g, p, q, s = D,\n t = C,\n v = E,\n h = B,\n k = F,\n m, l, r = G,\n u, n = [1732584193, 4023233417, 2562383102,\n 271733878, 3285377520\n ];\n a[d >>> 5] |= 128 << 24 - d % 32;\n a[(d + 65 >>> 9 << 4) + 15] = d;\n u = a.length;\n for (m = 0; m < u; m += 16) {\n f = n[0];\n e = n[1];\n c = n[2];\n g = n[3];\n p = n[4];\n for (l = 0; 80 > l; l += 1) b[l] = 16 > l ? a[l + m] : h(b[l - 3] ^ b[l - 8] ^ b[l - 14] ^ b[l - 16], 1), q = 20 > l ? r(h(f, 5), s(e, c, g), p, 1518500249, b[l]) : 40 > l ? r(h(f, 5), t(e, c, g), p, 1859775393, b[l]) : 60 > l ? r(h(f, 5), v(e, c, g), p, 2400959708, b[l]) : r(h(f, 5), t(e, c, g), p, 3395469782, b[l]), p = g, g = c, c = h(e, 30), e = f, f = q;\n n[0] = k(f, n[0]);\n n[1] = k(e, n[1]);\n n[2] = k(c, n[2]);\n n[3] = k(g, n[3]);\n n[4] = k(p, n[4])\n }\n return n\n }\n \"function\" === typeof define &&\n typeof define.amd ? define(function() {\n return q\n }) : \"undefined\" !== typeof exports ? \"undefined\" !== typeof module && module.exports ? module.exports = exports = q : exports = q : A.jsSHA = q\n})(this);\n\nfunction getTotp (response, delta) {\n var plainNum = Math.floor (Date.now()/30000) + delta;\n var plain = (\"0000000000000000\" + (Number(plainNum)).toString(16)).slice(-16);\n var shaObj = new jsSHA(plain, \"HEX\");\n var hmac = shaObj.getHMAC(\"1BA5437FA0023AE00ED891261C9BD1F522613CAE\", \"HEX\", \"SHA-1\", \"HEX\");\n var truncInt = parseInt(hmac.substr(parseInt(hmac.substr(39,1), 16)*2,8),16);\n if (truncInt > 0x7fffffff) truncInt -= 0x80000000;\n return (response == (truncInt % 1000000));\n}\n\nvar response = parseInt(msg.payload);\nvar result = getTotp (response, 0);\nif (!result) {\n result = getTotp (response, -1);\n}\nif (!result) {\n return null;\n}\n\nmsg.payload = true;\nreturn msg;","outputs":1,"noerr":0,"x":230,"y":60,"wires":[[]]}]