(c: Context<AppEnv>)
| 157 | * Enforce authentication requirement |
| 158 | */ |
| 159 | export async function enforceAuthRequirement(c: Context<AppEnv>) : Promise<Response | undefined> { |
| 160 | let user: AuthUser | null = c.get('user') || null; |
| 161 | |
| 162 | const requirement = c.get('authLevel') as AuthRequirement | undefined; |
| 163 | const authOptions = c.get('authLevelOptions') as AuthLevelOptions | undefined; |
| 164 | |
| 165 | if (!requirement) { |
| 166 | logger.error('No authentication level found'); |
| 167 | return errorResponse('No authentication level found', 500); |
| 168 | } |
| 169 | |
| 170 | // Only perform auth if we need it or don't have user yet |
| 171 | if (!user && (requirement.level === 'authenticated' || requirement.level === 'owner-only')) { |
| 172 | const request = c.req.raw; |
| 173 | const env = c.env; |
| 174 | const params = c.req.param(); |
| 175 | |
| 176 | // Strategy 1: Ticket-based auth (if configured and ticket present) |
| 177 | if (authOptions?.ticketAuth && hasTicketParam(request)) { |
| 178 | const ticketAuth = await authenticateViaTicket(request, env, authOptions.ticketAuth, params); |
| 179 | if (ticketAuth) { |
| 180 | user = ticketAuth.user; |
| 181 | c.set('user', user); |
| 182 | c.set('sessionId', ticketAuth.sessionId); |
| 183 | Sentry.setUser({ id: user.id, email: user.email }); |
| 184 | |
| 185 | const config = await getUserConfigurableSettings(c.env, user.id); |
| 186 | c.set('config', config); |
| 187 | |
| 188 | // Skip rate limiting for ticket auth (already rate-limited at ticket creation) |
| 189 | logger.info('Authenticated via ticket', { userId: user.id, resourceType: authOptions.ticketAuth.resourceType }); |
| 190 | } else { |
| 191 | // Ticket was provided but invalid - reject immediately |
| 192 | return errorResponse('Invalid or expired ticket', 403); |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | // Strategy 2: Standard JWT auth (header/cookie) |
| 197 | if (!user) { |
| 198 | const userSession = await authMiddleware(c.req.raw, c.env); |
| 199 | if (!userSession) { |
| 200 | return errorResponse('Authentication required', 401); |
| 201 | } |
| 202 | user = userSession.user; |
| 203 | c.set('user', user); |
| 204 | c.set('sessionId', userSession.sessionId); |
| 205 | Sentry.setUser({ id: user.id, email: user.email }); |
| 206 | |
| 207 | const config = await getUserConfigurableSettings(c.env, user.id); |
| 208 | c.set('config', config); |
| 209 | |
| 210 | try { |
| 211 | await RateLimitService.enforceAuthRateLimit(c.env, config.security.rateLimit, user, c.req.raw); |
| 212 | } catch (error) { |
| 213 | if (error instanceof RateLimitExceededError) { |
| 214 | return errorResponse(error, 429); |
| 215 | } |
| 216 | logger.error('Error enforcing auth rate limit', error); |
no test coverage detected