Compare commits

...

107 Commits

Author SHA1 Message Date
RiotRobot af0b6fc6ac v8.4.0-rc.1 2020-09-23 15:10:06 +01:00
RiotRobot 6347031f61 Prepare changelog for v8.4.0-rc.1 2020-09-23 15:10:06 +01:00
J. Ryan Stinnett 3eda039898 Merge pull request #1477 from matrix-org/hs/fix-no-queryparams
If there are extraParams set, ensure that queryParams is defined
2020-09-23 14:20:55 +01:00
Will Hunt 5447d99481 If there are extraParams set, ensure that queryParams is defined 2020-09-23 14:06:39 +01:00
J. Ryan Stinnett 9d08744fe2 Merge pull request #1475 from matrix-org/jryans/security-diags
Add diagnostics to security bootstrap paths
2020-09-23 13:18:28 +01:00
J. Ryan Stinnett 848fa257ea Add diagnostics to security bootstrap paths
May help with https://github.com/vector-im/element-web/issues/15230
2020-09-23 12:37:13 +01:00
Michael Telatynski 54553fb671 Merge pull request #1459 from matrix-org/t3chguy/docdash
Switch to a combination of better-docs and docdash
2020-09-22 17:25:13 +01:00
J. Ryan Stinnett ad658ead37 Merge pull request #1474 from matrix-org/jryans/stop-sudden-key-prompts
Undo attempts to cache private keys aggressively
2020-09-21 17:00:11 +01:00
J. Ryan Stinnett c787f0e9d0 Remove redundant comment 2020-09-21 16:29:23 +01:00
J. Ryan Stinnett 6f5da701aa Undo attempts to cache private keys aggressively
This was triggering security prompts at random times (after any device list
update).

Fixes https://github.com/vector-im/element-web/issues/15250
2020-09-21 16:21:41 +01:00
J. Ryan Stinnett a01368bd60 Merge pull request #1472 from matrix-org/jryans/cross-signing-half-cached
Repair secret storage reset, cache keys when missing
2020-09-21 13:03:10 +01:00
Michael Telatynski f682097e45 Merge pull request #1471 from matrix-org/t3chguy/fix/15204
Prevent parallel getVersions calls
2020-09-18 18:08:50 +01:00
J. Ryan Stinnett 89ebffd69f Tweak error handling 2020-09-18 16:28:18 +01:00
David Baker cdeb4ead9e Merge pull request #1473 from matrix-org/dbkr/end_of_candidates
Send end-of-candidates
2020-09-18 15:46:31 +01:00
David Baker 79cc835874 Send end-of-candidates
As per https://github.com/matrix-org/matrix-doc/pull/2746
2020-09-18 15:06:41 +01:00
Travis Ralston 8df866865d Merge pull request #1470 from matrix-org/travis/e2e-default-serverside
Add a function for checking the /versions flag for forced e2ee
2020-09-18 07:50:50 -06:00
J. Ryan Stinnett fa7eff50e5 Cache cross-signing private keys if missing as well
We were only caching private keys locally on public key change, but we should
also do so if they are missing from the current session: e.g. for most users
that will be true for the master key, since previously we were not caching it.

Part of https://github.com/vector-im/element-web/issues/15230
2020-09-18 14:46:22 +01:00
Michael Telatynski 6558881952 update comment
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2020-09-18 14:29:50 +01:00
Michael Telatynski 9cbe2c985d Prevent parallel getVersions calls
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2020-09-18 14:28:37 +01:00
J. Ryan Stinnett 7769c53cd6 Skip over key when uncached
This change ensures we omit any uncached keys, rather than adding nulls. This is
helpful for future steps that might try to store all of the values in one call.

