Compare commits

...

85 Commits

Author SHA1 Message Date
RiotRobot 0d59963b53 v2.4.6 2019-12-09 11:23:37 +00:00
RiotRobot c669aafedb Prepare changelog for v2.4.6 2019-12-09 11:23:37 +00:00
RiotRobot 358f13500b v2.4.6-rc.1 2019-12-04 11:57:08 +00:00
RiotRobot 016f16954a Prepare changelog for v2.4.6-rc.1 2019-12-04 11:57:07 +00:00
Travis Ralston c1543545d2 Merge pull request #1102 from matrix-org/travis/aliases
Update alias handling
2019-12-03 13:54:27 -07:00
Travis Ralston 5da936d96a Fix tests 2019-12-03 13:38:40 -07:00
Travis Ralston 0dead73837 Update alias handling
Fixes https://github.com/vector-im/riot-web/issues/11551
2019-12-03 12:29:50 -07:00
Hubert Chathi 92ca2386ea Merge pull request #1096 from uhoreg/fix_sas_unit_test
increase timeout on flush to fix failing unit test
2019-11-28 17:19:41 -05:00
Hubert Chathi 59b25d6837 increase timeout on flush to fix failing unit test
also remove unused requests
2019-11-28 16:53:21 -05:00
Travis Ralston a6f7936311 Merge pull request #1095 from matrix-org/travis/fix-tests-18
Disable broken cross-signing test
2019-11-28 09:11:05 -07:00
Travis Ralston 7392b4de17 xit instead of comment 2019-11-27 19:23:59 -07:00
Travis Ralston 79b0a5fada Add issue to comment 2019-11-27 19:21:57 -07:00
Travis Ralston aee9442e52 Disable broken cross-signing test
I don't know why it's broken, but the two errors I can get out of it are "unknown device for verification" and "user_signing key does not match". Someone who knows a bit more about cross-signing will probably need to take a look at this one.

Fixes https://github.com/vector-im/riot-web/issues/11520 (technically)
Opened https://github.com/vector-im/riot-web/issues/11545 to fix this correctly.
2019-11-27 19:20:09 -07:00
Travis Ralston 569d5d1fce Merge pull request #1094 from matrix-org/travis/fix-tests-13
Fix a couple SAS tests
2019-11-27 09:24:27 -07:00
RiotRobot 6ea8003df2 Merge branch 'master' into develop 2019-11-27 10:28:14 +00:00
RiotRobot c8ab82010a v2.4.5 2019-11-27 10:17:54 +00:00
RiotRobot bf1bec9c6c Prepare changelog for v2.4.5 2019-11-27 10:17:54 +00:00
Travis Ralston e0c90ec9e3 Fix test flakes in SAS verification with old MAC
This has similar fixes to 7ad5021147

Part of https://github.com/vector-im/riot-web/issues/11520
2019-11-26 23:29:06 -07:00
Travis Ralston 7ad5021147 Fix SAS verification test
There's 3 things going on in this commit:
1. `this` is maintained in the tests. Some binds are added instead of the `.call(this, ...)` syntax.
2. We use the right `origSendToDevice`
3. We ensure `downloadKeys` is actually on the client

The combination of these 3 fixes makes the test pass.

Part of https://github.com/vector-im/riot-web/issues/11520
2019-11-26 23:24:37 -07:00
Matthew Hodgson fd73c3fb3a fix bogus logline 2019-11-27 01:19:17 +00:00
Travis Ralston e3dbf7cc41 Merge pull request #1093 from matrix-org/travis/fix-tests-3
Fix Olm unwedging test
2019-11-26 15:32:50 -07:00
Travis Ralston 18749c580e Fix Olm unwedging test
Deep within the crypto layers we call `getId()`, and when we don't have that function the async call on the emitter fails but doesn't fail the test. This manifests as a timeout because the code path that would call the thing blew up.
2019-11-26 15:06:56 -07:00
J. Ryan Stinnett 396db30fbf Update tests 2019-11-26 12:04:14 -07:00
J. Ryan Stinnett 6b38868de6 Relax identity server discovery checks to FAIL_PROMPT
As discussed in MSC2284, this relaxes the identity server discovery to a
`FAIL_PROMPT` state so that clients can choose to warn and continue.

Part of https://github.com/vector-im/riot-web/issues/11102
Implements https://github.com/matrix-org/matrix-doc/pull/2284
2019-11-26 12:04:07 -07:00
Matthew Hodgson 01a46ad880 log outbound to_device msgs for tracking keyshares 2019-11-26 12:03:34 -07:00
Matthew Hodgson 46f8251e94 s/console/logger/ as per review 2019-11-26 12:03:28 -07:00
Matthew Hodgson 77f882f45a log keyshare ID 2019-11-26 12:03:24 -07:00
Matthew Hodgson 8c72fd104e lint 2019-11-26 12:03:20 -07:00
Matthew Hodgson 549656884b expand e2ee logging to better debug UISIs 2019-11-26 12:03:11 -07:00
Matthew Hodgson 5b8b0a8aa3 log outbound to_device msgs for tracking keyshares 2019-11-26 18:35:25 +00:00
Travis Ralston b1924d4db6 Merge pull request #1089 from matrix-org/travis/upgrade-notifications
Fix empty string handling in push notifications
2019-11-26 11:00:24 -07:00
Travis Ralston 1b877118ef Only do one type check 2019-11-26 10:31:04 -07:00
Travis Ralston 682a5daf1c Merge branch 'develop' into travis/upgrade-notifications 2019-11-26 10:29:40 -07:00
Matthew Hodgson fcbfaac1fd Merge pull request #1090 from matrix-org/matthew/more_e2ee_logging
expand e2ee logging to better debug UISIs
2019-11-26 10:18:28 +00:00
Matthew Hodgson 3787b6f1c7 s/console/logger/ as per review 2019-11-26 09:07:23 +00:00
Matthew Hodgson 6e08835496 log keyshare ID 2019-11-26 01:58:04 +00:00
Matthew Hodgson 191695da5a lint 2019-11-26 01:41:59 +00:00
Matthew Hodgson 2215087f96 expand e2ee logging to better debug UISIs 2019-11-26 01:17:12 +00:00
Michael Telatynski 32234ee7fc Merge pull request #1087 from matrix-org/t3chguy/remove_bluebird_11
Remove Bluebird: phase 2
2019-11-26 00:03:22 +00:00
Travis Ralston aa37f697bf Fix empty string handling in push notifications
Fixes https://github.com/vector-im/riot-web/issues/11460

