wulf-pulse/app/api/duo/status/route.ts
lorentz 5f4e326804 feat: Separate bypass vs disabled users in Duo UI
Bypass = security risk (MFA not enforced) — shown in red, expandable panel
Disabled = locked out, no threat — shown in muted gray, separate expandable panel

- Split /api/duo/status counts into bypass and disabled separately
- /api/duo/users/flagged returns { bypass: [], disabled: [] } instead of flat list
- Overview card: only bypass triggers red warning icon (disabled does not)
- Detail page: two separate expandable sections with distinct severity styling
- Both sections include user, email, account name, enrolled status, last login, notes
- Covers all accounts (parent + children)
2026-03-27 11:41:52 -04:00

44 lines
1.8 KiB
TypeScript

import { NextResponse } from 'next/server';
import { postgresClient } from '@/lib/services/postgres-client';
import { duoSyncService } from '@/lib/services/duo-sync-service';
export async function GET() {
try {
const [accounts, users, phones, authLogs, groups, integrations, lastSync] = await Promise.all([
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_accounts WHERE is_parent = false`),
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_users`),
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_phones`),
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_auth_logs`),
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_groups`),
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_integrations`),
postgresClient.query(`SELECT MAX(synced_at) as last_sync FROM duo_accounts`),
]);
const [bypassRes, disabledRes] = await Promise.all([
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_users WHERE status = 'bypass'`),
postgresClient.query(`SELECT COUNT(*) as cnt FROM duo_users WHERE status = 'disabled'`),
]);
return NextResponse.json({
connected: true,
syncing: duoSyncService.isSyncInProgress(),
lastSync: lastSync.rows[0]?.last_sync ?? null,
counts: {
accounts: Number(accounts.rows[0].cnt),
users: Number(users.rows[0].cnt),
phones: Number(phones.rows[0].cnt),
authLogs: Number(authLogs.rows[0].cnt),
groups: Number(groups.rows[0].cnt),
integrations: Number(integrations.rows[0].cnt),
bypass: Number(bypassRes.rows[0].cnt),
disabled: Number(disabledRes.rows[0].cnt),
},
});
} catch (error: any) {
return NextResponse.json({
connected: false,
error: error.message,
counts: {},
});
}
}