Einstellungen strikt pro Benutzer: kein process.env-Fallback mehr
config.get() ist bei einem nicht gesetzten Schluessel auf process.env zurueckgefallen. Da die Env-Variablen die Konfiguration des Admins enthalten (Docker-Env: MAIL_*, CALDAV_URL, OLLAMA_API_KEY, API_TOKEN), hat damit JEDER neu angelegte Benutzer ohne eigene Einstellungen stillschweigend die Zugangsdaten des Admins geerbt: - /einstellungen zeigte ihm die Zugangsdaten des Admins an. - mailer/caldav isConfigured() war true -> der IMAP-Poller hat fuer den neuen Benutzer das Postfach des Admins abgerufen und dessen E-Mails in sein Konto einsortiert; CalDAV synchronisierte den Kalender des Admins. - Der bezahlte Ollama-Key des Admins wurde mitbenutzt. Jetzt: - config.get() loest ausschliesslich die Zeilen des aktuellen Benutzers auf, sonst den eingebauten Standard (nicht-geheime Werte wie Modell, Host, Ports, Intervalle). Alle Credentials sind bei neuen Benutzern leer, d. h. Ollama/E-Mail/CalDAV/API sind fuer sie aus, bis sie sich selbst etwas eintragen. - Noch per Env gesetzte Konfiguration wird einmalig in die Zeilen des ADMIN uebernommen (importEnvIntoAdmin, Aufruf beim Boot nachdem app_state existiert - in runMigration war das bei Neuinstallationen ein No-op, weil die Tabelle dort noch nicht angelegt ist). - config.ensureLoaded(user.id) beim Aufloesen der Session bzw. des X-API-Key. config.get() ist synchron und liest den Per-User-Cache; ohne Warmladen las ein Web-Request die Werte als "nicht konfiguriert". Das hat bisher der env-Fallback verdeckt (er hielt zufaellig die Werte des Admins) - ohne ihn muss die Config pro Request wirklich geladen werden. Verifiziert gegen eine Kopie der Produktions-DB mit Sentinel-Env-Werten: Admin behaelt seine kompletten Einstellungen, der zweite Benutzer sieht ueberall leere Credentials, Mail/CalDAV sind fuer ihn inaktiv, und der Env-API-Token wird nicht mehr als gueltiger X-API-Key akzeptiert. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -242,12 +242,28 @@ async function runMigration({ db, dbAll, dbGet, dbRun }) {
|
||||
// 5. Move on-disk files into a per-user subdirectory for the admin -----
|
||||
moveFilesIntoUserSubdir(adminId);
|
||||
|
||||
// 6. One-time .env -> admin cfg migration ------------------------------
|
||||
// 6. One-time env -> admin cfg import ----------------------------------
|
||||
// On an upgraded install app_state already exists here, so this fills the
|
||||
// admin's rows right away. On a *fresh* install the table is only created
|
||||
// after this migration returns, so this is a no-op — server.js therefore
|
||||
// calls importEnvIntoAdmin() again once the schema is complete. Idempotent
|
||||
// either way (it only fills keys the admin has not stored).
|
||||
await migrateEnvForAdmin(dbAll, adminId);
|
||||
|
||||
return { adminId };
|
||||
}
|
||||
|
||||
// Import any still-present env config into the admin's rows. Called at boot from
|
||||
// server.js, after initializeDatabase() has created app_state — this is what
|
||||
// makes a deployment that passes its config as container env vars (as ours does)
|
||||
// end up with those values owned by the admin, instead of leaking to every user
|
||||
// through a read-time process.env fallback (which config.get() no longer has).
|
||||
async function importEnvIntoAdmin({ dbAll, dbGet }) {
|
||||
const admin = await dbGet('SELECT id FROM users WHERE username = ?', [ADMIN_USERNAME]);
|
||||
if (!admin) return;
|
||||
await migrateEnvForAdmin(dbAll, admin.id);
|
||||
}
|
||||
|
||||
// Rename `table` to `table_old`, create the new table from `newSchemaSql`,
|
||||
// copy rows via `copySql` (with `copyParams`), then drop `table_old`.
|
||||
async function recreate(db, dbAll, dbRun, table, newSchemaSql, copySql, copyParams) {
|
||||
@@ -308,4 +324,4 @@ async function migrateEnvForAdmin(dbAll, adminId) {
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { runMigration, moveFilesIntoUserSubdir, STORAGE_DIRS, ADMIN_USERNAME, ADMIN_DEFAULT_PASSWORD };
|
||||
module.exports = { runMigration, importEnvIntoAdmin, moveFilesIntoUserSubdir, STORAGE_DIRS, ADMIN_USERNAME, ADMIN_DEFAULT_PASSWORD };
|
||||
Reference in New Issue
Block a user