Compare commits

...

129 Commits

Author SHA1 Message Date
RiotRobot a12c250f2b v8.5.0 2020-10-12 13:15:07 +01:00
RiotRobot 57eef2d832 Prepare changelog for v8.5.0 2020-10-12 13:15:06 +01:00
RiotRobot 293860b6c5 v8.5.0-rc.1 2020-10-07 14:18:52 +01:00
RiotRobot 07667172cd Prepare changelog for v8.5.0-rc.1 2020-10-07 14:18:52 +01:00
J. Ryan Stinnett f5240cdac6 Merge pull request #1467 from uhoreg/fallback_keys
Add support for olm fallback keys
2020-10-07 10:24:12 +01:00
Michael Telatynski 03fc12e888 Merge pull request #1492 from matrix-org/t3chguy/fix/10545
Fix editing local echoes not updating them in real time
2020-10-07 00:15:16 +01:00
Hubert Chathi e05a50528e make test no longer dependent on emscripten internals 2020-10-06 19:01:01 -04:00
Hubert Chathi 356ee90417 lint 2020-10-06 18:33:45 -04:00
Hubert Chathi 5dced57724 bump olm release again and fix global.d.ts to work with the olm TS definitions 2020-10-06 17:55:40 -04:00
Michael Telatynski 8ec3b88c5d Update comments
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2020-10-06 22:55:34 +01:00
Michael Telatynski d7ef128510 Merge pull request #1491 from matrix-org/t3chguy/fix/9836
Fix re-emit of Event.replaced to be on client and not room
2020-10-06 22:50:14 +01:00
Hubert Chathi bb2502409b update yarn.lock 2020-10-06 15:34:02 -04:00
Hubert Chathi aa6aab4245 Merge remote-tracking branch 'origin/develop' into fallback_keys 2020-10-06 15:22:25 -04:00
Hubert Chathi 12aab0caeb depend on newer olm 2020-10-06 15:18:18 -04:00
David Baker 2f316c558d Merge pull request #1496 from matrix-org/dbkr/space_in_log_line
Add space to log line
2020-10-06 19:16:25 +01:00
David Baker f447273b75 Add space to log line 2020-10-06 18:59:34 +01:00
David Baker a0e66291df Merge pull request #1493 from matrix-org/revert-1487-dbkr/tsify_call
Revert "Convert call.js to Typescript & update WebRTC APIs"
2020-10-06 15:21:38 +01:00
David Baker 5733f46f4c Revert "Convert call.js to Typescript & update WebRTC APIs" 2020-10-06 15:16:32 +01:00
David Baker da2128feff Merge pull request #1487 from matrix-org/dbkr/tsify_call
Convert call.js to Typescript & update WebRTC APIs
2020-10-06 15:09:10 +01:00
Michael Telatynski d413faefdb double sync-browserify jest timeout
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2020-10-06 12:39:18 +01:00
Michael Telatynski 0d1d767d96 Fix editing local echoes not updating them in real time
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2020-10-06 12:32:50 +01:00
David Baker 5619554023 use MatrixEvent for event types 2020-10-06 11:03:05 +01:00
David Baker 53880a4bb2 This is how plurals work 2020-10-06 10:54:51 +01:00
David Baker 812ae227b6 Make type enums PascalCase 2020-10-06 10:53:42 +01:00
David Baker c6b44098ac remove space before type colon 2020-10-06 09:55:02 +01:00
David Baker 92b95a98d0 comment other snake case identifiers
and also sto mixing quotes
2020-10-06 09:52:59 +01:00
David Baker a3505ff42d Use right case for private enum field 2020-10-06 09:49:51 +01:00
Michael Telatynski 15b2e3ff1d Fix re-emit of Event.replaced to be on client and not room
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2020-10-06 08:23:19 +01:00
Hubert Chathi 1845d1ac55 Merge pull request #1436 from uhoreg/dehydration
Dehydrate and rehydrate devices
2020-10-05 17:19:28 -04:00
J. Ryan Stinnett 463819caa7 Merge pull request #1490 from matrix-org/jryans/key-setup-device-undefined
Keep local device after processing device list sync
2020-10-05 14:49:18 +01:00
J. Ryan Stinnett a0317d9587 Fix tests 2020-10-05 14:29:30 +01:00
J. Ryan Stinnett fa6ce0cb70 Keep local device after processing device list sync
This change ensure we always keep the local device in the device list, even if
the server claims it doesn't exist. This is important for initial startup, as it
is possible the device key upload takes a while to apply, and thus might not
appear in the first device list sync.

Fixes https://github.com/vector-im/element-web/issues/15319
2020-10-05 14:09:16 +01:00
David Baker 7471ff4b0d Make setSinkId reliable
As per comment, this seems to be the way to make setSinkId work reliably on Chrome.

Also don't make our own mediastreams if we don't need to (ie. in a normal call
our tracks should come with their owen MediaStreams).
2020-10-03 16:57:33 +01:00
Hubert Chathi 65a5bfac88 update property name 2020-10-02 15:52:09 -04:00
David Baker d2321410f8 Pass stream to addTrack too
Otherwise we end up with separate, unbundled 'streamless tracks'
which is not what we want.
2020-10-02 15:12:12 +01:00
Hubert Chathi f90b5a99cd Merge remote-tracking branch 'origin/develop' into dehydration 2020-10-01 21:55:05 -04:00
David Baker cc4656b36a Update call.js to use new WebRTC APIs
and some other related & semi-related refactoring
2020-10-01 19:15:49 +01:00
J. Ryan Stinnett 34bc63a146 Merge pull request #1489 from matrix-org/jryans/no-console
Enforce logger module via lint rules
2020-10-01 14:56:15 +01:00
J. Ryan Stinnett 09bd91a588 Enforce logger module via lint rules
This adds lint rules (and fixes various errors) to ensure we use the `logger`
intermediary module, rather than accessing the console directly.
2020-10-01 14:28:24 +01:00
David Baker bb3e082e5b Make direction public, remove didConnect
Various flags that may or may not have been part of the poorly defined
external API before. Neither were used internally. Make direction a
public export but remove didConnect.
2020-10-01 10:15:27 +01:00
Hubert Chathi 60c863f829 lint 2020-09-30 18:33:27 -04:00
Hubert Chathi 2d2a73bf52 make dehydrated device name configurable 2020-09-30 18:05:52 -04:00
Hubert Chathi 7b9f73709d use "dehydration" as the cache name 2020-09-30 17:50:37 -04:00
Hubert Chathi 1dc89f642d use logger instead of console 2020-09-30 17:46:18 -04:00
David Baker a78b59010a Convert call.js to Typescript
This does a fairly basic rewriting of the whole file to bring it up
to a vaguely modern standard of code. Nothing should have changed
fundamentally, but it probably should do: as per the global type
overrides, we use a lot of deprecated WebRTC APIs and should probably
update.
2020-09-30 18:54:48 +01:00
Hubert Chathi a2e1d94fcf more lint 2020-09-30 01:22:46 -04:00
Hubert Chathi b181c83b93 lint 2020-09-30 01:16:57 -04:00
Hubert Chathi cf7c84c4ba more linting, because GitHub is showing me outdated CI info 2020-09-30 01:10:33 -04:00
Hubert Chathi 6e5230f9f9 fix lint again 2020-09-30 01:07:35 -04:00
Hubert Chathi f03f7c0acb fix lint 2020-09-30 00:58:37 -04:00
Hubert Chathi aa9b807b82 update to latest dehydration endpoints, and simplify API 2020-09-30 00:48:07 -04:00
Travis Ralston fa9921e091 Merge pull request #1462 from orangecms/develop
extend method redactEvent with reason
2020-09-28 15:05:00 -06:00
RiotRobot a9a6b2de48 Merge branch 'master' into develop 2020-09-28 16:09:28 +01:00
RiotRobot 1ef746658f v8.4.1 2020-09-28 16:06:30 +01:00
RiotRobot fe0099b497 Prepare changelog for v8.4.1 2020-09-28 16:06:30 +01:00
J. Ryan Stinnett 7e9c4146a5 Merge pull request #1486 from matrix-org/dbkr/catch_exceptions_from_call_event_handler_rel
Catch exception from call event handler
2020-09-28 16:01:07 +01:00
David Baker 3e978c64e4 Merge pull request #1484 from matrix-org/dbkr/catch_exceptions_from_call_event_handler
Catch exception from call event handler
2020-09-28 15:56:29 +01:00
David Baker 13c5920a46 Merge pull request #1485 from matrix-org/dbkr/ignore_invalid_candidates_rel
Ignore invalid candidates
2020-09-28 15:55:00 +01:00
David Baker 3b19203fd2 Catch exception from call event handler
Otherwise they leak out ot the sync loop. It's unfortunate that
exceptions from event handlers leak out to the emitter, and this
seems a bit clumsy, but having to wrap eveery event emit in a try
block seems worse.
2020-09-28 15:48:06 +01:00
David Baker 84cd05b218 Ignore invalid candidates 2020-09-28 15:47:02 +01:00
David Baker 9b9a9642ee Merge pull request #1483 from matrix-org/dbkr/ignore_invalid_candidates
Ignore invalid candidates
2020-09-28 15:41:32 +01:00
David Baker 639d2317ed Catch exception from call event handler
Otherwise they leak out ot the sync loop. It's unfortunate that
exceptions from event handlers leak out to the emitter, and this
seems a bit clumsy, but having to wrap eveery event emit in a try
block seems worse.
2020-09-28 15:39:21 +01:00
David Baker 52379d7655 Ignore invalid candidates 2020-09-28 15:22:01 +01:00
Michael Telatynski 29827362d6 Merge pull request #1478 from matrix-org/t3chguy-patch-1
Always push docs if they are generated
2020-09-28 14:32:07 +01:00
RiotRobot f33315f610 Merge branch 'master' into develop 2020-09-28 14:23:19 +01:00
RiotRobot aec92a41da v8.4.0 2020-09-28 14:20:06 +01:00
RiotRobot d570811ddc Prepare changelog for v8.4.0 2020-09-28 14:20:06 +01:00
J. Ryan Stinnett 9cd015a218 Merge pull request #1482 from matrix-org/jryans/guard-backup-sig-release
Only sign key backup with cross-signing keys when available
2020-09-28 12:13:23 +01:00
J. Ryan Stinnett 8d2cc5096e Fix default key cache check 2020-09-28 10:38:13 +01:00
J. Ryan Stinnett 7ec0bf69f3 Only sign key backup with cross-signing keys when available
This changes the key backup setup step to only sign with cross-signing keys when
both the public and private keys are already available without prompting. In
many cases down these paths, the cross-signing keys either may not exist or may
not be accessible. We always sign the key backup with your device key as well,
so there is always a route to trust the key backup even if this is skipped.

