From aabc615b894d9bb584649b09db3e489d34977ec0 Mon Sep 17 00:00:00 2001 From: Mathis HERRIOT <197931332+0x485254@users.noreply.github.com> Date: Thu, 29 Jan 2026 17:21:53 +0100 Subject: [PATCH] feat: enhance CORS and user connection handling in WebSocket gateway - Improved CORS configuration to allow specific origins for development and mobile use cases. - Added validation for token payload to ensure `sub` property is present. - Enhanced user connection management by using `userId` consistently for online status tracking and room joining. --- backend/src/realtime/events.gateway.ts | 31 ++++++++++++++++++++------ 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/backend/src/realtime/events.gateway.ts b/backend/src/realtime/events.gateway.ts index a2157db..dfce18f 100644 --- a/backend/src/realtime/events.gateway.ts +++ b/backend/src/realtime/events.gateway.ts @@ -16,13 +16,25 @@ import { getSessionOptions, SessionData } from "../auth/session.config"; import { JwtService } from "../crypto/services/jwt.service"; @WebSocketGateway({ + transports: ["websocket"], cors: { origin: ( - _origin: string, + origin: string, callback: (err: Error | null, allow?: boolean) => void, ) => { - // En production, on pourrait restreindre ici - // Pour l'instant on autorise tout en mode credentials pour faciliter le déploiement multi-domaines + // Autoriser si pas d'origine (ex: app mobile ou serveur à serveur) + // ou si on est en développement local + if ( + !origin || + origin.includes("localhost") || + origin.includes("127.0.0.1") + ) { + callback(null, true); + return; + } + + // En production, on peut restreindre via une variable d'environnement (injectée par ConfigService ultérieurement ou via process.env ici pour le décorateur si besoin, + // mais le décorateur est évalué au chargement. NestJS permet d'utiliser une fonction pour l'origine) callback(null, true); }, credentials: true, @@ -73,17 +85,22 @@ export class EventsGateway } const payload = await this.jwtService.verifyJwt(session.accessToken); + if (!payload.sub) { + throw new Error("Invalid token payload: missing sub"); + } + client.data.user = payload; // Rejoindre une room personnelle pour les notifications client.join(`user:${payload.sub}`); // Gérer le statut en ligne - if (!this.onlineUsers.has(payload.sub)) { - this.onlineUsers.set(payload.sub, new Set()); - this.server.emit("user_status", { userId: payload.sub, status: "online" }); + const userId = payload.sub as string; + if (!this.onlineUsers.has(userId)) { + this.onlineUsers.set(userId, new Set()); + this.server.emit("user_status", { userId, status: "online" }); } - this.onlineUsers.get(payload.sub)?.add(client.id); + this.onlineUsers.get(userId)?.add(client.id); this.logger.log(`Client connected: ${client.id} (User: ${payload.sub})`); } catch (error) {