/* * Copyright (C) Sapphirecode - All Rights Reserved * Created by Timo Hocker , March 2020 */ /* eslint-disable no-magic-numbers */ 'use strict'; const crypto = require ('crypto'); const encoding = require ('@scode/encoding-helper'); /** * creates a random string * * @param {number} len string length default: 6 * @returns {string} random string */ function random_string (len = 8) { if (len < 1) throw new Error ('invalid length'); return crypto.randomBytes (Math.ceil (len * 3 / 4)) .toString ('base64') .replace (/[=]+$/u, '') .substr (0, len); } /** * creates a random hexadecimal string * * @param {number} len length * @returns {string} hex string */ function random_hex (len = 8) { if (len < 1) throw new Error ('invalid length'); return crypto.randomBytes (Math.ceil (len / 2)) .toString ('hex') .substr (0, len); } /** * creates a 64 character long random hex string * * @returns {string} salt */ function create_salt () { return random_hex (64); } /** * creates a sha512 hash * * @param {string} str string input * @param {string} salt salt * @returns {string} salt */ function hash_sha512 (str, salt) { const md = crypto.createHash ('sha512'); md.update (str); md.update (salt); return md.digest ('hex'); } /** * sign an object * * @param {any} obj object to sign * @param {string} key key to use * @param {string} key_info key identifier * @returns {string} signed object */ function sign_object (obj, key, key_info = null) { const payload = { iat: Date.now (), key_info, obj }; const str = encoding.to_b64 (JSON.stringify (payload)); const token = encoding.to_b64 (hash_sha512 (str, key), 'hex'); const res = `${str}.${token}`; return encodeURIComponent (res); } /** * verify a signed object and return its contents * * @param {string} str string to verify * @param {string} key used key * @param {number} timeout timeout (optional) * @returns {any} returns object if successful, else null */ function verify_signature (str, key, timeout = 0) { const dec = decodeURIComponent (str) .split ('.'); const json = JSON.parse (encoding.to_utf8 (dec[0], 'base64')); const token = encoding.to_hex (dec[1], 'base64'); const verify_token = hash_sha512 (dec[0], key); if (token !== verify_token) return null; const time = Date.now () - json.iat; if (timeout !== 0 && time > timeout) return null; return json.obj; } /** * get a signed object info and data * * @param {string} str string to decode * @returns {any} data */ function get_signature_info (str) { const dec = decodeURIComponent (str) .split ('.'); const json = JSON.parse (encoding.to_utf8 (dec[0], 'base64')); return json; } /** * decode a signed object without verifying the signature * * @param {string} str string to decode * @returns {any} object */ function decode_signed (str) { return get_signature_info (str).obj; } /** * creates a sha256 hash * * @param {any} data input * @returns {string} hash */ function checksum (data) { const md = crypto.createHash ('sha256'); md.update (String (data)); return md.digest ('hex'); } module.exports = { checksum, create_salt, decode_signed, get_signature_info, hash_sha512, random_hex, random_string, sign_object, verify_signature };