element-web/src/MatrixClientPeg.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

485 lines
19 KiB
TypeScript
Raw Normal View History

/*
2016-01-07 04:06:39 +00:00
Copyright 2015, 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd.
2019-12-05 15:20:30 +00:00
Copyright 2017, 2018, 2019 New Vector Ltd
Copyright 2019 - 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {
EventTimeline,
EventTimelineSet,
ICreateClientOpts,
IStartClientOpts,
MatrixClient,
MemoryStore,
PendingEventOrdering,
RoomNameState,
RoomNameType,
TokenRefreshFunction,
} from "matrix-js-sdk/src/matrix";
import { VerificationMethod } from "matrix-js-sdk/src/types";
import * as utils from "matrix-js-sdk/src/utils";
import { logger } from "matrix-js-sdk/src/logger";
import createMatrixClient from "./utils/createMatrixClient";
import SettingsStore from "./settings/SettingsStore";
import MatrixActionCreators from "./actions/MatrixActionCreators";
import Modal from "./Modal";
import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientBackedSettingsHandler";
import * as StorageManager from "./utils/StorageManager";
import IdentityAuthClient from "./IdentityAuthClient";
import { crossSigningCallbacks, tryToUnlockSecretStorageWithDehydrationKey } from "./SecurityManager";
Replace `SecurityCustomisations` with `CryptoSetupExtension` (#12342) * Changed call sites from customisations/security to ModuleRunner.extensions * Updated depenndecy and added tests * Fixed style and formatting with prettier * Fix according to Element PR comments * Fixing issues raised in PR review * Removed commented code. Improved encapsulation. Removed noisy logging * Improved language of comment about calling the factory * Refactor to get better encapsulation * Find a better name. Provide explicit reset function. Provide more TSDoc * Simplify mock for cryptoSetup, and add assertion for exception message. * Remove unused className property. Adjust TSDoc comments * Fix linting and code style issues * Added test to ensure we canregister anduse experimental extensions * Fix linting and code-style issues * Added test to ensure only on registration of experimental extensions * Added test toensure call to getDehydratedDeviceCallback() * Test what happens when there is no implementation * Iterating cryptoSetup tests * Lint/prettier fix * Assert both branches when checking for dehydrationkey callback * Update src/modules/ModuleRunner.ts Language and formatting Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/modules/ModuleRunner.ts Reset by setting a fresh ExtensionsManager Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/modules/ModuleRunner.ts Use regular comment instead of TSDoc style comment Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update test/MatrixClientPeg-test.ts No need to extend the base class Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/modules/ModuleRunner.ts Fix spelling Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/modules/ModuleRunner.ts Fix spelling Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/modules/ModuleRunner.ts Fix TSDoc formatting Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Simplify mock setup * Simplified mock and cleaned up a bit * Keeping track of extensions is an implementation detail internal to ExtensionsManager. Language and punctuation * Addressed issues and comments from PR review * Update src/modules/ModuleRunner.ts Keep the flags to track implementations as direct properties Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Fix flattening of implementation map * Update src/modules/ModuleRunner.ts Fix whitespace Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --------- Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-04-12 15:15:17 +00:00
import { ModuleRunner } from "./modules/ModuleRunner";
Implement MSC3575: Sliding Sync (#8328) * Add labs flag for sliding sync; add sliding_sync_proxy_url to config.json * Disable the labs toggle if sliding_sync_proxy_url is not set * Do validation checks on the sliding sync proxy URL before enabling it in Labs * Enable sliding sync and add SlidingSyncManager * Get room subscriptions working * Hijack renderSublists in sliding sync mode * Add support for sorting alphabetically/recency and room name filters * Filter out tombstoned rooms; start adding show more logic list ranges update but the UI doesn't * update the UI when the list is updated * bugfix: make sure the list sorts numerically * Get invites transitioning correctly * Force enable sliding sync and labs for now * Linting * Disable spotlight search * Initial cypress plugins for Sliding Sync Proxy * Use --rm when running Synapse in Docker for Cypress tests * Update src/MatrixClientPeg.ts Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/components/views/rooms/RoomSublist.tsx Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/settings/controllers/SlidingSyncController.ts Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/components/views/rooms/RoomSublist.tsx Co-authored-by: Travis Ralston <travisr@matrix.org> * WIP add room searching to spotlight search * Only read sliding sync results when there is a result, else use the local cache * Use feature_sliding_sync not slidingSync * Some review comments * More review comments * Use RoomViewStore to set room subscriptions * Comment why any * Update src/components/views/rooms/RoomSublist.tsx Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> * Fix cypress docker abstraction * Iterate sliding sync proxy support * Stash mostly functional test * Update sliding sync proxy image * i18n * Add support for spaces; use list ID -> index mappings - Mappings are more reusable and easier to understand than racing for index positions. - Register for all spaces immediately on startup. * When the active space is updated, update the list registration * Set spaces filter in the correct place * Skeleton placeholder whilst loading the space * Filter out spaces from the room list * Use the new txn_id promises * Ensure we actually resolve list registrations * Fix matrix-org/sliding-sync#30: don't show tombstoned search results * Remove unused imports * Add SYNCV3_SECRET to proxy to ensure it starts up; correct aliases for SS test * Add another basic sliding sync e2e test * Unbreak netlify * Add more logging for debugging duplicate rooms * If sliding sync is enabled, always use the rooms result even if it's empty * Drop-in copy of RoomListStore for sliding sync * Remove conditionals from RoomListStore - we have SlidingRoomListStore now * WIP SlidingRoomListStore * Add most sliding sync logic to SlidingRoomListStore Still lots of logic in RoomSublist. Broken things: - Join count is wrong completely. - No skeleton placeholder when switching spaces. * Migrate joined count to SS RLS * Reinstate the skeleton UI when the list is loading * linting * Add support for sticky rooms based on the currently active room * Add a bunch of passing SS E2E tests; some WIP * Unbreak build from git merge * Suppress unread indicators in sliding sync mode * Add regression test for https://github.com/matrix-org/sliding-sync/issues/28 * Add invite test flows; show the invite list The refactor to SS RLS removed the invite list entirely. * Remove show more click as it wasn't the bug * Linting and i18n * only enable SS by default on netlify * Jest fixes; merge conflict fixes; remove debug logging; use right sort enum values * Actually fix jest tests * Add support for favourites and low priority * Bump sliding sync version * Update sliding sync labs to be user configurable * delint * To disable SS or change proxy URL the user has to log out * Review comments * Linting * Apply suggestions from code review Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/stores/room-list/SlidingRoomListStore.ts Co-authored-by: Travis Ralston <travisr@matrix.org> * Review comments * Add issue link for TODO markers * Linting * Apply suggestions from code review Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> * More review comments * More review comments * stricter types Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: Travis Ralston <travisr@matrix.org>
2022-09-07 15:42:39 +00:00
import { SlidingSyncManager } from "./SlidingSyncManager";
import CryptoStoreTooNewDialog from "./components/views/dialogs/CryptoStoreTooNewDialog";
import { _t, UserFriendlyError } from "./languageHandler";
import { SettingLevel } from "./settings/SettingLevel";
import MatrixClientBackedController from "./settings/controllers/MatrixClientBackedController";
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
import PlatformPeg from "./PlatformPeg";
import { formatList } from "./utils/FormattingUtils";
Added meaning full error message based on platform (#12074) * fix: fixed 'Database unexpectedly closed' is a bad error message (#25948) * Added deviceType condition check for web and desktop * Added Error description for web and desktop * Changed 'error_database_closed_title' Title to '%(brand)s stopped working' Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(platform): replace UA parsing with Platform for platform detection Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(platform-test): added getHumanReadableName function in testcase Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(platform): added %brand argument for description Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor by linter Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(linter): used prettier for linter * Enable `A thread with a redacted unread is still read after restart` (#12083) * [create-pull-request] automated change (#12085) Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> * Allow element-web hash to be specified when calling playwright tests workflow (#12087) * add link to issue for disabled test * [create-pull-request] automated change (#12093) Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> * Add tests about room list order (#12088) --------- Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> Co-authored-by: Florian Duros <florianduros@element.io> Co-authored-by: ElementRobot <releases@riot.im> Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: Richard van der Hoff <richard@matrix.org>
2024-01-02 11:48:12 +00:00
import SdkConfig from "./SdkConfig";
import { Features } from "./settings/Settings";
import { PhasedRolloutFeature } from "./utils/PhasedRolloutFeature";
export interface IMatrixClientCreds {
2020-06-18 13:32:43 +00:00
homeserverUrl: string;
identityServerUrl?: string;
2020-06-18 13:32:43 +00:00
userId: string;
2020-10-07 11:14:36 +00:00
deviceId?: string;
accessToken: string;
refreshToken?: string;
2020-10-06 11:42:28 +00:00
guest?: boolean;
2020-06-18 13:32:43 +00:00
pickleKey?: string;
2020-09-30 04:52:47 +00:00
freshLogin?: boolean;
}
/**
* Holds the current instance of the `MatrixClient` to use across the codebase.
* Looking for an `MatrixClient`? Just look for the `MatrixClientPeg` on the peg
* board. "Peg" is the literal meaning of something you hang something on. So
* you'll find a `MatrixClient` hanging on the `MatrixClientPeg`.
*/
export interface IMatrixClientPeg {
2021-07-10 14:43:46 +00:00
opts: IStartClientOpts;
/**
* Return the server name of the user's homeserver
* Throws an error if unable to deduce the homeserver name
* (eg. if the user is not logged in)
*
* @returns {string} The homeserver name, if present.
*/
getHomeserverName(): string;
get(): MatrixClient | null;
safeGet(): MatrixClient;
unset(): void;
assign(): Promise<any>;
start(): Promise<any>;
/**
* If we've registered a user ID we set this to the ID of the
* user we've just registered. If they then go & log in, we
* can send them to the welcome user (obviously this doesn't
* guarantee they'll get a chat with the welcome user).
*
* @param {string} uid The user ID of the user we've just registered
*/
setJustRegisteredUserId(uid: string | null): void;
/**
* Returns true if the current user has just been registered by this
* client as determined by setJustRegisteredUserId()
*
* @returns {bool} True if user has just been registered
*/
currentUserIsJustRegistered(): boolean;
2020-11-02 17:25:48 +00:00
/**
* If the current user has been registered by this device then this
* returns a boolean of whether it was within the last N hours given.
*/
userRegisteredWithinLastHours(hours: number): boolean;
/**
* If the current user has been registered by this device then this
* returns a boolean of whether it was after a given timestamp.
*/
userRegisteredAfter(date: Date): boolean;
/**
* Replace this MatrixClientPeg's client with a client instance that has
* homeserver / identity server URLs and active credentials
*
* @param {IMatrixClientCreds} creds The new credentials to use.
* @param {TokenRefreshFunction} tokenRefreshFunction OPTIONAL function used by MatrixClient to attempt token refresh
* see {@link ICreateClientOpts.tokenRefreshFunction}
*/
replaceUsingCreds(creds: IMatrixClientCreds, tokenRefreshFunction?: TokenRefreshFunction): void;
}
/**
* Wrapper object for handling the js-sdk Matrix Client object in the react-sdk
* Handles the creation/initialisation of client objects.
* This module provides a singleton instance of this class so the 'current'
* Matrix Client object is available easily.
*/
class MatrixClientPegClass implements IMatrixClientPeg {
// These are the default options used when when the
// client is started in 'start'. These can be altered
// at any time up to after the 'will_start_client'
// event is finished processing.
2021-07-10 14:43:46 +00:00
public opts: IStartClientOpts = {
initialSyncLimit: 20,
};
private matrixClient: MatrixClient | null = null;
private justRegisteredUserId: string | null = null;
public get(): MatrixClient | null {
return this.matrixClient;
}
public safeGet(): MatrixClient {
if (!this.matrixClient) {
throw new UserFriendlyError("error_user_not_logged_in");
}
return this.matrixClient;
}
public unset(): void {
this.matrixClient = null;
MatrixActionCreators.stop();
}
2015-09-16 12:48:24 +00:00
public setJustRegisteredUserId(uid: string | null): void {
this.justRegisteredUserId = uid;
2020-11-02 17:25:48 +00:00
if (uid) {
const registrationTime = Date.now().toString();
window.localStorage.setItem("mx_registration_time", registrationTime);
2020-11-02 17:25:48 +00:00
}
}
public currentUserIsJustRegistered(): boolean {
return !!this.matrixClient && this.matrixClient.credentials.userId === this.justRegisteredUserId;
}
2020-11-02 17:25:48 +00:00
public userRegisteredWithinLastHours(hours: number): boolean {
if (hours <= 0) {
return false;
}
2020-11-02 17:25:48 +00:00
try {
const registrationTime = parseInt(window.localStorage.getItem("mx_registration_time")!, 10);
const diff = Date.now() - registrationTime;
return diff / 36e5 <= hours;
2020-11-02 17:25:48 +00:00
} catch (e) {
return false;
}
}
public userRegisteredAfter(timestamp: Date): boolean {
try {
const registrationTime = parseInt(window.localStorage.getItem("mx_registration_time")!, 10);
return timestamp.getTime() <= registrationTime;
} catch (e) {
return false;
}
}
public replaceUsingCreds(creds: IMatrixClientCreds, tokenRefreshFunction?: TokenRefreshFunction): void {
this.createClient(creds, tokenRefreshFunction);
}
private onUnexpectedStoreClose = async (): Promise<void> => {
if (!this.matrixClient) return;
this.matrixClient.stopClient(); // stop the client as the database has failed
this.matrixClient.store.destroy();
if (!this.matrixClient.isGuest()) {
// If the user is not a guest then prompt them to reload rather than doing it for them
// For guests this is likely to happen during e-mail verification as part of registration
Added meaning full error message based on platform (#12074) * fix: fixed 'Database unexpectedly closed' is a bad error message (#25948) * Added deviceType condition check for web and desktop * Added Error description for web and desktop * Changed 'error_database_closed_title' Title to '%(brand)s stopped working' Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(platform): replace UA parsing with Platform for platform detection Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(platform-test): added getHumanReadableName function in testcase Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(platform): added %brand argument for description Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor by linter Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(linter): used prettier for linter * Enable `A thread with a redacted unread is still read after restart` (#12083) * [create-pull-request] automated change (#12085) Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> * Allow element-web hash to be specified when calling playwright tests workflow (#12087) * add link to issue for disabled test * [create-pull-request] automated change (#12093) Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> * Add tests about room list order (#12088) --------- Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> Co-authored-by: Florian Duros <florianduros@element.io> Co-authored-by: ElementRobot <releases@riot.im> Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: Richard van der Hoff <richard@matrix.org>
2024-01-02 11:48:12 +00:00
const brand = SdkConfig.get().brand;
const platform = PlatformPeg.get()?.getHumanReadableName();
// Determine the description based on the platform
const description =
platform === "Web Platform"
? _t("error_database_closed_description|for_web", { brand })
: _t("error_database_closed_description|for_desktop");
const [reload] = await Modal.createDialog(ErrorDialog, {
title: _t("error_database_closed_title", { brand }),
description,
button: _t("action|reload"),
Added meaning full error message based on platform (#12074) * fix: fixed 'Database unexpectedly closed' is a bad error message (#25948) * Added deviceType condition check for web and desktop * Added Error description for web and desktop * Changed 'error_database_closed_title' Title to '%(brand)s stopped working' Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(platform): replace UA parsing with Platform for platform detection Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(platform-test): added getHumanReadableName function in testcase Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(platform): added %brand argument for description Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor by linter Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> * refactor(linter): used prettier for linter * Enable `A thread with a redacted unread is still read after restart` (#12083) * [create-pull-request] automated change (#12085) Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> * Allow element-web hash to be specified when calling playwright tests workflow (#12087) * add link to issue for disabled test * [create-pull-request] automated change (#12093) Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> * Add tests about room list order (#12088) --------- Signed-off-by: Pankaj Singh <pankajsingh132000@gmail.com> Co-authored-by: Florian Duros <florianduros@element.io> Co-authored-by: ElementRobot <releases@riot.im> Co-authored-by: github-merge-queue <github-merge-queue@users.noreply.github.com> Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: Richard van der Hoff <richard@matrix.org>
2024-01-02 11:48:12 +00:00
}).finished;
if (!reload) return;
}
PlatformPeg.get()?.reload();
};
public async assign(): Promise<any> {
if (!this.matrixClient) {
throw new Error("createClient must be called first");
}
for (const dbType of ["indexeddb", "memory"]) {
try {
const promise = this.matrixClient.store.startup();
logger.log("MatrixClientPeg: waiting for MatrixClient store to initialise");
await promise;
break;
} catch (err) {
if (dbType === "indexeddb") {
logger.error("Error starting matrixclient store - falling back to memory store", err);
this.matrixClient.store = new MemoryStore({
localStorage: localStorage,
});
} else {
logger.error("Failed to start memory store!", err);
throw err;
}
}
}
this.matrixClient.store.on?.("closed", this.onUnexpectedStoreClose);
// try to initialise e2e on the new client
if (!SettingsStore.getValue("lowBandwidth")) {
await this.initClientCrypto();
}
const opts = utils.deepCopy(this.opts);
2016-08-03 16:23:09 +00:00
// the react sdk doesn't work without this, so don't allow
2021-07-10 14:43:46 +00:00
opts.pendingEventOrdering = PendingEventOrdering.Detached;
2019-02-07 18:24:07 +00:00
opts.lazyLoadMembers = true;
opts.clientWellKnownPollPeriod = 2 * 60 * 60; // 2 hours
opts.threadSupport = true;
Implement MSC3575: Sliding Sync (#8328) * Add labs flag for sliding sync; add sliding_sync_proxy_url to config.json * Disable the labs toggle if sliding_sync_proxy_url is not set * Do validation checks on the sliding sync proxy URL before enabling it in Labs * Enable sliding sync and add SlidingSyncManager * Get room subscriptions working * Hijack renderSublists in sliding sync mode * Add support for sorting alphabetically/recency and room name filters * Filter out tombstoned rooms; start adding show more logic list ranges update but the UI doesn't * update the UI when the list is updated * bugfix: make sure the list sorts numerically * Get invites transitioning correctly * Force enable sliding sync and labs for now * Linting * Disable spotlight search * Initial cypress plugins for Sliding Sync Proxy * Use --rm when running Synapse in Docker for Cypress tests * Update src/MatrixClientPeg.ts Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/components/views/rooms/RoomSublist.tsx Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/settings/controllers/SlidingSyncController.ts Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/components/views/rooms/RoomSublist.tsx Co-authored-by: Travis Ralston <travisr@matrix.org> * WIP add room searching to spotlight search * Only read sliding sync results when there is a result, else use the local cache * Use feature_sliding_sync not slidingSync * Some review comments * More review comments * Use RoomViewStore to set room subscriptions * Comment why any * Update src/components/views/rooms/RoomSublist.tsx Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> * Fix cypress docker abstraction * Iterate sliding sync proxy support * Stash mostly functional test * Update sliding sync proxy image * i18n * Add support for spaces; use list ID -> index mappings - Mappings are more reusable and easier to understand than racing for index positions. - Register for all spaces immediately on startup. * When the active space is updated, update the list registration * Set spaces filter in the correct place * Skeleton placeholder whilst loading the space * Filter out spaces from the room list * Use the new txn_id promises * Ensure we actually resolve list registrations * Fix matrix-org/sliding-sync#30: don't show tombstoned search results * Remove unused imports * Add SYNCV3_SECRET to proxy to ensure it starts up; correct aliases for SS test * Add another basic sliding sync e2e test * Unbreak netlify * Add more logging for debugging duplicate rooms * If sliding sync is enabled, always use the rooms result even if it's empty * Drop-in copy of RoomListStore for sliding sync * Remove conditionals from RoomListStore - we have SlidingRoomListStore now * WIP SlidingRoomListStore * Add most sliding sync logic to SlidingRoomListStore Still lots of logic in RoomSublist. Broken things: - Join count is wrong completely. - No skeleton placeholder when switching spaces. * Migrate joined count to SS RLS * Reinstate the skeleton UI when the list is loading * linting * Add support for sticky rooms based on the currently active room * Add a bunch of passing SS E2E tests; some WIP * Unbreak build from git merge * Suppress unread indicators in sliding sync mode * Add regression test for https://github.com/matrix-org/sliding-sync/issues/28 * Add invite test flows; show the invite list The refactor to SS RLS removed the invite list entirely. * Remove show more click as it wasn't the bug * Linting and i18n * only enable SS by default on netlify * Jest fixes; merge conflict fixes; remove debug logging; use right sort enum values * Actually fix jest tests * Add support for favourites and low priority * Bump sliding sync version * Update sliding sync labs to be user configurable * delint * To disable SS or change proxy URL the user has to log out * Review comments * Linting * Apply suggestions from code review Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/stores/room-list/SlidingRoomListStore.ts Co-authored-by: Travis Ralston <travisr@matrix.org> * Review comments * Add issue link for TODO markers * Linting * Apply suggestions from code review Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> * More review comments * More review comments * stricter types Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: Travis Ralston <travisr@matrix.org>
2022-09-07 15:42:39 +00:00
if (SettingsStore.getValue("feature_sliding_sync")) {
MSC3575 (Sliding Sync) add well-known proxy support (#12307) * Initial commit Signed-off-by: Ed Geraghty <ed@geraghty.family> * Remove commented code Signed-off-by: Ed Geraghty <ed@geraghty.family> * Change function to reflect it's proxy not native support Signed-off-by: Ed Geraghty <ed@geraghty.family> * Re-add check for servers with native support Signed-off-by: Ed Geraghty <ed@geraghty.family> * Add native support check back in Signed-off-by: Ed Geraghty <ed@geraghty.family> * Re-add endpoint health check function Signed-off-by: Ed Geraghty <ed@geraghty.family> * Use inbuilt `getWellKnown` function Signed-off-by: Ed Geraghty <ed@geraghty.family> * Change the error message to the correct function Signed-off-by: Ed Geraghty <ed@geraghty.family> * Stop storing the proxyurl in the settings for now Signed-off-by: Ed Geraghty <ed@geraghty.family> * Make the logger messages more useful Signed-off-by: Ed Geraghty <ed@geraghty.family> * Start moving the checking logic directly into the controller Signed-off-by: Ed Geraghty <ed@geraghty.family> * Add missing import Signed-off-by: Ed Geraghty <ed@geraghty.family> * Get the client rather than passing it in to the functions Signed-off-by: Ed Geraghty <ed@geraghty.family> * remove invalid `function` keyword Signed-off-by: Ed Geraghty <ed@geraghty.family> * Fix imports Signed-off-by: Ed Geraghty <ed@geraghty.family> * Our new functions are private We shouldn't(?) have to use these check in future elsewhere Signed-off-by: Ed Geraghty <ed@geraghty.family> * Change our proxy check function to return a boolean Signed-off-by: Ed Geraghty <ed@geraghty.family> * Make `nativeSlidingSyncSupport` also return boolean, add in health check Signed-off-by: Ed Geraghty <ed@geraghty.family> * Disable the sliding sync option if the server doesn't support Signed-off-by: Ed Geraghty <ed@geraghty.family> * Only enable the setting if it passes (again) Signed-off-by: Ed Geraghty <ed@geraghty.family> * Update our comments to better match what's going on Signed-off-by: Ed Geraghty <ed@geraghty.family> * Remove unused dialog Signed-off-by: Ed Geraghty <ed@geraghty.family> * Add a well-known check on start-up, if sliding sync has been enabled Signed-off-by: Ed Geraghty <ed@geraghty.family> * Check against the correct endpoint... Signed-off-by: Ed Geraghty <ed@geraghty.family> * Extract baseUrl as we'll reuse it Signed-off-by: Ed Geraghty <ed@geraghty.family> * Make the logs differentiate between the types of proxy Signed-off-by: Ed Geraghty <ed@geraghty.family> * Grab the client well-known directly for use Can't use the client object at this point, it hasn't read in the well-known Signed-off-by: Ed Geraghty <ed@geraghty.family> * Add myself to the copyright assignation I wrote the majority of this file... Signed-off-by: Ed Geraghty <ed@geraghty.family> * Only return `true` if it's actually there Signed-off-by: Ed Geraghty <ed@geraghty.family> * Correct the `proxySlidingSyncSupport` function comment to match the code Signed-off-by: Ed Geraghty <ed@geraghty.family> * Correct the `nativeSlidingSyncSupport`function comment to match the code Signed-off-by: Ed Geraghty <ed@geraghty.family> * Another comment/functionality paring Signed-off-by: Ed Geraghty <ed@geraghty.family> * Remove duplicated types from the doc Signed-off-by: Ed Geraghty <ed@geraghty.family> * Move await to the previous line Removes brackets, and corrects `wellKnown` from being a `Promise` Signed-off-by: Ed Geraghty <ed@geraghty.family> * use `waitForClientWellKnown` to avoid a race condition with the request Signed-off-by: Ed Geraghty <ed@geraghty.family> * Move getting the client out of the `if`, use `waitForClientWellKnown` Signed-off-by: Ed Geraghty <ed@geraghty.family> * Remove `beforeChange` override Signed-off-by: Ed Geraghty <ed@geraghty.family> * Move proxy setup logic into `SlidingSyncManager` Signed-off-by: Ed Geraghty <ed@geraghty.family> * Swap `configure` to private, we call it from `setup` which handles proxy Signed-off-by: Ed Geraghty <ed@geraghty.family> * Promises are always `true` TIL. Signed-off-by: Ed Geraghty <ed@geraghty.family> * use `timeoutSignal` Signed-off-by: Ed Geraghty <ed@geraghty.family> * Change message when there's no server support Signed-off-by: Ed Geraghty <ed@geraghty.family> * Refactor `slidingSyncHealthCheck` Signed-off-by: Ed Geraghty <ed@geraghty.family> * Refactor `nativeSlidingSyncSupport` with try/catch Signed-off-by: Ed Geraghty <ed@geraghty.family> * Change comment to hotlink Signed-off-by: Ed Geraghty <ed@geraghty.family> * Try and make the toggle disabled when there's no endpoint Signed-off-by: Ed Geraghty <ed@geraghty.family> * Move the if statement outside the refactored fn to avoid an await Signed-off-by: Ed Geraghty <ed@geraghty.family> * Revert "Swap `configure` to private, we call it from `setup` which handles proxy" This reverts commit c80a00b50c261becc9ad58e08d2a893d572d8426. * Remove unused import Signed-off-by: Ed Geraghty <ed@geraghty.family> * Further refactor `slidingSyncHealthCheck` `proxySlidingSyncSupport` already checks the client well-known is there Signed-off-by: Ed Geraghty <ed@geraghty.family> * Make `proxySlidingSyncSupport` log on success Signed-off-by: Ed Geraghty <ed@geraghty.family> * Clarify log message for proxy being up Signed-off-by: Ed Geraghty <ed@geraghty.family> * Move the logic into SlidingSyncManager All so we can set a static variable because the disabled check isn't asynchronous :) Signed-off-by: Ed Geraghty <ed@geraghty.family> * Obviously this isn't a return so don't overwrite with false! Signed-off-by: Ed Geraghty <ed@geraghty.family> * Remove outdated comment Signed-off-by: Ed Geraghty <ed@geraghty.family> * No need to pass in the client Signed-off-by: Ed Geraghty <ed@geraghty.family> * Activating SS should probably be info level logs Signed-off-by: Ed Geraghty <ed@geraghty.family> * If we've not enabled sliding sync, push the logs down a bit Signed-off-by: Ed Geraghty <ed@geraghty.family> * Update i18n error message Signed-off-by: Ed Geraghty <ed@geraghty.family> * Remove unused i18n strings Signed-off-by: Ed Geraghty <ed@geraghty.family> * Correct log message Signed-off-by: Ed Geraghty <ed@geraghty.family> * Prettier Signed-off-by: Ed Geraghty <ed@geraghty.family> * Remove many of the log messages Signed-off-by: Ed Geraghty <ed@geraghty.family> * Short out of `checkSupport` if it's `true` Signed-off-by: Ed Geraghty <ed@geraghty.family> * Add the endpoint back into the log when we're enabling it Signed-off-by: Ed Geraghty <ed@geraghty.family> * Note in the comment that `feature_sliding_sync_proxy_url` is legacy Signed-off-by: Ed Geraghty <ed@geraghty.family> * Expand the well-known liveness check log Signed-off-by: Ed Geraghty <ed@geraghty.family> * No need to stall the client waiting for sliding sync support * `AutoDiscovery.findClientConfig` throws if the baseUrl is blank * Fix `getProxyFromWellKnown` (?) * Add missing semicolon Sorry, linter! Signed-off-by: Ed Geraghty <ed@geraghty.family> * Pass our `MatrixClient` through instead of trying to grab it Signed-off-by: Ed Geraghty <ed@geraghty.family> * Add missing return in function comment Signed-off-by: Ed Geraghty <ed@geraghty.family> * Actually pass through our Client, not the Peg object Signed-off-by: Ed Geraghty <ed@geraghty.family> * Remove SonarCube smell complaint Signed-off-by: Ed Geraghty <ed@geraghty.family> * Neew to make our other two methods public to test Signed-off-by: Ed Geraghty <ed@geraghty.family> * First passing test Hurrah! Signed-off-by: Ed Geraghty <ed@geraghty.family> * Two more tests, this time on `checkSupport` Signed-off-by: Ed Geraghty <ed@geraghty.family> * Reset our `serverSupportsSlidingSync` between tests Signed-off-by: Ed Geraghty <ed@geraghty.family> * Check the static member is being set Signed-off-by: Ed Geraghty <ed@geraghty.family> * Move the static assignation down to the relevant tests Signed-off-by: Ed Geraghty <ed@geraghty.family> * Pull getProxyFromWellKnown mocking up Signed-off-by: Ed Geraghty <ed@geraghty.family> * Check we /haven't/ shorted out Signed-off-by: Ed Geraghty <ed@geraghty.family> * Move our spy up so we can reuse it Signed-off-by: Ed Geraghty <ed@geraghty.family> * Check spidering is being called Signed-off-by: Ed Geraghty <ed@geraghty.family> * Test the proxy is declared Signed-off-by: Ed Geraghty <ed@geraghty.family> * Test entered manually Signed-off-by: Ed Geraghty <ed@geraghty.family> * Sorry, linter * I guess these strings are wrong? * Replace any with string Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Ed Geraghty <ed@geraghty.family> Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-04-30 18:11:11 +00:00
opts.slidingSync = await SlidingSyncManager.instance.setup(this.matrixClient);
} else {
SlidingSyncManager.instance.checkSupport(this.matrixClient);
Implement MSC3575: Sliding Sync (#8328) * Add labs flag for sliding sync; add sliding_sync_proxy_url to config.json * Disable the labs toggle if sliding_sync_proxy_url is not set * Do validation checks on the sliding sync proxy URL before enabling it in Labs * Enable sliding sync and add SlidingSyncManager * Get room subscriptions working * Hijack renderSublists in sliding sync mode * Add support for sorting alphabetically/recency and room name filters * Filter out tombstoned rooms; start adding show more logic list ranges update but the UI doesn't * update the UI when the list is updated * bugfix: make sure the list sorts numerically * Get invites transitioning correctly * Force enable sliding sync and labs for now * Linting * Disable spotlight search * Initial cypress plugins for Sliding Sync Proxy * Use --rm when running Synapse in Docker for Cypress tests * Update src/MatrixClientPeg.ts Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/components/views/rooms/RoomSublist.tsx Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/settings/controllers/SlidingSyncController.ts Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/components/views/rooms/RoomSublist.tsx Co-authored-by: Travis Ralston <travisr@matrix.org> * WIP add room searching to spotlight search * Only read sliding sync results when there is a result, else use the local cache * Use feature_sliding_sync not slidingSync * Some review comments * More review comments * Use RoomViewStore to set room subscriptions * Comment why any * Update src/components/views/rooms/RoomSublist.tsx Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> * Fix cypress docker abstraction * Iterate sliding sync proxy support * Stash mostly functional test * Update sliding sync proxy image * i18n * Add support for spaces; use list ID -> index mappings - Mappings are more reusable and easier to understand than racing for index positions. - Register for all spaces immediately on startup. * When the active space is updated, update the list registration * Set spaces filter in the correct place * Skeleton placeholder whilst loading the space * Filter out spaces from the room list * Use the new txn_id promises * Ensure we actually resolve list registrations * Fix matrix-org/sliding-sync#30: don't show tombstoned search results * Remove unused imports * Add SYNCV3_SECRET to proxy to ensure it starts up; correct aliases for SS test * Add another basic sliding sync e2e test * Unbreak netlify * Add more logging for debugging duplicate rooms * If sliding sync is enabled, always use the rooms result even if it's empty * Drop-in copy of RoomListStore for sliding sync * Remove conditionals from RoomListStore - we have SlidingRoomListStore now * WIP SlidingRoomListStore * Add most sliding sync logic to SlidingRoomListStore Still lots of logic in RoomSublist. Broken things: - Join count is wrong completely. - No skeleton placeholder when switching spaces. * Migrate joined count to SS RLS * Reinstate the skeleton UI when the list is loading * linting * Add support for sticky rooms based on the currently active room * Add a bunch of passing SS E2E tests; some WIP * Unbreak build from git merge * Suppress unread indicators in sliding sync mode * Add regression test for https://github.com/matrix-org/sliding-sync/issues/28 * Add invite test flows; show the invite list The refactor to SS RLS removed the invite list entirely. * Remove show more click as it wasn't the bug * Linting and i18n * only enable SS by default on netlify * Jest fixes; merge conflict fixes; remove debug logging; use right sort enum values * Actually fix jest tests * Add support for favourites and low priority * Bump sliding sync version * Update sliding sync labs to be user configurable * delint * To disable SS or change proxy URL the user has to log out * Review comments * Linting * Apply suggestions from code review Co-authored-by: Travis Ralston <travisr@matrix.org> * Update src/stores/room-list/SlidingRoomListStore.ts Co-authored-by: Travis Ralston <travisr@matrix.org> * Review comments * Add issue link for TODO markers * Linting * Apply suggestions from code review Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> * More review comments * More review comments * stricter types Co-authored-by: Michael Telatynski <7t3chguy@gmail.com> Co-authored-by: Travis Ralston <travisr@matrix.org>
2022-09-07 15:42:39 +00:00
}
// Connect the matrix client to the dispatcher and setting handlers
MatrixActionCreators.start(this.matrixClient);
MatrixClientBackedSettingsHandler.matrixClient = this.matrixClient;
MatrixClientBackedController.matrixClient = this.matrixClient;
return opts;
}
/**
* Attempt to initialize the crypto layer on a newly-created MatrixClient
*/
private async initClientCrypto(): Promise<void> {
if (!this.matrixClient) {
throw new Error("createClient must be called first");
}
let useRustCrypto = SettingsStore.getValue(Features.RustCrypto);
// We want the value that is set in the config.json for that web instance
const defaultUseRustCrypto = SettingsStore.getValueAt(SettingLevel.CONFIG, Features.RustCrypto);
const migrationPercent = SettingsStore.getValueAt(SettingLevel.CONFIG, "RustCrypto.staged_rollout_percent");
// If the default config is to use rust crypto, and the user is on legacy crypto,
// we want to check if we should migrate the current user.
if (!useRustCrypto && defaultUseRustCrypto && Number.isInteger(migrationPercent)) {
// The user is not on rust crypto, but the default stack is now rust; Let's check if we should migrate
// the current user to rust crypto.
try {
const stagedRollout = new PhasedRolloutFeature("RustCrypto.staged_rollout_percent", migrationPercent);
// Device id should not be null at that point, or init crypto will fail anyhow
const deviceId = this.matrixClient.getDeviceId()!;
// we use deviceId rather than userId because we don't particularly want all devices
// of a user to be migrated at the same time.
useRustCrypto = stagedRollout.isFeatureEnabled(deviceId);
} catch (e) {
logger.warn("Failed to create staged rollout feature for rust crypto migration", e);
}
}
// we want to make sure that the same crypto implementation is used throughout the lifetime of a device,
// so persist the setting at the device layer
// (At some point, we'll allow the user to *enable* the setting via labs, which will migrate their existing
// device to the rust-sdk implementation, but that won't change anything here).
await SettingsStore.setValue(Features.RustCrypto, null, SettingLevel.DEVICE, useRustCrypto);
// Now we can initialise the right crypto impl.
if (useRustCrypto) {
await this.matrixClient.initRustCrypto();
StorageManager.setCryptoInitialised(true);
// TODO: device dehydration and whathaveyou
return;
}
// fall back to the libolm layer.
try {
// check that we have a version of the js-sdk which includes initCrypto
if (this.matrixClient.initCrypto) {
await this.matrixClient.initCrypto();
this.matrixClient.setCryptoTrustCrossSignedDevices(
!SettingsStore.getValue("e2ee.manuallyVerifyAllSessions"),
);
await tryToUnlockSecretStorageWithDehydrationKey(this.matrixClient);
StorageManager.setCryptoInitialised(true);
}
} catch (e) {
if (e instanceof Error && e.name === "InvalidCryptoStoreError") {
// The js-sdk found a crypto DB too new for it to use
Modal.createDialog(CryptoStoreTooNewDialog);
}
// this can happen for a number of reasons, the most likely being
// that the olm library was missing. It's not fatal.
logger.warn("Unable to initialise e2e", e);
}
}
public async start(): Promise<any> {
const opts = await this.assign();
logger.log(`MatrixClientPeg: really starting MatrixClient`);
await this.matrixClient!.startClient(opts);
logger.log(`MatrixClientPeg: MatrixClient started`);
2016-08-03 15:41:22 +00:00
}
public getHomeserverName(): string {
const matches = /^@[^:]+:(.+)$/.exec(this.safeGet().getSafeUserId());
if (matches === null || matches.length < 1) {
2019-02-01 00:52:39 +00:00
throw new Error("Failed to derive homeserver name from user ID!");
}
return matches[1];
}
private namesToRoomName(names: string[], count: number): string | undefined {
const countWithoutMe = count - 1;
if (!names.length) {
return _t("empty_room");
}
if (names.length === 1 && countWithoutMe <= 1) {
return names[0];
}
}
private memberNamesToRoomName(names: string[], count: number): string {
const name = this.namesToRoomName(names, count);
if (name) return name;
if (names.length === 2 && count === 2) {
return formatList(names);
}
return formatList(names, 1);
}
private inviteeNamesToRoomName(names: string[], count: number): string {
const name = this.namesToRoomName(names, count);
if (name) return name;
if (names.length === 2 && count === 2) {
return _t("inviting_user1_and_user2", {
user1: names[0],
user2: names[1],
});
}
return _t("inviting_user_and_n_others", {
user: names[0],
count: count - 1,
});
}
private createClient(creds: IMatrixClientCreds, tokenRefreshFunction?: TokenRefreshFunction): void {
const opts: ICreateClientOpts = {
baseUrl: creds.homeserverUrl,
idBaseUrl: creds.identityServerUrl,
accessToken: creds.accessToken,
refreshToken: creds.refreshToken,
tokenRefreshFunction,
2020-09-30 04:52:47 +00:00
userId: creds.userId,
deviceId: creds.deviceId,
pickleKey: creds.pickleKey,
timelineSupport: true,
2020-07-29 17:03:43 +00:00
forceTURN: !SettingsStore.getValue("webRtcAllowPeerToPeer"),
fallbackICEServerAllowed: !!SettingsStore.getValue("fallbackICEServerAllowed"),
// Gather up to 20 ICE candidates when a call arrives: this should be more than we'd
// ever normally need, so effectively this should make all the gathering happen when
// the call arrives.
iceCandidatePoolSize: 20,
2020-01-29 15:02:52 +00:00
verificationMethods: [
VerificationMethod.Sas,
VerificationMethod.ShowQrCode,
VerificationMethod.Reciprocate,
2020-01-29 15:02:52 +00:00
],
2019-08-23 10:17:51 +00:00
identityServer: new IdentityAuthClient(),
// These are always installed regardless of the labs flag so that cross-signing features
// can toggle on without reloading and also be accessed immediately after login.
cryptoCallbacks: { ...crossSigningCallbacks },
roomNameGenerator: (_: string, state: RoomNameState) => {
switch (state.type) {
case RoomNameType.Generated:
switch (state.subtype) {
case "Inviting":
return this.inviteeNamesToRoomName(state.names, state.count);
default:
return this.memberNamesToRoomName(state.names, state.count);
}
case RoomNameType.EmptyRoom:
if (state.oldName) {
return _t("empty_room_was_name", {
oldName: state.oldName,
});
} else {
return _t("empty_room");
}
default:
return null;
}
},
};
Replace `SecurityCustomisations` with `CryptoSetupExtension` (#12342) * Changed call sites from customisations/security to ModuleRunner.extensions * Updated depenndecy and added tests * Fixed style and formatting with prettier * Fix according to Element PR comments * Fixing issues raised in PR review * Removed commented code. Improved encapsulation. Removed noisy logging * Improved language of comment about calling the factory * Refactor to get better encapsulation * Find a better name. Provide explicit reset function. Provide more TSDoc * Simplify mock for cryptoSetup, and add assertion for exception message. * Remove unused className property. Adjust TSDoc comments * Fix linting and code style issues * Added test to ensure we canregister anduse experimental extensions * Fix linting and code-style issues * Added test to ensure only on registration of experimental extensions * Added test toensure call to getDehydratedDeviceCallback() * Test what happens when there is no implementation * Iterating cryptoSetup tests * Lint/prettier fix * Assert both branches when checking for dehydrationkey callback * Update src/modules/ModuleRunner.ts Language and formatting Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/modules/ModuleRunner.ts Reset by setting a fresh ExtensionsManager Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/modules/ModuleRunner.ts Use regular comment instead of TSDoc style comment Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update test/MatrixClientPeg-test.ts No need to extend the base class Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/modules/ModuleRunner.ts Fix spelling Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/modules/ModuleRunner.ts Fix spelling Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/modules/ModuleRunner.ts Fix TSDoc formatting Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Simplify mock setup * Simplified mock and cleaned up a bit * Keeping track of extensions is an implementation detail internal to ExtensionsManager. Language and punctuation * Addressed issues and comments from PR review * Update src/modules/ModuleRunner.ts Keep the flags to track implementations as direct properties Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Fix flattening of implementation map * Update src/modules/ModuleRunner.ts Fix whitespace Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --------- Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-04-12 15:15:17 +00:00
const dehydrationKeyCallback = ModuleRunner.instance.extensions.cryptoSetup.getDehydrationKeyCallback();
if (dehydrationKeyCallback) {
opts.cryptoCallbacks!.getDehydrationKey = dehydrationKeyCallback;
}
this.matrixClient = createMatrixClient(opts);
this.matrixClient.setGuest(Boolean(creds.guest));
const notifTimelineSet = new EventTimelineSet(undefined, {
timelineSupport: true,
pendingEvents: false,
});
// XXX: what is our initial pagination token?! it somehow needs to be synchronised with /sync.
notifTimelineSet.getLiveTimeline().setPaginationToken("", EventTimeline.BACKWARDS);
this.matrixClient.setNotifTimelineSet(notifTimelineSet);
}
}
/**
* Note: You should be using a React context with access to a client rather than
* using this, as in a multi-account world this will not exist!
*/
2022-02-16 11:19:28 +00:00
export const MatrixClientPeg: IMatrixClientPeg = new MatrixClientPegClass();
if (!window.mxMatrixClientPeg) {
2022-02-16 11:19:28 +00:00
window.mxMatrixClientPeg = MatrixClientPeg;
}