Bug Description
In server.ts lines 344-347, the rejoin_session handler grabs the first entry from the disconnectedPeers Set without verifying the role:
for (const pid of session.disconnectedPeers) {
rejoiningOldPeerId = pid;
break;
}
This does not verify that the reconnecting client should assume the role of that specific disconnected peer.
Impact
If both tutor and viewer disconnect simultaneously and the viewer reconnects first with rejoin_session, it could claim the tutor's grace-period slot and be assigned role: 'tutor'.
Currently this is mitigated because only the tutor page sends rejoin_session (the viewer uses join_session), but the invariant is implicit and fragile. Any future change to the viewer reconnection logic could trigger this bug.
Suggested Fix
- Include the expected
role in the rejoin_session message and match it against peerRoles
- Iterate
disconnectedPeers to find a slot whose role matches the expected one
- Reject the rejoin if no matching role slot exists
This makes the role-matching invariant explicit and safe against future changes.
Bug Description
In
server.tslines 344-347, therejoin_sessionhandler grabs the first entry from thedisconnectedPeersSet without verifying the role:This does not verify that the reconnecting client should assume the role of that specific disconnected peer.
Impact
If both tutor and viewer disconnect simultaneously and the viewer reconnects first with
rejoin_session, it could claim the tutor's grace-period slot and be assignedrole: 'tutor'.Currently this is mitigated because only the tutor page sends
rejoin_session(the viewer usesjoin_session), but the invariant is implicit and fragile. Any future change to the viewer reconnection logic could trigger this bug.Suggested Fix
rolein therejoin_sessionmessage and match it againstpeerRolesdisconnectedPeersto find a slot whose role matches the expected oneThis makes the role-matching invariant explicit and safe against future changes.