Skip to content

Commit 5ce1e47

Browse files
committed
Update e2eStatus and urlPreview when isRoomEncrypted is computed
1 parent 223dd96 commit 5ce1e47

File tree

3 files changed

+644
-47
lines changed

3 files changed

+644
-47
lines changed

src/components/structures/RoomView.tsx

+36-20
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
MatrixError,
3939
ISearchResults,
4040
THREAD_RELATION_TYPE,
41+
MatrixClient,
4142
} from "matrix-js-sdk/src/matrix";
4243
import { KnownMembership } from "matrix-js-sdk/src/types";
4344
import { logger } from "matrix-js-sdk/src/logger";
@@ -431,7 +432,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
431432
canAskToJoin: this.askToJoinEnabled,
432433
promptAskToJoin: false,
433434
viewRoomOpts: { buttons: [] },
434-
isRoomEncrypted: false,
435+
isRoomEncrypted: null,
435436
};
436437
}
437438

@@ -929,7 +930,6 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
929930
const callState = call?.state;
930931
this.setState({
931932
callState,
932-
isRoomEncrypted: await this.getIsRoomEncrypted(),
933933
});
934934

935935
this.context.legacyCallHandler.on(LegacyCallHandlerEvent.CallState, this.onCallState);
@@ -1358,13 +1358,12 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
13581358
this.context.widgetLayoutStore.on(WidgetLayoutStore.emissionForRoom(room), this.onWidgetLayoutChange);
13591359

13601360
this.calculatePeekRules(room);
1361-
this.updatePreviewUrlVisibility(room);
13621361
this.loadMembersIfJoined(room);
13631362
this.calculateRecommendedVersion(room);
1364-
this.updateE2EStatus(room);
13651363
this.updatePermissions(room);
13661364
this.checkWidgets(room);
13671365
this.loadVirtualRoom(room);
1366+
this.updateRoomEncrypted(room);
13681367

13691368
if (
13701369
this.getMainSplitContentType(room) !== MainSplitContentType.Timeline &&
@@ -1432,12 +1431,15 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
14321431
});
14331432
}
14341433

1435-
private updatePreviewUrlVisibility({ roomId }: Room): void {
1436-
// URL Previews in E2EE rooms can be a privacy leak so use a different setting which is per-room explicit
1437-
const key = this.state.isRoomEncrypted ? "urlPreviewsEnabled_e2ee" : "urlPreviewsEnabled";
1438-
this.setState({
1439-
showUrlPreview: SettingsStore.getValue(key, roomId),
1440-
});
1434+
private updatePreviewUrlVisibility(room: Room): void {
1435+
this.setState(({ isRoomEncrypted }) => ({
1436+
showUrlPreview: this.getPreviewUrlVisibility(room, isRoomEncrypted),
1437+
}));
1438+
}
1439+
1440+
private getPreviewUrlVisibility({ roomId }: Room, isRoomEncrypted: boolean | null): boolean {
1441+
const key = isRoomEncrypted ? "urlPreviewsEnabled_e2ee" : "urlPreviewsEnabled";
1442+
return SettingsStore.getValue(key, roomId);
14411443
}
14421444

14431445
private onRoom = (room: Room): void => {
@@ -1490,13 +1492,18 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
14901492

14911493
if (this.context.client.getCrypto()) {
14921494
/* At this point, the user has encryption on and cross-signing on */
1493-
e2eStatus = await shieldStatusForRoom(this.context.client, room);
1494-
RoomView.e2eStatusCache.set(room.roomId, e2eStatus);
1495+
e2eStatus = await this.cacheAndGetE2EStatus(room, this.context.client);
14951496
if (this.unmounted) return;
14961497
this.setState({ e2eStatus });
14971498
}
14981499
}
14991500

1501+
private async cacheAndGetE2EStatus(room: Room, client: MatrixClient): Promise<E2EStatus> {
1502+
const e2eStatus = await shieldStatusForRoom(client, room);
1503+
RoomView.e2eStatusCache.set(room.roomId, e2eStatus);
1504+
return e2eStatus;
1505+
}
1506+
15001507
private onUrlPreviewsEnabledChange = (): void => {
15011508
if (this.state.room) {
15021509
this.updatePreviewUrlVisibility(this.state.room);
@@ -1505,25 +1512,34 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
15051512

15061513
private onRoomStateEvents = async (ev: MatrixEvent, state: RoomState): Promise<void> => {
15071514
// ignore if we don't have a room yet
1508-
if (!this.state.room || this.state.room.roomId !== state.roomId) return;
1515+
if (!this.state.room || this.state.room.roomId !== state.roomId || !this.context.client) return;
15091516

15101517
switch (ev.getType()) {
15111518
case EventType.RoomTombstone:
15121519
this.setState({ tombstone: this.getRoomTombstone() });
15131520
break;
1514-
case EventType.RoomEncryption:
1515-
this.setState({ isRoomEncrypted: await this.getIsRoomEncrypted() }, () => {
1516-
if (this.state.room) {
1517-
this.updatePreviewUrlVisibility(this.state.room);
1518-
this.updateE2EStatus(this.state.room);
1519-
}
1520-
});
1521+
case EventType.RoomEncryption: {
1522+
await this.updateRoomEncrypted();
15211523
break;
1524+
}
15221525
default:
15231526
this.updatePermissions(this.state.room);
15241527
}
15251528
};
15261529

1530+
private async updateRoomEncrypted(room = this.state.room): Promise<void> {
1531+
if (!room || !this.context.client) return;
1532+
1533+
const isRoomEncrypted = await this.getIsRoomEncrypted(room.roomId);
1534+
const newE2EStatus = isRoomEncrypted ? await this.cacheAndGetE2EStatus(room, this.context.client) : null;
1535+
1536+
this.setState({
1537+
isRoomEncrypted,
1538+
showUrlPreview: this.getPreviewUrlVisibility(room, isRoomEncrypted),
1539+
...(newE2EStatus && { e2eStatus: newE2EStatus }),
1540+
});
1541+
}
1542+
15271543
private onRoomStateUpdate = (state: RoomState): void => {
15281544
// ignore members in other rooms
15291545
if (state.roomId !== this.state.room?.roomId) {

test/unit-tests/components/structures/RoomView-test.tsx

+16
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import {
3535
cleanup,
3636
} from "jest-matrix-react";
3737
import userEvent from "@testing-library/user-event";
38+
import { defer } from "matrix-js-sdk/src/utils";
3839

3940
import {
4041
stubClient,
@@ -283,6 +284,21 @@ describe("RoomView", () => {
283284
await waitFor(() => expect(roomViewInstance.state.showUrlPreview).toBe(false));
284285
});
285286

287+
it("should not display the timeline when the room encryption is loading", async () => {
288+
jest.spyOn(room, "getMyMembership").mockReturnValue(KnownMembership.Join);
289+
jest.spyOn(cli, "getCrypto").mockReturnValue(crypto);
290+
const deferred = defer<boolean>();
291+
jest.spyOn(cli.getCrypto()!, "isEncryptionEnabledInRoom").mockImplementation(() => deferred.promise);
292+
293+
const { asFragment, container } = await mountRoomView();
294+
expect(container.querySelector(".mx_RoomView_messagePanel")).toBeNull();
295+
expect(asFragment()).toMatchSnapshot();
296+
297+
deferred.resolve(true);
298+
await waitFor(() => expect(container.querySelector(".mx_RoomView_messagePanel")).not.toBeNull());
299+
expect(asFragment()).toMatchSnapshot();
300+
});
301+
286302
it("updates live timeline when a timeline reset happens", async () => {
287303
const roomViewInstance = await getRoomViewInstance();
288304
const oldTimeline = roomViewInstance.state.liveTimeline;

0 commit comments

Comments
 (0)