Add per-app session timeout: max_session_hours column on apps, enforced in /verify
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
3fae52c36b
commit
788628485b
3 changed files with 23 additions and 6 deletions
|
|
@ -110,6 +110,7 @@ export async function initDb() {
|
||||||
await pool.query(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS category VARCHAR(100)`)
|
await pool.query(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS category VARCHAR(100)`)
|
||||||
await pool.query(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS internal_host TEXT`)
|
await pool.query(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS internal_host TEXT`)
|
||||||
await pool.query(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS internal_port INTEGER DEFAULT 3080`)
|
await pool.query(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS internal_port INTEGER DEFAULT 3080`)
|
||||||
|
await pool.query(`ALTER TABLE apps ADD COLUMN IF NOT EXISTS max_session_hours INTEGER`)
|
||||||
await pool.query(`ALTER TABLE users ADD COLUMN IF NOT EXISTS workforce_user_id TEXT`)
|
await pool.query(`ALTER TABLE users ADD COLUMN IF NOT EXISTS workforce_user_id TEXT`)
|
||||||
await pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS users_workforce_user_id_idx ON users (workforce_user_id) WHERE workforce_user_id IS NOT NULL`)
|
await pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS users_workforce_user_id_idx ON users (workforce_user_id) WHERE workforce_user_id IS NOT NULL`)
|
||||||
await pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS pending_reg_email_idx ON pending_registrations (email)`)
|
await pool.query(`CREATE UNIQUE INDEX IF NOT EXISTS pending_reg_email_idx ON pending_registrations (email)`)
|
||||||
|
|
|
||||||
|
|
@ -129,13 +129,17 @@ export async function adminRoutes(app) {
|
||||||
})
|
})
|
||||||
|
|
||||||
app.patch('/apps/:slug', async (request, reply) => {
|
app.patch('/apps/:slug', async (request, reply) => {
|
||||||
const { active } = request.body || {}
|
const { active, max_session_hours } = request.body || {}
|
||||||
const { rows: [app] } = await pool.query(
|
const updates = []; const values = []
|
||||||
'UPDATE apps SET active = $1 WHERE slug = $2 RETURNING *',
|
if (active !== undefined) updates.push(`active = $${values.push(active)}`)
|
||||||
[active, request.params.slug]
|
if (max_session_hours !== undefined) updates.push(`max_session_hours = $${values.push(max_session_hours ?? null)}`)
|
||||||
|
if (!updates.length) return reply.status(400).send({ error: 'Nothing to update' })
|
||||||
|
values.push(request.params.slug)
|
||||||
|
const { rows: [a] } = await pool.query(
|
||||||
|
`UPDATE apps SET ${updates.join(', ')} WHERE slug = $${values.length} RETURNING *`, values
|
||||||
)
|
)
|
||||||
if (!app) return reply.status(404).send({ error: 'App not found' })
|
if (!a) return reply.status(404).send({ error: 'App not found' })
|
||||||
return app
|
return a
|
||||||
})
|
})
|
||||||
|
|
||||||
// ── Roles ──────────────────────────────────────────────────────────────────
|
// ── Roles ──────────────────────────────────────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,18 @@ export async function authRoutes(app) {
|
||||||
|
|
||||||
if (!user) return reply.status(403).send({ error: 'Access denied' })
|
if (!user) return reply.status(403).send({ error: 'Access denied' })
|
||||||
|
|
||||||
|
if (appSlug) {
|
||||||
|
const { rows: [appRow] } = await pool.query(
|
||||||
|
'SELECT max_session_hours FROM apps WHERE slug = $1 AND active = true', [appSlug]
|
||||||
|
)
|
||||||
|
if (appRow?.max_session_hours) {
|
||||||
|
const ageHours = (Date.now() / 1000 - payload.iat) / 3600
|
||||||
|
if (ageHours > appRow.max_session_hours) {
|
||||||
|
return reply.status(401).send({ error: 'Session expired' })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!user.offsite_allowed) {
|
if (!user.offsite_allowed) {
|
||||||
const clientIP = request.headers['x-real-ip'] || request.ip
|
const clientIP = request.headers['x-real-ip'] || request.ip
|
||||||
if (!(await isOnsite(clientIP))) {
|
if (!(await isOnsite(clientIP))) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue