Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Prevent mutations of js-sdk owned objects as it breaks accountData #7504

Merged
merged 3 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/Rooms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -90,10 +91,10 @@ export function guessAndSetDMRoom(room: Room, isDirect: boolean): Promise<void>
export async function setDMRoom(roomId: string, userId: string): Promise<void> {
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)
Expand All @@ -117,7 +118,7 @@ export async function setDMRoom(roomId: string, userId: string): Promise<void> {
dmRoomMap[userId] = roomList;
}

await MatrixClientPeg.get().setAccountData('m.direct', dmRoomMap);
await MatrixClientPeg.get().setAccountData(EventType.Direct, dmRoomMap);
}

/**
Expand Down
14 changes: 4 additions & 10 deletions src/components/structures/MatrixChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -1297,16 +1297,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// 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);
Expand Down
3 changes: 2 additions & 1 deletion src/stores/room-list/RoomListStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -281,7 +282,7 @@ export class RoomListStoreClass extends AsyncStoreWithClient<IState> {
}
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 = (<any>payload); // TODO: Type out the dispatcher types
const dmMap = eventPayload.event.getContent();
for (const userId of Object.keys(dmMap)) {
Expand Down
24 changes: 13 additions & 11 deletions src/utils/DMRoomMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -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
}

/**
Expand Down Expand Up @@ -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;
}
Expand All @@ -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<string, string[]>) {
const myUserId = this.matrixClient.getUserId();
const selfRoomIds = userToRooms[myUserId];
if (selfRoomIds) {
Expand Down Expand Up @@ -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] || [];
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down