From 08617d330ceb909d90d0664e3483b0d7c918a806 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Wed, 23 Oct 2024 19:18:35 +0200 Subject: [PATCH 1/4] Replace `MatrixClient.isRoomEncrypted` by `MatrixClient.CryptoApi.isEncryptionEnabledInRoom` in `useIsEncrypted` --- src/hooks/useIsEncrypted.ts | 15 ++++++++++----- .../views/right_panel/RoomSummaryCard-test.tsx | 13 ++----------- .../views/right_panel/UserInfo-test.tsx | 4 ++-- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/hooks/useIsEncrypted.ts b/src/hooks/useIsEncrypted.ts index a90b795a858..ad3ab56ff92 100644 --- a/src/hooks/useIsEncrypted.ts +++ b/src/hooks/useIsEncrypted.ts @@ -6,19 +6,24 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { MatrixClient, MatrixEvent, Room, RoomStateEvent, EventType } from "matrix-js-sdk/src/matrix"; import { useTypedEventEmitter } from "./useEventEmitter"; -// Hook to simplify watching whether a Matrix room is encrypted, returns undefined if room is undefined +// Hook to simplify watching whether a Matrix room is encrypted, returns undefined if room is undefined or when isRoomEncrypted is computed export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefined { - const [isEncrypted, setIsEncrypted] = useState(room ? cli.isRoomEncrypted(room.roomId) : undefined); + const [isEncrypted, setIsEncrypted] = useState(); + useEffect(() => { + const func = async (): Promise => + room && setIsEncrypted(await cli.getCrypto()?.isEncryptionEnabledInRoom(room.roomId)); + func(); + }, [cli, room]); const update = useCallback( - (event: MatrixEvent) => { + async (event: MatrixEvent) => { if (room && event.getType() === EventType.RoomEncryption) { - setIsEncrypted(cli.isRoomEncrypted(room.roomId)); + setIsEncrypted(await cli.getCrypto()?.isEncryptionEnabledInRoom(room.roomId)); } }, [cli, room], diff --git a/test/unit-tests/components/views/right_panel/RoomSummaryCard-test.tsx b/test/unit-tests/components/views/right_panel/RoomSummaryCard-test.tsx index a98552ea078..4026149f984 100644 --- a/test/unit-tests/components/views/right_panel/RoomSummaryCard-test.tsx +++ b/test/unit-tests/components/views/right_panel/RoomSummaryCard-test.tsx @@ -23,7 +23,7 @@ import * as settingsHooks from "../../../../../src/hooks/useSettings"; import Modal from "../../../../../src/Modal"; import RightPanelStore from "../../../../../src/stores/right-panel/RightPanelStore"; import { RightPanelPhases } from "../../../../../src/stores/right-panel/RightPanelStorePhases"; -import { flushPromises, getMockClientWithEventEmitter, mockClientMethodsUser } from "../../../../test-utils"; +import { flushPromises, stubClient } from "../../../../test-utils"; import { PollHistoryDialog } from "../../../../../src/components/views/dialogs/PollHistoryDialog"; import { RoomPermalinkCreator } from "../../../../../src/utils/permalinks/Permalinks"; import { _t } from "../../../../../src/languageHandler"; @@ -56,16 +56,7 @@ describe("", () => { }; beforeEach(() => { - mockClient = getMockClientWithEventEmitter({ - ...mockClientMethodsUser(userId), - getAccountData: jest.fn(), - isRoomEncrypted: jest.fn(), - getOrCreateFilter: jest.fn().mockResolvedValue({ filterId: 1 }), - getRoom: jest.fn(), - isGuest: jest.fn().mockReturnValue(false), - deleteRoomTag: jest.fn().mockResolvedValue({}), - setRoomTag: jest.fn().mockResolvedValue({}), - }); + mockClient = mocked(stubClient()); room = new Room(roomId, mockClient, userId); const roomCreateEvent = new MatrixEvent({ type: "m.room.create", diff --git a/test/unit-tests/components/views/right_panel/UserInfo-test.tsx b/test/unit-tests/components/views/right_panel/UserInfo-test.tsx index c9996d7d67b..dbf5645ca8e 100644 --- a/test/unit-tests/components/views/right_panel/UserInfo-test.tsx +++ b/test/unit-tests/components/views/right_panel/UserInfo-test.tsx @@ -134,6 +134,7 @@ beforeEach(() => { getUserDeviceInfo: jest.fn(), userHasCrossSigningKeys: jest.fn().mockResolvedValue(false), getUserVerificationStatus: jest.fn(), + isEncryptionEnabledInRoom: jest.fn().mockResolvedValue(false), } as unknown as CryptoApi); mockClient = mocked({ @@ -148,7 +149,6 @@ beforeEach(() => { on: jest.fn(), off: jest.fn(), isSynapseAdministrator: jest.fn().mockResolvedValue(false), - isRoomEncrypted: jest.fn().mockReturnValue(false), doesServerSupportUnstableFeature: jest.fn().mockReturnValue(false), doesServerSupportExtendedProfiles: jest.fn().mockResolvedValue(false), getExtendedProfileProperty: jest.fn().mockRejectedValue(new Error("Not supported")), @@ -660,7 +660,7 @@ describe("", () => { describe("with an encrypted room", () => { beforeEach(() => { - mockClient.isRoomEncrypted.mockReturnValue(true); + jest.spyOn(mockClient.getCrypto()!, "isEncryptionEnabledInRoom").mockResolvedValue(true); }); it("renders unverified user info", async () => { From 639de212e9ea93732b68ee947f692f495df6b003 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Tue, 12 Nov 2024 15:49:01 +0100 Subject: [PATCH 2/4] Catch error --- src/hooks/useIsEncrypted.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/hooks/useIsEncrypted.ts b/src/hooks/useIsEncrypted.ts index ad3ab56ff92..e7ede593f5b 100644 --- a/src/hooks/useIsEncrypted.ts +++ b/src/hooks/useIsEncrypted.ts @@ -23,7 +23,11 @@ export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefi const update = useCallback( async (event: MatrixEvent) => { if (room && event.getType() === EventType.RoomEncryption) { - setIsEncrypted(await cli.getCrypto()?.isEncryptionEnabledInRoom(room.roomId)); + try { + setIsEncrypted(await cli.getCrypto()?.isEncryptionEnabledInRoom(room.roomId)); + } catch { + setIsEncrypted(false); + } } }, [cli, room], From c76f0869c29ebcbe60de868446f6ab138ca25ef4 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Tue, 12 Nov 2024 16:04:55 +0100 Subject: [PATCH 3/4] Return `null` when computed --- src/hooks/useIsEncrypted.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/hooks/useIsEncrypted.ts b/src/hooks/useIsEncrypted.ts index e7ede593f5b..33993f8ae8e 100644 --- a/src/hooks/useIsEncrypted.ts +++ b/src/hooks/useIsEncrypted.ts @@ -11,9 +11,9 @@ import { MatrixClient, MatrixEvent, Room, RoomStateEvent, EventType } from "matr import { useTypedEventEmitter } from "./useEventEmitter"; -// Hook to simplify watching whether a Matrix room is encrypted, returns undefined if room is undefined or when isRoomEncrypted is computed -export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefined { - const [isEncrypted, setIsEncrypted] = useState(); +// Hook to simplify watching whether a Matrix room is encrypted, returns undefined if room is undefined, return null when isRoomEncrypted is computed +export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefined | null { + const [isEncrypted, setIsEncrypted] = useState(null); useEffect(() => { const func = async (): Promise => From 0ee713a9f6e3cecb544613ffbdad0fe73e1516e8 Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Wed, 13 Nov 2024 10:02:05 +0100 Subject: [PATCH 4/4] Use `useRoomState` & `useAsyncMemo` --- src/hooks/useIsEncrypted.ts | 40 +++++++++++++++---------------------- 1 file changed, 16 insertions(+), 24 deletions(-) diff --git a/src/hooks/useIsEncrypted.ts b/src/hooks/useIsEncrypted.ts index 33993f8ae8e..c9d3ed3bc80 100644 --- a/src/hooks/useIsEncrypted.ts +++ b/src/hooks/useIsEncrypted.ts @@ -6,33 +6,25 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only Please see LICENSE files in the repository root for full details. */ -import { useCallback, useEffect, useState } from "react"; -import { MatrixClient, MatrixEvent, Room, RoomStateEvent, EventType } from "matrix-js-sdk/src/matrix"; +import { MatrixClient, MatrixEvent, Room, EventType } from "matrix-js-sdk/src/matrix"; -import { useTypedEventEmitter } from "./useEventEmitter"; +import { useRoomState } from "./useRoomState.ts"; +import { useAsyncMemo } from "./useAsyncMemo.ts"; -// Hook to simplify watching whether a Matrix room is encrypted, returns undefined if room is undefined, return null when isRoomEncrypted is computed -export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | undefined | null { - const [isEncrypted, setIsEncrypted] = useState(null); +// Hook to simplify watching whether a Matrix room is encrypted, returns null if room is undefined or the state is loading +export function useIsEncrypted(cli: MatrixClient, room?: Room): boolean | null { + const encryptionStateEvent: MatrixEvent | undefined = useRoomState( + room, + (roomState) => roomState.getStateEvents(EventType.RoomEncryption)?.[0], + ); + return useAsyncMemo( + async () => { + const crypto = cli.getCrypto(); + if (!room || !crypto) return null; - useEffect(() => { - const func = async (): Promise => - room && setIsEncrypted(await cli.getCrypto()?.isEncryptionEnabledInRoom(room.roomId)); - func(); - }, [cli, room]); - const update = useCallback( - async (event: MatrixEvent) => { - if (room && event.getType() === EventType.RoomEncryption) { - try { - setIsEncrypted(await cli.getCrypto()?.isEncryptionEnabledInRoom(room.roomId)); - } catch { - setIsEncrypted(false); - } - } + return crypto.isEncryptionEnabledInRoom(room.roomId); }, - [cli, room], + [room, encryptionStateEvent], + null, ); - useTypedEventEmitter(room?.currentState, RoomStateEvent.Events, update); - - return isEncrypted; }