From eee3275f0c9ea5341ec06bf6c299932d05fafc8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl?= Date: Tue, 23 Jun 2026 15:09:30 +0200 Subject: [PATCH] feat(desktop): use healthchat:// deep-link scheme instead of element:// Switch the friendly deep-link / legacy SSO callback scheme from element:// to healthchat:// and stop registering element:// entirely. The reverse-DNS OIDC primary scheme (ch.healthchat.desktop://) is unchanged. Also rebrand the round-tripped SSO id param element-desktop-ssoid -> healthchat-desktop-ssoid on both the desktop and web sides. --- apps/desktop/src/protocol.test.ts | 8 ++++---- apps/desktop/src/protocol.ts | 8 ++++---- apps/web/src/BasePlatform.ts | 2 +- apps/web/src/vector/platform/ElectronPlatform.tsx | 4 ++-- .../unit-tests/vector/platform/ElectronPlatform-test.ts | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/apps/desktop/src/protocol.test.ts b/apps/desktop/src/protocol.test.ts index 396a59f065..38ebcd1739 100644 --- a/apps/desktop/src/protocol.test.ts +++ b/apps/desktop/src/protocol.test.ts @@ -47,7 +47,7 @@ describe("ProtocolHandler", () => { expect( handler.getProfileFromDeeplink([ "Element.app", - `element://vector/webapp/?element-desktop-ssoid=${TEST_SESSION_ID}`, + `healthchat://vector/webapp/?healthchat-desktop-ssoid=${TEST_SESSION_ID}`, ]), ).toBe(USER_DATA_DIR); }); @@ -56,7 +56,7 @@ describe("ProtocolHandler", () => { expect( handler.getProfileFromDeeplink([ "Element.app", - `${TEST_PROTOCOL}:/vector/webapp/?no_universal_links=true&code=DEADBEEF&state=foobar:element-desktop-ssoid:${TEST_SESSION_ID}`, + `${TEST_PROTOCOL}:/vector/webapp/?no_universal_links=true&code=DEADBEEF&state=foobar:healthchat-desktop-ssoid:${TEST_SESSION_ID}`, ]), ).toBe(USER_DATA_DIR); }); @@ -65,7 +65,7 @@ describe("ProtocolHandler", () => { expect( handler.getProfileFromDeeplink([ "Element.app", - `${TEST_PROTOCOL}:/vector/webapp/?no_universal_links=true#code=DEADBEEF&state=foobar:element-desktop-ssoid:${TEST_SESSION_ID}`, + `${TEST_PROTOCOL}:/vector/webapp/?no_universal_links=true#code=DEADBEEF&state=foobar:healthchat-desktop-ssoid:${TEST_SESSION_ID}`, ]), ).toBe(USER_DATA_DIR); }); @@ -74,7 +74,7 @@ describe("ProtocolHandler", () => { expect( handler.getProfileFromDeeplink([ "Element.app", - `${TEST_PROTOCOL}:/vector/webapp/?no_universal_links=true#code=DEADBEEF:element-desktop-ssoid:${TEST_SESSION_ID}`, + `${TEST_PROTOCOL}:/vector/webapp/?no_universal_links=true#code=DEADBEEF:healthchat-desktop-ssoid:${TEST_SESSION_ID}`, ]), ).toBeUndefined(); }); diff --git a/apps/desktop/src/protocol.ts b/apps/desktop/src/protocol.ts index ad2558fc2a..a7595b5f9f 100644 --- a/apps/desktop/src/protocol.ts +++ b/apps/desktop/src/protocol.ts @@ -12,8 +12,8 @@ import path from "node:path"; import fs from "node:fs"; import { randomUUID } from "node:crypto"; -const LEGACY_PROTOCOL = "element"; -const SEARCH_PARAM = "element-desktop-ssoid"; +const LEGACY_PROTOCOL = "healthchat"; +const SEARCH_PARAM = "healthchat-desktop-ssoid"; const STORE_FILE_NAME = "sso-sessions.json"; // we getPath userData before electron-main changes it, so this is the default value @@ -130,8 +130,8 @@ export default class ProtocolHandler { const store = this.readStore(); let sessionId = parsedUrl.searchParams.get(SEARCH_PARAM); if (!sessionId) { - // In OIDC, we must shuttle the value in the `state` param rather than `element-desktop-ssoid` - // We encode it as a suffix like `:element-desktop-ssoid:XXYYZZ`. + // In OIDC, we must shuttle the value in the `state` param rather than `healthchat-desktop-ssoid` + // We encode it as a suffix like `:healthchat-desktop-ssoid:XXYYZZ`. // The OIDC flow may have used response_mode=fragment or query, so we need to handle both cases. let searchParams = parsedUrl.searchParams; if (parsedUrl.hash.includes("=")) { diff --git a/apps/web/src/BasePlatform.ts b/apps/web/src/BasePlatform.ts index 8f2ee41444..c8a9e64aa6 100644 --- a/apps/web/src/BasePlatform.ts +++ b/apps/web/src/BasePlatform.ts @@ -456,7 +456,7 @@ export default abstract class BasePlatform { /** * Suffix to append to the `state` parameter of OIDC /auth calls. Will be round-tripped to the callback URI. - * Currently only required for ElectronPlatform for passing element-desktop-ssoid. + * Currently only required for ElectronPlatform for passing healthchat-desktop-ssoid. */ public getOidcClientState(): string { return ""; diff --git a/apps/web/src/vector/platform/ElectronPlatform.tsx b/apps/web/src/vector/platform/ElectronPlatform.tsx index 941963602e..2c9c27b2d0 100644 --- a/apps/web/src/vector/platform/ElectronPlatform.tsx +++ b/apps/web/src/vector/platform/ElectronPlatform.tsx @@ -53,7 +53,7 @@ interface SquirrelUpdate { updateURL: string; } -const SSO_ID_KEY = "element-desktop-ssoid"; +const SSO_ID_KEY = "healthchat-desktop-ssoid"; function platformFriendlyName(): string { // used to use window.process but the same info is available here @@ -466,7 +466,7 @@ export default class ElectronPlatform extends BasePlatform { public getSSOCallbackUrl(fragmentAfterLogin?: string): URL { const url = super.getSSOCallbackUrl(fragmentAfterLogin); - url.protocol = "element"; + url.protocol = "healthchat"; url.searchParams.set(SSO_ID_KEY, this.sessionId); return url; } diff --git a/apps/web/test/unit-tests/vector/platform/ElectronPlatform-test.ts b/apps/web/test/unit-tests/vector/platform/ElectronPlatform-test.ts index 882bfa17c0..ad13defd71 100644 --- a/apps/web/test/unit-tests/vector/platform/ElectronPlatform-test.ts +++ b/apps/web/test/unit-tests/vector/platform/ElectronPlatform-test.ts @@ -83,7 +83,7 @@ describe("ElectronPlatform", () => { it("should return oidc client state as expected", async () => { const platform = new ElectronPlatform(); await platform.getConfig(); - expect(platform.getOidcClientState()).toMatchInlineSnapshot(`":element-desktop-ssoid:session-id"`); + expect(platform.getOidcClientState()).toMatchInlineSnapshot(`":healthchat-desktop-ssoid:session-id"`); }); it("dispatches view settings action on preferences event", () => {