fix: gate debug window hooks behind explicit flag

This commit is contained in:
lockbitchat
2026-05-17 22:58:21 -04:00
parent 026c81b775
commit 18022c6b68
4 changed files with 122 additions and 26 deletions
+1 -1
View File
@@ -11,7 +11,7 @@
"dev": "npm run build && python -m http.server 8000",
"watch": "npx tailwindcss -i src/styles/tw-input.css -o assets/tailwind.css --watch",
"serve": "npx http-server -p 8000",
"test": "node tests/sas-verification.test.mjs && node tests/file-transfer-consent.test.mjs && node tests/incoming-message-sanitization.test.mjs && node tests/file-type-allowlist.test.mjs && node tests/webrtc-privacy-mode.test.mjs && node tests/indexeddb-metadata-encryption.test.mjs && node tests/disconnect-cleanup.test.mjs && node tests/timer-lifecycle.test.mjs && node tests/file-transfer-cleanup.test.mjs && node tests/file-transfer-ui-cleanup.test.mjs && node tests/file-transfer-callback-propagation.test.mjs"
"test": "node tests/sas-verification.test.mjs && node tests/file-transfer-consent.test.mjs && node tests/incoming-message-sanitization.test.mjs && node tests/file-type-allowlist.test.mjs && node tests/webrtc-privacy-mode.test.mjs && node tests/indexeddb-metadata-encryption.test.mjs && node tests/disconnect-cleanup.test.mjs && node tests/timer-lifecycle.test.mjs && node tests/file-transfer-cleanup.test.mjs && node tests/file-transfer-ui-cleanup.test.mjs && node tests/file-transfer-callback-propagation.test.mjs && node tests/debug-window-hooks.test.mjs"
},
"keywords": [
"p2p",
+11 -25
View File
@@ -1,4 +1,4 @@
import { installDebugWindowHooks } from './utils/debugWindowHooks.js';
// Enhanced Copy Button with better UX
const EnhancedCopyButton = ({ text, className = "", children }) => {
const [copied, setCopied] = React.useState(false);
@@ -1639,32 +1639,18 @@
});
};
// Global functions for cleanup
React.useEffect(() => {
window.forceCleanup = () => {
handleClearData();
if (webrtcManagerRef.current) {
webrtcManagerRef.current.disconnect();
}
};
window.clearLogs = () => {
if (typeof console.clear === 'function') {
console.clear();
}
};
return () => {
delete window.forceCleanup;
delete window.clearLogs;
};
}, []);
const webrtcManagerRef = React.useRef(null);
const notificationIntegrationRef = React.useRef(null);
// Expose for modules/UI that run outside this closure (e.g., inline handlers)
// Safe because it's a ref object and we maintain it centrally here
window.webrtcManagerRef = webrtcManagerRef;
// Development-only debug helpers. Production never exposes
// manager internals or cleanup controls on `window`.
React.useEffect(() => {
return installDebugWindowHooks({
targetWindow: window,
webrtcManagerRef,
onClearData: handleClearData
});
}, []);
const addMessageWithAutoScroll = React.useCallback((message, type) => {
const newMessage = {
+35
View File
@@ -0,0 +1,35 @@
function isSecureBitDebugEnabled(targetWindow = globalThis.window) {
return targetWindow?.SECUREBIT_DEBUG === true;
}
function installDebugWindowHooks({
targetWindow = globalThis.window,
webrtcManagerRef,
onClearData,
clearConsole = () => {
if (typeof console.clear === 'function') {
console.clear();
}
}
}) {
if (!isSecureBitDebugEnabled(targetWindow)) {
return () => {};
}
targetWindow.forceCleanup = () => {
onClearData();
if (webrtcManagerRef.current) {
webrtcManagerRef.current.disconnect();
}
};
targetWindow.clearLogs = clearConsole;
targetWindow.webrtcManagerRef = webrtcManagerRef;
return () => {
delete targetWindow.forceCleanup;
delete targetWindow.clearLogs;
delete targetWindow.webrtcManagerRef;
};
}
export { installDebugWindowHooks, isSecureBitDebugEnabled };
+75
View File
@@ -0,0 +1,75 @@
import assert from 'node:assert/strict';
const { installDebugWindowHooks, isSecureBitDebugEnabled } = await import('../src/utils/debugWindowHooks.js');
// Production mode does not expose debug/control globals.
{
const targetWindow = {};
const managerRef = { current: { disconnect() {} } };
const cleanup = installDebugWindowHooks({
targetWindow,
webrtcManagerRef: managerRef,
onClearData() {}
});
assert.equal(isSecureBitDebugEnabled(targetWindow), false);
assert.equal('forceCleanup' in targetWindow, false);
assert.equal('clearLogs' in targetWindow, false);
assert.equal('webrtcManagerRef' in targetWindow, false);
cleanup();
}
// Debug mode exposes hooks only when explicitly requested.
{
let clearDataCalls = 0;
let disconnectCalls = 0;
let clearLogCalls = 0;
const targetWindow = { SECUREBIT_DEBUG: true };
const managerRef = {
current: {
disconnect() {
disconnectCalls += 1;
}
}
};
const cleanup = installDebugWindowHooks({
targetWindow,
webrtcManagerRef: managerRef,
onClearData() {
clearDataCalls += 1;
},
clearConsole() {
clearLogCalls += 1;
}
});
assert.equal(isSecureBitDebugEnabled(targetWindow), true);
assert.equal(targetWindow.webrtcManagerRef, managerRef);
targetWindow.forceCleanup();
targetWindow.clearLogs();
assert.equal(clearDataCalls, 1);
assert.equal(disconnectCalls, 1);
assert.equal(clearLogCalls, 1);
cleanup();
assert.equal('forceCleanup' in targetWindow, false);
assert.equal('clearLogs' in targetWindow, false);
assert.equal('webrtcManagerRef' in targetWindow, false);
}
// Normal cleanup remains available through the app-owned callback path.
{
let clearDataCalls = 0;
const onClearData = () => {
clearDataCalls += 1;
};
installDebugWindowHooks({
targetWindow: {},
webrtcManagerRef: { current: null },
onClearData
});
onClearData();
assert.equal(clearDataCalls, 1);
}
console.log('Debug window hook tests passed');