import { securityLogger as logger } from '../commons/logger.js'; import { PublicEndpointRegistry, AdminEndpointRegistry } from '../commons/registry.js'; import { getUserCached, supabase } from '../commons/supabase.js'; /** * Strict authentication middleware – requires a valid Bearer token. */ export async function authMiddleware(c, next) { const authHeader = c.req.header('authorization'); if (!authHeader?.startsWith('Bearer ')) { return c.json({ error: 'Unauthorized - Missing or invalid authorization header' }, 401); } const token = authHeader.substring(7); try { const user = await getUserCached(token); if (!user) { return c.json({ error: 'Invalid or expired token' }, 401); } c.set('userId', user.id); c.set('user', user); c.set('userEmail', user.email); await next(); } catch (err) { logger.error({ err }, 'Auth middleware error'); return c.json({ error: 'Authentication failed' }, 401); } } /** * Optional authentication middleware. * - Public endpoint: GET /api/products (no auth required). * - Otherwise respects REQUIRE_AUTH flag, but skips auth in test/dev environments. */ export async function optionalAuthMiddleware(c, next) { const path = c.req.path; const method = c.req.method; // Public endpoint – allow unauthenticated access const isPublicEndpoint = PublicEndpointRegistry.isPublic(path, method); const isProductsEndpoint = method === 'GET' && path === '/api/products'; if (isProductsEndpoint || isPublicEndpoint) { return await next(); } const requireAuth = process.env.REQUIRE_AUTH === 'true'; const isTestEnv = false; // process.env.NODE_ENV === 'test' || process.env.NODE_ENV === 'development'; const authHeader = c.req.header('authorization'); // If no auth header, or it's not a Bearer token... let token; if (authHeader && authHeader.startsWith('Bearer ')) { token = authHeader.substring(7); } else { // Check for token in query param (for SSE) const queryToken = c.req.query('token'); if (queryToken) { token = queryToken; } } if (!token) { // ...and we are in test env or auth not required, just continue. if (!requireAuth) { return await next(); } // ...otherwise reject return c.json({ error: 'Unauthorized' }, 401); } try { const user = await getUserCached(token); if (!user) { logger.warn('[Auth] Token verification failed'); if (isTestEnv) { return await next(); } return c.json({ error: 'Unauthorized' }, 401); } c.set('userId', user.id); c.set('user', user); c.set('userEmail', user.email); await next(); } catch (err) { logger.error({ err }, '[Auth] Optional auth middleware error - REJECTING'); return c.json({ error: 'Authentication failed' }, 401); } } /** * Admin‑only middleware – requires authentication and admin role. * Checks AdminEndpointRegistry to see if the route requires admin access. */ export async function adminMiddleware(c, next) { const path = c.req.path; const method = c.req.method; // Check if this is an admin endpoint if (!AdminEndpointRegistry.isAdmin(path, method)) { return await next(); } // If it is an admin endpoint, enforce auth and role const userId = c.get('userId'); if (!userId) { return c.json({ error: 'Unauthorized - Authentication required' }, 401); } try { const { data: profile, error } = await supabase .from('user_roles') .select('role') .eq('user_id', userId) .single(); // @todo : fix db - type | multiple - currently single string if (error || !profile || profile.role !== 'admin') { return c.json({ error: 'Forbidden - Admin access required' }, 403); } c.set('isAdmin', true); await next(); } catch (err) { logger.error({ err }, 'Admin middleware error'); return c.json({ error: 'Authorization check failed' }, 500); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXV0aC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9taWRkbGV3YXJlL2F1dGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGNBQWMsSUFBSSxNQUFNLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUNoRSxPQUFPLEVBQUUsc0JBQXNCLEVBQUUscUJBQXFCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUN2RixPQUFPLEVBQUUsYUFBYSxFQUFFLFFBQVEsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBR2pFOztHQUVHO0FBQ0gsTUFBTSxDQUFDLEtBQUssVUFBVSxjQUFjLENBQUMsQ0FBVSxFQUFFLElBQVU7SUFDdkQsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDakQsSUFBSSxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztRQUNyQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsd0RBQXdELEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztJQUM1RixDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0QyxJQUFJLENBQUM7UUFDRCxNQUFNLElBQUksR0FBRyxNQUFNLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN4QyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDUixPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxLQUFLLEVBQUUsMEJBQTBCLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUM5RCxDQUFDO1FBQ0QsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3pCLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1FB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