Lumi/src/services/overlay-secrets.js
2026-07-17 22:10:00 +02:00

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
};