UNPKG

jsm-utilities

Version:
149 lines (148 loc) 6.36 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.run = exports.verifyApiKeySignature = exports.generateApiKeySignature = void 0; exports.generateToken = generateToken; exports.verifyToken = verifyToken; exports.hashToken = hashToken; exports.verifyHashedString = verifyHashedString; const crypto_1 = require("crypto"); const argon2_1 = __importDefault(require("argon2")); const jsonwebtoken_1 = __importDefault(require("jsonwebtoken")); const colors_1 = __importDefault(require("colors")); const hash_wasm_1 = require("hash-wasm"); const moment_1 = __importDefault(require("moment")); /** * @description Generate signature for request, valide for 1 hour * @param api_key string * @param secret_key string * @returns string */ const generateApiKeySignature = (api_key, secret_key) => __awaiter(void 0, void 0, void 0, function* () { // for security reason, we use timestamp as password // and hash it with bcrypt // check if signature is already saved in localstorage if (typeof window !== "undefined") { const oldSignature = JSON.parse(window.localStorage.getItem("sign") || "null"); if (oldSignature) { const timestamp = oldSignature === null || oldSignature === void 0 ? void 0 : oldSignature.substring(18, 28); const now = (0, moment_1.default)().unix(); const diff = now - parseInt(timestamp); if (diff < 3000) { console.log("oldSignature", { oldSignature, diff }); return oldSignature; } } } const timestamp = (0, moment_1.default)().unix().toString(); const salt = (yield (0, hash_wasm_1.md5)(`${secret_key}${timestamp}`)).substring(0, 16); const hash = yield (0, hash_wasm_1.bcrypt)({ password: timestamp, salt, costFactor: 8, outputType: "encoded", }); const signature = `$${salt}$${timestamp}${hash}$${api_key}`; // save signature to localstorage if (typeof window !== "undefined") window.localStorage.setItem("sign", JSON.stringify(signature)); return signature; }); exports.generateApiKeySignature = generateApiKeySignature; /** * @description Verify signature from request * @param signature string * @returns boolean */ const verifyApiKeySignature = (signature) => __awaiter(void 0, void 0, void 0, function* () { let valid = false; try { const api_key = signature === null || signature === void 0 ? void 0 : signature.substring(89); if (!api_key) throw new Error("INVALID_SIGNATURE: "); // TODO: get secret_key from database const secret_key = process.env.NEXT_PUBLIC_API_SECRET_KEY || ""; const salt = signature === null || signature === void 0 ? void 0 : signature.substring(1, 17); const timestamp = signature === null || signature === void 0 ? void 0 : signature.substring(18, 28); const timestampSalt = (yield (0, hash_wasm_1.md5)(`${secret_key}${timestamp}`)).substring(0, 16); const hash = signature === null || signature === void 0 ? void 0 : signature.substring(28, 88); if (timestampSalt !== salt) throw new Error("INVALID_SIGNATURE: " + timestampSalt + " - " + salt); // check if signature is valid by timestamp const now = (0, moment_1.default)().unix(); const diff = now - parseInt(timestamp); if (diff > 3600) throw new Error("INVALID_SIGNATURE.expired: " + diff); console.log("bcryptHash", { signature, salt, hash, api_key, secret_key, now, timestamp: parseInt(timestamp), diff, }); // check if signature is valid by hash valid = yield (0, hash_wasm_1.bcryptVerify)({ password: timestamp, hash: hash, }); } catch (error) { console.log(colors_1.default.red("ERROR_ON_VALIDATE_SIGNATURE"), error.message); } return valid; }); exports.verifyApiKeySignature = verifyApiKeySignature; const run = () => __awaiter(void 0, void 0, void 0, function* () { console.clear(); console.group("Hash"); try { const signature = yield (0, exports.generateApiKeySignature)(process.env.NEXT_PUBLIC_API_KEY || "", process.env.NEXT_PUBLIC_API_SECRET_KEY || ""); console.log("signature", signature); const valid = yield (0, exports.verifyApiKeySignature)(signature); console.log("valid", valid); } catch (error) { console.log(colors_1.default.red("error"), error); } console.groupEnd(); }); exports.run = run; function generateToken(payload, config) { payload = Object.assign({}, payload); return jsonwebtoken_1.default.sign(Object.assign({}, payload), config.security.jwt.secret, { algorithm: config.security.jwt.algorithm, }); } function verifyToken(token, config) { return jsonwebtoken_1.default.verify(token, config.security.jwt.secret); } function hashToken(token) { return __awaiter(this, void 0, void 0, function* () { const salt = (0, crypto_1.randomBytes)(32); const hash = yield argon2_1.default.hash(token, { salt }); return { salt: salt.toString("hex"), hash, }; }); } function verifyHashedString(str, hash) { return __awaiter(this, void 0, void 0, function* () { const isValidPassword = yield argon2_1.default.verify(hash, str); return isValidPassword; }); }