Skip to content

Commit f5125ac

Browse files
authored
Support build-time specified protocol scheme for oidc callback (#29814)
* Support build-time specified protocol scheme for oidc callback Signed-off-by: Michael Telatynski <[email protected]> * Iterate Signed-off-by: Michael Telatynski <[email protected]> * Iterate Signed-off-by: Michael Telatynski <[email protected]> * Iterate Signed-off-by: Michael Telatynski <[email protected]> * Add tests Signed-off-by: Michael Telatynski <[email protected]> --------- Signed-off-by: Michael Telatynski <[email protected]>
1 parent bd14241 commit f5125ac

File tree

3 files changed

+40
-10
lines changed

3 files changed

+40
-10
lines changed

src/@types/global.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,11 @@ declare global {
130130
interface Electron {
131131
on(channel: ElectronChannel, listener: (event: Event, ...args: any[]) => void): void;
132132
send(channel: ElectronChannel, ...args: any[]): void;
133+
initialise(): Promise<{
134+
protocol: string;
135+
sessionId: string;
136+
config: IConfigOptions;
137+
}>;
133138
}
134139

135140
interface DesktopCapturerSource {

src/vector/platform/ElectronPlatform.tsx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ import {
1717
type OidcRegistrationClientMetadata,
1818
} from "matrix-js-sdk/src/matrix";
1919
import React from "react";
20-
import { secureRandomString } from "matrix-js-sdk/src/randomstring";
2120
import { logger } from "matrix-js-sdk/src/logger";
2221

2322
import BasePlatform, { UpdateCheckStatus, type UpdateStatus } from "../../BasePlatform";
@@ -97,8 +96,10 @@ function getUpdateCheckStatus(status: boolean | string): UpdateStatus {
9796
export default class ElectronPlatform extends BasePlatform {
9897
private readonly ipc = new IPCManager("ipcCall", "ipcReply");
9998
private readonly eventIndexManager: BaseEventIndexManager = new SeshatIndexManager();
100-
// this is the opaque token we pass to the HS which when we get it in our callback we can resolve to a profile
101-
private readonly ssoID: string = secureRandomString(32);
99+
private readonly initialised: Promise<void>;
100+
private protocol!: string;
101+
private sessionId!: string;
102+
private config!: IConfigOptions;
102103

103104
public constructor() {
104105
super();
@@ -186,13 +187,21 @@ export default class ElectronPlatform extends BasePlatform {
186187
await this.ipc.call("callDisplayMediaCallback", source ?? { id: "", name: "", thumbnailURL: "" });
187188
});
188189

189-
void this.ipc.call("startSSOFlow", this.ssoID);
190-
191190
BreadcrumbsStore.instance.on(UPDATE_EVENT, this.onBreadcrumbsUpdate);
191+
192+
this.initialised = this.initialise();
193+
}
194+
195+
private async initialise(): Promise<void> {
196+
const { protocol, sessionId, config } = await window.electron!.initialise();
197+
this.protocol = protocol;
198+
this.sessionId = sessionId;
199+
this.config = config;
192200
}
193201

194202
public async getConfig(): Promise<IConfigOptions | undefined> {
195-
return this.ipc.call("getConfig");
203+
await this.initialised;
204+
return this.config;
196205
}
197206

198207
private onBreadcrumbsUpdate = (): void => {
@@ -391,7 +400,7 @@ export default class ElectronPlatform extends BasePlatform {
391400
public getSSOCallbackUrl(fragmentAfterLogin?: string): URL {
392401
const url = super.getSSOCallbackUrl(fragmentAfterLogin);
393402
url.protocol = "element";
394-
url.searchParams.set(SSO_ID_KEY, this.ssoID);
403+
url.searchParams.set(SSO_ID_KEY, this.sessionId);
395404
return url;
396405
}
397406

@@ -469,15 +478,15 @@ export default class ElectronPlatform extends BasePlatform {
469478
}
470479

471480
public getOidcClientState(): string {
472-
return `:${SSO_ID_KEY}:${this.ssoID}`;
481+
return `:${SSO_ID_KEY}:${this.sessionId}`;
473482
}
474483

475484
/**
476485
* The URL to return to after a successful OIDC authentication
477486
*/
478487
public getOidcCallbackUrl(): URL {
479488
const url = super.getOidcCallbackUrl();
480-
url.protocol = "io.element.desktop";
489+
url.protocol = this.protocol;
481490
// Trim the double slash into a single slash to comply with https://datatracker.ietf.org/doc/html/rfc8252#section-7.1
482491
if (url.href.startsWith(`${url.protocol}//`)) {
483492
url.href = url.href.replace("://", ":/");

test/unit-tests/vector/platform/ElectronPlatform-test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ describe("ElectronPlatform", () => {
3131
const mockElectron = {
3232
on: jest.fn(),
3333
send: jest.fn(),
34+
initialise: jest.fn().mockResolvedValue({
35+
protocol: "io.element.desktop",
36+
sessionId: "session-id",
37+
config: { _config: true },
38+
}),
3439
};
3540

3641
const dispatchSpy = jest.spyOn(dispatcher, "dispatch");
@@ -64,6 +69,17 @@ describe("ElectronPlatform", () => {
6469
expect(rageshake.flush).toHaveBeenCalled();
6570
});
6671

72+
it("should load config", async () => {
73+
const platform = new ElectronPlatform();
74+
await expect(platform.getConfig()).resolves.toEqual({ _config: true });
75+
});
76+
77+
it("should return oidc client state as expected", async () => {
78+
const platform = new ElectronPlatform();
79+
await platform.getConfig();
80+
expect(platform.getOidcClientState()).toMatchInlineSnapshot(`":element-desktop-ssoid:session-id"`);
81+
});
82+
6783
it("dispatches view settings action on preferences event", () => {
6884
new ElectronPlatform();
6985
const [event, handler] = getElectronEventHandlerCall("preferences")!;
@@ -287,7 +303,7 @@ describe("ElectronPlatform", () => {
287303
});
288304
});
289305

290-
describe("breacrumbs", () => {
306+
describe("breadcrumbs", () => {
291307
it("should send breadcrumb updates over the IPC", () => {
292308
const spy = jest.spyOn(BreadcrumbsStore.instance, "on");
293309
new ElectronPlatform();

0 commit comments

Comments
 (0)