Replace the bare-https HTTPS proxy with a bare-tcp server that implements
SNI entirely in JavaScript. A pure-JS TLS ClientHello parser extracts the
SNI hostname from each incoming connection, derives the wildcard parent
domain by stripping the leftmost label, and selects (or generates on demand)
the correct wildcard cert via certificate-authority.getOrCreateWildcardCert().
This fixes ERR_SSL_SERVER_CERT_BAD_FORMAT for custom TLDs and supports
hostnames of any depth (e.g. i.love.hole.sail → cert *.love.hole.sail).
Also fixes ERR_INVALID_CHUNKED_ENCODING by stripping hop-by-hop headers
(Transfer-Encoding, Connection, etc.) from proxied responses — bare-http1
decodes chunked bodies internally so forwarding the header caused Chrome
to misinterpret the already-decoded body bytes.
- https-proxy.js: rewrite using bare-tcp + JS SNI peek + bare-tls per conn
- certificate-authority.js: add getOrCreateWildcardCert(parentDomain)
- host.js: remove refreshProxyCert/getActiveBaseDomains (no longer needed)
- background.js: PAC dnsDomainIs clauses already match any depth correctly
- dashboard.html: update vhost hint text to show deep hostnames are supported
- docs: update ARCHITECTURE, SECURITY, NATIVE-HOST; add VIRTUAL-HOSTS.md
- Replace SNI callback approach (unsupported by bare-tls) with a multi-SAN
wildcard cert covering all active base domains (e.g. *.hole.sail, *.heheh.jungle)
- Add buildMultiSanCert() in https-proxy.js — cert key encodes sorted domain list
so cache invalidates automatically when TLDs are added or removed
- Add restart(baseDomains, callback) to https-proxy.js to stop and restart the
proxy with a fresh cert without requiring a native host restart
- Add getActiveBaseDomains() and refreshProxyCert() in host.js; call after every
successful setVirtualHost and removeVirtualHost
- Fix background.js send handler to fetch updated virtualHosts via getState and
re-apply PAC immediately after setVirtualHost or removeVirtualHost succeeds,
so new TLDs are routed without waiting for the next dashboard refresh
- Remove unused tls require from https-proxy.js
- Remove invalid "permissions" entry from manifest.json permissions array
- Add isValidVhostHostname() to dashboard.js with embedded REAL_TLDS and
REAL_SLD_TLDS blocklists; enforces 3-label minimum (two-tier TLD requirement),
valid label characters, and blocks real public TLDs/SLDs (e.g. .com, co.uk)
- Replace hardcoded .hole.sail validation in vhost submit handler with new validator
- Update Add Virtual Host modal hint text and add inline format explanation
- Update applyPAC() in background.js to accept a tlds array, generating one
dnsDomainIs clause per unique two-label base domain; .hole.sail always included
- Store virtualHosts in extensionState and pass derived TLD list to applyPAC at
every getState response and retryGetStateForConnectProxy call
- Replace single upfront *.hole.sail cert in https-proxy.js with SNICallback that
lazily generates a wildcard cert per two-label base domain on first connection;
baseline *.hole.sail cert still pre-generated at startup
- Add chrome.permissions.request() in background.js send handler to grant host
permissions for new TLDs dynamically after successful setVirtualHost
- Add optional_host_permissions: ["*://*/*"] and "permissions" to manifest.json
to enable runtime host permission grants for custom TLDs
Critical fixes:
- Fix wrong registry key (com.bridgeswarm → com.holesail.browser) in
update-native-manifest-extension-id.ps1 — script was always failing on Windows
- Create missing wrong-domain.html redirect page for .host.test URLs
- Remove options_ui pointing to non-existent options.html from manifest
High-priority bug fixes:
- ssh-manager: track and kill orphaned printf FIFO writer when key auth succeeds
- ssh-manager: fix uncancelled 2000ms fallback password timer (assign to fallbackTimer,
clear in cancelPasswordWatch); fix null-check before removeAllListeners
- ssh-manager: add 30s Promise.race timeout to holesailInst.ready()
- backup-manager: fix macOS cp -R nesting bug by removing destination before copy;
add tar -tzf integrity check after archive creation
- host.js: restoreBackup now stops running tunnels before restore and re-starts them
- holesail-manager: fix stale closure bug in virtual host and service tunnel
error/close handlers (guard with v.holesail === hs check)
- dashboard.js: remove dead setText('dashTabs', ...) call referencing non-existent element
Medium improvements:
- manifest: remove unused storage and scripting permissions; restrict
web_accessible_resources match from <all_urls> to chrome-extension://*/*
- background.js: fix self-referential browser alias (globalThis.browser ?? chrome);
add 30s per-request timeout to send(); clean up dashboardTabs on tab close
- holesail-manager: gate saveStateSync stderr log behind DEBUG flag; updateSettings
now returns requiresRestart:true when proxy port changes; add backupRetention field
- host.js: pass requiresRestart through in updateSettings response
- dashboard.js: remove dead loadSettings() function; add requiresRestart warning toast;
add chrome.runtime.lastError guards in fetchState and refreshBackups;
set dynamic version from chrome.runtime.getManifest()
- dashboard.html: remove stray </button> tag; add id="sidebarVersion" for dynamic version
- install.sh/install.ps1: fetch version from RELEASE_BASE/VERSION instead of hardcoded 1.0.0
- install.ps1: add Firefox .xpi download and Firefox registry key
- update-native-manifest-extension-id.sh: add optional Firefox manifest update
- certificate-authority.js: defer RSA key generation to setImmediate to avoid blocking
startup; expose caReady promise
- host.js: await caReady before starting HTTPS proxy
Documentation:
- REMOTE-DESKTOP.md: correct RDP WebSocket protocol field names to match rdp-manager.js
(destLeft/destTop/destRight/destBottom, mouseMove/mouseButton/keyEvent/keyUnicode)
Feature additions:
- dashboard.js: add Reconnect button for service tunnels in error/closed state
- https-proxy.js: add WebSocket upgrade handler to support ws:// over *.hole.sail
- connect-proxy.js: add 10s header-read timeout to protect against idle connections
- native-host: add bare-fs as explicit dependency