Skip to content
This repository has been archived by the owner on Oct 22, 2024. It is now read-only.

Disable ICE fallback based on well-known configuration #111

Merged
merged 3 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/LegacyCallHandler.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -764,7 +764,6 @@ export default class LegacyCallHandler extends EventEmitter {
cancelButton: _t("action|ok"),
onFinished: (allow) => {
SettingsStore.setValue("fallbackICEServerAllowed", null, SettingLevel.DEVICE, allow);
cli.setFallbackICEServerAllowed(!!allow);
},
},
undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,6 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
this.context.setForceTURN(!p2p);
};

private changeFallbackICEServerAllowed = (allow: boolean): void => {
this.context.setFallbackICEServerAllowed(allow);
};

private renderDeviceOptions(devices: Array<MediaDeviceInfo>, category: MediaDeviceKindEnum): Array<JSX.Element> {
return devices.map((d) => {
return (
Expand Down Expand Up @@ -226,7 +222,7 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
server: new URL(FALLBACK_ICE_SERVER).pathname,
})}
level={SettingLevel.DEVICE}
onChange={this.changeFallbackICEServerAllowed}
hideIfCannotSet
/>
</SettingsSubsection>
</SettingsSection>
Expand Down
2 changes: 2 additions & 0 deletions src/settings/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import ServerSupportUnstableFeatureController from "./controllers/ServerSupportU
import { WatchManager } from "./WatchManager";
import { CustomTheme } from "../theme";
import AnalyticsController from "./controllers/AnalyticsController";
import FallbackIceServerController from "./controllers/FallbackIceServerController";

export const defaultWatchManager = new WatchManager();

Expand Down Expand Up @@ -992,6 +993,7 @@ export const SETTINGS: { [setting: string]: ISetting } = {
description: _td("settings|voip|enable_fallback_ice_server_description"),
// This is a tri-state value, where `null` means "prompt the user".
default: null,
controller: new FallbackIceServerController(),
},
"showImages": {
supportedLevels: LEVELS_ACCOUNT_SETTINGS,
Expand Down
52 changes: 52 additions & 0 deletions src/settings/controllers/FallbackIceServerController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
Copyright 2024 New Vector Ltd.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

import { ClientEvent, IClientWellKnown, MatrixClient } from "matrix-js-sdk/src/matrix";

import { SettingLevel } from "../SettingLevel";
import SettingsStore from "../SettingsStore.ts";
import MatrixClientBackedController from "./MatrixClientBackedController.ts";

/**
* Settings controller for the fallback ICE server setting.
* This setting may be forcibly disabled by well-known value ["io.element.voip"]["disable_fallback_ice"].
* This controller will update the MatrixClient's knowledge when the setting is changed.
*/
export default class FallbackIceServerController extends MatrixClientBackedController {
private disabled = false;

public constructor() {
super();
}

private checkWellKnown = (wellKnown: IClientWellKnown): void => {
this.disabled = !!wellKnown["io.element.voip"]?.["disable_fallback_ice"];
};

protected async initMatrixClient(newClient: MatrixClient, oldClient?: MatrixClient): Promise<void> {
oldClient?.off(ClientEvent.ClientWellKnown, this.checkWellKnown);
newClient.on(ClientEvent.ClientWellKnown, this.checkWellKnown);
const wellKnown = newClient.getClientWellKnown();
if (wellKnown) this.checkWellKnown(wellKnown);
}

public getValueOverride(): any {
if (this.disabled) {
return false;
}

return null; // no override
}

public get settingDisabled(): boolean | string {
return this.disabled;
}

public onChange(_level: SettingLevel, _roomId: string | null, _newValue: any): void {
this.client?.setFallbackICEServerAllowed(!!SettingsStore.getValue("fallbackICEServerAllowed"));
}
}
8 changes: 4 additions & 4 deletions src/settings/controllers/MatrixClientBackedController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,15 @@ import SettingController from "./SettingController";
* This class performs no logic and should be overridden.
*/
export default abstract class MatrixClientBackedController extends SettingController {
private static _matrixClient: MatrixClient;
private static _matrixClient?: MatrixClient;
private static instances: MatrixClientBackedController[] = [];

public static set matrixClient(client: MatrixClient) {
const oldClient = MatrixClientBackedController._matrixClient;
MatrixClientBackedController._matrixClient = client;

for (const instance of MatrixClientBackedController.instances) {
instance.initMatrixClient(oldClient, client);
instance.initMatrixClient(client, oldClient);
}
}

Expand All @@ -36,9 +36,9 @@ export default abstract class MatrixClientBackedController extends SettingContro
MatrixClientBackedController.instances.push(this);
}

public get client(): MatrixClient {
public get client(): MatrixClient | undefined {
return MatrixClientBackedController._matrixClient;
}

protected abstract initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient): void;
protected abstract initMatrixClient(newClient: MatrixClient, oldClient?: MatrixClient): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

import { MatrixClient } from "matrix-js-sdk/src/matrix";

import { SettingLevel } from "../SettingLevel";
import MatrixClientBackedController from "./MatrixClientBackedController";
import { WatchManager } from "../WatchManager";
Expand Down Expand Up @@ -53,9 +51,9 @@ export default class ServerSupportUnstableFeatureController extends MatrixClient
this.watchers.notifyUpdate(this.settingName, null, level, settingValue);
}

protected async initMatrixClient(oldClient: MatrixClient, newClient: MatrixClient): Promise<void> {
protected async initMatrixClient(): Promise<void> {
// Check for stable version support first
if (this.stableVersion && (await this.client.isVersionSupported(this.stableVersion))) {
if (this.stableVersion && (await this.client!.isVersionSupported(this.stableVersion))) {
this.disabled = false;
return;
}
Expand All @@ -66,7 +64,7 @@ export default class ServerSupportUnstableFeatureController extends MatrixClient
for (const featureGroup of this.unstableFeatureGroups) {
const featureSupportList = await Promise.all(
featureGroup.map(async (feature) => {
const isFeatureSupported = await this.client.doesServerSupportUnstableFeature(feature);
const isFeatureSupported = await this.client!.doesServerSupportUnstableFeature(feature);
return isFeatureSupported;
}),
);
Expand Down
57 changes: 57 additions & 0 deletions test/settings/controllers/FallbackIceServerController-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
Copyright 2024 New Vector Ltd.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
Please see LICENSE files in the repository root for full details.
*/

import fetchMockJest from "fetch-mock-jest";
import { ClientEvent, MatrixClient } from "matrix-js-sdk/src/matrix";

import { SettingLevel } from "../../../src/settings/SettingLevel";
import FallbackIceServerController from "../../../src/settings/controllers/FallbackIceServerController.ts";
import MatrixClientBackedController from "../../../src/settings/controllers/MatrixClientBackedController.ts";
import SettingsStore from "../../../src/settings/SettingsStore.ts";

describe("FallbackIceServerController", () => {
beforeEach(() => {
fetchMockJest.get("https://matrix.org/_matrix/client/versions", { versions: ["v1.4"] });
});

afterEach(() => {
jest.restoreAllMocks();
});

it("should update MatrixClient's state when the setting is updated", async () => {
const client = new MatrixClient({
baseUrl: "https://matrix.org",
userId: "@alice:matrix.org",
accessToken: "token",
});
MatrixClientBackedController.matrixClient = client;

expect(client.isFallbackICEServerAllowed()).toBeFalsy();
await SettingsStore.setValue("fallbackICEServerAllowed", null, SettingLevel.DEVICE, true);
expect(client.isFallbackICEServerAllowed()).toBeTruthy();
});

it("should force the setting to be disabled if disable_fallback_ice=true", async () => {
const controller = new FallbackIceServerController();
const client = new MatrixClient({
baseUrl: "https://matrix.org",
userId: "@alice:matrix.org",
accessToken: "token",
});
MatrixClientBackedController.matrixClient = client;
expect(controller.settingDisabled).toBeFalsy();

client["clientWellKnown"] = {
"io.element.voip": {
disable_fallback_ice: true,
},
};
client.emit(ClientEvent.ClientWellKnown, client["clientWellKnown"]);

expect(controller.settingDisabled).toBeTruthy();
});
});
Loading