63 lines
1.8 KiB
JavaScript
63 lines
1.8 KiB
JavaScript
const crypto = require("crypto");
|
|
const { getSetting } = require("./settings");
|
|
|
|
function encryptionKey() {
|
|
const secret = getSetting("session_secret");
|
|
if (!secret) {
|
|
throw new Error("Lumi's session secret is not initialized.");
|
|
}
|
|
return crypto.createHash("sha256").update(`lumi-overlay:${secret}`).digest();
|
|
}
|
|
|
|
function generateToken() {
|
|
return crypto.randomBytes(32).toString("base64url");
|
|
}
|
|
|
|
function tokenHash(token) {
|
|
return crypto.createHash("sha256").update(String(token || "")).digest("hex");
|
|
}
|
|
|
|
function encryptSecret(value) {
|
|
if (value === null || value === undefined || value === "") return null;
|
|
const iv = crypto.randomBytes(12);
|
|
const cipher = crypto.createCipheriv("aes-256-gcm", encryptionKey(), iv);
|
|
const encrypted = Buffer.concat([cipher.update(String(value), "utf8"), cipher.final()]);
|
|
const tag = cipher.getAuthTag();
|
|
return `v1.${iv.toString("base64url")}.${tag.toString("base64url")}.${encrypted.toString("base64url")}`;
|
|
}
|
|
|
|
function decryptSecret(value) {
|
|
if (!value) return "";
|
|
const [version, ivValue, tagValue, encryptedValue] = String(value).split(".");
|
|
if (version !== "v1" || !ivValue || !tagValue || !encryptedValue) {
|
|
throw new Error("Stored secret has an unsupported format.");
|
|
}
|
|
const decipher = crypto.createDecipheriv(
|
|
"aes-256-gcm",
|
|
encryptionKey(),
|
|
Buffer.from(ivValue, "base64url")
|
|
);
|
|
decipher.setAuthTag(Buffer.from(tagValue, "base64url"));
|
|
return Buffer.concat([
|
|
decipher.update(Buffer.from(encryptedValue, "base64url")),
|
|
decipher.final()
|
|
]).toString("utf8");
|
|
}
|
|
|
|
function createStoredToken() {
|
|
const token = generateToken();
|
|
return {
|
|
token,
|
|
hash: tokenHash(token),
|
|
encrypted: encryptSecret(token)
|
|
};
|
|
}
|
|
|
|
module.exports = {
|
|
createStoredToken,
|
|
decryptSecret,
|
|
encryptSecret,
|
|
generateToken,
|
|
tokenHash
|
|
};
|