fix: resolve 35 memory leaks, resource leaks, and bugs across native host and extension
CI / Build & Test (push) Successful in 2m52s
CI / Build & Test (push) Successful in 2m52s
CRITICAL:
- certificate-authority.js: declare `regenerated` variable in installRootCA Windows path to prevent ReferenceError crash
HIGH:
- virtual-hosts.js/service-tunnels.js: call hs.removeAllListeners() in catch blocks to prevent stale listeners on failed Holesail instances
- https-proxy.js: destroy rawSocket in TLS error handler to prevent file descriptor exhaustion
- message-router.js (native): move setEventEmitter() to module-level init instead of re-calling on every message
- ssh-manager.js: add error handler to WS server to prevent unhandled error crashes
- init.js: store setInterval ID and clear on beforeunload to prevent interval accumulation
- logs.js: store and remove chrome.runtime.onMessage listener on beforeunload; add duplicate-call guard
- events.js: move pending++ before async sendMessage call to fix SSH/RDP-only import showing "Nothing to import"
- ssh.js: store resizeTimer on activeSshSession and clear in disconnectSsh; fix auto-reconnect race with _sshConnecting lock
- native-messaging.js: track retry timer IDs in array and cancel all on disconnect
- rdp.js: reuse single offscreen canvas per session instead of allocating per bitmap
MEDIUM:
- virtual-hosts.js/service-tunnels.js: clear existing.reconnectTimer before replacing tunnel entries
- message-router.js (native): destroy pingTunnel socket on error path; clear 15s fallback timer via finally()
- startup.js: wrap setImmediate body in try/finally to always resolve proxiesReadyPromise
- https-proxy.js: fix pre-connect upstream error handler to avoid writing raw HTTP into piped TLS stream; move HOP_BY_HOP to module-level constant
- connect-proxy.js: destroy upstreamSocket on clientSocket close; track and destroy active sockets in stop()
- ssh-manager.js: call cancelPasswordWatch on WS disconnect during password collection
- rdp-manager.js: remove dead remotePort variable; add error handlers to both WS servers
- backup-manager.js: log cleanupStaging errors and non-zero exit codes
- rdp.js: null out ws callbacks before closing in disconnectRdp; disconnect MutationObserver on beforeunload
- proxy-ca.js: prune stale entries from validationResults Map in renderValidatorTable
- refresh.js: deduplicate in-flight pings per port via Set
- messaging.js: read chrome.runtime.lastError in sendToNative callback
- servers.js (dashboard): add null check for $('serverEditId') element
LOW:
- port-allocator.js: add dedup check before pushing to tunnelPortFreeList
- servers.js (native): add error listener to server-mode Holesail instances
- virtual-hosts.js: remove dead prevReconnectDelay variable
- tab-lifecycle.js: change swarmRefCount fallback from || 1 to || 0 to prevent premature swarm destroy
- ssh.js/rdp.js: disconnect MutationObservers on beforeunload
This commit is contained in:
@@ -4,6 +4,12 @@
|
||||
let rdpConnections = [];
|
||||
let activeRdpSession = null; // { sessionId, wsPort, type, ws, rfb, conn }
|
||||
|
||||
// Reusable offscreen canvas for bitmap rendering — resized only when dimensions change.
|
||||
let _rdpOffscreen = null;
|
||||
let _rdpOffscreenCtx = null;
|
||||
let _rdpOffscreenW = 0;
|
||||
let _rdpOffscreenH = 0;
|
||||
|
||||
function generateRdpId() {
|
||||
return 'rdp-' + Date.now().toString(36) + '-' + Math.random().toString(36).slice(2, 7);
|
||||
}
|
||||
@@ -341,11 +347,16 @@ function renderRdpBitmap(ctx, bitmap) {
|
||||
return; // unsupported depth
|
||||
}
|
||||
|
||||
const offscreen = document.createElement('canvas');
|
||||
offscreen.width = width;
|
||||
offscreen.height = height;
|
||||
offscreen.getContext('2d').putImageData(imgData, 0, 0);
|
||||
ctx.drawImage(offscreen, destLeft, destTop, drawW, drawH);
|
||||
if (!_rdpOffscreen || _rdpOffscreenW !== width || _rdpOffscreenH !== height) {
|
||||
_rdpOffscreen = document.createElement('canvas');
|
||||
_rdpOffscreen.width = width;
|
||||
_rdpOffscreen.height = height;
|
||||
_rdpOffscreenCtx = _rdpOffscreen.getContext('2d');
|
||||
_rdpOffscreenW = width;
|
||||
_rdpOffscreenH = height;
|
||||
}
|
||||
_rdpOffscreenCtx.putImageData(imgData, 0, 0);
|
||||
ctx.drawImage(_rdpOffscreen, destLeft, destTop, drawW, drawH);
|
||||
}
|
||||
|
||||
async function connectRdp(conn) {
|
||||
@@ -405,7 +416,12 @@ async function disconnectRdp() {
|
||||
activeRdpSession = null;
|
||||
|
||||
if (rfb) { try { rfb.disconnect(); } catch (_) {} }
|
||||
if (ws) { try { ws.close(); } catch (_) {} }
|
||||
if (ws) {
|
||||
ws.onclose = null;
|
||||
ws.onerror = null;
|
||||
ws.onmessage = null;
|
||||
try { ws.close(); } catch (_) {}
|
||||
}
|
||||
|
||||
const container = $('rdpViewerContainer');
|
||||
if (container) container.innerHTML = '';
|
||||
@@ -484,5 +500,6 @@ function setupRdpEvents() {
|
||||
}
|
||||
});
|
||||
observer.observe(viewerModal, { attributes: true, attributeFilter: ['class'] });
|
||||
window.addEventListener('beforeunload', () => observer.disconnect(), { once: true });
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user