fix: persist JWT_SECRET to SQLite so restarts don't invalidate sessions (#382)

This commit is contained in:
diegosouzapw
2026-03-15 12:56:52 -03:00
parent 282ec65e8b
commit ced98f2da7
+74 -8
View File
@@ -11,17 +11,80 @@
function ensureSecrets(): void {
// eslint-disable-next-line no-eval
const crypto = eval("require")("crypto");
// eslint-disable-next-line no-eval
const Database = eval("require")("better-sqlite3");
// eslint-disable-next-line no-eval
const path = eval("require")("path");
const os = eval("require")("os"); // eslint-disable-line no-eval
function getSecretsDb() {
const dataDir = process.env.DATA_DIR || path.join(os.homedir(), ".omniroute");
const dbPath = path.join(dataDir, "storage.sqlite");
try {
const db = new Database(dbPath);
db.exec(
"CREATE TABLE IF NOT EXISTS key_value (namespace TEXT, key TEXT, value TEXT, PRIMARY KEY (namespace, key))"
);
return db;
} catch {
return null;
}
}
function loadPersistedSecret(key: string): string | null {
try {
const db = getSecretsDb();
if (!db) return null;
const row = db
.prepare("SELECT value FROM key_value WHERE namespace = 'secrets' AND key = ?")
.get(key) as { value: string } | undefined;
db.close();
return row ? JSON.parse(row.value) : null;
} catch {
return null;
}
}
function persistSecret(key: string, value: string): void {
try {
const db = getSecretsDb();
if (!db) return;
db.prepare(
"INSERT OR IGNORE INTO key_value (namespace, key, value) VALUES ('secrets', ?, ?)"
).run(key, JSON.stringify(value));
db.close();
} catch {
// Non-fatal — secrets can still work in-memory if persist fails
}
}
if (!process.env.JWT_SECRET || process.env.JWT_SECRET.trim() === "") {
const generated = crypto.randomBytes(48).toString("base64");
process.env.JWT_SECRET = generated;
console.log("[STARTUP] JWT_SECRET auto-generated (random 64-char secret)");
// Try to load previously generated secret from DB (survives restarts)
const persisted = loadPersistedSecret("jwtSecret");
if (persisted) {
process.env.JWT_SECRET = persisted;
console.log("[STARTUP] JWT_SECRET restored from persistent store");
} else {
// First run — generate and persist
const generated = crypto.randomBytes(48).toString("base64");
process.env.JWT_SECRET = generated;
persistSecret("jwtSecret", generated);
console.log("[STARTUP] JWT_SECRET auto-generated and persisted (random 64-char secret)");
}
}
if (!process.env.API_KEY_SECRET || process.env.API_KEY_SECRET.trim() === "") {
const generated = crypto.randomBytes(32).toString("hex");
process.env.API_KEY_SECRET = generated;
console.log("[STARTUP] API_KEY_SECRET auto-generated (random 64-char hex secret)");
const persisted = loadPersistedSecret("apiKeySecret");
if (persisted) {
process.env.API_KEY_SECRET = persisted;
} else {
const generated = crypto.randomBytes(32).toString("hex");
process.env.API_KEY_SECRET = generated;
persistSecret("apiKeySecret", generated);
console.log(
"[STARTUP] API_KEY_SECRET auto-generated and persisted (random 64-char hex secret)"
);
}
}
}
@@ -52,7 +115,8 @@ export async function register() {
try {
const { getSettings } = await import("@/lib/db/settings");
const { setCustomAliases } = await import("@omniroute/open-sse/services/modelDeprecation.ts");
const { setDefaultFastServiceTierEnabled } = await import("@omniroute/open-sse/executors/codex.ts");
const { setDefaultFastServiceTierEnabled } =
await import("@omniroute/open-sse/executors/codex.ts");
const settings = await getSettings();
if (settings.modelAliases) {
@@ -75,7 +139,9 @@ export async function register() {
if (typeof persisted?.enabled === "boolean") {
setDefaultFastServiceTierEnabled(persisted.enabled);
console.log(`[STARTUP] Restored Codex fast service tier: ${persisted.enabled ? "on" : "off"}`);
console.log(
`[STARTUP] Restored Codex fast service tier: ${persisted.enabled ? "on" : "off"}`
);
}
} catch (err: unknown) {
const msg = err instanceof Error ? err.message : String(err);