From bf32a6351430a1185a9c4bf50a162ab7d6086c84 Mon Sep 17 00:00:00 2001 From: Luis Montes Date: Thu, 5 Feb 2026 19:18:56 -0700 Subject: [PATCH 1/4] feat: add password support to relays Part of #14 - adds optional password protection for relay connections --- lib/socket-relays.js | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/lib/socket-relays.js b/lib/socket-relays.js index a41448a..d5ba0be 100644 --- a/lib/socket-relays.js +++ b/lib/socket-relays.js @@ -27,12 +27,14 @@ export function initRelays(hsyncClient) { whitelist: l.whitelist || '', blacklist: l.blacklist || '', hostName: l.targetHost, + // Note: password is intentionally not exposed in listing + hasPassword: !!l.password, }; }); return retVal; } - function connectSocket(peer, { port, socketId, hostName }) { + function connectSocket(peer, { port, socketId, hostName, password }) { debug('connectSocket', port, socketId, hostName); peer.notifications.oncloseRelaySocket((peer, { socketId }) => { @@ -51,6 +53,17 @@ export function initRelays(hsyncClient) { throw new Error('no relay found for port: ' + port); } + // Check password if relay requires one + if (relay.password) { + if (!password) { + throw new Error('relay requires password'); + } + if (password !== relay.password) { + throw new Error('invalid relay password'); + } + debug('relay password verified for port', port); + } + // TODO: check white and black lists on peer // const relayDataTopic = `msg/${hostName}/${hsyncClient.myHostName}/relayData/${socketId}`; @@ -92,10 +105,10 @@ export function initRelays(hsyncClient) { }); } - function addSocketRelay({ whitelist, blacklist, port, targetPort, targetHost }) { + function addSocketRelay({ whitelist, blacklist, port, targetPort, targetHost, password }) { targetPort = targetPort || port; targetHost = targetHost || 'localhost'; - debug('creating relay', whitelist, blacklist, port, targetPort, targetHost); + debug('creating relay', whitelist, blacklist, port, targetPort, targetHost, password ? '(with password)' : '(no password)'); const newRelay = { whitelist, blacklist, @@ -103,6 +116,7 @@ export function initRelays(hsyncClient) { targetPort, targetHost, hostName: targetHost, + password: password || null, }; cachedRelays['p' + port] = newRelay; return newRelay; From a2e40b39f7346efcb8b5116b90fa7cc70ecfe8e9 Mon Sep 17 00:00:00 2001 From: Luis Montes Date: Thu, 5 Feb 2026 19:18:57 -0700 Subject: [PATCH 2/4] feat: add password support to listeners Part of #14 - pass password when connecting to relays --- lib/socket-listeners.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/socket-listeners.js b/lib/socket-listeners.js index 496faad..0f9ebf2 100644 --- a/lib/socket-listeners.js +++ b/lib/socket-listeners.js @@ -31,7 +31,7 @@ export function initListeners(hsyncClient) { } function addSocketListener(options = {}) { - const { port, targetPort, targetHost } = options; + const { port, targetPort, targetHost, password } = options; if (!targetHost) { throw new Error('no targetHost'); } @@ -43,7 +43,7 @@ export function initListeners(hsyncClient) { if (url.hostname.toLowerCase() === hsyncClient.myHostName.toLowerCase()) { throw new Error('targetHost must be a different host'); } - debug('creating handler', port, cleanHost); + debug('creating handler', port, cleanHost, password ? '(with password)' : ''); if (cleanHost !== targetHost) { debug('targetHost cleaned UP', targetHost, cleanHost); } @@ -134,6 +134,7 @@ export function initListeners(hsyncClient) { socketId: socket.socketId, port: targetPort || port, hostName: rpcPeer.hostName, + password: password || undefined, }); debug('connect result', result); socket.peerConnected = true; @@ -170,6 +171,7 @@ export function initListeners(hsyncClient) { targetHost: cleanHost, targetPort: targetPort || port, port, + hasPassword: !!password, }; socketListeners['p' + port] = listener; From 7f99bcea3f5668f33866fe1e010569aa27b20e17 Mon Sep 17 00:00:00 2001 From: Luis Montes Date: Thu, 5 Feb 2026 19:18:58 -0700 Subject: [PATCH 3/4] feat: wire password options through connection Part of #14 - pass listenerPassword/relayPassword to functions --- connection.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/connection.js b/connection.js index ffef33a..ebf7747 100644 --- a/connection.js +++ b/connection.js @@ -38,6 +38,8 @@ export async function createHsync(config) { relayInboundPort, relayTargetHost, relayTargetPort, + listenerPassword, + relayPassword, } = config; const { dynamicHost } = config; let { hsyncServer, hsyncSecret } = config; @@ -267,7 +269,8 @@ export async function createHsync(config) { lth = lth.substring(0, lth.length - 1); } const ltp = listenerTargetPort ? listenerTargetPort[i] : llp; - hsyncClient.addSocketListener({ port: llp, targetPort: ltp, targetHost: lth }); + const lpwd = listenerPassword ? listenerPassword[i] || listenerPassword[0] : undefined; + hsyncClient.addSocketListener({ port: llp, targetPort: ltp, targetHost: lth, password: lpwd }); debug('relaying local', llp, 'to', lth, ltp); } }); @@ -283,7 +286,8 @@ export async function createHsync(config) { rth = rth.substring(0, rth.length - 1); } const rtp = relayTargetPort ? relayTargetPort[i] : rip; - hsyncClient.addSocketRelay({ port: rip, targetHost: rth, targetPort: rtp }); + const rpwd = relayPassword ? relayPassword[i] || relayPassword[0] : undefined; + hsyncClient.addSocketRelay({ port: rip, targetHost: rth, targetPort: rtp, password: rpwd }); debug('relaying inbound', rip, 'to', rth, rtp); } }); @@ -291,3 +295,4 @@ export async function createHsync(config) { return hsyncClient; } + From 300648d0090329bb52f4e06683fd9f11693e6ed4 Mon Sep 17 00:00:00 2001 From: Luis Montes Date: Thu, 5 Feb 2026 19:18:58 -0700 Subject: [PATCH 4/4] feat: add CLI options for relay/listener passwords Part of #14 - adds --relay-password and --listener-password flags --- cli.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/cli.js b/cli.js index a440043..87caecc 100755 --- a/cli.js +++ b/cli.js @@ -41,6 +41,11 @@ program .addOption( new Option('-T, --listener-target-port ', 'target port for listener').env('HSYNC_LTP') ) + .addOption( + new Option('--listener-password ', 'password for connecting to relay').env( + 'HSYNC_LPWD' + ) + ) .addOption( new Option('-R, --relay-inbound-port ', 'inbound port for remote relay requests').env( 'HSYNC_RIP' @@ -70,6 +75,11 @@ program 'blacklist of domains that should be blocked from this relay' ).env('HSYNC_RBL') ) + .addOption( + new Option('--relay-password ', 'password required to connect to this relay').env( + 'HSYNC_RPWD' + ) + ) .addOption( new Option('-x, --shell', 'shell to localhost and --port for piping data to a listener') ); @@ -94,6 +104,9 @@ if (options.shell) { if (options.listenerTargetPort) { options.listenerTargetPort = options.listenerTargetPort.split(',').map((p) => Number(p)); } + if (options.listenerPassword) { + options.listenerPassword = options.listenerPassword.split(','); + } if (options.relayInboundPort) { options.relayInboundPort = options.relayInboundPort.split(',').map((p) => Number(p)); @@ -104,6 +117,9 @@ if (options.shell) { if (options.relayTargetPort) { options.relayTargetPort = options.relayTargetPort.split(',').map((p) => Number(p)); } + if (options.relayPassword) { + options.relayPassword = options.relayPassword.split(','); + } // console.log('options', options);