2015-06-23 15:41:25 +00:00
|
|
|
/*
|
2016-01-07 04:06:39 +00:00
|
|
|
Copyright 2015, 2016 OpenMarket Ltd
|
2017-06-21 13:04:43 +00:00
|
|
|
Copyright 2017 Vector Creations Ltd.
|
2019-12-05 15:20:30 +00:00
|
|
|
Copyright 2017, 2018, 2019 New Vector Ltd
|
2023-02-20 14:46:07 +00:00
|
|
|
Copyright 2019 - 2023 The Matrix.org Foundation C.I.C.
|
2015-06-23 15:41:25 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
|
|
|
|
2022-08-26 10:23:56 +00:00
|
|
|
import { ICreateClientOpts, PendingEventOrdering, RoomNameState, RoomNameType } from "matrix-js-sdk/src/matrix";
|
2021-07-10 14:43:46 +00:00
|
|
|
import { IStartClientOpts, MatrixClient } from "matrix-js-sdk/src/client";
|
2021-06-29 12:11:58 +00:00
|
|
|
import { MemoryStore } from "matrix-js-sdk/src/store/memory";
|
2019-12-20 02:08:43 +00:00
|
|
|
import * as utils from "matrix-js-sdk/src/utils";
|
2021-06-29 12:11:58 +00:00
|
|
|
import { EventTimeline } from "matrix-js-sdk/src/models/event-timeline";
|
|
|
|
import { EventTimelineSet } from "matrix-js-sdk/src/models/event-timeline-set";
|
2021-10-22 22:23:32 +00:00
|
|
|
import { verificationMethods } from "matrix-js-sdk/src/crypto";
|
|
|
|
import { SHOW_QR_CODE_METHOD } from "matrix-js-sdk/src/crypto/verification/QRCode";
|
|
|
|
import { logger } from "matrix-js-sdk/src/logger";
|
|
|
|
|
2017-06-13 11:46:49 +00:00
|
|
|
import createMatrixClient from "./utils/createMatrixClient";
|
2017-11-17 17:48:42 +00:00
|
|
|
import SettingsStore from "./settings/SettingsStore";
|
2017-12-07 17:10:45 +00:00
|
|
|
import MatrixActionCreators from "./actions/MatrixActionCreators";
|
2018-11-16 11:31:46 +00:00
|
|
|
import Modal from "./Modal";
|
2019-02-22 23:33:20 +00:00
|
|
|
import MatrixClientBackedSettingsHandler from "./settings/handlers/MatrixClientBackedSettingsHandler";
|
2019-04-04 10:59:53 +00:00
|
|
|
import * as StorageManager from "./utils/StorageManager";
|
2019-08-22 13:44:09 +00:00
|
|
|
import IdentityAuthClient from "./IdentityAuthClient";
|
2020-10-02 00:23:12 +00:00
|
|
|
import { crossSigningCallbacks, tryToUnlockSecretStorageWithDehydrationKey } from "./SecurityManager";
|
2020-11-04 15:51:45 +00:00
|
|
|
import SecurityCustomisations from "./customisations/Security";
|
2022-09-07 15:42:39 +00:00
|
|
|
import { SlidingSyncManager } from "./SlidingSyncManager";
|
2022-03-02 23:33:40 +00:00
|
|
|
import CryptoStoreTooNewDialog from "./components/views/dialogs/CryptoStoreTooNewDialog";
|
2023-06-05 17:12:23 +00:00
|
|
|
import { _t, UserFriendlyError } from "./languageHandler";
|
2022-12-16 17:10:26 +00:00
|
|
|
import { SettingLevel } from "./settings/SettingLevel";
|
2023-03-03 13:31:51 +00:00
|
|
|
import MatrixClientBackedController from "./settings/controllers/MatrixClientBackedController";
|
2023-03-31 09:08:45 +00:00
|
|
|
import ErrorDialog from "./components/views/dialogs/ErrorDialog";
|
|
|
|
import PlatformPeg from "./PlatformPeg";
|
2015-07-20 12:19:47 +00:00
|
|
|
|
2020-05-25 21:59:15 +00:00
|
|
|
export interface IMatrixClientCreds {
|
2020-06-18 13:32:43 +00:00
|
|
|
homeserverUrl: string;
|
2021-12-02 13:46:44 +00:00
|
|
|
identityServerUrl?: string;
|
2020-06-18 13:32:43 +00:00
|
|
|
userId: string;
|
2020-10-07 11:14:36 +00:00
|
|
|
deviceId?: string;
|
2023-07-04 13:49:27 +00:00
|
|
|
accessToken: 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;
|
2016-08-03 09:46:42 +00:00
|
|
|
}
|
|
|
|
|
2022-05-10 02:34:27 +00:00
|
|
|
/**
|
|
|
|
* 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`.
|
|
|
|
*/
|
2020-05-25 22:06:05 +00:00
|
|
|
export interface IMatrixClientPeg {
|
2021-07-10 14:43:46 +00:00
|
|
|
opts: IStartClientOpts;
|
2017-04-06 10:13:39 +00:00
|
|
|
|
2020-05-25 22:06:05 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2023-06-27 16:39:56 +00:00
|
|
|
getHomeserverName(): string;
|
2015-06-09 16:40:42 +00:00
|
|
|
|
2023-06-21 16:29:44 +00:00
|
|
|
get(): MatrixClient | null;
|
2023-06-05 17:12:23 +00:00
|
|
|
safeGet(): MatrixClient;
|
2020-05-25 22:06:05 +00:00
|
|
|
unset(): void;
|
|
|
|
assign(): Promise<any>;
|
|
|
|
start(): Promise<any>;
|
2017-12-07 17:10:45 +00:00
|
|
|
|
2019-09-18 08:27:43 +00:00
|
|
|
/**
|
2019-06-14 14:31:19 +00:00
|
|
|
* 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
|
2022-04-28 10:46:02 +00:00
|
|
|
* guarantee they'll get a chat with the welcome user).
|
2019-06-14 14:31:19 +00:00
|
|
|
*
|
|
|
|
* @param {string} uid The user ID of the user we've just registered
|
|
|
|
*/
|
2022-04-28 10:46:02 +00:00
|
|
|
setJustRegisteredUserId(uid: string | null): void;
|
2019-06-14 14:31:19 +00:00
|
|
|
|
2019-09-18 08:27:43 +00:00
|
|
|
/**
|
2019-06-14 14:31:19 +00:00
|
|
|
* 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
|
|
|
|
*/
|
2020-05-25 22:06:05 +00:00
|
|
|
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;
|
|
|
|
|
2022-07-29 11:43:29 +00:00
|
|
|
/**
|
|
|
|
* 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;
|
|
|
|
|
2020-05-25 22:06:05 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
replaceUsingCreds(creds: IMatrixClientCreds): void;
|
|
|
|
}
|
|
|
|
|
2016-07-22 14:47:47 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2021-07-19 21:43:11 +00:00
|
|
|
class MatrixClientPegClass implements IMatrixClientPeg {
|
2020-05-25 21:52:05 +00:00
|
|
|
// 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 = {
|
2020-05-25 21:52:05 +00:00
|
|
|
initialSyncLimit: 20,
|
|
|
|
};
|
|
|
|
|
2023-06-05 17:12:23 +00:00
|
|
|
private matrixClient: MatrixClient | null = null;
|
2022-04-13 18:05:08 +00:00
|
|
|
private justRegisteredUserId: string | null = null;
|
2020-05-25 21:59:15 +00:00
|
|
|
|
2023-06-21 16:29:44 +00:00
|
|
|
public get(): MatrixClient | null {
|
2016-07-21 16:57:55 +00:00
|
|
|
return this.matrixClient;
|
2015-09-28 16:46:49 +00:00
|
|
|
}
|
2015-06-09 16:40:42 +00:00
|
|
|
|
2023-06-05 17:12:23 +00:00
|
|
|
public safeGet(): MatrixClient {
|
|
|
|
if (!this.matrixClient) {
|
|
|
|
throw new UserFriendlyError("User is not logged in");
|
|
|
|
}
|
|
|
|
return this.matrixClient;
|
|
|
|
}
|
|
|
|
|
2020-05-25 21:52:05 +00:00
|
|
|
public unset(): void {
|
2016-07-21 16:57:55 +00:00
|
|
|
this.matrixClient = null;
|
2017-12-07 17:10:45 +00:00
|
|
|
|
|
|
|
MatrixActionCreators.stop();
|
2015-09-28 16:46:49 +00:00
|
|
|
}
|
2015-09-16 12:48:24 +00:00
|
|
|
|
2022-04-13 18:05:08 +00:00
|
|
|
public setJustRegisteredUserId(uid: string | null): void {
|
2020-05-25 21:52:05 +00:00
|
|
|
this.justRegisteredUserId = uid;
|
2020-11-02 17:25:48 +00:00
|
|
|
if (uid) {
|
2022-04-28 10:46:02 +00:00
|
|
|
const registrationTime = Date.now().toString();
|
|
|
|
window.localStorage.setItem("mx_registration_time", registrationTime);
|
2020-11-02 17:25:48 +00:00
|
|
|
}
|
2019-06-14 14:31:19 +00:00
|
|
|
}
|
|
|
|
|
2020-05-25 21:52:05 +00:00
|
|
|
public currentUserIsJustRegistered(): boolean {
|
2023-04-06 10:10:14 +00:00
|
|
|
return !!this.matrixClient && this.matrixClient.credentials.userId === this.justRegisteredUserId;
|
2019-06-14 14:31:19 +00:00
|
|
|
}
|
|
|
|
|
2020-11-02 17:25:48 +00:00
|
|
|
public userRegisteredWithinLastHours(hours: number): boolean {
|
2022-04-13 18:05:08 +00:00
|
|
|
if (hours <= 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-11-02 17:25:48 +00:00
|
|
|
try {
|
2023-02-24 15:28:40 +00:00
|
|
|
const registrationTime = parseInt(window.localStorage.getItem("mx_registration_time")!, 10);
|
2022-04-13 18:05:08 +00:00
|
|
|
const diff = Date.now() - registrationTime;
|
|
|
|
return diff / 36e5 <= hours;
|
2020-11-02 17:25:48 +00:00
|
|
|
} catch (e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-29 11:43:29 +00:00
|
|
|
public userRegisteredAfter(timestamp: Date): boolean {
|
|
|
|
try {
|
2023-02-24 15:28:40 +00:00
|
|
|
const registrationTime = parseInt(window.localStorage.getItem("mx_registration_time")!, 10);
|
2022-07-29 11:43:29 +00:00
|
|
|
return timestamp.getTime() <= registrationTime;
|
|
|
|
} catch (e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-25 21:59:15 +00:00
|
|
|
public replaceUsingCreds(creds: IMatrixClientCreds): void {
|
2020-05-25 22:14:51 +00:00
|
|
|
this.createClient(creds);
|
2016-07-25 15:28:28 +00:00
|
|
|
}
|
|
|
|
|
2023-03-31 09:08:45 +00:00
|
|
|
private onUnexpectedStoreClose = async (): Promise<void> => {
|
|
|
|
if (!this.matrixClient) return;
|
|
|
|
this.matrixClient.stopClient(); // stop the client as the database has failed
|
2023-05-16 15:08:01 +00:00
|
|
|
this.matrixClient.store.destroy();
|
2023-03-31 09:08:45 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
const { finished } = Modal.createDialog(ErrorDialog, {
|
|
|
|
title: _t("Database unexpectedly closed"),
|
|
|
|
description: _t(
|
|
|
|
"This may be caused by having the app open in multiple tabs or due to clearing browser data.",
|
|
|
|
),
|
|
|
|
button: _t("Reload"),
|
|
|
|
});
|
|
|
|
const [reload] = await finished;
|
|
|
|
if (!reload) return;
|
|
|
|
}
|
|
|
|
|
|
|
|
PlatformPeg.get()?.reload();
|
|
|
|
};
|
|
|
|
|
2020-05-25 21:52:05 +00:00
|
|
|
public async assign(): Promise<any> {
|
2023-06-05 17:12:23 +00:00
|
|
|
if (!this.matrixClient) {
|
|
|
|
throw new Error("createClient must be called first");
|
|
|
|
}
|
|
|
|
|
2018-10-04 12:40:56 +00:00
|
|
|
for (const dbType of ["indexeddb", "memory"]) {
|
|
|
|
try {
|
|
|
|
const promise = this.matrixClient.store.startup();
|
2021-09-21 15:48:09 +00:00
|
|
|
logger.log("MatrixClientPeg: waiting for MatrixClient store to initialise");
|
2018-10-04 12:40:56 +00:00
|
|
|
await promise;
|
|
|
|
break;
|
|
|
|
} catch (err) {
|
|
|
|
if (dbType === "indexeddb") {
|
2021-10-15 14:30:53 +00:00
|
|
|
logger.error("Error starting matrixclient store - falling back to memory store", err);
|
2019-09-18 08:27:43 +00:00
|
|
|
this.matrixClient.store = new MemoryStore({
|
2020-05-25 21:52:05 +00:00
|
|
|
localStorage: localStorage,
|
2018-10-04 12:40:56 +00:00
|
|
|
});
|
|
|
|
} else {
|
2021-10-15 14:30:53 +00:00
|
|
|
logger.error("Failed to start memory store!", err);
|
2018-10-04 12:40:56 +00:00
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-31 09:08:45 +00:00
|
|
|
this.matrixClient.store.on?.("closed", this.onUnexpectedStoreClose);
|
2018-10-04 12:40:56 +00:00
|
|
|
|
2017-07-18 22:46:03 +00:00
|
|
|
// try to initialise e2e on the new client
|
2022-12-16 17:10:26 +00:00
|
|
|
if (!SettingsStore.getValue("lowBandwidth")) {
|
|
|
|
await this.initClientCrypto();
|
2017-07-18 22:46:03 +00:00
|
|
|
}
|
|
|
|
|
2016-08-03 15:45:23 +00:00
|
|
|
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;
|
2020-06-03 11:25:57 +00:00
|
|
|
opts.clientWellKnownPollPeriod = 2 * 60 * 60; // 2 hours
|
2023-02-20 14:46:07 +00:00
|
|
|
opts.threadSupport = true;
|
2017-02-02 14:27:27 +00:00
|
|
|
|
2022-09-07 15:42:39 +00:00
|
|
|
if (SettingsStore.getValue("feature_sliding_sync")) {
|
|
|
|
const proxyUrl = SettingsStore.getValue("feature_sliding_sync_proxy_url");
|
|
|
|
if (proxyUrl) {
|
|
|
|
logger.log("Activating sliding sync using proxy at ", proxyUrl);
|
|
|
|
} else {
|
|
|
|
logger.log("Activating sliding sync");
|
|
|
|
}
|
|
|
|
opts.slidingSync = SlidingSyncManager.instance.configure(
|
|
|
|
this.matrixClient,
|
|
|
|
proxyUrl || this.matrixClient.baseUrl,
|
|
|
|
);
|
2022-11-01 10:27:03 +00:00
|
|
|
SlidingSyncManager.instance.startSpidering(100, 50); // 100 rooms at a time, 50ms apart
|
2022-09-07 15:42:39 +00:00
|
|
|
}
|
|
|
|
|
2019-02-22 23:33:20 +00:00
|
|
|
// Connect the matrix client to the dispatcher and setting handlers
|
2017-12-07 17:10:45 +00:00
|
|
|
MatrixActionCreators.start(this.matrixClient);
|
2019-02-22 23:33:20 +00:00
|
|
|
MatrixClientBackedSettingsHandler.matrixClient = this.matrixClient;
|
2023-03-03 13:31:51 +00:00
|
|
|
MatrixClientBackedController.matrixClient = this.matrixClient;
|
2017-12-07 17:10:45 +00:00
|
|
|
|
2019-07-04 22:45:40 +00:00
|
|
|
return opts;
|
|
|
|
}
|
|
|
|
|
2022-12-16 17:10:26 +00:00
|
|
|
/**
|
|
|
|
* Attempt to initialize the crypto layer on a newly-created MatrixClient
|
|
|
|
*/
|
|
|
|
private async initClientCrypto(): Promise<void> {
|
2023-06-05 17:12:23 +00:00
|
|
|
if (!this.matrixClient) {
|
|
|
|
throw new Error("createClient must be called first");
|
|
|
|
}
|
|
|
|
|
2022-12-16 17:10:26 +00:00
|
|
|
const useRustCrypto = SettingsStore.getValue("feature_rust_crypto");
|
|
|
|
|
|
|
|
// 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("feature_rust_crypto", null, SettingLevel.DEVICE, useRustCrypto);
|
|
|
|
|
|
|
|
// Now we can initialise the right crypto impl.
|
|
|
|
if (useRustCrypto) {
|
|
|
|
await this.matrixClient.initRustCrypto();
|
|
|
|
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-25 21:52:05 +00:00
|
|
|
public async start(): Promise<any> {
|
2019-07-04 22:45:40 +00:00
|
|
|
const opts = await this.assign();
|
|
|
|
|
2021-09-21 15:48:09 +00:00
|
|
|
logger.log(`MatrixClientPeg: really starting MatrixClient`);
|
2023-06-05 17:12:23 +00:00
|
|
|
await this.matrixClient!.startClient(opts);
|
2021-09-21 15:48:09 +00:00
|
|
|
logger.log(`MatrixClientPeg: MatrixClient started`);
|
2016-08-03 15:41:22 +00:00
|
|
|
}
|
2016-08-03 15:39:47 +00:00
|
|
|
|
2023-06-27 16:39:56 +00:00
|
|
|
public getHomeserverName(): string {
|
|
|
|
const matches = /^@[^:]+:(.+)$/.exec(this.safeGet().getSafeUserId());
|
2016-09-27 18:38:10 +00:00
|
|
|
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!");
|
2016-09-27 18:38:10 +00:00
|
|
|
}
|
|
|
|
return matches[1];
|
|
|
|
}
|
|
|
|
|
2022-08-26 10:23:56 +00:00
|
|
|
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 _t("%(user1)s and %(user2)s", {
|
|
|
|
user1: names[0],
|
|
|
|
user2: names[1],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return _t("%(user)s and %(count)s others", {
|
|
|
|
user: names[0],
|
|
|
|
count: count - 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)s and %(user2)s", {
|
|
|
|
user1: names[0],
|
|
|
|
user2: names[1],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return _t("Inviting %(user)s and %(count)s others", {
|
|
|
|
user: names[0],
|
|
|
|
count: count - 1,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-05-25 22:14:51 +00:00
|
|
|
private createClient(creds: IMatrixClientCreds): void {
|
2020-10-09 15:59:56 +00:00
|
|
|
const opts: ICreateClientOpts = {
|
2016-08-11 12:50:38 +00:00
|
|
|
baseUrl: creds.homeserverUrl,
|
|
|
|
idBaseUrl: creds.identityServerUrl,
|
|
|
|
accessToken: creds.accessToken,
|
2020-09-30 04:52:47 +00:00
|
|
|
userId: creds.userId,
|
|
|
|
deviceId: creds.deviceId,
|
2020-05-28 04:05:45 +00:00
|
|
|
pickleKey: creds.pickleKey,
|
2016-07-21 16:57:55 +00:00
|
|
|
timelineSupport: true,
|
2020-07-29 17:03:43 +00:00
|
|
|
forceTURN: !SettingsStore.getValue("webRtcAllowPeerToPeer"),
|
2019-08-14 13:02:25 +00:00
|
|
|
fallbackICEServerAllowed: !!SettingsStore.getValue("fallbackICEServerAllowed"),
|
2021-02-16 15:48:58 +00:00
|
|
|
// 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: [
|
|
|
|
verificationMethods.SAS,
|
|
|
|
SHOW_QR_CODE_METHOD,
|
|
|
|
verificationMethods.RECIPROCATE_QR_CODE,
|
|
|
|
],
|
2019-08-23 10:17:51 +00:00
|
|
|
identityServer: new IdentityAuthClient(),
|
2022-08-26 10:23:56 +00:00
|
|
|
// 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 %(oldName)s)", {
|
|
|
|
oldName: state.oldName,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
return _t("Empty room");
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
},
|
2016-07-21 16:57:55 +00:00
|
|
|
};
|
|
|
|
|
2021-03-22 23:52:09 +00:00
|
|
|
if (SecurityCustomisations.getDehydrationKey) {
|
2022-08-26 10:23:56 +00:00
|
|
|
opts.cryptoCallbacks!.getDehydrationKey = SecurityCustomisations.getDehydrationKey;
|
2021-03-22 23:52:09 +00:00
|
|
|
}
|
2019-11-15 10:57:20 +00:00
|
|
|
|
2020-09-03 20:28:42 +00:00
|
|
|
this.matrixClient = createMatrixClient(opts);
|
|
|
|
|
2016-07-21 16:57:55 +00:00
|
|
|
// we're going to add eventlisteners for each matrix event tile, so the
|
|
|
|
// potential number of event listeners is quite high.
|
|
|
|
this.matrixClient.setMaxListeners(500);
|
2016-07-25 15:20:03 +00:00
|
|
|
|
2016-08-11 12:50:38 +00:00
|
|
|
this.matrixClient.setGuest(Boolean(creds.guest));
|
2016-09-08 02:02:26 +00:00
|
|
|
|
2022-08-26 10:23:56 +00:00
|
|
|
const notifTimelineSet = new EventTimelineSet(undefined, {
|
2017-10-11 16:56:17 +00:00
|
|
|
timelineSupport: true,
|
2021-10-22 08:30:36 +00:00
|
|
|
pendingEvents: false,
|
2016-09-08 02:02:26 +00:00
|
|
|
});
|
|
|
|
// XXX: what is our initial pagination token?! it somehow needs to be synchronised with /sync.
|
|
|
|
notifTimelineSet.getLiveTimeline().setPaginationToken("", EventTimeline.BACKWARDS);
|
|
|
|
this.matrixClient.setNotifTimelineSet(notifTimelineSet);
|
2016-07-21 16:57:55 +00:00
|
|
|
}
|
2015-09-28 16:46:49 +00:00
|
|
|
}
|
2015-06-09 16:40:42 +00:00
|
|
|
|
2022-05-10 02:34:27 +00:00
|
|
|
/**
|
|
|
|
* 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();
|
|
|
|
|
2020-05-25 22:06:05 +00:00
|
|
|
if (!window.mxMatrixClientPeg) {
|
2022-02-16 11:19:28 +00:00
|
|
|
window.mxMatrixClientPeg = MatrixClientPeg;
|
2015-09-28 16:46:49 +00:00
|
|
|
}
|