Empty strings are falsey, and the state key match for a tombstone event is an empty string. Ergo, nothing happens because all the conditions fail.
2019-11-25 16:35:27 -07:00
Michael Telatynski 057303d57c s/beforeEach/beforeAll/ for Olm.init() and cleanup sas.spec.js 2019-11-25 13:26:10 +00:00
RiotRobot ccc85d98e2 Merge branch 'master' into develop 2019-11-25 13:24:08 +00:00
Michael Telatynski 7fb807919c Stop using bluebird .returns and .spread 2019-11-25 12:31:46 +00:00
Michael Telatynski bd8f8ef28d Replace yet more deferreds 2019-11-25 11:28:09 +00:00
Michael Telatynski 3901a381cc replace another couple of deferreds 2019-11-25 11:18:32 +00:00
J. Ryan Stinnett 12f6e51ef6 Merge pull request #1062 from matrix-org/jryans/identity-disco-opt
Relax identity server discovery checks to FAIL_PROMPT
2019-11-25 10:48:53 +00:00
Travis Ralston aa8454e30a Merge pull request #1061 from beaclnd92/develop
Fix incorrect return value of MatrixClient.prototype.uploadKeys
2019-11-24 22:19:09 -07:00
Travis Ralston 6b70230e0d Merge branch 'develop' into develop2-test 2019-11-24 22:13:53 -07:00
Michael Telatynski 5e0ba9971c nothing works anymore :(( 2019-11-23 12:18:39 +00:00
David Baker fa577c9475 Merge pull request #1086 from matrix-org/dbkr/fix_calls_in_e2e_rooms
Fix calls in e2e rooms
2019-11-22 17:48:33 +00:00
Bruno Windels 11a958b8ca Merge pull request #1085 from matrix-org/bwindels/verif-toasts
Monitor verification request over DM as well
2019-11-22 16:39:07 +00:00
Bruno Windels 6952db6762 no need to filter here anymore when listening for timeline, also remove obsolete docs 2019-11-22 17:32:37 +01:00
Bruno Windels 51898cffe8 add comments for timeout constants 2019-11-22 17:31:48 +01:00
David Baker d8337d703d Use the right variable name 2019-11-22 15:59:36 +00:00
David Baker adac0c353c Fix calls in e2e rooms
Events will be decrypted after the sync event, so we were having
to wait until the next sync event before they got processed.
2019-11-22 15:56:06 +00:00
Michael Telatynski 04fca16420 Stop using Bluebird promise::value 2019-11-22 15:36:42 +00:00
Bruno Windels ca89b6e7a8 use adapter for to_device requests to have same api as for verif over DM
Riot doesn't fully implement to_device verifications, e.g.
it doesn't send a `request` but immediately sends a `start` event.

Because of this, `crypto.verification.request` doesn't get fired,
as that code path doesn't get triggered. This is why MatrixChat
in the react-sdk was listening for `crypto.verification.start`.

Verification over DM *does* send a `request` event first, so
to have the same API for both methods, we fake the request and
wrap the verifier in it.
2019-11-22 16:12:19 +01:00
Bruno Windels ac1173c628 also emit crypto.verification.request for verification over DM 2019-11-22 16:11:49 +01:00
Michael Telatynski 0a0ae111f6 replace Bluebird::map 2019-11-22 15:03:03 +00:00
David Baker 71a6e015f4 Merge pull request #1084 from matrix-org/dbkr/remove_check
Remove 'check' npm script
2019-11-22 10:53:48 +00:00
David Baker e8bbb8a1cc Remove 'check' npm script
...whose only purpose was to run the tests without coverage because
the coverage tool was awful and ruined all the line numbers (moreso).
2019-11-21 19:30:46 +00:00
David Baker 04764998cb Merge pull request #1083 from matrix-org/dbkr/advanced_anti_chirp
Always process call events in batches
2019-11-21 19:22:24 +00:00
David Baker 5262d716e4 Lint 2019-11-21 19:10:27 +00:00
David Baker 7addacba38 Always process call events in batches
We had a bunch of logic in place to suppress calls if the answer
or hangup had already arrived, but we only used it on startup.
This extends this logic to happen all the time, which means we'll
also do the same suppression if a call happenned while we were
offline.
2019-11-21 18:56:37 +00:00
David Baker 8f8c9c8ec0 Merge pull request #1082 from matrix-org/dbkr/death_to_the_reload_chirp
Fix ringing chirp on loading
2019-11-21 18:20:20 +00:00
David Baker 3a9832a8c6 Fix ringing chirp on loading
We have a heap of logic to do the right thing when a call event
arrives, eg. wait until the client is ready so we can see if there's
already been a hangup event before saying there's an incoming call.

Unfortunately it only waited until the client was prepared, not
until it was syncing, so any events that arrived from the server
in the catchup sync bypassed this logic altogether.

This was probably broken back when we introduced the sync accumulator,
since before then, "PREPARED" meant, "done initialsync" rather than
"loaded fake initialsync from storage".

Fixes https://github.com/vector-im/riot-web/issues/3572
2019-11-21 17:56:04 +00:00
Bruno Windels 4a40c10d4c add helper method on event for current age according to local clock 2019-11-21 17:13:43 +01:00
Michael Telatynski 58f8ca7d66 Merge pull request #1081 from matrix-org/t3chguy/remove_bluebird_2
Remove *most* bluebird specific things
2019-11-21 11:34:19 +00:00
Michael Telatynski 4d950fec66 fixxy
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-21 10:59:18 +00:00
Michael Telatynski b4f68f4fc6 Stop using Bluebird promise::nodeify
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-21 10:43:58 +00:00
Michael Telatynski ac742aad70 use Bluebird in promise utils sleep so it has .done and .nodeify
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-21 10:14:06 +00:00
Michael Telatynski 53d225a1d1 fix stub timelineSet for timeline-window.spec
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-21 10:09:36 +00:00
Michael Telatynski 549b0f9313 Stop using Bluebird.delay and Bluebird promise::delay
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-21 10:05:59 +00:00
Michael Telatynski 2ce106382a Stop using Bluebird promise::isFulfilled()
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-21 10:01:16 +00:00
Michael Telatynski b44f43e5db fix import in relations.js
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-21 09:45:00 +00:00
Michael Telatynski 2321b9a04e Merge pull request #1080 from matrix-org/t3chguy/jest
Switch to Jest
2019-11-20 22:03:25 +00:00
Michael Telatynski 3bd518cf7f update buildkite pipeline name
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-20 21:59:50 +00:00
Michael Telatynski c57109c2f3 tidy up
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-20 21:16:11 +00:00
Michael Telatynski 522640edd9 rip out lolex also
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-20 21:05:21 +00:00
Michael Telatynski 5fc0629201 fix expect calls
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-20 20:19:54 +00:00
Michael Telatynski 26edd7431a fix yarn scripts test
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-20 19:56:50 +00:00
Michael Telatynski fd58957b06 migrate to jest from mocha+expect+istanbul
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2019-11-20 19:52:50 +00:00
J. Ryan Stinnett 91df096698 Update tests 2019-11-01 14:10:16 +00:00
J. Ryan Stinnett e8fd0498a7 Relax identity server discovery checks to FAIL_PROMPT
As discussed in MSC2284, this relaxes the identity server discovery to a
`FAIL_PROMPT` state so that clients can choose to warn and continue.

Part of https://github.com/vector-im/riot-web/issues/11102
Implements https://github.com/matrix-org/matrix-doc/pull/2284
2019-11-01 11:24:51 +00:00
ZengJing 7973b99f50 Fix incorrect return value of MatrixClient.prototype.uploadKeys
Signed-off-by: Zeng Jing <beaclnd92@gmail.com>
2019-11-01 09:25:50 +08:00
65 changed files with 2420 additions and 1226 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ steps:
- docker#v3.0.1:
image: "node:10"
- label: ":karma: Tests"
- label: ":jest: Tests"
command:
- "yarn install"
- "yarn test"
+2
View File
@@ -12,10 +12,12 @@ module.exports = {
// babel's transform-runtime converts references to ES6 globals such as
// Promise and Map to core-js polyfills, so we can use ES6 globals.
es6: true,
jest: true,
},
extends: ["eslint:recommended", "google"],
plugins: [
"babel",
"jest",
],
rules: {
// rules we've always adhered to or now do
+52
View File
@@ -1,3 +1,55 @@
Changes in [2.4.6](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.6) (2019-12-09)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.6-rc.1...v2.4.6)
* No changes since rc.1
Changes in [2.4.6-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.6-rc.1) (2019-12-04)
==========================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.5...v2.4.6-rc.1)
* Update alias handling
[\#1102](https://github.com/matrix-org/matrix-js-sdk/pull/1102)
* increase timeout on flush to fix failing unit test
[\#1096](https://github.com/matrix-org/matrix-js-sdk/pull/1096)
* Disable broken cross-signing test
[\#1095](https://github.com/matrix-org/matrix-js-sdk/pull/1095)
* Fix a couple SAS tests
[\#1094](https://github.com/matrix-org/matrix-js-sdk/pull/1094)
* Fix Olm unwedging test
[\#1093](https://github.com/matrix-org/matrix-js-sdk/pull/1093)
* Fix empty string handling in push notifications
[\#1089](https://github.com/matrix-org/matrix-js-sdk/pull/1089)
* expand e2ee logging to better debug UISIs
[\#1090](https://github.com/matrix-org/matrix-js-sdk/pull/1090)
* Remove Bluebird: phase 2
[\#1087](https://github.com/matrix-org/matrix-js-sdk/pull/1087)
* Relax identity server discovery checks to FAIL_PROMPT
[\#1062](https://github.com/matrix-org/matrix-js-sdk/pull/1062)
* Fix incorrect return value of MatrixClient.prototype.uploadKeys
[\#1061](https://github.com/matrix-org/matrix-js-sdk/pull/1061)
* Fix calls in e2e rooms
[\#1086](https://github.com/matrix-org/matrix-js-sdk/pull/1086)
* Monitor verification request over DM as well
[\#1085](https://github.com/matrix-org/matrix-js-sdk/pull/1085)
* Remove 'check' npm script
[\#1084](https://github.com/matrix-org/matrix-js-sdk/pull/1084)
* Always process call events in batches
[\#1083](https://github.com/matrix-org/matrix-js-sdk/pull/1083)
* Fix ringing chirp on loading
[\#1082](https://github.com/matrix-org/matrix-js-sdk/pull/1082)
* Remove *most* bluebird specific things
[\#1081](https://github.com/matrix-org/matrix-js-sdk/pull/1081)
* Switch to Jest
[\#1080](https://github.com/matrix-org/matrix-js-sdk/pull/1080)
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)
+6 -10
View File
@@ -1,14 +1,11 @@
{
"name": "matrix-js-sdk",
"version": "2.4.4",
"version": "2.4.6",
"description": "Matrix Client-Server SDK for Javascript",
"main": "index.js",
"scripts": {
"test:build": "babel -s -d specbuild spec",
"test:run": "istanbul cover --report text --report cobertura --config .istanbul.yml -i \"lib/**/*.js\" node_modules/mocha/bin/_mocha -- --recursive specbuild --colors",
"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",
"test:watch": "jest spec/ --coverage --testEnvironment node --watch",
"test": "jest spec/ --coverage --testEnvironment node",
"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:watch": "babel -s -w --skip-initial-build -d lib src",
@@ -65,6 +62,7 @@
"devDependencies": {
"babel-cli": "^6.18.0",
"babel-eslint": "^10.0.1",
"babel-jest": "^23.6.0",
"babel-plugin-transform-async-to-bluebird": "^1.1.1",
"babel-plugin-transform-class-properties": "^6.24.1",
"babel-plugin-transform-runtime": "^6.23.0",
@@ -75,13 +73,11 @@
"eslint": "^5.12.0",
"eslint-config-google": "^0.7.1",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-jest": "^23.0.4",
"exorcist": "^1.0.1",
"expect": "^1.20.2",
"istanbul": "^0.4.5",
"jest": "^23.6.0",
"jsdoc": "^3.5.5",
"lolex": "^1.5.2",
"matrix-mock-request": "^1.2.3",
"mocha": "^6.2.1",
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
"rimraf": "^3.0.0",
"source-map-support": "^0.5.13",
-5
View File
@@ -1,5 +0,0 @@
module.exports = {
env: {
mocha: true,
},
}
+1 -2
View File
@@ -24,7 +24,6 @@ import './olm-loader';
import sdk from '..';
import testUtils from './test-utils';
import MockHttpBackend from 'matrix-mock-request';
import expect from 'expect';
import Promise from 'bluebird';
import LocalStorageCryptoStore from '../lib/crypto/store/localStorage-crypto-store';
import logger from '../src/logger';
@@ -159,7 +158,7 @@ TestClient.prototype.awaitOneTimeKeyUpload = function() {
.respond(200, (path, content) => {
expect(content.device_keys).toBe(undefined);
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,
Object.keys(content.one_time_keys).length);
this.oneTimeKeys = content.one_time_keys;
-3
View File
@@ -15,7 +15,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import expect from 'expect';
import Promise from 'bluebird';
import TestClient from '../TestClient';
@@ -88,8 +87,6 @@ describe("DeviceList management:", 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
// another TestClient.
sessionStoreBackend = new testUtils.MockStorageApi();
+37 -43
View File
@@ -30,7 +30,6 @@ import 'source-map-support/register';
// load olm before the sdk if possible
import '../olm-loader';
import expect from 'expect';
const sdk = require("../..");
import Promise from 'bluebird';
const utils = require("../../lib/utils");
@@ -56,7 +55,7 @@ function bobUploadsDeviceKeys() {
bobTestClient.client.uploadKeys(),
bobTestClient.httpBackend.flush(),
]).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()
.then(expectAliClaimKeys)
.then(expectAliSendMessageRequest),
]).spread(function(_, ciphertext) {
]).then(function([_, ciphertext]) {
return ciphertext;
});
}
@@ -219,7 +218,7 @@ function aliSendsMessage() {
return Promise.all([
sendMessage(aliTestClient.client),
expectAliSendMessageRequest(),
]).spread(function(_, ciphertext) {
]).then(function([_, ciphertext]) {
return ciphertext;
});
}
@@ -235,7 +234,7 @@ function bobSendsReplyMessage() {
sendMessage(bobTestClient.client),
expectBobQueryKeys()
.then(expectBobSendMessageRequest),
]).spread(function(_, ciphertext) {
]).then(function([_, ciphertext]) {
return ciphertext;
});
}
@@ -280,16 +279,17 @@ function sendMessage(client) {
function expectSendMessageRequest(httpBackend) {
const path = "/send/m.room.encrypted/";
const deferred = Promise.defer();
httpBackend.when("PUT", path).respond(200, function(path, content) {
deferred.resolve(content);
return {
event_id: "asdfgh",
};
const prom = new Promise((resolve) => {
httpBackend.when("PUT", path).respond(200, function(path, content) {
resolve(content);
return {
event_id: "asdfgh",
};
});
});
// 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() {
@@ -406,8 +406,6 @@ describe("MatrixClient crypto", function() {
}
beforeEach(async function() {
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
aliTestClient = new TestClient(aliUserId, aliDeviceId, aliAccessToken);
await aliTestClient.client.initCrypto();
@@ -430,15 +428,14 @@ describe("MatrixClient crypto", function() {
.then(bobUploadsDeviceKeys);
});
it("Ali downloads Bobs device keys", function(done) {
Promise.resolve()
it("Ali downloads Bobs device keys", function() {
return Promise.resolve()
.then(bobUploadsDeviceKeys)
.then(aliDownloadsKeys)
.nodeify(done);
.then(aliDownloadsKeys);
});
it("Ali gets keys with an invalid signature", function(done) {
Promise.resolve()
it("Ali gets keys with an invalid signature", function() {
return Promise.resolve()
.then(bobUploadsDeviceKeys)
.then(function() {
// tamper bob's keys
@@ -455,11 +452,10 @@ describe("MatrixClient crypto", function() {
}).then((devices) => {
// should get an empty list
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 bobDeviceKeys = {
@@ -488,7 +484,7 @@ describe("MatrixClient crypto", function() {
return {device_keys: result};
});
Promise.all([
return Promise.all([
aliTestClient.client.downloadKeys([bobUserId, eveUserId]),
aliTestClient.httpBackend.flush("/keys/query", 1),
]).then(function() {
@@ -496,14 +492,14 @@ describe("MatrixClient crypto", function() {
aliTestClient.client.getStoredDevicesForUser(bobUserId),
aliTestClient.client.getStoredDevicesForUser(eveUserId),
]);
}).spread((bobDevices, eveDevices) => {
}).then(([bobDevices, eveDevices]) => {
// should get an empty list
expect(bobDevices).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 = {
algorithms: ['m.olm.v1.curve25519-aes-sha2', 'm.megolm.v1.aes-sha2'],
device_id: 'bad_device',
@@ -530,7 +526,7 @@ describe("MatrixClient crypto", function() {
return {device_keys: result};
});
Promise.all([
return Promise.all([
aliTestClient.client.downloadKeys([bobUserId]),
aliTestClient.httpBackend.flush("/keys/query", 1),
]).then(function() {
@@ -538,7 +534,7 @@ describe("MatrixClient crypto", function() {
}).then((devices) => {
// should get an empty list
expect(devices).toEqual([]);
}).nodeify(done);
});
});
@@ -548,19 +544,18 @@ describe("MatrixClient crypto", function() {
.then(() => bobTestClient.awaitOneTimeKeyUpload())
.then((keys) => {
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]: {}}});
Promise.resolve()
return Promise.resolve()
.then(() => aliTestClient.start())
.then(() => bobTestClient.start())
.then(() => firstSync(aliTestClient))
.then(aliEnablesEncryption)
.then(aliSendsFirstMessage)
.nodeify(done);
.then(aliSendsFirstMessage);
});
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]: {}}});
Promise.resolve()
return Promise.resolve()
.then(() => aliTestClient.start())
.then(() => bobTestClient.start())
.then(() => firstSync(aliTestClient))
@@ -645,12 +640,12 @@ describe("MatrixClient crypto", function() {
expect(sentContent.ciphertext).toEqual({});
});
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]: {}}});
Promise.resolve()
return Promise.resolve()
.then(() => aliTestClient.start())
.then(() => bobTestClient.start())
.then(() => firstSync(aliTestClient))
@@ -658,8 +653,7 @@ describe("MatrixClient crypto", function() {
.then(aliSendsFirstMessage)
.then(bobRecvMessage)
.then(aliSendsMessage)
.then(bobRecvMessage)
.nodeify(done);
.then(bobRecvMessage);
});
it("Bob replies to the message", function() {
@@ -753,9 +747,9 @@ describe("MatrixClient crypto", function() {
.then(() => httpBackend.when("POST", "/keys/upload")
.respond(200, (path, content) => {
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)
.toBeGreaterThanOrEqualTo(1);
.toBeGreaterThanOrEqual(1);
logger.log('received %i one-time keys',
Object.keys(content.one_time_keys).length);
// cancel futher calls by telling the client
@@ -4,7 +4,6 @@ const sdk = require("../..");
const HttpBackend = require("matrix-mock-request");
const utils = require("../test-utils");
import expect from 'expect';
import Promise from 'bluebird';
describe("MatrixClient events", function() {
@@ -15,7 +14,6 @@ describe("MatrixClient events", function() {
const selfAccessToken = "aseukfgwef";
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
client = sdk.createClient({
@@ -219,7 +217,7 @@ describe("MatrixClient events", function() {
client.on("RoomState.events", function(event, state) {
eventsInvokeCount++;
const index = roomStateEventTypes.indexOf(event.getType());
expect(index).toNotEqual(
expect(index).not.toEqual(
-1, "Unexpected room state event type: " + event.getType(),
);
if (index >= 0) {
+34 -39
View File
@@ -83,18 +83,19 @@ function startClient(httpBackend, client) {
client.startClient();
// set up a promise which will resolve once the client is initialised
const deferred = Promise.defer();
client.on("sync", function(state) {
logger.log("sync", state);
if (state != "SYNCING") {
return;
}
deferred.resolve();
const prom = new Promise((resolve) => {
client.on("sync", function(state) {
logger.log("sync", state);
if (state != "SYNCING") {
return;
}
resolve();
});
});
return Promise.all([
httpBackend.flushAllExpected(),
deferred.promise,
prom,
]);
}
@@ -103,7 +104,6 @@ describe("getEventTimeline support", function() {
let client;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
});
@@ -115,21 +115,20 @@ describe("getEventTimeline support", function() {
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({
baseUrl: baseUrl,
userId: userId,
accessToken: accessToken,
});
startClient(httpBackend, client,
).then(function() {
return startClient(httpBackend, client).then(function() {
const room = client.getRoom(roomId);
const timelineSet = room.getTimelineSets()[0];
expect(function() {
client.getEventTimeline(timelineSet, "event");
}).toThrow();
}).nodeify(done);
});
});
it("timeline support works when enabled", function() {
@@ -145,13 +144,13 @@ describe("getEventTimeline support", function() {
const timelineSet = room.getTimelineSets()[0];
expect(function() {
client.getEventTimeline(timelineSet, "event");
}).toNotThrow();
}).not.toThrow();
});
});
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
client = sdk.createClient({
baseUrl: baseUrl,
@@ -160,8 +159,7 @@ describe("getEventTimeline support", function() {
});
let room;
startClient(httpBackend, client,
).then(function() {
return startClient(httpBackend, client).then(function() {
room = client.getRoom(roomId);
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[1].event).toEqual(EVENTS[1]);
expect(room.oldState.paginationToken).toEqual("pagin_end");
}).nodeify(done);
});
});
});
import expect from 'expect';
describe("MatrixClient event timelines", function() {
let client = null;
let httpBackend = null;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
@@ -349,25 +344,25 @@ describe("MatrixClient event timelines", function() {
};
});
const deferred = Promise.defer();
client.on("sync", function() {
client.getEventTimeline(timelineSet, EVENTS[2].event_id,
).then(function(tl) {
expect(tl.getEvents().length).toEqual(4);
expect(tl.getEvents()[0].event).toEqual(EVENTS[1]);
expect(tl.getEvents()[1].event).toEqual(EVENTS[2]);
expect(tl.getEvents()[3].event).toEqual(EVENTS[3]);
expect(tl.getPaginationToken(EventTimeline.BACKWARDS))
.toEqual("start_token");
// expect(tl.getPaginationToken(EventTimeline.FORWARDS))
// .toEqual("s_5_4");
}).done(() => deferred.resolve(),
(e) => deferred.reject(e));
const prom = new Promise((resolve, reject) => {
client.on("sync", function() {
client.getEventTimeline(timelineSet, EVENTS[2].event_id,
).then(function(tl) {
expect(tl.getEvents().length).toEqual(4);
expect(tl.getEvents()[0].event).toEqual(EVENTS[1]);
expect(tl.getEvents()[1].event).toEqual(EVENTS[2]);
expect(tl.getEvents()[3].event).toEqual(EVENTS[3]);
expect(tl.getPaginationToken(EventTimeline.BACKWARDS))
.toEqual("start_token");
// expect(tl.getPaginationToken(EventTimeline.FORWARDS))
// .toEqual("s_5_4");
}).done(resolve, reject);
});
});
return Promise.all([
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
// a state event, followed by a redaction thereof
@@ -729,7 +724,7 @@ describe("MatrixClient event timelines", function() {
};
httpBackend.when("GET", "/sync").respond(200, syncData);
Promise.all([
return Promise.all([
httpBackend.flushAllExpected(),
utils.syncPromise(client),
]).then(function() {
@@ -765,6 +760,6 @@ describe("MatrixClient event timelines", function() {
const room = client.getRoom(roomId);
const tl = room.getLiveTimeline();
expect(tl.getEvents().length).toEqual(1);
}).nodeify(done);
});
});
});
+23 -22
View File
@@ -9,8 +9,6 @@ const Filter = publicGlobals.Filter;
const utils = require("../test-utils");
const MockStorageApi = require("../MockStorageApi");
import expect from 'expect';
describe("MatrixClient", function() {
const baseUrl = "http://localhost.or.something";
let client = null;
@@ -21,7 +19,6 @@ describe("MatrixClient", function() {
const accessToken = "aseukfgwef";
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
store = new MemoryStore();
@@ -46,7 +43,7 @@ describe("MatrixClient", function() {
describe("uploadContent", function() {
const buf = new Buffer('hello world');
it("should upload the file", function(done) {
it("should upload the file", function() {
httpBackend.when(
"POST", "/_matrix/media/r0/upload",
).check(function(req) {
@@ -74,25 +71,26 @@ describe("MatrixClient", function() {
expect(uploads[0].promise).toBe(prom);
expect(uploads[0].loaded).toEqual(0);
prom.then(function(response) {
const prom2 = prom.then(function(response) {
// for backwards compatibility, we return the raw JSON
expect(response).toEqual("content");
const uploads = client.getCurrentUploads();
expect(uploads.length).toEqual(0);
}).nodeify(done);
});
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(
"POST", "/_matrix/media/r0/upload",
).check(function(req) {
expect(req.opts.json).toBeFalsy();
}).respond(200, { "content_uri": "uri" });
client.uploadContent({
const prom = client.uploadContent({
stream: buf,
name: "hi.txt",
type: "text/plain",
@@ -100,12 +98,13 @@ describe("MatrixClient", function() {
rawResponse: false,
}).then(function(response) {
expect(response.content_uri).toEqual("uri");
}).nodeify(done);
});
httpBackend.flush();
return prom;
});
it("should parse errors into a MatrixError", function(done) {
it("should parse errors into a MatrixError", function() {
httpBackend.when(
"POST", "/_matrix/media/r0/upload",
).check(function(req) {
@@ -116,7 +115,7 @@ describe("MatrixClient", function() {
"error": "broken",
});
client.uploadContent({
const prom = client.uploadContent({
stream: buf,
name: "hi.txt",
type: "text/plain",
@@ -126,12 +125,13 @@ describe("MatrixClient", function() {
expect(error.httpStatus).toEqual(400);
expect(error.errcode).toEqual("M_SNAFU");
expect(error.message).toEqual("broken");
}).nodeify(done);
});
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({
stream: buf,
name: "hi.txt",
@@ -143,17 +143,18 @@ describe("MatrixClient", function() {
expect(uploads[0].promise).toBe(prom);
expect(uploads[0].loaded).toEqual(0);
prom.then(function(response) {
const prom2 = prom.then(function(response) {
throw Error("request not aborted");
}, function(error) {
expect(error).toEqual("aborted");
const uploads = client.getCurrentUploads();
expect(uploads.length).toEqual(0);
}).nodeify(done);
});
const r = client.cancelUpload(prom);
expect(r).toBe(true);
return prom2;
});
});
@@ -310,7 +311,7 @@ describe("MatrixClient", function() {
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";
// ed25519key = client.getDeviceEd25519Key();
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, {
verified: 0, // DeviceVerification.UNVERIFIED
keys: { "ed25519:dev1": ed25519key },
@@ -386,26 +387,26 @@ describe("MatrixClient", function() {
algorithms: ["2"],
unsigned: { "ghi": "def" },
});
}).nodeify(done);
});
httpBackend.flush();
return prom;
});
});
describe("deleteDevice", function() {
const auth = {a: 1};
it("should pass through an auth dict", function(done) {
it("should pass through an auth dict", function() {
httpBackend.when(
"DELETE", "/_matrix/client/r0/devices/my_device",
).check(function(req) {
expect(req.data).toEqual({auth: auth});
}).respond(200);
client.deleteDevice(
"my_device", auth,
).nodeify(done);
const prom = client.deleteDevice("my_device", auth);
httpBackend.flush();
return prom;
});
});
});
+1 -3
View File
@@ -5,7 +5,6 @@ const MatrixClient = sdk.MatrixClient;
const HttpBackend = require("matrix-mock-request");
const utils = require("../test-utils");
import expect from 'expect';
import Promise from 'bluebird';
describe("MatrixClient opts", function() {
@@ -58,7 +57,6 @@ describe("MatrixClient opts", function() {
};
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
});
@@ -101,7 +99,7 @@ describe("MatrixClient opts", function() {
"m.room.create",
];
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(),
);
expectedEventTypes.splice(
@@ -4,11 +4,8 @@ import Promise from 'bluebird';
const sdk = require("../..");
const HttpBackend = require("matrix-mock-request");
const utils = require("../test-utils");
const EventStatus = sdk.EventStatus;
import expect from 'expect';
describe("MatrixClient retrying", function() {
const baseUrl = "http://localhost.or.something";
let client = null;
@@ -20,7 +17,6 @@ describe("MatrixClient retrying", function() {
let room;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
scheduler = new sdk.MatrixScheduler();
@@ -6,7 +6,6 @@ const HttpBackend = require("matrix-mock-request");
const utils = require("../test-utils");
import Promise from 'bluebird';
import expect from 'expect';
describe("MatrixClient room timelines", function() {
const baseUrl = "http://localhost.or.something";
@@ -103,8 +102,7 @@ describe("MatrixClient room timelines", function() {
});
}
beforeEach(function(done) {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
beforeEach(function() {
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
client = sdk.createClient({
@@ -122,9 +120,9 @@ describe("MatrixClient room timelines", function() {
return NEXT_SYNC_DATA;
});
client.startClient();
httpBackend.flush("/pushrules").then(function() {
return httpBackend.flush("/pushrules").then(function() {
return httpBackend.flush("/filter");
}).nodeify(done);
});
});
afterEach(function() {
+8 -10
View File
@@ -6,7 +6,6 @@ const utils = require("../test-utils");
const MatrixEvent = sdk.MatrixEvent;
const EventTimeline = sdk.EventTimeline;
import expect from 'expect';
import Promise from 'bluebird';
describe("MatrixClient syncing", function() {
@@ -23,7 +22,6 @@ describe("MatrixClient syncing", function() {
const roomTwo = "!bar:localhost";
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new HttpBackend();
sdk.request(httpBackend.requestFn);
client = sdk.createClient({
@@ -528,7 +526,7 @@ describe("MatrixClient syncing", function() {
awaitSyncEvent(),
]).then(function() {
const room = client.getRoom(roomTwo);
expect(room).toExist();
expect(room).toBeDefined();
const tok = room.getLiveTimeline()
.getPaginationToken(EventTimeline.BACKWARDS);
expect(tok).toEqual("roomtwotok");
@@ -693,12 +691,12 @@ describe("MatrixClient syncing", function() {
include_leave: true }});
}).respond(200, { filter_id: "another_id" });
const defer = Promise.defer();
httpBackend.when("GET", "/sync").check(function(req) {
expect(req.queryParams.filter).toEqual("another_id");
defer.resolve();
}).respond(200, {});
const prom = new Promise((resolve) => {
httpBackend.when("GET", "/sync").check(function(req) {
expect(req.queryParams.filter).toEqual("another_id");
resolve();
}).respond(200, {});
});
client.syncLeftRooms();
@@ -709,7 +707,7 @@ describe("MatrixClient syncing", function() {
// flush the syncs
return httpBackend.flushAllExpected();
}),
defer.promise,
prom,
]);
});
+1 -4
View File
@@ -18,7 +18,6 @@ limitations under the License.
const anotherjson = require('another-json');
import Promise from 'bluebird';
import expect from 'expect';
const utils = require('../../lib/utils');
const testUtils = require('../test-utils');
@@ -283,8 +282,6 @@ describe("megolm", function() {
}
beforeEach(async function() {
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
aliceTestClient = new TestClient(
"@alice:localhost", "xzcvb", "akjgkrgjs",
);
@@ -713,7 +710,7 @@ describe("megolm", function() {
'PUT', '/send/',
).respond(200, function(path, content) {
logger.log('/send:', content);
expect(content.session_id).toNotEqual(megolmSessionId);
expect(content.session_id).not.toEqual(megolmSessionId);
return {
event_id: '$event_id',
};
+6 -19
View File
@@ -1,5 +1,4 @@
"use strict";
import expect from 'expect';
import Promise from 'bluebird';
// 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.
* @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
try {
if (constr.prototype[key] instanceof Function) {
result[key] = expect.createSpy();
result[key] = jest.fn();
}
} catch (ex) {
// Direct access to some non-function fields of DOM prototypes may
@@ -377,9 +364,9 @@ module.exports.setHttpResponses = function setHttpResponses(
client._http = [
"authedRequest", "authedRequestWithPrefix", "getContentUri",
"request", "requestWithPrefix", "uploadContent",
].reduce((r, k) => {r[k] = expect.createSpy(); return r;}, {});
client._http.authedRequest.andCall(httpReq);
client._http.authedRequestWithPrefix.andCall(httpReq);
client._http.requestWithPrefix.andCall(httpReq);
client._http.request.andCall(httpReq);
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
client._http.authedRequest.mockImplementation(httpReq);
client._http.authedRequestWithPrefix.mockImplementation(httpReq);
client._http.requestWithPrefix.mockImplementation(httpReq);
client._http.request.mockImplementation(httpReq);
};
+20 -23
View File
@@ -18,11 +18,9 @@ limitations under the License.
import 'source-map-support/register';
import Promise from 'bluebird';
const sdk = require("../..");
const utils = require("../test-utils");
const AutoDiscovery = sdk.AutoDiscovery;
import expect from 'expect';
import MockHttpBackend from "matrix-mock-request";
@@ -30,7 +28,6 @@ describe("AutoDiscovery", function() {
let httpBackend = null;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
httpBackend = new MockHttpBackend();
sdk.request(httpBackend.requestFn);
});
@@ -416,8 +413,8 @@ describe("AutoDiscovery", function() {
]);
});
it("should return FAIL_ERROR when the identity server configuration is wrong " +
"(missing base_url)", function() {
it("should return SUCCESS / FAIL_PROMPT when the identity server configuration " +
"is wrong (missing base_url)", function() {
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
expect(req.opts.uri)
.toEqual("https://chat.example.org/_matrix/client/versions");
@@ -438,14 +435,14 @@ describe("AutoDiscovery", function() {
AutoDiscovery.findClientConfig("example.org").then((conf) => {
const expected = {
"m.homeserver": {
state: "FAIL_ERROR",
error: AutoDiscovery.ERROR_INVALID_IS,
state: "SUCCESS",
error: null,
// We still expect the base_url to be here for debugging purposes.
base_url: "https://chat.example.org",
},
"m.identity_server": {
state: "FAIL_ERROR",
state: "FAIL_PROMPT",
error: AutoDiscovery.ERROR_INVALID_IS_BASE_URL,
base_url: null,
},
@@ -456,8 +453,8 @@ describe("AutoDiscovery", function() {
]);
});
it("should return FAIL_ERROR when the identity server configuration is wrong " +
"(empty base_url)", function() {
it("should return SUCCESS / FAIL_PROMPT when the identity server configuration " +
"is wrong (empty base_url)", function() {
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
expect(req.opts.uri)
.toEqual("https://chat.example.org/_matrix/client/versions");
@@ -478,14 +475,14 @@ describe("AutoDiscovery", function() {
AutoDiscovery.findClientConfig("example.org").then((conf) => {
const expected = {
"m.homeserver": {
state: "FAIL_ERROR",
error: AutoDiscovery.ERROR_INVALID_IS,
state: "SUCCESS",
error: null,
// We still expect the base_url to be here for debugging purposes.
base_url: "https://chat.example.org",
},
"m.identity_server": {
state: "FAIL_ERROR",
state: "FAIL_PROMPT",
error: AutoDiscovery.ERROR_INVALID_IS_BASE_URL,
base_url: null,
},
@@ -496,8 +493,8 @@ describe("AutoDiscovery", function() {
]);
});
it("should return FAIL_ERROR when the identity server configuration is wrong " +
"(validation error: 404)", function() {
it("should return SUCCESS / FAIL_PROMPT when the identity server configuration " +
"is wrong (validation error: 404)", function() {
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
expect(req.opts.uri)
.toEqual("https://chat.example.org/_matrix/client/versions");
@@ -519,14 +516,14 @@ describe("AutoDiscovery", function() {
AutoDiscovery.findClientConfig("example.org").then((conf) => {
const expected = {
"m.homeserver": {
state: "FAIL_ERROR",
error: AutoDiscovery.ERROR_INVALID_IS,
state: "SUCCESS",
error: null,
// We still expect the base_url to be here for debugging purposes.
base_url: "https://chat.example.org",
},
"m.identity_server": {
state: "FAIL_ERROR",
state: "FAIL_PROMPT",
error: AutoDiscovery.ERROR_INVALID_IDENTITY_SERVER,
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 " +
"(validation error: 500)", function() {
it("should return SUCCESS / FAIL_PROMPT when the identity server configuration " +
"is wrong (validation error: 500)", function() {
httpBackend.when("GET", "/_matrix/client/versions").check((req) => {
expect(req.opts.uri)
.toEqual("https://chat.example.org/_matrix/client/versions");
@@ -560,14 +557,14 @@ describe("AutoDiscovery", function() {
AutoDiscovery.findClientConfig("example.org").then((conf) => {
const expected = {
"m.homeserver": {
state: "FAIL_ERROR",
error: AutoDiscovery.ERROR_INVALID_IS,
state: "SUCCESS",
error: null,
// We still expect the base_url to be here for debugging purposes
base_url: "https://chat.example.org",
},
"m.identity_server": {
state: "FAIL_ERROR",
state: "FAIL_PROMPT",
error: AutoDiscovery.ERROR_INVALID_IDENTITY_SERVER,
base_url: "https://identity.example.org",
},
-7
View File
@@ -1,17 +1,10 @@
"use strict";
import 'source-map-support/register';
const ContentRepo = require("../../lib/content-repo");
const testUtils = require("../test-utils");
import expect from 'expect';
describe("ContentRepo", function() {
const baseUrl = "https://my.home.server";
beforeEach(function() {
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
describe("getHttpUriForMxc", function() {
it("should do nothing to HTTP URLs when allowing direct links", function() {
const httpUrl = "http://example.com/image.jpeg";
+41 -46
View File
@@ -3,7 +3,6 @@ import 'source-map-support/register';
import '../olm-loader';
import Crypto from '../../lib/crypto';
import expect from 'expect';
import WebStorageSessionStore from '../../lib/store/session/webstorage';
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 Room from '../../lib/models/room';
import olmlib from '../../lib/crypto/olmlib';
import lolex from 'lolex';
const EventEmitter = require("events").EventEmitter;
@@ -20,13 +18,15 @@ const sdk = require("../..");
const Olm = global.Olm;
jest.useFakeTimers();
describe("Crypto", function() {
if (!sdk.CRYPTO_ENABLED) {
return;
}
beforeEach(function(done) {
Olm.init().then(done);
beforeAll(function() {
return Olm.init();
});
it("Crypto exposes the correct olm library version", function() {
@@ -76,9 +76,9 @@ describe("Crypto", function() {
});
mockBaseApis = {
sendToDevice: expect.createSpy(),
getKeyBackupVersion: expect.createSpy(),
isGuest: expect.createSpy(),
sendToDevice: jest.fn(),
getKeyBackupVersion: jest.fn(),
isGuest: jest.fn(),
};
mockRoomList = {};
@@ -110,15 +110,16 @@ describe("Crypto", function() {
});
fakeEmitter.emit('toDeviceEvent', {
getType: expect.createSpy().andReturn('m.room.message'),
getContent: expect.createSpy().andReturn({
getId: jest.fn().mockReturnValue("$wedged"),
getType: jest.fn().mockReturnValue('m.room.message'),
getContent: jest.fn().mockReturnValue({
msgtype: 'm.bad.encrypted',
}),
getWireContent: expect.createSpy().andReturn({
getWireContent: jest.fn().mockReturnValue({
algorithm: 'm.olm.v1.curve25519-aes-sha2',
sender_key: 'this is a key',
}),
getSender: expect.createSpy().andReturn('@bob:home.server'),
getSender: jest.fn().mockReturnValue('@bob:home.server'),
});
await prom;
@@ -245,7 +246,7 @@ describe("Crypto", function() {
await bobDecryptor.onRoomKeyEvent(ksEvent);
await eventPromise;
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 eventContent = events[0].getWireContent();
@@ -260,7 +261,7 @@ describe("Crypto", function() {
// the room key request should still be there, since we haven't
// decrypted everything
expect(await cryptoStore.getOutgoingRoomKeyRequest(roomKeyRequestBody))
.toExist();
.toBeDefined();
// keyshare the session key starting at the first message, so
// that it can now be decrypted
@@ -268,10 +269,10 @@ describe("Crypto", function() {
ksEvent = await keyshareEventForEvent(events[0], 0);
await bobDecryptor.onRoomKeyEvent(ksEvent);
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
expect(await cryptoStore.getOutgoingRoomKeyRequest(roomKeyRequestBody))
.toNotExist();
.toBeFalsy();
},
);
@@ -296,7 +297,7 @@ describe("Crypto", function() {
sender_key: "senderkey",
};
expect(await cryptoStore.getOutgoingRoomKeyRequest(roomKeyRequestBody))
.toExist();
.toBeDefined();
});
it("uses a new txnid for re-requesting keys", async function() {
@@ -329,38 +330,32 @@ describe("Crypto", function() {
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 {
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);
clock.runToLast();
let args = await promise;
const txnId = args[2];
clock.runToLast();
// give the room key request manager time to update the state
// of the request
await Promise.resolve();
// give the room key request manager time to update the state
// of the request
await Promise.resolve();
// cancel and resend the room key request
({promise, func: aliceClient.sendToDevice} = awaitFunctionCall());
await aliceClient.cancelAndResendEventRoomKeyRequest(event);
clock.runToLast();
// the first call to sendToDevice will be the cancellation
args = await promise;
// the second call to sendToDevice will be the key request
({promise, func: aliceClient.sendToDevice} = awaitFunctionCall());
clock.runToLast();
args = await promise;
clock.runToLast();
expect(args[2]).toNotBe(txnId);
} finally {
clock.uninstall();
}
// cancel and resend the room key request
({promise, func: aliceClient.sendToDevice} = awaitFunctionCall());
await aliceClient.cancelAndResendEventRoomKeyRequest(event);
jest.runAllTimers();
// the first call to sendToDevice will be the cancellation
args = await promise;
// the second call to sendToDevice will be the key request
({promise, func: aliceClient.sendToDevice} = awaitFunctionCall());
jest.runAllTimers();
args = await promise;
jest.runAllTimers();
expect(args[2]).not.toBe(txnId);
});
});
});
+7 -11
View File
@@ -17,11 +17,9 @@ limitations under the License.
import DeviceList from '../../../lib/crypto/DeviceList';
import MemoryCryptoStore from '../../../lib/crypto/store/memory-crypto-store.js';
import testUtils from '../../test-utils';
import utils from '../../../lib/utils';
import logger from '../../../src/logger';
import expect from 'expect';
import Promise from 'bluebird';
const signedDeviceList = {
@@ -60,11 +58,9 @@ describe('DeviceList', function() {
let deviceLists = [];
beforeEach(function() {
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
deviceLists = [];
downloadSpy = expect.createSpy();
downloadSpy = jest.fn();
cryptoStore = new MemoryCryptoStore();
});
@@ -92,7 +88,7 @@ describe('DeviceList', function() {
dl.startTrackingDeviceList('@test1:sw1v.org');
const queryDefer1 = Promise.defer();
downloadSpy.andReturn(queryDefer1.promise);
downloadSpy.mockReturnValue(queryDefer1.promise);
const prom1 = dl.refreshOutdatedDeviceLists();
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
@@ -111,15 +107,15 @@ describe('DeviceList', function() {
dl.startTrackingDeviceList('@test1:sw1v.org');
const queryDefer1 = Promise.defer();
downloadSpy.andReturn(queryDefer1.promise);
downloadSpy.mockReturnValue(queryDefer1.promise);
const prom1 = dl.refreshOutdatedDeviceLists();
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
downloadSpy.reset();
downloadSpy.mockReset();
// outdated notif arrives while the request is in flight.
const queryDefer2 = Promise.defer();
downloadSpy.andReturn(queryDefer2.promise);
downloadSpy.mockReturnValue(queryDefer2.promise);
dl.invalidateUserDeviceList('@test1:sw1v.org');
dl.refreshOutdatedDeviceLists();
@@ -136,10 +132,10 @@ describe('DeviceList', function() {
// uh-oh; user restarts before second request completes. The new instance
// should know we never got a complete device list.
logger.log("Creating new devicelist to simulate app reload");
downloadSpy.reset();
downloadSpy.mockReset();
const dl2 = createTestDeviceList();
const queryDefer3 = Promise.defer();
downloadSpy.andReturn(queryDefer3.promise);
downloadSpy.mockReturnValue(queryDefer3.promise);
const prom3 = dl2.refreshOutdatedDeviceLists();
expect(downloadSpy).toHaveBeenCalledWith(['@test1:sw1v.org'], {});
+36 -39
View File
@@ -1,6 +1,5 @@
import '../../../olm-loader';
import expect from 'expect';
import Promise from 'bluebird';
import sdk from '../../../..';
@@ -26,16 +25,16 @@ describe("MegolmDecryption", function() {
return;
}
beforeAll(function() {
return Olm.init();
});
let megolmDecryption;
let mockOlmLib;
let mockCrypto;
let mockBaseApis;
beforeEach(async function() {
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
await Olm.init();
mockCrypto = testUtils.mock(Crypto, 'Crypto');
mockBaseApis = {};
@@ -55,9 +54,9 @@ describe("MegolmDecryption", function() {
// we stub out the olm encryption bits
mockOlmLib = {};
mockOlmLib.ensureOlmSessionsForDevices = expect.createSpy();
mockOlmLib.ensureOlmSessionsForDevices = jest.fn();
mockOlmLib.encryptMessageForDevice =
expect.createSpy().andReturn(Promise.resolve());
jest.fn().mockReturnValue(Promise.resolve());
megolmDecryption.olmlib = mockOlmLib;
});
@@ -135,22 +134,22 @@ describe("MegolmDecryption", function() {
// set up some pre-conditions for the share call
const deviceInfo = {};
mockCrypto.getStoredDevice.andReturn(deviceInfo);
mockCrypto.getStoredDevice.mockReturnValue(deviceInfo);
mockOlmLib.ensureOlmSessionsForDevices.andReturn(
mockOlmLib.ensureOlmSessionsForDevices.mockReturnValue(
Promise.resolve({'@alice:foo': {'alidevice': {
sessionId: 'alisession',
}}}),
);
const awaitEncryptForDevice = new Promise((res, rej) => {
mockOlmLib.encryptMessageForDevice.andCall(() => {
mockOlmLib.encryptMessageForDevice.mockImplementation(() => {
res();
return Promise.resolve();
});
});
mockBaseApis.sendToDevice = expect.createSpy();
mockBaseApis.sendToDevice = jest.fn();
// do the share
megolmDecryption.shareKeysWithDevice(keyRequest);
@@ -160,21 +159,20 @@ describe("MegolmDecryption", function() {
}).then(() => {
// check that it called encryptMessageForDevice with
// appropriate args.
expect(mockOlmLib.encryptMessageForDevice.calls.length)
.toEqual(1);
expect(mockOlmLib.encryptMessageForDevice).toBeCalledTimes(1);
const call = mockOlmLib.encryptMessageForDevice.calls[0];
const payload = call.arguments[6];
const call = mockOlmLib.encryptMessageForDevice.mock.calls[0];
const payload = call[6];
expect(payload.type).toEqual("m.forwarded_room_key");
expect(payload.content).toInclude({
expect(payload.content).toMatchObject({
sender_key: "SENDER_CURVE25519",
sender_claimed_ed25519_key: "SENDER_ED25519",
session_id: groupSession.session_id(),
chain_index: 0,
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,
});
const successHandler = expect.createSpy();
const failureHandler = expect.createSpy()
.andCall((err) => {
expect(err.toString()).toMatch(
/Duplicate message index, possible replay attack/,
);
});
const successHandler = jest.fn();
const failureHandler = jest.fn((err) => {
expect(err.toString()).toMatch(
/Duplicate message index, possible replay attack/,
);
});
return megolmDecryption.decryptEvent(event1).then((res) => {
const event2 = new MatrixEvent({
@@ -228,7 +225,7 @@ describe("MegolmDecryption", function() {
successHandler,
failureHandler,
).then(() => {
expect(successHandler).toNotHaveBeenCalled();
expect(successHandler).not.toHaveBeenCalled();
expect(failureHandler).toHaveBeenCalled();
});
});
@@ -266,10 +263,10 @@ describe("MegolmDecryption", function() {
const cryptoStore = new MemoryCryptoStore(mockStorage);
const olmDevice = new OlmDevice(cryptoStore);
olmDevice.verifySignature = expect.createSpy();
olmDevice.verifySignature = jest.fn();
await olmDevice.init();
mockBaseApis.claimOneTimeKeys = expect.createSpy().andReturn(Promise.resolve({
mockBaseApis.claimOneTimeKeys = jest.fn().mockReturnValue(Promise.resolve({
one_time_keys: {
'@alice:home.server': {
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': {
aliceDevice: {
deviceId: 'aliceDevice',
isBlocked: expect.createSpy().andReturn(false),
isUnverified: expect.createSpy().andReturn(false),
getIdentityKey: expect.createSpy().andReturn(
isBlocked: jest.fn().mockReturnValue(false),
isUnverified: jest.fn().mockReturnValue(false),
getIdentityKey: jest.fn().mockReturnValue(
'YWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWE',
),
getFingerprint: expect.createSpy().andReturn(''),
getFingerprint: jest.fn().mockReturnValue(''),
},
},
}));
@@ -312,10 +309,10 @@ describe("MegolmDecryption", function() {
},
});
const mockRoom = {
getEncryptionTargetMembers: expect.createSpy().andReturn(
getEncryptionTargetMembers: jest.fn().mockReturnValue(
[{userId: "@alice:home.server"}],
),
getBlacklistUnverifiedDevices: expect.createSpy().andReturn(false),
getBlacklistUnverifiedDevices: jest.fn().mockReturnValue(false),
};
const ct1 = await megolmEncryption.encryptMessage(mockRoom, "a.fake.type", {
body: "Some text",
@@ -323,25 +320,25 @@ describe("MegolmDecryption", function() {
expect(mockRoom.getEncryptionTargetMembers).toHaveBeenCalled();
// 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',
);
expect(mockCrypto.downloadKeys).toHaveBeenCalledWith(
['@alice:home.server'], false,
);
expect(mockBaseApis.sendToDevice).toHaveBeenCalled();
expect(mockBaseApis.claimOneTimeKeys).toHaveBeenCalled(
expect(mockBaseApis.claimOneTimeKeys).toHaveBeenCalledWith(
[['@alice:home.server', 'aliceDevice']], 'signed_curve25519',
);
mockBaseApis.claimOneTimeKeys.reset();
mockBaseApis.claimOneTimeKeys.mockReset();
const ct2 = await megolmEncryption.encryptMessage(mockRoom, "a.fake.type", {
body: "Some more text",
});
// 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
expect(ct2.session_id).toEqual(ct1.session_id);
+4 -6
View File
@@ -16,10 +16,8 @@ limitations under the License.
import '../../../olm-loader';
import expect from 'expect';
import MemoryCryptoStore from '../../../../lib/crypto/store/memory-crypto-store.js';
import MockStorageApi from '../../../MockStorageApi';
import testUtils from '../../../test-utils';
import logger from '../../../../src/logger';
import OlmDevice from '../../../../lib/crypto/OlmDevice';
@@ -50,14 +48,14 @@ describe("OlmDecryption", function() {
return;
}
beforeAll(function() {
return global.Olm.init();
});
let aliceOlmDevice;
let bobOlmDevice;
beforeEach(async function() {
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
await global.Olm.init();
aliceOlmDevice = makeOlmDevice();
bobOlmDevice = makeOlmDevice();
await aliceOlmDevice.init();
+24 -24
View File
@@ -16,7 +16,6 @@ limitations under the License.
import '../../olm-loader';
import expect from 'expect';
import Promise from 'bluebird';
import sdk from '../../..';
@@ -98,16 +97,16 @@ function makeTestClient(sessionStore, cryptoStore) {
const scheduler = [
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
"setProcessFunction",
].reduce((r, k) => {r[k] = expect.createSpy(); return r;}, {});
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
const store = [
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom",
"storeUser", "getFilterIdByName", "setFilterIdByName", "getFilter",
"storeFilter", "getSyncAccumulator", "startup", "deleteAllData",
].reduce((r, k) => {r[k] = expect.createSpy(); return r;}, {});
store.getSavedSync = expect.createSpy().andReturn(Promise.resolve(null));
store.getSavedSyncToken = expect.createSpy().andReturn(Promise.resolve(null));
store.setSyncData = expect.createSpy().andReturn(Promise.resolve(null));
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
store.getSavedSync = jest.fn().mockReturnValue(Promise.resolve(null));
store.getSavedSyncToken = jest.fn().mockReturnValue(Promise.resolve(null));
store.setSyncData = jest.fn().mockReturnValue(Promise.resolve(null));
return new MatrixClient({
baseUrl: "https://my.home.server",
idBaseUrl: "https://identity.server",
@@ -129,6 +128,10 @@ describe("MegolmBackup", function() {
return;
}
beforeAll(function() {
return Olm.init();
});
let olmDevice;
let mockOlmLib;
let mockCrypto;
@@ -137,9 +140,6 @@ describe("MegolmBackup", function() {
let cryptoStore;
let megolmDecryption;
beforeEach(async function() {
await Olm.init();
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
mockCrypto = testUtils.mock(Crypto, 'Crypto');
mockCrypto.backupKey = new Olm.PkEncryption();
mockCrypto.backupKey.set_recipient_key(
@@ -155,9 +155,9 @@ describe("MegolmBackup", function() {
// we stub out the olm encryption bits
mockOlmLib = {};
mockOlmLib.ensureOlmSessionsForDevices = expect.createSpy();
mockOlmLib.ensureOlmSessionsForDevices = jest.fn();
mockOlmLib.encryptMessageForDevice =
expect.createSpy().andReturn(Promise.resolve());
jest.fn().mockReturnValue(Promise.resolve());
});
describe("backup", function() {
@@ -218,7 +218,7 @@ describe("MegolmBackup", function() {
};
mockCrypto.cancelRoomKeyRequest = function() {};
mockCrypto.backupGroupSession = expect.createSpy();
mockCrypto.backupGroupSession = jest.fn();
return event.attemptDecryption(mockCrypto).then(() => {
return megolmDecryption.onRoomKeyEvent(event);
@@ -279,7 +279,7 @@ describe("MegolmBackup", function() {
callback, method, path, queryParams, data, opts,
) {
++numCalls;
expect(numCalls).toBeLessThanOrEqualTo(1);
expect(numCalls).toBeLessThanOrEqual(1);
if (numCalls >= 2) {
// exit out of retry loop if there's something wrong
reject(new Error("authedRequest called too many timmes"));
@@ -288,8 +288,8 @@ describe("MegolmBackup", function() {
expect(method).toBe("PUT");
expect(path).toBe("/room_keys/keys");
expect(queryParams.version).toBe(1);
expect(data.rooms[ROOM_ID].sessions).toExist();
expect(data.rooms[ROOM_ID].sessions).toIncludeKey(
expect(data.rooms[ROOM_ID].sessions).toBeDefined();
expect(data.rooms[ROOM_ID].sessions).toHaveProperty(
groupSession.session_id(),
);
resolve();
@@ -343,7 +343,7 @@ describe("MegolmBackup", function() {
callback, method, path, queryParams, data, opts,
) {
++numCalls;
expect(numCalls).toBeLessThanOrEqualTo(1);
expect(numCalls).toBeLessThanOrEqual(1);
if (numCalls >= 2) {
// exit out of retry loop if there's something wrong
reject(new Error("authedRequest called too many timmes"));
@@ -382,16 +382,16 @@ describe("MegolmBackup", function() {
const scheduler = [
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
"setProcessFunction",
].reduce((r, k) => {r[k] = expect.createSpy(); return r;}, {});
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
const store = [
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom",
"storeUser", "getFilterIdByName", "setFilterIdByName", "getFilter",
"storeFilter", "getSyncAccumulator", "startup", "deleteAllData",
].reduce((r, k) => {r[k] = expect.createSpy(); return r;}, {});
store.getSavedSync = expect.createSpy().andReturn(Promise.resolve(null));
store.getSavedSyncToken = expect.createSpy().andReturn(Promise.resolve(null));
store.setSyncData = expect.createSpy().andReturn(Promise.resolve(null));
].reduce((r, k) => {r[k] = jest.fn(); return r;}, {});
store.getSavedSync = jest.fn().mockReturnValue(Promise.resolve(null));
store.getSavedSyncToken = jest.fn().mockReturnValue(Promise.resolve(null));
store.setSyncData = jest.fn().mockReturnValue(Promise.resolve(null));
const client = new MatrixClient({
baseUrl: "https://my.home.server",
idBaseUrl: "https://identity.server",
@@ -449,7 +449,7 @@ describe("MegolmBackup", function() {
callback, method, path, queryParams, data, opts,
) {
++numCalls;
expect(numCalls).toBeLessThanOrEqualTo(2);
expect(numCalls).toBeLessThanOrEqual(2);
if (numCalls >= 3) {
// exit out of retry loop if there's something wrong
reject(new Error("authedRequest called too many timmes"));
@@ -458,8 +458,8 @@ describe("MegolmBackup", function() {
expect(method).toBe("PUT");
expect(path).toBe("/room_keys/keys");
expect(queryParams.version).toBe(1);
expect(data.rooms[ROOM_ID].sessions).toExist();
expect(data.rooms[ROOM_ID].sessions).toIncludeKey(
expect(data.rooms[ROOM_ID].sessions).toBeDefined();
expect(data.rooms[ROOM_ID].sessions).toHaveProperty(
groupSession.session_id(),
);
if (numCalls > 1) {
+10 -12
View File
@@ -17,7 +17,6 @@ limitations under the License.
import '../../olm-loader';
import expect from 'expect';
import anotherjson from 'another-json';
import olmlib from '../../../lib/crypto/olmlib';
@@ -56,21 +55,20 @@ describe("Cross Signing", function() {
return;
}
beforeEach(async function() {
await global.Olm.init();
beforeAll(function() {
return global.Olm.init();
});
it("should sign the master key with the device key", async function() {
const alice = await makeTestClient(
{userId: "@alice:example.com", deviceId: "Osborne2"},
);
alice.uploadDeviceSigningKeys = expect.createSpy()
.andCall(async (auth, keys) => {
await olmlib.verifySignature(
alice._crypto._olmDevice, keys.master_key, "@alice:example.com",
"Osborne2", alice._crypto._olmDevice.deviceEd25519Key,
);
});
alice.uploadDeviceSigningKeys = jest.fn(async (auth, keys) => {
await olmlib.verifySignature(
alice._crypto._olmDevice, keys.master_key, "@alice:example.com",
"Osborne2", alice._crypto._olmDevice.deviceEd25519Key,
);
});
alice.uploadKeySignatures = async () => {};
// set Alice's cross-signing key
await alice.resetCrossSigningKeys();
@@ -146,7 +144,7 @@ describe("Cross Signing", function() {
});
const uploadSigsPromise = new Promise((resolve, reject) => {
alice.uploadKeySignatures = expect.createSpy().andCall(async (content) => {
alice.uploadKeySignatures = jest.fn(async (content) => {
await olmlib.verifySignature(
alice._crypto._olmDevice,
content["@alice:example.com"][
@@ -732,7 +730,7 @@ describe("Cross Signing", function() {
{
cryptoCallbacks: {
shouldUpgradeDeviceVerifications: (verifs) => {
expect(verifs.users["@bob:example.com"]).toExist();
expect(verifs.users["@bob:example.com"]).toBeDefined();
upgradeResolveFunc();
return ["@bob:example.com"];
},
+3 -4
View File
@@ -16,7 +16,6 @@ limitations under the License.
import '../../olm-loader';
import expect from 'expect';
import { MatrixEvent } from '../../../lib/models/event';
import { SECRET_STORAGE_ALGORITHM_V1 } from '../../../lib/crypto/SecretStorage';
@@ -41,8 +40,8 @@ describe("Secrets", function() {
return;
}
beforeEach(async function() {
await global.Olm.init();
beforeAll(function() {
return global.Olm.init();
});
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"]);
return ['abc', privkey];
});
+14 -15
View File
@@ -21,7 +21,6 @@ try {
logger.warn("unable to run device verification tests: libolm not available");
}
import expect from 'expect';
import DeviceInfo from '../../../../lib/crypto/deviceinfo';
import {ShowQRCode, ScanQRCode} from '../../../../lib/crypto/verification/QRCode';
@@ -34,8 +33,8 @@ describe("QR code verification", function() {
return;
}
beforeEach(async function() {
await Olm.init();
beforeAll(function() {
return Olm.init();
});
describe("showing", function() {
@@ -47,7 +46,7 @@ describe("QR code verification", function() {
return "device+ed25519+key";
},
});
const spy = expect.createSpy().andCall((e) => {
const spy = jest.fn((e) => {
qrCode.done();
});
qrCode.on("show_qr_code", spy);
@@ -77,8 +76,8 @@ describe("QR code verification", function() {
"ABCDEFG",
);
const client = {
getStoredDevice: expect.createSpy().andReturn(device),
setDeviceVerified: expect.createSpy(),
getStoredDevice: jest.fn().mockReturnValue(device),
setDeviceVerified: jest.fn(),
};
const qrCode = new ScanQRCode(client);
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() {
const client = {
getStoredDevice: expect.createSpy(),
setDeviceVerified: expect.createSpy(),
getStoredDevice: jest.fn(),
setDeviceVerified: jest.fn(),
};
const qrCode = new ScanQRCode(client, "@bob:example.com", "ABCDEFG");
qrCode.on("scan", ({done}) => {
done(QR_CODE_URL);
});
const spy = expect.createSpy();
const spy = jest.fn();
await qrCode.verify().catch(spy);
expect(spy).toHaveBeenCalled();
expect(client.getStoredDevice).toNotHaveBeenCalled();
expect(client.setDeviceVerified).toNotHaveBeenCalled();
expect(client.getStoredDevice).not.toHaveBeenCalled();
expect(client.setDeviceVerified).not.toHaveBeenCalled();
});
it("should error if the key doesn't match", async function() {
@@ -129,18 +128,18 @@ describe("QR code verification", function() {
"ABCDEFG",
);
const client = {
getStoredDevice: expect.createSpy().andReturn(device),
setDeviceVerified: expect.createSpy(),
getStoredDevice: jest.fn().mockReturnValue(device),
setDeviceVerified: jest.fn(),
};
const qrCode = new ScanQRCode(client, "@alice:example.com", "ABCDEFG");
qrCode.on("scan", ({done}) => {
done(QR_CODE_URL);
});
const spy = expect.createSpy();
const spy = jest.fn();
await qrCode.verify().catch(spy);
expect(spy).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");
}
import expect from 'expect';
import {verificationMethods} from '../../../../lib/crypto';
import SAS from '../../../../lib/crypto/verification/SAS';
@@ -37,8 +35,8 @@ describe("verification request", function() {
return;
}
beforeEach(async function() {
await Olm.init();
beforeAll(function() {
return Olm.init();
});
it("should request and accept a verification", async function() {
@@ -74,7 +72,7 @@ describe("verification request", function() {
bobVerifier._endTimer();
});
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)
aliceVerifier._endTimer();
+35 -46
View File
@@ -21,7 +21,6 @@ try {
logger.warn("unable to run device verification tests: libolm not available");
}
import expect from 'expect';
import olmlib from '../../../../lib/crypto/olmlib';
import sdk from '../../../..';
@@ -46,8 +45,8 @@ describe("SAS verification", function() {
return;
}
beforeEach(async function() {
await Olm.init();
beforeAll(function() {
return Olm.init();
});
it("should error on an unexpected event", async function() {
@@ -57,16 +56,15 @@ describe("SAS verification", function() {
type: "es.inquisition",
content: {},
}));
const spy = expect.createSpy();
await sas.verify()
.catch(spy);
const spy = jest.fn();
await sas.verify().catch(spy);
expect(spy).toHaveBeenCalled();
// Cancel the SAS for cleanup (we started a verification, so abort)
sas.cancel();
});
describe("verification", function() {
describe("verification", () => {
let alice;
let bob;
let aliceSasEvent;
@@ -74,7 +72,7 @@ describe("SAS verification", function() {
let aliceVerifier;
let bobPromise;
beforeEach(async function() {
beforeEach(async () => {
[alice, bob] = await makeTestClients(
[
{userId: "@alice:example.com", deviceId: "Osborne2"},
@@ -115,14 +113,14 @@ describe("SAS verification", function() {
alice.client._crypto._deviceList.storeDevicesForUser(
"@bob:example.com", BOB_DEVICES,
);
alice.downloadKeys = () => {
alice.client.downloadKeys = () => {
return Promise.resolve();
};
bob.client._crypto._deviceList.storeDevicesForUser(
"@alice:example.com", ALICE_DEVICES,
);
bob.downloadKeys = () => {
bob.client.downloadKeys = () => {
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;
const origSendToDevice = alice.client.sendToDevice;
const origSendToDevice = bob.client.sendToDevice.bind(bob.client);
bob.client.sendToDevice = function(type, map) {
if (type === "m.key.verification.accept") {
macMethod = map[alice.client.getUserId()][alice.client.deviceId]
.message_authentication_code;
}
return origSendToDevice.call(this, type, map);
return origSendToDevice(type, map);
};
alice.httpBackend.when('POST', '/keys/query').respond(200, {
@@ -215,12 +219,12 @@ describe("SAS verification", function() {
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,
// and make sure that she can still verify with Bob
let macMethod;
const origSendToDevice = alice.client.sendToDevice;
alice.client.sendToDevice = function(type, map) {
const aliceOrigSendToDevice = alice.client.sendToDevice.bind(alice.client);
alice.client.sendToDevice = (type, map) => {
if (type === "m.key.verification.start") {
// Note: this modifies not only the message that Bob
// 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]
.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") {
macMethod = map[alice.client.getUserId()][alice.client.deviceId]
.message_authentication_code;
}
return origSendToDevice.call(this, type, map);
return bobOrigSendToDevice(type, map);
};
alice.httpBackend.when('POST', '/keys/query').respond(200, {
@@ -270,7 +275,7 @@ describe("SAS verification", function() {
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(
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([
aliceVerifier.verify(),
bobPromise.then((verifier) => {
bob.httpBackend.when(
'POST', '/keys/signatures/upload',
).respond(200, {});
bob.httpBackend.flush(undefined, 2);
bob.httpBackend.flush(undefined, 1, 2000);
return verifier.verify();
}),
]);
await alice.httpBackend.flush(undefined, 1);
console.log("alice reqs flushed");
await verifyProm;
const bobDeviceTrust = alice.client.checkDeviceTrust(
@@ -346,11 +335,11 @@ describe("SAS verification", function() {
verificationMethods: [verificationMethods.SAS],
},
);
alice.client.setDeviceVerified = expect.createSpy();
alice.client.setDeviceVerified = jest.fn();
alice.client.downloadKeys = () => {
return Promise.resolve();
};
bob.client.setDeviceVerified = expect.createSpy();
bob.client.setDeviceVerified = jest.fn();
bob.client.downloadKeys = () => {
return Promise.resolve();
};
@@ -368,8 +357,8 @@ describe("SAS verification", function() {
verificationMethods.SAS, bob.client.getUserId(), bob.client.deviceId,
);
const aliceSpy = expect.createSpy();
const bobSpy = expect.createSpy();
const aliceSpy = jest.fn();
const bobSpy = jest.fn();
await Promise.all([
aliceVerifier.verify().catch(aliceSpy),
bobPromise.then((verifier) => verifier.verify()).catch(bobSpy),
@@ -377,9 +366,9 @@ describe("SAS verification", function() {
expect(aliceSpy).toHaveBeenCalled();
expect(bobSpy).toHaveBeenCalled();
expect(alice.client.setDeviceVerified)
.toNotHaveBeenCalled();
.not.toHaveBeenCalled();
expect(bob.client.setDeviceVerified)
.toNotHaveBeenCalled();
.not.toHaveBeenCalled();
});
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 = () => {
return "alice+base64+ed25519+key";
};
@@ -419,7 +408,7 @@ describe("SAS verification", function() {
return Promise.resolve();
};
bob.client.setDeviceVerified = expect.createSpy();
bob.client.setDeviceVerified = jest.fn();
bob.client.getStoredDevice = () => {
return DeviceInfo.fromStorage(
{
@@ -445,7 +434,7 @@ describe("SAS verification", function() {
const content = event.getContent();
if (event.getType() === "m.room.message"
&& 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());
const verifier = bob.client.acceptVerificationDM(event, SAS.NAME);
verifier.on("show_sas", (e) => {
+9 -13
View File
@@ -9,8 +9,6 @@ function mockRoomStates(timeline) {
timeline._endState = utils.mock(sdk.RoomState, "endState");
}
import expect from 'expect';
describe("EventTimeline", function() {
const roomId = "!foo:bar";
const userA = "@alice:bar";
@@ -18,8 +16,6 @@ describe("EventTimeline", function() {
let timeline;
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
const timelineSet = { room: { roomId: roomId }};
timelineSet.room.getUnfilteredTimelineSet = function() {
@@ -78,7 +74,7 @@ describe("EventTimeline", function() {
expect(function() {
timeline.initialiseState(state);
}).toNotThrow();
}).not.toThrow();
timeline.addEvent(event, false);
expect(function() {
timeline.initialiseState(state);
@@ -121,7 +117,7 @@ describe("EventTimeline", function() {
const next = {b: "b"};
expect(function() {
timeline.setNeighbouringTimeline(prev, EventTimeline.BACKWARDS);
}).toNotThrow();
}).not.toThrow();
expect(timeline.getNeighbouringTimeline(EventTimeline.BACKWARDS))
.toBe(prev);
expect(function() {
@@ -130,7 +126,7 @@ describe("EventTimeline", function() {
expect(function() {
timeline.setNeighbouringTimeline(next, EventTimeline.FORWARDS);
}).toNotThrow();
}).not.toThrow();
expect(timeline.getNeighbouringTimeline(EventTimeline.FORWARDS))
.toBe(next);
expect(function() {
@@ -187,14 +183,14 @@ describe("EventTimeline", function() {
name: "Old Alice",
};
timeline.getState(EventTimeline.FORWARDS).getSentinelMember
.andCall(function(uid) {
.mockImplementation(function(uid) {
if (uid === userA) {
return sentinel;
}
return null;
});
timeline.getState(EventTimeline.BACKWARDS).getSentinelMember
.andCall(function(uid) {
.mockImplementation(function(uid) {
if (uid === userA) {
return oldSentinel;
}
@@ -229,14 +225,14 @@ describe("EventTimeline", function() {
name: "Old Alice",
};
timeline.getState(EventTimeline.FORWARDS).getSentinelMember
.andCall(function(uid) {
.mockImplementation(function(uid) {
if (uid === userA) {
return sentinel;
}
return null;
});
timeline.getState(EventTimeline.BACKWARDS).getSentinelMember
.andCall(function(uid) {
.mockImplementation(function(uid) {
if (uid === userA) {
return oldSentinel;
}
@@ -281,7 +277,7 @@ describe("EventTimeline", function() {
expect(events[1].forwardLooking).toBe(true);
expect(timeline.getState(EventTimeline.BACKWARDS).setStateEvents).
toNotHaveBeenCalled();
not.toHaveBeenCalled();
});
@@ -311,7 +307,7 @@ describe("EventTimeline", function() {
expect(events[1].forwardLooking).toBe(false);
expect(timeline.getState(EventTimeline.FORWARDS).setStateEvents).
toNotHaveBeenCalled();
not.toHaveBeenCalled();
});
});
+3 -8
View File
@@ -17,17 +17,10 @@ limitations under the License.
import sdk from '../..';
const MatrixEvent = sdk.MatrixEvent;
import testUtils from '../test-utils';
import expect from 'expect';
import Promise from 'bluebird';
import logger from '../../src/logger';
describe("MatrixEvent", () => {
beforeEach(function() {
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
describe(".attemptDecryption", () => {
let encryptedEvent;
@@ -45,6 +38,7 @@ describe("MatrixEvent", () => {
let callCount = 0;
let prom2;
let prom2Fulfilled = false;
const crypto = {
decryptEvent: function() {
@@ -54,12 +48,13 @@ describe("MatrixEvent", () => {
// schedule a second decryption attempt while
// the first one is still running.
prom2 = encryptedEvent.attemptDecryption(crypto);
prom2.then(() => prom2Fulfilled = true);
const error = new Error("nope");
error.name = 'DecryptionError';
return Promise.reject(error);
} else {
expect(prom2.isFulfilled()).toBe(
expect(prom2Fulfilled).toBe(
false, 'second attemptDecryption resolved too soon');
return Promise.resolve({
-4
View File
@@ -2,9 +2,6 @@
import 'source-map-support/register';
const sdk = require("../..");
const Filter = sdk.Filter;
const utils = require("../test-utils");
import expect from 'expect';
describe("Filter", function() {
const filterId = "f1lt3ring15g00d4ursoul";
@@ -12,7 +9,6 @@ describe("Filter", function() {
let filter;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
filter = new Filter(userId);
});
+19 -25
View File
@@ -18,12 +18,10 @@ limitations under the License.
import 'source-map-support/register';
import Promise from 'bluebird';
const sdk = require("../..");
const utils = require("../test-utils");
const InteractiveAuth = sdk.InteractiveAuth;
const MatrixError = sdk.MatrixError;
import expect from 'expect';
import logger from '../../src/logger';
// Trivial client object to test interactive auth
@@ -35,13 +33,9 @@ class FakeClient {
}
describe("InteractiveAuth", function() {
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
it("should start an auth stage and complete it", function(done) {
const doRequest = expect.createSpy();
const stateUpdated = expect.createSpy();
it("should start an auth stage and complete it", function() {
const doRequest = jest.fn();
const stateUpdated = jest.fn();
const ia = new InteractiveAuth({
matrixClient: new FakeClient(),
@@ -64,7 +58,7 @@ describe("InteractiveAuth", function() {
});
// first we expect a call here
stateUpdated.andCall(function(stage) {
stateUpdated.mockImplementation(function(stage) {
logger.log('aaaa');
expect(stage).toEqual("logintype");
ia.submitAuthDict({
@@ -75,7 +69,7 @@ describe("InteractiveAuth", function() {
// .. which should trigger a call here
const requestRes = {"a": "b"};
doRequest.andCall(function(authData) {
doRequest.mockImplementation(function(authData) {
logger.log('cccc');
expect(authData).toEqual({
session: "sessionId",
@@ -85,16 +79,16 @@ describe("InteractiveAuth", function() {
return Promise.resolve(requestRes);
});
ia.attemptAuth().then(function(res) {
return ia.attemptAuth().then(function(res) {
expect(res).toBe(requestRes);
expect(doRequest.calls.length).toEqual(1);
expect(stateUpdated.calls.length).toEqual(1);
}).nodeify(done);
expect(doRequest).toBeCalledTimes(1);
expect(stateUpdated).toBeCalledTimes(1);
});
});
it("should make a request if no authdata is provided", function(done) {
const doRequest = expect.createSpy();
const stateUpdated = expect.createSpy();
it("should make a request if no authdata is provided", function() {
const doRequest = jest.fn();
const stateUpdated = jest.fn();
const ia = new InteractiveAuth({
matrixClient: new FakeClient(),
@@ -106,7 +100,7 @@ describe("InteractiveAuth", function() {
expect(ia.getStageParams("logintype")).toBe(undefined);
// first we expect a call to doRequest
doRequest.andCall(function(authData) {
doRequest.mockImplementation(function(authData) {
logger.log("request1", authData);
expect(authData).toEqual({});
const err = new MatrixError({
@@ -124,7 +118,7 @@ describe("InteractiveAuth", function() {
// .. which should be followed by a call to stateUpdated
const requestRes = {"a": "b"};
stateUpdated.andCall(function(stage) {
stateUpdated.mockImplementation(function(stage) {
expect(stage).toEqual("logintype");
expect(ia.getSessionId()).toEqual("sessionId");
expect(ia.getStageParams("logintype")).toEqual({
@@ -132,7 +126,7 @@ describe("InteractiveAuth", function() {
});
// submitAuthDict should trigger another call to doRequest
doRequest.andCall(function(authData) {
doRequest.mockImplementation(function(authData) {
logger.log("request2", authData);
expect(authData).toEqual({
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(doRequest.calls.length).toEqual(2);
expect(stateUpdated.calls.length).toEqual(1);
}).nodeify(done);
expect(doRequest).toBeCalledTimes(2);
expect(stateUpdated).toBeCalledTimes(1);
});
});
});
-1
View File
@@ -1,4 +1,3 @@
import expect from 'expect';
import TestClient from '../TestClient';
describe('Login request', function() {
+22 -27
View File
@@ -3,12 +3,11 @@ import 'source-map-support/register';
import Promise from 'bluebird';
const sdk = require("../..");
const MatrixClient = sdk.MatrixClient;
const utils = require("../test-utils");
import expect from 'expect';
import lolex from 'lolex';
import logger from '../../src/logger';
jest.useFakeTimers();
describe("MatrixClient", function() {
const userId = "@alice:bar";
const identityServerUrl = "https://identity.server";
@@ -16,7 +15,6 @@ describe("MatrixClient", function() {
let client;
let store;
let scheduler;
let clock;
const KEEP_ALIVE_PATH = "/_matrix/client/versions";
@@ -125,24 +123,22 @@ describe("MatrixClient", function() {
}
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
clock = lolex.install();
scheduler = [
"getQueueForEvent", "queueEvent", "removeEventFromQueue",
"setProcessFunction",
].reduce((r, k) => { r[k] = expect.createSpy(); return r; }, {});
].reduce((r, k) => { r[k] = jest.fn(); return r; }, {});
store = [
"getRoom", "getRooms", "getUser", "getSyncToken", "scrollback",
"save", "wantsSave", "setSyncToken", "storeEvents", "storeRoom", "storeUser",
"getFilterIdByName", "setFilterIdByName", "getFilter", "storeFilter",
"getSyncAccumulator", "startup", "deleteAllData",
].reduce((r, k) => { r[k] = expect.createSpy(); return r; }, {});
store.getSavedSync = expect.createSpy().andReturn(Promise.resolve(null));
store.getSavedSyncToken = expect.createSpy().andReturn(Promise.resolve(null));
store.setSyncData = expect.createSpy().andReturn(Promise.resolve(null));
store.getClientOptions = expect.createSpy().andReturn(Promise.resolve(null));
store.storeClientOptions = expect.createSpy().andReturn(Promise.resolve(null));
store.isNewlyCreated = expect.createSpy().andReturn(Promise.resolve(true));
].reduce((r, k) => { r[k] = jest.fn(); return r; }, {});
store.getSavedSync = jest.fn().mockReturnValue(Promise.resolve(null));
store.getSavedSyncToken = jest.fn().mockReturnValue(Promise.resolve(null));
store.setSyncData = jest.fn().mockReturnValue(Promise.resolve(null));
store.getClientOptions = jest.fn().mockReturnValue(Promise.resolve(null));
store.storeClientOptions = jest.fn().mockReturnValue(Promise.resolve(null));
store.isNewlyCreated = jest.fn().mockReturnValue(Promise.resolve(true));
client = new MatrixClient({
baseUrl: "https://my.home.server",
idBaseUrl: identityServerUrl,
@@ -155,9 +151,9 @@ describe("MatrixClient", function() {
// FIXME: We shouldn't be yanking _http like this.
client._http = [
"authedRequest", "getContentUri", "request", "uploadContent",
].reduce((r, k) => { r[k] = expect.createSpy(); return r; }, {});
client._http.authedRequest.andCall(httpReq);
client._http.request.andCall(httpReq);
].reduce((r, k) => { r[k] = jest.fn(); return r; }, {});
client._http.authedRequest.mockImplementation(httpReq);
client._http.request.mockImplementation(httpReq);
// set reasonable working defaults
acceptKeepalives = true;
@@ -169,13 +165,12 @@ describe("MatrixClient", function() {
});
afterEach(function() {
clock.uninstall();
// 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
// means they may call /events and then fail an expect() which will fail
// a DIFFERENT test (pollution between tests!) - we return unresolved
// promises to stop the client from continuing to run.
client._http.authedRequest.andCall(function() {
client._http.authedRequest.mockImplementation(function() {
return Promise.defer().promise;
});
});
@@ -185,10 +180,10 @@ describe("MatrixClient", function() {
httpLookups.push(PUSH_RULES_RESPONSE);
httpLookups.push(SYNC_RESPONSE);
const filterId = "ehfewf";
store.getFilterIdByName.andReturn(filterId);
store.getFilterIdByName.mockReturnValue(filterId);
const filter = new sdk.Filter(0, filterId);
filter.setDefinition({"room": {"timeline": {"limit": 8}}});
store.getFilter.andReturn(filter);
store.getFilter.mockReturnValue(filter);
const syncPromise = new Promise((resolve, reject) => {
client.on("sync", function syncListener(state) {
if (state === "SYNCING") {
@@ -249,7 +244,7 @@ describe("MatrixClient", function() {
},
});
httpLookups.push(FILTER_RESPONSE);
store.getFilterIdByName.andReturn(invalidFilterId);
store.getFilterIdByName.mockReturnValue(invalidFilterId);
const filterName = getFilterName(client.credentials.userId);
client.store.setFilterIdByName(filterName, invalidFilterId);
@@ -281,7 +276,7 @@ describe("MatrixClient", function() {
if (state === "ERROR" && httpLookups.length > 0) {
expect(httpLookups.length).toEqual(2);
expect(client.retryImmediately()).toBe(true);
clock.tick(1);
jest.advanceTimersByTime(1);
} else if (state === "PREPARED" && httpLookups.length === 0) {
client.removeListener("sync", syncListener);
done();
@@ -307,9 +302,9 @@ describe("MatrixClient", function() {
expect(client.retryImmediately()).toBe(
true, "retryImmediately returned false",
);
clock.tick(1);
jest.advanceTimersByTime(1);
} else if (state === "RECONNECTING" && httpLookups.length > 0) {
clock.tick(10000);
jest.advanceTimersByTime(10000);
} else if (state === "SYNCING" && httpLookups.length === 0) {
client.removeListener("sync", syncListener);
done();
@@ -331,7 +326,7 @@ describe("MatrixClient", function() {
if (state === "ERROR" && httpLookups.length > 0) {
expect(httpLookups.length).toEqual(3);
expect(client.retryImmediately()).toBe(true);
clock.tick(1);
jest.advanceTimersByTime(1);
} else if (state === "PREPARED" && httpLookups.length === 0) {
client.removeListener("sync", syncListener);
done();
@@ -362,7 +357,7 @@ describe("MatrixClient", function() {
done();
}
// standard retry time is 5 to 10 seconds
clock.tick(10000);
jest.advanceTimersByTime(10000);
};
}
-2
View File
@@ -3,8 +3,6 @@ import 'source-map-support/register';
const PushProcessor = require("../../lib/pushprocessor");
const utils = require("../test-utils");
import expect from 'expect';
describe('NotificationService', function() {
const testUserId = "@ali:matrix.org";
const testDisplayName = "Alice M";
+43 -52
View File
@@ -1,53 +1,46 @@
"use strict";
import 'source-map-support/register';
const callbacks = require("../../lib/realtime-callbacks");
const testUtils = require("../test-utils.js");
const callbacks = require("../../src/realtime-callbacks");
import expect from 'expect';
import lolex from 'lolex';
let wallTime = 1234567890;
jest.useFakeTimers();
describe("realtime-callbacks", function() {
let clock;
function tick(millis) {
clock.tick(millis);
wallTime += millis;
jest.advanceTimersByTime(millis);
}
beforeEach(function() {
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
clock = lolex.install();
const fakeDate = clock.Date;
callbacks.setNow(fakeDate.now.bind(fakeDate));
callbacks.setNow(() => wallTime);
});
afterEach(function() {
callbacks.setNow();
clock.uninstall();
});
describe("setTimeout", function() {
it("should call the callback after the timeout", function() {
const callback = expect.createSpy();
const callback = jest.fn();
callbacks.setTimeout(callback, 100);
expect(callback).toNotHaveBeenCalled();
expect(callback).not.toHaveBeenCalled();
tick(100);
expect(callback).toHaveBeenCalled();
});
it("should default to a zero timeout", function() {
const callback = expect.createSpy();
const callback = jest.fn();
callbacks.setTimeout(callback);
expect(callback).toNotHaveBeenCalled();
expect(callback).not.toHaveBeenCalled();
tick(0);
expect(callback).toHaveBeenCalled();
});
it("should pass any parameters to the callback", function() {
const callback = expect.createSpy();
const callback = jest.fn();
callbacks.setTimeout(callback, 0, "a", "b", "c");
tick(0);
expect(callback).toHaveBeenCalledWith("a", "b", "c");
@@ -66,10 +59,10 @@ describe("realtime-callbacks", function() {
});
it("should handle timeouts of several seconds", function() {
const callback = expect.createSpy();
const callback = jest.fn();
callbacks.setTimeout(callback, 2000);
expect(callback).toNotHaveBeenCalled();
expect(callback).not.toHaveBeenCalled();
for (let i = 0; i < 4; i++) {
tick(500);
}
@@ -77,24 +70,24 @@ describe("realtime-callbacks", function() {
});
it("should call multiple callbacks in the right order", function() {
const callback1 = expect.createSpy();
const callback2 = expect.createSpy();
const callback3 = expect.createSpy();
const callback1 = jest.fn();
const callback2 = jest.fn();
const callback3 = jest.fn();
callbacks.setTimeout(callback2, 200);
callbacks.setTimeout(callback1, 100);
callbacks.setTimeout(callback3, 300);
expect(callback1).toNotHaveBeenCalled();
expect(callback2).toNotHaveBeenCalled();
expect(callback3).toNotHaveBeenCalled();
expect(callback1).not.toHaveBeenCalled();
expect(callback2).not.toHaveBeenCalled();
expect(callback3).not.toHaveBeenCalled();
tick(100);
expect(callback1).toHaveBeenCalled();
expect(callback2).toNotHaveBeenCalled();
expect(callback3).toNotHaveBeenCalled();
expect(callback2).not.toHaveBeenCalled();
expect(callback3).not.toHaveBeenCalled();
tick(100);
expect(callback1).toHaveBeenCalled();
expect(callback2).toHaveBeenCalled();
expect(callback3).toNotHaveBeenCalled();
expect(callback3).not.toHaveBeenCalled();
tick(100);
expect(callback1).toHaveBeenCalled();
expect(callback2).toHaveBeenCalled();
@@ -102,35 +95,34 @@ describe("realtime-callbacks", function() {
});
it("should treat -ve timeouts the same as a zero timeout", function() {
const callback1 = expect.createSpy();
const callback2 = expect.createSpy();
const callback1 = jest.fn();
const callback2 = jest.fn();
// check that cb1 is called before cb2
callback1.andCall(function() {
expect(callback2).toNotHaveBeenCalled();
callback1.mockImplementation(function() {
expect(callback2).not.toHaveBeenCalled();
});
callbacks.setTimeout(callback1);
callbacks.setTimeout(callback2, -100);
expect(callback1).toNotHaveBeenCalled();
expect(callback2).toNotHaveBeenCalled();
expect(callback1).not.toHaveBeenCalled();
expect(callback2).not.toHaveBeenCalled();
tick(0);
expect(callback1).toHaveBeenCalled();
expect(callback2).toHaveBeenCalled();
});
it("should not get confused by chained calls", function() {
const callback2 = expect.createSpy();
const callback1 = expect.createSpy();
callback1.andCall(function() {
const callback2 = jest.fn();
const callback1 = jest.fn(function() {
callbacks.setTimeout(callback2, 0);
expect(callback2).toNotHaveBeenCalled();
expect(callback2).not.toHaveBeenCalled();
});
callbacks.setTimeout(callback1);
expect(callback1).toNotHaveBeenCalled();
expect(callback2).toNotHaveBeenCalled();
expect(callback1).not.toHaveBeenCalled();
expect(callback2).not.toHaveBeenCalled();
tick(0);
expect(callback1).toHaveBeenCalled();
// 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() {
const callback1 = expect.createSpy();
callback1.andCall(function() {
const callback1 = jest.fn(function() {
throw new Error("prepare to die");
});
const callback2 = expect.createSpy();
const callback2 = jest.fn();
callbacks.setTimeout(callback1, 0);
callbacks.setTimeout(callback2, 0);
expect(callback1).toNotHaveBeenCalled();
expect(callback2).toNotHaveBeenCalled();
expect(callback1).not.toHaveBeenCalled();
expect(callback2).not.toHaveBeenCalled();
tick(0);
expect(callback1).toHaveBeenCalled();
expect(callback2).toHaveBeenCalled();
@@ -158,16 +149,16 @@ describe("realtime-callbacks", function() {
describe("cancelTimeout", function() {
it("should cancel a pending timeout", function() {
const callback = expect.createSpy();
const callback = jest.fn();
const k = callbacks.setTimeout(callback);
callbacks.clearTimeout(k);
tick(0);
expect(callback).toNotHaveBeenCalled();
expect(callback).not.toHaveBeenCalled();
});
it("should not affect sooner timeouts", function() {
const callback1 = expect.createSpy();
const callback2 = expect.createSpy();
const callback1 = jest.fn();
const callback2 = jest.fn();
callbacks.setTimeout(callback1, 100);
const k = callbacks.setTimeout(callback2, 200);
@@ -175,10 +166,10 @@ describe("realtime-callbacks", function() {
tick(100);
expect(callback1).toHaveBeenCalled();
expect(callback2).toNotHaveBeenCalled();
expect(callback2).not.toHaveBeenCalled();
tick(150);
expect(callback2).toNotHaveBeenCalled();
expect(callback2).not.toHaveBeenCalled();
});
});
});
+5 -8
View File
@@ -4,8 +4,6 @@ const sdk = require("../..");
const RoomMember = sdk.RoomMember;
const utils = require("../test-utils");
import expect from 'expect';
describe("RoomMember", function() {
const roomId = "!foo:bar";
const userA = "@alice:bar";
@@ -14,7 +12,6 @@ describe("RoomMember", function() {
let member;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
member = new RoomMember(roomId, userA);
});
@@ -36,7 +33,7 @@ describe("RoomMember", function() {
const url = member.getAvatarUrl(hsUrl);
// we don't care about how the mxc->http conversion is done, other
// 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 " +
@@ -255,9 +252,9 @@ describe("RoomMember", function() {
member.setMembershipEvent(joinEvent);
expect(member.name).toEqual("Alice"); // prefer displayname
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
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() {
@@ -328,9 +325,9 @@ describe("RoomMember", function() {
};
expect(member.name).toEqual(userA); // default = user_id
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
expect(member.name.indexOf(userA)).toNotEqual(-1);
expect(member.name.indexOf(userA)).not.toEqual(-1);
});
});
});
+6 -9
View File
@@ -5,8 +5,6 @@ const RoomState = sdk.RoomState;
const RoomMember = sdk.RoomMember;
const utils = require("../test-utils");
import expect from 'expect';
describe("RoomState", function() {
const roomId = "!foo:bar";
const userA = "@alice:bar";
@@ -17,7 +15,6 @@ describe("RoomState", function() {
let state;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
state = new RoomState(roomId);
state.setStateEvents([
utils.mkMembership({ // userA joined
@@ -49,8 +46,8 @@ describe("RoomState", function() {
const members = state.getMembers();
expect(members.length).toEqual(2);
// ordering unimportant
expect([userA, userB].indexOf(members[0].userId)).toNotEqual(-1);
expect([userA, userB].indexOf(members[1].userId)).toNotEqual(-1);
expect([userA, userB].indexOf(members[0].userId)).not.toEqual(-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");
expect(events.length).toEqual(2);
// ordering unimportant
expect([userA, userB].indexOf(events[0].getStateKey())).toNotEqual(-1);
expect([userA, userB].indexOf(events[1].getStateKey())).toNotEqual(-1);
expect([userA, userB].indexOf(events[0].getStateKey())).not.toEqual(-1);
expect([userA, userB].indexOf(events[1].getStateKey())).not.toEqual(-1);
});
it("should return a single MatrixEvent if a state_key was specified",
@@ -258,7 +255,7 @@ describe("RoomState", function() {
});
state.setStateEvents([memberEvent]);
expect(state.members[userA].setMembershipEvent).toNotHaveBeenCalled();
expect(state.members[userA].setMembershipEvent).not.toHaveBeenCalled();
expect(state.members[userB].setMembershipEvent).toHaveBeenCalledWith(
memberEvent, state,
);
@@ -306,7 +303,7 @@ describe("RoomState", function() {
state.markOutOfBandMembersStarted();
state.setOutOfBandMembers([oobMemberEvent]);
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);
});
+32 -33
View File
@@ -8,8 +8,6 @@ const EventStatus = sdk.EventStatus;
const EventTimeline = sdk.EventTimeline;
const utils = require("../test-utils");
import expect from 'expect';
describe("Room", function() {
const roomId = "!foo:bar";
const userA = "@alice:bar";
@@ -19,7 +17,6 @@ describe("Room", function() {
let room;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
room = new Room(roomId);
// mock RoomStates
room.oldState = room.getLiveTimeline()._startState =
@@ -32,7 +29,7 @@ describe("Room", function() {
const hsUrl = "https://my.home.server";
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 === "") {
return utils.mkEvent({
event: true,
@@ -49,7 +46,7 @@ describe("Room", function() {
const url = room.getAvatarUrl(hsUrl);
// we don't care about how the mxc->http conversion is done, other
// 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 " +
@@ -67,13 +64,13 @@ describe("Room", function() {
describe("getMember", function() {
beforeEach(function() {
room.currentState.getMember.andCall(function(userId) {
room.currentState.getMember.mockImplementation(function(userId) {
return {
"@alice:bar": {
userId: userA,
roomId: roomId,
},
}[userId];
}[userId] || null;
});
});
@@ -82,7 +79,7 @@ describe("Room", 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[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() {
@@ -183,7 +180,7 @@ describe("Room", function() {
membership: "join",
name: "Alice",
};
room.currentState.getSentinelMember.andCall(function(uid) {
room.currentState.getSentinelMember.mockImplementation(function(uid) {
if (uid === userA) {
return sentinel;
}
@@ -292,13 +289,13 @@ describe("Room", function() {
membership: "join",
name: "Old Alice",
};
room.currentState.getSentinelMember.andCall(function(uid) {
room.currentState.getSentinelMember.mockImplementation(function(uid) {
if (uid === userA) {
return sentinel;
}
return null;
});
room.oldState.getSentinelMember.andCall(function(uid) {
room.oldState.getSentinelMember.mockImplementation(function(uid) {
if (uid === userA) {
return oldSentinel;
}
@@ -331,13 +328,13 @@ describe("Room", function() {
membership: "join",
name: "Old Alice",
};
room.currentState.getSentinelMember.andCall(function(uid) {
room.currentState.getSentinelMember.mockImplementation(function(uid) {
if (uid === userA) {
return sentinel;
}
return null;
});
room.oldState.getSentinelMember.andCall(function(uid) {
room.oldState.getSentinelMember.mockImplementation(function(uid) {
if (uid === userA) {
return oldSentinel;
}
@@ -379,7 +376,7 @@ describe("Room", function() {
);
expect(events[0].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() {
it("should return members whose membership is 'join'", function() {
room.currentState.getMembers.andCall(function() {
room.currentState.getMembers.mockImplementation(function() {
return [
{ userId: "@alice:bar", membership: "join" },
{ userId: "@bob:bar", membership: "invite" },
@@ -558,7 +555,7 @@ describe("Room", function() {
});
it("should return an empty list if no membership is 'join'", function() {
room.currentState.getMembers.andCall(function() {
room.currentState.getMembers.mockImplementation(function() {
return [
{ userId: "@bob:bar", membership: "invite" },
];
@@ -571,7 +568,7 @@ describe("Room", function() {
describe("hasMembershipState", function() {
it("should return true for a matching userId and membership",
function() {
room.currentState.getMember.andCall(function(userId) {
room.currentState.getMember.mockImplementation(function(userId) {
return {
"@alice:bar": { userId: "@alice:bar", membership: "join" },
"@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",
function() {
room.currentState.getMember.andCall(function(userId) {
room.currentState.getMember.mockImplementation(function(userId) {
return {
"@alice:bar": { userId: "@alice:bar", membership: "join" },
}[userId];
@@ -592,7 +589,7 @@ describe("Room", function() {
it("should return false if match userId but no match membership",
function() {
room.currentState.getMember.andCall(function(userId) {
room.currentState.getMember.mockImplementation(function(userId) {
return {
"@alice:bar": { userId: "@alice:bar", membership: "join" },
}[userId];
@@ -602,7 +599,7 @@ describe("Room", function() {
it("should return false if no match membership or userId",
function() {
room.currentState.getMember.andCall(function(userId) {
room.currentState.getMember.mockImplementation(function(userId) {
return {
"@alice:bar": { userId: "@alice:bar", membership: "join" },
}[userId];
@@ -626,7 +623,9 @@ describe("Room", function() {
};
const setAliases = function(aliases, stateKey) {
if (!stateKey) {
stateKey = "flibble";
stateKey = aliases.length
? aliases[0].split(':').splice(1).join(':') // domain+port
: 'fibble';
}
room.addLiveEvents([utils.mkEvent({
type: "m.room.aliases", room: roomId, skey: stateKey, content: {
@@ -814,8 +813,8 @@ describe("Room", function() {
addMember(userC);
room.recalculate();
const name = room.name;
expect(name.indexOf(userB)).toNotEqual(-1, name);
expect(name.indexOf(userC)).toNotEqual(-1, name);
expect(name.indexOf(userB)).not.toEqual(-1, name);
expect(name.indexOf(userC)).not.toEqual(-1, name);
});
it("should return the names of members in a public (public join_rules)" +
@@ -827,8 +826,8 @@ describe("Room", function() {
addMember(userC);
room.recalculate();
const name = room.name;
expect(name.indexOf(userB)).toNotEqual(-1, name);
expect(name.indexOf(userC)).toNotEqual(-1, name);
expect(name.indexOf(userB)).not.toEqual(-1, name);
expect(name.indexOf(userC)).not.toEqual(-1, name);
});
it("should show the other user's name for public (public join_rules)" +
@@ -839,7 +838,7 @@ describe("Room", function() {
addMember(userB);
room.recalculate();
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 " +
@@ -850,7 +849,7 @@ describe("Room", function() {
addMember(userB);
room.recalculate();
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" +
@@ -860,14 +859,14 @@ describe("Room", function() {
addMember(userB);
room.recalculate();
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 " +
"(invite join_rules) rooms if a room name doesn't exist.", function() {
const alias = "#room_alias:here";
setJoinRule("invite");
setAliases([alias, "#another:one"]);
setAliases([alias, "#another:here"]);
room.recalculate();
const name = room.name;
expect(name).toEqual(alias);
@@ -877,7 +876,7 @@ describe("Room", function() {
"(public join_rules) rooms if a room name doesn't exist.", function() {
const alias = "#room_alias:here";
setJoinRule("public");
setAliases([alias, "#another:one"]);
setAliases([alias, "#another:here"]);
room.recalculate();
const name = room.name;
expect(name).toEqual(alias);
@@ -1004,7 +1003,7 @@ describe("Room", function() {
it("should emit an event when a receipt is added",
function() {
const listener = expect.createSpy();
const listener = jest.fn();
room.on("Room.receipt", listener);
const ts = 13787898424;
@@ -1175,7 +1174,7 @@ describe("Room", function() {
it("should emit Room.tags event when new tags are " +
"received on the event stream",
function() {
const listener = expect.createSpy();
const listener = jest.fn();
room.on("Room.tags", listener);
const tags = { "m.foo": { "order": 0.5 } };
+3 -11
View File
@@ -8,11 +8,9 @@ const MatrixScheduler = sdk.MatrixScheduler;
const MatrixError = sdk.MatrixError;
const utils = require("../test-utils");
import expect from 'expect';
import lolex from 'lolex';
jest.useFakeTimers();
describe("MatrixScheduler", function() {
let clock;
let scheduler;
let retryFn;
let queueFn;
@@ -26,8 +24,6 @@ describe("MatrixScheduler", function() {
});
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
clock = lolex.install();
scheduler = new MatrixScheduler(function(ev, attempts, err) {
if (retryFn) {
return retryFn(ev, attempts, err);
@@ -44,10 +40,6 @@ describe("MatrixScheduler", function() {
defer = Promise.defer();
});
afterEach(function() {
clock.uninstall();
});
it("should process events in a queue in a FIFO manner", async function() {
retryFn = function() {
return 0;
@@ -112,7 +104,7 @@ describe("MatrixScheduler", function() {
defer.reject({});
await retryDefer.promise;
expect(procCount).toEqual(1);
clock.tick(waitTimeMs);
jest.advanceTimersByTime(waitTimeMs);
await Promise.resolve();
expect(procCount).toEqual(2);
});
@@ -203,7 +195,7 @@ describe("MatrixScheduler", function() {
setTimeout(function() {
deferA.resolve({});
}, 1000);
clock.tick(1000);
jest.advanceTimersByTime(1000);
});
describe("queueEvent", function() {
-3
View File
@@ -16,9 +16,7 @@ limitations under the License.
"use strict";
import 'source-map-support/register';
import utils from "../test-utils";
import sdk from "../..";
import expect from 'expect';
const SyncAccumulator = sdk.SyncAccumulator;
@@ -26,7 +24,6 @@ describe("SyncAccumulator", function() {
let sa;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
sa = new SyncAccumulator({
maxTimelineEntries: 10,
});
+30 -42
View File
@@ -7,7 +7,6 @@ const TimelineWindow = sdk.TimelineWindow;
const TimelineIndex = require("../../lib/timeline-window").TimelineIndex;
const utils = require("../test-utils");
import expect from 'expect';
const ROOM_ID = "roomId";
const USER_ID = "userId";
@@ -67,10 +66,6 @@ function createLinkedTimelines() {
describe("TimelineIndex", function() {
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
describe("minIndex", function() {
it("should return the min index relative to BaseIndex", function() {
const timelineIndex = new TimelineIndex(createTimeline(), 0);
@@ -153,7 +148,7 @@ describe("TimelineWindow", function() {
let timelineSet;
let client;
function createWindow(timeline, opts) {
timelineSet = {};
timelineSet = {getTimelineForEvent: () => null};
client = {};
client.getEventTimeline = function(timelineSet0, eventId0) {
expect(timelineSet0).toBe(timelineSet);
@@ -163,12 +158,8 @@ describe("TimelineWindow", function() {
return new TimelineWindow(client, timelineSet, opts);
}
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
describe("load", function() {
it("should initialise from the live timeline", function(done) {
it("should initialise from the live timeline", function() {
const liveTimeline = createTimeline();
const room = {};
room.getLiveTimeline = function() {
@@ -176,17 +167,17 @@ describe("TimelineWindow", function() {
};
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);
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 eventId = timeline.getEvents()[1].getId();
const timelineSet = {};
const timelineSet = {getTimelineForEvent: () => null};
const client = {};
client.getEventTimeline = function(timelineSet0, eventId0) {
expect(timelineSet0).toBe(timelineSet);
@@ -195,21 +186,20 @@ describe("TimelineWindow", function() {
};
const timelineWindow = new TimelineWindow(client, timelineSet);
timelineWindow.load(eventId, 3).then(function() {
return timelineWindow.load(eventId, 3).then(function() {
const expectedEvents = timeline.getEvents();
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
}).nodeify(done);
});
});
it("canPaginate should return false until load has returned",
function(done) {
it("canPaginate should return false until load has returned", function() {
const timeline = createTimeline();
timeline.setPaginationToken("toktok1", EventTimeline.BACKWARDS);
timeline.setPaginationToken("toktok2", EventTimeline.FORWARDS);
const eventId = timeline.getEvents()[1].getId();
const timelineSet = {};
const timelineSet = {getTimelineForEvent: () => null};
const client = {};
const timelineWindow = new TimelineWindow(client, timelineSet);
@@ -222,25 +212,24 @@ describe("TimelineWindow", function() {
return Promise.resolve(timeline);
};
timelineWindow.load(eventId, 3).then(function() {
return timelineWindow.load(eventId, 3).then(function() {
const expectedEvents = timeline.getEvents();
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
expect(timelineWindow.canPaginate(EventTimeline.BACKWARDS))
.toBe(true);
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
.toBe(true);
}).nodeify(done);
});
});
});
describe("pagination", function() {
it("should be able to advance across the initial timeline",
function(done) {
it("should be able to advance across the initial timeline", function() {
const timeline = createTimeline();
const eventId = timeline.getEvents()[1].getId();
const timelineWindow = createWindow(timeline);
timelineWindow.load(eventId, 1).then(function() {
return timelineWindow.load(eventId, 1).then(function() {
const expectedEvents = [timeline.getEvents()[1]];
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
@@ -277,15 +266,15 @@ describe("TimelineWindow", function() {
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
}).then(function(success) {
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 eventId = tls[0].getEvents()[1].getId();
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();
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
@@ -322,15 +311,15 @@ describe("TimelineWindow", function() {
return timelineWindow.paginate(EventTimeline.FORWARDS, 2);
}).then(function(success) {
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 eventId = tls[1].getEvents()[1].getId();
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();
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
@@ -367,10 +356,10 @@ describe("TimelineWindow", function() {
return timelineWindow.paginate(EventTimeline.BACKWARDS, 2);
}).then(function(success) {
expect(success).toBe(false);
}).nodeify(done);
});
});
it("should make forward pagination requests", function(done) {
it("should make forward pagination requests", function() {
const timeline = createTimeline();
timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
@@ -386,7 +375,7 @@ describe("TimelineWindow", function() {
return Promise.resolve(true);
};
timelineWindow.load(eventId, 3).then(function() {
return timelineWindow.load(eventId, 3).then(function() {
const expectedEvents = timeline.getEvents();
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
@@ -399,11 +388,11 @@ describe("TimelineWindow", function() {
expect(success).toBe(true);
const expectedEvents = timeline.getEvents().slice(0, 5);
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();
timeline.setPaginationToken("toktok", EventTimeline.BACKWARDS);
@@ -419,7 +408,7 @@ describe("TimelineWindow", function() {
return Promise.resolve(true);
};
timelineWindow.load(eventId, 3).then(function() {
return timelineWindow.load(eventId, 3).then(function() {
const expectedEvents = timeline.getEvents();
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
@@ -432,11 +421,10 @@ describe("TimelineWindow", function() {
expect(success).toBe(true);
const expectedEvents = timeline.getEvents().slice(1, 6);
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
}).nodeify(done);
});
});
it("should limit the number of unsuccessful pagination requests",
function(done) {
it("should limit the number of unsuccessful pagination requests", function() {
const timeline = createTimeline();
timeline.setPaginationToken("toktok", EventTimeline.FORWARDS);
@@ -452,7 +440,7 @@ describe("TimelineWindow", function() {
return Promise.resolve(true);
};
timelineWindow.load(eventId, 3).then(function() {
return timelineWindow.load(eventId, 3).then(function() {
const expectedEvents = timeline.getEvents();
expect(timelineWindow.getEvents()).toEqual(expectedEvents);
@@ -471,7 +459,7 @@ describe("TimelineWindow", function() {
.toBe(false);
expect(timelineWindow.canPaginate(EventTimeline.FORWARDS))
.toBe(true);
}).nodeify(done);
});
});
});
});
-3
View File
@@ -4,14 +4,11 @@ const sdk = require("../..");
const User = sdk.User;
const utils = require("../test-utils");
import expect from 'expect';
describe("User", function() {
const userId = "@alice:bar";
let user;
beforeEach(function() {
utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
user = new User(userId);
});
+2 -9
View File
@@ -1,15 +1,8 @@
"use strict";
import 'source-map-support/register';
const utils = require("../../lib/utils");
const testUtils = require("../test-utils");
import expect from 'expect';
describe("utils", function() {
beforeEach(function() {
testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this
});
describe("encodeParams", function() {
it("should url encode and concat with &s", function() {
const params = {
@@ -135,7 +128,7 @@ describe("utils", function() {
utils.checkObjectHasKeys({
foo: "bar",
}, ["foo"]);
}).toNotThrow();
}).not.toThrow();
});
});
@@ -152,7 +145,7 @@ describe("utils", function() {
utils.checkObjectHasNoAdditionalKeys({
foo: "bar",
}, ["foo"]);
}).toNotThrow();
}).not.toThrow();
});
});
+4 -13
View File
@@ -1,5 +1,6 @@
/*
Copyright 2018 New Vector Ltd
Copyright 2019 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -275,21 +276,11 @@ export class AutoDiscovery {
let isUrl = "";
if (wellknown["m.identity_server"]) {
// We prepare a failing identity server response to save lines later
// in this branch. Note that we also fail the homeserver check in the
// 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.
// in this branch.
const failingClientConfig = {
"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.homeserver": clientConfig["m.homeserver"],
"m.identity_server": {
state: AutoDiscovery.FAIL_ERROR,
state: AutoDiscovery.FAIL_PROMPT,
error: AutoDiscovery.ERROR_INVALID_IS,
base_url: null,
},
+6
View File
@@ -2333,6 +2333,12 @@ MatrixBaseApis.prototype.sendToDevice = function(
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);
};
+128 -105
View File
@@ -19,6 +19,7 @@ limitations under the License.
"use strict";
const PushProcessor = require('./pushprocessor');
import {sleep} from './utils';
/**
* 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;
keys.push(decrypted);
} catch (e) {
logger.log("Failed to decrypt session from backup");
logger.log("Failed to decrypt megolm session from backup", e);
}
}
return keys;
@@ -1625,7 +1626,7 @@ MatrixClient.prototype._restoreKeyBackup = function(
key.session_id = targetSessionId;
keys.push(key);
} catch (e) {
logger.log("Failed to decrypt session from backup");
logger.log("Failed to decrypt megolm session from backup", e);
}
}
@@ -1871,33 +1872,33 @@ MatrixClient.prototype.joinRoom = function(roomIdOrAlias, opts, callback) {
const reqOpts = {qsStringifyOptions: {arrayFormat: 'repeat'}};
const defer = Promise.defer();
const self = this;
sign_promise.then(function(signed_invite_object) {
const data = {};
if (signed_invite_object) {
data.third_party_signed = signed_invite_object;
}
const prom = new Promise((resolve, reject) => {
sign_promise.then(function(signed_invite_object) {
const data = {};
if (signed_invite_object) {
data.third_party_signed = signed_invite_object;
}
const path = utils.encodeUri("/join/$roomid", { $roomid: roomIdOrAlias});
return self._http.authedRequest(
undefined, "POST", path, queryString, data, reqOpts);
}).then(function(res) {
const roomId = res.room_id;
const syncApi = new SyncApi(self, self._clientOpts);
const room = syncApi.createRoom(roomId);
if (opts.syncRoom) {
// v2 will do this for us
// return syncApi.syncRoom(room);
}
return Promise.resolve(room);
}).done(function(room) {
_resolve(callback, defer, room);
}, function(err) {
_reject(callback, defer, err);
const path = utils.encodeUri("/join/$roomid", { $roomid: roomIdOrAlias});
return self._http.authedRequest(
undefined, "POST", path, queryString, data, reqOpts);
}).then(function(res) {
const roomId = res.room_id;
const syncApi = new SyncApi(self, self._clientOpts);
const room = syncApi.createRoom(roomId);
if (opts.syncRoom) {
// v2 will do this for us
// return syncApi.syncRoom(room);
}
return Promise.resolve(room);
}).done(function(room) {
_resolve(callback, resolve, room);
}, function(err) {
_reject(callback, reject, err);
});
});
return defer.promise;
return prom;
};
/**
@@ -3213,42 +3214,45 @@ MatrixClient.prototype.scrollback = function(room, limit, callback) {
// reduce the required number of events appropriately
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 = {
promise: defer.promise,
promise: prom,
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;
return defer.promise;
return prom;
};
/**
@@ -3866,7 +3870,7 @@ MatrixClient.prototype.setRoomMutePushRule = function(scope, roomId, mute) {
} else if (!hasDontNotifyRule) {
// Remove the existing one before setting the mute push rule
// This is a workaround to SYN-590 (Push rule update fails)
deferred = Promise.defer();
deferred = utils.defer();
this.deletePushRule(scope, "room", roomPushRule.rule_id)
.done(function() {
self.addPushRule(scope, "room", roomId, {
@@ -3885,26 +3889,26 @@ MatrixClient.prototype.setRoomMutePushRule = function(scope, roomId, mute) {
}
if (deferred) {
// Update this.pushRules when the operation completes
const ruleRefreshDeferred = Promise.defer();
deferred.done(function() {
self.getPushRules().done(function(result) {
self.pushRules = result;
ruleRefreshDeferred.resolve();
return new Promise((resolve, reject) => {
// Update this.pushRules when the operation completes
deferred.done(function() {
self.getPushRules().done(function(result) {
self.pushRules = result;
resolve();
}, function(err) {
reject(err);
});
}, function(err) {
ruleRefreshDeferred.reject(err);
});
}, function(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
self.getPushRules().done(function(result) {
self.pushRules = result;
ruleRefreshDeferred.reject(err);
}, function(err2) {
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
self.getPushRules().done(function(result) {
self.pushRules = result;
reject(err);
}, function(err2) {
reject(err);
});
});
});
return ruleRefreshDeferred.promise;
}
};
@@ -4634,15 +4638,20 @@ function setupCallEventHandler(client) {
// callId: [Candidate]
};
// Maintain a buffer of events before the client has synced for the first time.
// This buffer will be inspected to see if we should send incoming call
// notifications. It needs to be buffered to correctly determine if an
// incoming call has had a matching answer/hangup.
// The sync code always emits one event at a time, so it will patiently
// wait for us to finish processing a call invite before delivering the
// next event, even if that next event is a hangup. We therefore accumulate
// 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 isClientPrepared = false;
client.on("sync", function(state) {
if (state === "PREPARED") {
isClientPrepared = true;
function evaluateEventBuffer() {
if (client.getSyncState() === "SYNCING") {
// don't process any events until they are all decrypted
if (callEventBuffer.some((e) => e.isBeingDecrypted())) return;
const ignoreCallIds = {}; // Set<String>
// inspect the buffer and mark all calls which have been answered
// or hung up before passing them to the call event handler.
@@ -4655,39 +4664,51 @@ function setupCallEventHandler(client) {
}
// now loop through the buffer chronologically and inject them
callEventBuffer.forEach(function(e) {
if (ignoreCallIds[e.getContent().call_id]) {
// This call has previously been ansered or hung up: ignore it
if (
e.getType() === "m.call.invite" &&
ignoreCallIds[e.getContent().call_id]
) {
// This call has previously been answered or hung up: ignore it
return;
}
callEventHandler(e);
});
callEventBuffer = [];
}
});
client.on("event", onEvent);
}
client.on("sync", evaluateEventBuffer);
function onEvent(event) {
if (event.getType().indexOf("m.call.") !== 0) {
// not a call event
if (event.isBeingDecrypted() || event.isDecryptionFailure()) {
// not *yet* a call event, but might become one...
event.once("Event.decrypted", onEvent);
}
return;
}
if (!isClientPrepared) {
// any call events or ones that might be once they're decrypted
if (event.getType().indexOf("m.call.") === 0 || event.isBeingDecrypted()) {
// queue up for processing once all events from this sync have been
// processed (see above).
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) {
const content = event.getContent();
let call = content.call_id ? client.callList[content.call_id] : undefined;
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.getSender() === client.credentials.userId) {
@@ -4858,18 +4879,18 @@ function checkTurnServers(client) {
});
}
function _reject(callback, defer, err) {
function _reject(callback, reject, err) {
if (callback) {
callback(err);
}
defer.reject(err);
reject(err);
}
function _resolve(callback, defer, res) {
function _resolve(callback, resolve, res) {
if (callback) {
callback(null, res);
}
defer.resolve(res);
resolve(res);
}
function _PojoToMatrixEventMapper(client) {
@@ -5201,6 +5222,8 @@ module.exports.CRYPTO_ENABLED = CRYPTO_ENABLED;
* @param {object} data
* @param {MatrixEvent} data.event the original verification request message
* @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
* verification should be performed. The function takes one argument: the
* name of the key verification method (taken from data.methods) to use.
+2 -1
View File
@@ -31,6 +31,7 @@ import DeviceInfo from './deviceinfo';
import {CrossSigningInfo} from './CrossSigning';
import olmlib from './olmlib';
import IndexedDBCryptoStore from './store/indexeddb-crypto-store';
import {sleep} from '../utils';
/* State transition diagram for DeviceList._deviceTrackingStatus
@@ -763,7 +764,7 @@ class DeviceListUpdateSerialiser {
// this serves as an easy solution for now.
let prom = Promise.resolve();
for (const userId of downloadUsers) {
prom = prom.delay(5).then(() => {
prom = prom.then(sleep(5)).then(() => {
return this._processQueryResponseForUser(
userId, dk[userId], {
master: masterKeys[userId],
+11 -7
View File
@@ -462,7 +462,7 @@ OlmDevice.prototype.createInboundSession = async function(
*/
OlmDevice.prototype.getSessionIdsForDevice = async function(theirDeviceIdentityKey) {
if (this._sessionsInProgress[theirDeviceIdentityKey]) {
logger.log("waiting for session to be created");
logger.log("waiting for olm session to be created");
try {
await this._sessionsInProgress[theirDeviceIdentityKey];
} catch (e) {
@@ -543,7 +543,7 @@ OlmDevice.prototype.getSessionIdForDevice = async function(
*/
OlmDevice.prototype.getSessionInfoForDevice = async function(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 {
await this._sessionsInProgress[deviceIdentityKey];
} catch (e) {
@@ -595,8 +595,8 @@ OlmDevice.prototype.encryptMessage = async function(
(txn) => {
this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => {
const sessionDesc = sessionInfo.session.describe();
console.log(
"Session ID " + sessionId + " to " +
logger.log(
"encryptMessage: Olm Session ID " + sessionId + " to " +
theirDeviceIdentityKey + ": " + sessionDesc,
);
res = sessionInfo.session.encrypt(payloadString);
@@ -627,8 +627,8 @@ OlmDevice.prototype.decryptMessage = async function(
(txn) => {
this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => {
const sessionDesc = sessionInfo.session.describe();
console.log(
"Session ID " + sessionId + " to " +
logger.log(
"decryptMessage: Olm Session ID " + sessionId + " from " +
theirDeviceIdentityKey + ": " + sessionDesc,
);
payloadString = sessionInfo.session.decrypt(messageType, ciphertext);
@@ -740,6 +740,8 @@ OlmDevice.prototype.createOutboundGroupSession = function() {
OlmDevice.prototype.encryptGroupMessage = function(sessionId, payloadString) {
const self = this;
logger.log(`encrypting msg with megolm session ${sessionId}`);
checkPayloadLength(payloadString);
return this._getOutboundGroupSession(sessionId, function(session) {
@@ -886,7 +888,9 @@ OlmDevice.prototype.addInboundGroupSession = async function(
<= session.first_known_index()) {
// existing session has lower index (i.e. can
// decrypt more), so keep it
logger.log("Keeping existing session");
logger.log(
`Keeping existing megolm session ${sessionId}`,
);
return;
}
}
+17 -16
View File
@@ -104,7 +104,7 @@ OutboundSessionInfo.prototype.sharedWithTooManyDevices = function(
}
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;
}
@@ -115,7 +115,7 @@ OutboundSessionInfo.prototype.sharedWithTooManyDevices = function(
if (!devicesInRoom[userId].hasOwnProperty(deviceId)) {
logger.log(
"Starting new session because we shared with " +
"Starting new megolm session because we shared with " +
userId + ":" + deviceId,
);
return true;
@@ -200,6 +200,8 @@ MegolmEncryption.prototype._ensureOutboundSession = function(devicesInRoom) {
if (!session) {
logger.log(`Starting new megolm session for room ${self._roomId}`);
session = await self._prepareNewSession();
logger.log(`Started new megolm session ${session.sessionId} ` +
`for room ${self._roomId}`);
self._outboundSessions[session.sessionId] = session;
}
@@ -278,7 +280,7 @@ MegolmEncryption.prototype._prepareNewSession = async function() {
).catch((e) => {
// This throws if the upload failed, but this is fine
// 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];
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;
}
// The chain index of the key we previously sent this device
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;
}
const sentChainIndex = obSessionInfo.sharedWithDevices[userId][device.deviceId];
if (sentChainIndex === undefined) {
logger.debug(
"Session ID " + sessionId + " never shared with device " +
"megolm session ID " + sessionId + " never shared with device " +
userId + ":" + device.deviceId,
);
return;
@@ -466,7 +468,7 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function(
if (!key) {
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;
}
@@ -513,9 +515,8 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function(
[device.deviceId]: encryptedContent,
},
});
logger.debug(
`Re-shared key for session ${sessionId} with ${userId}:${device.deviceId}`,
);
logger.debug(`Re-shared key for megolm session ${sessionId} ` +
`with ${userId}:${device.deviceId}`);
};
/**
@@ -550,10 +551,10 @@ MegolmEncryption.prototype._shareKeyWithDevices = async function(session, device
await this._encryptAndSendKeysToDevices(
session, key.chain_index, userDeviceMaps[i], payload,
);
logger.log(`Completed megolm keyshare in ${this._roomId} `
+ `(slice ${i + 1}/${userDeviceMaps.length})`);
logger.log(`Completed megolm keyshare for ${session.sessionId} `
+ `in ${this._roomId} (slice ${i + 1}/${userDeviceMaps.length})`);
} 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`);
throw e;
@@ -922,7 +923,7 @@ MegolmDecryption.prototype.onRoomKeyEvent = function(event) {
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(
content.room_id, senderKey, forwardingKeyChain, sessionId,
content.session_key, keysClaimed,
@@ -955,7 +956,7 @@ MegolmDecryption.prototype.onRoomKeyEvent = function(event) {
).catch((e) => {
// This throws if the upload failed, but this is fine
// 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) => {
@@ -1088,7 +1089,7 @@ MegolmDecryption.prototype.importRoomKey = function(session) {
).catch((e) => {
// This throws if the upload failed, but this is fine
// 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.
+1 -1
View File
@@ -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);
};
/**
+112 -23
View File
@@ -49,6 +49,7 @@ import {
newUnexpectedMessageError,
newUnknownMethodError,
} from './verification/Error';
import {sleep} from '../utils';
const defaultVerificationMethods = {
[ScanQRCode.NAME]: ScanQRCode,
@@ -65,6 +66,16 @@ export const verificationMethods = {
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() {
return Boolean(global.Olm);
}
@@ -919,6 +930,14 @@ Crypto.prototype.registerEventHandlers = function(eventEmitter) {
eventEmitter.on("toDeviceEvent", function(event) {
crypto._onToDeviceEvent(event);
});
eventEmitter.on("Room.timeline", function(event) {
crypto._onTimelineEvent(event);
});
eventEmitter.on("Event.decrypted", function(event) {
crypto._onTimelineEvent(event);
});
};
@@ -1619,7 +1638,7 @@ Crypto.prototype.setRoomEncryption = async function(roomId, config, inhibitDevic
// It would otherwise just throw later as an unknown algorithm would, but we may
// as well catch this here
if (!config.algorithm) {
console.log("Ignoring setRoomEncryption with no algorithm");
logger.log("Ignoring setRoomEncryption with no algorithm");
return;
}
@@ -1805,17 +1824,15 @@ Crypto.prototype.exportRoomKeys = async function() {
* @return {module:client.Promise} a promise which resolves once the keys have been imported
*/
Crypto.prototype.importRoomKeys = function(keys) {
return Promise.map(
keys, (key) => {
if (!key.room_id || !key.algorithm) {
logger.warn("ignoring room key entry with missing fields", key);
return null;
}
return Promise.all(keys.map((key) => {
if (!key.room_id || !key.algorithm) {
logger.warn("ignoring room key entry with missing fields", key);
return null;
}
const alg = this._getRoomDecryptor(key.room_id, key.algorithm);
return alg.importRoomKey(key);
},
);
const alg = this._getRoomDecryptor(key.room_id, key.algorithm);
return alg.importRoomKey(key);
}));
};
/**
@@ -1834,7 +1851,7 @@ Crypto.prototype.scheduleKeyBackupSend = async function(maxDelay = 10000) {
// requests from different clients hitting the server all at
// the same time when a new key is sent
const delay = Math.random() * maxDelay;
await Promise.delay(delay);
await sleep(delay);
let numFailures = 0; // number of consecutive failures
while (1) {
if (!this.backupKey) {
@@ -1868,7 +1885,7 @@ Crypto.prototype.scheduleKeyBackupSend = async function(maxDelay = 10000) {
}
if (numFailures) {
// 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 {
@@ -2277,6 +2294,9 @@ Crypto.prototype._getTrackedE2eRooms = function() {
Crypto.prototype._onToDeviceEvent = function(event) {
try {
logger.log(`received to_device ${event.getType()} from: ` +
`${event.getSender()} id: ${event.getId()}`);
if (event.getType() == "m.room_key"
|| event.getType() == "m.forwarded_room_key") {
this._onRoomKeyEvent(event);
@@ -2343,8 +2363,8 @@ Crypto.prototype._onKeyVerificationRequest = function(event) {
const content = event.getContent();
if (!("from_device" in content) || typeof content.from_device !== "string"
|| !("transaction_id" in content) || typeof content.from_device !== "string"
|| !("methods" in content) || !(content.methods instanceof Array)
|| !("transaction_id" in content)
|| !("methods" in content) || !Array.isArray(content.methods)
|| !("timestamp" in content) || typeof content.timestamp !== "number") {
logger.warn("received invalid verification request from " + event.getSender());
// ignore event if malformed
@@ -2420,6 +2440,7 @@ Crypto.prototype._onKeyVerificationRequest = function(event) {
// notify the application of the verification request, so it can
// decide what to do with it
const request = {
timeout: VERIFICATION_REQUEST_TIMEOUT,
event: event,
methods: methods,
beginKeyVerification: (method) => {
@@ -2552,6 +2573,31 @@ Crypto.prototype._onKeyVerificationStart = function(event) {
}
}
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);
}
};
@@ -2584,6 +2630,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
*
@@ -2766,14 +2859,10 @@ Crypto.prototype._processReceivedRoomKeyRequests = async function() {
// cancellation (and end up with a cancelled request), rather than the
// cancellation before the request (and end up with an outstanding
// request which should have been cancelled.)
await Promise.map(
requests, (req) =>
this._processReceivedRoomKeyRequest(req),
);
await Promise.map(
cancellations, (cancellation) =>
this._processReceivedRoomKeyRequestCancellation(cancellation),
);
await Promise.all(requests.map((req) =>
this._processReceivedRoomKeyRequest(req)));
await Promise.all(cancellations.map((cancellation) =>
this._processReceivedRoomKeyRequestCancellation(cancellation)));
} catch (e) {
logger.error(`Error processing room key requsts: ${e}`);
} finally {
+2 -2
View File
@@ -287,12 +287,12 @@ async function _verifyKeyAndStartSession(olmDevice, oneTimeKey, userId, deviceIn
);
} catch (e) {
// possibly a bad key
logger.error("Error starting session with device " +
logger.error("Error starting olm session with device " +
userId + ":" + deviceId + ": " + e);
return null;
}
logger.log("Started new sessionid " + sid +
logger.log("Started new olm sessionid " + sid +
" for device " + userId + ":" + deviceId);
return sid;
}
@@ -58,35 +58,34 @@ export class Backend {
getOrAddOutgoingRoomKeyRequest(request) {
const requestBody = request.requestBody;
const deferred = Promise.defer();
const txn = this._db.transaction("outgoingRoomKeyRequests", "readwrite");
txn.onerror = deferred.reject;
return new Promise((resolve, reject) => {
const txn = this._db.transaction("outgoingRoomKeyRequests", "readwrite");
txn.onerror = reject;
// first see if we already have an entry for this request.
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
if (existing) {
// this entry matches the request - return it.
// first see if we already have an entry for this request.
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
if (existing) {
// 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(
`already have key request outstanding for ` +
`${requestBody.room_id} / ${requestBody.session_id}: ` +
`not sending another`,
`enqueueing key request for ${requestBody.room_id} / ` +
requestBody.session_id,
);
deferred.resolve(existing);
return;
}
// 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);
txn.oncomplete = () => { resolve(request); };
const store = txn.objectStore("outgoingRoomKeyRequests");
store.add(request);
});
});
return deferred.promise;
}
/**
@@ -100,15 +99,14 @@ export class Backend {
* not found
*/
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");
txn.onerror = deferred.reject;
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
deferred.resolve(existing);
this._getOutgoingRoomKeyRequest(txn, requestBody, (existing) => {
resolve(existing);
});
});
return deferred.promise;
}
/**
+60 -26
View File
@@ -287,7 +287,9 @@ export default class IndexedDBCryptoStore {
* @param {function(string)} func Called with the account pickle
*/
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.
*/
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
*/
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()
*/
storeCrossSigningKeys(txn, keys) {
this._backendPromise.value().storeCrossSigningKeys(txn, keys);
this._backendPromise.then(backend => {
backend.storeCrossSigningKeys(txn, keys);
});
}
// Olm sessions
@@ -331,7 +339,9 @@ export default class IndexedDBCryptoStore {
* @param {function(int)} func Called with the count of sessions
*/
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.
*/
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.
*/
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.
*/
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().
*/
storeEndToEndSession(deviceKey, sessionId, sessionInfo, txn) {
this._backendPromise.value().storeEndToEndSession(
deviceKey, sessionId, sessionInfo, txn,
);
this._backendPromise.then(backend => {
backend.storeEndToEndSession(
deviceKey, sessionId, sessionInfo, txn,
);
});
}
// Inbound group saessions
// Inbound group sessions
/**
* 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.
*/
getEndToEndInboundGroupSession(senderCurve25519Key, sessionId, txn, func) {
this._backendPromise.value().getEndToEndInboundGroupSession(
senderCurve25519Key, sessionId, txn, func,
);
this._backendPromise.then(backend => {
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.
*/
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().
*/
addEndToEndInboundGroupSession(senderCurve25519Key, sessionId, sessionData, txn) {
this._backendPromise.value().addEndToEndInboundGroupSession(
senderCurve25519Key, sessionId, sessionData, txn,
);
this._backendPromise.then(backend => {
backend.addEndToEndInboundGroupSession(
senderCurve25519Key, sessionId, sessionData, txn,
);
});
}
/**
@@ -442,9 +466,11 @@ export default class IndexedDBCryptoStore {
* @param {*} txn An active transaction. See doTxn().
*/
storeEndToEndInboundGroupSession(senderCurve25519Key, sessionId, sessionData, txn) {
this._backendPromise.value().storeEndToEndInboundGroupSession(
senderCurve25519Key, sessionId, sessionData, txn,
);
this._backendPromise.then(backend => {
backend.storeEndToEndInboundGroupSession(
senderCurve25519Key, sessionId, sessionData, txn,
);
});
}
// End-to-end device tracking
@@ -460,7 +486,9 @@ export default class IndexedDBCryptoStore {
* @param {*} txn An active transaction. See doTxn().
*/
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
*/
getEndToEndDeviceData(txn, func) {
this._backendPromise.value().getEndToEndDeviceData(txn, func);
this._backendPromise.then(backend => {
backend.getEndToEndDeviceData(txn, func);
});
}
// End to End Rooms
@@ -483,7 +513,9 @@ export default class IndexedDBCryptoStore {
* @param {*} txn An active transaction. See doTxn().
*/
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
*/
getEndToEndRooms(txn, func) {
this._backendPromise.value().getEndToEndRooms(txn, func);
this._backendPromise.then(backend => {
backend.getEndToEndRooms(txn, func);
});
}
// session backups
+9
View File
@@ -297,6 +297,15 @@ utils.extend(module.exports.MatrixEvent.prototype, {
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
* </code> for message events.
+1 -1
View File
@@ -15,7 +15,7 @@ limitations under the License.
*/
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
+11 -5
View File
@@ -839,9 +839,15 @@ Room.prototype.getAliases = function() {
for (let i = 0; i < aliasEvents.length; ++i) {
const aliasEvent = aliasEvents[i];
if (utils.isArray(aliasEvent.getContent().aliases)) {
Array.prototype.push.apply(
aliasStrings, aliasEvent.getContent().aliases,
);
const filteredAliases = aliasEvent.getContent().aliases.filter(a => {
if (typeof(a) !== "string") return false;
if (a[0] !== '#') return false;
if (!a.endsWith(`:${aliasEvent.getStateKey()}`)) return false;
// It's probably valid by here.
return true;
});
Array.prototype.push.apply(aliasStrings, filteredAliases);
}
}
}
@@ -895,7 +901,7 @@ Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline,
* @return {RoomMember} The member or <code>null</code>.
*/
Room.prototype.getMember = function(userId) {
return this.currentState.getMember(userId);
return this.currentState.getMember(userId);
};
/**
@@ -903,7 +909,7 @@ Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline,
* @return {RoomMember[]} A list of currently joined members.
*/
Room.prototype.getJoinedMembers = function() {
return this.getMembersWithMembership("join");
return this.getMembersWithMembership("join");
};
/**
+7 -7
View File
@@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import {escapeRegExp, globToRegexp} from "./utils";
import {escapeRegExp, globToRegexp, isNullOrUndefined} from "./utils";
/**
* @module pushprocessor
@@ -268,7 +268,7 @@ function PushProcessor(client) {
}
const val = valueForDottedKey(cond.key, ev);
if (!val || typeof val != 'string') {
if (typeof val !== 'string') {
return false;
}
@@ -304,10 +304,10 @@ function PushProcessor(client) {
// special-case the first component to deal with encrypted messages
const firstPart = parts[0];
if (firstPart == 'content') {
if (firstPart === 'content') {
val = ev.getContent();
parts.shift();
} else if (firstPart == 'type') {
} else if (firstPart === 'type') {
val = ev.getType();
parts.shift();
} else {
@@ -316,11 +316,11 @@ function PushProcessor(client) {
}
while (parts.length > 0) {
const thispart = parts.shift();
if (!val[thispart]) {
const thisPart = parts.shift();
if (isNullOrUndefined(val[thisPart])) {
return null;
}
val = val[thispart];
val = val[thisPart];
}
return val;
};
+1 -1
View File
@@ -48,7 +48,7 @@ const debuglog = function() {};
*
* 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
*/
+2 -1
View File
@@ -17,6 +17,7 @@ limitations under the License.
import Promise from 'bluebird';
import logger from '../logger';
import {defer} from '../utils';
/**
* An IndexedDB store backend where the actual backend sits in a web
@@ -152,7 +153,7 @@ RemoteIndexedDBStoreBackend.prototype = {
// the promise automatically gets rejected
return Promise.resolve().then(() => {
const seq = this._nextSeq++;
const def = Promise.defer();
const def = defer();
this._inFlight[seq] = def;
+8 -7
View File
@@ -132,14 +132,15 @@ TimelineWindow.prototype.load = function(initialEventId, initialWindowSize) {
// feeling snappy.
//
if (initialEventId) {
const prom = this._client.getEventTimeline(this._timelineSet, initialEventId);
if (prom.isFulfilled()) {
initFields(prom.value());
return Promise.resolve();
} else {
return prom.then(initFields);
const timeline = this._timelineSet.getTimelineForEvent(initialEventId);
if (timeline) {
// hot-path optimization to save a reactor tick by replicating the sync check getTimelineForEvent does.
initFields(timeline);
return Promise.resolve(timeline);
}
const prom = this._client.getEventTimeline(this._timelineSet, initialEventId);
return prom.then(initFields);
} else {
const tl = this._timelineSet.getLiveTimeline();
initFields(tl);
+23
View File
@@ -21,6 +21,7 @@ limitations under the License.
*/
const unhomoglyph = require('unhomoglyph');
import Promise from 'bluebird';
/**
* Encode a dictionary of query parameters.
@@ -708,3 +709,25 @@ module.exports.ensureNoTrailingSlash = function(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};
};
+1438 -317
View File
File diff suppressed because it is too large Load Diff