diff --git a/ui/components/DashboardTab.js b/ui/components/DashboardTab.js index 25984ed..2ce878e 100644 --- a/ui/components/DashboardTab.js +++ b/ui/components/DashboardTab.js @@ -103,10 +103,18 @@ export class DashboardTab { Object.entries(features).forEach(([feature, enabled]) => { const featureElement = document.createElement('div'); featureElement.className = `feature-item ${enabled ? 'enabled' : 'disabled'}`; - featureElement.innerHTML = ` - ${this.formatFeatureName(feature)} - ${enabled ? '✓' : '✗'} - `; + + // Use textContent instead of innerHTML to prevent XSS + const featureNameSpan = document.createElement('span'); + featureNameSpan.className = 'feature-name'; + featureNameSpan.textContent = this.formatFeatureName(feature); + + const featureStatusSpan = document.createElement('span'); + featureStatusSpan.className = 'feature-status'; + featureStatusSpan.textContent = enabled ? '✓' : '✗'; + + featureElement.appendChild(featureNameSpan); + featureElement.appendChild(featureStatusSpan); featuresContainer.appendChild(featureElement); }); } @@ -296,10 +304,18 @@ export class DashboardTab { ['zone_1', 'zone_2', 'zone_3', 'zone_4'].forEach(zoneId => { const zoneElement = document.createElement('div'); zoneElement.className = 'zone-item'; - zoneElement.innerHTML = ` - ${zoneId} - undefined - `; + + // Use textContent instead of innerHTML to prevent XSS + const zoneNameSpan = document.createElement('span'); + zoneNameSpan.className = 'zone-name'; + zoneNameSpan.textContent = zoneId; + + const zoneCountSpan = document.createElement('span'); + zoneCountSpan.className = 'zone-count'; + zoneCountSpan.textContent = 'undefined'; + + zoneElement.appendChild(zoneNameSpan); + zoneElement.appendChild(zoneCountSpan); zonesContainer.appendChild(zoneElement); }); return; @@ -309,10 +325,18 @@ export class DashboardTab { const zoneElement = document.createElement('div'); zoneElement.className = 'zone-item'; const count = typeof data === 'object' ? (data.person_count || data.count || 0) : data; - zoneElement.innerHTML = ` - ${zoneId} - ${count} - `; + + // Use textContent instead of innerHTML to prevent XSS + const zoneNameSpan = document.createElement('span'); + zoneNameSpan.className = 'zone-name'; + zoneNameSpan.textContent = zoneId; + + const zoneCountSpan = document.createElement('span'); + zoneCountSpan.className = 'zone-count'; + zoneCountSpan.textContent = String(count); + + zoneElement.appendChild(zoneNameSpan); + zoneElement.appendChild(zoneCountSpan); zonesContainer.appendChild(zoneElement); }); } diff --git a/ui/components/HardwareTab.js b/ui/components/HardwareTab.js index baef164..7f36113 100644 --- a/ui/components/HardwareTab.js +++ b/ui/components/HardwareTab.js @@ -107,20 +107,29 @@ export class HardwareTab { const txActive = activeAntennas.filter(a => a.classList.contains('tx')).length; const rxActive = activeAntennas.filter(a => a.classList.contains('rx')).length; - arrayStatus.innerHTML = ` -