From 7973b99f50f9456d0bee4a7a8eeb3c58e2034a44 Mon Sep 17 00:00:00 2001 From: ZengJing Date: Thu, 31 Oct 2019 17:53:00 +0800 Subject: [PATCH 01/67] Fix incorrect return value of MatrixClient.prototype.uploadKeys Signed-off-by: Zeng Jing --- src/crypto/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/crypto/index.js b/src/crypto/index.js index 11b6ff07a..8d441e025 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -493,7 +493,7 @@ Crypto.prototype.uploadDeviceKeys = function() { }; return crypto._signObject(deviceKeys).then(() => { - crypto._baseApis.uploadKeysRequest({ + return crypto._baseApis.uploadKeysRequest({ device_keys: deviceKeys, }, { // for now, we set the device id explicitly, as we may not be using the From e8fd0498a7d44c2d74dbb8ff3aac03dea1c10d83 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 31 Oct 2019 17:58:14 +0000 Subject: [PATCH 02/67] 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 --- src/autodiscovery.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/autodiscovery.js b/src/autodiscovery.js index df52b368b..c8dc8c661 100644 --- a/src/autodiscovery.js +++ b/src/autodiscovery.js @@ -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, }, From 91df0966984529c30c7b4a17614ead3912242eb7 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 1 Nov 2019 14:10:16 +0000 Subject: [PATCH 03/67] Update tests --- spec/unit/autodiscovery.spec.js | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/spec/unit/autodiscovery.spec.js b/spec/unit/autodiscovery.spec.js index 6d4e5a3e9..77f0248fb 100644 --- a/spec/unit/autodiscovery.spec.js +++ b/spec/unit/autodiscovery.spec.js @@ -416,8 +416,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 +438,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 +456,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 +478,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 +496,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 +519,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 +537,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 +560,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", }, From 180fea8ace8a50471f43ef8ccae17a7a1ac8c805 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 18 Nov 2019 18:30:43 +0100 Subject: [PATCH 04/67] only send decrypted events to Verifier in e2ee rooms --- src/crypto/index.js | 45 +++++++++++++++++++++++++++++---- src/crypto/verification/Base.js | 19 ++++++++++++-- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/crypto/index.js b/src/crypto/index.js index 11b6ff07a..36a8c86d5 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -65,6 +65,32 @@ export function isCryptoAvailable() { return Boolean(global.Olm); } +/* subscribes to timeline events for SAS verification */ +function listenForEvents(client, roomId, listener) { + let isEncrypted = false; + if (roomId) { + isEncrypted = client.isRoomEncrypted(roomId); + } + + if (isEncrypted) { + client.on("Event.decrypted", listener); + } else { + client.on("event", listener); + } + let subscribed = true; + return function() { + if (subscribed) { + if (isEncrypted) { + client.off("Event.decrypted", listener); + } else { + client.off("event", listener); + } + subscribed = false; + } + return null; + }; +} + const MIN_FORCE_SESSION_INTERVAL_MS = 60 * 60 * 1000; const KEY_BACKUP_KEYS_PER_REQUEST = 200; @@ -826,7 +852,9 @@ Crypto.prototype.requestVerificationDM = async function(userId, roomId, methods) ); // this handler gets removed when the verification finishes // (see the verify method of crypto/verification/Base.js) - this._baseApis.on("event", verifier.handler); + const subscription = + listenForEvents(this._baseApis, roomId, verifier.handler); + verifier.setEventsSubscription(subscription); resolve(verifier); break; } @@ -836,14 +864,19 @@ Crypto.prototype.requestVerificationDM = async function(userId, roomId, methods) } } }; - this._baseApis.on("event", listener); + let initialResponseSubscription = + listenForEvents(this._baseApis, roomId, listener); const resolve = (...args) => { - this._baseApis.off("event", listener); + if (initialResponseSubscription) { + initialResponseSubscription = initialResponseSubscription(); + } _resolve(...args); }; const reject = (...args) => { - this._baseApis.off("event", listener); + if (initialResponseSubscription) { + initialResponseSubscription = initialResponseSubscription(); + } _reject(...args); }; }); @@ -878,7 +911,9 @@ Crypto.prototype.acceptVerificationDM = function(event, Method) { verifier.handler = verificationEventHandler( verifier, event.getSender(), event.getRoomId(), event.getId(), ); - this._baseApis.on("event", verifier.handler); + const subscription = listenForEvents( + this._baseApis, event.getRoomId(), verifier.handler); + verifier.setEventsSubscription(subscription); return verifier; }; diff --git a/src/crypto/verification/Base.js b/src/crypto/verification/Base.js index fa67c72a0..d9404ba63 100644 --- a/src/crypto/verification/Base.js +++ b/src/crypto/verification/Base.js @@ -74,6 +74,7 @@ export default class VerificationBase extends EventEmitter { this._done = false; this._promise = null; this._transactionTimeoutTimer = null; + this._eventsSubscription = null; // At this point, the verification request was received so start the timeout timer. this._resetTimer(); @@ -222,6 +223,10 @@ export default class VerificationBase extends EventEmitter { // but no reject function. If cancel is called again, we'd error. if (this._reject) this._reject(e); } else { + // unsubscribe from events, this happens in _reject usually but we don't have one here + if (this._eventsSubscription) { + this._eventsSubscription = this._eventsSubscription(); + } // FIXME: this causes an "Uncaught promise" console message // if nothing ends up chaining this promise. this._promise = Promise.reject(e); @@ -246,7 +251,10 @@ export default class VerificationBase extends EventEmitter { this._done = true; this._endTimer(); if (this.handler) { - this._baseApis.off("event", this.handler); + // these listeners are attached in Crypto.acceptVerificationDM + if (this._eventsSubscription) { + this._eventsSubscription = this._eventsSubscription(); + } } resolve(...args); }; @@ -254,7 +262,10 @@ export default class VerificationBase extends EventEmitter { this._done = true; this._endTimer(); if (this.handler) { - this._baseApis.off("event", this.handler); + // these listeners are attached in Crypto.acceptVerificationDM + if (this._eventsSubscription) { + this._eventsSubscription = this._eventsSubscription(); + } } reject(...args); }; @@ -295,4 +306,8 @@ export default class VerificationBase extends EventEmitter { await this._baseApis.setDeviceVerified(userId, deviceId); } } + + setEventsSubscription(subscription) { + this._eventsSubscription = subscription; + } } From cd735ef459ac4c6d175daef03bad44e4a4f3540e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 18 Nov 2019 18:31:39 +0100 Subject: [PATCH 05/67] use getRelation as getContent()[m.relates_to] doesn't work in e2ee rooms --- src/crypto/index.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/crypto/index.js b/src/crypto/index.js index 36a8c86d5..d598ea12f 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -789,13 +789,9 @@ function verificationEventHandler(target, userId, roomId, eventId) { || event.getSender() !== userId) { return; } - const content = event.getContent(); - if (!content["m.relates_to"]) { - return; - } - const relatesTo - = content["m.relationship"] || content["m.relates_to"]; - if (!relatesTo.rel_type + const relatesTo = event.getRelation(); + if (!relatesTo + || !relatesTo.rel_type || relatesTo.rel_type !== "m.reference" || !relatesTo.event_id || relatesTo.event_id !== eventId) { From 24ae7877364ae8e61f799743d4c179e25fd64241 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 18 Nov 2019 18:33:11 +0100 Subject: [PATCH 06/67] make it explicit that the transaction id is added for the start event as it should included in the commitment hash --- src/crypto/verification/Base.js | 31 ++++++++++++++++++++++--------- src/crypto/verification/SAS.js | 10 +++++----- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/src/crypto/verification/Base.js b/src/crypto/verification/Base.js index d9404ba63..3a9f76039 100644 --- a/src/crypto/verification/Base.js +++ b/src/crypto/verification/Base.js @@ -80,9 +80,9 @@ export default class VerificationBase extends EventEmitter { this._resetTimer(); if (this.roomId) { - this._send = this._sendMessage; + this._sendWithTxnId = this._sendMessage; } else { - this._send = this._sendToDevice; + this._sendWithTxnId = this._sendToDevice; } } @@ -106,13 +106,32 @@ export default class VerificationBase extends EventEmitter { } } + + /* creates a content object with the transaction id added to it */ + _contentWithTxnId(content) { + const copy = Object.assign({}, content); + if (this.roomId) { // verification as timeline event + copy["m.relates_to"] = { + rel_type: "m.reference", + event_id: this.transactionId, + }; + } else { // verification as to_device event + copy.transaction_id = this.transactionId; + } + return copy; + } + + _send(type, contentWithoutTxnId) { + const content = this._contentWithTxnId(contentWithoutTxnId); + return this._sendWithTxnId(type, content); + } + /* send a message to the other participant, using to-device messages */ _sendToDevice(type, content) { if (this._done) { return Promise.reject(new Error("Verification is already done")); } - content.transaction_id = this.transactionId; return this._baseApis.sendToDevice(type, { [this.userId]: { [this.deviceId]: content }, }); @@ -124,12 +143,6 @@ export default class VerificationBase extends EventEmitter { if (this._done) { return Promise.reject(new Error("Verification is already done")); } - // FIXME: if MSC1849 decides to use m.relationship instead of - // m.relates_to, we should follow suit here - content["m.relates_to"] = { - rel_type: "m.reference", - event_id: this.transactionId, - }; return this._baseApis.sendEvent(this.roomId, type, content); } diff --git a/src/crypto/verification/SAS.js b/src/crypto/verification/SAS.js index a2af399cf..9d3e7286c 100644 --- a/src/crypto/verification/SAS.js +++ b/src/crypto/verification/SAS.js @@ -205,7 +205,7 @@ export default class SAS extends Base { } async _doSendVerification() { - const initialMessage = { + const initialMessage = this._contentWithTxnId({ method: SAS.NAME, from_device: this._baseApis.deviceId, key_agreement_protocols: KEY_AGREEMENT_LIST, @@ -213,10 +213,10 @@ export default class SAS extends Base { message_authentication_codes: MAC_LIST, // FIXME: allow app to specify what SAS methods can be used short_authentication_string: SAS_LIST, - }; - // NOTE: this._send will modify initialMessage to include the - // transaction_id field, or the m.relationship/m.relates_to field - this._send("m.key.verification.start", initialMessage); + }); + // add the transaction id to the message beforehand because + // it needs to be included in the commitment hash later on + this._sendWithTxnId("m.key.verification.start", initialMessage); let e = await this._waitForEvent("m.key.verification.accept"); From 3b02b62ba53d693bff59562c4bf73149f77528df Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 18 Nov 2019 18:34:05 +0100 Subject: [PATCH 07/67] add m.relates_to back to the content on the requesting side for e2e room as it needs to be added to the commitment hash as before, getContent() in an e2ee room doesn't return the relation --- src/crypto/verification/Base.js | 11 +++++++++++ src/crypto/verification/SAS.js | 5 ++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/crypto/verification/Base.js b/src/crypto/verification/Base.js index 3a9f76039..553de34af 100644 --- a/src/crypto/verification/Base.js +++ b/src/crypto/verification/Base.js @@ -106,6 +106,17 @@ export default class VerificationBase extends EventEmitter { } } + _contentFromEventWithTxnId(event) { + if (this.roomId) { // verification as timeline event + // ensure m.related_to is included in e2ee rooms + // as the field is excluded from encryption + const content = Object.assign({}, event.getContent()); + content["m.relates_to"] = event.getRelation(); + return content; + } else { // verification as to_device event + return event.getContent(); + } + } /* creates a content object with the transaction id added to it */ _contentWithTxnId(content) { diff --git a/src/crypto/verification/SAS.js b/src/crypto/verification/SAS.js index 9d3e7286c..720e5e80c 100644 --- a/src/crypto/verification/SAS.js +++ b/src/crypto/verification/SAS.js @@ -281,7 +281,10 @@ export default class SAS extends Base { } async _doRespondVerification() { - let content = this.startEvent.getContent(); + // as m.related_to is not included in the encrypted content in e2e rooms, + // we need to make sure it is added + let content = this._contentFromEventWithTxnId(this.startEvent); + // Note: we intersect using our pre-made lists, rather than the sets, // so that the result will be in our order of preference. Then // fetching the first element from the array will give our preferred From 90512bdd5f4cb5f05d9d3c0c733a7c091bb027d9 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 19 Nov 2019 15:23:05 +0100 Subject: [PATCH 08/67] also listen for non-encrypted events when verifying over DM --- src/crypto/index.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/crypto/index.js b/src/crypto/index.js index d598ea12f..92c4686f1 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -65,7 +65,7 @@ export function isCryptoAvailable() { return Boolean(global.Olm); } -/* subscribes to timeline events for SAS verification */ +/* subscribes to timeline events / to_device events for SAS verification */ function listenForEvents(client, roomId, listener) { let isEncrypted = false; if (roomId) { @@ -74,17 +74,15 @@ function listenForEvents(client, roomId, listener) { if (isEncrypted) { client.on("Event.decrypted", listener); - } else { - client.on("event", listener); } + client.on("event", listener); let subscribed = true; return function() { if (subscribed) { if (isEncrypted) { client.off("Event.decrypted", listener); - } else { - client.off("event", listener); } + client.off("event", listener); subscribed = false; } return null; @@ -789,6 +787,12 @@ function verificationEventHandler(target, userId, roomId, eventId) { || event.getSender() !== userId) { return; } + // ignore events that haven't been decrypted yet. + // we also listen for undecrypted events, just in case + // the other side would be sending unencrypted events in an e2ee room + if (event.getType() === "m.room.encrypted") { + return; + } const relatesTo = event.getRelation(); if (!relatesTo || !relatesTo.rel_type From 165c1fc0b69b609aac8ccc9c67fff2ac7242ab94 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 20 Nov 2019 18:19:30 +0000 Subject: [PATCH 09/67] Prepare changelog for v2.4.4-rc.1 --- CHANGELOG.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b2e38801..452742844 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +Changes in [2.4.4-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.4-rc.1) (2019-11-20) +========================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.3...v2.4.4-rc.1) + + * Fix SAS verification in encrypted DMs + [\#1077](https://github.com/matrix-org/matrix-js-sdk/pull/1077) + * Cross-signing / secret storage tweaks + [\#1078](https://github.com/matrix-org/matrix-js-sdk/pull/1078) + * Fix local trust for key backups + [\#1075](https://github.com/matrix-org/matrix-js-sdk/pull/1075) + * Add method to get last active timestamp in room + [\#1072](https://github.com/matrix-org/matrix-js-sdk/pull/1072) + * Check the right Synapse endpoint for determining admin capabilities + [\#1071](https://github.com/matrix-org/matrix-js-sdk/pull/1071) + * Cross Signing Support + [\#832](https://github.com/matrix-org/matrix-js-sdk/pull/832) + * Don't double cancel verification request + [\#1064](https://github.com/matrix-org/matrix-js-sdk/pull/1064) + * Support for verification requests in the timeline + [\#1067](https://github.com/matrix-org/matrix-js-sdk/pull/1067) + * Use stable API prefix for 3PID APIs when supported + [\#1066](https://github.com/matrix-org/matrix-js-sdk/pull/1066) + * Remove Jenkins scripts + [\#1063](https://github.com/matrix-org/matrix-js-sdk/pull/1063) + Changes in [2.4.3](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.3) (2019-11-04) ================================================================================================ [Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.3-rc.1...v2.4.3) From 12bb0b86dd52c727f461fc4fccaae66e4cdc358a Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 20 Nov 2019 18:19:30 +0000 Subject: [PATCH 10/67] v2.4.4-rc.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8267926d1..0c9778cfd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-js-sdk", - "version": "2.4.3", + "version": "2.4.4-rc.1", "description": "Matrix Client-Server SDK for Javascript", "main": "index.js", "scripts": { From fd58957b06c3e11a5be5e67f4bc09a9f0d29add5 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 20 Nov 2019 19:52:50 +0000 Subject: [PATCH 11/67] migrate to jest from mocha+expect+istanbul Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .eslintrc.js | 2 + package.json | 11 +- spec/.eslintrc.js | 5 - spec/TestClient.js | 3 +- spec/integ/devicelist-integ-spec.js | 3 - spec/integ/matrix-client-crypto.spec.js | 11 +- .../integ/matrix-client-event-emitter.spec.js | 4 +- .../matrix-client-event-timeline.spec.js | 6 +- spec/integ/matrix-client-methods.spec.js | 3 - spec/integ/matrix-client-opts.spec.js | 4 +- spec/integ/matrix-client-retrying.spec.js | 4 - .../integ/matrix-client-room-timeline.spec.js | 2 - spec/integ/matrix-client-syncing.spec.js | 4 +- spec/integ/megolm-integ.spec.js | 5 +- spec/test-utils.js | 25 +- spec/unit/autodiscovery.spec.js | 3 - spec/unit/content-repo.spec.js | 7 - spec/unit/crypto.spec.js | 82 +- spec/unit/crypto/DeviceList.spec.js | 18 +- spec/unit/crypto/algorithms/megolm.spec.js | 69 +- spec/unit/crypto/algorithms/olm.spec.js | 4 - spec/unit/crypto/backup.spec.js | 37 +- spec/unit/crypto/cross-signing.spec.js | 18 +- spec/unit/crypto/secrets.spec.js | 3 +- spec/unit/crypto/verification/qr_code.spec.js | 25 +- spec/unit/crypto/verification/request.spec.js | 4 +- spec/unit/crypto/verification/sas.spec.js | 24 +- spec/unit/event-timeline.spec.js | 22 +- spec/unit/event.spec.js | 7 - spec/unit/filter.spec.js | 4 - spec/unit/interactive-auth.spec.js | 32 +- spec/unit/login.spec.js | 1 - spec/unit/matrix-client.spec.js | 49 +- spec/unit/pushprocessor.spec.js | 2 - spec/unit/realtime-callbacks.spec.js | 83 +- spec/unit/room-member.spec.js | 13 +- spec/unit/room-state.spec.js | 15 +- spec/unit/room.spec.js | 57 +- spec/unit/scheduler.spec.js | 14 +- spec/unit/sync-accumulator.spec.js | 3 - spec/unit/timeline-window.spec.js | 9 - spec/unit/user.spec.js | 3 - spec/unit/utils.spec.js | 11 +- src/models/room.js | 4 +- yarn.lock | 1750 ++++++++++++++--- 45 files changed, 1717 insertions(+), 748 deletions(-) delete mode 100644 spec/.eslintrc.js diff --git a/.eslintrc.js b/.eslintrc.js index 9a752b14f..e0b8c538e 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -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 diff --git a/package.json b/package.json index 8267926d1..4f7887752 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,8 @@ "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:run": "jest spec/ --coverage --testEnvironment node", + "test:watch": "jest spec/ --coverage --testEnvironment node --watch", "test": "yarn test:build && yarn test:run", "check": "yarn test:build && _mocha --recursive specbuild --colors", "gendoc": "babel --no-babelrc --plugins transform-class-properties -d .jsdocbuild src && jsdoc -r .jsdocbuild -P package.json -R README.md -d .jsdoc", @@ -65,6 +64,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 +75,12 @@ "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", diff --git a/spec/.eslintrc.js b/spec/.eslintrc.js deleted file mode 100644 index 4cc4659d7..000000000 --- a/spec/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - env: { - mocha: true, - }, -} diff --git a/spec/TestClient.js b/spec/TestClient.js index e29fb8bfb..8aeb3c291 100644 --- a/spec/TestClient.js +++ b/spec/TestClient.js @@ -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; diff --git a/spec/integ/devicelist-integ-spec.js b/spec/integ/devicelist-integ-spec.js index f59e46e3f..1d033c2f0 100644 --- a/spec/integ/devicelist-integ-spec.js +++ b/spec/integ/devicelist-integ-spec.js @@ -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(); diff --git a/spec/integ/matrix-client-crypto.spec.js b/spec/integ/matrix-client-crypto.spec.js index 297b8537f..4da8f4abf 100644 --- a/spec/integ/matrix-client-crypto.spec.js +++ b/spec/integ/matrix-client-crypto.spec.js @@ -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); }); } @@ -406,8 +405,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(); @@ -548,7 +545,7 @@ 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); }); }); @@ -753,9 +750,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 diff --git a/spec/integ/matrix-client-event-emitter.spec.js b/spec/integ/matrix-client-event-emitter.spec.js index 9f7b028eb..90fa5db8f 100644 --- a/spec/integ/matrix-client-event-emitter.spec.js +++ b/spec/integ/matrix-client-event-emitter.spec.js @@ -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) { diff --git a/spec/integ/matrix-client-event-timeline.spec.js b/spec/integ/matrix-client-event-timeline.spec.js index a89818abc..402c9fe3a 100644 --- a/spec/integ/matrix-client-event-timeline.spec.js +++ b/spec/integ/matrix-client-event-timeline.spec.js @@ -103,7 +103,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); }); @@ -145,7 +144,7 @@ describe("getEventTimeline support", function() { const timelineSet = room.getTimelineSets()[0]; expect(function() { client.getEventTimeline(timelineSet, "event"); - }).toNotThrow(); + }).not.toThrow(); }); }); @@ -221,14 +220,11 @@ describe("getEventTimeline support", function() { }); }); -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); diff --git a/spec/integ/matrix-client-methods.spec.js b/spec/integ/matrix-client-methods.spec.js index 55bf119f6..1a05ae896 100644 --- a/spec/integ/matrix-client-methods.spec.js +++ b/spec/integ/matrix-client-methods.spec.js @@ -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(); diff --git a/spec/integ/matrix-client-opts.spec.js b/spec/integ/matrix-client-opts.spec.js index 11bcf6b6d..a4b3083ef 100644 --- a/spec/integ/matrix-client-opts.spec.js +++ b/spec/integ/matrix-client-opts.spec.js @@ -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( diff --git a/spec/integ/matrix-client-retrying.spec.js b/spec/integ/matrix-client-retrying.spec.js index 0dabc0abe..e266ea98b 100644 --- a/spec/integ/matrix-client-retrying.spec.js +++ b/spec/integ/matrix-client-retrying.spec.js @@ -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(); diff --git a/spec/integ/matrix-client-room-timeline.spec.js b/spec/integ/matrix-client-room-timeline.spec.js index f951c0cf4..add82cb4e 100644 --- a/spec/integ/matrix-client-room-timeline.spec.js +++ b/spec/integ/matrix-client-room-timeline.spec.js @@ -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"; @@ -104,7 +103,6 @@ describe("MatrixClient room timelines", function() { } beforeEach(function(done) { - utils.beforeEach(this); // eslint-disable-line babel/no-invalid-this httpBackend = new HttpBackend(); sdk.request(httpBackend.requestFn); client = sdk.createClient({ diff --git a/spec/integ/matrix-client-syncing.spec.js b/spec/integ/matrix-client-syncing.spec.js index 2d702c8a7..1294b6a5d 100644 --- a/spec/integ/matrix-client-syncing.spec.js +++ b/spec/integ/matrix-client-syncing.spec.js @@ -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"); diff --git a/spec/integ/megolm-integ.spec.js b/spec/integ/megolm-integ.spec.js index 1851badce..1c1693bfc 100644 --- a/spec/integ/megolm-integ.spec.js +++ b/spec/integ/megolm-integ.spec.js @@ -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', }; diff --git a/spec/test-utils.js b/spec/test-utils.js index 9a81906c3..16ec18898 100644 --- a/spec/test-utils.js +++ b/spec/test-utils.js @@ -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); }; diff --git a/spec/unit/autodiscovery.spec.js b/spec/unit/autodiscovery.spec.js index 6d4e5a3e9..d273ce4d3 100644 --- a/spec/unit/autodiscovery.spec.js +++ b/spec/unit/autodiscovery.spec.js @@ -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); }); diff --git a/spec/unit/content-repo.spec.js b/spec/unit/content-repo.spec.js index 61b6fceb1..70174fc77 100644 --- a/spec/unit/content-repo.spec.js +++ b/spec/unit/content-repo.spec.js @@ -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"; diff --git a/spec/unit/crypto.spec.js b/spec/unit/crypto.spec.js index 1c25e6f68..acbc08731 100644 --- a/spec/unit/crypto.spec.js +++ b/spec/unit/crypto.spec.js @@ -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,6 +18,8 @@ const sdk = require("../.."); const Olm = global.Olm; +jest.useFakeTimers(); + describe("Crypto", function() { if (!sdk.CRYPTO_ENABLED) { return; @@ -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,15 @@ describe("Crypto", function() { }); fakeEmitter.emit('toDeviceEvent', { - getType: expect.createSpy().andReturn('m.room.message'), - getContent: expect.createSpy().andReturn({ + 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 +245,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 +260,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 +268,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 +296,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 +329,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); }); }); }); diff --git a/spec/unit/crypto/DeviceList.spec.js b/spec/unit/crypto/DeviceList.spec.js index 33c1e4955..14d4d91e3 100644 --- a/spec/unit/crypto/DeviceList.spec.js +++ b/spec/unit/crypto/DeviceList.spec.js @@ -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'], {}); diff --git a/spec/unit/crypto/algorithms/megolm.spec.js b/spec/unit/crypto/algorithms/megolm.spec.js index 0616ff0ae..eae11da59 100644 --- a/spec/unit/crypto/algorithms/megolm.spec.js +++ b/spec/unit/crypto/algorithms/megolm.spec.js @@ -1,6 +1,5 @@ import '../../../olm-loader'; -import expect from 'expect'; import Promise from 'bluebird'; import sdk from '../../../..'; @@ -32,8 +31,6 @@ describe("MegolmDecryption", function() { let mockBaseApis; beforeEach(async function() { - testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this - await Olm.init(); mockCrypto = testUtils.mock(Crypto, 'Crypto'); @@ -55,9 +52,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 +132,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 +157,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 +197,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 +223,7 @@ describe("MegolmDecryption", function() { successHandler, failureHandler, ).then(() => { - expect(successHandler).toNotHaveBeenCalled(); + expect(successHandler).not.toHaveBeenCalled(); expect(failureHandler).toHaveBeenCalled(); }); }); @@ -266,10 +261,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 +280,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 +307,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 +318,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); diff --git a/spec/unit/crypto/algorithms/olm.spec.js b/spec/unit/crypto/algorithms/olm.spec.js index 14e6bbf66..1b26a6d22 100644 --- a/spec/unit/crypto/algorithms/olm.spec.js +++ b/spec/unit/crypto/algorithms/olm.spec.js @@ -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'; @@ -54,8 +52,6 @@ describe("OlmDecryption", function() { let bobOlmDevice; beforeEach(async function() { - testUtils.beforeEach(this); // eslint-disable-line babel/no-invalid-this - await global.Olm.init(); aliceOlmDevice = makeOlmDevice(); diff --git a/spec/unit/crypto/backup.spec.js b/spec/unit/crypto/backup.spec.js index 236a7ed28..3f11a9a54 100644 --- a/spec/unit/crypto/backup.spec.js +++ b/spec/unit/crypto/backup.spec.js @@ -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", @@ -138,8 +137,6 @@ describe("MegolmBackup", function() { 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 +152,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 +215,7 @@ describe("MegolmBackup", function() { }; mockCrypto.cancelRoomKeyRequest = function() {}; - mockCrypto.backupGroupSession = expect.createSpy(); + mockCrypto.backupGroupSession = jest.fn(); return event.attemptDecryption(mockCrypto).then(() => { return megolmDecryption.onRoomKeyEvent(event); @@ -288,8 +285,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(); @@ -382,16 +379,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", @@ -458,8 +455,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) { diff --git a/spec/unit/crypto/cross-signing.spec.js b/spec/unit/crypto/cross-signing.spec.js index c26356d98..2023bc970 100644 --- a/spec/unit/crypto/cross-signing.spec.js +++ b/spec/unit/crypto/cross-signing.spec.js @@ -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'; @@ -64,13 +63,12 @@ describe("Cross Signing", 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"]; }, diff --git a/spec/unit/crypto/secrets.spec.js b/spec/unit/crypto/secrets.spec.js index fb7948143..0a348e937 100644 --- a/spec/unit/crypto/secrets.spec.js +++ b/spec/unit/crypto/secrets.spec.js @@ -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'; @@ -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]; }); diff --git a/spec/unit/crypto/verification/qr_code.spec.js b/spec/unit/crypto/verification/qr_code.spec.js index a64c5d5af..5a1507729 100644 --- a/spec/unit/crypto/verification/qr_code.spec.js +++ b/spec/unit/crypto/verification/qr_code.spec.js @@ -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'; @@ -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(); }); }); }); diff --git a/spec/unit/crypto/verification/request.spec.js b/spec/unit/crypto/verification/request.spec.js index 355597d04..761edc8b7 100644 --- a/spec/unit/crypto/verification/request.spec.js +++ b/spec/unit/crypto/verification/request.spec.js @@ -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'; @@ -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(); diff --git a/spec/unit/crypto/verification/sas.spec.js b/spec/unit/crypto/verification/sas.spec.js index cee4d1449..d5d5c1a9f 100644 --- a/spec/unit/crypto/verification/sas.spec.js +++ b/spec/unit/crypto/verification/sas.spec.js @@ -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 '../../../..'; @@ -57,9 +56,8 @@ 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) @@ -346,11 +344,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 +366,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 +375,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 +399,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 +417,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 +443,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) => { diff --git a/spec/unit/event-timeline.spec.js b/spec/unit/event-timeline.spec.js index 85f8a8215..ab4ce9f38 100644 --- a/spec/unit/event-timeline.spec.js +++ b/spec/unit/event-timeline.spec.js @@ -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(); }); }); diff --git a/spec/unit/event.spec.js b/spec/unit/event.spec.js index add962d88..d88324ced 100644 --- a/spec/unit/event.spec.js +++ b/spec/unit/event.spec.js @@ -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; diff --git a/spec/unit/filter.spec.js b/spec/unit/filter.spec.js index 249eaa171..ed7722cf8 100644 --- a/spec/unit/filter.spec.js +++ b/spec/unit/filter.spec.js @@ -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); }); diff --git a/spec/unit/interactive-auth.spec.js b/spec/unit/interactive-auth.spec.js index 110cb714c..dabcf9415 100644 --- a/spec/unit/interactive-auth.spec.js +++ b/spec/unit/interactive-auth.spec.js @@ -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(); + 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", @@ -87,14 +81,14 @@ describe("InteractiveAuth", function() { ia.attemptAuth().then(function(res) { expect(res).toBe(requestRes); - expect(doRequest.calls.length).toEqual(1); - expect(stateUpdated.calls.length).toEqual(1); + expect(doRequest).toBeCalledTimes(1); + expect(stateUpdated).toBeCalledTimes(1); }).nodeify(done); }); it("should make a request if no authdata is provided", function(done) { - const doRequest = expect.createSpy(); - const stateUpdated = expect.createSpy(); + 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", @@ -150,8 +144,8 @@ describe("InteractiveAuth", function() { ia.attemptAuth().then(function(res) { expect(res).toBe(requestRes); - expect(doRequest.calls.length).toEqual(2); - expect(stateUpdated.calls.length).toEqual(1); + expect(doRequest).toBeCalledTimes(2); + expect(stateUpdated).toBeCalledTimes(1); }).nodeify(done); }); }); diff --git a/spec/unit/login.spec.js b/spec/unit/login.spec.js index 97c0dade2..0a294adc3 100644 --- a/spec/unit/login.spec.js +++ b/spec/unit/login.spec.js @@ -1,4 +1,3 @@ -import expect from 'expect'; import TestClient from '../TestClient'; describe('Login request', function() { diff --git a/spec/unit/matrix-client.spec.js b/spec/unit/matrix-client.spec.js index 029ae1bb5..19f426609 100644 --- a/spec/unit/matrix-client.spec.js +++ b/spec/unit/matrix-client.spec.js @@ -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); }; } diff --git a/spec/unit/pushprocessor.spec.js b/spec/unit/pushprocessor.spec.js index 78d28473e..32580dec2 100644 --- a/spec/unit/pushprocessor.spec.js +++ b/spec/unit/pushprocessor.spec.js @@ -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"; diff --git a/spec/unit/realtime-callbacks.spec.js b/spec/unit/realtime-callbacks.spec.js index c78cf82db..448bf9a76 100644 --- a/spec/unit/realtime-callbacks.spec.js +++ b/spec/unit/realtime-callbacks.spec.js @@ -1,10 +1,8 @@ "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'; describe("realtime-callbacks", function() { @@ -15,7 +13,6 @@ describe("realtime-callbacks", function() { } 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)); @@ -28,26 +25,26 @@ describe("realtime-callbacks", function() { 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 +63,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 +74,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 +99,35 @@ 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(); + callback1.mockImplementation(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 +137,16 @@ describe("realtime-callbacks", function() { }); it("should be immune to exceptions", function() { - const callback1 = expect.createSpy(); - callback1.andCall(function() { + const callback1 = jest.fn(); + callback1.mockImplementation(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 +155,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 +172,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(); }); }); }); diff --git a/spec/unit/room-member.spec.js b/spec/unit/room-member.spec.js index e07de6c96..9c7a8ee32 100644 --- a/spec/unit/room-member.spec.js +++ b/spec/unit/room-member.spec.js @@ -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); }); }); }); diff --git a/spec/unit/room-state.spec.js b/spec/unit/room-state.spec.js index 553f424ff..87aedaf79 100644 --- a/spec/unit/room-state.spec.js +++ b/spec/unit/room-state.spec.js @@ -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); }); diff --git a/spec/unit/room.spec.js b/spec/unit/room.spec.js index b257ec637..c2f7a5521 100644 --- a/spec/unit/room.spec.js +++ b/spec/unit/room.spec.js @@ -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]; @@ -814,8 +811,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 +824,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 +836,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 +847,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,7 +857,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 room alias if one exists for private " + @@ -1004,7 +1001,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 +1172,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 } }; diff --git a/spec/unit/scheduler.spec.js b/spec/unit/scheduler.spec.js index b518e8323..941223a5a 100644 --- a/spec/unit/scheduler.spec.js +++ b/spec/unit/scheduler.spec.js @@ -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() { diff --git a/spec/unit/sync-accumulator.spec.js b/spec/unit/sync-accumulator.spec.js index 5f067b0b7..6dfd76043 100644 --- a/spec/unit/sync-accumulator.spec.js +++ b/spec/unit/sync-accumulator.spec.js @@ -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, }); diff --git a/spec/unit/timeline-window.spec.js b/spec/unit/timeline-window.spec.js index 3637fe968..6dc3ccc6d 100644 --- a/spec/unit/timeline-window.spec.js +++ b/spec/unit/timeline-window.spec.js @@ -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); @@ -163,10 +158,6 @@ 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) { const liveTimeline = createTimeline(); diff --git a/spec/unit/user.spec.js b/spec/unit/user.spec.js index 7448cdec9..8cea9c03d 100644 --- a/spec/unit/user.spec.js +++ b/spec/unit/user.spec.js @@ -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); }); diff --git a/spec/unit/utils.spec.js b/spec/unit/utils.spec.js index ca451eb81..c52d00d2b 100644 --- a/spec/unit/utils.spec.js +++ b/spec/unit/utils.spec.js @@ -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(); }); }); diff --git a/src/models/room.js b/src/models/room.js index ce240a876..e6d24c5d5 100644 --- a/src/models/room.js +++ b/src/models/room.js @@ -895,7 +895,7 @@ Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline, * @return {RoomMember} The member or null. */ Room.prototype.getMember = function(userId) { - return this.currentState.getMember(userId); + return this.currentState.getMember(userId); }; /** @@ -903,7 +903,7 @@ Room.prototype.addEventsToTimeline = function(events, toStartOfTimeline, * @return {RoomMember[]} A list of currently joined members. */ Room.prototype.getJoinedMembers = function() { - return this.getMembersWithMembership("join"); + return this.getMembersWithMembership("join"); }; /** diff --git a/yarn.lock b/yarn.lock index d708910ec..dc71a8198 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.0.0-beta.35", "@babel/code-frame@^7.5.5": version "7.5.5" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== @@ -89,6 +89,33 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@types/json-schema@^7.0.3": + version "7.0.3" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" + integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== + +"@typescript-eslint/experimental-utils@^2.5.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.8.0.tgz#208b4164d175587e9b03ce6fea97d55f19c30ca9" + integrity sha512-jZ05E4SxCbbXseQGXOKf3ESKcsGxT8Ucpkp1jiVp55MGhOvZB2twmWKf894PAuVQTCgbPbJz9ZbRDqtUWzP8xA== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.8.0" + eslint-scope "^5.0.0" + +"@typescript-eslint/typescript-estree@2.8.0": + version "2.8.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.8.0.tgz#fcc3fe6532840085d29b75432c8a59895876aeca" + integrity sha512-ksvjBDTdbAQ04cR5JyFSDX113k66FxH1tAXmi+dj6hufsl/G0eMc/f1GgLjEVPkYClDbRKv+rnBFuE5EusomUw== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash.unescape "4.0.1" + semver "^6.3.0" + tsutils "^3.17.1" + JSONStream@^1.0.3: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -97,16 +124,16 @@ JSONStream@^1.0.3: jsonparse "^1.2.0" through ">=2.2.7 <3" +abab@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" + integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== + abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -abbrev@1.0.x: - version "1.0.9" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" - integrity sha1-kbR5JYinc4wl813W9jdSovh3YTU= - accessory@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/accessory/-/accessory-1.1.0.tgz#7833e9839a32ded76d26021f36a41707a520f593" @@ -116,6 +143,14 @@ accessory@~1.1.0: balanced-match "~0.2.0" dot-parts "~1.0.0" +acorn-globals@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" + integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== + dependencies: + acorn "^6.0.1" + acorn-walk "^6.0.1" + acorn-jsx@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.2.tgz#84b68ea44b373c4f8686023a551f61a21b7c4a4f" @@ -130,17 +165,22 @@ acorn-node@^1.2.0, acorn-node@^1.3.0, acorn-node@^1.5.2, acorn-node@^1.6.1: acorn-walk "^7.0.0" xtend "^4.0.2" +acorn-walk@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" + integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== + acorn-walk@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.0.0.tgz#c8ba6f0f1aac4b0a9e32d1f0af12be769528f36b" integrity sha512-7Bv1We7ZGuU79zZbb6rRqcpxo3OY+zrdtloZWoyD8fmGX+FeXRjE+iuGkZjSXLVovLzrsvMGMy0EkwA0E0umxg== -acorn@^5.2.1: +acorn@^5.2.1, acorn@^5.5.3: version "5.7.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279" integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw== -acorn@^6.0.7: +acorn@^6.0.1, acorn@^6.0.7: version "6.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e" integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA== @@ -170,12 +210,7 @@ another-json@^0.2.0: resolved "https://registry.yarnpkg.com/another-json/-/another-json-0.2.0.tgz#b5f4019c973b6dd5c6506a2d93469cb6d32aeedc" integrity sha1-tfQBnJc7bdXGUGotk0acttMq7tw= -ansi-colors@3.2.3: - version "3.2.3" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.3.tgz#57d35b8686e851e2cc04c403f1c00203976a1813" - integrity sha512-LEHHyuhlPY3TmuUYMh2oz89lTShfvgbmzaBcxve9t/9Wuy7Dwf4yoAKcND7KFT1HAQfqZ12qtc+DUrBMeKF9nw== - -ansi-escapes@^3.2.0: +ansi-escapes@^3.0.0, ansi-escapes@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== @@ -228,6 +263,13 @@ ap@~0.2.0: resolved "https://registry.yarnpkg.com/ap/-/ap-0.2.0.tgz#ae0942600b29912f0d2b14ec60c45e8f330b6110" integrity sha1-rglCYAspkS8NKxTsYMRejzMLYRA= +append-transform@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" + integrity sha1-126/jKlNJ24keja61EpLdKthGZE= + dependencies: + default-require-extensions "^1.0.0" + aproba@^1.0.3: version "1.2.0" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" @@ -270,6 +312,11 @@ arr-union@^3.1.0: resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= +array-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93" + integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM= + array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" @@ -280,6 +327,11 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= + asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" @@ -324,10 +376,17 @@ async-each@^1.0.0, async-each@^1.0.1: resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== -async@1.x: - version "1.5.2" - resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" - integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= +async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + +async@^2.1.4: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" asynckit@^0.4.0: version "0.4.0" @@ -380,7 +439,7 @@ babel-code-frame@^6.26.0: esutils "^2.0.2" js-tokens "^3.0.2" -babel-core@^6.26.0: +babel-core@^6.0.0, babel-core@^6.26.0: version "6.26.3" resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.26.3.tgz#b2e2f09e342d0f0c88e2f02e067794125e75c207" integrity sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA== @@ -417,7 +476,7 @@ babel-eslint@^10.0.1: eslint-visitor-keys "^1.0.0" resolve "^1.12.0" -babel-generator@^6.26.0: +babel-generator@^6.18.0, babel-generator@^6.26.0: version "6.26.1" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== @@ -533,6 +592,14 @@ babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" +babel-jest@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-23.6.0.tgz#a644232366557a2240a0c083da6b25786185a2f1" + integrity sha512-lqKGG6LYXYu+DQh/slrQ8nxXQkEkhugdXsU6St7GmhVS7Ilc/22ArwqXNJrf0QaOBjZB0360qZMwXqDYQHXaew== + dependencies: + babel-plugin-istanbul "^4.1.6" + babel-preset-jest "^23.2.0" + babel-messages@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" @@ -547,6 +614,21 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-istanbul@^4.1.6: + version "4.1.6" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" + integrity sha512-PWP9FQ1AhZhS01T/4qLSKoHGY/xvkZdVBGlKM/HuxxS3+sC66HhTNR7+MpbO/so/cz/wY94MeSWJuP1hXIPfwQ== + dependencies: + babel-plugin-syntax-object-rest-spread "^6.13.0" + find-up "^2.1.0" + istanbul-lib-instrument "^1.10.1" + test-exclude "^4.2.1" + +babel-plugin-jest-hoist@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167" + integrity sha1-5h+uBaHKiAGq3uV6bWa4zvr0QWc= + babel-plugin-syntax-async-functions@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" @@ -562,6 +644,11 @@ babel-plugin-syntax-exponentiation-operator@^6.8.0: resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" integrity sha1-nufoM3KQ2pUoggGmpX9BcDF4MN4= +babel-plugin-syntax-object-rest-spread@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + integrity sha1-/WU28rzhODb/o6VFjEkDpZe7O/U= + babel-plugin-transform-async-to-bluebird@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-bluebird/-/babel-plugin-transform-async-to-bluebird-1.1.1.tgz#46ea3e7c5af629782ac9f1ed1b7cd38f8425afd4" @@ -849,6 +936,14 @@ babel-preset-es2016@^6.24.1: dependencies: babel-plugin-transform-exponentiation-operator "^6.24.1" +babel-preset-jest@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-23.2.0.tgz#8ec7a03a138f001a1a8fb1e8113652bf1a55da46" + integrity sha1-jsegOhOPABoaj7HoETZSvxpV2kY= + dependencies: + babel-plugin-jest-hoist "^23.2.0" + babel-plugin-syntax-object-rest-spread "^6.13.0" + babel-register@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.26.0.tgz#6ed021173e2fcb486d7acb45c6009a856f647071" @@ -870,7 +965,7 @@ babel-runtime@^6.18.0, babel-runtime@^6.22.0, babel-runtime@^6.26.0: core-js "^2.4.0" regenerator-runtime "^0.11.0" -babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.9.0: +babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.9.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.26.0.tgz#de03e2d16396b069f46dd9fff8521fb1a0e35e02" integrity sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI= @@ -881,7 +976,7 @@ babel-template@^6.24.1, babel-template@^6.26.0, babel-template@^6.9.0: babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.10.4, babel-traverse@^6.24.1, babel-traverse@^6.26.0: +babel-traverse@^6.0.0, babel-traverse@^6.10.4, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" integrity sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4= @@ -896,7 +991,7 @@ babel-traverse@^6.10.4, babel-traverse@^6.24.1, babel-traverse@^6.26.0: invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: +babel-types@^6.0.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" integrity sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc= @@ -1018,23 +1113,23 @@ browser-pack@^6.0.1: through2 "^2.0.0" umd "^3.0.0" +browser-process-hrtime@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz#616f00faef1df7ec1b5bf9cfe2bdc3170f26c7b4" + integrity sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw== + browser-request@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/browser-request/-/browser-request-0.3.3.tgz#9ece5b5aca89a29932242e18bf933def9876cc17" integrity sha1-ns5bWsqJopkyJC4Yv5M975h2zBc= -browser-resolve@^1.11.0, browser-resolve@^1.7.0: +browser-resolve@^1.11.0, browser-resolve@^1.11.3, browser-resolve@^1.7.0: version "1.11.3" resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== dependencies: resolve "1.1.7" -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" @@ -1166,6 +1261,13 @@ bs58@^4.0.1: dependencies: base-x "^3.0.2" +bser@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -1209,15 +1311,27 @@ cached-path-relative@^1.0.0, cached-path-relative@^1.0.2: resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.2.tgz#a13df4196d26776220cc3356eb147a52dba2c6db" integrity sha512-5r2GqsoEb4qMTTN9J+WzXfjov+hjxT+j3u5K+kIVNIwAd99DLCJE9pBIMP1qVeybV6JiijL385Oz0DcYxfbOIg== +callsites@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" + integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase@^5.0.0: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== +camelcase@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" + integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= + +capture-exit@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-1.2.0.tgz#1c5fcc489fd0ab00d4f1ac7ae1072e3173fbab6f" + integrity sha1-HF/MSJ/QqwDU8ax64QcuMXP7q28= + dependencies: + rsvp "^3.3.3" caseless@~0.12.0: version "0.12.0" @@ -1296,6 +1410,11 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== +ci-info@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" + integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -1326,14 +1445,19 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== +cliui@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49" + integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ== dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" + string-width "^2.1.1" + strip-ansi "^4.0.0" + wrap-ansi "^2.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= code-point-at@^1.0.0: version "1.1.0" @@ -1431,6 +1555,13 @@ convert-source-map@^1.1.0, convert-source-map@^1.1.3, convert-source-map@^1.5.0, dependencies: safe-buffer "~5.1.1" +convert-source-map@^1.4.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== + dependencies: + safe-buffer "~5.1.1" + convert-source-map@~1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" @@ -1482,7 +1613,7 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-spawn@^6.0.5: +cross-spawn@^6.0.0, cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== @@ -1510,6 +1641,18 @@ crypto-browserify@^3.0.0: randombytes "^2.0.0" randomfill "^1.0.3" +cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + +cssstyle@^1.0.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" + integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== + dependencies: + cssom "0.3.x" + dash-ast@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/dash-ast/-/dash-ast-1.0.0.tgz#12029ba5fb2f8aa6f0a861795b23c1b4b6c27d37" @@ -1522,18 +1665,20 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" +data-urls@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" + integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== + dependencies: + abab "^2.0.0" + whatwg-mimetype "^2.2.0" + whatwg-url "^7.0.0" + date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= -debug@3.2.6, debug@^3.2.6: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== - dependencies: - ms "^2.1.1" - debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -1541,14 +1686,21 @@ debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: dependencies: ms "2.0.0" -debug@^4.0.1, debug@^4.1.0: +debug@^3.1.0, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== dependencies: ms "^2.1.1" -decamelize@^1.2.0: +decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= @@ -1568,6 +1720,13 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +default-require-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + integrity sha1-836hXT4T/9m0N9M+GnW1+5eHTLg= + dependencies: + strip-bom "^2.0.0" + define-properties@^1.1.2, define-properties@^1.1.3, define-properties@~1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" @@ -1642,6 +1801,11 @@ detect-libc@^1.0.2: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= +detect-newline@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" + integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= + detective@^4.5.0: version "4.7.1" resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e" @@ -1667,7 +1831,7 @@ detective@~3.1.0: escodegen "~1.1.0" esprima-fb "3001.1.0-dev-harmony-fb" -diff@3.5.0: +diff@^3.2.0: version "3.5.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== @@ -1693,6 +1857,13 @@ domain-browser@^1.2.0: resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== +domexception@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" + integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug== + dependencies: + webidl-conversions "^4.0.2" + dot-parts@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/dot-parts/-/dot-parts-1.0.1.tgz#884bd7bcfc3082ffad2fe5db53e494d8f3e0743f" @@ -1731,11 +1902,25 @@ emoji-regex@^7.0.1: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + entities@~1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== +error-ex@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + es-abstract@^1.12.0: version "1.14.2" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.14.2.tgz#7ce108fad83068c8783c3cdf62e504e084d8c497" @@ -1777,7 +1962,7 @@ es-to-primitive@^1.2.0: is-date-object "^1.0.1" is-symbol "^1.0.2" -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -1787,17 +1972,17 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escodegen@1.8.x: - version "1.8.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" - integrity sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg= +escodegen@^1.9.1: + version "1.12.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.12.0.tgz#f763daf840af172bb3a2b6dd7219c0e17f7ff541" + integrity sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg== dependencies: - esprima "^2.7.1" - estraverse "^1.9.1" + esprima "^3.1.3" + estraverse "^4.2.0" esutils "^2.0.2" optionator "^0.8.1" optionalDependencies: - source-map "~0.2.0" + source-map "~0.6.1" escodegen@~1.1.0: version "1.1.0" @@ -1822,6 +2007,13 @@ eslint-plugin-babel@^5.3.0: dependencies: eslint-rule-composer "^0.3.0" +eslint-plugin-jest@^23.0.4: + version "23.0.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.0.4.tgz#1ab81ffe3b16c5168efa72cbd4db14d335092aa0" + integrity sha512-OaP8hhT8chJNodUPvLJ6vl8gnalcsU/Ww1t9oR3HnGdEWjm/DdCCUXLOral+IPGAeWu/EwgVQCK/QtxALpH1Yw== + dependencies: + "@typescript-eslint/experimental-utils" "^2.5.0" + eslint-rule-composer@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" @@ -1835,6 +2027,14 @@ eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-utils@^1.3.1: version "1.4.2" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.2.tgz#166a5180ef6ab7eb462f162fd0e6f2463d7309ab" @@ -1842,7 +2042,7 @@ eslint-utils@^1.3.1: dependencies: eslint-visitor-keys "^1.0.0" -eslint-visitor-keys@^1.0.0: +eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" integrity sha512-8y9YjtM1JBJU/A9Kc+SbaOV4y29sSWckBwMHa+FGtVj5gN/sbnKDf6xJUl+8g7FAij9LVaP8C24DUiH/f/2Z9A== @@ -1903,10 +2103,10 @@ esprima-fb@3001.1.0-dev-harmony-fb: resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-3001.0001.0000-dev-harmony-fb.tgz#b77d37abcd38ea0b77426bb8bc2922ce6b426411" integrity sha1-t303q8046gt3Qmu4vCkizmtCZBE= -esprima@2.7.x, esprima@^2.7.1: - version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" - integrity sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE= +esprima@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= esprima@^4.0.0: version "4.0.1" @@ -1932,12 +2132,7 @@ esrecurse@^4.1.0: dependencies: estraverse "^4.1.0" -estraverse@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" - integrity sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q= - -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -1970,6 +2165,31 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" +exec-sh@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.2.tgz#2a5e7ffcbd7d0ba2755bdecb16e5a427dfbdec36" + integrity sha512-FIUCJz1RbuS0FKTdaAafAByGS0CPvU3R0MeHxgtl+djzCc//F8HakL8GzmVNZanasTbTAY/3DRFA0KpVqj/eAw== + dependencies: + merge "^1.2.0" + +execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + exorcist@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/exorcist/-/exorcist-1.0.1.tgz#79316e3c4885845490f7bb405c0e5b5db1167c52" @@ -2020,6 +2240,18 @@ expect@^1.20.2: object-keys "^1.0.9" tmatch "^2.0.1" +expect@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-23.6.0.tgz#1e0c8d3ba9a581c87bd71fb9bc8862d443425f98" + integrity sha512-dgSoOHgmtn/aDGRVFWclQyPDKl2CQRq0hmIEoUAuQs/2rn2NcvCWcSCovm6BLeuB/7EZuLGu2QfnR+qRt5OM4w== + dependencies: + ansi-styles "^3.2.0" + jest-diff "^23.6.0" + jest-get-type "^22.1.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + exposify@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/exposify/-/exposify-0.5.0.tgz#f92d0094c265b3f553e1fa456a03a1883d1059cc" @@ -2106,6 +2338,13 @@ fast-levenshtein@~2.0.4: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= +fb-watchman@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.0.tgz#54e9abf7dfa2f26cd9b1636c588c1afc05de5d58" + integrity sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg= + dependencies: + bser "^2.0.0" + figures@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" @@ -2125,6 +2364,14 @@ filename-regex@^2.0.0: resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" integrity sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY= +fileset@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" + integrity sha1-jnVIqW08wjJ+5eZ0FocjozO7oqA= + dependencies: + glob "^7.0.3" + minimatch "^3.0.3" + fill-range@^2.1.0: version "2.2.4" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" @@ -2151,12 +2398,20 @@ find-parent-dir@~0.3.0: resolved "https://registry.yarnpkg.com/find-parent-dir/-/find-parent-dir-0.3.0.tgz#33c44b429ab2b2f0646299c5f9f718f376ff8d54" integrity sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ= -find-up@3.0.0, find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= dependencies: - locate-path "^3.0.0" + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" flat-cache@^2.0.1: version "2.0.1" @@ -2167,13 +2422,6 @@ flat-cache@^2.0.1: rimraf "2.6.3" write "1.0.3" -flat@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" - integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== - dependencies: - is-buffer "~2.0.3" - flatted@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08" @@ -2229,7 +2477,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fsevents@^1.0.0, fsevents@^1.2.7: +fsevents@^1.0.0, fsevents@^1.2.3, fsevents@^1.2.7: version "1.2.9" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== @@ -2266,10 +2514,17 @@ get-assigned-identifiers@^1.2.0: resolved "https://registry.yarnpkg.com/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz#6dbf411de648cbaf8d9169ebb0d2d576191e2ff1" integrity sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ== -get-caller-file@^2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== +get-caller-file@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" + integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w== + +get-stream@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" @@ -2306,10 +2561,10 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob@7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" - integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== +glob@^7.0.3, glob@^7.1.1, glob@^7.1.6: + version "7.1.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" + integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -2318,17 +2573,6 @@ glob@7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^5.0.15: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E= - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@^7.1.0, glob@^7.1.2, glob@^7.1.3: version "7.1.4" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" @@ -2365,15 +2609,20 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.4, graceful-fs@^4.1.9: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== +graceful-fs@^4.1.2: + version "4.2.3" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" + integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== -handlebars@^4.0.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.3.3.tgz#56dd05fe33d6bd8a7d797351c39a0cdcfd576be5" - integrity sha512-VupOxR91xcGojfINrzMqrvlyYbBs39sXIrWa7YdaQWeBudOlvKEGvCczMfJPgnuwHE/zyH1M6J+IUP6cgDVyxg== +growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= + +handlebars@^4.0.3: + version "4.5.3" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.5.3.tgz#5cf75bd8714f7605713511a56be7c349becb0482" + integrity sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA== dependencies: neo-async "^2.6.0" optimist "^0.6.1" @@ -2482,11 +2731,6 @@ hash.js@^1.0.0, hash.js@^1.0.3: inherits "^2.0.3" minimalistic-assert "^1.0.1" -he@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - hmac-drbg@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" @@ -2504,6 +2748,18 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" +hosted-git-info@^2.1.4: + version "2.8.5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.5.tgz#759cfcf2c4d156ade59b0b2dfabddc42a6b9c70c" + integrity sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg== + +html-encoding-sniffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" + integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== + dependencies: + whatwg-encoding "^1.0.1" + htmlescape@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" @@ -2523,7 +2779,7 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= -iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -2555,6 +2811,14 @@ import-fresh@^3.0.0: parent-module "^1.0.0" resolve-from "^4.0.0" +import-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-1.0.0.tgz#5e4ffdc03f4fe6c009c6729beb29631c2f8227bc" + integrity sha512-vAaZHieK9qjGo58agRBg+bhHX3hoTZU/Oa3GESWLz7t1U62fk63aHuDJJEteXoDeTCcPmUT+z38gkHPZkkmpmQ== + dependencies: + pkg-dir "^2.0.0" + resolve-cwd "^2.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -2630,13 +2894,18 @@ insert-module-globals@^7.0.0: undeclared-identifiers "^1.1.2" xtend "^4.0.0" -invariant@^2.2.2: +invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== dependencies: loose-envify "^1.0.0" +invert-kv@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" + integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== + is-accessor-descriptor@^0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" @@ -2651,6 +2920,11 @@ is-accessor-descriptor@^1.0.0: dependencies: kind-of "^6.0.0" +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + is-arrow-function@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/is-arrow-function/-/is-arrow-function-2.0.3.tgz#29be2c2d8d9450852b8bbafb635ba7b8d8e87ec2" @@ -2675,16 +2949,18 @@ is-buffer@^1.1.0, is-buffer@^1.1.5: resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-buffer@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" - integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== - is-callable@^1.0.4, is-callable@^1.1.3, is-callable@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== +is-ci@^1.0.10: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" + integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== + dependencies: + ci-info "^1.5.0" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -2797,6 +3073,11 @@ is-fullwidth-code-point@^2.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= +is-generator-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-1.0.0.tgz#969d49e1bb3329f6bb7f09089be26578b2ddd46a" + integrity sha1-lp1J4bszKfa7fwkIm+JleLLd1Go= + is-generator-function@^1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.7.tgz#d2132e529bb0000a7f80794d4bdf5cd5e5813522" @@ -2816,7 +3097,7 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0: +is-glob@^4.0.0, is-glob@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== @@ -2876,7 +3157,7 @@ is-regex@^1.0.3, is-regex@^1.0.4: dependencies: has "^1.0.1" -is-stream@~1.1.0: +is-stream@^1.1.0, is-stream@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= @@ -2898,11 +3179,21 @@ is-typedarray@~1.0.0: resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= + is-windows@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== +is-wsl@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= + isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -2935,25 +3226,392 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul@^0.4.5: - version "0.4.5" - resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" - integrity sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs= +istanbul-api@^1.3.1: + version "1.3.7" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.3.7.tgz#a86c770d2b03e11e3f778cd7aedd82d2722092aa" + integrity sha512-4/ApBnMVeEPG3EkSzcw25wDe4N66wxwn+KKn6b47vyek8Xb3NBAcg4xfuQbS7BqcZuTX4wxfD5lVagdggR3gyA== dependencies: - abbrev "1.0.x" - async "1.x" - escodegen "1.8.x" - esprima "2.7.x" - glob "^5.0.15" - handlebars "^4.0.1" - js-yaml "3.x" - mkdirp "0.5.x" - nopt "3.x" - once "1.x" - resolve "1.1.x" - supports-color "^3.1.0" - which "^1.1.1" - wordwrap "^1.0.0" + async "^2.1.4" + fileset "^2.0.2" + istanbul-lib-coverage "^1.2.1" + istanbul-lib-hook "^1.2.2" + istanbul-lib-instrument "^1.10.2" + istanbul-lib-report "^1.1.5" + istanbul-lib-source-maps "^1.2.6" + istanbul-reports "^1.5.1" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" + +istanbul-lib-coverage@^1.2.0, istanbul-lib-coverage@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.2.1.tgz#ccf7edcd0a0bb9b8f729feeb0930470f9af664f0" + integrity sha512-PzITeunAgyGbtY1ibVIUiV679EFChHjoMNRibEIobvmrCRaIgwLxNucOSimtNWUhEib/oO7QY2imD75JVgCJWQ== + +istanbul-lib-hook@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.2.2.tgz#bc6bf07f12a641fbf1c85391d0daa8f0aea6bf86" + integrity sha512-/Jmq7Y1VeHnZEQ3TL10VHyb564mn6VrQXHchON9Jf/AEcmQ3ZIiyD1BVzNOKTZf/G3gE+kiGK6SmpF9y3qGPLw== + dependencies: + append-transform "^0.4.0" + +istanbul-lib-instrument@^1.10.1, istanbul-lib-instrument@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.10.2.tgz#1f55ed10ac3c47f2bdddd5307935126754d0a9ca" + integrity sha512-aWHxfxDqvh/ZlxR8BBaEPVSWDPUkGD63VjGQn3jcw8jCp7sHEMKcrj4xfJn/ABzdMEHiQNyvDQhqm5o8+SQg7A== + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.18.0" + istanbul-lib-coverage "^1.2.1" + semver "^5.3.0" + +istanbul-lib-report@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.5.tgz#f2a657fc6282f96170aaf281eb30a458f7f4170c" + integrity sha512-UsYfRMoi6QO/doUshYNqcKJqVmFe9w51GZz8BS3WB0lYxAllQYklka2wP9+dGZeHYaWIdcXUx8JGdbqaoXRXzw== + dependencies: + istanbul-lib-coverage "^1.2.1" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" + +istanbul-lib-source-maps@^1.2.4, istanbul-lib-source-maps@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.6.tgz#37b9ff661580f8fca11232752ee42e08c6675d8f" + integrity sha512-TtbsY5GIHgbMsMiRw35YBHGpZ1DVFEO19vxxeiDMYaeOFOCzfnYVxvl6pOUIZR4dtPhAGpSMup8OyF8ubsaqEg== + dependencies: + debug "^3.1.0" + istanbul-lib-coverage "^1.2.1" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" + +istanbul-reports@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.5.1.tgz#97e4dbf3b515e8c484caea15d6524eebd3ff4e1a" + integrity sha512-+cfoZ0UXzWjhAdzosCPP3AN8vvef8XDkWtTfgaN+7L3YTpNYITnCaEkceo5SEYy644VkHka/P1FvkWvrG/rrJw== + dependencies: + handlebars "^4.0.3" + +jest-changed-files@^23.4.2: + version "23.4.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-23.4.2.tgz#1eed688370cd5eebafe4ae93d34bb3b64968fe83" + integrity sha512-EyNhTAUWEfwnK0Is/09LxoqNDOn7mU7S3EHskG52djOFS/z+IT0jT3h3Ql61+dklcG7bJJitIWEMB4Sp1piHmA== + dependencies: + throat "^4.0.0" + +jest-cli@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-23.6.0.tgz#61ab917744338f443ef2baa282ddffdd658a5da4" + integrity sha512-hgeD1zRUp1E1zsiyOXjEn4LzRLWdJBV//ukAHGlx6s5mfCNJTbhbHjgxnDUXA8fsKWN/HqFFF6X5XcCwC/IvYQ== + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.1.11" + import-local "^1.0.0" + is-ci "^1.0.10" + istanbul-api "^1.3.1" + istanbul-lib-coverage "^1.2.0" + istanbul-lib-instrument "^1.10.1" + istanbul-lib-source-maps "^1.2.4" + jest-changed-files "^23.4.2" + jest-config "^23.6.0" + jest-environment-jsdom "^23.4.0" + jest-get-type "^22.1.0" + jest-haste-map "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + jest-resolve-dependencies "^23.6.0" + jest-runner "^23.6.0" + jest-runtime "^23.6.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + jest-watcher "^23.4.0" + jest-worker "^23.2.0" + micromatch "^2.3.11" + node-notifier "^5.2.1" + prompts "^0.1.9" + realpath-native "^1.0.0" + rimraf "^2.5.4" + slash "^1.0.0" + string-length "^2.0.0" + strip-ansi "^4.0.0" + which "^1.2.12" + yargs "^11.0.0" + +jest-config@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-23.6.0.tgz#f82546a90ade2d8c7026fbf6ac5207fc22f8eb1d" + integrity sha512-i8V7z9BeDXab1+VNo78WM0AtWpBRXJLnkT+lyT+Slx/cbP5sZJ0+NDuLcmBE5hXAoK0aUp7vI+MOxR+R4d8SRQ== + dependencies: + babel-core "^6.0.0" + babel-jest "^23.6.0" + chalk "^2.0.1" + glob "^7.1.1" + jest-environment-jsdom "^23.4.0" + jest-environment-node "^23.4.0" + jest-get-type "^22.1.0" + jest-jasmine2 "^23.6.0" + jest-regex-util "^23.3.0" + jest-resolve "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + micromatch "^2.3.11" + pretty-format "^23.6.0" + +jest-diff@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-23.6.0.tgz#1500f3f16e850bb3d71233408089be099f610c7d" + integrity sha512-Gz9l5Ov+X3aL5L37IT+8hoCUsof1CVYBb2QEkOupK64XyRR3h+uRpYIm97K7sY8diFxowR8pIGEdyfMKTixo3g== + dependencies: + chalk "^2.0.1" + diff "^3.2.0" + jest-get-type "^22.1.0" + pretty-format "^23.6.0" + +jest-docblock@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-23.2.0.tgz#f085e1f18548d99fdd69b20207e6fd55d91383a7" + integrity sha1-8IXh8YVI2Z/dabICB+b9VdkTg6c= + dependencies: + detect-newline "^2.1.0" + +jest-each@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-23.6.0.tgz#ba0c3a82a8054387016139c733a05242d3d71575" + integrity sha512-x7V6M/WGJo6/kLoissORuvLIeAoyo2YqLOoCDkohgJ4XOXSqOtyvr8FbInlAWS77ojBsZrafbozWoKVRdtxFCg== + dependencies: + chalk "^2.0.1" + pretty-format "^23.6.0" + +jest-environment-jsdom@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-23.4.0.tgz#056a7952b3fea513ac62a140a2c368c79d9e6023" + integrity sha1-BWp5UrP+pROsYqFAosNox52eYCM= + dependencies: + jest-mock "^23.2.0" + jest-util "^23.4.0" + jsdom "^11.5.1" + +jest-environment-node@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-23.4.0.tgz#57e80ed0841dea303167cce8cd79521debafde10" + integrity sha1-V+gO0IQd6jAxZ8zozXlSHeuv3hA= + dependencies: + jest-mock "^23.2.0" + jest-util "^23.4.0" + +jest-get-type@^22.1.0: + version "22.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-22.4.3.tgz#e3a8504d8479342dd4420236b322869f18900ce4" + integrity sha512-/jsz0Y+V29w1chdXVygEKSz2nBoHoYqNShPe+QgxSNjAuP1i8+k4LbQNrfoliKej0P45sivkSCh7yiD6ubHS3w== + +jest-haste-map@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-23.6.0.tgz#2e3eb997814ca696d62afdb3f2529f5bbc935e16" + integrity sha512-uyNhMyl6dr6HaXGHp8VF7cK6KpC6G9z9LiMNsst+rJIZ8l7wY0tk8qwjPmEghczojZ2/ZhtEdIabZ0OQRJSGGg== + dependencies: + fb-watchman "^2.0.0" + graceful-fs "^4.1.11" + invariant "^2.2.4" + jest-docblock "^23.2.0" + jest-serializer "^23.0.1" + jest-worker "^23.2.0" + micromatch "^2.3.11" + sane "^2.0.0" + +jest-jasmine2@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-23.6.0.tgz#840e937f848a6c8638df24360ab869cc718592e0" + integrity sha512-pe2Ytgs1nyCs8IvsEJRiRTPC0eVYd8L/dXJGU08GFuBwZ4sYH/lmFDdOL3ZmvJR8QKqV9MFuwlsAi/EWkFUbsQ== + dependencies: + babel-traverse "^6.0.0" + chalk "^2.0.1" + co "^4.6.0" + expect "^23.6.0" + is-generator-fn "^1.0.0" + jest-diff "^23.6.0" + jest-each "^23.6.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + pretty-format "^23.6.0" + +jest-leak-detector@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-23.6.0.tgz#e4230fd42cf381a1a1971237ad56897de7e171de" + integrity sha512-f/8zA04rsl1Nzj10HIyEsXvYlMpMPcy0QkQilVZDFOaPbv2ur71X5u2+C4ZQJGyV/xvVXtCCZ3wQ99IgQxftCg== + dependencies: + pretty-format "^23.6.0" + +jest-matcher-utils@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-23.6.0.tgz#726bcea0c5294261a7417afb6da3186b4b8cac80" + integrity sha512-rosyCHQfBcol4NsckTn01cdelzWLU9Cq7aaigDf8VwwpIRvWE/9zLgX2bON+FkEW69/0UuYslUe22SOdEf2nog== + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + pretty-format "^23.6.0" + +jest-message-util@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-23.4.0.tgz#17610c50942349508d01a3d1e0bda2c079086a9f" + integrity sha1-F2EMUJQjSVCNAaPR4L2iwHkIap8= + dependencies: + "@babel/code-frame" "^7.0.0-beta.35" + chalk "^2.0.1" + micromatch "^2.3.11" + slash "^1.0.0" + stack-utils "^1.0.1" + +jest-mock@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-23.2.0.tgz#ad1c60f29e8719d47c26e1138098b6d18b261134" + integrity sha1-rRxg8p6HGdR8JuETgJi20YsmETQ= + +jest-regex-util@^23.3.0: + version "23.3.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-23.3.0.tgz#5f86729547c2785c4002ceaa8f849fe8ca471bc5" + integrity sha1-X4ZylUfCeFxAAs6qj4Sf6MpHG8U= + +jest-resolve-dependencies@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-23.6.0.tgz#b4526af24c8540d9a3fab102c15081cf509b723d" + integrity sha512-EkQWkFWjGKwRtRyIwRwI6rtPAEyPWlUC2MpzHissYnzJeHcyCn1Hc8j7Nn1xUVrS5C6W5+ZL37XTem4D4pLZdA== + dependencies: + jest-regex-util "^23.3.0" + jest-snapshot "^23.6.0" + +jest-resolve@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-23.6.0.tgz#cf1d1a24ce7ee7b23d661c33ba2150f3aebfa0ae" + integrity sha512-XyoRxNtO7YGpQDmtQCmZjum1MljDqUCob7XlZ6jy9gsMugHdN2hY4+Acz9Qvjz2mSsOnPSH7skBmDYCHXVZqkA== + dependencies: + browser-resolve "^1.11.3" + chalk "^2.0.1" + realpath-native "^1.0.0" + +jest-runner@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-23.6.0.tgz#3894bd219ffc3f3cb94dc48a4170a2e6f23a5a38" + integrity sha512-kw0+uj710dzSJKU6ygri851CObtCD9cN8aNkg8jWJf4ewFyEa6kwmiH/r/M1Ec5IL/6VFa0wnAk6w+gzUtjJzA== + dependencies: + exit "^0.1.2" + graceful-fs "^4.1.11" + jest-config "^23.6.0" + jest-docblock "^23.2.0" + jest-haste-map "^23.6.0" + jest-jasmine2 "^23.6.0" + jest-leak-detector "^23.6.0" + jest-message-util "^23.4.0" + jest-runtime "^23.6.0" + jest-util "^23.4.0" + jest-worker "^23.2.0" + source-map-support "^0.5.6" + throat "^4.0.0" + +jest-runtime@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-23.6.0.tgz#059e58c8ab445917cd0e0d84ac2ba68de8f23082" + integrity sha512-ycnLTNPT2Gv+TRhnAYAQ0B3SryEXhhRj1kA6hBPSeZaNQkJ7GbZsxOLUkwg6YmvWGdX3BB3PYKFLDQCAE1zNOw== + dependencies: + babel-core "^6.0.0" + babel-plugin-istanbul "^4.1.6" + chalk "^2.0.1" + convert-source-map "^1.4.0" + exit "^0.1.2" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.1.11" + jest-config "^23.6.0" + jest-haste-map "^23.6.0" + jest-message-util "^23.4.0" + jest-regex-util "^23.3.0" + jest-resolve "^23.6.0" + jest-snapshot "^23.6.0" + jest-util "^23.4.0" + jest-validate "^23.6.0" + micromatch "^2.3.11" + realpath-native "^1.0.0" + slash "^1.0.0" + strip-bom "3.0.0" + write-file-atomic "^2.1.0" + yargs "^11.0.0" + +jest-serializer@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-23.0.1.tgz#a3776aeb311e90fe83fab9e533e85102bd164165" + integrity sha1-o3dq6zEekP6D+rnlM+hRAr0WQWU= + +jest-snapshot@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-23.6.0.tgz#f9c2625d1b18acda01ec2d2b826c0ce58a5aa17a" + integrity sha512-tM7/Bprftun6Cvj2Awh/ikS7zV3pVwjRYU2qNYS51VZHgaAMBs5l4o/69AiDHhQrj5+LA2Lq4VIvK7zYk/bswg== + dependencies: + babel-types "^6.0.0" + chalk "^2.0.1" + jest-diff "^23.6.0" + jest-matcher-utils "^23.6.0" + jest-message-util "^23.4.0" + jest-resolve "^23.6.0" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + pretty-format "^23.6.0" + semver "^5.5.0" + +jest-util@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-23.4.0.tgz#4d063cb927baf0a23831ff61bec2cbbf49793561" + integrity sha1-TQY8uSe68KI4Mf9hvsLLv0l5NWE= + dependencies: + callsites "^2.0.0" + chalk "^2.0.1" + graceful-fs "^4.1.11" + is-ci "^1.0.10" + jest-message-util "^23.4.0" + mkdirp "^0.5.1" + slash "^1.0.0" + source-map "^0.6.0" + +jest-validate@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-23.6.0.tgz#36761f99d1ed33fcd425b4e4c5595d62b6597474" + integrity sha512-OFKapYxe72yz7agrDAWi8v2WL8GIfVqcbKRCLbRG9PAxtzF9b1SEDdTpytNDN12z2fJynoBwpMpvj2R39plI2A== + dependencies: + chalk "^2.0.1" + jest-get-type "^22.1.0" + leven "^2.1.0" + pretty-format "^23.6.0" + +jest-watcher@^23.4.0: + version "23.4.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-23.4.0.tgz#d2e28ce74f8dad6c6afc922b92cabef6ed05c91c" + integrity sha1-0uKM50+NrWxq/JIrksq+9u0FyRw= + dependencies: + ansi-escapes "^3.0.0" + chalk "^2.0.1" + string-length "^2.0.0" + +jest-worker@^23.2.0: + version "23.2.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-23.2.0.tgz#faf706a8da36fae60eb26957257fa7b5d8ea02b9" + integrity sha1-+vcGqNo2+uYOsmlXJX+ntdjqArk= + dependencies: + merge-stream "^1.0.1" + +jest@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-23.6.0.tgz#ad5835e923ebf6e19e7a1d7529a432edfee7813d" + integrity sha512-lWzcd+HSiqeuxyhG+EnZds6iO3Y3ZEnMrfZq/OTGvF/C+Z4fPMCdhWTGSAiO2Oym9rbEXfwddHhh6jqrTF3+Lw== + dependencies: + import-local "^1.0.0" + jest-cli "^23.6.0" "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" @@ -2965,7 +3623,7 @@ js-tokens@^3.0.2: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= -js-yaml@3.13.1, js-yaml@3.x, js-yaml@^3.13.0: +js-yaml@^3.13.0, js-yaml@^3.7.0: version "3.13.1" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== @@ -3005,6 +3663,38 @@ jsdoc@^3.5.5: taffydb "2.6.2" underscore "~1.9.1" +jsdom@^11.5.1: + version "11.12.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" + integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== + dependencies: + abab "^2.0.0" + acorn "^5.5.3" + acorn-globals "^4.1.0" + array-equal "^1.0.0" + cssom ">= 0.3.2 < 0.4.0" + cssstyle "^1.0.0" + data-urls "^1.0.0" + domexception "^1.0.1" + escodegen "^1.9.1" + html-encoding-sniffer "^1.0.2" + left-pad "^1.3.0" + nwsapi "^2.0.7" + parse5 "4.0.0" + pn "^1.1.0" + request "^2.87.0" + request-promise-native "^1.0.5" + sax "^1.2.4" + symbol-tree "^3.2.2" + tough-cookie "^2.3.4" + w3c-hr-time "^1.0.1" + webidl-conversions "^4.0.2" + whatwg-encoding "^1.0.3" + whatwg-mimetype "^2.1.0" + whatwg-url "^6.4.1" + ws "^5.2.0" + xml-name-validator "^3.0.0" + jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -3103,6 +3793,11 @@ klaw@^3.0.0: dependencies: graceful-fs "^4.1.9" +kleur@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-2.0.2.tgz#b704f4944d95e255d038f0cb05fb8a602c55a300" + integrity sha512-77XF9iTllATmG9lSlIv0qdQ2BQ/h9t0bJllHlbvsQ0zUWfU7Yi0S8L5JXzPZgkefIiajLmBJJ4BsMJmqcf7oxQ== + labeled-stream-splicer@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz#42a41a16abcd46fd046306cf4f2c3576fffb1c21" @@ -3111,6 +3806,23 @@ labeled-stream-splicer@^2.0.0: inherits "^2.0.1" stream-splicer "^2.0.0" +lcid@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf" + integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA== + dependencies: + invert-kv "^2.0.0" + +left-pad@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" + integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== + +leven@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-2.1.0.tgz#c2e7a9f772094dee9d34202ae8acce4687875580" + integrity sha1-wuep93IJTe6dNCAq6KzORoeHVYA= + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -3126,12 +3838,23 @@ linkify-it@^2.0.0: dependencies: uc.micro "^1.0.1" -locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= dependencies: - p-locate "^3.0.0" + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" path-exists "^3.0.0" lodash.memoize@~3.0.3: @@ -3139,18 +3862,21 @@ lodash.memoize@~3.0.3: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" integrity sha1-LcvSwofLwKVcxCMovQxzYVDVPj8= +lodash.sortby@^4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" + integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + +lodash.unescape@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.unescape/-/lodash.unescape-4.0.1.tgz#bf2249886ce514cda112fae9218cdc065211fc9c" + integrity sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw= + lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4: version "4.17.15" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== -log-symbols@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" - integrity sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg== - dependencies: - chalk "^2.0.1" - loglevel@^1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.4.tgz#f408f4f006db8354d0577dcf6d33485b3cb90d56" @@ -3168,6 +3894,20 @@ loose-envify@^1.0.0: dependencies: js-tokens "^3.0.0 || ^4.0.0" +makeerror@1.0.x: + version "1.0.11" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= + dependencies: + tmpl "1.0.x" + +map-age-cleaner@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" + integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w== + dependencies: + p-defer "^1.0.0" + map-cache@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -3233,7 +3973,28 @@ mdurl@^1.0.1: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= -micromatch@^2.1.5: +mem@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178" + integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w== + dependencies: + map-age-cleaner "^0.1.1" + mimic-fn "^2.0.0" + p-is-promise "^2.0.0" + +merge-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + integrity sha1-QEEgLVCKNCugAXQAjfDCUbjBNeE= + dependencies: + readable-stream "^2.0.1" + +merge@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.1.tgz#38bebf80c3220a8a487b6fcfb3941bb11720c145" + integrity sha512-VjFo4P5Whtj4vsLzsYBu5ayHhoHJ0UqNm7ibvShmbmoz7tGi0vXaoJbGdB+GmDMLUdg8DpQXEIeVDAe8MaABvQ== + +micromatch@^2.1.5, micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" integrity sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU= @@ -3296,6 +4057,11 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== +mimic-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" @@ -3306,7 +4072,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= -"minimatch@2 || 3", minimatch@3.0.4, minimatch@^3.0.4: +minimatch@^3.0.3, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== @@ -3364,42 +4130,13 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: +mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= dependencies: minimist "0.0.8" -mocha@^6.2.1: - version "6.2.1" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.2.1.tgz#da941c99437da9bac412097859ff99543969f94c" - integrity sha512-VCcWkLHwk79NYQc8cxhkmI8IigTIhsCwZ6RTxQsqK6go4UvEhzJkYuHm8B2YtlSxcYq2fY+ucr4JBwoD6ci80A== - dependencies: - ansi-colors "3.2.3" - browser-stdout "1.3.1" - debug "3.2.6" - diff "3.5.0" - escape-string-regexp "1.0.5" - find-up "3.0.0" - glob "7.1.3" - growl "1.10.5" - he "1.2.0" - js-yaml "3.13.1" - log-symbols "2.2.0" - minimatch "3.0.4" - mkdirp "0.5.1" - ms "2.1.1" - node-environment-flags "1.0.5" - object.assign "4.1.0" - strip-json-comments "2.0.1" - supports-color "6.0.0" - which "1.3.1" - wide-align "1.1.3" - yargs "13.3.0" - yargs-parser "13.1.1" - yargs-unparser "1.6.0" - module-deps@^6.0.0: version "6.2.1" resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-6.2.1.tgz#cfe558784060e926824f474b4e647287837cda50" @@ -3441,11 +4178,6 @@ ms@2.0.0: resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -3502,13 +4234,21 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-environment-flags@1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" - integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + +node-notifier@^5.2.1: + version "5.4.3" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.3.tgz#cb72daf94c93904098e28b9c590fd866e464bd50" + integrity sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q== dependencies: - object.getownpropertydescriptors "^2.0.3" - semver "^5.7.0" + growly "^1.3.0" + is-wsl "^1.1.0" + semver "^5.5.0" + shellwords "^0.1.1" + which "^1.3.0" node-pre-gyp@^0.12.0: version "0.12.0" @@ -3526,13 +4266,6 @@ node-pre-gyp@^0.12.0: semver "^5.3.0" tar "^4" -nopt@3.x: - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= - dependencies: - abbrev "1" - nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -3541,6 +4274,16 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" +normalize-package-data@^2.3.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" @@ -3566,6 +4309,13 @@ npm-packlist@^1.1.6: ignore-walk "^3.0.1" npm-bundled "^1.0.1" +npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + npmlog@^4.0.2: version "4.1.2" resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" @@ -3581,6 +4331,11 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= +nwsapi@^2.0.7: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + oauth-sign@~0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" @@ -3605,7 +4360,7 @@ object-inspect@^1.1.0, object-inspect@^1.6.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== -object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.0.9, object-keys@^1.1.1: +object-keys@^1.0.12, object-keys@^1.0.9, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== @@ -3622,16 +4377,6 @@ object-visit@^1.0.0: dependencies: isobject "^3.0.0" -object.assign@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" - integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== - dependencies: - define-properties "^1.1.2" - function-bind "^1.1.1" - has-symbols "^1.0.0" - object-keys "^1.0.11" - object.entries@^1.0.4: version "1.1.0" resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.0.tgz#2024fc6d6ba246aee38bdb0ffd5cfbcf371b7519" @@ -3669,7 +4414,7 @@ object.pick@^1.3.0: version "3.1.4" resolved "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz#0f03128b7d3b2f614d2216409a1dfccca765fdb3" -once@1.x, once@^1.3.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -3713,6 +4458,15 @@ os-homedir@^1.0.0: resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= +os-locale@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a" + integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q== + dependencies: + execa "^1.0.0" + lcid "^2.0.0" + mem "^4.0.0" + os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -3742,24 +4496,39 @@ output-file-sync@^1.1.2: mkdirp "^0.5.1" object-assign "^4.1.0" -p-limit@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" - integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== - dependencies: - p-try "^2.0.0" +p-defer@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c" + integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww= -p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +p-is-promise@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e" + integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg== + +p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + +p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= pako@~1.0.5: version "1.0.10" @@ -3802,6 +4571,18 @@ parse-glob@^3.0.4: is-extglob "^1.0.0" is-glob "^2.0.0" +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= + dependencies: + error-ex "^1.2.0" + +parse5@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" + integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -3822,6 +4603,13 @@ path-dirname@^1.0.0: resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= + dependencies: + pinkie-promise "^2.0.0" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -3837,12 +4625,12 @@ path-is-inside@^1.0.2: resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= -path-key@^2.0.1: +path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= -path-parse@^1.0.6: +path-parse@^1.0.5, path-parse@^1.0.6: version "1.0.6" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== @@ -3852,6 +4640,15 @@ path-platform@~0.11.15: resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" integrity sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I= +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + pbkdf2@^3.0.3: version "3.0.17" resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" @@ -3868,6 +4665,35 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + +pn@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" + integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== + posix-character-classes@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" @@ -3883,6 +4709,14 @@ preserve@^0.2.0: resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" integrity sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks= +pretty-format@^23.6.0: + version "23.6.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-23.6.0.tgz#5eaac8eeb6b33b987b7fe6097ea6a8a146ab5760" + integrity sha512-zf9NV1NSlDLDjycnwm6hpFATCGl/K1lt0R/GdkAK2O5LN/rwJoB+Mh93gGJjut4YbmecbfgLWVGSTCr0Ewvvbw== + dependencies: + ansi-regex "^3.0.0" + ansi-styles "^3.2.0" + private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -3903,7 +4737,15 @@ progress@^2.0.0: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -psl@^1.1.24: +prompts@^0.1.9: + version "0.1.14" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-0.1.14.tgz#a8e15c612c5c9ec8f8111847df3337c9cbd443b2" + integrity sha512-rxkyiE9YH6zAz/rZpywySLKkpaj0NMVyNw1qhsubdbjjSgcayjTShDreZGlFMcGSu5sab3bAKPfFk78PB90+8w== + dependencies: + kleur "^2.0.1" + sisteransi "^0.1.1" + +psl@^1.1.24, psl@^1.1.28: version "1.4.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.4.0.tgz#5dd26156cdb69fa1fdb8ab1991667d3f80ced7c2" integrity sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw== @@ -3920,6 +4762,14 @@ public-encrypt@^4.0.0: randombytes "^2.0.1" safe-buffer "^5.1.2" +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -3930,7 +4780,7 @@ punycode@^1.3.2, punycode@^1.4.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" integrity sha1-wNWmOycYgArY4esPpSachN1BhF4= -punycode@^2.1.0: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -3996,7 +4846,24 @@ read-only-stream@^2.0.0: dependencies: readable-stream "^2.0.2" -readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@~2.3.6: +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.2.2, readable-stream@~2.3.6: version "2.3.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== @@ -4047,6 +4914,13 @@ readdirp@^2.0.0, readdirp@^2.2.1: micromatch "^3.1.10" readable-stream "^2.0.2" +realpath-native@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" + integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== + dependencies: + util.promisify "^1.0.0" + regenerate@^1.2.1: version "1.4.0" resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" @@ -4151,7 +5025,23 @@ replace-requires@~1.0.3: patch-text "~1.0.2" xtend "~4.0.0" -request@^2.88.0: +request-promise-core@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" + integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== + dependencies: + lodash "^4.17.15" + +request-promise-native@^1.0.5: + version "1.0.8" + resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" + integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== + dependencies: + request-promise-core "1.1.3" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + +request@^2.87.0, request@^2.88.0: version "2.88.0" resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef" integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== @@ -4182,10 +5072,10 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= -require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE= requizzle@^0.2.3: version "0.2.3" @@ -4194,6 +5084,18 @@ requizzle@^0.2.3: dependencies: lodash "^4.17.14" +resolve-cwd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" + integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= + dependencies: + resolve-from "^3.0.0" + +resolve-from@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" + integrity sha1-six699nWiBvItuZTM17rywoYh0g= + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -4204,12 +5106,12 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@1.1.7, resolve@1.1.x: +resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.4, resolve@^1.12.0, resolve@^1.4.0: +resolve@^1.1.4, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.4.0: version "1.12.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== @@ -4241,7 +5143,7 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^2.6.1: +rimraf@^2.5.4, rimraf@^2.6.1: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -4263,6 +5165,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rsvp@^3.3.3: + version "3.6.2" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-3.6.2.tgz#2e96491599a96cde1b515d5674a8f7a91452926a" + integrity sha512-OfWGQTb9vnwRjwtA2QwpG2ICclHC3pgXZO5xt8H2EfgDquO0qVdSb5T88L4qJVAEugbS56pAuV4XZM58UX8ulw== + run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -4299,16 +5206,37 @@ safe-regex@^1.1.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== +sane@^2.0.0: + version "2.5.2" + resolved "https://registry.yarnpkg.com/sane/-/sane-2.5.2.tgz#b4dc1861c21b427e929507a3e751e2a2cb8ab3fa" + integrity sha1-tNwYYcIbQn6SlQej51HiosuKs/o= + dependencies: + anymatch "^2.0.0" + capture-exit "^1.2.0" + exec-sh "^0.2.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + watch "~0.18.0" + optionalDependencies: + fsevents "^1.2.3" + sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -semver@^5.3.0, semver@^5.5.0, semver@^5.5.1, semver@^5.7.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.5.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== +semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -4357,6 +5285,11 @@ shell-quote@^1.4.2, shell-quote@^1.6.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2" integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg== +shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -4367,6 +5300,11 @@ simple-concat@^1.0.0: resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= +sisteransi@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-0.1.1.tgz#5431447d5f7d1675aac667ccd0b865a4994cb3ce" + integrity sha512-PmGOd02bM9YO5ifxpw36nrNMBTptEtfRl4qUYl9SndkolplkrZZOW7PGHjrZL53QvMVj9nQ+TKqUnRsw4tJa4g== + slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -4437,12 +5375,20 @@ source-map-support@^0.5.13, source-map-support@~0.5.12: buffer-from "^1.0.0" source-map "^0.6.0" +source-map-support@^0.5.6: + version "0.5.16" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.16.tgz#0ae069e7fe3ba7538c64c98515e35339eac5a042" + integrity sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.3: +source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, source-map@~0.5.3: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= @@ -4459,13 +5405,6 @@ source-map@~0.1.30: dependencies: amdefine ">=0.0.4" -source-map@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" - integrity sha1-2rc/vPwrqBm03gO9b26qSBZLP50= - dependencies: - amdefine ">=0.0.4" - sourceify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/sourceify/-/sourceify-1.0.0.tgz#428da9a97fcbac6c250e03e58ea7aeb980c9e242" @@ -4474,6 +5413,32 @@ sourceify@^1.0.0: convert-source-map "^1.1.3" through2 "^2.0.0" +spdx-correct@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4" + integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977" + integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA== + +spdx-expression-parse@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0" + integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.5" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== + split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" @@ -4501,6 +5466,11 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +stack-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.2.tgz#33eba3897788558bebfc2db059dc158ec36cebb8" + integrity sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA== + static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -4509,6 +5479,11 @@ static-extend@^0.1.1: define-property "^0.2.5" object-copy "^0.1.0" +stealthy-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= + stream-browserify@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" @@ -4543,6 +5518,14 @@ stream-splicer@^2.0.0: inherits "^2.0.1" readable-stream "^2.0.2" +string-length@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" + integrity sha1-1A27aGo6zpYMHP/KVivyxF+DY+0= + dependencies: + astral-regex "^1.0.0" + strip-ansi "^4.0.0" + string-width@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" @@ -4552,7 +5535,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.1.0: +"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -4560,7 +5543,7 @@ string-width@^1.0.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" -string-width@^3.0.0, string-width@^3.1.0: +string-width@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== @@ -4618,14 +5601,31 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: +strip-ansi@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== dependencies: ansi-regex "^4.1.0" -strip-json-comments@2.0.1, strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: +strip-bom@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= + dependencies: + is-utf8 "^0.2.0" + +strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + +strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= @@ -4642,19 +5642,12 @@ subarg@^1.0.0: dependencies: minimist "^1.1.0" -supports-color@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.0.0.tgz#76cfe742cf1f41bb9b1c29ad03068c05b4c0e40a" - integrity sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg== - dependencies: - has-flag "^3.0.0" - supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= -supports-color@^3.1.0: +supports-color@^3.1.2: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" integrity sha1-ZawFBLOVQXHYpklGsq48u4pfVPY= @@ -4668,6 +5661,11 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" +symbol-tree@^3.2.2: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + syntax-error@^1.1.1: version "1.4.0" resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.4.0.tgz#2d9d4ff5c064acb711594a3e3b95054ad51d907c" @@ -4717,11 +5715,27 @@ terser@^4.3.8: source-map "~0.6.1" source-map-support "~0.5.12" +test-exclude@^4.2.1: + version "4.2.3" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-4.2.3.tgz#a9a5e64474e4398339245a0a769ad7c2f4a97c20" + integrity sha512-SYbXgY64PT+4GAL2ocI3HwPa4Q4TBKm0cwAVeKOt/Aoc0gSpNRjJX8w0pA1LMKZ3LBmd8pYBqApFNQLII9kavA== + dependencies: + arrify "^1.0.1" + micromatch "^2.3.11" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +throat@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" + integrity sha1-iQN8vJLFarGJJua6TLsgDhVnKmo= + through2@^2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" @@ -4767,6 +5781,11 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +tmpl@1.0.x: + version "1.0.4" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= + to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" @@ -4802,6 +5821,14 @@ to-regex@^3.0.1, to-regex@^3.0.2: regex-not "^1.0.2" safe-regex "^1.1.0" +tough-cookie@^2.3.3, tough-cookie@^2.3.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + tough-cookie@~2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781" @@ -4810,6 +5837,13 @@ tough-cookie@~2.4.3: psl "^1.1.24" punycode "^1.4.1" +tr46@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" + integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= + dependencies: + punycode "^2.1.0" + transformify@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/transformify/-/transformify-0.1.2.tgz#9a4f42a154433dd727b80575428a3c9e5489ebf1" @@ -4822,11 +5856,18 @@ trim-right@^1.0.1: resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= -tslib@^1.9.0: +tslib@^1.8.1, tslib@^1.9.0: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== +tsutils@^3.17.1: + version "3.17.1" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" + integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== + dependencies: + tslib "^1.8.1" + tty-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" @@ -4953,6 +5994,14 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= +util.promisify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030" + integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA== + dependencies: + define-properties "^1.1.2" + object.getownpropertydescriptors "^2.0.3" + util@0.10.3: version "0.10.3" resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" @@ -4979,6 +6028,14 @@ v8flags@^2.1.1: dependencies: user-home "^1.1.1" +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -4993,6 +6050,28 @@ vm-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019" integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw== +w3c-hr-time@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" + integrity sha1-gqwr/2PZUOqeMYmlimViX+3xkEU= + dependencies: + browser-process-hrtime "^0.1.2" + +walker@~1.0.5: + version "1.0.7" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + dependencies: + makeerror "1.0.x" + +watch@~0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/watch/-/watch-0.18.0.tgz#28095476c6df7c90c963138990c0a5423eb4b986" + integrity sha1-KAlUdsbffJDJYxOJkMClQj60uYY= + dependencies: + exec-sh "^0.2.0" + minimist "^1.2.0" + watchify@^3.11.1: version "3.11.1" resolved "https://registry.yarnpkg.com/watchify/-/watchify-3.11.1.tgz#8e4665871fff1ef64c0430d1a2c9d084d9721881" @@ -5006,49 +6085,92 @@ watchify@^3.11.1: through2 "^2.0.0" xtend "^4.0.0" +webidl-conversions@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" + integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== + +whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + +whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + +whatwg-url@^6.4.1: + version "6.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" + integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + +whatwg-url@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" + integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== + dependencies: + lodash.sortby "^4.7.0" + tr46 "^1.0.1" + webidl-conversions "^4.0.2" + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@1.3.1, which@^1.1.1, which@^1.2.9: +which@^1.2.12, which@^1.2.9, which@^1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" -wide-align@1.1.3, wide-align@^1.1.0: +wide-align@^1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: string-width "^1.0.2 || 2" -wordwrap@^1.0.0, wordwrap@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - wordwrap@~0.0.2: version "0.0.3" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU= dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= +write-file-atomic@^2.1.0: + version "2.4.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" + integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + signal-exit "^3.0.2" + write@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" @@ -5056,6 +6178,18 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" +ws@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.2.tgz#dffef14866b8e8dc9133582514d1befaf96e980f" + integrity sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA== + dependencies: + async-limiter "~1.0.0" + +xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + xmlcreate@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/xmlcreate/-/xmlcreate-2.0.1.tgz#2ec38bd7b708d213fd1a90e2431c4af9c09f6a52" @@ -5073,45 +6207,37 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -y18n@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" - integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + integrity sha1-bRX7qITAhnnA136I53WegR4H+kE= yallist@^3.0.0, yallist@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.0.tgz#906cc2100972dc2625ae78f566a2577230a1d6f7" integrity sha512-6gpP93MR+VOOehKbCPchro3wFZNSNmek8A2kbkOAZLIZAYx1KP/zAqwO0sOHi3xJEb+UBz8NaYt/17UNit1Q9w== -yargs-parser@13.1.1, yargs-parser@^13.1.1: - version "13.1.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0" - integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ== +yargs-parser@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077" + integrity sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc= dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" + camelcase "^4.1.0" -yargs-unparser@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" - integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== +yargs@^11.0.0: + version "11.1.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-11.1.1.tgz#5052efe3446a4df5ed669c995886cc0f13702766" + integrity sha512-PRU7gJrJaXv3q3yQZ/+/X6KBswZiaQ+zOmdprZcouPYtQgvNU35i+68M4b1ZHLZtYFT5QObFLV+ZkmJYcwKdiw== dependencies: - flat "^4.1.0" - lodash "^4.17.15" - yargs "^13.3.0" - -yargs@13.3.0, yargs@^13.3.0: - version "13.3.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.0.tgz#4c657a55e07e5f2cf947f8a366567c04a0dedc83" - integrity sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA== - dependencies: - cliui "^5.0.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" + cliui "^4.0.0" + decamelize "^1.1.1" + find-up "^2.1.0" + get-caller-file "^1.0.1" + os-locale "^3.1.0" require-directory "^2.1.1" - require-main-filename "^2.0.0" + require-main-filename "^1.0.1" set-blocking "^2.0.0" - string-width "^3.0.0" + string-width "^2.0.0" which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^13.1.1" + y18n "^3.2.1" + yargs-parser "^9.0.2" From 26edd7431a0f4e2b5233cfb9d3588028966f3ed4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 20 Nov 2019 19:56:50 +0000 Subject: [PATCH 12/67] fix yarn scripts test Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 4f7887752..4354be8b7 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,8 @@ "description": "Matrix Client-Server SDK for Javascript", "main": "index.js", "scripts": { - "test:run": "jest spec/ --coverage --testEnvironment node", "test:watch": "jest spec/ --coverage --testEnvironment node --watch", - "test": "yarn test:build && yarn test:run", + "test": "jest spec/ --coverage --testEnvironment node", "check": "yarn test:build && _mocha --recursive specbuild --colors", "gendoc": "babel --no-babelrc --plugins transform-class-properties -d .jsdocbuild src && jsdoc -r .jsdocbuild -P package.json -R README.md -d .jsdoc", "start": "yarn start:init && yarn start:watch", From 5fc0629201b9b443fc3de8407b5e7732a68f1148 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 20 Nov 2019 20:19:54 +0000 Subject: [PATCH 13/67] fix expect calls Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- spec/unit/crypto/backup.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/unit/crypto/backup.spec.js b/spec/unit/crypto/backup.spec.js index 3f11a9a54..c13287f22 100644 --- a/spec/unit/crypto/backup.spec.js +++ b/spec/unit/crypto/backup.spec.js @@ -276,7 +276,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")); @@ -340,7 +340,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")); @@ -446,7 +446,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")); From 522640edd9db8d2fca939721a91654269102ee9c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 20 Nov 2019 21:05:21 +0000 Subject: [PATCH 14/67] rip out lolex also Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- package.json | 1 - spec/unit/realtime-callbacks.spec.js | 14 +++++--------- src/realtime-callbacks.js | 2 +- yarn.lock | 5 ----- 4 files changed, 6 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 4354be8b7..0195dff2f 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,6 @@ "exorcist": "^1.0.1", "jest": "^23.6.0", "jsdoc": "^3.5.5", - "lolex": "^1.5.2", "matrix-mock-request": "^1.2.3", "olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz", "rimraf": "^3.0.0", diff --git a/spec/unit/realtime-callbacks.spec.js b/spec/unit/realtime-callbacks.spec.js index 448bf9a76..971e4e0ea 100644 --- a/spec/unit/realtime-callbacks.spec.js +++ b/spec/unit/realtime-callbacks.spec.js @@ -3,24 +3,21 @@ import 'source-map-support/register'; const callbacks = require("../../src/realtime-callbacks"); -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() { - 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() { @@ -33,7 +30,6 @@ describe("realtime-callbacks", function() { expect(callback).toHaveBeenCalled(); }); - it("should default to a zero timeout", function() { const callback = jest.fn(); callbacks.setTimeout(callback); diff --git a/src/realtime-callbacks.js b/src/realtime-callbacks.js index ee2faa1e5..7a4401257 100644 --- a/src/realtime-callbacks.js +++ b/src/realtime-callbacks.js @@ -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 */ diff --git a/yarn.lock b/yarn.lock index dc71a8198..af06e632b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3882,11 +3882,6 @@ loglevel@^1.6.4: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.4.tgz#f408f4f006db8354d0577dcf6d33485b3cb90d56" integrity sha512-p0b6mOGKcGa+7nnmKbpzR6qloPbrgLcnio++E+14Vo/XffOGwZtRpUhr8dTH/x2oCMmEoIU0Zwm3ZauhvYD17g== -lolex@^1.5.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-1.6.0.tgz#3a9a0283452a47d7439e72731b9e07d7386e49f6" - integrity sha1-OpoCg0UqR9dDnnJzG54H1zhuSfY= - loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" From c57109c2f364181108807e561be81d1a2096d335 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 20 Nov 2019 21:16:11 +0000 Subject: [PATCH 15/67] tidy up Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- spec/unit/realtime-callbacks.spec.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spec/unit/realtime-callbacks.spec.js b/spec/unit/realtime-callbacks.spec.js index 971e4e0ea..70510b26a 100644 --- a/spec/unit/realtime-callbacks.spec.js +++ b/spec/unit/realtime-callbacks.spec.js @@ -115,8 +115,7 @@ describe("realtime-callbacks", function() { it("should not get confused by chained calls", function() { const callback2 = jest.fn(); - const callback1 = jest.fn(); - callback1.mockImplementation(function() { + const callback1 = jest.fn(function() { callbacks.setTimeout(callback2, 0); expect(callback2).not.toHaveBeenCalled(); }); @@ -133,8 +132,7 @@ describe("realtime-callbacks", function() { }); it("should be immune to exceptions", function() { - const callback1 = jest.fn(); - callback1.mockImplementation(function() { + const callback1 = jest.fn(function() { throw new Error("prepare to die"); }); const callback2 = jest.fn(); From 3bd518cf7fb69043810fee9183a57c462ae2b23a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 20 Nov 2019 21:59:50 +0000 Subject: [PATCH 16/67] update buildkite pipeline name Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .buildkite/pipeline.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.buildkite/pipeline.yaml b/.buildkite/pipeline.yaml index 4909aabde..db885300a 100644 --- a/.buildkite/pipeline.yaml +++ b/.buildkite/pipeline.yaml @@ -7,7 +7,7 @@ steps: - docker#v3.0.1: image: "node:10" - - label: ":karma: Tests" + - label: ":jest: Tests" command: - "yarn install" - "yarn test" From b44f43e5db7dad08dbf69e0a4c0ade6cae936087 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Nov 2019 09:45:00 +0000 Subject: [PATCH 17/67] fix import in relations.js Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/models/relations.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/models/relations.js b/src/models/relations.js index 2ea549667..81ead22de 100644 --- a/src/models/relations.js +++ b/src/models/relations.js @@ -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 From 2ce106382a8fe87de382484921255f695c474a1a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Nov 2019 10:01:16 +0000 Subject: [PATCH 18/67] Stop using Bluebird promise::isFulfilled() Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- spec/unit/event.spec.js | 4 +++- src/timeline-window.js | 15 ++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/spec/unit/event.spec.js b/spec/unit/event.spec.js index d88324ced..cda4580f9 100644 --- a/spec/unit/event.spec.js +++ b/spec/unit/event.spec.js @@ -38,6 +38,7 @@ describe("MatrixEvent", () => { let callCount = 0; let prom2; + let prom2Fulfilled = false; const crypto = { decryptEvent: function() { @@ -47,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({ diff --git a/src/timeline-window.js b/src/timeline-window.js index a3edabcd0..9d845dd61 100644 --- a/src/timeline-window.js +++ b/src/timeline-window.js @@ -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); From 549b0f9313b1afcf3b4f5e16b510544c7baaad4a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Nov 2019 10:05:59 +0000 Subject: [PATCH 19/67] Stop using Bluebird.delay and Bluebird promise::delay Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/client.js | 3 ++- src/crypto/DeviceList.js | 3 ++- src/crypto/index.js | 5 +++-- src/utils.js | 5 +++++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/client.js b/src/client.js index 187944420..8af841c99 100644 --- a/src/client.js +++ b/src/client.js @@ -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. @@ -3221,7 +3222,7 @@ MatrixClient.prototype.scrollback = function(room, limit, callback) { 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() { + sleep(timeToWaitMs).then(function() { return self._createMessagesRequest( room.roomId, room.oldState.paginationToken, diff --git a/src/crypto/DeviceList.js b/src/crypto/DeviceList.js index 94b3140b0..27b1a23e4 100644 --- a/src/crypto/DeviceList.js +++ b/src/crypto/DeviceList.js @@ -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], diff --git a/src/crypto/index.js b/src/crypto/index.js index 11b450a8e..7b1dad314 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -49,6 +49,7 @@ import { newUnexpectedMessageError, newUnknownMethodError, } from './verification/Error'; +import {sleep} from '../utils'; const defaultVerificationMethods = { [ScanQRCode.NAME]: ScanQRCode, @@ -1834,7 +1835,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 +1869,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 { diff --git a/src/utils.js b/src/utils.js index b752299f0..8cab9fbb8 100644 --- a/src/utils.js +++ b/src/utils.js @@ -708,3 +708,8 @@ 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); +})); From 53d225a1d101acaafa5a06ce1f6602405131a6f8 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Nov 2019 10:09:36 +0000 Subject: [PATCH 20/67] fix stub timelineSet for timeline-window.spec Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- spec/unit/timeline-window.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/unit/timeline-window.spec.js b/spec/unit/timeline-window.spec.js index 6dc3ccc6d..d2e4b313e 100644 --- a/spec/unit/timeline-window.spec.js +++ b/spec/unit/timeline-window.spec.js @@ -148,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); @@ -177,7 +177,7 @@ describe("TimelineWindow", 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); @@ -200,7 +200,7 @@ describe("TimelineWindow", function() { const eventId = timeline.getEvents()[1].getId(); - const timelineSet = {}; + const timelineSet = {getTimelineForEvent: () => null}; const client = {}; const timelineWindow = new TimelineWindow(client, timelineSet); From ac742aad7027bd6e49e32820e74f147b83788a6b Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Nov 2019 10:14:06 +0000 Subject: [PATCH 21/67] use Bluebird in promise utils sleep so it has .done and .nodeify Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/utils.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/utils.js b/src/utils.js index 8cab9fbb8..4bea67129 100644 --- a/src/utils.js +++ b/src/utils.js @@ -21,6 +21,7 @@ limitations under the License. */ const unhomoglyph = require('unhomoglyph'); +import Promise from 'bluebird'; /** * Encode a dictionary of query parameters. From b4f68f4fc664c2400e95dcc7ce9dc583921429d1 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Nov 2019 10:43:58 +0000 Subject: [PATCH 22/67] Stop using Bluebird promise::nodeify Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- spec/integ/matrix-client-crypto.spec.js | 46 +++++++-------- .../matrix-client-event-timeline.spec.js | 20 +++---- spec/integ/matrix-client-methods.spec.js | 40 +++++++------ .../integ/matrix-client-room-timeline.spec.js | 6 +- spec/unit/interactive-auth.spec.js | 12 ++-- spec/unit/timeline-window.spec.js | 57 +++++++++---------- 6 files changed, 88 insertions(+), 93 deletions(-) diff --git a/spec/integ/matrix-client-crypto.spec.js b/spec/integ/matrix-client-crypto.spec.js index 4da8f4abf..fe5f63eac 100644 --- a/spec/integ/matrix-client-crypto.spec.js +++ b/spec/integ/matrix-client-crypto.spec.js @@ -427,15 +427,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 @@ -452,11 +451,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 = { @@ -485,7 +483,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() { @@ -497,10 +495,10 @@ describe("MatrixClient crypto", function() { // 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', @@ -527,7 +525,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() { @@ -535,7 +533,7 @@ describe("MatrixClient crypto", function() { }).then((devices) => { // should get an empty list expect(devices).toEqual([]); - }).nodeify(done); + }); }); @@ -549,15 +547,14 @@ describe("MatrixClient crypto", function() { }); }); - 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() { @@ -625,9 +622,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)) @@ -642,12 +639,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)) @@ -655,8 +652,7 @@ describe("MatrixClient crypto", function() { .then(aliSendsFirstMessage) .then(bobRecvMessage) .then(aliSendsMessage) - .then(bobRecvMessage) - .nodeify(done); + .then(bobRecvMessage); }); it("Bob replies to the message", function() { diff --git a/spec/integ/matrix-client-event-timeline.spec.js b/spec/integ/matrix-client-event-timeline.spec.js index 402c9fe3a..96b28e58f 100644 --- a/spec/integ/matrix-client-event-timeline.spec.js +++ b/spec/integ/matrix-client-event-timeline.spec.js @@ -114,21 +114,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() { @@ -150,7 +149,7 @@ describe("getEventTimeline support", function() { 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, @@ -159,8 +158,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, { @@ -216,7 +214,7 @@ 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); + }); }); }); @@ -693,7 +691,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 @@ -725,7 +723,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() { @@ -761,6 +759,6 @@ describe("MatrixClient event timelines", function() { const room = client.getRoom(roomId); const tl = room.getLiveTimeline(); expect(tl.getEvents().length).toEqual(1); - }).nodeify(done); + }); }); }); diff --git a/spec/integ/matrix-client-methods.spec.js b/spec/integ/matrix-client-methods.spec.js index 1a05ae896..09fac9fc6 100644 --- a/spec/integ/matrix-client-methods.spec.js +++ b/spec/integ/matrix-client-methods.spec.js @@ -43,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) { @@ -71,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", @@ -97,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) { @@ -113,7 +115,7 @@ describe("MatrixClient", function() { "error": "broken", }); - client.uploadContent({ + const prom = client.uploadContent({ stream: buf, name: "hi.txt", type: "text/plain", @@ -123,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", @@ -140,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; }); }); @@ -307,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 = { @@ -369,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 }, @@ -383,9 +387,10 @@ describe("MatrixClient", function() { algorithms: ["2"], unsigned: { "ghi": "def" }, }); - }).nodeify(done); + }); httpBackend.flush(); + return prom; }); }); @@ -398,11 +403,10 @@ describe("MatrixClient", function() { 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; }); }); }); diff --git a/spec/integ/matrix-client-room-timeline.spec.js b/spec/integ/matrix-client-room-timeline.spec.js index add82cb4e..b93ec1bc9 100644 --- a/spec/integ/matrix-client-room-timeline.spec.js +++ b/spec/integ/matrix-client-room-timeline.spec.js @@ -102,7 +102,7 @@ describe("MatrixClient room timelines", function() { }); } - beforeEach(function(done) { + beforeEach(function() { httpBackend = new HttpBackend(); sdk.request(httpBackend.requestFn); client = sdk.createClient({ @@ -120,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() { diff --git a/spec/unit/interactive-auth.spec.js b/spec/unit/interactive-auth.spec.js index dabcf9415..c4633f554 100644 --- a/spec/unit/interactive-auth.spec.js +++ b/spec/unit/interactive-auth.spec.js @@ -33,7 +33,7 @@ class FakeClient { } describe("InteractiveAuth", function() { - it("should start an auth stage and complete it", function(done) { + it("should start an auth stage and complete it", function() { const doRequest = jest.fn(); const stateUpdated = jest.fn(); @@ -79,14 +79,14 @@ describe("InteractiveAuth", function() { return Promise.resolve(requestRes); }); - ia.attemptAuth().then(function(res) { + return ia.attemptAuth().then(function(res) { expect(res).toBe(requestRes); expect(doRequest).toBeCalledTimes(1); expect(stateUpdated).toBeCalledTimes(1); - }).nodeify(done); + }); }); - it("should make a request if no authdata is provided", function(done) { + it("should make a request if no authdata is provided", function() { const doRequest = jest.fn(); const stateUpdated = jest.fn(); @@ -142,10 +142,10 @@ describe("InteractiveAuth", function() { }); }); - ia.attemptAuth().then(function(res) { + return ia.attemptAuth().then(function(res) { expect(res).toBe(requestRes); expect(doRequest).toBeCalledTimes(2); expect(stateUpdated).toBeCalledTimes(1); - }).nodeify(done); + }); }); }); diff --git a/spec/unit/timeline-window.spec.js b/spec/unit/timeline-window.spec.js index d2e4b313e..35520b1d7 100644 --- a/spec/unit/timeline-window.spec.js +++ b/spec/unit/timeline-window.spec.js @@ -159,7 +159,7 @@ describe("TimelineWindow", function() { } describe("load", function() { - it("should initialise from the live timeline", function(done) { + it("should initialise from the live timeline", function() { const liveTimeline = createTimeline(); const room = {}; room.getLiveTimeline = function() { @@ -167,13 +167,13 @@ 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(); @@ -186,14 +186,13 @@ 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); @@ -213,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); @@ -268,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); @@ -313,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); @@ -358,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); @@ -377,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); @@ -390,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); @@ -410,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); @@ -423,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); @@ -443,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); @@ -462,7 +459,7 @@ describe("TimelineWindow", function() { .toBe(false); expect(timelineWindow.canPaginate(EventTimeline.FORWARDS)) .toBe(true); - }).nodeify(done); + }); }); }); }); From 4d950fec663d894704fbe6f1c52d4ed541fc1645 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 21 Nov 2019 10:59:18 +0000 Subject: [PATCH 23/67] fixxy Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- spec/integ/matrix-client-methods.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/integ/matrix-client-methods.spec.js b/spec/integ/matrix-client-methods.spec.js index 09fac9fc6..d8d12e7e3 100644 --- a/spec/integ/matrix-client-methods.spec.js +++ b/spec/integ/matrix-client-methods.spec.js @@ -396,7 +396,7 @@ describe("MatrixClient", function() { 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) { From 4a40c10d4cce4af31ae0f9be7e1c1a76e398be0d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 21 Nov 2019 17:13:43 +0100 Subject: [PATCH 24/67] add helper method on event for current age according to local clock --- src/models/event.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/models/event.js b/src/models/event.js index 6aa39c943..83ca20d2e 100644 --- a/src/models/event.js +++ b/src/models/event.js @@ -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 undefined * for message events. From 3a9832a8c6467f292127f9f2faea18442e8c1826 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 21 Nov 2019 17:56:04 +0000 Subject: [PATCH 25/67] 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 --- src/client.js | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/client.js b/src/client.js index 8af841c99..8f2dec601 100644 --- a/src/client.js +++ b/src/client.js @@ -4640,10 +4640,12 @@ function setupCallEventHandler(client) { // notifications. It needs to be buffered to correctly determine if an // incoming call has had a matching answer/hangup. let callEventBuffer = []; - let isClientPrepared = false; - client.on("sync", function(state) { - if (state === "PREPARED") { - isClientPrepared = true; + let isClientSyncing = false; + const onSync = function(state) { + if (state === "SYNCING") { + isClientSyncing = true; + client.removeListener("sync", onSync); + const ignoreCallIds = {}; // Set // inspect the buffer and mark all calls which have been answered // or hung up before passing them to the call event handler. @@ -4664,7 +4666,8 @@ function setupCallEventHandler(client) { }); callEventBuffer = []; } - }); + }; + client.on("sync", onSync); client.on("event", onEvent); @@ -4677,7 +4680,7 @@ function setupCallEventHandler(client) { } return; } - if (!isClientPrepared) { + if (!isClientSyncing) { callEventBuffer.push(event); return; } From 7addacba38b65b22f3b36c58ee153e4a0c118b1f Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 21 Nov 2019 18:56:37 +0000 Subject: [PATCH 26/67] 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. --- src/client.js | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/client.js b/src/client.js index 8f2dec601..410b0e78b 100644 --- a/src/client.js +++ b/src/client.js @@ -4635,17 +4635,17 @@ 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 isClientSyncing = false; - const onSync = function(state) { + function onSync(state) { if (state === "SYNCING") { - isClientSyncing = true; - client.removeListener("sync", onSync); - const ignoreCallIds = {}; // Set // inspect the buffer and mark all calls which have been answered // or hung up before passing them to the call event handler. @@ -4658,8 +4658,8 @@ 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); @@ -4669,8 +4669,6 @@ function setupCallEventHandler(client) { }; client.on("sync", onSync); - client.on("event", onEvent); - function onEvent(event) { if (event.getType().indexOf("m.call.") !== 0) { // not a call event @@ -4680,12 +4678,11 @@ function setupCallEventHandler(client) { } return; } - if (!isClientSyncing) { - callEventBuffer.push(event); - return; - } - callEventHandler(event); + // queue up for processing once all events from this sync have been + // processed (see above). + callEventBuffer.push(event); } + client.on("event", onEvent); function callEventHandler(event) { const content = event.getContent(); From 5262d716e4d63da680d549de4dc233021a2a1021 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 21 Nov 2019 19:10:27 +0000 Subject: [PATCH 27/67] Lint --- src/client.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/client.js b/src/client.js index 410b0e78b..2a7654bfc 100644 --- a/src/client.js +++ b/src/client.js @@ -4658,7 +4658,10 @@ function setupCallEventHandler(client) { } // now loop through the buffer chronologically and inject them callEventBuffer.forEach(function(e) { - if (e.getType() === "m.call.invite" && ignoreCallIds[e.getContent().call_id]) { + if ( + e.getType() === "m.call.invite" && + ignoreCallIds[e.getContent().call_id] + ) { // This call has previously been answered or hung up: ignore it return; } @@ -4666,7 +4669,7 @@ function setupCallEventHandler(client) { }); callEventBuffer = []; } - }; + } client.on("sync", onSync); function onEvent(event) { From e8bbb8a1cc7f64fc085f1eeb8f1c9bbee6d71740 Mon Sep 17 00:00:00 2001 From: David Baker Date: Thu, 21 Nov 2019 19:30:46 +0000 Subject: [PATCH 28/67] 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). --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 0195dff2f..c125a9cef 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,6 @@ "scripts": { "test:watch": "jest spec/ --coverage --testEnvironment node --watch", "test": "jest spec/ --coverage --testEnvironment node", - "check": "yarn test:build && _mocha --recursive specbuild --colors", "gendoc": "babel --no-babelrc --plugins transform-class-properties -d .jsdocbuild src && jsdoc -r .jsdocbuild -P package.json -R README.md -d .jsdoc", "start": "yarn start:init && yarn start:watch", "start:watch": "babel -s -w --skip-initial-build -d lib src", From 0a0ae111f6cb97c07ea5b94517b3686e53e46898 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 22 Nov 2019 15:03:03 +0000 Subject: [PATCH 29/67] replace Bluebird::map --- src/crypto/index.js | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/crypto/index.js b/src/crypto/index.js index 7b1dad314..c71f6bd63 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -1806,17 +1806,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); + })); }; /** @@ -2767,14 +2765,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 { From ac1173c628a2c70cdfaaac9efc95cfb558c773be Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 22 Nov 2019 16:11:49 +0100 Subject: [PATCH 30/67] also emit `crypto.verification.request` for verification over DM --- src/crypto/index.js | 60 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/src/crypto/index.js b/src/crypto/index.js index 11b450a8e..cc3dc1f96 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -65,6 +65,9 @@ export const verificationMethods = { SAS: SAS.NAME, }; +const VERIFICATION_REQUEST_TIMEOUT = 5 * 60 * 1000; //5m +const VERIFICATION_REQUEST_MARGIN = 3 * 1000; //3s + export function isCryptoAvailable() { return Boolean(global.Olm); } @@ -919,6 +922,17 @@ Crypto.prototype.registerEventHandlers = function(eventEmitter) { eventEmitter.on("toDeviceEvent", function(event) { crypto._onToDeviceEvent(event); }); + + // only sync timeline events, not events when backpaginating, loading, ... + eventEmitter.on("Room.timeline", function(event) { + if (event.getRoomId()) { + crypto._onTimelineEvent(event); + } + }); + + eventEmitter.on("Event.decrypted", function(event) { + crypto._onTimelineEvent(event); + }); }; @@ -2584,6 +2598,52 @@ 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, + 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 * From ca89b6e7a81b097f1938c092d15a7bd57ccf689e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 22 Nov 2019 16:12:19 +0100 Subject: [PATCH 31/67] 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. --- src/client.js | 2 ++ src/crypto/index.js | 31 +++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/client.js b/src/client.js index 187944420..f2e74fc99 100644 --- a/src/client.js +++ b/src/client.js @@ -5201,6 +5201,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. diff --git a/src/crypto/index.js b/src/crypto/index.js index cc3dc1f96..496aca155 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -2357,8 +2357,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 @@ -2434,6 +2434,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) => { @@ -2566,6 +2567,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); } }; @@ -2631,6 +2657,7 @@ Crypto.prototype._onTimelineEvent = function(event) { } const request = { event, + timeout: VERIFICATION_REQUEST_TIMEOUT, methods: content.methods, beginKeyVerification: (method) => { const verifier = this.acceptVerificationDM(event, method); From 04fca16420489708332d52d0bdeb433356d8b7c2 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 22 Nov 2019 15:36:42 +0000 Subject: [PATCH 32/67] Stop using Bluebird promise::value --- src/crypto/store/indexeddb-crypto-store.js | 84 +++++++++++++++------- 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/src/crypto/store/indexeddb-crypto-store.js b/src/crypto/store/indexeddb-crypto-store.js index b2c2fe4d0..8b96631f8 100644 --- a/src/crypto/store/indexeddb-crypto-store.js +++ b/src/crypto/store/indexeddb-crypto-store.js @@ -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,9 +400,11 @@ 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 @@ -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 From adac0c353cab2faa78b2c0c51e066935583382a7 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 22 Nov 2019 15:56:06 +0000 Subject: [PATCH 33/67] 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. --- src/client.js | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/client.js b/src/client.js index 2a7654bfc..5803e6807 100644 --- a/src/client.js +++ b/src/client.js @@ -4644,8 +4644,11 @@ function setupCallEventHandler(client) { // This happens quite often, eg. replaying sync from storage, catchup sync // after loading and after we've been offline for a bit. let callEventBuffer = []; - function onSync(state) { - if (state === "SYNCING") { + 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 // inspect the buffer and mark all calls which have been answered // or hung up before passing them to the call event handler. @@ -4670,20 +4673,31 @@ function setupCallEventHandler(client) { callEventBuffer = []; } } - client.on("sync", onSync); + 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; + // 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); + } + + 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(e); + } + }); } - // queue up for processing once all events from this sync have been - // processed (see above). - callEventBuffer.push(event); } client.on("event", onEvent); From d8337d703d61ad9300da763cf4e1f2a579366828 Mon Sep 17 00:00:00 2001 From: David Baker Date: Fri, 22 Nov 2019 15:59:36 +0000 Subject: [PATCH 34/67] Use the right variable name --- src/client.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.js b/src/client.js index 5803e6807..c62c8fca0 100644 --- a/src/client.js +++ b/src/client.js @@ -4694,7 +4694,7 @@ function setupCallEventHandler(client) { } else { // This one wasn't buffered so just run the event handler for it // straight away - callEventHandler(e); + callEventHandler(event); } }); } From 51898cffe8e84714b988d494aea6d4e117e49cf1 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 22 Nov 2019 17:31:48 +0100 Subject: [PATCH 35/67] add comments for timeout constants --- src/crypto/index.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/crypto/index.js b/src/crypto/index.js index 496aca155..78cfdf576 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -65,7 +65,14 @@ 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() { From 6952db67625f8e1af7d5055505f75a0c8e960a75 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 22 Nov 2019 17:32:37 +0100 Subject: [PATCH 36/67] no need to filter here anymore when listening for timeline, also remove obsolete docs --- src/crypto/index.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/crypto/index.js b/src/crypto/index.js index 78cfdf576..c987d03cc 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -930,11 +930,8 @@ Crypto.prototype.registerEventHandlers = function(eventEmitter) { crypto._onToDeviceEvent(event); }); - // only sync timeline events, not events when backpaginating, loading, ... eventEmitter.on("Room.timeline", function(event) { - if (event.getRoomId()) { - crypto._onTimelineEvent(event); - } + crypto._onTimelineEvent(event); }); eventEmitter.on("Event.decrypted", function(event) { From 5e0ba9971c3ea6f554ebd8a62765292ae2ba27e0 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 23 Nov 2019 12:18:39 +0000 Subject: [PATCH 37/67] nothing works anymore :(( --- spec/integ/matrix-client-crypto.spec.js | 15 ++--- .../matrix-client-event-timeline.spec.js | 47 +++++++------- spec/integ/matrix-client-syncing.spec.js | 14 ++--- src/client.js | 34 +++++----- .../store/indexeddb-crypto-store-backend.js | 62 +++++++++---------- 5 files changed, 86 insertions(+), 86 deletions(-) diff --git a/spec/integ/matrix-client-crypto.spec.js b/spec/integ/matrix-client-crypto.spec.js index fe5f63eac..284ff2ab2 100644 --- a/spec/integ/matrix-client-crypto.spec.js +++ b/spec/integ/matrix-client-crypto.spec.js @@ -279,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() { diff --git a/spec/integ/matrix-client-event-timeline.spec.js b/spec/integ/matrix-client-event-timeline.spec.js index 96b28e58f..86436c27d 100644 --- a/spec/integ/matrix-client-event-timeline.spec.js +++ b/spec/integ/matrix-client-event-timeline.spec.js @@ -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, ]); } @@ -343,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, ]); }); diff --git a/spec/integ/matrix-client-syncing.spec.js b/spec/integ/matrix-client-syncing.spec.js index 1294b6a5d..f015943c7 100644 --- a/spec/integ/matrix-client-syncing.spec.js +++ b/spec/integ/matrix-client-syncing.spec.js @@ -691,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(); @@ -707,7 +707,7 @@ describe("MatrixClient syncing", function() { // flush the syncs return httpBackend.flushAllExpected(); }), - defer.promise, + prom, ]); }); diff --git a/src/client.js b/src/client.js index 2a7654bfc..0624211b5 100644 --- a/src/client.js +++ b/src/client.js @@ -3886,26 +3886,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; } }; diff --git a/src/crypto/store/indexeddb-crypto-store-backend.js b/src/crypto/store/indexeddb-crypto-store-backend.js index 98c5d8945..ede785d00 100644 --- a/src/crypto/store/indexeddb-crypto-store-backend.js +++ b/src/crypto/store/indexeddb-crypto-store-backend.js @@ -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; } /** From 3901a381cc18871b2e3551f3f39f6923f4978a2f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 25 Nov 2019 11:18:32 +0000 Subject: [PATCH 38/67] replace another couple of deferreds --- src/client.js | 123 ++++++++++++++++++++++++++------------------------ 1 file changed, 63 insertions(+), 60 deletions(-) diff --git a/src/client.js b/src/client.js index 0624211b5..679b34d53 100644 --- a/src/client.js +++ b/src/client.js @@ -1872,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; }; /** @@ -3214,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) - 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, 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; }; /** @@ -4862,18 +4865,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) { From bd8f8ef28dada37ec24ac16499f7ba6531227e92 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 25 Nov 2019 11:28:09 +0000 Subject: [PATCH 39/67] Replace yet more deferreds --- src/client.js | 2 +- src/store/indexeddb-remote-backend.js | 3 ++- src/utils.js | 13 +++++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/client.js b/src/client.js index 679b34d53..9ebdfd2d6 100644 --- a/src/client.js +++ b/src/client.js @@ -3870,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, { diff --git a/src/store/indexeddb-remote-backend.js b/src/store/indexeddb-remote-backend.js index 920739b6e..270bef961 100644 --- a/src/store/indexeddb-remote-backend.js +++ b/src/store/indexeddb-remote-backend.js @@ -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; diff --git a/src/utils.js b/src/utils.js index 4bea67129..f4887ac32 100644 --- a/src/utils.js +++ b/src/utils.js @@ -714,3 +714,16 @@ module.exports.ensureNoTrailingSlash = function(url) { module.exports.sleep = (ms, value) => new Promise((resolve => { setTimeout(resolve, ms, value); })); + +// Returns a Deferred +module.exports.defer = () => { + let resolve; + let reject; + + const promise = new Promise((_resolve, _reject) => { + resolve = _resolve; + reject = _reject; + }); + + return {resolve, reject, promise}; +}; From 7fb807919ce5e9aa3db4482e9cf24e802326f6de Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 25 Nov 2019 12:27:12 +0000 Subject: [PATCH 40/67] Stop using bluebird .returns and .spread --- spec/integ/matrix-client-crypto.spec.js | 8 ++++---- src/crypto/algorithms/olm.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/integ/matrix-client-crypto.spec.js b/spec/integ/matrix-client-crypto.spec.js index 284ff2ab2..d74009177 100644 --- a/spec/integ/matrix-client-crypto.spec.js +++ b/spec/integ/matrix-client-crypto.spec.js @@ -203,7 +203,7 @@ function aliSendsFirstMessage() { expectAliQueryKeys() .then(expectAliClaimKeys) .then(expectAliSendMessageRequest), - ]).spread(function(_, ciphertext) { + ]).then(function([_, ciphertext]) { return ciphertext; }); } @@ -218,7 +218,7 @@ function aliSendsMessage() { return Promise.all([ sendMessage(aliTestClient.client), expectAliSendMessageRequest(), - ]).spread(function(_, ciphertext) { + ]).then(function([_, ciphertext]) { return ciphertext; }); } @@ -234,7 +234,7 @@ function bobSendsReplyMessage() { sendMessage(bobTestClient.client), expectBobQueryKeys() .then(expectBobSendMessageRequest), - ]).spread(function(_, ciphertext) { + ]).then(function([_, ciphertext]) { return ciphertext; }); } @@ -492,7 +492,7 @@ 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([]); diff --git a/src/crypto/algorithms/olm.js b/src/crypto/algorithms/olm.js index f233e8f9f..93d651d49 100644 --- a/src/crypto/algorithms/olm.js +++ b/src/crypto/algorithms/olm.js @@ -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); }; /** From 295010893ddca4b0b9d526a68ab6c4cafb90219a Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 25 Nov 2019 13:10:04 +0000 Subject: [PATCH 41/67] Prepare changelog for v2.4.4 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 452742844..4afc35da8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Changes in [2.4.4](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.4) (2019-11-25) +================================================================================================ +[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.4-rc.1...v2.4.4) + + * No changes since rc.1 + Changes in [2.4.4-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v2.4.4-rc.1) (2019-11-20) ========================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v2.4.3...v2.4.4-rc.1) From c30a8b5a291eb80dac699a5f762740d7338ad82c Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 25 Nov 2019 13:10:04 +0000 Subject: [PATCH 42/67] v2.4.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0c9778cfd..ff9404d2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-js-sdk", - "version": "2.4.4-rc.1", + "version": "2.4.4", "description": "Matrix Client-Server SDK for Javascript", "main": "index.js", "scripts": { From 057303d57c969c91855b9fb28218026082e03775 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Mon, 25 Nov 2019 13:26:10 +0000 Subject: [PATCH 43/67] s/beforeEach/beforeAll/ for Olm.init() and cleanup sas.spec.js --- spec/unit/crypto.spec.js | 4 ++-- spec/unit/crypto/algorithms/megolm.spec.js | 6 ++++-- spec/unit/crypto/algorithms/olm.spec.js | 6 ++++-- spec/unit/crypto/backup.spec.js | 5 ++++- spec/unit/crypto/cross-signing.spec.js | 4 ++-- spec/unit/crypto/secrets.spec.js | 4 ++-- spec/unit/crypto/verification/qr_code.spec.js | 4 ++-- spec/unit/crypto/verification/request.spec.js | 4 ++-- spec/unit/crypto/verification/sas.spec.js | 10 ++++++++-- 9 files changed, 30 insertions(+), 17 deletions(-) diff --git a/spec/unit/crypto.spec.js b/spec/unit/crypto.spec.js index acbc08731..67ed8db19 100644 --- a/spec/unit/crypto.spec.js +++ b/spec/unit/crypto.spec.js @@ -25,8 +25,8 @@ describe("Crypto", function() { return; } - beforeEach(function(done) { - Olm.init().then(done); + beforeAll(function() { + return Olm.init(); }); it("Crypto exposes the correct olm library version", function() { diff --git a/spec/unit/crypto/algorithms/megolm.spec.js b/spec/unit/crypto/algorithms/megolm.spec.js index eae11da59..ad5e7f20a 100644 --- a/spec/unit/crypto/algorithms/megolm.spec.js +++ b/spec/unit/crypto/algorithms/megolm.spec.js @@ -25,14 +25,16 @@ describe("MegolmDecryption", function() { return; } + beforeAll(function() { + return Olm.init(); + }); + let megolmDecryption; let mockOlmLib; let mockCrypto; let mockBaseApis; beforeEach(async function() { - await Olm.init(); - mockCrypto = testUtils.mock(Crypto, 'Crypto'); mockBaseApis = {}; diff --git a/spec/unit/crypto/algorithms/olm.spec.js b/spec/unit/crypto/algorithms/olm.spec.js index 1b26a6d22..04bd0c322 100644 --- a/spec/unit/crypto/algorithms/olm.spec.js +++ b/spec/unit/crypto/algorithms/olm.spec.js @@ -48,12 +48,14 @@ describe("OlmDecryption", function() { return; } + beforeAll(function() { + return global.Olm.init(); + }); + let aliceOlmDevice; let bobOlmDevice; beforeEach(async function() { - await global.Olm.init(); - aliceOlmDevice = makeOlmDevice(); bobOlmDevice = makeOlmDevice(); await aliceOlmDevice.init(); diff --git a/spec/unit/crypto/backup.spec.js b/spec/unit/crypto/backup.spec.js index c13287f22..7413ee0da 100644 --- a/spec/unit/crypto/backup.spec.js +++ b/spec/unit/crypto/backup.spec.js @@ -128,6 +128,10 @@ describe("MegolmBackup", function() { return; } + beforeAll(function() { + return Olm.init(); + }); + let olmDevice; let mockOlmLib; let mockCrypto; @@ -136,7 +140,6 @@ describe("MegolmBackup", function() { let cryptoStore; let megolmDecryption; beforeEach(async function() { - await Olm.init(); mockCrypto = testUtils.mock(Crypto, 'Crypto'); mockCrypto.backupKey = new Olm.PkEncryption(); mockCrypto.backupKey.set_recipient_key( diff --git a/spec/unit/crypto/cross-signing.spec.js b/spec/unit/crypto/cross-signing.spec.js index 2023bc970..06840b74a 100644 --- a/spec/unit/crypto/cross-signing.spec.js +++ b/spec/unit/crypto/cross-signing.spec.js @@ -55,8 +55,8 @@ 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() { diff --git a/spec/unit/crypto/secrets.spec.js b/spec/unit/crypto/secrets.spec.js index 0a348e937..845f756d3 100644 --- a/spec/unit/crypto/secrets.spec.js +++ b/spec/unit/crypto/secrets.spec.js @@ -40,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() { diff --git a/spec/unit/crypto/verification/qr_code.spec.js b/spec/unit/crypto/verification/qr_code.spec.js index 5a1507729..b59bddb72 100644 --- a/spec/unit/crypto/verification/qr_code.spec.js +++ b/spec/unit/crypto/verification/qr_code.spec.js @@ -33,8 +33,8 @@ describe("QR code verification", function() { return; } - beforeEach(async function() { - await Olm.init(); + beforeAll(function() { + return Olm.init(); }); describe("showing", function() { diff --git a/spec/unit/crypto/verification/request.spec.js b/spec/unit/crypto/verification/request.spec.js index 761edc8b7..4fb103457 100644 --- a/spec/unit/crypto/verification/request.spec.js +++ b/spec/unit/crypto/verification/request.spec.js @@ -35,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() { diff --git a/spec/unit/crypto/verification/sas.spec.js b/spec/unit/crypto/verification/sas.spec.js index d5d5c1a9f..bf41fefa8 100644 --- a/spec/unit/crypto/verification/sas.spec.js +++ b/spec/unit/crypto/verification/sas.spec.js @@ -45,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() { @@ -169,6 +169,12 @@ describe("SAS verification", function() { } }); }); + afterEach(async function() { + await Promise.all([ + alice.stop(), + bob.stop(), + ]); + }); it("should verify a key", async function() { let macMethod; From aa37f697bf129dd2d21edc4f1a44c73bf1874edd Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 25 Nov 2019 16:35:27 -0700 Subject: [PATCH 44/67] 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. --- src/pushprocessor.js | 14 +++++++------- src/utils.js | 4 ++++ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/pushprocessor.js b/src/pushprocessor.js index 0cf05cacf..f3befd2c7 100644 --- a/src/pushprocessor.js +++ b/src/pushprocessor.js @@ -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 (isNullOrUndefined(val) || 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; }; diff --git a/src/utils.js b/src/utils.js index 4bea67129..e3ca7dd81 100644 --- a/src/utils.js +++ b/src/utils.js @@ -714,3 +714,7 @@ module.exports.ensureNoTrailingSlash = function(url) { module.exports.sleep = (ms, value) => new Promise((resolve => { setTimeout(resolve, ms, value); })); + +module.exports.isNullOrUndefined = function(val) { + return val === null || val === undefined; +}; From 2215087f96a150383f95703c9f505d6bf8be73c6 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 26 Nov 2019 01:17:12 +0000 Subject: [PATCH 45/67] expand e2ee logging to better debug UISIs --- src/client.js | 6 +++--- src/crypto/OlmDevice.js | 12 +++++++----- src/crypto/algorithms/megolm.js | 23 ++++++++++++----------- src/crypto/index.js | 2 ++ src/crypto/olmlib.js | 4 ++-- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/client.js b/src/client.js index 6fc6a3223..820404c50 100644 --- a/src/client.js +++ b/src/client.js @@ -73,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; @@ -1626,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); } } @@ -4705,7 +4705,7 @@ function setupCallEventHandler(client) { 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) { diff --git a/src/crypto/OlmDevice.js b/src/crypto/OlmDevice.js index 7060074a7..6bbdfda84 100644 --- a/src/crypto/OlmDevice.js +++ b/src/crypto/OlmDevice.js @@ -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) { @@ -596,7 +596,7 @@ OlmDevice.prototype.encryptMessage = async function( this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => { const sessionDesc = sessionInfo.session.describe(); console.log( - "Session ID " + sessionId + " to " + + "encryptMessage: Olm Session ID " + sessionId + " to " + theirDeviceIdentityKey + ": " + sessionDesc, ); res = sessionInfo.session.encrypt(payloadString); @@ -628,7 +628,7 @@ OlmDevice.prototype.decryptMessage = async function( this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => { const sessionDesc = sessionInfo.session.describe(); console.log( - "Session ID " + sessionId + " to " + + "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; + console.log(`encrypting msg with megolm session ${sessionId}`); + checkPayloadLength(payloadString); return this._getOutboundGroupSession(sessionId, function(session) { @@ -886,7 +888,7 @@ 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; } } diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index 4262c2cee..f6fe7afc0 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -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,7 @@ 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 +279,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 +441,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 ID " + 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 ID " + 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 +467,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; } @@ -514,7 +515,7 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function( }, }); logger.debug( - `Re-shared key for session ${sessionId} with ${userId}:${device.deviceId}`, + `Re-shared key for megolm session ${sessionId} with ${userId}:${device.deviceId}`, ); }; @@ -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. diff --git a/src/crypto/index.js b/src/crypto/index.js index 20ec1a2dd..989117bf9 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -2296,6 +2296,8 @@ Crypto.prototype._getTrackedE2eRooms = function() { Crypto.prototype._onToDeviceEvent = function(event) { try { + console.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); diff --git a/src/crypto/olmlib.js b/src/crypto/olmlib.js index 93a492e26..4af8e035d 100644 --- a/src/crypto/olmlib.js +++ b/src/crypto/olmlib.js @@ -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; } From 191695da5a8c4d2ad3058b2c0b23c9e9fb91b97d Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 26 Nov 2019 01:41:59 +0000 Subject: [PATCH 46/67] lint --- src/crypto/OlmDevice.js | 4 +++- src/crypto/algorithms/megolm.js | 14 +++++++------- src/crypto/index.js | 3 ++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/crypto/OlmDevice.js b/src/crypto/OlmDevice.js index 6bbdfda84..abe0bc90b 100644 --- a/src/crypto/OlmDevice.js +++ b/src/crypto/OlmDevice.js @@ -888,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 megolm session ${sessionId}`); + logger.log( + `Keeping existing megolm session ${sessionId}`, + ); return; } } diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index f6fe7afc0..c9124c401 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -200,7 +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}`); + logger.log(`Started new megolm session ${session.sessionId} ` + + `for room ${self._roomId}`); self._outboundSessions[session.sessionId] = session; } @@ -441,13 +442,13 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function( ) { const obSessionInfo = this._outboundSessions[sessionId]; if (!obSessionInfo) { - logger.debug("megolm 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("megolm 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]; @@ -467,7 +468,7 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function( if (!key) { logger.warn( - "No inbound session key found for megolm " + sessionId + ": not re-sharing keys", + `No inbound session key found for megolm ${sessionId}: not re-sharing keys`, ); return; } @@ -514,9 +515,8 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function( [device.deviceId]: encryptedContent, }, }); - logger.debug( - `Re-shared key for megolm session ${sessionId} with ${userId}:${device.deviceId}`, - ); + logger.debug(`Re-shared key for megolm session ${sessionId} ` + + `with ${userId}:${device.deviceId}`); }; /** diff --git a/src/crypto/index.js b/src/crypto/index.js index 989117bf9..4f29d15af 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -2296,7 +2296,8 @@ Crypto.prototype._getTrackedE2eRooms = function() { Crypto.prototype._onToDeviceEvent = function(event) { try { - console.log(`received to_device ${event.getType()} from: ${event.getSender()} id: ${event.getId()}`); + console.log(`received to_device ${event.getType()} from: ` + + `${event.getSender()} id: ${event.getId()}`); if (event.getType() == "m.room_key" || event.getType() == "m.forwarded_room_key") { From 6e08835496cec5a4551ba8476ee181430d6de2d9 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 26 Nov 2019 01:58:04 +0000 Subject: [PATCH 47/67] log keyshare ID --- src/crypto/algorithms/megolm.js | 6 +++--- src/crypto/store/indexeddb-crypto-store.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index c9124c401..286c29804 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -551,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; diff --git a/src/crypto/store/indexeddb-crypto-store.js b/src/crypto/store/indexeddb-crypto-store.js index b2c2fe4d0..e20edf18b 100644 --- a/src/crypto/store/indexeddb-crypto-store.js +++ b/src/crypto/store/indexeddb-crypto-store.js @@ -389,7 +389,7 @@ export default class IndexedDBCryptoStore { ); } - // Inbound group saessions + // Inbound group sessions /** * Retrieve the end-to-end inbound group session for a given From 3787b6f1c7ba293e9acb09545535bb5fffefb974 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 26 Nov 2019 09:07:23 +0000 Subject: [PATCH 48/67] s/console/logger/ as per review --- src/crypto/OlmDevice.js | 6 +++--- src/crypto/index.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/crypto/OlmDevice.js b/src/crypto/OlmDevice.js index abe0bc90b..b86b4f858 100644 --- a/src/crypto/OlmDevice.js +++ b/src/crypto/OlmDevice.js @@ -595,7 +595,7 @@ OlmDevice.prototype.encryptMessage = async function( (txn) => { this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => { const sessionDesc = sessionInfo.session.describe(); - console.log( + logger.log( "encryptMessage: Olm Session ID " + sessionId + " to " + theirDeviceIdentityKey + ": " + sessionDesc, ); @@ -627,7 +627,7 @@ OlmDevice.prototype.decryptMessage = async function( (txn) => { this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => { const sessionDesc = sessionInfo.session.describe(); - console.log( + logger.log( "decryptMessage: Olm Session ID " + sessionId + " from " + theirDeviceIdentityKey + ": " + sessionDesc, ); @@ -740,7 +740,7 @@ OlmDevice.prototype.createOutboundGroupSession = function() { OlmDevice.prototype.encryptGroupMessage = function(sessionId, payloadString) { const self = this; - console.log(`encrypting msg with megolm session ${sessionId}`); + logger.log(`encrypting msg with megolm session ${sessionId}`); checkPayloadLength(payloadString); diff --git a/src/crypto/index.js b/src/crypto/index.js index 4f29d15af..f53d1fcce 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -1638,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; } @@ -2296,7 +2296,7 @@ Crypto.prototype._getTrackedE2eRooms = function() { Crypto.prototype._onToDeviceEvent = function(event) { try { - console.log(`received to_device ${event.getType()} from: ` + + logger.log(`received to_device ${event.getType()} from: ` + `${event.getSender()} id: ${event.getId()}`); if (event.getType() == "m.room_key" From 1b877118ef233559e518137676c571259cd10aae Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 26 Nov 2019 10:31:04 -0700 Subject: [PATCH 49/67] Only do one type check --- src/pushprocessor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pushprocessor.js b/src/pushprocessor.js index f3befd2c7..3d0fc2db5 100644 --- a/src/pushprocessor.js +++ b/src/pushprocessor.js @@ -268,7 +268,7 @@ function PushProcessor(client) { } const val = valueForDottedKey(cond.key, ev); - if (isNullOrUndefined(val) || typeof val != 'string') { + if (typeof val !== 'string') { return false; } From 5b8b0a8aa34b4b26b0d10aa88ca2cb456f3eb12f Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 26 Nov 2019 18:35:25 +0000 Subject: [PATCH 50/67] log outbound to_device msgs for tracking keyshares --- src/base-apis.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/base-apis.js b/src/base-apis.js index ccb16420e..645ba6e23 100644 --- a/src/base-apis.js +++ b/src/base-apis.js @@ -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); }; From 549656884b61920ac420e21c59ece80983387bef Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 26 Nov 2019 01:17:12 +0000 Subject: [PATCH 51/67] expand e2ee logging to better debug UISIs --- src/client.js | 6 +++--- src/crypto/OlmDevice.js | 12 +++++++----- src/crypto/algorithms/megolm.js | 23 ++++++++++++----------- src/crypto/index.js | 2 ++ src/crypto/olmlib.js | 4 ++-- 5 files changed, 26 insertions(+), 21 deletions(-) diff --git a/src/client.js b/src/client.js index 187944420..ebfec09de 100644 --- a/src/client.js +++ b/src/client.js @@ -72,7 +72,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 +1625,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); } } @@ -4687,7 +4687,7 @@ function setupCallEventHandler(client) { 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) { diff --git a/src/crypto/OlmDevice.js b/src/crypto/OlmDevice.js index 7060074a7..6bbdfda84 100644 --- a/src/crypto/OlmDevice.js +++ b/src/crypto/OlmDevice.js @@ -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) { @@ -596,7 +596,7 @@ OlmDevice.prototype.encryptMessage = async function( this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => { const sessionDesc = sessionInfo.session.describe(); console.log( - "Session ID " + sessionId + " to " + + "encryptMessage: Olm Session ID " + sessionId + " to " + theirDeviceIdentityKey + ": " + sessionDesc, ); res = sessionInfo.session.encrypt(payloadString); @@ -628,7 +628,7 @@ OlmDevice.prototype.decryptMessage = async function( this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => { const sessionDesc = sessionInfo.session.describe(); console.log( - "Session ID " + sessionId + " to " + + "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; + console.log(`encrypting msg with megolm session ${sessionId}`); + checkPayloadLength(payloadString); return this._getOutboundGroupSession(sessionId, function(session) { @@ -886,7 +888,7 @@ 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; } } diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index 4262c2cee..f6fe7afc0 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -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,7 @@ 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 +279,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 +441,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 ID " + 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 ID " + 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 +467,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; } @@ -514,7 +515,7 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function( }, }); logger.debug( - `Re-shared key for session ${sessionId} with ${userId}:${device.deviceId}`, + `Re-shared key for megolm session ${sessionId} with ${userId}:${device.deviceId}`, ); }; @@ -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. diff --git a/src/crypto/index.js b/src/crypto/index.js index 11b450a8e..906d42b25 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -2277,6 +2277,8 @@ Crypto.prototype._getTrackedE2eRooms = function() { Crypto.prototype._onToDeviceEvent = function(event) { try { + console.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); diff --git a/src/crypto/olmlib.js b/src/crypto/olmlib.js index 93a492e26..4af8e035d 100644 --- a/src/crypto/olmlib.js +++ b/src/crypto/olmlib.js @@ -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; } From 8c72fd104e627de8a9ca0ab77e543802c1c8bc0c Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 26 Nov 2019 01:41:59 +0000 Subject: [PATCH 52/67] lint --- src/crypto/OlmDevice.js | 4 +++- src/crypto/algorithms/megolm.js | 14 +++++++------- src/crypto/index.js | 3 ++- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/crypto/OlmDevice.js b/src/crypto/OlmDevice.js index 6bbdfda84..abe0bc90b 100644 --- a/src/crypto/OlmDevice.js +++ b/src/crypto/OlmDevice.js @@ -888,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 megolm session ${sessionId}`); + logger.log( + `Keeping existing megolm session ${sessionId}`, + ); return; } } diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index f6fe7afc0..c9124c401 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -200,7 +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}`); + logger.log(`Started new megolm session ${session.sessionId} ` + + `for room ${self._roomId}`); self._outboundSessions[session.sessionId] = session; } @@ -441,13 +442,13 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function( ) { const obSessionInfo = this._outboundSessions[sessionId]; if (!obSessionInfo) { - logger.debug("megolm 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("megolm 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]; @@ -467,7 +468,7 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function( if (!key) { logger.warn( - "No inbound session key found for megolm " + sessionId + ": not re-sharing keys", + `No inbound session key found for megolm ${sessionId}: not re-sharing keys`, ); return; } @@ -514,9 +515,8 @@ MegolmEncryption.prototype.reshareKeyWithDevice = async function( [device.deviceId]: encryptedContent, }, }); - logger.debug( - `Re-shared key for megolm session ${sessionId} with ${userId}:${device.deviceId}`, - ); + logger.debug(`Re-shared key for megolm session ${sessionId} ` + + `with ${userId}:${device.deviceId}`); }; /** diff --git a/src/crypto/index.js b/src/crypto/index.js index 906d42b25..1de64157b 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -2277,7 +2277,8 @@ Crypto.prototype._getTrackedE2eRooms = function() { Crypto.prototype._onToDeviceEvent = function(event) { try { - console.log(`received to_device ${event.getType()} from: ${event.getSender()} id: ${event.getId()}`); + console.log(`received to_device ${event.getType()} from: ` + + `${event.getSender()} id: ${event.getId()}`); if (event.getType() == "m.room_key" || event.getType() == "m.forwarded_room_key") { From 77f882f45ab4be9b2b70546f71accabd629b629e Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 26 Nov 2019 01:58:04 +0000 Subject: [PATCH 53/67] log keyshare ID --- src/crypto/algorithms/megolm.js | 6 +++--- src/crypto/store/indexeddb-crypto-store.js | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/crypto/algorithms/megolm.js b/src/crypto/algorithms/megolm.js index c9124c401..286c29804 100644 --- a/src/crypto/algorithms/megolm.js +++ b/src/crypto/algorithms/megolm.js @@ -551,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; diff --git a/src/crypto/store/indexeddb-crypto-store.js b/src/crypto/store/indexeddb-crypto-store.js index b2c2fe4d0..e20edf18b 100644 --- a/src/crypto/store/indexeddb-crypto-store.js +++ b/src/crypto/store/indexeddb-crypto-store.js @@ -389,7 +389,7 @@ export default class IndexedDBCryptoStore { ); } - // Inbound group saessions + // Inbound group sessions /** * Retrieve the end-to-end inbound group session for a given From 46f8251e941687d9b8aa6b808cd4a17d4b6b33d0 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 26 Nov 2019 09:07:23 +0000 Subject: [PATCH 54/67] s/console/logger/ as per review --- src/crypto/OlmDevice.js | 6 +++--- src/crypto/index.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/crypto/OlmDevice.js b/src/crypto/OlmDevice.js index abe0bc90b..b86b4f858 100644 --- a/src/crypto/OlmDevice.js +++ b/src/crypto/OlmDevice.js @@ -595,7 +595,7 @@ OlmDevice.prototype.encryptMessage = async function( (txn) => { this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => { const sessionDesc = sessionInfo.session.describe(); - console.log( + logger.log( "encryptMessage: Olm Session ID " + sessionId + " to " + theirDeviceIdentityKey + ": " + sessionDesc, ); @@ -627,7 +627,7 @@ OlmDevice.prototype.decryptMessage = async function( (txn) => { this._getSession(theirDeviceIdentityKey, sessionId, txn, (sessionInfo) => { const sessionDesc = sessionInfo.session.describe(); - console.log( + logger.log( "decryptMessage: Olm Session ID " + sessionId + " from " + theirDeviceIdentityKey + ": " + sessionDesc, ); @@ -740,7 +740,7 @@ OlmDevice.prototype.createOutboundGroupSession = function() { OlmDevice.prototype.encryptGroupMessage = function(sessionId, payloadString) { const self = this; - console.log(`encrypting msg with megolm session ${sessionId}`); + logger.log(`encrypting msg with megolm session ${sessionId}`); checkPayloadLength(payloadString); diff --git a/src/crypto/index.js b/src/crypto/index.js index 1de64157b..099751b49 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -1619,7 +1619,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; } @@ -2277,7 +2277,7 @@ Crypto.prototype._getTrackedE2eRooms = function() { Crypto.prototype._onToDeviceEvent = function(event) { try { - console.log(`received to_device ${event.getType()} from: ` + + logger.log(`received to_device ${event.getType()} from: ` + `${event.getSender()} id: ${event.getId()}`); if (event.getType() == "m.room_key" From 01a46ad880d19a83fd60500acc5bb5060bb7bfb6 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Tue, 26 Nov 2019 18:35:25 +0000 Subject: [PATCH 55/67] log outbound to_device msgs for tracking keyshares --- src/base-apis.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/base-apis.js b/src/base-apis.js index ccb16420e..645ba6e23 100644 --- a/src/base-apis.js +++ b/src/base-apis.js @@ -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); }; From 6b38868de6ea7b4786e9b742b929f6cd265cfb97 Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Thu, 31 Oct 2019 17:58:14 +0000 Subject: [PATCH 56/67] 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 --- src/autodiscovery.js | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/autodiscovery.js b/src/autodiscovery.js index df52b368b..c8dc8c661 100644 --- a/src/autodiscovery.js +++ b/src/autodiscovery.js @@ -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, }, From 396db30fbf8cbd02028ebe595e5669eb3d87c7ee Mon Sep 17 00:00:00 2001 From: "J. Ryan Stinnett" Date: Fri, 1 Nov 2019 14:10:16 +0000 Subject: [PATCH 57/67] Update tests --- spec/unit/autodiscovery.spec.js | 40 ++++++++++++++++----------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/spec/unit/autodiscovery.spec.js b/spec/unit/autodiscovery.spec.js index 6d4e5a3e9..77f0248fb 100644 --- a/spec/unit/autodiscovery.spec.js +++ b/spec/unit/autodiscovery.spec.js @@ -416,8 +416,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 +438,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 +456,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 +478,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 +496,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 +519,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 +537,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 +560,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", }, From 18749c580e26a230ed78e3013e14fc99ca640f6b Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 26 Nov 2019 15:06:56 -0700 Subject: [PATCH 58/67] 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. --- spec/unit/crypto.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/unit/crypto.spec.js b/spec/unit/crypto.spec.js index 67ed8db19..55acf8b04 100644 --- a/spec/unit/crypto.spec.js +++ b/spec/unit/crypto.spec.js @@ -110,6 +110,7 @@ describe("Crypto", function() { }); fakeEmitter.emit('toDeviceEvent', { + getId: jest.fn().mockReturnValue("$wedged"), getType: jest.fn().mockReturnValue('m.room.message'), getContent: jest.fn().mockReturnValue({ msgtype: 'm.bad.encrypted', From fd73c3fb3af4e1389e35d122e6becd9eb78bbc15 Mon Sep 17 00:00:00 2001 From: Matthew Hodgson Date: Wed, 27 Nov 2019 01:19:17 +0000 Subject: [PATCH 59/67] fix bogus logline --- src/crypto/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/crypto/index.js b/src/crypto/index.js index d749d1d3f..5eeeb6145 100644 --- a/src/crypto/index.js +++ b/src/crypto/index.js @@ -2294,8 +2294,7 @@ Crypto.prototype._getTrackedE2eRooms = function() { Crypto.prototype._onToDeviceEvent = function(event) { try { - logger.log(`received to_device ${event.getType()} from: ` + - `${event.getSender()} id: ${event.getId()}`); + logger.log(`received to_device ${event.getType()} from: ${event.getSender()}`); if (event.getType() == "m.room_key" || event.getType() == "m.forwarded_room_key") { From 7ad50211470d717e920a2dab8d1604cea33d436e Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 26 Nov 2019 23:24:37 -0700 Subject: [PATCH 60/67] 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 --- spec/unit/crypto/verification/sas.spec.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/unit/crypto/verification/sas.spec.js b/spec/unit/crypto/verification/sas.spec.js index bf41fefa8..8ea72cf87 100644 --- a/spec/unit/crypto/verification/sas.spec.js +++ b/spec/unit/crypto/verification/sas.spec.js @@ -64,7 +64,7 @@ describe("SAS verification", function() { sas.cancel(); }); - describe("verification", function() { + describe("verification", () => { let alice; let bob; let aliceSasEvent; @@ -72,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"}, @@ -113,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(); }; @@ -169,22 +169,22 @@ describe("SAS verification", function() { } }); }); - afterEach(async 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, { From e0c90ec9e3b1250578b4932aed3fc6f88871bacf Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Tue, 26 Nov 2019 23:29:06 -0700 Subject: [PATCH 61/67] Fix test flakes in SAS verification with old MAC This has similar fixes to 7ad50211470d717e920a2dab8d1604cea33d436e Part of https://github.com/vector-im/riot-web/issues/11520 --- spec/unit/crypto/verification/sas.spec.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/spec/unit/crypto/verification/sas.spec.js b/spec/unit/crypto/verification/sas.spec.js index 8ea72cf87..d66967e9e 100644 --- a/spec/unit/crypto/verification/sas.spec.js +++ b/spec/unit/crypto/verification/sas.spec.js @@ -219,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 @@ -234,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, { @@ -274,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, {}, ); From bf1bec9c6c618dc57666ebccdeb3dbc30fee7206 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 27 Nov 2019 10:17:54 +0000 Subject: [PATCH 62/67] Prepare changelog for v2.4.5 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4afc35da8..cc0ab61ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +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) From c8ab82010a717f19fdeaae743d28c0655d57fbce Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 27 Nov 2019 10:17:54 +0000 Subject: [PATCH 63/67] v2.4.5 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ff9404d2a..49b2e55d6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-js-sdk", - "version": "2.4.4", + "version": "2.4.5", "description": "Matrix Client-Server SDK for Javascript", "main": "index.js", "scripts": { From aee9442e52ad08e73dd8d1fb206958a303f2137a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 27 Nov 2019 19:18:54 -0700 Subject: [PATCH 64/67] 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. --- spec/unit/crypto/verification/sas.spec.js | 129 +++++++++++----------- 1 file changed, 65 insertions(+), 64 deletions(-) diff --git a/spec/unit/crypto/verification/sas.spec.js b/spec/unit/crypto/verification/sas.spec.js index d66967e9e..e56a63bbe 100644 --- a/spec/unit/crypto/verification/sas.spec.js +++ b/spec/unit/crypto/verification/sas.spec.js @@ -275,70 +275,71 @@ describe("SAS verification", function() { expect(aliceDevice.isVerified()).toBeTruthy(); }); - it("should verify a cross-signing key", async () => { - alice.httpBackend.when('POST', '/keys/device_signing/upload').respond( - 200, {}, - ); - alice.httpBackend.when('POST', '/keys/signatures/upload').respond(200, {}); - alice.httpBackend.flush(undefined, 2); - await alice.client.resetCrossSigningKeys(); - bob.httpBackend.when('POST', '/keys/device_signing/upload').respond(200, {}); - bob.httpBackend.when('POST', '/keys/signatures/upload').respond(200, {}); - bob.httpBackend.flush(undefined, 2); - - await bob.client.resetCrossSigningKeys(); - - bob.client._crypto._deviceList.storeCrossSigningForUser( - "@alice:example.com", { - keys: alice.client._crypto._crossSigningInfo.keys, - }, - ); - - 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); - return verifier.verify(); - }), - ]); - - await alice.httpBackend.flush(undefined, 1); - console.log("alice reqs flushed"); - - await verifyProm; - - const bobDeviceTrust = alice.client.checkDeviceTrust( - "@bob:example.com", "Dynabook", - ); - expect(bobDeviceTrust.isLocallyVerified()).toBeTruthy(); - expect(bobDeviceTrust.isCrossSigningVerified()).toBeFalsy(); - - const aliceTrust = bob.client.checkUserTrust("@alice:example.com"); - expect(aliceTrust.isCrossSigningVerified()).toBeTruthy(); - expect(aliceTrust.isTofu()).toBeTruthy(); - - const aliceDeviceTrust = bob.client.checkDeviceTrust( - "@alice:example.com", "Osborne2", - ); - expect(aliceDeviceTrust.isLocallyVerified()).toBeTruthy(); - expect(aliceDeviceTrust.isCrossSigningVerified()).toBeFalsy(); - }); + // TODO: Turn this test back on by fixing it. + // it("should verify a cross-signing key", async () => { + // alice.httpBackend.when('POST', '/keys/device_signing/upload').respond( + // 200, {}, + // ); + // alice.httpBackend.when('POST', '/keys/signatures/upload').respond(200, {}); + // alice.httpBackend.flush(undefined, 2); + // await alice.client.resetCrossSigningKeys(); + // bob.httpBackend.when('POST', '/keys/device_signing/upload').respond(200, {}); + // bob.httpBackend.when('POST', '/keys/signatures/upload').respond(200, {}); + // bob.httpBackend.flush(undefined, 2); + // + // await bob.client.resetCrossSigningKeys(); + // + // bob.client._crypto._deviceList.storeCrossSigningForUser( + // "@alice:example.com", { + // keys: alice.client._crypto._crossSigningInfo.keys, + // }, + // ); + // + // 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); + // return verifier.verify(); + // }), + // ]); + // + // await alice.httpBackend.flush(undefined, 1); + // console.log("alice reqs flushed"); + // + // await verifyProm; + // + // const bobDeviceTrust = alice.client.checkDeviceTrust( + // "@bob:example.com", "Dynabook", + // ); + // expect(bobDeviceTrust.isLocallyVerified()).toBeTruthy(); + // expect(bobDeviceTrust.isCrossSigningVerified()).toBeFalsy(); + // + // const aliceTrust = bob.client.checkUserTrust("@alice:example.com"); + // expect(aliceTrust.isCrossSigningVerified()).toBeTruthy(); + // expect(aliceTrust.isTofu()).toBeTruthy(); + // + // const aliceDeviceTrust = bob.client.checkDeviceTrust( + // "@alice:example.com", "Osborne2", + // ); + // expect(aliceDeviceTrust.isLocallyVerified()).toBeTruthy(); + // expect(aliceDeviceTrust.isCrossSigningVerified()).toBeFalsy(); + // }); }); it("should send a cancellation message on error", async function() { From 79b0a5fadaef012f30b18453608dbca0ba22f8bb Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 27 Nov 2019 19:21:57 -0700 Subject: [PATCH 65/67] Add issue to comment --- spec/unit/crypto/verification/sas.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/unit/crypto/verification/sas.spec.js b/spec/unit/crypto/verification/sas.spec.js index e56a63bbe..368ababcf 100644 --- a/spec/unit/crypto/verification/sas.spec.js +++ b/spec/unit/crypto/verification/sas.spec.js @@ -276,6 +276,7 @@ describe("SAS verification", function() { }); // TODO: Turn this test back on by fixing it. + // See https://github.com/vector-im/riot-web/issues/11545 and related issues. // it("should verify a cross-signing key", async () => { // alice.httpBackend.when('POST', '/keys/device_signing/upload').respond( // 200, {}, From 7392b4de17a359d8dba11047115a983ae4a32ee2 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Wed, 27 Nov 2019 19:23:59 -0700 Subject: [PATCH 66/67] xit instead of comment --- spec/unit/crypto/verification/sas.spec.js | 128 +++++++++++----------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/spec/unit/crypto/verification/sas.spec.js b/spec/unit/crypto/verification/sas.spec.js index 368ababcf..3c9aa666e 100644 --- a/spec/unit/crypto/verification/sas.spec.js +++ b/spec/unit/crypto/verification/sas.spec.js @@ -277,70 +277,70 @@ describe("SAS verification", function() { // TODO: Turn this test back on by fixing it. // See https://github.com/vector-im/riot-web/issues/11545 and related issues. - // it("should verify a cross-signing key", async () => { - // alice.httpBackend.when('POST', '/keys/device_signing/upload').respond( - // 200, {}, - // ); - // alice.httpBackend.when('POST', '/keys/signatures/upload').respond(200, {}); - // alice.httpBackend.flush(undefined, 2); - // await alice.client.resetCrossSigningKeys(); - // bob.httpBackend.when('POST', '/keys/device_signing/upload').respond(200, {}); - // bob.httpBackend.when('POST', '/keys/signatures/upload').respond(200, {}); - // bob.httpBackend.flush(undefined, 2); - // - // await bob.client.resetCrossSigningKeys(); - // - // bob.client._crypto._deviceList.storeCrossSigningForUser( - // "@alice:example.com", { - // keys: alice.client._crypto._crossSigningInfo.keys, - // }, - // ); - // - // 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); - // return verifier.verify(); - // }), - // ]); - // - // await alice.httpBackend.flush(undefined, 1); - // console.log("alice reqs flushed"); - // - // await verifyProm; - // - // const bobDeviceTrust = alice.client.checkDeviceTrust( - // "@bob:example.com", "Dynabook", - // ); - // expect(bobDeviceTrust.isLocallyVerified()).toBeTruthy(); - // expect(bobDeviceTrust.isCrossSigningVerified()).toBeFalsy(); - // - // const aliceTrust = bob.client.checkUserTrust("@alice:example.com"); - // expect(aliceTrust.isCrossSigningVerified()).toBeTruthy(); - // expect(aliceTrust.isTofu()).toBeTruthy(); - // - // const aliceDeviceTrust = bob.client.checkDeviceTrust( - // "@alice:example.com", "Osborne2", - // ); - // expect(aliceDeviceTrust.isLocallyVerified()).toBeTruthy(); - // expect(aliceDeviceTrust.isCrossSigningVerified()).toBeFalsy(); - // }); + xit("should verify a cross-signing key", async () => { + alice.httpBackend.when('POST', '/keys/device_signing/upload').respond( + 200, {}, + ); + alice.httpBackend.when('POST', '/keys/signatures/upload').respond(200, {}); + alice.httpBackend.flush(undefined, 2); + await alice.client.resetCrossSigningKeys(); + bob.httpBackend.when('POST', '/keys/device_signing/upload').respond(200, {}); + bob.httpBackend.when('POST', '/keys/signatures/upload').respond(200, {}); + bob.httpBackend.flush(undefined, 2); + + await bob.client.resetCrossSigningKeys(); + + bob.client._crypto._deviceList.storeCrossSigningForUser( + "@alice:example.com", { + keys: alice.client._crypto._crossSigningInfo.keys, + }, + ); + + 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); + return verifier.verify(); + }), + ]); + + await alice.httpBackend.flush(undefined, 1); + console.log("alice reqs flushed"); + + await verifyProm; + + const bobDeviceTrust = alice.client.checkDeviceTrust( + "@bob:example.com", "Dynabook", + ); + expect(bobDeviceTrust.isLocallyVerified()).toBeTruthy(); + expect(bobDeviceTrust.isCrossSigningVerified()).toBeFalsy(); + + const aliceTrust = bob.client.checkUserTrust("@alice:example.com"); + expect(aliceTrust.isCrossSigningVerified()).toBeTruthy(); + expect(aliceTrust.isTofu()).toBeTruthy(); + + const aliceDeviceTrust = bob.client.checkDeviceTrust( + "@alice:example.com", "Osborne2", + ); + expect(aliceDeviceTrust.isLocallyVerified()).toBeTruthy(); + expect(aliceDeviceTrust.isCrossSigningVerified()).toBeFalsy(); + }); }); it("should send a cancellation message on error", async function() { From 59b25d6837483ff681c2cb349ff8db871c396543 Mon Sep 17 00:00:00 2001 From: Hubert Chathi Date: Thu, 28 Nov 2019 16:53:21 -0500 Subject: [PATCH 67/67] increase timeout on flush to fix failing unit test also remove unused requests --- spec/unit/crypto/verification/sas.spec.js | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/spec/unit/crypto/verification/sas.spec.js b/spec/unit/crypto/verification/sas.spec.js index 3c9aa666e..5511c6652 100644 --- a/spec/unit/crypto/verification/sas.spec.js +++ b/spec/unit/crypto/verification/sas.spec.js @@ -275,9 +275,7 @@ describe("SAS verification", function() { expect(aliceDevice.isVerified()).toBeTruthy(); }); - // TODO: Turn this test back on by fixing it. - // See https://github.com/vector-im/riot-web/issues/11545 and related issues. - xit("should verify a cross-signing key", async () => { + it("should verify a cross-signing key", async () => { alice.httpBackend.when('POST', '/keys/device_signing/upload').respond( 200, {}, ); @@ -296,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(