Fixes https://github.com/vector-im/element-web/issues/15230
2020-09-18 12:57:55 +01:00
Travis Ralston 7a5a47ecc7 Add a function for checking the /versions flag for forced e2ee 2020-09-17 22:44:34 -06:00
Will Hunt 8c315ebd15 Merge pull request #1469 from matrix-org/hs/usingE2EProxy-flag
Add option to allow users of pantialaimon to use the SDK
2020-09-16 17:01:11 +01:00
Will Hunt 6044b2cbad fix lint & tests 2020-09-16 16:49:51 +01:00
Will Hunt 7acfd0b423 Improve flag name and docstring
Co-authored-by: J. Ryan Stinnett <jryans@gmail.com>
2020-09-16 16:19:25 +01:00
Will Hunt e201aab440 Add 'usingE2EProxy' to allow users of pantialaimon to use the SDK 2020-09-15 17:43:17 +01:00
J. Ryan Stinnett fb25fa3a27 Merge pull request #1468 from Charly98cma/develop
Fixed Yarn broken link
2020-09-15 16:26:13 +01:00
Carlos 857ad9b180 Fixed Yarn broken link
Yarn install guide link was broken, so I just fixed.
2020-09-15 17:08:36 +02:00
Hubert Chathi 14843a1bca Merge pull request #1466 from matrix-org/uhoreg/typescript-fixes
some TypeScript and doc fixes
2020-09-15 09:17:27 -04:00
Hubert Chathi 6bdbee533c TypeScript and doc fixes 2020-09-14 18:53:48 -04:00
RiotRobot b9886d4f34 Merge branch 'master' into develop 2020-09-14 13:29:32 +01:00
RiotRobot 666cbbce08 v8.3.0 2020-09-14 13:26:27 +01:00
RiotRobot 69c575a4be Prepare changelog for v8.3.0 2020-09-14 13:26:27 +01:00
J. Ryan Stinnett c920de0d28 Merge pull request #1464 from matrix-org/jryans/remove-travis-refs
Remove Travis CI reference
2020-09-10 15:32:10 +01:00
Travis Ralston 53cdf53f63 Merge pull request #1463 from matrix-org/travis/fix-3pid-createRoom
Inject identity server token for 3pid invites on createRoom
2020-09-10 07:05:01 -06:00
J. Ryan Stinnett d9dda6aebc Remove Travis CI reference
Fixes https://github.com/vector-im/element-web/issues/15098
2020-09-10 10:16:54 +01:00
Travis Ralston 3d4a9a24ce Inject identity server token for 3pid invites on createRoom
We only inject if needed to avoid potentially overwriting the value with something unknown. The docs in the react-sdk imply this was supposed to happen.

