1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-28 05:03:59 +03:00

Merge branch 'develop' into backup_refactor

This commit is contained in:
Hubert Chathi
2021-06-03 18:43:46 -04:00
120 changed files with 1045 additions and 911 deletions

View File

@@ -2,7 +2,9 @@ module.exports = {
plugins: [
"matrix-org",
],
extends: ["plugin:matrix-org/javascript"],
extends: [
"plugin:matrix-org/babel",
],
env: {
browser: true,
node: true,
@@ -31,14 +33,26 @@ module.exports = {
"no-console": "error",
},
overrides: [{
"files": ["src/**/*.ts"],
"extends": ["plugin:matrix-org/typescript"],
"rules": {
files: [
"**/*.ts",
],
extends: [
"plugin:matrix-org/typescript",
],
rules: {
// TypeScript has its own version of this
"@babel/no-invalid-this": "off",
// We're okay being explicit at the moment
"@typescript-eslint/no-empty-interface": "off",
// While we're converting to ts we make heavy use of this
// We disable this while we're transitioning
"@typescript-eslint/no-explicit-any": "off",
// We'd rather not do this but we do
"@typescript-eslint/ban-ts-comment": "off",
"quotes": "off",
// We use a `logger` intermediary module
"no-console": "error",
},
}],
};

View File

@@ -1,3 +1,26 @@
Changes in [11.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v11.1.0) (2021-05-24)
==================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v11.1.0-rc.1...v11.1.0)
* [Release] Bump libolm version and update package name
[\#1707](https://github.com/matrix-org/matrix-js-sdk/pull/1707)
* [Release] Change call event handlers to adapt to undecrypted events
[\#1699](https://github.com/matrix-org/matrix-js-sdk/pull/1699)
Changes in [11.1.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v11.1.0-rc.1) (2021-05-19)
============================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v11.0.0...v11.1.0-rc.1)
* Fix regressed glare
[\#1690](https://github.com/matrix-org/matrix-js-sdk/pull/1690)
* Add m.reaction to EventType enum
[\#1692](https://github.com/matrix-org/matrix-js-sdk/pull/1692)
* Prioritise and reduce the amount of events decrypted on application startup
[\#1684](https://github.com/matrix-org/matrix-js-sdk/pull/1684)
* Decrypt relations before applying them to target event
[\#1696](https://github.com/matrix-org/matrix-js-sdk/pull/1696)
* Guard against duplicates in `Relations` model
Changes in [11.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v11.0.0) (2021-05-17)
==================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v11.0.0-rc.1...v11.0.0)

View File

@@ -1,6 +1,6 @@
{
"name": "matrix-js-sdk",
"version": "11.0.0",
"version": "11.1.0",
"description": "Matrix Client-Server SDK for Javascript",
"scripts": {
"prepublishOnly": "yarn build",
@@ -72,6 +72,7 @@
"@babel/preset-env": "^7.12.11",
"@babel/preset-typescript": "^7.12.7",
"@babel/register": "^7.12.10",
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz",
"@types/jest": "^26.0.20",
"@types/node": "12",
"@types/request": "^2.48.5",
@@ -91,7 +92,6 @@
"jest-localstorage-mock": "^2.4.6",
"jsdoc": "^3.6.6",
"matrix-mock-request": "^1.2.3",
"olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz",
"rimraf": "^3.0.2",
"terser": "^5.5.1",
"tsify": "^5.0.2",

View File

@@ -133,7 +133,6 @@ TestClient.prototype.expectDeviceKeyUpload = function() {
});
};
/**
* If one-time keys have already been uploaded, return them. Otherwise,
* set up an expectation that the keys will be uploaded, and wait for
@@ -197,7 +196,6 @@ TestClient.prototype.expectKeyQuery = function(response) {
});
};
/**
* get the uploaded curve25519 device key
*
@@ -208,7 +206,6 @@ TestClient.prototype.getDeviceKey = function() {
return this.deviceKeys.keys[keyId];
};
/**
* get the uploaded ed25519 device key
*

View File

@@ -67,7 +67,6 @@ function getSyncResponse(roomMembers) {
return syncResponse;
}
describe("DeviceList management:", function() {
if (!global.Olm) {
logger.warn('not running deviceList tests: Olm not present');
@@ -137,7 +136,6 @@ describe("DeviceList management:", function() {
});
});
it("We should not get confused by out-of-order device query responses",
() => {
// https://github.com/vector-im/element-web/issues/3126
@@ -323,7 +321,6 @@ describe("DeviceList management:", function() {
},
);
await aliceTestClient.flushSync();
await aliceTestClient.client._crypto._deviceList.saveIfDirty();

View File

@@ -144,7 +144,6 @@ function expectAliClaimKeys() {
});
}
function aliDownloadsKeys() {
// can't query keys before bob has uploaded them
expect(bobTestClient.getSigningKey()).toBeTruthy();
@@ -357,7 +356,6 @@ function recvMessage(httpBackend, client, sender, message) {
});
}
/**
* Send an initial sync response to the client (which just includes the member
* list for our test room).
@@ -395,7 +393,6 @@ function firstSync(testClient) {
return testClient.flushSync();
}
describe("MatrixClient crypto", function() {
if (!CRYPTO_ENABLED) {
return;
@@ -533,7 +530,6 @@ describe("MatrixClient crypto", function() {
});
});
it("Bob starts his client and uploads device keys and one-time keys", function() {
return Promise.resolve()
.then(() => bobTestClient.start())

View File

@@ -141,7 +141,6 @@ describe("getEventTimeline support", function() {
});
});
it("scrollback should be able to scroll back to before a gappy /sync",
function() {
// need a client with timelineSupport disabled to make this work
@@ -532,7 +531,6 @@ describe("MatrixClient event timelines", function() {
]);
});
it("should allow you to paginate forwards", function() {
const room = client.getRoom(roomId);
const timelineSet = room.getTimelineSets()[0];
@@ -680,7 +678,6 @@ describe("MatrixClient event timelines", function() {
});
});
it("should handle gappy syncs after redactions", function() {
// https://github.com/vector-im/vector-web/issues/1389

View File

@@ -285,7 +285,6 @@ describe("MatrixClient", function() {
});
});
describe("downloadKeys", function() {
if (!CRYPTO_ENABLED) {
return;

View File

@@ -2,7 +2,6 @@ import * as utils from "../test-utils";
import { EventStatus } from "../../src/models/event";
import { TestClient } from "../TestClient";
describe("MatrixClient room timelines", function() {
let client = null;
let httpBackend = null;

View File

@@ -122,7 +122,6 @@ describe("MatrixClient syncing", function() {
resolveInvitesToProfiles: true,
});
return Promise.all([
httpBackend.flushAllExpected(),
awaitSyncEvent(),

View File

@@ -196,7 +196,6 @@ function getSyncResponse(roomMembers) {
return syncResponse;
}
describe("megolm", function() {
if (!global.Olm) {
logger.warn('not running megolm tests: Olm not present');
@@ -841,7 +840,6 @@ describe("megolm", function() {
});
});
it('Alice should wait for device list to complete when sending a megolm message',
function() {
let downloadPromise;
@@ -887,7 +885,6 @@ describe("megolm", function() {
});
});
it("Alice exports megolm keys and imports them to a new device", function() {
let messageEncrypted;

View File

@@ -20,7 +20,7 @@ import * as utils from "../src/utils";
// try to load the olm library.
try {
global.Olm = require('olm');
global.Olm = require('@matrix-org/olm');
logger.log('loaded libolm');
} catch (e) {
logger.warn("unable to run crypto tests: libolm not available");

View File

@@ -177,7 +177,6 @@ export function mkMessage(opts) {
return mkEvent(opts);
}
/**
* A mock implementation of webstorage
*
@@ -204,7 +203,6 @@ MockStorageApi.prototype = {
},
};
/**
* If an event is being decrypted, wait for it to finish being decrypted.
*
@@ -229,7 +227,6 @@ export function awaitDecryption(event) {
}
}
export function HttpResponse(
httpLookups, acceptKeepalives, ignoreUnhandledSync,
) {

View File

@@ -50,7 +50,6 @@ describe("MegolmDecryption", function() {
roomId: ROOM_ID,
});
// we stub out the olm encryption bits
mockOlmLib = {};
mockOlmLib.ensureOlmSessionsForDevices = jest.fn();

View File

@@ -1,6 +1,5 @@
import { IndexedDBCryptoStore } from '../../../src/crypto/store/indexeddb-crypto-store';
// needs to be phased out and replaced with bootstrapSecretStorage,
// but that is doing too much extra stuff for it to be an easy transition.
export async function resetCrossSigningKeys(client, {

View File

@@ -94,7 +94,6 @@ describe("EventTimeline", function() {
});
});
describe("neighbouringTimelines", function() {
it("neighbouring timelines should start null", function() {
expect(timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS)).toBe(null);
@@ -278,7 +277,6 @@ describe("EventTimeline", function() {
not.toHaveBeenCalled();
});
it("should call setStateEvents on the right RoomState with the right " +
"forwardLooking value for old events", function() {
const events = [

133
spec/unit/relations.spec.ts Normal file
View File

@@ -0,0 +1,133 @@
/*
Copyright 2021 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { EventTimelineSet } from "../../src/models/event-timeline-set";
import { MatrixEvent } from "../../src/models/event";
import { Relations } from "../../src/models/relations";
describe("Relations", function() {
it("should deduplicate annotations", function() {
const relations = new Relations("m.annotation", "m.reaction");
// Create an instance of an annotation
const eventData = {
"sender": "@bob:example.com",
"type": "m.reaction",
"event_id": "$cZ1biX33ENJqIm00ks0W_hgiO_6CHrsAc3ZQrnLeNTw",
"room_id": "!pzVjCQSoQPpXQeHpmK:example.com",
"content": {
"m.relates_to": {
"event_id": "$2s4yYpEkVQrPglSCSqB_m6E8vDhWsg0yFNyOJdVIb_o",
"key": "👍️",
"rel_type": "m.annotation",
},
},
};
const eventA = new MatrixEvent(eventData);
// Add the event once and check results
{
relations.addEvent(eventA);
const annotationsByKey = relations.getSortedAnnotationsByKey();
expect(annotationsByKey.length).toEqual(1);
const [key, events] = annotationsByKey[0];
expect(key).toEqual("👍️");
expect(events.size).toEqual(1);
}
// Add the event again and expect the same
{
relations.addEvent(eventA);
const annotationsByKey = relations.getSortedAnnotationsByKey();
expect(annotationsByKey.length).toEqual(1);
const [key, events] = annotationsByKey[0];
expect(key).toEqual("👍️");
expect(events.size).toEqual(1);
}
// Create a fresh object with the same event content
const eventB = new MatrixEvent(eventData);
// Add the event again and expect the same
{
relations.addEvent(eventB);
const annotationsByKey = relations.getSortedAnnotationsByKey();
expect(annotationsByKey.length).toEqual(1);
const [key, events] = annotationsByKey[0];
expect(key).toEqual("👍️");
expect(events.size).toEqual(1);
}
});
it("should emit created regardless of ordering", async function() {
const targetEvent = new MatrixEvent({
"sender": "@bob:example.com",
"type": "m.room.message",
"event_id": "$2s4yYpEkVQrPglSCSqB_m6E8vDhWsg0yFNyOJdVIb_o",
"room_id": "!pzVjCQSoQPpXQeHpmK:example.com",
"content": {},
});
const relationEvent = new MatrixEvent({
"sender": "@bob:example.com",
"type": "m.reaction",
"event_id": "$cZ1biX33ENJqIm00ks0W_hgiO_6CHrsAc3ZQrnLeNTw",
"room_id": "!pzVjCQSoQPpXQeHpmK:example.com",
"content": {
"m.relates_to": {
"event_id": "$2s4yYpEkVQrPglSCSqB_m6E8vDhWsg0yFNyOJdVIb_o",
"key": "👍️",
"rel_type": "m.annotation",
},
},
});
// Stub the room
const room = {
getPendingEvent() { return null; },
getUnfilteredTimelineSet() { return null; },
};
// Add the target event first, then the relation event
{
const relationsCreated = new Promise(resolve => {
targetEvent.once("Event.relationsCreated", resolve);
})
const timelineSet = new EventTimelineSet(room, {
unstableClientRelationAggregation: true,
});
timelineSet.addLiveEvent(targetEvent);
timelineSet.addLiveEvent(relationEvent);
await relationsCreated;
}
// Add the relation event first, then the target event
{
const relationsCreated = new Promise(resolve => {
targetEvent.once("Event.relationsCreated", resolve);
})
const timelineSet = new EventTimelineSet(room, {
unstableClientRelationAggregation: true,
});
timelineSet.addLiveEvent(relationEvent);
timelineSet.addLiveEvent(targetEvent);
await relationsCreated;
}
});
});

View File

@@ -1267,7 +1267,6 @@ describe("Room", function() {
expect(callCount).toEqual(1);
});
it("should remove cancelled events from the timeline", function() {
const room = new Room(roomId, null, userA);
const eventA = utils.mkMessage({

View File

@@ -46,7 +46,6 @@ function addEventsToTimeline(timeline, numEvents, atStart) {
}
}
/*
* create a pair of linked timelines
*/
@@ -58,7 +57,6 @@ function createLinkedTimelines() {
return [tl1, tl2];
}
describe("TimelineIndex", function() {
describe("minIndex", function() {
it("should return the min index relative to BaseIndex", function() {
@@ -133,7 +131,6 @@ describe("TimelineIndex", function() {
});
});
describe("TimelineWindow", function() {
/**
* create a dummy eventTimelineSet and client, and a TimelineWindow
@@ -385,7 +382,6 @@ describe("TimelineWindow", function() {
});
});
it("should make backward pagination requests", function() {
const timeline = createTimeline();
timeline.setPaginationToken("toktok", EventTimeline.BACKWARDS);

View File

@@ -175,7 +175,6 @@ describe("utils", function() {
});
});
describe("extend", function() {
const SOURCE = { "prop2": 1, "string2": "x", "newprop": "new" };

View File

@@ -15,7 +15,7 @@ limitations under the License.
*/
// this is needed to tell TS about global.Olm
import * as Olm from "olm"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as Olm from "@matrix-org/olm"; // eslint-disable-line @typescript-eslint/no-unused-vars
export {};

View File

@@ -158,7 +158,6 @@ MatrixBaseApis.prototype.makeTxnId = function() {
return "m" + new Date().getTime() + "." + (this._txnCtr++);
};
// Registration/Login operations
// =============================
@@ -379,14 +378,12 @@ MatrixBaseApis.prototype.getSsoLoginUrl = function(redirectUrl, loginType, idpId
loginType = "sso";
}
let prefix = PREFIX_R0;
let url = "/login/" + loginType + "/redirect";
if (idpId) {
url += "/" + idpId;
prefix = "/_matrix/client/unstable/org.matrix.msc2858";
}
return this._http.getUrl(url, { redirectUrl }, prefix);
return this._http.getUrl(url, { redirectUrl }, PREFIX_R0);
};
/**
@@ -401,7 +398,6 @@ MatrixBaseApis.prototype.loginWithToken = function(token, callback) {
}, callback);
};
/**
* Logs out the current session.
* Obviously, further calls that require authorisation should fail after this
@@ -613,7 +609,6 @@ MatrixBaseApis.prototype.upgradeRoom = function(roomId, newVersion) {
);
};
/**
* @param {string} groupId
* @return {Promise} Resolves: Group summary object
@@ -1278,7 +1273,6 @@ MatrixBaseApis.prototype.searchUserDirectory = function(opts) {
);
};
// Media operations
// ================
@@ -1347,7 +1341,6 @@ MatrixBaseApis.prototype.getCurrentUploads = function() {
return this._http.getCurrentUploads();
};
// Profile operations
// ==================
@@ -1372,7 +1365,6 @@ MatrixBaseApis.prototype.getProfileInfo = function(userId, info, callback) {
return this._http.authedRequest(callback, "GET", path);
};
// Account operations
// ==================
@@ -1518,7 +1510,6 @@ MatrixBaseApis.prototype.setPassword = function(authDict, newPassword, callback)
);
};
// Device operations
// =================
@@ -1605,7 +1596,6 @@ MatrixBaseApis.prototype.deleteMultipleDevices = function(devices, auth) {
return this._http.authedRequest(undefined, "POST", path, undefined, body);
};
// Push operations
// ===============
@@ -1728,7 +1718,6 @@ MatrixBaseApis.prototype.setPushRuleActions = function(scope, kind,
);
};
// Search
// ======

View File

@@ -17,7 +17,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* This is an internal module. See {@link MatrixClient} for the public class.
* @module client
@@ -335,6 +334,10 @@ export function MatrixClient(opts) {
if (call) {
this._callEventHandler = new CallEventHandler(this);
this._supportsVoip = true;
// Start listening for calls after the initial sync is done
// We do not need to backfill the call event buffer
// with encrypted events that might never get decrypted
this.on("sync", this._startCallEventHandler);
} else {
this._callEventHandler = null;
}
@@ -684,7 +687,6 @@ MatrixClient.prototype.getDeviceId = function() {
return this.deviceId;
};
/**
* Check if the runtime environment supports VoIP calling.
* @return {boolean} True if VoIP is supported.
@@ -947,14 +949,12 @@ MatrixClient.prototype.initCrypto = async function() {
this.olmVersion = Crypto.getOlmVersion();
// if crypto initialisation was successful, tell it to attach its event
// handlers.
crypto.registerEventHandlers(this);
this._crypto = crypto;
};
/**
* Is end-to-end crypto enabled for this client.
* @return {boolean} True if end-to-end is enabled.
@@ -2842,7 +2842,6 @@ MatrixClient.prototype._sendCompleteEvent = function(roomId, eventObject, txnId,
return _sendEvent(this, room, localEvent, callback);
};
// encrypts the event if necessary
// adds the event to the queue, or sends it
// marks the event as sent/unsent
@@ -4526,7 +4525,6 @@ MatrixClient.prototype._requestTokenFromEndpoint = async function(endpoint, para
);
};
// Push operations
// ===============
@@ -4782,7 +4780,6 @@ MatrixClient.prototype._processRoomEventsSearch = function(searchResults, respon
return searchResults;
};
/**
* Populate the store with rooms the user has left.
* @return {Promise} Resolves: TODO - Resolved when the rooms have
@@ -4928,7 +4925,6 @@ MatrixClient.prototype.getOrCreateFilter = async function(filterName, filter) {
return createdFilter.filterId;
};
/**
* Gets a bearer token from the Home Server that the user can
* present to a third party in order to prove their ownership
@@ -4946,10 +4942,16 @@ MatrixClient.prototype.getOpenIdToken = function() {
);
};
// VoIP operations
// ===============
MatrixClient.prototype._startCallEventHandler = function() {
if (this.isInitialSyncComplete()) {
this._callEventHandler.start();
this.off("sync", this._startCallEventHandler);
}
};
/**
* @param {module:client.callback} callback Optional.
* @return {Promise} Resolves: TODO
@@ -5107,7 +5109,6 @@ MatrixClient.prototype.deactivateSynapseUser = function(userId) {
// due to ambiguity (or should this be on a chat-specific layer)?
// reconnect after connectivity outages
/**
* High level helper method to begin syncing and poll for new events. To listen for these
* events, add a listener for {@link module:client~MatrixClient#event:"event"}
@@ -5530,7 +5531,7 @@ function _PojoToMatrixEventMapper(client, options = {}) {
]);
}
if (decrypt) {
event.attemptDecryption(client._crypto);
client.decryptEventIfNeeded(event);
}
}
if (!preventReEmit) {
@@ -5572,6 +5573,26 @@ MatrixClient.prototype.generateClientSecret = function() {
return randomString(32);
};
/**
* Attempts to decrypt an event
* @param {MatrixEvent} event The event to decrypt
* @returns {Promise<void>} A decryption promise
* @param {object} options
* @param {bool} options.isRetry True if this is a retry (enables more logging)
* @param {bool} options.emit Emits "event.decrypted" if set to true
*/
MatrixClient.prototype.decryptEventIfNeeded = function(event, options) {
if (event.shouldAttemptDecryption()) {
event.attemptDecryption(this._crypto, options);
}
if (event.isBeingDecrypted()) {
return event._decryptionPromise;
} else {
return Promise.resolve();
}
};
// MatrixClient Event JSDocs
/**

View File

@@ -30,7 +30,6 @@ import * as olmlib from './olmlib';
import { IndexedDBCryptoStore } from './store/indexeddb-crypto-store';
import { chunkPromises, defer, sleep } from '../utils';
/* State transition diagram for DeviceList._deviceTrackingStatus
*
* |
@@ -51,7 +50,6 @@ import {chunkPromises, defer, sleep} from '../utils';
* +----------------------- UP_TO_DATE ------------------------+
*/
// constants for DeviceList._deviceTrackingStatus
const TRACKING_STATUS_NOT_TRACKED = 0;
const TRACKING_STATUS_PENDING_DOWNLOAD = 1;
@@ -892,7 +890,6 @@ class DeviceListUpdateSerialiser {
}
}
async function _updateStoredDeviceKeysForUser(
_olmDevice, userId, userStore, userResult, localUserId, localDeviceId,
) {

View File

@@ -86,7 +86,6 @@ export class EncryptionSetupBuilder {
userSignatures[deviceId] = signature;
}
/**
* @param {String} type
* @param {Object} content
@@ -225,7 +224,6 @@ export class EncryptionSetupOperation {
}
}
/**
* Catches account data set by SecretStorage during bootstrapping by
* implementing the methods related to account data in MatrixClient

View File

@@ -48,7 +48,6 @@ function checkPayloadLength(payloadString) {
}
}
/**
* The type of object we use for importing and exporting megolm session data.
*
@@ -62,7 +61,6 @@ function checkPayloadLength(payloadString) {
* @property {String} session_key Base64'ed key data
*/
/**
* Manages the olm cryptography functions. Each OlmDevice has a single
* OlmAccount and a number of OlmSessions.
@@ -376,7 +374,6 @@ OlmDevice.prototype._saveSession = function(deviceKey, sessionInfo, txn) {
);
};
/**
* get an OlmUtility and call the given function
*
@@ -393,7 +390,6 @@ OlmDevice.prototype._getUtility = function(func) {
}
};
/**
* Signs a message with the ed25519 key for this account.
*
@@ -434,7 +430,6 @@ OlmDevice.prototype.getOneTimeKeys = async function() {
return result;
};
/**
* Get the maximum number of one-time keys we can store.
*
@@ -550,7 +545,6 @@ OlmDevice.prototype.createOutboundSession = async function(
return newSessionId;
};
/**
* Generate a new inbound session, given an incoming message
*
@@ -612,7 +606,6 @@ OlmDevice.prototype.createInboundSession = async function(
return result;
};
/**
* Get a list of known session IDs for the given device
*
@@ -856,7 +849,6 @@ OlmDevice.prototype.filterOutNotifiedErrorDevices = async function(devices) {
return await this._cryptoStore.filterOutNotifiedErrorDevices(devices);
};
// Outbound group session
// ======================
@@ -871,7 +863,6 @@ OlmDevice.prototype._saveOutboundGroupSession = function(session) {
this._outboundGroupSessionStore[session.session_id()] = pickledSession;
};
/**
* extract an OutboundGroupSession from _outboundGroupSessionStore and call the
* given function
@@ -896,7 +887,6 @@ OlmDevice.prototype._getOutboundGroupSession = function(sessionId, func) {
}
};
/**
* Generate a new outbound group session
*
@@ -913,7 +903,6 @@ OlmDevice.prototype.createOutboundGroupSession = function() {
}
};
/**
* Encrypt an outgoing message with an outbound group session
*
@@ -953,7 +942,6 @@ OlmDevice.prototype.getOutboundGroupSessionKey = function(sessionId) {
});
};
// Inbound group session
// =====================

View File

@@ -75,7 +75,6 @@ function OutboundSessionInfo(sessionId, sharedHistory = false) {
this.sharedHistory = sharedHistory;
}
/**
* Check if it's time to rotate the session
*
@@ -158,7 +157,6 @@ OutboundSessionInfo.prototype.sharedWithTooManyDevices = function(
}
};
/**
* Megolm encryption implementation
*
@@ -1340,7 +1338,6 @@ MegolmDecryption.prototype._removeEventFromPendingList = function(event) {
}
};
/**
* @inheritdoc
*

View File

@@ -358,5 +358,4 @@ OlmDecryption.prototype._reallyDecryptMessage = async function(
return res.payload;
};
registerAlgorithm(olmlib.OLM_ALGORITHM, OlmEncryption, OlmDecryption);

View File

@@ -1604,7 +1604,6 @@ Crypto.prototype.registerEventHandlers = function(eventEmitter) {
eventEmitter.on("Event.decrypted", timelineHandler);
};
/** Start background processes related to crypto */
Crypto.prototype.start = function() {
this._outgoingRoomKeyRequestManager.start();
@@ -2198,7 +2197,6 @@ Crypto.prototype.legacyDeviceVerification = async function(
return request;
};
/**
* Get information on the active olm sessions with a user
* <p>
@@ -2229,7 +2227,6 @@ Crypto.prototype.getOlmSessionsForUser = async function(userId) {
return result;
};
/**
* Get the device which sent an event
*
@@ -2474,7 +2471,6 @@ Crypto.prototype.setRoomEncryption = async function(roomId, config, inhibitDevic
}
};
/**
* Make sure we are tracking the device lists for all users in this room.
*
@@ -2952,7 +2948,6 @@ Crypto.prototype._getTrackedE2eRooms = function() {
});
};
Crypto.prototype._onToDeviceEvent = function(event) {
try {
logger.log(`received to_device ${event.getType()} from: ` +
@@ -2973,7 +2968,10 @@ Crypto.prototype._onToDeviceEvent = function(event) {
this._onKeyVerificationMessage(event);
} else if (event.getContent().msgtype === "m.bad.encrypted") {
this._onToDeviceBadEncrypted(event);
} else if (event.isBeingDecrypted()) {
} else if (event.isBeingDecrypted() || event.shouldAttemptDecryption()) {
if (!event.isBeingDecrypted()) {
event.attemptDecryption(this);
}
// once the event has been decrypted, try again
event.once('Event.decrypted', (ev) => {
this._onToDeviceEvent(ev);
@@ -3240,7 +3238,6 @@ Crypto.prototype._onToDeviceBadEncrypted = async function(event) {
},
});
// Most of the time this probably won't be necessary since we'll have queued up a key request when
// we failed to decrypt the message and will be waiting a bit for the key to arrive before sending
// it. This won't always be the case though so we need to re-send any that have already been sent
@@ -3297,7 +3294,6 @@ Crypto.prototype._onRoomMembership = function(event, member, oldMembership) {
alg.onRoomMembership(event, member, oldMembership);
};
/**
* Called when we get an m.room_key_request event.
*
@@ -3450,7 +3446,6 @@ Crypto.prototype._processReceivedRoomKeyRequest = async function(req) {
this.emit("crypto.roomKeyRequest", req);
};
/**
* Helper for processReceivedRoomKeyRequests
*
@@ -3526,7 +3521,6 @@ Crypto.prototype._getRoomDecryptor = function(roomId, algorithm) {
return alg;
};
/**
* Get all the room decryptors for a given encryption algorithm.
*
@@ -3544,7 +3538,6 @@ Crypto.prototype._getRoomDecryptors = function(algorithm) {
return decryptors;
};
/**
* sign the given object with our ed25519 key
*
@@ -3564,7 +3557,6 @@ Crypto.prototype._signObject = async function(obj) {
if (unsigned !== undefined) obj.unsigned = unsigned;
};
/**
* The parameters of a room key request. The details of the request may
* vary with the crypto algorithm, but the management and storage layers for

View File

@@ -41,7 +41,6 @@ export const MEGOLM_ALGORITHM = "m.megolm.v1.aes-sha2";
*/
export const MEGOLM_BACKUP_ALGORITHM = "m.megolm_backup.v1.curve25519-aes-sha2";
/**
* Encrypt an event payload for an Olm device
*
@@ -408,7 +407,6 @@ async function _verifyKeyAndStartSession(olmDevice, oneTimeKey, userId, deviceIn
return sid;
}
/**
* Verify the signature on an object
*

View File

@@ -323,7 +323,6 @@ export class SAS extends Base {
key: this.ourSASPubKey,
});
e = await this._waitForEvent("m.key.verification.key");
// FIXME: make sure event is properly formed
content = e.getContent();
@@ -353,7 +352,6 @@ export class SAS extends Base {
this.emit("show_sas", this.sasEvent);
});
[e] = await Promise.all([
this._waitForEvent("m.key.verification.mac")
.then((e) => {
@@ -411,7 +409,6 @@ export class SAS extends Base {
commitment: olmutil.sha256(commitmentStr),
});
let e = await this._waitForEvent("m.key.verification.key");
// FIXME: make sure event is properly formed
content = e.getContent();
@@ -440,7 +437,6 @@ export class SAS extends Base {
this.emit("show_sas", this.sasEvent);
});
[e] = await Promise.all([
this._waitForEvent("m.key.verification.mac")
.then((e) => {

View File

@@ -292,7 +292,6 @@ export class ToDeviceChannel {
}
}
export class ToDeviceRequests {
constructor() {
this._requestsByUserId = new Map();

View File

@@ -37,7 +37,6 @@ const TIMEOUT_FROM_EVENT_RECEIPT = 2 * 60 * 1000; // 2 minutes
// are this amount of time away from expiring.
const VERIFICATION_REQUEST_MARGIN = 3 * 1000; // 3 seconds
export const EVENT_PREFIX = "m.key.verification.";
export const REQUEST_TYPE = EVENT_PREFIX + "request";
export const START_TYPE = EVENT_PREFIX + "start";
@@ -52,7 +51,6 @@ export const PHASE_STARTED = 4;
export const PHASE_CANCELLED = 5;
export const PHASE_DONE = 6;
/**
* State machine for verification requests.
* Things that differ based on what channel is used to
@@ -98,7 +96,6 @@ export class VerificationRequest extends EventEmitter {
static validateEvent(type, event, client) {
const content = event.getContent();
if (!type || !type.startsWith(EVENT_PREFIX)) {
return false;
}
@@ -355,7 +352,6 @@ export class VerificationRequest extends EventEmitter {
return this._observeOnly;
}
/**
* Gets which device the verification should be started with
* given the events sent so far in the verification. This is the

View File

@@ -22,7 +22,6 @@ InvalidStoreError.prototype = Object.create(Error.prototype, {
});
Reflect.setPrototypeOf(InvalidStoreError, Error);
export function InvalidCryptoStoreError(reason) {
const message = `Crypto store is invalid because ${reason}, ` +
`please stop the client, delete all data and start the client again`;

View File

@@ -803,7 +803,8 @@ const requestCallback = function(
}
if (!err) {
try {
if (response.statusCode >= 400) {
const httpStatus = response.status || response.statusCode; // XMLHttpRequest vs http.IncomingMessage
if (httpStatus >= 400) {
err = parseErrorResponse(response, body);
} else if (bodyParser) {
body = bodyParser(body);
@@ -818,7 +819,7 @@ const requestCallback = function(
userDefinedCallback(err);
} else {
const res = {
code: response.statusCode,
code: response.status || response.statusCode, // XMLHttpRequest vs http.IncomingMessage
// XXX: why do we bother with this? it doesn't work for
// XMLHttpRequest, so clearly we don't use it.
@@ -842,7 +843,7 @@ const requestCallback = function(
* @returns {Error}
*/
function parseErrorResponse(response, body) {
const httpStatus = response.statusCode;
const httpStatus = response.status || response.statusCode; // XMLHttpRequest vs http.IncomingMessage
const contentType = getResponseContentType(response);
let err;
@@ -862,7 +863,6 @@ function parseErrorResponse(response, body) {
return err;
}
/**
* extract the Content-Type header from the response object, and
* parse it to a `{type, parameters}` object.

View File

@@ -16,6 +16,7 @@ limitations under the License.
import * as matrixcs from "./matrix";
import * as utils from "./utils";
import { logger } from './logger';
import request from "request";
matrixcs.request(request);
@@ -25,7 +26,7 @@ try {
const crypto = require('crypto');
utils.setCrypto(crypto);
} catch (err) {
console.log('nodejs was compiled without crypto support');
logger.log('nodejs was compiled without crypto support');
}
export * from "./matrix";

View File

@@ -36,11 +36,11 @@ const DEFAULT_NAMESPACE = "matrix";
// when logging so we always get the current value of console methods.
log.methodFactory = function(methodName, logLevel, loggerName) {
return function(...args) {
/* eslint-disable @babel/no-invalid-this */
/* eslint-disable @typescript-eslint/no-invalid-this */
if (this.prefix) {
args.unshift(this.prefix);
}
/* eslint-enable @babel/no-invalid-this */
/* eslint-enable @typescript-eslint/no-invalid-this */
const supportedByConsole = methodName === "error" ||
methodName === "warn" ||
methodName === "trace" ||

View File

@@ -59,7 +59,6 @@ export {
setVideoInput as setMatrixCallVideoInput,
} from "./webrtc/call";
// expose the underlying request object so different environments can use
// different request libs (e.g. request or browser-request)
let requestInstance;

View File

@@ -271,7 +271,6 @@ EventTimelineSet.prototype.addTimeline = function() {
return timeline;
};
/**
* Add events to a timeline
*
@@ -740,17 +739,12 @@ EventTimelineSet.prototype.setRelationsTarget = function(event) {
if (!relationsForEvent) {
return;
}
// don't need it for non m.replace relations for now
const relationsWithRelType = relationsForEvent["m.replace"];
if (!relationsWithRelType) {
return;
}
// only doing replacements for messages for now (e.g. edits)
const relationsWithEventType = relationsWithRelType["m.room.message"];
if (relationsWithEventType) {
for (const relationsWithRelType of Object.values(relationsForEvent)) {
for (const relationsWithEventType of Object.values(relationsWithRelType)) {
relationsWithEventType.setTargetEvent(event);
}
}
};
/**
@@ -769,7 +763,7 @@ EventTimelineSet.prototype.aggregateRelations = function(event) {
}
// If the event is currently encrypted, wait until it has been decrypted.
if (event.isBeingDecrypted()) {
if (event.isBeingDecrypted() || event.shouldAttemptDecryption()) {
event.once("Event.decrypted", () => {
this.aggregateRelations(event);
});
@@ -797,7 +791,6 @@ EventTimelineSet.prototype.aggregateRelations = function(event) {
}
let relationsWithEventType = relationsWithRelType[eventType];
let isNewRelations = false;
let relatesToEvent;
if (!relationsWithEventType) {
relationsWithEventType = relationsWithRelType[eventType] = new Relations(
@@ -805,7 +798,6 @@ EventTimelineSet.prototype.aggregateRelations = function(event) {
eventType,
this.room,
);
isNewRelations = true;
relatesToEvent = this.findEventById(relatesToEventId) || this.room.getPendingEvent(relatesToEventId);
if (relatesToEvent) {
relationsWithEventType.setTargetEvent(relatesToEvent);
@@ -813,11 +805,6 @@ EventTimelineSet.prototype.aggregateRelations = function(event) {
}
relationsWithEventType.addEvent(event);
// only emit once event has been added to relations
if (isNewRelations && relatesToEvent) {
relatesToEvent.emit("Event.relationsCreated", relationType, eventType);
}
};
/**

View File

@@ -180,7 +180,6 @@ export const MatrixEvent = function(
};
utils.inherits(MatrixEvent, EventEmitter);
utils.extend(MatrixEvent.prototype, {
/**
* Get the event_id for this event.
@@ -1146,7 +1145,6 @@ utils.extend(MatrixEvent.prototype, {
},
});
/* _REDACT_KEEP_KEY_MAP gives the keys we keep when an event is redacted
*
* This is specified here:
@@ -1175,7 +1173,6 @@ const _REDACT_KEEP_CONTENT_MAP = {
'm.room.aliases': { 'aliases': 1 },
};
/**
* Fires when an event is decrypted
*

View File

@@ -41,11 +41,14 @@ export class Relations extends EventEmitter {
super();
this.relationType = relationType;
this.eventType = eventType;
this._relationEventIds = new Set();
this._relations = new Set();
this._annotationsByKey = {};
this._annotationsBySender = {};
this._sortedAnnotationsByKey = [];
this._targetEvent = null;
this._room = room;
this._creationEmitted = false;
}
/**
@@ -54,8 +57,8 @@ export class Relations extends EventEmitter {
* @param {MatrixEvent} event
* The new relation event to be added.
*/
addEvent(event) {
if (this._relations.has(event)) {
async addEvent(event) {
if (this._relationEventIds.has(event.getId())) {
return;
}
@@ -80,16 +83,20 @@ export class Relations extends EventEmitter {
}
this._relations.add(event);
this._relationEventIds.add(event.getId());
if (this.relationType === "m.annotation") {
this._addAnnotationToAggregation(event);
} else if (this.relationType === "m.replace" && this._targetEvent) {
this._targetEvent.makeReplaced(this.getLastReplacement());
const lastReplacement = await this.getLastReplacement();
this._targetEvent.makeReplaced(lastReplacement);
}
event.on("Event.beforeRedaction", this._onBeforeRedaction);
this.emit("Relations.add", event);
this._maybeEmitCreated();
}
/**
@@ -98,7 +105,7 @@ export class Relations extends EventEmitter {
* @param {MatrixEvent} event
* The relation event to remove.
*/
_removeEvent(event) {
async _removeEvent(event) {
if (!this._relations.has(event)) {
return;
}
@@ -122,7 +129,8 @@ export class Relations extends EventEmitter {
if (this.relationType === "m.annotation") {
this._removeAnnotationFromAggregation(event);
} else if (this.relationType === "m.replace" && this._targetEvent) {
this._targetEvent.makeReplaced(this.getLastReplacement());
const lastReplacement = await this.getLastReplacement();
this._targetEvent.makeReplaced(lastReplacement);
}
this.emit("Relations.remove", event);
@@ -227,7 +235,7 @@ export class Relations extends EventEmitter {
* @param {MatrixEvent} redactedEvent
* The original relation event that is about to be redacted.
*/
_onBeforeRedaction = (redactedEvent) => {
_onBeforeRedaction = async (redactedEvent) => {
if (!this._relations.has(redactedEvent)) {
return;
}
@@ -238,7 +246,8 @@ export class Relations extends EventEmitter {
// Remove the redacted annotation from aggregation by key
this._removeAnnotationFromAggregation(redactedEvent);
} else if (this.relationType === "m.replace" && this._targetEvent) {
this._targetEvent.makeReplaced(this.getLastReplacement());
const lastReplacement = await this.getLastReplacement();
this._targetEvent.makeReplaced(lastReplacement);
}
redactedEvent.removeListener("Event.beforeRedaction", this._onBeforeRedaction);
@@ -291,7 +300,7 @@ export class Relations extends EventEmitter {
*
* @return {MatrixEvent?}
*/
getLastReplacement() {
async getLastReplacement() {
if (this.relationType !== "m.replace") {
// Aggregating on last only makes sense for this relation type
return null;
@@ -309,7 +318,7 @@ export class Relations extends EventEmitter {
this._targetEvent.getServerAggregatedRelation("m.replace");
const minTs = replaceRelation && replaceRelation.origin_server_ts;
return this.getRelations().reduce((last, event) => {
const lastReplacement = this.getRelations().reduce((last, event) => {
if (event.getSender() !== this._targetEvent.getSender()) {
return last;
}
@@ -321,23 +330,51 @@ export class Relations extends EventEmitter {
}
return event;
}, null);
if (lastReplacement?.shouldAttemptDecryption()) {
await lastReplacement.attemptDecryption(this._room._client._crypto);
} else if (lastReplacement?.isBeingDecrypted()) {
await lastReplacement._decryptionPromise;
}
return lastReplacement;
}
/*
* @param {MatrixEvent} targetEvent the event the relations are related to.
*/
setTargetEvent(event) {
async setTargetEvent(event) {
if (this._targetEvent) {
return;
}
this._targetEvent = event;
if (this.relationType === "m.replace") {
const replacement = this.getLastReplacement();
const replacement = await this.getLastReplacement();
// this is the initial update, so only call it if we already have something
// to not emit Event.replaced needlessly
if (replacement) {
this._targetEvent.makeReplaced(replacement);
}
}
this._maybeEmitCreated();
}
_maybeEmitCreated() {
if (this._creationEmitted) {
return;
}
// Only emit we're "created" once we have a target event instance _and_
// at least one related event.
if (!this._targetEvent || !this._relations.size) {
return;
}
this._creationEmitted = true;
this._targetEvent.emit(
"Event.relationsCreated",
this.relationType,
this.eventType,
);
}
}

View File

@@ -203,7 +203,6 @@ RoomMember.prototype.getLastModifiedTime = function() {
return this._modified;
};
RoomMember.prototype.isKicked = function() {
return this.membership === "leave" &&
this.events.member.getSender() !== this.events.member.getStateKey();
@@ -240,7 +239,6 @@ RoomMember.prototype.getDMInviter = function() {
}
};
/**
* Get the avatar URL for a room member.
* @param {string} baseUrl The base homeserver URL See

View File

@@ -349,6 +349,11 @@ RoomState.prototype.setStateEvents = function(stateEvents) {
self._updateMember(member);
self.emit("RoomState.members", event, self, member);
} else if (event.getType() === "m.room.power_levels") {
// events with unknown state keys should be ignored
// and should not aggregate onto members power levels
if (event.getStateKey() !== "") {
return;
}
const members = Object.values(self.members);
members.forEach(function(member) {
// We only propagate `RoomState.members` event if the
@@ -735,7 +740,6 @@ RoomState.prototype.getJoinRule = function() {
return joinRuleContent["join_rule"] || "invite";
};
function _updateThirdPartyTokenCache(roomState, memberEvent) {
if (!memberEvent.getContent().third_party_invite) {
return;

View File

@@ -31,6 +31,7 @@ import {RoomSummary} from "./room-summary";
import { logger } from '../logger';
import { ReEmitter } from '../ReEmitter';
import { EventType, RoomCreateTypeField, RoomType } from "../@types/event";
import { normalize } from "../utils";
// These constants are used as sane defaults when the homeserver doesn't support
// the m.room_versions capability. In practice, KNOWN_SAFE_ROOM_VERSION should be
@@ -58,7 +59,6 @@ function synthesizeReceipt(userId, event, receiptType) {
return new MatrixEvent(fakeReceipt);
}
/**
* Construct a new Room.
*
@@ -102,6 +102,7 @@ function synthesizeReceipt(userId, event, receiptType) {
*
* @prop {string} roomId The ID of this room.
* @prop {string} name The human-readable display name for this room.
* @prop {string} normalizedName The unhomoglyphed name for this room.
* @prop {Array<MatrixEvent>} timeline The live event timeline for this room,
* with the oldest event at index 0. Present for backwards compatibility -
* prefer getLiveTimeline().getEvents().
@@ -216,6 +217,10 @@ export function Room(roomId, client, myUserId, opts) {
} else {
this._membersPromise = null;
}
// flags to stop logspam about missing m.room.create events
this.getTypeWarning = false;
this.getVersionWarning = false;
}
/**
@@ -228,7 +233,6 @@ function pendingEventsKey(roomId) {
utils.inherits(Room, EventEmitter);
/**
* Bulk decrypt critical events in a room
*
@@ -280,7 +284,10 @@ Room.prototype.decryptAllEvents = function() {
Room.prototype.getVersion = function() {
const createEvent = this.currentState.getStateEvents("m.room.create", "");
if (!createEvent) {
if (!this.getVersionWarning) {
logger.warn("[getVersion] Room " + this.roomId + " does not have an m.room.create event");
this.getVersionWarning = true;
}
return '1';
}
const ver = createEvent.getContent()['room_version'];
@@ -486,7 +493,6 @@ Room.prototype.getLiveTimeline = function() {
return this.getUnfilteredTimelineSet().getLiveTimeline();
};
/**
* Get the timestamp of the last message in the room
*
@@ -631,7 +637,6 @@ Room.prototype._loadMembersFromServer = async function() {
return response.chunk;
};
Room.prototype._loadMembers = async function() {
// were the members loaded from the server?
let fromServer = false;
@@ -1116,7 +1121,6 @@ Room.prototype.getInvitedAndJoinedMemberCount = function() {
return calculateRoomName(this, userId, true);
};
/**
* Check if the given user_id has the given membership state.
* @param {string} userId The user ID to check.
@@ -1273,7 +1277,6 @@ Room.prototype._addLiveEvent = function(event, duplicateStrategy, fromCache) {
}
};
/**
* Add a pending outgoing event to this room.
*
@@ -1684,7 +1687,6 @@ Room.prototype.removeEvent = function(eventId) {
return removedAny;
};
/**
* Recalculate various aspects of the room, including the room name and
* room summary. Call this any time the room's current state is modified.
@@ -1720,6 +1722,7 @@ Room.prototype.recalculate = function() {
const oldName = this.name;
this.name = calculateRoomName(this, this.myUserId);
this.normalizedName = normalize(this.name);
this.summary = new RoomSummary(this.roomId, {
title: this.name,
});
@@ -1908,7 +1911,6 @@ Room.prototype._buildReceiptCache = function(receipts) {
return receiptCacheByEventId;
};
/**
* Add a temporary local-echo receipt to the room to reflect in the
* client the fact that we've sent one.
@@ -1966,7 +1968,6 @@ Room.prototype.getAccountData = function(type) {
return this.accountData[type];
};
/**
* Returns whether the syncing user has permission to send a message in the room
* @return {boolean} true if the user should be permitted to send
@@ -2008,7 +2009,10 @@ Room.prototype.getJoinRule = function() {
Room.prototype.getType = function() {
const createEvent = this.currentState.getStateEvents("m.room.create", "");
if (!createEvent) {
if (!this.getTypeWarning) {
logger.warn("[getType] Room " + this.roomId + " does not have an m.room.create event");
this.getTypeWarning = true;
}
return undefined;
}
return createEvent.getContent()[RoomCreateTypeField];

View File

@@ -139,7 +139,6 @@ User.prototype.setDisplayName = function(name) {
}
};
/**
* Manually set this user's non-disambiguated display name. No event is emitted
* in response to this as there is no underlying MatrixEvent to emit with.
@@ -153,7 +152,6 @@ User.prototype.setRawDisplayName = function(name) {
}
};
/**
* Manually set this user's avatar URL. No event is emitted in response to this
* as there is no underlying MatrixEvent to emit with.

View File

@@ -360,7 +360,6 @@ export function PushProcessor(client) {
return ret;
};
/**
* Get the user's push actions for the given event
*
@@ -468,4 +467,3 @@ PushProcessor.rewriteDefaultRules = function(incomingRules) {
* noise.
*/

View File

@@ -177,7 +177,6 @@ function _runCallbacks() {
}
}
/* search in a sorted array.
*
* returns the index of the last element for which func returns

View File

@@ -93,7 +93,6 @@ MatrixScheduler.prototype.removeEventFromQueue = function(event) {
return removed;
};
/**
* Set the process function. Required for events in the queue to be processed.
* If set after events have been added to the queue, this will immediately start

View File

@@ -48,7 +48,6 @@ function upgradeSchemaV3(db) {
{ keyPath: ["clobber"] });
}
/**
* Helper method to collect results from a Cursor and promiseify it.
* @param {ObjectStore|Index} store The store to perform openCursor on.

View File

@@ -48,7 +48,6 @@ export function RemoteIndexedDBStoreBackend(
this._startPromise = null;
}
RemoteIndexedDBStoreBackend.prototype = {
/**
* Attempt to connect to the database. This can fail if the user does not

View File

@@ -39,7 +39,6 @@ import {logger} from '../logger';
// response is persisted each time.
const WRITE_DELAY_MS = 1000 * 60 * 5; // once every 5 minutes
/**
* Construct a new Indexed Database store, which extends MemoryStore.
*

View File

@@ -62,7 +62,6 @@ function debuglog(...params) {
logger.log(...params);
}
/**
* <b>Internal class - unstable.</b>
* Construct an entity which is able to sync with a homeserver.
@@ -188,7 +187,6 @@ SyncApi.prototype._deregisterStateListeners = function(room) {
room.currentState.removeAllListeners("RoomState.newMember");
};
/**
* Sync rooms the user has left.
* @return {Promise} Resolved when they've been added to the store.

View File

@@ -335,7 +335,6 @@ TimelineWindow.prototype.paginate = function(direction, size, makeRequest,
return prom;
};
/**
* Remove `delta` events from the start or end of the timeline.
*
@@ -368,7 +367,6 @@ TimelineWindow.prototype.unpaginate = function(delta, startOfTimeline) {
}
};
/**
* Get a list of the events currently in the window
*
@@ -420,7 +418,6 @@ TimelineWindow.prototype.getEvents = function() {
return result;
};
/**
* a thing which contains a timeline reference, and an index into it.
*

View File

@@ -346,6 +346,16 @@ export function removeHiddenChars(str: string): string {
return "";
}
export function normalize(str: string): string {
// Note: we have to match the filter with the removeHiddenChars() because the
// function strips spaces and other characters (M becomes RN for example, in lowercase).
return removeHiddenChars(str.toLowerCase())
// Strip all punctuation
.replace(/[\\'!"#$%&()*+,\-./:;<=>?@[\]^_`{|}~\u2000-\u206f\u2e00-\u2e7f]/g, "")
// We also doubly convert to lowercase to work around oddities of the library.
.toLowerCase();
}
// Regex matching bunch of unicode control characters and otherwise misleading/invisible characters.
// Includes:
// various width spaces U+2000 - U+200D

View File

@@ -37,7 +37,6 @@ import {
} from './callEventTypes';
import { CallFeed } from './callFeed';
// events: hangup, error(err), replaced(call), state(state, oldState)
/**
@@ -189,6 +188,11 @@ export enum CallErrorCode {
* Signalling for the call could not be sent (other than the initial invite)
*/
SignallingFailed = 'signalling_timeout',
/**
* The remote party is busy
*/
UserBusy = 'user_busy'
}
enum ConstraintsType {
@@ -643,7 +647,7 @@ export class MatrixCall extends EventEmitter {
// Continue to send no reason for user hangups temporarily, until
// clients understand the user_hangup reason (voip v1)
if (reason !== CallErrorCode.UserHangup) content['reason'] = reason;
this.sendVoipEvent(EventType.CallHangup, {});
this.sendVoipEvent(EventType.CallHangup, content);
}
/**
@@ -1102,21 +1106,8 @@ export class MatrixCall extends EventEmitter {
await this.peerConn.setRemoteDescription(description);
if (description.type === 'offer') {
// First we sent the direction of the tranciever to what we'd like it to be,
// irresepective of whether the other side has us on hold - so just whether we
// want the call to be on hold or not. This is necessary because in a few lines,
// we'll adjust the direction and unless we do this too, we'll never come off hold.
for (const tranceiver of this.peerConn.getTransceivers()) {
tranceiver.direction = this.isRemoteOnHold() ? 'inactive' : 'sendrecv';
}
const localDescription = await this.peerConn.createAnswer();
await this.peerConn.setLocalDescription(localDescription);
// Now we've got our answer, set the direction to the outcome of the negotiation.
// We need to do this otherwise Firefox will notice that the direction is not the
// currentDirection and try to negotiate itself off hold again.
for (const tranceiver of this.peerConn.getTransceivers()) {
tranceiver.direction = tranceiver.currentDirection;
}
this.sendVoipEvent(EventType.CallNegotiate, {
description: this.peerConn.localDescription,
@@ -1375,7 +1366,7 @@ export class MatrixCall extends EventEmitter {
);
if (shouldTerminate) {
this.terminate(CallParty.Remote, CallErrorCode.UserHangup, true);
this.terminate(CallParty.Remote, msg.reason || CallErrorCode.UserHangup, true);
} else {
logger.debug(`Call is in state: ${this.state}: ignoring reject`);
}
@@ -1804,7 +1795,10 @@ export function createNewMatrixCall(client: any, roomId: string, options?: CallO
window.RTCIceCandidate || navigator.mediaDevices,
);
if (!supported) {
// Adds a lot of noise to test runs, so disable logging there.
if (process.env.NODE_ENV !== "test") {
logger.error("WebRTC is not supported in this browser / environment");
}
return null;
}
} catch (e) {

View File

@@ -43,6 +43,9 @@ export class CallEventHandler {
// after loading and after we've been offline for a bit.
this.callEventBuffer = [];
this.candidateEventsByCall = new Map<string, Array<MatrixEvent>>();
}
public start() {
this.client.on("sync", this.evaluateEventBuffer);
this.client.on("event", this.onEvent);
}
@@ -52,10 +55,11 @@ export class CallEventHandler {
this.client.removeListener("event", this.onEvent);
}
private evaluateEventBuffer = () => {
private evaluateEventBuffer = async () => {
if (this.client.getSyncState() === "SYNCING") {
// don't process any events until they are all decrypted
if (this.callEventBuffer.some((e) => e.isBeingDecrypted())) return;
await Promise.all(this.callEventBuffer.map(event => {
this.client.decryptEventIfNeeded(event);
}));
const ignoreCallIds = new Set<String>();
// inspect the buffer and mark all calls which have been answered
@@ -86,12 +90,9 @@ export class CallEventHandler {
}
private onEvent = (event: MatrixEvent) => {
this.client.decryptEventIfNeeded(event);
// any call events or ones that might be once they're decrypted
if (
event.getType().indexOf("m.call.") === 0 ||
event.getType().indexOf("org.matrix.call.") === 0
|| event.isBeingDecrypted()
) {
if (this.eventIsACall(event) || event.isBeingDecrypted()) {
// queue up for processing once all events from this sync have been
// processed (see above).
this.callEventBuffer.push(event);
@@ -100,7 +101,7 @@ export class CallEventHandler {
if (event.isBeingDecrypted() || event.isDecryptionFailure()) {
// add an event listener for once the event is decrypted.
event.once("Event.decrypted", () => {
if (event.getType().indexOf("m.call.") === -1) return;
if (!this.eventIsACall(event)) return;
if (this.callEventBuffer.includes(event)) {
// we were waiting for that event to decrypt, so recheck the buffer
@@ -118,6 +119,15 @@ export class CallEventHandler {
}
}
private eventIsACall(event: MatrixEvent): boolean {
const type = event.getType();
/**
* Unstable prefixes:
* - org.matrix.call. : MSC3086 https://github.com/matrix-org/matrix-doc/pull/3086
*/
return type.startsWith("m.call.") || type.startsWith("org.matrix.call.");
}
private handleCallEvent(event: MatrixEvent) {
const content = event.getContent();
let call = content.call_id ? this.calls.get(content.call_id) : undefined;

View File

@@ -1130,6 +1130,10 @@
"@types/yargs" "^15.0.0"
chalk "^4.0.0"
"@matrix-org/olm@https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz":
version "3.2.3"
resolved "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.3.tgz#cc332fdd25c08ef0e40f4d33fc3f822a0f98b6f4"
"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents":
version "2.1.8-no-fsevents"
resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.tgz#da7c3996b8e6e19ebd14d82eaced2313e7769f9b"
@@ -2030,15 +2034,15 @@ browserify@^17.0.0:
xtend "^4.0.0"
browserslist@^4.14.5, browserslist@^4.16.1:
version "4.16.1"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.1.tgz#bf757a2da376b3447b800a16f0f1c96358138766"
integrity sha512-UXhDrwqsNcpTYJBTZsbGATDxZbiVDsx6UjpmRUmtnP10pr8wAYr5LgFoEFw9ixriQH2mv/NX2SfGzE/o8GndLA==
version "4.16.6"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.6.tgz#d7901277a5a88e554ed305b183ec9b0c08f66fa2"
integrity sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==
dependencies:
caniuse-lite "^1.0.30001173"
colorette "^1.2.1"
electron-to-chromium "^1.3.634"
caniuse-lite "^1.0.30001219"
colorette "^1.2.2"
electron-to-chromium "^1.3.723"
escalade "^3.1.1"
node-releases "^1.1.69"
node-releases "^1.1.71"
bs58@^4.0.1:
version "4.0.1"
@@ -2125,10 +2129,10 @@ camelcase@^6.0.0:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809"
integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==
caniuse-lite@^1.0.30001173:
version "1.0.30001178"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001178.tgz#3ad813b2b2c7d585b0be0a2440e1e233c6eabdbc"
integrity sha512-VtdZLC0vsXykKni8Uztx45xynytOi71Ufx9T8kHptSw9AL4dpqailUJJHavttuzUe1KYuBYtChiWv+BAb7mPmQ==
caniuse-lite@^1.0.30001219:
version "1.0.30001230"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001230.tgz#8135c57459854b2240b57a4a6786044bdc5a9f71"
integrity sha512-5yBd5nWCBS+jWKTcHOzXwo5xzcj4ePE/yjtkZyUV1BTUmrBaA9MRGC+e7mxnqXSA90CmCA8L3eKLaSUkt099IQ==
capture-exit@^2.0.0:
version "2.0.0"
@@ -2296,10 +2300,10 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
colorette@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b"
integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==
colorette@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
combine-source-map@^0.8.0, combine-source-map@~0.8.0:
version "0.8.0"
@@ -2711,10 +2715,10 @@ ecc-jsbn@~0.1.1:
jsbn "~0.1.0"
safer-buffer "^2.1.0"
electron-to-chromium@^1.3.634:
version "1.3.642"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.642.tgz#8b884f50296c2ae2a9997f024d0e3e57facc2b94"
integrity sha512-cev+jOrz/Zm1i+Yh334Hed6lQVOkkemk2wRozfMF4MtTR7pxf3r3L5Rbd7uX1zMcEqVJ7alJBnJL7+JffkC6FQ==
electron-to-chromium@^1.3.723:
version "1.3.738"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.738.tgz#aec24b091c82acbfabbdcce08076a703941d17ca"
integrity sha512-vCMf4gDOpEylPSLPLSwAEsz+R3ShP02Y3cAKMZvTqule3XcPp7tgc/0ESI7IS6ZeyBlGClE50N53fIOkcIVnpw==
elliptic@^6.5.3:
version "6.5.4"
@@ -2841,8 +2845,8 @@ eslint-config-google@^0.14.0:
integrity sha512-WsbX4WbjuMvTdeVL6+J3rK1RGhCTqjsFjX7UMSMgZiyxxaNLkoJENbrGExzERFeoTpGw3F3FypTiWAP9ZXzkEw==
"eslint-plugin-matrix-org@github:matrix-org/eslint-plugin-matrix-org#main":
version "0.2.0"
resolved "https://codeload.github.com/matrix-org/eslint-plugin-matrix-org/tar.gz/0ae103fe9af97655be6039fc1e7ad6ea95da310b"
version "0.3.1"
resolved "https://codeload.github.com/matrix-org/eslint-plugin-matrix-org/tar.gz/b55649a0f48ee27155c1968ed5050b6ddc5afdbe"
eslint-rule-composer@^0.3.0:
version "0.3.0"
@@ -5033,10 +5037,10 @@ node-notifier@^8.0.0:
uuid "^8.3.0"
which "^2.0.2"
node-releases@^1.1.69:
version "1.1.70"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.70.tgz#66e0ed0273aa65666d7fe78febe7634875426a08"
integrity sha512-Slf2s69+2/uAD79pVVQo8uSiC34+g8GWY8UH2Qtqv34ZfhYrxpYpfzs9Js9d6O0mbDmALuxaTlplnBTnSELcrw==
node-releases@^1.1.71:
version "1.1.72"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.72.tgz#14802ab6b1039a79a0c7d662b610a5bbd76eacbe"
integrity sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==
normalize-package-data@^2.5.0:
version "2.5.0"
@@ -5142,10 +5146,6 @@ object.pick@^1.3.0:
dependencies:
isobject "^3.0.1"
"olm@https://packages.matrix.org/npm/olm/olm-3.2.1.tgz":
version "3.2.1"
resolved "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz#d623d76f99c3518dde68be8c86618d68bc7b004a"
once@^1.3.0, once@^1.3.1, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@@ -7135,9 +7135,9 @@ write-file-atomic@^3.0.0:
typedarray-to-buffer "^3.1.5"
ws@^7.2.3:
version "7.4.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.2.tgz#782100048e54eb36fe9843363ab1c68672b261dd"
integrity sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==
version "7.4.6"
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
xml-name-validator@^3.0.0:
version "3.0.0"