import type { Context } from "jsr:@hono/hono@4"; import { getCookie } from "jsr:@hono/hono@4/cookie"; import { sql } from "./db.ts"; import { valkey } from "./valkey.ts"; export interface AuthenticatedUser { userId: string; sessionId: string; username: string; } /** * Helper to get authenticated user from session cookie. * Checks Valkey cache first, with automatic PostgreSQL sessions table fallback. */ export async function getAuthenticatedUser( c: Context, ): Promise { const sessionId = getCookie(c, "session_id"); if (!sessionId) return null; // 1. Try Valkey cache try { const sessionDataStr = await valkey.get(sessionId); if (sessionDataStr) { const sessionData = JSON.parse(sessionDataStr); if (sessionData && sessionData.uuid) { return { userId: sessionData.uuid, sessionId, username: sessionData.username || "", }; } } } catch (_err) { // Valkey cache miss or connection hiccup - fallback to DB } // 2. Fallback to PostgreSQL sessions table try { const session = await sql` SELECT s.user_id, s.expires_at, u.username FROM sessions s JOIN users u ON s.user_id = u.id WHERE s.id = ${sessionId} AND s.expires_at > NOW() `.then((res) => res[0]); if (session) { const username = session.username || ""; // Repopulate Valkey in background try { const ttlSeconds = Math.max( 1, Math.floor( (new Date(session.expires_at).getTime() - Date.now()) / 1000, ), ); await valkey.setex( sessionId, ttlSeconds, JSON.stringify({ uuid: session.user_id, username }), ); } catch (_e) {} return { userId: session.user_id, sessionId, username }; } } catch (_err) { return null; } return null; } /** * Helper to check if user has global admin privileges. * Strict check: Requires an explicit 'admin' grant on the Management Console * or global role, or is the bootstrap root user. */ export async function isGlobalAdmin(userId: string): Promise { try { // Check 1: User has an explicit 'admin' grant for the Auth-Yes Management Console or global app const adminGrant = await sql` SELECT g.id FROM grants g LEFT JOIN apps a ON g.app_id = a.id WHERE g.user_id = ${userId} AND g.role = 'admin' AND ( a.spiffe_id = 'spiffe://system.local/auth-yes-management' OR a.name = 'Auth-Yes Management Console' OR g.app_id IS NULL ) `.then((res) => res[0]); if (adminGrant) return true; // Check 2: First registered user in system fallback const firstUser = await sql` SELECT id FROM users ORDER BY created_at ASC LIMIT 1 `.then((res) => res[0]); if (firstUser && firstUser.id === userId) { return true; } } catch (err) { console.error("[Auth API] isGlobalAdmin error:", err); } return false; }