Fixes https://github.com/vector-im/element-web/issues/14814
2020-09-09 12:33:00 -06:00
RiotRobot de339d3098 v8.3.0-rc.1 2020-09-09 15:06:48 +01:00
RiotRobot 0f83234be9 Prepare changelog for v8.3.0-rc.1 2020-09-09 15:06:47 +01:00
Michael Telatynski bcd9b45589 Switch to a combination of better-docs and docdash 2020-09-04 11:08:26 +01:00
J. Ryan Stinnett eec7c4c61b Merge pull request #1452 from dalcde/develop
Add missing options in ICreateClientOpts
2020-09-03 15:51:25 +01:00
J. Ryan Stinnett 25b4b049b7 Merge pull request #1457 from matrix-org/jryans/is-x-ready-bools
Ensure ready functions return boolean values
2020-09-02 17:30:16 +01:00
J. Ryan Stinnett 2191eb3f41 Ensure ready functions return boolean values
Fixes https://github.com/vector-im/element-web/issues/15087
2020-09-02 17:18:47 +01:00
J. Ryan Stinnett bebdbf7e05 Merge pull request #1456 from matrix-org/jryans/cross-signing-verif-errors
Handle missing cross-signing keys gracefully
2020-09-02 15:07:27 +01:00
J. Ryan Stinnett 646c091966 Skip self-signing if device already signed
When adding a device to your account, both devices attempt to sign each other
using the self-signing key, but in reality only the new device needs to be
signed. This avoids a case where web would fail verification while attempting to
sign the old device because of missing private keys (since they aren't in 4S and
it hasn't requested them from the other device yet), even though signing the old
device is redundant anyway.

Part of https://github.com/vector-im/element-web/issues/14970
2020-09-02 12:54:26 +01:00
J. Ryan Stinnett 952729cb1b Abort early if cross-signing key not found
This helps us print a better error message when the key does not exist.

Part of https://github.com/vector-im/element-web/issues/14970
2020-09-02 12:32:35 +01:00
RiotRobot c6992e2056 Merge branch 'master' into develop 2020-09-01 17:00:47 +01:00
RiotRobot 77ed79e9a9 v8.2.0 2020-09-01 16:57:34 +01:00
RiotRobot c4f4add0ec Prepare changelog for v8.2.0 2020-09-01 16:57:33 +01:00
Michael Telatynski 7eeb60c838 Merge pull request #1451 from matrix-org/t3chguy/lint-ts
Fix eslint ts override tsx matching
2020-09-01 09:10:22 +01:00
Dexter Chua d42cdbbc5b Add missing options in ICreateClientOpts
This makes the examples in the README actually compile.

Signed-off-by: Dexter Chua <dec41@srcf.net>
2020-08-29 14:40:40 +08:00
Michael Telatynski 66237e1ea6 Fix eslint ts override tsx matching 2020-08-29 01:10:08 +01:00
J. Ryan Stinnett a51c0450c3 Merge pull request #1450 from matrix-org/jryans/defer-cross-signing-setup
Untangle cross-signing and secret storage
2020-08-28 12:40:28 +01:00
J. Ryan Stinnett 7a2416bb6d Add callback for app to cache secret storage key
This is useful when e.g. resetting both secret storage and cross-signing
together, as it avoids prompting for the secret storage key that was just
created.
2020-08-28 12:07:35 +01:00
J. Ryan Stinnett a1528e9e33 Change log messages for uniqueness 2020-08-28 11:38:19 +01:00
J. Ryan Stinnett 71cc4d535e Clean up comment 2020-08-28 11:36:02 +01:00
J. Ryan Stinnett c06723df3d Always store cross-signing keys when new 4S key ID 2020-08-28 11:35:25 +01:00
J. Ryan Stinnett 06b285c013 Add comment about trap with multiple devices 2020-08-28 11:11:51 +01:00
J. Ryan Stinnett 49c06ef0ca Check cross-signing reset branch first
If we're resetting keys, we have to check that branch first.
2020-08-28 11:00:10 +01:00
J. Ryan Stinnett 5f92357fec Tweak code style 2020-08-27 17:32:46 +01:00
J. Ryan Stinnett 3e0dd3d918 Copy docs to client.js as well 2020-08-27 14:09:12 +01:00
J. Ryan Stinnett f19d76b08d Untangle cross-signing and secret storage
This untangles cross-signing and secret storage setup into separate path that
can be invoked independently. There is no functional change with this patch, but
instead this just separates one giant monster API into two.

Part of https://github.com/vector-im/element-web/issues/13895
2020-08-27 13:32:54 +01:00
RiotRobot 8b6b16067b v8.2.0-rc.1 2020-08-26 11:45:48 +01:00
RiotRobot a2da0de17d Prepare changelog for v8.2.0-rc.1 2020-08-26 11:45:48 +01:00
J. Ryan Stinnett 93ff3edb6b Merge pull request #1449 from matrix-org/jryans/strict-enc-check
Add state event check
2020-08-26 11:03:42 +01:00
J. Ryan Stinnett 7c67fd69dd Add state event check
State events are never encrypted, so we can ignore them here.
2020-08-26 10:55:03 +01:00
J. Ryan Stinnett 5ef5412a55 Move storage methods up to constructor 2020-08-25 19:27:26 +01:00
J. Ryan Stinnett e88a384aa7 Update and reformat client.js docs copy 2020-08-25 12:56:30 +01:00
J. Ryan Stinnett 9067feeafb Update comment on 4S signatures
As part of changing 4S to symmetric encryption, we no longer sign the 4S key
with the cross-signing MSK.
2020-08-25 12:56:25 +01:00
J. Ryan Stinnett ed978f69fb Merge pull request #1444 from matrix-org/jryans/secure-backup-required
Add method to check whether client .well-known has been fetched
2020-08-24 17:32:49 +01:00
J. Ryan Stinnett 743f2465ea Document WellKnown.client event 2020-08-24 15:56:14 +01:00
J. Ryan Stinnett 41fffa233a Switch to promise-based API 2020-08-24 15:56:14 +01:00
J. Ryan Stinnett e45377166b Merge pull request #1443 from matrix-org/jryans/cross-signing-auth-errors
Handle auth errors during cross-signing key upload
2020-08-24 11:52:40 +01:00
David Baker 24939bf0b0 Merge pull request #1448 from matrix-org/dbkr/dont_fail_if_audio_output_unavailable
Don't fail if the requested audio output isn't available
2020-08-21 16:19:20 +01:00
David Baker 3221be4855 Don't fail if the requested audio output isn't available
This thorws an exception if the requested device isn't available,
in which case we should catch it  & carry on with the default device.

Fixes https://github.com/vector-im/element-web/issues/15019
2020-08-21 16:02:08 +01:00
David Baker 3135f1ed24 Merge pull request #1447 from matrix-org/dbkr/fix_log_fail
Fix logging failures
2020-08-21 11:12:11 +01:00
David Baker 1b0834ffb0 Fix logging failures 2020-08-21 11:01:34 +01:00
David Baker d79d613cb7 Merge pull request #1446 from matrix-org/dbkr/log_user_media_constraints
Log the constraints we pass to getUserMedia
2020-08-19 18:30:39 +01:00
David Baker d8cc1f7b7a Log the constraints we pass to getUserMedia
To help debug voip calls
2020-08-19 18:13:44 +01:00
J. Ryan Stinnett d7c8856fdd Add method to check whether client .well-known has been fetched
This allows clearly detecting whether we have _ever_ fetched .well-known at all.
Without this, it's hard to be sure whether the value is `undefined` because the
fetch has not been attempted yet or because an error occurred.
2020-08-19 16:10:10 +01:00
J. Ryan Stinnett 9d80a332aa Upload cross-signing keys first to handle failure
This changes to uploading cross-signing keys first, since they require a valid
UI auth session, and so are more likely to fail than other API calls. With the
new ordering, if they do fail, then by failing first, we won't have made any
changes to the user's account, so everything rolls back correctly.
2020-08-19 11:55:09 +01:00
J. Ryan Stinnett e14f7b63c7 Handle auth errors during cross-signing key upload
In order to handle auth errors (such as incorrect passwords), we need to ensure
we only try to upload cross-signing keys from within the auth flow helper
function.

This rearranges things to store that function in the builder to use it when the
actual upload happens.
2020-08-19 11:44:41 +01:00
Travis Ralston 3bd2880923 Revert "Merge pull request #1440 from matrix-org/travis/spec-i18n"
This reverts commit 2401ad7159.
2020-08-18 13:07:31 -06:00
Travis Ralston 2401ad7159 Merge pull request #1440 from matrix-org/travis/spec-i18n
Use SAS emoji data from matrix-doc
2020-08-18 11:41:36 -06:00
Travis Ralston 5d95398621 Use SAS emoji data from matrix-doc
Fixes https://github.com/vector-im/element-web/issues/14947

Much like element-web's Jitsi wrapper build steps, this downloads the emoji JSON at build time to ensure it gets reasonably updated. In the future, the spec might want to consider publishing a dedicated i18n package on npm for this, however this is fine for now. We download rather than copy/paste to ensure we always have an updated copy.
2020-08-17 15:35:03 -06:00
RiotRobot 64cdd73b93 v8.1.0 2020-08-17 12:43:32 +01:00
RiotRobot 48a9236ea8 Prepare changelog for v8.1.0 2020-08-17 12:43:31 +01:00
RiotRobot 8b3126e9d8 v8.1.0-rc.1 2020-08-13 12:05:35 +01:00
RiotRobot 74d497cd2d Prepare changelog for v8.1.0-rc.1 2020-08-13 12:05:35 +01:00
Michael Telatynski 5070a5c598 Merge pull request #1438 from brettz9/patch-1
Update on Promises
2020-08-09 13:11:51 +01:00
Brett Zamir 2e30b08e74 Update on Promises
It seems that with ES6 Promises being apparently used, the reference to `done()` is outdated.

Also clarifies that it is "problematic" to discard the results of promises rather than it being an "error" .
2020-08-09 17:39:53 +08:00
J. Ryan Stinnett 8bf63f5f0b Merge pull request #1437 from matrix-org/jryans/defer-cross-signing-setup
Store and request master cross-signing key
2020-08-07 16:06:28 +01:00
J. Ryan Stinnett 11665d18ee Cache all cross-signing private keys when checking trust
This ensures we try to get all private keys when e.g. logging in and using the
passphrase to unlock 4S.

Part of https://github.com/vector-im/element-web/issues/13896
2020-08-06 16:43:56 +01:00
J. Ryan Stinnett a8a9fc0c9d Log secret name received via sharing 2020-08-06 16:43:56 +01:00
J. Ryan Stinnett 098cd1b8d4 Request master cross-signing private key during verification
This change adds a request for the master cross-signing private key, in case the
other device is willing to share it.

Part of https://github.com/vector-im/element-web/issues/13896
2020-08-06 16:43:56 +01:00
J. Ryan Stinnett 3166a4880d Move cross-signing key request path out of verification
This was always quite awkwardly placed in verification, so this moves it to
somewhere more expected. No changes are made to the logic or features in this
commit.
2020-08-06 16:39:56 +01:00
J. Ryan Stinnett 9d1c7136cc Store master cross-signing private key in local cache
We now want to store all private keys in the local cache, including the master
key if available.

Part of https://github.com/vector-im/element-web/issues/13896
2020-08-06 16:39:56 +01:00
J. Ryan Stinnett e100943edf Fix typo in comments 2020-08-06 16:24:49 +01:00
RiotRobot a6fe4cdf1c Merge branch 'master' into develop 2020-08-05 15:30:42 +01:00
J. Ryan Stinnett 69c4496dfe Merge pull request #1433 from matrix-org/bwindels/fixinvaliddisplaynames
Filter out non-string display names
2020-08-05 15:03:53 +01:00
Bruno Windels a9a4ba33aa respect signature 2020-08-04 15:43:57 +02:00
Bruno Windels 7116ad9f58 filter out non-string display names 2020-08-04 15:30:32 +02:00
J. Ryan Stinnett 3d18bdb2aa Merge pull request #1427 from matrix-org/dependabot/npm_and_yarn/elliptic-6.5.3
Bump elliptic from 6.5.2 to 6.5.3
2020-08-04 10:38:10 +01:00
J. Ryan Stinnett 4c14581606 Merge pull request #1431 from matrix-org/jryans/riot-to-element
Replace Riot with Element in docs and comments
2020-08-04 10:27:32 +01:00
J. Ryan Stinnett a9c9ec3977 Replace Riot with Element in docs and comments
This only covers the simple cases of references to issues and repos. More
complex areas, such as deployment scripts, will be handled separately.

Part of https://github.com/vector-im/element-web/issues/14864
2020-08-03 18:32:52 +01:00
J. Ryan Stinnett 694d1f9631 Merge pull request #1430 from matrix-org/jryans/rm-tslint
Remove leftover bits of TSLint
2020-07-31 20:30:44 +01:00
J. Ryan Stinnett 2b9cfae18a Remove leftover bits of TSLint 2020-07-31 14:31:19 +01:00
dependabot[bot] 02b37e1219 Bump elliptic from 6.5.2 to 6.5.3
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.2 to 6.5.3.
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.2...v6.5.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-30 12:41:01 +00:00
29 changed files with 1071 additions and 524 deletions
+1 -1
View File
@@ -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
+108
View File
@@ -1,3 +1,111 @@
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)
* 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)
+3 -4
View File
@@ -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
~~~~~~~~~~
+3 -5
View File
@@ -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``
@@ -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.
+8 -1
View File
@@ -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 -4
View File
@@ -1,6 +1,6 @@
{
"name": "matrix-js-sdk",
"version": "8.0.1",
"version": "8.4.0-rc.1",
"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,13 +82,12 @@
"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",
"terser": "^4.4.3",
"tsify": "^4.0.1",
"tslint": "^5.20.1",
"typescript": "^3.7.3"
},
"jest": {
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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();
+2 -2
View File
@@ -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.
+1 -1
View File
@@ -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 },
+54 -3
View File
@@ -20,7 +20,8 @@ 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) {
if (!keys) keys = {};
@@ -70,13 +71,63 @@ 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();
});
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.bootstrapCrossSigning({
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"},
+9 -9
View File
@@ -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();
@@ -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);
+6
View File
@@ -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;
}
}
+21 -3
View File
@@ -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.
*
@@ -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,
);
+185 -39
View File
@@ -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.
*
@@ -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,12 +366,15 @@ 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 }
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 +398,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 +416,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
@@ -1091,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
@@ -1102,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
@@ -1112,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
@@ -1122,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
@@ -1134,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
@@ -1143,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
@@ -1155,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",
@@ -1167,6 +1231,7 @@ wrapCryptoFuncs(MatrixClient, [
"legacyDeviceVerification",
"prepareToEncrypt",
"isCrossSigningReady",
"bootstrapCrossSigning",
"getCryptoTrustCrossSignedDevices",
"setCryptoTrustCrossSignedDevices",
"countSessionsNeedingBackup",
@@ -1193,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
@@ -1205,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
@@ -1235,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
@@ -1244,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
@@ -1256,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
@@ -1266,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
@@ -1280,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
@@ -1291,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
@@ -1300,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
@@ -1310,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
@@ -1321,6 +1432,7 @@ wrapCryptoFuncs(MatrixClient, [
wrapCryptoFuncs(MatrixClient, [
"getEventEncryptionInfo",
"createRecoveryKeyFromPassphrase",
"isSecretStorageReady",
"bootstrapSecretStorage",
"addSecretStorageKey",
"hasSecretStorageKey",
@@ -2644,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
@@ -4810,20 +4929,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
@@ -4873,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;
};
/**
@@ -4984,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
@@ -5698,6 +5837,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
/**
+153 -19
View File
@@ -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
@@ -64,15 +66,34 @@ 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.
* @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");
@@ -125,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
@@ -199,9 +202,47 @@ 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.
*
* @returns {boolean} True if all keys are stored in the local cache.
*/
async isStoredInKeyCache() {
const cacheCallbacks = this._cacheCallbacks;
if (!cacheCallbacks) return false;
for (const type of ["master", "self_signing", "user_signing"]) {
if (!await cacheCallbacks.getCrossSigningKeyCache(type)) {
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.
@@ -677,3 +718,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);
});
}
+1 -1
View File
@@ -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.
+34 -17
View File
@@ -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) {
@@ -336,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);
}
}
}
+5
View File
@@ -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);
}
}
+2 -2
View File
@@ -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;
+281 -138
View File
@@ -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 sucessfully, 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,11 +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:
@@ -473,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,
@@ -490,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;
@@ -519,35 +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);
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, {});
}
});
// 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(
@@ -569,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 = {};
@@ -632,36 +756,16 @@ 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(
await this._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);
}
} 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
@@ -670,21 +774,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.
@@ -702,15 +811,14 @@ Crypto.prototype.bootstrapSecretStorage = async function({
auth_data: info.auth_data,
};
// sign with cross-sign master key
await crossSigningInfo.signObject(data.auth_data, "master");
await this._crossSigningInfo.signObject(data.auth_data, "master");
// 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");
@@ -1191,23 +1299,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");
@@ -1216,10 +1321,26 @@ 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"));
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 cross-signing self-signing private key");
} catch (e) {
logger.error("Cross-signing self-signing private key not available", e);
} finally {
if (signing) signing.free();
}
const device = this._deviceList.getStoredDevice(this._userId, this._deviceId);
const signedDevice = await this._crossSigningInfo.signDevice(
@@ -1227,8 +1348,21 @@ 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"));
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 cross-signing user-signing private key");
} catch (e) {
logger.error("Cross-signing user-signing private key not available", e);
} finally {
if (signing) signing.free();
}
}
if (masterChanged) {
@@ -1403,7 +1537,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");
@@ -2004,9 +2138,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);
@@ -2410,7 +2553,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 +3127,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();
+2 -91
View File
@@ -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);
}
}
+4 -6
View File
@@ -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 || {});
+36
View File
@@ -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>;
};
}
/**
+2 -2
View File
@@ -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";
},
/**
+36 -9
View File
@@ -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;
@@ -403,7 +405,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 +414,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),
);
@@ -701,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;
}
};
@@ -1065,7 +1086,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 +1148,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 +1213,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 +1230,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,
@@ -1224,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;
};
-72
View File
@@ -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"
]
}
}
+103 -89
View File
@@ -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"
@@ -1914,11 +1926,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 +1998,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 +2160,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 +2476,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"
@@ -2483,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"
@@ -2543,9 +2550,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"
@@ -4362,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"
@@ -4651,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==
@@ -4661,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"
@@ -4805,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"
@@ -4928,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"
@@ -5637,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"
@@ -6055,7 +6078,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==
@@ -6482,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"
@@ -6715,36 +6745,15 @@ 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"
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"
@@ -6799,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"
@@ -6859,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==
@@ -7023,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"