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 remote-tracking branch 'origin/develop' into jryans/4s-new-key-backup
This commit is contained in:
@@ -7,7 +7,7 @@ steps:
|
|||||||
- docker#v3.0.1:
|
- docker#v3.0.1:
|
||||||
image: "node:10"
|
image: "node:10"
|
||||||
|
|
||||||
- label: ":karma: Tests"
|
- label: ":jest: Tests"
|
||||||
command:
|
command:
|
||||||
- "yarn install"
|
- "yarn install"
|
||||||
- "yarn test"
|
- "yarn test"
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ module.exports = {
|
|||||||
// babel's transform-runtime converts references to ES6 globals such as
|
// babel's transform-runtime converts references to ES6 globals such as
|
||||||
// Promise and Map to core-js polyfills, so we can use ES6 globals.
|
// Promise and Map to core-js polyfills, so we can use ES6 globals.
|
||||||
es6: true,
|
es6: true,
|
||||||
|
jest: true,
|
||||||
},
|
},
|
||||||
extends: ["eslint:recommended", "google"],
|
extends: ["eslint:recommended", "google"],
|
||||||
plugins: [
|
plugins: [
|
||||||
"babel",
|
"babel",
|
||||||
|
"jest",
|
||||||
],
|
],
|
||||||
rules: {
|
rules: {
|
||||||
// rules we've always adhered to or now do
|
// rules we've always adhered to or now do
|
||||||
|
|||||||
38
CHANGELOG.md
38
CHANGELOG.md
@@ -1,3 +1,41 @@
|
|||||||
|
Changes in [2.4.5](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.5) (2019-11-27)
|
||||||
|
================================================================================================
|
||||||
|
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.4...v2.4.5)
|
||||||
|
|
||||||
|
* Relax identity server discovery checks to FAIL_PROMPT
|
||||||
|
* Expand E2EE debug logging to diagnose "unable to decrypt" errors
|
||||||
|
|
||||||
|
Changes in [2.4.4](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.4) (2019-11-25)
|
||||||
|
================================================================================================
|
||||||
|
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.4-rc.1...v2.4.4)
|
||||||
|
|
||||||
|
* No changes since rc.1
|
||||||
|
|
||||||
|
Changes in [2.4.4-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.4-rc.1) (2019-11-20)
|
||||||
|
==========================================================================================================
|
||||||
|
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.3...v2.4.4-rc.1)
|
||||||
|
|
||||||
|
* Fix SAS verification in encrypted DMs
|
||||||
|
[\#1077](https://github.com/matrix-org/matrix-js-sdk/pull/1077)
|
||||||
|
* Cross-signing / secret storage tweaks
|
||||||
|
[\#1078](https://github.com/matrix-org/matrix-js-sdk/pull/1078)
|
||||||
|
* Fix local trust for key backups
|
||||||
|
[\#1075](https://github.com/matrix-org/matrix-js-sdk/pull/1075)
|
||||||
|
* Add method to get last active timestamp in room
|
||||||
|
[\#1072](https://github.com/matrix-org/matrix-js-sdk/pull/1072)
|
||||||
|
* Check the right Synapse endpoint for determining admin capabilities
|
||||||
|
[\#1071](https://github.com/matrix-org/matrix-js-sdk/pull/1071)
|
||||||
|
* Cross Signing Support
|
||||||
|
[\#832](https://github.com/matrix-org/matrix-js-sdk/pull/832)
|
||||||
|
* Don't double cancel verification request
|
||||||
|
[\#1064](https://github.com/matrix-org/matrix-js-sdk/pull/1064)
|
||||||
|
* Support for verification requests in the timeline
|
||||||
|
[\#1067](https://github.com/matrix-org/matrix-js-sdk/pull/1067)
|
||||||
|
* Use stable API prefix for 3PID APIs when supported
|
||||||
|
[\#1066](https://github.com/matrix-org/matrix-js-sdk/pull/1066)
|
||||||
|
* Remove Jenkins scripts
|
||||||
|
[\#1063](https://github.com/matrix-org/matrix-js-sdk/pull/1063)
|
||||||
|
|
||||||
Changes in [2.4.3](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.3) (2019-11-04)
|
Changes in [2.4.3](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.3) (2019-11-04)
|
||||||
================================================================================================
|
================================================================================================
|
||||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.3-rc.1...v2.4.3)
|
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.3-rc.1...v2.4.3)
|
||||||
|
|||||||
16
package.json
16
package.json
@@ -1,14 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "matrix-js-sdk",
|
"name": "matrix-js-sdk",
|
||||||
"version": "2.4.3",
|
"version": "2.4.5",
|
||||||
"description": "Matrix Client-Server SDK for Javascript",
|
"description": "Matrix Client-Server SDK for Javascript",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test:build": "babel -s -d specbuild spec",
|
"test:watch": "jest spec/ --coverage --testEnvironment node --watch",
|
||||||
"test:run": "istanbul cover --report text --report cobertura --config .istanbul.yml -i \"lib/**/*.js\" node_modules/mocha/bin/_mocha -- --recursive specbuild --colors",
|
"test": "jest spec/ --coverage --testEnvironment node",
|
||||||
"test:watch": "mocha --watch --compilers js:babel-core/register --recursive spec --colors",
|
|
||||||
"test": "yarn test:build && yarn test:run",
|
|
||||||
"check": "yarn test:build && _mocha --recursive specbuild --colors",
|
|
||||||
"gendoc": "babel --no-babelrc --plugins transform-class-properties -d .jsdocbuild src && jsdoc -r .jsdocbuild -P package.json -R README.md -d .jsdoc",
|
"gendoc": "babel --no-babelrc --plugins transform-class-properties -d .jsdocbuild src && jsdoc -r .jsdocbuild -P package.json -R README.md -d .jsdoc",
|
||||||
"start": "yarn start:init && yarn start:watch",
|
"start": "yarn start:init && yarn start:watch",
|
||||||
"start:watch": "babel -s -w --skip-initial-build -d lib src",
|
"start:watch": "babel -s -w --skip-initial-build -d lib src",
|
||||||
@@ -65,6 +62,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"babel-cli": "^6.18.0",
|
"babel-cli": "^6.18.0",
|
||||||
"babel-eslint": "^10.0.1",
|
"babel-eslint": "^10.0.1",
|
||||||
|
"babel-jest": "^23.6.0",
|
||||||
"babel-plugin-transform-async-to-bluebird": "^1.1.1",
|
"babel-plugin-transform-async-to-bluebird": "^1.1.1",
|
||||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"babel-plugin-transform-runtime": "^6.23.0",
|
||||||
@@ -75,13 +73,11 @@
|
|||||||
"eslint": "^5.12.0",
|
"eslint": "^5.12.0",
|
||||||
"eslint-config-google": "^0.7.1",
|
"eslint-config-google": "^0.7.1",
|
||||||
"eslint-plugin-babel": "^5.3.0",
|
"eslint-plugin-babel": "^5.3.0",
|
||||||
|
"eslint-plugin-jest": "^23.0.4",
|
||||||
"exorcist": "^1.0.1",
|
"exorcist": "^1.0.1",
|
||||||
"expect": "^1.20.2",
|
"jest": "^23.6.0",
|
||||||
"istanbul": "^0.4.5",
|
|
||||||
"jsdoc": "^3.5.5",
|
"jsdoc": "^3.5.5",
|
||||||
"lolex": "^1.5.2",
|
|
||||||
"matrix-mock-request": "^1.2.3",
|
"matrix-mock-request": "^1.2.3",
|
||||||
"mocha": "^6.2.1",
|
|
||||||
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
|
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
|
||||||
"rimraf": "^3.0.0",
|
"rimraf": "^3.0.0",
|
||||||
"source-map-support": "^0.5.13",
|
"source-map-support": "^0.5.13",
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
env: {
|
|
||||||
mocha: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
@@ -24,7 +24,6 @@ import './olm-loader';
|
|||||||
import sdk from '..';
|
import sdk from '..';
|
||||||
import testUtils from './test-utils';
|
import testUtils from './test-utils';
|
||||||
import MockHttpBackend from 'matrix-mock-request';
|
import MockHttpBackend from 'matrix-mock-request';
|
||||||
import expect from 'expect';
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
import LocalStorageCryptoStore from '../lib/crypto/store/localStorage-crypto-store';
|
import LocalStorageCryptoStore from '../lib/crypto/store/localStorage-crypto-store';
|
||||||
import logger from '../src/logger';
|
import logger from '../src/logger';
|
||||||
@@ -159,7 +158,7 @@ TestClient.prototype.awaitOneTimeKeyUpload = function() {
|
|||||||
.respond(200, (path, content) => {
|
.respond(200, (path, content) => {
|
||||||
expect(content.device_keys).toBe(undefined);
|
expect(content.device_keys).toBe(undefined);
|
||||||
expect(content.one_time_keys).toBeTruthy();
|
expect(content.one_time_keys).toBeTruthy();
|
||||||
expect(content.one_time_keys).toNotEqual({});
|
expect(content.one_time_keys).not.toEqual({});
|
||||||
logger.log('%s: received %i one-time keys', this,
|
logger.log('%s: received %i one-time keys', this,
|
||||||
Object.keys(content.one_time_keys).length);
|
Object.keys(content.one_time_keys).length);
|
||||||
this.oneTimeKeys = content.one_time_keys;
|
this.oneTimeKeys = content.one_time_keys;
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
import TestClient from '../TestClient';
|
import TestClient from '../TestClient';
|
||||||
@@ -88,8 +87,6 @@ describe("DeviceList management:", function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeEach(async function() {
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
|
|
||||||
// we create our own sessionStoreBackend so that we can use it for
|
// we create our own sessionStoreBackend so that we can use it for
|
||||||
// another TestClient.
|
// another TestClient.
|
||||||
sessionStoreBackend = new testUtils.MockStorageApi();
|
sessionStoreBackend = new testUtils.MockStorageApi();
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import 'source-map-support/register';
|
|||||||
// load olm before the sdk if possible
|
// load olm before the sdk if possible
|
||||||
import '../olm-loader';
|
import '../olm-loader';
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
const sdk = require("../..");
|
const sdk = require("../..");
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
const utils = require("../../lib/utils");
|
const utils = require("../../lib/utils");
|
||||||
@@ -56,7 +55,7 @@ function bobUploadsDeviceKeys() {
|
|||||||
bobTestClient.client.uploadKeys(),
|
bobTestClient.client.uploadKeys(),
|
||||||
bobTestClient.httpBackend.flush(),
|
bobTestClient.httpBackend.flush(),
|
||||||
]).then(() => {
|
]).then(() => {
|
||||||
expect(Object.keys(bobTestClient.deviceKeys).length).toNotEqual(0);
|
expect(Object.keys(bobTestClient.deviceKeys).length).not.toEqual(0);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,7 +203,7 @@ function aliSendsFirstMessage() {
|
|||||||
expectAliQueryKeys()
|
expectAliQueryKeys()
|
||||||
.then(expectAliClaimKeys)
|
.then(expectAliClaimKeys)
|
||||||
.then(expectAliSendMessageRequest),
|
.then(expectAliSendMessageRequest),
|
||||||
]).spread(function(_, ciphertext) {
|
]).then(function([_, ciphertext]) {
|
||||||
return ciphertext;
|
return ciphertext;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -219,7 +218,7 @@ function aliSendsMessage() {
|
|||||||
return Promise.all([
|
return Promise.all([
|
||||||
sendMessage(aliTestClient.client),
|
sendMessage(aliTestClient.client),
|
||||||
expectAliSendMessageRequest(),
|
expectAliSendMessageRequest(),
|
||||||
]).spread(function(_, ciphertext) {
|
]).then(function([_, ciphertext]) {
|
||||||
return ciphertext;
|
return ciphertext;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -235,7 +234,7 @@ function bobSendsReplyMessage() {
|
|||||||
sendMessage(bobTestClient.client),
|
sendMessage(bobTestClient.client),
|
||||||
expectBobQueryKeys()
|
expectBobQueryKeys()
|
||||||
.then(expectBobSendMessageRequest),
|
.then(expectBobSendMessageRequest),
|
||||||
]).spread(function(_, ciphertext) {
|
]).then(function([_, ciphertext]) {
|
||||||
return ciphertext;
|
return ciphertext;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -280,16 +279,17 @@ function sendMessage(client) {
|
|||||||
|
|
||||||
function expectSendMessageRequest(httpBackend) {
|
function expectSendMessageRequest(httpBackend) {
|
||||||
const path = "/send/m.room.encrypted/";
|
const path = "/send/m.room.encrypted/";
|
||||||
const deferred = Promise.defer();
|
const prom = new Promise((resolve) => {
|
||||||
httpBackend.when("PUT", path).respond(200, function(path, content) {
|
httpBackend.when("PUT", path).respond(200, function(path, content) {
|
||||||
deferred.resolve(content);
|
resolve(content);
|
||||||
return {
|
return {
|
||||||
event_id: "asdfgh",
|
event_id: "asdfgh",
|
||||||
};
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// it can take a while to process the key query
|
// it can take a while to process the key query
|
||||||
return httpBackend.flush(path, 1).then(() => deferred.promise);
|
return httpBackend.flush(path, 1).then(() => prom);
|
||||||
}
|
}
|
||||||
|
|
||||||
function aliRecvMessage() {
|
function aliRecvMessage() {
|
||||||
@@ -406,8 +406,6 @@ describe("MatrixClient crypto", function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeEach(async function() {
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
|
|
||||||
aliTestClient = new TestClient(aliUserId, aliDeviceId, aliAccessToken);
|
aliTestClient = new TestClient(aliUserId, aliDeviceId, aliAccessToken);
|
||||||
await aliTestClient.client.initCrypto();
|
await aliTestClient.client.initCrypto();
|
||||||
|
|
||||||
@@ -430,15 +428,14 @@ describe("MatrixClient crypto", function() {
|
|||||||
.then(bobUploadsDeviceKeys);
|
.then(bobUploadsDeviceKeys);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Ali downloads Bobs device keys", function(done) {
|
it("Ali downloads Bobs device keys", function() {
|
||||||
Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(bobUploadsDeviceKeys)
|
.then(bobUploadsDeviceKeys)
|
||||||
.then(aliDownloadsKeys)
|
.then(aliDownloadsKeys);
|
||||||
.nodeify(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Ali gets keys with an invalid signature", function(done) {
|
it("Ali gets keys with an invalid signature", function() {
|
||||||
Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(bobUploadsDeviceKeys)
|
.then(bobUploadsDeviceKeys)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
// tamper bob's keys
|
// tamper bob's keys
|
||||||
@@ -455,11 +452,10 @@ describe("MatrixClient crypto", function() {
|
|||||||
}).then((devices) => {
|
}).then((devices) => {
|
||||||
// should get an empty list
|
// should get an empty list
|
||||||
expect(devices).toEqual([]);
|
expect(devices).toEqual([]);
|
||||||
})
|
});
|
||||||
.nodeify(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Ali gets keys with an incorrect userId", function(done) {
|
it("Ali gets keys with an incorrect userId", function() {
|
||||||
const eveUserId = "@eve:localhost";
|
const eveUserId = "@eve:localhost";
|
||||||
|
|
||||||
const bobDeviceKeys = {
|
const bobDeviceKeys = {
|
||||||
@@ -488,7 +484,7 @@ describe("MatrixClient crypto", function() {
|
|||||||
return {device_keys: result};
|
return {device_keys: result};
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all([
|
return Promise.all([
|
||||||
aliTestClient.client.downloadKeys([bobUserId, eveUserId]),
|
aliTestClient.client.downloadKeys([bobUserId, eveUserId]),
|
||||||
aliTestClient.httpBackend.flush("/keys/query", 1),
|
aliTestClient.httpBackend.flush("/keys/query", 1),
|
||||||
]).then(function() {
|
]).then(function() {
|
||||||
@@ -496,14 +492,14 @@ describe("MatrixClient crypto", function() {
|
|||||||
aliTestClient.client.getStoredDevicesForUser(bobUserId),
|
aliTestClient.client.getStoredDevicesForUser(bobUserId),
|
||||||
aliTestClient.client.getStoredDevicesForUser(eveUserId),
|
aliTestClient.client.getStoredDevicesForUser(eveUserId),
|
||||||
]);
|
]);
|
||||||
}).spread((bobDevices, eveDevices) => {
|
}).then(([bobDevices, eveDevices]) => {
|
||||||
// should get an empty list
|
// should get an empty list
|
||||||
expect(bobDevices).toEqual([]);
|
expect(bobDevices).toEqual([]);
|
||||||
expect(eveDevices).toEqual([]);
|
expect(eveDevices).toEqual([]);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Ali gets keys with an incorrect deviceId", function(done) {
|
it("Ali gets keys with an incorrect deviceId", function() {
|
||||||
const bobDeviceKeys = {
|
const bobDeviceKeys = {
|
||||||
algorithms: ['m.olm.v1.curve25519-aes-sha2', 'm.megolm.v1.aes-sha2'],
|
algorithms: ['m.olm.v1.curve25519-aes-sha2', 'm.megolm.v1.aes-sha2'],
|
||||||
device_id: 'bad_device',
|
device_id: 'bad_device',
|
||||||
@@ -530,7 +526,7 @@ describe("MatrixClient crypto", function() {
|
|||||||
return {device_keys: result};
|
return {device_keys: result};
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all([
|
return Promise.all([
|
||||||
aliTestClient.client.downloadKeys([bobUserId]),
|
aliTestClient.client.downloadKeys([bobUserId]),
|
||||||
aliTestClient.httpBackend.flush("/keys/query", 1),
|
aliTestClient.httpBackend.flush("/keys/query", 1),
|
||||||
]).then(function() {
|
]).then(function() {
|
||||||
@@ -538,7 +534,7 @@ describe("MatrixClient crypto", function() {
|
|||||||
}).then((devices) => {
|
}).then((devices) => {
|
||||||
// should get an empty list
|
// should get an empty list
|
||||||
expect(devices).toEqual([]);
|
expect(devices).toEqual([]);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -548,19 +544,18 @@ describe("MatrixClient crypto", function() {
|
|||||||
.then(() => bobTestClient.awaitOneTimeKeyUpload())
|
.then(() => bobTestClient.awaitOneTimeKeyUpload())
|
||||||
.then((keys) => {
|
.then((keys) => {
|
||||||
expect(Object.keys(keys).length).toEqual(5);
|
expect(Object.keys(keys).length).toEqual(5);
|
||||||
expect(Object.keys(bobTestClient.deviceKeys).length).toNotEqual(0);
|
expect(Object.keys(bobTestClient.deviceKeys).length).not.toEqual(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Ali sends a message", function(done) {
|
it("Ali sends a message", function() {
|
||||||
aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
|
aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
|
||||||
Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => aliTestClient.start())
|
.then(() => aliTestClient.start())
|
||||||
.then(() => bobTestClient.start())
|
.then(() => bobTestClient.start())
|
||||||
.then(() => firstSync(aliTestClient))
|
.then(() => firstSync(aliTestClient))
|
||||||
.then(aliEnablesEncryption)
|
.then(aliEnablesEncryption)
|
||||||
.then(aliSendsFirstMessage)
|
.then(aliSendsFirstMessage);
|
||||||
.nodeify(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Bob receives a message", function() {
|
it("Bob receives a message", function() {
|
||||||
@@ -628,9 +623,9 @@ describe("MatrixClient crypto", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Ali blocks Bob's device", function(done) {
|
it("Ali blocks Bob's device", function() {
|
||||||
aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
|
aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
|
||||||
Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => aliTestClient.start())
|
.then(() => aliTestClient.start())
|
||||||
.then(() => bobTestClient.start())
|
.then(() => bobTestClient.start())
|
||||||
.then(() => firstSync(aliTestClient))
|
.then(() => firstSync(aliTestClient))
|
||||||
@@ -645,12 +640,12 @@ describe("MatrixClient crypto", function() {
|
|||||||
expect(sentContent.ciphertext).toEqual({});
|
expect(sentContent.ciphertext).toEqual({});
|
||||||
});
|
});
|
||||||
return Promise.all([p1, p2]);
|
return Promise.all([p1, p2]);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Bob receives two pre-key messages", function(done) {
|
it("Bob receives two pre-key messages", function() {
|
||||||
aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
|
aliTestClient.expectKeyQuery({device_keys: {[aliUserId]: {}}});
|
||||||
Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => aliTestClient.start())
|
.then(() => aliTestClient.start())
|
||||||
.then(() => bobTestClient.start())
|
.then(() => bobTestClient.start())
|
||||||
.then(() => firstSync(aliTestClient))
|
.then(() => firstSync(aliTestClient))
|
||||||
@@ -658,8 +653,7 @@ describe("MatrixClient crypto", function() {
|
|||||||
.then(aliSendsFirstMessage)
|
.then(aliSendsFirstMessage)
|
||||||
.then(bobRecvMessage)
|
.then(bobRecvMessage)
|
||||||
.then(aliSendsMessage)
|
.then(aliSendsMessage)
|
||||||
.then(bobRecvMessage)
|
.then(bobRecvMessage);
|
||||||
.nodeify(done);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Bob replies to the message", function() {
|
it("Bob replies to the message", function() {
|
||||||
@@ -753,9 +747,9 @@ describe("MatrixClient crypto", function() {
|
|||||||
.then(() => httpBackend.when("POST", "/keys/upload")
|
.then(() => httpBackend.when("POST", "/keys/upload")
|
||||||
.respond(200, (path, content) => {
|
.respond(200, (path, content) => {
|
||||||
expect(content.one_time_keys).toBeTruthy();
|
expect(content.one_time_keys).toBeTruthy();
|
||||||
expect(content.one_time_keys).toNotEqual({});
|
expect(content.one_time_keys).not.toEqual({});
|
||||||
expect(Object.keys(content.one_time_keys).length)
|
expect(Object.keys(content.one_time_keys).length)
|
||||||
.toBeGreaterThanOrEqualTo(1);
|
.toBeGreaterThanOrEqual(1);
|
||||||
logger.log('received %i one-time keys',
|
logger.log('received %i one-time keys',
|
||||||
Object.keys(content.one_time_keys).length);
|
Object.keys(content.one_time_keys).length);
|
||||||
// cancel futher calls by telling the client
|
// cancel futher calls by telling the client
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ const sdk = require("../..");
|
|||||||
const HttpBackend = require("matrix-mock-request");
|
const HttpBackend = require("matrix-mock-request");
|
||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
describe("MatrixClient events", function() {
|
describe("MatrixClient events", function() {
|
||||||
@@ -15,7 +14,6 @@ describe("MatrixClient events", function() {
|
|||||||
const selfAccessToken = "aseukfgwef";
|
const selfAccessToken = "aseukfgwef";
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
httpBackend = new HttpBackend();
|
httpBackend = new HttpBackend();
|
||||||
sdk.request(httpBackend.requestFn);
|
sdk.request(httpBackend.requestFn);
|
||||||
client = sdk.createClient({
|
client = sdk.createClient({
|
||||||
@@ -219,7 +217,7 @@ describe("MatrixClient events", function() {
|
|||||||
client.on("RoomState.events", function(event, state) {
|
client.on("RoomState.events", function(event, state) {
|
||||||
eventsInvokeCount++;
|
eventsInvokeCount++;
|
||||||
const index = roomStateEventTypes.indexOf(event.getType());
|
const index = roomStateEventTypes.indexOf(event.getType());
|
||||||
expect(index).toNotEqual(
|
expect(index).not.toEqual(
|
||||||
-1, "Unexpected room state event type: " + event.getType(),
|
-1, "Unexpected room state event type: " + event.getType(),
|
||||||
);
|
);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
|
|||||||
@@ -83,18 +83,19 @@ function startClient(httpBackend, client) {
|
|||||||
client.startClient();
|
client.startClient();
|
||||||
|
|
||||||
// set up a promise which will resolve once the client is initialised
|
// set up a promise which will resolve once the client is initialised
|
||||||
const deferred = Promise.defer();
|
const prom = new Promise((resolve) => {
|
||||||
client.on("sync", function(state) {
|
client.on("sync", function(state) {
|
||||||
logger.log("sync", state);
|
logger.log("sync", state);
|
||||||
if (state != "SYNCING") {
|
if (state != "SYNCING") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
deferred.resolve();
|
resolve();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
httpBackend.flushAllExpected(),
|
httpBackend.flushAllExpected(),
|
||||||
deferred.promise,
|
prom,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +104,6 @@ describe("getEventTimeline support", function() {
|
|||||||
let client;
|
let client;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
httpBackend = new HttpBackend();
|
httpBackend = new HttpBackend();
|
||||||
sdk.request(httpBackend.requestFn);
|
sdk.request(httpBackend.requestFn);
|
||||||
});
|
});
|
||||||
@@ -115,21 +115,20 @@ describe("getEventTimeline support", function() {
|
|||||||
return httpBackend.stop();
|
return httpBackend.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("timeline support must be enabled to work", function(done) {
|
it("timeline support must be enabled to work", function() {
|
||||||
client = sdk.createClient({
|
client = sdk.createClient({
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
userId: userId,
|
userId: userId,
|
||||||
accessToken: accessToken,
|
accessToken: accessToken,
|
||||||
});
|
});
|
||||||
|
|
||||||
startClient(httpBackend, client,
|
return startClient(httpBackend, client).then(function() {
|
||||||
).then(function() {
|
|
||||||
const room = client.getRoom(roomId);
|
const room = client.getRoom(roomId);
|
||||||
const timelineSet = room.getTimelineSets()[0];
|
const timelineSet = room.getTimelineSets()[0];
|
||||||
expect(function() {
|
expect(function() {
|
||||||
client.getEventTimeline(timelineSet, "event");
|
client.getEventTimeline(timelineSet, "event");
|
||||||
}).toThrow();
|
}).toThrow();
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("timeline support works when enabled", function() {
|
it("timeline support works when enabled", function() {
|
||||||
@@ -145,13 +144,13 @@ describe("getEventTimeline support", function() {
|
|||||||
const timelineSet = room.getTimelineSets()[0];
|
const timelineSet = room.getTimelineSets()[0];
|
||||||
expect(function() {
|
expect(function() {
|
||||||
client.getEventTimeline(timelineSet, "event");
|
client.getEventTimeline(timelineSet, "event");
|
||||||
}).toNotThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("scrollback should be able to scroll back to before a gappy /sync",
|
it("scrollback should be able to scroll back to before a gappy /sync",
|
||||||
function(done) {
|
function() {
|
||||||
// need a client with timelineSupport disabled to make this work
|
// need a client with timelineSupport disabled to make this work
|
||||||
client = sdk.createClient({
|
client = sdk.createClient({
|
||||||
baseUrl: baseUrl,
|
baseUrl: baseUrl,
|
||||||
@@ -160,8 +159,7 @@ describe("getEventTimeline support", function() {
|
|||||||
});
|
});
|
||||||
let room;
|
let room;
|
||||||
|
|
||||||
startClient(httpBackend, client,
|
return startClient(httpBackend, client).then(function() {
|
||||||
).then(function() {
|
|
||||||
room = client.getRoom(roomId);
|
room = client.getRoom(roomId);
|
||||||
|
|
||||||
httpBackend.when("GET", "/sync").respond(200, {
|
httpBackend.when("GET", "/sync").respond(200, {
|
||||||
@@ -217,18 +215,15 @@ describe("getEventTimeline support", function() {
|
|||||||
expect(room.timeline[0].event).toEqual(EVENTS[0]);
|
expect(room.timeline[0].event).toEqual(EVENTS[0]);
|
||||||
expect(room.timeline[1].event).toEqual(EVENTS[1]);
|
expect(room.timeline[1].event).toEqual(EVENTS[1]);
|
||||||
expect(room.oldState.paginationToken).toEqual("pagin_end");
|
expect(room.oldState.paginationToken).toEqual("pagin_end");
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("MatrixClient event timelines", function() {
|
describe("MatrixClient event timelines", function() {
|
||||||
let client = null;
|
let client = null;
|
||||||
let httpBackend = null;
|
let httpBackend = null;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
httpBackend = new HttpBackend();
|
httpBackend = new HttpBackend();
|
||||||
sdk.request(httpBackend.requestFn);
|
sdk.request(httpBackend.requestFn);
|
||||||
|
|
||||||
@@ -349,25 +344,25 @@ describe("MatrixClient event timelines", function() {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
const deferred = Promise.defer();
|
const prom = new Promise((resolve, reject) => {
|
||||||
client.on("sync", function() {
|
client.on("sync", function() {
|
||||||
client.getEventTimeline(timelineSet, EVENTS[2].event_id,
|
client.getEventTimeline(timelineSet, EVENTS[2].event_id,
|
||||||
).then(function(tl) {
|
).then(function(tl) {
|
||||||
expect(tl.getEvents().length).toEqual(4);
|
expect(tl.getEvents().length).toEqual(4);
|
||||||
expect(tl.getEvents()[0].event).toEqual(EVENTS[1]);
|
expect(tl.getEvents()[0].event).toEqual(EVENTS[1]);
|
||||||
expect(tl.getEvents()[1].event).toEqual(EVENTS[2]);
|
expect(tl.getEvents()[1].event).toEqual(EVENTS[2]);
|
||||||
expect(tl.getEvents()[3].event).toEqual(EVENTS[3]);
|
expect(tl.getEvents()[3].event).toEqual(EVENTS[3]);
|
||||||
expect(tl.getPaginationToken(EventTimeline.BACKWARDS))
|
expect(tl.getPaginationToken(EventTimeline.BACKWARDS))
|
||||||
.toEqual("start_token");
|
.toEqual("start_token");
|
||||||
// expect(tl.getPaginationToken(EventTimeline.FORWARDS))
|
// expect(tl.getPaginationToken(EventTimeline.FORWARDS))
|
||||||
// .toEqual("s_5_4");
|
// .toEqual("s_5_4");
|
||||||
}).done(() => deferred.resolve(),
|
}).done(resolve, reject);
|
||||||
(e) => deferred.reject(e));
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
httpBackend.flushAllExpected(),
|
httpBackend.flushAllExpected(),
|
||||||
deferred.promise,
|
prom,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -697,7 +692,7 @@ describe("MatrixClient event timelines", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("should handle gappy syncs after redactions", function(done) {
|
it("should handle gappy syncs after redactions", function() {
|
||||||
// https://github.com/vector-im/vector-web/issues/1389
|
// https://github.com/vector-im/vector-web/issues/1389
|
||||||
|
|
||||||
// a state event, followed by a redaction thereof
|
// a state event, followed by a redaction thereof
|
||||||
@@ -729,7 +724,7 @@ describe("MatrixClient event timelines", function() {
|
|||||||
};
|
};
|
||||||
httpBackend.when("GET", "/sync").respond(200, syncData);
|
httpBackend.when("GET", "/sync").respond(200, syncData);
|
||||||
|
|
||||||
Promise.all([
|
return Promise.all([
|
||||||
httpBackend.flushAllExpected(),
|
httpBackend.flushAllExpected(),
|
||||||
utils.syncPromise(client),
|
utils.syncPromise(client),
|
||||||
]).then(function() {
|
]).then(function() {
|
||||||
@@ -765,6 +760,6 @@ describe("MatrixClient event timelines", function() {
|
|||||||
const room = client.getRoom(roomId);
|
const room = client.getRoom(roomId);
|
||||||
const tl = room.getLiveTimeline();
|
const tl = room.getLiveTimeline();
|
||||||
expect(tl.getEvents().length).toEqual(1);
|
expect(tl.getEvents().length).toEqual(1);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ const Filter = publicGlobals.Filter;
|
|||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
const MockStorageApi = require("../MockStorageApi");
|
const MockStorageApi = require("../MockStorageApi");
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("MatrixClient", function() {
|
describe("MatrixClient", function() {
|
||||||
const baseUrl = "http://localhost.or.something";
|
const baseUrl = "http://localhost.or.something";
|
||||||
let client = null;
|
let client = null;
|
||||||
@@ -21,7 +19,6 @@ describe("MatrixClient", function() {
|
|||||||
const accessToken = "aseukfgwef";
|
const accessToken = "aseukfgwef";
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
httpBackend = new HttpBackend();
|
httpBackend = new HttpBackend();
|
||||||
store = new MemoryStore();
|
store = new MemoryStore();
|
||||||
|
|
||||||
@@ -46,7 +43,7 @@ describe("MatrixClient", function() {
|
|||||||
|
|
||||||
describe("uploadContent", function() {
|
describe("uploadContent", function() {
|
||||||
const buf = new Buffer('hello world');
|
const buf = new Buffer('hello world');
|
||||||
it("should upload the file", function(done) {
|
it("should upload the file", function() {
|
||||||
httpBackend.when(
|
httpBackend.when(
|
||||||
"POST", "/_matrix/media/r0/upload",
|
"POST", "/_matrix/media/r0/upload",
|
||||||
).check(function(req) {
|
).check(function(req) {
|
||||||
@@ -74,25 +71,26 @@ describe("MatrixClient", function() {
|
|||||||
expect(uploads[0].promise).toBe(prom);
|
expect(uploads[0].promise).toBe(prom);
|
||||||
expect(uploads[0].loaded).toEqual(0);
|
expect(uploads[0].loaded).toEqual(0);
|
||||||
|
|
||||||
prom.then(function(response) {
|
const prom2 = prom.then(function(response) {
|
||||||
// for backwards compatibility, we return the raw JSON
|
// for backwards compatibility, we return the raw JSON
|
||||||
expect(response).toEqual("content");
|
expect(response).toEqual("content");
|
||||||
|
|
||||||
const uploads = client.getCurrentUploads();
|
const uploads = client.getCurrentUploads();
|
||||||
expect(uploads.length).toEqual(0);
|
expect(uploads.length).toEqual(0);
|
||||||
}).nodeify(done);
|
});
|
||||||
|
|
||||||
httpBackend.flush();
|
httpBackend.flush();
|
||||||
|
return prom2;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should parse the response if rawResponse=false", function(done) {
|
it("should parse the response if rawResponse=false", function() {
|
||||||
httpBackend.when(
|
httpBackend.when(
|
||||||
"POST", "/_matrix/media/r0/upload",
|
"POST", "/_matrix/media/r0/upload",
|
||||||
).check(function(req) {
|
).check(function(req) {
|
||||||
expect(req.opts.json).toBeFalsy();
|
expect(req.opts.json).toBeFalsy();
|
||||||
}).respond(200, { "content_uri": "uri" });
|
}).respond(200, { "content_uri": "uri" });
|
||||||
|
|
||||||
client.uploadContent({
|
const prom = client.uploadContent({
|
||||||
stream: buf,
|
stream: buf,
|
||||||
name: "hi.txt",
|
name: "hi.txt",
|
||||||
type: "text/plain",
|
type: "text/plain",
|
||||||
@@ -100,12 +98,13 @@ describe("MatrixClient", function() {
|
|||||||
rawResponse: false,
|
rawResponse: false,
|
||||||
}).then(function(response) {
|
}).then(function(response) {
|
||||||
expect(response.content_uri).toEqual("uri");
|
expect(response.content_uri).toEqual("uri");
|
||||||
}).nodeify(done);
|
});
|
||||||
|
|
||||||
httpBackend.flush();
|
httpBackend.flush();
|
||||||
|
return prom;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should parse errors into a MatrixError", function(done) {
|
it("should parse errors into a MatrixError", function() {
|
||||||
httpBackend.when(
|
httpBackend.when(
|
||||||
"POST", "/_matrix/media/r0/upload",
|
"POST", "/_matrix/media/r0/upload",
|
||||||
).check(function(req) {
|
).check(function(req) {
|
||||||
@@ -116,7 +115,7 @@ describe("MatrixClient", function() {
|
|||||||
"error": "broken",
|
"error": "broken",
|
||||||
});
|
});
|
||||||
|
|
||||||
client.uploadContent({
|
const prom = client.uploadContent({
|
||||||
stream: buf,
|
stream: buf,
|
||||||
name: "hi.txt",
|
name: "hi.txt",
|
||||||
type: "text/plain",
|
type: "text/plain",
|
||||||
@@ -126,12 +125,13 @@ describe("MatrixClient", function() {
|
|||||||
expect(error.httpStatus).toEqual(400);
|
expect(error.httpStatus).toEqual(400);
|
||||||
expect(error.errcode).toEqual("M_SNAFU");
|
expect(error.errcode).toEqual("M_SNAFU");
|
||||||
expect(error.message).toEqual("broken");
|
expect(error.message).toEqual("broken");
|
||||||
}).nodeify(done);
|
});
|
||||||
|
|
||||||
httpBackend.flush();
|
httpBackend.flush();
|
||||||
|
return prom;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return a promise which can be cancelled", function(done) {
|
it("should return a promise which can be cancelled", function() {
|
||||||
const prom = client.uploadContent({
|
const prom = client.uploadContent({
|
||||||
stream: buf,
|
stream: buf,
|
||||||
name: "hi.txt",
|
name: "hi.txt",
|
||||||
@@ -143,17 +143,18 @@ describe("MatrixClient", function() {
|
|||||||
expect(uploads[0].promise).toBe(prom);
|
expect(uploads[0].promise).toBe(prom);
|
||||||
expect(uploads[0].loaded).toEqual(0);
|
expect(uploads[0].loaded).toEqual(0);
|
||||||
|
|
||||||
prom.then(function(response) {
|
const prom2 = prom.then(function(response) {
|
||||||
throw Error("request not aborted");
|
throw Error("request not aborted");
|
||||||
}, function(error) {
|
}, function(error) {
|
||||||
expect(error).toEqual("aborted");
|
expect(error).toEqual("aborted");
|
||||||
|
|
||||||
const uploads = client.getCurrentUploads();
|
const uploads = client.getCurrentUploads();
|
||||||
expect(uploads.length).toEqual(0);
|
expect(uploads.length).toEqual(0);
|
||||||
}).nodeify(done);
|
});
|
||||||
|
|
||||||
const r = client.cancelUpload(prom);
|
const r = client.cancelUpload(prom);
|
||||||
expect(r).toBe(true);
|
expect(r).toBe(true);
|
||||||
|
return prom2;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -310,7 +311,7 @@ describe("MatrixClient", function() {
|
|||||||
return client.initCrypto();
|
return client.initCrypto();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should do an HTTP request and then store the keys", function(done) {
|
it("should do an HTTP request and then store the keys", function() {
|
||||||
const ed25519key = "7wG2lzAqbjcyEkOP7O4gU7ItYcn+chKzh5sT/5r2l78";
|
const ed25519key = "7wG2lzAqbjcyEkOP7O4gU7ItYcn+chKzh5sT/5r2l78";
|
||||||
// ed25519key = client.getDeviceEd25519Key();
|
// ed25519key = client.getDeviceEd25519Key();
|
||||||
const borisKeys = {
|
const borisKeys = {
|
||||||
@@ -372,7 +373,7 @@ describe("MatrixClient", function() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
client.downloadKeys(["boris", "chaz"]).then(function(res) {
|
const prom = client.downloadKeys(["boris", "chaz"]).then(function(res) {
|
||||||
assertObjectContains(res.boris.dev1, {
|
assertObjectContains(res.boris.dev1, {
|
||||||
verified: 0, // DeviceVerification.UNVERIFIED
|
verified: 0, // DeviceVerification.UNVERIFIED
|
||||||
keys: { "ed25519:dev1": ed25519key },
|
keys: { "ed25519:dev1": ed25519key },
|
||||||
@@ -386,26 +387,26 @@ describe("MatrixClient", function() {
|
|||||||
algorithms: ["2"],
|
algorithms: ["2"],
|
||||||
unsigned: { "ghi": "def" },
|
unsigned: { "ghi": "def" },
|
||||||
});
|
});
|
||||||
}).nodeify(done);
|
});
|
||||||
|
|
||||||
httpBackend.flush();
|
httpBackend.flush();
|
||||||
|
return prom;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("deleteDevice", function() {
|
describe("deleteDevice", function() {
|
||||||
const auth = {a: 1};
|
const auth = {a: 1};
|
||||||
it("should pass through an auth dict", function(done) {
|
it("should pass through an auth dict", function() {
|
||||||
httpBackend.when(
|
httpBackend.when(
|
||||||
"DELETE", "/_matrix/client/r0/devices/my_device",
|
"DELETE", "/_matrix/client/r0/devices/my_device",
|
||||||
).check(function(req) {
|
).check(function(req) {
|
||||||
expect(req.data).toEqual({auth: auth});
|
expect(req.data).toEqual({auth: auth});
|
||||||
}).respond(200);
|
}).respond(200);
|
||||||
|
|
||||||
client.deleteDevice(
|
const prom = client.deleteDevice("my_device", auth);
|
||||||
"my_device", auth,
|
|
||||||
).nodeify(done);
|
|
||||||
|
|
||||||
httpBackend.flush();
|
httpBackend.flush();
|
||||||
|
return prom;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ const MatrixClient = sdk.MatrixClient;
|
|||||||
const HttpBackend = require("matrix-mock-request");
|
const HttpBackend = require("matrix-mock-request");
|
||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
describe("MatrixClient opts", function() {
|
describe("MatrixClient opts", function() {
|
||||||
@@ -58,7 +57,6 @@ describe("MatrixClient opts", function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
httpBackend = new HttpBackend();
|
httpBackend = new HttpBackend();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -101,7 +99,7 @@ describe("MatrixClient opts", function() {
|
|||||||
"m.room.create",
|
"m.room.create",
|
||||||
];
|
];
|
||||||
client.on("event", function(event) {
|
client.on("event", function(event) {
|
||||||
expect(expectedEventTypes.indexOf(event.getType())).toNotEqual(
|
expect(expectedEventTypes.indexOf(event.getType())).not.toEqual(
|
||||||
-1, "Recv unexpected event type: " + event.getType(),
|
-1, "Recv unexpected event type: " + event.getType(),
|
||||||
);
|
);
|
||||||
expectedEventTypes.splice(
|
expectedEventTypes.splice(
|
||||||
|
|||||||
@@ -4,11 +4,8 @@ import Promise from 'bluebird';
|
|||||||
|
|
||||||
const sdk = require("../..");
|
const sdk = require("../..");
|
||||||
const HttpBackend = require("matrix-mock-request");
|
const HttpBackend = require("matrix-mock-request");
|
||||||
const utils = require("../test-utils");
|
|
||||||
const EventStatus = sdk.EventStatus;
|
const EventStatus = sdk.EventStatus;
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("MatrixClient retrying", function() {
|
describe("MatrixClient retrying", function() {
|
||||||
const baseUrl = "http://localhost.or.something";
|
const baseUrl = "http://localhost.or.something";
|
||||||
let client = null;
|
let client = null;
|
||||||
@@ -20,7 +17,6 @@ describe("MatrixClient retrying", function() {
|
|||||||
let room;
|
let room;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
httpBackend = new HttpBackend();
|
httpBackend = new HttpBackend();
|
||||||
sdk.request(httpBackend.requestFn);
|
sdk.request(httpBackend.requestFn);
|
||||||
scheduler = new sdk.MatrixScheduler();
|
scheduler = new sdk.MatrixScheduler();
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ const HttpBackend = require("matrix-mock-request");
|
|||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("MatrixClient room timelines", function() {
|
describe("MatrixClient room timelines", function() {
|
||||||
const baseUrl = "http://localhost.or.something";
|
const baseUrl = "http://localhost.or.something";
|
||||||
@@ -103,8 +102,7 @@ describe("MatrixClient room timelines", function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(function(done) {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
httpBackend = new HttpBackend();
|
httpBackend = new HttpBackend();
|
||||||
sdk.request(httpBackend.requestFn);
|
sdk.request(httpBackend.requestFn);
|
||||||
client = sdk.createClient({
|
client = sdk.createClient({
|
||||||
@@ -122,9 +120,9 @@ describe("MatrixClient room timelines", function() {
|
|||||||
return NEXT_SYNC_DATA;
|
return NEXT_SYNC_DATA;
|
||||||
});
|
});
|
||||||
client.startClient();
|
client.startClient();
|
||||||
httpBackend.flush("/pushrules").then(function() {
|
return httpBackend.flush("/pushrules").then(function() {
|
||||||
return httpBackend.flush("/filter");
|
return httpBackend.flush("/filter");
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ const utils = require("../test-utils");
|
|||||||
const MatrixEvent = sdk.MatrixEvent;
|
const MatrixEvent = sdk.MatrixEvent;
|
||||||
const EventTimeline = sdk.EventTimeline;
|
const EventTimeline = sdk.EventTimeline;
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
describe("MatrixClient syncing", function() {
|
describe("MatrixClient syncing", function() {
|
||||||
@@ -23,7 +22,6 @@ describe("MatrixClient syncing", function() {
|
|||||||
const roomTwo = "!bar:localhost";
|
const roomTwo = "!bar:localhost";
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
httpBackend = new HttpBackend();
|
httpBackend = new HttpBackend();
|
||||||
sdk.request(httpBackend.requestFn);
|
sdk.request(httpBackend.requestFn);
|
||||||
client = sdk.createClient({
|
client = sdk.createClient({
|
||||||
@@ -528,7 +526,7 @@ describe("MatrixClient syncing", function() {
|
|||||||
awaitSyncEvent(),
|
awaitSyncEvent(),
|
||||||
]).then(function() {
|
]).then(function() {
|
||||||
const room = client.getRoom(roomTwo);
|
const room = client.getRoom(roomTwo);
|
||||||
expect(room).toExist();
|
expect(room).toBeDefined();
|
||||||
const tok = room.getLiveTimeline()
|
const tok = room.getLiveTimeline()
|
||||||
.getPaginationToken(EventTimeline.BACKWARDS);
|
.getPaginationToken(EventTimeline.BACKWARDS);
|
||||||
expect(tok).toEqual("roomtwotok");
|
expect(tok).toEqual("roomtwotok");
|
||||||
@@ -693,12 +691,12 @@ describe("MatrixClient syncing", function() {
|
|||||||
include_leave: true }});
|
include_leave: true }});
|
||||||
}).respond(200, { filter_id: "another_id" });
|
}).respond(200, { filter_id: "another_id" });
|
||||||
|
|
||||||
const defer = Promise.defer();
|
const prom = new Promise((resolve) => {
|
||||||
|
httpBackend.when("GET", "/sync").check(function(req) {
|
||||||
httpBackend.when("GET", "/sync").check(function(req) {
|
expect(req.queryParams.filter).toEqual("another_id");
|
||||||
expect(req.queryParams.filter).toEqual("another_id");
|
resolve();
|
||||||
defer.resolve();
|
}).respond(200, {});
|
||||||
}).respond(200, {});
|
});
|
||||||
|
|
||||||
client.syncLeftRooms();
|
client.syncLeftRooms();
|
||||||
|
|
||||||
@@ -709,7 +707,7 @@ describe("MatrixClient syncing", function() {
|
|||||||
// flush the syncs
|
// flush the syncs
|
||||||
return httpBackend.flushAllExpected();
|
return httpBackend.flushAllExpected();
|
||||||
}),
|
}),
|
||||||
defer.promise,
|
prom,
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ limitations under the License.
|
|||||||
|
|
||||||
const anotherjson = require('another-json');
|
const anotherjson = require('another-json');
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
const utils = require('../../lib/utils');
|
const utils = require('../../lib/utils');
|
||||||
const testUtils = require('../test-utils');
|
const testUtils = require('../test-utils');
|
||||||
@@ -283,8 +282,6 @@ describe("megolm", function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeEach(async function() {
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
|
|
||||||
aliceTestClient = new TestClient(
|
aliceTestClient = new TestClient(
|
||||||
"@alice:localhost", "xzcvb", "akjgkrgjs",
|
"@alice:localhost", "xzcvb", "akjgkrgjs",
|
||||||
);
|
);
|
||||||
@@ -713,7 +710,7 @@ describe("megolm", function() {
|
|||||||
'PUT', '/send/',
|
'PUT', '/send/',
|
||||||
).respond(200, function(path, content) {
|
).respond(200, function(path, content) {
|
||||||
logger.log('/send:', content);
|
logger.log('/send:', content);
|
||||||
expect(content.session_id).toNotEqual(megolmSessionId);
|
expect(content.session_id).not.toEqual(megolmSessionId);
|
||||||
return {
|
return {
|
||||||
event_id: '$event_id',
|
event_id: '$event_id',
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
import expect from 'expect';
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
// load olm before the sdk if possible
|
// load olm before the sdk if possible
|
||||||
@@ -41,18 +40,6 @@ module.exports.syncPromise = function(client, count) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* Perform common actions before each test case, e.g. printing the test case
|
|
||||||
* name to stdout.
|
|
||||||
* @param {Mocha.Context} context The test context
|
|
||||||
*/
|
|
||||||
module.exports.beforeEach = function(context) {
|
|
||||||
const desc = context.currentTest.fullTitle();
|
|
||||||
|
|
||||||
logger.log(desc);
|
|
||||||
logger.log(new Array(1 + desc.length).join("="));
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a spy for an object and automatically spy its methods.
|
* Create a spy for an object and automatically spy its methods.
|
||||||
* @param {*} constr The class constructor (used with 'new')
|
* @param {*} constr The class constructor (used with 'new')
|
||||||
@@ -71,7 +58,7 @@ module.exports.mock = function(constr, name) {
|
|||||||
for (const key in constr.prototype) { // eslint-disable-line guard-for-in
|
for (const key in constr.prototype) { // eslint-disable-line guard-for-in
|
||||||
try {
|
try {
|
||||||
if (constr.prototype[key] instanceof Function) {
|
if (constr.prototype[key] instanceof Function) {
|
||||||
result[key] = expect.createSpy();
|
result[key] = jest.fn();
|
||||||
}
|
}
|
||||||
} catch (ex) {
|
} catch (ex) {
|
||||||
// Direct access to some non-function fields of DOM prototypes may
|
// Direct access to some non-function fields of DOM prototypes may
|
||||||
@@ -377,9 +364,9 @@ module.exports.setHttpResponses = function setHttpResponses(
|
|||||||
client._http = [
|
client._http = [
|
||||||
"authedRequest", "authedRequestWithPrefix", "getContentUri",
|
"authedRequest", "authedRequestWithPrefix", "getContentUri",
|
||||||
"request", "requestWithPrefix", "uploadContent",
|
"request", "requestWithPrefix", "uploadContent",
|
||||||
].reduce((r, k) => {r[k] = expect.createSpy(); return r;}, {});
|
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
|
||||||
client._http.authedRequest.andCall(httpReq);
|
client._http.authedRequest.mockImplementation(httpReq);
|
||||||
client._http.authedRequestWithPrefix.andCall(httpReq);
|
client._http.authedRequestWithPrefix.mockImplementation(httpReq);
|
||||||
client._http.requestWithPrefix.andCall(httpReq);
|
client._http.requestWithPrefix.mockImplementation(httpReq);
|
||||||
client._http.request.andCall(httpReq);
|
client._http.request.mockImplementation(httpReq);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,11 +18,9 @@ limitations under the License.
|
|||||||
import 'source-map-support/register';
|
import 'source-map-support/register';
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
const sdk = require("../..");
|
const sdk = require("../..");
|
||||||
const utils = require("../test-utils");
|
|
||||||
|
|
||||||
const AutoDiscovery = sdk.AutoDiscovery;
|
const AutoDiscovery = sdk.AutoDiscovery;
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import MockHttpBackend from "matrix-mock-request";
|
import MockHttpBackend from "matrix-mock-request";
|
||||||
|
|
||||||
|
|
||||||
@@ -30,7 +28,6 @@ describe("AutoDiscovery", function() {
|
|||||||
let httpBackend = null;
|
let httpBackend = null;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
httpBackend = new MockHttpBackend();
|
httpBackend = new MockHttpBackend();
|
||||||
sdk.request(httpBackend.requestFn);
|
sdk.request(httpBackend.requestFn);
|
||||||
});
|
});
|
||||||
@@ -416,8 +413,8 @@ describe("AutoDiscovery", function() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return FAIL_ERROR when the identity server configuration is wrong " +
|
it("should return SUCCESS / FAIL_PROMPT when the identity server configuration " +
|
||||||
"(missing base_url)", function() {
|
"is wrong (missing base_url)", function() {
|
||||||
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
|
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
|
||||||
expect(req.opts.uri)
|
expect(req.opts.uri)
|
||||||
.toEqual("https://chat.example.org/_matrix/client/versions");
|
.toEqual("https://chat.example.org/_matrix/client/versions");
|
||||||
@@ -438,14 +435,14 @@ describe("AutoDiscovery", function() {
|
|||||||
AutoDiscovery.findClientConfig("example.org").then((conf) => {
|
AutoDiscovery.findClientConfig("example.org").then((conf) => {
|
||||||
const expected = {
|
const expected = {
|
||||||
"m.homeserver": {
|
"m.homeserver": {
|
||||||
state: "FAIL_ERROR",
|
state: "SUCCESS",
|
||||||
error: AutoDiscovery.ERROR_INVALID_IS,
|
error: null,
|
||||||
|
|
||||||
// We still expect the base_url to be here for debugging purposes.
|
// We still expect the base_url to be here for debugging purposes.
|
||||||
base_url: "https://chat.example.org",
|
base_url: "https://chat.example.org",
|
||||||
},
|
},
|
||||||
"m.identity_server": {
|
"m.identity_server": {
|
||||||
state: "FAIL_ERROR",
|
state: "FAIL_PROMPT",
|
||||||
error: AutoDiscovery.ERROR_INVALID_IS_BASE_URL,
|
error: AutoDiscovery.ERROR_INVALID_IS_BASE_URL,
|
||||||
base_url: null,
|
base_url: null,
|
||||||
},
|
},
|
||||||
@@ -456,8 +453,8 @@ describe("AutoDiscovery", function() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return FAIL_ERROR when the identity server configuration is wrong " +
|
it("should return SUCCESS / FAIL_PROMPT when the identity server configuration " +
|
||||||
"(empty base_url)", function() {
|
"is wrong (empty base_url)", function() {
|
||||||
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
|
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
|
||||||
expect(req.opts.uri)
|
expect(req.opts.uri)
|
||||||
.toEqual("https://chat.example.org/_matrix/client/versions");
|
.toEqual("https://chat.example.org/_matrix/client/versions");
|
||||||
@@ -478,14 +475,14 @@ describe("AutoDiscovery", function() {
|
|||||||
AutoDiscovery.findClientConfig("example.org").then((conf) => {
|
AutoDiscovery.findClientConfig("example.org").then((conf) => {
|
||||||
const expected = {
|
const expected = {
|
||||||
"m.homeserver": {
|
"m.homeserver": {
|
||||||
state: "FAIL_ERROR",
|
state: "SUCCESS",
|
||||||
error: AutoDiscovery.ERROR_INVALID_IS,
|
error: null,
|
||||||
|
|
||||||
// We still expect the base_url to be here for debugging purposes.
|
// We still expect the base_url to be here for debugging purposes.
|
||||||
base_url: "https://chat.example.org",
|
base_url: "https://chat.example.org",
|
||||||
},
|
},
|
||||||
"m.identity_server": {
|
"m.identity_server": {
|
||||||
state: "FAIL_ERROR",
|
state: "FAIL_PROMPT",
|
||||||
error: AutoDiscovery.ERROR_INVALID_IS_BASE_URL,
|
error: AutoDiscovery.ERROR_INVALID_IS_BASE_URL,
|
||||||
base_url: null,
|
base_url: null,
|
||||||
},
|
},
|
||||||
@@ -496,8 +493,8 @@ describe("AutoDiscovery", function() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return FAIL_ERROR when the identity server configuration is wrong " +
|
it("should return SUCCESS / FAIL_PROMPT when the identity server configuration " +
|
||||||
"(validation error: 404)", function() {
|
"is wrong (validation error: 404)", function() {
|
||||||
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
|
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
|
||||||
expect(req.opts.uri)
|
expect(req.opts.uri)
|
||||||
.toEqual("https://chat.example.org/_matrix/client/versions");
|
.toEqual("https://chat.example.org/_matrix/client/versions");
|
||||||
@@ -519,14 +516,14 @@ describe("AutoDiscovery", function() {
|
|||||||
AutoDiscovery.findClientConfig("example.org").then((conf) => {
|
AutoDiscovery.findClientConfig("example.org").then((conf) => {
|
||||||
const expected = {
|
const expected = {
|
||||||
"m.homeserver": {
|
"m.homeserver": {
|
||||||
state: "FAIL_ERROR",
|
state: "SUCCESS",
|
||||||
error: AutoDiscovery.ERROR_INVALID_IS,
|
error: null,
|
||||||
|
|
||||||
// We still expect the base_url to be here for debugging purposes.
|
// We still expect the base_url to be here for debugging purposes.
|
||||||
base_url: "https://chat.example.org",
|
base_url: "https://chat.example.org",
|
||||||
},
|
},
|
||||||
"m.identity_server": {
|
"m.identity_server": {
|
||||||
state: "FAIL_ERROR",
|
state: "FAIL_PROMPT",
|
||||||
error: AutoDiscovery.ERROR_INVALID_IDENTITY_SERVER,
|
error: AutoDiscovery.ERROR_INVALID_IDENTITY_SERVER,
|
||||||
base_url: "https://identity.example.org",
|
base_url: "https://identity.example.org",
|
||||||
},
|
},
|
||||||
@@ -537,8 +534,8 @@ describe("AutoDiscovery", function() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return FAIL_ERROR when the identity server configuration is wrong " +
|
it("should return SUCCESS / FAIL_PROMPT when the identity server configuration " +
|
||||||
"(validation error: 500)", function() {
|
"is wrong (validation error: 500)", function() {
|
||||||
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
|
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
|
||||||
expect(req.opts.uri)
|
expect(req.opts.uri)
|
||||||
.toEqual("https://chat.example.org/_matrix/client/versions");
|
.toEqual("https://chat.example.org/_matrix/client/versions");
|
||||||
@@ -560,14 +557,14 @@ describe("AutoDiscovery", function() {
|
|||||||
AutoDiscovery.findClientConfig("example.org").then((conf) => {
|
AutoDiscovery.findClientConfig("example.org").then((conf) => {
|
||||||
const expected = {
|
const expected = {
|
||||||
"m.homeserver": {
|
"m.homeserver": {
|
||||||
state: "FAIL_ERROR",
|
state: "SUCCESS",
|
||||||
error: AutoDiscovery.ERROR_INVALID_IS,
|
error: null,
|
||||||
|
|
||||||
// We still expect the base_url to be here for debugging purposes
|
// We still expect the base_url to be here for debugging purposes
|
||||||
base_url: "https://chat.example.org",
|
base_url: "https://chat.example.org",
|
||||||
},
|
},
|
||||||
"m.identity_server": {
|
"m.identity_server": {
|
||||||
state: "FAIL_ERROR",
|
state: "FAIL_PROMPT",
|
||||||
error: AutoDiscovery.ERROR_INVALID_IDENTITY_SERVER,
|
error: AutoDiscovery.ERROR_INVALID_IDENTITY_SERVER,
|
||||||
base_url: "https://identity.example.org",
|
base_url: "https://identity.example.org",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,17 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
import 'source-map-support/register';
|
import 'source-map-support/register';
|
||||||
const ContentRepo = require("../../lib/content-repo");
|
const ContentRepo = require("../../lib/content-repo");
|
||||||
const testUtils = require("../test-utils");
|
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("ContentRepo", function() {
|
describe("ContentRepo", function() {
|
||||||
const baseUrl = "https://my.home.server";
|
const baseUrl = "https://my.home.server";
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("getHttpUriForMxc", function() {
|
describe("getHttpUriForMxc", function() {
|
||||||
it("should do nothing to HTTP URLs when allowing direct links", function() {
|
it("should do nothing to HTTP URLs when allowing direct links", function() {
|
||||||
const httpUrl = "http://example.com/image.jpeg";
|
const httpUrl = "http://example.com/image.jpeg";
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'source-map-support/register';
|
|||||||
import '../olm-loader';
|
import '../olm-loader';
|
||||||
|
|
||||||
import Crypto from '../../lib/crypto';
|
import Crypto from '../../lib/crypto';
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
import WebStorageSessionStore from '../../lib/store/session/webstorage';
|
import WebStorageSessionStore from '../../lib/store/session/webstorage';
|
||||||
import MemoryCryptoStore from '../../lib/crypto/store/memory-crypto-store.js';
|
import MemoryCryptoStore from '../../lib/crypto/store/memory-crypto-store.js';
|
||||||
@@ -12,7 +11,6 @@ import TestClient from '../TestClient';
|
|||||||
import {MatrixEvent} from '../../lib/models/event';
|
import {MatrixEvent} from '../../lib/models/event';
|
||||||
import Room from '../../lib/models/room';
|
import Room from '../../lib/models/room';
|
||||||
import olmlib from '../../lib/crypto/olmlib';
|
import olmlib from '../../lib/crypto/olmlib';
|
||||||
import lolex from 'lolex';
|
|
||||||
|
|
||||||
const EventEmitter = require("events").EventEmitter;
|
const EventEmitter = require("events").EventEmitter;
|
||||||
|
|
||||||
@@ -20,13 +18,15 @@ const sdk = require("../..");
|
|||||||
|
|
||||||
const Olm = global.Olm;
|
const Olm = global.Olm;
|
||||||
|
|
||||||
|
jest.useFakeTimers();
|
||||||
|
|
||||||
describe("Crypto", function() {
|
describe("Crypto", function() {
|
||||||
if (!sdk.CRYPTO_ENABLED) {
|
if (!sdk.CRYPTO_ENABLED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(function(done) {
|
beforeAll(function() {
|
||||||
Olm.init().then(done);
|
return Olm.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Crypto exposes the correct olm library version", function() {
|
it("Crypto exposes the correct olm library version", function() {
|
||||||
@@ -76,9 +76,9 @@ describe("Crypto", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
mockBaseApis = {
|
mockBaseApis = {
|
||||||
sendToDevice: expect.createSpy(),
|
sendToDevice: jest.fn(),
|
||||||
getKeyBackupVersion: expect.createSpy(),
|
getKeyBackupVersion: jest.fn(),
|
||||||
isGuest: expect.createSpy(),
|
isGuest: jest.fn(),
|
||||||
};
|
};
|
||||||
mockRoomList = {};
|
mockRoomList = {};
|
||||||
|
|
||||||
@@ -110,15 +110,16 @@ describe("Crypto", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
fakeEmitter.emit('toDeviceEvent', {
|
fakeEmitter.emit('toDeviceEvent', {
|
||||||
getType: expect.createSpy().andReturn('m.room.message'),
|
getId: jest.fn().mockReturnValue("$wedged"),
|
||||||
getContent: expect.createSpy().andReturn({
|
getType: jest.fn().mockReturnValue('m.room.message'),
|
||||||
|
getContent: jest.fn().mockReturnValue({
|
||||||
msgtype: 'm.bad.encrypted',
|
msgtype: 'm.bad.encrypted',
|
||||||
}),
|
}),
|
||||||
getWireContent: expect.createSpy().andReturn({
|
getWireContent: jest.fn().mockReturnValue({
|
||||||
algorithm: 'm.olm.v1.curve25519-aes-sha2',
|
algorithm: 'm.olm.v1.curve25519-aes-sha2',
|
||||||
sender_key: 'this is a key',
|
sender_key: 'this is a key',
|
||||||
}),
|
}),
|
||||||
getSender: expect.createSpy().andReturn('@bob:home.server'),
|
getSender: jest.fn().mockReturnValue('@bob:home.server'),
|
||||||
});
|
});
|
||||||
|
|
||||||
await prom;
|
await prom;
|
||||||
@@ -245,7 +246,7 @@ describe("Crypto", function() {
|
|||||||
await bobDecryptor.onRoomKeyEvent(ksEvent);
|
await bobDecryptor.onRoomKeyEvent(ksEvent);
|
||||||
await eventPromise;
|
await eventPromise;
|
||||||
expect(events[0].getContent().msgtype).toBe("m.bad.encrypted");
|
expect(events[0].getContent().msgtype).toBe("m.bad.encrypted");
|
||||||
expect(events[1].getContent().msgtype).toNotBe("m.bad.encrypted");
|
expect(events[1].getContent().msgtype).not.toBe("m.bad.encrypted");
|
||||||
|
|
||||||
const cryptoStore = bobClient._cryptoStore;
|
const cryptoStore = bobClient._cryptoStore;
|
||||||
const eventContent = events[0].getWireContent();
|
const eventContent = events[0].getWireContent();
|
||||||
@@ -260,7 +261,7 @@ describe("Crypto", function() {
|
|||||||
// the room key request should still be there, since we haven't
|
// the room key request should still be there, since we haven't
|
||||||
// decrypted everything
|
// decrypted everything
|
||||||
expect(await cryptoStore.getOutgoingRoomKeyRequest(roomKeyRequestBody))
|
expect(await cryptoStore.getOutgoingRoomKeyRequest(roomKeyRequestBody))
|
||||||
.toExist();
|
.toBeDefined();
|
||||||
|
|
||||||
// keyshare the session key starting at the first message, so
|
// keyshare the session key starting at the first message, so
|
||||||
// that it can now be decrypted
|
// that it can now be decrypted
|
||||||
@@ -268,10 +269,10 @@ describe("Crypto", function() {
|
|||||||
ksEvent = await keyshareEventForEvent(events[0], 0);
|
ksEvent = await keyshareEventForEvent(events[0], 0);
|
||||||
await bobDecryptor.onRoomKeyEvent(ksEvent);
|
await bobDecryptor.onRoomKeyEvent(ksEvent);
|
||||||
await eventPromise;
|
await eventPromise;
|
||||||
expect(events[0].getContent().msgtype).toNotBe("m.bad.encrypted");
|
expect(events[0].getContent().msgtype).not.toBe("m.bad.encrypted");
|
||||||
// the room key request should be gone since we've now decypted everything
|
// the room key request should be gone since we've now decypted everything
|
||||||
expect(await cryptoStore.getOutgoingRoomKeyRequest(roomKeyRequestBody))
|
expect(await cryptoStore.getOutgoingRoomKeyRequest(roomKeyRequestBody))
|
||||||
.toNotExist();
|
.toBeFalsy();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -296,7 +297,7 @@ describe("Crypto", function() {
|
|||||||
sender_key: "senderkey",
|
sender_key: "senderkey",
|
||||||
};
|
};
|
||||||
expect(await cryptoStore.getOutgoingRoomKeyRequest(roomKeyRequestBody))
|
expect(await cryptoStore.getOutgoingRoomKeyRequest(roomKeyRequestBody))
|
||||||
.toExist();
|
.toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses a new txnid for re-requesting keys", async function() {
|
it("uses a new txnid for re-requesting keys", async function() {
|
||||||
@@ -329,38 +330,32 @@ describe("Crypto", function() {
|
|||||||
|
|
||||||
aliceClient.startClient();
|
aliceClient.startClient();
|
||||||
|
|
||||||
const clock = lolex.install();
|
let promise;
|
||||||
|
// make a room key request, and record the transaction ID for the
|
||||||
|
// sendToDevice call
|
||||||
|
({promise, func: aliceClient.sendToDevice} = awaitFunctionCall());
|
||||||
|
await aliceClient.cancelAndResendEventRoomKeyRequest(event);
|
||||||
|
jest.runAllTimers();
|
||||||
|
let args = await promise;
|
||||||
|
const txnId = args[2];
|
||||||
|
jest.runAllTimers();
|
||||||
|
|
||||||
try {
|
// give the room key request manager time to update the state
|
||||||
let promise;
|
// of the request
|
||||||
// make a room key request, and record the transaction ID for the
|
await Promise.resolve();
|
||||||
// sendToDevice call
|
|
||||||
({promise, func: aliceClient.sendToDevice} = awaitFunctionCall());
|
|
||||||
await aliceClient.cancelAndResendEventRoomKeyRequest(event);
|
|
||||||
clock.runToLast();
|
|
||||||
let args = await promise;
|
|
||||||
const txnId = args[2];
|
|
||||||
clock.runToLast();
|
|
||||||
|
|
||||||
// give the room key request manager time to update the state
|
// cancel and resend the room key request
|
||||||
// of the request
|
({promise, func: aliceClient.sendToDevice} = awaitFunctionCall());
|
||||||
await Promise.resolve();
|
await aliceClient.cancelAndResendEventRoomKeyRequest(event);
|
||||||
|
jest.runAllTimers();
|
||||||
// cancel and resend the room key request
|
// the first call to sendToDevice will be the cancellation
|
||||||
({promise, func: aliceClient.sendToDevice} = awaitFunctionCall());
|
args = await promise;
|
||||||
await aliceClient.cancelAndResendEventRoomKeyRequest(event);
|
// the second call to sendToDevice will be the key request
|
||||||
clock.runToLast();
|
({promise, func: aliceClient.sendToDevice} = awaitFunctionCall());
|
||||||
// the first call to sendToDevice will be the cancellation
|
jest.runAllTimers();
|
||||||
args = await promise;
|
args = await promise;
|
||||||
// the second call to sendToDevice will be the key request
|
jest.runAllTimers();
|
||||||
({promise, func: aliceClient.sendToDevice} = awaitFunctionCall());
|
expect(args[2]).not.toBe(txnId);
|
||||||
clock.runToLast();
|
|
||||||
args = await promise;
|
|
||||||
clock.runToLast();
|
|
||||||
expect(args[2]).toNotBe(txnId);
|
|
||||||
} finally {
|
|
||||||
clock.uninstall();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -17,11 +17,9 @@ limitations under the License.
|
|||||||
|
|
||||||
import DeviceList from '../../../lib/crypto/DeviceList';
|
import DeviceList from '../../../lib/crypto/DeviceList';
|
||||||
import MemoryCryptoStore from '../../../lib/crypto/store/memory-crypto-store.js';
|
import MemoryCryptoStore from '../../../lib/crypto/store/memory-crypto-store.js';
|
||||||
import testUtils from '../../test-utils';
|
|
||||||
import utils from '../../../lib/utils';
|
import utils from '../../../lib/utils';
|
||||||
import logger from '../../../src/logger';
|
import logger from '../../../src/logger';
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
const signedDeviceList = {
|
const signedDeviceList = {
|
||||||
@@ -60,11 +58,9 @@ describe('DeviceList', function() {
|
|||||||
let deviceLists = [];
|
let deviceLists = [];
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
|
|
||||||
deviceLists = [];
|
deviceLists = [];
|
||||||
|
|
||||||
downloadSpy = expect.createSpy();
|
downloadSpy = jest.fn();
|
||||||
cryptoStore = new MemoryCryptoStore();
|
cryptoStore = new MemoryCryptoStore();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -92,7 +88,7 @@ describe('DeviceList', function() {
|
|||||||
dl.startTrackingDeviceList('@test1:sw1v.org');
|
dl.startTrackingDeviceList('@test1:sw1v.org');
|
||||||
|
|
||||||
const queryDefer1 = Promise.defer();
|
const queryDefer1 = Promise.defer();
|
||||||
downloadSpy.andReturn(queryDefer1.promise);
|
downloadSpy.mockReturnValue(queryDefer1.promise);
|
||||||
|
|
||||||
const prom1 = dl.refreshOutdatedDeviceLists();
|
const prom1 = dl.refreshOutdatedDeviceLists();
|
||||||
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
|
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
|
||||||
@@ -111,15 +107,15 @@ describe('DeviceList', function() {
|
|||||||
dl.startTrackingDeviceList('@test1:sw1v.org');
|
dl.startTrackingDeviceList('@test1:sw1v.org');
|
||||||
|
|
||||||
const queryDefer1 = Promise.defer();
|
const queryDefer1 = Promise.defer();
|
||||||
downloadSpy.andReturn(queryDefer1.promise);
|
downloadSpy.mockReturnValue(queryDefer1.promise);
|
||||||
|
|
||||||
const prom1 = dl.refreshOutdatedDeviceLists();
|
const prom1 = dl.refreshOutdatedDeviceLists();
|
||||||
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
|
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
|
||||||
downloadSpy.reset();
|
downloadSpy.mockReset();
|
||||||
|
|
||||||
// outdated notif arrives while the request is in flight.
|
// outdated notif arrives while the request is in flight.
|
||||||
const queryDefer2 = Promise.defer();
|
const queryDefer2 = Promise.defer();
|
||||||
downloadSpy.andReturn(queryDefer2.promise);
|
downloadSpy.mockReturnValue(queryDefer2.promise);
|
||||||
|
|
||||||
dl.invalidateUserDeviceList('@test1:sw1v.org');
|
dl.invalidateUserDeviceList('@test1:sw1v.org');
|
||||||
dl.refreshOutdatedDeviceLists();
|
dl.refreshOutdatedDeviceLists();
|
||||||
@@ -136,10 +132,10 @@ describe('DeviceList', function() {
|
|||||||
// uh-oh; user restarts before second request completes. The new instance
|
// uh-oh; user restarts before second request completes. The new instance
|
||||||
// should know we never got a complete device list.
|
// should know we never got a complete device list.
|
||||||
logger.log("Creating new devicelist to simulate app reload");
|
logger.log("Creating new devicelist to simulate app reload");
|
||||||
downloadSpy.reset();
|
downloadSpy.mockReset();
|
||||||
const dl2 = createTestDeviceList();
|
const dl2 = createTestDeviceList();
|
||||||
const queryDefer3 = Promise.defer();
|
const queryDefer3 = Promise.defer();
|
||||||
downloadSpy.andReturn(queryDefer3.promise);
|
downloadSpy.mockReturnValue(queryDefer3.promise);
|
||||||
|
|
||||||
const prom3 = dl2.refreshOutdatedDeviceLists();
|
const prom3 = dl2.refreshOutdatedDeviceLists();
|
||||||
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
|
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import '../../../olm-loader';
|
import '../../../olm-loader';
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
import sdk from '../../../..';
|
import sdk from '../../../..';
|
||||||
@@ -26,16 +25,16 @@ describe("MegolmDecryption", function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
beforeAll(function() {
|
||||||
|
return Olm.init();
|
||||||
|
});
|
||||||
|
|
||||||
let megolmDecryption;
|
let megolmDecryption;
|
||||||
let mockOlmLib;
|
let mockOlmLib;
|
||||||
let mockCrypto;
|
let mockCrypto;
|
||||||
let mockBaseApis;
|
let mockBaseApis;
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeEach(async function() {
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
|
|
||||||
await Olm.init();
|
|
||||||
|
|
||||||
mockCrypto = testUtils.mock(Crypto, 'Crypto');
|
mockCrypto = testUtils.mock(Crypto, 'Crypto');
|
||||||
mockBaseApis = {};
|
mockBaseApis = {};
|
||||||
|
|
||||||
@@ -55,9 +54,9 @@ describe("MegolmDecryption", function() {
|
|||||||
|
|
||||||
// we stub out the olm encryption bits
|
// we stub out the olm encryption bits
|
||||||
mockOlmLib = {};
|
mockOlmLib = {};
|
||||||
mockOlmLib.ensureOlmSessionsForDevices = expect.createSpy();
|
mockOlmLib.ensureOlmSessionsForDevices = jest.fn();
|
||||||
mockOlmLib.encryptMessageForDevice =
|
mockOlmLib.encryptMessageForDevice =
|
||||||
expect.createSpy().andReturn(Promise.resolve());
|
jest.fn().mockReturnValue(Promise.resolve());
|
||||||
megolmDecryption.olmlib = mockOlmLib;
|
megolmDecryption.olmlib = mockOlmLib;
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -135,22 +134,22 @@ describe("MegolmDecryption", function() {
|
|||||||
|
|
||||||
// set up some pre-conditions for the share call
|
// set up some pre-conditions for the share call
|
||||||
const deviceInfo = {};
|
const deviceInfo = {};
|
||||||
mockCrypto.getStoredDevice.andReturn(deviceInfo);
|
mockCrypto.getStoredDevice.mockReturnValue(deviceInfo);
|
||||||
|
|
||||||
mockOlmLib.ensureOlmSessionsForDevices.andReturn(
|
mockOlmLib.ensureOlmSessionsForDevices.mockReturnValue(
|
||||||
Promise.resolve({'@alice:foo': {'alidevice': {
|
Promise.resolve({'@alice:foo': {'alidevice': {
|
||||||
sessionId: 'alisession',
|
sessionId: 'alisession',
|
||||||
}}}),
|
}}}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const awaitEncryptForDevice = new Promise((res, rej) => {
|
const awaitEncryptForDevice = new Promise((res, rej) => {
|
||||||
mockOlmLib.encryptMessageForDevice.andCall(() => {
|
mockOlmLib.encryptMessageForDevice.mockImplementation(() => {
|
||||||
res();
|
res();
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
mockBaseApis.sendToDevice = expect.createSpy();
|
mockBaseApis.sendToDevice = jest.fn();
|
||||||
|
|
||||||
// do the share
|
// do the share
|
||||||
megolmDecryption.shareKeysWithDevice(keyRequest);
|
megolmDecryption.shareKeysWithDevice(keyRequest);
|
||||||
@@ -160,21 +159,20 @@ describe("MegolmDecryption", function() {
|
|||||||
}).then(() => {
|
}).then(() => {
|
||||||
// check that it called encryptMessageForDevice with
|
// check that it called encryptMessageForDevice with
|
||||||
// appropriate args.
|
// appropriate args.
|
||||||
expect(mockOlmLib.encryptMessageForDevice.calls.length)
|
expect(mockOlmLib.encryptMessageForDevice).toBeCalledTimes(1);
|
||||||
.toEqual(1);
|
|
||||||
|
|
||||||
const call = mockOlmLib.encryptMessageForDevice.calls[0];
|
const call = mockOlmLib.encryptMessageForDevice.mock.calls[0];
|
||||||
const payload = call.arguments[6];
|
const payload = call[6];
|
||||||
|
|
||||||
expect(payload.type).toEqual("m.forwarded_room_key");
|
expect(payload.type).toEqual("m.forwarded_room_key");
|
||||||
expect(payload.content).toInclude({
|
expect(payload.content).toMatchObject({
|
||||||
sender_key: "SENDER_CURVE25519",
|
sender_key: "SENDER_CURVE25519",
|
||||||
sender_claimed_ed25519_key: "SENDER_ED25519",
|
sender_claimed_ed25519_key: "SENDER_ED25519",
|
||||||
session_id: groupSession.session_id(),
|
session_id: groupSession.session_id(),
|
||||||
chain_index: 0,
|
chain_index: 0,
|
||||||
forwarding_curve25519_key_chain: [],
|
forwarding_curve25519_key_chain: [],
|
||||||
});
|
});
|
||||||
expect(payload.content.session_key).toExist();
|
expect(payload.content.session_key).toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -201,13 +199,12 @@ describe("MegolmDecryption", function() {
|
|||||||
origin_server_ts: 1507753886000,
|
origin_server_ts: 1507753886000,
|
||||||
});
|
});
|
||||||
|
|
||||||
const successHandler = expect.createSpy();
|
const successHandler = jest.fn();
|
||||||
const failureHandler = expect.createSpy()
|
const failureHandler = jest.fn((err) => {
|
||||||
.andCall((err) => {
|
expect(err.toString()).toMatch(
|
||||||
expect(err.toString()).toMatch(
|
/Duplicate message index, possible replay attack/,
|
||||||
/Duplicate message index, possible replay attack/,
|
);
|
||||||
);
|
});
|
||||||
});
|
|
||||||
|
|
||||||
return megolmDecryption.decryptEvent(event1).then((res) => {
|
return megolmDecryption.decryptEvent(event1).then((res) => {
|
||||||
const event2 = new MatrixEvent({
|
const event2 = new MatrixEvent({
|
||||||
@@ -228,7 +225,7 @@ describe("MegolmDecryption", function() {
|
|||||||
successHandler,
|
successHandler,
|
||||||
failureHandler,
|
failureHandler,
|
||||||
).then(() => {
|
).then(() => {
|
||||||
expect(successHandler).toNotHaveBeenCalled();
|
expect(successHandler).not.toHaveBeenCalled();
|
||||||
expect(failureHandler).toHaveBeenCalled();
|
expect(failureHandler).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -266,10 +263,10 @@ describe("MegolmDecryption", function() {
|
|||||||
const cryptoStore = new MemoryCryptoStore(mockStorage);
|
const cryptoStore = new MemoryCryptoStore(mockStorage);
|
||||||
|
|
||||||
const olmDevice = new OlmDevice(cryptoStore);
|
const olmDevice = new OlmDevice(cryptoStore);
|
||||||
olmDevice.verifySignature = expect.createSpy();
|
olmDevice.verifySignature = jest.fn();
|
||||||
await olmDevice.init();
|
await olmDevice.init();
|
||||||
|
|
||||||
mockBaseApis.claimOneTimeKeys = expect.createSpy().andReturn(Promise.resolve({
|
mockBaseApis.claimOneTimeKeys = jest.fn().mockReturnValue(Promise.resolve({
|
||||||
one_time_keys: {
|
one_time_keys: {
|
||||||
'@alice:home.server': {
|
'@alice:home.server': {
|
||||||
aliceDevice: {
|
aliceDevice: {
|
||||||
@@ -285,18 +282,18 @@ describe("MegolmDecryption", function() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
mockBaseApis.sendToDevice = expect.createSpy().andReturn(Promise.resolve());
|
mockBaseApis.sendToDevice = jest.fn().mockReturnValue(Promise.resolve());
|
||||||
|
|
||||||
mockCrypto.downloadKeys.andReturn(Promise.resolve({
|
mockCrypto.downloadKeys.mockReturnValue(Promise.resolve({
|
||||||
'@alice:home.server': {
|
'@alice:home.server': {
|
||||||
aliceDevice: {
|
aliceDevice: {
|
||||||
deviceId: 'aliceDevice',
|
deviceId: 'aliceDevice',
|
||||||
isBlocked: expect.createSpy().andReturn(false),
|
isBlocked: jest.fn().mockReturnValue(false),
|
||||||
isUnverified: expect.createSpy().andReturn(false),
|
isUnverified: jest.fn().mockReturnValue(false),
|
||||||
getIdentityKey: expect.createSpy().andReturn(
|
getIdentityKey: jest.fn().mockReturnValue(
|
||||||
'YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE',
|
'YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE',
|
||||||
),
|
),
|
||||||
getFingerprint: expect.createSpy().andReturn(''),
|
getFingerprint: jest.fn().mockReturnValue(''),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
@@ -312,10 +309,10 @@ describe("MegolmDecryption", function() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
const mockRoom = {
|
const mockRoom = {
|
||||||
getEncryptionTargetMembers: expect.createSpy().andReturn(
|
getEncryptionTargetMembers: jest.fn().mockReturnValue(
|
||||||
[{userId: "@alice:home.server"}],
|
[{userId: "@alice:home.server"}],
|
||||||
),
|
),
|
||||||
getBlacklistUnverifiedDevices: expect.createSpy().andReturn(false),
|
getBlacklistUnverifiedDevices: jest.fn().mockReturnValue(false),
|
||||||
};
|
};
|
||||||
const ct1 = await megolmEncryption.encryptMessage(mockRoom, "a.fake.type", {
|
const ct1 = await megolmEncryption.encryptMessage(mockRoom, "a.fake.type", {
|
||||||
body: "Some text",
|
body: "Some text",
|
||||||
@@ -323,25 +320,25 @@ describe("MegolmDecryption", function() {
|
|||||||
expect(mockRoom.getEncryptionTargetMembers).toHaveBeenCalled();
|
expect(mockRoom.getEncryptionTargetMembers).toHaveBeenCalled();
|
||||||
|
|
||||||
// this should have claimed a key for alice as it's starting a new session
|
// this should have claimed a key for alice as it's starting a new session
|
||||||
expect(mockBaseApis.claimOneTimeKeys).toHaveBeenCalled(
|
expect(mockBaseApis.claimOneTimeKeys).toHaveBeenCalledWith(
|
||||||
[['@alice:home.server', 'aliceDevice']], 'signed_curve25519',
|
[['@alice:home.server', 'aliceDevice']], 'signed_curve25519',
|
||||||
);
|
);
|
||||||
expect(mockCrypto.downloadKeys).toHaveBeenCalledWith(
|
expect(mockCrypto.downloadKeys).toHaveBeenCalledWith(
|
||||||
['@alice:home.server'], false,
|
['@alice:home.server'], false,
|
||||||
);
|
);
|
||||||
expect(mockBaseApis.sendToDevice).toHaveBeenCalled();
|
expect(mockBaseApis.sendToDevice).toHaveBeenCalled();
|
||||||
expect(mockBaseApis.claimOneTimeKeys).toHaveBeenCalled(
|
expect(mockBaseApis.claimOneTimeKeys).toHaveBeenCalledWith(
|
||||||
[['@alice:home.server', 'aliceDevice']], 'signed_curve25519',
|
[['@alice:home.server', 'aliceDevice']], 'signed_curve25519',
|
||||||
);
|
);
|
||||||
|
|
||||||
mockBaseApis.claimOneTimeKeys.reset();
|
mockBaseApis.claimOneTimeKeys.mockReset();
|
||||||
|
|
||||||
const ct2 = await megolmEncryption.encryptMessage(mockRoom, "a.fake.type", {
|
const ct2 = await megolmEncryption.encryptMessage(mockRoom, "a.fake.type", {
|
||||||
body: "Some more text",
|
body: "Some more text",
|
||||||
});
|
});
|
||||||
|
|
||||||
// this should *not* have claimed a key as it should be using the same session
|
// this should *not* have claimed a key as it should be using the same session
|
||||||
expect(mockBaseApis.claimOneTimeKeys).toNotHaveBeenCalled();
|
expect(mockBaseApis.claimOneTimeKeys).not.toHaveBeenCalled();
|
||||||
|
|
||||||
// likewise they should show the same session ID
|
// likewise they should show the same session ID
|
||||||
expect(ct2.session_id).toEqual(ct1.session_id);
|
expect(ct2.session_id).toEqual(ct1.session_id);
|
||||||
|
|||||||
@@ -16,10 +16,8 @@ limitations under the License.
|
|||||||
|
|
||||||
import '../../../olm-loader';
|
import '../../../olm-loader';
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import MemoryCryptoStore from '../../../../lib/crypto/store/memory-crypto-store.js';
|
import MemoryCryptoStore from '../../../../lib/crypto/store/memory-crypto-store.js';
|
||||||
import MockStorageApi from '../../../MockStorageApi';
|
import MockStorageApi from '../../../MockStorageApi';
|
||||||
import testUtils from '../../../test-utils';
|
|
||||||
import logger from '../../../../src/logger';
|
import logger from '../../../../src/logger';
|
||||||
|
|
||||||
import OlmDevice from '../../../../lib/crypto/OlmDevice';
|
import OlmDevice from '../../../../lib/crypto/OlmDevice';
|
||||||
@@ -50,14 +48,14 @@ describe("OlmDecryption", function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
beforeAll(function() {
|
||||||
|
return global.Olm.init();
|
||||||
|
});
|
||||||
|
|
||||||
let aliceOlmDevice;
|
let aliceOlmDevice;
|
||||||
let bobOlmDevice;
|
let bobOlmDevice;
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeEach(async function() {
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
|
|
||||||
await global.Olm.init();
|
|
||||||
|
|
||||||
aliceOlmDevice = makeOlmDevice();
|
aliceOlmDevice = makeOlmDevice();
|
||||||
bobOlmDevice = makeOlmDevice();
|
bobOlmDevice = makeOlmDevice();
|
||||||
await aliceOlmDevice.init();
|
await aliceOlmDevice.init();
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ limitations under the License.
|
|||||||
|
|
||||||
import '../../olm-loader';
|
import '../../olm-loader';
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
import sdk from '../../..';
|
import sdk from '../../..';
|
||||||
@@ -98,16 +97,16 @@ function makeTestClient(sessionStore, cryptoStore) {
|
|||||||
const scheduler = [
|
const scheduler = [
|
||||||
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
|
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
|
||||||
"setProcessFunction",
|
"setProcessFunction",
|
||||||
].reduce((r, k) => {r[k] = expect.createSpy(); return r;}, {});
|
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
|
||||||
const store = [
|
const store = [
|
||||||
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
|
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
|
||||||
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom",
|
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom",
|
||||||
"storeUser", "getFilterIdByName", "setFilterIdByName", "getFilter",
|
"storeUser", "getFilterIdByName", "setFilterIdByName", "getFilter",
|
||||||
"storeFilter", "getSyncAccumulator", "startup", "deleteAllData",
|
"storeFilter", "getSyncAccumulator", "startup", "deleteAllData",
|
||||||
].reduce((r, k) => {r[k] = expect.createSpy(); return r;}, {});
|
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
|
||||||
store.getSavedSync = expect.createSpy().andReturn(Promise.resolve(null));
|
store.getSavedSync = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
store.getSavedSyncToken = expect.createSpy().andReturn(Promise.resolve(null));
|
store.getSavedSyncToken = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
store.setSyncData = expect.createSpy().andReturn(Promise.resolve(null));
|
store.setSyncData = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
return new MatrixClient({
|
return new MatrixClient({
|
||||||
baseUrl: "https://my.home.server",
|
baseUrl: "https://my.home.server",
|
||||||
idBaseUrl: "https://identity.server",
|
idBaseUrl: "https://identity.server",
|
||||||
@@ -129,6 +128,10 @@ describe("MegolmBackup", function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
beforeAll(function() {
|
||||||
|
return Olm.init();
|
||||||
|
});
|
||||||
|
|
||||||
let olmDevice;
|
let olmDevice;
|
||||||
let mockOlmLib;
|
let mockOlmLib;
|
||||||
let mockCrypto;
|
let mockCrypto;
|
||||||
@@ -137,9 +140,6 @@ describe("MegolmBackup", function() {
|
|||||||
let cryptoStore;
|
let cryptoStore;
|
||||||
let megolmDecryption;
|
let megolmDecryption;
|
||||||
beforeEach(async function() {
|
beforeEach(async function() {
|
||||||
await Olm.init();
|
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
|
|
||||||
mockCrypto = testUtils.mock(Crypto, 'Crypto');
|
mockCrypto = testUtils.mock(Crypto, 'Crypto');
|
||||||
mockCrypto.backupKey = new Olm.PkEncryption();
|
mockCrypto.backupKey = new Olm.PkEncryption();
|
||||||
mockCrypto.backupKey.set_recipient_key(
|
mockCrypto.backupKey.set_recipient_key(
|
||||||
@@ -155,9 +155,9 @@ describe("MegolmBackup", function() {
|
|||||||
|
|
||||||
// we stub out the olm encryption bits
|
// we stub out the olm encryption bits
|
||||||
mockOlmLib = {};
|
mockOlmLib = {};
|
||||||
mockOlmLib.ensureOlmSessionsForDevices = expect.createSpy();
|
mockOlmLib.ensureOlmSessionsForDevices = jest.fn();
|
||||||
mockOlmLib.encryptMessageForDevice =
|
mockOlmLib.encryptMessageForDevice =
|
||||||
expect.createSpy().andReturn(Promise.resolve());
|
jest.fn().mockReturnValue(Promise.resolve());
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("backup", function() {
|
describe("backup", function() {
|
||||||
@@ -218,7 +218,7 @@ describe("MegolmBackup", function() {
|
|||||||
};
|
};
|
||||||
mockCrypto.cancelRoomKeyRequest = function() {};
|
mockCrypto.cancelRoomKeyRequest = function() {};
|
||||||
|
|
||||||
mockCrypto.backupGroupSession = expect.createSpy();
|
mockCrypto.backupGroupSession = jest.fn();
|
||||||
|
|
||||||
return event.attemptDecryption(mockCrypto).then(() => {
|
return event.attemptDecryption(mockCrypto).then(() => {
|
||||||
return megolmDecryption.onRoomKeyEvent(event);
|
return megolmDecryption.onRoomKeyEvent(event);
|
||||||
@@ -279,7 +279,7 @@ describe("MegolmBackup", function() {
|
|||||||
callback, method, path, queryParams, data, opts,
|
callback, method, path, queryParams, data, opts,
|
||||||
) {
|
) {
|
||||||
++numCalls;
|
++numCalls;
|
||||||
expect(numCalls).toBeLessThanOrEqualTo(1);
|
expect(numCalls).toBeLessThanOrEqual(1);
|
||||||
if (numCalls >= 2) {
|
if (numCalls >= 2) {
|
||||||
// exit out of retry loop if there's something wrong
|
// exit out of retry loop if there's something wrong
|
||||||
reject(new Error("authedRequest called too many timmes"));
|
reject(new Error("authedRequest called too many timmes"));
|
||||||
@@ -288,8 +288,8 @@ describe("MegolmBackup", function() {
|
|||||||
expect(method).toBe("PUT");
|
expect(method).toBe("PUT");
|
||||||
expect(path).toBe("/room_keys/keys");
|
expect(path).toBe("/room_keys/keys");
|
||||||
expect(queryParams.version).toBe(1);
|
expect(queryParams.version).toBe(1);
|
||||||
expect(data.rooms[ROOM_ID].sessions).toExist();
|
expect(data.rooms[ROOM_ID].sessions).toBeDefined();
|
||||||
expect(data.rooms[ROOM_ID].sessions).toIncludeKey(
|
expect(data.rooms[ROOM_ID].sessions).toHaveProperty(
|
||||||
groupSession.session_id(),
|
groupSession.session_id(),
|
||||||
);
|
);
|
||||||
resolve();
|
resolve();
|
||||||
@@ -343,7 +343,7 @@ describe("MegolmBackup", function() {
|
|||||||
callback, method, path, queryParams, data, opts,
|
callback, method, path, queryParams, data, opts,
|
||||||
) {
|
) {
|
||||||
++numCalls;
|
++numCalls;
|
||||||
expect(numCalls).toBeLessThanOrEqualTo(1);
|
expect(numCalls).toBeLessThanOrEqual(1);
|
||||||
if (numCalls >= 2) {
|
if (numCalls >= 2) {
|
||||||
// exit out of retry loop if there's something wrong
|
// exit out of retry loop if there's something wrong
|
||||||
reject(new Error("authedRequest called too many timmes"));
|
reject(new Error("authedRequest called too many timmes"));
|
||||||
@@ -382,16 +382,16 @@ describe("MegolmBackup", function() {
|
|||||||
const scheduler = [
|
const scheduler = [
|
||||||
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
|
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
|
||||||
"setProcessFunction",
|
"setProcessFunction",
|
||||||
].reduce((r, k) => {r[k] = expect.createSpy(); return r;}, {});
|
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
|
||||||
const store = [
|
const store = [
|
||||||
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
|
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
|
||||||
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom",
|
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom",
|
||||||
"storeUser", "getFilterIdByName", "setFilterIdByName", "getFilter",
|
"storeUser", "getFilterIdByName", "setFilterIdByName", "getFilter",
|
||||||
"storeFilter", "getSyncAccumulator", "startup", "deleteAllData",
|
"storeFilter", "getSyncAccumulator", "startup", "deleteAllData",
|
||||||
].reduce((r, k) => {r[k] = expect.createSpy(); return r;}, {});
|
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
|
||||||
store.getSavedSync = expect.createSpy().andReturn(Promise.resolve(null));
|
store.getSavedSync = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
store.getSavedSyncToken = expect.createSpy().andReturn(Promise.resolve(null));
|
store.getSavedSyncToken = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
store.setSyncData = expect.createSpy().andReturn(Promise.resolve(null));
|
store.setSyncData = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
const client = new MatrixClient({
|
const client = new MatrixClient({
|
||||||
baseUrl: "https://my.home.server",
|
baseUrl: "https://my.home.server",
|
||||||
idBaseUrl: "https://identity.server",
|
idBaseUrl: "https://identity.server",
|
||||||
@@ -449,7 +449,7 @@ describe("MegolmBackup", function() {
|
|||||||
callback, method, path, queryParams, data, opts,
|
callback, method, path, queryParams, data, opts,
|
||||||
) {
|
) {
|
||||||
++numCalls;
|
++numCalls;
|
||||||
expect(numCalls).toBeLessThanOrEqualTo(2);
|
expect(numCalls).toBeLessThanOrEqual(2);
|
||||||
if (numCalls >= 3) {
|
if (numCalls >= 3) {
|
||||||
// exit out of retry loop if there's something wrong
|
// exit out of retry loop if there's something wrong
|
||||||
reject(new Error("authedRequest called too many timmes"));
|
reject(new Error("authedRequest called too many timmes"));
|
||||||
@@ -458,8 +458,8 @@ describe("MegolmBackup", function() {
|
|||||||
expect(method).toBe("PUT");
|
expect(method).toBe("PUT");
|
||||||
expect(path).toBe("/room_keys/keys");
|
expect(path).toBe("/room_keys/keys");
|
||||||
expect(queryParams.version).toBe(1);
|
expect(queryParams.version).toBe(1);
|
||||||
expect(data.rooms[ROOM_ID].sessions).toExist();
|
expect(data.rooms[ROOM_ID].sessions).toBeDefined();
|
||||||
expect(data.rooms[ROOM_ID].sessions).toIncludeKey(
|
expect(data.rooms[ROOM_ID].sessions).toHaveProperty(
|
||||||
groupSession.session_id(),
|
groupSession.session_id(),
|
||||||
);
|
);
|
||||||
if (numCalls > 1) {
|
if (numCalls > 1) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ limitations under the License.
|
|||||||
|
|
||||||
import '../../olm-loader';
|
import '../../olm-loader';
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import anotherjson from 'another-json';
|
import anotherjson from 'another-json';
|
||||||
|
|
||||||
import olmlib from '../../../lib/crypto/olmlib';
|
import olmlib from '../../../lib/crypto/olmlib';
|
||||||
@@ -56,21 +55,20 @@ describe("Cross Signing", function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeAll(function() {
|
||||||
await global.Olm.init();
|
return global.Olm.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should sign the master key with the device key", async function() {
|
it("should sign the master key with the device key", async function() {
|
||||||
const alice = await makeTestClient(
|
const alice = await makeTestClient(
|
||||||
{userId: "@alice:example.com", deviceId: "Osborne2"},
|
{userId: "@alice:example.com", deviceId: "Osborne2"},
|
||||||
);
|
);
|
||||||
alice.uploadDeviceSigningKeys = expect.createSpy()
|
alice.uploadDeviceSigningKeys = jest.fn(async (auth, keys) => {
|
||||||
.andCall(async (auth, keys) => {
|
await olmlib.verifySignature(
|
||||||
await olmlib.verifySignature(
|
alice._crypto._olmDevice, keys.master_key, "@alice:example.com",
|
||||||
alice._crypto._olmDevice, keys.master_key, "@alice:example.com",
|
"Osborne2", alice._crypto._olmDevice.deviceEd25519Key,
|
||||||
"Osborne2", alice._crypto._olmDevice.deviceEd25519Key,
|
);
|
||||||
);
|
});
|
||||||
});
|
|
||||||
alice.uploadKeySignatures = async () => {};
|
alice.uploadKeySignatures = async () => {};
|
||||||
// set Alice's cross-signing key
|
// set Alice's cross-signing key
|
||||||
await alice.resetCrossSigningKeys();
|
await alice.resetCrossSigningKeys();
|
||||||
@@ -146,7 +144,7 @@ describe("Cross Signing", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const uploadSigsPromise = new Promise((resolve, reject) => {
|
const uploadSigsPromise = new Promise((resolve, reject) => {
|
||||||
alice.uploadKeySignatures = expect.createSpy().andCall(async (content) => {
|
alice.uploadKeySignatures = jest.fn(async (content) => {
|
||||||
await olmlib.verifySignature(
|
await olmlib.verifySignature(
|
||||||
alice._crypto._olmDevice,
|
alice._crypto._olmDevice,
|
||||||
content["@alice:example.com"][
|
content["@alice:example.com"][
|
||||||
@@ -732,7 +730,7 @@ describe("Cross Signing", function() {
|
|||||||
{
|
{
|
||||||
cryptoCallbacks: {
|
cryptoCallbacks: {
|
||||||
shouldUpgradeDeviceVerifications: (verifs) => {
|
shouldUpgradeDeviceVerifications: (verifs) => {
|
||||||
expect(verifs.users["@bob:example.com"]).toExist();
|
expect(verifs.users["@bob:example.com"]).toBeDefined();
|
||||||
upgradeResolveFunc();
|
upgradeResolveFunc();
|
||||||
return ["@bob:example.com"];
|
return ["@bob:example.com"];
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ limitations under the License.
|
|||||||
|
|
||||||
import '../../olm-loader';
|
import '../../olm-loader';
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import { MatrixEvent } from '../../../lib/models/event';
|
import { MatrixEvent } from '../../../lib/models/event';
|
||||||
import { SECRET_STORAGE_ALGORITHM_V1 } from '../../../lib/crypto/SecretStorage';
|
import { SECRET_STORAGE_ALGORITHM_V1 } from '../../../lib/crypto/SecretStorage';
|
||||||
|
|
||||||
@@ -41,8 +40,8 @@ describe("Secrets", function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeAll(function() {
|
||||||
await global.Olm.init();
|
return global.Olm.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should store and retrieve a secret", async function() {
|
it("should store and retrieve a secret", async function() {
|
||||||
@@ -62,7 +61,7 @@ describe("Secrets", function() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const getKey = expect.createSpy().andCall(e => {
|
const getKey = jest.fn(e => {
|
||||||
expect(Object.keys(e.keys)).toEqual(["abc"]);
|
expect(Object.keys(e.keys)).toEqual(["abc"]);
|
||||||
return ['abc', privkey];
|
return ['abc', privkey];
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ try {
|
|||||||
logger.warn("unable to run device verification tests: libolm not available");
|
logger.warn("unable to run device verification tests: libolm not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import DeviceInfo from '../../../../lib/crypto/deviceinfo';
|
import DeviceInfo from '../../../../lib/crypto/deviceinfo';
|
||||||
|
|
||||||
import {ShowQRCode, ScanQRCode} from '../../../../lib/crypto/verification/QRCode';
|
import {ShowQRCode, ScanQRCode} from '../../../../lib/crypto/verification/QRCode';
|
||||||
@@ -34,8 +33,8 @@ describe("QR code verification", function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeAll(function() {
|
||||||
await Olm.init();
|
return Olm.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("showing", function() {
|
describe("showing", function() {
|
||||||
@@ -47,7 +46,7 @@ describe("QR code verification", function() {
|
|||||||
return "device+ed25519+key";
|
return "device+ed25519+key";
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const spy = expect.createSpy().andCall((e) => {
|
const spy = jest.fn((e) => {
|
||||||
qrCode.done();
|
qrCode.done();
|
||||||
});
|
});
|
||||||
qrCode.on("show_qr_code", spy);
|
qrCode.on("show_qr_code", spy);
|
||||||
@@ -77,8 +76,8 @@ describe("QR code verification", function() {
|
|||||||
"ABCDEFG",
|
"ABCDEFG",
|
||||||
);
|
);
|
||||||
const client = {
|
const client = {
|
||||||
getStoredDevice: expect.createSpy().andReturn(device),
|
getStoredDevice: jest.fn().mockReturnValue(device),
|
||||||
setDeviceVerified: expect.createSpy(),
|
setDeviceVerified: jest.fn(),
|
||||||
};
|
};
|
||||||
const qrCode = new ScanQRCode(client);
|
const qrCode = new ScanQRCode(client);
|
||||||
qrCode.on("confirm_user_id", ({userId, confirm}) => {
|
qrCode.on("confirm_user_id", ({userId, confirm}) => {
|
||||||
@@ -100,18 +99,18 @@ describe("QR code verification", function() {
|
|||||||
|
|
||||||
it("should error when the user ID doesn't match", async function() {
|
it("should error when the user ID doesn't match", async function() {
|
||||||
const client = {
|
const client = {
|
||||||
getStoredDevice: expect.createSpy(),
|
getStoredDevice: jest.fn(),
|
||||||
setDeviceVerified: expect.createSpy(),
|
setDeviceVerified: jest.fn(),
|
||||||
};
|
};
|
||||||
const qrCode = new ScanQRCode(client, "@bob:example.com", "ABCDEFG");
|
const qrCode = new ScanQRCode(client, "@bob:example.com", "ABCDEFG");
|
||||||
qrCode.on("scan", ({done}) => {
|
qrCode.on("scan", ({done}) => {
|
||||||
done(QR_CODE_URL);
|
done(QR_CODE_URL);
|
||||||
});
|
});
|
||||||
const spy = expect.createSpy();
|
const spy = jest.fn();
|
||||||
await qrCode.verify().catch(spy);
|
await qrCode.verify().catch(spy);
|
||||||
expect(spy).toHaveBeenCalled();
|
expect(spy).toHaveBeenCalled();
|
||||||
expect(client.getStoredDevice).toNotHaveBeenCalled();
|
expect(client.getStoredDevice).not.toHaveBeenCalled();
|
||||||
expect(client.setDeviceVerified).toNotHaveBeenCalled();
|
expect(client.setDeviceVerified).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should error if the key doesn't match", async function() {
|
it("should error if the key doesn't match", async function() {
|
||||||
@@ -129,18 +128,18 @@ describe("QR code verification", function() {
|
|||||||
"ABCDEFG",
|
"ABCDEFG",
|
||||||
);
|
);
|
||||||
const client = {
|
const client = {
|
||||||
getStoredDevice: expect.createSpy().andReturn(device),
|
getStoredDevice: jest.fn().mockReturnValue(device),
|
||||||
setDeviceVerified: expect.createSpy(),
|
setDeviceVerified: jest.fn(),
|
||||||
};
|
};
|
||||||
const qrCode = new ScanQRCode(client, "@alice:example.com", "ABCDEFG");
|
const qrCode = new ScanQRCode(client, "@alice:example.com", "ABCDEFG");
|
||||||
qrCode.on("scan", ({done}) => {
|
qrCode.on("scan", ({done}) => {
|
||||||
done(QR_CODE_URL);
|
done(QR_CODE_URL);
|
||||||
});
|
});
|
||||||
const spy = expect.createSpy();
|
const spy = jest.fn();
|
||||||
await qrCode.verify().catch(spy);
|
await qrCode.verify().catch(spy);
|
||||||
expect(spy).toHaveBeenCalled();
|
expect(spy).toHaveBeenCalled();
|
||||||
expect(client.getStoredDevice).toHaveBeenCalled();
|
expect(client.getStoredDevice).toHaveBeenCalled();
|
||||||
expect(client.setDeviceVerified).toNotHaveBeenCalled();
|
expect(client.setDeviceVerified).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ try {
|
|||||||
logger.warn("unable to run device verification tests: libolm not available");
|
logger.warn("unable to run device verification tests: libolm not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
import {verificationMethods} from '../../../../lib/crypto';
|
import {verificationMethods} from '../../../../lib/crypto';
|
||||||
|
|
||||||
import SAS from '../../../../lib/crypto/verification/SAS';
|
import SAS from '../../../../lib/crypto/verification/SAS';
|
||||||
@@ -37,8 +35,8 @@ describe("verification request", function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeAll(function() {
|
||||||
await Olm.init();
|
return Olm.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should request and accept a verification", async function() {
|
it("should request and accept a verification", async function() {
|
||||||
@@ -74,7 +72,7 @@ describe("verification request", function() {
|
|||||||
bobVerifier._endTimer();
|
bobVerifier._endTimer();
|
||||||
});
|
});
|
||||||
const aliceVerifier = await alice.client.requestVerification("@bob:example.com");
|
const aliceVerifier = await alice.client.requestVerification("@bob:example.com");
|
||||||
expect(aliceVerifier).toBeAn(SAS);
|
expect(aliceVerifier).toBeInstanceOf(SAS);
|
||||||
|
|
||||||
// XXX: Private function access (but it's a test, so we're okay)
|
// XXX: Private function access (but it's a test, so we're okay)
|
||||||
aliceVerifier._endTimer();
|
aliceVerifier._endTimer();
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ try {
|
|||||||
logger.warn("unable to run device verification tests: libolm not available");
|
logger.warn("unable to run device verification tests: libolm not available");
|
||||||
}
|
}
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import olmlib from '../../../../lib/crypto/olmlib';
|
import olmlib from '../../../../lib/crypto/olmlib';
|
||||||
|
|
||||||
import sdk from '../../../..';
|
import sdk from '../../../..';
|
||||||
@@ -46,8 +45,8 @@ describe("SAS verification", function() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeAll(function() {
|
||||||
await Olm.init();
|
return Olm.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should error on an unexpected event", async function() {
|
it("should error on an unexpected event", async function() {
|
||||||
@@ -57,16 +56,15 @@ describe("SAS verification", function() {
|
|||||||
type: "es.inquisition",
|
type: "es.inquisition",
|
||||||
content: {},
|
content: {},
|
||||||
}));
|
}));
|
||||||
const spy = expect.createSpy();
|
const spy = jest.fn();
|
||||||
await sas.verify()
|
await sas.verify().catch(spy);
|
||||||
.catch(spy);
|
|
||||||
expect(spy).toHaveBeenCalled();
|
expect(spy).toHaveBeenCalled();
|
||||||
|
|
||||||
// Cancel the SAS for cleanup (we started a verification, so abort)
|
// Cancel the SAS for cleanup (we started a verification, so abort)
|
||||||
sas.cancel();
|
sas.cancel();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("verification", function() {
|
describe("verification", () => {
|
||||||
let alice;
|
let alice;
|
||||||
let bob;
|
let bob;
|
||||||
let aliceSasEvent;
|
let aliceSasEvent;
|
||||||
@@ -74,7 +72,7 @@ describe("SAS verification", function() {
|
|||||||
let aliceVerifier;
|
let aliceVerifier;
|
||||||
let bobPromise;
|
let bobPromise;
|
||||||
|
|
||||||
beforeEach(async function() {
|
beforeEach(async () => {
|
||||||
[alice, bob] = await makeTestClients(
|
[alice, bob] = await makeTestClients(
|
||||||
[
|
[
|
||||||
{userId: "@alice:example.com", deviceId: "Osborne2"},
|
{userId: "@alice:example.com", deviceId: "Osborne2"},
|
||||||
@@ -115,14 +113,14 @@ describe("SAS verification", function() {
|
|||||||
alice.client._crypto._deviceList.storeDevicesForUser(
|
alice.client._crypto._deviceList.storeDevicesForUser(
|
||||||
"@bob:example.com", BOB_DEVICES,
|
"@bob:example.com", BOB_DEVICES,
|
||||||
);
|
);
|
||||||
alice.downloadKeys = () => {
|
alice.client.downloadKeys = () => {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
bob.client._crypto._deviceList.storeDevicesForUser(
|
bob.client._crypto._deviceList.storeDevicesForUser(
|
||||||
"@alice:example.com", ALICE_DEVICES,
|
"@alice:example.com", ALICE_DEVICES,
|
||||||
);
|
);
|
||||||
bob.downloadKeys = () => {
|
bob.client.downloadKeys = () => {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -171,16 +169,22 @@ describe("SAS verification", function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
afterEach(async () => {
|
||||||
|
await Promise.all([
|
||||||
|
alice.stop(),
|
||||||
|
bob.stop(),
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it("should verify a key", async function() {
|
it("should verify a key", async () => {
|
||||||
let macMethod;
|
let macMethod;
|
||||||
const origSendToDevice = alice.client.sendToDevice;
|
const origSendToDevice = bob.client.sendToDevice.bind(bob.client);
|
||||||
bob.client.sendToDevice = function(type, map) {
|
bob.client.sendToDevice = function(type, map) {
|
||||||
if (type === "m.key.verification.accept") {
|
if (type === "m.key.verification.accept") {
|
||||||
macMethod = map[alice.client.getUserId()][alice.client.deviceId]
|
macMethod = map[alice.client.getUserId()][alice.client.deviceId]
|
||||||
.message_authentication_code;
|
.message_authentication_code;
|
||||||
}
|
}
|
||||||
return origSendToDevice.call(this, type, map);
|
return origSendToDevice(type, map);
|
||||||
};
|
};
|
||||||
|
|
||||||
alice.httpBackend.when('POST', '/keys/query').respond(200, {
|
alice.httpBackend.when('POST', '/keys/query').respond(200, {
|
||||||
@@ -215,12 +219,12 @@ describe("SAS verification", function() {
|
|||||||
expect(aliceDevice.isVerified()).toBeTruthy();
|
expect(aliceDevice.isVerified()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should be able to verify using the old MAC", async function() {
|
it("should be able to verify using the old MAC", async () => {
|
||||||
// pretend that Alice can only understand the old (incorrect) MAC,
|
// pretend that Alice can only understand the old (incorrect) MAC,
|
||||||
// and make sure that she can still verify with Bob
|
// and make sure that she can still verify with Bob
|
||||||
let macMethod;
|
let macMethod;
|
||||||
const origSendToDevice = alice.client.sendToDevice;
|
const aliceOrigSendToDevice = alice.client.sendToDevice.bind(alice.client);
|
||||||
alice.client.sendToDevice = function(type, map) {
|
alice.client.sendToDevice = (type, map) => {
|
||||||
if (type === "m.key.verification.start") {
|
if (type === "m.key.verification.start") {
|
||||||
// Note: this modifies not only the message that Bob
|
// Note: this modifies not only the message that Bob
|
||||||
// receives, but also the copy of the message that Alice
|
// receives, but also the copy of the message that Alice
|
||||||
@@ -230,14 +234,15 @@ describe("SAS verification", function() {
|
|||||||
map[bob.client.getUserId()][bob.client.deviceId]
|
map[bob.client.getUserId()][bob.client.deviceId]
|
||||||
.message_authentication_codes = ['hmac-sha256'];
|
.message_authentication_codes = ['hmac-sha256'];
|
||||||
}
|
}
|
||||||
return origSendToDevice.call(this, type, map);
|
return aliceOrigSendToDevice(type, map);
|
||||||
};
|
};
|
||||||
bob.client.sendToDevice = function(type, map) {
|
const bobOrigSendToDevice = bob.client.sendToDevice.bind(bob.client);
|
||||||
|
bob.client.sendToDevice = (type, map) => {
|
||||||
if (type === "m.key.verification.accept") {
|
if (type === "m.key.verification.accept") {
|
||||||
macMethod = map[alice.client.getUserId()][alice.client.deviceId]
|
macMethod = map[alice.client.getUserId()][alice.client.deviceId]
|
||||||
.message_authentication_code;
|
.message_authentication_code;
|
||||||
}
|
}
|
||||||
return origSendToDevice.call(this, type, map);
|
return bobOrigSendToDevice(type, map);
|
||||||
};
|
};
|
||||||
|
|
||||||
alice.httpBackend.when('POST', '/keys/query').respond(200, {
|
alice.httpBackend.when('POST', '/keys/query').respond(200, {
|
||||||
@@ -270,7 +275,7 @@ describe("SAS verification", function() {
|
|||||||
expect(aliceDevice.isVerified()).toBeTruthy();
|
expect(aliceDevice.isVerified()).toBeTruthy();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should verify a cross-signing key", async function() {
|
it("should verify a cross-signing key", async () => {
|
||||||
alice.httpBackend.when('POST', '/keys/device_signing/upload').respond(
|
alice.httpBackend.when('POST', '/keys/device_signing/upload').respond(
|
||||||
200, {},
|
200, {},
|
||||||
);
|
);
|
||||||
@@ -289,33 +294,17 @@ describe("SAS verification", function() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
alice.httpBackend.when('POST', '/keys/query').respond(200, {
|
|
||||||
failures: {},
|
|
||||||
device_keys: {
|
|
||||||
"@bob:example.com": BOB_DEVICES,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
bob.httpBackend.when('POST', '/keys/query').respond(200, {
|
|
||||||
failures: {},
|
|
||||||
device_keys: {
|
|
||||||
"@alice:example.com": ALICE_DEVICES,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const verifyProm = Promise.all([
|
const verifyProm = Promise.all([
|
||||||
aliceVerifier.verify(),
|
aliceVerifier.verify(),
|
||||||
bobPromise.then((verifier) => {
|
bobPromise.then((verifier) => {
|
||||||
bob.httpBackend.when(
|
bob.httpBackend.when(
|
||||||
'POST', '/keys/signatures/upload',
|
'POST', '/keys/signatures/upload',
|
||||||
).respond(200, {});
|
).respond(200, {});
|
||||||
bob.httpBackend.flush(undefined, 2);
|
bob.httpBackend.flush(undefined, 1, 2000);
|
||||||
return verifier.verify();
|
return verifier.verify();
|
||||||
}),
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await alice.httpBackend.flush(undefined, 1);
|
|
||||||
console.log("alice reqs flushed");
|
|
||||||
|
|
||||||
await verifyProm;
|
await verifyProm;
|
||||||
|
|
||||||
const bobDeviceTrust = alice.client.checkDeviceTrust(
|
const bobDeviceTrust = alice.client.checkDeviceTrust(
|
||||||
@@ -346,11 +335,11 @@ describe("SAS verification", function() {
|
|||||||
verificationMethods: [verificationMethods.SAS],
|
verificationMethods: [verificationMethods.SAS],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
alice.client.setDeviceVerified = expect.createSpy();
|
alice.client.setDeviceVerified = jest.fn();
|
||||||
alice.client.downloadKeys = () => {
|
alice.client.downloadKeys = () => {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
bob.client.setDeviceVerified = expect.createSpy();
|
bob.client.setDeviceVerified = jest.fn();
|
||||||
bob.client.downloadKeys = () => {
|
bob.client.downloadKeys = () => {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
@@ -368,8 +357,8 @@ describe("SAS verification", function() {
|
|||||||
verificationMethods.SAS, bob.client.getUserId(), bob.client.deviceId,
|
verificationMethods.SAS, bob.client.getUserId(), bob.client.deviceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const aliceSpy = expect.createSpy();
|
const aliceSpy = jest.fn();
|
||||||
const bobSpy = expect.createSpy();
|
const bobSpy = jest.fn();
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
aliceVerifier.verify().catch(aliceSpy),
|
aliceVerifier.verify().catch(aliceSpy),
|
||||||
bobPromise.then((verifier) => verifier.verify()).catch(bobSpy),
|
bobPromise.then((verifier) => verifier.verify()).catch(bobSpy),
|
||||||
@@ -377,9 +366,9 @@ describe("SAS verification", function() {
|
|||||||
expect(aliceSpy).toHaveBeenCalled();
|
expect(aliceSpy).toHaveBeenCalled();
|
||||||
expect(bobSpy).toHaveBeenCalled();
|
expect(bobSpy).toHaveBeenCalled();
|
||||||
expect(alice.client.setDeviceVerified)
|
expect(alice.client.setDeviceVerified)
|
||||||
.toNotHaveBeenCalled();
|
.not.toHaveBeenCalled();
|
||||||
expect(bob.client.setDeviceVerified)
|
expect(bob.client.setDeviceVerified)
|
||||||
.toNotHaveBeenCalled();
|
.not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("verification in DM", function() {
|
describe("verification in DM", function() {
|
||||||
@@ -401,7 +390,7 @@ describe("SAS verification", function() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
alice.client.setDeviceVerified = expect.createSpy();
|
alice.client.setDeviceVerified = jest.fn();
|
||||||
alice.client.getDeviceEd25519Key = () => {
|
alice.client.getDeviceEd25519Key = () => {
|
||||||
return "alice+base64+ed25519+key";
|
return "alice+base64+ed25519+key";
|
||||||
};
|
};
|
||||||
@@ -419,7 +408,7 @@ describe("SAS verification", function() {
|
|||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
};
|
};
|
||||||
|
|
||||||
bob.client.setDeviceVerified = expect.createSpy();
|
bob.client.setDeviceVerified = jest.fn();
|
||||||
bob.client.getStoredDevice = () => {
|
bob.client.getStoredDevice = () => {
|
||||||
return DeviceInfo.fromStorage(
|
return DeviceInfo.fromStorage(
|
||||||
{
|
{
|
||||||
@@ -445,7 +434,7 @@ describe("SAS verification", function() {
|
|||||||
const content = event.getContent();
|
const content = event.getContent();
|
||||||
if (event.getType() === "m.room.message"
|
if (event.getType() === "m.room.message"
|
||||||
&& content.msgtype === "m.key.verification.request") {
|
&& content.msgtype === "m.key.verification.request") {
|
||||||
expect(content.methods).toInclude(SAS.NAME);
|
expect(content.methods).toContain(SAS.NAME);
|
||||||
expect(content.to).toBe(bob.client.getUserId());
|
expect(content.to).toBe(bob.client.getUserId());
|
||||||
const verifier = bob.client.acceptVerificationDM(event, SAS.NAME);
|
const verifier = bob.client.acceptVerificationDM(event, SAS.NAME);
|
||||||
verifier.on("show_sas", (e) => {
|
verifier.on("show_sas", (e) => {
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ function mockRoomStates(timeline) {
|
|||||||
timeline._endState = utils.mock(sdk.RoomState, "endState");
|
timeline._endState = utils.mock(sdk.RoomState, "endState");
|
||||||
}
|
}
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("EventTimeline", function() {
|
describe("EventTimeline", function() {
|
||||||
const roomId = "!foo:bar";
|
const roomId = "!foo:bar";
|
||||||
const userA = "@alice:bar";
|
const userA = "@alice:bar";
|
||||||
@@ -18,8 +16,6 @@ describe("EventTimeline", function() {
|
|||||||
let timeline;
|
let timeline;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
|
|
||||||
// XXX: this is a horrid hack; should use sinon or something instead to mock
|
// XXX: this is a horrid hack; should use sinon or something instead to mock
|
||||||
const timelineSet = { room: { roomId: roomId }};
|
const timelineSet = { room: { roomId: roomId }};
|
||||||
timelineSet.room.getUnfilteredTimelineSet = function() {
|
timelineSet.room.getUnfilteredTimelineSet = function() {
|
||||||
@@ -78,7 +74,7 @@ describe("EventTimeline", function() {
|
|||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
timeline.initialiseState(state);
|
timeline.initialiseState(state);
|
||||||
}).toNotThrow();
|
}).not.toThrow();
|
||||||
timeline.addEvent(event, false);
|
timeline.addEvent(event, false);
|
||||||
expect(function() {
|
expect(function() {
|
||||||
timeline.initialiseState(state);
|
timeline.initialiseState(state);
|
||||||
@@ -121,7 +117,7 @@ describe("EventTimeline", function() {
|
|||||||
const next = {b: "b"};
|
const next = {b: "b"};
|
||||||
expect(function() {
|
expect(function() {
|
||||||
timeline.setNeighbouringTimeline(prev, EventTimeline.BACKWARDS);
|
timeline.setNeighbouringTimeline(prev, EventTimeline.BACKWARDS);
|
||||||
}).toNotThrow();
|
}).not.toThrow();
|
||||||
expect(timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS))
|
expect(timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS))
|
||||||
.toBe(prev);
|
.toBe(prev);
|
||||||
expect(function() {
|
expect(function() {
|
||||||
@@ -130,7 +126,7 @@ describe("EventTimeline", function() {
|
|||||||
|
|
||||||
expect(function() {
|
expect(function() {
|
||||||
timeline.setNeighbouringTimeline(next, EventTimeline.FORWARDS);
|
timeline.setNeighbouringTimeline(next, EventTimeline.FORWARDS);
|
||||||
}).toNotThrow();
|
}).not.toThrow();
|
||||||
expect(timeline.getNeighbouringTimeline(EventTimeline.FORWARDS))
|
expect(timeline.getNeighbouringTimeline(EventTimeline.FORWARDS))
|
||||||
.toBe(next);
|
.toBe(next);
|
||||||
expect(function() {
|
expect(function() {
|
||||||
@@ -187,14 +183,14 @@ describe("EventTimeline", function() {
|
|||||||
name: "Old Alice",
|
name: "Old Alice",
|
||||||
};
|
};
|
||||||
timeline.getState(EventTimeline.FORWARDS).getSentinelMember
|
timeline.getState(EventTimeline.FORWARDS).getSentinelMember
|
||||||
.andCall(function(uid) {
|
.mockImplementation(function(uid) {
|
||||||
if (uid === userA) {
|
if (uid === userA) {
|
||||||
return sentinel;
|
return sentinel;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
timeline.getState(EventTimeline.BACKWARDS).getSentinelMember
|
timeline.getState(EventTimeline.BACKWARDS).getSentinelMember
|
||||||
.andCall(function(uid) {
|
.mockImplementation(function(uid) {
|
||||||
if (uid === userA) {
|
if (uid === userA) {
|
||||||
return oldSentinel;
|
return oldSentinel;
|
||||||
}
|
}
|
||||||
@@ -229,14 +225,14 @@ describe("EventTimeline", function() {
|
|||||||
name: "Old Alice",
|
name: "Old Alice",
|
||||||
};
|
};
|
||||||
timeline.getState(EventTimeline.FORWARDS).getSentinelMember
|
timeline.getState(EventTimeline.FORWARDS).getSentinelMember
|
||||||
.andCall(function(uid) {
|
.mockImplementation(function(uid) {
|
||||||
if (uid === userA) {
|
if (uid === userA) {
|
||||||
return sentinel;
|
return sentinel;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
timeline.getState(EventTimeline.BACKWARDS).getSentinelMember
|
timeline.getState(EventTimeline.BACKWARDS).getSentinelMember
|
||||||
.andCall(function(uid) {
|
.mockImplementation(function(uid) {
|
||||||
if (uid === userA) {
|
if (uid === userA) {
|
||||||
return oldSentinel;
|
return oldSentinel;
|
||||||
}
|
}
|
||||||
@@ -281,7 +277,7 @@ describe("EventTimeline", function() {
|
|||||||
expect(events[1].forwardLooking).toBe(true);
|
expect(events[1].forwardLooking).toBe(true);
|
||||||
|
|
||||||
expect(timeline.getState(EventTimeline.BACKWARDS).setStateEvents).
|
expect(timeline.getState(EventTimeline.BACKWARDS).setStateEvents).
|
||||||
toNotHaveBeenCalled();
|
not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -311,7 +307,7 @@ describe("EventTimeline", function() {
|
|||||||
expect(events[1].forwardLooking).toBe(false);
|
expect(events[1].forwardLooking).toBe(false);
|
||||||
|
|
||||||
expect(timeline.getState(EventTimeline.FORWARDS).setStateEvents).
|
expect(timeline.getState(EventTimeline.FORWARDS).setStateEvents).
|
||||||
toNotHaveBeenCalled();
|
not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -17,17 +17,10 @@ limitations under the License.
|
|||||||
import sdk from '../..';
|
import sdk from '../..';
|
||||||
const MatrixEvent = sdk.MatrixEvent;
|
const MatrixEvent = sdk.MatrixEvent;
|
||||||
|
|
||||||
import testUtils from '../test-utils';
|
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
import logger from '../../src/logger';
|
import logger from '../../src/logger';
|
||||||
|
|
||||||
describe("MatrixEvent", () => {
|
describe("MatrixEvent", () => {
|
||||||
beforeEach(function() {
|
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
});
|
|
||||||
|
|
||||||
describe(".attemptDecryption", () => {
|
describe(".attemptDecryption", () => {
|
||||||
let encryptedEvent;
|
let encryptedEvent;
|
||||||
|
|
||||||
@@ -45,6 +38,7 @@ describe("MatrixEvent", () => {
|
|||||||
let callCount = 0;
|
let callCount = 0;
|
||||||
|
|
||||||
let prom2;
|
let prom2;
|
||||||
|
let prom2Fulfilled = false;
|
||||||
|
|
||||||
const crypto = {
|
const crypto = {
|
||||||
decryptEvent: function() {
|
decryptEvent: function() {
|
||||||
@@ -54,12 +48,13 @@ describe("MatrixEvent", () => {
|
|||||||
// schedule a second decryption attempt while
|
// schedule a second decryption attempt while
|
||||||
// the first one is still running.
|
// the first one is still running.
|
||||||
prom2 = encryptedEvent.attemptDecryption(crypto);
|
prom2 = encryptedEvent.attemptDecryption(crypto);
|
||||||
|
prom2.then(() => prom2Fulfilled = true);
|
||||||
|
|
||||||
const error = new Error("nope");
|
const error = new Error("nope");
|
||||||
error.name = 'DecryptionError';
|
error.name = 'DecryptionError';
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
} else {
|
} else {
|
||||||
expect(prom2.isFulfilled()).toBe(
|
expect(prom2Fulfilled).toBe(
|
||||||
false, 'second attemptDecryption resolved too soon');
|
false, 'second attemptDecryption resolved too soon');
|
||||||
|
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
import 'source-map-support/register';
|
import 'source-map-support/register';
|
||||||
const sdk = require("../..");
|
const sdk = require("../..");
|
||||||
const Filter = sdk.Filter;
|
const Filter = sdk.Filter;
|
||||||
const utils = require("../test-utils");
|
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("Filter", function() {
|
describe("Filter", function() {
|
||||||
const filterId = "f1lt3ring15g00d4ursoul";
|
const filterId = "f1lt3ring15g00d4ursoul";
|
||||||
@@ -12,7 +9,6 @@ describe("Filter", function() {
|
|||||||
let filter;
|
let filter;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
filter = new Filter(userId);
|
filter = new Filter(userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -18,12 +18,10 @@ limitations under the License.
|
|||||||
import 'source-map-support/register';
|
import 'source-map-support/register';
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
const sdk = require("../..");
|
const sdk = require("../..");
|
||||||
const utils = require("../test-utils");
|
|
||||||
|
|
||||||
const InteractiveAuth = sdk.InteractiveAuth;
|
const InteractiveAuth = sdk.InteractiveAuth;
|
||||||
const MatrixError = sdk.MatrixError;
|
const MatrixError = sdk.MatrixError;
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import logger from '../../src/logger';
|
import logger from '../../src/logger';
|
||||||
|
|
||||||
// Trivial client object to test interactive auth
|
// Trivial client object to test interactive auth
|
||||||
@@ -35,13 +33,9 @@ class FakeClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("InteractiveAuth", function() {
|
describe("InteractiveAuth", function() {
|
||||||
beforeEach(function() {
|
it("should start an auth stage and complete it", function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
const doRequest = jest.fn();
|
||||||
});
|
const stateUpdated = jest.fn();
|
||||||
|
|
||||||
it("should start an auth stage and complete it", function(done) {
|
|
||||||
const doRequest = expect.createSpy();
|
|
||||||
const stateUpdated = expect.createSpy();
|
|
||||||
|
|
||||||
const ia = new InteractiveAuth({
|
const ia = new InteractiveAuth({
|
||||||
matrixClient: new FakeClient(),
|
matrixClient: new FakeClient(),
|
||||||
@@ -64,7 +58,7 @@ describe("InteractiveAuth", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// first we expect a call here
|
// first we expect a call here
|
||||||
stateUpdated.andCall(function(stage) {
|
stateUpdated.mockImplementation(function(stage) {
|
||||||
logger.log('aaaa');
|
logger.log('aaaa');
|
||||||
expect(stage).toEqual("logintype");
|
expect(stage).toEqual("logintype");
|
||||||
ia.submitAuthDict({
|
ia.submitAuthDict({
|
||||||
@@ -75,7 +69,7 @@ describe("InteractiveAuth", function() {
|
|||||||
|
|
||||||
// .. which should trigger a call here
|
// .. which should trigger a call here
|
||||||
const requestRes = {"a": "b"};
|
const requestRes = {"a": "b"};
|
||||||
doRequest.andCall(function(authData) {
|
doRequest.mockImplementation(function(authData) {
|
||||||
logger.log('cccc');
|
logger.log('cccc');
|
||||||
expect(authData).toEqual({
|
expect(authData).toEqual({
|
||||||
session: "sessionId",
|
session: "sessionId",
|
||||||
@@ -85,16 +79,16 @@ describe("InteractiveAuth", function() {
|
|||||||
return Promise.resolve(requestRes);
|
return Promise.resolve(requestRes);
|
||||||
});
|
});
|
||||||
|
|
||||||
ia.attemptAuth().then(function(res) {
|
return ia.attemptAuth().then(function(res) {
|
||||||
expect(res).toBe(requestRes);
|
expect(res).toBe(requestRes);
|
||||||
expect(doRequest.calls.length).toEqual(1);
|
expect(doRequest).toBeCalledTimes(1);
|
||||||
expect(stateUpdated.calls.length).toEqual(1);
|
expect(stateUpdated).toBeCalledTimes(1);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should make a request if no authdata is provided", function(done) {
|
it("should make a request if no authdata is provided", function() {
|
||||||
const doRequest = expect.createSpy();
|
const doRequest = jest.fn();
|
||||||
const stateUpdated = expect.createSpy();
|
const stateUpdated = jest.fn();
|
||||||
|
|
||||||
const ia = new InteractiveAuth({
|
const ia = new InteractiveAuth({
|
||||||
matrixClient: new FakeClient(),
|
matrixClient: new FakeClient(),
|
||||||
@@ -106,7 +100,7 @@ describe("InteractiveAuth", function() {
|
|||||||
expect(ia.getStageParams("logintype")).toBe(undefined);
|
expect(ia.getStageParams("logintype")).toBe(undefined);
|
||||||
|
|
||||||
// first we expect a call to doRequest
|
// first we expect a call to doRequest
|
||||||
doRequest.andCall(function(authData) {
|
doRequest.mockImplementation(function(authData) {
|
||||||
logger.log("request1", authData);
|
logger.log("request1", authData);
|
||||||
expect(authData).toEqual({});
|
expect(authData).toEqual({});
|
||||||
const err = new MatrixError({
|
const err = new MatrixError({
|
||||||
@@ -124,7 +118,7 @@ describe("InteractiveAuth", function() {
|
|||||||
|
|
||||||
// .. which should be followed by a call to stateUpdated
|
// .. which should be followed by a call to stateUpdated
|
||||||
const requestRes = {"a": "b"};
|
const requestRes = {"a": "b"};
|
||||||
stateUpdated.andCall(function(stage) {
|
stateUpdated.mockImplementation(function(stage) {
|
||||||
expect(stage).toEqual("logintype");
|
expect(stage).toEqual("logintype");
|
||||||
expect(ia.getSessionId()).toEqual("sessionId");
|
expect(ia.getSessionId()).toEqual("sessionId");
|
||||||
expect(ia.getStageParams("logintype")).toEqual({
|
expect(ia.getStageParams("logintype")).toEqual({
|
||||||
@@ -132,7 +126,7 @@ describe("InteractiveAuth", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// submitAuthDict should trigger another call to doRequest
|
// submitAuthDict should trigger another call to doRequest
|
||||||
doRequest.andCall(function(authData) {
|
doRequest.mockImplementation(function(authData) {
|
||||||
logger.log("request2", authData);
|
logger.log("request2", authData);
|
||||||
expect(authData).toEqual({
|
expect(authData).toEqual({
|
||||||
session: "sessionId",
|
session: "sessionId",
|
||||||
@@ -148,10 +142,10 @@ describe("InteractiveAuth", function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
ia.attemptAuth().then(function(res) {
|
return ia.attemptAuth().then(function(res) {
|
||||||
expect(res).toBe(requestRes);
|
expect(res).toBe(requestRes);
|
||||||
expect(doRequest.calls.length).toEqual(2);
|
expect(doRequest).toBeCalledTimes(2);
|
||||||
expect(stateUpdated.calls.length).toEqual(1);
|
expect(stateUpdated).toBeCalledTimes(1);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import expect from 'expect';
|
|
||||||
import TestClient from '../TestClient';
|
import TestClient from '../TestClient';
|
||||||
|
|
||||||
describe('Login request', function() {
|
describe('Login request', function() {
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ import 'source-map-support/register';
|
|||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
const sdk = require("../..");
|
const sdk = require("../..");
|
||||||
const MatrixClient = sdk.MatrixClient;
|
const MatrixClient = sdk.MatrixClient;
|
||||||
const utils = require("../test-utils");
|
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
import lolex from 'lolex';
|
|
||||||
import logger from '../../src/logger';
|
import logger from '../../src/logger';
|
||||||
|
|
||||||
|
jest.useFakeTimers();
|
||||||
|
|
||||||
describe("MatrixClient", function() {
|
describe("MatrixClient", function() {
|
||||||
const userId = "@alice:bar";
|
const userId = "@alice:bar";
|
||||||
const identityServerUrl = "https://identity.server";
|
const identityServerUrl = "https://identity.server";
|
||||||
@@ -16,7 +15,6 @@ describe("MatrixClient", function() {
|
|||||||
let client;
|
let client;
|
||||||
let store;
|
let store;
|
||||||
let scheduler;
|
let scheduler;
|
||||||
let clock;
|
|
||||||
|
|
||||||
const KEEP_ALIVE_PATH = "/_matrix/client/versions";
|
const KEEP_ALIVE_PATH = "/_matrix/client/versions";
|
||||||
|
|
||||||
@@ -125,24 +123,22 @@ describe("MatrixClient", function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
clock = lolex.install();
|
|
||||||
scheduler = [
|
scheduler = [
|
||||||
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
|
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
|
||||||
"setProcessFunction",
|
"setProcessFunction",
|
||||||
].reduce((r, k) => { r[k] = expect.createSpy(); return r; }, {});
|
].reduce((r, k) => { r[k] = jest.fn(); return r; }, {});
|
||||||
store = [
|
store = [
|
||||||
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
|
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
|
||||||
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom", "storeUser",
|
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom", "storeUser",
|
||||||
"getFilterIdByName", "setFilterIdByName", "getFilter", "storeFilter",
|
"getFilterIdByName", "setFilterIdByName", "getFilter", "storeFilter",
|
||||||
"getSyncAccumulator", "startup", "deleteAllData",
|
"getSyncAccumulator", "startup", "deleteAllData",
|
||||||
].reduce((r, k) => { r[k] = expect.createSpy(); return r; }, {});
|
].reduce((r, k) => { r[k] = jest.fn(); return r; }, {});
|
||||||
store.getSavedSync = expect.createSpy().andReturn(Promise.resolve(null));
|
store.getSavedSync = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
store.getSavedSyncToken = expect.createSpy().andReturn(Promise.resolve(null));
|
store.getSavedSyncToken = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
store.setSyncData = expect.createSpy().andReturn(Promise.resolve(null));
|
store.setSyncData = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
store.getClientOptions = expect.createSpy().andReturn(Promise.resolve(null));
|
store.getClientOptions = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
store.storeClientOptions = expect.createSpy().andReturn(Promise.resolve(null));
|
store.storeClientOptions = jest.fn().mockReturnValue(Promise.resolve(null));
|
||||||
store.isNewlyCreated = expect.createSpy().andReturn(Promise.resolve(true));
|
store.isNewlyCreated = jest.fn().mockReturnValue(Promise.resolve(true));
|
||||||
client = new MatrixClient({
|
client = new MatrixClient({
|
||||||
baseUrl: "https://my.home.server",
|
baseUrl: "https://my.home.server",
|
||||||
idBaseUrl: identityServerUrl,
|
idBaseUrl: identityServerUrl,
|
||||||
@@ -155,9 +151,9 @@ describe("MatrixClient", function() {
|
|||||||
// FIXME: We shouldn't be yanking _http like this.
|
// FIXME: We shouldn't be yanking _http like this.
|
||||||
client._http = [
|
client._http = [
|
||||||
"authedRequest", "getContentUri", "request", "uploadContent",
|
"authedRequest", "getContentUri", "request", "uploadContent",
|
||||||
].reduce((r, k) => { r[k] = expect.createSpy(); return r; }, {});
|
].reduce((r, k) => { r[k] = jest.fn(); return r; }, {});
|
||||||
client._http.authedRequest.andCall(httpReq);
|
client._http.authedRequest.mockImplementation(httpReq);
|
||||||
client._http.request.andCall(httpReq);
|
client._http.request.mockImplementation(httpReq);
|
||||||
|
|
||||||
// set reasonable working defaults
|
// set reasonable working defaults
|
||||||
acceptKeepalives = true;
|
acceptKeepalives = true;
|
||||||
@@ -169,13 +165,12 @@ describe("MatrixClient", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
clock.uninstall();
|
|
||||||
// need to re-stub the requests with NOPs because there are no guarantees
|
// need to re-stub the requests with NOPs because there are no guarantees
|
||||||
// clients from previous tests will be GC'd before the next test. This
|
// clients from previous tests will be GC'd before the next test. This
|
||||||
// means they may call /events and then fail an expect() which will fail
|
// means they may call /events and then fail an expect() which will fail
|
||||||
// a DIFFERENT test (pollution between tests!) - we return unresolved
|
// a DIFFERENT test (pollution between tests!) - we return unresolved
|
||||||
// promises to stop the client from continuing to run.
|
// promises to stop the client from continuing to run.
|
||||||
client._http.authedRequest.andCall(function() {
|
client._http.authedRequest.mockImplementation(function() {
|
||||||
return Promise.defer().promise;
|
return Promise.defer().promise;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -185,10 +180,10 @@ describe("MatrixClient", function() {
|
|||||||
httpLookups.push(PUSH_RULES_RESPONSE);
|
httpLookups.push(PUSH_RULES_RESPONSE);
|
||||||
httpLookups.push(SYNC_RESPONSE);
|
httpLookups.push(SYNC_RESPONSE);
|
||||||
const filterId = "ehfewf";
|
const filterId = "ehfewf";
|
||||||
store.getFilterIdByName.andReturn(filterId);
|
store.getFilterIdByName.mockReturnValue(filterId);
|
||||||
const filter = new sdk.Filter(0, filterId);
|
const filter = new sdk.Filter(0, filterId);
|
||||||
filter.setDefinition({"room": {"timeline": {"limit": 8}}});
|
filter.setDefinition({"room": {"timeline": {"limit": 8}}});
|
||||||
store.getFilter.andReturn(filter);
|
store.getFilter.mockReturnValue(filter);
|
||||||
const syncPromise = new Promise((resolve, reject) => {
|
const syncPromise = new Promise((resolve, reject) => {
|
||||||
client.on("sync", function syncListener(state) {
|
client.on("sync", function syncListener(state) {
|
||||||
if (state === "SYNCING") {
|
if (state === "SYNCING") {
|
||||||
@@ -249,7 +244,7 @@ describe("MatrixClient", function() {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
httpLookups.push(FILTER_RESPONSE);
|
httpLookups.push(FILTER_RESPONSE);
|
||||||
store.getFilterIdByName.andReturn(invalidFilterId);
|
store.getFilterIdByName.mockReturnValue(invalidFilterId);
|
||||||
|
|
||||||
const filterName = getFilterName(client.credentials.userId);
|
const filterName = getFilterName(client.credentials.userId);
|
||||||
client.store.setFilterIdByName(filterName, invalidFilterId);
|
client.store.setFilterIdByName(filterName, invalidFilterId);
|
||||||
@@ -281,7 +276,7 @@ describe("MatrixClient", function() {
|
|||||||
if (state === "ERROR" && httpLookups.length > 0) {
|
if (state === "ERROR" && httpLookups.length > 0) {
|
||||||
expect(httpLookups.length).toEqual(2);
|
expect(httpLookups.length).toEqual(2);
|
||||||
expect(client.retryImmediately()).toBe(true);
|
expect(client.retryImmediately()).toBe(true);
|
||||||
clock.tick(1);
|
jest.advanceTimersByTime(1);
|
||||||
} else if (state === "PREPARED" && httpLookups.length === 0) {
|
} else if (state === "PREPARED" && httpLookups.length === 0) {
|
||||||
client.removeListener("sync", syncListener);
|
client.removeListener("sync", syncListener);
|
||||||
done();
|
done();
|
||||||
@@ -307,9 +302,9 @@ describe("MatrixClient", function() {
|
|||||||
expect(client.retryImmediately()).toBe(
|
expect(client.retryImmediately()).toBe(
|
||||||
true, "retryImmediately returned false",
|
true, "retryImmediately returned false",
|
||||||
);
|
);
|
||||||
clock.tick(1);
|
jest.advanceTimersByTime(1);
|
||||||
} else if (state === "RECONNECTING" && httpLookups.length > 0) {
|
} else if (state === "RECONNECTING" && httpLookups.length > 0) {
|
||||||
clock.tick(10000);
|
jest.advanceTimersByTime(10000);
|
||||||
} else if (state === "SYNCING" && httpLookups.length === 0) {
|
} else if (state === "SYNCING" && httpLookups.length === 0) {
|
||||||
client.removeListener("sync", syncListener);
|
client.removeListener("sync", syncListener);
|
||||||
done();
|
done();
|
||||||
@@ -331,7 +326,7 @@ describe("MatrixClient", function() {
|
|||||||
if (state === "ERROR" && httpLookups.length > 0) {
|
if (state === "ERROR" && httpLookups.length > 0) {
|
||||||
expect(httpLookups.length).toEqual(3);
|
expect(httpLookups.length).toEqual(3);
|
||||||
expect(client.retryImmediately()).toBe(true);
|
expect(client.retryImmediately()).toBe(true);
|
||||||
clock.tick(1);
|
jest.advanceTimersByTime(1);
|
||||||
} else if (state === "PREPARED" && httpLookups.length === 0) {
|
} else if (state === "PREPARED" && httpLookups.length === 0) {
|
||||||
client.removeListener("sync", syncListener);
|
client.removeListener("sync", syncListener);
|
||||||
done();
|
done();
|
||||||
@@ -362,7 +357,7 @@ describe("MatrixClient", function() {
|
|||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
// standard retry time is 5 to 10 seconds
|
// standard retry time is 5 to 10 seconds
|
||||||
clock.tick(10000);
|
jest.advanceTimersByTime(10000);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,6 @@ import 'source-map-support/register';
|
|||||||
const PushProcessor = require("../../lib/pushprocessor");
|
const PushProcessor = require("../../lib/pushprocessor");
|
||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe('NotificationService', function() {
|
describe('NotificationService', function() {
|
||||||
const testUserId = "@ali:matrix.org";
|
const testUserId = "@ali:matrix.org";
|
||||||
const testDisplayName = "Alice M";
|
const testDisplayName = "Alice M";
|
||||||
|
|||||||
@@ -1,53 +1,46 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import 'source-map-support/register';
|
import 'source-map-support/register';
|
||||||
const callbacks = require("../../lib/realtime-callbacks");
|
const callbacks = require("../../src/realtime-callbacks");
|
||||||
const testUtils = require("../test-utils.js");
|
|
||||||
|
|
||||||
import expect from 'expect';
|
let wallTime = 1234567890;
|
||||||
import lolex from 'lolex';
|
jest.useFakeTimers();
|
||||||
|
|
||||||
describe("realtime-callbacks", function() {
|
describe("realtime-callbacks", function() {
|
||||||
let clock;
|
|
||||||
|
|
||||||
function tick(millis) {
|
function tick(millis) {
|
||||||
clock.tick(millis);
|
wallTime += millis;
|
||||||
|
jest.advanceTimersByTime(millis);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
callbacks.setNow(() => wallTime);
|
||||||
clock = lolex.install();
|
|
||||||
const fakeDate = clock.Date;
|
|
||||||
callbacks.setNow(fakeDate.now.bind(fakeDate));
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
callbacks.setNow();
|
callbacks.setNow();
|
||||||
clock.uninstall();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("setTimeout", function() {
|
describe("setTimeout", function() {
|
||||||
it("should call the callback after the timeout", function() {
|
it("should call the callback after the timeout", function() {
|
||||||
const callback = expect.createSpy();
|
const callback = jest.fn();
|
||||||
callbacks.setTimeout(callback, 100);
|
callbacks.setTimeout(callback, 100);
|
||||||
|
|
||||||
expect(callback).toNotHaveBeenCalled();
|
expect(callback).not.toHaveBeenCalled();
|
||||||
tick(100);
|
tick(100);
|
||||||
expect(callback).toHaveBeenCalled();
|
expect(callback).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("should default to a zero timeout", function() {
|
it("should default to a zero timeout", function() {
|
||||||
const callback = expect.createSpy();
|
const callback = jest.fn();
|
||||||
callbacks.setTimeout(callback);
|
callbacks.setTimeout(callback);
|
||||||
|
|
||||||
expect(callback).toNotHaveBeenCalled();
|
expect(callback).not.toHaveBeenCalled();
|
||||||
tick(0);
|
tick(0);
|
||||||
expect(callback).toHaveBeenCalled();
|
expect(callback).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should pass any parameters to the callback", function() {
|
it("should pass any parameters to the callback", function() {
|
||||||
const callback = expect.createSpy();
|
const callback = jest.fn();
|
||||||
callbacks.setTimeout(callback, 0, "a", "b", "c");
|
callbacks.setTimeout(callback, 0, "a", "b", "c");
|
||||||
tick(0);
|
tick(0);
|
||||||
expect(callback).toHaveBeenCalledWith("a", "b", "c");
|
expect(callback).toHaveBeenCalledWith("a", "b", "c");
|
||||||
@@ -66,10 +59,10 @@ describe("realtime-callbacks", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should handle timeouts of several seconds", function() {
|
it("should handle timeouts of several seconds", function() {
|
||||||
const callback = expect.createSpy();
|
const callback = jest.fn();
|
||||||
callbacks.setTimeout(callback, 2000);
|
callbacks.setTimeout(callback, 2000);
|
||||||
|
|
||||||
expect(callback).toNotHaveBeenCalled();
|
expect(callback).not.toHaveBeenCalled();
|
||||||
for (let i = 0; i < 4; i++) {
|
for (let i = 0; i < 4; i++) {
|
||||||
tick(500);
|
tick(500);
|
||||||
}
|
}
|
||||||
@@ -77,24 +70,24 @@ describe("realtime-callbacks", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should call multiple callbacks in the right order", function() {
|
it("should call multiple callbacks in the right order", function() {
|
||||||
const callback1 = expect.createSpy();
|
const callback1 = jest.fn();
|
||||||
const callback2 = expect.createSpy();
|
const callback2 = jest.fn();
|
||||||
const callback3 = expect.createSpy();
|
const callback3 = jest.fn();
|
||||||
callbacks.setTimeout(callback2, 200);
|
callbacks.setTimeout(callback2, 200);
|
||||||
callbacks.setTimeout(callback1, 100);
|
callbacks.setTimeout(callback1, 100);
|
||||||
callbacks.setTimeout(callback3, 300);
|
callbacks.setTimeout(callback3, 300);
|
||||||
|
|
||||||
expect(callback1).toNotHaveBeenCalled();
|
expect(callback1).not.toHaveBeenCalled();
|
||||||
expect(callback2).toNotHaveBeenCalled();
|
expect(callback2).not.toHaveBeenCalled();
|
||||||
expect(callback3).toNotHaveBeenCalled();
|
expect(callback3).not.toHaveBeenCalled();
|
||||||
tick(100);
|
tick(100);
|
||||||
expect(callback1).toHaveBeenCalled();
|
expect(callback1).toHaveBeenCalled();
|
||||||
expect(callback2).toNotHaveBeenCalled();
|
expect(callback2).not.toHaveBeenCalled();
|
||||||
expect(callback3).toNotHaveBeenCalled();
|
expect(callback3).not.toHaveBeenCalled();
|
||||||
tick(100);
|
tick(100);
|
||||||
expect(callback1).toHaveBeenCalled();
|
expect(callback1).toHaveBeenCalled();
|
||||||
expect(callback2).toHaveBeenCalled();
|
expect(callback2).toHaveBeenCalled();
|
||||||
expect(callback3).toNotHaveBeenCalled();
|
expect(callback3).not.toHaveBeenCalled();
|
||||||
tick(100);
|
tick(100);
|
||||||
expect(callback1).toHaveBeenCalled();
|
expect(callback1).toHaveBeenCalled();
|
||||||
expect(callback2).toHaveBeenCalled();
|
expect(callback2).toHaveBeenCalled();
|
||||||
@@ -102,35 +95,34 @@ describe("realtime-callbacks", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should treat -ve timeouts the same as a zero timeout", function() {
|
it("should treat -ve timeouts the same as a zero timeout", function() {
|
||||||
const callback1 = expect.createSpy();
|
const callback1 = jest.fn();
|
||||||
const callback2 = expect.createSpy();
|
const callback2 = jest.fn();
|
||||||
|
|
||||||
// check that cb1 is called before cb2
|
// check that cb1 is called before cb2
|
||||||
callback1.andCall(function() {
|
callback1.mockImplementation(function() {
|
||||||
expect(callback2).toNotHaveBeenCalled();
|
expect(callback2).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
callbacks.setTimeout(callback1);
|
callbacks.setTimeout(callback1);
|
||||||
callbacks.setTimeout(callback2, -100);
|
callbacks.setTimeout(callback2, -100);
|
||||||
|
|
||||||
expect(callback1).toNotHaveBeenCalled();
|
expect(callback1).not.toHaveBeenCalled();
|
||||||
expect(callback2).toNotHaveBeenCalled();
|
expect(callback2).not.toHaveBeenCalled();
|
||||||
tick(0);
|
tick(0);
|
||||||
expect(callback1).toHaveBeenCalled();
|
expect(callback1).toHaveBeenCalled();
|
||||||
expect(callback2).toHaveBeenCalled();
|
expect(callback2).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not get confused by chained calls", function() {
|
it("should not get confused by chained calls", function() {
|
||||||
const callback2 = expect.createSpy();
|
const callback2 = jest.fn();
|
||||||
const callback1 = expect.createSpy();
|
const callback1 = jest.fn(function() {
|
||||||
callback1.andCall(function() {
|
|
||||||
callbacks.setTimeout(callback2, 0);
|
callbacks.setTimeout(callback2, 0);
|
||||||
expect(callback2).toNotHaveBeenCalled();
|
expect(callback2).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
callbacks.setTimeout(callback1);
|
callbacks.setTimeout(callback1);
|
||||||
expect(callback1).toNotHaveBeenCalled();
|
expect(callback1).not.toHaveBeenCalled();
|
||||||
expect(callback2).toNotHaveBeenCalled();
|
expect(callback2).not.toHaveBeenCalled();
|
||||||
tick(0);
|
tick(0);
|
||||||
expect(callback1).toHaveBeenCalled();
|
expect(callback1).toHaveBeenCalled();
|
||||||
// the fake timer won't actually run callbacks registered during
|
// the fake timer won't actually run callbacks registered during
|
||||||
@@ -140,16 +132,15 @@ describe("realtime-callbacks", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should be immune to exceptions", function() {
|
it("should be immune to exceptions", function() {
|
||||||
const callback1 = expect.createSpy();
|
const callback1 = jest.fn(function() {
|
||||||
callback1.andCall(function() {
|
|
||||||
throw new Error("prepare to die");
|
throw new Error("prepare to die");
|
||||||
});
|
});
|
||||||
const callback2 = expect.createSpy();
|
const callback2 = jest.fn();
|
||||||
callbacks.setTimeout(callback1, 0);
|
callbacks.setTimeout(callback1, 0);
|
||||||
callbacks.setTimeout(callback2, 0);
|
callbacks.setTimeout(callback2, 0);
|
||||||
|
|
||||||
expect(callback1).toNotHaveBeenCalled();
|
expect(callback1).not.toHaveBeenCalled();
|
||||||
expect(callback2).toNotHaveBeenCalled();
|
expect(callback2).not.toHaveBeenCalled();
|
||||||
tick(0);
|
tick(0);
|
||||||
expect(callback1).toHaveBeenCalled();
|
expect(callback1).toHaveBeenCalled();
|
||||||
expect(callback2).toHaveBeenCalled();
|
expect(callback2).toHaveBeenCalled();
|
||||||
@@ -158,16 +149,16 @@ describe("realtime-callbacks", function() {
|
|||||||
|
|
||||||
describe("cancelTimeout", function() {
|
describe("cancelTimeout", function() {
|
||||||
it("should cancel a pending timeout", function() {
|
it("should cancel a pending timeout", function() {
|
||||||
const callback = expect.createSpy();
|
const callback = jest.fn();
|
||||||
const k = callbacks.setTimeout(callback);
|
const k = callbacks.setTimeout(callback);
|
||||||
callbacks.clearTimeout(k);
|
callbacks.clearTimeout(k);
|
||||||
tick(0);
|
tick(0);
|
||||||
expect(callback).toNotHaveBeenCalled();
|
expect(callback).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not affect sooner timeouts", function() {
|
it("should not affect sooner timeouts", function() {
|
||||||
const callback1 = expect.createSpy();
|
const callback1 = jest.fn();
|
||||||
const callback2 = expect.createSpy();
|
const callback2 = jest.fn();
|
||||||
|
|
||||||
callbacks.setTimeout(callback1, 100);
|
callbacks.setTimeout(callback1, 100);
|
||||||
const k = callbacks.setTimeout(callback2, 200);
|
const k = callbacks.setTimeout(callback2, 200);
|
||||||
@@ -175,10 +166,10 @@ describe("realtime-callbacks", function() {
|
|||||||
|
|
||||||
tick(100);
|
tick(100);
|
||||||
expect(callback1).toHaveBeenCalled();
|
expect(callback1).toHaveBeenCalled();
|
||||||
expect(callback2).toNotHaveBeenCalled();
|
expect(callback2).not.toHaveBeenCalled();
|
||||||
|
|
||||||
tick(150);
|
tick(150);
|
||||||
expect(callback2).toNotHaveBeenCalled();
|
expect(callback2).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ const sdk = require("../..");
|
|||||||
const RoomMember = sdk.RoomMember;
|
const RoomMember = sdk.RoomMember;
|
||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("RoomMember", function() {
|
describe("RoomMember", function() {
|
||||||
const roomId = "!foo:bar";
|
const roomId = "!foo:bar";
|
||||||
const userA = "@alice:bar";
|
const userA = "@alice:bar";
|
||||||
@@ -14,7 +12,6 @@ describe("RoomMember", function() {
|
|||||||
let member;
|
let member;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
member = new RoomMember(roomId, userA);
|
member = new RoomMember(roomId, userA);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -36,7 +33,7 @@ describe("RoomMember", function() {
|
|||||||
const url = member.getAvatarUrl(hsUrl);
|
const url = member.getAvatarUrl(hsUrl);
|
||||||
// we don't care about how the mxc->http conversion is done, other
|
// we don't care about how the mxc->http conversion is done, other
|
||||||
// than it contains the mxc body.
|
// than it contains the mxc body.
|
||||||
expect(url.indexOf("flibble/wibble")).toNotEqual(-1);
|
expect(url.indexOf("flibble/wibble")).not.toEqual(-1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return an identicon HTTP URL if allowDefault was set and there " +
|
it("should return an identicon HTTP URL if allowDefault was set and there " +
|
||||||
@@ -255,9 +252,9 @@ describe("RoomMember", function() {
|
|||||||
member.setMembershipEvent(joinEvent);
|
member.setMembershipEvent(joinEvent);
|
||||||
expect(member.name).toEqual("Alice"); // prefer displayname
|
expect(member.name).toEqual("Alice"); // prefer displayname
|
||||||
member.setMembershipEvent(joinEvent, roomState);
|
member.setMembershipEvent(joinEvent, roomState);
|
||||||
expect(member.name).toNotEqual("Alice"); // it should disambig.
|
expect(member.name).not.toEqual("Alice"); // it should disambig.
|
||||||
// user_id should be there somewhere
|
// user_id should be there somewhere
|
||||||
expect(member.name.indexOf(userA)).toNotEqual(-1);
|
expect(member.name.indexOf(userA)).not.toEqual(-1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should emit 'RoomMember.membership' if the membership changes", function() {
|
it("should emit 'RoomMember.membership' if the membership changes", function() {
|
||||||
@@ -328,9 +325,9 @@ describe("RoomMember", function() {
|
|||||||
};
|
};
|
||||||
expect(member.name).toEqual(userA); // default = user_id
|
expect(member.name).toEqual(userA); // default = user_id
|
||||||
member.setMembershipEvent(joinEvent, roomState);
|
member.setMembershipEvent(joinEvent, roomState);
|
||||||
expect(member.name).toNotEqual("Alíce"); // it should disambig.
|
expect(member.name).not.toEqual("Alíce"); // it should disambig.
|
||||||
// user_id should be there somewhere
|
// user_id should be there somewhere
|
||||||
expect(member.name.indexOf(userA)).toNotEqual(-1);
|
expect(member.name.indexOf(userA)).not.toEqual(-1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ const RoomState = sdk.RoomState;
|
|||||||
const RoomMember = sdk.RoomMember;
|
const RoomMember = sdk.RoomMember;
|
||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("RoomState", function() {
|
describe("RoomState", function() {
|
||||||
const roomId = "!foo:bar";
|
const roomId = "!foo:bar";
|
||||||
const userA = "@alice:bar";
|
const userA = "@alice:bar";
|
||||||
@@ -17,7 +15,6 @@ describe("RoomState", function() {
|
|||||||
let state;
|
let state;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
state = new RoomState(roomId);
|
state = new RoomState(roomId);
|
||||||
state.setStateEvents([
|
state.setStateEvents([
|
||||||
utils.mkMembership({ // userA joined
|
utils.mkMembership({ // userA joined
|
||||||
@@ -49,8 +46,8 @@ describe("RoomState", function() {
|
|||||||
const members = state.getMembers();
|
const members = state.getMembers();
|
||||||
expect(members.length).toEqual(2);
|
expect(members.length).toEqual(2);
|
||||||
// ordering unimportant
|
// ordering unimportant
|
||||||
expect([userA, userB].indexOf(members[0].userId)).toNotEqual(-1);
|
expect([userA, userB].indexOf(members[0].userId)).not.toEqual(-1);
|
||||||
expect([userA, userB].indexOf(members[1].userId)).toNotEqual(-1);
|
expect([userA, userB].indexOf(members[1].userId)).not.toEqual(-1);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -120,8 +117,8 @@ describe("RoomState", function() {
|
|||||||
const events = state.getStateEvents("m.room.member");
|
const events = state.getStateEvents("m.room.member");
|
||||||
expect(events.length).toEqual(2);
|
expect(events.length).toEqual(2);
|
||||||
// ordering unimportant
|
// ordering unimportant
|
||||||
expect([userA, userB].indexOf(events[0].getStateKey())).toNotEqual(-1);
|
expect([userA, userB].indexOf(events[0].getStateKey())).not.toEqual(-1);
|
||||||
expect([userA, userB].indexOf(events[1].getStateKey())).toNotEqual(-1);
|
expect([userA, userB].indexOf(events[1].getStateKey())).not.toEqual(-1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return a single MatrixEvent if a state_key was specified",
|
it("should return a single MatrixEvent if a state_key was specified",
|
||||||
@@ -258,7 +255,7 @@ describe("RoomState", function() {
|
|||||||
});
|
});
|
||||||
state.setStateEvents([memberEvent]);
|
state.setStateEvents([memberEvent]);
|
||||||
|
|
||||||
expect(state.members[userA].setMembershipEvent).toNotHaveBeenCalled();
|
expect(state.members[userA].setMembershipEvent).not.toHaveBeenCalled();
|
||||||
expect(state.members[userB].setMembershipEvent).toHaveBeenCalledWith(
|
expect(state.members[userB].setMembershipEvent).toHaveBeenCalledWith(
|
||||||
memberEvent, state,
|
memberEvent, state,
|
||||||
);
|
);
|
||||||
@@ -306,7 +303,7 @@ describe("RoomState", function() {
|
|||||||
state.markOutOfBandMembersStarted();
|
state.markOutOfBandMembersStarted();
|
||||||
state.setOutOfBandMembers([oobMemberEvent]);
|
state.setOutOfBandMembers([oobMemberEvent]);
|
||||||
const memberA = state.getMember(userA);
|
const memberA = state.getMember(userA);
|
||||||
expect(memberA.events.member.getId()).toNotEqual(oobMemberEvent.getId());
|
expect(memberA.events.member.getId()).not.toEqual(oobMemberEvent.getId());
|
||||||
expect(memberA.isOutOfBand()).toEqual(false);
|
expect(memberA.isOutOfBand()).toEqual(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ const EventStatus = sdk.EventStatus;
|
|||||||
const EventTimeline = sdk.EventTimeline;
|
const EventTimeline = sdk.EventTimeline;
|
||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("Room", function() {
|
describe("Room", function() {
|
||||||
const roomId = "!foo:bar";
|
const roomId = "!foo:bar";
|
||||||
const userA = "@alice:bar";
|
const userA = "@alice:bar";
|
||||||
@@ -19,7 +17,6 @@ describe("Room", function() {
|
|||||||
let room;
|
let room;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
room = new Room(roomId);
|
room = new Room(roomId);
|
||||||
// mock RoomStates
|
// mock RoomStates
|
||||||
room.oldState = room.getLiveTimeline()._startState =
|
room.oldState = room.getLiveTimeline()._startState =
|
||||||
@@ -32,7 +29,7 @@ describe("Room", function() {
|
|||||||
const hsUrl = "https://my.home.server";
|
const hsUrl = "https://my.home.server";
|
||||||
|
|
||||||
it("should return the URL from m.room.avatar preferentially", function() {
|
it("should return the URL from m.room.avatar preferentially", function() {
|
||||||
room.currentState.getStateEvents.andCall(function(type, key) {
|
room.currentState.getStateEvents.mockImplementation(function(type, key) {
|
||||||
if (type === "m.room.avatar" && key === "") {
|
if (type === "m.room.avatar" && key === "") {
|
||||||
return utils.mkEvent({
|
return utils.mkEvent({
|
||||||
event: true,
|
event: true,
|
||||||
@@ -49,7 +46,7 @@ describe("Room", function() {
|
|||||||
const url = room.getAvatarUrl(hsUrl);
|
const url = room.getAvatarUrl(hsUrl);
|
||||||
// we don't care about how the mxc->http conversion is done, other
|
// we don't care about how the mxc->http conversion is done, other
|
||||||
// than it contains the mxc body.
|
// than it contains the mxc body.
|
||||||
expect(url.indexOf("flibble/wibble")).toNotEqual(-1);
|
expect(url.indexOf("flibble/wibble")).not.toEqual(-1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return an identicon HTTP URL if allowDefault was set and there " +
|
it("should return an identicon HTTP URL if allowDefault was set and there " +
|
||||||
@@ -67,13 +64,13 @@ describe("Room", function() {
|
|||||||
|
|
||||||
describe("getMember", function() {
|
describe("getMember", function() {
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
room.currentState.getMember.andCall(function(userId) {
|
room.currentState.getMember.mockImplementation(function(userId) {
|
||||||
return {
|
return {
|
||||||
"@alice:bar": {
|
"@alice:bar": {
|
||||||
userId: userA,
|
userId: userA,
|
||||||
roomId: roomId,
|
roomId: roomId,
|
||||||
},
|
},
|
||||||
}[userId];
|
}[userId] || null;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,7 +79,7 @@ describe("Room", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should return the member from current state", function() {
|
it("should return the member from current state", function() {
|
||||||
expect(room.getMember(userA)).toNotEqual(null);
|
expect(room.getMember(userA)).not.toEqual(null);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -174,7 +171,7 @@ describe("Room", function() {
|
|||||||
);
|
);
|
||||||
expect(events[0].forwardLooking).toBe(true);
|
expect(events[0].forwardLooking).toBe(true);
|
||||||
expect(events[1].forwardLooking).toBe(true);
|
expect(events[1].forwardLooking).toBe(true);
|
||||||
expect(room.oldState.setStateEvents).toNotHaveBeenCalled();
|
expect(room.oldState.setStateEvents).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should synthesize read receipts for the senders of events", function() {
|
it("should synthesize read receipts for the senders of events", function() {
|
||||||
@@ -183,7 +180,7 @@ describe("Room", function() {
|
|||||||
membership: "join",
|
membership: "join",
|
||||||
name: "Alice",
|
name: "Alice",
|
||||||
};
|
};
|
||||||
room.currentState.getSentinelMember.andCall(function(uid) {
|
room.currentState.getSentinelMember.mockImplementation(function(uid) {
|
||||||
if (uid === userA) {
|
if (uid === userA) {
|
||||||
return sentinel;
|
return sentinel;
|
||||||
}
|
}
|
||||||
@@ -292,13 +289,13 @@ describe("Room", function() {
|
|||||||
membership: "join",
|
membership: "join",
|
||||||
name: "Old Alice",
|
name: "Old Alice",
|
||||||
};
|
};
|
||||||
room.currentState.getSentinelMember.andCall(function(uid) {
|
room.currentState.getSentinelMember.mockImplementation(function(uid) {
|
||||||
if (uid === userA) {
|
if (uid === userA) {
|
||||||
return sentinel;
|
return sentinel;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
room.oldState.getSentinelMember.andCall(function(uid) {
|
room.oldState.getSentinelMember.mockImplementation(function(uid) {
|
||||||
if (uid === userA) {
|
if (uid === userA) {
|
||||||
return oldSentinel;
|
return oldSentinel;
|
||||||
}
|
}
|
||||||
@@ -331,13 +328,13 @@ describe("Room", function() {
|
|||||||
membership: "join",
|
membership: "join",
|
||||||
name: "Old Alice",
|
name: "Old Alice",
|
||||||
};
|
};
|
||||||
room.currentState.getSentinelMember.andCall(function(uid) {
|
room.currentState.getSentinelMember.mockImplementation(function(uid) {
|
||||||
if (uid === userA) {
|
if (uid === userA) {
|
||||||
return sentinel;
|
return sentinel;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
room.oldState.getSentinelMember.andCall(function(uid) {
|
room.oldState.getSentinelMember.mockImplementation(function(uid) {
|
||||||
if (uid === userA) {
|
if (uid === userA) {
|
||||||
return oldSentinel;
|
return oldSentinel;
|
||||||
}
|
}
|
||||||
@@ -379,7 +376,7 @@ describe("Room", function() {
|
|||||||
);
|
);
|
||||||
expect(events[0].forwardLooking).toBe(false);
|
expect(events[0].forwardLooking).toBe(false);
|
||||||
expect(events[1].forwardLooking).toBe(false);
|
expect(events[1].forwardLooking).toBe(false);
|
||||||
expect(room.currentState.setStateEvents).toNotHaveBeenCalled();
|
expect(room.currentState.setStateEvents).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -545,7 +542,7 @@ describe("Room", function() {
|
|||||||
|
|
||||||
describe("getJoinedMembers", function() {
|
describe("getJoinedMembers", function() {
|
||||||
it("should return members whose membership is 'join'", function() {
|
it("should return members whose membership is 'join'", function() {
|
||||||
room.currentState.getMembers.andCall(function() {
|
room.currentState.getMembers.mockImplementation(function() {
|
||||||
return [
|
return [
|
||||||
{ userId: "@alice:bar", membership: "join" },
|
{ userId: "@alice:bar", membership: "join" },
|
||||||
{ userId: "@bob:bar", membership: "invite" },
|
{ userId: "@bob:bar", membership: "invite" },
|
||||||
@@ -558,7 +555,7 @@ describe("Room", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should return an empty list if no membership is 'join'", function() {
|
it("should return an empty list if no membership is 'join'", function() {
|
||||||
room.currentState.getMembers.andCall(function() {
|
room.currentState.getMembers.mockImplementation(function() {
|
||||||
return [
|
return [
|
||||||
{ userId: "@bob:bar", membership: "invite" },
|
{ userId: "@bob:bar", membership: "invite" },
|
||||||
];
|
];
|
||||||
@@ -571,7 +568,7 @@ describe("Room", function() {
|
|||||||
describe("hasMembershipState", function() {
|
describe("hasMembershipState", function() {
|
||||||
it("should return true for a matching userId and membership",
|
it("should return true for a matching userId and membership",
|
||||||
function() {
|
function() {
|
||||||
room.currentState.getMember.andCall(function(userId) {
|
room.currentState.getMember.mockImplementation(function(userId) {
|
||||||
return {
|
return {
|
||||||
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
||||||
"@bob:bar": { userId: "@bob:bar", membership: "invite" },
|
"@bob:bar": { userId: "@bob:bar", membership: "invite" },
|
||||||
@@ -582,7 +579,7 @@ describe("Room", function() {
|
|||||||
|
|
||||||
it("should return false if match membership but no match userId",
|
it("should return false if match membership but no match userId",
|
||||||
function() {
|
function() {
|
||||||
room.currentState.getMember.andCall(function(userId) {
|
room.currentState.getMember.mockImplementation(function(userId) {
|
||||||
return {
|
return {
|
||||||
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
||||||
}[userId];
|
}[userId];
|
||||||
@@ -592,7 +589,7 @@ describe("Room", function() {
|
|||||||
|
|
||||||
it("should return false if match userId but no match membership",
|
it("should return false if match userId but no match membership",
|
||||||
function() {
|
function() {
|
||||||
room.currentState.getMember.andCall(function(userId) {
|
room.currentState.getMember.mockImplementation(function(userId) {
|
||||||
return {
|
return {
|
||||||
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
||||||
}[userId];
|
}[userId];
|
||||||
@@ -602,7 +599,7 @@ describe("Room", function() {
|
|||||||
|
|
||||||
it("should return false if no match membership or userId",
|
it("should return false if no match membership or userId",
|
||||||
function() {
|
function() {
|
||||||
room.currentState.getMember.andCall(function(userId) {
|
room.currentState.getMember.mockImplementation(function(userId) {
|
||||||
return {
|
return {
|
||||||
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
"@alice:bar": { userId: "@alice:bar", membership: "join" },
|
||||||
}[userId];
|
}[userId];
|
||||||
@@ -814,8 +811,8 @@ describe("Room", function() {
|
|||||||
addMember(userC);
|
addMember(userC);
|
||||||
room.recalculate();
|
room.recalculate();
|
||||||
const name = room.name;
|
const name = room.name;
|
||||||
expect(name.indexOf(userB)).toNotEqual(-1, name);
|
expect(name.indexOf(userB)).not.toEqual(-1, name);
|
||||||
expect(name.indexOf(userC)).toNotEqual(-1, name);
|
expect(name.indexOf(userC)).not.toEqual(-1, name);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should return the names of members in a public (public join_rules)" +
|
it("should return the names of members in a public (public join_rules)" +
|
||||||
@@ -827,8 +824,8 @@ describe("Room", function() {
|
|||||||
addMember(userC);
|
addMember(userC);
|
||||||
room.recalculate();
|
room.recalculate();
|
||||||
const name = room.name;
|
const name = room.name;
|
||||||
expect(name.indexOf(userB)).toNotEqual(-1, name);
|
expect(name.indexOf(userB)).not.toEqual(-1, name);
|
||||||
expect(name.indexOf(userC)).toNotEqual(-1, name);
|
expect(name.indexOf(userC)).not.toEqual(-1, name);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the other user's name for public (public join_rules)" +
|
it("should show the other user's name for public (public join_rules)" +
|
||||||
@@ -839,7 +836,7 @@ describe("Room", function() {
|
|||||||
addMember(userB);
|
addMember(userB);
|
||||||
room.recalculate();
|
room.recalculate();
|
||||||
const name = room.name;
|
const name = room.name;
|
||||||
expect(name.indexOf(userB)).toNotEqual(-1, name);
|
expect(name.indexOf(userB)).not.toEqual(-1, name);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the other user's name for private " +
|
it("should show the other user's name for private " +
|
||||||
@@ -850,7 +847,7 @@ describe("Room", function() {
|
|||||||
addMember(userB);
|
addMember(userB);
|
||||||
room.recalculate();
|
room.recalculate();
|
||||||
const name = room.name;
|
const name = room.name;
|
||||||
expect(name.indexOf(userB)).toNotEqual(-1, name);
|
expect(name.indexOf(userB)).not.toEqual(-1, name);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the other user's name for private" +
|
it("should show the other user's name for private" +
|
||||||
@@ -860,7 +857,7 @@ describe("Room", function() {
|
|||||||
addMember(userB);
|
addMember(userB);
|
||||||
room.recalculate();
|
room.recalculate();
|
||||||
const name = room.name;
|
const name = room.name;
|
||||||
expect(name.indexOf(userB)).toNotEqual(-1, name);
|
expect(name.indexOf(userB)).not.toEqual(-1, name);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should show the room alias if one exists for private " +
|
it("should show the room alias if one exists for private " +
|
||||||
@@ -1004,7 +1001,7 @@ describe("Room", function() {
|
|||||||
|
|
||||||
it("should emit an event when a receipt is added",
|
it("should emit an event when a receipt is added",
|
||||||
function() {
|
function() {
|
||||||
const listener = expect.createSpy();
|
const listener = jest.fn();
|
||||||
room.on("Room.receipt", listener);
|
room.on("Room.receipt", listener);
|
||||||
|
|
||||||
const ts = 13787898424;
|
const ts = 13787898424;
|
||||||
@@ -1175,7 +1172,7 @@ describe("Room", function() {
|
|||||||
it("should emit Room.tags event when new tags are " +
|
it("should emit Room.tags event when new tags are " +
|
||||||
"received on the event stream",
|
"received on the event stream",
|
||||||
function() {
|
function() {
|
||||||
const listener = expect.createSpy();
|
const listener = jest.fn();
|
||||||
room.on("Room.tags", listener);
|
room.on("Room.tags", listener);
|
||||||
|
|
||||||
const tags = { "m.foo": { "order": 0.5 } };
|
const tags = { "m.foo": { "order": 0.5 } };
|
||||||
|
|||||||
@@ -8,11 +8,9 @@ const MatrixScheduler = sdk.MatrixScheduler;
|
|||||||
const MatrixError = sdk.MatrixError;
|
const MatrixError = sdk.MatrixError;
|
||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
|
|
||||||
import expect from 'expect';
|
jest.useFakeTimers();
|
||||||
import lolex from 'lolex';
|
|
||||||
|
|
||||||
describe("MatrixScheduler", function() {
|
describe("MatrixScheduler", function() {
|
||||||
let clock;
|
|
||||||
let scheduler;
|
let scheduler;
|
||||||
let retryFn;
|
let retryFn;
|
||||||
let queueFn;
|
let queueFn;
|
||||||
@@ -26,8 +24,6 @@ describe("MatrixScheduler", function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
clock = lolex.install();
|
|
||||||
scheduler = new MatrixScheduler(function(ev, attempts, err) {
|
scheduler = new MatrixScheduler(function(ev, attempts, err) {
|
||||||
if (retryFn) {
|
if (retryFn) {
|
||||||
return retryFn(ev, attempts, err);
|
return retryFn(ev, attempts, err);
|
||||||
@@ -44,10 +40,6 @@ describe("MatrixScheduler", function() {
|
|||||||
defer = Promise.defer();
|
defer = Promise.defer();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(function() {
|
|
||||||
clock.uninstall();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should process events in a queue in a FIFO manner", async function() {
|
it("should process events in a queue in a FIFO manner", async function() {
|
||||||
retryFn = function() {
|
retryFn = function() {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -112,7 +104,7 @@ describe("MatrixScheduler", function() {
|
|||||||
defer.reject({});
|
defer.reject({});
|
||||||
await retryDefer.promise;
|
await retryDefer.promise;
|
||||||
expect(procCount).toEqual(1);
|
expect(procCount).toEqual(1);
|
||||||
clock.tick(waitTimeMs);
|
jest.advanceTimersByTime(waitTimeMs);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
expect(procCount).toEqual(2);
|
expect(procCount).toEqual(2);
|
||||||
});
|
});
|
||||||
@@ -203,7 +195,7 @@ describe("MatrixScheduler", function() {
|
|||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
deferA.resolve({});
|
deferA.resolve({});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
clock.tick(1000);
|
jest.advanceTimersByTime(1000);
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("queueEvent", function() {
|
describe("queueEvent", function() {
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ limitations under the License.
|
|||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
import 'source-map-support/register';
|
import 'source-map-support/register';
|
||||||
import utils from "../test-utils";
|
|
||||||
import sdk from "../..";
|
import sdk from "../..";
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
const SyncAccumulator = sdk.SyncAccumulator;
|
const SyncAccumulator = sdk.SyncAccumulator;
|
||||||
|
|
||||||
@@ -26,7 +24,6 @@ describe("SyncAccumulator", function() {
|
|||||||
let sa;
|
let sa;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
sa = new SyncAccumulator({
|
sa = new SyncAccumulator({
|
||||||
maxTimelineEntries: 10,
|
maxTimelineEntries: 10,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ const TimelineWindow = sdk.TimelineWindow;
|
|||||||
const TimelineIndex = require("../../lib/timeline-window").TimelineIndex;
|
const TimelineIndex = require("../../lib/timeline-window").TimelineIndex;
|
||||||
|
|
||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
const ROOM_ID = "roomId";
|
const ROOM_ID = "roomId";
|
||||||
const USER_ID = "userId";
|
const USER_ID = "userId";
|
||||||
@@ -67,10 +66,6 @@ function createLinkedTimelines() {
|
|||||||
|
|
||||||
|
|
||||||
describe("TimelineIndex", function() {
|
describe("TimelineIndex", function() {
|
||||||
beforeEach(function() {
|
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("minIndex", function() {
|
describe("minIndex", function() {
|
||||||
it("should return the min index relative to BaseIndex", function() {
|
it("should return the min index relative to BaseIndex", function() {
|
||||||
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
const timelineIndex = new TimelineIndex(createTimeline(), 0);
|
||||||
@@ -153,7 +148,7 @@ describe("TimelineWindow", function() {
|
|||||||
let timelineSet;
|
let timelineSet;
|
||||||
let client;
|
let client;
|
||||||
function createWindow(timeline, opts) {
|
function createWindow(timeline, opts) {
|
||||||
timelineSet = {};
|
timelineSet = {getTimelineForEvent: () => null};
|
||||||
client = {};
|
client = {};
|
||||||
client.getEventTimeline = function(timelineSet0, eventId0) {
|
client.getEventTimeline = function(timelineSet0, eventId0) {
|
||||||
expect(timelineSet0).toBe(timelineSet);
|
expect(timelineSet0).toBe(timelineSet);
|
||||||
@@ -163,12 +158,8 @@ describe("TimelineWindow", function() {
|
|||||||
return new TimelineWindow(client, timelineSet, opts);
|
return new TimelineWindow(client, timelineSet, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach(function() {
|
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("load", function() {
|
describe("load", function() {
|
||||||
it("should initialise from the live timeline", function(done) {
|
it("should initialise from the live timeline", function() {
|
||||||
const liveTimeline = createTimeline();
|
const liveTimeline = createTimeline();
|
||||||
const room = {};
|
const room = {};
|
||||||
room.getLiveTimeline = function() {
|
room.getLiveTimeline = function() {
|
||||||
@@ -176,17 +167,17 @@ describe("TimelineWindow", function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const timelineWindow = new TimelineWindow(undefined, room);
|
const timelineWindow = new TimelineWindow(undefined, room);
|
||||||
timelineWindow.load(undefined, 2).then(function() {
|
return timelineWindow.load(undefined, 2).then(function() {
|
||||||
const expectedEvents = liveTimeline.getEvents().slice(1);
|
const expectedEvents = liveTimeline.getEvents().slice(1);
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should initialise from a specific event", function(done) {
|
it("should initialise from a specific event", function() {
|
||||||
const timeline = createTimeline();
|
const timeline = createTimeline();
|
||||||
const eventId = timeline.getEvents()[1].getId();
|
const eventId = timeline.getEvents()[1].getId();
|
||||||
|
|
||||||
const timelineSet = {};
|
const timelineSet = {getTimelineForEvent: () => null};
|
||||||
const client = {};
|
const client = {};
|
||||||
client.getEventTimeline = function(timelineSet0, eventId0) {
|
client.getEventTimeline = function(timelineSet0, eventId0) {
|
||||||
expect(timelineSet0).toBe(timelineSet);
|
expect(timelineSet0).toBe(timelineSet);
|
||||||
@@ -195,21 +186,20 @@ describe("TimelineWindow", function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const timelineWindow = new TimelineWindow(client, timelineSet);
|
const timelineWindow = new TimelineWindow(client, timelineSet);
|
||||||
timelineWindow.load(eventId, 3).then(function() {
|
return timelineWindow.load(eventId, 3).then(function() {
|
||||||
const expectedEvents = timeline.getEvents();
|
const expectedEvents = timeline.getEvents();
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("canPaginate should return false until load has returned",
|
it("canPaginate should return false until load has returned", function() {
|
||||||
function(done) {
|
|
||||||
const timeline = createTimeline();
|
const timeline = createTimeline();
|
||||||
timeline.setPaginationToken("toktok1", EventTimeline.BACKWARDS);
|
timeline.setPaginationToken("toktok1", EventTimeline.BACKWARDS);
|
||||||
timeline.setPaginationToken("toktok2", EventTimeline.FORWARDS);
|
timeline.setPaginationToken("toktok2", EventTimeline.FORWARDS);
|
||||||
|
|
||||||
const eventId = timeline.getEvents()[1].getId();
|
const eventId = timeline.getEvents()[1].getId();
|
||||||
|
|
||||||
const timelineSet = {};
|
const timelineSet = {getTimelineForEvent: () => null};
|
||||||
const client = {};
|
const client = {};
|
||||||
|
|
||||||
const timelineWindow = new TimelineWindow(client, timelineSet);
|
const timelineWindow = new TimelineWindow(client, timelineSet);
|
||||||
@@ -222,25 +212,24 @@ describe("TimelineWindow", function() {
|
|||||||
return Promise.resolve(timeline);
|
return Promise.resolve(timeline);
|
||||||
};
|
};
|
||||||
|
|
||||||
timelineWindow.load(eventId, 3).then(function() {
|
return timelineWindow.load(eventId, 3).then(function() {
|
||||||
const expectedEvents = timeline.getEvents();
|
const expectedEvents = timeline.getEvents();
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
|
||||||
.toBe(true);
|
.toBe(true);
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
.toBe(true);
|
.toBe(true);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("pagination", function() {
|
describe("pagination", function() {
|
||||||
it("should be able to advance across the initial timeline",
|
it("should be able to advance across the initial timeline", function() {
|
||||||
function(done) {
|
|
||||||
const timeline = createTimeline();
|
const timeline = createTimeline();
|
||||||
const eventId = timeline.getEvents()[1].getId();
|
const eventId = timeline.getEvents()[1].getId();
|
||||||
const timelineWindow = createWindow(timeline);
|
const timelineWindow = createWindow(timeline);
|
||||||
|
|
||||||
timelineWindow.load(eventId, 1).then(function() {
|
return timelineWindow.load(eventId, 1).then(function() {
|
||||||
const expectedEvents = [timeline.getEvents()[1]];
|
const expectedEvents = [timeline.getEvents()[1]];
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
@@ -277,15 +266,15 @@ describe("TimelineWindow", function() {
|
|||||||
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
|
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
|
||||||
}).then(function(success) {
|
}).then(function(success) {
|
||||||
expect(success).toBe(false);
|
expect(success).toBe(false);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should advance into next timeline", function(done) {
|
it("should advance into next timeline", function() {
|
||||||
const tls = createLinkedTimelines();
|
const tls = createLinkedTimelines();
|
||||||
const eventId = tls[0].getEvents()[1].getId();
|
const eventId = tls[0].getEvents()[1].getId();
|
||||||
const timelineWindow = createWindow(tls[0], {windowLimit: 5});
|
const timelineWindow = createWindow(tls[0], {windowLimit: 5});
|
||||||
|
|
||||||
timelineWindow.load(eventId, 3).then(function() {
|
return timelineWindow.load(eventId, 3).then(function() {
|
||||||
const expectedEvents = tls[0].getEvents();
|
const expectedEvents = tls[0].getEvents();
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
@@ -322,15 +311,15 @@ describe("TimelineWindow", function() {
|
|||||||
return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
|
return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
|
||||||
}).then(function(success) {
|
}).then(function(success) {
|
||||||
expect(success).toBe(false);
|
expect(success).toBe(false);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should retreat into previous timeline", function(done) {
|
it("should retreat into previous timeline", function() {
|
||||||
const tls = createLinkedTimelines();
|
const tls = createLinkedTimelines();
|
||||||
const eventId = tls[1].getEvents()[1].getId();
|
const eventId = tls[1].getEvents()[1].getId();
|
||||||
const timelineWindow = createWindow(tls[1], {windowLimit: 5});
|
const timelineWindow = createWindow(tls[1], {windowLimit: 5});
|
||||||
|
|
||||||
timelineWindow.load(eventId, 3).then(function() {
|
return timelineWindow.load(eventId, 3).then(function() {
|
||||||
const expectedEvents = tls[1].getEvents();
|
const expectedEvents = tls[1].getEvents();
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
@@ -367,10 +356,10 @@ describe("TimelineWindow", function() {
|
|||||||
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
|
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
|
||||||
}).then(function(success) {
|
}).then(function(success) {
|
||||||
expect(success).toBe(false);
|
expect(success).toBe(false);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should make forward pagination requests", function(done) {
|
it("should make forward pagination requests", function() {
|
||||||
const timeline = createTimeline();
|
const timeline = createTimeline();
|
||||||
timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
|
timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
|
||||||
|
|
||||||
@@ -386,7 +375,7 @@ describe("TimelineWindow", function() {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
timelineWindow.load(eventId, 3).then(function() {
|
return timelineWindow.load(eventId, 3).then(function() {
|
||||||
const expectedEvents = timeline.getEvents();
|
const expectedEvents = timeline.getEvents();
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
@@ -399,11 +388,11 @@ describe("TimelineWindow", function() {
|
|||||||
expect(success).toBe(true);
|
expect(success).toBe(true);
|
||||||
const expectedEvents = timeline.getEvents().slice(0, 5);
|
const expectedEvents = timeline.getEvents().slice(0, 5);
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it("should make backward pagination requests", function(done) {
|
it("should make backward pagination requests", function() {
|
||||||
const timeline = createTimeline();
|
const timeline = createTimeline();
|
||||||
timeline.setPaginationToken("toktok", EventTimeline.BACKWARDS);
|
timeline.setPaginationToken("toktok", EventTimeline.BACKWARDS);
|
||||||
|
|
||||||
@@ -419,7 +408,7 @@ describe("TimelineWindow", function() {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
timelineWindow.load(eventId, 3).then(function() {
|
return timelineWindow.load(eventId, 3).then(function() {
|
||||||
const expectedEvents = timeline.getEvents();
|
const expectedEvents = timeline.getEvents();
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
@@ -432,11 +421,10 @@ describe("TimelineWindow", function() {
|
|||||||
expect(success).toBe(true);
|
expect(success).toBe(true);
|
||||||
const expectedEvents = timeline.getEvents().slice(1, 6);
|
const expectedEvents = timeline.getEvents().slice(1, 6);
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should limit the number of unsuccessful pagination requests",
|
it("should limit the number of unsuccessful pagination requests", function() {
|
||||||
function(done) {
|
|
||||||
const timeline = createTimeline();
|
const timeline = createTimeline();
|
||||||
timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
|
timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
|
||||||
|
|
||||||
@@ -452,7 +440,7 @@ describe("TimelineWindow", function() {
|
|||||||
return Promise.resolve(true);
|
return Promise.resolve(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
timelineWindow.load(eventId, 3).then(function() {
|
return timelineWindow.load(eventId, 3).then(function() {
|
||||||
const expectedEvents = timeline.getEvents();
|
const expectedEvents = timeline.getEvents();
|
||||||
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
|
||||||
|
|
||||||
@@ -471,7 +459,7 @@ describe("TimelineWindow", function() {
|
|||||||
.toBe(false);
|
.toBe(false);
|
||||||
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
|
||||||
.toBe(true);
|
.toBe(true);
|
||||||
}).nodeify(done);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,14 +4,11 @@ const sdk = require("../..");
|
|||||||
const User = sdk.User;
|
const User = sdk.User;
|
||||||
const utils = require("../test-utils");
|
const utils = require("../test-utils");
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("User", function() {
|
describe("User", function() {
|
||||||
const userId = "@alice:bar";
|
const userId = "@alice:bar";
|
||||||
let user;
|
let user;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
user = new User(userId);
|
user = new User(userId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,8 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
import 'source-map-support/register';
|
import 'source-map-support/register';
|
||||||
const utils = require("../../lib/utils");
|
const utils = require("../../lib/utils");
|
||||||
const testUtils = require("../test-utils");
|
|
||||||
|
|
||||||
import expect from 'expect';
|
|
||||||
|
|
||||||
describe("utils", function() {
|
describe("utils", function() {
|
||||||
beforeEach(function() {
|
|
||||||
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("encodeParams", function() {
|
describe("encodeParams", function() {
|
||||||
it("should url encode and concat with &s", function() {
|
it("should url encode and concat with &s", function() {
|
||||||
const params = {
|
const params = {
|
||||||
@@ -135,7 +128,7 @@ describe("utils", function() {
|
|||||||
utils.checkObjectHasKeys({
|
utils.checkObjectHasKeys({
|
||||||
foo: "bar",
|
foo: "bar",
|
||||||
}, ["foo"]);
|
}, ["foo"]);
|
||||||
}).toNotThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -152,7 +145,7 @@ describe("utils", function() {
|
|||||||
utils.checkObjectHasNoAdditionalKeys({
|
utils.checkObjectHasNoAdditionalKeys({
|
||||||
foo: "bar",
|
foo: "bar",
|
||||||
}, ["foo"]);
|
}, ["foo"]);
|
||||||
}).toNotThrow();
|
}).not.toThrow();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
Copyright 2018 New Vector Ltd
|
Copyright 2018 New Vector Ltd
|
||||||
|
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -275,21 +276,11 @@ export class AutoDiscovery {
|
|||||||
let isUrl = "";
|
let isUrl = "";
|
||||||
if (wellknown["m.identity_server"]) {
|
if (wellknown["m.identity_server"]) {
|
||||||
// We prepare a failing identity server response to save lines later
|
// We prepare a failing identity server response to save lines later
|
||||||
// in this branch. Note that we also fail the homeserver check in the
|
// in this branch.
|
||||||
// object because according to the spec we're supposed to FAIL_ERROR
|
|
||||||
// if *anything* goes wrong with the IS validation, including invalid
|
|
||||||
// format. This means we're supposed to stop discovery completely.
|
|
||||||
const failingClientConfig = {
|
const failingClientConfig = {
|
||||||
"m.homeserver": {
|
"m.homeserver": clientConfig["m.homeserver"],
|
||||||
state: AutoDiscovery.FAIL_ERROR,
|
|
||||||
error: AutoDiscovery.ERROR_INVALID_IS,
|
|
||||||
|
|
||||||
// We'll provide the base_url that was previously valid for
|
|
||||||
// debugging purposes.
|
|
||||||
base_url: clientConfig["m.homeserver"].base_url,
|
|
||||||
},
|
|
||||||
"m.identity_server": {
|
"m.identity_server": {
|
||||||
state: AutoDiscovery.FAIL_ERROR,
|
state: AutoDiscovery.FAIL_PROMPT,
|
||||||
error: AutoDiscovery.ERROR_INVALID_IS,
|
error: AutoDiscovery.ERROR_INVALID_IS,
|
||||||
base_url: null,
|
base_url: null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -2333,6 +2333,12 @@ MatrixBaseApis.prototype.sendToDevice = function(
|
|||||||
messages: contentMap,
|
messages: contentMap,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const targets = Object.keys(contentMap).reduce((obj, key) => {
|
||||||
|
obj[key] = Object.keys(contentMap[key]);
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
logger.log(`PUT ${path}`, targets);
|
||||||
|
|
||||||
return this._http.authedRequest(undefined, "PUT", path, undefined, body);
|
return this._http.authedRequest(undefined, "PUT", path, undefined, body);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
233
src/client.js
233
src/client.js
@@ -19,6 +19,7 @@ limitations under the License.
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const PushProcessor = require('./pushprocessor');
|
const PushProcessor = require('./pushprocessor');
|
||||||
|
import {sleep} from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is an internal module. See {@link MatrixClient} for the public class.
|
* This is an internal module. See {@link MatrixClient} for the public class.
|
||||||
@@ -72,7 +73,7 @@ function keysFromRecoverySession(sessions, decryptionKey, roomId) {
|
|||||||
decrypted.room_id = roomId;
|
decrypted.room_id = roomId;
|
||||||
keys.push(decrypted);
|
keys.push(decrypted);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.log("Failed to decrypt session from backup");
|
logger.log("Failed to decrypt megolm session from backup", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return keys;
|
return keys;
|
||||||
@@ -1646,7 +1647,7 @@ MatrixClient.prototype._restoreKeyBackup = function(
|
|||||||
key.session_id = targetSessionId;
|
key.session_id = targetSessionId;
|
||||||
keys.push(key);
|
keys.push(key);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.log("Failed to decrypt session from backup");
|
logger.log("Failed to decrypt megolm session from backup", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1892,33 +1893,33 @@ MatrixClient.prototype.joinRoom = function(roomIdOrAlias, opts, callback) {
|
|||||||
|
|
||||||
const reqOpts = {qsStringifyOptions: {arrayFormat: 'repeat'}};
|
const reqOpts = {qsStringifyOptions: {arrayFormat: 'repeat'}};
|
||||||
|
|
||||||
const defer = Promise.defer();
|
|
||||||
|
|
||||||
const self = this;
|
const self = this;
|
||||||
sign_promise.then(function(signed_invite_object) {
|
const prom = new Promise((resolve, reject) => {
|
||||||
const data = {};
|
sign_promise.then(function(signed_invite_object) {
|
||||||
if (signed_invite_object) {
|
const data = {};
|
||||||
data.third_party_signed = signed_invite_object;
|
if (signed_invite_object) {
|
||||||
}
|
data.third_party_signed = signed_invite_object;
|
||||||
|
}
|
||||||
|
|
||||||
const path = utils.encodeUri("/join/$roomid", { $roomid: roomIdOrAlias});
|
const path = utils.encodeUri("/join/$roomid", { $roomid: roomIdOrAlias});
|
||||||
return self._http.authedRequest(
|
return self._http.authedRequest(
|
||||||
undefined, "POST", path, queryString, data, reqOpts);
|
undefined, "POST", path, queryString, data, reqOpts);
|
||||||
}).then(function(res) {
|
}).then(function(res) {
|
||||||
const roomId = res.room_id;
|
const roomId = res.room_id;
|
||||||
const syncApi = new SyncApi(self, self._clientOpts);
|
const syncApi = new SyncApi(self, self._clientOpts);
|
||||||
const room = syncApi.createRoom(roomId);
|
const room = syncApi.createRoom(roomId);
|
||||||
if (opts.syncRoom) {
|
if (opts.syncRoom) {
|
||||||
// v2 will do this for us
|
// v2 will do this for us
|
||||||
// return syncApi.syncRoom(room);
|
// return syncApi.syncRoom(room);
|
||||||
}
|
}
|
||||||
return Promise.resolve(room);
|
return Promise.resolve(room);
|
||||||
}).done(function(room) {
|
}).done(function(room) {
|
||||||
_resolve(callback, defer, room);
|
_resolve(callback, resolve, room);
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
_reject(callback, defer, err);
|
_reject(callback, reject, err);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
return defer.promise;
|
return prom;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3234,42 +3235,45 @@ MatrixClient.prototype.scrollback = function(room, limit, callback) {
|
|||||||
// reduce the required number of events appropriately
|
// reduce the required number of events appropriately
|
||||||
limit = limit - numAdded;
|
limit = limit - numAdded;
|
||||||
|
|
||||||
const defer = Promise.defer();
|
const self = this;
|
||||||
|
const prom = new Promise((resolve, reject) => {
|
||||||
|
// wait for a time before doing this request
|
||||||
|
// (which may be 0 in order not to special case the code paths)
|
||||||
|
sleep(timeToWaitMs).then(function() {
|
||||||
|
return self._createMessagesRequest(
|
||||||
|
room.roomId,
|
||||||
|
room.oldState.paginationToken,
|
||||||
|
limit,
|
||||||
|
'b');
|
||||||
|
}).done(function(res) {
|
||||||
|
const matrixEvents = utils.map(res.chunk, _PojoToMatrixEventMapper(self));
|
||||||
|
if (res.state) {
|
||||||
|
const stateEvents = utils.map(res.state, _PojoToMatrixEventMapper(self));
|
||||||
|
room.currentState.setUnknownStateEvents(stateEvents);
|
||||||
|
}
|
||||||
|
room.addEventsToTimeline(matrixEvents, true, room.getLiveTimeline());
|
||||||
|
room.oldState.paginationToken = res.end;
|
||||||
|
if (res.chunk.length === 0) {
|
||||||
|
room.oldState.paginationToken = null;
|
||||||
|
}
|
||||||
|
self.store.storeEvents(room, matrixEvents, res.end, true);
|
||||||
|
self._ongoingScrollbacks[room.roomId] = null;
|
||||||
|
_resolve(callback, resolve, room);
|
||||||
|
}, function(err) {
|
||||||
|
self._ongoingScrollbacks[room.roomId] = {
|
||||||
|
errorTs: Date.now(),
|
||||||
|
};
|
||||||
|
_reject(callback, reject, err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
info = {
|
info = {
|
||||||
promise: defer.promise,
|
promise: prom,
|
||||||
errorTs: null,
|
errorTs: null,
|
||||||
};
|
};
|
||||||
const self = this;
|
|
||||||
// wait for a time before doing this request
|
|
||||||
// (which may be 0 in order not to special case the code paths)
|
|
||||||
Promise.delay(timeToWaitMs).then(function() {
|
|
||||||
return self._createMessagesRequest(
|
|
||||||
room.roomId,
|
|
||||||
room.oldState.paginationToken,
|
|
||||||
limit,
|
|
||||||
'b');
|
|
||||||
}).done(function(res) {
|
|
||||||
const matrixEvents = utils.map(res.chunk, _PojoToMatrixEventMapper(self));
|
|
||||||
if (res.state) {
|
|
||||||
const stateEvents = utils.map(res.state, _PojoToMatrixEventMapper(self));
|
|
||||||
room.currentState.setUnknownStateEvents(stateEvents);
|
|
||||||
}
|
|
||||||
room.addEventsToTimeline(matrixEvents, true, room.getLiveTimeline());
|
|
||||||
room.oldState.paginationToken = res.end;
|
|
||||||
if (res.chunk.length === 0) {
|
|
||||||
room.oldState.paginationToken = null;
|
|
||||||
}
|
|
||||||
self.store.storeEvents(room, matrixEvents, res.end, true);
|
|
||||||
self._ongoingScrollbacks[room.roomId] = null;
|
|
||||||
_resolve(callback, defer, room);
|
|
||||||
}, function(err) {
|
|
||||||
self._ongoingScrollbacks[room.roomId] = {
|
|
||||||
errorTs: Date.now(),
|
|
||||||
};
|
|
||||||
_reject(callback, defer, err);
|
|
||||||
});
|
|
||||||
this._ongoingScrollbacks[room.roomId] = info;
|
this._ongoingScrollbacks[room.roomId] = info;
|
||||||
return defer.promise;
|
return prom;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -3887,7 +3891,7 @@ MatrixClient.prototype.setRoomMutePushRule = function(scope, roomId, mute) {
|
|||||||
} else if (!hasDontNotifyRule) {
|
} else if (!hasDontNotifyRule) {
|
||||||
// Remove the existing one before setting the mute push rule
|
// Remove the existing one before setting the mute push rule
|
||||||
// This is a workaround to SYN-590 (Push rule update fails)
|
// This is a workaround to SYN-590 (Push rule update fails)
|
||||||
deferred = Promise.defer();
|
deferred = utils.defer();
|
||||||
this.deletePushRule(scope, "room", roomPushRule.rule_id)
|
this.deletePushRule(scope, "room", roomPushRule.rule_id)
|
||||||
.done(function() {
|
.done(function() {
|
||||||
self.addPushRule(scope, "room", roomId, {
|
self.addPushRule(scope, "room", roomId, {
|
||||||
@@ -3906,26 +3910,26 @@ MatrixClient.prototype.setRoomMutePushRule = function(scope, roomId, mute) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (deferred) {
|
if (deferred) {
|
||||||
// Update this.pushRules when the operation completes
|
return new Promise((resolve, reject) => {
|
||||||
const ruleRefreshDeferred = Promise.defer();
|
// Update this.pushRules when the operation completes
|
||||||
deferred.done(function() {
|
deferred.done(function() {
|
||||||
self.getPushRules().done(function(result) {
|
self.getPushRules().done(function(result) {
|
||||||
self.pushRules = result;
|
self.pushRules = result;
|
||||||
ruleRefreshDeferred.resolve();
|
resolve();
|
||||||
|
}, function(err) {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
ruleRefreshDeferred.reject(err);
|
// Update it even if the previous operation fails. This can help the
|
||||||
});
|
// app to recover when push settings has been modifed from another client
|
||||||
}, function(err) {
|
self.getPushRules().done(function(result) {
|
||||||
// Update it even if the previous operation fails. This can help the
|
self.pushRules = result;
|
||||||
// app to recover when push settings has been modifed from another client
|
reject(err);
|
||||||
self.getPushRules().done(function(result) {
|
}, function(err2) {
|
||||||
self.pushRules = result;
|
reject(err);
|
||||||
ruleRefreshDeferred.reject(err);
|
});
|
||||||
}, function(err2) {
|
|
||||||
ruleRefreshDeferred.reject(err);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
return ruleRefreshDeferred.promise;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -4655,15 +4659,20 @@ function setupCallEventHandler(client) {
|
|||||||
// callId: [Candidate]
|
// callId: [Candidate]
|
||||||
};
|
};
|
||||||
|
|
||||||
// Maintain a buffer of events before the client has synced for the first time.
|
// The sync code always emits one event at a time, so it will patiently
|
||||||
// This buffer will be inspected to see if we should send incoming call
|
// wait for us to finish processing a call invite before delivering the
|
||||||
// notifications. It needs to be buffered to correctly determine if an
|
// next event, even if that next event is a hangup. We therefore accumulate
|
||||||
// incoming call has had a matching answer/hangup.
|
// all our call events and then process them on the 'sync' event, ie.
|
||||||
|
// each time a sync has completed. This way, we can avoid emitting incoming
|
||||||
|
// call events if we get both the invite and answer/hangup in the same sync.
|
||||||
|
// This happens quite often, eg. replaying sync from storage, catchup sync
|
||||||
|
// after loading and after we've been offline for a bit.
|
||||||
let callEventBuffer = [];
|
let callEventBuffer = [];
|
||||||
let isClientPrepared = false;
|
function evaluateEventBuffer() {
|
||||||
client.on("sync", function(state) {
|
if (client.getSyncState() === "SYNCING") {
|
||||||
if (state === "PREPARED") {
|
// don't process any events until they are all decrypted
|
||||||
isClientPrepared = true;
|
if (callEventBuffer.some((e) => e.isBeingDecrypted())) return;
|
||||||
|
|
||||||
const ignoreCallIds = {}; // Set<String>
|
const ignoreCallIds = {}; // Set<String>
|
||||||
// inspect the buffer and mark all calls which have been answered
|
// inspect the buffer and mark all calls which have been answered
|
||||||
// or hung up before passing them to the call event handler.
|
// or hung up before passing them to the call event handler.
|
||||||
@@ -4676,39 +4685,51 @@ function setupCallEventHandler(client) {
|
|||||||
}
|
}
|
||||||
// now loop through the buffer chronologically and inject them
|
// now loop through the buffer chronologically and inject them
|
||||||
callEventBuffer.forEach(function(e) {
|
callEventBuffer.forEach(function(e) {
|
||||||
if (ignoreCallIds[e.getContent().call_id]) {
|
if (
|
||||||
// This call has previously been ansered or hung up: ignore it
|
e.getType() === "m.call.invite" &&
|
||||||
|
ignoreCallIds[e.getContent().call_id]
|
||||||
|
) {
|
||||||
|
// This call has previously been answered or hung up: ignore it
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
callEventHandler(e);
|
callEventHandler(e);
|
||||||
});
|
});
|
||||||
callEventBuffer = [];
|
callEventBuffer = [];
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
client.on("sync", evaluateEventBuffer);
|
||||||
client.on("event", onEvent);
|
|
||||||
|
|
||||||
function onEvent(event) {
|
function onEvent(event) {
|
||||||
if (event.getType().indexOf("m.call.") !== 0) {
|
// any call events or ones that might be once they're decrypted
|
||||||
// not a call event
|
if (event.getType().indexOf("m.call.") === 0 || event.isBeingDecrypted()) {
|
||||||
if (event.isBeingDecrypted() || event.isDecryptionFailure()) {
|
// queue up for processing once all events from this sync have been
|
||||||
// not *yet* a call event, but might become one...
|
// processed (see above).
|
||||||
event.once("Event.decrypted", onEvent);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!isClientPrepared) {
|
|
||||||
callEventBuffer.push(event);
|
callEventBuffer.push(event);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
callEventHandler(event);
|
|
||||||
|
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 (callEventBuffer.includes(event)) {
|
||||||
|
// we were waiting for that event to decrypt, so recheck the buffer
|
||||||
|
evaluateEventBuffer();
|
||||||
|
} else {
|
||||||
|
// This one wasn't buffered so just run the event handler for it
|
||||||
|
// straight away
|
||||||
|
callEventHandler(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
client.on("event", onEvent);
|
||||||
|
|
||||||
function callEventHandler(event) {
|
function callEventHandler(event) {
|
||||||
const content = event.getContent();
|
const content = event.getContent();
|
||||||
let call = content.call_id ? client.callList[content.call_id] : undefined;
|
let call = content.call_id ? client.callList[content.call_id] : undefined;
|
||||||
let i;
|
let i;
|
||||||
//console.log("RECV %s content=%s", event.getType(), JSON.stringify(content));
|
//console.info("RECV %s content=%s", event.getType(), JSON.stringify(content));
|
||||||
|
|
||||||
if (event.getType() === "m.call.invite") {
|
if (event.getType() === "m.call.invite") {
|
||||||
if (event.getSender() === client.credentials.userId) {
|
if (event.getSender() === client.credentials.userId) {
|
||||||
@@ -4879,18 +4900,18 @@ function checkTurnServers(client) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function _reject(callback, defer, err) {
|
function _reject(callback, reject, err) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(err);
|
callback(err);
|
||||||
}
|
}
|
||||||
defer.reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _resolve(callback, defer, res) {
|
function _resolve(callback, resolve, res) {
|
||||||
if (callback) {
|
if (callback) {
|
||||||
callback(null, res);
|
callback(null, res);
|
||||||
}
|
}
|
||||||
defer.resolve(res);
|
resolve(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
function _PojoToMatrixEventMapper(client) {
|
function _PojoToMatrixEventMapper(client) {
|
||||||
@@ -5222,6 +5243,8 @@ module.exports.CRYPTO_ENABLED = CRYPTO_ENABLED;
|
|||||||
* @param {object} data
|
* @param {object} data
|
||||||
* @param {MatrixEvent} data.event the original verification request message
|
* @param {MatrixEvent} data.event the original verification request message
|
||||||
* @param {Array} data.methods the verification methods that can be used
|
* @param {Array} data.methods the verification methods that can be used
|
||||||
|
* @param {Number} data.timeout the amount of milliseconds that should be waited
|
||||||
|
* before cancelling the request automatically.
|
||||||
* @param {Function} data.beginKeyVerification a function to call if a key
|
* @param {Function} data.beginKeyVerification a function to call if a key
|
||||||
* verification should be performed. The function takes one argument: the
|
* verification should be performed. The function takes one argument: the
|
||||||
* name of the key verification method (taken from data.methods) to use.
|
* name of the key verification method (taken from data.methods) to use.
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import DeviceInfo from './deviceinfo';
|
|||||||
import {CrossSigningInfo} from './CrossSigning';
|
import {CrossSigningInfo} from './CrossSigning';
|
||||||
import olmlib from './olmlib';
|
import olmlib from './olmlib';
|
||||||
import IndexedDBCryptoStore from './store/indexeddb-crypto-store';
|
import IndexedDBCryptoStore from './store/indexeddb-crypto-store';
|
||||||
|
import {sleep} from '../utils';
|
||||||
|
|
||||||
|
|
||||||
/* State transition diagram for DeviceList._deviceTrackingStatus
|
/* State transition diagram for DeviceList._deviceTrackingStatus
|
||||||
@@ -763,7 +764,7 @@ class DeviceListUpdateSerialiser {
|
|||||||
// this serves as an easy solution for now.
|
// this serves as an easy solution for now.
|
||||||
let prom = Promise.resolve();
|
let prom = Promise.resolve();
|
||||||
for (const userId of downloadUsers) {
|
for (const userId of downloadUsers) {
|
||||||
prom = prom.delay(5).then(() => {
|
prom = prom.then(sleep(5)).then(() => {
|
||||||
return this._processQueryResponseForUser(
|
return this._processQueryResponseForUser(
|
||||||
userId, dk[userId], {
|
userId, dk[userId], {
|
||||||
master: masterKeys[userId],
|
master: masterKeys[userId],
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ OlmDevice.prototype.createInboundSession = async function(
|
|||||||
*/
|
*/
|
||||||
OlmDevice.prototype.getSessionIdsForDevice = async function(theirDeviceIdentityKey) {
|
OlmDevice.prototype.getSessionIdsForDevice = async function(theirDeviceIdentityKey) {
|
||||||
if (this._sessionsInProgress[theirDeviceIdentityKey]) {
|
if (this._sessionsInProgress[theirDeviceIdentityKey]) {
|
||||||
logger.log("waiting for session to be created");
|
logger.log("waiting for olm session to be created");
|
||||||
try {
|
try {
|
||||||
await this._sessionsInProgress[theirDeviceIdentityKey];
|
await this._sessionsInProgress[theirDeviceIdentityKey];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -543,7 +543,7 @@ OlmDevice.prototype.getSessionIdForDevice = async function(
|
|||||||
*/
|
*/
|
||||||
OlmDevice.prototype.getSessionInfoForDevice = async function(deviceIdentityKey, nowait) {
|
OlmDevice.prototype.getSessionInfoForDevice = async function(deviceIdentityKey, nowait) {
|
||||||
if (this._sessionsInProgress[deviceIdentityKey] && !nowait) {
|
if (this._sessionsInProgress[deviceIdentityKey] && !nowait) {
|
||||||
logger.log("waiting for session to be created");
|
logger.log("waiting for olm session to be created");
|
||||||
try {
|
try {
|
||||||
await this._sessionsInProgress[deviceIdentityKey];
|
await this._sessionsInProgress[deviceIdentityKey];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -595,8 +595,8 @@ OlmDevice.prototype.encryptMessage = async function(
|
|||||||
(txn) => {
|
(txn) => {
|
||||||
this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => {
|
this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => {
|
||||||
const sessionDesc = sessionInfo.session.describe();
|
const sessionDesc = sessionInfo.session.describe();
|
||||||
console.log(
|
logger.log(
|
||||||
"Session ID " + sessionId + " to " +
|
"encryptMessage: Olm Session ID " + sessionId + " to " +
|
||||||
theirDeviceIdentityKey + ": " + sessionDesc,
|
theirDeviceIdentityKey + ": " + sessionDesc,
|
||||||
);
|
);
|
||||||
res = sessionInfo.session.encrypt(payloadString);
|
res = sessionInfo.session.encrypt(payloadString);
|
||||||
@@ -627,8 +627,8 @@ OlmDevice.prototype.decryptMessage = async function(
|
|||||||
(txn) => {
|
(txn) => {
|
||||||
this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => {
|
this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => {
|
||||||
const sessionDesc = sessionInfo.session.describe();
|
const sessionDesc = sessionInfo.session.describe();
|
||||||
console.log(
|
logger.log(
|
||||||
"Session ID " + sessionId + " to " +
|
"decryptMessage: Olm Session ID " + sessionId + " from " +
|
||||||
theirDeviceIdentityKey + ": " + sessionDesc,
|
theirDeviceIdentityKey + ": " + sessionDesc,
|
||||||
);
|
);
|
||||||
payloadString = sessionInfo.session.decrypt(messageType, ciphertext);
|
payloadString = sessionInfo.session.decrypt(messageType, ciphertext);
|
||||||
@@ -740,6 +740,8 @@ OlmDevice.prototype.createOutboundGroupSession = function() {
|
|||||||
OlmDevice.prototype.encryptGroupMessage = function(sessionId, payloadString) {
|
OlmDevice.prototype.encryptGroupMessage = function(sessionId, payloadString) {
|
||||||
const self = this;
|
const self = this;
|
||||||
|
|
||||||
|
logger.log(`encrypting msg with megolm session ${sessionId}`);
|
||||||
|
|
||||||
checkPayloadLength(payloadString);
|
checkPayloadLength(payloadString);
|
||||||
|
|
||||||
return this._getOutboundGroupSession(sessionId, function(session) {
|
return this._getOutboundGroupSession(sessionId, function(session) {
|
||||||
@@ -886,7 +888,9 @@ OlmDevice.prototype.addInboundGroupSession = async function(
|
|||||||
<= session.first_known_index()) {
|
<= session.first_known_index()) {
|
||||||
// existing session has lower index (i.e. can
|
// existing session has lower index (i.e. can
|
||||||
// decrypt more), so keep it
|
// decrypt more), so keep it
|
||||||
logger.log("Keeping existing session");
|
logger.log(
|
||||||
|
`Keeping existing megolm session ${sessionId}`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ OutboundSessionInfo.prototype.sharedWithTooManyDevices = function(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!devicesInRoom.hasOwnProperty(userId)) {
|
if (!devicesInRoom.hasOwnProperty(userId)) {
|
||||||
logger.log("Starting new session because we shared with " + userId);
|
logger.log("Starting new megolm session because we shared with " + userId);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,7 +115,7 @@ OutboundSessionInfo.prototype.sharedWithTooManyDevices = function(
|
|||||||
|
|
||||||
if (!devicesInRoom[userId].hasOwnProperty(deviceId)) {
|
if (!devicesInRoom[userId].hasOwnProperty(deviceId)) {
|
||||||
logger.log(
|
logger.log(
|
||||||
"Starting new session because we shared with " +
|
"Starting new megolm session because we shared with " +
|
||||||
userId + ":" + deviceId,
|
userId + ":" + deviceId,
|
||||||
);
|
);
|
||||||
return true;
|
return true;
|
||||||
@@ -200,6 +200,8 @@ MegolmEncryption.prototype._ensureOutboundSession = function(devicesInRoom) {
|
|||||||
if (!session) {
|
if (!session) {
|
||||||
logger.log(`Starting new megolm session for room ${self._roomId}`);
|
logger.log(`Starting new megolm session for room ${self._roomId}`);
|
||||||
session = await self._prepareNewSession();
|
session = await self._prepareNewSession();
|
||||||
|
logger.log(`Started new megolm session ${session.sessionId} ` +
|
||||||
|
`for room ${self._roomId}`);
|
||||||
self._outboundSessions[session.sessionId] = session;
|
self._outboundSessions[session.sessionId] = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +280,7 @@ MegolmEncryption.prototype._prepareNewSession = async function() {
|
|||||||
).catch((e) => {
|
).catch((e) => {
|
||||||
// This throws if the upload failed, but this is fine
|
// This throws if the upload failed, but this is fine
|
||||||
// since it will have written it to the db and will retry.
|
// since it will have written it to the db and will retry.
|
||||||
logger.log("Failed to back up group session", e);
|
logger.log("Failed to back up megolm session", e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,19 +442,19 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function(
|
|||||||
) {
|
) {
|
||||||
const obSessionInfo = this._outboundSessions[sessionId];
|
const obSessionInfo = this._outboundSessions[sessionId];
|
||||||
if (!obSessionInfo) {
|
if (!obSessionInfo) {
|
||||||
logger.debug("Session ID " + sessionId + " not found: not re-sharing keys");
|
logger.debug(`megolm session ${sessionId} not found: not re-sharing keys`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The chain index of the key we previously sent this device
|
// The chain index of the key we previously sent this device
|
||||||
if (obSessionInfo.sharedWithDevices[userId] === undefined) {
|
if (obSessionInfo.sharedWithDevices[userId] === undefined) {
|
||||||
logger.debug("Session ID " + sessionId + " never shared with user " + userId);
|
logger.debug(`megolm session ${sessionId} never shared with user ${userId}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const sentChainIndex = obSessionInfo.sharedWithDevices[userId][device.deviceId];
|
const sentChainIndex = obSessionInfo.sharedWithDevices[userId][device.deviceId];
|
||||||
if (sentChainIndex === undefined) {
|
if (sentChainIndex === undefined) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
"Session ID " + sessionId + " never shared with device " +
|
"megolm session ID " + sessionId + " never shared with device " +
|
||||||
userId + ":" + device.deviceId,
|
userId + ":" + device.deviceId,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@@ -466,7 +468,7 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function(
|
|||||||
|
|
||||||
if (!key) {
|
if (!key) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"No outbound session key found for " + sessionId + ": not re-sharing keys",
|
`No inbound session key found for megolm ${sessionId}: not re-sharing keys`,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -513,9 +515,8 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function(
|
|||||||
[device.deviceId]: encryptedContent,
|
[device.deviceId]: encryptedContent,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
logger.debug(
|
logger.debug(`Re-shared key for megolm session ${sessionId} ` +
|
||||||
`Re-shared key for session ${sessionId} with ${userId}:${device.deviceId}`,
|
`with ${userId}:${device.deviceId}`);
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -550,10 +551,10 @@ MegolmEncryption.prototype._shareKeyWithDevices = async function(session, device
|
|||||||
await this._encryptAndSendKeysToDevices(
|
await this._encryptAndSendKeysToDevices(
|
||||||
session, key.chain_index, userDeviceMaps[i], payload,
|
session, key.chain_index, userDeviceMaps[i], payload,
|
||||||
);
|
);
|
||||||
logger.log(`Completed megolm keyshare in ${this._roomId} `
|
logger.log(`Completed megolm keyshare for ${session.sessionId} `
|
||||||
+ `(slice ${i + 1}/${userDeviceMaps.length})`);
|
+ `in ${this._roomId} (slice ${i + 1}/${userDeviceMaps.length})`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.log(`megolm keyshare in ${this._roomId} `
|
logger.log(`megolm keyshare for ${session.sessionId} in ${this._roomId} `
|
||||||
+ `(slice ${i + 1}/${userDeviceMaps.length}) failed`);
|
+ `(slice ${i + 1}/${userDeviceMaps.length}) failed`);
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
@@ -922,7 +923,7 @@ MegolmDecryption.prototype.onRoomKeyEvent = function(event) {
|
|||||||
keysClaimed = event.getKeysClaimed();
|
keysClaimed = event.getKeysClaimed();
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log(`Adding key for megolm session ${senderKey}|${sessionId}`);
|
logger.log(`Received and adding key for megolm session ${senderKey}|${sessionId}`);
|
||||||
return this._olmDevice.addInboundGroupSession(
|
return this._olmDevice.addInboundGroupSession(
|
||||||
content.room_id, senderKey, forwardingKeyChain, sessionId,
|
content.room_id, senderKey, forwardingKeyChain, sessionId,
|
||||||
content.session_key, keysClaimed,
|
content.session_key, keysClaimed,
|
||||||
@@ -955,7 +956,7 @@ MegolmDecryption.prototype.onRoomKeyEvent = function(event) {
|
|||||||
).catch((e) => {
|
).catch((e) => {
|
||||||
// This throws if the upload failed, but this is fine
|
// This throws if the upload failed, but this is fine
|
||||||
// since it will have written it to the db and will retry.
|
// since it will have written it to the db and will retry.
|
||||||
logger.log("Failed to back up group session", e);
|
logger.log("Failed to back up megolm session", e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
@@ -1088,7 +1089,7 @@ MegolmDecryption.prototype.importRoomKey = function(session) {
|
|||||||
).catch((e) => {
|
).catch((e) => {
|
||||||
// This throws if the upload failed, but this is fine
|
// This throws if the upload failed, but this is fine
|
||||||
// since it will have written it to the db and will retry.
|
// since it will have written it to the db and will retry.
|
||||||
logger.log("Failed to back up group session", e);
|
logger.log("Failed to back up megolm session", e);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// have another go at decrypting events sent with this session.
|
// have another go at decrypting events sent with this session.
|
||||||
|
|||||||
@@ -139,7 +139,7 @@ OlmEncryption.prototype.encryptMessage = async function(room, eventType, content
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await Promise.all(promises).return(encryptedContent);
|
return await Promise.all(promises).then(() => encryptedContent);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import {
|
|||||||
newUnexpectedMessageError,
|
newUnexpectedMessageError,
|
||||||
newUnknownMethodError,
|
newUnknownMethodError,
|
||||||
} from './verification/Error';
|
} from './verification/Error';
|
||||||
|
import {sleep} from '../utils';
|
||||||
|
|
||||||
const defaultVerificationMethods = {
|
const defaultVerificationMethods = {
|
||||||
[ScanQRCode.NAME]: ScanQRCode,
|
[ScanQRCode.NAME]: ScanQRCode,
|
||||||
@@ -70,10 +71,44 @@ export const verificationMethods = {
|
|||||||
SAS: SAS.NAME,
|
SAS: SAS.NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// the recommended amount of time before a verification request
|
||||||
|
// should be (automatically) cancelled without user interaction
|
||||||
|
// and ignored.
|
||||||
|
const VERIFICATION_REQUEST_TIMEOUT = 5 * 60 * 1000; //5m
|
||||||
|
// to avoid almost expired verification notifications
|
||||||
|
// from showing a notification and almost immediately
|
||||||
|
// disappearing, also ignore verification requests that
|
||||||
|
// are this amount of time away from expiring.
|
||||||
|
const VERIFICATION_REQUEST_MARGIN = 3 * 1000; //3s
|
||||||
|
|
||||||
export function isCryptoAvailable() {
|
export function isCryptoAvailable() {
|
||||||
return Boolean(global.Olm);
|
return Boolean(global.Olm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* subscribes to timeline events / to_device events for SAS verification */
|
||||||
|
function listenForEvents(client, roomId, listener) {
|
||||||
|
let isEncrypted = false;
|
||||||
|
if (roomId) {
|
||||||
|
isEncrypted = client.isRoomEncrypted(roomId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEncrypted) {
|
||||||
|
client.on("Event.decrypted", listener);
|
||||||
|
}
|
||||||
|
client.on("event", listener);
|
||||||
|
let subscribed = true;
|
||||||
|
return function() {
|
||||||
|
if (subscribed) {
|
||||||
|
if (isEncrypted) {
|
||||||
|
client.off("Event.decrypted", listener);
|
||||||
|
}
|
||||||
|
client.off("event", listener);
|
||||||
|
subscribed = false;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const MIN_FORCE_SESSION_INTERVAL_MS = 60 * 60 * 1000;
|
const MIN_FORCE_SESSION_INTERVAL_MS = 60 * 60 * 1000;
|
||||||
const KEY_BACKUP_KEYS_PER_REQUEST = 200;
|
const KEY_BACKUP_KEYS_PER_REQUEST = 200;
|
||||||
|
|
||||||
@@ -979,6 +1014,14 @@ Crypto.prototype.registerEventHandlers = function(eventEmitter) {
|
|||||||
eventEmitter.on("toDeviceEvent", function(event) {
|
eventEmitter.on("toDeviceEvent", function(event) {
|
||||||
crypto._onToDeviceEvent(event);
|
crypto._onToDeviceEvent(event);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
eventEmitter.on("Room.timeline", function(event) {
|
||||||
|
crypto._onTimelineEvent(event);
|
||||||
|
});
|
||||||
|
|
||||||
|
eventEmitter.on("Event.decrypted", function(event) {
|
||||||
|
crypto._onTimelineEvent(event);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -1362,13 +1405,15 @@ function verificationEventHandler(target, userId, roomId, eventId) {
|
|||||||
|| event.getSender() !== userId) {
|
|| event.getSender() !== userId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const content = event.getContent();
|
// ignore events that haven't been decrypted yet.
|
||||||
if (!content["m.relates_to"]) {
|
// we also listen for undecrypted events, just in case
|
||||||
|
// the other side would be sending unencrypted events in an e2ee room
|
||||||
|
if (event.getType() === "m.room.encrypted") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const relatesTo
|
const relatesTo = event.getRelation();
|
||||||
= content["m.relationship"] || content["m.relates_to"];
|
if (!relatesTo
|
||||||
if (!relatesTo.rel_type
|
|| !relatesTo.rel_type
|
||||||
|| relatesTo.rel_type !== "m.reference"
|
|| relatesTo.rel_type !== "m.reference"
|
||||||
|| !relatesTo.event_id
|
|| !relatesTo.event_id
|
||||||
|| relatesTo.event_id !== eventId) {
|
|| relatesTo.event_id !== eventId) {
|
||||||
@@ -1425,7 +1470,9 @@ Crypto.prototype.requestVerificationDM = async function(userId, roomId, methods)
|
|||||||
);
|
);
|
||||||
// this handler gets removed when the verification finishes
|
// this handler gets removed when the verification finishes
|
||||||
// (see the verify method of crypto/verification/Base.js)
|
// (see the verify method of crypto/verification/Base.js)
|
||||||
this._baseApis.on("event", verifier.handler);
|
const subscription =
|
||||||
|
listenForEvents(this._baseApis, roomId, verifier.handler);
|
||||||
|
verifier.setEventsSubscription(subscription);
|
||||||
resolve(verifier);
|
resolve(verifier);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1435,14 +1482,19 @@ Crypto.prototype.requestVerificationDM = async function(userId, roomId, methods)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this._baseApis.on("event", listener);
|
let initialResponseSubscription =
|
||||||
|
listenForEvents(this._baseApis, roomId, listener);
|
||||||
|
|
||||||
const resolve = (...args) => {
|
const resolve = (...args) => {
|
||||||
this._baseApis.off("event", listener);
|
if (initialResponseSubscription) {
|
||||||
|
initialResponseSubscription = initialResponseSubscription();
|
||||||
|
}
|
||||||
_resolve(...args);
|
_resolve(...args);
|
||||||
};
|
};
|
||||||
const reject = (...args) => {
|
const reject = (...args) => {
|
||||||
this._baseApis.off("event", listener);
|
if (initialResponseSubscription) {
|
||||||
|
initialResponseSubscription = initialResponseSubscription();
|
||||||
|
}
|
||||||
_reject(...args);
|
_reject(...args);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@@ -1477,7 +1529,9 @@ Crypto.prototype.acceptVerificationDM = function(event, Method) {
|
|||||||
verifier.handler = verificationEventHandler(
|
verifier.handler = verificationEventHandler(
|
||||||
verifier, event.getSender(), event.getRoomId(), event.getId(),
|
verifier, event.getSender(), event.getRoomId(), event.getId(),
|
||||||
);
|
);
|
||||||
this._baseApis.on("event", verifier.handler);
|
const subscription = listenForEvents(
|
||||||
|
this._baseApis, event.getRoomId(), verifier.handler);
|
||||||
|
verifier.setEventsSubscription(subscription);
|
||||||
return verifier;
|
return verifier;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1668,7 +1722,7 @@ Crypto.prototype.setRoomEncryption = async function(roomId, config, inhibitDevic
|
|||||||
// It would otherwise just throw later as an unknown algorithm would, but we may
|
// It would otherwise just throw later as an unknown algorithm would, but we may
|
||||||
// as well catch this here
|
// as well catch this here
|
||||||
if (!config.algorithm) {
|
if (!config.algorithm) {
|
||||||
console.log("Ignoring setRoomEncryption with no algorithm");
|
logger.log("Ignoring setRoomEncryption with no algorithm");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1854,17 +1908,15 @@ Crypto.prototype.exportRoomKeys = async function() {
|
|||||||
* @return {module:client.Promise} a promise which resolves once the keys have been imported
|
* @return {module:client.Promise} a promise which resolves once the keys have been imported
|
||||||
*/
|
*/
|
||||||
Crypto.prototype.importRoomKeys = function(keys) {
|
Crypto.prototype.importRoomKeys = function(keys) {
|
||||||
return Promise.map(
|
return Promise.all(keys.map((key) => {
|
||||||
keys, (key) => {
|
if (!key.room_id || !key.algorithm) {
|
||||||
if (!key.room_id || !key.algorithm) {
|
logger.warn("ignoring room key entry with missing fields", key);
|
||||||
logger.warn("ignoring room key entry with missing fields", key);
|
return null;
|
||||||
return null;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const alg = this._getRoomDecryptor(key.room_id, key.algorithm);
|
const alg = this._getRoomDecryptor(key.room_id, key.algorithm);
|
||||||
return alg.importRoomKey(key);
|
return alg.importRoomKey(key);
|
||||||
},
|
}));
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1883,7 +1935,7 @@ Crypto.prototype.scheduleKeyBackupSend = async function(maxDelay = 10000) {
|
|||||||
// requests from different clients hitting the server all at
|
// requests from different clients hitting the server all at
|
||||||
// the same time when a new key is sent
|
// the same time when a new key is sent
|
||||||
const delay = Math.random() * maxDelay;
|
const delay = Math.random() * maxDelay;
|
||||||
await Promise.delay(delay);
|
await sleep(delay);
|
||||||
let numFailures = 0; // number of consecutive failures
|
let numFailures = 0; // number of consecutive failures
|
||||||
while (1) {
|
while (1) {
|
||||||
if (!this.backupKey) {
|
if (!this.backupKey) {
|
||||||
@@ -1917,7 +1969,7 @@ Crypto.prototype.scheduleKeyBackupSend = async function(maxDelay = 10000) {
|
|||||||
}
|
}
|
||||||
if (numFailures) {
|
if (numFailures) {
|
||||||
// exponential backoff if we have failures
|
// exponential backoff if we have failures
|
||||||
await Promise.delay(1000 * Math.pow(2, Math.min(numFailures - 1, 4)));
|
await sleep(1000 * Math.pow(2, Math.min(numFailures - 1, 4)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -2326,6 +2378,9 @@ Crypto.prototype._getTrackedE2eRooms = function() {
|
|||||||
|
|
||||||
Crypto.prototype._onToDeviceEvent = function(event) {
|
Crypto.prototype._onToDeviceEvent = function(event) {
|
||||||
try {
|
try {
|
||||||
|
logger.log(`received to_device ${event.getType()} from: ` +
|
||||||
|
`${event.getSender()} id: ${event.getId()}`);
|
||||||
|
|
||||||
if (event.getType() == "m.room_key"
|
if (event.getType() == "m.room_key"
|
||||||
|| event.getType() == "m.forwarded_room_key") {
|
|| event.getType() == "m.forwarded_room_key") {
|
||||||
this._onRoomKeyEvent(event);
|
this._onRoomKeyEvent(event);
|
||||||
@@ -2392,8 +2447,8 @@ Crypto.prototype._onKeyVerificationRequest = function(event) {
|
|||||||
|
|
||||||
const content = event.getContent();
|
const content = event.getContent();
|
||||||
if (!("from_device" in content) || typeof content.from_device !== "string"
|
if (!("from_device" in content) || typeof content.from_device !== "string"
|
||||||
|| !("transaction_id" in content) || typeof content.from_device !== "string"
|
|| !("transaction_id" in content)
|
||||||
|| !("methods" in content) || !(content.methods instanceof Array)
|
|| !("methods" in content) || !Array.isArray(content.methods)
|
||||||
|| !("timestamp" in content) || typeof content.timestamp !== "number") {
|
|| !("timestamp" in content) || typeof content.timestamp !== "number") {
|
||||||
logger.warn("received invalid verification request from " + event.getSender());
|
logger.warn("received invalid verification request from " + event.getSender());
|
||||||
// ignore event if malformed
|
// ignore event if malformed
|
||||||
@@ -2469,6 +2524,7 @@ Crypto.prototype._onKeyVerificationRequest = function(event) {
|
|||||||
// notify the application of the verification request, so it can
|
// notify the application of the verification request, so it can
|
||||||
// decide what to do with it
|
// decide what to do with it
|
||||||
const request = {
|
const request = {
|
||||||
|
timeout: VERIFICATION_REQUEST_TIMEOUT,
|
||||||
event: event,
|
event: event,
|
||||||
methods: methods,
|
methods: methods,
|
||||||
beginKeyVerification: (method) => {
|
beginKeyVerification: (method) => {
|
||||||
@@ -2601,6 +2657,31 @@ Crypto.prototype._onKeyVerificationStart = function(event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
this._baseApis.emit("crypto.verification.start", verifier);
|
this._baseApis.emit("crypto.verification.start", verifier);
|
||||||
|
|
||||||
|
// Riot does not implement `m.key.verification.request` while
|
||||||
|
// verifying over to_device messages, but the protocol is made to
|
||||||
|
// work when starting with a `m.key.verification.start` event straight
|
||||||
|
// away as well. Verification over DM *does* start with a request event first,
|
||||||
|
// and to expose a uniform api to monitor verification requests, we mock
|
||||||
|
// the request api here for to_device messages.
|
||||||
|
// "crypto.verification.start" is kept for backwards compatibility.
|
||||||
|
|
||||||
|
// ahh, this will create 2 request notifications for clients that do support the request event
|
||||||
|
// so maybe we should remove emitting the request when actually receiving it *sigh*
|
||||||
|
const requestAdapter = {
|
||||||
|
event,
|
||||||
|
timeout: VERIFICATION_REQUEST_TIMEOUT,
|
||||||
|
methods: [content.method],
|
||||||
|
beginKeyVerification: (method) => {
|
||||||
|
if (content.method === method) {
|
||||||
|
return verifier;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cancel: () => {
|
||||||
|
return verifier.cancel("User cancelled");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this._baseApis.emit("crypto.verification.request", requestAdapter);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2633,6 +2714,53 @@ Crypto.prototype._onKeyVerificationMessage = function(event) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle key verification requests sent as timeline events
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {module:models/event.MatrixEvent} event the timeline event
|
||||||
|
*/
|
||||||
|
Crypto.prototype._onTimelineEvent = function(event) {
|
||||||
|
if (event.getType() !== "m.room.message") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const content = event.getContent();
|
||||||
|
if (content.msgtype !== "m.key.verification.request") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// ignore event if malformed
|
||||||
|
if (!("from_device" in content) || typeof content.from_device !== "string"
|
||||||
|
|| !("methods" in content) || !Array.isArray(content.methods)
|
||||||
|
|| !("to" in content) || typeof content.to !== "string") {
|
||||||
|
logger.warn("received invalid verification request over DM from "
|
||||||
|
+ event.getSender());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// check the request was directed to the syncing user
|
||||||
|
if (content.to !== this._baseApis.getUserId()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const timeout = VERIFICATION_REQUEST_TIMEOUT - VERIFICATION_REQUEST_MARGIN;
|
||||||
|
if (event.getLocalAge() >= timeout) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const request = {
|
||||||
|
event,
|
||||||
|
timeout: VERIFICATION_REQUEST_TIMEOUT,
|
||||||
|
methods: content.methods,
|
||||||
|
beginKeyVerification: (method) => {
|
||||||
|
const verifier = this.acceptVerificationDM(event, method);
|
||||||
|
return verifier;
|
||||||
|
},
|
||||||
|
cancel: () => {
|
||||||
|
const verifier = this.acceptVerificationDM(event, content.methods[0]);
|
||||||
|
verifier.cancel("User declined");
|
||||||
|
},
|
||||||
|
};
|
||||||
|
this._baseApis.emit("crypto.verification.request", request);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a toDevice event that couldn't be decrypted
|
* Handle a toDevice event that couldn't be decrypted
|
||||||
*
|
*
|
||||||
@@ -2815,14 +2943,10 @@ Crypto.prototype._processReceivedRoomKeyRequests = async function() {
|
|||||||
// cancellation (and end up with a cancelled request), rather than the
|
// cancellation (and end up with a cancelled request), rather than the
|
||||||
// cancellation before the request (and end up with an outstanding
|
// cancellation before the request (and end up with an outstanding
|
||||||
// request which should have been cancelled.)
|
// request which should have been cancelled.)
|
||||||
await Promise.map(
|
await Promise.all(requests.map((req) =>
|
||||||
requests, (req) =>
|
this._processReceivedRoomKeyRequest(req)));
|
||||||
this._processReceivedRoomKeyRequest(req),
|
await Promise.all(cancellations.map((cancellation) =>
|
||||||
);
|
this._processReceivedRoomKeyRequestCancellation(cancellation)));
|
||||||
await Promise.map(
|
|
||||||
cancellations, (cancellation) =>
|
|
||||||
this._processReceivedRoomKeyRequestCancellation(cancellation),
|
|
||||||
);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error(`Error processing room key requsts: ${e}`);
|
logger.error(`Error processing room key requsts: ${e}`);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -287,12 +287,12 @@ async function _verifyKeyAndStartSession(olmDevice, oneTimeKey, userId, deviceIn
|
|||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// possibly a bad key
|
// possibly a bad key
|
||||||
logger.error("Error starting session with device " +
|
logger.error("Error starting olm session with device " +
|
||||||
userId + ":" + deviceId + ": " + e);
|
userId + ":" + deviceId + ": " + e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log("Started new sessionid " + sid +
|
logger.log("Started new olm sessionid " + sid +
|
||||||
" for device " + userId + ":" + deviceId);
|
" for device " + userId + ":" + deviceId);
|
||||||
return sid;
|
return sid;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,35 +58,34 @@ export class Backend {
|
|||||||
getOrAddOutgoingRoomKeyRequest(request) {
|
getOrAddOutgoingRoomKeyRequest(request) {
|
||||||
const requestBody = request.requestBody;
|
const requestBody = request.requestBody;
|
||||||
|
|
||||||
const deferred = Promise.defer();
|
return new Promise((resolve, reject) => {
|
||||||
const txn = this._db.transaction("outgoingRoomKeyRequests", "readwrite");
|
const txn = this._db.transaction("outgoingRoomKeyRequests", "readwrite");
|
||||||
txn.onerror = deferred.reject;
|
txn.onerror = reject;
|
||||||
|
|
||||||
// first see if we already have an entry for this request.
|
// first see if we already have an entry for this request.
|
||||||
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
|
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
|
||||||
if (existing) {
|
if (existing) {
|
||||||
// this entry matches the request - return it.
|
// this entry matches the request - return it.
|
||||||
|
logger.log(
|
||||||
|
`already have key request outstanding for ` +
|
||||||
|
`${requestBody.room_id} / ${requestBody.session_id}: ` +
|
||||||
|
`not sending another`,
|
||||||
|
);
|
||||||
|
resolve(existing);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we got to the end of the list without finding a match
|
||||||
|
// - add the new request.
|
||||||
logger.log(
|
logger.log(
|
||||||
`already have key request outstanding for ` +
|
`enqueueing key request for ${requestBody.room_id} / ` +
|
||||||
`${requestBody.room_id} / ${requestBody.session_id}: ` +
|
requestBody.session_id,
|
||||||
`not sending another`,
|
|
||||||
);
|
);
|
||||||
deferred.resolve(existing);
|
txn.oncomplete = () => { resolve(request); };
|
||||||
return;
|
const store = txn.objectStore("outgoingRoomKeyRequests");
|
||||||
}
|
store.add(request);
|
||||||
|
});
|
||||||
// we got to the end of the list without finding a match
|
|
||||||
// - add the new request.
|
|
||||||
logger.log(
|
|
||||||
`enqueueing key request for ${requestBody.room_id} / ` +
|
|
||||||
requestBody.session_id,
|
|
||||||
);
|
|
||||||
txn.oncomplete = () => { deferred.resolve(request); };
|
|
||||||
const store = txn.objectStore("outgoingRoomKeyRequests");
|
|
||||||
store.add(request);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return deferred.promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -100,15 +99,14 @@ export class Backend {
|
|||||||
* not found
|
* not found
|
||||||
*/
|
*/
|
||||||
getOutgoingRoomKeyRequest(requestBody) {
|
getOutgoingRoomKeyRequest(requestBody) {
|
||||||
const deferred = Promise.defer();
|
return new Promise((resolve, reject) => {
|
||||||
|
const txn = this._db.transaction("outgoingRoomKeyRequests", "readonly");
|
||||||
|
txn.onerror = reject;
|
||||||
|
|
||||||
const txn = this._db.transaction("outgoingRoomKeyRequests", "readonly");
|
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
|
||||||
txn.onerror = deferred.reject;
|
resolve(existing);
|
||||||
|
});
|
||||||
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
|
|
||||||
deferred.resolve(existing);
|
|
||||||
});
|
});
|
||||||
return deferred.promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -287,7 +287,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* @param {function(string)} func Called with the account pickle
|
* @param {function(string)} func Called with the account pickle
|
||||||
*/
|
*/
|
||||||
getAccount(txn, func) {
|
getAccount(txn, func) {
|
||||||
this._backendPromise.value().getAccount(txn, func);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.getAccount(txn, func);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -298,7 +300,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* @param {string} newData The new account pickle to store.
|
* @param {string} newData The new account pickle to store.
|
||||||
*/
|
*/
|
||||||
storeAccount(txn, newData) {
|
storeAccount(txn, newData) {
|
||||||
this._backendPromise.value().storeAccount(txn, newData);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.storeAccount(txn, newData);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -310,7 +314,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* { key_type: base64 encoded seed } where key type = user_signing_key_seed or self_signing_key_seed
|
* { key_type: base64 encoded seed } where key type = user_signing_key_seed or self_signing_key_seed
|
||||||
*/
|
*/
|
||||||
getCrossSigningKeys(txn, func) {
|
getCrossSigningKeys(txn, func) {
|
||||||
this._backendPromise.value().getCrossSigningKeys(txn, func);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.getCrossSigningKeys(txn, func);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -320,7 +326,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* @param {string} keys keys object as getCrossSigningKeys()
|
* @param {string} keys keys object as getCrossSigningKeys()
|
||||||
*/
|
*/
|
||||||
storeCrossSigningKeys(txn, keys) {
|
storeCrossSigningKeys(txn, keys) {
|
||||||
this._backendPromise.value().storeCrossSigningKeys(txn, keys);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.storeCrossSigningKeys(txn, keys);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Olm sessions
|
// Olm sessions
|
||||||
@@ -331,7 +339,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* @param {function(int)} func Called with the count of sessions
|
* @param {function(int)} func Called with the count of sessions
|
||||||
*/
|
*/
|
||||||
countEndToEndSessions(txn, func) {
|
countEndToEndSessions(txn, func) {
|
||||||
this._backendPromise.value().countEndToEndSessions(txn, func);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.countEndToEndSessions(txn, func);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -347,7 +357,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* a message.
|
* a message.
|
||||||
*/
|
*/
|
||||||
getEndToEndSession(deviceKey, sessionId, txn, func) {
|
getEndToEndSession(deviceKey, sessionId, txn, func) {
|
||||||
this._backendPromise.value().getEndToEndSession(deviceKey, sessionId, txn, func);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.getEndToEndSession(deviceKey, sessionId, txn, func);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -362,7 +374,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* a message.
|
* a message.
|
||||||
*/
|
*/
|
||||||
getEndToEndSessions(deviceKey, txn, func) {
|
getEndToEndSessions(deviceKey, txn, func) {
|
||||||
this._backendPromise.value().getEndToEndSessions(deviceKey, txn, func);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.getEndToEndSessions(deviceKey, txn, func);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -373,7 +387,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* and session keys.
|
* and session keys.
|
||||||
*/
|
*/
|
||||||
getAllEndToEndSessions(txn, func) {
|
getAllEndToEndSessions(txn, func) {
|
||||||
this._backendPromise.value().getAllEndToEndSessions(txn, func);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.getAllEndToEndSessions(txn, func);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -384,12 +400,14 @@ export default class IndexedDBCryptoStore {
|
|||||||
* @param {*} txn An active transaction. See doTxn().
|
* @param {*} txn An active transaction. See doTxn().
|
||||||
*/
|
*/
|
||||||
storeEndToEndSession(deviceKey, sessionId, sessionInfo, txn) {
|
storeEndToEndSession(deviceKey, sessionId, sessionInfo, txn) {
|
||||||
this._backendPromise.value().storeEndToEndSession(
|
this._backendPromise.then(backend => {
|
||||||
deviceKey, sessionId, sessionInfo, txn,
|
backend.storeEndToEndSession(
|
||||||
);
|
deviceKey, sessionId, sessionInfo, txn,
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inbound group saessions
|
// Inbound group sessions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the end-to-end inbound group session for a given
|
* Retrieve the end-to-end inbound group session for a given
|
||||||
@@ -401,9 +419,11 @@ export default class IndexedDBCryptoStore {
|
|||||||
* to Base64 end-to-end session.
|
* to Base64 end-to-end session.
|
||||||
*/
|
*/
|
||||||
getEndToEndInboundGroupSession(senderCurve25519Key, sessionId, txn, func) {
|
getEndToEndInboundGroupSession(senderCurve25519Key, sessionId, txn, func) {
|
||||||
this._backendPromise.value().getEndToEndInboundGroupSession(
|
this._backendPromise.then(backend => {
|
||||||
senderCurve25519Key, sessionId, txn, func,
|
backend.getEndToEndInboundGroupSession(
|
||||||
);
|
senderCurve25519Key, sessionId, txn, func,
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -414,7 +434,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* sessionData}, then once with null to indicate the end of the list.
|
* sessionData}, then once with null to indicate the end of the list.
|
||||||
*/
|
*/
|
||||||
getAllEndToEndInboundGroupSessions(txn, func) {
|
getAllEndToEndInboundGroupSessions(txn, func) {
|
||||||
this._backendPromise.value().getAllEndToEndInboundGroupSessions(txn, func);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.getAllEndToEndInboundGroupSessions(txn, func);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -427,9 +449,11 @@ export default class IndexedDBCryptoStore {
|
|||||||
* @param {*} txn An active transaction. See doTxn().
|
* @param {*} txn An active transaction. See doTxn().
|
||||||
*/
|
*/
|
||||||
addEndToEndInboundGroupSession(senderCurve25519Key, sessionId, sessionData, txn) {
|
addEndToEndInboundGroupSession(senderCurve25519Key, sessionId, sessionData, txn) {
|
||||||
this._backendPromise.value().addEndToEndInboundGroupSession(
|
this._backendPromise.then(backend => {
|
||||||
senderCurve25519Key, sessionId, sessionData, txn,
|
backend.addEndToEndInboundGroupSession(
|
||||||
);
|
senderCurve25519Key, sessionId, sessionData, txn,
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -442,9 +466,11 @@ export default class IndexedDBCryptoStore {
|
|||||||
* @param {*} txn An active transaction. See doTxn().
|
* @param {*} txn An active transaction. See doTxn().
|
||||||
*/
|
*/
|
||||||
storeEndToEndInboundGroupSession(senderCurve25519Key, sessionId, sessionData, txn) {
|
storeEndToEndInboundGroupSession(senderCurve25519Key, sessionId, sessionData, txn) {
|
||||||
this._backendPromise.value().storeEndToEndInboundGroupSession(
|
this._backendPromise.then(backend => {
|
||||||
senderCurve25519Key, sessionId, sessionData, txn,
|
backend.storeEndToEndInboundGroupSession(
|
||||||
);
|
senderCurve25519Key, sessionId, sessionData, txn,
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// End-to-end device tracking
|
// End-to-end device tracking
|
||||||
@@ -460,7 +486,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* @param {*} txn An active transaction. See doTxn().
|
* @param {*} txn An active transaction. See doTxn().
|
||||||
*/
|
*/
|
||||||
storeEndToEndDeviceData(deviceData, txn) {
|
storeEndToEndDeviceData(deviceData, txn) {
|
||||||
this._backendPromise.value().storeEndToEndDeviceData(deviceData, txn);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.storeEndToEndDeviceData(deviceData, txn);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -471,7 +499,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* device data
|
* device data
|
||||||
*/
|
*/
|
||||||
getEndToEndDeviceData(txn, func) {
|
getEndToEndDeviceData(txn, func) {
|
||||||
this._backendPromise.value().getEndToEndDeviceData(txn, func);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.getEndToEndDeviceData(txn, func);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// End to End Rooms
|
// End to End Rooms
|
||||||
@@ -483,7 +513,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* @param {*} txn An active transaction. See doTxn().
|
* @param {*} txn An active transaction. See doTxn().
|
||||||
*/
|
*/
|
||||||
storeEndToEndRoom(roomId, roomInfo, txn) {
|
storeEndToEndRoom(roomId, roomInfo, txn) {
|
||||||
this._backendPromise.value().storeEndToEndRoom(roomId, roomInfo, txn);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.storeEndToEndRoom(roomId, roomInfo, txn);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -492,7 +524,9 @@ export default class IndexedDBCryptoStore {
|
|||||||
* @param {function(Object)} func Function called with the end to end encrypted rooms
|
* @param {function(Object)} func Function called with the end to end encrypted rooms
|
||||||
*/
|
*/
|
||||||
getEndToEndRooms(txn, func) {
|
getEndToEndRooms(txn, func) {
|
||||||
this._backendPromise.value().getEndToEndRooms(txn, func);
|
this._backendPromise.then(backend => {
|
||||||
|
backend.getEndToEndRooms(txn, func);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// session backups
|
// session backups
|
||||||
|
|||||||
@@ -75,14 +75,15 @@ export default class VerificationBase extends EventEmitter {
|
|||||||
this._done = false;
|
this._done = false;
|
||||||
this._promise = null;
|
this._promise = null;
|
||||||
this._transactionTimeoutTimer = null;
|
this._transactionTimeoutTimer = null;
|
||||||
|
this._eventsSubscription = null;
|
||||||
|
|
||||||
// At this point, the verification request was received so start the timeout timer.
|
// At this point, the verification request was received so start the timeout timer.
|
||||||
this._resetTimer();
|
this._resetTimer();
|
||||||
|
|
||||||
if (this.roomId) {
|
if (this.roomId) {
|
||||||
this._send = this._sendMessage;
|
this._sendWithTxnId = this._sendMessage;
|
||||||
} else {
|
} else {
|
||||||
this._send = this._sendToDevice;
|
this._sendWithTxnId = this._sendToDevice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,13 +107,43 @@ export default class VerificationBase extends EventEmitter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_contentFromEventWithTxnId(event) {
|
||||||
|
if (this.roomId) { // verification as timeline event
|
||||||
|
// ensure m.related_to is included in e2ee rooms
|
||||||
|
// as the field is excluded from encryption
|
||||||
|
const content = Object.assign({}, event.getContent());
|
||||||
|
content["m.relates_to"] = event.getRelation();
|
||||||
|
return content;
|
||||||
|
} else { // verification as to_device event
|
||||||
|
return event.getContent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* creates a content object with the transaction id added to it */
|
||||||
|
_contentWithTxnId(content) {
|
||||||
|
const copy = Object.assign({}, content);
|
||||||
|
if (this.roomId) { // verification as timeline event
|
||||||
|
copy["m.relates_to"] = {
|
||||||
|
rel_type: "m.reference",
|
||||||
|
event_id: this.transactionId,
|
||||||
|
};
|
||||||
|
} else { // verification as to_device event
|
||||||
|
copy.transaction_id = this.transactionId;
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
_send(type, contentWithoutTxnId) {
|
||||||
|
const content = this._contentWithTxnId(contentWithoutTxnId);
|
||||||
|
return this._sendWithTxnId(type, content);
|
||||||
|
}
|
||||||
|
|
||||||
/* send a message to the other participant, using to-device messages
|
/* send a message to the other participant, using to-device messages
|
||||||
*/
|
*/
|
||||||
_sendToDevice(type, content) {
|
_sendToDevice(type, content) {
|
||||||
if (this._done) {
|
if (this._done) {
|
||||||
return Promise.reject(new Error("Verification is already done"));
|
return Promise.reject(new Error("Verification is already done"));
|
||||||
}
|
}
|
||||||
content.transaction_id = this.transactionId;
|
|
||||||
return this._baseApis.sendToDevice(type, {
|
return this._baseApis.sendToDevice(type, {
|
||||||
[this.userId]: { [this.deviceId]: content },
|
[this.userId]: { [this.deviceId]: content },
|
||||||
});
|
});
|
||||||
@@ -124,12 +155,6 @@ export default class VerificationBase extends EventEmitter {
|
|||||||
if (this._done) {
|
if (this._done) {
|
||||||
return Promise.reject(new Error("Verification is already done"));
|
return Promise.reject(new Error("Verification is already done"));
|
||||||
}
|
}
|
||||||
// FIXME: if MSC1849 decides to use m.relationship instead of
|
|
||||||
// m.relates_to, we should follow suit here
|
|
||||||
content["m.relates_to"] = {
|
|
||||||
rel_type: "m.reference",
|
|
||||||
event_id: this.transactionId,
|
|
||||||
};
|
|
||||||
return this._baseApis.sendEvent(this.roomId, type, content);
|
return this._baseApis.sendEvent(this.roomId, type, content);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,6 +248,10 @@ export default class VerificationBase extends EventEmitter {
|
|||||||
// but no reject function. If cancel is called again, we'd error.
|
// but no reject function. If cancel is called again, we'd error.
|
||||||
if (this._reject) this._reject(e);
|
if (this._reject) this._reject(e);
|
||||||
} else {
|
} else {
|
||||||
|
// unsubscribe from events, this happens in _reject usually but we don't have one here
|
||||||
|
if (this._eventsSubscription) {
|
||||||
|
this._eventsSubscription = this._eventsSubscription();
|
||||||
|
}
|
||||||
// FIXME: this causes an "Uncaught promise" console message
|
// FIXME: this causes an "Uncaught promise" console message
|
||||||
// if nothing ends up chaining this promise.
|
// if nothing ends up chaining this promise.
|
||||||
this._promise = Promise.reject(e);
|
this._promise = Promise.reject(e);
|
||||||
@@ -247,7 +276,10 @@ export default class VerificationBase extends EventEmitter {
|
|||||||
this._done = true;
|
this._done = true;
|
||||||
this._endTimer();
|
this._endTimer();
|
||||||
if (this.handler) {
|
if (this.handler) {
|
||||||
this._baseApis.off("event", this.handler);
|
// these listeners are attached in Crypto.acceptVerificationDM
|
||||||
|
if (this._eventsSubscription) {
|
||||||
|
this._eventsSubscription = this._eventsSubscription();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
resolve(...args);
|
resolve(...args);
|
||||||
};
|
};
|
||||||
@@ -255,7 +287,10 @@ export default class VerificationBase extends EventEmitter {
|
|||||||
this._done = true;
|
this._done = true;
|
||||||
this._endTimer();
|
this._endTimer();
|
||||||
if (this.handler) {
|
if (this.handler) {
|
||||||
this._baseApis.off("event", this.handler);
|
// these listeners are attached in Crypto.acceptVerificationDM
|
||||||
|
if (this._eventsSubscription) {
|
||||||
|
this._eventsSubscription = this._eventsSubscription();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
reject(...args);
|
reject(...args);
|
||||||
};
|
};
|
||||||
@@ -309,4 +344,8 @@ export default class VerificationBase extends EventEmitter {
|
|||||||
await this._baseApis.setDeviceVerified(userId, deviceId);
|
await this._baseApis.setDeviceVerified(userId, deviceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setEventsSubscription(subscription) {
|
||||||
|
this._eventsSubscription = subscription;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ export default class SAS extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _doSendVerification() {
|
async _doSendVerification() {
|
||||||
const initialMessage = {
|
const initialMessage = this._contentWithTxnId({
|
||||||
method: SAS.NAME,
|
method: SAS.NAME,
|
||||||
from_device: this._baseApis.deviceId,
|
from_device: this._baseApis.deviceId,
|
||||||
key_agreement_protocols: KEY_AGREEMENT_LIST,
|
key_agreement_protocols: KEY_AGREEMENT_LIST,
|
||||||
@@ -213,10 +213,10 @@ export default class SAS extends Base {
|
|||||||
message_authentication_codes: MAC_LIST,
|
message_authentication_codes: MAC_LIST,
|
||||||
// FIXME: allow app to specify what SAS methods can be used
|
// FIXME: allow app to specify what SAS methods can be used
|
||||||
short_authentication_string: SAS_LIST,
|
short_authentication_string: SAS_LIST,
|
||||||
};
|
});
|
||||||
// NOTE: this._send will modify initialMessage to include the
|
// add the transaction id to the message beforehand because
|
||||||
// transaction_id field, or the m.relationship/m.relates_to field
|
// it needs to be included in the commitment hash later on
|
||||||
this._send("m.key.verification.start", initialMessage);
|
this._sendWithTxnId("m.key.verification.start", initialMessage);
|
||||||
|
|
||||||
|
|
||||||
let e = await this._waitForEvent("m.key.verification.accept");
|
let e = await this._waitForEvent("m.key.verification.accept");
|
||||||
@@ -281,7 +281,10 @@ export default class SAS extends Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async _doRespondVerification() {
|
async _doRespondVerification() {
|
||||||
let content = this.startEvent.getContent();
|
// as m.related_to is not included in the encrypted content in e2e rooms,
|
||||||
|
// we need to make sure it is added
|
||||||
|
let content = this._contentFromEventWithTxnId(this.startEvent);
|
||||||
|
|
||||||
// Note: we intersect using our pre-made lists, rather than the sets,
|
// Note: we intersect using our pre-made lists, rather than the sets,
|
||||||
// so that the result will be in our order of preference. Then
|
// so that the result will be in our order of preference. Then
|
||||||
// fetching the first element from the array will give our preferred
|
// fetching the first element from the array will give our preferred
|
||||||
|
|||||||
@@ -297,6 +297,15 @@ utils.extend(module.exports.MatrixEvent.prototype, {
|
|||||||
return this.getUnsigned().age || this.event.age; // v2 / v1
|
return this.getUnsigned().age || this.event.age; // v2 / v1
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the age of the event when this function was called.
|
||||||
|
* Relies on the local clock being in sync with the clock of the original homeserver.
|
||||||
|
* @return {Number} The age of this event in milliseconds.
|
||||||
|
*/
|
||||||
|
getLocalAge: function() {
|
||||||
|
return Date.now() - this.getTs();
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the event state_key if it has one. This will return <code>undefined
|
* Get the event state_key if it has one. This will return <code>undefined
|
||||||
* </code> for message events.
|
* </code> for message events.
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
import { EventStatus } from '../../lib/models/event';
|
import { EventStatus } from '../models/event';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A container for relation events that supports easy access to common ways of
|
* A container for relation events that supports easy access to common ways of
|
||||||
|
|||||||
@@ -895,7 +895,7 @@ Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline,
|
|||||||
* @return {RoomMember} The member or <code>null</code>.
|
* @return {RoomMember} The member or <code>null</code>.
|
||||||
*/
|
*/
|
||||||
Room.prototype.getMember = function(userId) {
|
Room.prototype.getMember = function(userId) {
|
||||||
return this.currentState.getMember(userId);
|
return this.currentState.getMember(userId);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -903,7 +903,7 @@ Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline,
|
|||||||
* @return {RoomMember[]} A list of currently joined members.
|
* @return {RoomMember[]} A list of currently joined members.
|
||||||
*/
|
*/
|
||||||
Room.prototype.getJoinedMembers = function() {
|
Room.prototype.getJoinedMembers = function() {
|
||||||
return this.getMembersWithMembership("join");
|
return this.getMembersWithMembership("join");
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {escapeRegExp, globToRegexp} from "./utils";
|
import {escapeRegExp, globToRegexp, isNullOrUndefined} from "./utils";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @module pushprocessor
|
* @module pushprocessor
|
||||||
@@ -268,7 +268,7 @@ function PushProcessor(client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const val = valueForDottedKey(cond.key, ev);
|
const val = valueForDottedKey(cond.key, ev);
|
||||||
if (!val || typeof val != 'string') {
|
if (typeof val !== 'string') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,10 +304,10 @@ function PushProcessor(client) {
|
|||||||
|
|
||||||
// special-case the first component to deal with encrypted messages
|
// special-case the first component to deal with encrypted messages
|
||||||
const firstPart = parts[0];
|
const firstPart = parts[0];
|
||||||
if (firstPart == 'content') {
|
if (firstPart === 'content') {
|
||||||
val = ev.getContent();
|
val = ev.getContent();
|
||||||
parts.shift();
|
parts.shift();
|
||||||
} else if (firstPart == 'type') {
|
} else if (firstPart === 'type') {
|
||||||
val = ev.getType();
|
val = ev.getType();
|
||||||
parts.shift();
|
parts.shift();
|
||||||
} else {
|
} else {
|
||||||
@@ -316,11 +316,11 @@ function PushProcessor(client) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (parts.length > 0) {
|
while (parts.length > 0) {
|
||||||
const thispart = parts.shift();
|
const thisPart = parts.shift();
|
||||||
if (!val[thispart]) {
|
if (isNullOrUndefined(val[thisPart])) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
val = val[thispart];
|
val = val[thisPart];
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ const debuglog = function() {};
|
|||||||
*
|
*
|
||||||
* Intended for use by the unit tests.
|
* Intended for use by the unit tests.
|
||||||
*
|
*
|
||||||
* @param {function} f function which should return a millisecond counter
|
* @param {function} [f] function which should return a millisecond counter
|
||||||
*
|
*
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
|
|
||||||
import Promise from 'bluebird';
|
import Promise from 'bluebird';
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
|
import {defer} from '../utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An IndexedDB store backend where the actual backend sits in a web
|
* An IndexedDB store backend where the actual backend sits in a web
|
||||||
@@ -152,7 +153,7 @@ RemoteIndexedDBStoreBackend.prototype = {
|
|||||||
// the promise automatically gets rejected
|
// the promise automatically gets rejected
|
||||||
return Promise.resolve().then(() => {
|
return Promise.resolve().then(() => {
|
||||||
const seq = this._nextSeq++;
|
const seq = this._nextSeq++;
|
||||||
const def = Promise.defer();
|
const def = defer();
|
||||||
|
|
||||||
this._inFlight[seq] = def;
|
this._inFlight[seq] = def;
|
||||||
|
|
||||||
|
|||||||
@@ -132,14 +132,15 @@ TimelineWindow.prototype.load = function(initialEventId, initialWindowSize) {
|
|||||||
// feeling snappy.
|
// feeling snappy.
|
||||||
//
|
//
|
||||||
if (initialEventId) {
|
if (initialEventId) {
|
||||||
const prom = this._client.getEventTimeline(this._timelineSet, initialEventId);
|
const timeline = this._timelineSet.getTimelineForEvent(initialEventId);
|
||||||
|
if (timeline) {
|
||||||
if (prom.isFulfilled()) {
|
// hot-path optimization to save a reactor tick by replicating the sync check getTimelineForEvent does.
|
||||||
initFields(prom.value());
|
initFields(timeline);
|
||||||
return Promise.resolve();
|
return Promise.resolve(timeline);
|
||||||
} else {
|
|
||||||
return prom.then(initFields);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const prom = this._client.getEventTimeline(this._timelineSet, initialEventId);
|
||||||
|
return prom.then(initFields);
|
||||||
} else {
|
} else {
|
||||||
const tl = this._timelineSet.getLiveTimeline();
|
const tl = this._timelineSet.getLiveTimeline();
|
||||||
initFields(tl);
|
initFields(tl);
|
||||||
|
|||||||
23
src/utils.js
23
src/utils.js
@@ -21,6 +21,7 @@ limitations under the License.
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
const unhomoglyph = require('unhomoglyph');
|
const unhomoglyph = require('unhomoglyph');
|
||||||
|
import Promise from 'bluebird';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode a dictionary of query parameters.
|
* Encode a dictionary of query parameters.
|
||||||
@@ -708,3 +709,25 @@ module.exports.ensureNoTrailingSlash = function(url) {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Returns a promise which resolves with a given value after the given number of ms
|
||||||
|
module.exports.sleep = (ms, value) => new Promise((resolve => {
|
||||||
|
setTimeout(resolve, ms, value);
|
||||||
|
}));
|
||||||
|
|
||||||
|
module.exports.isNullOrUndefined = function(val) {
|
||||||
|
return val === null || val === undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns a Deferred
|
||||||
|
module.exports.defer = () => {
|
||||||
|
let resolve;
|
||||||
|
let reject;
|
||||||
|
|
||||||
|
const promise = new Promise((_resolve, _reject) => {
|
||||||
|
resolve = _resolve;
|
||||||
|
reject = _reject;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {resolve, reject, promise};
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user