import { env } from '../config/env'; import { AppError } from '../errors/app-error'; import { findByEmail, findByMicrosoftId, UtilisateurAvecRole, } from '../repositories/utilisateur.repository'; import { AuthenticatedUser } from '../types/authenticated-user'; import { verifyAzureAccessToken } from './azure-token.service'; export interface AuthenticationHeaders { authorization?: string; demoEmail?: string; } function toAuthenticatedUser(utilisateur: UtilisateurAvecRole): AuthenticatedUser { return { id: utilisateur.id, email: utilisateur.email, roleCode: utilisateur.role.code, campusId: utilisateur.campusId, }; } function bearerToken(authorization: string | undefined): string { const match = authorization?.match(/^Bearer\s+(\S+)$/i); if (!match) { throw new AppError(401, 'Jeton Bearer requis'); } return match[1]; } async function authenticateDemo(email: string | undefined): Promise { if (!email) { throw new AppError(401, 'En-tete x-user-email requis en mode demo'); } return findByEmail(email.trim().toLowerCase()); } async function authenticateAzure( authorization: string | undefined, ): Promise { const identity = await verifyAzureAccessToken(bearerToken(authorization)); const byMicrosoftId = await findByMicrosoftId(identity.microsoftId); if (byMicrosoftId) { return byMicrosoftId; } return findByEmail(identity.email); } export async function authenticateUser( headers: AuthenticationHeaders, ): Promise { const utilisateur = env.auth.mode === 'azure' ? await authenticateAzure(headers.authorization) : await authenticateDemo(headers.demoEmail); if (!utilisateur || !utilisateur.actif) { throw new AppError(401, 'Utilisateur non reconnu'); } return toAuthenticatedUser(utilisateur); }