From cab42985a5a31807f7e0279a84a401fbbbfa3562 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Sun, 10 May 2026 19:29:56 +0800 Subject: [PATCH] Fix old relay pairing URL TLS compat (#896) --- packages/app/src/runtime/host-runtime.test.ts | 44 +++++++++++++++++++ packages/app/src/runtime/host-runtime.ts | 4 +- .../src/shared/connection-offer.test.ts | 4 +- .../server/src/shared/connection-offer.ts | 2 +- 4 files changed, 50 insertions(+), 4 deletions(-) diff --git a/packages/app/src/runtime/host-runtime.test.ts b/packages/app/src/runtime/host-runtime.test.ts index 7246a7ab3..b63d42fe6 100644 --- a/packages/app/src/runtime/host-runtime.test.ts +++ b/packages/app/src/runtime/host-runtime.test.ts @@ -203,6 +203,15 @@ function makeOffer(input?: Partial): ConnectionOffer { }; } +function encodeOfferUrl(payload: unknown): string { + const encoded = Buffer.from(JSON.stringify(payload), "utf8") + .toString("base64") + .replace(/\+/g, "-") + .replace(/\//g, "_") + .replace(/=+$/g, ""); + return `https://app.paseo.sh/#offer=${encoded}`; +} + function makeDeps( latencyByConnectionId: Record, createdClients: FakeDaemonClient[], @@ -1734,6 +1743,41 @@ describe("HostRuntimeStore", () => { store.syncHosts([]); }); + it("uses TLS for old pairing URLs that omit relay TLS on port 443", async () => { + const store = new HostRuntimeStore({ + deps: { + createClient: () => new FakeDaemonClient() as unknown as DaemonClient, + connectToDaemon: async ({ host }) => ({ + client: makeConnectedProbeClient(5) as unknown as DaemonClient, + serverId: host.serverId, + hostname: host.label ?? null, + }), + getClientId: async () => "cid_test_runtime", + }, + }); + const oldPairingUrl = encodeOfferUrl({ + v: 2, + serverId: "srv_offer", + daemonPublicKeyB64: "pk_test_offer", + relay: { endpoint: "relay.paseo.sh:443" }, + }); + + await store.upsertConnectionFromOfferUrl(oldPairingUrl, "old relay"); + + const pairedHost = store.getHosts().find((host) => host.serverId === "srv_offer"); + expect(pairedHost?.connections).toEqual([ + { + id: "relay:wss:relay.paseo.sh:443", + type: "relay", + relayEndpoint: "relay.paseo.sh:443", + useTls: true, + daemonPublicKeyB64: "pk_test_offer", + }, + ]); + + store.syncHosts([]); + }); + it("uses the latest advertised hostname when re-pairing an existing relay host", async () => { const store = new HostRuntimeStore({ deps: { diff --git a/packages/app/src/runtime/host-runtime.ts b/packages/app/src/runtime/host-runtime.ts index 0851d838e..617617cfc 100644 --- a/packages/app/src/runtime/host-runtime.ts +++ b/packages/app/src/runtime/host-runtime.ts @@ -1506,10 +1506,12 @@ export class HostRuntimeStore { } async upsertConnectionFromOffer(offer: ConnectionOffer, label?: string): Promise { + // COMPAT(oldRelayOfferTls): added in v0.1.73, remove after 2026-11-10. + const useTls = offer.relay.useTls ?? shouldUseTlsForDefaultHostedRelay(offer.relay.endpoint); return this.upsertRelayConnection({ serverId: offer.serverId, relayEndpoint: offer.relay.endpoint, - useTls: offer.relay.useTls, + useTls, daemonPublicKeyB64: offer.daemonPublicKeyB64, label, }); diff --git a/packages/server/src/shared/connection-offer.test.ts b/packages/server/src/shared/connection-offer.test.ts index 562b4897b..5930e47ce 100644 --- a/packages/server/src/shared/connection-offer.test.ts +++ b/packages/server/src/shared/connection-offer.test.ts @@ -40,7 +40,7 @@ describe("connection offer", () => { expect(parseConnectionOfferFromUrl(`https://app.paseo.sh/#offer=${encoded}`)).toEqual(offer); }); - it("defaults relay TLS to false when absent", () => { + it("leaves relay TLS unset when absent", () => { expect( ConnectionOfferSchema.parse({ v: 2, @@ -52,7 +52,7 @@ describe("connection offer", () => { v: 2, serverId: "server-123", daemonPublicKeyB64: "pubkey", - relay: { endpoint: "relay.example.com:80", useTls: false }, + relay: { endpoint: "relay.example.com:80" }, }); }); diff --git a/packages/server/src/shared/connection-offer.ts b/packages/server/src/shared/connection-offer.ts index 6ba5e5159..073cf0be0 100644 --- a/packages/server/src/shared/connection-offer.ts +++ b/packages/server/src/shared/connection-offer.ts @@ -12,7 +12,7 @@ export const ConnectionOfferV2Schema = z.object({ daemonPublicKeyB64: z.string().min(1), relay: z.object({ endpoint: z.string().min(1), - useTls: z.boolean().optional().default(false), + useTls: z.boolean().optional(), }), });