Compare commits
43 Commits
v8.0.1
...
v8.2.0-rc.1
| Author | SHA1 | Date | |
|---|---|---|---|
| 8b6b16067b | |||
| a2da0de17d | |||
| 93ff3edb6b | |||
| 7c67fd69dd | |||
| ed978f69fb | |||
| 743f2465ea | |||
| 41fffa233a | |||
| e45377166b | |||
| 24939bf0b0 | |||
| 3221be4855 | |||
| 3135f1ed24 | |||
| 1b0834ffb0 | |||
| d79d613cb7 | |||
| d8cc1f7b7a | |||
| d7c8856fdd | |||
| 9d80a332aa | |||
| e14f7b63c7 | |||
| 3bd2880923 | |||
| 2401ad7159 | |||
| 5d95398621 | |||
| 64cdd73b93 | |||
| 48a9236ea8 | |||
| 8b3126e9d8 | |||
| 74d497cd2d | |||
| 5070a5c598 | |||
| 2e30b08e74 | |||
| 8bf63f5f0b | |||
| 11665d18ee | |||
| a8a9fc0c9d | |||
| 098cd1b8d4 | |||
| 3166a4880d | |||
| 9d1c7136cc | |||
| e100943edf | |||
| a6fe4cdf1c | |||
| 69c4496dfe | |||
| a9a4ba33aa | |||
| 7116ad9f58 | |||
| 3d18bdb2aa | |||
| 4c14581606 | |||
| a9c9ec3977 | |||
| 694d1f9631 | |||
| 2b9cfae18a | |||
| 02b37e1219 |
@@ -1,3 +1,45 @@
|
||||
Changes in [8.2.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.2.0-rc.1) (2020-08-26)
|
||||
==========================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.1.0...v8.2.0-rc.1)
|
||||
|
||||
* Add state event check
|
||||
[\#1449](https://github.com/matrix-org/matrix-js-sdk/pull/1449)
|
||||
* Add method to check whether client .well-known has been fetched
|
||||
[\#1444](https://github.com/matrix-org/matrix-js-sdk/pull/1444)
|
||||
* Handle auth errors during cross-signing key upload
|
||||
[\#1443](https://github.com/matrix-org/matrix-js-sdk/pull/1443)
|
||||
* Don't fail if the requested audio output isn't available
|
||||
[\#1448](https://github.com/matrix-org/matrix-js-sdk/pull/1448)
|
||||
* Fix logging failures
|
||||
[\#1447](https://github.com/matrix-org/matrix-js-sdk/pull/1447)
|
||||
* Log the constraints we pass to getUserMedia
|
||||
[\#1446](https://github.com/matrix-org/matrix-js-sdk/pull/1446)
|
||||
* Use SAS emoji data from matrix-doc
|
||||
[\#1440](https://github.com/matrix-org/matrix-js-sdk/pull/1440)
|
||||
|
||||
Changes in [8.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.1.0) (2020-08-17)
|
||||
================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.1.0-rc.1...v8.1.0)
|
||||
|
||||
* No changes since rc.1
|
||||
|
||||
Changes in [8.1.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.1.0-rc.1) (2020-08-13)
|
||||
==========================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.0.1...v8.1.0-rc.1)
|
||||
|
||||
* Update on Promises
|
||||
[\#1438](https://github.com/matrix-org/matrix-js-sdk/pull/1438)
|
||||
* Store and request master cross-signing key
|
||||
[\#1437](https://github.com/matrix-org/matrix-js-sdk/pull/1437)
|
||||
* Filter out non-string display names
|
||||
[\#1433](https://github.com/matrix-org/matrix-js-sdk/pull/1433)
|
||||
* Bump elliptic from 6.5.2 to 6.5.3
|
||||
[\#1427](https://github.com/matrix-org/matrix-js-sdk/pull/1427)
|
||||
* Replace Riot with Element in docs and comments
|
||||
[\#1431](https://github.com/matrix-org/matrix-js-sdk/pull/1431)
|
||||
* Remove leftover bits of TSLint
|
||||
[\#1430](https://github.com/matrix-org/matrix-js-sdk/pull/1430)
|
||||
|
||||
Changes in [8.0.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.0.1) (2020-08-05)
|
||||
================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.0.1-rc.1...v8.0.1)
|
||||
|
||||
@@ -182,10 +182,8 @@ you can pass the result of the promise into it with something like:
|
||||
matrixClient.someMethod(arg1, arg2).nodeify(callback);
|
||||
```
|
||||
|
||||
The main thing to note is that it is an error to discard the result of a
|
||||
promise-returning function, as that will cause exceptions to go unobserved. If
|
||||
you have nothing better to do with the result, just call ``.done()`` on it. See
|
||||
http://documentup.com/kriskowal/q/#the-end for more information.
|
||||
The main thing to note is that it is problematic to discard the result of a
|
||||
promise-returning function, as that will cause exceptions to go unobserved.
|
||||
|
||||
Methods which return a promise show this in their documentation.
|
||||
|
||||
|
||||
+1
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "matrix-js-sdk",
|
||||
"version": "8.0.1",
|
||||
"version": "8.2.0-rc.1",
|
||||
"description": "Matrix Client-Server SDK for Javascript",
|
||||
"scripts": {
|
||||
"prepare": "yarn build",
|
||||
@@ -87,7 +87,6 @@
|
||||
"rimraf": "^3.0.0",
|
||||
"terser": "^4.4.3",
|
||||
"tsify": "^4.0.1",
|
||||
"tslint": "^5.20.1",
|
||||
"typescript": "^3.7.3"
|
||||
},
|
||||
"jest": {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
# npm; typically installed by Node.js
|
||||
# yarn; install via brew (macOS) or similar (https://yarnpkg.com/docs/install/)
|
||||
#
|
||||
# Note: this script is also used to release matrix-react-sdk and riot-web.
|
||||
# Note: this script is also used to release matrix-react-sdk and element-web.
|
||||
|
||||
set -e
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ describe("DeviceList management:", function() {
|
||||
|
||||
it("We should not get confused by out-of-order device query responses",
|
||||
() => {
|
||||
// https://github.com/vector-im/riot-web/issues/3126
|
||||
// https://github.com/vector-im/element-web/issues/3126
|
||||
aliceTestClient.expectKeyQuery({device_keys: {'@alice:localhost': {}}});
|
||||
return aliceTestClient.start().then(() => {
|
||||
aliceTestClient.httpBackend.when('GET', '/sync').respond(
|
||||
@@ -271,7 +271,7 @@ describe("DeviceList management:", function() {
|
||||
});
|
||||
}).timeout(3000);
|
||||
|
||||
// https://github.com/vector-im/riot-web/issues/4983
|
||||
// https://github.com/vector-im/element-web/issues/4983
|
||||
describe("Alice should know she has stale device lists", () => {
|
||||
beforeEach(async function() {
|
||||
await aliceTestClient.start();
|
||||
|
||||
@@ -346,7 +346,7 @@ describe("megolm", function() {
|
||||
});
|
||||
|
||||
it("Alice receives a megolm message before the session keys", function() {
|
||||
// https://github.com/vector-im/riot-web/issues/2273
|
||||
// https://github.com/vector-im/element-web/issues/2273
|
||||
let roomKeyEncrypted;
|
||||
|
||||
return aliceTestClient.start().then(() => {
|
||||
@@ -726,7 +726,7 @@ describe("megolm", function() {
|
||||
});
|
||||
});
|
||||
|
||||
// https://github.com/vector-im/riot-web/issues/2676
|
||||
// https://github.com/vector-im/element-web/issues/2676
|
||||
it("Alice should send to her other devices", function() {
|
||||
// for this test, we make the testOlmAccount be another of Alice's devices.
|
||||
// it ought to get included in messages Alice sends.
|
||||
|
||||
@@ -38,7 +38,7 @@ const testKey = new Uint8Array([
|
||||
]);
|
||||
|
||||
const types = [
|
||||
{ type: "master", shouldCache: false },
|
||||
{ type: "master", shouldCache: true },
|
||||
{ type: "self_signing", shouldCache: true },
|
||||
{ type: "user_signing", shouldCache: true },
|
||||
{ type: "invalid", shouldCache: false },
|
||||
|
||||
@@ -21,6 +21,7 @@ import * as olmlib from "../../../src/crypto/olmlib";
|
||||
import {TestClient} from '../../TestClient';
|
||||
import {HttpResponse, setHttpResponses} from '../../test-utils';
|
||||
import {resetCrossSigningKeys, createSecretStorageKey} from "./crypto-utils";
|
||||
import { MatrixError } from '../../../src/http-api';
|
||||
|
||||
async function makeTestClient(userInfo, options, keys) {
|
||||
if (!keys) keys = {};
|
||||
@@ -77,6 +78,58 @@ describe("Cross Signing", function() {
|
||||
expect(alice.uploadDeviceSigningKeys).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should abort bootstrap if device signing auth fails", async function() {
|
||||
const alice = await makeTestClient(
|
||||
{userId: "@alice:example.com", deviceId: "Osborne2"},
|
||||
);
|
||||
alice.uploadDeviceSigningKeys = async (auth, keys) => {
|
||||
const errorResponse = {
|
||||
session: "sessionId",
|
||||
flows: [
|
||||
{
|
||||
stages: [
|
||||
"m.login.password",
|
||||
],
|
||||
},
|
||||
],
|
||||
params: {},
|
||||
};
|
||||
|
||||
// If we're not just polling for flows, add on error rejecting the
|
||||
// auth attempt.
|
||||
if (auth) {
|
||||
Object.assign(errorResponse, {
|
||||
completed: [],
|
||||
error: "Invalid password",
|
||||
errcode: "M_FORBIDDEN",
|
||||
});
|
||||
}
|
||||
|
||||
const error = new MatrixError(errorResponse);
|
||||
error.httpStatus == 401;
|
||||
throw error;
|
||||
};
|
||||
alice.uploadKeySignatures = async () => {};
|
||||
alice.setAccountData = async () => {};
|
||||
alice.getAccountDataFromServer = async () => { };
|
||||
const authUploadDeviceSigningKeys = async func => await func({});
|
||||
|
||||
// Try bootstrap, expecting `authUploadDeviceSigningKeys` to pass
|
||||
// through failure, stopping before actually applying changes.
|
||||
let bootstrapDidThrow = false;
|
||||
try {
|
||||
await alice.bootstrapSecretStorage({
|
||||
createSecretStorageKey,
|
||||
authUploadDeviceSigningKeys,
|
||||
});
|
||||
} catch (e) {
|
||||
if (e.errcode === "M_FORBIDDEN") {
|
||||
bootstrapDidThrow = true;
|
||||
}
|
||||
}
|
||||
expect(bootstrapDidThrow).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should upload a signature when a user is verified", async function() {
|
||||
const alice = await makeTestClient(
|
||||
{userId: "@alice:example.com", deviceId: "Osborne2"},
|
||||
|
||||
@@ -54,6 +54,7 @@ describe("self-verifications", () => {
|
||||
cacheCallbacks,
|
||||
);
|
||||
_crossSigningInfo.keys = {
|
||||
master: { keys: { X: testKeyPub } },
|
||||
self_signing: { keys: { X: testKeyPub } },
|
||||
user_signing: { keys: { X: testKeyPub } },
|
||||
};
|
||||
@@ -96,9 +97,9 @@ describe("self-verifications", () => {
|
||||
|
||||
const result = await verification.done();
|
||||
|
||||
/* We should request, and store, two cross signing key and the key backup key */
|
||||
expect(cacheCallbacks.storeCrossSigningKeyCache.mock.calls.length).toBe(2);
|
||||
expect(_secretStorage.request.mock.calls.length).toBe(3);
|
||||
/* We should request, and store, 3 cross signing keys and the key backup key */
|
||||
expect(cacheCallbacks.storeCrossSigningKeyCache.mock.calls.length).toBe(3);
|
||||
expect(_secretStorage.request.mock.calls.length).toBe(4);
|
||||
|
||||
expect(cacheCallbacks.storeCrossSigningKeyCache.mock.calls[0][1])
|
||||
.toEqual(testKey);
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ function termsUrlForService(serviceType, baseUrl) {
|
||||
* callback that returns a Promise<String> of an identity access token to supply
|
||||
* with identity requests. If the object is unset, no access token will be
|
||||
* supplied.
|
||||
* See also https://github.com/vector-im/riot-web/issues/10615 which seeks to
|
||||
* See also https://github.com/vector-im/element-web/issues/10615 which seeks to
|
||||
* replace the previous approach of manual access tokens params with this
|
||||
* callback throughout the SDK.
|
||||
*
|
||||
|
||||
+24
-11
@@ -119,7 +119,7 @@ function keyFromRecoverySession(session, decryptionKey) {
|
||||
* callback that returns a Promise<String> of an identity access token to supply
|
||||
* with identity requests. If the object is unset, no access token will be
|
||||
* supplied.
|
||||
* See also https://github.com/vector-im/riot-web/issues/10615 which seeks to
|
||||
* See also https://github.com/vector-im/element-web/issues/10615 which seeks to
|
||||
* replace the previous approach of manual access tokens params with this
|
||||
* callback throughout the SDK.
|
||||
*
|
||||
@@ -357,6 +357,9 @@ export function MatrixClient(opts) {
|
||||
|
||||
this._cachedCapabilities = null; // { capabilities: {}, lastUpdated: timestamp }
|
||||
|
||||
this._clientWellKnown = undefined;
|
||||
this._clientWellKnownPromise = undefined;
|
||||
|
||||
// The SDK doesn't really provide a clean way for events to recalculate the push
|
||||
// actions for themselves, so we have to kinda help them out when they are encrypted.
|
||||
// We do this so that push rules are correctly executed on events in their decrypted
|
||||
@@ -380,7 +383,7 @@ export function MatrixClient(opts) {
|
||||
? !!actions.tweaks.highlight : false;
|
||||
if (oldHighlight !== newHighlight || currentCount > 0) {
|
||||
// TODO: Handle mentions received while the client is offline
|
||||
// See also https://github.com/vector-im/riot-web/issues/9069
|
||||
// See also https://github.com/vector-im/element-web/issues/9069
|
||||
if (!room.hasUserReadEvent(this.getUserId(), event.getId())) {
|
||||
let newCount = currentCount;
|
||||
if (newHighlight && !oldHighlight) newCount++;
|
||||
@@ -398,7 +401,7 @@ export function MatrixClient(opts) {
|
||||
|
||||
// Like above, we have to listen for read receipts from ourselves in order to
|
||||
// correctly handle notification counts on encrypted rooms.
|
||||
// This fixes https://github.com/vector-im/riot-web/issues/9421
|
||||
// This fixes https://github.com/vector-im/element-web/issues/9421
|
||||
this.on("Room.receipt", (event, room) => {
|
||||
if (room && this.isRoomEncrypted(room.roomId)) {
|
||||
// Figure out if we've read something or if it's just informational
|
||||
@@ -4810,20 +4813,23 @@ MatrixClient.prototype.startClient = async function(opts) {
|
||||
};
|
||||
|
||||
MatrixClient.prototype._fetchClientWellKnown = async function() {
|
||||
try {
|
||||
this._clientWellKnown = await AutoDiscovery.getRawClientConfig(this.getDomain());
|
||||
this.emit("WellKnown.client", this._clientWellKnown);
|
||||
} catch (err) {
|
||||
logger.error("Failed to get client well-known", err);
|
||||
this._clientWellKnown = undefined;
|
||||
this.emit("WellKnown.error", err);
|
||||
}
|
||||
// `getRawClientConfig` does not throw or reject on network errors, instead
|
||||
// it absorbs errors and returns `{}`.
|
||||
this._clientWellKnownPromise = AutoDiscovery.getRawClientConfig(
|
||||
this.getDomain(),
|
||||
);
|
||||
this._clientWellKnown = await this._clientWellKnownPromise;
|
||||
this.emit("WellKnown.client", this._clientWellKnown);
|
||||
};
|
||||
|
||||
MatrixClient.prototype.getClientWellKnown = function() {
|
||||
return this._clientWellKnown;
|
||||
};
|
||||
|
||||
MatrixClient.prototype.waitForClientWellKnown = function() {
|
||||
return this._clientWellKnownPromise;
|
||||
};
|
||||
|
||||
/**
|
||||
* store client options with boolean/string/numeric values
|
||||
* to know in the next session what flags the sync data was
|
||||
@@ -5698,6 +5704,13 @@ MatrixClient.prototype.generateClientSecret = function() {
|
||||
* @param {string} data.request_id The ID of the original request.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fires when the client .well-known info is fetched.
|
||||
*
|
||||
* @event module:client~MatrixClient#"WellKnown.client"
|
||||
* @param {object} data The JSON object returned by the server
|
||||
*/
|
||||
|
||||
// EventEmitter JSDocs
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,8 @@ import {logger} from '../logger';
|
||||
import {IndexedDBCryptoStore} from '../crypto/store/indexeddb-crypto-store';
|
||||
import {decryptAES, encryptAES} from './aes';
|
||||
|
||||
const KEY_REQUEST_TIMEOUT_MS = 1000 * 60;
|
||||
|
||||
function publicKeyFromKeyInfo(keyInfo) {
|
||||
// `keys` is an object with { [`ed25519:${pubKey}`]: pubKey }
|
||||
// We assume only a single key, and we want the bare form without type
|
||||
@@ -72,7 +74,7 @@ export class CrossSigningInfo extends EventEmitter {
|
||||
* @returns {Array} An array with [ public key, Olm.PkSigning ]
|
||||
*/
|
||||
async getCrossSigningKey(type, expectedPubkey) {
|
||||
const shouldCache = ["self_signing", "user_signing"].indexOf(type) >= 0;
|
||||
const shouldCache = ["master", "self_signing", "user_signing"].indexOf(type) >= 0;
|
||||
|
||||
if (!this._callbacks.getCrossSigningKey) {
|
||||
throw new Error("No getCrossSigningKey callback supplied");
|
||||
@@ -677,3 +679,96 @@ export function createCryptoStoreCacheCallbacks(store, olmdevice) {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Request cross-signing keys from another device during verification.
|
||||
*
|
||||
* @param {module:base-apis~MatrixBaseApis} baseApis base Matrix API interface
|
||||
* @param {string} userId The user ID being verified
|
||||
* @param {string} deviceId The device ID being verified
|
||||
*/
|
||||
export async function requestKeysDuringVerification(baseApis, userId, deviceId) {
|
||||
// If this is a self-verification, ask the other party for keys
|
||||
if (baseApis.getUserId() !== userId) {
|
||||
return;
|
||||
}
|
||||
console.log("Cross-signing: Self-verification done; requesting keys");
|
||||
// This happens asynchronously, and we're not concerned about waiting for
|
||||
// it. We return here in order to test.
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = baseApis;
|
||||
const original = client._crypto._crossSigningInfo;
|
||||
|
||||
// We already have all of the infrastructure we need to validate and
|
||||
// cache cross-signing keys, so instead of replicating that, here we set
|
||||
// up callbacks that request them from the other device and call
|
||||
// CrossSigningInfo.getCrossSigningKey() to validate/cache
|
||||
const crossSigning = new CrossSigningInfo(
|
||||
original.userId,
|
||||
{ getCrossSigningKey: async (type) => {
|
||||
console.debug("Cross-signing: requesting secret",
|
||||
type, deviceId);
|
||||
const { promise } = client.requestSecret(
|
||||
`m.cross_signing.${type}`, [deviceId],
|
||||
);
|
||||
const result = await promise;
|
||||
const decoded = decodeBase64(result);
|
||||
return Uint8Array.from(decoded);
|
||||
} },
|
||||
original._cacheCallbacks,
|
||||
);
|
||||
crossSigning.keys = original.keys;
|
||||
|
||||
// XXX: get all keys out if we get one key out
|
||||
// https://github.com/vector-im/element-web/issues/12604
|
||||
// then change here to reject on the timeout
|
||||
// Requests can be ignored, so don't wait around forever
|
||||
const timeout = new Promise((resolve, reject) => {
|
||||
setTimeout(
|
||||
resolve,
|
||||
KEY_REQUEST_TIMEOUT_MS,
|
||||
new Error("Timeout"),
|
||||
);
|
||||
});
|
||||
|
||||
// also request and cache the key backup key
|
||||
const backupKeyPromise = new Promise(async resolve => {
|
||||
const cachedKey = await client._crypto.getSessionBackupPrivateKey();
|
||||
if (!cachedKey) {
|
||||
logger.info("No cached backup key found. Requesting...");
|
||||
const secretReq = client.requestSecret(
|
||||
'm.megolm_backup.v1', [deviceId],
|
||||
);
|
||||
const base64Key = await secretReq.promise;
|
||||
logger.info("Got key backup key, decoding...");
|
||||
const decodedKey = decodeBase64(base64Key);
|
||||
logger.info("Decoded backup key, storing...");
|
||||
client._crypto.storeSessionBackupPrivateKey(
|
||||
Uint8Array.from(decodedKey),
|
||||
);
|
||||
logger.info("Backup key stored. Starting backup restore...");
|
||||
const backupInfo = await client.getKeyBackupVersion();
|
||||
// no need to await for this - just let it go in the bg
|
||||
client.restoreKeyBackupWithCache(
|
||||
undefined, undefined, backupInfo,
|
||||
).then(() => {
|
||||
logger.info("Backup restored.");
|
||||
});
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
|
||||
// We call getCrossSigningKey() for its side-effects
|
||||
return Promise.race([
|
||||
Promise.all([
|
||||
crossSigning.getCrossSigningKey("master"),
|
||||
crossSigning.getCrossSigningKey("self_signing"),
|
||||
crossSigning.getCrossSigningKey("user_signing"),
|
||||
backupKeyPromise,
|
||||
]),
|
||||
timeout,
|
||||
]).then(resolve, reject);
|
||||
}).catch((e) => {
|
||||
console.warn("Cross-signing: failure while requesting keys:", e);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -790,7 +790,7 @@ class DeviceListUpdateSerialiser {
|
||||
|
||||
// yield to other things that want to execute in between users, to
|
||||
// avoid wedging the CPU
|
||||
// (https://github.com/vector-im/riot-web/issues/3158)
|
||||
// (https://github.com/vector-im/element-web/issues/3158)
|
||||
//
|
||||
// of course we ought to do this in a web worker or similar, but
|
||||
// this serves as an easy solution for now.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { logger } from "../logger";
|
||||
import {MatrixEvent} from "../models/event";
|
||||
import {EventEmitter} from "events";
|
||||
import {createCryptoStoreCacheCallbacks} from "./CrossSigning";
|
||||
@@ -17,7 +18,7 @@ import {
|
||||
*/
|
||||
export class EncryptionSetupBuilder {
|
||||
/**
|
||||
* @param {Object.<String, MatrixEvent>} accountData pre-existing account data, will only be read, not written.
|
||||
* @param {Object.<String, MatrixEvent>} accountData pre-existing account data, will only be read, not written.
|
||||
* @param {CryptoCallbacks} delegateCryptoCallbacks crypto callbacks to delegate to if the key isn't in cache yet
|
||||
*/
|
||||
constructor(accountData, delegateCryptoCallbacks) {
|
||||
@@ -32,11 +33,17 @@ export class EncryptionSetupBuilder {
|
||||
|
||||
/**
|
||||
* Adds new cross-signing public keys
|
||||
* @param {Object} auth auth dictionary needed to upload the new keys
|
||||
*
|
||||
* @param {function} authUpload Function called to await an interactive auth
|
||||
* flow when uploading device signing keys.
|
||||
* Args:
|
||||
* {function} A function that makes the request requiring auth. Receives
|
||||
* the auth data as an object. Can be called multiple times, first with
|
||||
* an empty authDict, to obtain the flows.
|
||||
* @param {Object} keys the new keys
|
||||
*/
|
||||
addCrossSigningKeys(auth, keys) {
|
||||
this._crossSigningKeys = {auth, keys};
|
||||
addCrossSigningKeys(authUpload, keys) {
|
||||
this._crossSigningKeys = {authUpload, keys};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,12 +120,12 @@ export class EncryptionSetupBuilder {
|
||||
* @return {Promise}
|
||||
*/
|
||||
async persist(crypto) {
|
||||
// store self_signing and user_signing private key in cache
|
||||
// store private keys in cache
|
||||
if (this._crossSigningKeys) {
|
||||
const cacheCallbacks = createCryptoStoreCacheCallbacks(
|
||||
crypto._cryptoStore, crypto._olmDevice);
|
||||
for (const type of ["self_signing", "user_signing"]) {
|
||||
// logger.log(`Cache ${type} cross-signing private key locally`);
|
||||
for (const type of ["master", "self_signing", "user_signing"]) {
|
||||
logger.log(`Cache ${type} cross-signing private key locally`);
|
||||
const privateKey = this.crossSigningCallbacks.privateKeys.get(type);
|
||||
await cacheCallbacks.storeCrossSigningKeyCache(type, privateKey);
|
||||
}
|
||||
@@ -164,25 +171,28 @@ export class EncryptionSetupOperation {
|
||||
*/
|
||||
async apply(crypto) {
|
||||
const baseApis = crypto._baseApis;
|
||||
// set account data
|
||||
if (this._accountData) {
|
||||
for (const [type, content] of this._accountData) {
|
||||
await baseApis.setAccountData(type, content);
|
||||
}
|
||||
}
|
||||
// upload cross-signing keys
|
||||
if (this._crossSigningKeys) {
|
||||
const keys = {};
|
||||
for (const [name, key] of Object.entries(this._crossSigningKeys.keys)) {
|
||||
keys[name + "_key"] = key;
|
||||
}
|
||||
await baseApis.uploadDeviceSigningKeys(
|
||||
this._crossSigningKeys.auth,
|
||||
keys,
|
||||
);
|
||||
|
||||
// We must only call `uploadDeviceSigningKeys` from inside this auth
|
||||
// helper to ensure we properly handle auth errors.
|
||||
await this._crossSigningKeys.authUpload(authDict => {
|
||||
return baseApis.uploadDeviceSigningKeys(authDict, keys);
|
||||
});
|
||||
|
||||
// pass the new keys to the main instance of our own CrossSigningInfo.
|
||||
crypto._crossSigningInfo.setKeys(this._crossSigningKeys.keys);
|
||||
}
|
||||
// set account data
|
||||
if (this._accountData) {
|
||||
for (const [type, content] of this._accountData) {
|
||||
await baseApis.setAccountData(type, content);
|
||||
}
|
||||
}
|
||||
// upload first cross-signing signatures with the new key
|
||||
// (e.g. signing our own device)
|
||||
if (this._keySignatures) {
|
||||
|
||||
@@ -373,6 +373,7 @@ export class SecretStorage extends EventEmitter {
|
||||
const requestId = this._baseApis.makeTxnId();
|
||||
|
||||
const requestControl = this._requests[requestId] = {
|
||||
name,
|
||||
devices,
|
||||
};
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
@@ -536,6 +537,10 @@ export class SecretStorage extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
logger.log(
|
||||
`Successfully received secret ${requestControl.name} ` +
|
||||
`from ${deviceInfo.deviceId}`,
|
||||
);
|
||||
requestControl.resolve(content.secret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1015,7 +1015,7 @@ MegolmEncryption.prototype._getDevicesInRoom = async function(room) {
|
||||
// with them, which means that they will have announced any new devices via
|
||||
// device_lists in their /sync response. This cache should then be maintained
|
||||
// using all the device_lists changes and left fields.
|
||||
// See https://github.com/vector-im/riot-web/issues/2305 for details.
|
||||
// See https://github.com/vector-im/element-web/issues/2305 for details.
|
||||
const devices = await this._crypto.downloadKeys(roomMembers, false);
|
||||
const blocked = {};
|
||||
// remove any blocked devices
|
||||
@@ -1109,7 +1109,7 @@ MegolmDecryption.prototype.decryptEvent = async function(event) {
|
||||
//
|
||||
// then, if the key turns up while decryption is in progress (and
|
||||
// decryption fails), we will schedule a retry.
|
||||
// (fixes https://github.com/vector-im/riot-web/issues/5001)
|
||||
// (fixes https://github.com/vector-im/element-web/issues/5001)
|
||||
this._addEventToPendingList(event);
|
||||
|
||||
let res;
|
||||
|
||||
+37
-16
@@ -413,7 +413,7 @@ Crypto.prototype.createRecoveryKeyFromPassphrase = async function(password) {
|
||||
*
|
||||
* If this function returns false, bootstrapSecretStorage() can be used
|
||||
* to fix things such that it returns true. That is to say, after
|
||||
* bootstrapSecretStorage() completes sucessfully, this function should
|
||||
* bootstrapSecretStorage() completes successfully, this function should
|
||||
* return true.
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
@@ -453,7 +453,8 @@ Crypto.prototype.isCrossSigningReady = async function() {
|
||||
* called to await an interactive auth flow when uploading device signing keys.
|
||||
* Args:
|
||||
* {function} A function that makes the request requiring auth. Receives the
|
||||
* auth data as an object. Can be called multiple times, first with an empty authDict, to obtain the flows.
|
||||
* auth data as an object. Can be called multiple times, first with an empty
|
||||
* authDict, to obtain the flows.
|
||||
* @param {function} [opts.createSecretStorageKey] Optional. Function
|
||||
* called to await a secret storage key creation flow.
|
||||
* Returns:
|
||||
@@ -525,17 +526,9 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
// sign master key with device key
|
||||
await this._signObject(crossSigningInfo.keys.master);
|
||||
|
||||
await authUploadDeviceSigningKeys(authDict => {
|
||||
if (authDict) {
|
||||
builder.addCrossSigningKeys(authDict, crossSigningInfo.keys);
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
// This callback also gets called to obtain the IUA flows,
|
||||
// so do a call to obtain those if we don't have the authDict yet
|
||||
// We should get called again at a later point with the authDict.
|
||||
return this._baseApis.uploadDeviceSigningKeys(null, {});
|
||||
}
|
||||
});
|
||||
// Store auth flow helper function, as we need to call it when uploading
|
||||
// to ensure we handle auth errors properly.
|
||||
builder.addCrossSigningKeys(authUploadDeviceSigningKeys, crossSigningInfo.keys);
|
||||
|
||||
// cross-sign own device
|
||||
const device = this._deviceList.getStoredDevice(this._userId, this._deviceId);
|
||||
@@ -1221,6 +1214,20 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
|
||||
if (oldSelfSigningId !== newCrossSigning.getId("self_signing")) {
|
||||
logger.info("Got new self-signing key", newCrossSigning.getId("self_signing"));
|
||||
|
||||
// Try to cache the self-signing private key as a side-effect
|
||||
let signing = null;
|
||||
try {
|
||||
const ret = await this._crossSigningInfo.getCrossSigningKey(
|
||||
"self_signing", newCrossSigning.getId("self_signing"),
|
||||
);
|
||||
signing = ret[1];
|
||||
logger.info(
|
||||
"Got matching private key from callback for new public self-signing key",
|
||||
);
|
||||
} finally {
|
||||
if (signing) signing.free();
|
||||
}
|
||||
|
||||
const device = this._deviceList.getStoredDevice(this._userId, this._deviceId);
|
||||
const signedDevice = await this._crossSigningInfo.signDevice(
|
||||
this._userId, device,
|
||||
@@ -1229,6 +1236,20 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
|
||||
}
|
||||
if (oldUserSigningId !== newCrossSigning.getId("user_signing")) {
|
||||
logger.info("Got new user-signing key", newCrossSigning.getId("user_signing"));
|
||||
|
||||
// Try to cache the user-signing private key as a side-effect
|
||||
let signing = null;
|
||||
try {
|
||||
const ret = await this._crossSigningInfo.getCrossSigningKey(
|
||||
"user_signing", newCrossSigning.getId("user_signing"),
|
||||
);
|
||||
signing = ret[1];
|
||||
logger.info(
|
||||
"Got matching private key from callback for new public user-signing key",
|
||||
);
|
||||
} finally {
|
||||
if (signing) signing.free();
|
||||
}
|
||||
}
|
||||
|
||||
if (masterChanged) {
|
||||
@@ -1403,7 +1424,7 @@ Crypto.prototype._checkAndStartKeyBackup = async function() {
|
||||
// uploaded to the new backup. This is a bit of a workaround to upload
|
||||
// keys to a new backup in *most* cases, but it won't cover all cases
|
||||
// because we don't remember what backup version we uploaded keys to:
|
||||
// see https://github.com/vector-im/riot-web/issues/14833
|
||||
// see https://github.com/vector-im/element-web/issues/14833
|
||||
await this.scheduleAllGroupSessionsForBackup();
|
||||
} else {
|
||||
logger.log("Backup version " + backupInfo.version + " still current");
|
||||
@@ -2410,7 +2431,7 @@ Crypto.prototype.setRoomEncryption = async function(roomId, config, inhibitDevic
|
||||
|
||||
await this.trackRoomDevices(roomId);
|
||||
// TODO: this flag is only not used from MatrixClient::setRoomEncryption
|
||||
// which is never used (inside riot at least)
|
||||
// which is never used (inside Element at least)
|
||||
// but didn't want to remove it as it technically would
|
||||
// be a breaking change.
|
||||
if (!this.inhibitDeviceQuery) {
|
||||
@@ -2984,7 +3005,7 @@ Crypto.prototype.onSyncCompleted = async function(syncData) {
|
||||
// we don't start uploading one-time keys until we've caught up with
|
||||
// to-device messages, to help us avoid throwing away one-time-keys that we
|
||||
// are about to receive messages for
|
||||
// (https://github.com/vector-im/riot-web/issues/2782).
|
||||
// (https://github.com/vector-im/element-web/issues/2782).
|
||||
if (!syncData.catchingUp) {
|
||||
_maybeUploadOneTimeKeys(this);
|
||||
this._processReceivedRoomKeyRequests();
|
||||
|
||||
@@ -25,8 +25,7 @@ import {EventEmitter} from 'events';
|
||||
import {logger} from '../../logger';
|
||||
import {DeviceInfo} from '../deviceinfo';
|
||||
import {newTimeoutError} from "./Error";
|
||||
import {CrossSigningInfo} from "../CrossSigning";
|
||||
import {decodeBase64} from "../olmlib";
|
||||
import {requestKeysDuringVerification} from "../CrossSigning";
|
||||
|
||||
const timeoutException = new Error("Verification timed out");
|
||||
|
||||
@@ -79,8 +78,6 @@ export class VerificationBase extends EventEmitter {
|
||||
this._transactionTimeoutTimer = null;
|
||||
}
|
||||
|
||||
static keyRequestTimeoutMs = 1000 * 60;
|
||||
|
||||
get initiatedByMe() {
|
||||
// if there is no start event yet,
|
||||
// we probably want to send it,
|
||||
@@ -198,93 +195,7 @@ export class VerificationBase extends EventEmitter {
|
||||
if (!this._done) {
|
||||
this.request.onVerifierFinished();
|
||||
this._resolve();
|
||||
|
||||
//#region Cross-signing keys request
|
||||
// If this is a self-verification, ask the other party for keys
|
||||
if (this._baseApis.getUserId() !== this.userId) {
|
||||
return;
|
||||
}
|
||||
// FIXME: This is a lot of logic that isn't anything to do with verification
|
||||
// and probably ought to be somewhere else.
|
||||
console.log("VerificationBase.done: Self-verification done; requesting keys");
|
||||
/* This happens asynchronously, and we're not concerned about
|
||||
* waiting for it. We return here in order to test. */
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = this._baseApis;
|
||||
const original = client._crypto._crossSigningInfo;
|
||||
|
||||
/* We already have all of the infrastructure we need to validate and
|
||||
* cache cross-signing keys, so instead of replicating that, here we
|
||||
* set up callbacks that request them from the other device and call
|
||||
* CrossSigningInfo.getCrossSigningKey() to validate/cache */
|
||||
const crossSigning = new CrossSigningInfo(
|
||||
original.userId,
|
||||
{ getCrossSigningKey: async (type) => {
|
||||
console.debug("VerificationBase.done: requesting secret",
|
||||
type, this.deviceId);
|
||||
const { promise } = client.requestSecret(
|
||||
`m.cross_signing.${type}`, [this.deviceId],
|
||||
);
|
||||
const result = await promise;
|
||||
const decoded = decodeBase64(result);
|
||||
return Uint8Array.from(decoded);
|
||||
} },
|
||||
original._cacheCallbacks,
|
||||
);
|
||||
crossSigning.keys = original.keys;
|
||||
|
||||
// XXX: get all keys out if we get one key out
|
||||
// https://github.com/vector-im/riot-web/issues/12604
|
||||
// then change here to reject on the timeout
|
||||
/* Requests can be ignored, so don't wait around forever */
|
||||
const timeout = new Promise((resolve, reject) => {
|
||||
setTimeout(
|
||||
resolve,
|
||||
VerificationBase.keyRequestTimeoutMs,
|
||||
new Error("Timeout"),
|
||||
);
|
||||
});
|
||||
|
||||
// also request and cache the key backup key
|
||||
const backupKeyPromise = new Promise(async resolve => {
|
||||
const cachedKey = await client._crypto.getSessionBackupPrivateKey();
|
||||
if (!cachedKey) {
|
||||
logger.info("No cached backup key found. Requesting...");
|
||||
const secretReq = client.requestSecret(
|
||||
'm.megolm_backup.v1', [this.deviceId],
|
||||
);
|
||||
const base64Key = await secretReq.promise;
|
||||
logger.info("Got key backup key, decoding...");
|
||||
const decodedKey = decodeBase64(base64Key);
|
||||
logger.info("Decoded backup key, storing...");
|
||||
client._crypto.storeSessionBackupPrivateKey(
|
||||
Uint8Array.from(decodedKey),
|
||||
);
|
||||
logger.info("Backup key stored. Starting backup restore...");
|
||||
const backupInfo = await client.getKeyBackupVersion();
|
||||
// no need to await for this - just let it go in the bg
|
||||
client.restoreKeyBackupWithCache(
|
||||
undefined, undefined, backupInfo,
|
||||
).then(() => {
|
||||
logger.info("Backup restored.");
|
||||
});
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
|
||||
/* We call getCrossSigningKey() for its side-effects */
|
||||
return Promise.race([
|
||||
Promise.all([
|
||||
crossSigning.getCrossSigningKey("self_signing"),
|
||||
crossSigning.getCrossSigningKey("user_signing"),
|
||||
backupKeyPromise,
|
||||
]),
|
||||
timeout,
|
||||
]).then(resolve, reject);
|
||||
}).catch((e) => {
|
||||
console.warn("VerificationBase: failure while requesting keys:", e);
|
||||
});
|
||||
//#endregion
|
||||
return requestKeysDuringVerification(this._baseApis, this.userId, this.deviceId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -87,7 +87,7 @@ export const MatrixEvent = function(
|
||||
// amount of needless string duplication. This can save moderate amounts of
|
||||
// memory (~10% on a 350MB heap).
|
||||
// 'membership' at the event level (rather than the content level) is a legacy
|
||||
// field that Riot never otherwise looks at, but it will still take up a lot
|
||||
// field that Element never otherwise looks at, but it will still take up a lot
|
||||
// of space if we don't intern it.
|
||||
["state_key", "type", "sender", "room_id", "membership"].forEach((prop) => {
|
||||
if (!event[prop]) {
|
||||
@@ -626,7 +626,7 @@ utils.extend(MatrixEvent.prototype, {
|
||||
* @return {boolean} True if this event is encrypted.
|
||||
*/
|
||||
isEncrypted: function() {
|
||||
return this.event.type === "m.room.encrypted";
|
||||
return !this.isState() && this.event.type === "m.room.encrypted";
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
+13
-6
@@ -403,7 +403,7 @@ MatrixCall.prototype._initWithHangup = function(event) {
|
||||
* Answer a call.
|
||||
*/
|
||||
MatrixCall.prototype.answer = function() {
|
||||
debuglog("Answering call %s of type %s", this.callId, this.type);
|
||||
debuglog(`Answering call ${this.callId} of type ${this.type}`);
|
||||
const self = this;
|
||||
|
||||
if (self._answerContent) {
|
||||
@@ -412,8 +412,10 @@ MatrixCall.prototype.answer = function() {
|
||||
}
|
||||
|
||||
if (!this.localAVStream && !this.waitForLocalAVStream) {
|
||||
const constraints = _getUserMediaVideoContraints(this.type);
|
||||
logger.log("Getting user media with constraints", constraints);
|
||||
this.webRtc.getUserMedia(
|
||||
_getUserMediaVideoContraints(this.type),
|
||||
constraints,
|
||||
hookCallback(self, self._maybeGotUserMediaForAnswer),
|
||||
hookCallback(self, self._maybeGotUserMediaForAnswer),
|
||||
);
|
||||
@@ -1065,7 +1067,7 @@ const terminate = function(self, hangupParty, hangupReason, shouldEmit) {
|
||||
};
|
||||
|
||||
const stopAllMedia = function(self) {
|
||||
debuglog("stopAllMedia (stream=%s)", self.localAVStream);
|
||||
debuglog(`stopAllMedia (stream=${self.localAVStream})`);
|
||||
if (self.localAVStream) {
|
||||
forAllTracksOnStream(self.localAVStream, function(t) {
|
||||
if (t.stop) {
|
||||
@@ -1127,7 +1129,11 @@ const _tryPlayRemoteAudioStream = async function(self) {
|
||||
const player = self.getRemoteAudioElement();
|
||||
|
||||
// if audioOutput is non-default:
|
||||
if (audioOutput) await player.setSinkId(audioOutput);
|
||||
try {
|
||||
if (audioOutput) await player.setSinkId(audioOutput);
|
||||
} catch (e) {
|
||||
logger.warn("Couldn't set requested audio output device: using default", e);
|
||||
}
|
||||
|
||||
player.autoplay = true;
|
||||
self.assignElement(player, self.remoteAStream, "remoteAudio");
|
||||
@@ -1188,8 +1194,8 @@ const _sendCandidateQueue = function(self) {
|
||||
|
||||
if (self.candidateSendTries > 5) {
|
||||
debuglog(
|
||||
"Failed to send candidates on attempt %s. Giving up for now.",
|
||||
self.candidateSendTries,
|
||||
"Failed to send candidates on attempt " + self.candidateSendTries +
|
||||
". Giving up for now.",
|
||||
);
|
||||
self.candidateSendTries = 0;
|
||||
return;
|
||||
@@ -1205,6 +1211,7 @@ const _sendCandidateQueue = function(self) {
|
||||
};
|
||||
|
||||
const _placeCallWithConstraints = function(self, constraints) {
|
||||
logger.log("Getting user media with constraints", constraints);
|
||||
self.client.callList[self.callId] = self;
|
||||
self.webRtc.getUserMedia(
|
||||
constraints,
|
||||
|
||||
-72
@@ -1,72 +0,0 @@
|
||||
{
|
||||
"rules": {
|
||||
"class-name": false,
|
||||
"comment-format": [
|
||||
true
|
||||
],
|
||||
"curly": false,
|
||||
"eofline": false,
|
||||
"forin": false,
|
||||
"indent": [
|
||||
true,
|
||||
"spaces"
|
||||
],
|
||||
"label-position": true,
|
||||
"max-line-length": false,
|
||||
"member-access": false,
|
||||
"member-ordering": [
|
||||
true,
|
||||
"static-after-instance",
|
||||
"variables-before-functions"
|
||||
],
|
||||
"no-arg": true,
|
||||
"no-bitwise": false,
|
||||
"no-console": false,
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-empty": false,
|
||||
"no-eval": true,
|
||||
"no-inferrable-types": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-string-literal": false,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": false,
|
||||
"no-var-keyword": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"one-line": [
|
||||
true,
|
||||
"check-open-brace",
|
||||
"check-catch",
|
||||
"check-else",
|
||||
"check-whitespace"
|
||||
],
|
||||
"quotemark": false,
|
||||
"radix": true,
|
||||
"semicolon": [
|
||||
"always"
|
||||
],
|
||||
"triple-equals": [],
|
||||
"typedef-whitespace": [
|
||||
true,
|
||||
{
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}
|
||||
],
|
||||
"variable-name": false,
|
||||
"whitespace": [
|
||||
true,
|
||||
"check-branch",
|
||||
"check-decl",
|
||||
"check-operator",
|
||||
"check-separator",
|
||||
"check-type"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1914,11 +1914,6 @@ buffer@~5.2.1:
|
||||
base64-js "^1.0.2"
|
||||
ieee754 "^1.1.4"
|
||||
|
||||
builtin-modules@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
|
||||
integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
|
||||
|
||||
builtin-status-codes@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
|
||||
@@ -1991,7 +1986,7 @@ center-align@^0.1.1:
|
||||
align-text "^0.1.3"
|
||||
lazy-cache "^1.0.3"
|
||||
|
||||
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.2:
|
||||
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
|
||||
integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
|
||||
@@ -2153,7 +2148,7 @@ combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
commander@^2.12.1, commander@^2.19.0, commander@^2.20.0:
|
||||
commander@^2.19.0, commander@^2.20.0:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
@@ -2469,11 +2464,6 @@ diff-sequences@^24.9.0:
|
||||
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5"
|
||||
integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==
|
||||
|
||||
diff@^4.0.1:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
|
||||
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
|
||||
|
||||
diffie-hellman@^5.0.0:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
|
||||
@@ -2543,9 +2533,9 @@ electron-to-chromium@^1.3.413:
|
||||
integrity sha512-Oo+0+CN9d2z6FToQW6Hwvi9ez09Y/usKwr0tsDsyg43a871zVJCi1nR0v03djLbRNcaCKjtrnVf2XJhTxEpPCg==
|
||||
|
||||
elliptic@^6.0.0, elliptic@^6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.2.tgz#05c5678d7173c049d8ca433552224a495d0e3762"
|
||||
integrity sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6"
|
||||
integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==
|
||||
dependencies:
|
||||
bn.js "^4.4.0"
|
||||
brorand "^1.0.1"
|
||||
@@ -6055,7 +6045,7 @@ sax@^1.2.4:
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
|
||||
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
|
||||
"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
|
||||
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
|
||||
@@ -6715,37 +6705,11 @@ tsify@^4.0.1:
|
||||
through2 "^2.0.0"
|
||||
tsconfig "^5.0.3"
|
||||
|
||||
tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0:
|
||||
tslib@^1.8.1, tslib@^1.9.0:
|
||||
version "1.13.0"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
||||
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
||||
|
||||
tslint@^5.20.1:
|
||||
version "5.20.1"
|
||||
resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d"
|
||||
integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==
|
||||
dependencies:
|
||||
"@babel/code-frame" "^7.0.0"
|
||||
builtin-modules "^1.1.1"
|
||||
chalk "^2.3.0"
|
||||
commander "^2.12.1"
|
||||
diff "^4.0.1"
|
||||
glob "^7.1.1"
|
||||
js-yaml "^3.13.1"
|
||||
minimatch "^3.0.4"
|
||||
mkdirp "^0.5.1"
|
||||
resolve "^1.3.2"
|
||||
semver "^5.3.0"
|
||||
tslib "^1.8.0"
|
||||
tsutils "^2.29.0"
|
||||
|
||||
tsutils@^2.29.0:
|
||||
version "2.29.0"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99"
|
||||
integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==
|
||||
dependencies:
|
||||
tslib "^1.8.1"
|
||||
|
||||
tsutils@^3.17.1:
|
||||
version "3.17.1"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
|
||||
|
||||
Reference in New Issue
Block a user