Pass around MatrixClients instead of using MatrixClientPeg (#10984)

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
Michael Telatynski 2023-06-01 14:43:24 +01:00 committed by GitHub
parent b6b9ce3c46
commit 21ffc50f1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 152 additions and 135 deletions

View file

@ -17,11 +17,10 @@ limitations under the License.
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { CryptoEvent } from "matrix-js-sdk/src/crypto"; import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { ClientEvent, EventType, RoomStateEvent } from "matrix-js-sdk/src/matrix"; import { ClientEvent, EventType, MatrixClient, RoomStateEvent } from "matrix-js-sdk/src/matrix";
import { SyncState } from "matrix-js-sdk/src/sync"; import { SyncState } from "matrix-js-sdk/src/sync";
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup"; import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
import { MatrixClientPeg } from "./MatrixClientPeg";
import dis from "./dispatcher/dispatcher"; import dis from "./dispatcher/dispatcher";
import { import {
hideToast as hideBulkUnverifiedSessionsToast, hideToast as hideBulkUnverifiedSessionsToast,
@ -67,6 +66,8 @@ export default class DeviceListener {
// The set of device IDs we're currently displaying toasts for // The set of device IDs we're currently displaying toasts for
private displayingToastsForDeviceIds = new Set<string>(); private displayingToastsForDeviceIds = new Set<string>();
private running = false; private running = false;
// The client with which the instance is running. Only set if `running` is true, otherwise undefined.
private client?: MatrixClient;
private shouldRecordClientInformation = false; private shouldRecordClientInformation = false;
private enableBulkUnverifiedSessionsReminder = true; private enableBulkUnverifiedSessionsReminder = true;
private deviceClientInformationSettingWatcherRef: string | undefined; private deviceClientInformationSettingWatcherRef: string | undefined;
@ -76,16 +77,17 @@ export default class DeviceListener {
return window.mxDeviceListener; return window.mxDeviceListener;
} }
public start(): void { public start(matrixClient: MatrixClient): void {
this.running = true; this.running = true;
MatrixClientPeg.get().on(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices); this.client = matrixClient;
MatrixClientPeg.get().on(CryptoEvent.DevicesUpdated, this.onDevicesUpdated); this.client.on(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices);
MatrixClientPeg.get().on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged); this.client.on(CryptoEvent.DevicesUpdated, this.onDevicesUpdated);
MatrixClientPeg.get().on(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged); this.client.on(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
MatrixClientPeg.get().on(CryptoEvent.KeysChanged, this.onCrossSingingKeysChanged); this.client.on(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged);
MatrixClientPeg.get().on(ClientEvent.AccountData, this.onAccountData); this.client.on(CryptoEvent.KeysChanged, this.onCrossSingingKeysChanged);
MatrixClientPeg.get().on(ClientEvent.Sync, this.onSync); this.client.on(ClientEvent.AccountData, this.onAccountData);
MatrixClientPeg.get().on(RoomStateEvent.Events, this.onRoomStateEvents); this.client.on(ClientEvent.Sync, this.onSync);
this.client.on(RoomStateEvent.Events, this.onRoomStateEvents);
this.shouldRecordClientInformation = SettingsStore.getValue("deviceClientInformationOptIn"); this.shouldRecordClientInformation = SettingsStore.getValue("deviceClientInformationOptIn");
// only configurable in config, so we don't need to watch the value // only configurable in config, so we don't need to watch the value
this.enableBulkUnverifiedSessionsReminder = SettingsStore.getValue(UIFeature.BulkUnverifiedSessionsReminder); this.enableBulkUnverifiedSessionsReminder = SettingsStore.getValue(UIFeature.BulkUnverifiedSessionsReminder);
@ -101,18 +103,15 @@ export default class DeviceListener {
public stop(): void { public stop(): void {
this.running = false; this.running = false;
if (MatrixClientPeg.get()) { if (this.client) {
MatrixClientPeg.get().removeListener(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices); this.client.removeListener(CryptoEvent.WillUpdateDevices, this.onWillUpdateDevices);
MatrixClientPeg.get().removeListener(CryptoEvent.DevicesUpdated, this.onDevicesUpdated); this.client.removeListener(CryptoEvent.DevicesUpdated, this.onDevicesUpdated);
MatrixClientPeg.get().removeListener( this.client.removeListener(CryptoEvent.DeviceVerificationChanged, this.onDeviceVerificationChanged);
CryptoEvent.DeviceVerificationChanged, this.client.removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged);
this.onDeviceVerificationChanged, this.client.removeListener(CryptoEvent.KeysChanged, this.onCrossSingingKeysChanged);
); this.client.removeListener(ClientEvent.AccountData, this.onAccountData);
MatrixClientPeg.get().removeListener(CryptoEvent.UserTrustStatusChanged, this.onUserTrustStatusChanged); this.client.removeListener(ClientEvent.Sync, this.onSync);
MatrixClientPeg.get().removeListener(CryptoEvent.KeysChanged, this.onCrossSingingKeysChanged); this.client.removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
MatrixClientPeg.get().removeListener(ClientEvent.AccountData, this.onAccountData);
MatrixClientPeg.get().removeListener(ClientEvent.Sync, this.onSync);
MatrixClientPeg.get().removeListener(RoomStateEvent.Events, this.onRoomStateEvents);
} }
if (this.deviceClientInformationSettingWatcherRef) { if (this.deviceClientInformationSettingWatcherRef) {
SettingsStore.unwatchSetting(this.deviceClientInformationSettingWatcherRef); SettingsStore.unwatchSetting(this.deviceClientInformationSettingWatcherRef);
@ -128,6 +127,7 @@ export default class DeviceListener {
this.keyBackupStatusChecked = false; this.keyBackupStatusChecked = false;
this.ourDeviceIdsAtStart = null; this.ourDeviceIdsAtStart = null;
this.displayingToastsForDeviceIds = new Set(); this.displayingToastsForDeviceIds = new Set();
this.client = undefined;
} }
/** /**
@ -160,22 +160,23 @@ export default class DeviceListener {
* @returns the set of device IDs * @returns the set of device IDs
*/ */
private async getDeviceIds(): Promise<Set<string>> { private async getDeviceIds(): Promise<Set<string>> {
const cli = MatrixClientPeg.get(); const cli = this.client;
const crypto = cli.getCrypto(); const crypto = cli?.getCrypto();
if (crypto === undefined) return new Set(); if (crypto === undefined) return new Set();
const userId = cli.getSafeUserId(); const userId = cli!.getSafeUserId();
const devices = await crypto.getUserDeviceInfo([userId]); const devices = await crypto.getUserDeviceInfo([userId]);
return new Set(devices.get(userId)?.keys() ?? []); return new Set(devices.get(userId)?.keys() ?? []);
} }
private onWillUpdateDevices = async (users: string[], initialFetch?: boolean): Promise<void> => { private onWillUpdateDevices = async (users: string[], initialFetch?: boolean): Promise<void> => {
if (!this.client) return;
// If we didn't know about *any* devices before (ie. it's fresh login), // If we didn't know about *any* devices before (ie. it's fresh login),
// then they are all pre-existing devices, so ignore this and set the // then they are all pre-existing devices, so ignore this and set the
// devicesAtStart list to the devices that we see after the fetch. // devicesAtStart list to the devices that we see after the fetch.
if (initialFetch) return; if (initialFetch) return;
const myUserId = MatrixClientPeg.get().getUserId()!; const myUserId = this.client.getSafeUserId();
if (users.includes(myUserId)) await this.ensureDeviceIdsAtStartPopulated(); if (users.includes(myUserId)) await this.ensureDeviceIdsAtStartPopulated();
// No need to do a recheck here: we just need to get a snapshot of our devices // No need to do a recheck here: we just need to get a snapshot of our devices
@ -183,17 +184,20 @@ export default class DeviceListener {
}; };
private onDevicesUpdated = (users: string[]): void => { private onDevicesUpdated = (users: string[]): void => {
if (!users.includes(MatrixClientPeg.get().getUserId()!)) return; if (!this.client) return;
if (!users.includes(this.client.getSafeUserId())) return;
this.recheck(); this.recheck();
}; };
private onDeviceVerificationChanged = (userId: string): void => { private onDeviceVerificationChanged = (userId: string): void => {
if (userId !== MatrixClientPeg.get().getUserId()) return; if (!this.client) return;
if (userId !== this.client.getUserId()) return;
this.recheck(); this.recheck();
}; };
private onUserTrustStatusChanged = (userId: string): void => { private onUserTrustStatusChanged = (userId: string): void => {
if (userId !== MatrixClientPeg.get().getUserId()) return; if (!this.client) return;
if (userId !== this.client.getUserId()) return;
this.recheck(); this.recheck();
}; };
@ -239,13 +243,14 @@ export default class DeviceListener {
// The server doesn't tell us when key backup is set up, so we poll // The server doesn't tell us when key backup is set up, so we poll
// & cache the result // & cache the result
private async getKeyBackupInfo(): Promise<IKeyBackupInfo | null> { private async getKeyBackupInfo(): Promise<IKeyBackupInfo | null> {
if (!this.client) return null;
const now = new Date().getTime(); const now = new Date().getTime();
if ( if (
!this.keyBackupInfo || !this.keyBackupInfo ||
!this.keyBackupFetchedAt || !this.keyBackupFetchedAt ||
this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL this.keyBackupFetchedAt < now - KEY_BACKUP_POLL_INTERVAL
) { ) {
this.keyBackupInfo = await MatrixClientPeg.get().getKeyBackupVersion(); this.keyBackupInfo = await this.client.getKeyBackupVersion();
this.keyBackupFetchedAt = now; this.keyBackupFetchedAt = now;
} }
return this.keyBackupInfo; return this.keyBackupInfo;
@ -256,13 +261,13 @@ export default class DeviceListener {
// modifying the state involved here, so don't add new toasts to setup. // modifying the state involved here, so don't add new toasts to setup.
if (isSecretStorageBeingAccessed()) return false; if (isSecretStorageBeingAccessed()) return false;
// Show setup toasts once the user is in at least one encrypted room. // Show setup toasts once the user is in at least one encrypted room.
const cli = MatrixClientPeg.get(); const cli = this.client;
return cli && cli.getRooms().some((r) => cli.isRoomEncrypted(r.roomId)); return cli?.getRooms().some((r) => cli.isRoomEncrypted(r.roomId)) ?? false;
} }
private async recheck(): Promise<void> { private async recheck(): Promise<void> {
if (!this.running) return; // we have been stopped if (!this.running || !this.client) return; // we have been stopped
const cli = MatrixClientPeg.get(); const cli = this.client;
// cross-signing support was added to Matrix in MSC1756, which landed in spec v1.1 // cross-signing support was added to Matrix in MSC1756, which landed in spec v1.1
if (!(await cli.isVersionSupported("v1.1"))) return; if (!(await cli.isVersionSupported("v1.1"))) return;
@ -285,11 +290,11 @@ export default class DeviceListener {
this.checkKeyBackupStatus(); this.checkKeyBackupStatus();
} else if (this.shouldShowSetupEncryptionToast()) { } else if (this.shouldShowSetupEncryptionToast()) {
// make sure our keys are finished downloading // make sure our keys are finished downloading
await crypto.getUserDeviceInfo([cli.getUserId()!]); await crypto.getUserDeviceInfo([cli.getSafeUserId()]);
// cross signing isn't enabled - nag to enable it // cross signing isn't enabled - nag to enable it
// There are 3 different toasts for: // There are 3 different toasts for:
if (!(await crypto.getCrossSigningKeyId()) && cli.getStoredCrossSigningForUser(cli.getUserId()!)) { if (!(await crypto.getCrossSigningKeyId()) && cli.getStoredCrossSigningForUser(cli.getSafeUserId())) {
// Cross-signing on account but this device doesn't trust the master key (verify this session) // Cross-signing on account but this device doesn't trust the master key (verify this session)
showSetupEncryptionToast(SetupKind.VERIFY_THIS_SESSION); showSetupEncryptionToast(SetupKind.VERIFY_THIS_SESSION);
this.checkKeyBackupStatus(); this.checkKeyBackupStatus();
@ -327,7 +332,9 @@ export default class DeviceListener {
const isCurrentDeviceTrusted = const isCurrentDeviceTrusted =
crossSigningReady && crossSigningReady &&
Boolean((await crypto.getDeviceVerificationStatus(cli.getUserId()!, cli.deviceId!))?.crossSigningVerified); Boolean(
(await crypto.getDeviceVerificationStatus(cli.getSafeUserId(), cli.deviceId!))?.crossSigningVerified,
);
// as long as cross-signing isn't ready, // as long as cross-signing isn't ready,
// you can't see or dismiss any device toasts // you can't see or dismiss any device toasts
@ -336,7 +343,7 @@ export default class DeviceListener {
for (const deviceId of devices) { for (const deviceId of devices) {
if (deviceId === cli.deviceId) continue; if (deviceId === cli.deviceId) continue;
const deviceTrust = await crypto.getDeviceVerificationStatus(cli.getUserId()!, deviceId); const deviceTrust = await crypto.getDeviceVerificationStatus(cli.getSafeUserId(), deviceId);
if (!deviceTrust?.crossSigningVerified && !this.dismissed.has(deviceId)) { if (!deviceTrust?.crossSigningVerified && !this.dismissed.has(deviceId)) {
if (this.ourDeviceIdsAtStart?.has(deviceId)) { if (this.ourDeviceIdsAtStart?.has(deviceId)) {
oldUnverifiedDeviceIds.add(deviceId); oldUnverifiedDeviceIds.add(deviceId);
@ -383,11 +390,11 @@ export default class DeviceListener {
} }
private checkKeyBackupStatus = async (): Promise<void> => { private checkKeyBackupStatus = async (): Promise<void> => {
if (this.keyBackupStatusChecked) { if (this.keyBackupStatusChecked || !this.client) {
return; return;
} }
// returns null when key backup status hasn't finished being checked // returns null when key backup status hasn't finished being checked
const isKeyBackupEnabled = MatrixClientPeg.get().getKeyBackupEnabled(); const isKeyBackupEnabled = this.client.getKeyBackupEnabled();
this.keyBackupStatusChecked = isKeyBackupEnabled !== null; this.keyBackupStatusChecked = isKeyBackupEnabled !== null;
if (isKeyBackupEnabled === false) { if (isKeyBackupEnabled === false) {
@ -412,11 +419,12 @@ export default class DeviceListener {
}; };
private updateClientInformation = async (): Promise<void> => { private updateClientInformation = async (): Promise<void> => {
if (!this.client) return;
try { try {
if (this.shouldRecordClientInformation) { if (this.shouldRecordClientInformation) {
await recordClientInformation(MatrixClientPeg.get(), SdkConfig.get(), PlatformPeg.get() ?? undefined); await recordClientInformation(this.client, SdkConfig.get(), PlatformPeg.get() ?? undefined);
} else { } else {
await removeClientInformation(MatrixClientPeg.get()); await removeClientInformation(this.client);
} }
} catch (error) { } catch (error) {
// this is a best effort operation // this is a best effort operation

View file

@ -129,7 +129,7 @@ export default class IdentityAuthClient {
} catch (e) { } catch (e) {
if (e instanceof MatrixError && e.errcode === "M_TERMS_NOT_SIGNED") { if (e instanceof MatrixError && e.errcode === "M_TERMS_NOT_SIGNED") {
logger.log("Identity server requires new terms to be agreed to"); logger.log("Identity server requires new terms to be agreed to");
await startTermsFlow([new Service(SERVICE_TYPES.IS, identityServerUrl, token)]); await startTermsFlow(this.matrixClient, [new Service(SERVICE_TYPES.IS, identityServerUrl, token)]);
return; return;
} }
throw e; throw e;

View file

@ -553,7 +553,7 @@ export async function hydrateSession(credentials: IMatrixClientCreds): Promise<M
logger.warn("Clearing all data: Old session belongs to a different user/session"); logger.warn("Clearing all data: Old session belongs to a different user/session");
} }
if (!credentials.pickleKey) { if (!credentials.pickleKey && credentials.deviceId !== undefined) {
logger.info("Lifecycle#hydrateSession: Pickle key not provided - trying to get one"); logger.info("Lifecycle#hydrateSession: Pickle key not provided - trying to get one");
credentials.pickleKey = credentials.pickleKey =
(await PlatformPeg.get()?.getPickleKey(credentials.userId, credentials.deviceId)) ?? undefined; (await PlatformPeg.get()?.getPickleKey(credentials.userId, credentials.deviceId)) ?? undefined;
@ -603,14 +603,14 @@ async function doSetLoggedIn(credentials: IMatrixClientCreds, clearStorageEnable
} }
MatrixClientPeg.replaceUsingCreds(credentials); MatrixClientPeg.replaceUsingCreds(credentials);
const client = MatrixClientPeg.get();
setSentryUser(credentials.userId); setSentryUser(credentials.userId);
if (PosthogAnalytics.instance.isEnabled()) { if (PosthogAnalytics.instance.isEnabled()) {
PosthogAnalytics.instance.startListeningToSettingsChanges(); PosthogAnalytics.instance.startListeningToSettingsChanges(client);
} }
const client = MatrixClientPeg.get();
if (credentials.freshLogin && SettingsStore.getValue("feature_dehydration")) { if (credentials.freshLogin && SettingsStore.getValue("feature_dehydration")) {
// If we just logged in, try to rehydrate a device instead of using a // If we just logged in, try to rehydrate a device instead of using a
// new device. If it succeeds, we'll get a new device ID, so make sure // new device. If it succeeds, we'll get a new device ID, so make sure
@ -825,7 +825,7 @@ async function startMatrixClient(client: MatrixClient, startSyncing = true): Pro
SettingsStore.runMigrations(); SettingsStore.runMigrations();
// This needs to be started after crypto is set up // This needs to be started after crypto is set up
DeviceListener.sharedInstance().start(); DeviceListener.sharedInstance().start(client);
// Similarly, don't start sending presence updates until we've started // Similarly, don't start sending presence updates until we've started
// the client // the client
if (!SettingsStore.getValue("lowBandwidth")) { if (!SettingsStore.getValue("lowBandwidth")) {

View file

@ -15,8 +15,8 @@ limitations under the License.
*/ */
import { ClientWidgetApi } from "matrix-widget-api"; import { ClientWidgetApi } from "matrix-widget-api";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "./MatrixClientPeg";
import SdkConfig from "./SdkConfig"; import SdkConfig from "./SdkConfig";
import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions"; import { ElementWidgetActions } from "./stores/widgets/ElementWidgetActions";
@ -27,8 +27,8 @@ export function getConfigLivestreamUrl(): string | undefined {
// Dummy rtmp URL used to signal that we want a special audio-only stream // Dummy rtmp URL used to signal that we want a special audio-only stream
const AUDIOSTREAM_DUMMY_URL = "rtmp://audiostream.dummy/"; const AUDIOSTREAM_DUMMY_URL = "rtmp://audiostream.dummy/";
async function createLiveStream(roomId: string): Promise<void> { async function createLiveStream(matrixClient: MatrixClient, roomId: string): Promise<void> {
const openIdToken = await MatrixClientPeg.get().getOpenIdToken(); const openIdToken = await matrixClient.getOpenIdToken();
const url = getConfigLivestreamUrl() + "/createStream"; const url = getConfigLivestreamUrl() + "/createStream";
@ -47,8 +47,12 @@ async function createLiveStream(roomId: string): Promise<void> {
return respBody["stream_id"]; return respBody["stream_id"];
} }
export async function startJitsiAudioLivestream(widgetMessaging: ClientWidgetApi, roomId: string): Promise<void> { export async function startJitsiAudioLivestream(
const streamId = await createLiveStream(roomId); matrixClient: MatrixClient,
widgetMessaging: ClientWidgetApi,
roomId: string,
): Promise<void> {
const streamId = await createLiveStream(matrixClient, roomId);
await widgetMessaging.transport.send(ElementWidgetActions.StartLiveStream, { await widgetMessaging.transport.send(ElementWidgetActions.StartLiveStream, {
rtmpStreamKey: AUDIOSTREAM_DUMMY_URL + streamId, rtmpStreamKey: AUDIOSTREAM_DUMMY_URL + streamId,

View file

@ -254,7 +254,7 @@ export class PosthogAnalytics {
}; };
} }
// eslint-disable-nextline no-unused-varsx // eslint-disable-nextline no-unused-vars
private capture(eventName: string, properties: Properties, options?: IPostHogEventOptions): void { private capture(eventName: string, properties: Properties, options?: IPostHogEventOptions): void {
if (!this.enabled) { if (!this.enabled) {
return; return;
@ -375,12 +375,12 @@ export class PosthogAnalytics {
this.registerSuperProperties(this.platformSuperProperties); this.registerSuperProperties(this.platformSuperProperties);
} }
public async updateAnonymityFromSettings(pseudonymousOptIn: boolean): Promise<void> { public async updateAnonymityFromSettings(client: MatrixClient, pseudonymousOptIn: boolean): Promise<void> {
// Update this.anonymity based on the user's analytics opt-in settings // Update this.anonymity based on the user's analytics opt-in settings
const anonymity = pseudonymousOptIn ? Anonymity.Pseudonymous : Anonymity.Disabled; const anonymity = pseudonymousOptIn ? Anonymity.Pseudonymous : Anonymity.Disabled;
this.setAnonymity(anonymity); this.setAnonymity(anonymity);
if (anonymity === Anonymity.Pseudonymous) { if (anonymity === Anonymity.Pseudonymous) {
await this.identifyUser(MatrixClientPeg.get(), PosthogAnalytics.getRandomAnalyticsId); await this.identifyUser(client, PosthogAnalytics.getRandomAnalyticsId);
if (MatrixClientPeg.currentUserIsJustRegistered()) { if (MatrixClientPeg.currentUserIsJustRegistered()) {
this.trackNewUserEvent(); this.trackNewUserEvent();
} }
@ -391,7 +391,7 @@ export class PosthogAnalytics {
} }
} }
public startListeningToSettingsChanges(): void { public startListeningToSettingsChanges(client: MatrixClient): void {
// Listen to account data changes from sync so we can observe changes to relevant flags and update. // Listen to account data changes from sync so we can observe changes to relevant flags and update.
// This is called - // This is called -
// * On page load, when the account data is first received by sync // * On page load, when the account data is first received by sync
@ -404,7 +404,7 @@ export class PosthogAnalytics {
"pseudonymousAnalyticsOptIn", "pseudonymousAnalyticsOptIn",
null, null,
(originalSettingName, changedInRoomId, atLevel, newValueAtLevel, newValue) => { (originalSettingName, changedInRoomId, atLevel, newValueAtLevel, newValue) => {
this.updateAnonymityFromSettings(!!newValue); this.updateAnonymityFromSettings(client, !!newValue);
}, },
); );
} }

View file

@ -21,7 +21,6 @@ import { ConditionKind, PushRuleActionName, PushRuleKind, TweakName } from "matr
import type { IPushRule } from "matrix-js-sdk/src/@types/PushRules"; import type { IPushRule } from "matrix-js-sdk/src/@types/PushRules";
import type { Room } from "matrix-js-sdk/src/models/room"; import type { Room } from "matrix-js-sdk/src/models/room";
import type { MatrixClient } from "matrix-js-sdk/src/matrix"; import type { MatrixClient } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "./MatrixClientPeg";
import { NotificationColor } from "./stores/notifications/NotificationColor"; import { NotificationColor } from "./stores/notifications/NotificationColor";
import { getUnsentMessages } from "./components/structures/RoomStatusBar"; import { getUnsentMessages } from "./components/structures/RoomStatusBar";
import { doesRoomHaveUnreadMessages, doesRoomOrThreadHaveUnreadMessages } from "./Unread"; import { doesRoomHaveUnreadMessages, doesRoomOrThreadHaveUnreadMessages } from "./Unread";
@ -40,7 +39,7 @@ export function getRoomNotifsState(client: MatrixClient, roomId: string): RoomNo
// look through the override rules for a rule affecting this room: // look through the override rules for a rule affecting this room:
// if one exists, it will take precedence. // if one exists, it will take precedence.
const muteRule = findOverrideMuteRule(roomId); const muteRule = findOverrideMuteRule(client, roomId);
if (muteRule) { if (muteRule) {
return RoomNotifState.Mute; return RoomNotifState.Mute;
} }
@ -70,11 +69,11 @@ export function getRoomNotifsState(client: MatrixClient, roomId: string): RoomNo
return null; return null;
} }
export function setRoomNotifsState(roomId: string, newState: RoomNotifState): Promise<void> { export function setRoomNotifsState(client: MatrixClient, roomId: string, newState: RoomNotifState): Promise<void> {
if (newState === RoomNotifState.Mute) { if (newState === RoomNotifState.Mute) {
return setRoomNotifsStateMuted(roomId); return setRoomNotifsStateMuted(client, roomId);
} else { } else {
return setRoomNotifsStateUnmuted(roomId, newState); return setRoomNotifsStateUnmuted(client, roomId, newState);
} }
} }
@ -91,7 +90,7 @@ export function getUnreadNotificationCount(room: Room, type: NotificationCountTy
// Exclude threadId, as the same thread can't continue over a room upgrade // Exclude threadId, as the same thread can't continue over a room upgrade
if (!threadId && predecessor?.roomId) { if (!threadId && predecessor?.roomId) {
const oldRoomId = predecessor.roomId; const oldRoomId = predecessor.roomId;
const oldRoom = MatrixClientPeg.get().getRoom(oldRoomId); const oldRoom = room.client.getRoom(oldRoomId);
if (oldRoom) { if (oldRoom) {
// We only ever care if there's highlights in the old room. No point in // We only ever care if there's highlights in the old room. No point in
// notifying the user for unread messages because they would have extreme // notifying the user for unread messages because they would have extreme
@ -104,8 +103,7 @@ export function getUnreadNotificationCount(room: Room, type: NotificationCountTy
return notificationCount; return notificationCount;
} }
function setRoomNotifsStateMuted(roomId: string): Promise<any> { function setRoomNotifsStateMuted(cli: MatrixClient, roomId: string): Promise<any> {
const cli = MatrixClientPeg.get();
const promises: Promise<unknown>[] = []; const promises: Promise<unknown>[] = [];
// delete the room rule // delete the room rule
@ -135,11 +133,10 @@ function setRoomNotifsStateMuted(roomId: string): Promise<any> {
return Promise.all(promises); return Promise.all(promises);
} }
function setRoomNotifsStateUnmuted(roomId: string, newState: RoomNotifState): Promise<any> { function setRoomNotifsStateUnmuted(cli: MatrixClient, roomId: string, newState: RoomNotifState): Promise<any> {
const cli = MatrixClientPeg.get();
const promises: Promise<unknown>[] = []; const promises: Promise<unknown>[] = [];
const overrideMuteRule = findOverrideMuteRule(roomId); const overrideMuteRule = findOverrideMuteRule(cli, roomId);
if (overrideMuteRule) { if (overrideMuteRule) {
promises.push(cli.deletePushRule("global", PushRuleKind.Override, overrideMuteRule.rule_id)); promises.push(cli.deletePushRule("global", PushRuleKind.Override, overrideMuteRule.rule_id));
} }
@ -176,8 +173,7 @@ function setRoomNotifsStateUnmuted(roomId: string, newState: RoomNotifState): Pr
return Promise.all(promises); return Promise.all(promises);
} }
function findOverrideMuteRule(roomId: string): IPushRule | null { function findOverrideMuteRule(cli: MatrixClient | undefined, roomId: string): IPushRule | null {
const cli = MatrixClientPeg.get();
if (!cli?.pushRules?.global?.override) { if (!cli?.pushRules?.global?.override) {
return null; return null;
} }

View file

@ -17,8 +17,8 @@ limitations under the License.
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { EventType } from "matrix-js-sdk/src/@types/event"; import { EventType } from "matrix-js-sdk/src/@types/event";
import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import { RoomMember } from "matrix-js-sdk/src/models/room-member";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "./MatrixClientPeg";
import AliasCustomisations from "./customisations/Alias"; import AliasCustomisations from "./customisations/Alias";
/** /**
@ -52,20 +52,21 @@ export function guessAndSetDMRoom(room: Room, isDirect: boolean): Promise<void>
newTarget = null; newTarget = null;
} }
return setDMRoom(room.roomId, newTarget); return setDMRoom(room.client, room.roomId, newTarget);
} }
/** /**
* Marks or unmarks the given room as being as a DM room. * Marks or unmarks the given room as being as a DM room.
* @param client the Matrix Client instance of the logged-in user
* @param {string} roomId The ID of the room to modify * @param {string} roomId The ID of the room to modify
* @param {string | null} userId The user ID of the desired DM room target user or * @param {string | null} userId The user ID of the desired DM room target user or
* null to un-mark this room as a DM room * null to un-mark this room as a DM room
* @returns {object} A promise * @returns {object} A promise
*/ */
export async function setDMRoom(roomId: string, userId: string | null): Promise<void> { export async function setDMRoom(client: MatrixClient, roomId: string, userId: string | null): Promise<void> {
if (MatrixClientPeg.get().isGuest()) return; if (client.isGuest()) return;
const mDirectEvent = MatrixClientPeg.get().getAccountData(EventType.Direct); const mDirectEvent = client.getAccountData(EventType.Direct);
const currentContent = mDirectEvent?.getContent() || {}; const currentContent = mDirectEvent?.getContent() || {};
const dmRoomMap = new Map(Object.entries(currentContent)); const dmRoomMap = new Map(Object.entries(currentContent));
@ -98,7 +99,7 @@ export async function setDMRoom(roomId: string, userId: string | null): Promise<
// prevent unnecessary calls to setAccountData // prevent unnecessary calls to setAccountData
if (!modified) return; if (!modified) return;
await MatrixClientPeg.get().setAccountData(EventType.Direct, Object.fromEntries(dmRoomMap)); await client.setAccountData(EventType.Direct, Object.fromEntries(dmRoomMap));
} }
/** /**

View file

@ -157,6 +157,7 @@ export default class ScalarAuthClient {
const parsedImRestUrl = parseUrl(this.apiUrl); const parsedImRestUrl = parseUrl(this.apiUrl);
parsedImRestUrl.pathname = ""; parsedImRestUrl.pathname = "";
return startTermsFlow( return startTermsFlow(
MatrixClientPeg.get(),
[new Service(SERVICE_TYPES.IM, parsedImRestUrl.toString(), token)], [new Service(SERVICE_TYPES.IM, parsedImRestUrl.toString(), token)],
this.termsInteractionCallback, this.termsInteractionCallback,
).then(() => { ).then(() => {

View file

@ -876,7 +876,7 @@ const onMessage = function (event: MessageEvent<any>): void {
// No integrations UI URL, ignore silently. // No integrations UI URL, ignore silently.
return; return;
} }
let eventOriginUrl; let eventOriginUrl: URL;
try { try {
eventOriginUrl = new URL(event.origin); eventOriginUrl = new URL(event.origin);
} catch (e) { } catch (e) {

View file

@ -17,8 +17,8 @@ limitations under the License.
import classNames from "classnames"; import classNames from "classnames";
import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types"; import { SERVICE_TYPES } from "matrix-js-sdk/src/service-types";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { MatrixClient } from "matrix-js-sdk/src/matrix";
import { MatrixClientPeg } from "./MatrixClientPeg";
import Modal from "./Modal"; import Modal from "./Modal";
import TermsDialog from "./components/views/dialogs/TermsDialog"; import TermsDialog from "./components/views/dialogs/TermsDialog";
@ -66,6 +66,7 @@ export type TermsInteractionCallback = (
/** /**
* Start a flow where the user is presented with terms & conditions for some services * Start a flow where the user is presented with terms & conditions for some services
* *
* @param client The Matrix Client instance of the logged-in user
* @param {Service[]} services Object with keys 'serviceType', 'baseUrl', 'accessToken' * @param {Service[]} services Object with keys 'serviceType', 'baseUrl', 'accessToken'
* @param {function} interactionCallback Function called with: * @param {function} interactionCallback Function called with:
* * an array of { service: {Service}, policies: {terms response from API} } * * an array of { service: {Service}, policies: {terms response from API} }
@ -75,10 +76,11 @@ export type TermsInteractionCallback = (
* if they cancel. * if they cancel.
*/ */
export async function startTermsFlow( export async function startTermsFlow(
client: MatrixClient,
services: Service[], services: Service[],
interactionCallback: TermsInteractionCallback = dialogTermsInteractionCallback, interactionCallback: TermsInteractionCallback = dialogTermsInteractionCallback,
): Promise<void> { ): Promise<void> {
const termsPromises = services.map((s) => MatrixClientPeg.get().getTerms(s.serviceType, s.baseUrl)); const termsPromises = services.map((s) => client.getTerms(s.serviceType, s.baseUrl));
/* /*
* a /terms response looks like: * a /terms response looks like:
@ -105,7 +107,7 @@ export async function startTermsFlow(
}); });
// fetch the set of agreed policy URLs from account data // fetch the set of agreed policy URLs from account data
const currentAcceptedTerms = await MatrixClientPeg.get().getAccountData("m.accepted_terms"); const currentAcceptedTerms = await client.getAccountData("m.accepted_terms");
let agreedUrlSet: Set<string>; let agreedUrlSet: Set<string>;
if (!currentAcceptedTerms || !currentAcceptedTerms.getContent() || !currentAcceptedTerms.getContent().accepted) { if (!currentAcceptedTerms || !currentAcceptedTerms.getContent() || !currentAcceptedTerms.getContent().accepted) {
agreedUrlSet = new Set(); agreedUrlSet = new Set();
@ -152,7 +154,7 @@ export async function startTermsFlow(
// We only ever add to the set of URLs, so if anything has changed then we'd see a different length // We only ever add to the set of URLs, so if anything has changed then we'd see a different length
if (agreedUrlSet.size !== numAcceptedBeforeAgreement) { if (agreedUrlSet.size !== numAcceptedBeforeAgreement) {
const newAcceptedTerms = { accepted: Array.from(agreedUrlSet) }; const newAcceptedTerms = { accepted: Array.from(agreedUrlSet) };
await MatrixClientPeg.get().setAccountData("m.accepted_terms", newAcceptedTerms); await client.setAccountData("m.accepted_terms", newAcceptedTerms);
} }
const agreePromises = policiesAndServicePairs.map((policiesAndService) => { const agreePromises = policiesAndServicePairs.map((policiesAndService) => {
@ -171,7 +173,7 @@ export async function startTermsFlow(
if (urlsForService.length === 0) return Promise.resolve(); if (urlsForService.length === 0) return Promise.resolve();
return MatrixClientPeg.get().agreeToTerms( return client.agreeToTerms(
policiesAndService.service.serviceType, policiesAndService.service.serviceType,
policiesAndService.service.baseUrl, policiesAndService.service.baseUrl,
policiesAndService.service.accessToken, policiesAndService.service.accessToken,

View file

@ -1512,7 +1512,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
} }
const dmInviter = room.getDMInviter(); const dmInviter = room.getDMInviter();
if (dmInviter) { if (dmInviter) {
Rooms.setDMRoom(room.roomId, dmInviter); Rooms.setDMRoom(room.client, room.roomId, dmInviter);
} }
} }

View file

@ -67,7 +67,7 @@ export const WidgetContextMenu: React.FC<IProps> = ({
if (roomId && getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) { if (roomId && getConfigLivestreamUrl() && WidgetType.JITSI.matches(app.type)) {
const onStreamAudioClick = async (): Promise<void> => { const onStreamAudioClick = async (): Promise<void> => {
try { try {
await startJitsiAudioLivestream(widgetMessaging!, roomId); await startJitsiAudioLivestream(cli, widgetMessaging!, roomId);
} catch (err) { } catch (err) {
logger.error("Failed to start livestream", err); logger.error("Failed to start livestream", err);
// XXX: won't i18n well, but looks like widget api only support 'message'? // XXX: won't i18n well, but looks like widget api only support 'message'?

View file

@ -191,7 +191,7 @@ export function DeviceItem({ userId, device }: { userId: string; device: IDevice
const onDeviceClick = (): void => { const onDeviceClick = (): void => {
const user = cli.getUser(userId); const user = cli.getUser(userId);
if (user) { if (user) {
verifyDevice(user, device); verifyDevice(cli, user, device);
} }
}; };
@ -1446,9 +1446,9 @@ const BasicUserInfo: React.FC<{
className="mx_UserInfo_field mx_UserInfo_verifyButton" className="mx_UserInfo_field mx_UserInfo_verifyButton"
onClick={() => { onClick={() => {
if (hasCrossSigningKeys) { if (hasCrossSigningKeys) {
verifyUser(member as User); verifyUser(cli, member as User);
} else { } else {
legacyVerifyUser(member as User); legacyVerifyUser(cli, member as User);
} }
}} }}
> >

View file

@ -61,6 +61,7 @@ import SettingsSubsection, { SettingsSubsectionText } from "../../shared/Setting
import { SettingsSubsectionHeading } from "../../shared/SettingsSubsectionHeading"; import { SettingsSubsectionHeading } from "../../shared/SettingsSubsectionHeading";
import Heading from "../../../typography/Heading"; import Heading from "../../../typography/Heading";
import InlineSpinner from "../../../elements/InlineSpinner"; import InlineSpinner from "../../../elements/InlineSpinner";
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
interface IProps { interface IProps {
closeSettingsFn: () => void; closeSettingsFn: () => void;
@ -96,6 +97,9 @@ interface IState {
} }
export default class GeneralUserSettingsTab extends React.Component<IProps, IState> { export default class GeneralUserSettingsTab extends React.Component<IProps, IState> {
public static contextType = MatrixClientContext;
public context!: React.ContextType<typeof MatrixClientContext>;
private readonly dispatcherRef: string; private readonly dispatcherRef: string;
public constructor(props: IProps) { public constructor(props: IProps) {
@ -217,6 +221,7 @@ export default class GeneralUserSettingsTab extends React.Component<IProps, ISta
try { try {
const idAccessToken = await authClient.getAccessToken({ check: false }); const idAccessToken = await authClient.getAccessToken({ check: false });
await startTermsFlow( await startTermsFlow(
this.context,
[new Service(SERVICE_TYPES.IS, idServerUrl, idAccessToken!)], [new Service(SERVICE_TYPES.IS, idServerUrl, idAccessToken!)],
(policiesAndServices, agreedUrls, extraClassNames) => { (policiesAndServices, agreedUrls, extraClassNames) => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View file

@ -321,7 +321,7 @@ export default async function createRoom(client: MatrixClient, opts: IOpts): Pro
} }
}); });
if (opts.dmUserId) await Rooms.setDMRoom(roomId, opts.dmUserId); if (opts.dmUserId) await Rooms.setDMRoom(client, roomId, opts.dmUserId);
}) })
.then(() => { .then(() => {
if (opts.parentSpace) { if (opts.parentSpace) {

View file

@ -189,7 +189,7 @@ async function collectBugReport(opts: IOpts = {}, gzipLogs = true): Promise<Form
// compress // compress
if (gzipLogs) { if (gzipLogs) {
buf = pako.gzip(buf); buf = pako!.gzip(buf);
} }
body.append("compressed-log", new Blob([buf]), entry.id); body.append("compressed-log", new Blob([buf]), entry.id);

View file

@ -78,7 +78,7 @@ export class RoomEchoChamber extends GenericEchoChamber<RoomEchoContext, CachedR
CachedRoomKey.NotificationVolume, CachedRoomKey.NotificationVolume,
v, v,
async (): Promise<void> => { async (): Promise<void> => {
return setRoomNotifsState(this.context.room.roomId, v); return setRoomNotifsState(this.context.room.client, this.context.room.roomId, v);
}, },
implicitlyReverted, implicitlyReverted,
); );

View file

@ -35,6 +35,7 @@ import { ActionPayload } from "../../dispatcher/payloads";
import { Action } from "../../dispatcher/actions"; import { Action } from "../../dispatcher/actions";
import { ActiveRoomChangedPayload } from "../../dispatcher/payloads/ActiveRoomChangedPayload"; import { ActiveRoomChangedPayload } from "../../dispatcher/payloads/ActiveRoomChangedPayload";
import { SdkContextClass } from "../../contexts/SDKContext"; import { SdkContextClass } from "../../contexts/SDKContext";
import { MatrixClientPeg } from "../../MatrixClientPeg";
/** /**
* A class for tracking the state of the right panel between layouts and * A class for tracking the state of the right panel between layouts and
@ -308,7 +309,9 @@ export default class RightPanelStore extends ReadyWatchingStore {
if (card.phase === RightPanelPhases.RoomMemberInfo && card.state) { if (card.phase === RightPanelPhases.RoomMemberInfo && card.state) {
// RightPanelPhases.RoomMemberInfo -> needs to be changed to RightPanelPhases.EncryptionPanel if there is a pending verification request // RightPanelPhases.RoomMemberInfo -> needs to be changed to RightPanelPhases.EncryptionPanel if there is a pending verification request
const { member } = card.state; const { member } = card.state;
const pendingRequest = member ? pendingVerificationRequestForUser(member) : undefined; const pendingRequest = member
? pendingVerificationRequestForUser(MatrixClientPeg.get(), member)
: undefined;
if (pendingRequest) { if (pendingRequest) {
return { return {
phase: RightPanelPhases.EncryptionPanel, phase: RightPanelPhases.EncryptionPanel,
@ -341,7 +344,7 @@ export default class RightPanelStore extends ReadyWatchingStore {
if (!this.currentCard?.state) return; if (!this.currentCard?.state) return;
const { member } = this.currentCard.state; const { member } = this.currentCard.state;
if (!member) return; if (!member) return;
const pendingRequest = pendingVerificationRequestForUser(member); const pendingRequest = pendingVerificationRequestForUser(MatrixClientPeg.get(), member);
if (pendingRequest) { if (pendingRequest) {
this.currentCard.state.verificationRequest = pendingRequest; this.currentCard.state.verificationRequest = pendingRequest;
this.emitAndUpdateSettings(); this.emitAndUpdateSettings();

View file

@ -16,11 +16,10 @@ limitations under the License.
import { User } from "matrix-js-sdk/src/models/user"; import { User } from "matrix-js-sdk/src/models/user";
import { verificationMethods as VerificationMethods } from "matrix-js-sdk/src/crypto"; import { verificationMethods as VerificationMethods } from "matrix-js-sdk/src/crypto";
import { RoomMember } from "matrix-js-sdk/src/matrix"; import { MatrixClient, RoomMember } from "matrix-js-sdk/src/matrix";
import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest"; import { VerificationRequest } from "matrix-js-sdk/src/crypto/verification/request/VerificationRequest";
import { CrossSigningKey } from "matrix-js-sdk/src/crypto-api"; import { CrossSigningKey } from "matrix-js-sdk/src/crypto-api";
import { MatrixClientPeg } from "./MatrixClientPeg";
import dis from "./dispatcher/dispatcher"; import dis from "./dispatcher/dispatcher";
import Modal from "./Modal"; import Modal from "./Modal";
import { RightPanelPhases } from "./stores/right-panel/RightPanelStorePhases"; import { RightPanelPhases } from "./stores/right-panel/RightPanelStorePhases";
@ -32,9 +31,8 @@ import RightPanelStore from "./stores/right-panel/RightPanelStore";
import { IRightPanelCardState } from "./stores/right-panel/RightPanelStoreIPanelState"; import { IRightPanelCardState } from "./stores/right-panel/RightPanelStoreIPanelState";
import { findDMForUser } from "./utils/dm/findDMForUser"; import { findDMForUser } from "./utils/dm/findDMForUser";
async function enable4SIfNeeded(): Promise<boolean> { async function enable4SIfNeeded(matrixClient: MatrixClient): Promise<boolean> {
const cli = MatrixClientPeg.get(); const crypto = matrixClient.getCrypto();
const crypto = cli.getCrypto();
if (!crypto) return false; if (!crypto) return false;
const usk = await crypto.getCrossSigningKeyId(CrossSigningKey.UserSigning); const usk = await crypto.getCrossSigningKeyId(CrossSigningKey.UserSigning);
if (!usk) { if (!usk) {
@ -45,15 +43,14 @@ async function enable4SIfNeeded(): Promise<boolean> {
return true; return true;
} }
export async function verifyDevice(user: User, device: IDevice): Promise<void> { export async function verifyDevice(matrixClient: MatrixClient, user: User, device: IDevice): Promise<void> {
const cli = MatrixClientPeg.get(); if (matrixClient.isGuest()) {
if (cli.isGuest()) {
dis.dispatch({ action: "require_registration" }); dis.dispatch({ action: "require_registration" });
return; return;
} }
// if cross-signing is not explicitly disabled, check if it should be enabled first. // if cross-signing is not explicitly disabled, check if it should be enabled first.
if (cli.getCryptoTrustCrossSignedDevices()) { if (matrixClient.getCryptoTrustCrossSignedDevices()) {
if (!(await enable4SIfNeeded())) { if (!(await enable4SIfNeeded(matrixClient))) {
return; return;
} }
} }
@ -63,7 +60,7 @@ export async function verifyDevice(user: User, device: IDevice): Promise<void> {
device, device,
onFinished: async (action): Promise<void> => { onFinished: async (action): Promise<void> => {
if (action === "sas") { if (action === "sas") {
const verificationRequestPromise = cli.legacyDeviceVerification( const verificationRequestPromise = matrixClient.legacyDeviceVerification(
user.userId, user.userId,
device.deviceId, device.deviceId,
VerificationMethods.SAS, VerificationMethods.SAS,
@ -79,32 +76,30 @@ export async function verifyDevice(user: User, device: IDevice): Promise<void> {
}); });
} }
export async function legacyVerifyUser(user: User): Promise<void> { export async function legacyVerifyUser(matrixClient: MatrixClient, user: User): Promise<void> {
const cli = MatrixClientPeg.get(); if (matrixClient.isGuest()) {
if (cli.isGuest()) {
dis.dispatch({ action: "require_registration" }); dis.dispatch({ action: "require_registration" });
return; return;
} }
// if cross-signing is not explicitly disabled, check if it should be enabled first. // if cross-signing is not explicitly disabled, check if it should be enabled first.
if (cli.getCryptoTrustCrossSignedDevices()) { if (matrixClient.getCryptoTrustCrossSignedDevices()) {
if (!(await enable4SIfNeeded())) { if (!(await enable4SIfNeeded(matrixClient))) {
return; return;
} }
} }
const verificationRequestPromise = cli.requestVerification(user.userId); const verificationRequestPromise = matrixClient.requestVerification(user.userId);
setRightPanel({ member: user, verificationRequestPromise }); setRightPanel({ member: user, verificationRequestPromise });
} }
export async function verifyUser(user: User): Promise<void> { export async function verifyUser(matrixClient: MatrixClient, user: User): Promise<void> {
const cli = MatrixClientPeg.get(); if (matrixClient.isGuest()) {
if (cli.isGuest()) {
dis.dispatch({ action: "require_registration" }); dis.dispatch({ action: "require_registration" });
return; return;
} }
if (!(await enable4SIfNeeded())) { if (!(await enable4SIfNeeded(matrixClient))) {
return; return;
} }
const existingRequest = pendingVerificationRequestForUser(user); const existingRequest = pendingVerificationRequestForUser(matrixClient, user);
setRightPanel({ member: user, verificationRequest: existingRequest }); setRightPanel({ member: user, verificationRequest: existingRequest });
} }
@ -120,10 +115,12 @@ function setRightPanel(state: IRightPanelCardState): void {
} }
} }
export function pendingVerificationRequestForUser(user: User | RoomMember): VerificationRequest | undefined { export function pendingVerificationRequestForUser(
const cli = MatrixClientPeg.get(); matrixClient: MatrixClient,
const dmRoom = findDMForUser(cli, user.userId); user: User | RoomMember,
): VerificationRequest | undefined {
const dmRoom = findDMForUser(matrixClient, user.userId);
if (dmRoom) { if (dmRoom) {
return cli.findVerificationRequestDMInProgress(dmRoom.roomId); return matrixClient.findVerificationRequestDMInProgress(dmRoom.roomId);
} }
} }

View file

@ -59,8 +59,8 @@ const mockDispatcher = mocked(dis);
const flushPromises = async () => await new Promise(process.nextTick); const flushPromises = async () => await new Promise(process.nextTick);
describe("DeviceListener", () => { describe("DeviceListener", () => {
let mockClient: Mocked<MatrixClient> | undefined; let mockClient: Mocked<MatrixClient>;
let mockCrypto: Mocked<CryptoApi> | undefined; let mockCrypto: Mocked<CryptoApi>;
// spy on various toasts' hide and show functions // spy on various toasts' hide and show functions
// easier than mocking // easier than mocking
@ -111,7 +111,7 @@ describe("DeviceListener", () => {
const createAndStart = async (): Promise<DeviceListener> => { const createAndStart = async (): Promise<DeviceListener> => {
const instance = new DeviceListener(); const instance = new DeviceListener();
instance.start(); instance.start(mockClient);
await flushPromises(); await flushPromises();
return instance; return instance;
}; };

View file

@ -52,7 +52,7 @@ describe("setDMRoom", () => {
describe("when logged in as a guest and marking a room as DM", () => { describe("when logged in as a guest and marking a room as DM", () => {
beforeEach(() => { beforeEach(() => {
mocked(client.isGuest).mockReturnValue(true); mocked(client.isGuest).mockReturnValue(true);
setDMRoom(roomId1, userId1); setDMRoom(client, roomId1, userId1);
}); });
it("should not update the account data", () => { it("should not update the account data", () => {
@ -62,7 +62,7 @@ describe("setDMRoom", () => {
describe("when adding a new room to an existing DM relation", () => { describe("when adding a new room to an existing DM relation", () => {
beforeEach(() => { beforeEach(() => {
setDMRoom(roomId4, userId1); setDMRoom(client, roomId4, userId1);
}); });
it("should update the account data accordingly", () => { it("should update the account data accordingly", () => {
@ -75,7 +75,7 @@ describe("setDMRoom", () => {
describe("when adding a new DM room", () => { describe("when adding a new DM room", () => {
beforeEach(() => { beforeEach(() => {
setDMRoom(roomId4, userId3); setDMRoom(client, roomId4, userId3);
}); });
it("should update the account data accordingly", () => { it("should update the account data accordingly", () => {
@ -89,7 +89,7 @@ describe("setDMRoom", () => {
describe("when trying to add a DM, that already exists", () => { describe("when trying to add a DM, that already exists", () => {
beforeEach(() => { beforeEach(() => {
setDMRoom(roomId1, userId1); setDMRoom(client, roomId1, userId1);
}); });
it("should not update the account data", () => { it("should not update the account data", () => {
@ -99,7 +99,7 @@ describe("setDMRoom", () => {
describe("when removing an existing DM", () => { describe("when removing an existing DM", () => {
beforeEach(() => { beforeEach(() => {
setDMRoom(roomId1, null); setDMRoom(client, roomId1, null);
}); });
it("should update the account data accordingly", () => { it("should update the account data accordingly", () => {
@ -112,7 +112,7 @@ describe("setDMRoom", () => {
describe("when removing an unknown room", () => { describe("when removing an unknown room", () => {
beforeEach(() => { beforeEach(() => {
setDMRoom(roomId4, null); setDMRoom(client, roomId4, null);
}); });
it("should not update the account data", () => { it("should not update the account data", () => {
@ -123,7 +123,7 @@ describe("setDMRoom", () => {
describe("when the direct event is undefined", () => { describe("when the direct event is undefined", () => {
beforeEach(() => { beforeEach(() => {
mocked(client.getAccountData).mockReturnValue(undefined); mocked(client.getAccountData).mockReturnValue(undefined);
setDMRoom(roomId1, userId1); setDMRoom(client, roomId1, userId1);
}); });
it("should update the account data accordingly", () => { it("should update the account data accordingly", () => {
@ -139,7 +139,7 @@ describe("setDMRoom", () => {
mocked(client.getAccountData).mockReturnValue({ mocked(client.getAccountData).mockReturnValue({
getContent: jest.fn(), getContent: jest.fn(),
}); });
setDMRoom(roomId1, userId1); setDMRoom(client, roomId1, userId1);
}); });
it("should update the account data accordingly", () => { it("should update the account data accordingly", () => {

View file

@ -66,7 +66,7 @@ describe("Terms", function () {
}, },
}); });
const interactionCallback = jest.fn().mockResolvedValue([]); const interactionCallback = jest.fn().mockResolvedValue([]);
await startTermsFlow([IM_SERVICE_ONE], interactionCallback); await startTermsFlow(mockClient, [IM_SERVICE_ONE], interactionCallback);
expect(interactionCallback).toHaveBeenCalledWith( expect(interactionCallback).toHaveBeenCalledWith(
[ [
@ -97,7 +97,7 @@ describe("Terms", function () {
mockClient.agreeToTerms; mockClient.agreeToTerms;
const interactionCallback = jest.fn(); const interactionCallback = jest.fn();
await startTermsFlow([IM_SERVICE_ONE], interactionCallback); await startTermsFlow(mockClient, [IM_SERVICE_ONE], interactionCallback);
expect(interactionCallback).not.toHaveBeenCalled(); expect(interactionCallback).not.toHaveBeenCalled();
expect(mockClient.agreeToTerms).toHaveBeenCalledWith(SERVICE_TYPES.IM, "https://imone.test", "a token token", [ expect(mockClient.agreeToTerms).toHaveBeenCalledWith(SERVICE_TYPES.IM, "https://imone.test", "a token token", [
@ -122,7 +122,7 @@ describe("Terms", function () {
}); });
const interactionCallback = jest.fn().mockResolvedValue(["http://example.com/one", "http://example.com/two"]); const interactionCallback = jest.fn().mockResolvedValue(["http://example.com/one", "http://example.com/two"]);
await startTermsFlow([IM_SERVICE_ONE], interactionCallback); await startTermsFlow(mockClient, [IM_SERVICE_ONE], interactionCallback);
expect(interactionCallback).toHaveBeenCalledWith( expect(interactionCallback).toHaveBeenCalledWith(
[ [
@ -168,7 +168,7 @@ describe("Terms", function () {
}); });
const interactionCallback = jest.fn().mockResolvedValue(["http://example.com/one", "http://example.com/two"]); const interactionCallback = jest.fn().mockResolvedValue(["http://example.com/one", "http://example.com/two"]);
await startTermsFlow([IM_SERVICE_ONE, IM_SERVICE_TWO], interactionCallback); await startTermsFlow(mockClient, [IM_SERVICE_ONE, IM_SERVICE_TWO], interactionCallback);
expect(interactionCallback).toHaveBeenCalledWith( expect(interactionCallback).toHaveBeenCalledWith(
[ [

View file

@ -500,7 +500,7 @@ describe("<DeviceItem />", () => {
await userEvent.click(button); await userEvent.click(button);
expect(mockVerifyDevice).toHaveBeenCalledTimes(1); expect(mockVerifyDevice).toHaveBeenCalledTimes(1);
expect(mockVerifyDevice).toHaveBeenCalledWith(defaultUser, device); expect(mockVerifyDevice).toHaveBeenCalledWith(mockClient, defaultUser, device);
}); });
it("with display name", async () => { it("with display name", async () => {