From dc965c3b289e4196b62f94081604d9a1328e123c Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Thu, 21 Nov 2024 10:31:55 +0100 Subject: [PATCH] Replace `MatrixClient.isRoomEncrypted` by `MatrixClient.CryptoApi.isEncryptionEnabledInRoom` in `EventTile.tsx` --- src/components/views/rooms/EventTile.tsx | 34 +++++++++++++++++-- test/test-utils/test-utils.ts | 1 + .../views/dialogs/ForwardDialog-test.tsx | 3 +- .../components/views/rooms/EventTile-test.tsx | 28 ++++++++++++++- 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 22da73bef7f..c49c75c2187 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -11,6 +11,7 @@ import React, { createRef, forwardRef, JSX, MouseEvent, ReactNode } from "react" import classNames from "classnames"; import { EventStatus, + EventTimeline, EventType, MatrixEvent, MatrixEventEvent, @@ -21,6 +22,7 @@ import { Room, RoomEvent, RoomMember, + RoomStateEvent, Thread, ThreadEvent, } from "matrix-js-sdk/src/matrix"; @@ -262,6 +264,10 @@ interface IState { thread: Thread | null; threadNotification?: NotificationCountType; + /** + * Whether the event is encrypted. + */ + isRoomEncrypted: boolean; } /** @@ -318,6 +324,7 @@ export class UnwrappedEventTile extends React.Component hover: false, thread, + isRoomEncrypted: false, }; // don't do RR animations until we are mounted @@ -386,7 +393,7 @@ export class UnwrappedEventTile extends React.Component return true; } - public componentDidMount(): void { + public async componentDidMount(): Promise { this.unmounted = false; this.suppressReadReceiptAnimation = false; const client = MatrixClientPeg.safeGet(); @@ -413,6 +420,12 @@ export class UnwrappedEventTile extends React.Component room?.on(ThreadEvent.New, this.onNewThread); this.verifyEvent(); + + room?.getLiveTimeline().getState(EventTimeline.FORWARDS)?.on(RoomStateEvent.Events, this.onRoomStateEvents); + + const crypto = client.getCrypto(); + if (!room || !crypto) return; + this.setState({ isRoomEncrypted: await crypto.isEncryptionEnabledInRoom(room.roomId) }); } private updateThread = (thread: Thread): void => { @@ -434,6 +447,10 @@ export class UnwrappedEventTile extends React.Component client.removeListener(RoomEvent.Receipt, this.onRoomReceipt); const room = client.getRoom(this.props.mxEvent.getRoomId()); room?.off(ThreadEvent.New, this.onNewThread); + room + ?.getLiveTimeline() + .getState(EventTimeline.FORWARDS) + ?.off(RoomStateEvent.Events, this.onRoomStateEvents); } this.isListeningForReceipts = false; this.props.mxEvent.removeListener(MatrixEventEvent.Decrypted, this.onDecrypted); @@ -470,6 +487,17 @@ export class UnwrappedEventTile extends React.Component } }; + private onRoomStateEvents = async (evt: MatrixEvent): Promise => { + const client = MatrixClientPeg.safeGet(); + const crypto = client.getCrypto(); + if (!crypto) return; + + const room = client.getRoom(evt.getRoomId()); + if (room && evt.getType() === EventType.RoomEncryption) { + this.setState({ isRoomEncrypted: await crypto.isEncryptionEnabledInRoom(room.roomId) }); + } + }; + private get thread(): Thread | null { let thread: Thread | undefined = this.props.mxEvent.getThread(); /** @@ -767,7 +795,8 @@ export class UnwrappedEventTile extends React.Component } } - if (MatrixClientPeg.safeGet().isRoomEncrypted(ev.getRoomId()!)) { + console.log("this.state.isRoomEncrypted", this.state.isRoomEncrypted); + if (this.state.isRoomEncrypted) { // else if room is encrypted // and event is being encrypted or is not_sent (Unknown Devices/Network Error) if (ev.status === EventStatus.ENCRYPTING) { @@ -783,6 +812,7 @@ export class UnwrappedEventTile extends React.Component return null; // we expect this to be unencrypted } if (!ev.isEncrypted()) { + console.log("pad lock unencrypted"); // if the event is not encrypted, but it's an e2e room, show a warning return ; } diff --git a/test/test-utils/test-utils.ts b/test/test-utils/test-utils.ts index 78481c2fd06..790f39d018e 100644 --- a/test/test-utils/test-utils.ts +++ b/test/test-utils/test-utils.ts @@ -135,6 +135,7 @@ export function createTestClient(): MatrixClient { restoreKeyBackupWithPassphrase: jest.fn(), loadSessionBackupPrivateKeyFromSecretStorage: jest.fn(), storeSessionBackupPrivateKey: jest.fn(), + getEncryptionInfoForEvent: jest.fn().mockResolvedValue(null), }), getPushActionsForEvent: jest.fn(), diff --git a/test/unit-tests/components/views/dialogs/ForwardDialog-test.tsx b/test/unit-tests/components/views/dialogs/ForwardDialog-test.tsx index 6942f76cda0..2912f47f277 100644 --- a/test/unit-tests/components/views/dialogs/ForwardDialog-test.tsx +++ b/test/unit-tests/components/views/dialogs/ForwardDialog-test.tsx @@ -32,6 +32,7 @@ import { mkEvent, mkMessage, mkStubRoom, + mockClientMethodsCrypto, mockPlatformPeg, } from "../../../../test-utils"; import { TILE_SERVER_WK_KEY } from "../../../../../src/utils/WellKnownUtils"; @@ -67,7 +68,6 @@ describe("ForwardDialog", () => { getAccountData: jest.fn().mockReturnValue(accountDataEvent), getPushActionsForEvent: jest.fn(), mxcUrlToHttp: jest.fn().mockReturnValue(""), - isRoomEncrypted: jest.fn().mockReturnValue(false), getProfileInfo: jest.fn().mockResolvedValue({ displayname: "Alice", }), @@ -76,6 +76,7 @@ describe("ForwardDialog", () => { getClientWellKnown: jest.fn().mockReturnValue({ [TILE_SERVER_WK_KEY.name]: { map_style_url: "maps.com" }, }), + ...mockClientMethodsCrypto(), }); const defaultRooms = ["a", "A", "b"].map((name) => mkStubRoom(name, name, mockClient)); diff --git a/test/unit-tests/components/views/rooms/EventTile-test.tsx b/test/unit-tests/components/views/rooms/EventTile-test.tsx index 4cb22967608..7400b399b58 100644 --- a/test/unit-tests/components/views/rooms/EventTile-test.tsx +++ b/test/unit-tests/components/views/rooms/EventTile-test.tsx @@ -10,6 +10,7 @@ import * as React from "react"; import { act, fireEvent, render, screen, waitFor } from "jest-matrix-react"; import { mocked } from "jest-mock"; import { + EventTimeline, EventType, IEventDecryptionResult, MatrixClient, @@ -17,6 +18,7 @@ import { NotificationCountType, PendingEventOrdering, Room, + RoomStateEvent, TweakName, } from "matrix-js-sdk/src/matrix"; import { @@ -243,6 +245,7 @@ describe("EventTile", () => { const mockCrypto = { // a mocked version of getEncryptionInfoForEvent which will pick its result from `eventToEncryptionInfoMap` getEncryptionInfoForEvent: async (event: MatrixEvent) => eventToEncryptionInfoMap.get(event.getId()!)!, + isEncryptionEnabledInRoom: jest.fn().mockResolvedValue(false), } as unknown as CryptoApi; client.getCrypto = () => mockCrypto; }); @@ -434,7 +437,7 @@ describe("EventTile", () => { }); it("should update the warning when the event is replaced with an unencrypted one", async () => { - jest.spyOn(client, "isRoomEncrypted").mockReturnValue(true); + jest.spyOn(client.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true); // we start out with an event from the trusted device mxEvent = await mkEncryptedMatrixEvent({ @@ -578,4 +581,27 @@ describe("EventTile", () => { }); }); }); + + it("should display the not encrypted status for an unencrypted event when the room becomes encrypted", async () => { + jest.spyOn(client.getCrypto()!, "getEncryptionInfoForEvent").mockResolvedValue({ + shieldColour: EventShieldColour.NONE, + shieldReason: null, + }); + + getComponent(); + await flushPromises(); + // The room and the event are unencrypted, the tile should not show the not encrypted status + expect(screen.queryByText("Not encrypted")).toBeNull(); + + // The room is now encrypted + jest.spyOn(client.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true); + // Emit a state event to trigger a re-render + const roomState = room!.getLiveTimeline().getState(EventTimeline.FORWARDS)!; + act(() => { + roomState.emit(RoomStateEvent.Events, new MatrixEvent({ type: EventType.RoomEncryption }), roomState, null); + }); + + // The event tile should now show the not encrypted status + await waitFor(() => expect(screen.getByText("Not encrypted")).toBeInTheDocument()); + }); });