@@ -21,6 +21,10 @@ function sanitizeHtml(str) {
2121 . replace ( / > / g, '>' ) ;
2222}
2323
24+ async function wait ( ms ) {
25+ return new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
26+ }
27+
2428// Add card sanitization helper
2529function sanitizeCard ( card ) {
2630 return {
@@ -47,7 +51,7 @@ app.use(sessionParser);
4751
4852// In-memory storage (intentionally vulnerable)
4953const users = new Map ( ) ; // username -> {password, cards}
50- const activeConnections = new Map ( ) ; // username -> WebSocket
54+ const activeConnections = new Map ( ) ; // username -> Set< WebSocket>
5155
5256// Card generation utilities
5357function generateUniqueCard ( username ) {
@@ -85,16 +89,20 @@ function checkForDuplication(username) {
8589
8690// Broadcast active players to all connected clients
8791function broadcastActivePlayers ( ) {
92+ // Get unique active players
8893 const activePlayers = Array . from ( activeConnections . keys ( ) ) ;
8994 const message = JSON . stringify ( {
9095 type : 'activePlayers' ,
9196 players : activePlayers . filter ( player => isValidUsername ( player ) )
9297 } ) ;
9398
94- activeConnections . forEach ( ws => {
95- if ( ws . readyState === WebSocket . OPEN ) {
96- ws . send ( message ) ;
97- }
99+ // Send to all connections
100+ activeConnections . forEach ( ( connections , username ) => {
101+ connections . forEach ( ws => {
102+ if ( ws . readyState === WebSocket . OPEN ) {
103+ ws . send ( message ) ;
104+ }
105+ } ) ;
98106 } ) ;
99107}
100108
@@ -191,7 +199,13 @@ wss.on('connection', (ws, req) => {
191199 return ;
192200 }
193201
194- activeConnections . set ( username , ws ) ;
202+ // Create a Set for this user's connections if it doesn't exist
203+ if ( ! activeConnections . has ( username ) ) {
204+ activeConnections . set ( username , new Set ( ) ) ;
205+ }
206+
207+ // Add this connection to the user's set of connections
208+ activeConnections . get ( username ) . add ( ws ) ;
195209 broadcastActivePlayers ( ) ;
196210
197211 ws . on ( 'message' , ( message ) => {
@@ -210,7 +224,15 @@ wss.on('connection', (ws, req) => {
210224 } ) ;
211225
212226 ws . on ( 'close' , ( ) => {
213- activeConnections . delete ( username ) ;
227+ // Remove this specific connection
228+ const userConnections = activeConnections . get ( username ) ;
229+ if ( userConnections ) {
230+ userConnections . delete ( ws ) ;
231+ // Only remove the user from activeConnections if they have no connections left
232+ if ( userConnections . size === 0 ) {
233+ activeConnections . delete ( username ) ;
234+ }
235+ }
214236 broadcastActivePlayers ( ) ;
215237 } ) ;
216238 } ) ;
@@ -231,39 +253,48 @@ async function handleGiftCards(username, data, ws) {
231253 }
232254
233255 // Simulate network delay
234- await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
256+ await wait ( 300 ) ;
235257
236258 const giftedCards = cardIds
237259 . map ( cardId => fromUser . cards . find ( card => card . id === cardId ) )
238260 . filter ( card => card )
239261 . map ( sanitizeCard ) ;
240262
241263 // Simulate more network delay
242- await new Promise ( resolve => setTimeout ( resolve , 100 ) ) ;
264+ await wait ( 300 ) ;
243265
244266 giftedCards . forEach ( card => {
245267 fromUser . cards = fromUser . cards . filter ( c => c . id !== card . id ) ;
246268 } ) ;
247269
248270 toUserData . cards . push ( ...giftedCards ) ;
249271
250- const fromWs = activeConnections . get ( username ) ;
251- const toWs = activeConnections . get ( toUser ) ;
252-
253- if ( fromWs && fromWs . readyState === WebSocket . OPEN ) {
254- fromWs . send ( JSON . stringify ( {
255- type : 'giftComplete' ,
256- inventory : fromUser . cards . map ( sanitizeCard )
257- } ) ) ;
272+ // Send updates to all connections for both users
273+ const fromConnections = activeConnections . get ( username ) ;
274+ const toConnections = activeConnections . get ( toUser ) ;
275+
276+ if ( fromConnections ) {
277+ fromConnections . forEach ( conn => {
278+ if ( conn . readyState === WebSocket . OPEN ) {
279+ conn . send ( JSON . stringify ( {
280+ type : 'giftComplete' ,
281+ inventory : fromUser . cards . map ( sanitizeCard )
282+ } ) ) ;
283+ }
284+ } ) ;
258285 }
259286
260- if ( toWs && toWs . readyState === WebSocket . OPEN ) {
261- toWs . send ( JSON . stringify ( {
262- type : 'giftReceived' ,
263- from : sanitizeHtml ( username ) ,
264- cards : giftedCards ,
265- inventory : toUserData . cards . map ( sanitizeCard )
266- } ) ) ;
287+ if ( toConnections ) {
288+ toConnections . forEach ( conn => {
289+ if ( conn . readyState === WebSocket . OPEN ) {
290+ conn . send ( JSON . stringify ( {
291+ type : 'giftReceived' ,
292+ from : sanitizeHtml ( username ) ,
293+ cards : giftedCards ,
294+ inventory : toUserData . cards . map ( sanitizeCard )
295+ } ) ) ;
296+ }
297+ } ) ;
267298 }
268299}
269300
0 commit comments