From b98cfc9ca18a0774f5bc8f6fdce5c928d74538a8 Mon Sep 17 00:00:00 2001 From: Koala <6156589+Shik3i@users.noreply.github.com> Date: Mon, 25 May 2026 12:23:16 +0200 Subject: [PATCH] fix(server): add missing room creation lock to prevent concurrent join race Two parallel JOIN_ROOM to a non-existent room could race past each other during bcrypt.hash, causing the second to overwrite the first room (password hash lost). The lock was read but never written. - Create lock promise before bcrypt.hash async boundary - Release in finally to cover all exit paths (success, MAX_ROOMS, error) - Concurrent waiters now correctly await existing room creation --- server/index.js | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/server/index.js b/server/index.js index 64be368..af3e82c 100644 --- a/server/index.js +++ b/server/index.js @@ -302,21 +302,30 @@ io.on('connection', (socket) => { } } if (!room) { - if (rooms.size >= MAX_ROOMS) { - socket.emit(EVENTS.ERROR, { message: "Server capacity reached" }); - return; - } + // Create and store lock before async boundary + let resolveLock; + lockPromise = new Promise(resolve => { resolveLock = resolve; }); + roomCreationLocks.set(roomId, lockPromise); + try { + if (rooms.size >= MAX_ROOMS) { + socket.emit(EVENTS.ERROR, { message: "Server capacity reached" }); + return; + } - const passwordHash = password ? await bcrypt.hash(password, 10) : null; - room = { - passwordHash, - peers: new Set(), - peerIds: new Map(), - peerData: new Map(), - lastActivity: Date.now() - }; - rooms.set(roomId, room); - log('ROOM', `Created room: ${roomId.substring(0, 3)}***`); + const passwordHash = password ? await bcrypt.hash(password, 10) : null; + room = { + passwordHash, + peers: new Set(), + peerIds: new Map(), + peerData: new Map(), + lastActivity: Date.now() + }; + rooms.set(roomId, room); + log('ROOM', `Created room: ${roomId.substring(0, 3)}***`); + } finally { + roomCreationLocks.delete(roomId); + resolveLock(); + } } } else { if (room.passwordHash) {