Fixes https://github.com/vector-im/element-web/issues/15230
2020-09-28 10:38:13 +01:00
J. Ryan Stinnett f3a8306107 Merge pull request #1481 from matrix-org/jryans/guard-backup-sig
Only sign key backup with cross-signing keys when available
2020-09-28 10:21:34 +01:00
J. Ryan Stinnett 2b29e9934c Fix default key cache check 2020-09-28 10:16:20 +01:00
J. Ryan Stinnett 4b1104e463 Only sign key backup with cross-signing keys when available
This changes the key backup setup step to only sign with cross-signing keys when
both the public and private keys are already available without prompting. In
many cases down these paths, the cross-signing keys either may not exist or may
not be accessible. We always sign the key backup with your device key as well,
so there is always a route to trust the key backup even if this is skipped.

Fixes https://github.com/vector-im/element-web/issues/15230
2020-09-25 17:36:47 +01:00
Hubert Chathi 60b9ef959d don't include an empty signatures field when calculating the signature 2020-09-24 18:46:17 -04:00
Hubert Chathi 0074c2cf57 mark fallback keys as fallback 2020-09-24 18:09:07 -04:00
Hubert Chathi b0204ab54e use unstable prefix 2020-09-24 17:41:08 -04:00
J. Ryan Stinnett bc5b07aa75 Merge pull request #1479 from matrix-org/jryans/upgrade-deps-2020-09-23
Upgrade dependencies
2020-09-24 16:40:36 +01:00
Michael Telatynski cfe90dbed5 Always push docs if they are generated 2020-09-24 12:47:23 +01:00
J. Ryan Stinnett fa913655bc Upgrade dependencies 2020-09-23 17:35:24 +01:00
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
Daniel Maslowski aad7484c8d Add optional reason to be passed to redactEvent
Signed-off-by: Daniel Maslowski <info@orangecms.org>
2020-09-21 21:50:38 +02: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
Hubert Chathi 16dccd75c1 fix string 2020-09-18 19:20:09 -04:00
Hubert Chathi 5151b52688 Merge remote-tracking branch 'origin/develop' into dehydration 2020-09-18 19:13:22 -04: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
Hubert Chathi 492c1d77d8 style fixes 2020-09-16 17:09:33 -04: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
Hubert Chathi 3952768667 Merge remote-tracking branch 'origin/develop' into fallback_keys 2020-09-15 12:04:30 -04: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 6331b34cf7 lint 2020-09-14 23:00:07 -04:00
Hubert Chathi 2ebe1dfa16 support olm fallback keys 2020-09-14 22:10:16 -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
Michael Telatynski bcd9b45589 Switch to a combination of better-docs and docdash 2020-09-04 11:08:26 +01:00
Hubert Chathi 19f3996e09 only cross-sign dehydrated device if cross-signing is available 2020-09-03 16:06:06 -04:00
Hubert Chathi 25c2cc1768 various fixes 2020-09-03 11:45:37 -04:00
Hubert Chathi 438861ae5e separate dehydration functions to its own file and cache the key 2020-08-31 15:44:29 -04:00
Hubert Chathi ad85740ae2 allow other login functions to be used 2020-08-19 18:01:31 -04:00
Hubert Chathi 6e8e3e4150 use newer version of dehydration proposal and add some comments 2020-08-17 18:09:23 -04:00
Hubert Chathi 8a4440c314 initial work on dehydration 2020-08-04 16:06:19 -04:00
35 changed files with 1754 additions and 655 deletions
+2
View File
@@ -28,6 +28,8 @@ module.exports = {
"indent": "off",
"no-constant-condition": "off",
"no-async-promise-executor": "off",
// We use a `logger` intermediary module
"no-console": "error",
},
overrides: [{
"files": ["src/**/*.ts"],
+94
View File
@@ -1,3 +1,97 @@
Changes in [8.5.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.5.0) (2020-10-12)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.5.0-rc.1...v8.5.0)
* No changes since rc.1
Changes in [8.5.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.5.0-rc.1) (2020-10-07)
==========================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.4.1...v8.5.0-rc.1)
* Add support for olm fallback keys
[\#1467](https://github.com/matrix-org/matrix-js-sdk/pull/1467)
* Fix editing local echoes not updating them in real time
[\#1492](https://github.com/matrix-org/matrix-js-sdk/pull/1492)
* Fix re-emit of Event.replaced to be on client and not room
[\#1491](https://github.com/matrix-org/matrix-js-sdk/pull/1491)
* Add space to log line
[\#1496](https://github.com/matrix-org/matrix-js-sdk/pull/1496)
* Revert "Convert call.js to Typescript & update WebRTC APIs"
[\#1493](https://github.com/matrix-org/matrix-js-sdk/pull/1493)
* Convert call.js to Typescript & update WebRTC APIs
[\#1487](https://github.com/matrix-org/matrix-js-sdk/pull/1487)
* Dehydrate and rehydrate devices
[\#1436](https://github.com/matrix-org/matrix-js-sdk/pull/1436)
* Keep local device after processing device list sync
[\#1490](https://github.com/matrix-org/matrix-js-sdk/pull/1490)
* Enforce logger module via lint rules
[\#1489](https://github.com/matrix-org/matrix-js-sdk/pull/1489)
* Extend method redactEvent with reason
[\#1462](https://github.com/matrix-org/matrix-js-sdk/pull/1462)
* Catch exception from call event handler
[\#1484](https://github.com/matrix-org/matrix-js-sdk/pull/1484)
* Ignore invalid candidates
[\#1483](https://github.com/matrix-org/matrix-js-sdk/pull/1483)
* Always push docs if they are generated
[\#1478](https://github.com/matrix-org/matrix-js-sdk/pull/1478)
* Only sign key backup with cross-signing keys when available
[\#1481](https://github.com/matrix-org/matrix-js-sdk/pull/1481)
* Upgrade dependencies
[\#1479](https://github.com/matrix-org/matrix-js-sdk/pull/1479)
Changes in [8.4.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.4.1) (2020-09-28)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.4.0...v8.4.1)
* Catch exception from call event handler
[\#1486](https://github.com/matrix-org/matrix-js-sdk/pull/1486)
* Ignore invalid candidates
[\#1485](https://github.com/matrix-org/matrix-js-sdk/pull/1485)
Changes in [8.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.4.0) (2020-09-28)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.4.0-rc.1...v8.4.0)
* Only sign key backup with cross-signing keys when available
[\#1482](https://github.com/matrix-org/matrix-js-sdk/pull/1482)
Changes in [8.4.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.4.0-rc.1) (2020-09-23)
==========================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.3.0...v8.4.0-rc.1)
* If there are extraParams set, ensure that queryParams is defined
[\#1477](https://github.com/matrix-org/matrix-js-sdk/pull/1477)
* Add diagnostics to security bootstrap paths
[\#1475](https://github.com/matrix-org/matrix-js-sdk/pull/1475)
* Switch to a combination of better-docs and docdash
[\#1459](https://github.com/matrix-org/matrix-js-sdk/pull/1459)
* Undo attempts to cache private keys aggressively
[\#1474](https://github.com/matrix-org/matrix-js-sdk/pull/1474)
* Repair secret storage reset, cache keys when missing
[\#1472](https://github.com/matrix-org/matrix-js-sdk/pull/1472)
* Prevent parallel getVersions calls
[\#1471](https://github.com/matrix-org/matrix-js-sdk/pull/1471)
* Send end-of-candidates
[\#1473](https://github.com/matrix-org/matrix-js-sdk/pull/1473)
* Add a function for checking the /versions flag for forced e2ee
[\#1470](https://github.com/matrix-org/matrix-js-sdk/pull/1470)
* Add option to allow users of pantialaimon to use the SDK
[\#1469](https://github.com/matrix-org/matrix-js-sdk/pull/1469)
* Fixed Yarn broken link
[\#1468](https://github.com/matrix-org/matrix-js-sdk/pull/1468)
* some TypeScript and doc fixes
[\#1466](https://github.com/matrix-org/matrix-js-sdk/pull/1466)
* Remove Travis CI reference
[\#1464](https://github.com/matrix-org/matrix-js-sdk/pull/1464)
* Inject identity server token for 3pid invites on createRoom
[\#1463](https://github.com/matrix-org/matrix-js-sdk/pull/1463)
Changes in [8.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.3.0) (2020-09-14)
================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.3.0-rc.1...v8.3.0)
* No changes since rc.1
Changes in [8.3.0-rc.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v8.3.0-rc.1) (2020-09-09)
==========================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-js-sdk/compare/v8.2.0...v8.3.0-rc.1)
+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
~~~~~~~~~~
+1 -1
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``
+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
}
}
+32 -31
View File
@@ -1,6 +1,6 @@
{
"name": "matrix-js-sdk",
"version": "8.3.0-rc.1",
"version": "8.5.0",
"description": "Matrix Client-Server SDK for Javascript",
"scripts": {
"prepare": "yarn build",
@@ -46,48 +46,49 @@
"release.sh"
],
"dependencies": {
"@babel/runtime": "^7.8.3",
"@babel/runtime": "^7.11.2",
"another-json": "^0.2.0",
"browser-request": "^0.3.3",
"bs58": "^4.0.1",
"content-type": "^1.0.2",
"loglevel": "^1.6.4",
"qs": "^6.5.2",
"request": "^2.88.0",
"unhomoglyph": "^1.0.2"
"content-type": "^1.0.4",
"loglevel": "^1.7.0",
"qs": "^6.9.4",
"request": "^2.88.2",
"unhomoglyph": "^1.0.6"
},
"devDependencies": {
"@babel/cli": "^7.7.5",
"@babel/core": "^7.7.5",
"@babel/plugin-proposal-class-properties": "^7.7.4",
"@babel/plugin-proposal-numeric-separator": "^7.7.4",
"@babel/plugin-proposal-object-rest-spread": "^7.7.4",
"@babel/plugin-syntax-dynamic-import": "^7.7.4",
"@babel/plugin-transform-runtime": "^7.8.3",
"@babel/preset-env": "^7.7.6",
"@babel/preset-typescript": "^7.7.4",
"@babel/register": "^7.7.4",
"@babel/cli": "^7.11.6",
"@babel/core": "^7.11.6",
"@babel/plugin-proposal-class-properties": "^7.10.4",
"@babel/plugin-proposal-numeric-separator": "^7.10.4",
"@babel/plugin-proposal-object-rest-spread": "^7.11.0",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.11.5",
"@babel/preset-env": "^7.11.5",
"@babel/preset-typescript": "^7.10.4",
"@babel/register": "^7.11.5",
"@types/node": "12",
"@types/request": "^2.48.4",
"babel-eslint": "^10.0.3",
"@types/request": "^2.48.5",
"babel-eslint": "^10.1.0",
"babel-jest": "^24.9.0",
"babelify": "^10.0.0",
"better-docs": "^1.4.7",
"browserify": "^16.5.0",
"eslint": "7.3.1",
"better-docs": "^2.3.2",
"browserify": "^16.5.2",
"docdash": "^1.2.0",
"eslint": "7.9.0",
"eslint-config-matrix-org": "^0.1.2",
"eslint-plugin-babel": "^5.3.0",
"eslint-plugin-babel": "^5.3.1",
"exorcist": "^1.0.1",
"fake-indexeddb": "^3.0.0",
"fake-indexeddb": "^3.1.2",
"jest": "^24.9.0",
"jest-localstorage-mock": "^2.4.0",
"jsdoc": "^3.5.5",
"jest-localstorage-mock": "^2.4.3",
"jsdoc": "^3.6.6",
"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",
"typescript": "^3.7.3"
"olm": "https://packages.matrix.org/npm/olm/olm-3.2.1.tgz",
"rimraf": "^3.0.2",
"terser": "^4.8.0",
"tsify": "^4.0.2",
"typescript": "^3.9.7"
},
"jest": {
"testEnvironment": "node"
+2 -4
View File
@@ -327,6 +327,7 @@ if [ -z "$skip_jsdoc" ]; then
$release index.html
git add "$release"
git commit --no-verify -m "Add jsdoc for $release" index.html "$release"
git push origin gh-pages
fi
# if it is a pre-release, leave it on the release branch for now.
@@ -341,11 +342,8 @@ git checkout master
git pull
git merge "$rel_branch"
# push master and docs (if generated) to github
# push master to github
git push origin master
if [ -z "$skip_jsdoc" ]; then
git push origin gh-pages
fi
# finally, merge master back onto develop (if it exists)
if [ $(git branch -lr | grep origin/develop -c) -ge 1 ]; then
+1 -1
View File
@@ -99,5 +99,5 @@ describe("Browserify Test", function() {
client.once("sync.unexpectedError", reject);
}),
]);
}, 10000);
}, 20000); // additional timeout as this test can take quite a while
});
+1 -1
View File
@@ -31,5 +31,5 @@ try {
const crypto = require('crypto');
utils.setCrypto(crypto);
} catch (err) {
console.log('nodejs was compiled without crypto support: some tests will fail');
logger.log('nodejs was compiled without crypto support: some tests will fail');
}
+11 -3
View File
@@ -26,6 +26,7 @@ import {MemoryCryptoStore} from '../../../src/crypto/store/memory-crypto-store';
import 'fake-indexeddb/auto';
import 'jest-localstorage-mock';
import {OlmDevice} from "../../../src/crypto/OlmDevice";
import {logger} from '../../../src/logger';
const userId = "@alice:example.com";
@@ -51,7 +52,7 @@ const masterKeyPub = "nqOvzeuGWT/sRx3h7+MHoInYj3Uk2LD/unI9kDYcHwk";
describe("CrossSigningInfo.getCrossSigningKey", function() {
if (!global.Olm) {
console.warn('Not running megolm backup unit tests: libolm not present');
logger.warn('Not running megolm backup unit tests: libolm not present');
return;
}
@@ -83,9 +84,16 @@ describe("CrossSigningInfo.getCrossSigningKey", function() {
const info = new CrossSigningInfo(userId, {
getCrossSigningKey: () => testKey,
});
const [pubKey, ab] = await info.getCrossSigningKey("master", masterKeyPub);
const [pubKey, pkSigning] = await info.getCrossSigningKey("master", masterKeyPub);
expect(pubKey).toEqual(masterKeyPub);
expect(ab).toEqual({a: 106712, b: 106712});
// check that the pkSigning object corresponds to the pubKey
const signature = pkSigning.sign("message");
const util = new global.Olm.Utility();
try {
util.ed25519_verify(pubKey, "message", signature);
} finally {
util.free();
}
});
it.each(types)("should request a key from the cache callback (if set)" +
+2
View File
@@ -72,6 +72,8 @@ describe('DeviceList', function() {
function createTestDeviceList() {
const baseApis = {
downloadKeysForUsers: downloadSpy,
getUserId: () => '@test1:sw1v.org',
deviceId: 'HGKAWHRVJQ',
};
const mockOlm = {
verifySignature: function(key, message, signature) {},
+2 -1
View File
@@ -22,6 +22,7 @@ import {TestClient} from '../../TestClient';
import {HttpResponse, setHttpResponses} from '../../test-utils';
import { resetCrossSigningKeys } from "./crypto-utils";
import { MatrixError } from '../../../src/http-api';
import {logger} from '../../../src/logger';
async function makeTestClient(userInfo, options, keys) {
if (!keys) keys = {};
@@ -49,7 +50,7 @@ async function makeTestClient(userInfo, options, keys) {
describe("Cross Signing", function() {
if (!global.Olm) {
console.warn('Not running megolm backup unit tests: libolm not present');
logger.warn('Not running megolm backup unit tests: libolm not present');
return;
}
+3 -2
View File
@@ -22,6 +22,7 @@ import {TestClient} from '../../TestClient';
import {makeTestClients} from './verification/util';
import {encryptAES} from "../../../src/crypto/aes";
import {resetCrossSigningKeys, createSecretStorageKey} from "./crypto-utils";
import {logger} from '../../../src/logger';
import * as utils from "../../../src/utils";
@@ -29,7 +30,7 @@ try {
const crypto = require('crypto');
utils.setCrypto(crypto);
} catch (err) {
console.log('nodejs was compiled without crypto support');
logger.log('nodejs was compiled without crypto support');
}
async function makeTestClient(userInfo, options) {
@@ -60,7 +61,7 @@ function sign(obj, key, userId) {
describe("Secrets", function() {
if (!global.Olm) {
console.warn('Not running megolm backup unit tests: libolm not present');
logger.warn('Not running megolm backup unit tests: libolm not present');
return;
}
+3 -2
View File
@@ -18,12 +18,13 @@ limitations under the License.
import {TestClient} from '../../../TestClient';
import {MatrixEvent} from "../../../../src/models/event";
import nodeCrypto from "crypto";
import {logger} from '../../../../src/logger';
export async function makeTestClients(userInfos, options) {
const clients = [];
const clientMap = {};
const sendToDevice = function(type, map) {
// console.log(this.getUserId(), "sends", type, map);
// logger.log(this.getUserId(), "sends", type, map);
for (const [userId, devMap] of Object.entries(map)) {
if (userId in clientMap) {
for (const [deviceId, msg] of Object.entries(devMap)) {
@@ -67,7 +68,7 @@ export async function makeTestClients(userInfos, options) {
setImmediate(() => {
for (const tc of clients) {
if (tc.client === this) { // eslint-disable-line babel/no-invalid-this
console.log("sending remote echo!!");
logger.log("sending remote echo!!");
tc.client.emit("Room.timeline", remoteEcho);
} else {
tc.client.emit("Room.timeline", event);
+3
View File
@@ -14,6 +14,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// this is needed to tell TS about global.Olm
import * as Olm from "olm"; // eslint-disable-line @typescript-eslint/no-unused-vars
export {};
declare global {
+20 -2
View File
@@ -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,
);
+186 -27
View File
@@ -55,6 +55,7 @@ import {PushProcessor} from "./pushprocessor";
import {encodeBase64, decodeBase64} from "./crypto/olmlib";
import { User } from "./models/user";
import {AutoDiscovery} from "./autodiscovery";
import {DEHYDRATION_ALGORITHM} from "./crypto/dehydration";
const SCROLLBACK_DELAY_MS = 3000;
export const CRYPTO_ENABLED = isCryptoAvailable();
@@ -182,6 +183,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.
*
@@ -248,12 +254,12 @@ function keyFromRecoverySession(session, decryptionKey) {
* 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) {
@@ -266,6 +272,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;
@@ -359,9 +367,9 @@ export function MatrixClient(opts) {
// The pushprocessor caches useful things, so keep one and re-use it
this._pushProcessor = new PushProcessor(this);
// Cache of the server's /versions response
// Promise to a response of the server's /versions response
// TODO: This should expire: https://github.com/matrix-org/matrix-js-sdk/issues/1020
this._serverVersionsCache = null;
this._serverVersionsPromise = null;
this._cachedCapabilities = null; // { capabilities: {}, lastUpdated: timestamp }
@@ -452,6 +460,121 @@ export function MatrixClient(opts) {
utils.inherits(MatrixClient, EventEmitter);
utils.extend(MatrixClient.prototype, MatrixBaseApis.prototype);
/**
* Try to rehydrate a device if available. The client must have been
* initialized with a `cryptoCallback.getDehydrationKey` option, and this
* function must be called before initCrypto and startClient are called.
*
* @return {Promise} Resolves to undefined if a device could not be dehydrated, or
* to the new device ID if the dehydration was successful.
* @return {module:http-api.MatrixError} Rejects: with an error response.
*/
MatrixClient.prototype.rehydrateDevice = async function() {
if (this._crypto) {
throw new Error("Cannot rehydrate device after crypto is initialized");
}
if (!this._cryptoCallbacks.getDehydrationKey) {
return;
}
let getDeviceResult;
try {
getDeviceResult = await this._http.authedRequest(
undefined,
"GET",
"/dehydrated_device",
undefined, undefined,
{
prefix: "/_matrix/client/unstable/org.matrix.msc2697.v2",
},
);
} catch (e) {
logger.info("could not get dehydrated device", e);
return;
}
if (!getDeviceResult.device_data || !getDeviceResult.device_id) {
logger.info("no dehydrated device found");
return;
}
const account = new global.Olm.Account();
try {
const deviceData = getDeviceResult.device_data;
if (deviceData.algorithm !== DEHYDRATION_ALGORITHM) {
logger.warn("Wrong algorithm for dehydrated device");
return;
}
logger.log("unpickling dehydrated device");
const key = await this._cryptoCallbacks.getDehydrationKey(
deviceData,
(k) => {
// copy the key so that it doesn't get clobbered
account.unpickle(new Uint8Array(k), deviceData.account);
},
);
account.unpickle(key, deviceData.account);
logger.log("unpickled device");
const rehydrateResult = await this._http.authedRequest(
undefined,
"POST",
"/dehydrated_device/claim",
undefined,
{
device_id: getDeviceResult.device_id,
},
{
prefix: "/_matrix/client/unstable/org.matrix.msc2697.v2",
},
);
if (rehydrateResult.success === true) {
this.deviceId = getDeviceResult.device_id;
logger.info("using dehydrated device");
const pickleKey = this.pickleKey || "DEFAULT_KEY";
this._exportedOlmDeviceToImport = {
pickledAccount: account.pickle(pickleKey),
sessions: [],
pickleKey: pickleKey,
};
account.free();
return this.deviceId;
} else {
account.free();
logger.info("not using dehydrated device");
return;
}
} catch (e) {
account.free();
logger.warn("could not unpickle", e);
}
};
/**
* Set the dehydration key. This will also periodically dehydrate devices to
* the server.
*
* @param {Uint8Array} key the dehydration key
* @param {object} [keyInfo] Information about the key. Primarily for
* information about how to generate the key from a passphrase.
* @param {string} [deviceDisplayName] The device display name for the
* dehydrated device.
* @return {Promise} A promise that resolves when the dehydrated device is stored.
*/
MatrixClient.prototype.setDehydrationKey = async function(
key, keyInfo = {}, deviceDisplayName = undefined,
) {
if (!(this._crypto)) {
logger.warn('not dehydrating device if crypto is not enabled');
return;
}
return await this._crypto._dehydrationManager.setDehydrationKey(
key, keyInfo, deviceDisplayName,
);
};
MatrixClient.prototype.exportDevice = async function() {
if (!(this._crypto)) {
logger.warn('not exporting device if crypto is not enabled');
@@ -2047,7 +2170,7 @@ MatrixClient.prototype._restoreKeyBackup = function(
// This is async.
this._crypto.storeSessionBackupPrivateKey(privKey)
.catch((e) => {
console.warn("Error caching session backup key:", e);
logger.warn("Error caching session backup key:", e);
}).then(cacheCompleteCallback);
if (progressCallback) {
@@ -2749,6 +2872,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
@@ -2844,14 +2974,19 @@ function _sendEventHttpRequest(client, event) {
* @param {string} eventId
* @param {string} [txnId] transaction id. One will be made up if not
* supplied.
* @param {module:client.callback} callback Optional.
* @param {object|module:client.callback} callbackOrOpts
* Options to pass on, may contain `reason`.
* Can be callback for backwards compatibility.
* @return {Promise} Resolves: TODO
* @return {module:http-api.MatrixError} Rejects: with an error response.
*/
MatrixClient.prototype.redactEvent = function(roomId, eventId, txnId, callback) {
MatrixClient.prototype.redactEvent = function(roomId, eventId, txnId, callbackOrOpts) {
const opts = typeof(callbackOrOpts) === 'object' ? callbackOrOpts : {};
const reason = opts.reason;
const callback = typeof(callbackOrOpts) === 'function' ? callbackOrOpts : undefined;
return this._sendCompleteEvent(roomId, {
type: "m.room.redaction",
content: {},
content: { reason: reason },
redacts: eventId,
}, txnId, callback);
};
@@ -4981,19 +5116,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;
};
/**
@@ -5092,6 +5230,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
@@ -5200,7 +5352,11 @@ function setupCallEventHandler(client) {
// This call has previously been answered or hung up: ignore it
return;
}
callEventHandler(e);
try {
callEventHandler(e);
} catch (e) {
logger.error("Caught exception handling call event", e);
}
});
callEventBuffer = [];
}
@@ -5226,7 +5382,11 @@ function setupCallEventHandler(client) {
} else {
// This one wasn't buffered so just run the event handler for it
// straight away
callEventHandler(event);
try {
callEventHandler(event);
} catch (e) {
logger.error("Caught exception handling call event", e);
}
}
});
}
@@ -5431,9 +5591,8 @@ function _PojoToMatrixEventMapper(client, options) {
}
event.attemptDecryption(client._crypto);
}
const room = client.getRoom(event.getRoomId());
if (room && !preventReEmit) {
room.reEmitter.reEmit(event, ["Event.replaced"]);
if (!preventReEmit) {
client.reEmitter.reEmit(event, ["Event.replaced"]);
}
return event;
}
+12 -6
View File
@@ -211,13 +211,16 @@ export class CrossSigningInfo extends EventEmitter {
/**
* Check whether the private keys exist in the local key cache.
*
* @param {string} [type] The type of key to get. One of "master",
* "self_signing", or "user_signing". Optional, will check all by default.
* @returns {boolean} True if all keys are stored in the local cache.
*/
async isStoredInKeyCache() {
async isStoredInKeyCache(type) {
const cacheCallbacks = this._cacheCallbacks;
if (!cacheCallbacks) return false;
for (const type of ["master", "self_signing", "user_signing"]) {
if (!await cacheCallbacks.getCrossSigningKeyCache(type)) {
const types = type ? [type] : ["master", "self_signing", "user_signing"];
for (const t of types) {
if (!await cacheCallbacks.getCrossSigningKeyCache(t)) {
return false;
}
}
@@ -235,6 +238,9 @@ export class CrossSigningInfo extends EventEmitter {
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;
@@ -728,7 +734,7 @@ export async function requestKeysDuringVerification(baseApis, userId, deviceId)
if (baseApis.getUserId() !== userId) {
return;
}
console.log("Cross-signing: Self-verification done; requesting keys");
logger.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) => {
@@ -742,7 +748,7 @@ export async function requestKeysDuringVerification(baseApis, userId, deviceId)
const crossSigning = new CrossSigningInfo(
original.userId,
{ getCrossSigningKey: async (type) => {
console.debug("Cross-signing: requesting secret",
logger.debug("Cross-signing: requesting secret",
type, deviceId);
const { promise } = client.requestSecret(
`m.cross_signing.${type}`, [deviceId],
@@ -805,6 +811,6 @@ export async function requestKeysDuringVerification(baseApis, userId, deviceId)
timeout,
]).then(resolve, reject);
}).catch((e) => {
console.warn("Cross-signing: failure while requesting keys:", e);
logger.warn("Cross-signing: failure while requesting keys:", e);
});
}
+11 -2
View File
@@ -848,6 +848,7 @@ class DeviceListUpdateSerialiser {
await _updateStoredDeviceKeysForUser(
this._olmDevice, userId, userStore, dkResponse || {},
this._baseApis.getUserId(), this._baseApis.deviceId,
);
// put the updates into the object that will be returned as our results
@@ -885,8 +886,9 @@ class DeviceListUpdateSerialiser {
}
async function _updateStoredDeviceKeysForUser(_olmDevice, userId, userStore,
userResult) {
async function _updateStoredDeviceKeysForUser(
_olmDevice, userId, userStore, userResult, localUserId, localDeviceId,
) {
let updated = false;
// remove any devices in the store which aren't in the response
@@ -896,6 +898,13 @@ async function _updateStoredDeviceKeysForUser(_olmDevice, userId, userStore,
}
if (!(deviceId in userResult)) {
if (userId === localUserId && deviceId === localDeviceId) {
logger.warn(
`Local device ${deviceId} missing from sync, skipping removal`,
);
continue;
}
logger.log("Device " + userId + ":" + deviceId +
" has been removed");
delete userStore[deviceId];
+31 -1
View File
@@ -144,7 +144,7 @@ OlmDevice.prototype.init = async function(opts = {}) {
try {
if (fromExportedDevice) {
if (pickleKey) {
console.warn(
logger.warn(
'ignoring opts.pickleKey'
+ ' because opts.fromExportedDevice is present.',
);
@@ -477,6 +477,36 @@ OlmDevice.prototype.generateOneTimeKeys = function(numKeys) {
);
};
/**
* Generate a new fallback keys
*
* @return {Promise} Resolved once the account is saved back having generated the key
*/
OlmDevice.prototype.generateFallbackKey = async function() {
await this._cryptoStore.doTxn(
'readwrite', [IndexedDBCryptoStore.STORE_ACCOUNT],
(txn) => {
this._getAccount(txn, (account) => {
account.generate_fallback_key();
this._storeAccount(txn, account);
});
},
);
};
OlmDevice.prototype.getFallbackKey = async function() {
let result;
await this._cryptoStore.doTxn(
'readonly', [IndexedDBCryptoStore.STORE_ACCOUNT],
(txn) => {
this._getAccount(txn, (account) => {
result = JSON.parse(account.fallback_key());
});
},
);
return result;
};
/**
* Generate a new outbound session
*
+1 -1
View File
@@ -247,7 +247,7 @@ export class SecretStorage extends EventEmitter {
) {
const hasKey = await this.hasKey(keys[0]);
if (hasKey) {
console.log("Fixing up passthrough secret: " + name);
logger.log("Fixing up passthrough secret: " + name);
await this.storePassthrough(name, keys[0]);
const newData = await this._baseApis.getAccountDataFromServer(name);
return newData;
+265
View File
@@ -0,0 +1,265 @@
/*
Copyright 2020 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {decodeBase64, encodeBase64} from './olmlib';
import {IndexedDBCryptoStore} from '../crypto/store/indexeddb-crypto-store';
import {decryptAES, encryptAES} from './aes';
import anotherjson from "another-json";
import {logger} from '../logger';
// FIXME: these types should eventually go in a different file
type Signatures = Record<string, Record<string, string>>;
interface DeviceKeys {
algorithms: Array<string>;
device_id: string; // eslint-disable-line camelcase
user_id: string; // eslint-disable-line camelcase
keys: Record<string, string>;
signatures?: Signatures;
}
interface OneTimeKey {
key: string;
fallback?: boolean;
signatures?: Signatures;
}
export const DEHYDRATION_ALGORITHM = "org.matrix.msc2697.v1.olm.libolm_pickle";
const oneweek = 7 * 24 * 60 * 60 * 1000;
export class DehydrationManager {
private inProgress = false;
private timeoutId: any;
private key: Uint8Array;
private keyInfo: {[props: string]: any};
private deviceDisplayName: string;
constructor(private crypto) {
this.getDehydrationKeyFromCache();
}
async getDehydrationKeyFromCache(): Promise<void> {
return this.crypto._cryptoStore.doTxn(
'readonly',
[IndexedDBCryptoStore.STORE_ACCOUNT],
(txn) => {
this.crypto._cryptoStore.getSecretStorePrivateKey(
txn,
async (result) => {
if (result) {
const {key, keyInfo, deviceDisplayName, time} = result;
const pickleKey = Buffer.from(this.crypto._olmDevice._pickleKey);
const decrypted = await decryptAES(key, pickleKey, DEHYDRATION_ALGORITHM);
this.key = decodeBase64(decrypted);
this.keyInfo = keyInfo;
this.deviceDisplayName = deviceDisplayName;
const now = Date.now();
const delay = Math.max(1, time + oneweek - now);
this.timeoutId = global.setTimeout(
this.dehydrateDevice.bind(this), delay,
);
}
},
"dehydration",
);
},
);
}
async setDehydrationKey(
key: Uint8Array, keyInfo: {[props: string]: any} = {},
deviceDisplayName: string = undefined,
): Promise<void> {
if (!key) {
// unsetting the key -- cancel any pending dehydration task
if (this.timeoutId) {
global.clearTimeout(this.timeoutId);
this.timeoutId = undefined;
}
// clear storage
this.crypto._cryptoStore.doTxn(
'readwrite',
[IndexedDBCryptoStore.STORE_ACCOUNT],
(txn) => {
this.crypto._cryptoStore.storeSecretStorePrivateKey(
txn, "dehydration", null,
);
},
);
this.key = undefined;
this.keyInfo = undefined;
return;
}
// Check to see if it's the same key as before. If it's different,
// dehydrate a new device. If it's the same, we can keep the same
// device. (Assume that keyInfo and deviceDisplayNamme will be the
// same if the key is the same.)
let matches: boolean = this.key && key.length == this.key.length;
for (let i = 0; matches && i < key.length; i++) {
if (key[i] != this.key[i]) {
matches = false;
}
}
if (!matches) {
this.key = key;
this.keyInfo = keyInfo;
this.deviceDisplayName = deviceDisplayName;
// start dehydration in the background
this.dehydrateDevice();
}
}
private async dehydrateDevice(): Promise<void> {
if (this.inProgress) {
logger.log("Dehydration already in progress -- not starting new dehydration");
return;
}
this.inProgress = true;
if (this.timeoutId) {
global.clearTimeout(this.timeoutId);
this.timeoutId = undefined;
}
try {
const pickleKey = Buffer.from(this.crypto._olmDevice._pickleKey);
// update the crypto store with the timestamp
const key = await encryptAES(encodeBase64(this.key), pickleKey, DEHYDRATION_ALGORITHM);
this.crypto._cryptoStore.doTxn(
'readwrite',
[IndexedDBCryptoStore.STORE_ACCOUNT],
(txn) => {
this.crypto._cryptoStore.storeSecretStorePrivateKey(
txn, "dehydration",
{
keyInfo: this.keyInfo,
key,
deviceDisplayName: this.deviceDisplayName,
time: Date.now(),
},
);
},
);
logger.log("Attempting to dehydrate device");
logger.log("Creating account");
// create the account and all the necessary keys
const account = new global.Olm.Account();
account.create();
const e2eKeys = JSON.parse(account.identity_keys());
const maxKeys = account.max_number_of_one_time_keys();
// FIXME: generate in small batches?
account.generate_one_time_keys(maxKeys / 2);
account.generate_fallback_key();
const otks: Record<string, string> = JSON.parse(account.one_time_keys());
const fallbacks: Record<string, string> = JSON.parse(account.fallback_key());
account.mark_keys_as_published();
// dehydrate the account and store it on the server
const pickledAccount = account.pickle(new Uint8Array(this.key));
const deviceData: {[props: string]: any} = {
algorithm: DEHYDRATION_ALGORITHM,
account: pickledAccount,
};
if (this.keyInfo.passphrase) {
deviceData.passphrase = this.keyInfo.passphrase;
}
logger.log("Uploading account to server");
const dehydrateResult = await this.crypto._baseApis._http.authedRequest(
undefined,
"PUT",
"/dehydrated_device",
undefined,
{
device_data: deviceData,
initial_device_display_name: this.deviceDisplayName,
},
{
prefix: "/_matrix/client/unstable/org.matrix.msc2697.v2",
},
);
// send the keys to the server
const deviceId = dehydrateResult.device_id;
logger.log("Preparing device keys", deviceId);
const deviceKeys: DeviceKeys = {
algorithms: this.crypto._supportedAlgorithms,
device_id: deviceId,
user_id: this.crypto._userId,
keys: {
[`ed25519:${deviceId}`]: e2eKeys.ed25519,
[`curve25519:${deviceId}`]: e2eKeys.curve25519,
},
};
const deviceSignature = account.sign(anotherjson.stringify(deviceKeys));
deviceKeys.signatures = {
[this.crypto._userId]: {
[`ed25519:${deviceId}`]: deviceSignature,
},
};
if (this.crypto._crossSigningInfo.getId("self_signing")) {
await this.crypto._crossSigningInfo.signObject(deviceKeys, "self_signing");
}
logger.log("Preparing one-time keys");
const oneTimeKeys = {};
for (const [keyId, key] of Object.entries(otks.curve25519)) {
const k: OneTimeKey = {key};
const signature = account.sign(anotherjson.stringify(k));
k.signatures = {
[this.crypto._userId]: {
[`ed25519:${deviceId}`]: signature,
},
};
oneTimeKeys[`signed_curve25519:${keyId}`] = k;
}
logger.log("Preparing fallback keys");
const fallbackKeys = {};
for (const [keyId, key] of Object.entries(fallbacks.curve25519)) {
const k: OneTimeKey = {key, fallback: true};
const signature = account.sign(anotherjson.stringify(k));
k.signatures = {
[this.crypto._userId]: {
[`ed25519:${deviceId}`]: signature,
},
};
fallbackKeys[`signed_curve25519:${keyId}`] = k;
}
logger.log("Uploading keys to server");
await this.crypto._baseApis._http.authedRequest(
undefined,
"POST",
"/keys/upload/" + encodeURI(deviceId),
undefined,
{
"device_keys": deviceKeys,
"one_time_keys": oneTimeKeys,
"org.matrix.msc2732.fallback_keys": fallbackKeys,
},
);
logger.log("Done dehydrating");
// dehydrate again in a week
this.timeoutId = global.setTimeout(
this.dehydrateDevice.bind(this), oneweek,
);
} finally {
this.inProgress = false;
}
}
}
+109 -44
View File
@@ -56,6 +56,7 @@ import {ToDeviceChannel, ToDeviceRequests} from "./verification/request/ToDevice
import {IllegalMethod} from "./verification/IllegalMethod";
import {KeySignatureUploadError} from "../errors";
import {decryptAES, encryptAES} from './aes';
import {DehydrationManager} from './dehydration';
const DeviceVerification = DeviceInfo.DeviceVerification;
@@ -146,7 +147,7 @@ export function Crypto(baseApis, sessionStore, userId, deviceId,
method,
);
} else {
console.warn(`Excluding unknown verification method ${method}`);
logger.warn(`Excluding unknown verification method ${method}`);
}
}
} else {
@@ -243,6 +244,8 @@ export function Crypto(baseApis, sessionStore, userId, deviceId,
baseApis, cryptoCallbacks,
);
this._dehydrationManager = new DehydrationManager(this);
// Assuming no app-supplied callback, default to getting from SSSS.
if (!cryptoCallbacks.getCrossSigningKey && cryptoCallbacks.getSecretStorageKey) {
cryptoCallbacks.getCrossSigningKey = async (type) => {
@@ -534,6 +537,15 @@ Crypto.prototype.bootstrapCrossSigning = async function({
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, " +
@@ -691,6 +703,15 @@ Crypto.prototype.bootstrapSecretStorage = async function({
oldKeyInfo.algorithm === SECRET_STORAGE_ALGORITHM_V1_AES
);
// 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
@@ -740,10 +761,20 @@ 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
// be trusted via cross-signing.
logger.log("Adding cross signing signature to key backup");
await this._crossSigningInfo.signObject(
keyBackupInfo.auth_data, "master",
);
if (
this._crossSigningInfo.getId() &&
this._crossSigningInfo.isStoredInKeyCache("master")
) {
logger.log("Adding cross-signing signature to key backup");
await this._crossSigningInfo.signObject(
keyBackupInfo.auth_data, "master",
);
} else {
logger.warn(
"Cross-signing keys not available, skipping signature on key backup",
);
}
builder.addSessionBackup(keyBackupInfo);
} else {
// 4S is already set up
@@ -792,8 +823,20 @@ Crypto.prototype.bootstrapSecretStorage = async function({
algorithm: info.algorithm,
auth_data: info.auth_data,
};
// sign with cross-sign master key
await this._crossSigningInfo.signObject(data.auth_data, "master");
if (
this._crossSigningInfo.getId() &&
this._crossSigningInfo.isStoredInKeyCache("master")
) {
// sign with cross-sign master key
logger.log("Adding cross-signing signature to key backup");
await this._crossSigningInfo.signObject(data.auth_data, "master");
} else {
logger.warn(
"Cross-signing keys not available, skipping signature on key backup",
);
}
// sign with the device fingerprint
await this._signObject(data.auth_data);
@@ -1281,23 +1324,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");
@@ -1306,21 +1346,23 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
// Update the version of our keys in our cross-signing object and the local store
this._storeTrustedSelfKeys(newCrossSigning.keys);
const selfSigningChanged = oldSelfSigningId !== newCrossSigning.getId("self_signing");
const userSigningChanged = oldUserSigningId !== newCrossSigning.getId("user_signing");
const keySignatures = {};
if (oldSelfSigningId !== newCrossSigning.getId("self_signing")) {
if (selfSigningChanged) {
logger.info("Got new self-signing key", newCrossSigning.getId("self_signing"));
// Try to cache the self-signing private key as a side-effect
logger.info("Attempting to retrieve cross-signing self-signing private key");
let signing = null;
try {
const ret = await this._crossSigningInfo.getCrossSigningKey(
"self_signing", newCrossSigning.getId("self_signing"),
);
signing = ret[1];
logger.info(
"Got matching private key from callback for new public self-signing key",
);
logger.info("Got cross-signing self-signing private key");
} catch (e) {
logger.error("Cross-signing self-signing private key not available", e);
} finally {
if (signing) signing.free();
}
@@ -1331,19 +1373,18 @@ Crypto.prototype.checkOwnCrossSigningTrust = async function() {
);
keySignatures[this._deviceId] = signedDevice;
}
if (oldUserSigningId !== newCrossSigning.getId("user_signing")) {
if (userSigningChanged) {
logger.info("Got new user-signing key", newCrossSigning.getId("user_signing"));
// Try to cache the user-signing private key as a side-effect
logger.info("Attempting to retrieve cross-signing user-signing private key");
let signing = null;
try {
const ret = await this._crossSigningInfo.getCrossSigningKey(
"user_signing", newCrossSigning.getId("user_signing"),
);
signing = ret[1];
logger.info(
"Got matching private key from callback for new public user-signing key",
);
logger.info("Got cross-signing user-signing private key");
} catch (e) {
logger.error("Cross-signing user-signing private key not available", e);
} finally {
if (signing) signing.free();
}
@@ -1818,6 +1859,14 @@ Crypto.prototype.updateOneTimeKeyCount = function(currentCount) {
}
};
Crypto.prototype.setNeedsNewFallback = function(needsNewFallback) {
this._needsNewFallback = !!needsNewFallback;
};
Crypto.prototype.getNeedsNewFallback = function() {
return this._needsNewFallback;
};
// check if it's time to upload one-time keys, and do so if so.
function _maybeUploadOneTimeKeys(crypto) {
// frequency with which to check & upload one-time keys
@@ -1865,27 +1914,31 @@ function _maybeUploadOneTimeKeys(crypto) {
// out stale private keys that won't receive a message.
const keyLimit = Math.floor(maxOneTimeKeys / 2);
function uploadLoop(keyCount) {
if (keyLimit <= keyCount) {
// If we don't need to generate any more keys then we are done.
return Promise.resolve();
}
async function uploadLoop(keyCount) {
while (keyLimit > keyCount || crypto.getNeedsNewFallback()) {
// Ask olm to generate new one time keys, then upload them to synapse.
if (keyLimit > keyCount) {
logger.info("generating oneTimeKeys");
const keysThisLoop = Math.min(keyLimit - keyCount, maxKeysPerCycle);
await crypto._olmDevice.generateOneTimeKeys(keysThisLoop);
}
const keysThisLoop = Math.min(keyLimit - keyCount, maxKeysPerCycle);
if (crypto.getNeedsNewFallback()) {
logger.info("generating fallback key");
await crypto._olmDevice.generateFallbackKey();
}
// Ask olm to generate new one time keys, then upload them to synapse.
return crypto._olmDevice.generateOneTimeKeys(keysThisLoop).then(() => {
return _uploadOneTimeKeys(crypto);
}).then((res) => {
logger.info("calling _uploadOneTimeKeys");
const res = await _uploadOneTimeKeys(crypto);
if (res.one_time_key_counts && res.one_time_key_counts.signed_curve25519) {
// if the response contains a more up to date value use this
// for the next loop
return uploadLoop(res.one_time_key_counts.signed_curve25519);
keyCount = res.one_time_key_counts.signed_curve25519;
} else {
throw new Error("response for uploading keys does not contain "
+ "one_time_key_counts.signed_curve25519");
throw new Error("response for uploading keys does not contain " +
"one_time_key_counts.signed_curve25519");
}
});
}
}
crypto._oneTimeKeyCheckInProgress = true;
@@ -1917,11 +1970,22 @@ function _maybeUploadOneTimeKeys(crypto) {
// returns a promise which resolves to the response
async function _uploadOneTimeKeys(crypto) {
const promises = [];
const fallbackJson = {};
if (crypto.getNeedsNewFallback()) {
const fallbackKeys = await crypto._olmDevice.getFallbackKey();
for (const [keyId, key] of Object.entries(fallbackKeys.curve25519)) {
const k = { key, fallback: true };
fallbackJson["signed_curve25519:" + keyId] = k;
promises.push(crypto._signObject(k));
}
crypto.setNeedsNewFallback(false);
}
const oneTimeKeys = await crypto._olmDevice.getOneTimeKeys();
const oneTimeJson = {};
const promises = [];
for (const keyId in oneTimeKeys.curve25519) {
if (oneTimeKeys.curve25519.hasOwnProperty(keyId)) {
const k = {
@@ -1935,7 +1999,8 @@ async function _uploadOneTimeKeys(crypto) {
await Promise.all(promises);
const res = await crypto._baseApis.uploadKeysRequest({
one_time_keys: oneTimeJson,
"one_time_keys": oneTimeJson,
"org.matrix.msc2732.fallback_keys": fallbackJson,
});
await crypto._olmDevice.markKeysAsPublished();
@@ -2362,7 +2427,7 @@ Crypto.prototype.getEventSenderDeviceInfo = function(event) {
if (claimedKey !== device.getFingerprint()) {
logger.warn(
"Event " + event.getId() + " claims ed25519 key " + claimedKey +
"but sender device has key " + device.getFingerprint());
" but sender device has key " + device.getFingerprint());
return null;
}
+3 -2
View File
@@ -26,6 +26,7 @@ import {
newUserCancelledError,
} from './Error';
import {encodeUnpaddedBase64, decodeBase64} from "../olmlib";
import {logger} from '../../logger';
export const SHOW_QR_CODE_METHOD = "m.qr_code.show.v1";
export const SCAN_QR_CODE_METHOD = "m.qr_code.scan.v1";
@@ -94,7 +95,7 @@ export class ReciprocateQRCode extends Base {
if (!targetKey) throw newKeyMismatchError();
if (keyInfo !== targetKey) {
console.error("key ID from key info does not match");
logger.error("key ID from key info does not match");
throw newKeyMismatchError();
}
for (const deviceKeyId in device.keys) {
@@ -102,7 +103,7 @@ export class ReciprocateQRCode extends Base {
const deviceTargetKey = keys[deviceKeyId];
if (!deviceTargetKey) throw newKeyMismatchError();
if (device.keys[deviceKeyId] !== deviceTargetKey) {
console.error("master key does not match");
logger.error("master key does not match");
throw newKeyMismatchError();
}
}
+5 -7
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 || {});
@@ -963,7 +961,7 @@ export async function retryNetworkOperation(maxAttempts, callback) {
try {
if (attempts > 0) {
const timeout = 1000 * Math.pow(2, attempts);
console.log(`network operation failed ${attempts} times,` +
logger.log(`network operation failed ${attempts} times,` +
` retrying in ${timeout}ms...`);
await new Promise(r => setTimeout(r, timeout));
}
+2
View File
@@ -40,11 +40,13 @@ log.methodFactory = function(methodName, logLevel, loggerName) {
methodName === "warn" ||
methodName === "trace" ||
methodName === "info";
/* eslint-disable no-console */
if (supportedByConsole) {
return console[methodName](...args);
} else {
return console.log(...args);
}
/* eslint-enable no-console */
};
};
+30
View File
@@ -121,11 +121,41 @@ interface ICreateClientOpts {
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>;
};
}
/**
+1 -1
View File
@@ -806,7 +806,7 @@ EventTimelineSet.prototype.aggregateRelations = function(event) {
this.room,
);
isNewRelations = true;
relatesToEvent = this.findEventById(relatesToEventId);
relatesToEvent = this.findEventById(relatesToEventId) || this.room.getPendingEvent(relatesToEventId);
if (relatesToEvent) {
relationsWithEventType.setTargetEvent(relatesToEvent);
}
+2
View File
@@ -904,6 +904,8 @@ utils.extend(MatrixEvent.prototype, {
/**
* Set an event that replaces the content of this event, through an m.replace relation.
*
* @fires module:models/event.MatrixEvent#"Event.replaced"
*
* @param {MatrixEvent?} newEvent the event with the replacing content, if any.
*/
makeReplaced(newEvent) {
+5 -4
View File
@@ -16,6 +16,7 @@ limitations under the License.
import {EventEmitter} from 'events';
import {EventStatus} from '../models/event';
import {logger} from '../logger';
/**
* A container for relation events that supports easy access to common ways of
@@ -60,7 +61,7 @@ export class Relations extends EventEmitter {
const relation = event.getRelation();
if (!relation) {
console.error("Event must have relation info");
logger.error("Event must have relation info");
return;
}
@@ -68,7 +69,7 @@ export class Relations extends EventEmitter {
const eventType = event.getType();
if (this.relationType !== relationType || this.eventType !== eventType) {
console.error("Event relation info doesn't match this container");
logger.error("Event relation info doesn't match this container");
return;
}
@@ -104,7 +105,7 @@ export class Relations extends EventEmitter {
const relation = event.getRelation();
if (!relation) {
console.error("Event must have relation info");
logger.error("Event must have relation info");
return;
}
@@ -112,7 +113,7 @@ export class Relations extends EventEmitter {
const eventType = event.getType();
if (this.relationType !== relationType || this.eventType !== eventType) {
console.error("Event relation info doesn't match this container");
logger.error("Event relation info doesn't match this container");
return;
}
+14
View File
@@ -373,6 +373,20 @@ Room.prototype.hasPendingEvent = function(eventId) {
return this._pendingEventList.some(event => event.getId() === eventId);
};
/**
* Get a specific event from the pending event list, if configured, null otherwise.
*
* @param {string} eventId The event ID to check for.
* @return {MatrixEvent}
*/
Room.prototype.getPendingEvent = function(eventId) {
if (this._opts.pendingEventOrdering !== "detached") {
return null;
}
return this._pendingEventList.find(event => event.getId() === eventId);
};
/**
* Get the live unfiltered timeline for this room.
*
+2 -1
View File
@@ -16,6 +16,7 @@ limitations under the License.
*/
import {escapeRegExp, globToRegexp, isNullOrUndefined} from "./utils";
import {logger} from './logger';
/**
* @module pushprocessor
@@ -444,7 +445,7 @@ PushProcessor.rewriteDefaultRules = function(incomingRules) {
} else {
// Add the rule
const ruleId = override.rule_id;
console.warn(`Adding default global override for ${ruleId}`);
logger.warn(`Adding default global override for ${ruleId}`);
globalOverrides.push(override);
}
}
+10
View File
@@ -1361,6 +1361,16 @@ SyncApi.prototype._processSyncResponse = async function(
const currentCount = data.device_one_time_keys_count.signed_curve25519 || 0;
this.opts.crypto.updateOneTimeKeyCount(currentCount);
}
if (this.opts.crypto && data["org.matrix.msc2732.device_unused_fallback_key_types"]) {
// The presence of device_unused_fallback_key_types indicates that the
// server supports fallback keys. If there's no unused
// signed_curve25519 fallback key we need a new one.
const unusedFallbackKeys = data["org.matrix.msc2732.device_unused_fallback_key_types"];
this.opts.crypto.setNeedsNewFallback(
unusedFallbackKeys instanceof Array &&
!unusedFallbackKeys.includes("signed_curve25519"),
);
}
};
/**
+30 -3
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;
@@ -703,12 +705,29 @@ MatrixCall.prototype._gotLocalIceCandidate = function(event) {
// As with the offer, note we need to make a copy of this object, not
// pass the original: that broke in Chrome ~m43.
if (event.candidate.candidate !== '' || !this._sentEndOfCandidates) {
const c = {
candidate: event.candidate.candidate,
sdpMid: event.candidate.sdpMid,
sdpMLineIndex: event.candidate.sdpMLineIndex,
};
sendCandidate(this, c);
if (event.candidate.candidate === '') this._sentEndOfCandidates = true;
}
}
};
MatrixCall.prototype._onIceGatheringStateChange = function(event) {
debuglog("ice gathering state changed to " + this.peerConn.iceGatheringState);
if (this.peerConn.iceGatheringState === 'complete' && !this._sentEndOfCandidates) {
// If we didn't get an empty-string candidate to signal the end of candidates,
// create one ourselves now gathering has finished.
const c = {
candidate: event.candidate.candidate,
sdpMid: event.candidate.sdpMid,
sdpMLineIndex: event.candidate.sdpMLineIndex,
candidate: '',
};
sendCandidate(this, c);
this._sentEndOfCandidates = true;
}
};
@@ -722,6 +741,13 @@ MatrixCall.prototype._gotRemoteIceCandidate = function(cand) {
//debuglog("Ignoring remote ICE candidate because call has ended");
return;
}
if (
(cand.sdpMid === null || cand.sdpMid === undefined) &&
(cand.sdpMLineIndex === null || cand.sdpMLineIndex === undefined)
) {
debuglog("Ignoring remote ICE candidate with no sdpMid or sdpMLineIndex");
return;
}
debuglog("Got remote ICE " + cand.sdpMid + " candidate: " + cand.candidate);
this.peerConn.addIceCandidate(
new this.webRtc.RtcIceCandidate(cand),
@@ -1231,6 +1257,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;
};
+847 -503
View File
File diff suppressed because it is too large Load Diff