Merge pull request #42 from ruvnet/security/fix-critical-vulnerabilities
Security: Fix critical vulnerabilities (includes fr4iser90 PR #38 + fix)
This commit was merged in pull request #42.
This commit is contained in:
@@ -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 = `
|
||||
<span class="feature-name">${this.formatFeatureName(feature)}</span>
|
||||
<span class="feature-status">${enabled ? '✓' : '✗'}</span>
|
||||
`;
|
||||
|
||||
// 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 = `
|
||||
<span class="zone-name">${zoneId}</span>
|
||||
<span class="zone-count">undefined</span>
|
||||
`;
|
||||
|
||||
// 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 = `
|
||||
<span class="zone-name">${zoneId}</span>
|
||||
<span class="zone-count">${count}</span>
|
||||
`;
|
||||
|
||||
// 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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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 = `
|
||||
<div class="array-info">
|
||||
<span class="info-label">Active TX:</span>
|
||||
<span class="info-value">${txActive}/3</span>
|
||||
</div>
|
||||
<div class="array-info">
|
||||
<span class="info-label">Active RX:</span>
|
||||
<span class="info-value">${rxActive}/6</span>
|
||||
</div>
|
||||
<div class="array-info">
|
||||
<span class="info-label">Signal Quality:</span>
|
||||
<span class="info-value">${this.calculateSignalQuality(txActive, rxActive)}%</span>
|
||||
</div>
|
||||
`;
|
||||
// Clear and rebuild using safe DOM methods to prevent XSS
|
||||
arrayStatus.innerHTML = '';
|
||||
|
||||
const createInfoDiv = (label, value) => {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'array-info';
|
||||
|
||||
const labelSpan = document.createElement('span');
|
||||
labelSpan.className = 'info-label';
|
||||
labelSpan.textContent = label;
|
||||
|
||||
const valueSpan = document.createElement('span');
|
||||
valueSpan.className = 'info-value';
|
||||
valueSpan.textContent = value;
|
||||
|
||||
div.appendChild(labelSpan);
|
||||
div.appendChild(valueSpan);
|
||||
return div;
|
||||
};
|
||||
|
||||
arrayStatus.appendChild(createInfoDiv('Active TX:', `${txActive}/3`));
|
||||
arrayStatus.appendChild(createInfoDiv('Active RX:', `${rxActive}/6`));
|
||||
arrayStatus.appendChild(createInfoDiv('Signal Quality:', `${this.calculateSignalQuality(txActive, rxActive)}%`));
|
||||
}
|
||||
|
||||
// Calculate signal quality based on active antennas
|
||||
|
||||
@@ -539,14 +539,23 @@ export class PoseDetectionCanvas {
|
||||
const persons = this.state.lastPoseData?.persons?.length || 0;
|
||||
const zones = Object.keys(this.state.lastPoseData?.zone_summary || {}).length;
|
||||
|
||||
statsEl.innerHTML = `
|
||||
Connection: ${this.state.connectionState}<br>
|
||||
Frames: ${this.state.frameCount}<br>
|
||||
FPS: ${fps.toFixed(1)}<br>
|
||||
Persons: ${persons}<br>
|
||||
Zones: ${zones}<br>
|
||||
Uptime: ${uptime}s
|
||||
`;
|
||||
// Use textContent instead of innerHTML to prevent XSS
|
||||
statsEl.textContent = '';
|
||||
const lines = [
|
||||
`Connection: ${this.state.connectionState}`,
|
||||
`Frames: ${this.state.frameCount}`,
|
||||
`FPS: ${fps.toFixed(1)}`,
|
||||
`Persons: ${persons}`,
|
||||
`Zones: ${zones}`,
|
||||
`Uptime: ${uptime}s`
|
||||
];
|
||||
lines.forEach((line, index) => {
|
||||
if (index > 0) {
|
||||
statsEl.appendChild(document.createElement('br'));
|
||||
}
|
||||
const textNode = document.createTextNode(line);
|
||||
statsEl.appendChild(textNode);
|
||||
});
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
|
||||
@@ -107,8 +107,12 @@ export function buildApiUrl(endpoint, params = {}) {
|
||||
|
||||
// Helper function to build WebSocket URLs
|
||||
export function buildWsUrl(endpoint, params = {}) {
|
||||
const protocol = window.location.protocol === 'https:'
|
||||
? API_CONFIG.WSS_PREFIX
|
||||
// Use secure WebSocket (wss://) when serving over HTTPS or on non-localhost
|
||||
// Use ws:// only for localhost development
|
||||
const isLocalhost = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
|
||||
const isSecure = window.location.protocol === 'https:';
|
||||
const protocol = (isSecure || !isLocalhost)
|
||||
? API_CONFIG.WSS_PREFIX
|
||||
: API_CONFIG.WS_PREFIX;
|
||||
|
||||
// Match Rust sensing server port
|
||||
|
||||
Reference in New Issue
Block a user