Compare commits
69 Commits
v8.2.0-rc.1
...
v8.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
| aec92a41da | |||
| d570811ddc | |||
| 9cd015a218 | |||
| 8d2cc5096e | |||
| 7ec0bf69f3 | |||
| af0b6fc6ac | |||
| 6347031f61 | |||
| 3eda039898 | |||
| 5447d99481 | |||
| 9d08744fe2 | |||
| 848fa257ea | |||
| 54553fb671 | |||
| ad658ead37 | |||
| c787f0e9d0 | |||
| 6f5da701aa | |||
| a01368bd60 | |||
| f682097e45 | |||
| 89ebffd69f | |||
| cdeb4ead9e | |||
| 79cc835874 | |||
| 8df866865d | |||
| fa7eff50e5 | |||
| 6558881952 | |||
| 9cbe2c985d | |||
| 7769c53cd6 | |||
| 7a5a47ecc7 | |||
| 8c315ebd15 | |||
| 6044b2cbad | |||
| 7acfd0b423 | |||
| e201aab440 | |||
| fb25fa3a27 | |||
| 857ad9b180 | |||
| 14843a1bca | |||
| 6bdbee533c | |||
| b9886d4f34 | |||
| 666cbbce08 | |||
| 69c575a4be | |||
| c920de0d28 | |||
| 53cdf53f63 | |||
| d9dda6aebc | |||
| 3d4a9a24ce | |||
| de339d3098 | |||
| 0f83234be9 | |||
| bcd9b45589 | |||
| eec7c4c61b | |||
| 25b4b049b7 | |||
| 2191eb3f41 | |||
| bebdbf7e05 | |||
| 646c091966 | |||
| 952729cb1b | |||
| c6992e2056 | |||
| 77ed79e9a9 | |||
| c4f4add0ec | |||
| 7eeb60c838 | |||
| d42cdbbc5b | |||
| 66237e1ea6 | |||
| a51c0450c3 | |||
| 7a2416bb6d | |||
| a1528e9e33 | |||
| 71cc4d535e | |||
| c06723df3d | |||
| 06b285c013 | |||
| 49c06ef0ca | |||
| 5f92357fec | |||
| 3e0dd3d918 | |||
| f19d76b08d | |||
| 5ef5412a55 | |||
| e88a384aa7 | |||
| 9067feeafb |
+1
-1
@@ -30,7 +30,7 @@ module.exports = {
|
||||
"no-async-promise-executor": "off",
|
||||
},
|
||||
overrides: [{
|
||||
"files": ["src/**/*.{ts, tsx}"],
|
||||
"files": ["src/**/*.ts"],
|
||||
"extends": ["matrix-org/ts"],
|
||||
"rules": {
|
||||
// While we're converting to ts we make heavy use of this
|
||||
|
||||
@@ -1,3 +1,76 @@
|
||||
Changes in [8.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.4.0) (2020-09-28)
|
||||
================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.4.0-rc.1...v8.4.0)
|
||||
|
||||
* Only sign key backup with cross-signing keys when available
|
||||
[\#1482](https://github.com/matrix-org/matrix-js-sdk/pull/1482)
|
||||
|
||||
Changes in [8.4.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.4.0-rc.1) (2020-09-23)
|
||||
==========================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.3.0...v8.4.0-rc.1)
|
||||
|
||||
* If there are extraParams set, ensure that queryParams is defined
|
||||
[\#1477](https://github.com/matrix-org/matrix-js-sdk/pull/1477)
|
||||
* Add diagnostics to security bootstrap paths
|
||||
[\#1475](https://github.com/matrix-org/matrix-js-sdk/pull/1475)
|
||||
* Switch to a combination of better-docs and docdash
|
||||
[\#1459](https://github.com/matrix-org/matrix-js-sdk/pull/1459)
|
||||
* Undo attempts to cache private keys aggressively
|
||||
[\#1474](https://github.com/matrix-org/matrix-js-sdk/pull/1474)
|
||||
* Repair secret storage reset, cache keys when missing
|
||||
[\#1472](https://github.com/matrix-org/matrix-js-sdk/pull/1472)
|
||||
* Prevent parallel getVersions calls
|
||||
[\#1471](https://github.com/matrix-org/matrix-js-sdk/pull/1471)
|
||||
* Send end-of-candidates
|
||||
[\#1473](https://github.com/matrix-org/matrix-js-sdk/pull/1473)
|
||||
* Add a function for checking the /versions flag for forced e2ee
|
||||
[\#1470](https://github.com/matrix-org/matrix-js-sdk/pull/1470)
|
||||
* Add option to allow users of pantialaimon to use the SDK
|
||||
[\#1469](https://github.com/matrix-org/matrix-js-sdk/pull/1469)
|
||||
* Fixed Yarn broken link
|
||||
[\#1468](https://github.com/matrix-org/matrix-js-sdk/pull/1468)
|
||||
* some TypeScript and doc fixes
|
||||
[\#1466](https://github.com/matrix-org/matrix-js-sdk/pull/1466)
|
||||
* Remove Travis CI reference
|
||||
[\#1464](https://github.com/matrix-org/matrix-js-sdk/pull/1464)
|
||||
* Inject identity server token for 3pid invites on createRoom
|
||||
[\#1463](https://github.com/matrix-org/matrix-js-sdk/pull/1463)
|
||||
|
||||
Changes in [8.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.3.0) (2020-09-14)
|
||||
================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.3.0-rc.1...v8.3.0)
|
||||
|
||||
* No changes since rc.1
|
||||
|
||||
Changes in [8.3.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.3.0-rc.1) (2020-09-09)
|
||||
==========================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.2.0...v8.3.0-rc.1)
|
||||
|
||||
* Add missing options in ICreateClientOpts
|
||||
[\#1452](https://github.com/matrix-org/matrix-js-sdk/pull/1452)
|
||||
* Ensure ready functions return boolean values
|
||||
[\#1457](https://github.com/matrix-org/matrix-js-sdk/pull/1457)
|
||||
* Handle missing cross-signing keys gracefully
|
||||
[\#1456](https://github.com/matrix-org/matrix-js-sdk/pull/1456)
|
||||
* Fix eslint ts override tsx matching
|
||||
[\#1451](https://github.com/matrix-org/matrix-js-sdk/pull/1451)
|
||||
* Untangle cross-signing and secret storage
|
||||
[\#1450](https://github.com/matrix-org/matrix-js-sdk/pull/1450)
|
||||
|
||||
Changes in [8.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.2.0) (2020-09-01)
|
||||
================================================================================================
|
||||
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.2.0-rc.1...v8.2.0)
|
||||
|
||||
## Security notice
|
||||
|
||||
JS SDK 8.2.0 fixes an issue where encrypted state events could break incoming call handling.
|
||||
Thanks to @awesome-michael from Awesome Technologies for responsibly disclosing this via Matrix's
|
||||
Security Disclosure Policy.
|
||||
|
||||
## All changes
|
||||
|
||||
* No changes since rc.1
|
||||
|
||||
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)
|
||||
|
||||
+3
-4
@@ -28,10 +28,9 @@ use GitHub's pull request workflow to review the contribution, and either ask
|
||||
you to make any refinements needed or merge it and make them ourselves. The
|
||||
changes will then land on master when we next do a release.
|
||||
|
||||
We use Travis for continuous integration, and all pull requests get
|
||||
automatically tested by Travis: if your change breaks the build, then the PR
|
||||
will show that there are failed checks, so please check back after a few
|
||||
minutes.
|
||||
We use continuous integration, and all pull requests get automatically tested:
|
||||
if your change breaks the build, then the PR will show that there are failed
|
||||
checks, so please check back after a few minutes.
|
||||
|
||||
Code style
|
||||
~~~~~~~~~~
|
||||
|
||||
@@ -30,7 +30,7 @@ This SDK targets Node 10 for compatibility, which translates to ES6. If you're u
|
||||
a bundler like webpack you'll likely have to transpile dependencies, including this
|
||||
SDK, to match your target browsers.
|
||||
|
||||
Using `yarn` instead of `npm` is recommended. Please see the Yarn [install guide](https://yarnpkg.com/docs/install/)
|
||||
Using `yarn` instead of `npm` is recommended. Please see the Yarn [install guide](https://classic.yarnpkg.com/en/docs/install)
|
||||
if you do not have it already.
|
||||
|
||||
``yarn add matrix-js-sdk``
|
||||
|
||||
+8
-1
@@ -18,6 +18,13 @@
|
||||
"readme": "README.md",
|
||||
"recurse": true,
|
||||
"verbose": true,
|
||||
"template": "node_modules/better-docs"
|
||||
"template": "node_modules/docdash"
|
||||
},
|
||||
"docdash": {
|
||||
"static": true,
|
||||
"private": false,
|
||||
"search": true,
|
||||
"collapse": true,
|
||||
"typedefs": true
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "matrix-js-sdk",
|
||||
"version": "8.2.0-rc.1",
|
||||
"version": "8.4.0",
|
||||
"description": "Matrix Client-Server SDK for Javascript",
|
||||
"scripts": {
|
||||
"prepare": "yarn build",
|
||||
@@ -72,8 +72,9 @@
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-jest": "^24.9.0",
|
||||
"babelify": "^10.0.0",
|
||||
"better-docs": "^1.4.7",
|
||||
"better-docs": "^2.3.2",
|
||||
"browserify": "^16.5.0",
|
||||
"docdash": "^1.2.0",
|
||||
"eslint": "7.3.1",
|
||||
"eslint-config-matrix-org": "^0.1.2",
|
||||
"eslint-plugin-babel": "^5.3.0",
|
||||
@@ -81,7 +82,7 @@
|
||||
"fake-indexeddb": "^3.0.0",
|
||||
"jest": "^24.9.0",
|
||||
"jest-localstorage-mock": "^2.4.0",
|
||||
"jsdoc": "^3.5.5",
|
||||
"jsdoc": "^3.6.5",
|
||||
"matrix-mock-request": "^1.2.3",
|
||||
"olm": "https://packages.matrix.org/npm/olm/olm-3.1.4.tgz",
|
||||
"rimraf": "^3.0.0",
|
||||
|
||||
@@ -20,7 +20,7 @@ import anotherjson from 'another-json';
|
||||
import * as olmlib from "../../../src/crypto/olmlib";
|
||||
import {TestClient} from '../../TestClient';
|
||||
import {HttpResponse, setHttpResponses} from '../../test-utils';
|
||||
import {resetCrossSigningKeys, createSecretStorageKey} from "./crypto-utils";
|
||||
import { resetCrossSigningKeys } from "./crypto-utils";
|
||||
import { MatrixError } from '../../../src/http-api';
|
||||
|
||||
async function makeTestClient(userInfo, options, keys) {
|
||||
@@ -71,8 +71,7 @@ describe("Cross Signing", function() {
|
||||
alice.setAccountData = async () => {};
|
||||
alice.getAccountDataFromServer = async () => {};
|
||||
// set Alice's cross-signing key
|
||||
await alice.bootstrapSecretStorage({
|
||||
createSecretStorageKey,
|
||||
await alice.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
expect(alice.uploadDeviceSigningKeys).toHaveBeenCalled();
|
||||
@@ -118,8 +117,7 @@ describe("Cross Signing", function() {
|
||||
// through failure, stopping before actually applying changes.
|
||||
let bootstrapDidThrow = false;
|
||||
try {
|
||||
await alice.bootstrapSecretStorage({
|
||||
createSecretStorageKey,
|
||||
await alice.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys,
|
||||
});
|
||||
} catch (e) {
|
||||
|
||||
@@ -326,9 +326,11 @@ describe("Secrets", function() {
|
||||
this.emit("accountData", event);
|
||||
};
|
||||
|
||||
await bob.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
await bob.bootstrapSecretStorage({
|
||||
createSecretStorageKey,
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
|
||||
const crossSigning = bob._crypto._crossSigningInfo;
|
||||
@@ -379,13 +381,15 @@ describe("Secrets", function() {
|
||||
const secretStorage = bob._crypto._secretStorage;
|
||||
|
||||
// Set up cross-signing keys from scratch with specific storage key
|
||||
await bob.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
await bob.bootstrapSecretStorage({
|
||||
createSecretStorageKey: async () => ({
|
||||
// `pubkey` not used anymore with symmetric 4S
|
||||
keyInfo: { pubkey: storagePublicKey },
|
||||
privateKey: storagePrivateKey,
|
||||
}),
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
|
||||
// Clear local cross-signing keys and read from secret storage
|
||||
@@ -394,7 +398,7 @@ describe("Secrets", function() {
|
||||
crossSigning.toStorage(),
|
||||
);
|
||||
crossSigning.keys = {};
|
||||
await bob.bootstrapSecretStorage({
|
||||
await bob.bootstrapCrossSigning({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
|
||||
@@ -517,9 +521,7 @@ describe("Secrets", function() {
|
||||
this.emit("accountData", event);
|
||||
};
|
||||
|
||||
await alice.bootstrapSecretStorage({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
await alice.bootstrapSecretStorage();
|
||||
|
||||
expect(alice.getAccountData("m.secret_storage.default_key").getContent())
|
||||
.toEqual({key: "key_id"});
|
||||
@@ -659,9 +661,7 @@ describe("Secrets", function() {
|
||||
this.emit("accountData", event);
|
||||
};
|
||||
|
||||
await alice.bootstrapSecretStorage({
|
||||
authUploadDeviceSigningKeys: async func => await func({}),
|
||||
});
|
||||
await alice.bootstrapSecretStorage();
|
||||
|
||||
const backupKey = alice.getAccountData("m.megolm_backup.v1")
|
||||
.getContent();
|
||||
|
||||
Vendored
+6
@@ -14,12 +14,18 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import * as Olm from "olm";
|
||||
|
||||
export {};
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface Global {
|
||||
localStorage: Storage;
|
||||
Olm: Olm;
|
||||
}
|
||||
}
|
||||
interface Global {
|
||||
Olm: Olm;
|
||||
}
|
||||
}
|
||||
|
||||
+20
-2
@@ -462,8 +462,26 @@ MatrixBaseApis.prototype.getFallbackAuthUrl = function(loginType, authSessionId)
|
||||
* room_alias: {string(opt)}}</code>
|
||||
* @return {module:http-api.MatrixError} Rejects: with an error response.
|
||||
*/
|
||||
MatrixBaseApis.prototype.createRoom = function(options, callback) {
|
||||
// valid options include: room_alias_name, visibility, invite
|
||||
MatrixBaseApis.prototype.createRoom = async function(options, callback) {
|
||||
// some valid options include: room_alias_name, visibility, invite
|
||||
|
||||
// inject the id_access_token if inviting 3rd party addresses
|
||||
const invitesNeedingToken = (options.invite_3pid || [])
|
||||
.filter(i => !i.id_access_token);
|
||||
if (
|
||||
invitesNeedingToken.length > 0 &&
|
||||
this.identityServer &&
|
||||
this.identityServer.getAccessToken &&
|
||||
await this.doesServerAcceptIdentityAccessToken()
|
||||
) {
|
||||
const identityAccessToken = await this.identityServer.getAccessToken();
|
||||
if (identityAccessToken) {
|
||||
for (const invite of invitesNeedingToken) {
|
||||
invite.id_access_token = identityAccessToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return this._http.authedRequest(
|
||||
callback, "POST", "/createRoom", undefined, options,
|
||||
);
|
||||
|
||||
+161
-28
@@ -182,6 +182,11 @@ function keyFromRecoverySession(session, decryptionKey) {
|
||||
* Optional. Whether to allow a fallback ICE server should be used for negotiating a
|
||||
* WebRTC connection if the homeserver doesn't provide any servers. Defaults to false.
|
||||
*
|
||||
* @param {boolean} [opts.usingExternalCrypto]
|
||||
* Optional. Whether to allow sending messages to encrypted rooms when encryption
|
||||
* is not available internally within this SDK. This is useful if you are using an external
|
||||
* E2E proxy, for example. Defaults to false.
|
||||
*
|
||||
* @param {object} opts.cryptoCallbacks Optional. Callbacks for crypto and cross-signing.
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
@@ -235,17 +240,25 @@ function keyFromRecoverySession(session, decryptionKey) {
|
||||
* }
|
||||
* {string} name the name of the value we want to read out of SSSS, for UI purposes.
|
||||
*
|
||||
* @param {function} [opts.cryptoCallbacks.cacheSecretStorageKey]
|
||||
* Optional. Function called when a new encryption key for secret storage
|
||||
* has been created. This allows the application a chance to cache this key if
|
||||
* desired to avoid user prompts.
|
||||
* Args:
|
||||
* {string} keyId the ID of the new key
|
||||
* {Uint8Array} key the new private key
|
||||
*
|
||||
* @param {function} [opts.cryptoCallbacks.onSecretRequested]
|
||||
* Optional. Function called when a request for a secret is received from another
|
||||
* device.
|
||||
* Args:
|
||||
* {string} name The name of the secret being requested.
|
||||
* {string} user_id (string) The user ID of the client requesting
|
||||
* {string} device_id The device ID of the client requesting the secret.
|
||||
* {string} request_id The ID of the request. Used to match a
|
||||
* {string} userId The user ID of the client requesting
|
||||
* {string} deviceId The device ID of the client requesting the secret.
|
||||
* {string} requestId The ID of the request. Used to match a
|
||||
* corresponding `crypto.secrets.request_cancelled`. The request ID will be
|
||||
* unique per sender, device pair.
|
||||
* {DeviceTrustLevel} device_trust: The trust status of the device requesting
|
||||
* {DeviceTrustLevel} deviceTrust: The trust status of the device requesting
|
||||
* the secret as returned by {@link module:client~MatrixClient#checkDeviceTrust}.
|
||||
*/
|
||||
export function MatrixClient(opts) {
|
||||
@@ -258,6 +271,8 @@ export function MatrixClient(opts) {
|
||||
|
||||
this.reEmitter = new ReEmitter(this);
|
||||
|
||||
this.usingExternalCrypto = opts.usingExternalCrypto;
|
||||
|
||||
this.store = opts.store || new StubStore();
|
||||
|
||||
this.deviceId = opts.deviceId || null;
|
||||
@@ -351,9 +366,9 @@ export function MatrixClient(opts) {
|
||||
// The pushprocessor caches useful things, so keep one and re-use it
|
||||
this._pushProcessor = new PushProcessor(this);
|
||||
|
||||
// Cache of the server's /versions response
|
||||
// Promise to a response of the server's /versions response
|
||||
// TODO: This should expire: https://github.com/matrix-org/matrix-js-sdk/issues/1020
|
||||
this._serverVersionsCache = null;
|
||||
this._serverVersionsPromise = null;
|
||||
|
||||
this._cachedCapabilities = null; // { capabilities: {}, lastUpdated: timestamp }
|
||||
|
||||
@@ -1094,6 +1109,7 @@ function wrapCryptoFuncs(MatrixClient, names) {
|
||||
|
||||
/**
|
||||
* Get the user's cross-signing key ID.
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#getCrossSigningId
|
||||
@@ -1105,6 +1121,7 @@ function wrapCryptoFuncs(MatrixClient, names) {
|
||||
|
||||
/**
|
||||
* Get the cross signing information for a given user.
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#getStoredCrossSigningForUser
|
||||
@@ -1115,6 +1132,7 @@ function wrapCryptoFuncs(MatrixClient, names) {
|
||||
|
||||
/**
|
||||
* Check whether a given user is trusted.
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#checkUserTrust
|
||||
@@ -1125,6 +1143,7 @@ function wrapCryptoFuncs(MatrixClient, names) {
|
||||
|
||||
/**
|
||||
* Check whether a given device is trusted.
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#checkDeviceTrust
|
||||
@@ -1137,6 +1156,7 @@ function wrapCryptoFuncs(MatrixClient, names) {
|
||||
/**
|
||||
* Check the copy of our cross-signing key that we have in the device list and
|
||||
* see if we can get the private key. If so, mark it as trusted.
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#checkOwnCrossSigningTrust
|
||||
@@ -1146,6 +1166,7 @@ function wrapCryptoFuncs(MatrixClient, names) {
|
||||
* Checks that a given cross-signing private key matches a given public key.
|
||||
* This can be used by the getCrossSigningKey callback to verify that the
|
||||
* private key it is about to supply is the one that was requested.
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#checkCrossSigningPrivateKey
|
||||
@@ -1158,8 +1179,48 @@ function wrapCryptoFuncs(MatrixClient, names) {
|
||||
* Perform any background tasks that can be done before a message is ready to
|
||||
* send, in order to speed up sending of the message.
|
||||
*
|
||||
* @function module:client~MatrixClient#prepareToEncrypt
|
||||
* @param {module:models/room} room the room the event is in
|
||||
*/
|
||||
|
||||
/**
|
||||
* Checks whether cross signing:
|
||||
* - is enabled on this account and trusted by this device
|
||||
* - has private keys either cached locally or stored in secret storage
|
||||
*
|
||||
* If this function returns false, bootstrapCrossSigning() can be used
|
||||
* to fix things such that it returns true. That is to say, after
|
||||
* bootstrapCrossSigning() completes successfully, this function should
|
||||
* return true.
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#isCrossSigningReady
|
||||
* @return {bool} True if cross-signing is ready to be used on this device
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bootstrap cross-signing by creating keys if needed. If everything is already
|
||||
* set up, then no changes are made, so this is safe to run to ensure
|
||||
* cross-signing is ready for use.
|
||||
*
|
||||
* This function:
|
||||
* - creates new cross-signing keys if they are not found locally cached nor in
|
||||
* secret storage (if it has been setup)
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#bootstrapCrossSigning
|
||||
* @param {function} opts.authUploadDeviceSigningKeys Function
|
||||
* called to await an interactive auth flow when uploading device signing keys.
|
||||
* @param {bool} [opts.setupNewCrossSigning] Optional. Reset even if keys
|
||||
* already exist.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
wrapCryptoFuncs(MatrixClient, [
|
||||
"getCrossSigningId",
|
||||
"getStoredCrossSigningForUser",
|
||||
@@ -1170,6 +1231,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
"legacyDeviceVerification",
|
||||
"prepareToEncrypt",
|
||||
"isCrossSigningReady",
|
||||
"bootstrapCrossSigning",
|
||||
"getCryptoTrustCrossSignedDevices",
|
||||
"setCryptoTrustCrossSignedDevices",
|
||||
"countSessionsNeedingBackup",
|
||||
@@ -1196,6 +1258,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
|
||||
/**
|
||||
* Create a recovery key from a user-supplied passphrase.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#createRecoveryKeyFromPassphrase
|
||||
@@ -1208,22 +1271,59 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bootstrap Secure Secret Storage if needed by creating a default key and signing it with
|
||||
* the cross-signing master key. If everything is already set up, then no
|
||||
* changes are made, so this is safe to run to ensure secret storage is ready
|
||||
* for use.
|
||||
* Checks whether secret storage:
|
||||
* - is enabled on this account
|
||||
* - is storing cross-signing private keys
|
||||
* - is storing session backup key (if enabled)
|
||||
*
|
||||
* If this function returns false, bootstrapSecretStorage() can be used
|
||||
* to fix things such that it returns true. That is to say, after
|
||||
* bootstrapSecretStorage() completes successfully, this function should
|
||||
* return true.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#isSecretStorageReady
|
||||
* @return {bool} True if secret storage is ready to be used on this device
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bootstrap Secure Secret Storage if needed by creating a default key. If everything is
|
||||
* already set up, then no changes are made, so this is safe to run to ensure secret
|
||||
* storage is ready for use.
|
||||
*
|
||||
* This function
|
||||
* - creates a new Secure Secret Storage key if no default key exists
|
||||
* - if a key backup exists, it is migrated to store the key in the Secret
|
||||
* Storage
|
||||
* - creates a backup if none exists, and one is requested
|
||||
* - migrates Secure Secret Storage to use the latest algorithm, if an outdated
|
||||
* algorithm is found
|
||||
*
|
||||
* @function module:client~MatrixClient#bootstrapSecretStorage
|
||||
* @param {function} [opts.authUploadDeviceSigningKeys] Optional. 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.
|
||||
* @param {function} [opts.createSecretStorageKey] Optional. Function
|
||||
* called to await a secret storage key creation flow.
|
||||
* Returns:
|
||||
* {Promise<Object>} Object with public key metadata, encoded private
|
||||
* recovery key which should be disposed of after displaying to the user,
|
||||
* and raw private key to avoid round tripping if needed.
|
||||
* @param {object} [opts.keyBackupInfo] The current key backup object. If passed,
|
||||
* the passphrase and recovery key from this backup will be used.
|
||||
* @param {bool} [opts.setupNewKeyBackup] If true, a new key backup version will be
|
||||
* created and the private key stored in the new SSSS store. Ignored if keyBackupInfo
|
||||
* is supplied.
|
||||
* @param {bool} [opts.setupNewSecretStorage] Optional. Reset even if keys already exist.
|
||||
* @param {func} [opts.getKeyBackupPassphrase] Optional. Function called to get the user's
|
||||
* current key backup passphrase. Should return a promise that resolves with a Buffer
|
||||
* containing the key, or rejects if the key cannot be obtained.
|
||||
* Returns:
|
||||
* {Promise} A promise which resolves to key creation data for
|
||||
* SecretStorage#addKey: an object with `passphrase` and/or `pubkey` fields.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Add a key for encrypting secrets.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#addSecretStorageKey
|
||||
@@ -1238,6 +1338,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
|
||||
/**
|
||||
* Check whether we have a key with a given ID.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#hasSecretStorageKey
|
||||
@@ -1247,7 +1348,8 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
*/
|
||||
|
||||
/**
|
||||
* Store an encrypted secret on the server
|
||||
* Store an encrypted secret on the server.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#storeSecret
|
||||
@@ -1259,6 +1361,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
|
||||
/**
|
||||
* Get a secret from storage.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#getSecret
|
||||
@@ -1269,6 +1372,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
|
||||
/**
|
||||
* Check if a secret is stored on the server.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#isSecretStored
|
||||
@@ -1283,6 +1387,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
|
||||
/**
|
||||
* Request a secret from another device.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#requestSecret
|
||||
@@ -1294,6 +1399,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
|
||||
/**
|
||||
* Get the current default key ID for encrypting secrets.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#getDefaultSecretStorageKeyId
|
||||
@@ -1303,6 +1409,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
|
||||
/**
|
||||
* Set the current default key ID for encrypting secrets.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#setDefaultSecretStorageKeyId
|
||||
@@ -1313,6 +1420,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
* Checks that a given secret storage private key matches a given public key.
|
||||
* This can be used by the getSecretStorageKey callback to verify that the
|
||||
* private key it is about to supply is the one that was requested.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @function module:client~MatrixClient#checkSecretStoragePrivateKey
|
||||
@@ -1324,6 +1432,7 @@ wrapCryptoFuncs(MatrixClient, [
|
||||
wrapCryptoFuncs(MatrixClient, [
|
||||
"getEventEncryptionInfo",
|
||||
"createRecoveryKeyFromPassphrase",
|
||||
"isSecretStorageReady",
|
||||
"bootstrapSecretStorage",
|
||||
"addSecretStorageKey",
|
||||
"hasSecretStorageKey",
|
||||
@@ -2647,6 +2756,13 @@ function _encryptEventIfNeeded(client, event, room) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!client._crypto && client.usingExternalCrypto) {
|
||||
// The client has opted to allow sending messages to encrypted
|
||||
// rooms even if the room is encrypted, and we haven't setup
|
||||
// crypto. This is useful for users of matrix-org/pantalaimon
|
||||
return null;
|
||||
}
|
||||
|
||||
if (event.getType() === "m.reaction") {
|
||||
// For reactions, there is a very little gained by encrypting the entire
|
||||
// event, as relation data is already kept in the clear. Event
|
||||
@@ -4879,19 +4995,22 @@ MatrixClient.prototype.stopClient = function() {
|
||||
* unstable APIs it supports
|
||||
* @return {Promise<object>} The server /versions response
|
||||
*/
|
||||
MatrixClient.prototype.getVersions = async function() {
|
||||
if (this._serverVersionsCache === null) {
|
||||
this._serverVersionsCache = await this._http.request(
|
||||
undefined, // callback
|
||||
"GET", "/_matrix/client/versions",
|
||||
undefined, // queryParams
|
||||
undefined, // data
|
||||
{
|
||||
prefix: '',
|
||||
},
|
||||
);
|
||||
MatrixClient.prototype.getVersions = function() {
|
||||
if (this._serverVersionsPromise) {
|
||||
return this._serverVersionsPromise;
|
||||
}
|
||||
return this._serverVersionsCache;
|
||||
|
||||
this._serverVersionsPromise = this._http.request(
|
||||
undefined, // callback
|
||||
"GET", "/_matrix/client/versions",
|
||||
undefined, // queryParams
|
||||
undefined, // data
|
||||
{
|
||||
prefix: '',
|
||||
},
|
||||
);
|
||||
|
||||
return this._serverVersionsPromise;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -4990,6 +5109,20 @@ MatrixClient.prototype.doesServerSupportUnstableFeature = async function(feature
|
||||
return unstableFeatures && !!unstableFeatures[feature];
|
||||
};
|
||||
|
||||
/**
|
||||
* Query the server to see if it is forcing encryption to be enabled for
|
||||
* a given room preset, based on the /versions response.
|
||||
* @param {string} presetName The name of the preset to check.
|
||||
* @returns {Promise<boolean>} true if the server is forcing encryption
|
||||
* for the preset.
|
||||
*/
|
||||
MatrixClient.prototype.doesServerForceEncryptionForPreset = async function(presetName) {
|
||||
const response = await this.getVersions();
|
||||
if (!response) return false;
|
||||
const unstableFeatures = response["unstable_features"];
|
||||
return unstableFeatures && !!unstableFeatures[`io.element.e2ee_forced.${presetName}`];
|
||||
};
|
||||
|
||||
/**
|
||||
* Get if lazy loading members is being used.
|
||||
* @return {boolean} Whether or not members are lazy loaded by this client
|
||||
|
||||
+60
-18
@@ -66,8 +66,27 @@ export class CrossSigningInfo extends EventEmitter {
|
||||
this.crossSigningVerifiedBefore = false;
|
||||
}
|
||||
|
||||
static fromStorage(obj, userId) {
|
||||
const res = new CrossSigningInfo(userId);
|
||||
for (const prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
res[prop] = obj[prop];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
toStorage() {
|
||||
return {
|
||||
keys: this.keys,
|
||||
firstUse: this.firstUse,
|
||||
crossSigningVerifiedBefore: this.crossSigningVerifiedBefore,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the app callback to ask for a private key
|
||||
*
|
||||
* @param {string} type The key type ("master", "self_signing", or "user_signing")
|
||||
* @param {string} expectedPubkey The matching public key or undefined to use
|
||||
* the stored public key for the given key type.
|
||||
@@ -127,24 +146,6 @@ export class CrossSigningInfo extends EventEmitter {
|
||||
);
|
||||
}
|
||||
|
||||
static fromStorage(obj, userId) {
|
||||
const res = new CrossSigningInfo(userId);
|
||||
for (const prop in obj) {
|
||||
if (obj.hasOwnProperty(prop)) {
|
||||
res[prop] = obj[prop];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
toStorage() {
|
||||
return {
|
||||
keys: this.keys,
|
||||
firstUse: this.firstUse,
|
||||
crossSigningVerifiedBefore: this.crossSigningVerifiedBefore,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the private keys exist in secret storage.
|
||||
* XXX: This could be static, be we often seem to have an instance when we
|
||||
@@ -201,9 +202,50 @@ export class CrossSigningInfo extends EventEmitter {
|
||||
*/
|
||||
static async getFromSecretStorage(type, secretStorage) {
|
||||
const encodedKey = await secretStorage.get(`m.cross_signing.${type}`);
|
||||
if (!encodedKey) {
|
||||
return null;
|
||||
}
|
||||
return decodeBase64(encodedKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the private keys exist in the local key cache.
|
||||
*
|
||||
* @param {string} [type] The type of key to get. One of "master",
|
||||
* "self_signing", or "user_signing". Optional, will check all by default.
|
||||
* @returns {boolean} True if all keys are stored in the local cache.
|
||||
*/
|
||||
async isStoredInKeyCache(type) {
|
||||
const cacheCallbacks = this._cacheCallbacks;
|
||||
if (!cacheCallbacks) return false;
|
||||
const types = type ? [type] : ["master", "self_signing", "user_signing"];
|
||||
for (const t of types) {
|
||||
if (!await cacheCallbacks.getCrossSigningKeyCache(t)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cross-signing private keys from the local cache.
|
||||
*
|
||||
* @returns {Map} A map from key type (string) to private key (Uint8Array)
|
||||
*/
|
||||
async getCrossSigningKeysFromCache() {
|
||||
const keys = new Map();
|
||||
const cacheCallbacks = this._cacheCallbacks;
|
||||
if (!cacheCallbacks) return keys;
|
||||
for (const type of ["master", "self_signing", "user_signing"]) {
|
||||
const privKey = await cacheCallbacks.getCrossSigningKeyCache(type);
|
||||
if (!privKey) {
|
||||
continue;
|
||||
}
|
||||
keys.set(type, privKey);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ID used to identify the user. This can also be used to test for
|
||||
* the existence of a given key type.
|
||||
|
||||
@@ -346,5 +346,12 @@ class SSSSCryptoCallbacks {
|
||||
|
||||
addPrivateKey(keyId, privKey) {
|
||||
this._privateKeys.set(keyId, privKey);
|
||||
// Also pass along to application to cache if it wishes
|
||||
if (
|
||||
this._delegateCryptoCallbacks &&
|
||||
this._delegateCryptoCallbacks.cacheSecretStorageKey
|
||||
) {
|
||||
this._delegateCryptoCallbacks.cacheSecretStorageKey(keyId, privKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+286
-142
@@ -406,14 +406,12 @@ Crypto.prototype.createRecoveryKeyFromPassphrase = async function(password) {
|
||||
|
||||
/**
|
||||
* Checks whether cross signing:
|
||||
* - is enabled on this account
|
||||
* - is trusted by this device
|
||||
* - has private keys stored in secret storage
|
||||
* and that the account has a secret storage key
|
||||
* - is enabled on this account and trusted by this device
|
||||
* - has private keys either cached locally or stored in secret storage
|
||||
*
|
||||
* If this function returns false, bootstrapSecretStorage() can be used
|
||||
* If this function returns false, bootstrapCrossSigning() can be used
|
||||
* to fix things such that it returns true. That is to say, after
|
||||
* bootstrapSecretStorage() completes successfully, this function should
|
||||
* bootstrapCrossSigning() completes successfully, this function should
|
||||
* return true.
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
@@ -422,24 +420,188 @@ Crypto.prototype.createRecoveryKeyFromPassphrase = async function(password) {
|
||||
*/
|
||||
Crypto.prototype.isCrossSigningReady = async function() {
|
||||
const publicKeysOnDevice = this._crossSigningInfo.getId();
|
||||
const privateKeysInStorage = await this._crossSigningInfo.isStoredInSecretStorage(
|
||||
this._secretStorage,
|
||||
const privateKeysExistSomewhere = (
|
||||
await this._crossSigningInfo.isStoredInKeyCache() ||
|
||||
await this._crossSigningInfo.isStoredInSecretStorage(
|
||||
this._secretStorage,
|
||||
)
|
||||
);
|
||||
const secretStorageKeyInAccount = await this._secretStorage.hasKey();
|
||||
|
||||
return (
|
||||
return !!(
|
||||
publicKeysOnDevice &&
|
||||
privateKeysInStorage &&
|
||||
secretStorageKeyInAccount
|
||||
privateKeysExistSomewhere
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks whether secret storage:
|
||||
* - is enabled on this account
|
||||
* - is storing cross-signing private keys
|
||||
* - is storing session backup key (if enabled)
|
||||
*
|
||||
* If this function returns false, bootstrapSecretStorage() can be used
|
||||
* to fix things such that it returns true. That is to say, after
|
||||
* bootstrapSecretStorage() completes successfully, this function should
|
||||
* return true.
|
||||
*
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @return {bool} True if secret storage is ready to be used on this device
|
||||
*/
|
||||
Crypto.prototype.isSecretStorageReady = async function() {
|
||||
const secretStorageKeyInAccount = await this._secretStorage.hasKey();
|
||||
const privateKeysInStorage = await this._crossSigningInfo.isStoredInSecretStorage(
|
||||
this._secretStorage,
|
||||
);
|
||||
const sessionBackupInStorage = (
|
||||
!this._baseApis.getKeyBackupEnabled() ||
|
||||
this._baseApis.isKeyBackupKeyStored()
|
||||
);
|
||||
|
||||
return !!(
|
||||
secretStorageKeyInAccount &&
|
||||
privateKeysInStorage &&
|
||||
sessionBackupInStorage
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Bootstrap Secure Secret Storage if needed by creating a default key and
|
||||
* signing it with the cross-signing master key. If everything is already set
|
||||
* up, then no changes are made, so this is safe to run to ensure secret storage
|
||||
* is ready for use.
|
||||
* Bootstrap cross-signing by creating keys if needed. If everything is already
|
||||
* set up, then no changes are made, so this is safe to run to ensure
|
||||
* cross-signing is ready for use.
|
||||
*
|
||||
* This function:
|
||||
* - creates new cross-signing keys if they are not found locally cached nor in
|
||||
* secret storage (if it has been setup)
|
||||
*
|
||||
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @param {function} opts.authUploadDeviceSigningKeys Function
|
||||
* called to await an interactive auth flow when uploading device signing keys.
|
||||
* @param {bool} [opts.setupNewCrossSigning] Optional. Reset even if keys
|
||||
* already exist.
|
||||
* 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.
|
||||
*/
|
||||
Crypto.prototype.bootstrapCrossSigning = async function({
|
||||
authUploadDeviceSigningKeys,
|
||||
setupNewCrossSigning,
|
||||
} = {}) {
|
||||
logger.log("Bootstrapping cross-signing");
|
||||
|
||||
const delegateCryptoCallbacks = this._baseApis._cryptoCallbacks;
|
||||
const builder = new EncryptionSetupBuilder(
|
||||
this._baseApis.store.accountData,
|
||||
delegateCryptoCallbacks,
|
||||
);
|
||||
const crossSigningInfo = new CrossSigningInfo(
|
||||
this._userId,
|
||||
builder.crossSigningCallbacks,
|
||||
builder.crossSigningCallbacks,
|
||||
);
|
||||
|
||||
// Reset the cross-signing keys
|
||||
const resetCrossSigning = async () => {
|
||||
crossSigningInfo.resetKeys();
|
||||
// Sign master key with device key
|
||||
await this._signObject(crossSigningInfo.keys.master);
|
||||
|
||||
// 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);
|
||||
const deviceSignature = await crossSigningInfo.signDevice(this._userId, device);
|
||||
builder.addKeySignature(this._userId, this._deviceId, deviceSignature);
|
||||
|
||||
// Sign message key backup with cross-signing master key
|
||||
if (this.backupInfo) {
|
||||
await crossSigningInfo.signObject(this.backupInfo.auth_data, "master");
|
||||
builder.addSessionBackup(this.backupInfo);
|
||||
}
|
||||
};
|
||||
|
||||
const publicKeysOnDevice = this._crossSigningInfo.getId();
|
||||
const privateKeysInCache = await this._crossSigningInfo.isStoredInKeyCache();
|
||||
const privateKeysInStorage = await this._crossSigningInfo.isStoredInSecretStorage(
|
||||
this._secretStorage,
|
||||
);
|
||||
const privateKeysExistSomewhere = (
|
||||
privateKeysInCache ||
|
||||
privateKeysInStorage
|
||||
);
|
||||
|
||||
// Log all relevant state for easier parsing of debug logs.
|
||||
logger.log({
|
||||
setupNewCrossSigning,
|
||||
publicKeysOnDevice,
|
||||
privateKeysInCache,
|
||||
privateKeysInStorage,
|
||||
privateKeysExistSomewhere,
|
||||
});
|
||||
|
||||
if (!privateKeysExistSomewhere || setupNewCrossSigning) {
|
||||
logger.log(
|
||||
"Cross-signing private keys not found locally or in secret storage, " +
|
||||
"creating new keys",
|
||||
);
|
||||
// If a user has multiple devices, it important to only call bootstrap
|
||||
// as part of some UI flow (and not silently during startup), as they
|
||||
// may have setup cross-signing on a platform which has not saved keys
|
||||
// to secret storage, and this would reset them. In such a case, you
|
||||
// should prompt the user to verify any existing devices first (and
|
||||
// request private keys from those devices) before calling bootstrap.
|
||||
await resetCrossSigning();
|
||||
} else if (publicKeysOnDevice && privateKeysInCache) {
|
||||
logger.log(
|
||||
"Cross-signing public keys trusted and private keys found locally",
|
||||
);
|
||||
} else if (privateKeysInStorage) {
|
||||
logger.log(
|
||||
"Cross-signing private keys not found locally, but they are available " +
|
||||
"in secret storage, reading storage and caching locally",
|
||||
);
|
||||
await this.checkOwnCrossSigningTrust();
|
||||
}
|
||||
|
||||
// Assuming no app-supplied callback, default to storing new private keys in
|
||||
// secret storage if it exists. If it does not, it is assumed this will be
|
||||
// done as part of setting up secret storage later.
|
||||
const crossSigningPrivateKeys = builder.crossSigningCallbacks.privateKeys;
|
||||
if (
|
||||
crossSigningPrivateKeys.size &&
|
||||
!this._baseApis._cryptoCallbacks.saveCrossSigningKeys
|
||||
) {
|
||||
const secretStorage = new SecretStorage(
|
||||
builder.accountDataClientAdapter,
|
||||
builder.ssssCryptoCallbacks);
|
||||
if (await secretStorage.hasKey()) {
|
||||
logger.log("Storing new cross-signing private keys in secret storage");
|
||||
// This is writing to in-memory account data in
|
||||
// builder.accountDataClientAdapter so won't fail
|
||||
await CrossSigningInfo.storeInSecretStorage(
|
||||
crossSigningPrivateKeys,
|
||||
secretStorage,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const operation = builder.buildOperation();
|
||||
await operation.apply(this);
|
||||
// This persists private keys and public keys as trusted,
|
||||
// only do this if apply succeeded for now as retry isn't in place yet
|
||||
await builder.persist(this);
|
||||
|
||||
logger.log("Cross-signing ready");
|
||||
};
|
||||
|
||||
/**
|
||||
* Bootstrap Secure Secret Storage if needed by creating a default key. If everything is
|
||||
* already set up, then no changes are made, so this is safe to run to ensure secret
|
||||
* storage is ready for use.
|
||||
*
|
||||
* This function
|
||||
* - creates a new Secure Secret Storage key if no default key exists
|
||||
@@ -449,12 +611,8 @@ Crypto.prototype.isCrossSigningReady = async function() {
|
||||
* - migrates Secure Secret Storage to use the latest algorithm, if an outdated
|
||||
* algorithm is found
|
||||
*
|
||||
* @param {function} opts.authUploadDeviceSigningKeys 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.
|
||||
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
|
||||
*
|
||||
* @param {function} [opts.createSecretStorageKey] Optional. Function
|
||||
* called to await a secret storage key creation flow.
|
||||
* Returns:
|
||||
@@ -474,9 +632,7 @@ Crypto.prototype.isCrossSigningReady = async function() {
|
||||
* {Promise} A promise which resolves to key creation data for
|
||||
* SecretStorage#addKey: an object with `passphrase` and/or `pubkey` fields.
|
||||
*/
|
||||
|
||||
Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
authUploadDeviceSigningKeys,
|
||||
createSecretStorageKey = async () => ({ }),
|
||||
keyBackupInfo,
|
||||
setupNewKeyBackup,
|
||||
@@ -491,11 +647,8 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
);
|
||||
const secretStorage = new SecretStorage(
|
||||
builder.accountDataClientAdapter,
|
||||
builder.ssssCryptoCallbacks);
|
||||
const crossSigningInfo = new CrossSigningInfo(
|
||||
this._userId,
|
||||
builder.crossSigningCallbacks,
|
||||
builder.crossSigningCallbacks);
|
||||
builder.ssssCryptoCallbacks,
|
||||
);
|
||||
|
||||
// the ID of the new SSSS key, if we create one
|
||||
let newKeyId = null;
|
||||
@@ -520,27 +673,6 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
return keyId;
|
||||
};
|
||||
|
||||
// reset the cross-signing keys
|
||||
const resetCrossSigning = async () => {
|
||||
crossSigningInfo.resetKeys();
|
||||
// sign master key with device key
|
||||
await this._signObject(crossSigningInfo.keys.master);
|
||||
|
||||
// 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);
|
||||
const deviceSignature = await crossSigningInfo.signDevice(this._userId, device);
|
||||
builder.addKeySignature(this._userId, this._deviceId, deviceSignature);
|
||||
|
||||
if (keyBackupInfo) {
|
||||
await crossSigningInfo.signObject(keyBackupInfo.auth_data, "master");
|
||||
builder.addSessionBackup(keyBackupInfo);
|
||||
}
|
||||
};
|
||||
|
||||
const ensureCanCheckPassphrase = async (keyId, keyInfo) => {
|
||||
if (!keyInfo.mac) {
|
||||
const key = await this._baseApis._cryptoCallbacks.getSecretStorageKey(
|
||||
@@ -562,46 +694,45 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
|
||||
const oldSSSSKey = await this.getSecretStorageKey();
|
||||
const [oldKeyId, oldKeyInfo] = oldSSSSKey || [null, null];
|
||||
const decryptionKeys =
|
||||
await this._crossSigningInfo.isStoredInSecretStorage(this._secretStorage);
|
||||
const inStorage = !setupNewSecretStorage && decryptionKeys;
|
||||
const storageExists = (
|
||||
!setupNewSecretStorage &&
|
||||
oldKeyInfo &&
|
||||
oldKeyInfo.algorithm === SECRET_STORAGE_ALGORITHM_V1_AES
|
||||
);
|
||||
|
||||
if (!inStorage && !keyBackupInfo) {
|
||||
// Log all relevant state for easier parsing of debug logs.
|
||||
logger.log({
|
||||
keyBackupInfo,
|
||||
setupNewKeyBackup,
|
||||
setupNewSecretStorage,
|
||||
storageExists,
|
||||
oldKeyInfo,
|
||||
});
|
||||
|
||||
if (!storageExists && !keyBackupInfo) {
|
||||
// either we don't have anything, or we've been asked to restart
|
||||
// from scratch
|
||||
logger.log(
|
||||
"Cross-signing private keys not found in secret storage, " +
|
||||
"creating new keys",
|
||||
"Secret storage does not exist, creating new storage key",
|
||||
);
|
||||
|
||||
await resetCrossSigning();
|
||||
|
||||
if (
|
||||
setupNewSecretStorage ||
|
||||
!oldKeyInfo ||
|
||||
oldKeyInfo.algorithm !== SECRET_STORAGE_ALGORITHM_V1_AES
|
||||
) {
|
||||
// if we already have a usable default SSSS key and aren't resetting SSSS just use it.
|
||||
// otherwise, create a new one
|
||||
// Note: we leave the old SSSS key in place: there could be other secrets using it, in theory.
|
||||
// We could move them to the new key but a) that would mean we'd need to prompt for the old
|
||||
// passphrase, and b) it's not clear that would be the right thing to do anyway.
|
||||
const { keyInfo, privateKey } = await createSecretStorageKey();
|
||||
newKeyId = await createSSSS(keyInfo, privateKey);
|
||||
}
|
||||
} else if (!inStorage && keyBackupInfo) {
|
||||
// if we already have a usable default SSSS key and aren't resetting
|
||||
// SSSS just use it. otherwise, create a new one
|
||||
// Note: we leave the old SSSS key in place: there could be other
|
||||
// secrets using it, in theory. We could move them to the new key but a)
|
||||
// that would mean we'd need to prompt for the old passphrase, and b)
|
||||
// it's not clear that would be the right thing to do anyway.
|
||||
const { keyInfo, privateKey } = await createSecretStorageKey();
|
||||
newKeyId = await createSSSS(keyInfo, privateKey);
|
||||
} else if (!storageExists && keyBackupInfo) {
|
||||
// we have an existing backup, but no SSSS
|
||||
|
||||
logger.log("Secret storage default key not found, using key backup key");
|
||||
logger.log("Secret storage does not exist, using key backup key");
|
||||
|
||||
// if we have the backup key already cached, use it; otherwise use the
|
||||
// callback to prompt for the key
|
||||
const backupKey = await this.getSessionBackupPrivateKey() ||
|
||||
await getKeyBackupPassphrase();
|
||||
|
||||
// create new cross-signing keys
|
||||
await resetCrossSigning();
|
||||
|
||||
// create a new SSSS key and use the backup key as the new SSSS key
|
||||
const opts = {};
|
||||
|
||||
@@ -625,36 +756,26 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
);
|
||||
|
||||
// The backup is trusted because the user provided the private key.
|
||||
// Sign the backup with the cross signing key so the key backup can
|
||||
// Sign the backup with the cross-signing key so the key backup can
|
||||
// be trusted via cross-signing.
|
||||
logger.log("Adding cross signing signature to key backup");
|
||||
await crossSigningInfo.signObject(
|
||||
keyBackupInfo.auth_data, "master",
|
||||
);
|
||||
builder.addSessionBackup(keyBackupInfo);
|
||||
} else if (!this._crossSigningInfo.getId()) {
|
||||
// we have SSSS, but we don't know if the server's cross-signing
|
||||
// keys should be trusted
|
||||
logger.log("Cross-signing private keys found in secret storage");
|
||||
|
||||
// TODO: take this use case out of bootstrapping
|
||||
// fetch the private keys and set up our local copy of the keys for
|
||||
// use
|
||||
//
|
||||
// so if some other device resets the cross-signing keys,
|
||||
// we mark them as untrusted from _onDeviceListUserCrossSigningUpdated
|
||||
// you can either fix this by hitting the verify this session which (might?) call this method,
|
||||
// or the reset button in the settings
|
||||
await this.checkOwnCrossSigningTrust();
|
||||
|
||||
if (oldKeyInfo && oldKeyInfo.algorithm === SECRET_STORAGE_ALGORITHM_V1_AES) {
|
||||
// make sure that the default key has the information needed to
|
||||
// check the passphrase
|
||||
await ensureCanCheckPassphrase(oldKeyId, oldKeyInfo);
|
||||
if (
|
||||
this._crossSigningInfo.getId() &&
|
||||
this._crossSigningInfo.isStoredInKeyCache("master")
|
||||
) {
|
||||
logger.log("Adding cross-signing signature to key backup");
|
||||
await this._crossSigningInfo.signObject(
|
||||
keyBackupInfo.auth_data, "master",
|
||||
);
|
||||
} else {
|
||||
logger.warn(
|
||||
"Cross-signing keys not available, skipping signature on key backup",
|
||||
);
|
||||
}
|
||||
|
||||
builder.addSessionBackup(keyBackupInfo);
|
||||
} else {
|
||||
// we have SSSS and we cross-signing is already set up
|
||||
logger.log("Cross signing keys are present in secret storage");
|
||||
// 4S is already set up
|
||||
logger.log("Secret storage exists");
|
||||
|
||||
if (oldKeyInfo && oldKeyInfo.algorithm === SECRET_STORAGE_ALGORITHM_V1_AES) {
|
||||
// make sure that the default key has the information needed to
|
||||
@@ -663,21 +784,26 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
}
|
||||
}
|
||||
|
||||
const crossSigningPrivateKeys = builder.crossSigningCallbacks.privateKeys;
|
||||
if (crossSigningPrivateKeys.size) {
|
||||
logger.log("Storing cross-signing private keys in secret storage");
|
||||
// Assuming no app-supplied callback, default to storing in SSSS.
|
||||
if (!this._baseApis._cryptoCallbacks.saveCrossSigningKeys) {
|
||||
// this is writing to in-memory account data in builder.accountDataClientAdapter
|
||||
// so won't fail
|
||||
await CrossSigningInfo.storeInSecretStorage(
|
||||
crossSigningPrivateKeys,
|
||||
secretStorage,
|
||||
);
|
||||
}
|
||||
// If we have cross-signing private keys cached, store them in secret
|
||||
// storage if they are not there already.
|
||||
if (
|
||||
!this._baseApis._cryptoCallbacks.saveCrossSigningKeys &&
|
||||
await this.isCrossSigningReady() &&
|
||||
(newKeyId || !await this._crossSigningInfo.isStoredInSecretStorage(secretStorage))
|
||||
) {
|
||||
logger.log("Copying cross-signing private keys from cache to secret storage");
|
||||
const crossSigningPrivateKeys =
|
||||
await this._crossSigningInfo.getCrossSigningKeysFromCache();
|
||||
// This is writing to in-memory account data in
|
||||
// builder.accountDataClientAdapter so won't fail
|
||||
await CrossSigningInfo.storeInSecretStorage(
|
||||
crossSigningPrivateKeys,
|
||||
secretStorage,
|
||||
);
|
||||
}
|
||||
|
||||
if (setupNewKeyBackup && !keyBackupInfo) {
|
||||
logger.log("Creating new message key backup version");
|
||||
const info = await this._baseApis.prepareKeyBackupVersion(
|
||||
null /* random key */,
|
||||
// don't write to secret storage, as it will write to this._secretStorage.
|
||||
@@ -694,16 +820,27 @@ Crypto.prototype.bootstrapSecretStorage = async function({
|
||||
algorithm: info.algorithm,
|
||||
auth_data: info.auth_data,
|
||||
};
|
||||
// sign with cross-sign master key
|
||||
await crossSigningInfo.signObject(data.auth_data, "master");
|
||||
|
||||
if (
|
||||
this._crossSigningInfo.getId() &&
|
||||
this._crossSigningInfo.isStoredInKeyCache("master")
|
||||
) {
|
||||
// sign with cross-sign master key
|
||||
logger.log("Adding cross-signing signature to key backup");
|
||||
await this._crossSigningInfo.signObject(data.auth_data, "master");
|
||||
} else {
|
||||
logger.warn(
|
||||
"Cross-signing keys not available, skipping signature on key backup",
|
||||
);
|
||||
}
|
||||
|
||||
// sign with the device fingerprint
|
||||
await this._signObject(data.auth_data);
|
||||
|
||||
|
||||
builder.addSessionBackup(data);
|
||||
}
|
||||
|
||||
// and likewise for the session backup key
|
||||
// Cache the session backup key
|
||||
const sessionBackupKey = await secretStorage.get('m.megolm_backup.v1');
|
||||
if (sessionBackupKey) {
|
||||
logger.info("Got session backup key from secret storage: caching");
|
||||
@@ -1184,23 +1321,20 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
|
||||
const seenPubkey = newCrossSigning.getId();
|
||||
const masterChanged = this._crossSigningInfo.getId() !== seenPubkey;
|
||||
if (masterChanged) {
|
||||
// try to get the private key if the master key changed
|
||||
logger.info("Got new master public key", seenPubkey);
|
||||
|
||||
logger.info("Attempting to retrieve cross-signing master private key");
|
||||
let signing = null;
|
||||
try {
|
||||
const ret = await this._crossSigningInfo.getCrossSigningKey(
|
||||
'master', seenPubkey,
|
||||
);
|
||||
signing = ret[1];
|
||||
if (!signing) {
|
||||
throw new Error("Cross-signing master private key not available");
|
||||
}
|
||||
logger.info("Got cross-signing master private key");
|
||||
} catch (e) {
|
||||
logger.error("Cross-signing master private key not available", e);
|
||||
} finally {
|
||||
if (signing) signing.free();
|
||||
}
|
||||
|
||||
logger.info("Got matching private key from callback for new public master key");
|
||||
}
|
||||
|
||||
const oldSelfSigningId = this._crossSigningInfo.getId("self_signing");
|
||||
@@ -1209,21 +1343,23 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
|
||||
// Update the version of our keys in our cross-signing object and the local store
|
||||
this._storeTrustedSelfKeys(newCrossSigning.keys);
|
||||
|
||||
const selfSigningChanged = oldSelfSigningId !== newCrossSigning.getId("self_signing");
|
||||
const userSigningChanged = oldUserSigningId !== newCrossSigning.getId("user_signing");
|
||||
|
||||
const keySignatures = {};
|
||||
|
||||
if (oldSelfSigningId !== newCrossSigning.getId("self_signing")) {
|
||||
if (selfSigningChanged) {
|
||||
logger.info("Got new self-signing key", newCrossSigning.getId("self_signing"));
|
||||
|
||||
// Try to cache the self-signing private key as a side-effect
|
||||
logger.info("Attempting to retrieve cross-signing self-signing private key");
|
||||
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",
|
||||
);
|
||||
logger.info("Got cross-signing self-signing private key");
|
||||
} catch (e) {
|
||||
logger.error("Cross-signing self-signing private key not available", e);
|
||||
} finally {
|
||||
if (signing) signing.free();
|
||||
}
|
||||
@@ -1234,19 +1370,18 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
|
||||
);
|
||||
keySignatures[this._deviceId] = signedDevice;
|
||||
}
|
||||
if (oldUserSigningId !== newCrossSigning.getId("user_signing")) {
|
||||
if (userSigningChanged) {
|
||||
logger.info("Got new user-signing key", newCrossSigning.getId("user_signing"));
|
||||
|
||||
// Try to cache the user-signing private key as a side-effect
|
||||
logger.info("Attempting to retrieve cross-signing user-signing private key");
|
||||
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",
|
||||
);
|
||||
logger.info("Got cross-signing user-signing private key");
|
||||
} catch (e) {
|
||||
logger.error("Cross-signing user-signing private key not available", e);
|
||||
} finally {
|
||||
if (signing) signing.free();
|
||||
}
|
||||
@@ -2025,9 +2160,18 @@ Crypto.prototype.setDeviceVerification = async function(
|
||||
// do cross-signing
|
||||
if (verified && userId === this._userId) {
|
||||
logger.info("Own device " + deviceId + " marked verified: signing");
|
||||
const device = await this._crossSigningInfo.signDevice(
|
||||
userId, DeviceInfo.fromStorage(dev, deviceId),
|
||||
);
|
||||
|
||||
// Signing only needed if other device not already signed
|
||||
let device;
|
||||
const deviceTrust = this.checkDeviceTrust(userId, deviceId);
|
||||
if (deviceTrust.isCrossSigningVerified()) {
|
||||
logger.log(`Own device ${deviceId} already cross-signing verified`);
|
||||
} else {
|
||||
device = await this._crossSigningInfo.signDevice(
|
||||
userId, DeviceInfo.fromStorage(dev, deviceId),
|
||||
);
|
||||
}
|
||||
|
||||
if (device) {
|
||||
const upload = async ({shouldEmit}) => {
|
||||
logger.info("Uploading signature for " + deviceId);
|
||||
|
||||
+4
-6
@@ -651,12 +651,10 @@ MatrixHttpApi.prototype = {
|
||||
|
||||
const self = this;
|
||||
if (this.opts.extraParams) {
|
||||
for (const key in this.opts.extraParams) {
|
||||
if (!this.opts.extraParams.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
queryParams[key] = this.opts.extraParams[key];
|
||||
}
|
||||
queryParams = {
|
||||
...queryParams,
|
||||
...this.opts.extraParams,
|
||||
};
|
||||
}
|
||||
|
||||
const headers = utils.extend({}, opts.headers || {});
|
||||
|
||||
@@ -120,6 +120,42 @@ interface ICreateClientOpts {
|
||||
cryptoStore?: CryptoStore;
|
||||
scheduler?: MatrixScheduler;
|
||||
request?: Request;
|
||||
userId?: string;
|
||||
deviceId?: string;
|
||||
accessToken?: string;
|
||||
identityServer?: any;
|
||||
localTimeoutMs?: number;
|
||||
useAuthorizationHeader?: boolean;
|
||||
queryParams?: Record<string, unknown>;
|
||||
deviceToImport?: {
|
||||
olmDevice: {
|
||||
pickledAccount: string;
|
||||
sessions: Array<Record<string, any>>;
|
||||
pickleKey: string;
|
||||
};
|
||||
userId: string;
|
||||
deviceId: string;
|
||||
};
|
||||
sessionStore?: any;
|
||||
unstableClientRelationAggregation?: boolean;
|
||||
verificationMethods?: Array<any>;
|
||||
forceTURN?: boolean;
|
||||
fallbackICEServerAllowed?: boolean;
|
||||
cryptoCallbacks?: {
|
||||
getCrossSigningKey?: (keyType: string, pubKey: Uint8Array) => Promise<Uint8Array>;
|
||||
saveCrossSigningKeys?: (keys: Record<string, Uint8Array>) => unknown;
|
||||
shouldUpgradeDeviceVerifications?: (
|
||||
users: Record<string, any>
|
||||
) => Promise<Array<string>>;
|
||||
getSecretStorageKey?: (
|
||||
keys: {keys: Record<string, {pubkey: Uint8Array}>}, name: string
|
||||
) => Promise<[string, Uint8Array] | null>;
|
||||
cacheSecretStorageKey?: (keyId: string, key: Uint8Array) => unknown;
|
||||
onSecretRequested?: (
|
||||
name: string, userId: string, deviceId: string,
|
||||
requestId: string, deviceTrust: any
|
||||
) => Promise<string>;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+23
-3
@@ -92,6 +92,8 @@ export function MatrixCall(opts) {
|
||||
this.screenSharingStream = null;
|
||||
|
||||
this._answerContent = null;
|
||||
|
||||
this._sentEndOfCandidates = false;
|
||||
}
|
||||
/** The length of time a call can be ringing for. */
|
||||
MatrixCall.CALL_TIMEOUT_MS = 60000;
|
||||
@@ -703,12 +705,29 @@ MatrixCall.prototype._gotLocalIceCandidate = function(event) {
|
||||
|
||||
// As with the offer, note we need to make a copy of this object, not
|
||||
// pass the original: that broke in Chrome ~m43.
|
||||
if (event.candidate.candidate !== '' || !this._sentEndOfCandidates) {
|
||||
const c = {
|
||||
candidate: event.candidate.candidate,
|
||||
sdpMid: event.candidate.sdpMid,
|
||||
sdpMLineIndex: event.candidate.sdpMLineIndex,
|
||||
};
|
||||
sendCandidate(this, c);
|
||||
|
||||
if (event.candidate.candidate === '') this._sentEndOfCandidates = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MatrixCall.prototype._onIceGatheringStateChange = function(event) {
|
||||
debuglog("ice gathering state changed to " + this.peerConn.iceGatheringState);
|
||||
if (this.peerConn.iceGatheringState === 'complete' && !this._sentEndOfCandidates) {
|
||||
// If we didn't get an empty-string candidate to signal the end of candidates,
|
||||
// create one ourselves now gathering has finished.
|
||||
const c = {
|
||||
candidate: event.candidate.candidate,
|
||||
sdpMid: event.candidate.sdpMid,
|
||||
sdpMLineIndex: event.candidate.sdpMLineIndex,
|
||||
candidate: '',
|
||||
};
|
||||
sendCandidate(this, c);
|
||||
this._sentEndOfCandidates = true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1231,6 +1250,7 @@ const _createPeerConnection = function(self) {
|
||||
pc.oniceconnectionstatechange = hookCallback(self, self._onIceConnectionStateChanged);
|
||||
pc.onsignalingstatechange = hookCallback(self, self._onSignallingStateChanged);
|
||||
pc.onicecandidate = hookCallback(self, self._gotLocalIceCandidate);
|
||||
pc.onicegatheringstatechange = hookCallback(self, self._onIceGatheringStateChange);
|
||||
pc.onaddstream = hookCallback(self, self._onAddStream);
|
||||
return pc;
|
||||
};
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
invariant "^2.2.4"
|
||||
semver "^5.5.0"
|
||||
|
||||
"@babel/core@^7.0.0", "@babel/core@^7.1.0", "@babel/core@^7.7.5":
|
||||
"@babel/core@^7.1.0", "@babel/core@^7.7.5":
|
||||
version "7.10.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.2.tgz#bd6786046668a925ac2bd2fd95b579b92a23b36a"
|
||||
integrity sha512-KQmV9yguEjQsXqyOUGKjS4+3K8/DlOCE2pZcq4augdQmtTy5iv5EHtmMSJ7V4c1BIPjuwtZYqYLCq9Ga+hGBRQ==
|
||||
@@ -268,11 +268,16 @@
|
||||
chalk "^2.0.0"
|
||||
js-tokens "^4.0.0"
|
||||
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.10.1", "@babel/parser@^7.10.2", "@babel/parser@^7.2.3", "@babel/parser@^7.4.3", "@babel/parser@^7.7.0", "@babel/parser@^7.9.4":
|
||||
"@babel/parser@^7.1.0", "@babel/parser@^7.10.1", "@babel/parser@^7.10.2", "@babel/parser@^7.4.3", "@babel/parser@^7.7.0", "@babel/parser@^7.9.4":
|
||||
version "7.10.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.2.tgz#871807f10442b92ff97e4783b9b54f6a0ca812d0"
|
||||
integrity sha512-PApSXlNMJyB4JiGVhCOlzKIif+TKFTvu0aQAhnTvfP/z3vVSN6ZypH5bfUNwFXXjRQtUEBNFd2PtmCmG2Py3qQ==
|
||||
|
||||
"@babel/parser@^7.2.3":
|
||||
version "7.11.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.11.5.tgz#c7ff6303df71080ec7a4f5b8c003c58f1cf51037"
|
||||
integrity sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==
|
||||
|
||||
"@babel/plugin-proposal-async-generator-functions@^7.10.1":
|
||||
version "7.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.1.tgz#6911af5ba2e615c4ff3c497fe2f47b35bf6d7e55"
|
||||
@@ -711,9 +716,9 @@
|
||||
"@babel/helper-plugin-utils" "^7.10.1"
|
||||
|
||||
"@babel/polyfill@^7.4.4":
|
||||
version "7.10.1"
|
||||
resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.10.1.tgz#d56d4c8be8dd6ec4dce2649474e9b707089f739f"
|
||||
integrity sha512-TviueJ4PBW5p48ra8IMtLXVkDucrlOZAIZ+EXqS3Ot4eukHbWiqcn7DcqpA1k5PcKtmJ4Xl9xwdv6yQvvcA+3g==
|
||||
version "7.11.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/polyfill/-/polyfill-7.11.5.tgz#df550b2ec53abbc2ed599367ec59e64c7a707bb5"
|
||||
integrity sha512-FunXnE0Sgpd61pKSj2OSOs1D44rKTD3pGOfGilZ6LGrrIH0QEtJlTjqOqdF8Bs98JmjfGhni2BBkTfv9KcKJ9g==
|
||||
dependencies:
|
||||
core-js "^2.6.5"
|
||||
regenerator-runtime "^0.13.4"
|
||||
@@ -818,7 +823,14 @@
|
||||
pirates "^4.0.0"
|
||||
source-map-support "^0.5.16"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4":
|
||||
"@babel/runtime@^7.7.6":
|
||||
version "7.11.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
|
||||
integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4":
|
||||
version "7.10.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.10.2.tgz#d103f21f2602497d38348a32e008637d506db839"
|
||||
integrity sha512-6sF3uQw2ivImfVIl62RZ7MXhO2tap69WeWK57vAaimT6AZbE4FbqjdEJIN1UqoD6wI6B+1n9UiagafH1sxjOtg==
|
||||
@@ -1015,9 +1027,9 @@
|
||||
"@types/yargs" "^13.0.0"
|
||||
|
||||
"@types/babel-types@*", "@types/babel-types@^7.0.0":
|
||||
version "7.0.7"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.7.tgz#667eb1640e8039436028055737d2b9986ee336e3"
|
||||
integrity sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ==
|
||||
version "7.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@types/babel-types/-/babel-types-7.0.9.tgz#01d7b86949f455402a94c788883fe4ba574cad41"
|
||||
integrity sha512-qZLoYeXSTgQuK1h7QQS16hqLGdmqtRmN8w/rl3Au/l5x/zkHx+a4VHrHyBsi1I1vtK2oBHxSzKIu0R5p6spdOA==
|
||||
|
||||
"@types/babel__core@^7.1.0":
|
||||
version "7.1.8"
|
||||
@@ -1484,6 +1496,13 @@ ast-types@0.12.4, ast-types@^0.12.2:
|
||||
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.12.4.tgz#71ce6383800f24efc9a1a3308f3a6e420a0974d1"
|
||||
integrity sha512-ky/YVYCbtVAS8TdMIaTiPFHwEpRB5z1hctepJplTr3UW5q8TDrpIMCILyk8pmLxGtn2KCtC/lSn7zOsaI7nzDw==
|
||||
|
||||
ast-types@^0.13.2:
|
||||
version "0.13.4"
|
||||
resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782"
|
||||
integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==
|
||||
dependencies:
|
||||
tslib "^2.0.1"
|
||||
|
||||
astral-regex@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
|
||||
@@ -1499,13 +1518,6 @@ async-limiter@~1.0.0:
|
||||
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"
|
||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||
@@ -1653,14 +1665,14 @@ bcrypt-pbkdf@^1.0.0:
|
||||
dependencies:
|
||||
tweetnacl "^0.14.3"
|
||||
|
||||
better-docs@^1.4.7:
|
||||
version "1.4.13"
|
||||
resolved "https://registry.yarnpkg.com/better-docs/-/better-docs-1.4.13.tgz#6c9b44a27b31e536e5da5920cfac11e8720e4c5a"
|
||||
integrity sha512-9lT9icIKOyOvZTs3M7yk05eg9EWsC7kpQK2VlsZlhkFLXaI8DUShkm9p9cv7NwLlGh1Q6p/bWeRxqmize+jBWg==
|
||||
better-docs@^2.3.2:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/better-docs/-/better-docs-2.3.2.tgz#0de059301c49669a4350409d8c235868cf8bcbf7"
|
||||
integrity sha512-VlbXQgEftaynJSaPa853XB5WqTlPoQQr2TnxIkKi6OsyJJxF42Ke+9SIES/hqTe58aaBnuoDGrIzOso8RdNx6Q==
|
||||
dependencies:
|
||||
brace "^0.11.1"
|
||||
react-ace "^6.5.0"
|
||||
react-docgen "^4.1.1"
|
||||
react-docgen "^5.3.0"
|
||||
react-frame-component "^4.1.1"
|
||||
typescript "^3.7.5"
|
||||
underscore "^1.9.1"
|
||||
@@ -2473,6 +2485,11 @@ diffie-hellman@^5.0.0:
|
||||
miller-rabin "^4.0.0"
|
||||
randombytes "^2.0.0"
|
||||
|
||||
docdash@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/docdash/-/docdash-1.2.0.tgz#f99dde5b8a89aa4ed083a3150383e042d06c7f49"
|
||||
integrity sha512-IYZbgYthPTspgqYeciRJNPhSwL51yer7HAwDXhF5p+H7mTDbPvY3PCk/QDjNxdPCpWkaJVFC4t7iCNB/t9E5Kw==
|
||||
|
||||
doctrine@1.5.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa"
|
||||
@@ -4352,10 +4369,10 @@ jsbn@~0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
||||
|
||||
jsdoc@^3.5.5:
|
||||
version "3.6.4"
|
||||
resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.6.4.tgz#246b2832a0ea8b37a441b61745509cfe29e174b6"
|
||||
integrity sha512-3G9d37VHv7MFdheviDCjUfQoIjdv4TC5zTTf5G9VODLtOnVS6La1eoYBDlbWfsRT3/Xo+j2MIqki2EV12BZfwA==
|
||||
jsdoc@^3.6.5:
|
||||
version "3.6.5"
|
||||
resolved "https://registry.yarnpkg.com/jsdoc/-/jsdoc-3.6.5.tgz#e004372ca6f2dcdf19b3d2ebcd7c725528485502"
|
||||
integrity sha512-SbY+i9ONuxSK35cgVHaI8O9senTE4CDYAmGSDJ5l3+sfe62Ff4gy96osy6OW84t4K4A8iGnMrlRrsSItSNp3RQ==
|
||||
dependencies:
|
||||
"@babel/parser" "^7.9.4"
|
||||
bluebird "^3.7.2"
|
||||
@@ -4641,7 +4658,7 @@ lodash.sortby@^4.7.0:
|
||||
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
||||
|
||||
lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4:
|
||||
lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15:
|
||||
version "4.17.15"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
|
||||
integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==
|
||||
@@ -4651,6 +4668,11 @@ lodash@^4.17.16:
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
|
||||
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
|
||||
|
||||
lodash@^4.17.4:
|
||||
version "4.17.20"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
|
||||
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
|
||||
|
||||
loglevel@^1.6.4:
|
||||
version "1.6.8"
|
||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171"
|
||||
@@ -4795,6 +4817,11 @@ mimic-fn@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
|
||||
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
|
||||
|
||||
min-indent@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869"
|
||||
integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==
|
||||
|
||||
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"
|
||||
@@ -4918,6 +4945,11 @@ natural-compare@^1.4.0:
|
||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
|
||||
|
||||
neo-async@^2.6.1:
|
||||
version "2.6.2"
|
||||
resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
|
||||
integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
|
||||
|
||||
nice-try@^1.0.4:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
||||
@@ -5627,23 +5659,24 @@ react-ace@^6.5.0:
|
||||
lodash.isequal "^4.5.0"
|
||||
prop-types "^15.7.2"
|
||||
|
||||
react-docgen@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-4.1.1.tgz#8fef0212dbf14733e09edecef1de6b224d87219e"
|
||||
integrity sha512-o1wdswIxbgJRI4pckskE7qumiFyqkbvCO++TylEDOo2RbMiueIOg8YzKU4X9++r0DjrbXePw/LHnh81GRBTWRw==
|
||||
react-docgen@^5.3.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/react-docgen/-/react-docgen-5.3.0.tgz#9aabde5e69f1993c8ba839fd9a86696504654589"
|
||||
integrity sha512-hUrv69k6nxazOuOmdGeOpC/ldiKy7Qj/UFpxaQi0eDMrUFUTIPGtY5HJu7BggSmiyAMfREaESbtBL9UzdQ+hyg==
|
||||
dependencies:
|
||||
"@babel/core" "^7.0.0"
|
||||
"@babel/runtime" "^7.0.0"
|
||||
async "^2.1.4"
|
||||
"@babel/core" "^7.7.5"
|
||||
"@babel/runtime" "^7.7.6"
|
||||
ast-types "^0.13.2"
|
||||
commander "^2.19.0"
|
||||
doctrine "^3.0.0"
|
||||
neo-async "^2.6.1"
|
||||
node-dir "^0.1.10"
|
||||
recast "^0.17.3"
|
||||
strip-indent "^3.0.0"
|
||||
|
||||
react-frame-component@^4.1.1:
|
||||
version "4.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-frame-component/-/react-frame-component-4.1.2.tgz#c88fcc1e73fbe83eea6c82d95d66eefe44cd1ea4"
|
||||
integrity sha512-gWTtpOoi8Mgxayj0iWLL3SXRu2jW4eW4oim6B/FycaOH9HHIsCTPulC9u7CZ2BwY0CtqA+v8FsINp6qPuaN6qQ==
|
||||
version "4.1.3"
|
||||
resolved "https://registry.yarnpkg.com/react-frame-component/-/react-frame-component-4.1.3.tgz#64c09dd29574720879c5f43ee36c17d8ae74d4ec"
|
||||
integrity sha512-4PurhctiqnmC1F5prPZ+LdsalH7pZ3SFA5xoc0HBe8mSHctdLLt4Cr2WXfXOoajHBYq/yiipp9zOgx+vy8GiEA==
|
||||
|
||||
react-is@^16.8.1, react-is@^16.8.4:
|
||||
version "16.13.1"
|
||||
@@ -6472,6 +6505,13 @@ strip-eof@^1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
|
||||
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
|
||||
|
||||
strip-indent@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
|
||||
integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
|
||||
dependencies:
|
||||
min-indent "^1.0.0"
|
||||
|
||||
strip-json-comments@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||
@@ -6710,6 +6750,11 @@ tslib@^1.8.1, tslib@^1.9.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
|
||||
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
|
||||
|
||||
tslib@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e"
|
||||
integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==
|
||||
|
||||
tsutils@^3.17.1:
|
||||
version "3.17.1"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
|
||||
@@ -6763,16 +6808,16 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
typescript@^3.2.2, typescript@^3.7.3, typescript@^3.7.5:
|
||||
version "3.9.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36"
|
||||
integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==
|
||||
|
||||
typescript@^3.9.5:
|
||||
typescript@^3.2.2, typescript@^3.7.5, typescript@^3.9.5:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
||||
|
||||
typescript@^3.7.3:
|
||||
version "3.9.5"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.5.tgz#586f0dba300cde8be52dd1ac4f7e1009c1b13f36"
|
||||
integrity sha512-hSAifV3k+i6lEoCJ2k6R2Z/rp/H3+8sdmcn5NrS3/3kE7+RyZXm9aqvxWqjEXHAd8b0pShatpcdMTvEdvAJltQ==
|
||||
|
||||
typeson-registry@^1.0.0-alpha.20:
|
||||
version "1.0.0-alpha.37"
|
||||
resolved "https://registry.yarnpkg.com/typeson-registry/-/typeson-registry-1.0.0-alpha.37.tgz#23e6bffc264b4dfc80603e2a8545bd4750102d42"
|
||||
@@ -6823,7 +6868,12 @@ undeclared-identifiers@^1.1.2:
|
||||
simple-concat "^1.0.0"
|
||||
xtend "^4.0.1"
|
||||
|
||||
underscore@^1.9.1, underscore@~1.10.2:
|
||||
underscore@^1.9.1:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.11.0.tgz#dd7c23a195db34267186044649870ff1bab5929e"
|
||||
integrity sha512-xY96SsN3NA461qIRKZ/+qox37YXPtSBswMGfiNptr+wrt6ds4HaMw23TP612fEyGekRE6LNRiLYr/aqbHXNedw==
|
||||
|
||||
underscore@~1.10.2:
|
||||
version "1.10.2"
|
||||
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.10.2.tgz#73d6aa3668f3188e4adb0f1943bd12cfd7efaaaf"
|
||||
integrity sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==
|
||||
@@ -6987,9 +7037,9 @@ vue-docgen-api@^3.22.0:
|
||||
vue-template-compiler "^2.0.0"
|
||||
|
||||
vue-template-compiler@^2.0.0:
|
||||
version "2.6.11"
|
||||
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.11.tgz#c04704ef8f498b153130018993e56309d4698080"
|
||||
integrity sha512-KIq15bvQDrcCjpGjrAhx4mUlyyHfdmTaoNfeoATHLAiWB+MU3cx4lOzMwrnUh9cCxy0Lt1T11hAFY6TQgroUAA==
|
||||
version "2.6.12"
|
||||
resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.12.tgz#947ed7196744c8a5285ebe1233fe960437fcc57e"
|
||||
integrity sha512-OzzZ52zS41YUbkCBfdXShQTe69j1gQDZ9HIX8miuC9C3rBCk9wIRjLiZZLrmX9V+Ftq/YEyv1JaVr5Y/hNtByg==
|
||||
dependencies:
|
||||
de-indent "^1.0.2"
|
||||
he "^1.1.0"
|
||||
|
||||
Reference in New Issue
Block a user