jsm-utilities
Version:
A utilities library.
149 lines (148 loc) • 6.36 kB
JavaScript
;
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;
});
}