@@ -25,6 +25,22 @@ function setRoomsContent(html) {
2525 roomsDiv . innerHTML = html ;
2626}
2727
28+ // Security: escape user-controlled strings before injecting into innerHTML.
29+ function escapeHtml ( value ) {
30+ return String ( value ?? '' ) . replace ( / [ & < > " ' ` = \/ ] / g, ( c ) => {
31+ return {
32+ '&' : '&' ,
33+ '<' : '<' ,
34+ '>' : '>' ,
35+ '"' : '"' ,
36+ "'" : ''' ,
37+ '`' : '`' ,
38+ '=' : '=' ,
39+ '/' : '/' ,
40+ } [ c ] ;
41+ } ) ;
42+ }
43+
2844function getRoomsData ( res ) {
2945 return ! isTest ? res . data . activeRooms || [ ] : mockRooms ( ) ;
3046}
@@ -75,30 +91,33 @@ function renderRooms(rooms) {
7591 }
7692 setRoomsContent (
7793 rooms
78- . map (
79- ( room ) => `
94+ . map ( ( room ) => {
95+ const id = escapeHtml ( room . id ) ;
96+ const peers = Number ( room . peers ) || 0 ;
97+ const join = escapeHtml ( room . join ) ;
98+ return `
8099 <div class="room-card">
81100 <div class="room-card-header">
82101 <div class="room-title">
83- <i class="fa-solid fa-door-open"></i>${ room . id }
102+ <i class="fa-solid fa-door-open"></i>${ id }
84103 </div>
85104 <div class="peer-badge">
86105 <i class="fa-solid fa-users"></i>
87- ${ room . peers }
106+ ${ peers }
88107 </div>
89108 </div>
90109 <div class="room-card-footer">
91110 <div class="peer-status">
92111 <span class="dot"></span>
93- ${ room . peers } ${ room . peers === 1 ? 'peer' : 'peers' } connected
112+ ${ peers } ${ peers === 1 ? 'peer' : 'peers' } connected
94113 </div>
95- <a href="${ room . join } " class="join-btn" target="_blank">
114+ <a href="${ join } " class="join-btn" target="_blank" rel="noopener noreferrer ">
96115 <i class="fa-solid fa-arrow-right-to-bracket"></i> Join
97116 </a>
98117 </div>
99118 </div>
100- `
101- )
119+ ` ;
120+ } )
102121 . join ( '' )
103122 ) ;
104123}
0 commit comments