diff --git a/server/endpoints/system.js b/server/endpoints/system.js index 1717e6357..89896aaa5 100644 --- a/server/endpoints/system.js +++ b/server/endpoints/system.js @@ -239,6 +239,16 @@ function systemEndpoints(app) { async (request, response) => { try { const body = reqBody(request); + + // Only admins can update the ENV settings. + if (multiUserMode(response)) { + const user = await userFromSession(request, response); + if (!user || user?.role !== "admin") { + response.sendStatus(401).end(); + return; + } + } + const { newValues, error } = updateENV(body); if (process.env.NODE_ENV === "production") await dumpENV(); response.status(200).json({ newValues, error }); @@ -254,11 +264,21 @@ function systemEndpoints(app) { [validatedRequest], async (request, response) => { try { + // Cannot update password in multi - user mode. + if (multiUserMode(response)) { + response.sendStatus(401).end(); + return; + } + const { usePassword, newPassword } = reqBody(request); - const { error } = updateENV({ - AuthToken: usePassword ? newPassword : "", - JWTSecret: usePassword ? v4() : "", - }); + const { error } = updateENV( + { + AuthToken: usePassword ? newPassword : "", + JWTSecret: usePassword ? v4() : "", + }, + true + ); + if (process.env.NODE_ENV === "production") await dumpENV(); response.status(200).json({ success: !error, error }); } catch (e) { console.log(e.message, e); @@ -293,8 +313,15 @@ function systemEndpoints(app) { limit_user_messages: false, message_limit: 25, }); - process.env.AUTH_TOKEN = null; - process.env.JWT_SECRET = process.env.JWT_SECRET ?? v4(); // Make sure JWT_SECRET is set for JWT issuance. + + updateENV( + { + AuthToken: null, + JWTSecret: process.env.JWT_SECRET ?? v4(), + }, + true + ); + if (process.env.NODE_ENV === "production") await dumpENV(); await Telemetry.sendTelemetry("enabled_multi_user_mode"); response.status(200).json({ success: !!user, error }); } catch (e) { diff --git a/server/utils/helpers/updateENV.js b/server/utils/helpers/updateENV.js index 2abff32dc..78561cba9 100644 --- a/server/utils/helpers/updateENV.js +++ b/server/utils/helpers/updateENV.js @@ -72,11 +72,11 @@ const KEY_MAPPING = { // System Settings AuthToken: { envKey: "AUTH_TOKEN", - checks: [], + checks: [requiresForceMode], }, JWTSecret: { envKey: "JWT_SECRET", - checks: [], + checks: [requiresForceMode], }, // Not supported yet. // 'StorageDir': 'STORAGE_DIR', @@ -143,11 +143,15 @@ function validAzureURL(input = "") { } } +function requiresForceMode(_, forceModeEnabled = false) { + return forceModeEnabled === true ? null : "Cannot set this setting."; +} + // This will force update .env variables which for any which reason were not able to be parsed or // read from an ENV file as this seems to be a complicating step for many so allowing people to write // to the process will at least alleviate that issue. It does not perform comprehensive validity checks or sanity checks // and is simply for debugging when the .env not found issue many come across. -function updateENV(newENVs = {}) { +function updateENV(newENVs = {}, force = false) { let error = ""; const validKeys = Object.keys(KEY_MAPPING); const ENV_KEYS = Object.keys(newENVs).filter( @@ -159,7 +163,7 @@ function updateENV(newENVs = {}) { const { envKey, checks } = KEY_MAPPING[key]; const value = newENVs[key]; const errors = checks - .map((validityCheck) => validityCheck(value)) + .map((validityCheck) => validityCheck(value, force)) .filter((err) => typeof err === "string"); if (errors.length > 0) { diff --git a/server/utils/prisma/migrateFromSqlite.js b/server/utils/prisma/migrateFromSqlite.js index c874aefcf..4e5e379cf 100644 --- a/server/utils/prisma/migrateFromSqlite.js +++ b/server/utils/prisma/migrateFromSqlite.js @@ -253,7 +253,7 @@ async function migrateTable(tableName, migrateRowFunc) { // Check table exists const { count } = await db.get( `SELECT COUNT(*) as count FROM sqlite_master WHERE name='${tableName}'` - ) + ); if (count === 0) { console.log( `${tableName} does not exist in legacy DB - nothing to migrate - skipping.`