@bee.js/node
Version:
A JavaScript framework for making Node.js API´s
108 lines (82 loc) • 3.19 kB
JavaScript
const CryptoJS = require("crypto-js");
const log = require("../beeHive/log");
const bee = { tools: require("../../tools/beeTools") };
function base64url(source) {
let encodedSource = CryptoJS.enc.Base64.stringify(source);
encodedSource = encodedSource.replace(/=+$/, "");
encodedSource = encodedSource.replace(/\+/g, "-");
encodedSource = encodedSource.replace(/\//g, "_");
return encodedSource;
}
function base64urlDecode(input = "") {
if (!input) return "";
let normalized = input.replace(/-/g, "+").replace(/_/g, "/");
const pad = normalized.length % 4;
if (pad) normalized += "=".repeat(4 - pad);
return Buffer.from(normalized, "base64").toString("utf8");
}
module.exports = function token(_payload = null, header = {}, options = {}) {
if (_payload) {
let { jwt, ...payload } = _payload;
if (!global.configs.jwt && !global.configs.jwt.secret)
return log("ERROR: no jwt.secret defined in configs.");
let secret = global.configs.jwt.secret;
let iat = new Date().getTime();
// options.expires is in minutes (default: 1 minute)
const expiresInMinutes =
typeof options.expires === "number" ? options.expires : 1;
let exp = new Date().getTime() + expiresInMinutes * 60 * 1000;
header = {
...header,
typ: header.typ || "JWT",
alg: header.alg || "HS256",
};
payload = { ...payload, iat: iat, exp: exp };
header = base64url(CryptoJS.enc.Utf8.parse(JSON.stringify(header)));
payload = base64url(CryptoJS.enc.Utf8.parse(JSON.stringify(payload)));
const signature = base64url(
CryptoJS.HmacSHA256(`${header}.${payload}`, secret)
);
const token = `${header}.${payload}.${signature}`;
this.data.jwt =
this.data.jwt && typeof this.data.jwt !== "object"
? [this.data.jwt]
: this.data.jwt;
this.data.jwt = !this.data.jwt ? token : this.data.jwt.concat(token);
this.counters.jwt = (this.counters.jwt || 0) + 1;
log("JWT created: " + this.data.jwt);
return this;
}
return {
...this,
verify: function (token, headers = {}) {
const secret = global.configs.jwt.secret;
const apiKey =
headers["x-api-key"] || headers["api-key"] || headers["apikey"];
// Acesso de maquinas via API key (md5 do segredo JWT).
if (apiKey && apiKey === bee.tools.md5(secret)) {
return JSON.stringify({ machine: true });
}
if (!token || typeof token !== "string") return false;
const array = token.split(".");
if (array.length !== 3) return false;
const header = array[0];
const payload = array[1];
const signature = base64url(
CryptoJS.HmacSHA256(`${header}.${payload}`, secret)
);
if (token !== `${header}.${payload}.${signature}`) return false;
let payloadDecoded = base64urlDecode(payload);
let payloadJson;
try {
payloadJson = JSON.parse(payloadDecoded);
} catch (error) {
return false;
}
if (payloadJson?.exp && new Date().getTime() > payloadJson.exp) {
return { error: { message: "TOKEN_EXPIRED", status: 419 } };
}
return payloadDecoded;
},
};
};