You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-25 05:23:13 +03:00
Merge branch 'master' into develop
This commit is contained in:
17
CHANGELOG.md
17
CHANGELOG.md
@@ -1,3 +1,20 @@
|
|||||||
|
Changes in [19.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v19.4.0) (2022-08-31)
|
||||||
|
==================================================================================================
|
||||||
|
|
||||||
|
## ✨ Features
|
||||||
|
* Re-emit room state events on rooms ([\#2607](https://github.com/matrix-org/matrix-js-sdk/pull/2607)).
|
||||||
|
* Add ability to override built in room name generator for an i18n'able one ([\#2609](https://github.com/matrix-org/matrix-js-sdk/pull/2609)).
|
||||||
|
* Add txn_id support to sliding sync ([\#2567](https://github.com/matrix-org/matrix-js-sdk/pull/2567)).
|
||||||
|
|
||||||
|
## 🐛 Bug Fixes
|
||||||
|
* Refactor Sync and fix `initialSyncLimit` ([\#2587](https://github.com/matrix-org/matrix-js-sdk/pull/2587)).
|
||||||
|
* Use deep equality comparisons when searching for outgoing key requests by target ([\#2623](https://github.com/matrix-org/matrix-js-sdk/pull/2623)). Contributed by @duxovni.
|
||||||
|
* Fix room membership race with PREPARED event ([\#2613](https://github.com/matrix-org/matrix-js-sdk/pull/2613)). Contributed by @jotto.
|
||||||
|
* fixed a sliding sync bug which could cause the `roomIndexToRoomId` map to be incorrect when a new room is added in the middle of the list or when an existing room is deleted from the middle of the list. ([\#2610](https://github.com/matrix-org/matrix-js-sdk/pull/2610)).
|
||||||
|
* Fix: Handle parsing of a beacon info event without asset ([\#2591](https://github.com/matrix-org/matrix-js-sdk/pull/2591)). Fixes vector-im/element-web#23078. Contributed by @kerryarchibald.
|
||||||
|
* Fix finding event read up to if stable private read receipts is missing ([\#2585](https://github.com/matrix-org/matrix-js-sdk/pull/2585)). Fixes vector-im/element-web#23027.
|
||||||
|
* fixed a sliding sync issue where history could be interpreted as live events. ([\#2583](https://github.com/matrix-org/matrix-js-sdk/pull/2583)).
|
||||||
|
|
||||||
Changes in [19.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v19.3.0) (2022-08-16)
|
Changes in [19.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v19.3.0) (2022-08-16)
|
||||||
==================================================================================================
|
==================================================================================================
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "matrix-js-sdk",
|
"name": "matrix-js-sdk",
|
||||||
"version": "19.3.0",
|
"version": "19.4.0",
|
||||||
"description": "Matrix Client-Server SDK for Javascript",
|
"description": "Matrix Client-Server SDK for Javascript",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.9.0"
|
"node": ">=12.9.0"
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
"keywords": [
|
"keywords": [
|
||||||
"matrix-org"
|
"matrix-org"
|
||||||
],
|
],
|
||||||
"main": "./src/index.ts",
|
"main": "./lib/index.js",
|
||||||
"browser": "./lib/browser-index.js",
|
"browser": "./lib/browser-index.js",
|
||||||
"matrix_src_main": "./src/index.ts",
|
"matrix_src_main": "./src/index.ts",
|
||||||
"matrix_src_browser": "./src/browser-index.js",
|
"matrix_src_browser": "./src/browser-index.js",
|
||||||
@@ -125,5 +125,6 @@
|
|||||||
"jestSonar": {
|
"jestSonar": {
|
||||||
"reportPath": "coverage",
|
"reportPath": "coverage",
|
||||||
"sonar56x": true
|
"sonar56x": true
|
||||||
}
|
},
|
||||||
|
"typings": "./lib/index.d.ts"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ import { ClientEvent, MatrixClient, RoomMember } from '../../../../src';
|
|||||||
import { DeviceInfo, IDevice } from '../../../../src/crypto/deviceinfo';
|
import { DeviceInfo, IDevice } from '../../../../src/crypto/deviceinfo';
|
||||||
import { DeviceTrustLevel } from '../../../../src/crypto/CrossSigning';
|
import { DeviceTrustLevel } from '../../../../src/crypto/CrossSigning';
|
||||||
|
|
||||||
const MegolmDecryption = algorithms.DECRYPTION_CLASSES['m.megolm.v1.aes-sha2'];
|
const MegolmDecryption = algorithms.DECRYPTION_CLASSES.get('m.megolm.v1.aes-sha2');
|
||||||
const MegolmEncryption = algorithms.ENCRYPTION_CLASSES['m.megolm.v1.aes-sha2'];
|
const MegolmEncryption = algorithms.ENCRYPTION_CLASSES.get('m.megolm.v1.aes-sha2');
|
||||||
|
|
||||||
const ROOM_ID = '!ROOM:ID';
|
const ROOM_ID = '!ROOM:ID';
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import { IAbortablePromise, MatrixScheduler } from '../../../src';
|
|||||||
|
|
||||||
const Olm = global.Olm;
|
const Olm = global.Olm;
|
||||||
|
|
||||||
const MegolmDecryption = algorithms.DECRYPTION_CLASSES['m.megolm.v1.aes-sha2'];
|
const MegolmDecryption = algorithms.DECRYPTION_CLASSES.get('m.megolm.v1.aes-sha2');
|
||||||
|
|
||||||
const ROOM_ID = '!ROOM:ID';
|
const ROOM_ID = '!ROOM:ID';
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import { IRoomEncryption } from "../RoomList";
|
|||||||
*
|
*
|
||||||
* @type {Object.<string, function(new: module:crypto/algorithms/base.EncryptionAlgorithm)>}
|
* @type {Object.<string, function(new: module:crypto/algorithms/base.EncryptionAlgorithm)>}
|
||||||
*/
|
*/
|
||||||
export const ENCRYPTION_CLASSES: Record<string, new (params: IParams) => EncryptionAlgorithm> = {};
|
export const ENCRYPTION_CLASSES = new Map<string, new (params: IParams) => EncryptionAlgorithm>();
|
||||||
|
|
||||||
type DecryptionClassParams = Omit<IParams, "deviceId" | "config">;
|
type DecryptionClassParams = Omit<IParams, "deviceId" | "config">;
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ type DecryptionClassParams = Omit<IParams, "deviceId" | "config">;
|
|||||||
*
|
*
|
||||||
* @type {Object.<string, function(new: module:crypto/algorithms/base.DecryptionAlgorithm)>}
|
* @type {Object.<string, function(new: module:crypto/algorithms/base.DecryptionAlgorithm)>}
|
||||||
*/
|
*/
|
||||||
export const DECRYPTION_CLASSES: Record<string, new (params: DecryptionClassParams) => DecryptionAlgorithm> = {};
|
export const DECRYPTION_CLASSES = new Map<string, new (params: DecryptionClassParams) => DecryptionAlgorithm>();
|
||||||
|
|
||||||
export interface IParams {
|
export interface IParams {
|
||||||
userId: string;
|
userId: string;
|
||||||
@@ -297,6 +297,6 @@ export function registerAlgorithm(
|
|||||||
encryptor: new (params: IParams) => EncryptionAlgorithm,
|
encryptor: new (params: IParams) => EncryptionAlgorithm,
|
||||||
decryptor: new (params: Omit<IParams, "deviceId">) => DecryptionAlgorithm,
|
decryptor: new (params: Omit<IParams, "deviceId">) => DecryptionAlgorithm,
|
||||||
): void {
|
): void {
|
||||||
ENCRYPTION_CLASSES[algorithm] = encryptor;
|
ENCRYPTION_CLASSES.set(algorithm, encryptor);
|
||||||
DECRYPTION_CLASSES[algorithm] = decryptor;
|
DECRYPTION_CLASSES.set(algorithm, decryptor);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1191,7 +1191,7 @@ class MegolmEncryption extends EncryptionAlgorithm {
|
|||||||
class MegolmDecryption extends DecryptionAlgorithm {
|
class MegolmDecryption extends DecryptionAlgorithm {
|
||||||
// events which we couldn't decrypt due to unknown sessions / indexes: map from
|
// events which we couldn't decrypt due to unknown sessions / indexes: map from
|
||||||
// senderKey|sessionId to Set of MatrixEvents
|
// senderKey|sessionId to Set of MatrixEvents
|
||||||
private pendingEvents: Record<string, Map<string, Set<MatrixEvent>>> = {};
|
private pendingEvents = new Map<string, Map<string, Set<MatrixEvent>>>();
|
||||||
|
|
||||||
// this gets stubbed out by the unit tests.
|
// this gets stubbed out by the unit tests.
|
||||||
private olmlib = olmlib;
|
private olmlib = olmlib;
|
||||||
@@ -1343,10 +1343,10 @@ class MegolmDecryption extends DecryptionAlgorithm {
|
|||||||
const content = event.getWireContent();
|
const content = event.getWireContent();
|
||||||
const senderKey = content.sender_key;
|
const senderKey = content.sender_key;
|
||||||
const sessionId = content.session_id;
|
const sessionId = content.session_id;
|
||||||
if (!this.pendingEvents[senderKey]) {
|
if (!this.pendingEvents.has(senderKey)) {
|
||||||
this.pendingEvents[senderKey] = new Map();
|
this.pendingEvents.set(senderKey, new Map<string, Set<MatrixEvent>>());
|
||||||
}
|
}
|
||||||
const senderPendingEvents = this.pendingEvents[senderKey];
|
const senderPendingEvents = this.pendingEvents.get(senderKey);
|
||||||
if (!senderPendingEvents.has(sessionId)) {
|
if (!senderPendingEvents.has(sessionId)) {
|
||||||
senderPendingEvents.set(sessionId, new Set());
|
senderPendingEvents.set(sessionId, new Set());
|
||||||
}
|
}
|
||||||
@@ -1364,7 +1364,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
|
|||||||
const content = event.getWireContent();
|
const content = event.getWireContent();
|
||||||
const senderKey = content.sender_key;
|
const senderKey = content.sender_key;
|
||||||
const sessionId = content.session_id;
|
const sessionId = content.session_id;
|
||||||
const senderPendingEvents = this.pendingEvents[senderKey];
|
const senderPendingEvents = this.pendingEvents.get(senderKey);
|
||||||
const pendingEvents = senderPendingEvents?.get(sessionId);
|
const pendingEvents = senderPendingEvents?.get(sessionId);
|
||||||
if (!pendingEvents) {
|
if (!pendingEvents) {
|
||||||
return;
|
return;
|
||||||
@@ -1375,7 +1375,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
|
|||||||
senderPendingEvents.delete(sessionId);
|
senderPendingEvents.delete(sessionId);
|
||||||
}
|
}
|
||||||
if (senderPendingEvents.size === 0) {
|
if (senderPendingEvents.size === 0) {
|
||||||
delete this.pendingEvents[senderKey];
|
this.pendingEvents.delete(senderKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1711,7 +1711,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
|
|||||||
* @return {Boolean} whether all messages were successfully decrypted
|
* @return {Boolean} whether all messages were successfully decrypted
|
||||||
*/
|
*/
|
||||||
private async retryDecryption(senderKey: string, sessionId: string): Promise<boolean> {
|
private async retryDecryption(senderKey: string, sessionId: string): Promise<boolean> {
|
||||||
const senderPendingEvents = this.pendingEvents[senderKey];
|
const senderPendingEvents = this.pendingEvents.get(senderKey);
|
||||||
if (!senderPendingEvents) {
|
if (!senderPendingEvents) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1732,16 +1732,16 @@ class MegolmDecryption extends DecryptionAlgorithm {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// If decrypted successfully, they'll have been removed from pendingEvents
|
// If decrypted successfully, they'll have been removed from pendingEvents
|
||||||
return !this.pendingEvents[senderKey]?.has(sessionId);
|
return !this.pendingEvents.get(senderKey)?.has(sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async retryDecryptionFromSender(senderKey: string): Promise<boolean> {
|
public async retryDecryptionFromSender(senderKey: string): Promise<boolean> {
|
||||||
const senderPendingEvents = this.pendingEvents[senderKey];
|
const senderPendingEvents = this.pendingEvents.get(senderKey);
|
||||||
if (!senderPendingEvents) {
|
if (!senderPendingEvents) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete this.pendingEvents[senderKey];
|
this.pendingEvents.delete(senderKey);
|
||||||
|
|
||||||
await Promise.all([...senderPendingEvents].map(async ([_sessionId, pending]) => {
|
await Promise.all([...senderPendingEvents].map(async ([_sessionId, pending]) => {
|
||||||
await Promise.all([...pending].map(async (ev) => {
|
await Promise.all([...pending].map(async (ev) => {
|
||||||
@@ -1753,7 +1753,7 @@ class MegolmDecryption extends DecryptionAlgorithm {
|
|||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return !this.pendingEvents[senderKey];
|
return !this.pendingEvents.has(senderKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async sendSharedHistoryInboundSessions(devicesByUser: Record<string, DeviceInfo[]>): Promise<void> {
|
public async sendSharedHistoryInboundSessions(devicesByUser: Record<string, DeviceInfo[]>): Promise<void> {
|
||||||
|
|||||||
@@ -278,9 +278,9 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
private oneTimeKeyCheckInProgress = false;
|
private oneTimeKeyCheckInProgress = false;
|
||||||
|
|
||||||
// EncryptionAlgorithm instance for each room
|
// EncryptionAlgorithm instance for each room
|
||||||
private roomEncryptors: Record<string, EncryptionAlgorithm> = {};
|
private roomEncryptors = new Map<string, EncryptionAlgorithm>();
|
||||||
// map from algorithm to DecryptionAlgorithm instance, for each room
|
// map from algorithm to DecryptionAlgorithm instance, for each room
|
||||||
private roomDecryptors: Record<string, Record<string, DecryptionAlgorithm>> = {};
|
private roomDecryptors = new Map<string, Map<string, DecryptionAlgorithm>>();
|
||||||
|
|
||||||
private deviceKeys: Record<string, string> = {}; // type: key
|
private deviceKeys: Record<string, string> = {}; // type: key
|
||||||
|
|
||||||
@@ -422,7 +422,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
this.deviceList.on(CryptoEvent.UserCrossSigningUpdated, this.onDeviceListUserCrossSigningUpdated);
|
this.deviceList.on(CryptoEvent.UserCrossSigningUpdated, this.onDeviceListUserCrossSigningUpdated);
|
||||||
this.reEmitter.reEmit(this.deviceList, [CryptoEvent.DevicesUpdated, CryptoEvent.WillUpdateDevices]);
|
this.reEmitter.reEmit(this.deviceList, [CryptoEvent.DevicesUpdated, CryptoEvent.WillUpdateDevices]);
|
||||||
|
|
||||||
this.supportedAlgorithms = Object.keys(algorithms.DECRYPTION_CLASSES);
|
this.supportedAlgorithms = Array.from(algorithms.DECRYPTION_CLASSES.keys());
|
||||||
|
|
||||||
this.outgoingRoomKeyRequestManager = new OutgoingRoomKeyRequestManager(
|
this.outgoingRoomKeyRequestManager = new OutgoingRoomKeyRequestManager(
|
||||||
baseApis, this.deviceId, this.cryptoStore,
|
baseApis, this.deviceId, this.cryptoStore,
|
||||||
@@ -2527,7 +2527,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
* This should not normally be necessary.
|
* This should not normally be necessary.
|
||||||
*/
|
*/
|
||||||
public forceDiscardSession(roomId: string): void {
|
public forceDiscardSession(roomId: string): void {
|
||||||
const alg = this.roomEncryptors[roomId];
|
const alg = this.roomEncryptors.get(roomId);
|
||||||
if (alg === undefined) throw new Error("Room not encrypted");
|
if (alg === undefined) throw new Error("Room not encrypted");
|
||||||
if (alg.forceDiscardSession === undefined) {
|
if (alg.forceDiscardSession === undefined) {
|
||||||
throw new Error("Room encryption algorithm doesn't support session discarding");
|
throw new Error("Room encryption algorithm doesn't support session discarding");
|
||||||
@@ -2580,7 +2580,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
// the encryption event would appear in both.
|
// the encryption event would appear in both.
|
||||||
// If it's called more than twice though,
|
// If it's called more than twice though,
|
||||||
// it signals a bug on client or server.
|
// it signals a bug on client or server.
|
||||||
const existingAlg = this.roomEncryptors[roomId];
|
const existingAlg = this.roomEncryptors.get(roomId);
|
||||||
if (existingAlg) {
|
if (existingAlg) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -2594,7 +2594,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
storeConfigPromise = this.roomList.setRoomEncryption(roomId, config);
|
storeConfigPromise = this.roomList.setRoomEncryption(roomId, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
const AlgClass = algorithms.ENCRYPTION_CLASSES[config.algorithm];
|
const AlgClass = algorithms.ENCRYPTION_CLASSES.get(config.algorithm);
|
||||||
if (!AlgClass) {
|
if (!AlgClass) {
|
||||||
throw new Error("Unable to encrypt with " + config.algorithm);
|
throw new Error("Unable to encrypt with " + config.algorithm);
|
||||||
}
|
}
|
||||||
@@ -2608,7 +2608,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
roomId,
|
roomId,
|
||||||
config,
|
config,
|
||||||
});
|
});
|
||||||
this.roomEncryptors[roomId] = alg;
|
this.roomEncryptors.set(roomId, alg);
|
||||||
|
|
||||||
if (storeConfigPromise) {
|
if (storeConfigPromise) {
|
||||||
await storeConfigPromise;
|
await storeConfigPromise;
|
||||||
@@ -2640,7 +2640,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
public trackRoomDevices(roomId: string): Promise<void> {
|
public trackRoomDevices(roomId: string): Promise<void> {
|
||||||
const trackMembers = async () => {
|
const trackMembers = async () => {
|
||||||
// not an encrypted room
|
// not an encrypted room
|
||||||
if (!this.roomEncryptors[roomId]) {
|
if (!this.roomEncryptors.has(roomId)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const room = this.clientStore.getRoom(roomId);
|
const room = this.clientStore.getRoom(roomId);
|
||||||
@@ -2785,7 +2785,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
* @param {module:models/room} room the room the event is in
|
* @param {module:models/room} room the room the event is in
|
||||||
*/
|
*/
|
||||||
public prepareToEncrypt(room: Room): void {
|
public prepareToEncrypt(room: Room): void {
|
||||||
const alg = this.roomEncryptors[room.roomId];
|
const alg = this.roomEncryptors.get(room.roomId);
|
||||||
if (alg) {
|
if (alg) {
|
||||||
alg.prepareToEncrypt(room);
|
alg.prepareToEncrypt(room);
|
||||||
}
|
}
|
||||||
@@ -2808,7 +2808,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
|
|
||||||
const roomId = event.getRoomId();
|
const roomId = event.getRoomId();
|
||||||
|
|
||||||
const alg = this.roomEncryptors[roomId];
|
const alg = this.roomEncryptors.get(roomId);
|
||||||
if (!alg) {
|
if (!alg) {
|
||||||
// MatrixClient has already checked that this room should be encrypted,
|
// MatrixClient has already checked that this room should be encrypted,
|
||||||
// so this is an unexpected situation.
|
// so this is an unexpected situation.
|
||||||
@@ -3097,7 +3097,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
private getTrackedE2eRooms(): Room[] {
|
private getTrackedE2eRooms(): Room[] {
|
||||||
return this.clientStore.getRooms().filter((room) => {
|
return this.clientStore.getRooms().filter((room) => {
|
||||||
// check for rooms with encryption enabled
|
// check for rooms with encryption enabled
|
||||||
const alg = this.roomEncryptors[room.roomId];
|
const alg = this.roomEncryptors.get(room.roomId);
|
||||||
if (!alg) {
|
if (!alg) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -3533,7 +3533,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
|
|
||||||
const roomId = member.roomId;
|
const roomId = member.roomId;
|
||||||
|
|
||||||
const alg = this.roomEncryptors[roomId];
|
const alg = this.roomEncryptors.get(roomId);
|
||||||
if (!alg) {
|
if (!alg) {
|
||||||
// not encrypting in this room
|
// not encrypting in this room
|
||||||
return;
|
return;
|
||||||
@@ -3634,11 +3634,11 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
` for ${roomId} / ${body.session_id} (id ${req.requestId})`);
|
` for ${roomId} / ${body.session_id} (id ${req.requestId})`);
|
||||||
|
|
||||||
if (userId !== this.userId) {
|
if (userId !== this.userId) {
|
||||||
if (!this.roomEncryptors[roomId]) {
|
if (!this.roomEncryptors.get(roomId)) {
|
||||||
logger.debug(`room key request for unencrypted room ${roomId}`);
|
logger.debug(`room key request for unencrypted room ${roomId}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const encryptor = this.roomEncryptors[roomId];
|
const encryptor = this.roomEncryptors.get(roomId);
|
||||||
const device = this.deviceList.getStoredDevice(userId, deviceId);
|
const device = this.deviceList.getStoredDevice(userId, deviceId);
|
||||||
if (!device) {
|
if (!device) {
|
||||||
logger.debug(`Ignoring keyshare for unknown device ${userId}:${deviceId}`);
|
logger.debug(`Ignoring keyshare for unknown device ${userId}:${deviceId}`);
|
||||||
@@ -3674,12 +3674,12 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
|
|
||||||
// if we don't have a decryptor for this room/alg, we don't have
|
// if we don't have a decryptor for this room/alg, we don't have
|
||||||
// the keys for the requested events, and can drop the requests.
|
// the keys for the requested events, and can drop the requests.
|
||||||
if (!this.roomDecryptors[roomId]) {
|
if (!this.roomDecryptors.has(roomId)) {
|
||||||
logger.log(`room key request for unencrypted room ${roomId}`);
|
logger.log(`room key request for unencrypted room ${roomId}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const decryptor = this.roomDecryptors[roomId][alg];
|
const decryptor = this.roomDecryptors.get(roomId).get(alg);
|
||||||
if (!decryptor) {
|
if (!decryptor) {
|
||||||
logger.log(`room key request for unknown alg ${alg} in room ${roomId}`);
|
logger.log(`room key request for unknown alg ${alg} in room ${roomId}`);
|
||||||
return;
|
return;
|
||||||
@@ -3745,23 +3745,24 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
* unknown
|
* unknown
|
||||||
*/
|
*/
|
||||||
public getRoomDecryptor(roomId: string, algorithm: string): DecryptionAlgorithm {
|
public getRoomDecryptor(roomId: string, algorithm: string): DecryptionAlgorithm {
|
||||||
let decryptors: Record<string, DecryptionAlgorithm>;
|
let decryptors: Map<string, DecryptionAlgorithm>;
|
||||||
let alg: DecryptionAlgorithm;
|
let alg: DecryptionAlgorithm;
|
||||||
|
|
||||||
roomId = roomId || null;
|
roomId = roomId || null;
|
||||||
if (roomId) {
|
if (roomId) {
|
||||||
decryptors = this.roomDecryptors[roomId];
|
decryptors = this.roomDecryptors.get(roomId);
|
||||||
if (!decryptors) {
|
if (!decryptors) {
|
||||||
this.roomDecryptors[roomId] = decryptors = {};
|
decryptors = new Map<string, DecryptionAlgorithm>();
|
||||||
|
this.roomDecryptors.set(roomId, decryptors);
|
||||||
}
|
}
|
||||||
|
|
||||||
alg = decryptors[algorithm];
|
alg = decryptors.get(algorithm);
|
||||||
if (alg) {
|
if (alg) {
|
||||||
return alg;
|
return alg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AlgClass = algorithms.DECRYPTION_CLASSES[algorithm];
|
const AlgClass = algorithms.DECRYPTION_CLASSES.get(algorithm);
|
||||||
if (!AlgClass) {
|
if (!AlgClass) {
|
||||||
throw new algorithms.DecryptionError(
|
throw new algorithms.DecryptionError(
|
||||||
'UNKNOWN_ENCRYPTION_ALGORITHM',
|
'UNKNOWN_ENCRYPTION_ALGORITHM',
|
||||||
@@ -3777,7 +3778,7 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (decryptors) {
|
if (decryptors) {
|
||||||
decryptors[algorithm] = alg;
|
decryptors.set(algorithm, alg);
|
||||||
}
|
}
|
||||||
return alg;
|
return alg;
|
||||||
}
|
}
|
||||||
@@ -3791,9 +3792,9 @@ export class Crypto extends TypedEventEmitter<CryptoEvent, CryptoEventHandlerMap
|
|||||||
*/
|
*/
|
||||||
private getRoomDecryptors(algorithm: string): DecryptionAlgorithm[] {
|
private getRoomDecryptors(algorithm: string): DecryptionAlgorithm[] {
|
||||||
const decryptors = [];
|
const decryptors = [];
|
||||||
for (const d of Object.values(this.roomDecryptors)) {
|
for (const d of this.roomDecryptors.values()) {
|
||||||
if (algorithm in d) {
|
if (d.has(algorithm)) {
|
||||||
decryptors.push(d[algorithm]);
|
decryptors.push(d.get(algorithm));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return decryptors;
|
return decryptors;
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
private readonly displayPendingEvents: boolean;
|
private readonly displayPendingEvents: boolean;
|
||||||
private liveTimeline: EventTimeline;
|
private liveTimeline: EventTimeline;
|
||||||
private timelines: EventTimeline[];
|
private timelines: EventTimeline[];
|
||||||
private _eventIdToTimeline: Record<string, EventTimeline>;
|
private _eventIdToTimeline = new Map<string, EventTimeline>();
|
||||||
private filter?: Filter;
|
private filter?: Filter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -138,7 +138,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
|
|
||||||
// just a list - *not* ordered.
|
// just a list - *not* ordered.
|
||||||
this.timelines = [this.liveTimeline];
|
this.timelines = [this.liveTimeline];
|
||||||
this._eventIdToTimeline = {};
|
this._eventIdToTimeline = new Map<string, EventTimeline>();
|
||||||
|
|
||||||
this.filter = opts.filter;
|
this.filter = opts.filter;
|
||||||
|
|
||||||
@@ -210,7 +210,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
* @return {module:models/event-timeline~EventTimeline} timeline
|
* @return {module:models/event-timeline~EventTimeline} timeline
|
||||||
*/
|
*/
|
||||||
public eventIdToTimeline(eventId: string): EventTimeline {
|
public eventIdToTimeline(eventId: string): EventTimeline {
|
||||||
return this._eventIdToTimeline[eventId];
|
return this._eventIdToTimeline.get(eventId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -220,10 +220,10 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
* @param {String} newEventId event ID of the replacement event
|
* @param {String} newEventId event ID of the replacement event
|
||||||
*/
|
*/
|
||||||
public replaceEventId(oldEventId: string, newEventId: string): void {
|
public replaceEventId(oldEventId: string, newEventId: string): void {
|
||||||
const existingTimeline = this._eventIdToTimeline[oldEventId];
|
const existingTimeline = this._eventIdToTimeline.get(oldEventId);
|
||||||
if (existingTimeline) {
|
if (existingTimeline) {
|
||||||
delete this._eventIdToTimeline[oldEventId];
|
this._eventIdToTimeline.delete(oldEventId);
|
||||||
this._eventIdToTimeline[newEventId] = existingTimeline;
|
this._eventIdToTimeline.set(newEventId, existingTimeline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,7 +257,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
|
|
||||||
if (resetAllTimelines) {
|
if (resetAllTimelines) {
|
||||||
this.timelines = [newTimeline];
|
this.timelines = [newTimeline];
|
||||||
this._eventIdToTimeline = {};
|
this._eventIdToTimeline = new Map<string, EventTimeline>();
|
||||||
} else {
|
} else {
|
||||||
this.timelines.push(newTimeline);
|
this.timelines.push(newTimeline);
|
||||||
}
|
}
|
||||||
@@ -288,7 +288,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
* the given event, or null if unknown
|
* the given event, or null if unknown
|
||||||
*/
|
*/
|
||||||
public getTimelineForEvent(eventId: string): EventTimeline | null {
|
public getTimelineForEvent(eventId: string): EventTimeline | null {
|
||||||
const res = this._eventIdToTimeline[eventId];
|
const res = this._eventIdToTimeline.get(eventId);
|
||||||
return (res === undefined) ? null : res;
|
return (res === undefined) ? null : res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -450,7 +450,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
const event = events[i];
|
const event = events[i];
|
||||||
const eventId = event.getId();
|
const eventId = event.getId();
|
||||||
|
|
||||||
const existingTimeline = this._eventIdToTimeline[eventId];
|
const existingTimeline = this._eventIdToTimeline.get(eventId);
|
||||||
|
|
||||||
if (!existingTimeline) {
|
if (!existingTimeline) {
|
||||||
// we don't know about this event yet. Just add it to the timeline.
|
// we don't know about this event yet. Just add it to the timeline.
|
||||||
@@ -601,7 +601,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeline = this._eventIdToTimeline[event.getId()];
|
const timeline = this._eventIdToTimeline.get(event.getId());
|
||||||
if (timeline) {
|
if (timeline) {
|
||||||
if (duplicateStrategy === DuplicateStrategy.Replace) {
|
if (duplicateStrategy === DuplicateStrategy.Replace) {
|
||||||
debuglog("EventTimelineSet.addLiveEvent: replacing duplicate event " + event.getId());
|
debuglog("EventTimelineSet.addLiveEvent: replacing duplicate event " + event.getId());
|
||||||
@@ -697,7 +697,7 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
roomState,
|
roomState,
|
||||||
timelineWasEmpty,
|
timelineWasEmpty,
|
||||||
});
|
});
|
||||||
this._eventIdToTimeline[eventId] = timeline;
|
this._eventIdToTimeline.set(eventId, timeline);
|
||||||
|
|
||||||
this.relations.aggregateParentEvent(event);
|
this.relations.aggregateParentEvent(event);
|
||||||
this.relations.aggregateChildEvent(event, this);
|
this.relations.aggregateChildEvent(event, this);
|
||||||
@@ -725,10 +725,10 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
newEventId: string,
|
newEventId: string,
|
||||||
): void {
|
): void {
|
||||||
// XXX: why don't we infer newEventId from localEvent?
|
// XXX: why don't we infer newEventId from localEvent?
|
||||||
const existingTimeline = this._eventIdToTimeline[oldEventId];
|
const existingTimeline = this._eventIdToTimeline.get(oldEventId);
|
||||||
if (existingTimeline) {
|
if (existingTimeline) {
|
||||||
delete this._eventIdToTimeline[oldEventId];
|
this._eventIdToTimeline.delete(oldEventId);
|
||||||
this._eventIdToTimeline[newEventId] = existingTimeline;
|
this._eventIdToTimeline.set(newEventId, existingTimeline);
|
||||||
} else {
|
} else {
|
||||||
if (this.filter) {
|
if (this.filter) {
|
||||||
if (this.filter.filterRoomTimeline([localEvent]).length) {
|
if (this.filter.filterRoomTimeline([localEvent]).length) {
|
||||||
@@ -753,14 +753,14 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
* in this room.
|
* in this room.
|
||||||
*/
|
*/
|
||||||
public removeEvent(eventId: string): MatrixEvent | null {
|
public removeEvent(eventId: string): MatrixEvent | null {
|
||||||
const timeline = this._eventIdToTimeline[eventId];
|
const timeline = this._eventIdToTimeline.get(eventId);
|
||||||
if (!timeline) {
|
if (!timeline) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const removed = timeline.removeEvent(eventId);
|
const removed = timeline.removeEvent(eventId);
|
||||||
if (removed) {
|
if (removed) {
|
||||||
delete this._eventIdToTimeline[eventId];
|
this._eventIdToTimeline.delete(eventId);
|
||||||
const data = {
|
const data = {
|
||||||
timeline: timeline,
|
timeline: timeline,
|
||||||
};
|
};
|
||||||
@@ -787,8 +787,8 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeline1 = this._eventIdToTimeline[eventId1];
|
const timeline1 = this._eventIdToTimeline.get(eventId1);
|
||||||
const timeline2 = this._eventIdToTimeline[eventId2];
|
const timeline2 = this._eventIdToTimeline.get(eventId2);
|
||||||
|
|
||||||
if (timeline1 === undefined) {
|
if (timeline1 === undefined) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { logger } from '../logger';
|
|||||||
import { VerificationRequest } from "../crypto/verification/request/VerificationRequest";
|
import { VerificationRequest } from "../crypto/verification/request/VerificationRequest";
|
||||||
import { EVENT_VISIBILITY_CHANGE_TYPE, EventType, MsgType, RelationType } from "../@types/event";
|
import { EVENT_VISIBILITY_CHANGE_TYPE, EventType, MsgType, RelationType } from "../@types/event";
|
||||||
import { Crypto, IEventDecryptionResult } from "../crypto";
|
import { Crypto, IEventDecryptionResult } from "../crypto";
|
||||||
import { deepSortedObjectEntries } from "../utils";
|
import { deepSortedObjectEntries, internaliseString } from "../utils";
|
||||||
import { RoomMember } from "./room-member";
|
import { RoomMember } from "./room-member";
|
||||||
import { Thread, ThreadEvent, EventHandlerMap as ThreadEventHandlerMap, THREAD_RELATION_TYPE } from "./thread";
|
import { Thread, ThreadEvent, EventHandlerMap as ThreadEventHandlerMap, THREAD_RELATION_TYPE } from "./thread";
|
||||||
import { IActionsObject } from '../pushprocessor';
|
import { IActionsObject } from '../pushprocessor';
|
||||||
@@ -37,14 +37,6 @@ import { EventStatus } from "./event-status";
|
|||||||
|
|
||||||
export { EventStatus } from "./event-status";
|
export { EventStatus } from "./event-status";
|
||||||
|
|
||||||
const interns: Record<string, string> = {};
|
|
||||||
function intern(str: string): string {
|
|
||||||
if (!interns[str]) {
|
|
||||||
interns[str] = str;
|
|
||||||
}
|
|
||||||
return interns[str];
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
export interface IContent {
|
export interface IContent {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
@@ -326,17 +318,17 @@ export class MatrixEvent extends TypedEventEmitter<EmittedEvents, MatrixEventHan
|
|||||||
// of space if we don't intern it.
|
// of space if we don't intern it.
|
||||||
["state_key", "type", "sender", "room_id", "membership"].forEach((prop) => {
|
["state_key", "type", "sender", "room_id", "membership"].forEach((prop) => {
|
||||||
if (typeof event[prop] !== "string") return;
|
if (typeof event[prop] !== "string") return;
|
||||||
event[prop] = intern(event[prop]);
|
event[prop] = internaliseString(event[prop]);
|
||||||
});
|
});
|
||||||
|
|
||||||
["membership", "avatar_url", "displayname"].forEach((prop) => {
|
["membership", "avatar_url", "displayname"].forEach((prop) => {
|
||||||
if (typeof event.content?.[prop] !== "string") return;
|
if (typeof event.content?.[prop] !== "string") return;
|
||||||
event.content[prop] = intern(event.content[prop]);
|
event.content[prop] = internaliseString(event.content[prop]);
|
||||||
});
|
});
|
||||||
|
|
||||||
["rel_type"].forEach((prop) => {
|
["rel_type"].forEach((prop) => {
|
||||||
if (typeof event.content?.["m.relates_to"]?.[prop] !== "string") return;
|
if (typeof event.content?.["m.relates_to"]?.[prop] !== "string") return;
|
||||||
event.content["m.relates_to"][prop] = intern(event.content["m.relates_to"][prop]);
|
event.content["m.relates_to"][prop] = internaliseString(event.content["m.relates_to"][prop]);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.txnId = event.txn_id || null;
|
this.txnId = event.txn_id || null;
|
||||||
@@ -796,6 +788,8 @@ export class MatrixEvent extends TypedEventEmitter<EmittedEvents, MatrixEventHan
|
|||||||
// not a decryption error: log the whole exception as an error
|
// not a decryption error: log the whole exception as an error
|
||||||
// (and don't bother with a retry)
|
// (and don't bother with a retry)
|
||||||
const re = options.isRetry ? 're' : '';
|
const re = options.isRetry ? 're' : '';
|
||||||
|
// For find results: this can produce "Error decrypting event (id=$ev)" and
|
||||||
|
// "Error redecrypting event (id=$ev)".
|
||||||
logger.error(
|
logger.error(
|
||||||
`Error ${re}decrypting event ` +
|
`Error ${re}decrypting event ` +
|
||||||
`(id=${this.getId()}): ${e.stack || e}`,
|
`(id=${this.getId()}): ${e.stack || e}`,
|
||||||
|
|||||||
@@ -23,14 +23,8 @@ import { Room } from "./room";
|
|||||||
|
|
||||||
export class RelationsContainer {
|
export class RelationsContainer {
|
||||||
// A tree of objects to access a set of related children for an event, as in:
|
// A tree of objects to access a set of related children for an event, as in:
|
||||||
// this.relations[parentEventId][relationType][relationEventType]
|
// this.relations.get(parentEventId).get(relationType).get(relationEventType)
|
||||||
private relations: {
|
private relations = new Map<string, Map<RelationType | string, Map<EventType | string, Relations>>>();
|
||||||
[parentEventId: string]: {
|
|
||||||
[relationType: RelationType | string]: {
|
|
||||||
[eventType: EventType | string]: Relations;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
} = {};
|
|
||||||
|
|
||||||
constructor(private readonly client: MatrixClient, private readonly room?: Room) {
|
constructor(private readonly client: MatrixClient, private readonly room?: Room) {
|
||||||
}
|
}
|
||||||
@@ -57,14 +51,15 @@ export class RelationsContainer {
|
|||||||
relationType: RelationType | string,
|
relationType: RelationType | string,
|
||||||
eventType: EventType | string,
|
eventType: EventType | string,
|
||||||
): Relations | undefined {
|
): Relations | undefined {
|
||||||
return this.relations[eventId]?.[relationType]?.[eventType];
|
return this.relations.get(eventId)?.get(relationType)?.get(eventType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAllChildEventsForEvent(parentEventId: string): MatrixEvent[] {
|
public getAllChildEventsForEvent(parentEventId: string): MatrixEvent[] {
|
||||||
const relationsForEvent = this.relations[parentEventId] ?? {};
|
const relationsForEvent = this.relations.get(parentEventId)
|
||||||
|
?? new Map<RelationType | string, Map<EventType | string, Relations>>();
|
||||||
const events: MatrixEvent[] = [];
|
const events: MatrixEvent[] = [];
|
||||||
for (const relationsRecord of Object.values(relationsForEvent)) {
|
for (const relationsRecord of relationsForEvent.values()) {
|
||||||
for (const relations of Object.values(relationsRecord)) {
|
for (const relations of relationsRecord.values()) {
|
||||||
events.push(...relations.getRelations());
|
events.push(...relations.getRelations());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,11 +74,11 @@ export class RelationsContainer {
|
|||||||
* @param {MatrixEvent} event The event to check as relation target.
|
* @param {MatrixEvent} event The event to check as relation target.
|
||||||
*/
|
*/
|
||||||
public aggregateParentEvent(event: MatrixEvent): void {
|
public aggregateParentEvent(event: MatrixEvent): void {
|
||||||
const relationsForEvent = this.relations[event.getId()];
|
const relationsForEvent = this.relations.get(event.getId());
|
||||||
if (!relationsForEvent) return;
|
if (!relationsForEvent) return;
|
||||||
|
|
||||||
for (const relationsWithRelType of Object.values(relationsForEvent)) {
|
for (const relationsWithRelType of relationsForEvent.values()) {
|
||||||
for (const relationsWithEventType of Object.values(relationsWithRelType)) {
|
for (const relationsWithEventType of relationsWithRelType.values()) {
|
||||||
relationsWithEventType.setTargetEvent(event);
|
relationsWithEventType.setTargetEvent(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,23 +118,26 @@ export class RelationsContainer {
|
|||||||
const { event_id: relatesToEventId, rel_type: relationType } = relation;
|
const { event_id: relatesToEventId, rel_type: relationType } = relation;
|
||||||
const eventType = event.getType();
|
const eventType = event.getType();
|
||||||
|
|
||||||
let relationsForEvent = this.relations[relatesToEventId];
|
let relationsForEvent = this.relations.get(relatesToEventId);
|
||||||
if (!relationsForEvent) {
|
if (!relationsForEvent) {
|
||||||
relationsForEvent = this.relations[relatesToEventId] = {};
|
relationsForEvent = new Map<RelationType | string, Map<EventType | string, Relations>>();
|
||||||
|
this.relations.set(relatesToEventId, relationsForEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
let relationsWithRelType = relationsForEvent[relationType];
|
let relationsWithRelType = relationsForEvent.get(relationType);
|
||||||
if (!relationsWithRelType) {
|
if (!relationsWithRelType) {
|
||||||
relationsWithRelType = relationsForEvent[relationType] = {};
|
relationsWithRelType = new Map<EventType | string, Relations>();
|
||||||
|
relationsForEvent.set(relationType, relationsWithRelType);
|
||||||
}
|
}
|
||||||
|
|
||||||
let relationsWithEventType = relationsWithRelType[eventType];
|
let relationsWithEventType = relationsWithRelType.get(eventType);
|
||||||
if (!relationsWithEventType) {
|
if (!relationsWithEventType) {
|
||||||
relationsWithEventType = relationsWithRelType[eventType] = new Relations(
|
relationsWithEventType = new Relations(
|
||||||
relationType,
|
relationType,
|
||||||
eventType,
|
eventType,
|
||||||
this.client,
|
this.client,
|
||||||
);
|
);
|
||||||
|
relationsWithRelType.set(eventType, relationsWithEventType);
|
||||||
|
|
||||||
const room = this.room ?? timelineSet?.room;
|
const room = this.room ?? timelineSet?.room;
|
||||||
const relatesToEvent = timelineSet?.findEventById(relatesToEventId)
|
const relatesToEvent = timelineSet?.findEventById(relatesToEventId)
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
|
|||||||
public readonly reEmitter = new TypedReEmitter<EmittedEvents, EventHandlerMap>(this);
|
public readonly reEmitter = new TypedReEmitter<EmittedEvents, EventHandlerMap>(this);
|
||||||
private sentinels: Record<string, RoomMember> = {}; // userId: RoomMember
|
private sentinels: Record<string, RoomMember> = {}; // userId: RoomMember
|
||||||
// stores fuzzy matches to a list of userIDs (applies utils.removeHiddenChars to keys)
|
// stores fuzzy matches to a list of userIDs (applies utils.removeHiddenChars to keys)
|
||||||
private displayNameToUserIds: Record<string, string[]> = {};
|
private displayNameToUserIds = new Map<string, string[]>();
|
||||||
private userIdsToDisplayNames: Record<string, string> = {};
|
private userIdsToDisplayNames: Record<string, string> = {};
|
||||||
private tokenToInvite: Record<string, MatrixEvent> = {}; // 3pid invite state_key to m.room.member invite
|
private tokenToInvite: Record<string, MatrixEvent> = {}; // 3pid invite state_key to m.room.member invite
|
||||||
private joinedMemberCount: number = null; // cache of the number of joined members
|
private joinedMemberCount: number = null; // cache of the number of joined members
|
||||||
@@ -709,7 +709,7 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
|
|||||||
* @return {string[]} An array of user IDs or an empty array.
|
* @return {string[]} An array of user IDs or an empty array.
|
||||||
*/
|
*/
|
||||||
public getUserIdsWithDisplayName(displayName: string): string[] {
|
public getUserIdsWithDisplayName(displayName: string): string[] {
|
||||||
return this.displayNameToUserIds[utils.removeHiddenChars(displayName)] || [];
|
return this.displayNameToUserIds.get(utils.removeHiddenChars(displayName)) ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -941,11 +941,11 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
|
|||||||
// the lot.
|
// the lot.
|
||||||
const strippedOldName = utils.removeHiddenChars(oldName);
|
const strippedOldName = utils.removeHiddenChars(oldName);
|
||||||
|
|
||||||
const existingUserIds = this.displayNameToUserIds[strippedOldName];
|
const existingUserIds = this.displayNameToUserIds.get(strippedOldName);
|
||||||
if (existingUserIds) {
|
if (existingUserIds) {
|
||||||
// remove this user ID from this array
|
// remove this user ID from this array
|
||||||
const filteredUserIDs = existingUserIds.filter((id) => id !== userId);
|
const filteredUserIDs = existingUserIds.filter((id) => id !== userId);
|
||||||
this.displayNameToUserIds[strippedOldName] = filteredUserIDs;
|
this.displayNameToUserIds.set(strippedOldName, filteredUserIDs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -954,10 +954,9 @@ export class RoomState extends TypedEventEmitter<EmittedEvents, EventHandlerMap>
|
|||||||
const strippedDisplayname = displayName && utils.removeHiddenChars(displayName);
|
const strippedDisplayname = displayName && utils.removeHiddenChars(displayName);
|
||||||
// an empty stripped displayname (undefined/'') will be set to MXID in room-member.js
|
// an empty stripped displayname (undefined/'') will be set to MXID in room-member.js
|
||||||
if (strippedDisplayname) {
|
if (strippedDisplayname) {
|
||||||
if (!this.displayNameToUserIds[strippedDisplayname]) {
|
const arr = this.displayNameToUserIds.get(strippedDisplayname) ?? [];
|
||||||
this.displayNameToUserIds[strippedDisplayname] = [];
|
arr.push(userId);
|
||||||
}
|
this.displayNameToUserIds.set(strippedDisplayname, arr);
|
||||||
this.displayNameToUserIds[strippedDisplayname].push(userId);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
src/utils.ts
24
src/utils.ts
@@ -28,6 +28,30 @@ import { MatrixClient, MatrixEvent } from ".";
|
|||||||
import { M_TIMESTAMP } from "./@types/location";
|
import { M_TIMESTAMP } from "./@types/location";
|
||||||
import { ReceiptType } from "./@types/read_receipts";
|
import { ReceiptType } from "./@types/read_receipts";
|
||||||
|
|
||||||
|
const interns = new Map<string, string>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internalises a string, reusing a known pointer or storing the pointer
|
||||||
|
* if needed for future strings.
|
||||||
|
* @param str The string to internalise.
|
||||||
|
* @returns The internalised string.
|
||||||
|
*/
|
||||||
|
export function internaliseString(str: string): string {
|
||||||
|
// Unwrap strings before entering the map, if we somehow got a wrapped
|
||||||
|
// string as our input. This should only happen from tests.
|
||||||
|
if ((str as unknown) instanceof String) {
|
||||||
|
str = str.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the map to see if we can store the value
|
||||||
|
if (!interns.has(str)) {
|
||||||
|
interns.set(str, str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return any cached string reference
|
||||||
|
return interns.get(str);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode a dictionary of query parameters.
|
* Encode a dictionary of query parameters.
|
||||||
* Omits any undefined/null values.
|
* Omits any undefined/null values.
|
||||||
|
|||||||
Reference in New Issue
Block a user