import type { Server as SocketIOServer } from 'socket.io'; import jwt from 'jsonwebtoken'; import { config } from '../config/env.js'; import pino from 'pino'; const logger = pino({ level: 'info', transport: { target: 'pino-pretty', options: { colorize: true } } }); export function setupScanEvents(io: SocketIOServer) { io.on('connection', (socket) => { // Authenticate the socket connection using JWT from cookies or auth query let userId: string | null = null; try { const cookieHeader = socket.handshake.headers.cookie || ''; const tokenMatch = cookieHeader.match(/token=([^;]+)/); const token = tokenMatch?.[1] || (socket.handshake.auth?.token as string); if (token) { const payload = jwt.verify(token, config.JWT_SECRET) as { userId: string }; userId = payload.userId; // Join user-specific room so events are scoped socket.join(`user:${userId}`); logger.info({ socketId: socket.id, userId }, 'Client authenticated and joined user room'); } else { logger.warn({ socketId: socket.id }, 'Client connected without auth token'); } } catch (err) { logger.warn({ socketId: socket.id }, 'Client connected with invalid token'); } socket.on('scan:join', (jobId: string) => { socket.join(`scan:${jobId}`); logger.info({ socketId: socket.id, jobId }, 'Client joined scan room'); }); socket.on('scan:leave', (jobId: string) => { socket.leave(`scan:${jobId}`); }); socket.on('disconnect', () => { logger.info(`Client disconnected: ${socket.id}`); }); }); }