mirror of
https://github.com/element-hq/element-web
synced 2024-11-22 01:05:42 +03:00
First batch: Replace MatrixClient.isRoomEncrypted
by MatrixClient.CryptoApi.isEncryptionEnabledInRoom
(#28242)
* Replace `MatrixClient.isRoomEncrypted` by `MatrixClient.CryptoApi.isEncryptionEnabledInRoom` in `DeviceListener.ts` * Replace `MatrixClient.isRoomEncrypted` by `MatrixClient.CryptoApi.isEncryptionEnabledInRoom` in `Searching.ts` * Replace `MatrixClient.isRoomEncrypted` by `MatrixClient.CryptoApi.isEncryptionEnabledInRoom` in `SlidingSyncManager.ts` * Replace `MatrixClient.isRoomEncrypted` by `MatrixClient.CryptoApi.isEncryptionEnabledInRoom` in `EncryptionEvent.tsx` * Replace `MatrixClient.isRoomEncrypted` by `MatrixClient.CryptoApi.isEncryptionEnabledInRoom` in `ReportEventDialog.tsx` * Replace `MatrixClient.isRoomEncrypted` by `MatrixClient.CryptoApi.isEncryptionEnabledInRoom` in `RoomNotifications.tsx` * Fix MessagePanel-test.tsx * ReplaceReplace `MatrixCient..isRoomEncrypted` by `MatrixClient.CryptoApi.isEncryptionEnabledInRoom` in `shouldSkipSetupEncryption.ts` * Add missing `await` * Use `Promise.any` instead of `asyncSome` * Add `asyncSomeParallel` * Use `asyncSomeParallel` instead of `asyncSome`
This commit is contained in:
parent
c8e4ffe1dd
commit
d4ab40990b
16 changed files with 129 additions and 43 deletions
|
@ -46,6 +46,7 @@ import SettingsStore, { CallbackFn } from "./settings/SettingsStore";
|
||||||
import { UIFeature } from "./settings/UIFeature";
|
import { UIFeature } from "./settings/UIFeature";
|
||||||
import { isBulkUnverifiedDeviceReminderSnoozed } from "./utils/device/snoozeBulkUnverifiedDeviceReminder";
|
import { isBulkUnverifiedDeviceReminderSnoozed } from "./utils/device/snoozeBulkUnverifiedDeviceReminder";
|
||||||
import { getUserDeviceIds } from "./utils/crypto/deviceInfo";
|
import { getUserDeviceIds } from "./utils/crypto/deviceInfo";
|
||||||
|
import { asyncSomeParallel } from "./utils/arrays.ts";
|
||||||
|
|
||||||
const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000;
|
const KEY_BACKUP_POLL_INTERVAL = 5 * 60 * 1000;
|
||||||
|
|
||||||
|
@ -240,13 +241,16 @@ export default class DeviceListener {
|
||||||
return this.keyBackupInfo;
|
return this.keyBackupInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
private shouldShowSetupEncryptionToast(): boolean {
|
private async shouldShowSetupEncryptionToast(): Promise<boolean> {
|
||||||
// If we're in the middle of a secret storage operation, we're likely
|
// If we're in the middle of a secret storage operation, we're likely
|
||||||
// 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 = this.client;
|
const cli = this.client;
|
||||||
return cli?.getRooms().some((r) => cli.isRoomEncrypted(r.roomId)) ?? false;
|
const cryptoApi = cli?.getCrypto();
|
||||||
|
if (!cli || !cryptoApi) return false;
|
||||||
|
|
||||||
|
return await asyncSomeParallel(cli.getRooms(), ({ roomId }) => cryptoApi.isEncryptionEnabledInRoom(roomId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private recheck(): void {
|
private recheck(): void {
|
||||||
|
@ -283,7 +287,7 @@ export default class DeviceListener {
|
||||||
hideSetupEncryptionToast();
|
hideSetupEncryptionToast();
|
||||||
|
|
||||||
this.checkKeyBackupStatus();
|
this.checkKeyBackupStatus();
|
||||||
} else if (this.shouldShowSetupEncryptionToast()) {
|
} else if (await this.shouldShowSetupEncryptionToast()) {
|
||||||
// make sure our keys are finished downloading
|
// make sure our keys are finished downloading
|
||||||
await crypto.getUserDeviceInfo([cli.getSafeUserId()]);
|
await crypto.getUserDeviceInfo([cli.getSafeUserId()]);
|
||||||
|
|
||||||
|
|
|
@ -596,7 +596,7 @@ async function combinedPagination(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function eventIndexSearch(
|
async function eventIndexSearch(
|
||||||
client: MatrixClient,
|
client: MatrixClient,
|
||||||
term: string,
|
term: string,
|
||||||
roomId?: string,
|
roomId?: string,
|
||||||
|
@ -605,7 +605,7 @@ function eventIndexSearch(
|
||||||
let searchPromise: Promise<ISearchResults>;
|
let searchPromise: Promise<ISearchResults>;
|
||||||
|
|
||||||
if (roomId !== undefined) {
|
if (roomId !== undefined) {
|
||||||
if (client.isRoomEncrypted(roomId)) {
|
if (await client.getCrypto()?.isEncryptionEnabledInRoom(roomId)) {
|
||||||
// The search is for a single encrypted room, use our local
|
// The search is for a single encrypted room, use our local
|
||||||
// search method.
|
// search method.
|
||||||
searchPromise = localSearchProcess(client, term, roomId);
|
searchPromise = localSearchProcess(client, term, roomId);
|
||||||
|
|
|
@ -229,7 +229,7 @@ export class SlidingSyncManager {
|
||||||
subscriptions.delete(roomId);
|
subscriptions.delete(roomId);
|
||||||
}
|
}
|
||||||
const room = this.client?.getRoom(roomId);
|
const room = this.client?.getRoom(roomId);
|
||||||
let shouldLazyLoad = !this.client?.isRoomEncrypted(roomId);
|
let shouldLazyLoad = !(await this.client?.getCrypto()?.isEncryptionEnabledInRoom(roomId));
|
||||||
if (!room) {
|
if (!room) {
|
||||||
// default to safety: request all state if we can't work it out. This can happen if you
|
// default to safety: request all state if we can't work it out. This can happen if you
|
||||||
// refresh the app whilst viewing a room: we call setRoomVisible before we know anything
|
// refresh the app whilst viewing a room: we call setRoomVisible before we know anything
|
||||||
|
|
|
@ -427,7 +427,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
(await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) &&
|
(await cli.doesServerSupportUnstableFeature("org.matrix.e2e_cross_signing")) &&
|
||||||
!shouldSkipSetupEncryption(cli)
|
!(await shouldSkipSetupEncryption(cli))
|
||||||
) {
|
) {
|
||||||
// if cross-signing is not yet set up, do so now if possible.
|
// if cross-signing is not yet set up, do so now if possible.
|
||||||
this.setStateForNewView({ view: Views.E2E_SETUP });
|
this.setStateForNewView({ view: Views.E2E_SETUP });
|
||||||
|
|
|
@ -43,6 +43,10 @@ interface IState {
|
||||||
// If we know it, the nature of the abuse, as specified by MSC3215.
|
// If we know it, the nature of the abuse, as specified by MSC3215.
|
||||||
nature?: ExtendedNature;
|
nature?: ExtendedNature;
|
||||||
ignoreUserToo: boolean; // if true, user will be ignored/blocked on submit
|
ignoreUserToo: boolean; // if true, user will be ignored/blocked on submit
|
||||||
|
/*
|
||||||
|
* Whether the room is encrypted.
|
||||||
|
*/
|
||||||
|
isRoomEncrypted: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MODERATED_BY_STATE_EVENT_TYPE = [
|
const MODERATED_BY_STATE_EVENT_TYPE = [
|
||||||
|
@ -188,9 +192,20 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
|
||||||
// If specified, the nature of the abuse, as specified by MSC3215.
|
// If specified, the nature of the abuse, as specified by MSC3215.
|
||||||
nature: undefined,
|
nature: undefined,
|
||||||
ignoreUserToo: false, // default false, for now. Could easily be argued as default true
|
ignoreUserToo: false, // default false, for now. Could easily be argued as default true
|
||||||
|
isRoomEncrypted: false, // async, will be set later
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public componentDidMount = async (): Promise<void> => {
|
||||||
|
const crypto = MatrixClientPeg.safeGet().getCrypto();
|
||||||
|
const roomId = this.props.mxEvent.getRoomId();
|
||||||
|
if (!crypto || !roomId) return;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
isRoomEncrypted: await crypto.isEncryptionEnabledInRoom(roomId),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
private onIgnoreUserTooChanged = (newVal: boolean): void => {
|
private onIgnoreUserTooChanged = (newVal: boolean): void => {
|
||||||
this.setState({ ignoreUserToo: newVal });
|
this.setState({ ignoreUserToo: newVal });
|
||||||
};
|
};
|
||||||
|
@ -319,7 +334,6 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
|
||||||
if (this.moderation) {
|
if (this.moderation) {
|
||||||
// Display report-to-moderator dialog.
|
// Display report-to-moderator dialog.
|
||||||
// We let the user pick a nature.
|
// We let the user pick a nature.
|
||||||
const client = MatrixClientPeg.safeGet();
|
|
||||||
const homeServerName = SdkConfig.get("validated_server_config")!.hsName;
|
const homeServerName = SdkConfig.get("validated_server_config")!.hsName;
|
||||||
let subtitle: string;
|
let subtitle: string;
|
||||||
switch (this.state.nature) {
|
switch (this.state.nature) {
|
||||||
|
@ -336,7 +350,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
|
||||||
subtitle = _t("report_content|nature_spam");
|
subtitle = _t("report_content|nature_spam");
|
||||||
break;
|
break;
|
||||||
case NonStandardValue.Admin:
|
case NonStandardValue.Admin:
|
||||||
if (client.isRoomEncrypted(this.props.mxEvent.getRoomId()!)) {
|
if (this.state.isRoomEncrypted) {
|
||||||
subtitle = _t("report_content|nature_nonstandard_admin_encrypted", {
|
subtitle = _t("report_content|nature_nonstandard_admin_encrypted", {
|
||||||
homeserver: homeServerName,
|
homeserver: homeServerName,
|
||||||
});
|
});
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { determineUnreadState } from "../../../../RoomNotifs";
|
||||||
import { humanReadableNotificationLevel } from "../../../../stores/notifications/NotificationLevel";
|
import { humanReadableNotificationLevel } from "../../../../stores/notifications/NotificationLevel";
|
||||||
import { doesRoomOrThreadHaveUnreadMessages } from "../../../../Unread";
|
import { doesRoomOrThreadHaveUnreadMessages } from "../../../../Unread";
|
||||||
import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
|
import BaseTool, { DevtoolsContext, IDevtoolsProps } from "./BaseTool";
|
||||||
|
import { useIsEncrypted } from "../../../../hooks/useIsEncrypted.ts";
|
||||||
|
|
||||||
function UserReadUpTo({ target }: { target: ReadReceipt<any, any> }): JSX.Element {
|
function UserReadUpTo({ target }: { target: ReadReceipt<any, any> }): JSX.Element {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
|
@ -59,6 +60,7 @@ function UserReadUpTo({ target }: { target: ReadReceipt<any, any> }): JSX.Elemen
|
||||||
export default function RoomNotifications({ onBack }: IDevtoolsProps): JSX.Element {
|
export default function RoomNotifications({ onBack }: IDevtoolsProps): JSX.Element {
|
||||||
const { room } = useContext(DevtoolsContext);
|
const { room } = useContext(DevtoolsContext);
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
|
const isRoomEncrypted = useIsEncrypted(cli, room);
|
||||||
|
|
||||||
const { level, count } = determineUnreadState(room, undefined, false);
|
const { level, count } = determineUnreadState(room, undefined, false);
|
||||||
const [notificationState] = useNotificationState(room);
|
const [notificationState] = useNotificationState(room);
|
||||||
|
@ -93,9 +95,7 @@ export default function RoomNotifications({ onBack }: IDevtoolsProps): JSX.Eleme
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
{_t(
|
{_t(
|
||||||
cli.isRoomEncrypted(room.roomId!)
|
isRoomEncrypted ? _td("devtools|room_encrypted") : _td("devtools|room_not_encrypted"),
|
||||||
? _td("devtools|room_encrypted")
|
|
||||||
: _td("devtools|room_not_encrypted"),
|
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
strong: (sub) => <strong>{sub}</strong>,
|
strong: (sub) => <strong>{sub}</strong>,
|
||||||
|
|
|
@ -6,18 +6,18 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
|
||||||
Please see LICENSE files in the repository root for full details.
|
Please see LICENSE files in the repository root for full details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { forwardRef, useContext } from "react";
|
import React, { forwardRef } from "react";
|
||||||
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
import { MatrixEvent } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import type { RoomEncryptionEventContent } from "matrix-js-sdk/src/types";
|
import type { RoomEncryptionEventContent } from "matrix-js-sdk/src/types";
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
|
||||||
import EventTileBubble from "./EventTileBubble";
|
import EventTileBubble from "./EventTileBubble";
|
||||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
import { useMatrixClientContext } from "../../../contexts/MatrixClientContext";
|
||||||
import DMRoomMap from "../../../utils/DMRoomMap";
|
import DMRoomMap from "../../../utils/DMRoomMap";
|
||||||
import { objectHasDiff } from "../../../utils/objects";
|
import { objectHasDiff } from "../../../utils/objects";
|
||||||
import { isLocalRoom } from "../../../utils/localRoom/isLocalRoom";
|
import { isLocalRoom } from "../../../utils/localRoom/isLocalRoom";
|
||||||
import { MEGOLM_ENCRYPTION_ALGORITHM } from "../../../utils/crypto";
|
import { MEGOLM_ENCRYPTION_ALGORITHM } from "../../../utils/crypto";
|
||||||
|
import { useIsEncrypted } from "../../../hooks/useIsEncrypted.ts";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
mxEvent: MatrixEvent;
|
mxEvent: MatrixEvent;
|
||||||
|
@ -25,9 +25,9 @@ interface IProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent, timestamp }, ref) => {
|
const EncryptionEvent = forwardRef<HTMLDivElement, IProps>(({ mxEvent, timestamp }, ref) => {
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useMatrixClientContext();
|
||||||
const roomId = mxEvent.getRoomId()!;
|
const roomId = mxEvent.getRoomId()!;
|
||||||
const isRoomEncrypted = MatrixClientPeg.safeGet().isRoomEncrypted(roomId);
|
const isRoomEncrypted = useIsEncrypted(cli, cli.getRoom(roomId) || undefined);
|
||||||
|
|
||||||
const prevContent = mxEvent.getPrevContent() as RoomEncryptionEventContent;
|
const prevContent = mxEvent.getPrevContent() as RoomEncryptionEventContent;
|
||||||
const content = mxEvent.getContent<RoomEncryptionEventContent>();
|
const content = mxEvent.getContent<RoomEncryptionEventContent>();
|
||||||
|
|
|
@ -328,6 +328,28 @@ export async function asyncSome<T>(values: Iterable<T>, predicate: (value: T) =>
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Async version of Array.some that runs all promises in parallel.
|
||||||
|
* @param values
|
||||||
|
* @param predicate
|
||||||
|
*/
|
||||||
|
export async function asyncSomeParallel<T>(
|
||||||
|
values: Array<T>,
|
||||||
|
predicate: (value: T) => Promise<boolean>,
|
||||||
|
): Promise<boolean> {
|
||||||
|
try {
|
||||||
|
return await Promise.any<boolean>(
|
||||||
|
values.map((value) =>
|
||||||
|
predicate(value).then((result) => (result ? Promise.resolve(true) : Promise.reject(false))),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
// If the array is empty or all the promises are false, Promise.any will reject an AggregateError
|
||||||
|
if (e instanceof AggregateError) return false;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function filterBoolean<T>(values: Array<T | null | undefined>): T[] {
|
export function filterBoolean<T>(values: Array<T | null | undefined>): T[] {
|
||||||
return values.filter(Boolean) as T[];
|
return values.filter(Boolean) as T[];
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ Please see LICENSE files in the repository root for full details.
|
||||||
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
import { shouldForceDisableEncryption } from "./shouldForceDisableEncryption";
|
import { shouldForceDisableEncryption } from "./shouldForceDisableEncryption";
|
||||||
|
import { asyncSomeParallel } from "../arrays.ts";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If encryption is force disabled AND the user is not in any encrypted rooms
|
* If encryption is force disabled AND the user is not in any encrypted rooms
|
||||||
|
@ -16,7 +17,13 @@ import { shouldForceDisableEncryption } from "./shouldForceDisableEncryption";
|
||||||
* @param client
|
* @param client
|
||||||
* @returns {boolean} true when we can skip settings up encryption
|
* @returns {boolean} true when we can skip settings up encryption
|
||||||
*/
|
*/
|
||||||
export const shouldSkipSetupEncryption = (client: MatrixClient): boolean => {
|
export const shouldSkipSetupEncryption = async (client: MatrixClient): Promise<boolean> => {
|
||||||
const isEncryptionForceDisabled = shouldForceDisableEncryption(client);
|
const isEncryptionForceDisabled = shouldForceDisableEncryption(client);
|
||||||
return isEncryptionForceDisabled && !client.getRooms().some((r) => client.isRoomEncrypted(r.roomId));
|
const crypto = client.getCrypto();
|
||||||
|
if (!crypto) return true;
|
||||||
|
|
||||||
|
return (
|
||||||
|
isEncryptionForceDisabled &&
|
||||||
|
!(await asyncSomeParallel(client.getRooms(), ({ roomId }) => crypto.isEncryptionEnabledInRoom(roomId)))
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -162,6 +162,7 @@ export const mockClientMethodsCrypto = (): Partial<
|
||||||
getVersion: jest.fn().mockReturnValue("Version 0"),
|
getVersion: jest.fn().mockReturnValue("Version 0"),
|
||||||
getOwnDeviceKeys: jest.fn().mockReturnValue(new Promise(() => {})),
|
getOwnDeviceKeys: jest.fn().mockReturnValue(new Promise(() => {})),
|
||||||
getCrossSigningKeyId: jest.fn(),
|
getCrossSigningKeyId: jest.fn(),
|
||||||
|
isEncryptionEnabledInRoom: jest.fn().mockResolvedValue(false),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,7 @@ describe("DeviceListener", () => {
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
getSessionBackupPrivateKey: jest.fn(),
|
getSessionBackupPrivateKey: jest.fn(),
|
||||||
|
isEncryptionEnabledInRoom: jest.fn(),
|
||||||
} as unknown as Mocked<CryptoApi>;
|
} as unknown as Mocked<CryptoApi>;
|
||||||
mockClient = getMockClientWithEventEmitter({
|
mockClient = getMockClientWithEventEmitter({
|
||||||
isGuest: jest.fn(),
|
isGuest: jest.fn(),
|
||||||
|
@ -105,7 +106,6 @@ describe("DeviceListener", () => {
|
||||||
isVersionSupported: jest.fn().mockResolvedValue(true),
|
isVersionSupported: jest.fn().mockResolvedValue(true),
|
||||||
isInitialSyncComplete: jest.fn().mockReturnValue(true),
|
isInitialSyncComplete: jest.fn().mockReturnValue(true),
|
||||||
waitForClientWellKnown: jest.fn(),
|
waitForClientWellKnown: jest.fn(),
|
||||||
isRoomEncrypted: jest.fn(),
|
|
||||||
getClientWellKnown: jest.fn(),
|
getClientWellKnown: jest.fn(),
|
||||||
getDeviceId: jest.fn().mockReturnValue(deviceId),
|
getDeviceId: jest.fn().mockReturnValue(deviceId),
|
||||||
setAccountData: jest.fn(),
|
setAccountData: jest.fn(),
|
||||||
|
@ -292,7 +292,7 @@ describe("DeviceListener", () => {
|
||||||
mockCrypto!.isCrossSigningReady.mockResolvedValue(false);
|
mockCrypto!.isCrossSigningReady.mockResolvedValue(false);
|
||||||
mockCrypto!.isSecretStorageReady.mockResolvedValue(false);
|
mockCrypto!.isSecretStorageReady.mockResolvedValue(false);
|
||||||
mockClient!.getRooms.mockReturnValue(rooms);
|
mockClient!.getRooms.mockReturnValue(rooms);
|
||||||
mockClient!.isRoomEncrypted.mockReturnValue(true);
|
jest.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("hides setup encryption toast when cross signing and secret storage are ready", async () => {
|
it("hides setup encryption toast when cross signing and secret storage are ready", async () => {
|
||||||
|
@ -317,7 +317,7 @@ describe("DeviceListener", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not show any toasts when no rooms are encrypted", async () => {
|
it("does not show any toasts when no rooms are encrypted", async () => {
|
||||||
mockClient!.isRoomEncrypted.mockReturnValue(false);
|
jest.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(false);
|
||||||
await createAndStart();
|
await createAndStart();
|
||||||
|
|
||||||
expect(SetupEncryptionToast.showToast).not.toHaveBeenCalled();
|
expect(SetupEncryptionToast.showToast).not.toHaveBeenCalled();
|
||||||
|
|
|
@ -146,7 +146,6 @@ describe("<MatrixChat />", () => {
|
||||||
matrixRTC: createStubMatrixRTC(),
|
matrixRTC: createStubMatrixRTC(),
|
||||||
getDehydratedDevice: jest.fn(),
|
getDehydratedDevice: jest.fn(),
|
||||||
whoami: jest.fn(),
|
whoami: jest.fn(),
|
||||||
isRoomEncrypted: jest.fn(),
|
|
||||||
logout: jest.fn(),
|
logout: jest.fn(),
|
||||||
getDeviceId: jest.fn(),
|
getDeviceId: jest.fn(),
|
||||||
getKeyBackupVersion: jest.fn().mockResolvedValue(null),
|
getKeyBackupVersion: jest.fn().mockResolvedValue(null),
|
||||||
|
@ -1011,6 +1010,7 @@ describe("<MatrixChat />", () => {
|
||||||
userHasCrossSigningKeys: jest.fn().mockResolvedValue(false),
|
userHasCrossSigningKeys: jest.fn().mockResolvedValue(false),
|
||||||
// This needs to not finish immediately because we need to test the screen appears
|
// This needs to not finish immediately because we need to test the screen appears
|
||||||
bootstrapCrossSigning: jest.fn().mockImplementation(() => bootstrapDeferred.promise),
|
bootstrapCrossSigning: jest.fn().mockImplementation(() => bootstrapDeferred.promise),
|
||||||
|
isEncryptionEnabledInRoom: jest.fn().mockResolvedValue(false),
|
||||||
};
|
};
|
||||||
loginClient.getCrypto.mockReturnValue(mockCrypto as any);
|
loginClient.getCrypto.mockReturnValue(mockCrypto as any);
|
||||||
});
|
});
|
||||||
|
@ -1058,9 +1058,11 @@ describe("<MatrixChat />", () => {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
loginClient.isRoomEncrypted.mockImplementation((roomId) => {
|
jest.spyOn(loginClient.getCrypto()!, "isEncryptionEnabledInRoom").mockImplementation(
|
||||||
return roomId === encryptedRoom.roomId;
|
async (roomId) => {
|
||||||
});
|
return roomId === encryptedRoom.roomId;
|
||||||
|
},
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should go straight to logged in view when user is not in any encrypted rooms", async () => {
|
it("should go straight to logged in view when user is not in any encrypted rooms", async () => {
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
createTestClient,
|
createTestClient,
|
||||||
getMockClientWithEventEmitter,
|
getMockClientWithEventEmitter,
|
||||||
makeBeaconInfoEvent,
|
makeBeaconInfoEvent,
|
||||||
|
mockClientMethodsCrypto,
|
||||||
mockClientMethodsEvents,
|
mockClientMethodsEvents,
|
||||||
mockClientMethodsUser,
|
mockClientMethodsUser,
|
||||||
} from "../../../test-utils";
|
} from "../../../test-utils";
|
||||||
|
@ -42,6 +43,7 @@ describe("MessagePanel", function () {
|
||||||
const client = getMockClientWithEventEmitter({
|
const client = getMockClientWithEventEmitter({
|
||||||
...mockClientMethodsUser(userId),
|
...mockClientMethodsUser(userId),
|
||||||
...mockClientMethodsEvents(),
|
...mockClientMethodsEvents(),
|
||||||
|
...mockClientMethodsCrypto(),
|
||||||
getAccountData: jest.fn(),
|
getAccountData: jest.fn(),
|
||||||
isUserIgnored: jest.fn().mockReturnValue(false),
|
isUserIgnored: jest.fn().mockReturnValue(false),
|
||||||
isRoomEncrypted: jest.fn().mockReturnValue(false),
|
isRoomEncrypted: jest.fn().mockReturnValue(false),
|
||||||
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
SearchResult,
|
SearchResult,
|
||||||
IEvent,
|
IEvent,
|
||||||
} from "matrix-js-sdk/src/matrix";
|
} from "matrix-js-sdk/src/matrix";
|
||||||
|
import { CryptoApi, UserVerificationStatus } from "matrix-js-sdk/src/crypto-api";
|
||||||
import { KnownMembership } from "matrix-js-sdk/src/types";
|
import { KnownMembership } from "matrix-js-sdk/src/types";
|
||||||
import { fireEvent, render, screen, RenderResult, waitForElementToBeRemoved, waitFor } from "jest-matrix-react";
|
import { fireEvent, render, screen, RenderResult, waitForElementToBeRemoved, waitFor } from "jest-matrix-react";
|
||||||
import userEvent from "@testing-library/user-event";
|
import userEvent from "@testing-library/user-event";
|
||||||
|
@ -72,6 +73,7 @@ describe("RoomView", () => {
|
||||||
let rooms: Map<string, Room>;
|
let rooms: Map<string, Room>;
|
||||||
let roomCount = 0;
|
let roomCount = 0;
|
||||||
let stores: SdkContextClass;
|
let stores: SdkContextClass;
|
||||||
|
let crypto: CryptoApi;
|
||||||
|
|
||||||
// mute some noise
|
// mute some noise
|
||||||
filterConsole("RVS update", "does not have an m.room.create event", "Current version: 1", "Version capability");
|
filterConsole("RVS update", "does not have an m.room.create event", "Current version: 1", "Version capability");
|
||||||
|
@ -97,6 +99,7 @@ describe("RoomView", () => {
|
||||||
stores.rightPanelStore.useUnitTestClient(cli);
|
stores.rightPanelStore.useUnitTestClient(cli);
|
||||||
|
|
||||||
jest.spyOn(VoipUserMapper.sharedInstance(), "getVirtualRoomForRoom").mockResolvedValue(undefined);
|
jest.spyOn(VoipUserMapper.sharedInstance(), "getVirtualRoomForRoom").mockResolvedValue(undefined);
|
||||||
|
crypto = cli.getCrypto()!;
|
||||||
jest.spyOn(cli, "getCrypto").mockReturnValue(undefined);
|
jest.spyOn(cli, "getCrypto").mockReturnValue(undefined);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -341,7 +344,13 @@ describe("RoomView", () => {
|
||||||
|
|
||||||
describe("that is encrypted", () => {
|
describe("that is encrypted", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
// Not all the calls to cli.isRoomEncrypted are migrated, so we need to mock both.
|
||||||
mocked(cli.isRoomEncrypted).mockReturnValue(true);
|
mocked(cli.isRoomEncrypted).mockReturnValue(true);
|
||||||
|
jest.spyOn(cli, "getCrypto").mockReturnValue(crypto);
|
||||||
|
jest.spyOn(cli.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true);
|
||||||
|
jest.spyOn(cli.getCrypto()!, "getUserVerificationStatus").mockResolvedValue(
|
||||||
|
new UserVerificationStatus(false, true, false),
|
||||||
|
);
|
||||||
localRoom.encrypted = true;
|
localRoom.encrypted = true;
|
||||||
localRoom.currentState.setStateEvents([
|
localRoom.currentState.setStateEvents([
|
||||||
new MatrixEvent({
|
new MatrixEvent({
|
||||||
|
@ -360,7 +369,7 @@ describe("RoomView", () => {
|
||||||
|
|
||||||
it("should match the snapshot", async () => {
|
it("should match the snapshot", async () => {
|
||||||
const { container } = await renderRoomView();
|
const { container } = await renderRoomView();
|
||||||
expect(container).toMatchSnapshot();
|
await waitFor(() => expect(container).toMatchSnapshot());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -10,6 +10,7 @@ import React from "react";
|
||||||
import { mocked } from "jest-mock";
|
import { mocked } from "jest-mock";
|
||||||
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
import { MatrixClient, MatrixEvent, Room } from "matrix-js-sdk/src/matrix";
|
||||||
import { render, screen } from "jest-matrix-react";
|
import { render, screen } from "jest-matrix-react";
|
||||||
|
import { waitFor } from "@testing-library/dom";
|
||||||
|
|
||||||
import EncryptionEvent from "../../../../../src/components/views/messages/EncryptionEvent";
|
import EncryptionEvent from "../../../../../src/components/views/messages/EncryptionEvent";
|
||||||
import { createTestClient, mkMessage } from "../../../../test-utils";
|
import { createTestClient, mkMessage } from "../../../../test-utils";
|
||||||
|
@ -55,17 +56,19 @@ describe("EncryptionEvent", () => {
|
||||||
describe("for an encrypted room", () => {
|
describe("for an encrypted room", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
event.event.content!.algorithm = algorithm;
|
event.event.content!.algorithm = algorithm;
|
||||||
mocked(client.isRoomEncrypted).mockReturnValue(true);
|
jest.spyOn(client.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true);
|
||||||
const room = new Room(roomId, client, client.getUserId()!);
|
const room = new Room(roomId, client, client.getUserId()!);
|
||||||
mocked(client.getRoom).mockReturnValue(room);
|
mocked(client.getRoom).mockReturnValue(room);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the expected texts", () => {
|
it("should show the expected texts", async () => {
|
||||||
renderEncryptionEvent(client, event);
|
renderEncryptionEvent(client, event);
|
||||||
checkTexts(
|
await waitFor(() =>
|
||||||
"Encryption enabled",
|
checkTexts(
|
||||||
"Messages in this room are end-to-end encrypted. " +
|
"Encryption enabled",
|
||||||
"When people join, you can verify them in their profile, just tap on their profile picture.",
|
"Messages in this room are end-to-end encrypted. " +
|
||||||
|
"When people join, you can verify them in their profile, just tap on their profile picture.",
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -76,9 +79,9 @@ describe("EncryptionEvent", () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the expected texts", () => {
|
it("should show the expected texts", async () => {
|
||||||
renderEncryptionEvent(client, event);
|
renderEncryptionEvent(client, event);
|
||||||
checkTexts("Encryption enabled", "Some encryption parameters have been changed.");
|
await waitFor(() => checkTexts("Encryption enabled", "Some encryption parameters have been changed."));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -87,36 +90,38 @@ describe("EncryptionEvent", () => {
|
||||||
event.event.content!.algorithm = "unknown";
|
event.event.content!.algorithm = "unknown";
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the expected texts", () => {
|
it("should show the expected texts", async () => {
|
||||||
renderEncryptionEvent(client, event);
|
renderEncryptionEvent(client, event);
|
||||||
checkTexts("Encryption enabled", "Ignored attempt to disable encryption");
|
await waitFor(() => checkTexts("Encryption enabled", "Ignored attempt to disable encryption"));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("for an unencrypted room", () => {
|
describe("for an unencrypted room", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mocked(client.isRoomEncrypted).mockReturnValue(false);
|
jest.spyOn(client.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(false);
|
||||||
renderEncryptionEvent(client, event);
|
renderEncryptionEvent(client, event);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the expected texts", () => {
|
it("should show the expected texts", async () => {
|
||||||
expect(client.isRoomEncrypted).toHaveBeenCalledWith(roomId);
|
expect(client.getCrypto()!.isEncryptionEnabledInRoom).toHaveBeenCalledWith(roomId);
|
||||||
checkTexts("Encryption not enabled", "The encryption used by this room isn't supported.");
|
await waitFor(() =>
|
||||||
|
checkTexts("Encryption not enabled", "The encryption used by this room isn't supported."),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("for an encrypted local room", () => {
|
describe("for an encrypted local room", () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
event.event.content!.algorithm = algorithm;
|
event.event.content!.algorithm = algorithm;
|
||||||
mocked(client.isRoomEncrypted).mockReturnValue(true);
|
jest.spyOn(client.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true);
|
||||||
const localRoom = new LocalRoom(roomId, client, client.getUserId()!);
|
const localRoom = new LocalRoom(roomId, client, client.getUserId()!);
|
||||||
mocked(client.getRoom).mockReturnValue(localRoom);
|
mocked(client.getRoom).mockReturnValue(localRoom);
|
||||||
renderEncryptionEvent(client, event);
|
renderEncryptionEvent(client, event);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the expected texts", () => {
|
it("should show the expected texts", () => {
|
||||||
expect(client.isRoomEncrypted).toHaveBeenCalledWith(roomId);
|
expect(client.getCrypto()!.isEncryptionEnabledInRoom).toHaveBeenCalledWith(roomId);
|
||||||
checkTexts("Encryption enabled", "Messages in this chat will be end-to-end encrypted.");
|
checkTexts("Encryption enabled", "Messages in this chat will be end-to-end encrypted.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
concat,
|
concat,
|
||||||
asyncEvery,
|
asyncEvery,
|
||||||
asyncSome,
|
asyncSome,
|
||||||
|
asyncSomeParallel,
|
||||||
} from "../../../src/utils/arrays";
|
} from "../../../src/utils/arrays";
|
||||||
|
|
||||||
type TestParams = { input: number[]; output: number[] };
|
type TestParams = { input: number[]; output: number[] };
|
||||||
|
@ -460,4 +461,23 @@ describe("arrays", () => {
|
||||||
expect(predicate).toHaveBeenCalledWith(2);
|
expect(predicate).toHaveBeenCalledWith(2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("asyncSomeParallel", () => {
|
||||||
|
it("when called with an empty array, it should return false", async () => {
|
||||||
|
expect(await asyncSomeParallel([], jest.fn().mockResolvedValue(true))).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when all the predicates return false", async () => {
|
||||||
|
expect(await asyncSomeParallel([1, 2, 3], jest.fn().mockResolvedValue(false))).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when all the predicates return true", async () => {
|
||||||
|
expect(await asyncSomeParallel([1, 2, 3], jest.fn().mockResolvedValue(true))).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("when one of the predicate return true", async () => {
|
||||||
|
const predicate = jest.fn().mockImplementation((value) => Promise.resolve(value === 2));
|
||||||
|
expect(await asyncSomeParallel([1, 2, 3], predicate)).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue