From 8c20bcfe560f303b1c6cb9d9f3a42392018d1b12 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 10 Jan 2022 17:09:35 +0000 Subject: [PATCH] Prevent mutations of js-sdk owned objects as it breaks accountData (#7504) --- src/Rooms.ts | 7 ++++--- src/components/structures/MatrixChat.tsx | 14 ++++---------- src/stores/room-list/RoomListStore.ts | 3 ++- src/utils/DMRoomMap.ts | 24 +++++++++++++----------- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/src/Rooms.ts b/src/Rooms.ts index 14f3571bab..0b17cdcc43 100644 --- a/src/Rooms.ts +++ b/src/Rooms.ts @@ -15,6 +15,7 @@ limitations under the License. */ import { Room } from "matrix-js-sdk/src/models/room"; +import { EventType } from "matrix-js-sdk/src/@types/event"; import { MatrixClientPeg } from './MatrixClientPeg'; import AliasCustomisations from './customisations/Alias'; @@ -90,10 +91,10 @@ export function guessAndSetDMRoom(room: Room, isDirect: boolean): Promise export async function setDMRoom(roomId: string, userId: string): Promise { if (MatrixClientPeg.get().isGuest()) return; - const mDirectEvent = MatrixClientPeg.get().getAccountData('m.direct'); + const mDirectEvent = MatrixClientPeg.get().getAccountData(EventType.Direct); let dmRoomMap = {}; - if (mDirectEvent !== undefined) dmRoomMap = mDirectEvent.getContent(); + if (mDirectEvent !== undefined) dmRoomMap = { ...mDirectEvent.getContent() }; // copy as we will mutate // remove it from the lists of any others users // (it can only be a DM room for one person) @@ -117,7 +118,7 @@ export async function setDMRoom(roomId: string, userId: string): Promise { dmRoomMap[userId] = roomList; } - await MatrixClientPeg.get().setAccountData('m.direct', dmRoomMap); + await MatrixClientPeg.get().setAccountData(EventType.Direct, dmRoomMap); } /** diff --git a/src/components/structures/MatrixChat.tsx b/src/components/structures/MatrixChat.tsx index 8b7ddaf218..57cb860d95 100644 --- a/src/components/structures/MatrixChat.tsx +++ b/src/components/structures/MatrixChat.tsx @@ -15,7 +15,7 @@ limitations under the License. */ import React, { ComponentType, createRef } from 'react'; -import { createClient, MatrixClient } from 'matrix-js-sdk/src/matrix'; +import { createClient, EventType, MatrixClient } from 'matrix-js-sdk/src/matrix'; import { ISyncStateData, SyncState } from 'matrix-js-sdk/src/sync'; import { MatrixError } from 'matrix-js-sdk/src/http-api'; import { InvalidStoreError } from "matrix-js-sdk/src/errors"; @@ -1297,16 +1297,10 @@ export default class MatrixChat extends React.PureComponent { // run without the update to m.direct, making another welcome // user room (it doesn't wait for new data from the server, just // the saved sync to be loaded). - const saveWelcomeUser = (ev) => { - if ( - ev.getType() === 'm.direct' && - ev.getContent() && - ev.getContent()[this.props.config.welcomeUserId] - ) { + const saveWelcomeUser = (ev: MatrixEvent) => { + if (ev.getType() === EventType.Direct && ev.getContent()[this.props.config.welcomeUserId]) { MatrixClientPeg.get().store.save(true); - MatrixClientPeg.get().removeListener( - "accountData", saveWelcomeUser, - ); + MatrixClientPeg.get().removeListener("accountData", saveWelcomeUser); } }; MatrixClientPeg.get().on("accountData", saveWelcomeUser); diff --git a/src/stores/room-list/RoomListStore.ts b/src/stores/room-list/RoomListStore.ts index 4c3e6d3f11..d639b76c2b 100644 --- a/src/stores/room-list/RoomListStore.ts +++ b/src/stores/room-list/RoomListStore.ts @@ -18,6 +18,7 @@ import { MatrixClient } from "matrix-js-sdk/src/client"; import { Room } from "matrix-js-sdk/src/models/room"; import { isNullOrUndefined } from "matrix-js-sdk/src/utils"; import { logger } from "matrix-js-sdk/src/logger"; +import { EventType } from "matrix-js-sdk/src/@types/event"; import SettingsStore from "../../settings/SettingsStore"; import { DefaultTagID, isCustomTag, OrderedDefaultTagIDs, RoomUpdateCause, TagID } from "./models"; @@ -281,7 +282,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient { } await this.handleRoomUpdate(room, RoomUpdateCause.Timeline); this.updateFn.trigger(); - } else if (payload.action === 'MatrixActions.accountData' && payload.event_type === 'm.direct') { + } else if (payload.action === 'MatrixActions.accountData' && payload.event_type === EventType.Direct) { const eventPayload = (payload); // TODO: Type out the dispatcher types const dmMap = eventPayload.event.getContent(); for (const userId of Object.keys(dmMap)) { diff --git a/src/utils/DMRoomMap.ts b/src/utils/DMRoomMap.ts index 0cec18816c..92cf07016e 100644 --- a/src/utils/DMRoomMap.ts +++ b/src/utils/DMRoomMap.ts @@ -18,6 +18,8 @@ import { uniq } from "lodash"; import { Room } from "matrix-js-sdk/src/models/room"; import { MatrixClient } from "matrix-js-sdk/src/client"; import { logger } from "matrix-js-sdk/src/logger"; +import { EventType } from "matrix-js-sdk/src/@types/event"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixClientPeg } from '../MatrixClientPeg'; @@ -35,14 +37,14 @@ export default class DMRoomMap { private roomToUser: {[key: string]: string} = null; private userToRooms: {[key: string]: string[]} = null; private hasSentOutPatchDirectAccountDataPatch: boolean; - private mDirectEvent: object; + private mDirectEvent: {[key: string]: string[]}; constructor(private readonly matrixClient: MatrixClient) { // see onAccountData this.hasSentOutPatchDirectAccountDataPatch = false; - const mDirectEvent = matrixClient.getAccountData('m.direct'); - this.mDirectEvent = mDirectEvent ? mDirectEvent.getContent() : {}; + const mDirectEvent = matrixClient.getAccountData(EventType.Direct)?.getContent() ?? {}; + this.mDirectEvent = { ...mDirectEvent }; // copy as we will mutate } /** @@ -81,9 +83,9 @@ export default class DMRoomMap { this.matrixClient.removeListener("accountData", this.onAccountData); } - private onAccountData = (ev) => { - if (ev.getType() == 'm.direct') { - this.mDirectEvent = this.matrixClient.getAccountData('m.direct').getContent() || {}; + private onAccountData = (ev: MatrixEvent) => { + if (ev.getType() == EventType.Direct) { + this.mDirectEvent = { ...ev.getContent() }; // copy as we will mutate this.userToRooms = null; this.roomToUser = null; } @@ -94,7 +96,7 @@ export default class DMRoomMap { * with ourself, not the other user. Fix it by guessing the other user and * modifying userToRooms */ - private patchUpSelfDMs(userToRooms) { + private patchUpSelfDMs(userToRooms: Record) { const myUserId = this.matrixClient.getUserId(); const selfRoomIds = userToRooms[myUserId]; if (selfRoomIds) { @@ -130,7 +132,7 @@ export default class DMRoomMap { } } - public getDMRoomsForUserId(userId): string[] { + public getDMRoomsForUserId(userId: string): string[] { // Here, we return the empty list if there are no rooms, // since the number of conversations you have with this user is zero. return this.getUserToRooms()[userId] || []; @@ -189,10 +191,10 @@ export default class DMRoomMap { private getUserToRooms(): {[key: string]: string[]} { if (!this.userToRooms) { - const userToRooms = this.mDirectEvent as {[key: string]: string[]}; + const userToRooms = this.mDirectEvent; const myUserId = this.matrixClient.getUserId(); const selfDMs = userToRooms[myUserId]; - if (selfDMs && selfDMs.length) { + if (selfDMs?.length) { const neededPatching = this.patchUpSelfDMs(userToRooms); // to avoid multiple devices fighting to correct // the account data, only try to send the corrected @@ -201,7 +203,7 @@ export default class DMRoomMap { `(self-chats that shouldn't be), patching it up.`); if (neededPatching && !this.hasSentOutPatchDirectAccountDataPatch) { this.hasSentOutPatchDirectAccountDataPatch = true; - this.matrixClient.setAccountData('m.direct', userToRooms); + this.matrixClient.setAccountData(EventType.Direct, userToRooms); } } this.userToRooms = userToRooms;