From ec0eef7de0573eef56bddbadacb5cf32c1ad662e Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Wed, 15 Jul 2026 15:46:39 +0000 Subject: [PATCH] =?UTF-8?q?Add=20reveal-secret=20endpoint=20=E2=80=94=20re?= =?UTF-8?q?-verifies=20admin=20password=20before=20returning=20CENTRAL=5FA?= =?UTF-8?q?UTH=5FSECRET?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Used by the settings UI so operators can securely copy the shared session secret into Hosted Tables without ever exposing it in logs or config files. Co-Authored-By: Claude Sonnet 4.6 --- src/routes/admin.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/routes/admin.js b/src/routes/admin.js index 3c060bb..5b7a0f0 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -1,5 +1,5 @@ import { pool } from '../db.js' -import { hashPassword, verifyToken } from '../jwt.js' +import { hashPassword, verifyToken, verifyPassword } from '../jwt.js' import { getAllDepartments, getLocationsByIds, getSyncConfig, findEmployeeByEmail, getEmployeeDepartments } from '../workforce.js' import { syncAllWorkforceUsers } from '../sync.js' @@ -407,4 +407,25 @@ export async function adminRoutes(app) { return reply.status(502).send({ error: err.message }) } }) + + // Re-authenticates the calling admin then returns CENTRAL_AUTH_SECRET. + // Used by the Settings UI so operators can copy the secret into Hosted Tables. + app.post('/reveal-secret', async (request, reply) => { + const { password } = request.body || {} + if (!password) return reply.status(400).send({ error: 'Password required' }) + + const adminId = request.adminPayload.id + const { rows: [user] } = await pool.query( + 'SELECT password_hash FROM users WHERE id = $1 AND active = true AND is_admin = true', + [adminId] + ) + if (!user || !(await verifyPassword(password, user.password_hash))) { + return reply.status(401).send({ error: 'Incorrect password' }) + } + + const secret = process.env.CENTRAL_AUTH_SECRET + if (!secret) return reply.status(503).send({ error: 'CENTRAL_AUTH_SECRET is not set on this server' }) + + return { secret } + }) }