feat(virtual-hosts): add TLS option for HTTPS/443 backends
CI / Build & Test (push) Failing after 2m44s

- Add "Use TLS (secure connection)" checkbox in Add Virtual Host modal
- Persist and restore useTls in state; show TLS badge in table
- When enabled, HTTPS proxy connects to tunnel backend over TLS (SNI =
  hostname) for HTTP and WebSocket; supports services on port 443
This commit is contained in:
Raven Scott
2026-03-03 03:59:53 -05:00
parent 516d387aca
commit 3a13334779
6 changed files with 87 additions and 28 deletions
+9 -3
View File
@@ -54,6 +54,7 @@ function updateConnectionsTable(state) {
tbody.innerHTML = virtualHosts.map(v => {
const hostname = v.hostname || v.id || '';
const hsUrl = v.hsUrl || '';
const useTls = v.useTls === true;
const backend = (v.localHost && v.localPort != null) ? v.localHost + ':' + v.localPort : '—';
const openUrl = `https://${hostname}`;
const safeHostname = hostname.replace(/"/g, '"');
@@ -63,6 +64,7 @@ function updateConnectionsTable(state) {
<td style="width:32px;"><input type="checkbox" class="vhost-row-cb" data-hostname="${safeHostname}"></td>
<td>
<span class="mono-chip">${escapeHtml(hostname)}</span>
${useTls ? '<span class="badge badge-cyan" style="margin-left:6px;font-size:10px;">TLS</span>' : ''}
</td>
<td>
<div style="display:flex;align-items:center;gap:6px;">
@@ -84,7 +86,7 @@ function updateConnectionsTable(state) {
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15,3 21,3 21,9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>
Open
</a>
${needsReconnect ? `<button class="btn btn-secondary btn-sm" data-reconnect-vhost="${safeHostname}" data-hs-url="${escapeHtml(hsUrl)}" title="Reconnect tunnel">
${needsReconnect ? `<button class="btn btn-secondary btn-sm" data-reconnect-vhost="${safeHostname}" data-hs-url="${escapeHtml(hsUrl)}" data-use-tls="${useTls ? '1' : '0'}" title="Reconnect tunnel">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="23,4 23,10 17,10"/><path d="M20.49 15a9 9 0 1 1-.07-8.13"/></svg>
Reconnect
</button>` : ''}
@@ -119,10 +121,11 @@ function updateConnectionsTable(state) {
btn.addEventListener('click', () => {
const hostname = btn.dataset.reconnectVhost;
const hsUrl = btn.dataset.hsUrl;
const useTls = btn.dataset.useTls === '1';
btn.disabled = true;
btn.textContent = 'Reconnecting…';
chrome.runtime.sendMessage(
{ target: 'holesail-native', action: 'send', payload: { type: 'setVirtualHost', payload: { hostname, hsUrl } } },
{ target: 'holesail-native', action: 'send', payload: { type: 'setVirtualHost', payload: { hostname, hsUrl, useTls } } },
(response) => {
if (response?.ok) {
showToast('Tunnel reconnecting…', 'success');
@@ -177,9 +180,11 @@ function setupVirtualHostEvents() {
$('addVhostSubmit')?.addEventListener('click', () => {
const hostnameEl = $('addVhostHostname');
const hsUrlEl = $('addVhostHsUrl');
const useTlsEl = $('addVhostUseTls');
let hostname = (hostnameEl?.value || '').trim();
hostname = hostname.replace(/^https?:\/\//i, '').replace(/[/:?#].*$/, '').toLowerCase().trim();
const hsUrl = (hsUrlEl?.value || '').trim();
const useTls = useTlsEl ? useTlsEl.checked : false;
const hostnameValidation = isValidVhostHostname(hostname);
if (!hostnameValidation.ok) { showModalError('modal-addVhost', 'addVhostError', hostnameValidation.error); return; }
if (!hsUrl || !hsUrl.startsWith('hs://')) { showModalError('modal-addVhost', 'addVhostError', 'Enter a valid hs:// URL'); return; }
@@ -188,12 +193,13 @@ function setupVirtualHostEvents() {
function doAddVhost() {
chrome.runtime.sendMessage(
{ target: 'holesail-native', action: 'send', payload: { type: 'setVirtualHost', payload: { hostname, hsUrl } } },
{ target: 'holesail-native', action: 'send', payload: { type: 'setVirtualHost', payload: { hostname, hsUrl, useTls } } },
(response) => {
if (btn) { btn.disabled = false; btn.textContent = 'Add Host'; }
if (response?.ok) {
if (hostnameEl) hostnameEl.value = '';
if (hsUrlEl) hsUrlEl.value = '';
if (useTlsEl) useTlsEl.checked = false;
closeModal('modal-addVhost');
showToast('Virtual host added', 'success');
refresh();