Compare commits

...

1613 Commits

Author SHA1 Message Date
RiotRobot 6d018826f4 v30.2.0 2023-12-05 13:35:06 +00:00
RiotRobot df1a6a583a v30.2.0-rc.0 2023-11-28 16:11:15 +00:00
Richard van der Hoff a7496627fc Explicitly free some Rust-side objects (#3911)
* Explicitly `free` stuff returned by `OlmMachine.getIdentity()`

* Explicitly `free` stuff returned by `OlmMachine.getDevice()`

* one more
2023-11-28 13:14:53 +00:00
Richard van der Hoff 8ef2ca681c Update to matrix-sdk-crypto-wasm 3.1.0 (#3909) 2023-11-27 15:15:58 +00:00
Johannes Marbach 0c7342cb20 Set up CI to lint workflows with action-validator (#3905)
* Set up CI to lint workflows with action-validator

* Rename release-action workflow
2023-11-24 14:41:19 +00:00
Will Hunt 429c05ba85 TimestampToEventResponse.origin_server_ts should be a number (#3906) 2023-11-23 16:46:01 +00:00
Andy Balaam af9993a710 Remove 'Ignoring receipt' log line that logs very often' (#3904)
* Remove 'Ignoring receipt' log line that logs very often'

* Fix test expecting the log line I removed
2023-11-22 12:14:42 +00:00
Valere ff501834e6 Only await key query after lazy members resolved (#3902)
* Only await key query after lazy members resolved

* code review

* Update src/rust-crypto/RoomEncryptor.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-11-22 09:19:13 +00:00
Michael Telatynski ef9157b37a Fix Ingest upstream changes for downstreams with missing sections
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-21 12:31:40 +00:00
Michael Telatynski da0a55cea4 Merge remote-tracking branch 'origin/develop' into develop 2023-11-21 11:46:06 +00:00
Michael Telatynski d644f111ea Fix Ingest upstream changes for element-desktop
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-21 11:45:55 +00:00
RiotRobot b2018ef81b Resetting package fields for development 2023-11-21 11:00:05 +00:00
RiotRobot a4faab6155 Merge branch 'master' into develop 2023-11-21 11:00:04 +00:00
RiotRobot 4ab226e580 v30.1.0 2023-11-21 10:59:16 +00:00
Richard van der Hoff 1889f8dad5 Reduce console log spam (#3896)
* Reduce console log spam

A couple of different things:

 * Increase the `MaxListeners` setting on `MatrixClient` and `Thread`, so that
   we don't get "possible EventEmitter leak" warnings

 * Disable a couple of warnings/info lines that are just part of regular
   operation and are logged in large volumes.

* another noisy log line

* Reinstate warning about receipts for missing events

Apparently this is being worked on
2023-11-20 18:17:06 +00:00
Timo e98ce78027 Better fallback for the event localTimestamp calculation. (#3900)
* better fallback to localTimestamp calculation

Signed-off-by: Timo K <toger5@hotmail.de>

* make `isExpired` impl simpler to read

Signed-off-by: Timo K <toger5@hotmail.de>

* update tests

Signed-off-by: Timo K <toger5@hotmail.de>

* refactor to use localTimestamp in the mocks

Signed-off-by: Timo K <toger5@hotmail.de>

* Update src/models/event.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/models/event.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update and clarify comments.
So that the localTimestamp and localAge behavior is easier to understand.

Signed-off-by: Timo K <toger5@hotmail.de>

* Replace localTimestamp biding
with binding the whole roomState

Signed-off-by: Timo K <toger5@hotmail.de>

---------

Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-11-20 17:20:04 +00:00
Richard van der Hoff 83ba0fbb49 Improve logging of event encryption in RustCrypto (#3898)
* Improve logging of event encryption in `RustCrypto`

* fix tests
2023-11-19 21:16:41 +00:00
Richard van der Hoff 757c5e1d71 Stop logging decryptions as retries (#3897)
Somebody seems to have decided that `isRetry` needs setting whenever we try to decrypt an event. This is nonsense, and leads to confusing logs.
2023-11-17 14:30:27 +00:00
Johannes Marbach eca651c0c2 Explicitly forward ELEMENT_BOT_TOKEN (#3894)
`inherit` doesn't work across orgs, sadly.
2023-11-16 14:46:56 +00:00
Andy Balaam 2205445a50 Specify the correct environment for the docs builder workflow (#3893) 2023-11-16 13:40:02 +00:00
renovate[bot] f168144c84 Update matrix-org/sonarcloud-workflow-action action to v2.7 (#3892)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-16 10:58:00 +00:00
Michael Telatynski eb288d125f Remove unused dependencies and add transitive dep (#3874)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-16 09:47:30 +00:00
Michael Telatynski 4a72364fe3 Merge remote-tracking branch 'origin/develop' into develop 2023-11-16 08:33:20 +00:00
Michael Telatynski c2fa579fb2 Fix merge-release-notes.js script
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-16 08:33:08 +00:00
renovate[bot] f71735d0c2 Update babel monorepo to v7.23.3 (#3881)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-15 22:26:23 +00:00
renovate[bot] e5ccfa86fe Update actions/github-script action to v7 (#3886)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-15 22:25:24 +00:00
renovate[bot] 97c531aa42 Update all non-major dependencies (#3884)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-15 22:24:58 +00:00
renovate[bot] 44487078fb Update dependency @types/jest to v29.5.8 (#3883)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-15 22:24:49 +00:00
renovate[bot] e3c70a3ee4 Update actions/setup-node action to v4 (#3887)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 22:19:02 +00:00
renovate[bot] feb60a54b2 Update definitelyTyped (#3882)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 22:10:00 +00:00
David Baker c6e6248cd6 Don't rotate keys if not managing media keys (#3877)
This could have caused weirdness in non per-user key calling mode.
2023-11-15 14:44:58 +00:00
Timo 10cd84a653 Add CallNotifyEvent to support matrixRTC ringing (#3878)
* Add CallNotifyEvent to support matrix rtc ringing

Signed-off-by: Timo K <toger5@hotmail.de>

* test SessionId

Signed-off-by: Timo K <toger5@hotmail.de>

* docs + sessionId->callId

Signed-off-by: Timo K <toger5@hotmail.de>

---------

Signed-off-by: Timo K <toger5@hotmail.de>
2023-11-15 11:20:05 +00:00
Andy Balaam c36166d156 Merge pull request #3869 from matrix-org/andybalaam/unrevert-deletion-move-prs
Unrevert "Move redacted messages out of any thread, into main thread"
2023-11-15 08:23:50 +00:00
renovate[bot] 3a2cf14a68 Update matrix-org/matrix-react-sdk digest to f6ef476 (#3879)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-15 00:58:24 +00:00
Andy Balaam dd94f67a4f Merge branch 'develop' into andybalaam/unrevert-deletion-move-prs 2023-11-14 16:13:56 +00:00
Michael Telatynski 138281c620 Fix RELEASE_ID
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-14 17:12:49 +01:00
RiotRobot f75abecc92 v30.1.0-rc.1 2023-11-14 15:37:50 +00:00
Michael Telatynski 378a91fe10 Fix yarn version call in release-action.yml
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-14 16:31:58 +01:00
Michael Telatynski 300635e3ee Update package.json 2023-11-14 15:31:26 +00:00
Michael Telatynski 37ba169abf Update release-drafter.yml 2023-11-14 14:52:56 +00:00
RiotRobot e6e7798389 v30.1.0-rc.0 2023-11-14 14:29:48 +00:00
Michael Telatynski 48fe267ea7 release-action.yml iterate
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-14 15:26:31 +01:00
Michael Telatynski a11fd8bc86 release-npm.yml ref=staging
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-14 15:22:03 +01:00
Michael Telatynski eb9e557a64 Update release-action.yml 2023-11-14 14:19:52 +00:00
RiotRobot 41c8c40d47 v30.1.0-rc.1 2023-11-14 14:17:37 +00:00
Michael Telatynski b9e684fdc3 Update release-action.yml 2023-11-14 14:07:25 +00:00
RiotRobot 9faff0dbff v30.1.0-rc.0 2023-11-14 14:04:14 +00:00
Michael Telatynski 9044145a7e Update release-action.yml 2023-11-14 14:03:09 +00:00
Michael Telatynski 939def2aa1 Update release-drafter.yml 2023-11-14 13:51:16 +00:00
Michael Telatynski c54f8f6106 Update release-drafter.yml 2023-11-14 13:47:56 +00:00
Michael Telatynski 25a777a0a6 Update release-drafter.yml 2023-11-14 13:41:37 +00:00
Michael Telatynski 7de9b23e59 Add support for ingest-changes to refer to a project without package.json (#3864)
* Tidy reusable release workflow

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add ability to include upstream changes

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add ability to upload assets and gpg sign them

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update relative composite actions

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Wire up validating release tarball signature

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Validate release has expected assets

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Paths

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Use gpg outputs for email instead of scraping it ourselves

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* v6

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Extract pre-release and post-merge-master scripts

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Reuse pre-release and post-merge-master scripts in gha

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Cull unused vars

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Revert

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove unused variables

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Simplify

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Simplify and fix merge-release-notes script

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Tidy release automation

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update release.sh

* Move environment

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* s/includes/contains/

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate uses syntax

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix action-repo calls

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix RELEASE_NOTES env

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix if check

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix gpg tag signing

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Cull stale params

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix sign-release-tarball paths being outside the workspace

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix gpg validation (of course wget uses `-O` and not `-o`)

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix expected asset assertion

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix release publish mode

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add support for ingest-changes to refer to a project without it being in node_modules

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-13 12:43:18 +00:00
Michael Telatynski d179b8c557 Add automation to advance release blocker labels during the release (#3866)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-13 09:46:11 +00:00
ElementRobot 76f993e7ff Merge branch 'master' into develop 2023-11-13 09:44:12 +00:00
ElementRobot 430e6cae94 v30.0.1 2023-11-13 09:44:06 +00:00
ElementRobot e01a1d533c Prepare changelog for v30.0.1 2023-11-13 09:44:04 +00:00
ElementRobot 46a6a76a41 [Backport staging] Ensure setUserCreator is called when a store is assigned (#3876)
Co-authored-by: R Midhun Suresh <hi@midhun.dev>
2023-11-13 09:11:27 +00:00
Johannes Marbach d2e951738a Automatically add tech-debt issues to the right project (#3872) 2023-11-11 07:21:31 +00:00
R Midhun Suresh 882dc920c3 Ensure setUserCreator is called when a store is assigned (#3867)
* Add method to set store

* Use not null assertion

* Use getter/setter

* No need for check if we use setter
2023-11-11 07:20:36 +00:00
Michael Telatynski 9efc0acb9d Automate checking there is no published release using the version already (#3865)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-11 06:53:14 +00:00
Michael Telatynski 625753c388 Update tests.yml (#3847) 2023-11-10 20:30:33 +00:00
Richard van der Hoff a28530004a Bump matrix-sdk-crypto-wasm to 3.0.1 (#3849)
* Bump matrix-sdk-crypto-wasm to 3.0.0

... which changes the API of `bootstrapCrossSigning` a bit.

* Fix class names in test

* fix brokenness in bootstrapCrossSigning

* Bump to `matrix-sdk-crypto-wasm` 3.0.1
2023-11-10 16:57:50 +00:00
Richard van der Hoff 437b7ff780 Revert "Better fallback for unavailable event age (#3854)" (#3870)
This reverts commit 84bd8ab81f.
2023-11-10 00:06:48 +00:00
Michael Telatynski 24ed030294 Extend release automation with GPG signing, assets & changelog merging (#3852)
* Tidy reusable release workflow

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add ability to include upstream changes

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add ability to upload assets and gpg sign them

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update relative composite actions

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Wire up validating release tarball signature

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Validate release has expected assets

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Paths

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Use gpg outputs for email instead of scraping it ourselves

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* v6

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Extract pre-release and post-merge-master scripts

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Reuse pre-release and post-merge-master scripts in gha

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Cull unused vars

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Revert

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove unused variables

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Simplify

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Simplify and fix merge-release-notes script

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Tidy release automation

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update release.sh

* Move environment

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* s/includes/contains/

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Iterate uses syntax

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix action-repo calls

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix RELEASE_NOTES env

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix if check

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix gpg tag signing

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Cull stale params

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix sign-release-tarball paths being outside the workspace

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix gpg validation (of course wget uses `-O` and not `-o`)

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix expected asset assertion

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix release publish mode

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-09 20:54:29 +00:00
Andy Balaam 5c160d0f45 Shorten TimelineWindow when an event is removed (#3862)
* Shorten TimelineWindow when an event is removed

Needed for the fix for https://github.com/vector-im/element-web/issues/26498

* Declare onTimelineEvent as a standard method to match surrounding code
2023-11-09 16:41:15 +00:00
Andy Balaam 53615c9938 Merge pull request #3855 from matrix-org/rav/cypress-element-r
Cypress workflow: remove redundant `rust-crypto` param
2023-11-09 15:34:49 +00:00
Andy Balaam d8735cf543 Merge pull request #3868 from matrix-org/midhun/update-cypress-workfile
Update workfile to pull in changes from react-sdk
2023-11-09 15:07:40 +00:00
R Midhun Suresh ffb4cae792 Update workfile 2023-11-09 20:00:45 +05:30
Andy Balaam 0261868eb6 Revert "Revert "Move the redaction event to main at the same time we move redacted""
This reverts commit 11755f5a0a1486fa6ad3cb9e4b8959ddc7e1d276.
2023-11-09 14:30:41 +00:00
Andy Balaam 6ba4b35526 Revert "Revert "Don't remove thread info from a thread root when it is redacted""
This reverts commit 4dbff2a837cbc5ba37424c65ccdc833a1843deb2.
2023-11-09 14:30:41 +00:00
Andy Balaam f5ad4d0a73 Revert "Revert "Move all related messages into main timeline on redaction""
This reverts commit 257b40bceb304001c03aaec7b140a1fd05c96d9e.
2023-11-09 14:30:41 +00:00
Andy Balaam 582ea68c31 Revert "Revert "Factor out the code for moving an event to the main timeline""
This reverts commit 272be48a54a45df89603a27fbbe6e26da88b95ba.
2023-11-09 14:30:41 +00:00
Andy Balaam 304c2b12bf Revert "Revert "Factor out utils in redaction tests""
This reverts commit 2525c82049dc1a958446b66cc85656c1b57a5271.
2023-11-09 14:30:41 +00:00
Andy Balaam a3762c8e22 Revert "Revert "Move redaction event tests into their own describe block""
This reverts commit 2e24481df335411ee489ac7046c5514821afa4fa.
2023-11-09 14:30:41 +00:00
Andy Balaam 8b2a334ac4 Revert "Revert "Move redacted messages out of any thread, into main timeline.""
This reverts commit 46114a025c5ec5b2658803c8c86d5e855b55a4fb.
2023-11-09 14:30:41 +00:00
Michael Telatynski 5931a5119c Tidy release automation (#3857) 2023-11-08 12:20:25 +00:00
renovate[bot] 6ae3c208f6 Update all non-major dependencies (#3863)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-08 12:08:04 +00:00
ElementRobot 107e28e114 Resetting package fields for development 2023-11-07 15:11:56 +00:00
ElementRobot 1d1157f546 Merge branch 'master' into develop 2023-11-07 15:11:53 +00:00
ElementRobot fe3f969698 v30.0.0 2023-11-07 15:11:47 +00:00
ElementRobot 96c6c99644 Prepare changelog for v30.0.0 2023-11-07 15:11:45 +00:00
ElementRobot 55230dd0ea [Backport staging] Revert code moving deleted messages to main timeline (#3859)
Co-authored-by: Andy Balaam <andy.balaam@matrix.org>
2023-11-07 14:31:37 +00:00
Andy Balaam 7813e12eb0 Revert code moving deleted messages to main timeline (#3858)
* Revert "Move the redaction event to main at the same time we move redacted"

This reverts commit 378a776815f63fdd1e4d507af35046c0ba88153c.

Context: https://github.com/vector-im/element-web/issues/26498

* Revert "Don't remove thread info from a thread root when it is redacted"

This reverts commit 17b61a69c20677e39e4f3b1b4ed5903421eaee6b.

Context: https://github.com/vector-im/element-web/issues/26498

* Revert "Move all related messages into main timeline on redaction"

This reverts commit d8fc1795f1319b6a77175c5c584ae03be53c457c.

Context: https://github.com/vector-im/element-web/issues/26498

* Revert "Factor out the code for moving an event to the main timeline"

This reverts commit 942dfcb84b8aef6ea84a419d73e845d3611bd91c.

Context: https://github.com/vector-im/element-web/issues/26498

* Revert "Factor out utils in redaction tests"

This reverts commit 43a0dc56e130f75ef695b52cd23945e10393119a.

Context: https://github.com/vector-im/element-web/issues/26498

* Revert "Move redaction event tests into their own describe block"

This reverts commit 9b0ea80f93fe944da03c27df26064cae1765c94d.

Context: https://github.com/vector-im/element-web/issues/26498

* Revert "Move redacted messages out of any thread, into main timeline."

This reverts commit b94d137398.

Context: https://github.com/vector-im/element-web/issues/26498
2023-11-07 13:41:33 +00:00
David Baker 036fd943ac Rotate per-participant keys when a member leaves (#3833)
* WIP refactor for removing m.call events

* Always remember rtcsessions since we need to only have one instance

* Fix tests

* Fix import loop

* Fix more cyclic imports & tests

* Test session joining

* Attempt to make tests happy

* Always leave calls in the tests to clean up

* comment + desperate attempt to work out what's failing

* More test debugging

* Okay, so these ones are fine?

* Stop more timers and hopefully have happy tests

* Test no rejoin

* Test malformed m.call.member events

* Test event emitting

and also move some code to a more sensible place in the file

* Test getActiveFoci()

* Test event emitting (and also fix it)

* Test membership updating & pruning on join

* Test getOldestMembership()

* Test member event renewal

* Don't start the rtc manager until the client has synced

Then we can initialise from the state once it's completed.

* Fix type

* Remove listeners added in constructor

* Stop the client here too

* Stop the client here also also

* ARGH. Disable tests to work out which one is causing the exception

* Disable everything

* Re-jig to avoid setting listeners in the constructor

and re-enable tests

* No need to rename this anymore

* argh, remove the right listener

* Is it this test???

* Re-enable some tests

* Try mocking getRooms to return something valid

* Re-enable other tests

* Give up trying to get the tests to work sensibly and deal with getRooms() returning nothing

* Oops, don't enable the ones that were skipped before

* One more try at the sensible way

* Didn't work, go back to the hack way.

* Log when we manage to send the member event update

* Support `getOpenIdToken()` in embedded mode (#3676)

* Call `sendContentLoaded()` (#3677)

* Start MatrixRTC in embedded mode (#3679)

* Reschedule the membership event check

* Bump widget api version

* Add mock for sendContentLoaded()

* Embeded mode pre-requisites

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Embeded mode E2EE

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Encryption condition

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Revert "Embeded mode pre-requisites"

This reverts commit 8cd73702052609c995ad754e31f85d0da0be4aa9.

* Get back event type

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

fds

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Change embedded E2EE implementation

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* More log detail

* Fix tests

and also better assert because the tests were passing undefined which
was considered fine because we were only checking for null.

* Simplify updateCallMembershipEvent a bit

* Split up updateCallMembershipEvent some more

* Use `crypto.getRandomValues()`

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Rename to `membershipToUserAndDeviceId()`

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Better error

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Add log line

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Add comment

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Send call ID in enc events

(also a small refactor)

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Revert making `joinRoomSession()` async

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Make `client` `private` again

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Just use `toString()`

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix `callId` check

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix map

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix map compare

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix emitting

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Explicit logging

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Refactor

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Make `updateEncryptionKeyEvent()` public

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Only update keys based on others

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix call order

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Improve logging

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Avoid races

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Revert "Avoid races"

This reverts commit f65ed72d6e.

* Add try-catch

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Make `updateEncryptionKeyEvent()` private

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Handle indices and throttling

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix merge mistakes

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Mort post-merge fixes

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Split out key generation from key sending

And send all keys in a key event (changes the format of the key event)
rather than just the one we just generated.

* Remember and clear the timeout for the send key event

So we don't schedule more key updates if one is already pending.
Also don't update the last sent time when we didn't actually send the
keys.

* Make key event resends more robust

* Attempt to make tests pass

* crypto wasn't defined at all

* Hopefully get interface right

* Fix key format on the wire to base64

* Add comment

* More standard method order

* Rename encryptMedia

The js-sdk doesn't do media and therefore doesn't do media encryption

* Stop logging encryption keys now

* Use regular base64

It's not going in a URL, so no need

* Re-add base64url

randomstring was using it. Also give it a test.

* Add tests for randomstring

* Switch between either browser or node crypto

Let's see if this will work...

* Obviously crypto has already solved this

* Some tests for MatrixRTCSession key stuff

* Test keys object contents

* Change keys event format

To move away from m. keys

* Test key event retries

* Test onCallEncryption

* Test event sending & spam prevention

* Test event cancelation

* Test onCallEncryption called

* Better before/after member comparison

Only trigger for when members actually join, and just generally
make it a bit more understandable.

* Rotate per-participant keys when a member leaves

With a delay borth before making a new key, to try to batch up multiple
people leaving into a single key change, and a delay before actually
using the new key to allow time for it to arrive.

This increasingly feels like storing our own sender key in the same set
is suboptimal because we're starting to have to treat it more & more
specially.

* Some errors didn't have data

* Fix binary key comparison

& add log line

* Fix compare function with undefined values

* Test key rotation

* Test caught a merge bug!

* The missing word was, 'delay'

* More input validation

---------

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>
2023-11-07 11:12:11 +00:00
Timo 84bd8ab81f Better fallback for unavailable event age (#3854)
* Age fallback using origin_server_ts instead of 0

Signed-off-by: Timo K <toger5@hotmail.de>

* use getMsUntilExpiry for isExpired

Signed-off-by: Timo K <toger5@hotmail.de>

* fix tests
tests now also rely on localTimestamp. So this need to be mocked as well

Signed-off-by: Timo K <toger5@hotmail.de>

* better fallback for unavailable unsigned

Signed-off-by: Timo K <toger5@hotmail.de>

---------

Signed-off-by: Timo K <toger5@hotmail.de>
2023-11-06 17:12:24 +00:00
Michael Telatynski a25ba7bfd9 Iterate reusable release automation workflows (#3851)
* Clean up unused envvar

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Make the gitflow workflow reusable

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add support for resetting dependencies to develop after merge

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Rename workflow file

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-06 13:25:19 +00:00
Andy Balaam 311494bd44 Ignore receipts pointing at missing or invalid events (#3817)
* Ignore receipts pointing at missing or invalid events

* Remove extra whitespace from log message

* Unit tests for ignoring invalid receipts

* Improve comments around getEventReadUpTo

* Re-instate second param to compareEventOrdering in test

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Further improve comments around getEventReadUpTo

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-11-06 09:19:21 +00:00
Richard van der Hoff 89b7e7d792 Cypress workflow: remove redundant rust-crypto param
https://github.com/matrix-org/matrix-react-sdk/pull/11828 removes the
`rust-crypto` input param from the reusable cypress workflow. This gets rid of
it on the calling side.
2023-11-03 15:51:07 +00:00
Valere 7921fee164 Fix members being loaded from server on initial sync (defeating lazy loading) (#3830)
* fix members loaded on intitial sync

* Update test to use KeyResponder

* Use E2EKeyResponder

* code review

* better comment

* fix test

* post merge fix

* fix imports

* refactoring, better names

* code review

* clean tests

* Cleanups per review comments

* fix test

* Apply suggestions from code review

---------

Co-authored-by: Richard van der Hoff <richard@matrix.org>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-11-03 14:55:48 +00:00
Richard van der Hoff 5bc132a24c Revert "Age fallback using origin_server_ts instead of 0 (#3839)" (#3853)
This reverts commit 685ef791c8.
2023-11-03 13:32:42 +00:00
Timo 685ef791c8 Age fallback using origin_server_ts instead of 0 (#3839)
* Age fallback using origin_server_ts instead of 0

Signed-off-by: Timo K <toger5@hotmail.de>

* use getMsUntilExpiry for isExpired

Signed-off-by: Timo K <toger5@hotmail.de>

* fix tests
tests now also rely on localTimestamp. So this need to be mocked as well

Signed-off-by: Timo K <toger5@hotmail.de>

* fix another test that now also depends on localTimestamp

Signed-off-by: Timo K <toger5@hotmail.de>

* fix tests and cleanup

Signed-off-by: Timo K <toger5@hotmail.de>

* format

Signed-off-by: Timo K <toger5@hotmail.de>

* make things simpler by calculating localTimestamp
from getLocalAge

Signed-off-by: Timo K <toger5@hotmail.de>

* this test was not covered by the change to mockRTCEvent

Signed-off-by: Timo K <toger5@hotmail.de>

* format

Signed-off-by: Timo K <toger5@hotmail.de>

---------

Signed-off-by: Timo K <toger5@hotmail.de>
2023-11-02 13:02:02 +00:00
Michael Telatynski 4458dcc2a4 Make release automation reusable and add dependency upgrade support (#3848)
* Extract release into reusable action

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add dependency upgrade task to release-action

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Prevent develop dependencies

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Simplify dependency management

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Add missing secret declaration

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-11-01 23:24:05 +00:00
renovate[bot] 36c958642c Update all non-major dependencies (#3842)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-01 08:34:18 +00:00
renovate[bot] b62e97eb92 Update actions/setup-node action to v4 (#3844)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-01 08:31:51 +00:00
Michael Telatynski 448fab9e8a New release automations (#3813) 2023-11-01 08:40:43 +00:00
Hugh Nimmo-Smith e2a2039aa8 Remove deprecated support for unstable MSC3882 (#3755)
* Support for stable MSC3882 get_login_token

* Make changes non-breaking by deprecation

* Remove deprecated exports from MSC3882 stabilisation

* Feat remove support for unstable MSC3882

* Remove bad line from rebase
2023-10-31 17:15:54 +00:00
renovate[bot] 99f70cd048 Update JS-DevTools/npm-publish action to v3 (#3843)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-31 16:09:00 +00:00
Šimon Brandner bf81c4bfeb Add E2EE for embedded mode of Element Call (#3667)
* WIP refactor for removing m.call events

* Always remember rtcsessions since we need to only have one instance

* Fix tests

* Fix import loop

* Fix more cyclic imports & tests

* Test session joining

* Attempt to make tests happy

* Always leave calls in the tests to clean up

* comment + desperate attempt to work out what's failing

* More test debugging

* Okay, so these ones are fine?

* Stop more timers and hopefully have happy tests

* Test no rejoin

* Test malformed m.call.member events

* Test event emitting

and also move some code to a more sensible place in the file

* Test getActiveFoci()

* Test event emitting (and also fix it)

* Test membership updating & pruning on join

* Test getOldestMembership()

* Test member event renewal

* Don't start the rtc manager until the client has synced

Then we can initialise from the state once it's completed.

* Fix type

* Remove listeners added in constructor

* Stop the client here too

* Stop the client here also also

* ARGH. Disable tests to work out which one is causing the exception

* Disable everything

* Re-jig to avoid setting listeners in the constructor

and re-enable tests

* No need to rename this anymore

* argh, remove the right listener

* Is it this test???

* Re-enable some tests

* Try mocking getRooms to return something valid

* Re-enable other tests

* Give up trying to get the tests to work sensibly and deal with getRooms() returning nothing

* Oops, don't enable the ones that were skipped before

* One more try at the sensible way

* Didn't work, go back to the hack way.

* Log when we manage to send the member event update

* Support `getOpenIdToken()` in embedded mode (#3676)

* Call `sendContentLoaded()` (#3677)

* Start MatrixRTC in embedded mode (#3679)

* Reschedule the membership event check

* Bump widget api version

* Add mock for sendContentLoaded()

* Embeded mode pre-requisites

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Embeded mode E2EE

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Encryption condition

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Revert "Embeded mode pre-requisites"

This reverts commit 8cd73702052609c995ad754e31f85d0da0be4aa9.

* Get back event type

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

fds

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Change embedded E2EE implementation

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* More log detail

* Fix tests

and also better assert because the tests were passing undefined which
was considered fine because we were only checking for null.

* Simplify updateCallMembershipEvent a bit

* Split up updateCallMembershipEvent some more

* Use `crypto.getRandomValues()`

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Rename to `membershipToUserAndDeviceId()`

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Better error

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Add log line

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Add comment

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Send call ID in enc events

(also a small refactor)

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Revert making `joinRoomSession()` async

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Make `client` `private` again

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Just use `toString()`

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix `callId` check

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix map

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix map compare

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix emitting

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Explicit logging

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Refactor

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Make `updateEncryptionKeyEvent()` public

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Only update keys based on others

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix call order

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Improve logging

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Avoid races

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Revert "Avoid races"

This reverts commit f65ed72d6e.

* Add try-catch

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Make `updateEncryptionKeyEvent()` private

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Handle indices and throttling

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix merge mistakes

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Mort post-merge fixes

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Split out key generation from key sending

And send all keys in a key event (changes the format of the key event)
rather than just the one we just generated.

* Remember and clear the timeout for the send key event

So we don't schedule more key updates if one is already pending.
Also don't update the last sent time when we didn't actually send the
keys.

* Make key event resends more robust

* Attempt to make tests pass

* crypto wasn't defined at all

* Hopefully get interface right

* Fix key format on the wire to base64

* Add comment

* More standard method order

* Rename encryptMedia

The js-sdk doesn't do media and therefore doesn't do media encryption

* Stop logging encryption keys now

* Use regular base64

It's not going in a URL, so no need

* Re-add base64url

randomstring was using it. Also give it a test.

* Add tests for randomstring

* Switch between either browser or node crypto

Let's see if this will work...

* Obviously crypto has already solved this

* Some tests for MatrixRTCSession key stuff

* Test keys object contents

* Change keys event format

To move away from m. keys

* Test key event retries

* Test onCallEncryption

* Test event sending & spam prevention

* Test event cancelation

* Test onCallEncryption called

* Some errors didn't have data

* Fix binary key comparison

& add log line

* Fix compare function with undefined values

* Remove more key logging

* Check content.keys is an array

* Check key index & key

* Better function name

* Tests too

---------

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
Co-authored-by: David Baker <dave@matrix.org>
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2023-10-31 16:01:46 +00:00
renovate[bot] 370dd6a0eb Update dependency eslint-plugin-unicorn to v49 (#3845)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-31 15:59:16 +00:00
renovate[bot] f760ece8b4 Update dependency @types/jest to v29.5.6 (#3841)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-31 15:57:27 +00:00
renovate[bot] 93e339affe Update definitelyTyped (#3840)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-31 15:57:11 +00:00
ElementRobot 5707b48fd2 v30.0.0-rc.1 2023-10-31 14:40:50 +00:00
ElementRobot 8ac918c10f Prepare changelog for v30.0.0-rc.1 2023-10-31 14:40:48 +00:00
Florian Duros 1cd8bed705 Element-R: Add the git sha of the binding crate to CryptoApi#getVersion (#3838)
* Update `@matrix-org/matrix-sdk-crypto-wasm` to `v2.2.0`

* Add the git sha of the binding crate to `CryptoApi#getVersions`
2023-10-31 09:15:14 +00:00
Hubert Chathi e0dacf7529 use olm from default npm registry, since it's there now (#3837)
and bump to latest version
2023-10-28 10:23:03 +00:00
Dariusz Niemczyk 29d9bdac61 feat: Add autoformat and lint for ts/tsx files (#3835)
* feat: Add autoformat and lint for ts/tsx files

* Update .lintstagedrc

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-10-27 14:38:18 +00:00
R Midhun Suresh 88d066a10c Fix reemitter not being correctly wired on user objects created in storage classes (#3796)
* Fix issue

* Fix jest test

* Fix even more jest failures

* Fix formatting

* Add a test

* Write test for older code

* Fix lint

* Rename method

* Make ctor deprecated
2023-10-27 07:00:13 +00:00
Florian Duros ce7b7bf44f Element-R: Wire up globalBlacklistUnverifiedDevices field to rust crypto encryption settings (#3790)
* Wire up `globalBlacklistUnverifiedDevices` rust crypto encrypted settings

* Improve test comment

* Update comments

* Review changes

* Fix lint due to merge
2023-10-26 13:57:37 +00:00
Richard van der Hoff 07a9eb3c96 Element-R: reduce log spam when checking server key backup (#3826)
* Element-R: reduce log spam when checking server key backup

Fixes a lot of spam in the logs about "uncaught in promise: No room_keys
found".

* Improve integ tests for backup query after UTD

* Yield in the backup decryption loop

* Fix another broken test
2023-10-26 11:10:04 +00:00
Florian Duros f8f22a3edd Element-R: Wire up room rotation (#3807)
* Wire up rotation

* Wire up algorithm

* Add encryption settings test

* Update comments
2023-10-25 15:12:04 +00:00
Richard van der Hoff 084beaa947 Fix up comments on globalErrorOnUnknownDevices (#3834)
The current deprecation notice advises you to use a method which does something
completely different.

Fixing this "properly" is slightly challenging because we don't want to support
setting it to `true` in Rust Crypto; yet I don't really want to change the
default for legacy crypto.

Let's just document the behaviour for now.
2023-10-25 14:32:16 +00:00
Florian Duros 73a87652fe Element-R: Add current version of the rust-sdk and vodozemac (#3825)
* Add current version of the rust-sdk and vodozemac

* Return OlmVersion in `CryptoApi#getVersion` for old crypto

* Add `Olm` prefix

* Fix documentation

* Review changes
2023-10-25 13:12:15 +00:00
Florian Duros 4a4b454f27 Element-R: Wire up room history visibility (#3805)
* Wire up history visibility in `RoomEncryptor.ts`

* Add more tests to history visibility conversion

* Factorize `expectSendMessage` and `expectSendMegolmMessage`

* Use correct import

* Fix overwriteRoutes

* Update comments
2023-10-25 11:49:03 +00:00
Richard van der Hoff 6f82f08c7b Element-R: silence log errors when viewing a pending event (#3824)
* Element-R: silence log errors when viewing a pending event

Fixes the second half of vector-im/element-web#26272

* Update spec/integ/crypto/crypto.spec.ts
2023-10-25 09:11:40 +00:00
Dominik Henneke c41949de15 Don't emit a closed event if the indexeddb is closed by Element (#3832)
Signed-off-by: Dominik Henneke <dominik.henneke@nordeck.net>
2023-10-25 08:14:12 +00:00
David Baker f941fd896e Change latest node ver to '*' (#3831)
* Change latest node ver to '*'

This uses the latest cached version rather than fetching the latest released version so we don't reply on (and hammer) node's download servers for the very latest version before the actions runners get updated. We'll still stay current, just not quite so aggressively current.

* Fix artifact uploading hopefully

* Hopefully make job name 'node latest'
2023-10-24 14:45:03 +00:00
ElementRobot d750e33ec9 Resetting package fields for development 2023-10-24 15:27:12 +01:00
ElementRobot a370442328 Merge branch 'master' into develop 2023-10-24 15:27:09 +01:00
ElementRobot bddf2b9682 v29.1.0 2023-10-24 15:27:03 +01:00
ElementRobot 74a2e694c3 Prepare changelog for v29.1.0 2023-10-24 15:27:01 +01:00
Michael Telatynski 748d03ba11 Delete .github/workflows/upgrade_dependencies.yml 2023-10-24 00:48:22 +01:00
Richard van der Hoff 2f3f0b340e Bump matrix-sdk-crypto-wasm to 2.1.1 (#3823)
... for recent changes including a fix to a panic
2023-10-23 12:42:50 +01:00
Richard van der Hoff 12e479a93e Element-R: silence log errors when viewing a decryption failure (#3821) 2023-10-23 10:16:42 +00:00
Richard van der Hoff 6e2ac03f7e Reduce log spam from rust crypto (#3819)
* turn the log level down to DEBUG
* don't pointlessly log every call to `outgoingRequests`
2023-10-20 21:43:28 +00:00
David Baker 6359e10bcf Merge pull request #3820 from matrix-org/dbkr/export_base64
Export base64 utils
2023-10-20 18:18:08 +01:00
David Baker b3a2b8b8c4 Export base64 utils
We use these from react-sdk (from crypto, when they were there,
but I just moved them and inadvertantly broke react-sdk).
2023-10-20 17:47:57 +01:00
Valere 30a9119e31 Bump wasm bindings version to 2.1.0 (#3811) 2023-10-20 17:44:55 +01:00
David Baker 7a52dba86c Merge pull request #3818 from matrix-org/dbkr/all_your_base64
Refactor & make base64 functions browser-safe
2023-10-20 16:47:29 +01:00
David Baker d6177cdfc9 Another one appeared 2023-10-20 16:23:58 +01:00
David Baker c4f3fd3289 Remove another crypto mention. None of this is crypto specific. 2023-10-20 16:11:48 +01:00
David Baker 31f38550e3 Refactor & make base64 functions browser-safe
We had two identical sets of base64 functions in the js-sdk, both
using Buffer which isn't really available in the browser unless you're
using an old webpack (ie. what element-web uses). This PR:

 * Takes the crypto base64 file and moves it out of crypto (because
   we use base64 for much more than just crypto)
 * Makes them work in a browser without the Buffer global
 * Removes the other base64 functions
 * Changes everything to use the new common ones
 * Adds a comment explaining why the function is kinda ugly and how
   soul destroyingly awful the JS ecosystem is.
 * Runs the tests with both impls
 * Changes the test to not just test the decoder against the encoder
 * Adds explicit support & tests for (decoding) base64Url (I'll add an
   encode method later, no need for that to go in this PR too).
2023-10-20 16:00:55 +01:00
Andy Balaam 0643f38592 Don't remove thread info from a thread root when it is redacted (#3814)
* Don't remove thread info from a thread root when it is redacted

* Move the redaction event to main at the same time we move redacted

Since the redacted event is moving to the main timeline, the redaction
belongs there too, since its relationship to the redacted event is the
only thing making it part of the thread.
2023-10-20 14:45:34 +00:00
Richard van der Hoff c0264954ed Reduce some log spam from MatrixRTCSession.callMembershipsForRoom (#3812)
This gets logged very frequently - including once for each room at startup -
and it's filling the logs.
2023-10-20 09:49:20 +00:00
Richard van der Hoff 7501e28dec Element-R: log when we send to-device messages (#3810)
* Log when we send to-device messages

* lint

* fix test
2023-10-19 12:58:49 +00:00
Valere febc4c9ad6 Handle backup secret gossip (#3778)
* Handle backup secret gossip

* use getSecretsFromInbox

* add gossip test

* use delete secret API

* fix logger

* better comment and cleaning

* free the pkSigning

* fix typo

* add missing mocks

* improve coverage

* better var name

* quick refactoring

* add more tests

* Review, format and comments

* refactor move more logic to backup.ts

* poll secret inbox

* missing mock

* Update src/rust-crypto/rust-crypto.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/rust-crypto/rust-crypto.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/rust-crypto/rust-crypto.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/rust-crypto/backup.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/rust-crypto/rust-crypto.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* code review

* fix comment

* remove comment

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* quick factorise

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-10-19 12:39:16 +00:00
Andy Balaam 6b1d53cc14 Move events related to a redacted event into the main timeline (#3800)
* Move redaction event tests into their own describe block

* Factor out utils in redaction tests

* Factor out the code for moving an event to the main timeline

* Move all related messages into main timeline on redaction
2023-10-19 07:58:46 +00:00
renovate[bot] 04fcd5880b Update all non-major dependencies (#3776)
* Update all non-major dependencies

* Remove `name wrap-ansi-cjs`

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Remove `name string-width-cjs`

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Hold jest-sonar-reporter back

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-10-19 07:31:15 +00:00
Kerry 4bcea2cead OIDC: document OidcError use (#3808)
* comments

* Update src/oidc/authorize.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/oidc/register.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-10-18 21:01:56 +00:00
renovate[bot] 6468d79458 Update typedoc (#3740)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-18 11:49:04 +00:00
renovate[bot] a871376350 Update dependency fake-indexeddb to v5 (#3803)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-18 08:12:53 +00:00
Michael Telatynski 6beb693616 Update cypress.yml 2023-10-18 09:11:40 +01:00
Andy Balaam 11661bbc8d Merge pull request #3798 from matrix-org/andybalaam/move-redacted-message-to-main
Move redacted messages out of any thread, into main timeline.
2023-10-18 08:00:29 +01:00
renovate[bot] 2d57f28d5a Update matrix-org/matrix-react-sdk digest to 94ca061 (#3774)
* Update matrix-org/matrix-react-sdk digest to 94ca061

* Update cypress.yml

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-10-17 17:40:07 +00:00
dependabot[bot] c52f857599 Bump @babel/traverse from 7.22.17 to 7.23.2 (#3806)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.22.17 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 17:05:31 +00:00
renovate[bot] 5d016c1e4f Update tspascoal/get-user-teams-membership action to v3 (#3804)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-17 16:50:40 +00:00
Richard van der Hoff 9f04c0555c Deprecate MatrixEvent.toJSON (#3801)
* Deprecate `MatrixEvent.toJSON`

Per https://github.com/vector-im/element-web/issues/26380, this method is too
easy to use accidentally, and per the comments, it doesn't even return a
meaningful JSON-serialisation of the object.

* Update src/models/event.ts
2023-10-17 15:54:02 +00:00
renovate[bot] 9293986e3b Update definitelyTyped (#3775)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-17 15:44:16 +00:00
renovate[bot] 8426d8cae1 Update babel monorepo (#3777)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-10-17 15:07:20 +00:00
Andy Balaam 3baf6ec2c6 Add events to the thread even if they appear to be out of order (#3787) 2023-10-17 14:15:15 +00:00
ElementRobot 38cd6f93e6 v29.1.0-rc.1 2023-10-17 15:09:00 +01:00
ElementRobot a3a6742c67 Prepare changelog for v29.1.0-rc.1 2023-10-17 15:08:57 +01:00
David Baker 4ce837b20e Fix sending call member events on leave (#3799)
https://github.com/matrix-org/matrix-js-sdk/pull/3756 changed
the membership update function to await on the next call, but this
meant it never returned and therefore never cleared
`updateCallMembershipRunning`. We therefore didn't send the updated
call member event when leaving, instead sending it whenever the next
poll interval arrived.

This changes it to only await if we are retrying, not if we're just
scheduling the next poll.

Fixes https://github.com/vector-im/element-call/issues/1763
2023-10-17 13:26:18 +00:00
Michael Telatynski 884bd2585a Prettier
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-10-17 10:27:19 +01:00
Michael Telatynski c306d87f80 Add SUMMARY.md
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-10-17 10:01:17 +01:00
Andy Balaam b94d137398 Move redacted messages out of any thread, into main timeline.
For consistency with the spec at room version 11. See
https://github.com/matrix-org/matrix-spec-proposals/pull/3389
for a proposal to make this unnecessary.
2023-10-16 12:49:57 +01:00
Andy Balaam 5595e8497f Clarify code that chooses a thread ID to include in a receipt (#3797)
* Extract threadIdForReceipt function from sendReceipt

* Tests for threadIdForReceipt

* Correct test of threadIdForReceipt to expect main for redaction of threaded

* Expand and comment implementation of threadIdForReceipt
2023-10-16 10:35:36 +00:00
Valere 5d233f3863 Bump wasm bindings version to 2.0.0 (#3795) 2023-10-12 16:29:30 +01:00
Kerry 0f4fa5ad51 OIDC: refresh tokens (#3764)
* very messy poc

* iterate

* more types and use tokenRefreshFunction

* working refresh without persistence

* tidy

* add claims to completeauhtorizationcodegrant response

* export tokenrefresher from matrix

* add idtokenclaims

* add claims to completeauhtorizationcodegrant response

* only one token refresh attempt at a time

* tests

* comments

* add tokenRefresher class

* export generateScope

* export oidc from matrix

* test refreshtoken

* mark experimental

* add getRefreshToken to client

* Apply suggestions from code review

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* remove some vars in test

* make TokenRefresher un-abstract, comments and improvements

* remove invalid jsdoc

* Update src/oidc/tokenRefresher.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Code review improvements

* fix verification integ tests

* remove unused type from props

* fix incomplete mock fn in fetch.spec

* document TokenRefreshFunction

* comments

* tidying

* update for injected logger

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-10-11 22:00:02 +00:00
Kerry 1de6de05a1 add prompt param to OIDC auth url creation (#3794) 2023-10-11 02:20:23 +00:00
David Baker c8f8fb587d Don't use event.sender in CallMembership (#3793)
* Don't use event.sender in CallMembership

I fell into another js-sdk trap: this is "only guaranteed to be set
for events that appear in a timeline" and not state events. It does
not say why. We only ever used it to get the sender user ID anyway,
so just use getSender().

* Fix test
2023-10-10 15:19:52 +00:00
Richard van der Hoff 2f79e6c056 Element-R: Don't mark QR code verification as done until it's done (#3791)
* Element-R: Don't mark QR code verification as done too soon

The rust crypto sdk doesn't actually finish QR code verification until the
`m.key.verification.done` is received, so make sure we don't tell the
application it is done before that happens.

Fixes https://github.com/vector-im/element-web/issues/26293

* ignore fallback line

* Revert unnecessary changes

Can't get the coverage high enough on this and it's not needed.
2023-10-10 09:38:30 +00:00
Richard van der Hoff 42be793a56 Allow applications to specify their own logger instance (#3792)
* Support MatrixClient-specific loggers.

Signed-off-by: Patrick Cloke <clokep@patrick.cloke.us>

* Use client-specific logger in client.ts.

Signed-off-by: Patrick Cloke <clokep@patrick.cloke.us>

* Log `fetch` requests to the per-client logger

* Use client-specific logger in rust-crypto
2023-10-10 10:34:03 +01:00
Dharshan 7c2a12085c Fix small typo in README.md in root dir (#3788) 2023-10-10 08:37:04 +00:00
RiotRobot 3cf6f568f3 Resetting package fields for development 2023-10-10 09:13:20 +01:00
RiotRobot 4db08cb78e Merge branch 'master' into develop 2023-10-10 09:13:15 +01:00
RiotRobot 25e5d79cf6 v29.0.0 2023-10-10 09:13:04 +01:00
RiotRobot 6c8e3d0707 Prepare changelog for v29.0.0 2023-10-10 09:13:01 +01:00
Kerry 3139f5729b OIDC: Token refresher class (#3769)
* add tokenRefresher class

* export generateScope

* export oidc from matrix

* mark experimental

* Apply suggestions from code review

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* remove some vars in test

* make TokenRefresher un-abstract, comments and improvements

* remove invalid jsdoc

* Update src/oidc/tokenRefresher.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Code review improvements

* document TokenRefreshFunction

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-10-09 20:46:43 +00:00
Florian Duros bb8a894105 Call RustBackupManager.checkKeyBackupAndEnable when RustCrypto is created (#3784) 2023-10-09 13:23:45 +00:00
Richard van der Hoff 223dfffdfb Define a new Logger interface (#3789)
* rename loglevel import to loglevel

* Define new `Logger` interface to replace `PrefixedLogger`

* PrefixedLogger -> Logger in crypto store

* PrefixedLogger -> Logger in `src/crypto`

* PrefixedLogger -> Logger in rust-crypto
2023-10-09 13:06:16 +00:00
Andy Balaam f19f0a8793 Comments attempting to explain the addEvent method (#3786)
* Warn when we drop an event trying to add it to a thread

Added to try and help debug https://github.com/vector-im/element-web/issues/26254

* Comment trying to explain lastEvent

* Document some of my understanding of the addEvent logic

* Refer to stable spec instead of MSC

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Re-word comments based on review

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-10-09 12:47:16 +00:00
Timo a5224c1820 make leaveRoomSession async (#3756)
* make leaveRoomSession async.
This does not resolve the promise until the event is actually send.
No network connection would make awaiting on this blocking.

Signed-off-by: Timo K <toger5@hotmail.de>

* add timeout to leave

Signed-off-by: Timo K <toger5@hotmail.de>

* formatting

Signed-off-by: Timo K <toger5@hotmail.de>

---------

Signed-off-by: Timo K <toger5@hotmail.de>
2023-10-09 11:52:19 +00:00
Andy Balaam 513201b9c1 Warn when we drop an event trying to add it to a thread (#3785)
Added to try and help debug https://github.com/vector-im/element-web/issues/26254
2023-10-06 14:40:57 +00:00
Richard van der Hoff 02ca5c78cf Element-R: don't log every HTTP request (#3780)
Since #3485, we log every request anyway, so there's no need to log twice.,
2023-10-05 14:31:28 +00:00
Florian Duros af63d9bd05 Element-R: Avoid errors in VerificationRequest.generateQRCode when QR code is unavailable (#3779)
* Avoid `VerificationRequest.generateQRCode` to crash when QRCode is unavailable

* Add tests `can try to generate a QR code when QR code is not supported`
2023-10-05 08:17:39 +00:00
Valere 95baccfbc1 Rust crypto: ensure we persist the key backup version (#3770)
Fixes vector-im/element-web#26259
2023-10-04 11:38:50 +01:00
Richard van der Hoff 10b6c2463d Grab bag of Element-R cleanups (#3773)
* `RustBackupManager.getActiveBackupVersion`: check that backup is enabled

The previous check on `isBackupEnabled` was a no-op

* Fix log spam on shieldless events

* Reduce log spam about tracking users

* Reduce log spam about decrypting events

Logging the entire event is excessive
2023-10-04 09:15:54 +00:00
Kerry 6e8d15e5ed add claims to completeauhtorizationcodegrant response (#3765) 2023-10-04 05:05:54 +01:00
Florian Duros 2e4276437a ElementR: Check key backup when user identity changes (#3760)
Fixes vector-im/element-web#26244
2023-10-03 13:38:51 +01:00
Richard van der Hoff 6a761af867 Element-R: emit VerificationRequestReceived on incoming request (#3762) 2023-10-03 13:37:58 +01:00
RiotRobot 53a72df01b v29.0.0-rc.1 2023-10-03 11:40:01 +01:00
RiotRobot 75e710d93e Prepare changelog for v29.0.0-rc.1 2023-10-03 11:39:58 +01:00
RiotRobot 1457ab0cf4 Revert "v29.0.0-rc.1"
This reverts commit f01037fe0d.
2023-10-03 11:39:12 +01:00
RiotRobot 14aafb7977 Revert "Prepare changelog for v29.0.0-rc.1"
This reverts commit 2cda6655d7.
2023-10-03 11:39:03 +01:00
Andy Balaam 90d00b863f Merge pull request #3772 from matrix-org/andybalaam/manually-backport-remove-dist-from-package
Remove the dist script since we no longer have a browserify build
2023-10-03 11:34:08 +01:00
Andy Balaam 5f0ada9578 Remove the dist script since we no longer have a browserify build 2023-10-03 11:32:59 +01:00
RiotRobot f01037fe0d v29.0.0-rc.1 2023-10-03 11:08:34 +01:00
RiotRobot 2cda6655d7 Prepare changelog for v29.0.0-rc.1 2023-10-03 11:08:31 +01:00
Michael Telatynski 6eec2ceeeb Export AutoDiscoveryError and fix type of ALL_ERRORS (#3768) 2023-10-03 11:01:16 +01:00
Michael Telatynski 68317ac836 Remove browserify builds (#3759) 2023-10-03 10:23:11 +01:00
Michael Telatynski 5c45c980e9 Update cypress.yml 2023-10-03 08:40:40 +01:00
Damon (Toal-Rossi) Vestervand 66251e0855 Use globalThis instead of global (#3763)
Switches use of `global` to `globalThis`, which is better supported when building with modern build tools like Vite.

Refs #2903

Signed-off-by: Damon Vestervand <damon@beyondwork.ai>
Signed-off-by: Damon <damon@vestervand.net>
2023-10-02 12:04:05 +00:00
Richard van der Hoff ff53557957 Clean up integ tests for incoming user verification (#3758)
Move the tests into verification.spec.ts, enable for both stacks, and other cleanups.
2023-09-29 17:26:24 +01:00
Richard van der Hoff 126352afd5 Bump matrix-sdk-crypto-wasm to 1.3.0 (#3757) 2023-09-29 17:25:33 +01:00
Hugh Nimmo-Smith f33da83d90 Support for stable MSC3882 get_login_token (#3416)
* Support for stable MSC3882 get_login_token

* Make changes non-breaking by deprecation

* Update src/@types/auth.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update spec/integ/matrix-client-methods.spec.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Suggestions from review

* Update src/client.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Fix and test prefix behaviour

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Co-authored-by: Andy Balaam <andy.balaam@matrix.org>
2023-09-29 13:14:22 +00:00
Valere 74193ad057 Implement exportCrossSigningKeysToStorage (#3731)
* Implement exportCrossSigningKeysToStorage

* fix bootstrap cross signing

* Update src/rust-crypto/CrossSigningIdentity.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/rust-crypto/CrossSigningIdentity.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/rust-crypto/CrossSigningIdentity.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update spec/unit/rust-crypto/CrossSigningIdentity.spec.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* code review

* Update src/rust-crypto/CrossSigningIdentity.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-09-27 09:07:02 +00:00
Kerry c672cad1a1 remove IsUserMention and IsRoomMention from DEFAULT_OVERRIDE_RULES (#3752) 2023-09-26 21:33:41 +00:00
Andy Balaam d59bb240fa Merge pull request #3746 from matrix-org/valere/element-r/backup/restore_test
fix restoreKeyBackupWithSecretStorage for rust
2023-09-26 12:42:47 +01:00
RiotRobot 65d988734e Resetting package fields for development 2023-09-26 12:20:14 +01:00
RiotRobot 4a402f0bd7 Merge branch 'master' into develop 2023-09-26 12:20:05 +01:00
RiotRobot a491508543 v28.2.0 2023-09-26 12:07:30 +01:00
RiotRobot 0abba3e626 Prepare changelog for v28.2.0 2023-09-26 12:07:26 +01:00
Valere 9fed45e47c quick test if no crypto 2023-09-26 12:05:27 +02:00
Valere fe67a68c95 fix typo 2023-09-26 09:13:19 +02:00
valere 4d3d4028a0 Merge branch 'develop' into valere/element-r/backup/restore_test 2023-09-26 09:05:03 +02:00
Robin 8f901590ff Fix a case where joinRoom creates a duplicate Room object (#3747)
When calling MatrixClient.joinRoom with a room alias, the method would create a new Room object, even if you were already present in that room. This changes its behavior to no-op, as the doc comment promises.
2023-09-25 18:07:51 +00:00
Michael Telatynski d29b8520f7 Update cypress.yml 2023-09-25 17:17:26 +01:00
Richard van der Hoff 37e1fd9af5 Another attempt at fixing the Cypress job (#3749) 2023-09-25 15:58:38 +01:00
Valere 76dbc7500f Update spec/integ/crypto/crypto.spec.ts
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-09-25 16:34:25 +02:00
Valere 3664f8c3c2 Update spec/integ/crypto/crypto.spec.ts
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-09-25 16:34:17 +02:00
Valere d0a10497bb Update spec/integ/crypto/crypto.spec.ts
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-09-25 16:34:10 +02:00
David Baker 6385c9c0da Add membershipID to call memberships (#3745)
* Add membershipID to call memberships

This allows us to recognise easily when a membership is from some
previous sessions rather than our own and therefore ignore it
(see comment for more).

This was causing us to see existing, expired membership events and
bump the expiry on them rather than send a new membership. This might
have been okay if we bumped them enough to actually make them un-expired,
but it's a fresh session so semanticly we want to post a fresh membership
rather than resurrecting a previous, expired membership.

* Fix test types

* Fix tests

* Make test coverage happy

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-09-22 15:31:17 +00:00
valere cecac3152e Merge branch 'develop' into valere/element-r/backup/restore_test 2023-09-22 14:09:35 +02:00
Valere f6c99b1d25 fix restoreKeyBackupWithSecretStorage for rust 2023-09-22 13:28:05 +02:00
Richard van der Hoff 407ec4d67a Add github action to mark cypress tests skipped (#3744) 2023-09-22 09:22:00 +00:00
Valere 4947a0cb64 Implement isSecretStorageReady in rust (#3730)
* Implement isSecretStorageReady in rust

* refactor extract common code to check 4S access

* fix incomplete mocks

* code review

* Remove keyId para from secretStorageCanAccessSecrets

* use map instead of array

* code review
2023-09-21 16:55:41 +00:00
Richard van der Hoff f134d6db01 Fix the message for messages from unknown devices (#3743) 2023-09-21 08:34:34 +00:00
Malte Finsterwalder fde6cebc20 Stop keep alive, when sync was stoped (#3720)
* T-Defect: stop keep alive, when sync was stoped

Signed-off-by: Malte Finsterwalder <malte@holi.team>

* T-Defect: add tests for keep alive

Signed-off-by: Malte Finsterwalder <malte@holi.team>

* fix copyright year

Signed-off-by: Malte Finsterwalder <malte@holi.team>

* fix copyright

Signed-off-by: Malte Finsterwalder <malte@holi.team>

---------

Signed-off-by: Malte Finsterwalder <malte@holi.team>
Co-authored-by: Malte Finsterwalder <malte@holi.team>
2023-09-20 16:44:27 +00:00
Richard van der Hoff 425cf6b91e Element-R: use the pickleKey to encrypt the crypto store (#3732)
* Element-R: use the pickleKey to encrypt the crypto store

`pickleKey` is a passphrase set by the application for this express purpose.

* update tests

* fix tests, again
2023-09-20 11:35:32 +00:00
renovate[bot] a3e273d6f1 Update all non-major dependencies (#3735)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-20 10:26:16 +00:00
renovate[bot] b1a3b264e5 Update SimenB/github-actions-cpu-cores action to v2 (#3741)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-20 10:25:40 +00:00
renovate[bot] 053643a8ba Update babel monorepo to v7.22.20 (#3737)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-19 19:38:40 +00:00
Richard van der Hoff d2ea149012 Undeprecate MatrixClient.getKeyBackupVersion (#3733)
... and add some better documentation while we're at it.
2023-09-19 17:33:41 +00:00
Richard van der Hoff 23d244520c Sort imports in MatrixClient (#3734)
My IDE keeps trying to do this, so let's just do it in its own PR
2023-09-19 17:32:58 +00:00
renovate[bot] 267b52099b Update definitelyTyped (#3736)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-19 16:18:45 +00:00
renovate[bot] 430fd5660a Update dependency @types/jest to v29.5.5 (#3738)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-19 16:18:08 +00:00
RiotRobot d669ddfab2 v28.2.0-rc.1 2023-09-19 12:34:58 +01:00
RiotRobot 9caa38d386 Prepare changelog for v28.2.0-rc.1 2023-09-19 12:34:55 +01:00
maheichyk 1c16b5cae6 Delete knocked room when knock membership changes (#3729)
* Store leave state when knock is denied

Signed-off-by: Mikhail Aheichyk <mikhail.aheichyk@nordeck.net>

* Delete knocked room when knock request is cancelled or denied

Signed-off-by: Mikhail Aheichyk <mikhail.aheichyk@nordeck.net>

* Test is updated

Signed-off-by: Mikhail Aheichyk <mikhail.aheichyk@nordeck.net>

---------

Signed-off-by: Mikhail Aheichyk <mikhail.aheichyk@nordeck.net>
Co-authored-by: Mikhail Aheichyk <mikhail.aheichyk@nordeck.net>
2023-09-18 17:08:53 +00:00
Richard van der Hoff cb375e1351 rust impl of getEncryptionInfoForEvent (#3718) 2023-09-18 14:49:24 +00:00
Richard van der Hoff 5e542b3869 Fix potential delay in sending out requests from the rust SDK (#3717)
* Emit a `UserTrustStatusChanged` when user identity is updated

* Remove redundant `onCrossSigningKeysImport` callback

This now happens as a side-effect of importing the keys.

* bump to alpha release of matrix-rust-sdk-crypto-wasm

* fixup! Remove redundant `onCrossSigningKeysImport` callback

* Fix potential delay in sending out requests from the rust SDK

There was a potential race which could cause us to be very slow to send out
pending HTTP requests, particularly when handling a user verification. Add some
resiliece to make sure we handle it correctly.

* add comments

* Add a unit test

---------

Co-authored-by: Andy Balaam <andy.balaam@matrix.org>
2023-09-18 14:11:33 +00:00
Valere c9435af637 Cleanup, separate backup bootstrap and mgmt (#3726)
* Cleanup, separate backup bootstrap and mgmt

* fix non spec compliant account data format
2023-09-15 11:38:49 +00:00
Valere 40168d4419 Rust: Query backup on fail to decrypt similar to libolm (#3711)
* Refactor key backup recovery to prepare for rust

* rust backup restore support

* map decryption errors correctly from rust

* query backup on fail to decrypt
2023-09-14 10:10:53 +00:00
Valere 6d118008b6 Map decryption errors correctly from rust (#3710)
* Refactor key backup recovery to prepare for rust

* rust backup restore support

* map decryption errors correctly from rust

* Move export out of old crypto to api with re-export

* extract base64 utility

* add tests for base64 util

* more efficient regex

* fix typo

* use different vector for bob

* missing import

* Group tests for decryption errors

* Do not map unneeded rust error for now
2023-09-13 13:34:55 +00:00
Valere 1503acb30a rust backup restore support (#3709)
* Refactor key backup recovery to prepare for rust

* rust backup restore support

* Move export out of old crypto to api with re-export

* extract base64 utility

* add tests for base64 util

* more efficient regex

* fix typo
2023-09-13 09:08:26 +00:00
David Baker 1b8507c060 Merge pull request #3723 from matrix-org/dbkr/fix_codeowners
Fix codeowners
2023-09-13 10:05:03 +01:00
David Baker d95b5ab27a Fix codeowners
Accidental change from merging https://github.com/matrix-org/matrix-js-sdk/pull/3663
2023-09-13 09:53:19 +01:00
ElementRobot 658e7b1be3 Resetting package fields for development 2023-09-12 16:53:47 +01:00
ElementRobot 95110eb889 Merge branch 'master' into develop 2023-09-12 16:53:44 +01:00
ElementRobot 9fbcef556e v28.1.0 2023-09-12 16:52:42 +01:00
ElementRobot b68ad00394 Prepare changelog for v28.1.0 2023-09-12 16:52:40 +01:00
David Baker 6836720e1e Introduce MatrixRTCSession lower level group call primitive (#3663)
* Add hacky option to disable the actual calling part of group calls.

So we can try using livekit instead.

* Put LiveKit info into the `m.call` state event (#3522)

* Put LK info into state

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Update to the new way the LK service works

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

---------

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Send 'contentLoaded' event

As per comment, so we can start digging ourselves out of the widget
API hole we're currently in.

* Add comment on updating the livekit service URL

* Appease CI on `livekit` branch (#3566)

* Update codeowners on `livekit` branch (#3567)

* add getOpenIdToken to embedded client backend

Signed-off-by: Timo K <toger5@hotmail.de>

* add test and update comment

Signed-off-by: Timo K <toger5@hotmail.de>

* Merge `develop` into `livekit` (#3569)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: RiotRobot <releases@riot.im>
Co-authored-by: Florian Duros <florianduros@element.io>
Co-authored-by: Kerry <kerrya@element.io>
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
Co-authored-by: Erik Johnston <erik@matrix.org>
Co-authored-by: Valere <bill.carson@valrsoft.com>
Co-authored-by: Hubert Chathi <hubertc@matrix.org>
Close IDB database before deleting it to prevent spurious unexpected close errors (#3478)
Fix export type `GeneratedSecretStorageKey` (#3479)
Fix order of things in `crypto-api.ts` (#3491)
Fix bug where switching media caused media in subsequent calls to fail (#3489)
fixes (#3515)
fix the integ tests, where #3509 etc fix the unit tests.
fix breakage on node 16 (#3527)
Fix an instance of failed to decrypt error when an in flight `/keys/query` fails. (#3486)
Fix `TypedEventEmitter::removeAllListeners(void)` not working (#3561)

* Revert "Merge `develop` into `livekit`" (#3572)

* Don't update calls with no livekit URL & expose method to update it instead

and generally simplify a bit: change it to a single string rather than
an array of structs.

* Fix other instances of passing focusInfo / livekit url

* Add temporary setter

* WIP refactor for removing m.call events

* Always remember rtcsessions since we need to only have one instance

* Fix tests

* Fix import loop

* Fix more cyclic imports & tests

* Test session joining

* Attempt to make tests happy

* Always leave calls in the tests to clean up

* comment + desperate attempt to work out what's failing

* More test debugging

* Okay, so these ones are fine?

* Stop more timers and hopefully have happy tests

* Test no rejoin

* Test malformed m.call.member events

* Test event emitting

and also move some code to a more sensible place in the file

* Test getActiveFoci()

* Test event emitting (and also fix it)

* Test membership updating & pruning on join

* Test getOldestMembership()

* Test member event renewal

* Don't start the rtc manager until the client has synced

Then we can initialise from the state once it's completed.

* Fix type

* Remove listeners added in constructor

* Stop the client here too

* Stop the client here also also

* ARGH. Disable tests to work out which one is causing the exception

* Disable everything

* Re-jig to avoid setting listeners in the constructor

and re-enable tests

* No need to rename this anymore

* argh, remove the right listener

* Is it this test???

* Re-enable some tests

* Try mocking getRooms to return something valid

* Re-enable other tests

* Give up trying to get the tests to work sensibly and deal with getRooms() returning nothing

* Oops, don't enable the ones that were skipped before

* One more try at the sensible way

* Didn't work, go back to the hack way.

* Log when we manage to send the member event update

* Support `getOpenIdToken()` in embedded mode (#3676)

* Call `sendContentLoaded()` (#3677)

* Start MatrixRTC in embedded mode (#3679)

* Reschedule the membership event check

* Bump widget api version

* Add mock for sendContentLoaded()

* More log detail

* Fix tests

and also better assert because the tests were passing undefined which
was considered fine because we were only checking for null.

* Simplify updateCallMembershipEvent a bit

* Split up updateCallMembershipEvent some more

* Typo

Co-authored-by: Daniel Abramov <inetcrack2@gmail.com>

* Expand comment

* Add comment

* More comments

* Better comment

* Sesson

* Rename some variables

* Comment

* Remove unused method

* Wrap updatecallMembershipEvent so it only runs one at a time

* Do another update if another one is triggered while the update happens

* Make triggerCallMembershipEventUpdate async

* Fix test & some missed timer removals

* Mark session manager as unstable

---------

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>
Co-authored-by: Timo K <toger5@hotmail.de>
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
Co-authored-by: Daniel Abramov <inetcrack2@gmail.com>
2023-09-12 15:08:15 +00:00
renovate[bot] 6f517478df Update jest to v29.5.4 (#3670)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-12 14:50:39 +00:00
Andy Balaam 35ba4074de Avoid an infinite loop in the interactive-auth test (#3722)
Reading the test "should fire stateUpdated callback with error when a
request fails" it looks like this would always cause an infinite loop
between doRequest and statusUpdated calls. I don't know why this wasn't
a problem until we updated Jest to v29.5.4, but after that point it was.

This change should fix the test failures for the Jest upgrade PR:
https://github.com/matrix-org/matrix-js-sdk/pull/3670 .
2023-09-12 14:03:47 +00:00
Valere c7827d971c Refactor key backup recovery to prepare for rust (#3708)
* Refactor key backup recovery to prepare for rust

* code review

* quick doc format

* code review fix
2023-09-12 11:19:35 +00:00
Richard van der Hoff f963ca5562 Element-R: Emit CryptoEvent.UserTrustStatusChanged when user identity is updated (#3716)
* Emit a `UserTrustStatusChanged` when user identity is updated

* Remove redundant `onCrossSigningKeysImport` callback

This now happens as a side-effect of importing the keys.

* bump to alpha release of matrix-rust-sdk-crypto-wasm

* fixup! Remove redundant `onCrossSigningKeysImport` callback
2023-09-08 04:40:02 +00:00
Malte Finsterwalder 8c30b0d12c Dont access indexed db when undefined (#3707)
* T-Defect: handle undefined indexedDB gracefully

Signed-off-by: Malte Finsterwalder <malte@holi.team>

* T-Defect: test to check handling of undefined indexedDB gracefully

Signed-off-by: Malte Finsterwalder <malte@holi.team>

---------

Signed-off-by: Malte Finsterwalder <malte@holi.team>
Co-authored-by: Malte Finsterwalder <malte@holi.team>
2023-09-07 21:52:32 +00:00
Andy Balaam 5d4334ba4c Explain why synthetic receipts don't mark the room as read (#3715)
* Explain why synthetic receipts don't mark the room as read

* Fix misleading "local echo" comment with "remote echo"

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-09-07 15:31:54 +00:00
Richard van der Hoff 7e691bf700 Implement getEncryptionInfoForEvent and deprecate getEventEncryptionInfo (#3693)
* Implement `getEncryptionInfoForEvent` and deprecate `getEventEncryptionInfo`

* fix tsdoc

* fix tests

* Improve test coverage
2023-09-07 09:39:10 +00:00
Andy Balaam 0700e86f58 Don't reset unread count when adding a synthetic receipt (#3706)
Fixes https://github.com/matrix-org/matrix-js-sdk/issues/3684
and there are lots more details about why we chose this solution in that
issue.
2023-09-07 07:24:51 +00:00
maheichyk 6c307d4c63 Sync knock rooms (#3703)
Signed-off-by: Mikhail Aheichyk <mikhail.aheichyk@nordeck.net>
Co-authored-by: Mikhail Aheichyk <mikhail.aheichyk@nordeck.net>
2023-09-06 17:10:14 +00:00
renovate[bot] 88ec0e3e17 Update babel monorepo to v7.22.15 (#3704)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-06 12:56:01 +00:00
renovate[bot] 015e9a5be7 Update all non-major dependencies (#3700)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-06 12:42:44 +00:00
renovate[bot] 2918d686ae Update definitelyTyped (#3698)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-06 09:04:49 +00:00
renovate[bot] 327c18ddc1 Update babel monorepo (#3697)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-06 09:04:32 +00:00
renovate[bot] 8cdd8e882b Update peter-evans/repository-dispatch digest to bf47d10 (#3696)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-06 09:02:54 +00:00
renovate[bot] 76e0d5a896 Update actions/checkout action to v4 (#3701)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-09-05 17:30:43 +00:00
ElementRobot 836238c3ba v28.1.0-rc.1 2023-09-05 16:51:26 +01:00
ElementRobot 014b29b303 Prepare changelog for v28.1.0-rc.1 2023-09-05 16:51:23 +01:00
Richard van der Hoff 74160806c0 Deprecate MatrixClient.checkUserTrust (#3691)
* New `CryptoApi.getUserVerificationStatus` API

* Add `RustCrypto#getUserVerificationStatus` tests

---------

Co-authored-by: Florian Duros <florianduros@element.io>
2023-09-05 14:58:10 +00:00
Michael Telatynski 8e0ef98bcc Provide better error for ICE Server SyntaxError (#3694)
* Provide better error for ICE Server SyntaxError

* Refactor

* Add test
2023-09-05 14:18:30 +00:00
Valere d7831f9e5b Implement key backup APIs for rust and create backup in bootstrapSecretStorage (#3690)
* new resetKeyBackup API

* add delete backup version test

* code review

* support backup creation in rust

* code review
2023-09-05 13:52:49 +00:00
Michael Telatynski 989c5a3dda Allow calls without ICE/TURN/STUN servers (#3695) 2023-09-05 12:44:39 +00:00
Richard van der Hoff 0778c4e01e Re-check key backup after bootstrapSecretStorage (#3692)
Fixes https://github.com/vector-im/element-web/issues/26115
2023-09-05 09:10:58 +00:00
Valere c65e329101 Deprecate MatrixClient.{prepare,create}KeyBackupVersion in favour of new CryptoApi.resetKeyBackup API (#3689)
* new resetKeyBackup API

* add delete backup version test

* code review

* code review
2023-09-04 20:00:28 +00:00
Germain 5ddd453699 Emit summary update event (#3687)
* Emit summary update event

* Add documentation

* Update RoomSummary event documentation

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-08-31 08:48:16 +00:00
Richard van der Hoff 42d982dd69 OutgoingRequestProcessor: do not throw errors if shutting down (#3683)
* `OutgoingRequestProcessor`: do not throw errors if shutting down

* Optimised builds throw a different error
2023-08-30 14:56:06 +00:00
Richard van der Hoff f406ffd3dd RustCrypto.getCrossSigningStatus: check the client is not stopped (#3682)
* `RustCrypto.getCrossSigningStatus`: check the client is not stopped

Better error handling for the case that a call to `MatrixClient.stop` happens
while the call to `getCrossSigningStatus` (or `isCrossSigningReady`) is in
flight.

* fix up tsdoc
2023-08-30 09:30:31 +00:00
Florian Duros dec4650d3d ElementR: Update CryptoApi.userHasCrossSigningKeys (#3646)
* WIP `CryptoApi.getStoredCrossSigningForUser`

* Fix QRCode

* Add docs and rename

* Add tests for `RustCrossSigningInfo.ts`

* Do `/keys/query` instead of using `UserIdentity`

* Review changes

* Get rid of `CrossSigningInfo`

* Merge `hasCrossSigningKeysForUser` into `userHasCrossSigningKeys`

* Apply suggestions from code review

* More review comments

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Co-authored-by: Richard van der Hoff <richard@matrix.org>
2023-08-29 11:27:28 +00:00
RiotRobot 4c00b41046 Resetting package fields for development 2023-08-29 10:55:15 +01:00
RiotRobot a1845ba0ff Merge branch 'master' into develop 2023-08-29 10:55:09 +01:00
RiotRobot fb9e258468 v28.0.0 2023-08-29 10:53:33 +01:00
RiotRobot 974723ceef Prepare changelog for v28.0.0 2023-08-29 10:53:30 +01:00
renovate[bot] 5788d9744b Update all non-major dependencies (#3671)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-24 13:01:48 +00:00
Johannes Marbach 65cbbaaf01 Use sender instead of content.creator field on m.room.create events (#3675)
* Use sender instead of content.creator field on m.room.create events

* Restore room_version fields in fixtures

* Add test case for undefined sender scenario
2023-08-24 11:58:04 +00:00
renovate[bot] c5245a887b Update dependency @types/node to v18.17.6 (#3669)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-23 13:47:35 +00:00
Charly Nguyen 321679fd63 Add join_rule field to /publicRooms response (#3673)
Signed-off-by: Charly Nguyen <charly.nguyen@nordeck.net>
2023-08-23 13:35:43 +00:00
Michael Weimann 15c679b29e Improve/fix restoreKeyBackupWithPassword docs (#3674) 2023-08-23 12:58:10 +00:00
Michael Telatynski 85ba069117 Export de-facto public types out of @types (#3666)
* Export de-facto public types out of @types

* Make typedoc happier
2023-08-22 15:47:22 +00:00
RiotRobot 9b8dcf53ed v28.0.0-rc.1 2023-08-22 15:18:45 +01:00
RiotRobot 324af3ee67 Prepare changelog for v28.0.0-rc.1 2023-08-22 15:18:42 +01:00
RiotRobot ec6c0946d4 v27.3.0-rc.1 2023-08-22 15:13:46 +01:00
RiotRobot e5f480b032 Prepare changelog for v27.3.0-rc.1 2023-08-22 15:13:43 +01:00
Florian Duros 6bf4ed8672 ElementR: Add CryptoApi.requestVerificationDM (#3643)
* Add `CryptoApi.requestVerificationDM`

* Fix RoomMessageRequest url

* Review changes

* Merge fixes

* Add BOB test data

* `requestVerificationDM` test works against old crypto (encrypted verification request)

* Update test data
2023-08-21 14:48:32 +00:00
Valere c18d691ef5 RustCrypto | Implement keybackup loop (#3652)
* Implement `CryptoApi.checkKeyBackup`

* Deprecate `MatrixClient.enableKeyBackup`.

* fix integ test

* more tests

* Implement keybackup loop

* cleaning

* update matrix-sdk-crypto-wasm to 1.2.1

* fix lint

* avoid real timer stuff

* Simplify test

* post merge lint fix

* revert change on yarn.lock

* code review

* Generate test data for exported keys

* code review cleaning

* cleanup legacy backup loop

* Update spec/test-utils/test-data/generate-test-data.py

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update spec/test-utils/test-data/generate-test-data.py

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* update yarn.lock for new wasm bindings

---------

Co-authored-by: Richard van der Hoff <richard@matrix.org>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-08-17 14:10:57 +00:00
ElementRobot 97cf73bc52 Resetting package fields for development 2023-08-15 13:19:02 +01:00
ElementRobot aa25103665 Merge branch 'master' into develop 2023-08-15 13:18:59 +01:00
ElementRobot 858db67778 v27.2.0 2023-08-15 13:17:57 +01:00
ElementRobot e230abee45 Prepare changelog for v27.2.0 2023-08-15 13:17:55 +01:00
Travis Ralston 8c16d69f3c Set minimum supported Matrix 1.1 version (drop legacy r0 versions) (#3007)
Co-authored-by: Germain <germains@element.io>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-08-14 09:25:15 +01:00
Michael Telatynski 55b9116c99 Re-export localStorage-crypto-store (#3660) 2023-08-11 06:02:52 +00:00
Florian Duros 3a5d66057e ElementR: Process all verification events, not just requests (#3650)
* Process all verification event

* Add test for `isVerificationEvent`

* Review changes

* Remove null comparison and add doc to remote echo

* review changes
2023-08-09 14:14:58 +00:00
Richard van der Hoff 3f7af189e4 Implement CryptoApi.checkKeyBackupAndEnable (#3633)
* Implement `CryptoApi.checkKeyBackup`

* Deprecate `MatrixClient.enableKeyBackup`.

* fix integ test

* more tests

---------

Co-authored-by: valere <valeref@matrix.org>
2023-08-09 09:59:03 +00:00
renovate[bot] 16ddcb0ed0 Lock file maintenance (#3659)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-08 15:32:57 +00:00
renovate[bot] 9e35b8dd0a Update all non-major dependencies (#3656)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-08 15:09:57 +00:00
renovate[bot] bed787b749 Update tibdex/backport digest to 9565281 (#3658)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-08 14:14:28 +00:00
renovate[bot] d260b8be56 Update dependency eslint-config-prettier to v9 (#3657)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-08 14:10:12 +00:00
renovate[bot] 97991dad02 Update dependency @types/node to v18.17.3 (#3655)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-08 14:09:52 +00:00
renovate[bot] b8c19c47ab Update babel monorepo to v7.22.10 (#3654)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-08-08 14:07:45 +00:00
ElementRobot 1476ffbd15 v27.2.0-rc.1 2023-08-08 15:01:44 +01:00
ElementRobot 62f0a65472 Prepare changelog for v27.2.0-rc.1 2023-08-08 15:01:41 +01:00
Charly Nguyen 2ef7ae7661 Allow knocking rooms (#3647)
Signed-off-by: Charly Nguyen <charly.nguyen@nordeck.net>
2023-08-03 08:16:18 +00:00
Michael Telatynski 61c0a49971 Mark more logs as debug to tidy the console (#3645) 2023-08-02 20:40:32 +00:00
Michael Telatynski 2172f28888 Fix wrong handling of encrypted rooms when loading them from sync accumulator (#3640)
* Revert "Ensure we don't overinflate the total notification count (#3634)"

This reverts commit fd0c4a7f56.

* Fix wrong handling of encrypted rooms when loading them from sync accumulator

* Tidy up code, removing sections which didn't make any difference

* Add test
2023-08-02 09:53:34 +00:00
Florian Duros 2e9b34e0c3 Throw error if missing userId in CryptoApi.findVerificationRequestDMInProgress (#3641) 2023-08-01 12:20:01 +00:00
ElementRobot 5a782b7377 Resetting package fields for development 2023-08-01 12:28:37 +01:00
ElementRobot 54bc807056 Merge branch 'master' into develop 2023-08-01 12:28:33 +01:00
ElementRobot 9e07710d80 v27.1.0 2023-08-01 12:27:34 +01:00
ElementRobot e9ed91d800 Prepare changelog for v27.1.0 2023-08-01 12:27:31 +01:00
Michael Telatynski 88ba4fad71 Skip processing thread roots and fetching threads list when support is disabled (#3642)
* Skip processing thread roots and fetching threads list when support is disabled

* Enable threads support in tests
2023-07-31 18:16:42 +00:00
Michael Telatynski 21b3471453 Bump pagination limit to account for threaded events (#3638) 2023-07-31 16:59:55 +00:00
Florian Duros 0ada9803ab ElementR: Add CryptoApi.findVerificationRequestDMInProgress (#3601)
* Add `CryptoApi.findVerificationRequestDMInProgress`

* Fix linting and missing parameters

* Move `ROOM_ID` into `test-data`

* Remove verification request from `EventDecryptor` pending list

* Fix duplicate timeline event processing

* Add extra documentation

* Try to fix sonar error

* Use `roomId`

* Fix typo

* Review changes

* Review changes

* Fix `initRustCrypto` jsdoc

* Listen to `ClientEvent.Event` instead of `RoomEvent.Timeline`

* Fix missing room id in `generate-test-data.py`

* Review changes

* Review changes

* Handle encrypted event

* Fix linting

* Comments and run timers

* Ignore 404

* Fix test
2023-07-31 15:00:15 +00:00
Michael Telatynski 1744f0e97b Revert "Ensure we don't overinflate the total notification count (#3634)" (#3639) 2023-07-31 11:57:11 +01:00
Michael Telatynski fd0c4a7f56 Ensure we don't overinflate the total notification count (#3634)
* Ensure we don't overinflate the total notification count

By correctly comparing push rules before & after decryption

* DRY the code

* Testsssss

* Update tests
2023-07-28 15:05:11 +00:00
Michael Telatynski 615f7f9e72 Export more into the public interface (#3614) 2023-07-28 11:54:17 +00:00
renovate[bot] 77259e81c9 Update all non-major dependencies (#3630)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-28 10:55:22 +00:00
Richard van der Hoff 2193cd9d1c Implement CryptoApi.isKeyBackupTrusted (#3632)
* Implement `CryptoApi.isKeyBackupTrusted`

Fixes https://github.com/vector-im/crypto-internal/issues/110

* Bump matrix-sdk-crypto-wasm to v1.2.0

* Back out some changes

These are unneeded, and break backwards compat
2023-07-28 09:54:55 +00:00
Valere 6d28154dcd Add CryptoApi.getActiveSessionBackupVersion() (#3555)
* stub backupmanager

* Implement `CryptoApi.getActiveSessionBackupVersion`

* Revert unnecessary change

we can do this later, once we have better test coverage

* more test coverage

---------

Co-authored-by: Richard van der Hoff <richard@matrix.org>
2023-07-28 08:04:20 +00:00
Richard van der Hoff 83d447adfe Clean up megolm-backup integ test (#3631)
* Add `CryptoApi.setDeviceVerified`

I need a way to mark devices as trusted for the backup tests.

* More tests

* Simplify E2EKeyResponder.addDeviceKeys

The user and device IDs are in the test data, so no need to pass them in

* Clean up key backup integration test

Make it use the CryptoApi rather than legacy `MatrixClient.crypto`, and use a
pre-signed backup instead of requiring a "blindlySignAnything" method.

* run megolm-backup tests on both crypto stacks

* avoid internal backupManager
2023-07-27 15:23:02 +00:00
Richard van der Hoff 73c9f4e322 Add CryptoApi.setDeviceVerified (#3624)
I need a way to mark devices as trusted for the backup tests.
2023-07-27 13:16:10 +01:00
renovate[bot] e6fa4cdb3c Lock file maintenance (#3629)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-27 09:45:53 +00:00
Michael Telatynski a04653a72c Upgrade matrix-widget-api (#3621)
* Fix threads ending up with chunks of their timelines missing

* delint

* Upgrade matrix-widget-api
2023-07-27 09:21:14 +00:00
renovate[bot] 5f9341f39c Update dependency eslint-plugin-unicorn to v48 (#3628)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-27 08:37:46 +00:00
renovate[bot] 906946c419 Update all non-major dependencies (#3626)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-27 08:37:23 +00:00
renovate[bot] 4397b9d640 Update dependency @types/node to v18.17.0 (#3627)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-27 08:37:02 +00:00
ElementRobot 90da2cf439 v27.1.0-rc.1 2023-07-27 09:28:56 +01:00
ElementRobot 6edd45787b Prepare changelog for v27.1.0-rc.1 2023-07-27 09:28:52 +01:00
Florian Duros 84444ec11e ElementR: Add CryptoApi.getCrossSigningKeyId (#3619)
* Add `CryptoApi.getCrossSigningKeyId`

* Rename `CrossSigningPubKey` to `CrossSigningKeyInfo`

* Remove old eslint disable

* Review changes

* Review changes
2023-07-26 16:09:49 +00:00
Richard van der Hoff 0e95df5dba Element-R: implement {get,store}SessionBackupPrivateKey (#3622) 2023-07-26 12:00:43 +01:00
Valere 29b815b678 Replace deprecated TestClient with fetchMock (#3550)
* replace deprecated TestClient with fetchMock

* add stop() api to BackupManager for clean shutdown

* fix merge

* code review cleaning

* lint

* Address review comments

* Remove unused `TestClient.expectKeyBackupQuery`

* clean up imports

---------

Co-authored-by: Richard van der Hoff <richard@matrix.org>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-07-25 20:42:41 +00:00
Richard van der Hoff 0cf056958b Fix broken unit tests for FetchHttpApi.getUrl (#3620)
These tests have broken on Node.js 18.17.0.

This is due to Node.js adopting an updated version of the URL parser, in which
the internal `Symbol(query)` property is populated lazily.

We shouldn't be relying on the internal state of the URL object anyway. Let's
just compare the stringified copy.
2023-07-25 19:48:15 +00:00
Florian Duros 79d4113a6b ElementR: Stub CheckOwnCrossSigningTrust, import cross signing keys and verify local device in bootstrapCrossSigning (#3608) 2023-07-25 18:03:43 +01:00
Michael Telatynski 8a80886358 Fix threads ending up with chunks of their timelines missing (#3618)
* Fix threads ending up with chunks of their timelines missing

* delint
2023-07-25 15:28:52 +00:00
Michael Telatynski de7959de6c Ensure we do not clobber a newer RR with an older unthreaded one (#3617)
* Ensure we do not clobber a newer RR with an older unthreaded one

or vice versa

* Fix test
2023-07-24 16:35:56 +00:00
Michael Telatynski 533c21a515 Fix registration check your emails stage regression (#3616)
* Fix registration check your emails stage regression

* Simplify diff

* Add test
2023-07-24 14:08:17 +00:00
Michael Telatynski 6b018b6927 Fix how Room::eventShouldLiveIn handles replies to unknown parents (#3615)
* Add warning

* Fix how Room::eventShouldLiveIn handles replies to unknown parents
2023-07-24 07:37:28 +00:00
Michael Telatynski 38c3abb364 Update downstream-artifacts.yml (#3613) 2023-07-20 21:43:49 +00:00
Michael Telatynski a47f319665 Only send threaded read receipts if threads support is enabled (#3612)
* Only send threaded read receipts if threads support is enabled

* Tests
2023-07-20 15:44:52 +00:00
Florian Duros ecef9fd755 Fix CryptoApi#getVerificationRequestsToDeviceInProgress (#3611) 2023-07-20 09:46:55 +00:00
Richard van der Hoff 7dffd8ffd3 Make sure to drop references to user device lists (#3610)
Empirically, this seems to fix some problems with leaking references to
IndexedDB.
2023-07-20 08:47:30 +00:00
Michael Telatynski 66492e7ba8 Fix edge cases around non-thread relations to thread roots and read receipts (#3607)
* Ensure non-thread relations to a thread root are actually in both timelines

* Make thread in sendReceipt & sendReadReceipt explicit rather than guessing it

* Apply suggestions from code review

* Fix Room::eventShouldLiveIn to better match Synapse to diverging ideas of notifications

* Update read receipt sending behaviour to align with Synapse

* Fix tests

* Fix thread rel type
2023-07-19 11:21:50 +00:00
Michael Telatynski 43b2404865 Specify /preview_url requests as low priority (#3609)
* Specify /preview_url requests as low priority

* Update src/@types/global.d.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Simplify interface

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-07-19 09:29:41 +00:00
Michael Telatynski fed9910fa1 Remove unused better-docs & docdash (#3605) 2023-07-19 07:44:11 +00:00
RiotRobot f77662406c Resetting package fields for development 2023-07-18 12:53:43 +01:00
RiotRobot 8cc0cf1a70 Merge branch 'master' into develop 2023-07-18 12:53:38 +01:00
RiotRobot dfa2429094 v27.0.0 2023-07-18 12:52:00 +01:00
RiotRobot 3e2460707c Prepare changelog for v27.0.0 2023-07-18 12:51:57 +01:00
Michael Telatynski 706c084fa7 Add tests for room-hierarchy (#3606)
* Add tests for room-hierarchy

* overwriteroutes
2023-07-18 10:37:17 +00:00
renovate[bot] eb7faa6c07 Lock file maintenance (#3604)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-17 17:59:37 +00:00
RiotRobot d45a0b894a v27.0.0-rc.2 2023-07-14 16:10:12 +01:00
RiotRobot 102739e0fb Prepare changelog for v27.0.0-rc.2 2023-07-14 16:10:09 +01:00
Andy Balaam 0d7e4a0fa5 Merge pull request #3603 from matrix-org/backport-3600-to-staging
[Backport staging] Fix read receipt sending behaviour around thread roots
2023-07-14 16:03:41 +01:00
Michael Telatynski d4628e78d4 Fix read receipt sending behaviour around thread roots (#3600)
* Fix read receipt sending behaviour around thread roots

* Update src/client.ts

Co-authored-by: Eric Eastwood <erice@element.io>

---------

Co-authored-by: Eric Eastwood <erice@element.io>
(cherry picked from commit b05f933d83)
2023-07-14 15:01:58 +00:00
Richard van der Hoff 0b193f4665 matrix-sdk-crypto-js -> matrix-sdk-crypto-wasm (#3602)
We've renamed matrix-sdk-crypto-js and released a v1.0.
2023-07-13 17:11:57 +00:00
Eric Eastwood 8ef2e848b9 Log query parameters on HTTP requests (#3591)
* Log query parameters on HTTP requests

Follow-up to https://github.com/matrix-org/matrix-js-sdk/pull/3485

* Only stringify once

See https://github.com/matrix-org/matrix-js-sdk/pull/3591#discussion_r1261300323
2023-07-13 13:07:01 +00:00
Richard van der Hoff d92936fba5 Element-R: support for displaying QR codes during verification (#3588)
* Support for showing QR codes

* Emit `VerificationRequestEvent.Change` events when the verifier changes

* Minor integ test tweaks

* Handle transitions from QR code display to SAS

* Fix naming

* Add a test for `ShowQrCodeCallbacks.cancel`
2023-07-13 11:11:13 +00:00
Michael Telatynski f005984df3 Export typed event emitter key types (#3597)
* Export typed event emitter key types

* Update src/matrix.ts
2023-07-13 11:10:24 +00:00
Richard van der Hoff 13fec49e74 Element-R: ensure that userHasCrossSigningKeys uses up-to-date data (#3599)
* Element-R: ensure that `userHasCrossSigningKeys` uses up-to-date data

* Bump matrix-sdk-crypto-js
2023-07-13 10:46:56 +00:00
renovate[bot] 008294cfc6 Update babel monorepo to v7.22.9 (#3434)
* Update babel monorepo to v7.22.9

* Make babel happier

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-07-13 09:41:03 +00:00
Michael Telatynski b05f933d83 Fix read receipt sending behaviour around thread roots (#3600)
* Fix read receipt sending behaviour around thread roots

* Update src/client.ts

Co-authored-by: Eric Eastwood <erice@element.io>

---------

Co-authored-by: Eric Eastwood <erice@element.io>
2023-07-13 08:25:23 +00:00
Michael Telatynski b186d79dde Fix jest/valid-expects lints (#3586) 2023-07-12 17:11:52 +00:00
Michael Telatynski e82b5fe1db Fix types in getSessionBackupPrivateKey (#3595)
* Fix type issue around `getSessionBackupPrivateKey`

* Fix sending auth: null due to broken types around UIA

* Discard changes to src/crypto/index.ts

* Add comment

* Fix types

* Fix types for MatrixClient::addThreePid

* Iterate
2023-07-12 14:38:14 +00:00
Michael Telatynski 9602aa88ea Fix sending auth: null due to broken types around UIA (#3594)
* Fix type issue around `getSessionBackupPrivateKey`

* Fix sending auth: null due to broken types around UIA

* Discard changes to src/crypto/index.ts

* Add comment
2023-07-12 13:55:02 +00:00
renovate[bot] 0fb3dc1b13 Update typescript-eslint monorepo to v5.62.0 (#3583)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-12 11:01:00 +00:00
renovate[bot] aeede332be Update dependency @types/jest to v29.5.3 (#3582)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-12 10:59:05 +00:00
renovate[bot] b052950a19 Update JS-DevTools/npm-publish action to v2.2.1 (#3581)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-12 10:57:45 +00:00
Michael Telatynski 1cb5fff5a1 Improve types (#3589)
* Improve types

* Improve coverage
2023-07-12 10:39:33 +00:00
Michael Telatynski 01226e41d9 Fix broken DeviceList.spec.ts test (#3590) 2023-07-12 10:01:57 +00:00
dependabot[bot] e3919fd93b Bump semver from 5.7.1 to 5.7.2 (#3575)
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Kerry <kerrya@element.io>
2023-07-12 02:20:47 +00:00
Kerry 3b88ea19b7 Stabilize support for MSC3952: intentional mentions (#3397)
* use stable identifiers for MSC3952: intentional mentions

* add matrix version to feature support for intentional mentions
2023-07-11 22:04:06 +00:00
Richard van der Hoff dcf26f3e48 bump rust-sdk (#3587) 2023-07-11 17:40:39 +00:00
Valere 3385adf5f6 Improve logging of http requests to aid debugging (#3485)
* Simple request logging with status and duration

* remove url params from logs

* superfluous toString()

* Add tests

* Apply suggestions from code review

* update snapshots

* update log format

* Apply suggestions from code review

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

* update snapshot

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Co-authored-by: Richard van der Hoff <richard@matrix.org>
2023-07-11 17:27:42 +00:00
Richard van der Hoff 9db6ce107a Add support for scanning QR codes during verification, with Rust crypto (#3565)
* Offer `m.qr_code.scan.v1` verification method by default

Normally, the application specifies the supported verification methods when
creating the MatrixClient (and matrix-react-sdk does so). If the application
leaves it unset, then the idea is that the js-sdk offers all known verification
methods.

However, by default, the rust-sdk doesn't specify `m.qr_code.scan.v1`. So
basically, we need to set our own list of supported methods, rather than
relying on the rust-sdk's defaults.

* Factor out base class from `RustSASVerifier`

* Implement QR code scanning

* Update src/rust-crypto/verification.ts
2023-07-11 16:00:59 +00:00
Florian Duros d5b22e1deb Use cryptoBackend in client.ts for new rust-crypto implementation (#3576)
* Use `cryptoBackend` in `client.ts` for new rust-crypto implementation for backward compatibility

* Use `cryptoBackend` in `client.ts` for new rust-crypto implementation for backward compatibility
2023-07-11 14:13:53 +00:00
Richard van der Hoff a5e606a1e7 Mark all the rust crypto stuff internal (#3574)
... for the avoidance of doubt.
2023-07-11 14:11:35 +00:00
Michael Telatynski f2471b6dbd Add methods to influence set_presence on /sync API calls (#3578)
* Add methods to influence set_presence on /sync API calls

* Tweak comment

* Improve coverage
2023-07-11 13:31:12 +00:00
RiotRobot dcf71e0c8f v27.0.0-rc.1 2023-07-11 13:37:19 +01:00
RiotRobot 77267e393c Prepare changelog for v27.0.0-rc.1 2023-07-11 13:37:16 +01:00
Michael Telatynski 1fdc0af5b7 Throw saner error when peeking has its room pulled out from under it (#3577) 2023-07-11 10:24:57 +00:00
Michael Telatynski d2b782a2f5 Simplify MatrixClient::setPowerLevel API (#3570)
* Simplify `MatrixClient::setPowerLevel` API

While making it more resilient to causing issues like nuking room state

* Handle edge case

* Fix tests

* Add test coverage
2023-07-11 07:26:30 +00:00
Kerry 5df4ebaada OIDC: Log in (#3554)
* use oidc-client-ts during oidc discovery

* export new type for auth config

* deprecate generateAuthorizationUrl in favour of generateOidcAuthorizationUrl

* testing util for oidc configurations

* test generateOidcAuthorizationUrl

* lint

* test discovery

* dont pass whole client wellknown to oidc validation funcs

* add nonce

* use oidc-client-ts for oidc response

* validate user state and update tests

* use oidc-client-ts for code exchange

* use oidc-client-ts in completing auth grant

* use client userState for homeserver

* more comments
2023-07-11 02:20:19 +00:00
renovate[bot] e68a1471c1 Update all non-major dependencies (#3564)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-10 14:38:14 +00:00
Richard van der Hoff e42dd74426 Add async method for generating a QR code (#3562)
The api to generate a QR code is async in rust, and the easiest way to deal
with it is to make a new method.
2023-07-10 14:22:10 +01:00
renovate[bot] 2751e191d3 Lock file maintenance (#3392)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-07-10 10:08:16 +00:00
Michael Telatynski b5b86bf1b5 Fix TypedEventEmitter::removeAllListeners(void) not working (#3561) 2023-07-10 10:04:38 +00:00
dependabot[bot] 4990bf5ca0 Bump tough-cookie from 4.1.2 to 4.1.3 (#3560)
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.1.2...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-10 08:24:08 +00:00
Kerry b8fa030d5d OIDC: use oidc-client-ts (#3544)
* use oidc-client-ts during oidc discovery

* export new type for auth config

* deprecate generateAuthorizationUrl in favour of generateOidcAuthorizationUrl

* testing util for oidc configurations

* test generateOidcAuthorizationUrl

* lint

* test discovery

* dont pass whole client wellknown to oidc validation funcs

* add nonce

* use client userState for homeserver
2023-07-09 21:19:32 +00:00
Hubert Chathi b606d1e54b Don't allow Olm unwedging rate-limiting to race (#3549)
* don't allow Olm unwedging rate-limiting to race

* apply changes from code review
2023-07-07 10:43:25 +00:00
Michael Telatynski cd7c519dc4 Prevent threads code from making identical simultaneous API hits (#3541) 2023-07-07 09:48:09 +01:00
Michael Telatynski 30dd28960c Update IUnsigned type to be extensible (#3547) 2023-07-07 07:43:17 +00:00
Valere 5b635df08d add stop() api to BackupManager for clean shutdown (#3553) 2023-07-06 16:43:47 +00:00
Florian Duros 592c497902 Upgrade @matrix-org/matrix-sdk-crypto-js to ^0.1.1 (#3552) 2023-07-06 16:00:36 +00:00
Richard van der Hoff 8e3f2f3262 Log message ID for undecryptable to-device messages (#3543)
... to help with debugging.
2023-07-06 06:09:39 +00:00
ElementRobot 5751df1288 Resetting package fields for development 2023-07-04 15:08:16 +01:00
ElementRobot 40a71101e2 Merge branch 'master' into develop 2023-07-04 15:08:12 +01:00
ElementRobot 3f095caf2d v26.2.0 2023-07-04 15:07:04 +01:00
ElementRobot 12a94bdd94 Prepare changelog for v26.2.0 2023-07-04 15:07:02 +01:00
Michael Telatynski 1c1ac137d3 Improve types around login, registration, UIA and identity servers (#3537) 2023-07-04 14:49:24 +01:00
Michael Telatynski 89cabc4912 Ignore thread relations on state events for consistency with edits (#3540)
* Ignore thread relations on state events for consistency with edits

* Add test
2023-07-04 12:07:49 +00:00
Erik Johnston 5be4548b3d Fix an instance of failed to decrypt error when an in flight /keys/query fails. (#3486)
* Fix an instance of failed to decrypt error

Specifically, when checking the event sender matches who sent us the
session keys we skip waiting for pending device list updates if we
already know who owns the session key.

* Apply suggestions from code review

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/crypto/algorithms/olm.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Fix line wrapping

* Update src/crypto/algorithms/olm.ts

* Fix null check

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-07-04 11:31:03 +00:00
Kerry 09de76bd43 OIDC: validate id token (#3531)
* validate id token

* comments

* tidy comments
2023-07-03 21:12:15 +00:00
Richard van der Hoff 3a694f4998 Element-R: Implement VerificationRequest.{timeout,pending} (#3532)
* implement `VerificationRequest.pending`

* Implement `VerificationRequest.timeout`

* Rust crypto: allow using a memory store (#3536)

* Rust crypto: allow using a memory store

It turns out that, for some usecases (in particular, "bot users" for cypress
tests), we don't need persistent storage and an in-memory store will be fine.

* Rust crypto: use a memory store for the unit tests
2023-07-03 11:27:38 +00:00
Richard van der Hoff 3a8a1389f5 Element-R: Implement VerificationRequest.accept (#3526)
* Pass `supportedVerificationMethods` into `VerificationRequest`

... so that the application can later call `accept()` and we know what to send.

* Implement `VerificationRequest.accept`

* Implement `VerificationRequest.declining`

* Update src/rust-crypto/verification.ts
2023-07-03 11:02:19 +00:00
Richard van der Hoff c271e1533a Use the right anchor emoji for SAS verification (#3534)
Currently, the anchor emoji has a ["Variation
Selector-16"](https://codepoints.net/U+FE0F) (U+FE0F) character after it.

The unicode specs do define U+2694 U+FE0F as a valid sequence (with suggested
rendering https://www.unicode.org/cgi-bin/varglyph?24-2693-FE0F), but our spec
spec doesn't include the variation selector, and the difference means that my
cypress tests (which attempt a verification between Element-R and unrusty
Element Web) fail intermittently.

Something of a follow-up to
https://github.com/matrix-org/matrix-js-sdk/pull/3523, but hopefully this will
be the last, because I have regenerated the whole list from the spec data.
2023-06-29 22:05:57 +00:00
Richard van der Hoff 722debe8f9 Drop support for Node 16 (#3533)
* Stop running tests on Node 16

* update package.json
2023-06-29 16:36:09 +00:00
Richard van der Hoff 5165899e82 Element-R: support for starting a SAS verification (#3528)
* integ tests: factor out some utility methods

* Add `VerificationRequest.startVerification` to replace `beginKeyVerification`

The rust SDK ties together creating the verifier and sending the
`m.key.verification.start` message, so we need to combine
`.beginKeyVerification` and `.verify`.

* add some unit tests
2023-06-29 16:34:49 +00:00
Richard van der Hoff 1828826661 QRCode: fix breakage on node 16 (#3527)
[`crypto.getRandomValues`](https://nodejs.org/docs/latest-v18.x/api/crypto.html#cryptogetrandomvaluestypedarray)
was added to the nodejs library in node 17. However, it was actually available
in node 16, hiding under
[`crypto.webcrypto`](https://nodejs.org/docs/latest-v16.x/api/webcrypto.html#cryptogetrandomvaluestypedarray). We
have some shims in `src/crypto/crypto.ts`, so let's use them.

All of this means that we don't need to monkey-patch `crypto` to run the tests
on node 16.
2023-06-29 09:58:38 +00:00
Richard van der Hoff 24cee68fa2 Rust crypto: emit VerificationRequestReceived events (#3525) 2023-06-28 14:32:27 +00:00
Richard van der Hoff e645af1fc5 use the right smiley in emoji verification (#3523) 2023-06-28 10:01:46 +00:00
Michael Telatynski de64779c27 Improve types to match reality (#3510) 2023-06-28 09:06:10 +00:00
Richard van der Hoff acbcb4658a Force coloured output from jest (#3521) 2023-06-27 15:14:47 +00:00
renovate[bot] 815484b543 Update dependency eslint-plugin-jsdoc to v46.3.0 (#3520)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-27 12:40:26 +00:00
renovate[bot] 5a3d1a2a67 Update typescript-eslint monorepo to v5.60.0 (#3519)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-06-27 12:37:30 +00:00
Richard van der Hoff 18626169e4 Create a new event type for verification requests (#3514)
* More slow test fixes

* Create a new event type for verification requests

Previous PRs (https://github.com/matrix-org/matrix-js-sdk/pull/3449, etc) have
pulled out an interface from the `VerificationRequest` class, but applications
registering for the `CryptoEvent.VerificationRequest` event could still be
expecting a fully-fledged class rather than the interface.

To handle this without breaking backwards compat, add a new event type that
carries the interface, not the class.
2023-06-27 11:24:29 +00:00
renovate[bot] e4a9f958a0 Update peter-evans/create-pull-request digest to 1534078 (#3518)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-27 11:11:12 +00:00
Michael Telatynski ff29de743c Update README.md 2023-06-27 12:38:58 +01:00
renovate[bot] 5a68861418 Update all non-major dependencies (#3513)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-27 11:00:37 +00:00
ElementRobot e285932776 v26.2.0-rc.1 2023-06-27 11:57:18 +01:00
ElementRobot 2af0706b16 Prepare changelog for v26.2.0-rc.1 2023-06-27 11:57:15 +01:00
Richard van der Hoff 4382d2a425 Increase another crypto test timeout (#3509)
Followup to https://github.com/matrix-org/matrix-js-sdk/pull/3500: increase the
timeout for another test which is also timing out.
2023-06-27 10:06:48 +00:00
Kerry 9de4a057df OIDC: navigate to authorization endpoint (#3499)
* utils for authorization step in OIDC code grant

* tidy

* completeAuthorizationCodeGrant util functions

* response_mode=query

* add scope to bearertoken type

* add is_guest to whoami response type

* doc comments

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* use shimmed TextEncoder

* fetchMockJest -> fetchMock

* comment

* bearertokenresponse

* test for lowercase bearer

* handle lowercase token_type

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-06-26 23:46:53 +00:00
Richard van der Hoff b703d4a2cc More slow test fixes (#3515)
We still seem to be suffering test timeouts. Hopefully this will fix the integ tests, where #3509 etc fix the unit tests.
2023-06-26 22:15:56 +01:00
Richard van der Hoff d1dec4cd08 Implement VerificationRequest.cancel (#3505) 2023-06-26 16:56:57 +00:00
Richard van der Hoff 326a13bcfe Rearrange the verification integration tests, again (#3504)
* Element-R: Implement `CryptoApi.getVerificationRequestsToDeviceInProgress`

* Element-R: Implement `requestOwnUserVerification`

* init aliceClient *after* the fetch interceptors

* Initialise the test client separately for each test

* Avoid running all the tests twice

Currently all of these tests are running twice, with different client
configurations. That's not really adding much value; we just need to run
specific tests that way.

* Factor out functions for building responses
2023-06-26 14:44:42 +00:00
renovate[bot] e8fb47fdca Update all non-major dependencies (#3467)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-26 14:30:06 +00:00
Richard van der Hoff bd66e3859d Element R: Implement requestOwnUserVerification (#3508)
Part of https://github.com/vector-im/element-web/issues/25319.
2023-06-26 15:17:35 +01:00
Richard van der Hoff 96e484a3fe Element-R: implement CryptoApi.getVerificationRequestsToDeviceInProgress (#3497)
* Element-R: Implement `CryptoApi.getVerificationRequestsToDeviceInProgress`

* Element-R: Implement `requestOwnUserVerification` (#3503)

* Revert "Element-R: Implement `requestOwnUserVerification` (#3503)"

This reverts commit 8da756503c3d72b8ecbf50b4c2cf807ac36229aa.

oops, merged too soon
2023-06-26 13:31:35 +00:00
Richard van der Hoff 3e646bdfa0 Bump version of the react-sdk cypress workflow file (#3501)
`cypress.yaml` is currently pinned to an old version of the react-sdk, meaning
that each attempt to run it is currently failing with an error.

(Introduced by https://github.com/matrix-org/matrix-js-sdk/pull/3480)
2023-06-26 09:09:20 +00:00
Richard van der Hoff 48c4127035 Element-R: Basic implementation of SAS verification (#3490)
* Return uploaded keys from `/keys/query`

* Basic implementation of SAS verification in Rust

* Update the `verifier` *before* emitting `erificationRequestEvent.Change`

* remove dead code
2023-06-26 08:48:44 +00:00
Michael Telatynski f16a6bc654 Aggregate relations regardless of whether event fits into the timeline (#3496) 2023-06-26 09:39:25 +01:00
Richard van der Hoff f884c78579 Improve integration test for interactive verification (#3495)
* Tweaks to the integ test to conform to the spec

Rust is a bit more insistent than legacy crypto...

* Improve documentation on request*Verification

* Check more things in the integration test

* Create an E2EKeyResponder

* Test verification with custom method list

* Add a test for SAS cancellation

* Update spec/integ/crypto/verification.spec.ts
2023-06-23 14:38:38 +00:00
Florian Duros 3c59476cf7 Element-R: Store cross signing keys in secret storage (#3498)
* Store cross signing keys in secret storage

* Update `bootstrapSecretStorage` doc

* Throw error when `createSecretStorageKey` is not set

* Move mocking functions

* Store cross signing keys and user signing keys

* Fix `awaitCrossSigningKeyUpload` documentation

* Remove useless comment

* Fix formatting after merge conflict
2023-06-23 13:10:54 +00:00
Richard van der Hoff c8f6c4dd0d Increase crypto test timeout (#3500)
For some reason, some tests seem to be timing out in GHA. Let's try bumping up
the timeout.
2023-06-23 12:32:56 +00:00
Richard van der Hoff e8c89e9977 Element-R: speed up slow unit test (#3492)
A couple of tests were waiting for a request that wasn't happening, so timing
out after 1.5 seconds. Let's avoid the extra slowth.

(This was introduced by changes in
https://github.com/matrix-org/matrix-js-sdk/pull/3487, but the changes in this
PR do no harm anyway)
2023-06-22 09:43:39 +00:00
Kerry df78d7cf67 OIDC: add dynamic client registration util function (#3481)
* rename OidcDiscoveryError to OidcError

* oidc client registration functions

* test registerOidcClient

* tidy test file

* reexport OidcDiscoveryError for backwards compatibility
2023-06-21 21:55:25 +00:00
Michael Telatynski 80fec814a2 Add getLastUnthreadedReceiptFor utility to Thread delegating to the underlying Room (#3493) 2023-06-21 12:54:30 +01:00
Michael Telatynski 8b9672ba43 Add debug logging to figure out missing reactions in main timeline (#3494)
* Fix debug logging not working

* Add debug logging to figure out missing reactions in main timeline
2023-06-20 15:28:02 +00:00
David Baker ca00094e67 Fix bug where switching media caused media in subsequent calls to fail (#3489) 2023-06-20 15:16:43 +00:00
Richard van der Hoff 9c6d5a6c55 Element-R: wait for OlmMachine on startup (#3487)
* Element-R: wait for OlmMachine on startup

Previously, if you called `CryptoApi.getUserDeviceInfo()` before the first
`/sync` request happened, it would return an empty list, which made a bunch of
the tests racy. Add a hack to get the OlmMachine to think about its device
lists during startup.

* add a test
2023-06-20 09:29:41 +00:00
RiotRobot b77fe465f7 Resetting package fields for development 2023-06-20 10:14:37 +01:00
RiotRobot 8d93f49443 Merge branch 'master' into develop 2023-06-20 10:14:32 +01:00
RiotRobot f03fbed668 v26.1.0 2023-06-20 10:12:27 +01:00
RiotRobot c84efb57ef Prepare changelog for v26.1.0 2023-06-20 10:12:24 +01:00
Florian Duros 49f11578f7 ElementR: Add CryptoApi#bootstrapSecretStorage (#3483)
* Add WIP bootstrapSecretStorage

* Add new test if `createSecretStorageKey` is not set

* Remove old comments

* Add docs for `crypto-api.bootstrapSecretStorage`

* Remove default parameter for `createSecretStorageKey`

* Move `bootstrapSecretStorage` next to `isSecretStorageReady`

* Deprecate `bootstrapSecretStorage` in `MatrixClient`

* Update documentations

* Raise error if missing `keyInfo`

* Update behavior around `setupNewSecretStorage`

* Move `ICreateSecretStorageOpts` to `rust-crypto`

* Move `ICryptoCallbacks` to `rust-crypto`

* Update `bootstrapSecretStorage` documentation

* Add partial `CryptoCallbacks` documentation

* Fix typo

* Review changes

* Review changes
2023-06-20 08:40:11 +00:00
Richard van der Hoff 8df4be0939 Fix order of things in crypto-api.ts (#3491)
* `CryptoApi` should be first
* `export *` should be last
* everything else in the middle
2023-06-20 08:12:33 +00:00
Richard van der Hoff 80cdbe1058 Element-R: implement userHasCrossSigningKeys (#3488) 2023-06-19 21:11:04 +00:00
Michael Telatynski 9c62d15447 Specify git tags for cypress workflow so updating tests is gated by renovate PRs (#3480) 2023-06-19 07:38:24 +00:00
renovate[bot] afc70528cc Update definitelyTyped (#3465)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-16 02:35:02 +00:00
Kerry f938d10f7b remove polls from room state on redaction (#3475) 2023-06-15 22:12:03 +00:00
Richard van der Hoff 22f0b781ea Add new methods for verification to CryptoApi (#3474)
* Add accessors for verification requests to CryptoApi

Part of https://github.com/vector-im/crypto-internal/issues/97

* Add new methods for verification to `CryptoApi` and deprecate old method

https://github.com/vector-im/crypto-internal/issues/98
2023-06-15 14:56:50 +01:00
Florian Duros 1bae10c4b2 Fix export type GeneratedSecretStorageKey (#3479) 2023-06-15 12:46:42 +00:00
Michael Telatynski 9b5b533c6f Close IDB database before deleting it to prevent spurious unexpected close errors (#3478) 2023-06-15 12:25:29 +00:00
Richard van der Hoff c425945353 Avoid deprecated classes in verification integ test (#3473)
https://github.com/matrix-org/matrix-js-sdk/pull/3449 deprecated a bunch of
exports from `src/crypto/verification/request/VerificationRequest`. Let's stop
using them in the integration test.
2023-06-15 11:24:01 +00:00
Florian Duros 0545f6df09 ElementR: Add rust-crypto#createRecoveryKeyFromPassphrase implementation (#3472)
* Add `rust-crypto#createRecoveryKeyFromPassphrase` implementation

* Use `crypto`

* Rename `IRecoveryKey` into `GeneratedSecretStorageKey` for rust crypto

* Improve comments

* Improve `createRecoveryKeyFromPassphrase`
2023-06-14 14:38:43 +00:00
renovate[bot] d14fc426e6 Update dependency eslint-plugin-jsdoc to v46 (#3468)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-14 10:49:28 +00:00
Michael Cousins 9f30defcd1 Upgrade JS-DevTools/npm-publish to v2 (#3456)
- Upgrade JS-DevTools/npm-publish to v2.2.0
- Remove workaround for bug JS-DevTools/npm-publish#15
- Remove usage of `jq` in favor of npm-publish output

Signed-off-by: Michael Cousins <michael@cousins.io>
2023-06-14 08:02:48 +00:00
renovate[bot] 9b175a4985 Update typescript-eslint monorepo to v5.59.9 (#3466)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-13 20:52:40 +00:00
Richard van der Hoff 826ea5bc58 Pull out a new VerificationRequest interface (#3449)
* add a test for incoming verification requests

* Move `VerificationRequestEvent` to crypto-api

* Move `VerificationPhase` to `crypto-api`

* Define `VerificationRequest` interface

* Implement `canAcceptVerificationRequest`
2023-06-13 11:55:37 +00:00
RiotRobot 7b316613f6 v26.1.0-rc1 2023-06-13 12:15:32 +01:00
RiotRobot 387b3485ae Prepare changelog for v26.1.0-rc1 2023-06-13 12:15:29 +01:00
Valere 9f6073478f Element-R: support for manual import/export of Room keys (#3364)
* Rust manual import/export for keys

* code review

* code review

* post merge fix

* code review

* doc: comma splice

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Better test name

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* quick doc update

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-06-13 10:28:35 +00:00
Florian Duros b47c87f909 Add rust-crypto#isCrossSigningReady implementation (#3462) 2023-06-12 14:00:31 +00:00
Kerry c66850e897 OIDC: Validate m.authentication configuration (#3419)
* validate m.authentication, fetch issuer wellknown

* move validation functions into separate file

* test validateWellKnownAuthentication

* test validateOIDCIssuerWellKnown

* add authentication cases to autodiscovery tests

* test invalid authentication config on wk

* improve types

* test case for account:false

* use hasOwnProperty in validateWellKnownAuthentication

* comments

* make registration_endpoint optional
2023-06-11 21:32:44 +00:00
Florian Duros 2766146c49 ElementR: Add CryptoApi.getCrossSigningStatus (#3452)
* Add `crypto.getCrossSigningStatus`

* Fix imports and boolean casting

* Moved `isStoredInSecretStorage` into a single function

* Review changes `CrossSigningStatus`

* Review changes for `cross-signing.spec.ts`

* Add test in case when cross signing is not setup

* Handle when the `crossSigningStatus` returned by the olmMachine is null

* Review changes for `crypto-api` documentation

* Update `cross-signing.spec.ts` according to review changes

* Moved and renamed `isStoredInSecretStorage`

* Remove noise in `CrossSigning.ts` imports

* Fix `returns` sentence in `secretStorageContainsCrossSigningKeys`

* Fix typos

* Add test for `secret-storage.ts`

* Improve documentation

* Add doc about fetch mock request name
2023-06-09 13:15:01 +00:00
Richard van der Hoff 61497c9a8f Pass Kiwi secrets to react-sdk Cypress build (#3461) 2023-06-09 11:03:33 +00:00
Richard van der Hoff 5981feeb44 Element-R: Pull out an interface from VerificationBase (#3414)
* pull out `Verifier` interface

* Mark old classes as deprecated

* Update integration tests to use new interface
2023-06-09 10:09:31 +00:00
Michael Telatynski 51218ddc1d Fix thread list being ordered based on all updates (#3458)
* Add test for thread list stability around non-reply updates

* Fix thread list being ordered based on all updates

* Fix test

* Update spec/integ/matrix-client-event-timeline.spec.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Iterate

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-06-09 08:29:21 +00:00
RiotRobot b907433d38 Merge branch 'master' into develop 2023-06-09 09:27:19 +01:00
RiotRobot 32c0b81332 v26.0.1 2023-06-09 09:25:30 +01:00
RiotRobot 634b8ebbb4 Prepare changelog for v26.0.1 2023-06-09 09:25:28 +01:00
Andy Balaam 4ab8066e1f Merge pull request #3460 from matrix-org/backport-3455-to-staging
[Backport staging] Fix: handle `baseUrl` with trailing slash in `fetch.getUrl`
2023-06-09 09:19:58 +01:00
Kerry 13dccb3d71 Fix: handle baseUrl with trailing slash in fetch.getUrl (#3455)
* tests

* tidy trailing slash in fetch.getUrl before forming url

* make sonar happy about Polynomial regular expression used on uncontrolled data

(cherry picked from commit ef1f5bf232)
2023-06-09 08:11:56 +00:00
Kerry ef1f5bf232 Fix: handle baseUrl with trailing slash in fetch.getUrl (#3455)
* tests

* tidy trailing slash in fetch.getUrl before forming url

* make sonar happy about Polynomial regular expression used on uncontrolled data
2023-06-08 21:36:34 +00:00
Florian Duros a03e3dd501 Update @matrix-org/matrix-sdk-crypto-js to 0.1.0-alpha.10 (#3453) 2023-06-07 14:10:38 +00:00
Enrico Schwendig 3cfad3cdeb Expand webrtc stats with connection and call feed track information (#3421)
* Refactor names in webrtc stats

* Refactor summary stats reporter to gatherer

* Add call and opponent member id to call stats reports

* Update opponent member when we know them

* Add missing return type

* remove async in test

* add call feed webrtc report

* add logger for error case in stats gathering

* gather connection track report

* expand call feed stats with call feed

* formation code and fix lint issues

* clean up new track stats

 * set label for call feed stats and
 * remove stream in track stats
 * transceiver stats based on mid
 * call feed stats based on stream id
 * fix lint and test issues

* Fix merge issues

* Add test for expanding call feed stats in group call

* Fix export issue from prv PR

* explain test data and fixed some linter issues

* convert tests to snapshot tests
2023-06-07 14:05:51 +00:00
Timo 60c715d5df Extend stats summary with call device and user count based on room state (#3424)
* send expected peer connections to posthog.
(based on roomState event)

* add tests

* change GroupCallStats initialized

* prettier

* more test and catch for promise

* seperate the participant logic in a summary extend function

Signed-off-by: Timo K <toger5@hotmail.de>

* remove unused

Signed-off-by: Timo K <toger5@hotmail.de>

* rename summaryStatsReportGatherer to "Reporter"
for the summary stats there is only one instance because there is only
one summary. Since we dont have a list of gatherers it this class only reports.
Hence we rename it to be a reporter.

Signed-off-by: Timo K <toger5@hotmail.de>

* review

Signed-off-by: Timo K <toger5@hotmail.de>

* Update src/webrtc/stats/groupCallStats.ts

Co-authored-by: Robin <robin@robin.town>

* revert rename

Signed-off-by: Timo K <toger5@hotmail.de>

* Update all non-major dependencies (#3433)

* Update all non-major dependencies

* Remove name wrap-ansi-cjs

* Remove name string-width-cjs

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

* Update definitelyTyped (#3430)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

* Export FALLBACK_ICE_SERVER (#3429)

* Add an integration test for verification (#3436)

* Move existing crypto integ tests into a subdirectory

* Factor out some common bits from `crypto.spec.ts`

* Integration test for device verification

* Ignore generated file in prettier

* Always show a summary after Jest tests (#3440)

... because it is otherwise impossible to see what failed.

* Use correct /v3 prefix for /refresh (#3016)

* Add tests to ensure /v3/refresh is called + automatic /v1 retry

* Request /refresh with v3 prefix, and quietly fall back to v1

* Add tests checking re-raising errors

* Update spec/unit/login.spec.ts

* Update comment

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update Mutual Rooms (MSC2666) support (#3381)

* update mutual rooms support

* clarify docs and switch eslint comment with todo

* please the holy linter

* change query variable names around

* add mock tests and fix issue

* ye holy linter

* GHA: build and cypress-test a copy of element-web after each push (#3412)

* Build a copy of element-web after each push

* Run cypress after each build of element-web

* Fix downstream-artifacts build (#3443)

* Fix downstream-artifacts build

* Update cypress.yml

* Fix edge cases around 2nd order relations and threads (#3437)

* Fix tests oversimplifying threads fixtures

* Check for unsigned thread_id in MatrixEvent::threadRootId

* Fix threads order being racy

* Make Sonar happier

* Iterate

* Make sliding sync linearize processing of sync requests (#3442)

* Make sliding sync linearize processing of sync requests

* Iterate

* Iterate

* Iterate

* Iterate

* Disable downstream artifacts build for develop branch (#3444)

* Export thread-related types from SDK (#3447)

* Export thread-related types from SDK

* address PR feedback

* Integration test for QR code verification (#3439)

* Integration test for QR code verification

Followup to https://github.com/matrix-org/matrix-js-sdk/pull/3436: another
integration test, this time using the QR code flow

* Use Object.defineProperty, and restore afterwards

Apparently global.crypto exists in some environments

* apply ts-ignore

* remove stray comment

* Update spec/integ/crypto/verification.spec.ts

* Add `getShowSasCallbacks`, `getShowQrCodeCallbacks` to VerifierBase (#3422)

* Add `getShowSasCallbacks`, `getShowQrCodeCallbacks` to VerifierBase

... to avoid some type-casting

* Integration test for QR code verification

Followup to https://github.com/matrix-org/matrix-js-sdk/pull/3436: another
integration test, this time using the QR code flow

* Rename method

... it turns out not to be used quite as I thought.

* tests for new methods

* Use Object.defineProperty, and restore afterwards

Apparently global.crypto exists in some environments

* apply ts-ignore

* More test coverage

* fix bad merge

* Fix changelog_head.py script to be Python 3 compatible

* Prepare changelog for v25.2.0-rc.1

* v25.2.0-rc.1

* Fix tsconfig-build.json

* Prepare changelog for v25.2.0-rc.2

* v25.2.0-rc.2

* Fix docs deployment

* Prepare changelog for v25.2.0-rc.3

* v25.2.0-rc.3

* Prepare changelog for v25.2.0-rc.4

* v25.2.0-rc.4

* [Backport staging] Attempt a potential workaround for stuck notifs (#3387)

Co-authored-by: Andy Balaam <andy.balaam@matrix.org>

* Prepare changelog for v25.2.0-rc.5

* v25.2.0-rc.5

* [Backport staging] Fix mark as unread button (#3401)

Co-authored-by: Michael Weimann <michaelw@matrix.org>

* Prepare changelog for v26.0.0-rc.1

* v26.0.0-rc.1

* Prepare changelog for v26.0.0

* v26.0.0

* Resetting package fields for development

* use cli.canSupport to determine intentional mentions support (#3445)

* use cli.canSupport to determine intentional mentions support

* more specific comment

* Update src/client.ts

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

* git fixup

Signed-off-by: Timo K <toger5@hotmail.de>

* import updates

Signed-off-by: Timo K <toger5@hotmail.de>

* dont revert enricos change

Signed-off-by: Timo K <toger5@hotmail.de>

* temp rename for lowercase

* lowercase

---------

Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Robin <robin@robin.town>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Co-authored-by: David Lee <david@david-lee.net>
Co-authored-by: Jonathan de Jong <jonathan@automatia.nl>
Co-authored-by: Stanislav Demydiuk <stas-demydiuk@users.noreply.github.com>
Co-authored-by: ElementRobot <releases@riot.im>
Co-authored-by: Andy Balaam <andy.balaam@matrix.org>
Co-authored-by: Michael Weimann <michaelw@matrix.org>
Co-authored-by: Kerry <kerrya@element.io>
2023-06-07 13:36:40 +00:00
Richard van der Hoff c2942ddbc7 Add new methods to VerificationRequest (#3441)
* Add new method `VerificationRequest.getQRCodeBytes`

... which requires fewer complicated classes than the existing `qrCodeData`

* Add new property `VerificationRequest.otherDeviceId`

... to save going via `.channel`

* Add more methods to `VerificationRequest`

... to avoid the need for `channel`

* Use new methods in integration tests
2023-06-07 13:23:27 +00:00
Michael Weimann 2d7fdde7ed Update MSC3912 implementation to use with_rel_type instead of with_relations (#3420)
* Migrate MSC3912

* Fix doc blocks

* Remove with_relations fallback

* Implement PR feedback

* Fix typo
2023-06-07 12:05:14 +00:00
Enrico Schwendig cf34e90cb4 Fix export issue from thread module (#3451)
* Fix export issue from thread module

* separate type from class export

* follow the pattern of what other exports do
2023-06-07 09:35:20 +00:00
Kerry f0fa4d2cc8 use cli.canSupport to determine intentional mentions support (#3445)
* use cli.canSupport to determine intentional mentions support

* more specific comment

* Update src/client.ts

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-06-06 21:52:55 +00:00
RiotRobot c52e4b6329 Resetting package fields for development 2023-06-06 13:45:40 +01:00
RiotRobot 9451b55985 Merge branch 'master' into develop 2023-06-06 13:45:34 +01:00
RiotRobot f41fa84e72 v26.0.0 2023-06-06 13:44:07 +01:00
RiotRobot 3c4134537a Prepare changelog for v26.0.0 2023-06-06 13:44:03 +01:00
Richard van der Hoff 39714bfe6f Add getShowSasCallbacks, getShowQrCodeCallbacks to VerifierBase (#3422)
* Add `getShowSasCallbacks`, `getShowQrCodeCallbacks` to VerifierBase

... to avoid some type-casting

* Integration test for QR code verification

Followup to https://github.com/matrix-org/matrix-js-sdk/pull/3436: another
integration test, this time using the QR code flow

* Rename method

... it turns out not to be used quite as I thought.

* tests for new methods

* Use Object.defineProperty, and restore afterwards

Apparently global.crypto exists in some environments

* apply ts-ignore

* More test coverage

* fix bad merge
2023-06-06 11:16:19 +00:00
Richard van der Hoff f5f6100b1e Integration test for QR code verification (#3439)
* Integration test for QR code verification

Followup to https://github.com/matrix-org/matrix-js-sdk/pull/3436: another
integration test, this time using the QR code flow

* Use Object.defineProperty, and restore afterwards

Apparently global.crypto exists in some environments

* apply ts-ignore

* remove stray comment

* Update spec/integ/crypto/verification.spec.ts
2023-06-06 10:22:12 +00:00
Stanislav Demydiuk ecd700a36e Export thread-related types from SDK (#3447)
* Export thread-related types from SDK

* address PR feedback
2023-06-06 07:59:10 +00:00
Richard van der Hoff ea7042efb9 Disable downstream artifacts build for develop branch (#3444) 2023-06-05 17:38:08 +00:00
Michael Telatynski 04a6c4e6c4 Make sliding sync linearize processing of sync requests (#3442)
* Make sliding sync linearize processing of sync requests

* Iterate

* Iterate

* Iterate

* Iterate
2023-06-05 16:40:19 +00:00
Michael Telatynski 0329824cab Fix edge cases around 2nd order relations and threads (#3437)
* Fix tests oversimplifying threads fixtures

* Check for unsigned thread_id in MatrixEvent::threadRootId

* Fix threads order being racy

* Make Sonar happier

* Iterate
2023-06-05 15:18:56 +00:00
Richard van der Hoff 3351c4f57a Fix downstream-artifacts build (#3443)
* Fix downstream-artifacts build

* Update cypress.yml
2023-06-05 15:05:14 +00:00
Richard van der Hoff e70a1a1eff GHA: build and cypress-test a copy of element-web after each push (#3412)
* Build a copy of element-web after each push

* Run cypress after each build of element-web
2023-06-05 09:11:00 +00:00
Jonathan de Jong 1a5af9d8e3 Update Mutual Rooms (MSC2666) support (#3381)
* update mutual rooms support

* clarify docs and switch eslint comment with todo

* please the holy linter

* change query variable names around

* add mock tests and fix issue

* ye holy linter
2023-06-05 08:23:44 +00:00
David Lee 258f157ebc Use correct /v3 prefix for /refresh (#3016)
* Add tests to ensure /v3/refresh is called + automatic /v1 retry

* Request /refresh with v3 prefix, and quietly fall back to v1

* Add tests checking re-raising errors

* Update spec/unit/login.spec.ts

* Update comment

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-06-03 14:56:12 +00:00
Richard van der Hoff dfb079a76f Always show a summary after Jest tests (#3440)
... because it is otherwise impossible to see what failed.
2023-06-02 17:38:17 +00:00
Richard van der Hoff 858155e0ef Add an integration test for verification (#3436)
* Move existing crypto integ tests into a subdirectory

* Factor out some common bits from `crypto.spec.ts`

* Integration test for device verification

* Ignore generated file in prettier
2023-06-02 15:01:21 +00:00
Michael Telatynski 946a1cef0f Export FALLBACK_ICE_SERVER (#3429) 2023-06-02 14:29:49 +00:00
renovate[bot] 6c1fdbb7e9 Update definitelyTyped (#3430)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-06-02 13:36:53 +00:00
renovate[bot] 8cd7c96496 Update all non-major dependencies (#3433)
* Update all non-major dependencies

* Remove name wrap-ansi-cjs

* Remove name string-width-cjs

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-06-02 13:33:05 +00:00
renovate[bot] cc9d530bcf Update dependency eslint-plugin-jsdoc to v45 (#3435)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-01 16:38:45 +00:00
renovate[bot] cabf6da6a7 Update typescript-eslint monorepo to v5.59.7 (#3432)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-01 16:38:30 +00:00
renovate[bot] 895a82efcd Update dependency @types/jest to v29.5.2 (#3431)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-06-01 16:38:26 +00:00
ElementRobot d4414341d6 v26.0.0-rc.1 2023-06-01 16:54:25 +01:00
ElementRobot f173014fc0 Prepare changelog for v26.0.0-rc.1 2023-06-01 16:54:22 +01:00
ElementRobot 81cb44db7f Merge branch 'develop' into staging
# Conflicts:
#	spec/unit/room.spec.ts
#	src/models/event-timeline.ts
#	src/models/thread.ts
2023-06-01 16:49:33 +01:00
Michael Telatynski 71f9b25db7 Ensure we do not add relations to the wrong timeline (#3427)
* Do not assume that a relation lives in main timeline if we do not know its parent

* For pagination, partition relations with unknown parents into a separate bucket

And only add them to relation map, no timelines

* Make addLiveEvents async and have it fetch parent events of unknown relations to not insert into the wrong timeline

* Fix tests not awaiting addLIveEvents

* Fix handling of thread roots in eventShouldLiveIn

* Fix types

* Fix tests

* Fix import

* Stash thread ID of relations in unsigned to be stashed in sync accumulator

* Persist after processing

* Revert "Persist after processing"

This reverts commit 05ed6409b35f5e9bea3b699d0abcaac3d02588c5.

* Update unsigned field name to match MSC4023

* Persist after processing to store thread id in unsigned sync accumulator

* Add test

* Fix replayEvents getting doubled up due to Thread::addEvents being called in createThread and separately

* Fix test

* Switch to using UnstableValue

* Add comment

* Iterate
2023-06-01 15:29:05 +00:00
Enrico Schwendig 9c5c7ddb17 Add remote user and call id in webrtc call stats (#3413)
* Refactor names in webrtc stats

* Refactor summary stats reporter to gatherer

* Add call and opponent member id to call stats reports

* Update opponent member when we know them

* Add missing return type

* remove async in test

* mark new stats property as optional to avoid braking changes
2023-06-01 15:07:44 +00:00
sigmaSd feb424b0a9 mention deno support in the README (#3417)
* mention deno support in the README

It seems to work fine, and I have a demo bot with it https://github.com/sigmaSd/deno-matrix-bot

* Update README.md
2023-06-01 07:52:55 +00:00
Travis Ralston 648a1a09b1 Mark room version 10 as safe (#3425)
As should have been done a year ago.
2023-05-31 14:15:49 +00:00
Michael Telatynski 56c5375bbd Remove spec non-compliant extended glob format (#3423)
* Remove spec non-compliant extended glob format

* Simplify

* Remove tests for non spec compliant behaviour

* Remove stale rules
2023-05-31 09:05:55 +00:00
Andy Balaam b29e1e9d21 Adjust fetchEditsWhereNeeded to use a clearer filter and async function (#3411)
* Make a clear and explicit filter on which events are considered for fetchEventsWhereNeeded

* Convert the logic in fetchEventsWhereNeeded to an async function
2023-05-26 08:29:35 +00:00
Enrico Schwendig 7ade461a4c Refactor naming of webrtc stats reporter (#3404)
* Refactor names in webrtc stats

* Refactor summary stats reporter to gatherer

* Add test for signal change

* rename test
2023-05-26 07:56:49 +00:00
Andy Balaam b5414ea914 Fix bug where original event was inserted into timeline instead of the edit event (#3398)
* Fix an existing test for editing messages in threads

While attempting to test a new change, I discovered that the test
"should allow edits to be added to thread timeline" did not actually
fail if its assertions failed. Further, those assertions were incorrect.

So this change fixes the test to create the thread, wait for it to be
initialised, and then add events to it. This simplifies the flow and
ensures the test fails if something unexpected happens.

* Move editing test into thread.spec.ts

* Isolate Thread global modification in beforeAll()

* Delete unneeded setUnsigned call

* Use standard message-creation methods

* Rename event variables

* Rename sender->user

* Remove unneeded variables

* Extract distractions into functions

* Fetch edits for thread messages

Modifies fetchEditsWhereNeeded to allow edits of threaded messages. The
code before prevented any relations from fetching edits, but of course
events in threads are relations.

We definitely want thread messages to get their edits fetched, and I
assume this is working in the real code, probably because the event
being looked at is some kind of eventmapped thing that doesn't have
proper relations visible on it.

In tests, if we don't make this change, we can't see edits getting
fetched.

* Add a test for fetching edits on demand in a thread

This test demonstrates the current behaviour, which contains a bug - we
don't actually add the right event to the timeline.

* Fix bug where original event was inserted into timeline instead of the edit event
2023-05-25 15:48:48 +00:00
Andy Balaam 711bf4710d Test inserting edit events into the thread timeline "on demand" (#3410)
* Fix an existing test for editing messages in threads

While attempting to test a new change, I discovered that the test
"should allow edits to be added to thread timeline" did not actually
fail if its assertions failed. Further, those assertions were incorrect.

So this change fixes the test to create the thread, wait for it to be
initialised, and then add events to it. This simplifies the flow and
ensures the test fails if something unexpected happens.

* Move editing test into thread.spec.ts

* Isolate Thread global modification in beforeAll()

* Delete unneeded setUnsigned call

* Use standard message-creation methods

* Rename event variables

* Rename sender->user

* Remove unneeded variables

* Extract distractions into functions

* Fetch edits for thread messages

Modifies fetchEditsWhereNeeded to allow edits of threaded messages. The
code before prevented any relations from fetching edits, but of course
events in threads are relations.

We definitely want thread messages to get their edits fetched, and I
assume this is working in the real code, probably because the event
being looked at is some kind of eventmapped thing that doesn't have
proper relations visible on it.

In tests, if we don't make this change, we can't see edits getting
fetched.

* Add a test for fetching edits on demand in a thread

This test demonstrates the current behaviour, which contains a bug - we
don't actually add the right event to the timeline.
2023-05-25 16:32:42 +01:00
Andy Balaam 48b60bb885 Simplify thread-editing test (#3409)
* Fix an existing test for editing messages in threads

While attempting to test a new change, I discovered that the test
"should allow edits to be added to thread timeline" did not actually
fail if its assertions failed. Further, those assertions were incorrect.

So this change fixes the test to create the thread, wait for it to be
initialised, and then add events to it. This simplifies the flow and
ensures the test fails if something unexpected happens.

* Move editing test into thread.spec.ts

* Isolate Thread global modification in beforeAll()

* Delete unneeded setUnsigned call

* Use standard message-creation methods

* Rename event variables

* Rename sender->user

* Remove unneeded variables

* Extract distractions into functions
2023-05-25 14:03:58 +00:00
Andy Balaam 7ed14dc749 Only add a local receipt if it's after an existing receipt (#3399)
* Add a test for creating local echo receipts in threads

* Only add local receipt if it's after existing receipt

* Refactor local receipt tests to be shorter

* Tests for local receipts where we DO have recursive relations support
2023-05-25 13:59:14 +00:00
Andy Balaam 26736b6bb1 Move editing test into thread.spec.ts (#3408)
* Fix an existing test for editing messages in threads

While attempting to test a new change, I discovered that the test
"should allow edits to be added to thread timeline" did not actually
fail if its assertions failed. Further, those assertions were incorrect.

So this change fixes the test to create the thread, wait for it to be
initialised, and then add events to it. This simplifies the flow and
ensures the test fails if something unexpected happens.

* Move editing test into thread.spec.ts
2023-05-25 13:20:59 +00:00
Andy Balaam 056aae823d Fix an existing test for editing messages in threads (#3407)
While attempting to test a new change, I discovered that the test
"should allow edits to be added to thread timeline" did not actually
fail if its assertions failed. Further, those assertions were incorrect.

So this change fixes the test to create the thread, wait for it to be
initialised, and then add events to it. This simplifies the flow and
ensures the test fails if something unexpected happens.
2023-05-25 12:38:53 +00:00
Andy Balaam d1bfdca0c9 Isolate changes to Thread global into a single describe block (#3390) 2023-05-25 11:45:47 +00:00
Andy Balaam c0577c29c4 Minor improvements to the code inserting events into timelines (#3389)
* Remove unneeded pling

* Comment clarifying why we bail out in insertEventIntoTimeline
2023-05-25 11:44:56 +00:00
Richard van der Hoff a2d1dee0a1 Minor fixes to CryptoApi doc comments (#3406)
Followups to #3287 and #3360: minor clarifications to the doc-comments
2023-05-24 16:02:40 +00:00
Richard van der Hoff d7bcdff29b Fix re-exports for SAS.ts (#3405)
These three are only types, not objects we can export.

Fixes warnings in EW (and probably some build failures for someone somewhere):

```
2023-05-24 11:27:28.294 [element-js] WARNING in ../matrix-js-sdk/src/crypto/verification/SAS.ts 31:0-123
2023-05-24 11:27:28.294 [element-js] "export 'EmojiMapping' was not found in '../../crypto-api/verification'
2023-05-24 11:27:28.294 [element-js]
2023-05-24 11:27:28.294 [element-js] WARNING in ../matrix-js-sdk/src/crypto/verification/SAS.ts 31:0-123
2023-05-24 11:27:28.294 [element-js] "export 'GeneratedSas' (reexported as 'IGeneratedSas') was not found in '../../crypto-api/verification'
2023-05-24 11:27:28.294 [element-js]
2023-05-24 11:27:28.294 [element-js] WARNING in ../matrix-js-sdk/src/crypto/verification/SAS.ts 31:0-123
2023-05-24 11:27:28.294 [element-js] "export 'ShowSasCallbacks' (reexported as 'ISasEvent') was not found in '../../crypto-api/verification'
```
2023-05-24 10:54:10 +00:00
Eric Eastwood ed71cdeccd Add more context for why threaded vs unthreaded read receipts (#3378)
* Add more context for why threaded vs unthreaded read receipts

See https://github.com/matrix-org/matrix-js-sdk/pull/3339#discussion_r1195364120

* Language updates from Andy

See https://github.com/matrix-org/matrix-js-sdk/pull/3378#discussion_r1197622113

* Fix lints
2023-05-24 10:48:22 +00:00
Michael Telatynski 729f924de1 Prioritise entirely supported flows for UIA (#3402)
* Prioritise entirely supported flows for UIA

* Add tests

* Fix types

* Apply suggestions from code review

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/interactive-auth.ts

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-05-24 10:33:48 +00:00
Andy Balaam 4732098731 Test for inserting events into the timeline in timestamp order (#3391)
* Move mkReaction into test-utils so it can be used by other code

* Basic test for inserting messages into the thread timeline
2023-05-24 10:29:57 +00:00
ElementRobot a7d503a8ac [Backport staging] Fix mark as unread button (#3401)
Co-authored-by: Michael Weimann <michaelw@matrix.org>
2023-05-24 09:02:18 +01:00
Michael Weimann 063d69eff1 Fix mark as unread button (#3393)
* Fix mark as unread button

* Revert to prefer the last event from the main timeline

* Refactor room test

* Fix type

* Improve docs

* Insert events to the end of the timeline

* Improve test doc
2023-05-23 20:34:18 +00:00
Richard van der Hoff 614f446361 Combine QrCodeEvent, SasEvent and VerificationEvent (#3386)
* Move IReciprocateQr to `crypto-api` and rename

* Move ISasEvent to `crypto-api`, and rename

... and add some comments

* Combine QrCodeEvent, SasEvent and VerificationEvent together

... as a precursor to extracting a single `Verifier` interface for `SAS` and `ReciprocateQRCode`.

`enum`s are slightly magical things that have both a type and a value, so we
have to re-export their backwards-compatibility fudges twice.

* Update src/crypto/verification/Base.ts
2023-05-22 11:02:10 +00:00
Michael Telatynski b62fac9dad Update client.ts 2023-05-19 16:39:02 +01:00
ElementRobot ff07cb642f v25.2.0-rc.5 2023-05-19 16:35:34 +01:00
ElementRobot fba3cf2756 Prepare changelog for v25.2.0-rc.5 2023-05-19 16:35:32 +01:00
Michael Telatynski 5973c66726 Make sonar happier about our code & tests (#3388) 2023-05-19 16:33:19 +01:00
ElementRobot b22fc1f9d9 [Backport staging] Attempt a potential workaround for stuck notifs (#3387)
Co-authored-by: Andy Balaam <andy.balaam@matrix.org>
2023-05-19 15:57:55 +01:00
Richard van der Hoff 3f48a954d8 Move crypto classes into a separate namespace (#3385)
* Move crypto classes into a separate namespace

* Add in re-exports for backwards compatibility

* Update src/matrix.ts
2023-05-19 12:43:16 +00:00
Michael Telatynski b5d544df68 Update sonarqube.yml (#3376) 2023-05-19 12:16:29 +00:00
Andy Balaam cd26ba67d4 Attempt a potential workaround for stuck notifs (#3384)
* Attempt a potential workaround for stuck notifs

* Remove TODOs

* Fix backwards logic about server support for MSC3981 in fetchEditsWhereNeeded

* Check for lack of MSC3981 server support before calling insertEventIntoTimeline

* If no parent event is found, insert purely based on timestamp

* Mark temporary methods as internal
2023-05-19 12:34:26 +01:00
Michael Telatynski 488390365a Add typedoc-plugin-coverage (#3379)
* Add typedoc-plugin-coverage

* Specify coverageLabel
2023-05-19 10:35:19 +00:00
Richard van der Hoff b7b1129478 Fix bug with pendingEventOrdering: "chronological" (#3382)
If we don't do this, then we end up trying to match the MAC on our own
`m.key.verification.mac`, which of course fails.
2023-05-18 13:47:24 +00:00
Richard van der Hoff 0fa9528a3f Comments for typed-event-emitter classes (#3380)
* Comments for typed-event-emitter classes

* Export `TypedEventEmitter`

... to stop tsdoc complaining.
2023-05-18 12:22:51 +00:00
Enrico Schwendig a7b1dcaf95 Filter all summary stats which collect the first time webrtc metrics. (#3377)
* remove comment

* Filter all summery stats which collect the first time webrtc stats

* Fix lint issues

* Fix lint second issues
2023-05-17 15:40:33 +00:00
Richard van der Hoff bb5bccbf78 Element-R: initial implementation of bootstrapCrossSigning (#3368)
* Working `bootstrapCrossSigning` for rust

* Remove unused `oldBackendOnly`

* update tests

* another test
2023-05-16 20:30:32 +00:00
renovate[bot] ece3ccb958 Lock file maintenance (#3375)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-16 16:31:36 +00:00
renovate[bot] a769cf88f7 Update dependency eslint-plugin-unicorn to v47 (#3373)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-16 15:23:34 +00:00
renovate[bot] 8b0f1a0c59 Update dependency @types/node to v18.16.9 (#3370)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-05-16 15:19:43 +00:00
renovate[bot] 978e748246 Update dependency eslint-plugin-jsdoc to v44 (#3372)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-16 15:15:21 +00:00
renovate[bot] 32a5cc4728 Update matrix-org/netlify-pr-preview action to v2 (#3374)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-16 15:01:13 +00:00
renovate[bot] d580f56c0b Update all non-major dependencies (#3371)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-16 14:51:21 +00:00
Michael Telatynski 789458e0d4 Add methods to terminate idb worker (#3362) 2023-05-16 16:05:55 +01:00
renovate[bot] 8d14d45272 Update typescript-eslint monorepo to v5.59.6 (#3334)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-16 14:37:05 +00:00
ElementRobot 2ec1fa6605 v25.2.0-rc.4 2023-05-16 14:22:04 +01:00
ElementRobot f15d682938 Prepare changelog for v25.2.0-rc.4 2023-05-16 14:22:02 +01:00
ElementRobot 21a10a2d14 v25.2.0-rc.3 2023-05-16 14:17:04 +01:00
ElementRobot fc02e550bd Prepare changelog for v25.2.0-rc.3 2023-05-16 14:17:02 +01:00
Michael Telatynski 78637a0689 Fix docs deployment 2023-05-16 14:15:27 +01:00
ElementRobot 4ca882fcd4 v25.2.0-rc.2 2023-05-16 13:58:35 +01:00
ElementRobot 13ee0eb7f5 Prepare changelog for v25.2.0-rc.2 2023-05-16 13:58:33 +01:00
ElementRobot cb018dfc80 Fix tsconfig-build.json 2023-05-16 13:58:05 +01:00
ElementRobot 7574dacdb3 v25.2.0-rc.1 2023-05-16 13:37:19 +01:00
ElementRobot 0c417b7c32 Prepare changelog for v25.2.0-rc.1 2023-05-16 13:37:17 +01:00
ElementRobot daf845d7bd Fix changelog_head.py script to be Python 3 compatible 2023-05-16 13:36:40 +01:00
Michael Telatynski 52792ec89b Fix CI failure on develop due to force merged PR and prettier failure (#3369) 2023-05-16 11:52:58 +00:00
Matthew Hodgson 6dc4a62e8c Merge pull request #3367 from matrix-org/matthew/fix-accumulated-sync-summaries
fix accumulated sync summaries - andy review
2023-05-16 12:34:54 +01:00
Matthew Hodgson 1cd8ea61ea merge 2023-05-16 12:08:02 +01:00
Matthew Hodgson 0c5eb277e4 incorporate andy review 2023-05-16 12:05:56 +01:00
Matthew Hodgson d459a91af3 correctly accumulate sync summaries. (#3366)
if a sync summary for (say) invited_member_count goes from 1 to 0, it should be
accumluated as 0, rather than 1.

Should fix https://github.com/vector-im/element-web/issues/23345
2023-05-16 10:41:35 +00:00
Matthew Hodgson 18722d0031 correctly accumulate sync summaries.
if a sync summary for (say) invited_member_count goes from 1 to 0, it should be
accumluated as 0, rather than 1.

Should fix https://github.com/vector-im/element-web/issues/23345
2023-05-16 11:34:06 +01:00
RiotRobot 5119934268 Merge branch 'master' into develop 2023-05-16 09:12:28 +01:00
RiotRobot 077da23d08 v25.1.1 2023-05-16 09:10:34 +01:00
RiotRobot 083b4cb17e Prepare changelog for v25.1.1 2023-05-16 09:10:31 +01:00
Richard van der Hoff 4316009401 Element-R: support for SigningKeysUploadRequest (#3365)
* OutgoingRequestProcessor: support for SigningKeysUploadRequest

* Tests

* Bump matrix-org/matrix-sdk-crypto-js

... to pick up bug fixes for outgoing requests
2023-05-15 19:14:05 +00:00
Richard van der Hoff 72f3c360b6 Add CryptoApi.getCrossSigningKeyId (#3360) 2023-05-15 18:46:33 +01:00
Enrico Schwendig fcbc195fbe Check permission on mute mic, only if no audio track exists. (#3359)
* check permission only if no audio track

* fix linter issues

* add missing tests for perfect negotiation pattern

* add null case in unit tests for audio muting

* fix issue with type MediaStream

* force right type of mock methode

* format code
2023-05-15 14:38:43 +00:00
Richard van der Hoff af38021d28 Deprecate device methods in MatrixClient (#3357) 2023-05-15 10:37:35 +00:00
Michael Telatynski 5e8cb9fa18 Fix typedoc release documentation deployment (#3358)
* Prune typedoc docs before generating new ones

* Only maintain 10 major versions

* Switch to deploy mechanism which doesn't mangle symlinks

* Convert absolute symlinks to relative
2023-05-15 09:14:35 +00:00
Michael Telatynski 6ef9f6c55e Enable better tree shaking (#3356) 2023-05-15 08:10:44 +00:00
Timo e6a3b0ebc0 Total summary count (#3351)
* add audio concealment to stats report

* audio concealment to summary

* make ts linter happy

* format and rename

* fix and add tests

* make it prettier!

* we can make it even prettier ?!

* review

* fix tests

* pretty

* one empty line to ...

* remove ratio in audio concealment (ratio is now done in the summary)

* remove comment

* fix test

* add peer connections to summary report

* tests
2023-05-14 16:58:38 +00:00
Robin aaae55736f Keep measuring a call feed's volume after a stream replacement (#3361) 2023-05-13 17:54:29 +00:00
Timo 9e586ab634 Audio concealment (#3349)
* add audio concealment to stats report

* audio concealment to summary

* make ts linter happy

* format and rename

* fix and add tests

* make it prettier!

* we can make it even prettier ?!

* review

* fix tests

* pretty

* one empty line to ...

* remove ratio in audio concealment (ratio is now done in the summary)

* remove comment

* fix test
2023-05-12 16:24:27 +00:00
Richard van der Hoff 7ff44d4a50 Integration test for bootstrapCrossSigning (#3355)
* Stub implementation of bootstrapCrossSigning

* Integration test for `bootstrapCrossSigning`
2023-05-12 16:19:18 +00:00
Richard van der Hoff 63abd00ca7 Element-R: Stub out isCrossSigningReady and isSecretStorageReady (#3354)
* Stub implementation of `isCrossSigningReady`

* Stub implementation of `isSecretStorageReady`

* add tests to meet quality gate

* factor out common

* Remove accidentally-added file
2023-05-12 12:21:52 +00:00
Richard van der Hoff 40f2579158 Pass SecretStorage into RustCrypto (#3353)
* Pass SecretStorage into RustCrypto

* Update src/rust-crypto/rust-crypto.ts
2023-05-12 09:38:33 +00:00
Richard van der Hoff ceb2a57feb Rename and move crypto.IBootstrapCrossSigningOpts (#3352)
* Define `UIAuthCallback` type and use in `IBootstrapCrossSigningOpts`

* Move `IBootstrapCrossSigningOpts` to `crypto-api` and rename

* Replace uses of `IBootstrapCrossSigningOpts`

... with `BootstrapCrossSigningOpts`

* Update src/crypto-api.ts
2023-05-11 18:41:58 +00:00
Enrico Schwendig 90e8336797 Do an ICE Restart if WebRTC become disconnected (#3341)
* Do an ice restart if ICE disconnected

  - Waite two seconds after disconnected
  - Remove check for finish ICE gathering and try to add each local candidate. Avoid race in multible ICE gathering

* Add tests for failed iceConnectionState

* suppress type check in unit test

* fix pr issues
2023-05-11 14:00:26 +00:00
Andy Balaam 73ca9c9ed2 Revert "Update JS-DevTools/npm-publish action to v2 (#3336)" (#3350)
Attempting to fix failure to publish to NPM due to an "invalid token"
error https://github.com/matrix-org/matrix-js-sdk/actions/runs/4926808655/jobs/8819822367 .

This reverts commit ca9263fa64.
2023-05-10 10:32:22 +00:00
RiotRobot cc065c2772 Resetting package fields for development 2023-05-09 15:14:29 +01:00
RiotRobot 028be0fee2 Merge branch 'master' into develop 2023-05-09 15:14:24 +01:00
RiotRobot d4500da59a v25.1.0 2023-05-09 15:12:52 +01:00
RiotRobot b6aef6772e Prepare changelog for v25.1.0 2023-05-09 15:12:49 +01:00
Michael Telatynski 49696cecbd Use WeakMap in ReEmitter to help enable garbage collection (#3344) 2023-05-09 13:24:34 +00:00
renovate[bot] 83cb52c89c Lock file maintenance (#3312)
* Lock file maintenance

* Fix types

* Iterate

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-05-09 13:11:30 +00:00
renovate[bot] e82bae2c4d Update dependency @types/node to v18.16.6 (#3347)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-09 10:52:45 +00:00
renovate[bot] ee2b0204aa Update dependency @types/node to v18.16.4 (#3335)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-09 04:58:36 +00:00
renovate[bot] 1ec7670f6a Update babel monorepo (#3332)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-08 02:47:30 +00:00
Michael Telatynski 8ab2e10471 Update types to match spec (#3330) 2023-05-05 08:13:07 +00:00
renovate[bot] 8ff8685ae5 Update dependency rimraf to v5 (#3298)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-04 21:43:38 +00:00
Florian Duros f3772cdf82 Avoid upload a new fallback key at every /sync (#3338) 2023-05-03 13:10:02 +00:00
Andy Balaam ee2f1cdfd4 Accumulate receipts for the main thread and unthreaded separately. (#3339)
Fixes matrix-org/element-web#24629
2023-05-02 15:57:53 +00:00
Florian Duros 0de73a0b3e Update @matrix-org/matrix-sdk-crypto-js to ^0.1.0-alpha.8 (#3337) 2023-05-02 15:53:36 +00:00
renovate[bot] be742e811c Update dependency @types/jest to v29.5.1 (#3333)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-02 13:58:33 +00:00
renovate[bot] ca9263fa64 Update JS-DevTools/npm-publish action to v2 (#3336)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-02 13:56:42 +00:00
renovate[bot] 9f619be08d Update peter-evans/create-pull-request digest to 284f54f (#3331)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-05-02 13:40:31 +00:00
RiotRobot 7792254c12 v25.1.0-rc.1 2023-05-02 11:31:10 +01:00
RiotRobot fff41f1f27 Prepare changelog for v25.1.0-rc.1 2023-05-02 11:31:04 +01:00
renovate[bot] 3e0f9f582e Update all non-major dependencies (#3329)
* Update all non-major dependencies

* Create typedoc.json

* Update typedoc-plugin-missing-exports

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-04-28 08:41:28 +00:00
Michael Telatynski 47ba8cfa24 Correct interactive-auth types (#3328) 2023-04-28 07:52:47 +00:00
renovate[bot] 54bb4c8011 Update all non-major dependencies (#3295)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-27 23:55:40 +00:00
Kerry 71e763263e add client method to remove pusher (#3324)
* add client method to remove pusher

* remove unused type
2023-04-27 21:49:35 +00:00
Andy Balaam 2ebcda2a55 Tests for the ReceiptAccumulator (#3326) 2023-04-27 13:06:17 +00:00
Janne Mareike Koschinski e10db6f7e9 Implement MSC 3981 (#3248)
* Implement MSC 3891

* Add necessary mocks to tests

* Only set recurse parameter if supported

* fix: address review comments

* task: unify unstable prefix code between client and tests

* Add test for relations recursion

* Make prettier happier :)

* Revert "task: unify unstable prefix code between client and tests"

This reverts commit f7401e05

* Fix broken tests
2023-04-27 13:01:48 +00:00
Michael Weimann 1e041a2957 Add Room.getLastLiveEvent and Room.getLastThread (#3321)
* Add room.getLastLiveEvent and remove room.lastThread

* Deprecate Room.lastThread

* Add comments about timestamps

* Improve lastThread prop doc

* Simplify test structure
2023-04-27 11:44:27 +00:00
Florian Duros 1631d6f3c0 Fix racing between one-time-keys processing and sync (#3327) 2023-04-27 10:21:01 +00:00
Andy Balaam 3d86821258 Move receipt-specific logic into ReceiptAccumulator (#3320)
* Extract receipt accumulation logic into ReceiptAccumulator

* Rename readReceipts to unthreadedReadReceipts

* Move AccumulatedReceipt into receipt-accumulator

* Move the logic for consuming events into ReceiptAccumulator
2023-04-27 07:25:16 +00:00
Enrico Schwendig 261bc81554 Make webrtc stats collection optional (#3307)
* stats: disable stats collection if interval zero

* stats: add groupcall property for stats interval

* stats: disable collecting webrtc stats by default

* add setup methode for group call stats

* suppress lint errors in test
2023-04-27 06:56:58 +00:00
Michael Telatynski 8f701f43fb Use safeSet in recursivelyAssign (#3323) 2023-04-27 06:13:38 +00:00
Richard van der Hoff 4bdb9111dd Fix incorrect uses of IAuthData (#3322)
`IAuthData` is the response, not the request
2023-04-26 18:15:58 +00:00
Andy Balaam 93e2135223 Factor out ReceiptAccumulator (#3319)
* Performance tests for receipt accumulation

* Split ReceiptAccumulator into its own module
2023-04-26 15:07:28 +00:00
Enrico Schwendig 56cb05aac0 Adjust negotiation process for pending answer process (#3314)
* add debug statements

* adjust negotiation process

* switch tp simpler proof setLocalDescription()

* fix second race in answer pending state and renegotiation trigger

* revert simpler proof setLocalDescription because of pre SDP munging. I will refactor this in an extra PR
* add state of answer pending process on the second received answer methode as well. Now in any case of receiving answer we take care of this state.

* Clean up pending state in error case
2023-04-26 15:04:50 +00:00
renovate[bot] 38d5b202c9 Update peter-evans/create-pull-request action to v5 (#3300)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-26 12:47:31 +00:00
David Baker cfffa9c518 Fix lack of media when a user reconnects (#3318)
* Fix lack of media when a user reconnects

This fixes broken media when someone reconnects to the call after
a forced disconnect (when their old call gets replaced immediately
by a new call). We listen for changes in the call feeds and the tearing
down of the feeds for the old call caused us to remove the feed for
the new call.

Also adds the call to the calls map before it'as initialised, such that
it's the active call for the user/device when the feedsChanged event arrives,
otherwise we'll ignore the event.

* Fix tests
2023-04-26 10:00:08 +00:00
Florian Duros 73dbd709d8 Element-R: Stub findVerificationRequestDMInProgress and getStoredCrossSigningForUser (#3315)
* Add `findVerificationRequestDMInProgress` into `CryptoBackend` and stub it `rust-crypto`

* Add `getStoredCrossSigningForUser` into `CryptoBackend` and stub it `rust-crypto`
2023-04-25 17:52:20 +01:00
Michael Telatynski eef67e2c03 Deprecate MatrixClient::resolveRoomAlias (#3316) 2023-04-25 15:39:01 +00:00
RiotRobot e3498f0668 Resetting package fields for development 2023-04-25 09:44:25 +01:00
RiotRobot f04c147faa Merge branch 'master' into develop 2023-04-25 09:44:20 +01:00
RiotRobot 33bbd45f1e v25.0.0 2023-04-25 09:42:44 +01:00
RiotRobot fd91a534c7 Prepare changelog for v25.0.0 2023-04-25 09:42:41 +01:00
Richard van der Hoff c2afc357b9 Add some comments to OlmDecryption.decryptEvent (#3308) 2023-04-24 11:25:07 +00:00
Richard van der Hoff 1d3f67f2ce DeviceVerificationStatus: add new signedByOwner property (#3311) 2023-04-24 10:41:36 +00:00
Michael Telatynski 514e4f07f1 Update sonarcloud.yml 2023-04-24 08:38:14 +01:00
Florian Duros fbb1c4b2bd Element-R: wire up device lists (#3272)
* Add `getUserDeviceInfo` to `CryptoBackend` and old crypto impl

* Add `getUserDeviceInfo` WIP impl to `rust-crypto`

* Add tests for `downloadUncached`

* WIP test

* Fix typo and use `downloadDeviceToJsDevice`

* Add `getUserDeviceInfo` to `client.ts`

* Use new `Device` class instead of `IDevice`

* Add tests for `device-convertor`

* Add method description for `isInRustUserIds` in `rust-crypto.ts`

* Misc

* Fix typo

* Fix `rustDeviceToJsDevice`

* Fix comments and new one

* Review of `device.ts`

* Remove `getUserDeviceInfo` from `client.ts`

* Review of `getUserDeviceInfo` in `rust-crypto.ts`

* Fix typo in `index.ts`

* Review `device-converter.ts`

* Add documentation to `getUserDeviceInfo` in `crypto-api.ts`

* Last changes in comments
2023-04-21 14:03:02 +00:00
Florian Duros 63dea599b1 Update @matrix-org/matrix-sdk-crypto-js to 0.1.0-alpha.7 (#3309) 2023-04-20 16:37:09 +00:00
Janne Mareike Koschinski 743ba5f050 Increase log level for scheduler (#3152) 2023-04-20 12:31:58 +00:00
Michael Telatynski cb180b4195 Improve types (#3305) 2023-04-20 08:02:38 +00:00
Richard van der Hoff c805b7e29d DeviceVerificationStatus: take a param object (#3303) 2023-04-19 14:38:23 +01:00
Michael Weimann 8f6814450b Add proper deprecation doc to room fields (#3291) 2023-04-19 08:08:37 +00:00
Michael Telatynski 37e8391cde Node 20 support (#3302) 2023-04-19 09:11:32 +01:00
Enrico Schwendig 90234402a7 stats: calculate received media and ignore not added tracks (#3301)
* stats: calculate received media by ignore not added tracks

* stats: fix lint issue

---------

Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2023-04-19 06:50:27 +00:00
renovate[bot] 8ecf603d73 Update dependency eslint-plugin-jsdoc to v41 (#3297)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Kerry <kerrya@element.io>
2023-04-19 03:11:41 +00:00
renovate[bot] af243581ff Update typescript-eslint monorepo to v5.58.0 (#3296)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-18 22:10:19 +00:00
renovate[bot] 01afed9ff9 Update dawidd6/action-download-artifact digest to 246dbf4 (#3294)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-18 22:10:19 +00:00
Michael Telatynski 2687bb37fb Update tests.yml 2023-04-18 17:51:06 +01:00
Michael Telatynski 65b1a10803 Fix TimelineWindow getEvents exploding if no neigbouring timeline (#3285) 2023-04-18 12:45:58 +00:00
Michael Telatynski 9d230ef0d6 Use typedoc-plugin-versions (#3289)
* Install typedoc-plugin-versions

* Iterate

* Remove typedoc.json

* Simplify

* Simplify

* gnu vs bsd

* Iterate

* Iterate
2023-04-18 12:39:17 +00:00
Richard van der Hoff a03438f2af New CryptoApi.getDeviceVerificationStatus api (#3287)
* Element-R: implement `{get,set}TrustCrossSignedDevices`

A precursor to https://github.com/vector-im/element-web/issues/25092

* Pull out new `DeviceVerificationStatus`

Define a new base class to replace `DeviceTrustLevel`. The intention is to have
a cleaner interface which is easier to expose from the new crypto impl

* Define, and implement, a new `CryptoApi.getDeviceVerificationStatus`

This is similar to `checkDeviceTrust`, which we're deprecating, but:
 * is `async`, meaning we can implement it in Rust
 * Returns a `DeviceVerificationStatus` instead of a `DeviceTrustLevel`
 * Returns `null` rather than "not verified" if the device is unknown

* add some tests

* Export DeviceVerificationStatus as a proper class

... so that we can instantiate it in tests
2023-04-18 10:52:13 +00:00
RiotRobot c622e9260f v25.0.0-rc.1 2023-04-18 11:41:03 +01:00
RiotRobot 8bf53d6f90 Prepare changelog for v25.0.0-rc.1 2023-04-18 11:41:00 +01:00
Enrico Schwendig 8c30a3b0df Add max jitter and max packet loss (#3293)
* stats: add max jitter and max packet loss

* stats: add test for max jitter and packet loss

* stats: add build summery report tests

* stats: switch to packetsLost instead of packetsTotal
2023-04-18 10:28:59 +00:00
Richard van der Hoff c61d53eed0 Element-R: implement {get,set}TrustCrossSignedDevices (#3281)
A precursor to https://github.com/vector-im/element-web/issues/25092
2023-04-18 10:28:47 +00:00
Michael Telatynski 95f7d1d347 Add typedoc-plugin-mdn-links (#3292) 2023-04-18 10:00:37 +00:00
Michael Telatynski 72d70bb929 Improve types and their safety (#3290)
* Improve types and their safety

* Iterate
2023-04-18 07:32:40 +00:00
Kerry 4f67e59692 Annotate events with executed push rule (#3284)
* unit test paginating /notifications

* add push rule to event

* 1% more test coverage
2023-04-17 21:35:56 +00:00
Kerry d40d5c8a39 unit test paginating /notifications (#3283) 2023-04-16 22:33:52 +00:00
Tulir Asokan 87398ac555 Fix screen sharing on Firefox 113 (#3282)
`getCapabilities` exists now(?), but `setCodecPreferences` doesn't,
which means it would throw an error and fail the call.

Signed-off-by: Tulir Asokan <tulir@maunium.net>
2023-04-15 05:08:21 +00:00
Michael Weimann de3d5ead42 Add Room.threadsTimelineSets doc (#3279)
* Add Room.threadsTimelineSets doc

* Tweak type checks

* Tweak type check again
2023-04-14 09:48:28 +00:00
Richard van der Hoff 1e1b571b28 Expose ServerSideSecretStorage independently of Crypto (#3280)
There is no reason to indirect secret storage via the Crypto layer, and
exposing it directly means it will work for Element-R.

Fixes: https://github.com/vector-im/element-web/issues/24982
2023-04-13 17:21:38 +01:00
Richard van der Hoff f400a7b1b2 Remove eventNames from TypedEventEmitter (#3276) 2023-04-13 10:43:57 +00:00
Enrico Schwendig a0bcb5777f Add Jitter to exported webrtc stats (#3270)
* stats: Add Jitter stats

* Update src/webrtc/stats/trackStatsReporter.ts

Co-authored-by: Robin <robin@robin.town>

* stats: Fix typos in tests

* stats: differences between 0 and undefined in jitter val

---------

Co-authored-by: Robin <robin@robin.town>
2023-04-13 08:51:13 +00:00
Richard van der Hoff f8a625eddb OutgoingRoomKeyRequest is only a type (#3278)
Followup to #3275

Fixes a warning from webpack:

    [element-js] WARNING in ../matrix-js-sdk/src/matrix.ts 46:0-61
    [element-js] "export 'OutgoingRoomKeyRequest' was not found in './crypto/store/base'
2023-04-13 07:43:19 +00:00
Richard van der Hoff 69a2a15b95 Add missing methods to ServerSideSecretStorgage (#3277)
(and improve some doc-comments)

Seems like I missed a couple of methods when I created this interface in #3267.
2023-04-13 06:08:53 +00:00
Richard van der Hoff b9d0596dd7 Fix typedoc warnings (#3275)
There aren't that many of these, so I've gone through and fixed them, and
configured the GHA workflow to complain if any creep back in.
2023-04-12 20:30:57 +00:00
Richard van der Hoff 72af8c193c Typescript fix to AccountDataClient (#3274)
* Typescript fix to `AccountDataClient`

obviously, `getAccountDataFromServer` can return null

* Update src/secret-storage.ts

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-04-12 18:38:05 +00:00
Richard van der Hoff ed8c326856 Pass UserId into receiveSyncChanges (#3273) 2023-04-12 18:33:12 +00:00
Michael Telatynski f5bf6b1be6 Update types to match reality (#3271) 2023-04-12 17:49:16 +00:00
Richard van der Hoff 0e19f8dc69 Split SecretStorage into two parts (#3267)
* Pull `SecretStorageCallbacks` out of `ICryptoCallbacks`

* Pull the storage part of SecretStorage out to a new class

* Move SecretSharing to a separate class

* Move `ISecretRequest` into `SecretSharing.ts`

* Pull out ISecretStorage interface, and use it

* Mark old `SecretStorage` as deprecated, and rename accesses to it

* Move a `SecretStorage` unit test into its own file

* Use new `SecretStorage` in a couple of places

* add some more unit tests

* Fix test file name

... to match the unit under test

* even more tests

* Add a load of comments

* Rename classes

* Fix some broken tsdoc links

* fix broken test

* Fix compaints about superlinear regex

* just one more test
2023-04-12 16:10:43 +00:00
Richard van der Hoff 6049c0bf37 Improve output in github actions for jest tests (#3269) 2023-04-11 18:53:10 +00:00
texuf a102253f30 Update storage interface so that save() is async to match indexeddb impl (#3221)
The only implementation of this is an async function, but I can’t await it because the interface hides the return type.

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-04-11 18:52:53 +00:00
Florian Duros f71d86f005 Element-R: pass device list change notifications into rust crypto-sdk (#3254) 2023-04-11 14:42:19 +01:00
RiotRobot 70e34ffb76 Resetting package fields for development 2023-04-11 14:00:55 +01:00
RiotRobot 91aa7b26e6 Merge branch 'master' into develop 2023-04-11 14:00:49 +01:00
RiotRobot 7d45947fb3 v24.1.0 2023-04-11 13:59:08 +01:00
RiotRobot 6e174328e8 Prepare changelog for v24.1.0 2023-04-11 13:59:05 +01:00
renovate[bot] 5fb97fcce4 Lock file maintenance (#3268)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-11 09:24:40 +00:00
Hugh Nimmo-Smith 3d1a450129 Export type for return of getCapabilities() (#3266)
* Export type for return of getCapabilities()

Renamed because it clashes with ICapabilities from embedded

* Export type for return of getCapabilities()

Renamed because it clashes with ICapabilities from embedded

* Rename to Capabilities
2023-04-06 12:46:44 +00:00
Michael Telatynski a58c5aacdf Update pull_request.yaml 2023-04-06 12:53:43 +01:00
Michael Weimann d7e165a279 Retry processing potential poll events after decryption (#3246)
* Retry processing potential poll events after decryption

* Point `typedoc` at `matrix.ts`, not `index.ts` (#3239)

This gets rid of the rather pointless "default" module in the generated docs.

* Split up, rename, and move `ISecretStorageKeyInfo` (#3242)

* Move SecretStorageKeyInfo interfaces out to a new module

* Replace usages of ISecretStorageKeyInfo with SecretStorageKeyDescription

* Skip clear text non-poll events

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-04-06 09:59:39 +00:00
renovate[bot] a57ee803f1 Update dependency typescript to v5 (#3262)
* Update dependency typescript to v5

* Update dependency typescript to v5

* Iterate

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-04-06 09:54:02 +00:00
Enrico Schwendig 170a52b09f Measure whether we receive media and add the mute state as an exception (#3249)
* stats: add summery stats reporter

* stats: export summery stats reports

* stats: fix typo of event name

* stats: check promise condition for node 16 test linter

* stats: remove weak test to figure out memory leak

* stats: remove second weak test

* stats: add starting processing test

* stats: fix tests

* stats: fix typo in group call

* stats: fix stats report gathering test

* stats: reactivate promise merge

* stats: add track counter and track mute counter in summary stats

* stats: add summery calculation

* stats: fix PR issues

* stats: adjust summery reporter for inbound and mute state

* stats: check async state

* stats: switch from an `Or` to `And` condition for entire received media value

* stats: Add property description

---------

Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2023-04-06 09:32:09 +00:00
renovate[bot] 2be5889d18 Update peter-evans/create-pull-request digest to 38e0b6e (#3257)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-06 09:20:40 +00:00
Michael Telatynski ca6b574bee Update upgrade_dependencies.yml (#3264) 2023-04-06 07:51:58 +00:00
Michael Telatynski 57b0172a2d Update pull_request.yaml 2023-04-06 09:17:30 +01:00
Michael Telatynski 53260ee25d Update pull_request.yaml (#3255) 2023-04-06 07:45:44 +00:00
renovate[bot] 964281322f Update all non-major dependencies (#3259)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-05 18:38:55 +00:00
David Baker 7c3f483396 Fix another export type (#3265)
Another case where we were importing types as normal imports which
confuses bundlers.
2023-04-05 17:14:14 +00:00
Hugh Nimmo-Smith 59784aa9fe Support for MSC3882 revision 1 (#3228)
* Support for MSC3882 revision 1

* Additional comments

* Revised field names

* Use UnstableValue for capability
2023-04-05 16:12:29 +00:00
Florian Duros 72a2b6d571 Use processKeyCounts in sliding sync (#3253) 2023-04-05 15:39:46 +00:00
renovate[bot] 5854af0eae Update definitelyTyped (#3260)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-05 15:39:24 +00:00
renovate[bot] acd3d3a804 Update peaceiris/actions-gh-pages digest to 373f7f2 (#3256)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-05 15:23:40 +00:00
renovate[bot] 1b8c04a430 Update babel monorepo (#3258)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-05 15:12:15 +00:00
renovate[bot] 378b73f8b8 Update typescript-eslint monorepo to v5.57.0 (#3261)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-04-05 15:10:56 +00:00
Michael Telatynski c482a6ab15 Tidy up merge queue automation (#3252)
* Tidy up merge queue automation

* Iterate

* Iterate

* Iterate
2023-04-05 13:48:57 +00:00
Florian Duros 2daa429b77 Improve #3215 implementation (#3226)
* Improve key upload request

* Add fallback keys check

* Review fixes

* Add comments about sliding sync usage of `processKeyCounts`

* Review fixes

* Better wording
2023-04-05 12:35:10 +00:00
Richard van der Hoff 6ebbc15359 Move SecretStorage-related interfaces out to new module (#3244)
* Remove redundant `IAccountDataClient.getAccountData`

This is never called, so we may as well get rid of it

* Move a few more interfaces into `secret-storage.ts`

* Use interfaces from `secret-storage`

* Move IAccountDataClient to secret-storage

* Use `AccountDataClient` from `secret-storage`

* move SECRET_STORAGE_ALGORITHM_V1_AES to secret-storage

* Use `SECRET_STORAGE_ALGORITHM_V1_AES` from `secret-storage`

* Add a test case for the quality gate

* Update src/secret-storage.ts
2023-04-05 11:42:15 +00:00
Richard van der Hoff 9a840d484c Element-R: handle events which arrive before their keys (#3230)
* minor cleanups to the crypto tests

mostly, this is about using `testUtils.awaitDecryption` rather than custom
code. Some other cleanups too.

* Keep a record of events which are missing their keys

* Retry event decryption when we receive megolm keys
2023-04-05 10:00:08 +00:00
David Baker e89467c9fb Add an event emitted when a Call creates a PeerConnection (#3251)
For apps that need acces to the per connection as soon as it's created
for debugging etc.
2023-04-05 08:32:50 +00:00
Enrico Schwendig 0b396c005c indicator whether call members send media. (#3241)
* stats: add summery stats reporter

* stats: export summery stats reports

* stats: fix typo of event name

* stats: check promise condition for node 16 test linter

* stats: remove weak test to figure out memory leak

* stats: remove second weak test

* stats: add starting processing test

* stats: fix tests

* stats: fix typo in group call

* stats: fix stats report gathering test

* stats: reactivate promise merge

* stats: fix PR issues

---------

Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2023-04-05 06:48:12 +00:00
David Baker d05313f95e Switch some imports to type imports (#3250)
Having these as regular imports confuses Vite for some reason.
2023-04-04 15:31:16 +00:00
RiotRobot 3f97853011 v24.1.0-rc.1 2023-04-04 11:53:22 +01:00
RiotRobot 2a5c4b1edf Prepare changelog for v24.1.0-rc.1 2023-04-04 11:53:18 +01:00
texuf 65a3c6707c indexddb-local-backend - return the current sync to database promise if a sync is in flight (#3222)
I’m trying to shutdown my matrix clients while using an indexdb, but awaiting the save() function has no effect because a previous sync was in flight. I ended up deleting the matrix client while the save was in flight and I saw a crash.

signed-off-by Austin Ellis <austin@hntlabs.com>

fix linter
2023-04-04 09:36:44 +00:00
Enrico Schwendig 942477f0bf screen share: remove set stream (#3238)
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2023-04-04 08:53:32 +00:00
Michael Telatynski 1770b3131a Skip sonarcloud & coverage in merge_queue (#3247) 2023-04-04 08:46:41 +01:00
Richard van der Hoff 41d3ffdab9 Split up, rename, and move ISecretStorageKeyInfo (#3242)
* Move SecretStorageKeyInfo interfaces out to a new module

* Replace usages of ISecretStorageKeyInfo with SecretStorageKeyDescription
2023-04-03 10:11:03 +00:00
Richard van der Hoff 78aa6cb62b Point typedoc at matrix.ts, not index.ts (#3239)
This gets rid of the rather pointless "default" module in the generated docs.
2023-04-03 09:55:11 +00:00
Michael Telatynski b56b8040e6 Use frozen lockfile instead of pure lockfile on yarn install (#3245) 2023-03-31 14:49:49 +00:00
Andy Balaam d1cf98b177 Allow via_servers property in findPredecessor (update to MSC3946) (#3240) 2023-03-31 12:51:10 +00:00
Michael Telatynski 5fc6b3ed17 Fire closed event when IndexedDB closes unexpectedly (#3218)
* Fire `closed` event when IndexedDB closes unexpectedly

* Add test

* Add tests

* Add test

* Add test

* Add test coverage
2023-03-31 08:46:11 +00:00
renovate[bot] 6e41533fed Update jest monorepo to v29.5.0 (#3204)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-31 07:52:07 +00:00
David Baker bc76532bd5 Refactor the way group calls hang up (#3234)
* Refactor how group call end calls

We previously used disposeCall to terminate the call which meant that
sometimes a call would never get a hangup event. This changes it so
that we always end a call by calling hangup, then do the cleanup
when the hangup event arrives, so the cleanup is the same whether
we hang up or the other side does.

* Some fixes for failing & hanging tests

* Add type for the call map
2023-03-30 15:57:47 +00:00
Enrico Schwendig 62f1dd79bc Add webrtc stats in full mesh calls (#3232)
* stats: merge stats classes in this branch

* stats: merge call object

* stats: merge export metric events

* stats: fix code style changes

* stats: add missing stats value formatter

* stats: add missing methode to call mock

* stats: add stats for callee

* stats: stop sending stats if call finish

* stats: rename StatsCollector to StatsReportGatherer
2023-03-30 15:17:59 +00:00
David Baker fd3f53e814 Merge pull request #3237 from matrix-org/dbkr/call_events_pass_call_2
Re-apply "Add the call object to Call events"
2023-03-30 10:22:17 +01:00
David Baker 798ac7b94c Revert "Revert "Add the call object to Call events"" 2023-03-29 15:32:25 +01:00
Richard van der Hoff eb0c0f7b93 Element-R: Add support for /discardsession (#3209)
Fixes https://github.com/vector-im/element-web/issues/24431
2023-03-29 13:26:02 +00:00
David Baker f03293f53d Merge pull request #3236 from matrix-org/revert-3229-dbkr/call_events_pass_call
Revert "Add the call object to Call events"
2023-03-29 14:41:59 +01:00
David Baker 7d062387b7 Revert "Add the call object to Call events" 2023-03-29 14:27:49 +01:00
Andy Balaam 9acf3b18ca Update changelog for v24.0.0 now the security issue is public (#3235) 2023-03-29 13:06:32 +00:00
David Baker b41d067c94 Merge pull request #3229 from matrix-org/dbkr/call_events_pass_call
Add the call object to Call events
2023-03-29 12:26:34 +01:00
David Baker c8503b3120 Run prettier on groupCall.ts (#3233) 2023-03-28 15:35:00 +00:00
David Baker da03c3b529 Fix an issue where participants could potentially view video without being displayed themselves
Fix from @robintown, manual merge due to Github having issues.
2023-03-28 15:20:34 +01:00
Robin d48b19e052 Handle group call redaction (#3231)
Redacted group call events should be interpreted as terminated calls.
2023-03-28 13:07:44 +00:00
RiotRobot 6861c67f56 Merge branch 'master' into develop 2023-03-28 14:15:09 +01:00
RiotRobot c87048bd9f v24.0.0 2023-03-28 14:10:53 +01:00
RiotRobot 02269f33b7 Prepare changelog for v24.0.0 2023-03-28 14:10:50 +01:00
Michael Weimann 7f46ae7b97 Further changes for v24.0.0 2023-03-28 14:05:24 +01:00
David Baker 2ab3566f95 Add comment on confusing exception handler I've failed to add a test for 2023-03-28 13:47:22 +01:00
Michael Weimann 9a504af18e Changes for v24.0.0 2023-03-28 11:22:02 +01:00
David Baker 8b50986906 Add test for incoming data channel 2023-03-28 09:30:17 +01:00
David Baker f9a222ecea Mock out media getter after setting up the vocie call
Otherwise we won't get far enough to test the right part
2023-03-27 16:18:00 +01:00
David Baker 5b5a3d8b5e Test failed call upgrade 2023-03-27 15:44:56 +01:00
David Baker 037cbdd214 Basic test for call replace 2023-03-27 14:33:58 +01:00
David Baker 0349411e6d Rename group call error event
So it doesn't clash with the call error event
2023-03-24 14:26:03 +00:00
David Baker d7b75e4b9e Add the call object to Call events
As explained in the comment. I've added it to the end so this should
be completely backwards compatible (although it would be much nicer
if it were the first arg, probably).
2023-03-24 14:09:22 +00:00
Richard van der Hoff 254f043ab0 Enable the prepareToEncrypt test for Element-R (#3225)
This Just Works, so I don't know why I didn't enable the test sooner.
2023-03-24 11:55:17 +00:00
J. Ryan Stinnett 5f3e115545 Stop doing O(n^2) work to find event's home (#3227)
* Stop doing O(n^2) work to find event's home

In certain rooms (e.g. with many state changes hidden via user preferences), the
events array presented to `eventShouldLiveIn` may contain 100s of events. As
part of its various checks, `eventShouldLiveIn` would get an event's associated
ID (reply / relation / redaction parent). It would then use `events.find` to
search the entire (possibly large) `events` array to look for the parent. (This
by itself seems sub-optimal and should probably change to use a map.)

For many events in a room, there is no associated ID. Unfortunately,
`eventShouldLiveIn` did not check whether the associated ID actually exists
before running off to search all of `events`, resulting in O(n^2) work.

This changes `eventShouldLiveIn` to first check that there is an associated ID
before proceeding with its (slow) search. For some rooms, this change
drastically improves performance from ~100% CPU usage to nearly idle.

Signed-off-by: J. Ryan Stinnett <jryans@gmail.com>

* Add type to `parentEvent`

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: J. Ryan Stinnett <jryans@gmail.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2023-03-23 19:02:55 +00:00
Patrick Cloke fc55c4c72a Implement MSC3952: intentional mentions (#3092)
* Add experimental push rules.

* Update for changes to MSC3952: Use event_property_is and event_property_contains.

* Revert custom user/room mention conditions.

* Skip legacy rule processing if mentions exist.

* Add client option for intentional mentions.

* Fix tests.

* Test leagcy behavior with intentional mentions.

* Handle simple review comments.
2023-03-22 20:22:34 +00:00
Florian Duros f795577e14 Send one time key count and unused fallback keys for rust-crypto (#3215)
* Send one time key count and unused fallback keys for rust-crypto

* Add tests

* Remove useless type in promise return

* Add test for one time key upload

* Fix rust-crypto.spec.ts tests

* Remove unneeded code in test

* Add key upload request test

* Fix tests
2023-03-22 10:19:04 +00:00
Eric Eastwood f12cee984a Export TimestampToEventResponse to use in matrix-react-sdk tests (#3223)
* Export ITimestampToEventResponse to use in matrix-react-sdk tests

Part of https://github.com/matrix-org/matrix-react-sdk/pull/10405

* Remove I from interface

As suggested by @weeman1337,
https://github.com/matrix-org/matrix-js-sdk/pull/3223#pullrequestreview-1350612347

See code style guide, https://github.com/vector-im/element-web/blob/50f8be4a623d2280a72920eb1679a4754961f807/code_style.md#typescript--javascript-typescript-javascript

> Interface names should not be marked with an uppercase `I`.
2023-03-21 17:10:28 +00:00
Richard van der Hoff c3b4572841 Add a new test for event encryption, which works with rust (#3203)
* crypto.spec.ts: factor out `expactAliceKeyClaim` utility

* Add a new test for event encryption

... one that actually works on the rust SDK.

* Bump matrix-sdk-crypto-js version

... to pick up recent fixes to race conditions
2023-03-21 16:24:57 +00:00
David Baker 40fe159c10 Merge pull request #3219 from robintown/matrix-widget-api
Update matrix-widget-api
2023-03-21 10:59:50 +00:00
Robin Townsend ddecc87947 Update matrix-widget-api 2023-03-20 10:28:46 -04:00
David Baker 23837266fc Merge pull request #3217 from matrix-org/dbkr/type_sendvoipevent
Add a type to the structure used by the SendVoipEvent event
2023-03-16 10:52:09 +00:00
David Baker 3c9ca8c373 Add a type to the structure used by the SendVoipEvent event 2023-03-15 16:07:10 +00:00
RiotRobot 7f2a4c2568 Resetting package fields for development 2023-03-15 12:41:24 +00:00
RiotRobot 2ad647a73c Merge branch 'master' into develop 2023-03-15 12:41:18 +00:00
RiotRobot 26663e67fd v23.5.0 2023-03-15 12:39:41 +00:00
RiotRobot 0cfc67c679 Prepare changelog for v23.5.0 2023-03-15 12:39:38 +00:00
David Baker 7faba5c2f0 Merge pull request #3213 from matrix-org/dbkr/fix_starting_with_video_muted
Fix bug where video would not unmute if it started muted
2023-03-14 11:18:39 +00:00
Michael Telatynski 1d9250b277 Fix CallOpts types (#3214) 2023-03-14 09:53:59 +00:00
David Baker 08054c1d6d Fix bug where video would not unmute if it started muted
Fixes https://github.com/vector-im/element-call/issues/925
2023-03-13 17:04:43 +00:00
Richard van der Hoff 333872e878 Pull out a public CryptoApi (#3211)
... so that we don't have to implement annoying shims in `MatrixClient`
2023-03-13 12:02:49 +00:00
Janne Mareike Koschinski 913cd257f4 Pin versions of third-party github actions (#3208) 2023-03-10 12:56:23 +00:00
Richard van der Hoff 69f7789c40 Merge pull request #3202 from matrix-org/rav/element-r/encryption_fixes
Fixes to event encryption in the Rust Crypto implementation
2023-03-10 11:00:18 +00:00
renovate[bot] e79ef1f33a Update typescript-eslint monorepo to v5.54.0 (#3198)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Kerry <kerrya@element.io>
2023-03-10 09:06:58 +00:00
renovate[bot] fb8f61a5ec Update dependency eslint-plugin-unicorn to v46 (#3199)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-09 21:28:20 +00:00
Kerry 9b1f2a1d11 adjust beacon model to make beaconInfo definitely assigned in constructor (#3201)
* adjust beacon model to make beaconInfo definitely assigned

* fix

* improvement from PR
2023-03-09 21:03:42 +00:00
Richard van der Hoff 686216fb75 Merge branch 'develop' into rav/element-r/encryption_fixes 2023-03-09 13:34:17 +00:00
Richard van der Hoff f4b83e1a27 Stop a failed /keys/claim request getting stuck
Putting the new request inside a `finally` block meant we would never actually
transition the promise chain from failure to success. Sticking a no-op `catch`
in the chain makes sure that we can recover from an error.
2023-03-09 10:54:50 +00:00
Richard van der Hoff 97f21b6635 Send the outgoing m.room_key messages returned by shareRoomKey
I forgot this in https://github.com/matrix-org/matrix-js-sdk/pull/3122 :(.

To be honest, I'm not sure how it ever worked.
2023-03-09 10:50:49 +00:00
Michael Telatynski 87641a6803 Improve processBeaconEvents hotpath (#3200)
* Attempt at improving beacons hotpath

* Iterate and fix tests
2023-03-09 09:24:57 +00:00
renovate[bot] 7e4331172a chore(deps): update all non-major dependencies (#3197)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-08 15:33:44 +00:00
renovate[bot] a976080d1b chore(deps): update dependency @types/node to v18.14.6 (#3196)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-08 08:16:55 +00:00
Patrick Cloke bcf3bba44e Implement MSC3966: a push rule condition to check if an array contains a value (#3180)
* Support MSC3966 to match values in an array in push rule conditions.

* Update to stable identifiers.

* Appease the linter.
2023-03-07 16:36:06 +00:00
Michael Telatynski 54ac36d424 Revert "Add GHA for requiring all reviews to be dismissed or approving before merging (#2391)" (#3195)
This reverts commit e84c90dbbc.
2023-03-07 15:21:20 +00:00
Michael Telatynski e84c90dbbc Add GHA for requiring all reviews to be dismissed or approving before merging (#2391)
* Add GHA for requiring all reviews to be dismissed or approving before merging

* Attempt again

* Try try try again

* stash

* Stash

* Dummy

* Fix indentation

* Iterate

* Tweak

* Iterate

* toJSON

* Iterate

* Iterate

* Fix

* typo

* Permissions

* tidy

* Update pending_reviews.yml

* delint
2023-03-07 14:23:56 +00:00
Michael Telatynski 4424438658 Fix jest/no-conditional-expect lint and enable it (#3194) 2023-03-07 12:44:03 +00:00
RiotRobot 13d95c8219 v23.5.0-rc.1 2023-03-07 11:19:25 +00:00
RiotRobot e119dc4e89 Prepare changelog for v23.5.0-rc.1 2023-03-07 11:19:22 +00:00
Patrick Cloke b4cdc5a923 Implement MSC3758: a push rule condition to match event properties exactly (#3179)
* Add some comments.

* Support MSC3758 to exactly match values in push rule conditions.

* Update to stable prefix.
2023-03-06 14:52:43 +00:00
Andy Balaam a82e22b5de Remove items incorrectly included in changelog for 23.4.0 (#3190) 2023-03-03 13:30:38 +00:00
Patrick Cloke c894d09d8c Room call is an underride, not an override. (#3185) 2023-03-03 13:30:28 +00:00
Richard van der Hoff 585ce07260 Stub out the rust crypto implementation for browserify (#3187)
Fixes #3182.
2023-03-03 10:18:45 +00:00
Enrico Schwendig 8cbbdaa239 groupCall: make no media call param optional (#3186)
- ensure group call backwards-compatibility and move `allowCallWithoutVideoAndAudio`to the end of the `CroupCall` constructor
2023-03-02 18:55:09 +00:00
Damir Jelić cd526a254d Stop requesting room keys from other users (#2982)
* Refactor the room key handling method

* Fix the forwarded room key test to use the same user ids.

We have some tests that check if receiving a forwarded room key works.
These claim to use the same user id, but in fact they change the user id
in the last moment before the event is passed into the client.

Let's change this so we're always operating with the same user id.

* Stop requesting room keys from other users

We never accept such room keys, so there isn't a point in requesting
them.

* fixup! Refactor the room key handling method

* Apply suggestions from code review

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* fixup! Refactor the room key handling method

* fixup! Apply suggestions from code review

* fixup! Refactor the room key handling method

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-03-02 16:38:24 +00:00
Enrico Schwendig e782a2afa3 Enable group calls without video and audio track by configuration of MatrixClient (#3162)
* groupCall: add configuration param to allow no audio and no camera

* groupCall: enable datachannel to do no media group calls

* groupCall: changed call no media property as object property

* groupCall: fix existing unit tests

* groupCall: remove not needed flag

* groupCall: rename property to allow no media calls

* groupCall: mute unmute even without device

* groupCall: switch to promise callbacks

* groupCall: switch to try catch

* test: filter dummy code from coverage

* test: extend media mute tests

* groupCall: move permission check to device handler

* mediaHandler: add error in log statement
2023-03-02 16:35:52 +00:00
Hugh Nimmo-Smith 565339b1fd Remove experimental support for MSC3903 v1 (#3184)
* v2 of MSC3903 implementation

This is a deliberate breaking change on an unstable feature.

* Reinstate v1 support to make this a non-breaking change

Deprecates several experimental types

* Remove MSC3903 v1 support

This is a breaking change in code marked unstable/experimental

Revert "Reinstate v1 support to make this a non-breaking change"

This reverts commit 89773458b9a1e5f332938e5574f35b16d204d75d.
2023-03-02 16:34:22 +00:00
Hugh Nimmo-Smith 493203050a Support for v2 of MSC3903 (#3155)
* v2 of MSC3903 implementation

This is a deliberate breaking change on an unstable feature.

* Test correct protocol version

* Fix up test

* v2 of MSC3903 implementation

This is a deliberate breaking change on an unstable feature.

* Test correct protocol version

* Fix up test

* Reinstate v1 support to make this a non-breaking change

Deprecates several experimental types
2023-03-02 13:15:17 +00:00
renovate[bot] 41782c4593 Update dependency eslint-plugin-jsdoc to v40 (#3173)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-02 07:23:55 +00:00
renovate[bot] 86256a4e74 Update definitelyTyped (#3170)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-03-02 07:23:42 +00:00
Kerry 933a0c9909 Polls push rules (#3181)
* add poll push rule ids

* add getPushRuleAndKindById method to pushprocessor
2023-03-01 20:30:40 +00:00
Patrick Cloke c8a4d9b88a Implement MSC3873 to handle escaped dots in push rule keys (#3134)
* Add comments.

* Implment MSC3873 to handle escaped dots in keys.

* Add some comments about tests.

* Clarify spec behavior.

* Fix typo.

* Don't manually iterate string.

* Clean-up tests.

* Simplify tests.

* Add more tests & fix bug with empty parts.

* Add more edge cases.

* Add a regular expression solution.

This is ~80% slower than the basic split(".").

* Split on a simpler regular expression.

This is ~50% slower than a simple split(".").

* Remove redundant case in regex.

* Enable sticky regex.

* Rollback use of regex.

* Cache values in the PushProcessor.

* Use more each in tests.

* Pre-calculate the key parts instead of caching them.

* Fix typo.

* Switch back to external cache, but clean out obsolete cached values.

* Remove obsolete property.

* Remove more obsolete properties.
2023-03-01 12:23:40 +00:00
RiotRobot 437128d11b Resetting package fields for development 2023-02-28 10:37:23 +00:00
RiotRobot c18d09fd22 Merge branch 'master' into develop 2023-02-28 10:36:51 +00:00
RiotRobot 2a5e5e6a59 v23.4.0 2023-02-28 10:25:34 +00:00
RiotRobot 68e354752b Prepare changelog for v23.4.0 2023-02-28 10:25:31 +00:00
Michael Telatyński d80b7499fd Fix spec compliance issue around encrypted m.relates_to (#3178)
* Fix spec compliance issue around encrypted `m.relates_to`

* Add test
2023-02-27 22:12:45 +00:00
Janne Mareike Koschinski 9c8093eb3e Fix reactions in threads sometimes causing stuck notifications (#3146)
* Associate event with thread before adding it to the thread timeline

* Make sure events can be added to thread correctly

* Write initial test case

* Add additional comment for why the code had to be reordered
2023-02-24 13:12:06 +00:00
renovate[bot] aec1c11037 Update all non-major dependencies (#3171)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-24 12:17:19 +00:00
renovate[bot] e2e9986059 Update babel monorepo to v7.21.0 (#3177)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-23 16:43:01 +00:00
Michael Telatynski d70ffdbc02 Improve types (#3175)
* Improve types

* Add test
2023-02-22 17:39:37 +00:00
RiotRobot 0f1f1db3d2 v23.4.0-rc.2 2023-02-22 11:07:38 +00:00
RiotRobot 77b91a45cb Prepare changelog for v23.4.0-rc.2 2023-02-22 11:07:35 +00:00
RiotRobot fe6add9396 Merge branch 'develop' into staging 2023-02-22 10:59:21 +00:00
renovate[bot] 21cc9c3d8a Update jest monorepo to v29.4.3 (#3169)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-22 10:23:29 +00:00
renovate[bot] 2d59c4647d Update typescript-eslint monorepo to v5.52.0 (#3172)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-22 10:19:53 +00:00
Florian Duros 1f0c6a6dc9 Add easy way to determine if the decryption failure is due to "DecryptionError: The sender has disabled encrypting to unverified devices." (#3167)
* Add isEncryptedDisabledForUnverifiedDevices in event.ts

* Add Tests

* Add isEncryptedDisabledForUnverifiedDevices properties to event

* Use WITHHELD_MESSAGES instead of hardcoded string

* Use getter instead of function

* Add documentation
2023-02-21 16:13:43 +00:00
RiotRobot c9b502fb0e v23.4.0-rc.1 2023-02-21 11:56:15 +00:00
RiotRobot 330fbaccfc Prepare changelog for v23.4.0-rc.1 2023-02-21 11:56:12 +00:00
Michael Telatynski 937f370655 Run matrix-react-sdk tests on merge queue (#3161)
* First attempt at merge queues for downstream testing

* Debug

* delint

* Fix typo

* Test

* Iterate

* Fix checkout

* rerun

* experiment

* Iterate

* Iterate

* iterate

* Iterate

* Finalise

* Disable coverage for downstream tests

* Update tests.yml

* Apply merge_queue trigger to other CI

* delint

* delint

* Add exception
2023-02-21 11:09:23 +00:00
Kerry a8ad3ed26d Polls: expose end event id on poll model (#3160) 2023-02-20 10:30:19 +00:00
Michael Telatynski decac58a18 Better type guard parseTopicContent (#3165) 2023-02-20 10:29:33 +00:00
Kerry 1a91ba59a6 Polls: count undecryptable poll relations (#3163) 2023-02-20 10:10:38 +00:00
Michael Telatynski 89df43a975 Fix predecessor types, nowhere does the spec say it can be null (#3159)
* Fix predecessor types, nowhere does the spec say it can be `null`

* Iterate

* Update comment

* update test
2023-02-16 09:38:36 +00:00
Michael Telatynski ad98706db4 Iterate types (#3156) 2023-02-15 13:38:41 +00:00
Will Hunt 195d1730bd Fix notification counts for encrypted rooms with ignored event rules (#3130)
* Validate vars early

* Split out unread  counts for total and highlight to different logic blocks

* Add tests for ignoring non notifying events

* Fix possibly incorrect tests?

* lint fix

* Refactor currentTotalCount

* Track Total locally too

* Lots of total count assumptions and comments

* Adjust for threading too

* Fixup tests

* a word

* lint fix
2023-02-15 11:25:13 +00:00
Richard van der Hoff db4bd907f8 Switch crypto.spec.ts away from TestClient and matrix-mock-request. (#3142)
I became sufficiently annoyed with matrix-mock-request that I decided to replace it with fetch-mock, which is what we use in matrix-react-sdk and is generally more powerful, easier to use, and actually maintained.

Unfortunately, we have a TestClient utility which is widely used and quite tightly integrated with matrix-mock-request. It wasn't going to be possible to change TestClient without changing all the tests that use it.

I also don't find TestClient particularly easy to use - it does a lot of stuff which I'm not convinced ought to be done for every single test.

So... I've introduced a couple of new classes (SyncResponder, E2EKeyReceiver) which do some of the useful bits of TestClient, but in a more granular way, and have switched crypto.spec.ts over so that rather than instantiating a TestClient for each test, it creates a MatrixClient directly and intercepts the endpoints necessary.
2023-02-15 10:39:24 +00:00
Kerry cdd7dbbb2b decrypt poll relations before processing (#3148) 2023-02-14 21:49:52 +00:00
RiotRobot 108f157324 Resetting package fields for development 2023-02-14 10:23:07 +00:00
RiotRobot 8da39ec8f4 Merge branch 'master' into develop 2023-02-14 10:23:02 +00:00
RiotRobot 182534288c v23.3.0 2023-02-14 10:21:24 +00:00
RiotRobot f81b7e5e6f Prepare changelog for v23.3.0 2023-02-14 10:21:21 +00:00
ElementRobot 6dda9e532d Include 'browser' in list of adjusted properties in release.sh (#3149) (#3151)
(cherry picked from commit 5e17626fe0)

Co-authored-by: Andy Balaam <andy.balaam@matrix.org>
2023-02-14 09:58:17 +00:00
Andy Balaam 5e17626fe0 Include 'browser' in list of adjusted properties in release.sh (#3149) 2023-02-14 09:50:55 +00:00
David Baker abc9c9dcb0 Merge pull request #3147 from matrix-org/dbkr/stop_ice_timer_on_terminate
Stop the ICE disconnected timer on call terminate
2023-02-13 17:35:45 +01:00
David Baker f346fcb056 Stop the ICE disconnected timer on call terminate
It just wasn't getting stopped, so if the call ended while ICE was
disconnected, we'd get confusing error messages after the call ended.
2023-02-13 16:15:57 +00:00
Eric Eastwood c67325ba07 Add matrix-org/jest linting (#2973) 2023-02-10 12:05:40 +01:00
renovate[bot] a063ae8ce7 Update jest monorepo to v29.4.1 (#3133)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-09 15:44:23 +00:00
renovate[bot] f9e5535492 Update typescript-eslint monorepo to v5.50.0 (#3136)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-09 16:29:03 +01:00
renovate[bot] 015d9c5c4f Update dependency @types/node to v18.11.19 (#3137)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-09 16:28:22 +01:00
Germain b6d40078d9 Clear notifications when we can infer read status from receipts (#3139) 2023-02-09 10:18:18 +00:00
David Baker b8a8f4850a Merge pull request #3123 from matrix-org/SimonBrandner/task/logging
Improve WebRTC logging
2023-02-08 17:10:40 +00:00
Šimon Brandner 1cc23d789c Add new tests to groupCall
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2023-02-08 17:24:15 +01:00
Janne Mareike Koschinski 5cf0bb46a4 Messages sent out of order after one message fails (#3131)
* Instead of skipping, bail out by clearing queue
* Allow additional status transition for events from QUEUED to NOT_SENT
2023-02-08 13:23:30 +01:00
renovate[bot] 16672b3d0c Update all non-major dependencies (#3132)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-02-07 17:36:38 +00:00
RiotRobot f61db81961 v23.3.0-rc.1 2023-02-07 12:00:46 +00:00
RiotRobot e2a694115f Prepare changelog for v23.3.0-rc.1 2023-02-07 12:00:44 +00:00
Michael Telatynski 71cf812d24 Add @typescript-eslint/no-base-to-string (#3129) 2023-02-07 10:08:03 +00:00
Richard van der Hoff 8a3d7d5671 Element-R: log outgoing HTTP requests (#3127)
otherwise it's rather hard to see them, at least in Firefox.
2023-02-06 10:50:05 +00:00
Richard van der Hoff 2a363598dd Element-R: fix a bug which prevented encryption working after a reload (#3126)
Upgrade matrix-sdk-crypto-js, to pick up
https://github.com/matrix-org/matrix-rust-sdk/pull/1429
2023-02-03 16:16:32 +00:00
Richard van der Hoff 05bf6428bc Element-R: implement encryption of outgoing events (#3122)
This PR wires up the Rust-SDK into the event encryption path
2023-02-03 15:58:50 +00:00
Michael Telatynski e492a44dde Update typescript bits to aid matrix-react-sdk achieve noImplicitAny (#3079) 2023-02-03 14:01:53 +00:00
Richard van der Hoff 44d2e47f96 Fix invite processing on Element-R (#3121)
Currently, whenever we receive an invite on element R, it crashes the sync
loop. A quick fix to make it not do that.
2023-02-03 10:56:24 +00:00
Šimon Brandner 31459a5d63 Improve logging
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2023-02-03 11:40:48 +01:00
Richard van der Hoff 8f5db463e7 Element R: Fix obscure errors when we fail to decrypt to-device events (#3117)
Previously, if we failed to decrypt a to-device event, we would raise an
"expected a string" error when we later tried to decrypt it as a room
event. This at least makes the error clearer.
2023-02-02 08:28:44 +00:00
Kerry 4e8affafcc Poll model - page /relations results (#3073)
* first cut poll model

* process incoming poll relations

* allow alt event types in relations model

* allow alt event types in relations model

* remove unneccesary checks on remove relation

* comment

* Revert "allow alt event types in relations model"

This reverts commit e578d84464403d4a15ee8a7cf3ac643f4fb86d69.

* Revert "Revert "allow alt event types in relations model""

This reverts commit 515db7a8bc2df5a1c619a37c86e17ccbe287ba7a.

* basic handling for new poll relations

* tests

* test room.processPollEvents

* join processBeaconEvents and poll events in client

* tidy and set 23 copyrights

* use rooms instance of matrixClient

* tidy

* more copyright

* simplify processPollEvent code

* throw when poll start event has no roomId

* updates for events-sdk move

* more type changes for events-sdk changes

* page poll relation results

* validate poll end event senders

* reformatted copyright

* undo more comment reformatting

* test paging

* use correct pollstartevent type

* emit after updating _isFetchingResponses state

* make rootEvent public readonly

* fix poll end validation logic to allow poll creator to end poll regardless of redaction
2023-02-01 20:44:40 +00:00
Kerry 2800681bb1 Poll model - validate end events (#3072)
* first cut poll model

* process incoming poll relations

* allow alt event types in relations model

* allow alt event types in relations model

* remove unneccesary checks on remove relation

* comment

* Revert "allow alt event types in relations model"

This reverts commit e578d84464403d4a15ee8a7cf3ac643f4fb86d69.

* Revert "Revert "allow alt event types in relations model""

This reverts commit 515db7a8bc2df5a1c619a37c86e17ccbe287ba7a.

* basic handling for new poll relations

* tests

* test room.processPollEvents

* join processBeaconEvents and poll events in client

* tidy and set 23 copyrights

* use rooms instance of matrixClient

* tidy

* more copyright

* simplify processPollEvent code

* throw when poll start event has no roomId

* updates for events-sdk move

* more type changes for events-sdk changes

* validate poll end event senders

* reformatted copyright

* undo more comment reformatting

* fix poll end validation logic to allow poll creator to end poll regardless of redaction

* Update src/models/poll.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* correct creator == sender validationin poll end

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-02-01 20:32:37 +00:00
Andy Balaam b2a9e6f12f Handle optional last_known_event_id property in m.predecessor (#3119) 2023-02-01 14:31:07 +00:00
Andy Balaam fbd2c97f87 Move the logic of roomPredecessor into the RoomState class (#3114)
* Move the logic of roomPredecessor into the RoomState class

* Fix review comments
2023-02-01 10:44:32 +00:00
Germain 6c6304a620 Cleanup pre MSC3773 thread unread notif logic (#3115) 2023-01-31 16:59:13 +00:00
Richard van der Hoff 0c1d5f6b25 Element-R: implement remaining OutgoingMessage request types (#3083)
This is a follow-up to #3019: it implements the remaining two types of message types, now that rust SDK has sensibly-shaped types for them.
2023-01-31 15:44:14 +00:00
RiotRobot 1c26dc0233 Resetting package fields for development 2023-01-31 10:47:39 +00:00
RiotRobot a163a202e7 Merge branch 'master' into develop 2023-01-31 10:47:34 +00:00
RiotRobot e15cf9976f v23.2.0 2023-01-31 10:46:15 +00:00
RiotRobot bdc3926417 Prepare changelog for v23.2.0 2023-01-31 10:46:12 +00:00
Hubert Chathi 4f918f684e add support for stable identifier for fixed MAC in SAS verification (#3101) 2023-01-30 09:26:43 -05:00
Germain c142232f4d Stop labelling threads as experimental (#3064) 2023-01-30 11:25:27 +00:00
Šimon Brandner c9bc20aa4d Don't throw with no opponentDeviceInfo (#3107) 2023-01-26 16:28:56 +00:00
renovate[bot] 5c0cb3a536 fix(deps): update all non-major dependencies (#3099)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-26 14:50:36 +00:00
Andy Balaam 415576d0a0 Provide eventId as well as roomId from Room.findPredecessor (#3095) 2023-01-26 10:58:33 +00:00
Andy Balaam 4f9fad66e4 MSC3946 Dynamic room predecessors (#3042)
* Implement MSC3946 for getVisibleRooms

* Implement MSC3946 for getRoomUpgradeHistory
2023-01-26 10:28:07 +00:00
renovate[bot] ebd9854980 chore(deps): update dependency @types/jest to v29.2.6 (#3096)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-26 09:42:54 +00:00
renovate[bot] cb2fab64d8 chore(deps): update typescript-eslint monorepo to v5.48.2 (#3097)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-26 09:41:59 +00:00
renovate[bot] f446b49e49 fix(deps): update dependency @babel/runtime to v7.20.13 (#3100)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-26 09:41:40 +00:00
renovate[bot] 22f5e41058 chore(deps): update dependency @types/uuid to v9 (#3102)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-26 09:41:33 +00:00
renovate[bot] fee5a006f1 chore(deps): update dependency rimraf to v4 (#3103)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-26 09:41:21 +00:00
Kerry ef51ee28fd Poll model (#3036)
* first cut poll model

* process incoming poll relations

* allow alt event types in relations model

* allow alt event types in relations model

* remove unneccesary checks on remove relation

* comment

* Revert "allow alt event types in relations model"

This reverts commit e578d84464403d4a15ee8a7cf3ac643f4fb86d69.

* Revert "Revert "allow alt event types in relations model""

This reverts commit 515db7a8bc2df5a1c619a37c86e17ccbe287ba7a.

* basic handling for new poll relations

* tests

* test room.processPollEvents

* join processBeaconEvents and poll events in client

* tidy and set 23 copyrights

* use rooms instance of matrixClient

* tidy

* more copyright

* simplify processPollEvent code

* throw when poll start event has no roomId

* updates for events-sdk move

* more type changes for events-sdk changes

* comment
2023-01-26 02:07:55 +00:00
David Baker cb61345780 Merge pull request #3091 from matrix-org/dbkr/video_mute_no_renegotiate
Remove video tracks on video mute without renegotiating
2023-01-25 15:38:51 +00:00
David Baker a18d4e226e Actually check audio sender too 2023-01-25 15:07:51 +00:00
David Baker b09b33eb4c Add tests 2023-01-25 15:06:36 +00:00
Clark Fischer 5fedc06d7c Remove flaky test (#3098)
I introduced a flaky test to confirm that `MegolmEncryption#prepareToEncrypt`
didn't block the main thread too much, but it turns out that, when run in
varying environments, it tends to fail.

The same behavior is guaranteed by the following cancellation test - if the
thread is blocked, it can't be cancelled.

Signed-off-by: Clark Fischer <clark.fischer@gmail.com>

Signed-off-by: Clark Fischer <clark.fischer@gmail.com>
2023-01-25 14:27:02 +00:00
David Baker d8c9f6db33 Check we have both a sender and a track to send 2023-01-25 11:20:25 +00:00
David Baker 0af5fa0328 Actually check we have a sender, not just a transceiver 2023-01-25 11:16:19 +00:00
David Baker b328b72cd5 Move timeout clear to be with its friends 2023-01-25 11:07:14 +00:00
David Baker ce2a9d7036 Fix test 2023-01-25 10:59:03 +00:00
Andy Balaam 66ae985af5 Refactor getRoomUpgradeHistory to use Room.findPredecessorRoomId (#3090)
* Refactor getRoomUpgradeHistory to use Room.findPredecessorRoomId

* Simplify getRoomUpgradeHistory implementation a little
2023-01-25 09:48:56 +01:00
David Baker 1828e2849c Remove timer on call terminate 2023-01-24 20:30:10 +00:00
David Baker b4f8b0fe4f Remove video tracks on video mute without renegotiating 2023-01-24 18:19:19 +00:00
Robin 70656e954f Merge pull request #3035 from clarkf/megolm-cancellation
Reduce Megolm blocking and add cancellation
2023-01-24 12:26:23 -05:00
Robin 40a4c8d954 Merge branch 'develop' into megolm-cancellation 2023-01-24 12:20:42 -05:00
Andy Balaam 7ed787b86a Fix bug in getRoomUpgradeHistory's verifyLinks functionality (#3089) 2023-01-24 13:44:03 +00:00
RiotRobot 1f58ee7f2c v23.2.0-rc.1 2023-01-24 11:21:25 +00:00
RiotRobot 2e28e9117a Prepare changelog for v23.2.0-rc.1 2023-01-24 11:21:22 +00:00
Andy Balaam a58a36e062 Tests for getRoomUpgradeHistory (#3088) 2023-01-24 10:45:04 +00:00
kegsay 6cf6a0c522 refactor: sliding sync: swap to lists-as-keys (#3086)
* refactor: sliding sync: swap to lists-as-keys

Update the request/response API shape to match the latest
MSC3575 version, which converts `lists` from being an array
of list objects to being a map of list objects.

* Linting

* prettier

* add extra setListRanges test

* Default to right type
2023-01-23 15:26:25 +00:00
Andy Balaam 02aa3edda4 Revert "refactor: sliding sync: swap to lists-as-keys (#3076)"
Reverting because the companion matrix-react-sdk change is not ready so
this is breaking our builds.

This reverts commit e04ea02c62.
2023-01-23 12:21:47 +00:00
kegsay e04ea02c62 refactor: sliding sync: swap to lists-as-keys (#3076)
* refactor: sliding sync: swap to lists-as-keys

Update the request/response API shape to match the latest
MSC3575 version, which converts `lists` from being an array
of list objects to being a map of list objects.

* Linting

* prettier

* add extra setListRanges test

* Default to right type
2023-01-23 11:45:22 +00:00
David Baker 64197bf4db Merge pull request #3082 from matrix-org/dbkr/ptt_null_member_workarounds
Add null check for our own member event
2023-01-20 13:11:16 +00:00
RiotRobot c309fe6942 Merge branch 'master' into develop 2023-01-20 12:28:33 +00:00
RiotRobot 8408f36c12 v23.1.1 2023-01-20 12:26:59 +00:00
RiotRobot dcd8f91e02 Prepare changelog for v23.1.1 2023-01-20 12:26:57 +00:00
ElementRobot cabe14d7e2 replace .at(-1) with array.length-1 (#3080) (#3081)
(cherry picked from commit baeb4acddf)

Co-authored-by: Germain <germains@element.io>
2023-01-20 12:13:36 +00:00
David Baker c019f2bb19 Add null check for our own member event
As per comment
2023-01-20 12:09:28 +00:00
Germain baeb4acddf replace .at(-1) with array.length-1 (#3080) 2023-01-20 12:05:35 +00:00
David Baker 4a6e9a0f8f Merge pull request #3078 from matrix-org/dbkr/group_call_double_stream_init
Handle group call getting initialised twice in quick succession
2023-01-20 11:01:46 +00:00
David Baker ea5ce8d1d8 Also wrap the initLocalFeed method of groupCall 2023-01-19 15:28:56 +00:00
David Baker 41854918a5 Merge branch 'develop' into dbkr/group_call_double_stream_init 2023-01-19 14:13:35 +00:00
David Baker 495642d041 Handle group call getting initialised twice in quick succession
This happens in dev mode with React 18 and caused extra user media
stream to end up floating around.

Fixes https://github.com/vector-im/element-call/issues/847
2023-01-19 14:04:59 +00:00
Richard van der Hoff c7210b9e9d Rename some of the .spec files which test crypto (#3077)
* `matrix-client-crypto.spec.ts` only tested a very specific bit of crypto (olm
  encryption). It goes back to the very early days, before Megolm was invented.
  I've renamed it to `olm-encryption-spec.ts`.

* `megolm-integ.spec.ts` is more of a general crypto test; it was just called
  `megolm` to distinguish it from the Olm tests above. Renamed to
  `crypto.spec.ts`.
2023-01-19 12:20:21 +00:00
Richard van der Hoff 83563c7a01 Implement decryption via the rust sdk (#3074)
A bunch of changes to tests, and wire up decryption.
2023-01-18 16:47:44 +00:00
RiotRobot 2fcc4811dd Resetting package fields for development 2023-01-18 13:38:53 +00:00
RiotRobot c392bc455d Merge branch 'master' into develop 2023-01-18 13:36:45 +00:00
RiotRobot b8711f15fd v23.1.0 2023-01-18 13:30:21 +00:00
RiotRobot 81f3aef960 Prepare changelog for v23.1.0 2023-01-18 13:30:19 +00:00
Richard van der Hoff d6b8332567 Element-R: stub implementations of some methods (#3075)
These are all called by the react-sdk when showing an encrypted event:

 * `getEventEncryptionInfo`
 * `checkUserTrust`
 * `checkDeviceTrust`

I don't particularly want to keep this API, but as a rapid means to an end,
let's stub them for now.
2023-01-18 12:07:49 +00:00
Richard van der Hoff 85b34b46c5 Remove brokenheaded encryption test (#3070)
This test seemed to be testing the behaviour of decrypting redacted events, but
that seems... strange. A redaction event cannot be encrypted (at least, there
is no spec for it), and it should be impossible to decrypt a (correctly)
redacted event, because such an event will lack a `ciphertext` property.

This test is just sticking a "redacted_because" property into a regular event,
which is a bit of a nonsense.
2023-01-17 11:27:30 +00:00
RiotRobot 4179f2978d v23.1.0-rc.4 2023-01-17 09:11:54 +00:00
RiotRobot 97df6db49c Prepare changelog for v23.1.0-rc.4 2023-01-17 09:11:52 +00:00
ElementRobot 3e693fab23 [Backport staging] Correctly handle limited sync responses by resetting the thread timeline (#3069)
Co-authored-by: Janne Mareike Koschinski <jannemk@element.io>
2023-01-17 09:06:28 +00:00
Clark Fischer 1ee487a2ff Make prepareToEncrypt cancellable.
NOTE: This commit introduces a backwards-compatible API change.

Adds the ability to cancel `MegolmEncryption#prepareToEncrypt` by returning
a cancellation function. The bulk of the processing happens in
`getDevicesInRoom`, which now accepts a 'getter' that allows the caller to
indicate cancellation.

See https://github.com/matrix-org/matrix-js-sdk/issues/1255
Closes #1255

Signed-off-by: Clark Fischer <clark.fischer@gmail.com>
2023-01-16 10:23:13 -08:00
Clark Fischer b76e7ca782 Reduce blocking while pre-fetching Megolm keys
Currently, calling `Client#prepareToEncrypt` in a megolm room has the potential
to block for multiple seconds while it crunches numbers.

Sleeping for 0 seconds (approximating `setImmediate`) allows the engine to
process other events, updates, or re-renders in between checks.

See
- https://github.com/vector-im/element-web/issues/21612
- https://github.com/vector-im/element-web/issues/11836

Signed-off-by: Clark Fischer <clark.fischer@gmail.com>
2023-01-16 10:11:37 -08:00
Clark Fischer ddce1bcd28 Add async setImmediate util
Adds an async/promise-based version of `setImmediate`. Note that, despite being
poorly adopted, `setImmediate` is polyfilled, and should be more performant
than `sleep(0)`.

Signed-off-by: Clark Fischer <clark.fischer@gmail.com>
2023-01-16 10:11:37 -08:00
Janne Mareike Koschinski a34d06c7c2 Correctly handle limited sync responses by resetting the thread timeline (#3056)
* Reset thread livetimelines when desynced
* Implement workaround for https://github.com/matrix-org/synapse/issues/14830
2023-01-16 16:27:28 +00:00
David Baker 7b10fa367d Merge pull request #3066 from matrix-org/dbkr/olm_savesession_undecryptable_todevice_debug
Add some debugging & a debug event for decryption
2023-01-13 21:40:36 +00:00
Šimon Brandner 7f5d7091de Fix typos in src/webrtc/ (#3065) 2023-01-13 19:56:55 +01:00
David Baker 96f673ae92 Merge branch 'develop' into dbkr/olm_savesession_undecryptable_todevice_debug 2023-01-13 18:36:22 +00:00
David Baker 79faee7a67 Add emit so tests don't throw 2023-01-13 18:32:21 +00:00
David Baker 89d2984432 Add some debugging & a debug event for decryption
Adds a log line whenever we save a session and also adds an event
that's fired whenever we get a to-device event we can't decrypt
(hopefully the comment explains all).
2023-01-13 18:24:33 +00:00
Travis Ralston bc78784688 Extract v1 extensible events polls types out of the events-sdk (#3062)
* Extract v1 extensible events polls out of events-sdk

* Appease tsdoc?

* Appease naming standards

* Bring the tests over too
2023-01-13 10:02:27 -07:00
Richard van der Hoff eb058edb1b Fix spurious "Decryption key withheld" messages (#3061)
When we receive an `m.unavailable` notification, do not show it as "Decryption
key withheld".
2023-01-13 13:17:48 +00:00
Richard van der Hoff 4847d78b42 Improvements to megolm integration tests (#3060)
The megolm tests were making a few assumptions which they really shouldn't; in
particular:

 * They were creating mock events with event_ids not starting `$`, and lacking
   `sender`, `origin_server_ts` and `unsigned` properties

 * They were not including the (now) required `keys.ed25519` property inside
   the ciphertext of an olm message.

These work ok currently, but they aren't really correct, and they cause
problems when testing the new rust implementation.
2023-01-13 13:14:44 +00:00
RiotRobot 94f1eda830 v23.1.0-rc.3 2023-01-13 10:40:31 +00:00
RiotRobot bc2a182ee9 Prepare changelog for v23.1.0-rc.3 2023-01-13 10:40:29 +00:00
renovate[bot] 789aec732a Update typescript-eslint monorepo to v5.48.1 (#3063)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-13 09:08:54 +00:00
renovate[bot] 3246114772 Update dependency docdash to v2.0.1 (#3057)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-12 18:38:54 +00:00
ElementRobot 39cf1863f1 Fix failure to start in firefox private browser (#3058) (#3059)
(cherry picked from commit aa1e118f18)

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-01-12 17:10:42 +00:00
Richard van der Hoff aa1e118f18 Fix failure to start in firefox private browser (#3058) 2023-01-12 17:03:16 +00:00
RiotRobot c10152e098 v23.1.0-rc.2 2023-01-12 13:31:20 +00:00
RiotRobot 6b7efbcd91 Prepare changelog for v23.1.0-rc.2 2023-01-12 13:31:18 +00:00
Richard van der Hoff d23c3cb8b2 Improve logging in legacy megolm code (#3043)
* Use a PrefixedLogger throughout `megolm.ts`

Rather than manually adding `in ${this.roomId}` to each log line, use a
PrefixedLogger to achieve the same effect more consistently.

* Clean up logging in megolm.ts

Where we log a list of devices, we don't need the whole deviceinfo, just the
device id. All that noise makes it very hard to read the logs.

* Log users that we find in the room when encrypting

* Reduce log verbosity on decryption retries
2023-01-12 11:49:32 +00:00
Richard van der Hoff 9e37980e2d Handle edits which are bundled with an event, per MSC3925 (#3045) 2023-01-12 10:53:36 +00:00
renovate[bot] de176dbd66 Update all non-major dependencies (#3053)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-11 16:55:07 +00:00
renovate[bot] ac10b40f67 Update dependency @babel/core to v7.20.12 (#3054)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-11 16:46:47 +00:00
Michael Telatynski f35298a326 [Release] Fix browser entrypoint (#3052) 2023-01-11 16:31:02 +00:00
Michael Telatynski d7bf0f85c0 Fix browser entrypoint (#3051) 2023-01-11 15:17:55 +00:00
RiotRobot 1d87f5b163 v23.1.0-rc.1 2023-01-11 13:29:05 +00:00
RiotRobot 3e97067b3e Prepare changelog for v23.1.0-rc.1 2023-01-11 13:29:02 +00:00
Michael Telatynski 3ce582d004 Fix dated example (#3049) 2023-01-11 13:08:30 +00:00
Michael Telatynski 3e48c76a77 Avoid use of mkdirp (#3050) 2023-01-11 12:02:56 +00:00
Germain 8e29f8ead0 Improve hasUserReadEvent and getUserReadUpTo realibility with threads (#3031)
Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-01-11 09:53:27 +00:00
Travis Ralston 185ded4ebc Remove extensible events v1 field population on legacy events (#3040)
* Remove extensible events v1 field population on legacy events

With extensible events v2, affected events are now gated by a room version, so we don't need this code anymore. 

The proposal has generally moved away from mixing m.room.message with extensible fields as well.

* Run prettier

* Remove unstable identifier from tests too

* Run prettier again
2023-01-10 09:19:55 -07:00
Andy Balaam 3564a3546f Merge pull request #3039 from andybalaam/factor-out-findPredecessor
Factor out a (public) function to find a room's predecessor
2023-01-10 13:43:59 +00:00
Andy Balaam c6090325b3 Update id string to reflect spec 2023-01-10 13:29:06 +00:00
Andy Balaam 999e355136 Use Room.getLiveTimeline instead of deprecated this.currentState 2023-01-10 10:16:22 +00:00
Andy Balaam 7de4164444 Factor out a (public) function to find a room's predecessor 2023-01-10 10:16:22 +00:00
Andy Balaam e2ce379b56 Merge pull request #3038 from andybalaam/andybalaam/tests-for-getVisibleRooms
Tests for getVisibleRooms
2023-01-10 10:07:53 +00:00
Andy Balaam 424212cd65 Merge pull request #2915 from matrix-org/madlittlemods/stablize-msc3030-timestamp-to-event
Prefer stable `/timestamp_to_event` endpoint first - MSC3030
2023-01-09 17:01:10 +00:00
Andy Balaam c7c16256df Update comment to reflect commonality between 404 and 405 status 2023-01-09 16:53:52 +00:00
Andy Balaam 8a4c95ee72 Tests for getVisibleRooms 2023-01-09 12:17:53 +00:00
Clark Fischer c3d422f5fb Remove 'qs' dependency (#3033)
'qs' appears to be unused since 34c5598 (PR #2719).

Signed-off-by: Clark Fischer <clark.fischer@gmail.com>

Signed-off-by: Clark Fischer <clark.fischer@gmail.com>
2023-01-06 22:37:05 +00:00
Šimon Brandner fdb80ad259 Remove video track when muting video (#3028) 2023-01-06 12:09:01 -05:00
Andy Balaam 981acf0044 Rename test to fit renamed function.
Co-authored-by: Eric Eastwood <erice@element.io>
2023-01-06 16:38:02 +00:00
Andy Balaam f00f70bfb8 Merge branch 'develop' into madlittlemods/stablize-msc3030-timestamp-to-event 2023-01-06 15:38:08 +00:00
Andy Balaam 12cc7be31c Test 400, 429 and 502 responses 2023-01-06 15:33:48 +00:00
Andy Balaam 628bcbf33a Fall back to the unstable endpoint if we receive a 405 status 2023-01-06 15:22:58 +00:00
Andy Balaam c4ca0b2e07 Refactor timestampToEvent tests 2023-01-06 15:13:44 +00:00
Andy Balaam d7442147b9 Rename convertQueryDictToMap 2023-01-06 14:21:35 +00:00
Andy Balaam b1566ee540 Switch to a Map for convertQueryDictToStringRecord 2023-01-06 14:20:24 +00:00
Andy Balaam ca98d9ff11 Tests for convertQueryDictToStringRecord 2023-01-06 14:20:24 +00:00
Andy Balaam bba4a35665 Merge pull request #3034 from matrix-org/johannes/poll-start-sent-receipt
Make poll start event type available (PSG-962)
2023-01-06 11:10:00 +00:00
Germain 896f6227a0 Fix threaded cache receipt when event holds multiple receipts (#3026) 2023-01-06 10:27:35 +00:00
Johannes Marbach 4d10cf3074 Make poll start event type available 2023-01-06 10:17:29 +01:00
Kerry bb23df9423 Add alt event type matching in Relations model (#3018)
* allow alt event types in relations model

* remove unneccesary checks on remove relation

* comment

* assert on event emitted
2023-01-05 20:00:12 +00:00
Richard van der Hoff d02559cf3c Make error handling in decryptionLoop more generic (#3024)
Not everything is a `DecryptionError`, and there's no real reason that we
should only do retries for `DecryptionError`s
2023-01-05 15:02:19 +00:00
Richard van der Hoff ec6272aa3d Fix outgoing messages for rust-crypto (#3025)
It turns out that MatrixClient uses a `FetchHttpApi` instance with
`opts.onlyData = true`, so it was returning the json-parsed response rather
than the raw response. Change the way we call `authedRequest` so that we get
the raw body back.
2023-01-05 15:00:37 +00:00
Michael Weimann 695b773f8b Fix false key requests after verifying new device (#3029) 2023-01-05 15:27:09 +01:00
Richard van der Hoff 030abe1563 Pass to-device messages into rust crypto-sdk (#3021)
We need a separate API, because `ClientEvent.ToDeviceEvent` is only emitted for
successfully decrypted to-device events
2023-01-05 09:54:56 +00:00
Richard van der Hoff 22f10f71b8 indirect decryption attempts via Client (#3023)
... to reduce the number of things referring to `client.crypto`
2023-01-05 09:54:44 +00:00
renovate[bot] 9ca3e7272e chore(deps): lock file maintenance (#3014)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-04 13:44:26 -07:00
Richard van der Hoff 64119ef915 Avoid logical assignment operator (#3022)
Apparently `??=` was only added to javascript in ES12, and our eleweb build
doesn't support it.

Fixes breakage introduced in #3019.
2023-01-04 14:17:55 +00:00
Richard van der Hoff 9ac7165e99 Handle outgoing requests from rust crypto SDK (#3019)
The rust matrix-sdk-crypto has an `outgoingRequests()` method which we need to poll, and make the requested requests.
2023-01-04 12:17:42 +00:00
Hubert Chathi 6168cedf32 Avoid triggering decryption errors when decrypting redacted events (#3004) 2023-01-03 11:06:54 -05:00
Richard van der Hoff 7c34deecb6 Pass CryptoBackend into SyncApi (#3010)
I need to start calling back into the new rust crypto implementation from the /sync loops, so I need to pass it into SyncApi. To reduce the coupling, I've defined a new interface specifying the methods which exist for that purpose. Currently it's only onSyncCompleted.
2023-01-03 15:37:51 +00:00
Ankit cef5507ab1 Include 'yarn install' . (#3011) 2023-01-03 14:07:37 +00:00
Richard van der Hoff 9b372d23ca Factor SyncApi options out of IStoredClientOptions (#3009)
There are a couple of callback interfaces which are currently stuffed into
`IStoredClientOpts` to make it easier to pass them into the `SyncApi`
constructor.

Before we add more fields to this, let's separate it out to a separate object.
2023-01-03 13:38:21 +00:00
renovate[bot] e9fef19c8f Update dependency @types/node to v18.11.18 (#2984)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-01-03 13:28:02 +00:00
Andy Balaam 9ebc91aa5a Merge pull request #3017 from andybalaam/andybalaam/use-env-variable-for-ref_name
In release.yml use an env section to get ref_name
2023-01-03 13:10:05 +00:00
Andy Balaam fcb75d547e Remove unneeded variable in workflow 2023-01-03 12:25:13 +00:00
Andy Balaam 33c9af952e Reformat release.yml 2023-01-03 10:25:59 +00:00
Andy Balaam 3b66b28e71 In release.yml use an env section to get ref_name 2023-01-03 10:21:40 +00:00
Travis Ralston 7d37bb1edb Remove usage of v1 Identity Server API (#3003)
* Remove usage of v1 Identity Server API

It's been deprecated for over a year at this point - everyone should be able to support v2.

* Missed one.
2023-01-03 00:59:12 -07:00
Travis Ralston 0f717a9306 Update comment for m.key.verification.ready event type definition (#3006) 2023-01-03 00:58:55 -07:00
Richard van der Hoff ce776b9989 Break coupling between Room and Crypto.trackRoomDevices (#2998)
`Room` and `Crypto` currently have some tight coupling in the form of a call to
`trackRoomDevices` when out-of-band members are loaded. We can improve this by
instead having Crypto listen out for a `RoomSateEvent.Update` notification.
2022-12-23 11:03:14 +00:00
kegsay ff1b0e51ea Merge pull request #3008 from matrix-org/kegan/upload-otks
bugfix: upload OTKs in sliding sync mode
2022-12-22 16:26:47 +01:00
Kegan Dougal 21e66a5c34 bugfix: upload OTKs in sliding sync mode 2022-12-22 14:52:16 +00:00
Germain aead401005 Apply edits discovered from sync after thread is initialised (#3002) 2022-12-22 08:54:55 +00:00
Travis Ralston af9525ed5f Add device_id to /account/whoami types (#3005)
* Add `device_id` to `/account/whoami` types

https://spec.matrix.org/v1.5/client-server-api/#get_matrixclientv3accountwhoami

* Appease the linter

* Modernize area of code

* Remove unused eslint disable comment
2022-12-21 16:46:10 -07:00
RiotRobot 1ebcac37cc Resetting package fields for development 2022-12-21 16:49:19 +00:00
RiotRobot 51a4cc5e18 Fix post-release script compatibility with prettier 2022-12-21 16:49:11 +00:00
RiotRobot 48baa6315c Merge branch 'master' into develop
# Conflicts:
#	release.sh
#	spec/integ/matrix-client-event-timeline.spec.ts
2022-12-21 16:48:43 +00:00
RiotRobot efc87d8084 v23.0.0 2022-12-21 16:40:30 +00:00
RiotRobot aab873fc58 Prepare changelog for v23.0.0 2022-12-21 16:40:28 +00:00
RiotRobot 52ed04c825 Fix release call to prettier 2022-12-21 16:38:37 +00:00
ElementRobot fdd1428e19 [Backport staging] Fix release scripts to not fight with prettier (#3000)
(cherry picked from commit ec2405ac99)

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2022-12-21 09:37:40 +00:00
Michael Telatynski ec2405ac99 Fix release scripts to not fight with prettier (#2999) 2022-12-21 09:31:16 +00:00
ElementRobot b31712f2ff [Backport staging] Threads are missing from the timeline (#2997)
(cherry picked from commit 4f86eee250)

Co-authored-by: Janne Mareike Koschinski <jannemk@element.io>
2022-12-20 17:27:18 +00:00
kegsay 61e2606bc4 Merge pull request #2991 from S7evinK/s7evink/slidingsync-unsub
sliding sync: Fix issue where no unsubs are sent when switching rooms
2022-12-20 17:57:19 +01:00
Richard van der Hoff 45f6c5b079 Add exportRoomKeys to CryptoBackend (#2970)
Element-web calls `exportRoomKeys` on logout, so we need a stub implementation
to get it EW working with the rust crypto sdk.
2022-12-20 11:11:00 +00:00
Michael Weimann b83c372848 Implement MSC3912: Relation-based redactions (#2954) 2022-12-20 09:22:26 +01:00
Šimon Brandner 6d58a54039 Don't use RoomMember as a calls a key on GroupCall (#2993) 2022-12-19 14:53:08 +01:00
Till 3872c5f099 Update src/sliding-sync.ts
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2022-12-19 11:54:20 +01:00
Janne Mareike Koschinski 4f86eee250 Threads are missing from the timeline (#2996) 2022-12-19 10:32:37 +00:00
David Baker 618242ef3c Merge pull request #2992 from matrix-org/dbkr/close_all_streams
Close all streams when a call ends
2022-12-19 10:31:36 +00:00
David Baker 96ee5b1256 Close all streams when a call ends
We didn't close streams in group calls (presumably from back when
we used the same stream for all calls rather than cloning?) but this
left stray screenshare streams in the mediahandler when a participant
left whilst we were screensharing.

Fixes https://github.com/vector-im/element-call/issues/742
2022-12-16 18:19:36 +00:00
Till Faelligen 8af0ff111b Add tests for custom subscriptions 2022-12-16 13:30:40 +01:00
Till Faelligen a04800f030 Fix issue where no unsubs are sent when switching rooms 2022-12-16 11:49:31 +01:00
Eric Eastwood 4683fbe848 Merge branch 'develop' into madlittlemods/stablize-msc3030-timestamp-to-event
Conflicts:
	spec/unit/matrix-client.spec.ts
2022-12-16 00:56:06 -06:00
renovate[bot] c973b26fa2 Update all non-major dependencies (#2981)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-15 22:06:40 -07:00
renovate[bot] 7b96c730b8 Update typescript-eslint monorepo to v5.46.0 (#2985)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-15 22:05:22 -07:00
renovate[bot] f8bf6083de Update dependency uuid to v9 (#2988)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-15 22:05:05 -07:00
Anderas 447319737a Merge pull request #2920 from Anderas/resume-todevice-queue
Resume to-device message queue after resumed sync
2022-12-14 14:27:47 +00:00
Janne Mareike Koschinski 39e127b4e3 Write test to validate #2971 (#2972) 2022-12-14 13:01:52 +01:00
Richard van der Hoff 15ef8fabb7 Introduce a mechanism for using the rust-crypto-sdk (#2969)
This PR introduces MatrixClient.initRustCrypto, which is similar to initCrypto, except that it will use the Rust crypto SDK instead of the old libolm-based implementation.

This is very much not something you want to use in production code right now, because the integration with the rust sdk is extremely skeletal and almost everything crypto-related will raise an exception rather than doing anything useful.

It is, however, enough to demonstrate the loading of the wasmified rust sdk in element web, and a react sdk with light modifications can successfully log in and out.

Part of vector-im/element-web#21972.
2022-12-14 11:02:02 +00:00
renovate[bot] df42014ef5 Update dependency @types/jest to v29.2.4 (#2980)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-14 10:55:40 +00:00
Michael Weimann b765b18381 Add prettier formatting to .git-blame-ignore-revs (#2979) 2022-12-14 11:46:18 +01:00
RiotRobot 6cc8e4436c v23.0.0-rc.1 2022-12-14 08:49:15 +00:00
RiotRobot 7f1fe46c7c Prepare changelog for v23.0.0-rc.1 2022-12-14 08:49:15 +00:00
Kerry b2a10e6db3 Support MSC3391: Account data deletion (#2967)
* add deleteAccountData endpoint

* check server support and test

* test current state of memorystore

* interpret account data events with empty content as deleted

* add handling for (future) stable version of endpoint

* add getSafeUserId

* user getSafeUserId in deleteAccountData

* better jsdoc for throws documentation
2022-12-14 04:14:21 +00:00
Eric Eastwood a0aa5074ed Fix prefix lint
See https://github.com/matrix-org/matrix-js-sdk/pull/2915#discussion_r1043951639
2022-12-13 16:37:47 -06:00
Eric Eastwood 70a033c2fd Prettier fixes 2022-12-13 16:26:14 -06:00
Eric Eastwood fcf12b49e3 Merge branch 'develop' into madlittlemods/stablize-msc3030-timestamp-to-event
Conflicts:
	spec/unit/matrix-client.spec.ts
	src/client.ts
2022-12-13 16:18:33 -06:00
RiotRobot 284a475dfb Exclude CHANGELOG from prettier and undo what it did 2022-12-13 15:35:12 +00:00
Janne Mareike Koschinski 193c38523c Fix messages loaded during initial fetch ending up out of order (#2971)
* Fix messages loaded during initial fetch ending up out of order
2022-12-13 15:23:43 +01:00
Andy Uhnak 11ac3d9e58 Add unit tests 2022-12-13 12:26:52 +00:00
Andy Uhnak 071d5e71e4 Resume to-device message queue after resumed sync 2022-12-13 11:54:52 +00:00
Michael Telatynski acd220b8a9 Tweak how the SonarCloud scan fails (#2947) 2022-12-13 09:59:52 +00:00
Germain 74b30246d0 Avoid creating duplicate threads (#2968) 2022-12-13 09:54:44 +00:00
Richard van der Hoff 9c17eb6c14 Begin factoring out a CryptoBackend interface (#2955)
Part of https://github.com/vector-im/element-web/issues/21972. Eventually I want to replace the whole of the current `Crypto` implementation with an alternative implementation, but in order to get from here to there, I'm factoring out a common interface which will be implemented by both implementations.

I'm also determined to fix the problem where the innards of the crypto implementation are exposed to applications via the `MatrixClient.crypto` property.

It's not (yet) entirely clear what shape this interface should be, so I'm going with a minimal approach and adding things as we know we need them. This means that we need to keep the old `client.crypto` property around as well as a new `client.cryptoBackend` property. Eventually `client.crypto` will go away, but that will be a breaking change in the js-sdk.
2022-12-12 17:49:39 +00:00
Janne Mareike Koschinski 8293011ee2 Fix #23916: Prevent edits of the last message in a thread getting lost (#2951)
* Fix issue where the root event of a thread had to be loaded in a complicated way
* Fix issue where edits to the last event of a thread would get lost
* Fix issue where thread reply count would desync
* Refactor relations pagination mocking for tests
2022-12-12 18:22:16 +01:00
Richard van der Hoff 4c5f416b32 Factor out some utility functions in the megolm integration tests (#2958)
There's a lot of repetition here, which can be reduced with some utility functions.
2022-12-12 16:31:56 +00:00
Janne Mareike Koschinski 66c678e9fb Fix #23919: Root message for new thread loaded from network (#2965)
* Load root events of threads without additional network roundtrip
2022-12-12 16:30:48 +01:00
Richard van der Hoff 8a892ede23 Exclude generated files from prettier (#2961)
The example directories include symlinks to the generated matrix.js, which we
should not prettify.
2022-12-12 10:37:52 +00:00
Germain 2dd06e368e Fix infinite loop when restoring cached read receipts (#2963) 2022-12-09 15:20:50 +00:00
Damir Jelić fc501de081 Don't swallow up errors coming from the shareSession call (#2962)
A call to ensureSession() has two steps:
    1. prepareSession(), where an outbound group session might get created
       or rotated
    2. shareSession(), where an outbound group session might get
       encrypted and queued up to be sent to other devices

Both of those calls may mostly fail due to storage errors, yet only the
errors from prepareSession get propagated to the caller.

Errors from prepareSession will mean that you can't get an
outbound group session so you can't encrypt an event.

Errors from shareSession, especially if the error happens in the part
where the to-device requests are queued up to be sent out, mean that
other people will not be able to decrypt the events that will get
encrypted using the outbound group session.

Both of those cases are catastrophic, the second case is just much
harder to debug, since the error happens on another device at some
arbitrary point in the future.

Let's just return the error instead, people can then retry and the
storage issue might have been resolved, or at least the error becomes
visible when it happens.
2022-12-09 15:07:42 +00:00
Damir Jelić ada401f4c0 Make sure that MegolmEncryption.setupPromise always resolves (#2960)
ensureOutboundSession uses and modifies the setupPromise of the
MegolmEncryption class. Some comments suggest that setupPromise will
always resolve, in other words it should never contain a promise that
will get rejected.

Other comments also seem to suggest that the return value of
ensureOutboundSession, a promise as well, may fail.

The critical error here is that the promise that gets set as
the next setupPromise, as well as the promise that ensureOutboundSession
returns, is the same promise.

It seems that the intention was for setupPromise to contain a promise
that will always resolve to either `null` or `OutboundSessionInfo`.

We can see that a couple of lines before we set setupPromise to its new
value we construct a promise that logs and discards errors using the
`Promise.catch()` method.

The `Promise.catch()` method does not mutate the promise, instead it
returns a new promise. The intention of the original author might have
been to set the next setupPromise to the promise which `Promise.catch()`
produces.

This patch modifies the updating of setupPromise in the
ensureOutboundSession so that setupPromise discards errors correctly.

Using `>>=` to represent the promise chaining operation, setupPromise is
now updated using the following logic:

    setupPromise = previousSetupPromise >>= setup >>= discardErrors
2022-12-09 14:46:33 +00:00
Damir Jelić 41d762171e Apply prettier to the client.ts file (#2959) 2022-12-09 15:03:49 +01:00
Germain 5b6bebc1d7 Do not calculate highlight notifs for threads unknown to the room (#2957) 2022-12-09 12:41:51 +00:00
Andy Balaam 7b5e137ec0 Merge pull request #2906 from matrix-org/weeman1337/prettier
Add prettier
2022-12-09 12:16:16 +00:00
Michael Weimann 6e0901258c Switch to eslint-plugin-matrix-org 0.9 2022-12-09 10:51:15 +01:00
Michael Weimann 559fbdda26 Update eslint-plugin-matrix-org 2022-12-09 09:54:36 +01:00
Michael Weimann 72dac9a107 Apply manual code style fixes after prettier 2022-12-09 09:43:22 +01:00
Michael Weimann 349c2c2587 Apply prettier formatting 2022-12-09 09:38:20 +01:00
Michael Weimann 08a9073bd5 Add prettier 2022-12-09 09:34:01 +01:00
Eric Eastwood 9841f92415 Fix some eslint 2022-12-08 18:37:33 -06:00
Eric Eastwood ed91bd9c11 Merge branch 'develop' into madlittlemods/stablize-msc3030-timestamp-to-event
Conflicts:
	spec/unit/matrix-client.spec.ts
	src/client.ts
2022-12-08 18:29:14 -06:00
Eric Eastwood c953fc9fb7 Update casing
See https://github.com/matrix-org/matrix-js-sdk/pull/2915#discussion_r1041542066
2022-12-08 17:56:53 -06:00
Eric Eastwood bf78a64d82 Remove console coloring in favor of future PR
See https://github.com/matrix-org/matrix-js-sdk/pull/2915#discussion_r1041539703
2022-12-08 17:47:56 -06:00
Šimon Brandner ae849fdd46 Minor VoIP stack improvements (#2946)
* Add `IGroupCallRoomState`

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Export values into `const`s

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Add `should correctly emit LengthChanged`

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Add `ICE disconnected timeout`

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Improve typing

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Don't cast `getContent()`

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Use `Date.now()` for call length

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Type fix

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2022-12-08 19:51:05 +01:00
Richard van der Hoff 39cf212628 Expose a new 'userHasCrossSigningKeys' method (#2950) 2022-12-08 11:53:38 +00:00
Richard van der Hoff 224e592701 Fix examples/browser/browserTest.js (#2952)
This seems to have been broken for ages
2022-12-08 10:43:20 +00:00
Germain 16d791b038 Cache read receipts for unknown threads (#2953) 2022-12-08 09:54:10 +00:00
Michael Telatynski c4006d752a Improve tsdoc types (#2940)
* Install eslint-plugin-jsdoc

* Enable lint rule jsdoc/no-types

* Make tsdoc more valid, add required hyphens and s/return/returns/g

* Stash tsdoc work

* Fix mistypes

* Stash

* Stash

* More tsdoc work

* Remove useless doc params

* Fixup docs

* Apply suggestions from code review

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/crypto/verification/request/ToDeviceChannel.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/client.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/client.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Update src/client.ts

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>

* Iterate

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2022-12-07 18:01:54 +00:00
Richard van der Hoff a9e7a46c56 Upload device keys during initCrypto (#2872)
Rather than waiting for the application to call `.startClient`, upload the
device keys during `initCrypto()`. Element-R is going to approach this slightly
differently (it wants to manage the decision on key uploads itself), so this
lays some groundwork by collecting the libolm-specific bits together.
2022-12-07 13:48:41 +00:00
Michael Telatynski 4a7365f32f Fix release documentation (#2949) 2022-12-07 13:06:41 +00:00
Germain a071a82a03 Update test runner instructions (#2948) 2022-12-07 11:18:32 +00:00
Michael Telatynski 8d018f9c2d Enable noImplicitAny (#2895)
* Stash noImplicitAny work

* Enable noImplicitAny

* Update olm

* Fun

* Fix msgid stuff

* Fix tests

* Attempt to fix Browserify
2022-12-06 18:21:44 +00:00
Richard van der Hoff 6f81371e61 Fix the message ID on key-share messages (#2945)
https://github.com/matrix-org/matrix-js-sdk/pull/2938 introduced message IDs on
outgoing to-device messages, but a typo meant that the IDs on key-share
messages were excessive.
2022-12-06 16:45:21 +00:00
RiotRobot ccab6985ad Resetting package fields for development 2022-12-06 12:34:38 +00:00
RiotRobot 569adc7b0c Merge branch 'master' into develop 2022-12-06 12:34:35 +00:00
RiotRobot b6369cc2bd v22.0.0 2022-12-06 12:32:58 +00:00
RiotRobot e6e079f487 Prepare changelog for v22.0.0 2022-12-06 12:32:58 +00:00
Richard van der Hoff 683e7fba4a Add a message ID on each to-device message (#2938)
To make it easier to track down where to-device messages are getting lost,
add a custom property to each one, and log its value. Synapse will also log
this property.
2022-12-06 10:31:48 +00:00
Šimon Brandner 2c8eece5ca Don't expose calls on GroupCall (#2941) 2022-12-05 18:44:13 +01:00
kegsay 4a4d493856 bugfix: sliding sync initial room timelines shouldn't notify (#2933)
* bugfix: sliding sync initial room timelines shouldn't notify

Flag timeline events as `fromCache` when `initial: true` rooms
are received. This stops notifications appearing inappropriately
when you scroll the room list or spider the room list, as it
causes `liveEvent=false`.

* Use num_live to detect liveness; with jest test

* Linting

* jsdoc

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2022-12-05 17:00:06 +00:00
Michael Weimann 11d8f562c5 Redo key sharing after own device verification (#2921) 2022-12-05 14:31:58 +01:00
Michael Telatynski 7799804762 Move @types deps into devDeps (#2927) 2022-12-02 16:27:59 +00:00
RiotRobot 83a1e07380 v22.0.0-rc.2 2022-12-02 16:23:53 +00:00
RiotRobot 7f3123ed65 Prepare changelog for v22.0.0-rc.2 2022-12-02 16:23:53 +00:00
ElementRobot 5a88a6c62a [Backport staging] Fix highlight notifications increasing when total notification is zero (#2939)
Co-authored-by: Germain <germains@element.io>
2022-12-02 16:16:41 +00:00
Janne Mareike Koschinski 8a7fd270e4 Move updated threads to the end of the thread list (#2923)
* Move updated threads to the end of the thread list
* Write new tests
2022-12-02 17:11:18 +01:00
ElementRobot 12cecbdcf1 [Backport staging] Fix synthesizeReceipt (#2934)
(cherry picked from commit 3577aa98b5)

Co-authored-by: Germain <germains@element.io>
2022-12-02 16:09:05 +00:00
Germain 53a45a34df Fix highlight notifications increasing when total notification is zero (#2937) 2022-12-02 15:41:15 +00:00
Janne Mareike Koschinski fa2eeac5b8 Improve perceived performance for threads (#2901)
* Improve perceived performance for threads
* Improve method naming and make it private
2022-12-02 15:50:19 +01:00
Janne Mareike Koschinski 720248466f Include pending events in thread summary and count again (#2922)
* Include pending events in thread summary and count again
* Pass through pending event status
2022-12-02 15:01:43 +01:00
Janne Mareike Koschinski 43bfa0c020 Switch to stable /relations endpoint, stop using unspecced original_event field (#2911)
* Switch to stable /relations endpoint, stop using unspecced original_event field
* Adapt the tests to the changed endpoint
2022-12-02 15:01:15 +01:00
Robin c17deb0806 Backport "Make GroupCall work better with widgets" to staging (#2936) 2022-12-02 10:34:41 +00:00
Robin 79ccd7c330 Merge pull request #2935 from robintown/entered-via-widget
Make GroupCall work better with widgets
2022-12-01 23:33:44 -05:00
Robin Townsend 9de9ff76b5 Test cleanMemberState 2022-12-01 23:27:31 -05:00
Robin Townsend c0090852ad Make GroupCall work better with widgets
If the client uses a widget to join group calls, like Element Web does, then the local device could be joined to the call without GroupCall knowing. This adds a field to GroupCall that allows the client to tell GroupCall when it's using another session to join the call.
2022-12-01 10:45:34 -05:00
Faye Duxovni 3870e3395d Add method to get outgoing room key requests for a given event (#2930)
* Add method to get outgoing room key requests for a given event

* Write test, fix typo

* Add test case for non-encrypted event
2022-12-01 09:49:36 +00:00
renovate[bot] a0f3e5d3bf Update babel monorepo (#2929)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-01 07:25:08 +00:00
renovate[bot] 720ea0e12e Update all non-major dependencies (#2928)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-12-01 07:24:50 +00:00
Eric Eastwood 9a98e8008f Fix relevant strict ts error 2022-11-30 19:13:29 -06:00
Eric Eastwood ad8bb5d2cd Fix lints 2022-11-30 19:01:20 -06:00
Eric Eastwood 9a731cdf4f Add some comments 2022-11-30 18:53:23 -06:00
Eric Eastwood d1ede036e2 Add return type 2022-11-30 18:51:49 -06:00
Eric Eastwood d3f08fec03 Add tests 2022-11-30 18:45:05 -06:00
renovate[bot] d692a5dbe2 Update tspascoal/get-user-teams-membership action to v2 (#2925)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-30 14:22:05 +00:00
renovate[bot] 4362297edc Update dependency @typescript-eslint/eslint-plugin to v5.44.0 (#2924)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-30 14:21:43 +00:00
Richard van der Hoff 1606274c36 Process m.room.encryption events before emitting RoomMember events (#2914)
vector-im/element-web#23819 is an intermittent failure to correctly initiate a user verification process. The
root cause is as follows:

* In matrix-react-sdk, ensureDMExists tries to create an encrypted DM room, and assumes it is ready for use
  (including sending encrypted events) as soon as it receives a RoomStateEvent.NewMember notification
  indicating that the other user has been invited or joined. 

* However, in sync.ts, we process the membership events in a /sync response (including emitting
  RoomStateEvent.NewMember notifications), which is long before we process any m.room.encryption event.
    
* The upshot is that we can end up trying to send an encrypted event in the new room before processing
  the m.room.encryption event, which causes the crypto layer to blow up with an error of "Room was 
  previously configured to use encryption, but is no longer".

Strictly speaking, ensureDMExists probably ought to be listening for ClientEvent.Room as well as RoomStateEvent.NewMember; but that doesn't help us, because ClientEvent.Room is also emitted
before we process the crypto event.

So, we need to process the crypto event before we start emitting these other events; but a corollary of that 
is that we need to do so before we store the new room in the client's store. That makes things tricky, because
currently the crypto layer expects the room to have been stored in the client first.

So... we have to rearrange everything to pass the newly-created Room object into the crypto layer, rather than
just the room id, so that it doesn't need to rely on getting the Room from the client's store.
2022-11-30 10:53:38 +00:00
Michael Telatynski 8d6d262e5f Update CODEOWNERS (#2918) 2022-11-30 09:27:23 +00:00
Germain 3577aa98b5 Fix synthesizeReceipt (#2916) 2022-11-30 07:58:29 +00:00
renovate[bot] e0df53c2ed Update dependency terser to v5.16.0 (#2919)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-30 01:11:32 +00:00
Marco Bartelt 6611cfa253 add-privileged-users-in-room (#2892) 2022-11-29 19:23:57 +00:00
Michael Weimann 25296bb486 Update @typescript-eslint/parser (#2917) 2022-11-29 18:38:38 +00:00
RiotRobot 31c4f6c16b v22.0.0-rc.1 2022-11-29 15:33:50 +00:00
RiotRobot 22271d22f8 Prepare changelog for v22.0.0-rc.1 2022-11-29 15:33:49 +00:00
Eric Eastwood 3a1897629a Prefer stable endpoint first 2022-11-28 22:50:37 -06:00
Robin 9d3ac66cf8 Merge pull request #2902 from robintown/group-call-participants
Refactor GroupCall participant management
2022-11-28 16:33:08 -05:00
Robin Townsend a4ad4ed2cf Merge branch 'develop' into group-call-participants 2022-11-28 16:11:24 -05:00
kegsay 7fd55a61bf Merge pull request #2912 from matrix-org/kegan/ss-receipts
sliding sync: add receipts extension
2022-11-28 18:22:11 +00:00
Kegan Dougal 847766c114 Review comments 2022-11-28 18:13:17 +00:00
Kegan Dougal c8c39052a7 Linting 2022-11-28 11:09:03 +00:00
Kegan Dougal 6592b2c205 sonarcloud 2022-11-28 10:58:38 +00:00
Michael Telatynski fc91153be4 Revert "Process m.room.encryption events before emitting RoomMember events" (#2913)
This reverts commit aaf3702c66.
2022-11-28 10:23:23 +00:00
Robin Townsend 5511a6ef8c Fix tests 2022-11-26 00:28:11 -05:00
Robin Townsend 19e02e894f Add a method for cleaning group call member state 2022-11-25 23:47:01 -05:00
Robin Townsend c54d61e158 Put creation timestamps on group calls 2022-11-25 23:45:45 -05:00
Robin Townsend 44da9040f4 Emit an event for outgoing group calls 2022-11-25 23:44:46 -05:00
Robin Townsend 995f5bf7d7 Merge branch 'develop' into group-call-participants 2022-11-25 11:56:45 -05:00
Travis Ralston ad16b26247 Define a spec support policy for the js-sdk (#2882)
* Define a spec support policy for the js-sdk

* Update timeline per team discussion
2022-11-25 09:07:09 -07:00
Richard van der Hoff aaf3702c66 Process m.room.encryption events before emitting RoomMember events (#2910)
* Update tests

* Call `Store.storeRoom` earlier

We're going to call `onCryptoEvent` earlier in `processSyncResponse`, but we
need to have stored the room before doing so. We therefore need to move the
call to `storeRoom` earlier.

We can actually reduce a bit of duplication by moving the call into
`SyncApi.createRoom`.

`storeRoom` has relatively few side-effects, so as far as I can tell this
should be pretty safe.

* Call onCryptoEvent before processing state events

This fixes the problematic race condition.
2022-11-25 13:47:28 +00:00
Kegan Dougal 74147b9943 Linting 2022-11-25 13:24:12 +00:00
Kegan Dougal 815370c5f9 sliding sync: add receipts extension 2022-11-25 13:21:16 +00:00
Damir Jelić a01d8e3174 Deprecate a function containing a typo (#2904) 2022-11-25 09:47:52 +00:00
Michael Telatynski 007b7dd242 Fix 3pid invite acceptance not working due to mxid being sent in body (#2907) 2022-11-25 09:22:10 +00:00
Florian Duros 77d6def1cc Add jest metrics (#2897)
* Add slow jest reporter
2022-11-24 13:06:19 +00:00
RiotRobot b318a77ece Resetting package fields for development 2022-11-22 11:25:53 +00:00
RiotRobot 1a90259326 Merge branch 'master' into develop 2022-11-22 11:25:49 +00:00
RiotRobot 3702ac56f4 v21.2.0 2022-11-22 11:24:19 +00:00
RiotRobot af4811b327 Prepare changelog for v21.2.0 2022-11-22 11:24:19 +00:00
Robin Townsend f46ecf970c Refactor GroupCall participant management
This refactoring brings a number of improvements to GroupCall, which I've unfortunately had to combine into a single commit due to coupling:

- Moves the expiration timestamp field on call membership state to be per-device
- Makes the participants of a group call visible without having to enter the call yourself
- Enables users to join group calls from multiple devices
- Identifies active speakers by their call feed, rather than just their user ID
- Plays nicely with clients that can be in multiple calls in a room at once
- Fixes a memory leak caused by the call retry loop never stopping
- Changes GroupCall to update its state synchronously, and write back to room state asynchronously
  - This was already sort of halfway being done, but now we'd be committing to it
  - Generally improves the robustness of the state machine
  - It means that group call joins will appear instant, in a sense

For many reasons, this is a breaking change.
2022-11-21 12:16:44 -05:00
Richard van der Hoff dd98d7eb2c Further improvements to e2ee logging (#2900)
A followup to #2884. In particular, it is not always the case that the
`sender_key` in a `m.room_key_withheld` message is the sender of that message.
2022-11-21 14:33:30 +00:00
kegsay f3dc1c4ca2 Merge pull request #2893 from matrix-org/kegan/ss-typing
sliding sync: add support for typing extension
2022-11-21 11:45:14 +00:00
Michael Telatynski 305b83f8ea Merge branch 'develop' into kegan/ss-typing 2022-11-21 11:36:07 +00:00
Kegan Dougal acc488da64 typing events don't need to be in an array 2022-11-21 11:31:33 +00:00
renovate[bot] 7217f83db9 Update all (major) (#2890)
* Update all

* Pin p-retry

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2022-11-21 08:58:04 +00:00
renovate[bot] 37ea905faa Update all (#2899)
* Update all

* Update webrtc.ts

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2022-11-21 08:57:49 +00:00
Kegan Dougal 78de55b835 Review comments 2022-11-21 08:42:45 +00:00
David Baker cb410f463a Merge pull request #2898 from matrix-org/dbkr/dont_hang_up_calls_that_didnt_start
Don't hang up calls that haven't started yet
2022-11-18 17:33:31 +00:00
David Baker 72f9d5e6f9 Move check so we still do cleanup but just don't send the hangup 2022-11-18 17:08:50 +00:00
Michael Telatynski c389de98f3 Merge branch 'develop' into dbkr/dont_hang_up_calls_that_didnt_start 2022-11-18 16:39:16 +00:00
Michael Telatynski 20745dc9ac Add CI check with tsc --noImplicitAny (#2896) 2022-11-18 16:26:08 +00:00
David Baker 9410902049 Don't hang up calls that haven't started yet 2022-11-18 16:16:19 +00:00
Kegan Dougal a6badbb7fa s/room_ephemeral/typing/ 2022-11-18 14:30:30 +00:00
Kegan Dougal 0b65b199e3 Add ExtensionRoomEphemeral tests 2022-11-18 11:49:02 +00:00
Kegan Dougal c1138bc085 sliding sync ext: add room ephemeral events 2022-11-18 11:41:58 +00:00
Michael Telatynski c0f7df8c3b Update eslint-plugin-matrix-org and improve visibilities & types (#2887) 2022-11-18 09:20:53 +00:00
renovate[bot] e085609572 Update jest monorepo to v29.2.3 (#2888)
* Update jest monorepo to v29.2.3

* Trigger CI

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Weimann <michaelw@matrix.org>
2022-11-18 07:40:07 +00:00
renovate[bot] 0a4f86a79e Update typescript-eslint monorepo to v5.43.0 (#2889)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-18 08:29:30 +01:00
renovate[bot] 5d6ff6c7f9 Update dependency jest-environment-jsdom to v29 (#2891)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-17 18:20:34 -07:00
Richard van der Hoff ffcdfe166e Improve logging on Olm session errors (#2885)
I strongly suspect we are logging "secure channel corruption" errors when no
such thing happened, bit I can't quite figure it out yet. Add a bit more
logging to try to track them down.
2022-11-16 17:22:04 +00:00
Richard van der Hoff e1aa7d335b Improve logging of e2ee messages (#2884)
Attempt to make the way we log megolm session ids more consistent.
2022-11-16 15:45:44 +00:00
kegsay 29643e745c Merge pull request #2883 from matrix-org/kegan/custom-room-subs
Define sliding sync consts
2022-11-16 14:41:22 +00:00
Kegan Dougal 54622ce424 Define msc3575 consts 2022-11-16 13:22:31 +00:00
Germain ca2ae24d46 Read receipt accumulation for threads (#2881) 2022-11-16 10:58:42 +00:00
RiotRobot d4601d9910 v21.2.0-rc.1 2022-11-15 17:41:32 +00:00
RiotRobot 2ced5e1aa4 Prepare changelog for v21.2.0-rc.1 2022-11-15 17:41:32 +00:00
David Baker 45e19e51c1 Merge pull request #2880 from matrix-org/dbkr/revert_to_connecting
Make calls go back to 'connecting' state when media lost
2022-11-15 17:36:50 +00:00
David Baker 3f1c3392d4 Make calls go back to 'connecting' state when media lost
This is a change in how the state machine works: technically it's
a breaking change. Calls will now now go back into the connecting
state if the media connection is lost (they'll try to re-establish
the connection).
2022-11-15 16:10:45 +00:00
Richard van der Hoff f86f67f5a5 Improve logs for decrypting events (#2879)
Some attempts to make debugging UISIs a bit easier
2022-11-15 15:11:13 +00:00
Mahdi Bagvand 4dcf54f448 fix registration add phone number not working (#2876)
Co-authored-by: Michael Weimann <michaelw@matrix.org>
2022-11-15 10:42:37 +01:00
Germain d43e664594 Add ability to send unthreaded receipt (#2878) 2022-11-14 16:14:07 +00:00
Michael Telatynski 0e322848f9 Add way to abort search requests (#2877) 2022-11-14 16:11:53 +00:00
Šimon Brandner b454318684 Use an underride rule for Element Call notifications (#2873) 2022-11-14 11:42:51 +01:00
Richard van der Hoff 692f1d49b9 Deprecate/remove some get/set methods on Crypto (#2874)
* Deprecate Crypto.{get,set}GlobalBlacklistUnverifiedDevices

... in favour of just exposing the properties.

* Remove Crypto.{get,set}GlobalErrorOnUnknownDevices

... in favour of exposing the property.

These methods are UNSTABLE so we can safely remove them, right?
2022-11-14 10:03:12 +00:00
Richard van der Hoff b40cf75c9d Remove Crypto.start() (#2871)
This isn't really needed, and its semantics are poorly defined. (Contrary to
the comment, it dos *not* set background processes running).
2022-11-14 10:01:05 +00:00
kegsay ba6a001d67 Merge pull request #2834 from matrix-org/kegan/custom-room-subs
sliding sync: add custom room subscriptions support
2022-11-14 09:19:40 +00:00
kegsay d0c71ec516 Merge branch 'develop' into kegan/custom-room-subs 2022-11-14 09:11:37 +00:00
Richard van der Hoff 67f343d6f0 Switch to typedoc for documentation (#2869)
This seems to give *much* better results than jsdoc, and means that we can
start to get rid of all the duplicated type information.
2022-11-11 11:38:04 +00:00
Germain a7f0ba97cd Fixes unwanted highlight notifications with encrypted threads (#2862) 2022-11-11 09:27:16 +00:00
Michael Telatynski 54d11e1745 Upload docs artifact for PRs (#2868) 2022-11-10 18:01:34 +00:00
David Baker 14744fd4dc Merge pull request #2865 from matrix-org/dbkr/log_call_id
Log the call ID when receiving a call
2022-11-09 16:03:51 +00:00
David Baker 9b0919350c Log the call ID when receiving a call 2022-11-09 15:47:37 +00:00
David Baker b53ad2c081 Merge pull request #2864 from matrix-org/dbkr/log_on_hangup
Add logging saying why we hung up calls
2022-11-09 15:42:11 +00:00
David Baker 6222d238e4 Add logging saying why we hung up calls 2022-11-09 15:20:10 +00:00
Michael Telatynski c6ee258789 Remove patch-package and update matrix-events-sdk (#2863) 2022-11-08 17:01:38 +00:00
László Várady a584324a0d webrtc: add advanced audio settings (#2434) 2022-11-08 16:02:31 +00:00
renovate[bot] 059b07cfa0 Lock file maintenance (#2857)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-08 14:40:33 +00:00
RiotRobot b628cabe58 Resetting package fields for development 2022-11-08 14:36:10 +00:00
RiotRobot b7d925f5ec Merge branch 'master' into develop
# Conflicts:
#	package.json
2022-11-08 14:36:02 +00:00
RiotRobot 47b729f085 v21.1.0 2022-11-08 14:31:37 +00:00
RiotRobot 05d980608a Prepare changelog for v21.1.0 2022-11-08 14:31:37 +00:00
Michael Telatynski 1c901e3137 Fix Node 19 compatibility and run CI against it (#2842) 2022-11-08 14:01:06 +00:00
Germain bd4589fcc4 Hide pending events in thread timelines (#2843) 2022-11-08 10:04:20 +00:00
Robin 0fbd0b3685 Merge pull request #2860 from robintown/patch-package-dependency
Move patch-package out of dev dependencies
2022-11-07 15:36:20 -05:00
Eric Eastwood 1646ea05bc Extra insurance that we don't mix events in the wrong timelines - v2 (#2856)
Add checks to `addEventToTimeline` as extra insurance that we don't mix events in the wrong timelines (main timeline vs thread timeline).

Split out from https://github.com/matrix-org/matrix-js-sdk/pull/2521

This PR is a v2 of https://github.com/matrix-org/matrix-js-sdk/pull/2848 since it was reverted in https://github.com/matrix-org/matrix-js-sdk/pull/2853

Previously, we just relied on the callers to make sure they're doing the right thing and since it's easy to get it wrong, we mixed and bugs happened.

Call stacks for how events get added to a timeline:

 - `TimelineSet.addEventsToTimeline` -> `TimelineSet.addEventToTimeline` -> `Timeline.addEvent`
 - `TimelineSet.addEventToTimeline` -> `Timeline.addEvent`
 - `TimelineSet.addLiveEvent` -> `TimelineSet.addEventToTimeline` -> `Timeline.addEvent`
2022-11-07 14:24:43 -06:00
Robin Townsend 885ec1fc73 Move patch-package out of dev dependencies
patch-package is used as a postinstall hook, but since it was in devDependencies, upstream packages would not install it. Moving it to dependencies isn't ideal since it's not needed at runtime, but the patch-package approach is only a temporary workaround for https://github.com/matrix-org/matrix-events-sdk/pull/16#pullrequestreview-1166721652 anyways.
2022-11-07 15:24:04 -05:00
David Baker df2b65f111 Merge pull request #2553 from matrix-org/robertlong/group-call
Add support for group calls using MSC3401
2022-11-07 17:24:31 +00:00
David Baker f09853ccb1 Merge remote-tracking branch 'origin/develop' into robertlong/group-call 2022-11-07 17:04:15 +00:00
Michael Telatynski 6c543382e6 Make SonarCloud happier (#2850)
* Make SonarCloud happier

* Revert one change due to lack of strict mode upstream

* Fix typo
2022-11-07 12:16:48 +00:00
Michael Telatynski 52932f59ab Fix pagination token tracking for mixed room timelines (#2855) 2022-11-05 12:36:20 +00:00
David Baker 4f63ff21ea Merge branch 'develop' into robertlong/group-call 2022-11-04 16:05:04 +00:00
David Baker c8dc71eb69 Merge pull request #2854 from matrix-org/dbkr/gcmerge_20221104
Merge changes from develop
2022-11-04 16:04:23 +00:00
David Baker 2dda837db6 Fix strict mode errors 2022-11-04 14:44:21 +00:00
David Baker fff4cdab7c Merge remote-tracking branch 'origin/develop' into dbkr/gcmerge_20221104 2022-11-04 14:05:48 +00:00
Šimon Brandner 4f00566b9f Do not freeze state in initialiseState() (#2846) 2022-11-04 14:48:42 +01:00
Michael Telatynski c1a3b95073 Revert "Extra insurance that we don't mix events in the wrong timelines" (#2853)
This reverts commit 433b7afd71.
2022-11-04 12:21:04 +00:00
Eric Eastwood 38adbaf923 Ignore random macOS cruft (.DS_Store) (#2851) 2022-11-04 06:25:10 -05:00
Travis Ralston 9459a95134 Delete .DS_Store 2022-11-04 10:59:23 +00:00
Eric Eastwood 433b7afd71 Extra insurance that we don't mix events in the wrong timelines (#2848)
Add checks to `addEventToTimeline` as extra insurance that we don't mix events in the wrong timelines (main timeline vs thread timeline).

Split out from https://github.com/matrix-org/matrix-js-sdk/pull/2521

Previously, we just relied on the callers to make sure they're doing the right thing and since it's easy to get it wrong, we mixed and bugs happened.

Call stacks for how events get added to a timeline:

 - `TimelineSet.addEventsToTimeline` -> `TimelineSet.addEventToTimeline` -> `Timeline.addEvent`
 - `TimelineSet.addEventToTimeline` -> `Timeline.addEvent`
 - `TimelineSet.addLiveEvent` -> `TimelineSet.addEventToTimeline` -> `Timeline.addEvent`
2022-11-04 05:54:23 -05:00
Michael Telatynski 777cf1f135 Remove tsc-strict ci, it has served its purpose (#2847) 2022-11-04 09:12:07 +00:00
Robin 8235b65d71 Merge pull request #2844 from robintown/dont-remove-self
Don't remove our own member for a split second when entering a call
2022-11-03 14:38:39 -04:00
Hubert Chathi 4a33e584b0 Add unit test for device de-/rehydration (#2821) 2022-11-03 13:12:57 -04:00
Michael Telatynski 6ee185e93f Merge remote-tracking branch 'origin/develop' into develop
# Conflicts:
#	.github/workflows/sonarqube.yml
2022-11-03 14:13:25 +00:00
Michael Telatynski 5df9705bae Update sonarqube.yml 2022-11-03 14:12:42 +00:00
Michael Telatynski 76458d3a40 Update sonarqube.yml 2022-11-03 13:58:50 +00:00
Michael Telatynski 27bb79a29a Switch to @casualbot/jest-sonar-reporter 2022-11-03 13:47:36 +00:00
Michael Telatynski 82d942dcc5 Update sonarqube.yml 2022-11-03 13:17:48 +00:00
Michael Telatynski ce6d0e2cb1 Update sonarqube.yml 2022-11-03 12:59:16 +00:00
Michael Telatynski db49cd8d13 Make the js-sdk conform to tsc --strict (#2835)
Co-authored-by: Faye Duxovni <fayed@matrix.org>
2022-11-03 12:50:05 +00:00
Michael Telatynski 42b08eca57 Update sonarqube.yml 2022-11-03 12:49:38 +00:00
Michael Telatynski a92c148f15 Update sonarqube.yml 2022-11-03 12:23:04 +00:00
Michael Telatynski 6cd60e32dc Update sonarqube.yml 2022-11-03 12:14:16 +00:00
Michael Telatynski b6633ad4b0 Update sonarqube.yml 2022-11-03 12:06:52 +00:00
Michael Telatynski e4dd7bcc87 Update sonarcloud.yml 2022-11-03 12:01:33 +00:00
Michael Telatynski b6e97fcecb Update sonarqube.yml 2022-11-03 12:01:20 +00:00
Michael Telatynski dee2b60c3d Update sonarqube.yml 2022-11-03 11:59:54 +00:00
Michael Telatynski a07fe44565 Update matrix-org/sonarcloud-workflow-action (#2845) 2022-11-03 11:46:31 +00:00
Michael Telatynski 0a35f2e2c7 Fix queueToDevice.spec.ts test flakiness (#2841) 2022-11-03 11:45:35 +00:00
Robin Townsend 32d535c2b1 Don't remove our own member for a split second when entering a call 2022-11-02 22:43:54 -04:00
David Baker 7fb313c17c Merge remote-tracking branch 'origin/develop' into robertlong/group-call 2022-11-02 10:38:05 +00:00
renovate[bot] d8f6449422 Update jest monorepo to v29.2.1 (#2837)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-02 08:53:09 +00:00
renovate[bot] c043e36f50 Update all (#2836)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-02 08:52:32 +00:00
renovate[bot] e6524239bd Update dependency @babel/runtime to v7.20.1 (#2838)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-02 02:20:24 -04:00
renovate[bot] daed4b9dcc Update typescript-eslint monorepo to v5.42.0 (#2839)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-11-01 20:29:45 +00:00
Kegan Dougal 135d2da143 Maybe satisfy the strict ts checker 2022-11-01 16:35:40 +00:00
Kegan Dougal fef53be5b4 Use Map not Objects 2022-11-01 16:31:17 +00:00
David Baker 7ec726e10b Give everything that isn't web rtc back to element-web 2022-11-01 16:18:14 +00:00
David Baker 476f6f78b1 Add more access modifiers 2022-11-01 16:14:48 +00:00
David Baker cb8123dec7 Add public/private modifiers 2022-11-01 16:07:07 +00:00
David Baker 6729c7d421 Merge remote-tracking branch 'origin/develop' into robertlong/group-call 2022-11-01 14:38:16 +00:00
RiotRobot 99af67a963 v21.1.0-rc.1 2022-11-01 14:38:04 +00:00
RiotRobot b77f5a5598 Prepare changelog for v21.1.0-rc.1 2022-11-01 14:38:04 +00:00
Michael Telatynski 76377c7cc4 Add eslint rule unicorn/no-instanceof-array (#2833) 2022-11-01 14:24:47 +00:00
Kegan Dougal 7ddd198df8 Linting 2022-11-01 11:08:47 +00:00
Kegan Dougal 81681f4090 Add custom room subscriptions support
This is mostly useful when you need to change the subscription depending
on the room. For example, unencrypted rooms have lazy-loaded members, but
encrypted rooms do not.
2022-11-01 11:04:40 +00:00
RiotRobot 52830a2a50 Merge branch 'master' into develop
# Conflicts:
#	src/client.ts
2022-11-01 09:21:54 +00:00
RiotRobot 81c3668cb6 v21.0.1 2022-11-01 09:16:11 +00:00
RiotRobot 8f40dc6304 Prepare changelog for v21.0.1 2022-11-01 09:16:11 +00:00
Michael Telatynski fcdd8c93f4 [Backport staging] Catch server versions API call exception when starting the client (#2832)
Co-authored-by: Germain <germains@element.io>
2022-11-01 09:01:52 +00:00
ElementRobot 7d7803380c [Backport staging] Fix default behavior of Room.getBlacklistUnverifiedDevices (#2831)
Co-authored-by: Faye Duxovni <fayed@matrix.org>
2022-11-01 08:47:47 +00:00
Faye Duxovni 9fa6616052 Fix default behavior of Room.getBlacklistUnverifiedDevices (#2830) 2022-10-31 18:21:27 +00:00
Robin 94072a096d Merge pull request #2826 from robintown/init-leave-race
Resolve races between `initLocalCallFeed` and `leave`
2022-10-31 13:46:30 -04:00
Germain 1f3ae4bde2 Catch server versions API call exception when starting the client (#2828) 2022-10-31 17:44:52 +00:00
ElementRobot 545a74364d [Backport staging] Fix authedRequest including Authorization: Bearer undefined for password resets (#2829)
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2022-10-31 17:14:06 +00:00
Michael Telatynski 646b3a69fe Fix authedRequest including Authorization: Bearer undefined for password resets (#2822) 2022-10-31 17:08:35 +00:00
ElementRobot db33f396b8 [Backport staging] Fix JSDoc (#2827)
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2022-10-31 17:00:45 +00:00
Michael Telatynski 6c475d9b54 Fix JSDoc (#2825) 2022-10-31 16:50:15 +00:00
Robin Townsend b9cccf9109 Resolve races between initLocalCallFeed and leave
Unfortunately there are still other methods that could race with leave and result in broken group call state, such as enter and terminate. For the future, should consider writing a more careful specification of how the whole group call state machine is meant to work.
2022-10-31 12:09:06 -04:00
David Baker f0d4ef7f99 Merge remote-tracking branch 'origin/develop' into robertlong/group-call 2022-10-31 15:36:30 +00:00
Janne Mareike Koschinski 068fbb7660 Loading threads with server-side assistance (#2735)
* Fix bug where undefined vs null in pagination tokens wasn't correctly handled
* Fix bug where thread list results were sorted incorrectly
* Allow removing the relationship of an event to a thread
* Implement feature detection for new threads MSCs and specs
* Prefix dir parameter for threads pagination if necessary
* Make threads conform to the same timeline APIs as any other timeline
* Extract thread timeline loading out of thread class
* fix thread roots not being updated correctly
* fix jumping to events by link
* implement new thread timeline loading
* Fix fetchRoomEvent incorrect return type

Co-authored-by: Germain <germains@element.io>
Co-authored-by: Germain <germain@souquet.com>
2022-10-28 13:48:14 +02:00
Robin 849e3d67c2 Merge pull request #2815 from robintown/keepalive-leave
Let leave requests outlive the window
2022-10-27 08:35:30 -04:00
Robin Townsend 4c6e1e5c21 Replace the keepAlive flag with request options 2022-10-27 08:19:41 -04:00
David Baker 9ff6b357fc Merge branch 'develop' into robertlong/group-call 2022-10-27 09:56:36 +01:00
David Baker 77ef8558bd Merge pull request #2816 from matrix-org/dbkr/groupcall_more_strict
A few more strict mode fixes
2022-10-27 09:55:17 +01:00
David Baker d979302e9b A few more strict mode fixes 2022-10-27 09:37:41 +01:00
Robin Townsend dbdaa1540a Let leave requests outlive the window 2022-10-26 17:50:20 -04:00
Michael Telatynski b44787192d Replace instanceof Array with Array.isArray (#2812) 2022-10-26 17:59:16 +01:00
Germain 6f2390a765 Switch ESLint warnings to be errors instead (#2814) 2022-10-26 16:25:40 +00:00
Germain dddc0aeccb Emit UnreadNotification event on notifications reset (#2804) 2022-10-26 14:23:54 +01:00
kegsay 9f6b42d3ae Merge pull request #2801 from matrix-org/kegan/ss-api-changes
Sliding sync: add include_old_rooms; remove is_tombstoned
2022-10-26 14:03:55 +01:00
David Baker 13c751c060 Merge pull request #2808 from matrix-org/dbkr/groupcall_more_strict
More TS strict mode fixes
2022-10-26 13:44:00 +01:00
Kegan Dougal 2e56c34df0 Merge branch 'develop' into kegan/ss-api-changes 2022-10-26 13:03:21 +01:00
David Baker 87115d181d Don't commit the strict mode flag 2022-10-26 12:34:18 +01:00
David Baker 5679c86ca6 More TS strict mode fixes 2022-10-26 12:33:06 +01:00
David Baker 4cd50e4871 Merge pull request #2807 from matrix-org/dbkr/gcmerge_26oct22
Merge changes from develop again
2022-10-26 12:08:28 +01:00
David Baker 0f1012278a Fix types 2022-10-26 12:01:53 +01:00
David Baker 0d211dfbad Clean up group call tests (#2806) 2022-10-26 11:57:16 +01:00
David Baker 384116c8f5 Merge remote-tracking branch 'origin/develop' into dbkr/gcmerge_26oct22 2022-10-26 11:56:41 +01:00
David Baker c374ba2367 TS strict mode compliance in the call / groupcall code (#2805)
* TS strict mode compliance in the call / groupcall code

* Also the test

* Fix initOpponentCrypto

to not panic if it doesn't actually need to init crypto
2022-10-26 11:45:03 +01:00
Michael Telatynski 9f2f08dfd3 Fix more typescript --strict violations (#2795)
* Stash tsc fixes

* Iterate

* Iterate

* Iterate

* Fix tests

* Iterate

* Iterate

* Iterate

* Iterate

* Add tests
2022-10-25 18:31:40 +01:00
RiotRobot 4b3e6939d6 Resetting package fields for development 2022-10-25 17:05:31 +01:00
RiotRobot f2ae3bc8ef Merge branch 'master' into develop 2022-10-25 17:05:28 +01:00
Kegan Dougal 11cc30f345 Remove debug logging 2022-10-25 13:47:16 +01:00
Kegan Dougal 24a9562b07 bugfix: allow subtly different DELETE/INSERT semantics
In sliding sync, with an empty list, it is possible for the proxy
to send back DELETE 0, INSERT 0 !room which has the net result of
`[!room]`. Previously, the JS SDK would not handle this correctly.
Now it does. With tests.
2022-10-25 13:07:53 +01:00
Kegan Dougal 8f10c0d921 Sliding sync: add include_old_rooms; remove is_tombstoned 2022-10-25 10:45:38 +01:00
David Baker 450ff00c3e Merge pull request #2800 from matrix-org/dbkr/gcmerge_oct22_3
Merge develop into group-call branch
2022-10-24 19:03:06 +01:00
David Baker b4ab7fc0b3 Merge branch 'robertlong/group-call' into dbkr/gcmerge_oct22_3 2022-10-24 18:53:54 +01:00
Robin 35f697a04b Merge pull request #2797 from robintown/matryoshka-events
Add event and message capabilities to RoomWidgetClient
2022-10-24 13:50:09 -04:00
David Baker 193d8a429a Merge remote-tracking branch 'origin/develop' into dbkr/gcmerge_oct22_3 2022-10-24 18:38:46 +01:00
Robin Townsend 8cd5aac128 Add event and message capabilities to RoomWidgetClient 2022-10-24 12:18:02 -04:00
Michael Telatynski 9bdeea0a8d Fix incorrect prevEv being sent in ClientEvent.AccountData events (#2794) 2022-10-24 15:30:55 +01:00
Michael Telatynski ade2e81d3d Revert "Sliding sync: add include_old_rooms; remove is_tombstoned" (#2796) 2022-10-24 14:16:02 +01:00
kegsay 2fe434f3ae Merge pull request #2785 from matrix-org/kegan/ss-api-changes
Sliding sync: add include_old_rooms; remove is_tombstoned
2022-10-24 13:23:51 +01:00
David Baker eddd0cafe8 Add throwOnFail to groupCall.setScreensharingEnabled (#2787)
* Add throwOnFail to groupCall.setScreensharingEnabled

For https://github.com/vector-im/element-call/pull/652

* Update mediaHandler.ts
2022-10-24 10:20:04 +01:00
Michael Telatynski 3a6561af36 Improve crypto init code and allow easier shimming (#2791) 2022-10-24 09:40:18 +01:00
renovate[bot] 403286cb81 Lock file maintenance (#2790)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-24 09:07:13 +01:00
Kegan Dougal 219eab9139 Sliding sync: add include_old_rooms; remove is_tombstoned 2022-10-21 17:16:55 +01:00
Šimon Brandner a12e6185f9 Update call notification push rule to match MSC3914 (#2781) 2022-10-21 15:17:34 +00:00
Michael Telatynski d9eac57e9c Add room_type field to /publicRooms response (#2784) 2022-10-21 16:09:34 +01:00
renovate[bot] 9a9009d838 Update dependency jest-mock to v29 (#2775)
* Update dependency jest-mock to v29

* Update imports

* Strict fixes

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2022-10-21 14:22:50 +00:00
Michael Telatynski 6f729ad7fd Switch /keys/signatures/upload to v3 prefix (#2782) 2022-10-21 14:31:28 +01:00
Janne Mareike Koschinski cd33bafa04 fix build error caused by wrong ts-strict improvements (#2783)
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2022-10-21 13:29:05 +00:00
Michael Telatynski 867a0ca7ee Apply more strict typescript around the codebase (#2778)
* Apply more strict typescript around the codebase

* Fix tests

* Revert strict mode commit

* Iterate strict

* Iterate

* Iterate strict

* Iterate

* Fix tests

* Iterate

* Iterate strict

* Add tests

* Iterate

* Iterate

* Fix tests

* Fix tests

* Strict types be strict

* Fix types

* detectOpenHandles

* Strict

* Fix client not stopping

* Add sync peeking tests

* Make test happier

* More strict

* Iterate

* Stabilise

* Moar strictness

* Improve coverage

* Fix types

* Fix types

* Improve types further

* Fix types

* Improve typing of NamespacedValue

* Fix types
2022-10-21 11:44:40 +01:00
Richard van der Hoff fdbbd9bca4 Merge pull request #2777 from matrix-org/rav/debug_to_device
An attempt to debug vector-im/element-web#23548: let's see if we can figure out where the to-device messages are getting lost.
2022-10-20 12:04:08 +01:00
Germain bf1137fc58 Fix to keep locally computed thread notifications (#2768) 2022-10-20 08:57:45 +01:00
David Baker 5a0787349d Fix connectivity regressions (#2780)
* Fix connectivity regressions

Switches back to addTrack, digging the transceivers out manually
to re-use, because the only way to group tracks into streams re-using
trasceivers from the offer is to use setStreams which FF doesn't
implement.

* Remove comments
2022-10-19 18:03:12 +01:00
David Baker c57c8978cf Fix screenshare failing after several attempts (#2771)
* Fix screenshare failing after several attempts

Re-use any existing transceivers when screen sharing. This prevents
transceivers accumulating and making the SDP too big: see linked bug.

This also switches from `addTrack()` to `addTransceiver ()` which is
not that large of a change, other than having to explicitly find the
transceivers after an offer has arrived rather than just adding tracks
and letting WebRTC take care of it.

Fixes https://github.com/vector-im/element-call/issues/625

* Fix tests

* Unused import

* Use a map instead of an array

* Add comment

* more comment

* Remove commented code

* Remove unintentional debugging

* Add test for screenshare transceiver re-use

* Type alias for transceiver map
2022-10-19 16:00:54 +01:00
renovate[bot] 508bb5841c Update all (#2774)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-19 12:59:56 +00:00
Richard van der Hoff 35227e3a75 Merge pull request #2776 from matrix-org/rav/fix-readme 2022-10-19 11:47:10 +01:00
Richard van der Hoff 620a8d9c7f Add debugging for unsent to-device messages 2022-10-19 11:23:52 +01:00
renovate[bot] 17e16b9b1a Update jest monorepo to v29.2.0 (#2773)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-19 10:55:47 +01:00
renovate[bot] 671dedca1c Update typescript-eslint monorepo to v5.40.1 (#2772)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2022-10-19 10:54:36 +01:00
Hugh Nimmo-Smith 2464a691ef Support sign in + E2EE set up using QR code implementing MSC3886, MSC3903 and MSC3906 (#2747)
* Clean implementation of MSC3886 and MSC3903

* Refactor to use object initialiser instead of lots of args + handle non-compliant fetch better

* Start of some unit tests

* Make AES work on Node.js as well as browser

* Tests for ECDH/X25519

* stric mode linting

* Fix incorrect test

* Refactor full rendezvous logic out of react-sdk into js-sdk

* Use correct unstable import

* Pass fetch around

* Make correct usage of fetch in tests

* fix: you can't call fetch when it's not on window

* Use class names to make it clearer that these are unstable MSC implementations

* Linting

* Clean implementation of MSC3886 and MSC3903

* Refactor to use object initialiser instead of lots of args + handle non-compliant fetch better

* Start of some unit tests

* Make AES work on Node.js as well as browser

* Tests for ECDH/X25519

* stric mode linting

* Fix incorrect test

* Refactor full rendezvous logic out of react-sdk into js-sdk

* Use correct unstable import

* Pass fetch around

* Make correct usage of fetch in tests

* fix: you can't call fetch when it's not on window

* Use class names to make it clearer that these are unstable MSC implementations

* Linting

* Reduce log noise

* Tidy up interface a bit

* Additional test for transport layer

* Linting

* Refactor dummy transport to be re-usable

* Remove redundant condition

* Handle more error cases

* Initial tests for MSC3906

* Reduce scope of PR to only cover generating a code on existing device

* Strict linting

* Additional test cases

* Lint

* additional test cases and remove some code smells

* More test cases

* Strict lint

* Strict lint

* Test case

* Refactor to handle UIA

* Unstable prefixes

* Lint

* Missed due to lack of strict...

* Test server capabilities using Feature

* Remove redundant assignment

* Refactor ro resuse generateDecimal from SAS

* Update src/rendezvous/transports/simpleHttpTransport.ts

Co-authored-by: Travis Ralston <travisr@matrix.org>

* Update src/rendezvous/transports/simpleHttpTransport.ts

Co-authored-by: Travis Ralston <travisr@matrix.org>

* Update src/rendezvous/channels/ecdhV1.ts

Co-authored-by: Travis Ralston <travisr@matrix.org>

* Update src/rendezvous/transports/simpleHttpTransport.ts

Co-authored-by: Travis Ralston <travisr@matrix.org>

* Rename files to titlecase

* Visibility modifiers

* Resolve public mutability

* Refactor logic to reduce duplication

* Refactor to have better defined data types throughout

* Rebase and remove Node.js crypto

* Wipe AES key out after use

* Add typing for MSC3906 layer

* Strict lint

* Fix double connect detection

* Remove unintended debug statement

* Return types

* Use generics

* Make type of MSC3903ECDHPayload explicit

* Use unstable prefix for RendezvousChannelAlgorithm

* Fix

* Extra unstable type

* Test types

Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Kerry <kerrya@element.io>
2022-10-19 09:30:15 +00:00
Richard van der Hoff d548b04d06 README.md: fix jsdoc viewer incantation
SimpleHTTPServer was python 2.
2022-10-19 10:19:23 +01:00
Richard van der Hoff 7ffdf17213 Merge pull request #2767 from matrix-org/rav/fix_comment 2022-10-19 10:13:18 +01:00
Valere 1c3dd0e51e Encryption should not hinder verification (#2734)
Co-authored-by: Faye Duxovni <fayed@matrix.org>
2022-10-18 15:56:34 -04:00
Michael Telatynski 0231d40277 Fix POST data not being passed for registerWithIdentityServer (#2769) 2022-10-18 15:58:17 +01:00
Richard van der Hoff b1e9f39d65 Remove incorrect comment
As with most of the crypto functionality, `setCryptoTrustCrossSignedDevices`
cannot be called until after `initCrypto`.
2022-10-17 22:58:04 +01:00
David Baker dfe535bc07 More debugging for multiple group calls (#2766) 2022-10-17 20:14:44 +01:00
Robin Townsend 3c33c422e6 Merge branch 'develop' into robertlong/group-call 2022-10-13 20:21:51 -04:00
Robin d521f97411 Merge pull request #2754 from robintown/unblock-mute
Don't block muting/unmuting on network requests
2022-10-13 19:54:57 -04:00
Robin Townsend c0a5299704 Don't block muting/unmuting on network requests
(PTT mode will still block on them, as expected)
2022-10-13 11:56:46 -04:00
Robin ce3b72c850 Merge pull request #2712 from robintown/merge
Merge develop
2022-09-29 08:03:36 -04:00
Robin Townsend 935517746a Merge branch 'develop' into robertlong/group-call 2022-09-28 14:13:45 -04:00
David Baker e48d919cd4 Fix ICE restarts (#2702)
We didn't reset the 'seen end of candidates' flag when doign an ICE
restart, so we would have ignored all locally gathered candidates
on an ICE restart.
2022-09-27 17:25:04 +01:00
Šimon Brandner ab39ee37d6 Add more MatrixCall tests (#2697)
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2022-09-26 12:02:41 +02:00
Šimon Brandner af6f9d49f4 Add CallEventHandler tests (#2696)
* Add `CallEventHandler` tests

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Avoid tests hanging

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2022-09-26 12:02:19 +02:00
Šimon Brandner a2981efac3 Add MatrixClient group call tests (#2692)
Co-authored-by: Robin <robin@robin.town>
2022-09-23 18:33:31 +02:00
Šimon Brandner 4625ed73cf Merge pull request #2695 from matrix-org/SimonBrandner/task/gc-merge 2022-09-23 17:43:23 +02:00
Šimon Brandner 6f7a72d69e Merge remote-tracking branch 'upstream/develop' into SimonBrandner/task/gc-merge
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2022-09-23 15:36:44 +02:00
Šimon Brandner 2a0ffe1223 Fix group call tests getting stuck (#2689) 2022-09-22 17:06:01 +02:00
Šimon Brandner 72a6ec0dd3 Add a few group call event handler tests (#2679) 2022-09-22 17:05:51 +02:00
Šimon Brandner 72b89fde6e Add test for call transfers (#2677) 2022-09-20 19:41:03 +02:00
Šimon Brandner c400dd4ff8 Add a few new GroupCall tests (#2678)
Co-authored-by: Robin <robin@robin.town>
2022-09-20 19:40:47 +02:00
Robin f41b7706e4 Upgrade matrix-widget-api (and fix the lockfile) (#2676) 2022-09-16 11:08:13 -04:00
Robin de694459be Target widget actions at a specific room (#2670)
Otherwise, the RoomWidgetClient class can end up accidentally sending and receiving events from rooms it didn't intend to, if it's an always-on-screen widget.
2022-09-16 10:26:03 -04:00
David Baker 6fc9827b10 Add tests for ice candidate sending (#2674) 2022-09-16 09:26:37 +01:00
David Baker f52c5eb667 Unused imports from merge 2022-09-14 09:53:07 +01:00
David Baker c05cb3ad2b Merge branch 'develop' into robertlong/group-call 2022-09-14 09:51:43 +01:00
David Baker 586a313c8d Add tests for call answering / candidate sending (#2666)
* Add tests for call answering / candidate sending

* Remopve unused stuff

* Capitalise

Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Capitalisation

* Capitalise

* Fix typescript strict error

* Actually fix TS strict error(?)

* TS strict mode try 3

Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>
2022-09-14 09:42:57 +01:00
David Baker c605310b87 Prevent exception when muting (#2667)
Fixes https://github.com/vector-im/element-call/issues/578
2022-09-13 20:02:14 +01:00
David Baker 41cee6f1cc Fix race in creating calls (#2662)
* Fix race in creating calls

We ran an async function between checking for an existing call and
adding the new one to the map, so it would have been possible to
start creating another call while we were placing the first call.
This changes the code to add the call to the map as soon as we've
created it.

Also adds more logging.

* Switch to logger.debug

* Fix unit tests
2022-09-13 16:30:34 +01:00
David Baker 3e1e99f8e5 Fix import in failed merge 2022-09-12 10:34:35 +01:00
David Baker 276849f068 Merge branch 'develop' into robertlong/group-call 2022-09-12 10:03:48 +01:00
David Baker 37118991f5 Add test for removing RTX codec (#2660)
* Add test for removing RTX codec

* Use mocked to cast
2022-09-12 09:40:28 +01:00
David Baker 00629e6dc9 Test fallback screensharing (#2659)
* Test fallback screensharing

* Test replacetrack is called

* Unused import

* Return type

* Fix other test after new track IDs
2022-09-09 21:15:34 +01:00
David Baker 02f6a09bcf Test active speaker events (#2658)
Fixes https://github.com/vector-im/element-call/issues/527
2022-09-09 18:57:25 +01:00
Robin 36a6117ee2 Misc fixes for group call widgets (#2657)
* Fix GroupCallEventHandler in matryoshka mode

GroupCallEventHandler needs to see a 'Syncing' event before it starts handling any events, so emit one immediately in matryoshka mode.

* Implement joinRoom on RoomWidgetClient

Element Call has undergone some changes to how it loads rooms, meaning that this method must be implemented for the app to work in matryoshka mode.

* Allow audio and video to be muted before local call feed exists

This is desirable for the Element Web integration of Element Call, because we need to be able to mute our devices before ever joining the call or creating a call feed, if the users requests it.

* Fix a strict mode error
2022-09-09 09:53:27 -04:00
David Baker aebe26db96 GroupCallEventhandler Tests (#2654)
* GroupCallEventhandler Tests

Fixes https://github.com/vector-im/element-call/issues/545

* Fix long line

* Fix strict mode error

Co-authored-by: Robin <robin@robin.town>

* Fix typo

Co-authored-by: Robin <robin@robin.town>

Co-authored-by: Robin <robin@robin.town>
2022-09-08 21:46:28 +01:00
David Baker 60e175a0e0 Merge branch 'develop' into robertlong/group-call 2022-09-08 20:52:08 +01:00
David Baker d950cda05c Merge branch 'develop' into robertlong/group-call 2022-09-08 15:03:55 +01:00
David Baker 83c848093f MediaHandler Tests (#2646)
* MediaHandler Tests, part 1

Haven't got through all the methods yet

For https://github.com/vector-im/element-call/issues/544

* Didn't need these in the end

* Rest of the media handler tests

* getUserMediaStream takes args

* use mockResolvedValue

* Add .off & reuse the mock we already made

* Re-use mock handler again

* Move updateLocalUsermediaStream to beforeEach

* add .off

* Add types

* Add more .offs
2022-09-07 15:56:38 +01:00
David Baker fa6f70f708 Log ID instead of object (#2643)
as otherwise it recurses and logs the entire client + store
2022-09-06 18:09:34 +01:00
David Baker 98d119d6e1 Add client.waitUntilRoomReadyForGroupCalls() (#2641)
See comment, although this still feels like a poor solution to the
problem. Might be better if the js-sdk processed everything internally
before emitting the 'Room' event (or indeed before joinRoom resolved)
so the app knows everything is ready when it gets that event.
2022-09-06 13:54:48 +01:00
David Baker aca51fd8a3 Test call mute status set on call state chnage (#2638) 2022-09-05 17:06:49 +01:00
David Baker c78631bdee Test that calls in a group call are retried (#2637)
* Test that calls in a group call are retried

* Add new flushpromises file
2022-09-05 09:45:32 +01:00
David Baker 0d6a93b5f6 Refactor the group call placing calls test (#2636)
Add some types & use mock-typed versions directly - it's clearer which
client we're making assertions about.
2022-09-02 15:33:22 +01:00
David Baker 40ecfa7932 Test disabling screenshare in group calls (#2634)
Also add a few more types
2022-09-02 12:57:29 +01:00
David Baker d656b848f8 Wait for client to start syncing before making group calls (#2632)
As hopefully explained in comment

Fixes https://github.com/matrix-org/matrix-js-sdk/issues/2589
2022-09-01 17:57:38 +01:00
David Baker 0981652de4 Add GroupCallEventHandlerEvent.Room (#2631)
* Add GroupCalEventHandlerEvent.Room

Emit an event when the group call event handler has processed all
pending group calls.

* Remove unused return value

* Add void return type

Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>

Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>
2022-09-01 16:18:37 +01:00
David Baker db32420d16 Add logging to diagnose connection issue (#2629)
For https://github.com/vector-im/element-call/issues/559
2022-08-31 13:40:55 +01:00
David Baker d5b82e343a Add types to the call unit test suites (#2627)
* Add types to the call unit test suites

Still involves quite a few casts to any unfortunately as it turns
out we access quite a few private methods on the Call class in these
tests.

* Remove commented line & use better expect syntax

* Replace more calls.length with toHaveBeenCalled

* Remove mistakenly added id field
2022-08-31 11:15:13 +01:00
David Baker 965f4fb13b Fix ICE end-of-candidates messages (#2622)
* Fix ICE end-of-candidates messages

We were casting a POJO to an RTCIceCandidate for the dummy
end-of-candidates candidate, but https://github.com/matrix-org/matrix-js-sdk/pull/2473
started calling .toJSON() on these objects.

Store separately whether we've seen the end of candidates rather than
adding on a dummy candidate object.

A test for this will follow, but a) I want to get this fix out and
b) I'm currently rewriting the call test file to add typing.

Fixes https://github.com/vector-im/element-call/issues/553

* Remove hacks for testing

* Switch if branches
2022-08-26 10:04:07 +01:00
David Baker 9e1b126854 1:1 screenshare tests (#2617)
* 1:1 screenshare tests

Fixes https://github.com/vector-im/element-call/issues/548

* Always hang up calls after tests

to prevent hanging tests

Also fix a null dereference as we may not have an invitee or opponent
member when sending voip events if not using to-device messages.

* use mockImplementationOnce

Co-authored-by: Robin <robin@robin.town>

* use mockImplementationOnce

Co-authored-by: Robin <robin@robin.town>

* Add type on mock

* Add corresponding call.off

* Merge enable & disable screenshare tests

Co-authored-by: Robin <robin@robin.town>
2022-08-24 15:45:53 +01:00
David Baker c527f85fb1 Revert 4a294c9dd3
Pushed to wrong branch
2022-08-23 22:03:25 +01:00
David Baker 4a294c9dd3 1:1 screenshare tests
Fixes https://github.com/vector-im/element-call/issues/548
2022-08-23 22:02:32 +01:00
David Baker be94f5ea93 Fix imports 2022-08-22 20:30:27 +01:00
David Baker 5f9369abee Merge branch 'develop' into robertlong/group-call 2022-08-22 20:19:53 +01:00
David Baker e7a7ec0673 Test call timeouts (#2611)
Fixes https://github.com/vector-im/element-call/issues/547
2022-08-22 20:17:19 +01:00
David Baker 92cd84fc0c Add unit tests for hangup / reject (#2606)
* Add unit tests for hangup / reject

Fixes https://github.com/vector-im/element-call/issues/537

* Fix some bugs where we carried on with the call after it had been ended
2022-08-22 13:29:54 +01:00
Šimon Brandner 45e56f8cc3 Add disposed to CallFeed (#2604) 2022-08-19 17:33:55 +02:00
Robin e95947dc73 Update lockfile (#2603) 2022-08-19 08:22:37 -04:00
Šimon Brandner 448a5c9a77 Add screensharing tests (#2598) 2022-08-18 10:42:03 +02:00
David Baker 9589a97952 Test muting in PTT mode (#2599)
Fixes https://github.com/vector-im/element-call/issues/523
2022-08-17 18:09:46 +01:00
David Baker 2566c40e96 Add tests for incoming calls in group calls (#2597)
* Add tests for incoming calls in group calls

Inspiration wwlecome for the renamed describe group which we're
really abusing for a bunch of things that happen to have the same
dependencies.

Fixes https://github.com/vector-im/element-call/issues/532

* Extract incoming call tests out into their own describe

and get the lexicographical ordering to match who should be calling who

* Trailing space
2022-08-17 15:10:03 +01:00
David Baker 099cac0162 Merge branch 'develop' into robertlong/group-call 2022-08-17 12:34:25 +01:00
David Baker e4cf5b26ee Add test for updateLocalUsermediaStream (#2596) 2022-08-17 12:33:11 +01:00
Šimon Brandner c698317f3f Add group call tests for muting (#2590) 2022-08-17 10:59:54 +02:00
David Baker e8f682f452 Test placing a call in a group call (#2593)
* Test placing a call in a group call

Refactors a bit of the call testing stuff

Fixes https://github.com/vector-im/element-call/issues/521

* Unused imports

* Use expect.toHaveBeenCalledWith()

* Types

* More types

* Add comment on mock typing

* Use toHaveBeenCalledWith()

* Initialise groupcall & room in beforeEach

* Initialise mockMediahandler sensibly

* Add type params to mock

* Rename mute tests

* Move comment

* Join / leave in parallel

* Remove leftover expect
2022-08-16 18:22:36 +01:00
David Baker 020743141b Tidy up imports (#2584)
Duplicate 'call' imports
2022-08-10 18:07:49 +01:00
David Baker 5f5a9b1a43 Merge branch 'develop' into robertlong/group-call 2022-08-10 14:31:39 +01:00
Robin 3334c01191 Support nested Matrix clients via the widget API (#2473)
* WIP RoomWidgetClient

* Wait for the widget API to become ready before backfilling

* Add support for sending user-defined encrypted to-device messages

This is a port of the same change from the robertlong/group-call branch.

* Fix tests

* Emit an event when the client receives TURN servers

* Expose the method in MatrixClient

* Override the encryptAndSendToDevices method

* Add support for TURN servers in embedded mode and make calls mostly work

* Don't put unclonable objects into VoIP events

RoomWidget clients were unable to send m.call.candidate events, because
the candidate objects were not clonable for use with postMessage.
Converting such objects to their canonical JSON form before attempting
to send them over the wire solves this.

* Fix types

* Fix more types

* Fix lint

* Upgrade matrix-widget-api

* Save lockfile

* Untangle dependencies to fix tests

* Add some preliminary tests

* Fix tests

* Fix indirect export

* Add more tests

* Resolve TODOs

* Add queueToDevice to RoomWidgetClient
2022-08-09 09:45:58 -04:00
David Baker 0b8de251bf Add basic creation / entering tests for group calls (#2575)
* Add basic creation / entering tests for group calls

* Missing space

Co-authored-by: Robin <robin@robin.town>

* Assert more of the group call member event

and also move call leaving to a finally so it doesn't leaving a call
hagning if it fails.

Co-authored-by: Robin <robin@robin.town>
2022-08-09 13:43:02 +01:00
David Baker 88ce017333 Fix return types of event sending functions (#2576)
These had somehow got mixed up so the type check was failing.
Nothing uses the response return type, so just return void.
2022-08-09 13:11:59 +01:00
David Baker 471f174889 Merge remote-tracking branch 'origin/develop' into robertlong/group-call 2022-08-05 15:59:01 +01:00
David Baker c0dacb5037 Merge remote-tracking branch 'origin/develop' into robertlong/group-call 2022-08-05 11:06:10 +01:00
David Baker 2cc51e0db7 Merge changes from develop (#2563)
* Prepare changelog for v19.2.0-rc.1

* v19.2.0-rc.1

* Sliding sync: add missing filters from latest MSC

* Gracefully handle missing room_ids

* Prepare changelog for v19.2.0

* v19.2.0

* Resetting package fields for development

* Use EventType enum values instead of hardcoded strings (#2557)

* Retry to-device messages (#2549)

* Retry to-device messages

This adds a queueToDevice API alongside sendToDevice which is a
much higher-level API that adds the messages to a queue, stored in
persistent storage, and retries them periodically. Also converts
sending of megolm keys to use the new API.

Other uses of sendToDevice are nopt converted in this PR, but could
be later.

Requires https://github.com/matrix-org/matrix-mock-request/pull/17

* Bump matrix-mock-request

* Add more waits to make indexeddb tests pass

* Switch some test expectations to queueToDevice

* Stop straight away if the client has been stopped

Hopefully will fix tests being flakey and logging after tests have
finished.

* Add return types & fix constant usage

* Fix return type

Co-authored-by: Germain <germains@element.io>

* Fix return type

Co-authored-by: Germain <germains@element.io>

* Fix return type

Co-authored-by: Germain <germains@element.io>

* Stop the client in all test cases

Co-authored-by: Germain <germains@element.io>

* Add support for sending user-defined encrypted to-device messages (#2528)

* Add support for sending user-defined encrypted to-device messages

This is a port of the same change from the robertlong/group-call branch.

* Fix tests

* Expose the method in MatrixClient

* Fix a code smell

* Fix types

* Test the MatrixClient method

* Fix some types in Crypto test suite

* Test the Crypto method

* Fix tests

* Upgrade matrix-mock-request

* Move useRealTimers to afterEach

* Remove stream-replacement (#2551)

* Reintroduce setNewStream method, fix test, update yarn.lock

Co-authored-by: RiotRobot <releases@riot.im>
Co-authored-by: Kegan Dougal <kegan@matrix.org>
Co-authored-by: Germain <germains@element.io>
Co-authored-by: Robin <robin@robin.town>
Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>
2022-08-04 17:28:54 +01:00
Šimon Brandner 22c5999fed Delint group calls (#2554) 2022-08-01 18:45:14 +02:00
David Baker b711781f16 Merge remote-tracking branch 'origin/develop' into robertlong/group-call 2022-07-29 10:56:01 +01:00
Šimon Brandner 8ba2d257ae Add support for audio sharing (#2530) 2022-07-28 18:12:11 +02:00
David Baker 9e2e144530 Make SDP munging media type specific (#2526)
* Make SDP munging media type specific

We were trying to apply modifications to all media types which led
to confusing warning messages saying opus wasn't present (when it
was for the video stream). Make the modifications media-type specific
to avoid this.

* Make codec * mediatype into enums
2022-07-28 09:38:57 +01:00
Timo 38a6949e5d add missing events from reemitter to GroupCall (#2527) 2022-07-25 09:44:37 -07:00
Šimon Brandner e876482e62 Add local volume control (#2525) 2022-07-25 15:51:06 +02:00
David Baker 544b1c6742 Merge develop into group call branch again (#2513)
* Send call version `1` as a string (#2471)

* test typescriptification - backup.spec (#2468)

* renamed:    spec/unit/crypto/crypto-utils.js -> spec/unit/crypto/crypto-utils.ts

* ts fixes in crypto-utils

* renamed:    spec/unit/crypto/backup.spec.js -> spec/unit/crypto/backup.spec.ts

* ts fixes in backup.spec

* remove fit

* remove debug

* Prepare changelog for v19.0.0-rc.1

* v19.0.0-rc.1

* Update jest monorepo (#2476)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update all (#2475)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Update dependency @types/jest to v28 (#2478)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Fix call.collectCallStats() (#2480)

Regressed by https://github.com/matrix-org/matrix-js-sdk/pull/2352
(you can just use RTCStatsReport as an iterator directly (which
was was what that code was doing before) which uses entries(
which gives you key/value pairs, but using forEach gives you just
the value.

* Go back to forEach in collectcallstats (#2481)

Older typescript library doesn't know about .values() on the stats
object, so it was failing in react sdk which had an older typescript.
https://github.com/matrix-org/matrix-react-sdk/pull/8935 was an
attempt to upgrade it but did not seem to be helping on CI, despite
being fine locally.

* Update babel monorepo to v7.18.6 (#2477)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Expose KNOWN_SAFE_ROOM_VERSION (#2474)

* Fix return type on funcs in matrixClient to be optionally null (#2488)

* Update pull_request.yaml (#2490)

* Lock file maintenance (#2491)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* Prepare changelog for v19.0.0

* v19.0.0

* Resetting package fields for development

* Improve VoIP integrations testing (#2495)

* Remove MSC3244 support (#2504)

* Actually store the identity server in the client when given as an option (#2503)

* Actually store the identity server in the client when given as an option

* Update requestRegisterEmailToken to a modern spec version too

* Properly re-insert room ID in bundled thread relation messages from sync (#2505)

Events returned by the `/sync` endpoint, including relations bundled with other events, may have their `room_id`s stripped out. This causes decryption errors if the IDs aren't repopulated.

Fixes vector-im/element-web#22094.

* Remove `setNow` from `realtime-callbacks.ts` (#2509)

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Remove dead code (#2510)

* Don't crash with undefined room in `processBeaconEvents()` (#2500)

* Add a basic PR checklist for all PRs (#2511)

It'll be mildly annoying for core developers who have to constantly remove or edit this, but it'll also serve as a good reminder to do these things.

Note that signoff is not required for core developers.

* Fix tests

Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>
Co-authored-by: Kerry <kerrya@element.io>
Co-authored-by: RiotRobot <releases@riot.im>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Weimann <michaelw@matrix.org>
Co-authored-by: texuf <texuf.eth@gmail.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: Travis Ralston <travisr@matrix.org>
Co-authored-by: Faye Duxovni <fayed@element.io>
2022-07-12 19:27:41 +01:00
David Baker 984dd26a13 Prevent double mute status changed events (#2502)
Audio & video mute status were set in separate calls but share a
mute status changed event, so you'd always get two mute status
changed events emitted. We could suppress events where the mute
status didn't change, but this would still get two events saying
the same thing when they both changed. Instead, merge setAudioMuted
& setVideoMuted into a single call that sets either or both.
2022-07-08 09:45:02 +01:00
David Baker bdb91b3806 Set max average bitrate on PTT calls (#2499)
* Set max average bitrate on PTT calls

Via SDP munging. Also makes the SDP munging a bit more generic and
codec-specific (we were previously adding usedtx to any codec that had an fmtp
line already, which was probably not really the intention).

* Make SDP munging for codecs that don't already have fmtp lines

* Use sensible typescript syntax

Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>

Co-authored-by: Šimon Brandner <simon.bra.ag@gmail.com>
2022-07-06 22:04:41 +01:00
David Baker 9a15094374 Add config option for e2e group call signalling (#2492) 2022-07-05 13:17:23 +01:00
Robin e980c88901 Don't mute the remote side immediately in PTT calls (#2487)
This clause was causing all PTT calls to mute the remote side
immediately upon ICE connection status changing to 'checking'.
2022-07-02 09:19:07 -04:00
David Baker 6ea2885796 Remove empty decryption listener (#2486)
* Remove empty decryption listener

This listener looks like it was left over from something as it just
did nothing at all. The todevice event gets put into the call
event buffer which awaits on decryption for each event before
processing, so it should already wait for decryption.

More info: https://github.com/vector-im/element-call/issues/428

* Unused import

* Unused function!
2022-07-01 17:44:00 +01:00
David Baker ca5ac79927 Revert hack to only clone streams on safari (#2485)
Reverts https://github.com/matrix-org/matrix-js-sdk/pull/2450

Looks like this wasn't really the problem (although may have made it
happens faster) and the actual problem was multiple audio contexts
and/or leaking peer connections as fixed in https://github.com/matrix-org/matrix-js-sdk/pull/2484
2022-07-01 17:32:17 +01:00
Robin f9672cf307 Fix some MatrixCall leaks and use a shared AudioContext (#2484)
* Fix some MatrixCall leaks and use a shared AudioContext

These leaks, combined with the dozens of AudioContexts floating around in memory across different CallFeeds, could cause some really bad performance issues and audio crashes on Chrome.

* Fully release the AudioContext in CallFeed's dispose method

* Fix tests
2022-07-01 11:58:00 -04:00
Robin e7493fd417 Enable DTX on audio tracks in calls (#2482)
This greatly reduces the amount of bandwidth used when transmitting
silence.
2022-06-29 16:06:17 -04:00
David Baker f553854730 Remove the feature to disable audio from muted members (#2479)
At the moment it looks like its more valuable to get the audio from
people even if they're not actually shown as speaking. We can always
re-introduce it later.
2022-06-29 18:47:01 +01:00
David Baker c89bbf4bf5 Fix call.collectCallStats() (#2480)
Regressed by https://github.com/matrix-org/matrix-js-sdk/pull/2352
(you can just use RTCStatsReport as an iterator directly (which
was was what that code was doing before) which uses entries(
which gives you key/value pairs, but using forEach gives you just
the value.
2022-06-29 12:39:36 +01:00
Robin Townsend ebcb26f1b3 Merge branch 'develop' into robertlong/group-call 2022-06-21 11:21:03 -04:00
Robin 5b4263bf55 Don't block muting on determining whether the device exists (#2461)
* Don't block muting on determining whether the device exists

* Add comments
2022-06-16 13:51:32 -04:00
Robin df9ffdc408 Don't ignore call member events with a distant future expiration date (#2466)
to match updates to MSC3401
2022-06-16 12:55:37 -04:00
Robin 70449ea003 Expire call member state events after 1 hour (#2446)
* Expire call member state events after 1 hour

* Fix lints

* Avoid a possible race
2022-06-16 11:31:13 -04:00
David Baker 9192b876d2 Disable playback of audio for muted users (#2456)
* Disable playback of audio for muted users

As hopefully explained by the comment

* forEach instead of map
2022-06-13 20:46:34 +01:00
Travis Ralston 04d0d61a0e Change CODEOWNERS for element-call feature branch (#2457)
To reduce review requests going to the "wrong" team. The team has been mirrored from the vector-im side.
2022-06-13 12:23:50 -06:00
David Baker 404f8e130e Only clone streams on Safari (#2450)
Only enable the stream cloning behaviour on Safari: it was causing
the audio renderer on Chrome (both desktop and Android) to hang,
causing audio to fail sometimes in Element Call and other Chrome
tabs (eg. YouTube) to fail to play audio.

Fixes https://github.com/vector-im/element-call/issues/267
2022-06-10 21:02:04 +01:00
David Baker b97b862fb6 Emit unknown device errors for group call participants without e2e (#2447)
* Emit unknown device errors for group call participants without e2e

There are a number of different cases here: there were some before
when dealing with versions that didn't send deviceId. This catches
all of them and makes all these cases emit the same error.

* Add type
2022-06-10 12:01:40 +01:00
David Baker 5e766978b8 Set PTT mode on call correctly (#2445)
And not always to true. This was causing audio & video to start muted
sometimes on normal calls because the ICE connection state would change
to 'checking', causing the feeds to be muted.
2022-06-08 19:28:53 +01:00
David Baker 34ef7bc64a Mute disconnected peers in PTT mode (#2421)
When we lose ICE connection to peers, set the status of their feeds
to muted so to end their talking session.

For https://github.com/vector-im/element-call/issues/331
2022-05-31 13:43:37 +01:00
David Baker 18e2052af2 Wait for mute event to send in PTT mode (#2401)
This waits until the mute metadata update is sent to all the calls
before telling the user they're unmuted, when in PTT mode (and only
when starting to talk, ie. unmuting). This should help avoid situations
where the signalling connection is slow enough that the unmute event
takes long enough to reach the other side that you hear someone speak
before they've apparently unmuted.

Involves splitting out the method to send the metadata update.
2022-05-26 13:06:57 +01:00
David Baker aa0d3bd1f5 Handle other members having no e2e keys (#2383)
Fetch the device info once at the start of the cal and cache it
rather than fetching every time, and throw if we're supposed to be
using e2e but the other end has no e2e keys.
2022-05-19 19:09:15 +01:00
Robert Long 942a28ddf6 Add support for sending encrypted to-device events with OLM (#2322) 2022-05-18 14:45:26 +01:00
David Baker 87791cd391 Fix races when muting/unmuting (#2370)
await on the async operation so the promise we return resolves once
everything's actuall complete
2022-05-13 19:26:25 +01:00
David Baker 38e54ae7f2 Remove PTT 'other user speaking' logic (#2362)
This was also in Element Call, and whilst js-=sdk might be a more
sensible place, EC has all the information to do it properly (this
impl didn't take admin talk-over into account).
2022-05-11 16:31:14 +01:00
David Baker acef1d7dd0 Merge branch 'dbkr/group-call-merge' of github.com:matrix-org/matrix-js-sdk into dbkr/group-call-merge 2022-05-10 17:24:40 +01:00
David Baker da615fd512 More setTimeout typings 2022-05-10 17:24:21 +01:00
Michael Telatynski f4f05550ef Merge branch 'develop' into dbkr/group-call-merge 2022-05-10 17:11:20 +01:00
David Baker f475251ddd Merge remote-tracking branch 'origin/develop' into dbkr/group-call-merge 2022-05-10 16:50:45 +01:00
David Baker 83f61c96f3 Merge remote-tracking branch 'origin/develop' into dbkr/group-call-merge 2022-05-10 16:39:07 +01:00
David Baker 85a6a552b5 Make tests pass again
Now we know what that bit in the crypto unit test was for...
2022-05-10 16:30:04 +01:00
David Baker 9702e8a5fa Remove test 'fix'
as I can't work out why it was needed, so I can't justify keeping
it in the group calls merge. It should be PRed to develop separately
if needed.
2022-05-09 22:49:32 +01:00
David Baker d82c041b99 Merge remote-tracking branch 'origin/develop' into robertlong/group-call 2022-05-09 22:46:43 +01:00
David Baker 8d9cd0fcb3 Support for PTT group call mode (#2338)
* Add PTT call mode & mute by default in PTT calls (#2311)

No other parts of PTT calls implemented yet

* Make the tests pass again (#2316)

https://github.com/matrix-org/matrix-js-sdk/commit/3280394bf93622c096e3e260296f7f089b97846b
made call use a bunch of methods that weren't mocked in the tests.

* Add maximum trasmit time for PTT (#2312)

on sender side by muting mic after the max transmit time has elapsed.

* Don't allow user to unmute if another user is speaking  (#2313)

* Add maximum trasmit time for PTT

on sender side by muting mic after the max transmit time has elapsed.

* Don't allow user to unmute if another user is speaking

Based on https://github.com/matrix-org/matrix-js-sdk/pull/2312
For https://github.com/vector-im/element-call/issues/298

* Fix createGroupCall arguments (#2325)

Comma instead of a colon...
2022-05-03 13:14:52 +01:00
Robert Long 96ba061732 Fix shouldRequestAudio logging 2022-03-01 16:27:41 -08:00
David Baker ee4cbd1ec9 Don't remove streams that still have tracks (#2104)
If a renogotiation ends up with one track being removed, we removed
the whole stream, which would cause us to lose, for example, audio
rather than just video.
2022-03-01 15:39:36 -08:00
David Baker 2a0dc39eec Fix bug with ine-way audio after a transfer (#2193)
Seems chrome at least will give you a disabled audio track if you
already had another user media audio track and disabled it, so make
sure our tracks are enabled when we add them. We already did this
on one code path but it didn't get moved over when a new code path
was added.

On the plus side, we now know the reason for the ancient code that
had the comment asking what it was for, so update that.
2022-03-01 15:36:48 -08:00
Robert Long 6e25b13312 Send / add end-of-candidates messages 2022-02-28 16:07:36 -08:00
Robert Long 94c5e37570 Fix import 2022-02-25 10:01:17 -08:00
Robert Long 09fee4a2d9 Allow calls to terminate properly when calling stopClient 2022-02-25 09:48:19 -08:00
Robert Long 49994ac4fc Add checks for call/groupCall ended for updateLocalUsermediaStream 2022-02-25 09:42:41 -08:00
Robert Long e68cabc70e Add logging for all stream creation/cloning/muting 2022-02-24 12:55:08 -08:00
Robert Long c819ac634f Fix updating local media streams 2022-02-24 12:10:02 -08:00
Robert Long 17f5ab4191 Move device changes to the application. Add methods to set device ids 2022-02-23 15:07:13 -08:00
Robert Long e270f075a4 Fix call log 2022-02-22 16:57:43 -08:00
Robert Long 0ef6c2e35f Add callId to all logs 2022-02-18 17:47:01 -08:00
Robert Long 7a249e3ef5 Switch media devices on disconnect 2022-02-18 14:35:09 -08:00
Robert Long 353d6bab47 Fix and add a test for toDevice ordering 2022-02-18 11:35:56 -08:00
Robert Long 7f21f569d5 Process toDevice events in order 2022-02-17 14:08:17 -08:00
Robert Long fa5eae70dd Log complete sync errors 2022-02-17 14:07:21 -08:00
David Baker 3db056ad3e Enable max-bundle (#2182)
No particular reason to worry about old user agents here
2022-02-16 11:06:46 -08:00
Robert Long a2a127d9a4 Remove unused isSafari check 2022-02-15 10:53:28 -08:00
Robert Long d12bccd211 Remove safari hack 2022-02-15 10:51:22 -08:00
Robert Long d8e597ccdf Avoid glare 2022-02-11 17:01:22 -08:00
Robert Long c801690e28 Don't reuse local call feeds that have been added to a RTCPeerConnection 2022-02-11 16:56:47 -08:00
Robert Long b4fe00a3a8 Add answer/negotiate response promise chain 2022-02-10 10:31:52 -08:00
Robert Long d42e2fe2c0 Ignore duplicate streams when adding local feeds 2022-02-10 09:32:34 -08:00
Robert Long 4a4465b9fc Don't send candidates after the call has ended 2022-02-07 14:42:07 -08:00
Robert Long 1a78301adb Fix restartIce on FF Android 2022-02-04 12:11:37 -08:00
Robert Long bbf7020755 Remove log 2022-01-18 10:39:02 -08:00
Robert Long 592fb0cf10 Re-enable retries 2022-01-18 10:37:49 -08:00
Robert Long 015eb5d5c4 Add sender/dest session ids 2022-01-14 13:40:42 -08:00
Robert Long 42fef0e7aa Add user id to all send voip events 2022-01-13 14:10:39 -08:00
Robert Long 28f3169a28 Use replace error code when replacing incoming calls 2022-01-12 13:17:19 -08:00
Robert Long d8285aad00 Remove call from callEventHandler after hangup 2022-01-12 13:17:03 -08:00
Robert Long eeacf8c22c Dont filter unstable call events 2022-01-11 17:47:01 -08:00
Robert Long ee995cb39b Ensure call events are processed once and in order 2022-01-11 16:54:40 -08:00
Robert Long 7529af43e4 Add NewSession CallErrorCode 2022-01-11 16:54:12 -08:00
Robert Long 3fac6d7180 Replace outbound calls only 2022-01-10 16:46:55 -08:00
Robert Long 487bfc88ef Merge branch 'robertlong/group-call-session-id' into robertlong/group-call-disable-retries 2022-01-10 16:25:39 -08:00
Robert Long c91617a799 Force hangup replaced calls 2022-01-10 16:22:52 -08:00
Robert Long 87bf115967 Use session ids to resolve refresh during invite/answer 2022-01-10 15:57:40 -08:00
Robert Long 18bb5c3079 Log opponentDeviceId 2022-01-07 11:14:44 -08:00
Robert Long f3f9e41787 Emit sent voip events 2022-01-07 11:14:27 -08:00
Robert Long 7993dd7630 Log opponentDeviceId 2022-01-06 15:46:55 -08:00
Robert Long bef557976b Emit sent voip events 2022-01-06 15:24:59 -08:00
Robert Long 549f9b7e29 Disable retries 2022-01-06 14:44:16 -08:00
Robert Long 06d9d6207c Send device id along with to device signaling messages 2021-11-30 13:39:43 -08:00
Robert Long e336aceaba Expose webrtc related types/props 2021-11-30 13:01:35 -08:00
Robert Long fcc4b71f06 Add LocalStreamsChanged event to MediaHandler 2021-11-29 14:34:43 -08:00
Robert Long d1a62eddfc Set initial audio/video input ids 2021-11-24 12:43:50 -08:00
Robert Long ffbd10a7b8 Make updateLocalUsermediaStreams stop tracks 2021-11-22 13:26:29 -08:00
Robert Long d0e37ee323 Hopefully resolve a race condition with missing device ids 2021-11-19 16:49:20 -08:00
Robert Long 96ef535ebb Make unknown device error more useful 2021-11-19 16:06:29 -08:00
Robert Long 0683133d5b Dont start retry loop until weve sent the member state event 2021-11-19 16:02:26 -08:00
Robert Long 64c3ac55a4 Stop screenshare when screensharing track ended 2021-11-19 13:56:50 -08:00
Robert Long 5f06df8a87 Properly stop screensharing feed 2021-11-18 13:53:30 -08:00
Robert Long 3291846714 Merge branch 'robertlong/abort-sync-error' into robertlong/group-call 2021-11-17 16:10:20 -08:00
Robert Long 139904f297 Update sync state to error when aborting 2021-11-17 16:05:02 -08:00
Robert Long c2fe2ab270 Add additional logging for removing feeds/tracks 2021-11-15 14:20:55 -08:00
Robert Long 4e26f29032 Add unknown device errors 2021-11-15 12:05:34 -08:00
Robert Long 31391121dc Clean up logging 2021-11-15 11:38:47 -08:00
Robert Long 7d48a8394d Don't immediately start retry call loop 2021-11-15 10:48:24 -08:00
Robert Long 28da62c01c Add retry call loop 2021-11-09 15:31:27 -08:00
Robert Long e880cece93 Add restart ICE 2021-11-09 14:40:29 -08:00
Robert Long 97e8fcea75 Clean up replacing calls for Safari 2021-11-09 14:01:16 -08:00
Robert Long f28cb48fe1 Re-enable safari hack 2021-11-08 13:07:22 -08:00
Robert Long a2e255c2c9 Merge branch 'robertlong/group-call' of github.com:matrix-org/matrix-js-sdk into robertlong/group-call 2021-11-08 12:58:54 -08:00
Robert Long 74c5a20371 Temporarily disable safari hack 2021-11-08 12:57:38 -08:00
Robert Long 4b87907b92 Update local usermedia streams serially 2021-11-08 12:30:56 -08:00
Robert Long f76f708c96 Ad a longer wait to safari media stream hack 2021-11-05 14:31:38 -07:00
Robert Long 17f7dc5463 Keep track of original stream id for sdp stream metadata 2021-11-04 17:44:47 -07:00
Robert Long b253ad9e81 Preserve the disabled tracks when updating local usermedia stream 2021-11-04 17:22:37 -07:00
Robert Long c1f56ba3c4 Fix indentation 2021-11-04 11:46:20 -07:00
Robert Long 7998817f7e Send candidate queue again on finish to flush out queue 2021-11-04 11:44:11 -07:00
Robert Long bdc12a2544 Revert changes to gotCallFeedsForAnswer 2021-11-02 17:25:41 -07:00
Robert Long 5a92597abd Check if call ended before getting user media 2021-11-02 15:33:58 -07:00
Robert Long 6f695c1b82 Ignore call call state in glare resolution 2021-11-02 15:30:38 -07:00
Robert Long d99428f2c1 Remove duplicate call answer 2021-11-02 11:39:45 -07:00
Robert Long 4c9648a23b Sanitize call member state 2021-10-28 13:46:27 -07:00
Robert Long 8c5f88c4a7 Fix handling null call 2021-10-28 13:27:35 -07:00
Robert Long 923e9c4ada Ensure that member call state is set correctly 2021-10-28 12:25:00 -07:00
Robert Long 13d62e71b6 Fix stopping all media streams 2021-10-26 16:50:56 -07:00
Robert Long 32aca09f47 Merge branch 'to-device-olm' into robertlong/group-call 2021-10-26 15:27:44 -07:00
Matthew Hodgson 067ac62271 lint 2021-10-26 15:15:30 -07:00
Matthew Hodgson 841e6e999d handle promises normally now tests are fixed 2021-10-26 15:15:16 -07:00
Matthew Hodgson a48546f60d fix the tests (thanks @turt2live!!!) 2021-10-26 15:15:02 -07:00
Matthew Hodgson 2f09e9641c chain promises correctly; log rejects 2021-10-26 15:14:52 -07:00
Matthew Hodgson f46355e7c0 don't choke on missing promise 2021-10-26 15:14:42 -07:00
Matthew Hodgson 53397ee0d1 lint 2021-10-26 15:14:30 -07:00
Matthew Hodgson 5a83635ef5 switch encryptAndSendToDevices to return a promise rather than use a cb
and assert that olm sessions are open to the destination devices
2021-10-26 15:14:13 -07:00
Matthew Hodgson 56c0c9be4d fix example in readme 2021-10-26 15:14:01 -07:00
Matthew Hodgson 24406d2411 make it build 2021-10-26 15:13:46 -07:00
Matthew Hodgson aeeed6ecd7 clarify the factoring 2021-10-26 15:13:27 -07:00
Matthew Hodgson 9f3f9990ef untested first cut at factoring out a encryptAndSendToDevices method 2021-10-26 15:13:13 -07:00
Robert Long 119ce2e46f Fix inbound calls in Safari 2021-10-26 12:44:37 -07:00
Šimon Brandner fc8a867e8e Start processing member state events only after we've set out own (#2000)
This avoids a race condition where the other side would first receive the to-device messages and only then the member state event which would result in the call being ignored

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-10-25 14:02:28 -07:00
Robert Long b4d8c0b603 Fix updating member state with no existing calls 2021-10-22 11:27:02 -07:00
Robert Long 3b0d1b2696 Add check for existing group call session 2021-10-21 14:23:27 -07:00
Robert Long 5110e0b91e Merge branch 'develop' into robertlong/group-call 2021-10-21 13:10:05 -07:00
Robert Long 305de54106 Fix screensharing and webrtc races 2021-10-21 12:57:30 -07:00
Robert Long 0555f9db1c Only send to device messages to a single device 2021-10-19 17:05:21 -07:00
Robert Long 159e825877 Fix unnecessary param to placeCallWithCallFeeds 2021-10-19 15:31:59 -07:00
Robert Long 8131b3900d Use glare resolution to manage group call setup 2021-10-19 15:30:20 -07:00
Robert Long 431d7a0933 Merge branch 'develop' into robertlong/group-call 2021-10-19 12:37:39 -07:00
Robert Long e9b52e23d2 Rermove session id 2021-10-19 10:57:09 -07:00
Šimon Brandner 0148ad0766 Group call improvements (#1985)
* Add group call events to EventType

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Use EventType instead of a const

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Make logging around sending group call member state event a bit better

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>

* Fix m.calls elements being null

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-10-19 10:25:47 -07:00
Robert Long 213f1134b6 Reduce logging for group calls 2021-10-18 11:49:15 -07:00
Robert Long 50e6a8f6b1 Add session_id check to group calls 2021-10-18 11:49:04 -07:00
Robert Long 4a82e1bf05 Merge pull request #1983 from SimonBrandner/robertlong/group-call
Remove left-over from old screen-sharing code
2021-10-15 16:39:21 -07:00
Šimon Brandner 843973c4da Remove left-over from old screen-sharing code
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-10-15 17:19:22 +02:00
Robert Long debeb66d6f Initialize speakingVolumeSamples for screenshare feeds 2021-10-14 17:24:05 -07:00
Robert Long 015d0f9135 Don't set local user as active speaker 2021-10-14 17:14:12 -07:00
Robert Long 5c8e7f2be0 Improve speaking detection using history 2021-10-14 13:34:20 -07:00
Robert Long 411b5f111c Fix talking indicator 2021-10-13 13:42:40 -07:00
Robert Long 2d231c0ae2 Fix how streams are stopped 2021-10-13 12:05:14 -07:00
Robert Long ec37eb8b6f Add support for switching media devices 2021-10-12 15:20:14 -07:00
Robert Long 1cdcebb5db Merge branch 'robertlong/change-media-device' into robertlong/group-call 2021-10-12 15:15:21 -07:00
Robert Long a0f6eea363 Add support for replacing existing sender tracks 2021-10-12 14:48:59 -07:00
Robert Long 18b1a44df7 Merge branch 'robertlong/change-media-device' into robertlong/group-call 2021-10-12 14:24:02 -07:00
Robert Long 4b6b1599a2 Change media devices mid-call 2021-10-12 14:11:57 -07:00
Robert Long a582b19435 Merge branch 'robertlong/group-call' of github.com:matrix-org/matrix-js-sdk into robertlong/group-call 2021-10-12 12:14:55 -07:00
Robert Long 4a8c3d273f Merge branch 'feature/answer-no-cam' into robertlong/group-call 2021-10-12 12:11:32 -07:00
Robert Long 8dc608d917 Fix connecting to a call without a webcam 2021-10-07 13:47:50 -07:00
Robert Long 7ef38ed1b2 Fix speaking threshold 2021-10-06 16:20:07 -07:00
Robert Long 593f62c1c4 Move to correct event types 2021-10-05 16:51:28 -07:00
Robert Long 04d674b8c7 Merge branch 'SimonBrandner-robertlong/group-call' into robertlong/group-call 2021-10-05 11:42:00 -07:00
Robert Long 27eb88f4a1 Update GroupCall to use new CallFeed constructor 2021-10-05 11:38:03 -07:00
Robert Long 1409a4f814 Merge branch 'develop' into robertlong/group-call 2021-10-05 11:34:55 -07:00
Šimon Brandner 8232896c85 Don't run screen-sharing code for each 1:1 call, share one call feed between them instead
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-10-05 06:17:01 +02:00
Šimon Brandner e2ed80ffa0 Add removeLocalFeed()
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-10-05 06:17:01 +02:00
Šimon Brandner 8ac3841a2f Handle joining a call after someone has started screen-sharing
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-10-05 06:16:59 +02:00
Robert Long ba57736bf6 Remove log that's stalling FF 2021-10-04 15:43:56 -07:00
Robert Long 8be4ca909e Add participants to GroupCall 2021-10-04 15:36:36 -07:00
Robert Long 0d964523a9 Add screensharing to GroupCall 2021-09-30 16:04:15 -07:00
Robert Long bb504bc001 Handle getUserMedia permissions blocked 2021-09-30 11:39:34 -07:00
Robert Long 326aec9f9e Fix getUserMediaStream 2021-09-29 17:30:34 -07:00
Robert Long 688327dab5 Handle new group call rooms 2021-09-29 17:00:17 -07:00
Robert Long 3f4522ba88 Add more verbose logging for testing. Create group calls on first sync. 2021-09-29 16:22:44 -07:00
Robert Long 625983a2b2 Revert changes to package.json and .npmignore 2021-09-29 14:37:07 -07:00
Robert Long 137fd2bd40 Export group call enums 2021-09-29 14:35:42 -07:00
Robert Long 1e65bfd316 Fix initLocalCallFeed state 2021-09-29 14:35:32 -07:00
Robert Long 5da072712d Use prepack instead of prepare 2021-09-29 11:47:09 -07:00
Robert Long 529d61b5f4 Add .npmignore 2021-09-29 11:44:12 -07:00
Robert Long 5111ca622a Change main path 2021-09-29 11:36:11 -07:00
Robert Long f627507b86 Test prepare script for git installs 2021-09-29 11:03:42 -07:00
Robert Long aee4459201 Merge pull request #1955 from SimonBrandner/robertlong/group-call
De-duplication for group calls
2021-09-28 10:31:55 -07:00
Šimon Brandner 1a824750dd Don't emit the same thing twice
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-28 19:11:53 +02:00
Šimon Brandner 73cb5e1ee9 Fix order of execution
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-28 19:10:42 +02:00
Šimon Brandner 96bde1f706 Fix field keys
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-28 18:17:36 +02:00
Šimon Brandner 5251dcf67f De-duplicate pushNewLocalFeed
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-28 08:58:01 +02:00
Šimon Brandner ce0b0ea182 De-duplicate invite/answer code
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-28 08:57:44 +02:00
Robert Long 7a142e9102 Implement new group call state events 2021-09-27 17:06:09 -07:00
Robert Long f85aa44f28 Remove duplicate FeedChanged event 2021-09-27 15:02:59 -07:00
Robert Long efbf252e22 Merge pull request #1951 from SimonBrandner/robertlong/group-call
Use to-device events for group calls and other improvements
2021-09-27 14:50:39 -07:00
Robert Long d873f14b6d Merge branch 'develop' into robertlong/group-call 2021-09-27 12:10:31 -07:00
Šimon Brandner cf1ba12232 Use arrays of CallFeeds
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:22 +02:00
Šimon Brandner df208e4de8 Avoid having duplicate call feeds
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:22 +02:00
Šimon Brandner d8ef7f9f63 pushLocalFeed() -> pushNewLocalFeed()
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:22 +02:00
Šimon Brandner 2515ba31a0 Use createNewMatrixCall()
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:21 +02:00
Šimon Brandner 715c4577d0 Add a prop for not stopping local feeds on end
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:21 +02:00
Šimon Brandner a2f23900c9 Use groupCallId isntead of roomId in to-device messages
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:21 +02:00
Šimon Brandner e9e65cf484 Change type key
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:21 +02:00
Šimon Brandner 205c80ea28 Add groupCallId
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:20 +02:00
Šimon Brandner 678023717b Add a setState() method
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:20 +02:00
Šimon Brandner b535969845 Use to-device messages in group calls
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:20 +02:00
Šimon Brandner 027bc6bfc9 Handle incoming to-device call signalling
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:19 +02:00
Šimon Brandner 71ca424712 Allow for sending toDevice messages
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:19 +02:00
Šimon Brandner 3280394bf9 Figure out opponentMember from the userId rather than the sender
This is because to-device messages don't have a sender

Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:19 +02:00
Šimon Brandner fc07530434 Add useToDevice to CallOpts
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-27 18:07:18 +02:00
Robert Long f592d4dbc5 Merge branch 'develop' into robertlong/group-call 2021-09-26 11:30:55 -07:00
Robert Long 96f48929ac Cleaning up group call state 2021-09-24 15:41:05 -07:00
Robert Long 454da84f6e Initialize activeSpeakerSamples 2021-09-24 13:29:23 -07:00
Robert Long 89bda6c2e5 Move from groupCallsParticipants to calls 2021-09-24 12:39:43 -07:00
Robert Long ac70dcfc91 Expose call feed getters on call 2021-09-23 16:23:32 -07:00
Robert Long 9c7cb3cbea Handle more edge cases around creating/ending group calls 2021-09-22 15:03:48 -07:00
Robert Long d8d7bd548f Merge branch 'SimonBrandner-robertlong/group-call' into robertlong/group-call 2021-09-22 12:18:53 -07:00
Šimon Brandner 55ef57ead8 Add GroupCallEventHandler
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-22 21:00:19 +02:00
Šimon Brandner 9996afed03 Throw with no room
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-22 21:00:18 +02:00
Šimon Brandner 61a80a11c9 Export CONF_ROOM
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
2021-09-22 21:00:18 +02:00
Robert Long 6a8e8ed0a6 Merge branch 'develop' into robertlong/group-call 2021-09-22 11:58:42 -07:00
Robert Long 5895ce32fa Revert unintended babelrc edit 2021-09-21 21:00:47 -07:00
Robert Long fe0a268991 Merge branch 'robertlong/group-call' of github.com:matrix-org/matrix-js-sdk into robertlong/group-call 2021-09-21 17:11:12 -07:00
Robert Long 7f189b0abd Add endCall 2021-09-21 17:10:45 -07:00
Robert Long 6e07c9e900 Clean up group call event listeners properly on hangup 2021-09-21 14:48:22 -07:00
Robert Long bbeea51a36 Add callType to room state event 2021-09-21 14:24:51 -07:00
Robert Long 151b54ed65 Clean up GroupCallParticipant listeners on remove 2021-09-21 14:24:37 -07:00
Robert Long 18986cb33a Fix typo 2021-09-20 17:31:02 -07:00
Robert Long aef5d73de4 Fix emitting participants_changed event 2021-09-20 17:30:49 -07:00
Robert Long e4fc1f3628 Merge branch 'develop' into robertlong/group-call 2021-09-17 09:16:05 -07:00
Robert Long 8b1c173659 Avoid changing member on replaced call 2021-09-16 16:35:41 -07:00
Robert Long f0916f14d1 Merge branch 'develop' into robertlong/group-call 2021-09-15 14:26:13 -07:00
Robert Long a291f5ab05 Merge branch 'robertlong/clone-streams' into robertlong/group-call 2021-09-15 13:23:56 -07:00
Robert Long 2d7e07f4ed Update to use latest datachannel / clone media stream PRs 2021-09-15 12:45:42 -07:00
Robert Long 2427f75f98 Merge branch 'robertlong/datachannels' into robertlong/group-call 2021-09-15 12:40:37 -07:00
Robert Long d25fb71eba Merge branch 'robertlong/clone-streams' into robertlong/group-call 2021-09-15 12:39:50 -07:00
Robert Long c81b9d2fd9 Merge branch 'develop' into robertlong/group-call 2021-09-15 11:27:59 -07:00
Robert Long fb3ca90bc9 Fix private method signatures 2021-09-10 16:06:26 -07:00
Robert Long eb2a47623f Fix active speaker 2021-09-10 15:58:44 -07:00
Robert Long f18d8ead08 Fix usermedia feeds 2021-09-10 14:31:39 -07:00
Robert Long 2da14bd6e9 Fix call feed changed event handler 2021-09-10 10:01:54 -07:00
Robert Long 1dbb776e12 Revert register types 2021-09-09 17:07:18 -07:00
Robert Long 07b2c57064 Remove CallFeed export 2021-09-09 16:40:08 -07:00
Robert Long 7021f70a66 Move from constants to configureable public variables 2021-09-09 16:24:26 -07:00
Robert Long 503e954671 Merge branch 'develop' into robertlong/group-call 2021-09-09 11:27:06 -07:00
Robert Long 2add1fcbcb Clean up group call events 2021-09-08 14:37:21 -07:00
Robert Long 4fe115b2c4 Add initial group call logic 2021-09-08 13:27:38 -07:00
Robert Long 60e168806d Properly dispose of call feeds 2021-09-02 13:27:13 -07:00
Robert Long 03dfab1282 Export CallFeed 2021-09-02 13:01:43 -07:00
Robert Long 19302ea4fb Fix initWithInvitePromise 2021-08-31 16:10:37 -07:00
Robert Long d5aaed67ba Merge branch 'develop' into robertlong/full-mesh-voip 2021-08-31 16:08:02 -07:00
Robert Long 8fe6afd9ab Merge branch 'master' into robertlong/full-mesh-voip 2021-08-31 16:02:05 -07:00
Robert Long 782fbb115f Stop all media on hangup 2021-08-20 14:42:41 -07:00
Robert Long 3971bf34ed Merge branch 'master' into robertlong/full-mesh-voip 2021-08-20 12:09:27 -07:00
Robert Long 6dac6e53f7 Merge branch 'develop' into robertlong/full-mesh-voip 2021-08-11 11:49:52 -07:00
Robert Long 7ec84e92a0 Merge branch 'develop' into robertlong/full-mesh-voip 2021-08-11 11:38:15 -07:00
Robert Long 154e5c45a6 Clear localAVStream when stopping local media stream. 2021-08-09 11:02:09 -07:00
Robert Long 2cd5c813ac Add local media stream functions to client 2021-08-05 18:22:29 -07:00
Robert Long 1c5101aa1a Add ice disconnected timeout 2021-08-04 18:23:21 -07:00
Robert Long 76f11bee9e Fix invitee glare detection and incoming call event 2021-07-26 11:38:18 -07:00
Robert Long 91f409e8f4 Add invitee field 2021-07-21 23:29:08 -07:00
434 changed files with 88910 additions and 34410 deletions
+9 -6
View File
@@ -1,12 +1,15 @@
{
"sourceMaps": true,
"presets": [
["@babel/preset-env", {
"targets": {
"node": 10
},
"modules": "commonjs"
}],
[
"@babel/preset-env",
{
"targets": {
"node": 10
},
"modules": "commonjs"
}
],
"@babel/preset-typescript"
],
"plugins": [
+1 -1
View File
@@ -23,4 +23,4 @@ indent_size = 4
trim_trailing_whitespace = true
[*.{yml,yaml}]
indent_size = 2
indent_size = 4
+100 -60
View File
@@ -1,12 +1,9 @@
module.exports = {
plugins: [
"matrix-org",
"import",
],
extends: [
"plugin:matrix-org/babel",
"plugin:import/typescript",
],
plugins: ["matrix-org", "import", "jsdoc"],
extends: ["plugin:matrix-org/babel", "plugin:matrix-org/jest", "plugin:import/typescript"],
parserOptions: {
project: ["./tsconfig.json"],
},
env: {
browser: true,
node: true,
@@ -20,70 +17,113 @@ module.exports = {
// NOTE: These rules are frozen and new rules should not be added here.
// New changes belong in https://github.com/matrix-org/eslint-plugin-matrix-org/
rules: {
"no-var": ["warn"],
"prefer-rest-params": ["warn"],
"prefer-spread": ["warn"],
"one-var": ["warn"],
"padded-blocks": ["warn"],
"no-extend-native": ["warn"],
"camelcase": ["warn"],
"no-multi-spaces": ["error", { "ignoreEOLComments": true }],
"space-before-function-paren": ["error", {
"anonymous": "never",
"named": "never",
"asyncArrow": "always",
}],
"no-var": ["error"],
"prefer-rest-params": ["error"],
"prefer-spread": ["error"],
"one-var": ["error"],
"padded-blocks": ["error"],
"no-extend-native": ["error"],
"camelcase": ["error"],
"no-multi-spaces": ["error", { ignoreEOLComments: true }],
"space-before-function-paren": [
"error",
{
anonymous: "never",
named: "never",
asyncArrow: "always",
},
],
"arrow-parens": "off",
"prefer-promise-reject-errors": "off",
"quotes": "off",
"indent": "off",
"no-constant-condition": "off",
"no-async-promise-executor": "off",
// We use a `logger` intermediary module
"no-console": "error",
// restrict EventEmitters to force callers to use TypedEventEmitter
"no-restricted-imports": ["error", {
name: "events",
message: "Please use TypedEventEmitter instead"
}],
"no-restricted-imports": [
"error",
{
name: "events",
message: "Please use TypedEventEmitter instead",
},
],
"import/no-restricted-paths": ["error", {
"zones": [{
"target": "./src/",
"from": "./src/index.ts",
"message": "The package index is dynamic between src and lib depending on " +
"whether release or development, target the specific module or matrix.ts instead",
}],
}],
"import/no-restricted-paths": [
"error",
{
zones: [
{
target: "./src/",
from: "./src/index.ts",
message:
"The package index is dynamic between src and lib depending on " +
"whether release or development, target the specific module or matrix.ts instead",
},
],
},
],
// Disabled tests are a reality for now but as soon as all of the xits are
// eliminated, we should enforce this.
"jest/no-disabled-tests": "off",
// Also treat "oldBackendOnly" as a test function.
// Used in some crypto tests.
"jest/no-standalone-expect": [
"error",
{
additionalTestBlockFunctions: ["beforeAll", "beforeEach", "oldBackendOnly", "newBackendOnly"],
},
],
},
overrides: [{
files: [
"**/*.ts",
],
extends: [
"plugin:matrix-org/typescript",
],
rules: {
// TypeScript has its own version of this
"@babel/no-invalid-this": "off",
overrides: [
{
files: ["**/*.ts"],
plugins: ["eslint-plugin-tsdoc"],
extends: ["plugin:matrix-org/typescript"],
rules: {
// TypeScript has its own version of this
"@babel/no-invalid-this": "off",
// We're okay being explicit at the moment
"@typescript-eslint/no-empty-interface": "off",
// We disable this while we're transitioning
"@typescript-eslint/no-explicit-any": "off",
// We'd rather not do this but we do
"@typescript-eslint/ban-ts-comment": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
// We're okay being explicit at the moment
"@typescript-eslint/no-empty-interface": "off",
// We disable this while we're transitioning
"@typescript-eslint/no-explicit-any": "off",
// We'd rather not do this but we do
"@typescript-eslint/ban-ts-comment": "off",
// We're okay with assertion errors when we ask for them
"@typescript-eslint/no-non-null-assertion": "off",
// The non-TypeScript rule produces false positives
"func-call-spacing": "off",
"@typescript-eslint/func-call-spacing": ["error"],
// The non-TypeScript rule produces false positives
"func-call-spacing": "off",
"@typescript-eslint/func-call-spacing": ["error"],
"quotes": "off",
// We use a `logger` intermediary module
"no-console": "error",
"quotes": "off",
// We use a `logger` intermediary module
"no-console": "error",
},
},
}],
{
// We don't need amazing docs in our spec files
files: ["src/**/*.ts"],
rules: {
"tsdoc/syntax": "error",
// We use some select jsdoc rules as the tsdoc linter has only one rule
"jsdoc/no-types": "error",
"jsdoc/empty-tags": "error",
"jsdoc/check-property-names": "error",
"jsdoc/check-values": "error",
// These need a bit more work before we can enable
// "jsdoc/check-param-names": "error",
// "jsdoc/check-indentation": "error",
},
},
{
files: ["spec/**/*.ts"],
rules: {
// We don't need super strict typing in test utilities
"@typescript-eslint/explicit-function-return-type": "off",
"@typescript-eslint/explicit-member-accessibility": "off",
},
},
],
};
+2 -1
View File
@@ -38,4 +38,5 @@ cee7f7a280a8c20bafc21c0a2911f60851f7a7ca
7ed65407e6cdf292ce3cf659310c68d19dcd52b2
# Switch to ESLint from JSHint (Google eslint rules as a base)
e057956ede9ad1a931ff8050c411aca7907e0394
# prettier
349c2c2587c2885bb69eda4aa078b5383724cf5e
+8 -1
View File
@@ -1 +1,8 @@
* @matrix-org/element-web
* @matrix-org/element-web
/.github/workflows/** @matrix-org/element-web-app-team
/package.json @matrix-org/element-web-app-team
/yarn.lock @matrix-org/element-web-app-team
/src/webrtc @matrix-org/element-call-reviewers
/src/matrixrtc @matrix-org/element-call-reviewers
/spec/*/webrtc @matrix-org/element-call-reviewers
/spec/*/matrixrtc @matrix-org/element-call-reviewers
+3 -3
View File
@@ -2,9 +2,9 @@
## Checklist
* [ ] Tests written for new code (and old code if feasible)
* [ ] Linter and other CI checks pass
* [ ] Sign-off given on the changes (see [CONTRIBUTING.md](https://github.com/matrix-org/matrix-js-sdk/blob/develop/CONTRIBUTING.md))
- [ ] Tests written for new code (and old code if feasible)
- [ ] Linter and other CI checks pass
- [ ] Sign-off given on the changes (see [CONTRIBUTING.md](https://github.com/matrix-org/matrix-js-sdk/blob/develop/CONTRIBUTING.md))
<!--
If you would like to specify text for the changelog entry other than your PR title, add the following:
@@ -0,0 +1,28 @@
name: Sign Release Tarball
description: Generates signature for release tarball and uploads it as a release asset
inputs:
gpg-fingerprint:
description: Fingerprint of the GPG key to use for signing the tarball.
required: true
upload-url:
description: GitHub release upload URL to upload the signature file to.
required: true
runs:
using: composite
steps:
- name: Generate tarball signature
shell: bash
run: |
git -c tar.tar.gz.command='gzip -cn' archive --format=tar.gz --prefix="${REPO#*/}-${VERSION#v}/" -o "/tmp/${VERSION}.tar.gz" "${VERSION}"
gpg -u "$GPG_FINGERPRINT" --armor --output "${VERSION}.tar.gz.asc" --detach-sig "/tmp/${VERSION}.tar.gz"
rm "/tmp/${VERSION}.tar.gz"
env:
GPG_FINGERPRINT: ${{ inputs.gpg-fingerprint }}
REPO: ${{ github.repository }}
- name: Upload tarball signature
if: ${{ inputs.upload-url }}
uses: shogo82148/actions-upload-release-asset@dccd6d23e64fd6a746dce6814c0bde0a04886085 # v1
with:
upload_url: ${{ inputs.upload-url }}
asset_path: ${{ env.VERSION }}.tar.gz.asc
@@ -0,0 +1,41 @@
name: Upload release assets
description: Uploads assets to an existing release and optionally signs them
inputs:
gpg-fingerprint:
description: Fingerprint of the GPG key to use for signing the assets, if any.
required: false
upload-url:
description: GitHub release upload URL to upload the assets to.
required: true
asset-path:
description: |
The path to the asset you want to upload, if any. You can use glob patterns here.
Will be GPG signed and an `.asc` file included in the release artifacts if `gpg-fingerprint` is set.
required: true
runs:
using: composite
steps:
- name: Sign assets
if: inputs.gpg-fingerprint
shell: bash
run: |
for FILE in $ASSET_PATH
do
gpg -u "$GPG_FINGERPRINT" --armor --output "$FILE".asc --detach-sig "$FILE"
done
env:
GPG_FINGERPRINT: ${{ inputs.gpg-fingerprint }}
ASSET_PATH: ${{ inputs.asset-path }}
- name: Upload asset signatures
if: inputs.gpg-fingerprint
uses: shogo82148/actions-upload-release-asset@dccd6d23e64fd6a746dce6814c0bde0a04886085 # v1
with:
upload_url: ${{ inputs.upload-url }}
asset_path: ${{ inputs.asset-path }}.asc
- name: Upload assets
uses: shogo82148/actions-upload-release-asset@dccd6d23e64fd6a746dce6814c0bde0a04886085 # v1
with:
upload_url: ${{ inputs.upload-url }}
asset_path: ${{ inputs.asset-path }}
+31
View File
@@ -0,0 +1,31 @@
name-template: "v$RESOLVED_VERSION"
tag-template: "v$RESOLVED_VERSION"
change-template: "* $TITLE ([#$NUMBER]($URL)). Contributed by @$AUTHOR."
categories:
- title: "🚨 BREAKING CHANGES"
label: "X-Breaking-Change"
- title: "🦖 Deprecations"
label: "T-Deprecation"
- title: "✨ Features"
label: "T-Enhancement"
- title: "🐛 Bug Fixes"
label: "T-Defect"
- title: "🧰 Maintenance"
label: "Dependencies"
collapse-after: 5
change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks.
version-resolver:
major:
labels:
- "X-Breaking-Change"
default: minor
exclude-labels:
- "T-Task"
- "X-Reverted"
exclude-contributors:
- "RiotRobot"
template: |
$CHANGES
prerelease: true
prerelease-identifier: rc
include-pre-releases: false
+2 -4
View File
@@ -1,6 +1,4 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"github>matrix-org/renovate-config-element-web"
]
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": ["github>matrix-org/renovate-config-element-web"]
}
+26 -26
View File
@@ -1,30 +1,30 @@
name: Backport
on:
pull_request_target:
types:
- closed
- labeled
branches:
- develop
pull_request_target:
types:
- closed
- labeled
branches:
- develop
jobs:
backport:
name: Backport
runs-on: ubuntu-latest
# Only react to merged PRs for security reasons.
# See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target.
if: >
github.event.pull_request.merged
&& (
github.event.action == 'closed'
|| (
github.event.action == 'labeled'
&& contains(github.event.label.name, 'backport')
)
)
steps:
- uses: tibdex/backport@v2
with:
labels_template: "<%= JSON.stringify([...labels, 'X-Release-Blocker']) %>"
# We can't use GITHUB_TOKEN here or CI won't run on the new PR
github_token: ${{ secrets.ELEMENT_BOT_TOKEN }}
backport:
name: Backport
runs-on: ubuntu-latest
# Only react to merged PRs for security reasons.
# See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target.
if: >
github.event.pull_request.merged
&& (
github.event.action == 'closed'
|| (
github.event.action == 'labeled'
&& contains(github.event.label.name, 'backport')
)
)
steps:
- uses: tibdex/backport@9565281eda0731b1d20c4025c43339fb0a23812e # v2
with:
labels_template: "<%= JSON.stringify([...labels, 'X-Release-Blocker']) %>"
# We can't use GITHUB_TOKEN here or CI won't run on the new PR
github_token: ${{ secrets.ELEMENT_BOT_TOKEN }}
+58
View File
@@ -0,0 +1,58 @@
# Triggers after the "Downstream artifacts" build has finished, to run the
# cypress tests (with access to repo secrets)
name: matrix-react-sdk Cypress End to End Tests
on:
workflow_run:
workflows: ["Build downstream artifacts"]
types:
- completed
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.run_id }}
cancel-in-progress: ${{ github.event.workflow_run.event == 'pull_request' }}
jobs:
cypress:
name: Cypress
# We only want to run the cypress tests on merge queue to prevent regressions
# from creeping in. They take a long time to run and consume 4 concurrent runners.
if: github.event.workflow_run.event == 'merge_group'
uses: matrix-org/matrix-react-sdk/.github/workflows/cypress.yaml@f6ef476f7905cc2b1f060f1a360b482e7546e682
permissions:
actions: read
issues: read
statuses: write
pull-requests: read
secrets:
# secrets are not automatically shared with called workflows, so share the cypress dashboard key, and the Kiwi login details
CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }}
TCMS_USERNAME: ${{ secrets.TCMS_USERNAME }}
TCMS_PASSWORD: ${{ secrets.TCMS_PASSWORD }}
with:
react-sdk-repository: matrix-org/matrix-react-sdk
# We want to make the cypress tests a required check for the merge queue.
#
# Unfortunately, github doesn't distinguish between "checks needed for branch
# protection" (ie, the things that must pass before the PR will even be added
# to the merge queue) and "checks needed in the merge queue". We just have to add
# the check to the branch protection list.
#
# Ergo, if we know we're not going to run the cypress tests, we need to add a
# passing status check manually.
mark_skipped:
if: github.event.workflow_run.event != 'merge_group'
permissions:
statuses: write
runs-on: ubuntu-latest
steps:
- uses: Sibz/github-status-action@650dd1a882a76dbbbc4576fb5974b8d22f29847f # v1.1.6
with:
authToken: "${{ secrets.GITHUB_TOKEN }}"
state: success
description: Cypress skipped
context: "${{ github.workflow }} / cypress"
sha: "${{ github.event.workflow_run.head_sha }}"
+35
View File
@@ -0,0 +1,35 @@
name: Deploy documentation PR preview
on:
workflow_run:
workflows: ["Static Analysis"]
types:
- completed
jobs:
netlify:
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request'
runs-on: ubuntu-latest
steps:
# There's a 'download artifact' action, but it hasn't been updated for the workflow_run action
# (https://github.com/actions/download-artifact/issues/60) so instead we get this mess:
- name: 📥 Download artifact
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2
with:
workflow: static_analysis.yml
run_id: ${{ github.event.workflow_run.id }}
name: docs
path: docs
- name: 📤 Deploy to Netlify
uses: matrix-org/netlify-pr-preview@v2
with:
path: docs
owner: ${{ github.event.workflow_run.head_repository.owner.login }}
branch: ${{ github.event.workflow_run.head_branch }}
revision: ${{ github.event.workflow_run.head_sha }}
token: ${{ secrets.NETLIFY_AUTH_TOKEN }}
site_id: ${{ secrets.NETLIFY_SITE_ID }}
desc: Documentation preview
deployment_env: PR Documentation Preview
environment: PR Documentation Preview
@@ -0,0 +1,26 @@
name: Build downstream artifacts
on:
merge_group:
types: [checks_requested]
pull_request: {}
# For now at least, we don't run this or the cypress-tests against pushes
# to develop or master.
#
# Note that if we later choose to do so, we'll need to find a way to stop
# the results in Cypress Cloud from clobbering those from the 'develop'
# branch of matrix-react-sdk.
#
#push:
# branches: [develop, master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build-element-web:
name: Build element-web
uses: matrix-org/matrix-react-sdk/.github/workflows/element-web.yaml@v3.84.1
with:
matrix-js-sdk-sha: ${{ github.sha }}
react-sdk-repository: matrix-org/matrix-react-sdk
+22 -22
View File
@@ -1,27 +1,27 @@
name: Notify Downstream Projects
on:
push:
branches: [ develop ]
push:
branches: [develop]
concurrency: ${{ github.workflow }}-${{ github.ref }}
jobs:
notify-downstream:
# Only respect triggers from our develop branch, ignore that of forks
if: github.repository == 'matrix-org/matrix-js-sdk'
continue-on-error: true
strategy:
fail-fast: false
matrix:
include:
- repo: vector-im/element-web
event: element-web-notify
- repo: matrix-org/matrix-react-sdk
event: upstream-sdk-notify
notify-downstream:
# Only respect triggers from our develop branch, ignore that of forks
if: github.repository == 'matrix-org/matrix-js-sdk'
continue-on-error: true
strategy:
fail-fast: false
matrix:
include:
- repo: vector-im/element-web
event: element-web-notify
- repo: matrix-org/matrix-react-sdk
event: upstream-sdk-notify
runs-on: ubuntu-latest
steps:
- name: Notify matrix-react-sdk repo that a new SDK build is on develop so it can CI against it
uses: peter-evans/repository-dispatch@v2
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
repository: ${{ matrix.repo }}
event-type: ${{ matrix.event }}
runs-on: ubuntu-latest
steps:
- name: Notify matrix-react-sdk repo that a new SDK build is on develop so it can CI against it
uses: peter-evans/repository-dispatch@bf47d102fdb849e755b0b0023ea3e81a44b6f570 # v2
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
repository: ${{ matrix.repo }}
event-type: ${{ matrix.event }}
+80 -83
View File
@@ -1,91 +1,88 @@
name: Pull Request
on:
pull_request_target:
types: [ opened, edited, labeled, unlabeled, synchronize ]
workflow_call:
inputs:
labels:
type: string
default: "T-Defect,T-Deprecation,T-Enhancement,T-Task"
required: false
description: "No longer used, uses allchange logic now, will be removed at a later date"
secrets:
ELEMENT_BOT_TOKEN:
required: true
concurrency: ${{ github.workflow }}-${{ github.event.pull_request.head.ref }}
pull_request_target:
types: [opened, edited, labeled, unlabeled, synchronize]
merge_group:
types: [checks_requested]
workflow_call:
secrets:
ELEMENT_BOT_TOKEN:
required: true
concurrency: ${{ github.workflow }}-${{ github.event.pull_request.head.ref || github.head_ref || github.ref }}
jobs:
changelog:
name: Preview Changelog
runs-on: ubuntu-latest
steps:
- uses: matrix-org/allchange@main
with:
ghToken: ${{ secrets.GITHUB_TOKEN }}
requireLabel: true
changelog:
name: Preview Changelog
runs-on: ubuntu-latest
steps:
- uses: matrix-org/allchange@main
if: github.event_name != 'merge_group'
with:
ghToken: ${{ secrets.GITHUB_TOKEN }}
requireLabel: true
prevent-blocked:
name: Prevent Blocked
runs-on: ubuntu-latest
permissions:
pull-requests: read
steps:
- name: Add notice
uses: actions/github-script@v6
if: contains(github.event.pull_request.labels.*.name, 'X-Blocked')
with:
script: |
core.setFailed("Preventing merge whilst PR is marked blocked!");
prevent-blocked:
name: Prevent Blocked
runs-on: ubuntu-latest
permissions:
pull-requests: read
steps:
- name: Add notice
uses: actions/github-script@v7
if: contains(github.event.pull_request.labels.*.name, 'X-Blocked')
with:
script: |
core.setFailed("Preventing merge whilst PR is marked blocked!");
community-prs:
name: Label Community PRs
runs-on: ubuntu-latest
if: github.event.action == 'opened'
steps:
- name: Check membership
uses: tspascoal/get-user-teams-membership@v1
id: teams
with:
username: ${{ github.event.pull_request.user.login }}
organization: matrix-org
team: Core Team
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
community-prs:
name: Label Community PRs
runs-on: ubuntu-latest
if: github.event.action == 'opened'
steps:
- name: Check membership
uses: tspascoal/get-user-teams-membership@ba78054988f58bea69b7c6136d563236f8ed2fc0 # v3
id: teams
with:
username: ${{ github.event.pull_request.user.login }}
organization: matrix-org
team: Core Team
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
- name: Add label
if: ${{ steps.teams.outputs.isTeamMember == 'false' }}
uses: actions/github-script@v6
with:
script: |
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['Z-Community-PR']
});
- name: Add label
if: ${{ steps.teams.outputs.isTeamMember == 'false' }}
uses: actions/github-script@v7
with:
script: |
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['Z-Community-PR']
});
close-if-fork-develop:
name: Forbid develop branch fork contributions
runs-on: ubuntu-latest
if: >
github.event.action == 'opened' &&
github.event.pull_request.head.ref == 'develop' &&
github.event.pull_request.head.repo.full_name != github.repository
steps:
- name: Close pull request
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: "Thanks for opening this pull request, unfortunately we do not accept contributions from the main" +
" branch of your fork, please re-open once you switch to an alternative branch for everyone's sanity." +
" See https://github.com/matrix-org/matrix-js-sdk/blob/develop/CONTRIBUTING.md",
});
close-if-fork-develop:
name: Forbid develop branch fork contributions
runs-on: ubuntu-latest
if: >
github.event.action == 'opened' &&
github.event.pull_request.head.ref == 'develop' &&
github.event.pull_request.head.repo.full_name != github.repository
steps:
- name: Close pull request
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: "Thanks for opening this pull request, unfortunately we do not accept contributions from the main" +
" branch of your fork, please re-open once you switch to an alternative branch for everyone's sanity." +
" See https://github.com/matrix-org/matrix-js-sdk/blob/develop/CONTRIBUTING.md",
});
github.rest.pulls.update({
pull_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
state: 'closed'
});
github.rest.pulls.update({
pull_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
state: 'closed'
});
+21
View File
@@ -0,0 +1,21 @@
name: Release Drafter
on:
push:
branches: [staging]
workflow_dispatch:
inputs:
previous-version:
description: What release to use as a base for release note purposes
required: false
type: string
concurrency: ${{ github.workflow }}
jobs:
draft:
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter@e64b19c4c46173209ed9f2e5a2f4ca7de89a0e86 # v5
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
disable-autolabeler: true
previous-version: ${{ inputs.previous-version }}
+85
View File
@@ -0,0 +1,85 @@
# Gitflow merge-back master->develop
name: Merge master -> develop
on:
push:
branches: [master]
workflow_call:
secrets:
ELEMENT_BOT_TOKEN:
required: true
inputs:
dependencies:
description: List of dependencies to reset.
type: string
required: false
concurrency: ${{ github.workflow }}
jobs:
merge:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
fetch-depth: 0
- name: Get actions scripts
uses: actions/checkout@v4
with:
repository: matrix-org/matrix-js-sdk
persist-credentials: false
path: .action-repo
sparse-checkout: |
scripts/release
- uses: actions/setup-node@v4
with:
cache: "yarn"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Set up git
run: |
git config --global user.email "releases@riot.im"
git config --global user.name "RiotRobot"
- name: Merge to develop
run: |
git checkout develop
git merge -X ours master
- name: Run post-merge-master script to revert package.json fields
run: ./.action-repo/scripts/release/post-merge-master.sh
- name: Reset dependencies
if: inputs.dependencies
run: |
while IFS= read -r PACKAGE; do
[ -z "$PACKAGE" ] && continue
CURRENT_VERSION=$(cat package.json | jq -r .dependencies[\"$PACKAGE\"])
echo "Current $PACKAGE version is $CURRENT_VERSION"
if [ "$CURRENT_VERSION" == "null" ]
then
echo "Unable to find $PACKAGE in package.json"
exit 1
fi
if [ "$CURRENT_VERSION" == "develop" ]
then
echo "Not updating dependency $PACKAGE"
continue
fi
echo "Resetting $1 to develop branch..."
yarn add "github:matrix-org/$PACKAGE#develop"
git add -u
git commit -m "Reset $PACKAGE back to develop branch"
done <<< "$DEPENDENCIES"
env:
DEPENDENCIES: ${{ inputs.dependencies }}
FINAL: ${{ inputs.final }}
- name: Push changes
run: git push origin develop
+353
View File
@@ -0,0 +1,353 @@
name: Release Make
on:
workflow_call:
secrets:
ELEMENT_BOT_TOKEN:
required: true
NPM_TOKEN:
required: false
GPG_PASSPHRASE:
required: false
GPG_PRIVATE_KEY:
required: false
inputs:
final:
description: Make final release
required: true
default: false
type: boolean
npm:
description: Publish to npm
type: boolean
default: false
dependencies:
description: |
List of dependencies to update in `npm-dep=version` format.
`version` can be `"current"` to leave it at the current version.
type: string
required: false
include-changes:
description: Project to include changelog entries from in this release.
type: string
required: false
gpg-fingerprint:
description: Fingerprint of the GPG key to use for signing the git tag and assets, if any.
type: string
required: false
asset-path:
description: |
The path to the asset you want to upload, if any. You can use glob patterns here.
Will be GPG signed and an `.asc` file included in the release artifacts if `gpg-fingerprint` is set.
type: string
required: false
expected-asset-count:
description: The number of expected assets, including signatures, excluding generated zip & tarball.
type: number
required: false
jobs:
release:
name: Release
runs-on: ubuntu-latest
environment: Release
steps:
- name: Load GPG key
id: gpg
if: inputs.gpg-fingerprint
uses: crazy-max/ghaction-import-gpg@82a020f1f7f605c65dd2449b392a52c3fcfef7ef # v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
fingerprint: ${{ inputs.gpg-fingerprint }}
- name: Get draft release
id: release
uses: cardinalby/git-get-release-action@cedef2faf69cb7c55b285bad07688d04430b7ada # v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
draft: true
latest: true
- uses: actions/checkout@v4
with:
ref: staging
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
fetch-depth: 0
- name: Get actions scripts
uses: actions/checkout@v4
with:
repository: matrix-org/matrix-js-sdk
persist-credentials: false
path: .action-repo
sparse-checkout: |
.github/actions
scripts/release
- name: Prepare variables
id: prepare
run: |
echo "VERSION=$VERSION" >> $GITHUB_ENV
{
echo "RELEASE_NOTES<<EOF"
echo "$BODY"
echo "EOF"
} >> $GITHUB_ENV
HAS_DIST=0
jq -e .scripts.dist package.json >/dev/null 2>&1 && HAS_DIST=1
echo "has-dist-script=$HAS_DIST" >> $GITHUB_OUTPUT
env:
BODY: ${{ steps.release.outputs.body }}
VERSION: ${{ steps.release.outputs.tag_name }}
- name: Finalise version
if: inputs.final
run: echo "VERSION=$(echo $VERSION | cut -d- -f1)" >> $GITHUB_ENV
- name: Check version number not in use
uses: actions/github-script@v7
with:
script: |
const { VERSION } = process.env;
github.rest.repos.getReleaseByTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag: VERSION,
}).then(() => {
core.setFailed(`Version ${VERSION} already exists`);
}).catch(() => {
// This is fine, we expect there to not be any release with this version yet
});
- name: Set up git
run: |
git config --global user.email "releases@riot.im"
git config --global user.name "RiotRobot"
- uses: actions/setup-node@v4
with:
cache: "yarn"
- name: Install dependencies
run: "yarn install --frozen-lockfile"
- name: Update dependencies
id: update-dependencies
if: inputs.dependencies
run: |
UPDATED=()
while IFS= read -r DEPENDENCY; do
[ -z "$DEPENDENCY" ] && continue
IFS="=" read -r PACKAGE UPDATE_VERSION <<< "$DEPENDENCY"
CURRENT_VERSION=$(cat package.json | jq -r .dependencies[\"$PACKAGE\"])
echo "Current $PACKAGE version is $CURRENT_VERSION"
if [ "$CURRENT_VERSION" == "null" ]
then
echo "Unable to find $PACKAGE in package.json"
exit 1
fi
if [ "$UPDATE_VERSION" == "current" ] || [ "$UPDATE_VERSION" == "$CURRENT_VERSION" ]
then
echo "Not updating dependency $PACKAGE"
continue
fi
echo "Upgrading $PACKAGE to $UPDATE_VERSION..."
yarn upgrade "$PACKAGE@$UPDATE_VERSION" --exact
git add -u
git commit -m "Upgrade $PACKAGE to $UPDATE_VERSION"
UPDATED+=("$PACKAGE")
done <<< "$DEPENDENCIES"
JSON=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${UPDATED[@]}")
echo "updated=$JSON" >> $GITHUB_OUTPUT
env:
DEPENDENCIES: ${{ inputs.dependencies }}
- name: Prevent develop dependencies
if: inputs.dependencies
run: |
ret=0
cat package.json | jq '.dependencies[]' | grep -q '#develop' || ret=$?
if [ "$ret" -eq 0 ]; then
echo "package.json contains develop dependencies. Refusing to release."
exit
fi
- name: Bump package.json version
run: yarn version --no-git-tag-version --new-version "${VERSION#v}"
- name: Ingest upstream changes
if: |
inputs.include-changes &&
(!inputs.dependencies || contains(fromJSON(steps.update-dependencies.outputs.updated), inputs.include-changes))
uses: actions/github-script@v7
env:
RELEASE_ID: ${{ steps.release.outputs.id }}
DEPENDENCY: ${{ inputs.include-changes }}
with:
retries: 3
script: |
const { RELEASE_ID: releaseId, DEPENDENCY, VERSION } = process.env;
const { owner, repo } = context.repo;
const script = require("./.action-repo/scripts/release/merge-release-notes.js");
const notes = await script({
github,
releaseId,
dependencies: [DEPENDENCY.replace("$VERSION", VERSION)],
});
core.exportVariable("RELEASE_NOTES", notes);
- name: Add to CHANGELOG.md
if: inputs.final
run: |
mv CHANGELOG.md CHANGELOG.md.old
HEADER="Changes in [${VERSION#v}](https://github.com/${{ github.repository }}/releases/tag/$VERSION) ($(date '+%Y-%m-%d'))"
{
echo "$HEADER"
printf '=%.0s' $(seq ${#HEADER})
echo ""
echo "$RELEASE_NOTES"
echo ""
} > CHANGELOG.md
cat CHANGELOG.md.old >> CHANGELOG.md
rm CHANGELOG.md.old
git add CHANGELOG.md
- name: Run pre-release script to update package.json fields
run: |
./.action-repo/scripts/release/pre-release.sh
git add package.json
- name: Commit changes
run: git commit -m "$VERSION"
- name: Build assets
if: steps.prepare.outputs.has-dist-script == '1'
run: DIST_VERSION="$VERSION" yarn dist
- name: Upload release assets & signatures
if: inputs.asset-path
uses: ./.action-repo/.github/actions/upload-release-assets
with:
gpg-fingerprint: ${{ inputs.gpg-fingerprint }}
upload-url: ${{ steps.release.outputs.upload_url }}
asset-path: ${{ inputs.asset-path }}
- name: Create signed tag
if: inputs.gpg-fingerprint
run: |
GIT_COMMITTER_EMAIL="$SIGNING_ID" GPG_TTY=$(tty) git tag -u "$SIGNING_ID" -m "Release $VERSION" "$VERSION"
env:
SIGNING_ID: ${{ steps.gpg.outputs.email }}
- name: Generate & upload tarball signature
if: inputs.gpg-fingerprint
uses: ./.action-repo/.github/actions/sign-release-tarball
with:
gpg-fingerprint: ${{ inputs.gpg-fingerprint }}
upload-url: ${{ steps.release.outputs.upload_url }}
# We defer pushing changes until after the release assets are built,
# signed & uploaded to improve the atomicity of this action.
- name: Push changes to staging
run: |
git push origin staging $TAG
git reset --hard
env:
TAG: ${{ inputs.gpg-fingerprint && env.VERSION || '' }}
- name: Validate tarball signature
if: inputs.gpg-fingerprint
run: |
wget https://github.com/$GITHUB_REPOSITORY/archive/refs/tags/$VERSION.tar.gz
gpg --verify "$VERSION.tar.gz.asc" "$VERSION.tar.gz"
- name: Validate release has expected assets
if: inputs.expected-asset-count
uses: actions/github-script@v7
env:
RELEASE_ID: ${{ steps.release.outputs.id }}
EXPECTED_ASSET_COUNT: ${{ inputs.expected-asset-count }}
with:
retries: 3
script: |
const { RELEASE_ID: release_id, EXPECTED_ASSET_COUNT } = process.env;
const { owner, repo } = context.repo;
const { data: release } = await github.rest.repos.getRelease({
owner,
repo,
release_id,
});
if (release.assets.length !== parseInt(EXPECTED_ASSET_COUNT, 10)) {
core.setFailed(`Found ${release.assets.length} assets but expected ${EXPECTED_ASSET_COUNT}`);
}
- name: Merge to master
if: inputs.final
run: |
git checkout master
git merge -X theirs staging
git push origin master
- name: Publish release
uses: actions/github-script@v7
env:
RELEASE_ID: ${{ steps.release.outputs.id }}
FINAL: ${{ inputs.final }}
with:
retries: 3
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
script: |
const { RELEASE_ID: release_id, RELEASE_NOTES, VERSION, FINAL } = process.env;
const { owner, repo } = context.repo;
const opts = {
owner,
repo,
release_id,
tag_name: VERSION,
name: VERSION,
draft: false,
body: RELEASE_NOTES,
};
if (FINAL == "true") {
opts.prerelease = false;
opts.make_latest = true;
}
github.rest.repos.updateRelease(opts);
npm:
name: Publish to npm
needs: release
if: inputs.npm
uses: matrix-org/matrix-js-sdk/.github/workflows/release-npm.yml@develop
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
update-labels:
name: Advance release blocker labels
needs: release
runs-on: ubuntu-latest
steps:
- id: repository
run: echo "REPO=${GITHUB_REPOSITORY#*/}" >> $GITHUB_OUTPUT
- uses: garganshu/github-label-updater@3770d15ebfed2fe2cb06a241047bc340f774a7d1 # v1.0.0
with:
owner: ${{ github.repository_owner }}
repo: ${{ steps.repository.outputs.REPO }}
token: ${{ secrets.GITHUB_TOKEN }}
filter-labels: X-Upcoming-Release-Blocker
remove-labels: X-Upcoming-Release-Blocker
add-labels: X-Release-Blocker
+33 -34
View File
@@ -1,41 +1,40 @@
# Must only be called from `release#published` triggers
name: Publish to npm
on:
workflow_call:
secrets:
NPM_TOKEN:
required: true
workflow_call:
secrets:
NPM_TOKEN:
required: true
jobs:
npm:
name: Publish to npm
runs-on: ubuntu-latest
steps:
- name: 🧮 Checkout code
uses: actions/checkout@v3
npm:
name: Publish to npm
runs-on: ubuntu-latest
steps:
- name: 🧮 Checkout code
uses: actions/checkout@v4
with:
ref: staging
- name: 🔧 Yarn cache
uses: actions/setup-node@v3
with:
cache: "yarn"
registry-url: 'https://registry.npmjs.org'
- name: 🔧 Yarn cache
uses: actions/setup-node@v4
with:
cache: "yarn"
registry-url: "https://registry.npmjs.org"
- name: 🔨 Install dependencies
run: "yarn install --pure-lockfile"
- name: 🔨 Install dependencies
run: "yarn install --frozen-lockfile"
- name: 🚀 Publish to npm
id: npm-publish
uses: JS-DevTools/npm-publish@v1
with:
token: ${{ secrets.NPM_TOKEN }}
access: public
tag: next
- name: 🚀 Publish to npm
id: npm-publish
uses: JS-DevTools/npm-publish@4b07b26a2f6e0a51846e1870223e545bae91c552 # v3.0.1
with:
token: ${{ secrets.NPM_TOKEN }}
access: public
tag: next
ignore-scripts: false
- name: 🎖️ Add `latest` dist-tag to final releases
if: github.event.release.prerelease == false
run: |
package=$(cat package.json | jq -er .name)
npm dist-tag add "$package@$release" latest
env:
# JS-DevTools/npm-publish overrides `NODE_AUTH_TOKEN` with `INPUT_TOKEN` in .npmrc
INPUT_TOKEN: ${{ secrets.NPM_TOKEN }}
release: ${{ steps.npm-publish.outputs.version }}
- name: 🎖️ Add `latest` dist-tag to final releases
if: steps.npm-publish.outputs.id && !contains(steps.npm-publish.outputs.id, '-rc.')
run: npm dist-tag add "$release" latest
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
release: ${{ steps.npm-publish.outputs.id }}
+64 -46
View File
@@ -1,58 +1,76 @@
name: Release Process
on:
release:
types: [ published ]
concurrency: ${{ github.workflow }}-${{ github.ref }}
workflow_dispatch:
inputs:
mode:
description: What type of release
required: true
default: rc
type: choice
options:
- rc
- final
docs:
description: Publish docs
required: true
type: boolean
default: true
npm:
description: Publish to npm
required: true
type: boolean
default: true
concurrency: ${{ github.workflow }}
jobs:
jsdoc:
name: Publish Documentation
runs-on: ubuntu-latest
steps:
- name: 🧮 Checkout code
uses: actions/checkout@v3
- name: 🔧 Yarn cache
uses: actions/setup-node@v3
release:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop
secrets: inherit
with:
cache: "yarn"
final: ${{ inputs.mode == 'final' }}
npm: ${{ inputs.npm }}
- name: 🔨 Install dependencies
run: "yarn install --pure-lockfile"
docs:
name: Publish Documentation
needs: release
if: inputs.docs
runs-on: ubuntu-latest
steps:
- name: 🧮 Checkout code
uses: actions/checkout@v4
- name: 📖 Generate JSDoc
run: "yarn gendoc"
- name: 🧮 Checkout gh-pages
uses: actions/checkout@v4
with:
ref: gh-pages
path: _docs
- name: 📋 Copy to temp
run: |
tag="${{ github.ref_name }}"
version="${tag#v}"
echo "VERSION=$version" >> $GITHUB_ENV
cp -a "./.jsdoc/matrix-js-sdk/$version" $RUNNER_TEMP
- name: 🔧 Yarn cache
uses: actions/setup-node@v4
with:
cache: "yarn"
- name: 🧮 Checkout gh-pages
uses: actions/checkout@v3
with:
ref: gh-pages
- name: 🔨 Install dependencies
run: "yarn install --frozen-lockfile"
- name: 🔪 Prepare
run: |
cp -a "$RUNNER_TEMP/$VERSION" .
- name: 🔨 Install symlinks
run: |
sudo apt-get update
sudo apt-get install -y symlinks
# Add the new directory to the index if it isn't there already
if ! grep -q ">Version $VERSION</a>" index.html; then
perl -i -pe 'BEGIN {$rel=shift} $_ =~ /^<\/ul>/ && print
"<li><a href=\"${rel}/index.html\">Version ${rel}</a></li>\n"' "$VERSION" index.html
fi
- name: 📖 Generate docs
run: |
yarn tpv purge --yes --out _docs --stale --major 10
yarn gendoc
symlinks -rc _docs
- name: 🚀 Deploy
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
keep_files: true
publish_dir: .
- name: 🔨 Set up git
run: |
git config --global user.email "releases@riot.im"
git config --global user.name "RiotRobot"
npm:
name: Publish
uses: matrix-org/matrix-js-sdk/.github/workflows/release-npm.yml@develop
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: 🚀 Deploy
run: |
git add . --all
git commit -m "Update docs"
git push
working-directory: _docs
+47 -40
View File
@@ -1,45 +1,52 @@
# Must only be called from a workflow_run in the context of the upstream repo
name: SonarCloud
on:
workflow_call:
secrets:
SONAR_TOKEN:
required: true
workflow_call:
secrets:
SONAR_TOKEN:
required: true
inputs:
extra_args:
type: string
required: false
description: "Extra args to pass to SonarCloud"
jobs:
sonarqube:
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion == 'success'
steps:
# We create the status here and then update it to success/failure in the `report` stage
# This provides an easy link to this workflow_run from the PR before Cypress is done.
- uses: Sibz/github-status-action@v1
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
state: pending
context: ${{ github.workflow }} / SonarCloud (${{ github.event.workflow_run.event }} => ${{ github.event_name }})
sha: ${{ github.event.workflow_run.head_sha }}
target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
sonarqube:
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion == 'success'
steps:
# We create the status here and then update it to success/failure in the `report` stage
# This provides an easy link to this workflow_run from the PR before Cypress is done.
- uses: Sibz/github-status-action@faaa4d96fecf273bd762985e0e7f9f933c774918 # v1
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
state: pending
context: ${{ github.workflow }} / SonarCloud (${{ github.event.workflow_run.event }} => ${{ github.event_name }})
sha: ${{ github.event.workflow_run.head_sha }}
target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: "🩻 SonarCloud Scan"
id: sonarcloud
uses: matrix-org/sonarcloud-workflow-action@v2.2
with:
repository: ${{ github.event.workflow_run.head_repository.full_name }}
is_pr: ${{ github.event.workflow_run.event == 'pull_request' }}
version_cmd: 'cat package.json | jq -r .version'
branch: ${{ github.event.workflow_run.head_branch }}
revision: ${{ github.event.workflow_run.head_sha }}
token: ${{ secrets.SONAR_TOKEN }}
coverage_run_id: ${{ github.event.workflow_run.id }}
coverage_workflow_name: tests.yml
coverage_extract_path: coverage
- uses: Sibz/github-status-action@v1
if: always()
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
state: ${{ steps.sonarcloud.outcome == 'success' && 'success' || 'failure' }}
context: ${{ github.workflow }} / SonarCloud (${{ github.event.workflow_run.event }} => ${{ github.event_name }})
sha: ${{ github.event.workflow_run.head_sha }}
target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: "🩻 SonarCloud Scan"
id: sonarcloud
uses: matrix-org/sonarcloud-workflow-action@v2.7
# workflow_run fails report against the develop commit always, we don't want that for PRs
continue-on-error: ${{ github.event.workflow_run.head_branch != 'develop' }}
with:
repository: ${{ github.event.workflow_run.head_repository.full_name }}
is_pr: ${{ github.event.workflow_run.event == 'pull_request' }}
version_cmd: "cat package.json | jq -r .version"
branch: ${{ github.event.workflow_run.head_branch }}
revision: ${{ github.event.workflow_run.head_sha }}
token: ${{ secrets.SONAR_TOKEN }}
coverage_run_id: ${{ github.event.workflow_run.id }}
coverage_workflow_name: tests.yml
coverage_extract_path: coverage
extra_args: ${{ inputs.extra_args }}
- uses: Sibz/github-status-action@faaa4d96fecf273bd762985e0e7f9f933c774918 # v1
if: always()
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
state: ${{ steps.sonarcloud.outcome == 'success' && 'success' || 'failure' }}
context: ${{ github.workflow }} / SonarCloud (${{ github.event.workflow_run.event }} => ${{ github.event_name }})
sha: ${{ github.event.workflow_run.head_sha }}
target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
+41 -11
View File
@@ -1,15 +1,45 @@
name: SonarQube
on:
workflow_run:
workflows: [ "Tests" ]
types:
- completed
workflow_run:
workflows: ["Tests"]
types:
- completed
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true
jobs:
sonarqube:
name: 🩻 SonarQube
uses: matrix-org/matrix-js-sdk/.github/workflows/sonarcloud.yml@develop
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
# This is a workaround for https://github.com/SonarSource/SonarJS/issues/578
prepare:
name: Prepare
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event != 'merge_group'
runs-on: ubuntu-latest
outputs:
reportPaths: ${{ steps.extra_args.outputs.reportPaths }}
testExecutionReportPaths: ${{ steps.extra_args.outputs.testExecutionReportPaths }}
steps:
# There's a 'download artifact' action, but it hasn't been updated for the workflow_run action
# (https://github.com/actions/download-artifact/issues/60) so instead we get this mess:
- name: 📥 Download artifact
uses: dawidd6/action-download-artifact@246dbf436b23d7c49e21a7ab8204ca9ecd1fe615 # v2
with:
workflow: tests.yaml
run_id: ${{ github.event.workflow_run.id }}
name: coverage
path: coverage
- id: extra_args
run: |
coverage=$(find coverage -type f -name '*lcov.info' | tr '\n' ',' | sed 's/,$//g')
echo "reportPaths=$coverage" >> $GITHUB_OUTPUT
reports=$(find coverage -type f -name 'jest-sonar-report*.xml' | tr '\n' ',' | sed 's/,$//g')
echo "testExecutionReportPaths=$reports" >> $GITHUB_OUTPUT
sonarqube:
name: 🩻 SonarQube
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event != 'merge_group'
needs: prepare
uses: matrix-org/matrix-js-sdk/.github/workflows/sonarcloud.yml@develop
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
with:
extra_args: -Dsonar.javascript.lcov.reportPaths=${{ needs.prepare.outputs.reportPaths }} -Dsonar.testExecutionReportPaths=${{ needs.prepare.outputs.testExecutionReportPaths }}
+78 -80
View File
@@ -1,101 +1,99 @@
name: Static Analysis
on:
pull_request: { }
push:
branches: [ develop, master ]
pull_request: {}
merge_group:
types: [checks_requested]
push:
branches: [develop, master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
ts_lint:
name: "Typescript Syntax Check"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
ts_lint:
name: "Typescript Syntax Check"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
cache: 'yarn'
- uses: actions/setup-node@v4
with:
cache: "yarn"
- name: Install Deps
run: "yarn install"
- name: Install Deps
run: "yarn install"
- name: Typecheck
run: "yarn run lint:types"
- name: Typecheck
run: "yarn run lint:types"
- name: Switch js-sdk to release mode
run: |
scripts/switch_package_to_release.js
yarn install
yarn run build:compile
yarn run build:types
- name: Switch js-sdk to release mode
run: |
scripts/switch_package_to_release.js
yarn install
yarn run build:compile
yarn run build:types
- name: Typecheck (release mode)
run: "yarn run lint:types"
- name: Typecheck (release mode)
run: "yarn run lint:types"
js_lint:
name: "ESLint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
js_lint:
name: "ESLint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
cache: 'yarn'
- uses: actions/setup-node@v4
with:
cache: "yarn"
- name: Install Deps
run: "yarn install"
- name: Install Deps
run: "yarn install"
- name: Run Linter
run: "yarn run lint:js"
- name: Run Linter
run: "yarn run lint:js"
docs:
name: "JSDoc Checker"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
workflow_lint:
name: "Workflow Lint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
cache: 'yarn'
- uses: actions/setup-node@v4
with:
cache: "yarn"
- name: Install Deps
run: "yarn install"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Generate Docs
run: "yarn run gendoc"
- name: Run Linter
run: "yarn lint:workflows"
tsc-strict:
name: Typescript Strict Error Checker
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
permissions:
pull-requests: read
checks: write
steps:
- uses: actions/checkout@v3
docs:
name: "JSDoc Checker"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get diff lines
id: diff
uses: Equip-Collaboration/diff-line-numbers@v1.0.0
with:
include: '["\\.tsx?$"]'
- uses: actions/setup-node@v4
with:
cache: "yarn"
- name: Detecting files changed
id: files
uses: futuratrepadeira/changed-files@v4.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
pattern: '^.*\.tsx?$'
- name: Install Deps
run: "yarn install"
- uses: t3chguy/typescript-check-action@main
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
use-check: false
check-fail-mode: added
output-behaviour: annotate
ts-extra-args: '--strict'
files-changed: ${{ steps.files.outputs.files_updated }}
files-added: ${{ steps.files.outputs.files_created }}
files-deleted: ${{ steps.files.outputs.files_deleted }}
line-numbers: ${{ steps.diff.outputs.lineNumbers }}
- name: Generate Docs
run: "yarn run gendoc --treatWarningsAsErrors"
# Upload artifact duplicates symlink contents so we do this to save 75% space
- name: Flatten symlink and write _redirects
run: |
find _docs -mindepth 1 -maxdepth 1 ! -type f ! -name stable -printf '/%f/* /stable/:splat\n' > _docs/_redirects
find _docs -mindepth 1 -maxdepth 1 -type l -delete
find _docs -mindepth 1 -maxdepth 1 -type d -execdir mv {} stable \; -quit
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: docs
path: _docs
# We'll only use this in a workflow_run, then we're done with it
retention-days: 1
+87 -29
View File
@@ -1,37 +1,95 @@
name: Tests
on:
pull_request: { }
push:
branches: [ develop, master ]
pull_request: {}
merge_group:
types: [checks_requested]
push:
branches: [develop, master]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
ENABLE_COVERAGE: ${{ github.event_name != 'merge_group' }}
jobs:
jest:
name: Jest
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
jest:
name: "Jest [${{ matrix.specs }}] (Node ${{ matrix.node == '*' && 'latest' || matrix.node }})"
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
matrix:
specs: [integ, unit]
node: [18, "lts/*", 21]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Yarn cache
uses: actions/setup-node@v3
- name: Setup Node
id: setupNode
uses: actions/setup-node@v4
with:
cache: "yarn"
node-version: ${{ matrix.node }}
- name: Install dependencies
run: "yarn install"
- name: Get number of CPU cores
id: cpu-cores
uses: SimenB/github-actions-cpu-cores@97ba232459a8e02ff6121db9362b09661c875ab8 # v2
- name: Run tests
run: |
yarn test \
--coverage=${{ env.ENABLE_COVERAGE }} \
--ci \
--max-workers ${{ steps.cpu-cores.outputs.count }} \
./spec/${{ matrix.specs }}
env:
JEST_SONAR_UNIQUE_OUTPUT_NAME: true
# tell jest to use coloured output
FORCE_COLOR: true
- name: Move coverage files into place
if: env.ENABLE_COVERAGE == 'true'
run: mv coverage/lcov.info coverage/${{ steps.setupNode.output.node-version }}-${{ matrix.specs }}.lcov.info
- name: Upload Artifact
if: env.ENABLE_COVERAGE == 'true'
uses: actions/upload-artifact@v3
with:
name: coverage
path: |
coverage
!coverage/lcov-report
matrix-react-sdk:
name: Downstream test matrix-react-sdk
if: github.event_name == 'merge_group'
uses: matrix-org/matrix-react-sdk/.github/workflows/tests.yml@develop
with:
cache: 'yarn'
disable_coverage: true
matrix-js-sdk-sha: ${{ github.sha }}
- name: Install dependencies
run: "yarn install"
# Hook for branch protection to skip downstream testing outside of merge queues
# and skip sonarcloud coverage within merge queues
downstream:
name: Downstream tests
runs-on: ubuntu-latest
if: always()
needs:
- matrix-react-sdk
steps:
- name: Skip SonarCloud on merge queues
if: env.ENABLE_COVERAGE == 'false'
uses: Sibz/github-status-action@faaa4d96fecf273bd762985e0e7f9f933c774918 # v1
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
state: success
description: SonarCloud skipped
context: SonarCloud Code Analysis
sha: ${{ github.sha }}
target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: Build
run: "yarn build"
- name: Run tests with coverage
run: "yarn coverage --ci --reporters github-actions"
- name: Upload Artifact
uses: actions/upload-artifact@v3
with:
name: coverage
path: |
coverage
!coverage/lcov-report
- if: needs.matrix-react-sdk.result != 'skipped' && needs.matrix-react-sdk.result != 'success'
run: exit 1
+11
View File
@@ -0,0 +1,11 @@
name: Move labelled issues to correct projects
on:
issues:
types: [labeled]
jobs:
call-triage-labelled:
uses: vector-im/element-web/.github/workflows/triage-labelled.yml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
@@ -1,38 +0,0 @@
name: Upgrade Dependencies
on:
workflow_dispatch: { }
workflow_call:
secrets:
ELEMENT_BOT_TOKEN:
required: true
jobs:
upgrade:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
cache: 'yarn'
- name: Upgrade
run: yarn upgrade && yarn install
- name: Create Pull Request
id: cpr
uses: peter-evans/create-pull-request@v4
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
branch: actions/upgrade-deps
delete-branch: true
title: Upgrade dependencies
labels: |
Dependencies
T-Task
- name: Enable automerge
uses: peter-evans/enable-pull-request-automerge@v2
if: steps.cpr.outputs.pull-request-operation == 'created'
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
pull-request-number: ${{ steps.cpr.outputs.pull-request-number }}
+3 -2
View File
@@ -1,5 +1,5 @@
/.jsdocbuild
/.jsdoc
/_docs
.DS_Store
node_modules
/.npmrc
@@ -19,3 +19,4 @@ out
.vscode
.vscode/
.idea/
+4
View File
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
+4
View File
@@ -0,0 +1,4 @@
{
"*.(ts|tsx)": ["eslint --fix", "prettier --write"],
"*.(py|md|yaml)": ["prettier --write"]
}
+29
View File
@@ -0,0 +1,29 @@
/_docs
.DS_Store
/.npmrc
/*.log
package-lock.json
.lock-wscript
build/Release
coverage
lib-cov
out
/dist
/lib
/examples/browser/lib
/examples/crypto-browser/lib
/examples/voip/lib
# version file and tarball created by `npm pack` / `yarn pack`
/git-revision.txt
/matrix-js-sdk-*.tgz
.vscode
.vscode/
# This file is owned, parsed, and generated by allchange, which doesn't comply with prettier
/CHANGELOG.md
# This file is also autogenerated
/spec/test-utils/test-data/index.ts
+1
View File
@@ -0,0 +1 @@
module.exports = require("eslint-plugin-matrix-org/.prettierrc.js");
+608
View File
@@ -1,3 +1,611 @@
Changes in [30.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v30.2.0) (2023-12-05)
==================================================================================================
## ✨ Features
* Only await key query after lazy members resolved ([#3902](https://github.com/matrix-org/matrix-js-sdk/pull/3902)). Contributed by @BillCarsonFr.
## 🐛 Bug Fixes
* Rewrite receipt-handling code ([#3901](https://github.com/matrix-org/matrix-js-sdk/pull/3901)). Contributed by @andybalaam.
* Explicitly free some Rust-side objects ([#3911](https://github.com/matrix-org/matrix-js-sdk/pull/3911)). Contributed by @richvdh.
* Fix type for TimestampToEventResponse.origin\_server\_ts ([#3906](https://github.com/matrix-org/matrix-js-sdk/pull/3906)). Contributed by @Half-Shot.
Changes in [30.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v30.1.0) (2023-11-21)
==================================================================================================
## ✨ Features
* Rotate per-participant keys when a member leaves ([#3833](https://github.com/matrix-org/matrix-js-sdk/pull/3833)). Contributed by @dbkr.
* Add E2EE for embedded mode of Element Call ([#3667](https://github.com/matrix-org/matrix-js-sdk/pull/3667)). Contributed by @SimonBrandner.
## 🐛 Bug Fixes
* Shorten TimelineWindow when an event is removed ([#3862](https://github.com/matrix-org/matrix-js-sdk/pull/3862)). Contributed by @andybalaam.
* Ignore receipts pointing at missing or invalid events ([#3817](https://github.com/matrix-org/matrix-js-sdk/pull/3817)). Contributed by @andybalaam.
* Fix members being loaded from server on initial sync (defeating lazy loading) ([#3830](https://github.com/matrix-org/matrix-js-sdk/pull/3830)). Contributed by @BillCarsonFr.
Changes in [30.0.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v30.0.1) (2023-11-13)
==================================================================================================
## 🐛 Bug Fixes
* Ensure `setUserCreator` is called when a store is assigned ([\#3867](https://github.com/matrix-org/matrix-js-sdk/pull/3867)). Fixes vector-im/element-web#26520. Contributed by @MidhunSureshR.
Changes in [30.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v30.0.0) (2023-11-07)
==================================================================================================
## 🚨 BREAKING CHANGES
* Refactor & make base64 functions browser-safe ([\#3818](https://github.com/matrix-org/matrix-js-sdk/pull/3818)).
## 🦖 Deprecations
* Deprecate `MatrixEvent.toJSON` ([\#3801](https://github.com/matrix-org/matrix-js-sdk/pull/3801)).
## ✨ Features
* Element-R: Add the git sha of the binding crate to `CryptoApi#getVersion` ([\#3838](https://github.com/matrix-org/matrix-js-sdk/pull/3838)). Contributed by @florianduros.
* Element-R: Wire up `globalBlacklistUnverifiedDevices` field to rust crypto encryption settings ([\#3790](https://github.com/matrix-org/matrix-js-sdk/pull/3790)). Fixes vector-im/element-web#26315. Contributed by @florianduros.
* Element-R: Wire up room rotation ([\#3807](https://github.com/matrix-org/matrix-js-sdk/pull/3807)). Fixes vector-im/element-web#26318. Contributed by @florianduros.
* Element-R: Add current version of the rust-sdk and vodozemac ([\#3825](https://github.com/matrix-org/matrix-js-sdk/pull/3825)). Contributed by @florianduros.
* Element-R: Wire up room history visibility ([\#3805](https://github.com/matrix-org/matrix-js-sdk/pull/3805)). Fixes vector-im/element-web#26319. Contributed by @florianduros.
* Element-R: log when we send to-device messages ([\#3810](https://github.com/matrix-org/matrix-js-sdk/pull/3810)).
## 🐛 Bug Fixes
* Fix reemitter not being correctly wired on user objects created in storage classes ([\#3796](https://github.com/matrix-org/matrix-js-sdk/pull/3796)). Contributed by @MidhunSureshR.
* Element-R: silence log errors when viewing a pending event ([\#3824](https://github.com/matrix-org/matrix-js-sdk/pull/3824)).
* Don't emit a closed event if the indexeddb is closed by Element ([\#3832](https://github.com/matrix-org/matrix-js-sdk/pull/3832)). Fixes vector-im/element-web#25941. Contributed by @dhenneke.
* Element-R: silence log errors when viewing a decryption failure ([\#3821](https://github.com/matrix-org/matrix-js-sdk/pull/3821)).
Changes in [29.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v29.1.0) (2023-10-24)
==================================================================================================
## ✨ Features
* OIDC: refresh tokens ([\#3764](https://github.com/matrix-org/matrix-js-sdk/pull/3764)). Contributed by @kerryarchibald.
* OIDC: add `prompt` param to auth url creation ([\#3794](https://github.com/matrix-org/matrix-js-sdk/pull/3794)). Contributed by @kerryarchibald.
* Allow applications to specify their own logger instance ([\#3792](https://github.com/matrix-org/matrix-js-sdk/pull/3792)). Fixes #1899.
* Export AutoDiscoveryError and fix type of ALL_ERRORS ([\#3768](https://github.com/matrix-org/matrix-js-sdk/pull/3768)).
## 🐛 Bug Fixes
* Fix sending call member events on leave ([\#3799](https://github.com/matrix-org/matrix-js-sdk/pull/3799)). Fixes vector-im/element-call#1763.
* Don't use event.sender in CallMembership ([\#3793](https://github.com/matrix-org/matrix-js-sdk/pull/3793)).
* Element-R: Don't mark QR code verification as done until it's done ([\#3791](https://github.com/matrix-org/matrix-js-sdk/pull/3791)). Fixes vector-im/element-web#26293.
* Element-R: Connect device to key backup when crypto is created ([\#3784](https://github.com/matrix-org/matrix-js-sdk/pull/3784)). Fixes vector-im/element-web#26316. Contributed by @florianduros.
* Element-R: Avoid errors in `VerificationRequest.generateQRCode` when QR code is unavailable ([\#3779](https://github.com/matrix-org/matrix-js-sdk/pull/3779)). Fixes vector-im/element-web#26300. Contributed by @florianduros.
* ElementR: Check key backup when user identity changes ([\#3760](https://github.com/matrix-org/matrix-js-sdk/pull/3760)). Fixes vector-im/element-web#26244. Contributed by @florianduros.
* Element-R: emit `VerificationRequestReceived` on incoming request ([\#3762](https://github.com/matrix-org/matrix-js-sdk/pull/3762)). Fixes vector-im/element-web#26245.
Changes in [29.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v29.0.0) (2023-10-10)
==================================================================================================
## 🚨 BREAKING CHANGES
* Remove browserify builds ([\#3759](https://github.com/matrix-org/matrix-js-sdk/pull/3759)).
## ✨ Features
* Export AutoDiscoveryError and fix type of ALL_ERRORS ([\#3768](https://github.com/matrix-org/matrix-js-sdk/pull/3768)).
* Support for stable MSC3882 get_login_token ([\#3416](https://github.com/matrix-org/matrix-js-sdk/pull/3416)). Contributed by @hughns.
* Remove IsUserMention and IsRoomMention from DEFAULT_OVERRIDE_RULES ([\#3752](https://github.com/matrix-org/matrix-js-sdk/pull/3752)). Contributed by @kerryarchibald.
## 🐛 Bug Fixes
* Fix a case where joinRoom creates a duplicate Room object ([\#3747](https://github.com/matrix-org/matrix-js-sdk/pull/3747)).
* Add membershipID to call memberships ([\#3745](https://github.com/matrix-org/matrix-js-sdk/pull/3745)).
* Fix the warning for messages from unsigned devices ([\#3743](https://github.com/matrix-org/matrix-js-sdk/pull/3743)).
* Stop keep alive, when sync was stoped ([\#3720](https://github.com/matrix-org/matrix-js-sdk/pull/3720)). Contributed by @finsterwalder.
Changes in [28.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v28.2.0) (2023-09-26)
==================================================================================================
## 🦖 Deprecations
* Implement `getEncryptionInfoForEvent` and deprecate `getEventEncryptionInfo` ([\#3693](https://github.com/matrix-org/matrix-js-sdk/pull/3693)).
* **The Browserify artifact is being deprecated, scheduled for removal in the October 10th release cycle. (#3189)**
## ✨ Features
* Delete knocked room when knock membership changes ([\#3729](https://github.com/matrix-org/matrix-js-sdk/pull/3729)). Contributed by @maheichyk.
* Introduce MatrixRTCSession lower level group call primitive ([\#3663](https://github.com/matrix-org/matrix-js-sdk/pull/3663)).
* Sync knock rooms ([\#3703](https://github.com/matrix-org/matrix-js-sdk/pull/3703)). Contributed by @maheichyk.
## 🐛 Bug Fixes
* Dont access indexed db when undefined ([\#3707](https://github.com/matrix-org/matrix-js-sdk/pull/3707)). Contributed by @finsterwalder.
* Don't reset unread count when adding a synthetic receipt ([\#3706](https://github.com/matrix-org/matrix-js-sdk/pull/3706)). Fixes #3684. Contributed by @andybalaam.
Changes in [28.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v28.1.0) (2023-09-12)
============================================================================================================
## 🦖 Deprecations
* Deprecate `MatrixClient.checkUserTrust` ([\#3691](https://github.com/matrix-org/matrix-js-sdk/pull/3691)).
* Deprecate `MatrixClient.{prepare,create}KeyBackupVersion` in favour of new `CryptoApi.resetKeyBackup` API ([\#3689](https://github.com/matrix-org/matrix-js-sdk/pull/3689)).
* **The Browserify artifact is being deprecated, scheduled for removal in the October 10th release cycle. (#3189)**
## ✨ Features
* Allow calls without ICE/TURN/STUN servers ([\#3695](https://github.com/matrix-org/matrix-js-sdk/pull/3695)).
* Emit summary update event ([\#3687](https://github.com/matrix-org/matrix-js-sdk/pull/3687)). Fixes vector-im/element-web#26033.
* ElementR: Update `CryptoApi.userHasCrossSigningKeys` ([\#3646](https://github.com/matrix-org/matrix-js-sdk/pull/3646)). Contributed by @florianduros.
* Add `join_rule` field to /publicRooms response ([\#3673](https://github.com/matrix-org/matrix-js-sdk/pull/3673)). Contributed by @charlynguyen.
* Use sender instead of content.creator field on m.room.create events ([\#3675](https://github.com/matrix-org/matrix-js-sdk/pull/3675)).
## 🐛 Bug Fixes
* Provide better error for ICE Server SyntaxError ([\#3694](https://github.com/matrix-org/matrix-js-sdk/pull/3694)). Fixes vector-im/element-web#21804.
* Legacy crypto: re-check key backup after `bootstrapSecretStorage` ([\#3692](https://github.com/matrix-org/matrix-js-sdk/pull/3692)). Fixes vector-im/element-web#26115.
Changes in [28.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v28.0.0) (2023-08-29)
==================================================================================================
## 🚨 BREAKING CHANGES
* Set minimum supported Matrix 1.1 version (drop legacy r0 versions) ([\#3007](https://github.com/matrix-org/matrix-js-sdk/pull/3007)). Fixes vector-im/element-web#16876.
## 🦖 Deprecations
* **The Browserify artifact is being deprecated, scheduled for removal in the October 10th release cycle. (#3189)**
## ✨ Features
* ElementR: Add `CryptoApi.requestVerificationDM` ([\#3643](https://github.com/matrix-org/matrix-js-sdk/pull/3643)). Contributed by @florianduros.
* Implement `CryptoApi.checkKeyBackupAndEnable` ([\#3633](https://github.com/matrix-org/matrix-js-sdk/pull/3633)). Fixes vector-im/crypto-internal#111 and vector-im/crypto-internal#112.
## 🐛 Bug Fixes
* ElementR: Process all verification events, not just requests ([\#3650](https://github.com/matrix-org/matrix-js-sdk/pull/3650)). Contributed by @florianduros.
Changes in [27.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v27.2.0) (2023-08-15)
==================================================================================================
## 🦖 Deprecations
* **The Browserify artifact is being deprecated, scheduled for removal in the October 10th release cycle. (#3189)**
## ✨ Features
* Allow knocking rooms ([\#3647](https://github.com/matrix-org/matrix-js-sdk/pull/3647)). Contributed by @charlynguyen.
* Bump pagination limit to account for threaded events ([\#3638](https://github.com/matrix-org/matrix-js-sdk/pull/3638)).
* ElementR: Add `CryptoApi.findVerificationRequestDMInProgress` ([\#3601](https://github.com/matrix-org/matrix-js-sdk/pull/3601)). Contributed by @florianduros.
* Export more into the public interface ([\#3614](https://github.com/matrix-org/matrix-js-sdk/pull/3614)).
## 🐛 Bug Fixes
* Fix wrong handling of encrypted rooms when loading them from sync accumulator ([\#3640](https://github.com/matrix-org/matrix-js-sdk/pull/3640)). Fixes vector-im/element-web#25803.
* Skip processing thread roots and fetching threads list when support is disabled ([\#3642](https://github.com/matrix-org/matrix-js-sdk/pull/3642)).
* Ensure we don't overinflate the total notification count ([\#3634](https://github.com/matrix-org/matrix-js-sdk/pull/3634)). Fixes vector-im/element-web#25803.
Changes in [27.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v27.1.0) (2023-08-01)
==================================================================================================
## 🦖 Deprecations
* **The Browserify artifact is being deprecated, scheduled for removal in the October 10th release cycle. (#3189)**
## ✨ Features
* ElementR: Add `CryptoApi.getCrossSigningKeyId` ([\#3619](https://github.com/matrix-org/matrix-js-sdk/pull/3619)). Contributed by @florianduros.
* ElementR: Stub `CheckOwnCrossSigningTrust`, import cross signing keys and verify local device in `bootstrapCrossSigning` ([\#3608](https://github.com/matrix-org/matrix-js-sdk/pull/3608)). Contributed by @florianduros.
* Specify /preview_url requests as low priority ([\#3609](https://github.com/matrix-org/matrix-js-sdk/pull/3609)). Fixes vector-im/element-web#7292.
* Element-R: support for displaying QR codes during verification ([\#3588](https://github.com/matrix-org/matrix-js-sdk/pull/3588)). Fixes vector-im/crypto-internal#124.
* Add support for scanning QR codes during verification, with Rust crypto ([\#3565](https://github.com/matrix-org/matrix-js-sdk/pull/3565)).
* Add methods to influence set_presence on /sync API calls ([\#3578](https://github.com/matrix-org/matrix-js-sdk/pull/3578)).
## 🐛 Bug Fixes
* Fix threads ending up with chunks of their timelines missing ([\#3618](https://github.com/matrix-org/matrix-js-sdk/pull/3618)). Fixes vector-im/element-web#24466.
* Ensure we do not clobber a newer RR with an older unthreaded one ([\#3617](https://github.com/matrix-org/matrix-js-sdk/pull/3617)). Fixes vector-im/element-web#25806.
* Fix registration check your emails stage regression ([\#3616](https://github.com/matrix-org/matrix-js-sdk/pull/3616)).
* Fix how `Room::eventShouldLiveIn` handles replies to unknown parents ([\#3615](https://github.com/matrix-org/matrix-js-sdk/pull/3615)). Fixes vector-im/element-web#22603.
* Only send threaded read receipts if threads support is enabled ([\#3612](https://github.com/matrix-org/matrix-js-sdk/pull/3612)).
* ElementR: Fix `userId` parameter usage in `CryptoApi#getVerificationRequestsToDeviceInProgress` ([\#3611](https://github.com/matrix-org/matrix-js-sdk/pull/3611)). Contributed by @florianduros.
* Fix edge cases around non-thread relations to thread roots and read receipts ([\#3607](https://github.com/matrix-org/matrix-js-sdk/pull/3607)).
* Fix read receipt sending behaviour around thread roots ([\#3600](https://github.com/matrix-org/matrix-js-sdk/pull/3600)).
* Export typed event emitter key types ([\#3597](https://github.com/matrix-org/matrix-js-sdk/pull/3597)). Fixes #3506.
* Element-R: ensure that `userHasCrossSigningKeys` uses up-to-date data ([\#3599](https://github.com/matrix-org/matrix-js-sdk/pull/3599)). Fixes vector-im/element-web#25773.
* Fix sending `auth: null` due to broken types around UIA ([\#3594](https://github.com/matrix-org/matrix-js-sdk/pull/3594)).
Changes in [27.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v27.0.0) (2023-07-18)
==================================================================================================
## 🚨 BREAKING CHANGES
* Drop support for Node 16 ([\#3533](https://github.com/matrix-org/matrix-js-sdk/pull/3533)).
* Improve types around login, registration, UIA and identity servers ([\#3537](https://github.com/matrix-org/matrix-js-sdk/pull/3537)).
## 🦖 Deprecations
* **The Browserify artifact is being deprecated, scheduled for removal in the October 10th release cycle. (#3189)**
* Simplify `MatrixClient::setPowerLevel` API ([\#3570](https://github.com/matrix-org/matrix-js-sdk/pull/3570)). Fixes vector-im/element-web#13900 and #1844.
* Deprecate `VerificationRequest.getQRCodeBytes` and replace it with the asynchronous `generateQRCode`. ([\#3562](https://github.com/matrix-org/matrix-js-sdk/pull/3562)).
* Deprecate `VerificationRequest.beginKeyVerification()` in favour of `VerificationRequest.startVerification()`. ([\#3528](https://github.com/matrix-org/matrix-js-sdk/pull/3528)).
* Deprecate `Crypto.VerificationRequest` application event, replacing it with `Crypto.VerificationRequestReceived`. ([\#3514](https://github.com/matrix-org/matrix-js-sdk/pull/3514)).
## ✨ Features
* Throw saner error when peeking has its room pulled out from under it ([\#3577](https://github.com/matrix-org/matrix-js-sdk/pull/3577)). Fixes vector-im/element-web#18679.
* OIDC: Log in ([\#3554](https://github.com/matrix-org/matrix-js-sdk/pull/3554)). Contributed by @kerryarchibald.
* Prevent threads code from making identical simultaneous API hits ([\#3541](https://github.com/matrix-org/matrix-js-sdk/pull/3541)). Fixes vector-im/element-web#25395.
* Update IUnsigned type to be extensible ([\#3547](https://github.com/matrix-org/matrix-js-sdk/pull/3547)).
* add stop() api to BackupManager for clean shutdown ([\#3553](https://github.com/matrix-org/matrix-js-sdk/pull/3553)).
* Log the message ID of any undecryptable to-device messages ([\#3543](https://github.com/matrix-org/matrix-js-sdk/pull/3543)).
* Ignore thread relations on state events for consistency with edits ([\#3540](https://github.com/matrix-org/matrix-js-sdk/pull/3540)).
* OIDC: validate id token ([\#3531](https://github.com/matrix-org/matrix-js-sdk/pull/3531)). Contributed by @kerryarchibald.
## 🐛 Bug Fixes
* Fix read receipt sending behaviour around thread roots ([\#3600](https://github.com/matrix-org/matrix-js-sdk/pull/3600)).
* Fix `TypedEventEmitter::removeAllListeners(void)` not working ([\#3561](https://github.com/matrix-org/matrix-js-sdk/pull/3561)).
* Don't allow Olm unwedging rate-limiting to race ([\#3549](https://github.com/matrix-org/matrix-js-sdk/pull/3549)). Fixes vector-im/element-web#25716.
* Fix an instance of failed to decrypt error when an in flight `/keys/query` fails. ([\#3486](https://github.com/matrix-org/matrix-js-sdk/pull/3486)).
* Use the right anchor emoji for SAS verification ([\#3534](https://github.com/matrix-org/matrix-js-sdk/pull/3534)).
* fix a bug which caused the wrong emoji to be shown during SAS device verification. ([\#3523](https://github.com/matrix-org/matrix-js-sdk/pull/3523)).
Changes in [26.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v26.2.0) (2023-07-04)
==================================================================================================
## 🦖 Deprecations
* The Browserify artifact is being deprecated, scheduled for removal in the October 10th release cycle. ([\#3189](https://github.com/matrix-org/matrix-js-sdk/issues/3189)).
* ElementR: Add `CryptoApi#bootstrapSecretStorage` ([\#3483](https://github.com/matrix-org/matrix-js-sdk/pull/3483)). Contributed by @florianduros.
* Deprecate `MatrixClient.findVerificationRequestDMInProgress`, `MatrixClient.getVerificationRequestsToDeviceInProgress`, and `MatrixClient.requestVerification`, in favour of methods in `CryptoApi`. ([\#3474](https://github.com/matrix-org/matrix-js-sdk/pull/3474)).
* Introduce a new `Crypto.VerificationRequest` interface, and deprecate direct access to the old `VerificationRequest` class. Also deprecate some related classes that were exported from `src/crypto/verification/request/VerificationRequest` ([\#3449](https://github.com/matrix-org/matrix-js-sdk/pull/3449)).
## ✨ Features
* OIDC: navigate to authorization endpoint ([\#3499](https://github.com/matrix-org/matrix-js-sdk/pull/3499)). Contributed by @kerryarchibald.
* Support for interactive device verification in Element-R. ([\#3505](https://github.com/matrix-org/matrix-js-sdk/pull/3505)).
* Support for interactive device verification in Element-R. ([\#3508](https://github.com/matrix-org/matrix-js-sdk/pull/3508)).
* Support for interactive device verification in Element-R. ([\#3490](https://github.com/matrix-org/matrix-js-sdk/pull/3490)). Fixes vector-im/element-web#25316.
* Element-R: Store cross signing keys in secret storage ([\#3498](https://github.com/matrix-org/matrix-js-sdk/pull/3498)). Contributed by @florianduros.
* OIDC: add dynamic client registration util function ([\#3481](https://github.com/matrix-org/matrix-js-sdk/pull/3481)). Contributed by @kerryarchibald.
* Add getLastUnthreadedReceiptFor utility to Thread delegating to the underlying Room ([\#3493](https://github.com/matrix-org/matrix-js-sdk/pull/3493)).
* ElementR: Add `rust-crypto#createRecoveryKeyFromPassphrase` implementation ([\#3472](https://github.com/matrix-org/matrix-js-sdk/pull/3472)). Contributed by @florianduros.
## 🐛 Bug Fixes
* Aggregate relations regardless of whether event fits into the timeline ([\#3496](https://github.com/matrix-org/matrix-js-sdk/pull/3496)). Fixes vector-im/element-web#25596.
* Fix bug where switching media caused media in subsequent calls to fail ([\#3489](https://github.com/matrix-org/matrix-js-sdk/pull/3489)).
* Fix: remove polls from room state on redaction ([\#3475](https://github.com/matrix-org/matrix-js-sdk/pull/3475)). Fixes vector-im/element-web#25573. Contributed by @kerryarchibald.
* Fix export type `GeneratedSecretStorageKey` ([\#3479](https://github.com/matrix-org/matrix-js-sdk/pull/3479)). Contributed by @florianduros.
* Close IDB database before deleting it to prevent spurious unexpected close errors ([\#3478](https://github.com/matrix-org/matrix-js-sdk/pull/3478)). Fixes vector-im/element-web#25597.
Changes in [26.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v26.1.0) (2023-06-20)
==================================================================================================
## 🦖 Deprecations
* Introduce a new `Crypto.Verifier` interface, and deprecate direct access to `VerificationBase`, `SAS` and `ReciprocateQRCode` ([\#3414](https://github.com/matrix-org/matrix-js-sdk/pull/3414)).
## ✨ Features
* Add `rust-crypto#isCrossSigningReady` implementation ([\#3462](https://github.com/matrix-org/matrix-js-sdk/pull/3462)). Contributed by @florianduros.
* OIDC: Validate `m.authentication` configuration ([\#3419](https://github.com/matrix-org/matrix-js-sdk/pull/3419)). Contributed by @kerryarchibald.
* ElementR: Add `CryptoApi.getCrossSigningStatus` ([\#3452](https://github.com/matrix-org/matrix-js-sdk/pull/3452)). Contributed by @florianduros.
* Extend stats summary with call device and user count based on room state ([\#3424](https://github.com/matrix-org/matrix-js-sdk/pull/3424)). Contributed by @toger5.
* Update MSC3912 implementation to use `with_rel_type` instead of `with_relations` ([\#3420](https://github.com/matrix-org/matrix-js-sdk/pull/3420)).
* Export thread-related types from SDK ([\#3447](https://github.com/matrix-org/matrix-js-sdk/pull/3447)). Contributed by @stas-demydiuk.
* Use correct /v3 prefix for /refresh ([\#3016](https://github.com/matrix-org/matrix-js-sdk/pull/3016)). Contributed by @davidisaaclee.
## 🐛 Bug Fixes
* Fix thread list being ordered based on all updates ([\#3458](https://github.com/matrix-org/matrix-js-sdk/pull/3458)). Fixes vector-im/element-web#25522.
* Fix: handle `baseUrl` with trailing slash in `fetch.getUrl` ([\#3455](https://github.com/matrix-org/matrix-js-sdk/pull/3455)). Fixes vector-im/element-web#25526. Contributed by @kerryarchibald.
* use cli.canSupport to determine intentional mentions support ([\#3445](https://github.com/matrix-org/matrix-js-sdk/pull/3445)). Fixes vector-im/element-web#25497. Contributed by @kerryarchibald.
* Make sliding sync linearize processing of sync requests ([\#3442](https://github.com/matrix-org/matrix-js-sdk/pull/3442)).
* Fix edge cases around 2nd order relations and threads ([\#3437](https://github.com/matrix-org/matrix-js-sdk/pull/3437)).
Changes in [26.0.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v26.0.1) (2023-06-09)
==================================================================================================
## 🐛 Bug Fixes
* Fix: handle `baseUrl` with trailing slash in `fetch.getUrl` ([\#3455](https://github.com/matrix-org/matrix-js-sdk/pull/3455)). Fixes vector-im/element-web#25526. Contributed by @kerryarchibald.
Changes in [26.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v26.0.0) (2023-06-06)
==================================================================================================
## 🚨 BREAKING CHANGES
* Ensure we do not add relations to the wrong timeline ([\#3427](https://github.com/matrix-org/matrix-js-sdk/pull/3427)). Fixes vector-im/element-web#25450 and vector-im/element-web#25494.
* Deprecate `QrCodeEvent`, `SasEvent` and `VerificationEvent` ([\#3386](https://github.com/matrix-org/matrix-js-sdk/pull/3386)).
## 🦖 Deprecations
* Move crypto classes into a separate namespace ([\#3385](https://github.com/matrix-org/matrix-js-sdk/pull/3385)).
## ✨ Features
* Mention deno support in the README ([\#3417](https://github.com/matrix-org/matrix-js-sdk/pull/3417)). Contributed by @sigmaSd.
* Mark room version 10 as safe ([\#3425](https://github.com/matrix-org/matrix-js-sdk/pull/3425)).
* Prioritise entirely supported flows for UIA ([\#3402](https://github.com/matrix-org/matrix-js-sdk/pull/3402)).
* Add methods to terminate idb worker ([\#3362](https://github.com/matrix-org/matrix-js-sdk/pull/3362)).
* Total summary count ([\#3351](https://github.com/matrix-org/matrix-js-sdk/pull/3351)). Contributed by @toger5.
* Audio concealment ([\#3349](https://github.com/matrix-org/matrix-js-sdk/pull/3349)). Contributed by @toger5.
## 🐛 Bug Fixes
* Correctly accumulate sync summaries. ([\#3366](https://github.com/matrix-org/matrix-js-sdk/pull/3366)). Fixes vector-im/element-web#23345.
* Keep measuring a call feed's volume after a stream replacement ([\#3361](https://github.com/matrix-org/matrix-js-sdk/pull/3361)). Fixes vector-im/element-call#1051.
* Element-R: Avoid uploading a new fallback key at every `/sync` ([\#3338](https://github.com/matrix-org/matrix-js-sdk/pull/3338)). Fixes vector-im/element-web#25215.
* Accumulate receipts for the main thread and unthreaded separately ([\#3339](https://github.com/matrix-org/matrix-js-sdk/pull/3339)). Fixes vector-im/element-web#24629.
* Remove spec non-compliant extended glob format ([\#3423](https://github.com/matrix-org/matrix-js-sdk/pull/3423)). Fixes vector-im/element-web#25474.
* Fix bug where original event was inserted into timeline instead of the edit event ([\#3398](https://github.com/matrix-org/matrix-js-sdk/pull/3398)). Contributed by @andybalaam.
* Only add a local receipt if it's after an existing receipt ([\#3399](https://github.com/matrix-org/matrix-js-sdk/pull/3399)). Contributed by @andybalaam.
* Attempt a potential workaround for stuck notifs ([\#3384](https://github.com/matrix-org/matrix-js-sdk/pull/3384)). Fixes vector-im/element-web#25406. Contributed by @andybalaam.
* Fix verification bug with `pendingEventOrdering: "chronological"` ([\#3382](https://github.com/matrix-org/matrix-js-sdk/pull/3382)).
Changes in [25.1.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v25.1.1) (2023-05-16)
==================================================================================================
## 🐛 Bug Fixes
* Rebuild to fix packaging glitch in 25.1.0. Fixes #3363
Changes in [25.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v25.1.0) (2023-05-09)
==================================================================================================
## 🦖 Deprecations
* Deprecate MatrixClient::resolveRoomAlias ([\#3316](https://github.com/matrix-org/matrix-js-sdk/pull/3316)).
## ✨ Features
* add client method to remove pusher ([\#3324](https://github.com/matrix-org/matrix-js-sdk/pull/3324)). Contributed by @kerryarchibald.
* Implement MSC 3981 ([\#3248](https://github.com/matrix-org/matrix-js-sdk/pull/3248)). Fixes vector-im/element-web#25021. Contributed by @justjanne.
* Added `Room.getLastLiveEvent` and `Room.getLastThread`. Deprecated `Room.lastThread` in favour of `Room.getLastThread`. ([\#3321](https://github.com/matrix-org/matrix-js-sdk/pull/3321)).
* Element-R: wire up device lists ([\#3272](https://github.com/matrix-org/matrix-js-sdk/pull/3272)). Contributed by @florianduros.
* Node 20 support ([\#3302](https://github.com/matrix-org/matrix-js-sdk/pull/3302)).
## 🐛 Bug Fixes
* Fix racing between one-time-keys processing and sync ([\#3327](https://github.com/matrix-org/matrix-js-sdk/pull/3327)). Fixes vector-im/element-web#25214. Contributed by @florianduros.
* Fix lack of media when a user reconnects ([\#3318](https://github.com/matrix-org/matrix-js-sdk/pull/3318)).
* Fix TimelineWindow getEvents exploding if no neigbouring timeline ([\#3285](https://github.com/matrix-org/matrix-js-sdk/pull/3285)). Fixes vector-im/element-web#25104.
Changes in [25.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v25.0.0) (2023-04-25)
==================================================================================================
## 🚨 BREAKING CHANGES
* Change `Store.save()` to return a `Promise` ([\#3221](https://github.com/matrix-org/matrix-js-sdk/pull/3221)). Contributed by @texuf.
## ✨ Features
* Add typedoc-plugin-mdn-links ([\#3292](https://github.com/matrix-org/matrix-js-sdk/pull/3292)).
* Annotate events with executed push rule ([\#3284](https://github.com/matrix-org/matrix-js-sdk/pull/3284)). Contributed by @kerryarchibald.
* Element-R: pass device list change notifications into rust crypto-sdk ([\#3254](https://github.com/matrix-org/matrix-js-sdk/pull/3254)). Fixes vector-im/element-web#24795. Contributed by @florianduros.
* Support for MSC3882 revision 1 ([\#3228](https://github.com/matrix-org/matrix-js-sdk/pull/3228)). Contributed by @hughns.
## 🐛 Bug Fixes
* Fix screen sharing on Firefox 113 ([\#3282](https://github.com/matrix-org/matrix-js-sdk/pull/3282)). Contributed by @tulir.
* Retry processing potential poll events after decryption ([\#3246](https://github.com/matrix-org/matrix-js-sdk/pull/3246)). Fixes vector-im/element-web#24568.
* Element-R: handle events which arrive before their keys ([\#3230](https://github.com/matrix-org/matrix-js-sdk/pull/3230)). Fixes vector-im/element-web#24489.
Changes in [24.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v24.1.0) (2023-04-11)
==================================================================================================
## ✨ Features
* Allow via_servers property in findPredecessor (update to MSC3946) ([\#3240](https://github.com/matrix-org/matrix-js-sdk/pull/3240)). Contributed by @andybalaam.
* Fire `closed` event when IndexedDB closes unexpectedly ([\#3218](https://github.com/matrix-org/matrix-js-sdk/pull/3218)).
* Implement MSC3952: intentional mentions ([\#3092](https://github.com/matrix-org/matrix-js-sdk/pull/3092)). Fixes vector-im/element-web#24376.
* Send one time key count and unused fallback keys for rust-crypto ([\#3215](https://github.com/matrix-org/matrix-js-sdk/pull/3215)). Fixes vector-im/element-web#24795. Contributed by @florianduros.
* Improve `processBeaconEvents` hotpath ([\#3200](https://github.com/matrix-org/matrix-js-sdk/pull/3200)).
* Implement MSC3966: a push rule condition to check if an array contains a value ([\#3180](https://github.com/matrix-org/matrix-js-sdk/pull/3180)).
## 🐛 Bug Fixes
* indexddb-local-backend - return the current sync to database promise … ([\#3222](https://github.com/matrix-org/matrix-js-sdk/pull/3222)). Contributed by @texuf.
* Revert "Add the call object to Call events" ([\#3236](https://github.com/matrix-org/matrix-js-sdk/pull/3236)).
* Handle group call redaction ([\#3231](https://github.com/matrix-org/matrix-js-sdk/pull/3231)). Fixes vector-im/voip-internal#128.
* Stop doing O(n^2) work to find event's home (`eventShouldLiveIn`) ([\#3227](https://github.com/matrix-org/matrix-js-sdk/pull/3227)). Contributed by @jryans.
* Fix bug where video would not unmute if it started muted ([\#3213](https://github.com/matrix-org/matrix-js-sdk/pull/3213)). Fixes vector-im/element-call#925.
* Fixes to event encryption in the Rust Crypto implementation ([\#3202](https://github.com/matrix-org/matrix-js-sdk/pull/3202)).
Changes in [24.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v24.0.0) (2023-03-28)
==================================================================================================
## 🔒 Security
* Fixes for [CVE-2023-28427](https://cve.mitre.org/cgi-bin/cvekey.cgi?keyword=CVE-2023-28427) / GHSA-mwq8-fjpf-c2gr
Changes in [23.5.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v23.5.0) (2023-03-15)
==================================================================================================
## ✨ Features
* Implement MSC3758: a push rule condition to match event properties exactly ([\#3179](https://github.com/matrix-org/matrix-js-sdk/pull/3179)).
* Enable group calls without video and audio track by configuration of MatrixClient ([\#3162](https://github.com/matrix-org/matrix-js-sdk/pull/3162)). Contributed by @EnricoSchw.
* Updates to protocol used for Sign in with QR code ([\#3155](https://github.com/matrix-org/matrix-js-sdk/pull/3155)). Contributed by @hughns.
* Implement MSC3873 to handle escaped dots in push rule keys ([\#3134](https://github.com/matrix-org/matrix-js-sdk/pull/3134)). Fixes undefined/matrix-js-sdk#1454.
## 🐛 Bug Fixes
* Fix spec compliance issue around encrypted `m.relates_to` ([\#3178](https://github.com/matrix-org/matrix-js-sdk/pull/3178)).
* Fix reactions in threads sometimes causing stuck notifications ([\#3146](https://github.com/matrix-org/matrix-js-sdk/pull/3146)). Fixes vector-im/element-web#24000. Contributed by @justjanne.
Changes in [23.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v23.4.0) (2023-02-28)
==================================================================================================
## ✨ Features
* Add easy way to determine if the decryption failure is due to "DecryptionError: The sender has disabled encrypting to unverified devices." ([\#3167](https://github.com/matrix-org/matrix-js-sdk/pull/3167)). Contributed by @florianduros.
* Polls: expose end event id on poll model ([\#3160](https://github.com/matrix-org/matrix-js-sdk/pull/3160)). Contributed by @kerryarchibald.
* Polls: count undecryptable poll relations ([\#3163](https://github.com/matrix-org/matrix-js-sdk/pull/3163)). Contributed by @kerryarchibald.
## 🐛 Bug Fixes
* Better type guard parseTopicContent ([\#3165](https://github.com/matrix-org/matrix-js-sdk/pull/3165)). Fixes matrix-org/element-web-rageshakes#20177 and matrix-org/element-web-rageshakes#20178.
* Fix a bug where events in encrypted rooms would sometimes erroneously increment the total unread counter after being processed locally. ([\#3130](https://github.com/matrix-org/matrix-js-sdk/pull/3130)). Fixes vector-im/element-web#24448. Contributed by @Half-Shot.
* Stop the ICE disconnected timer on call terminate ([\#3147](https://github.com/matrix-org/matrix-js-sdk/pull/3147)).
* Clear notifications when we can infer read status from receipts ([\#3139](https://github.com/matrix-org/matrix-js-sdk/pull/3139)). Fixes vector-im/element-web#23991.
* Messages sent out of order after one message fails ([\#3131](https://github.com/matrix-org/matrix-js-sdk/pull/3131)). Fixes vector-im/element-web#22885 and vector-im/element-web#18942. Contributed by @justjanne.
Changes in [23.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v23.3.0) (2023-02-14)
==================================================================================================
## ✨ Features
* Element-R: implement encryption of outgoing events ([\#3122](https://github.com/matrix-org/matrix-js-sdk/pull/3122)).
* Poll model - page /relations results ([\#3073](https://github.com/matrix-org/matrix-js-sdk/pull/3073)). Contributed by @kerryarchibald.
* Poll model - validate end events ([\#3072](https://github.com/matrix-org/matrix-js-sdk/pull/3072)). Contributed by @kerryarchibald.
* Handle optional last_known_event_id property in m.predecessor ([\#3119](https://github.com/matrix-org/matrix-js-sdk/pull/3119)). Contributed by @andybalaam.
* Add support for stable identifier for fixed MAC in SAS verification ([\#3101](https://github.com/matrix-org/matrix-js-sdk/pull/3101)).
* Provide eventId as well as roomId from Room.findPredecessor ([\#3095](https://github.com/matrix-org/matrix-js-sdk/pull/3095)). Contributed by @andybalaam.
* MSC3946 Dynamic room predecessors ([\#3042](https://github.com/matrix-org/matrix-js-sdk/pull/3042)). Contributed by @andybalaam.
* Poll model ([\#3036](https://github.com/matrix-org/matrix-js-sdk/pull/3036)). Contributed by @kerryarchibald.
* Remove video tracks on video mute without renegotiating ([\#3091](https://github.com/matrix-org/matrix-js-sdk/pull/3091)).
* Introduces a backwards-compatible API change. `MegolmEncrypter#prepareToEncrypt`'s return type has changed from `void` to `() => void`. ([\#3035](https://github.com/matrix-org/matrix-js-sdk/pull/3035)). Contributed by @clarkf.
## 🐛 Bug Fixes
* Stop the ICE disconnected timer on call terminate ([\#3147](https://github.com/matrix-org/matrix-js-sdk/pull/3147)).
* Clear notifications when we can infer read status from receipts ([\#3139](https://github.com/matrix-org/matrix-js-sdk/pull/3139)). Fixes vector-im/element-web#23991.
* Messages sent out of order after one message fails ([\#3131](https://github.com/matrix-org/matrix-js-sdk/pull/3131)). Fixes vector-im/element-web#22885 and vector-im/element-web#18942. Contributed by @justjanne.
* Element-R: fix a bug which prevented encryption working after a reload ([\#3126](https://github.com/matrix-org/matrix-js-sdk/pull/3126)).
* Element-R: Fix invite processing ([\#3121](https://github.com/matrix-org/matrix-js-sdk/pull/3121)).
* Don't throw with no `opponentDeviceInfo` ([\#3107](https://github.com/matrix-org/matrix-js-sdk/pull/3107)).
* Remove flaky megolm test ([\#3098](https://github.com/matrix-org/matrix-js-sdk/pull/3098)). Contributed by @clarkf.
* Fix "verifyLinks" functionality of getRoomUpgradeHistory ([\#3089](https://github.com/matrix-org/matrix-js-sdk/pull/3089)). Contributed by @andybalaam.
Changes in [23.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v23.2.0) (2023-01-31)
==================================================================================================
## ✨ Features
* Implement decryption via the rust sdk ([\#3074](https://github.com/matrix-org/matrix-js-sdk/pull/3074)).
* Handle edits which are bundled with an event, per MSC3925 ([\#3045](https://github.com/matrix-org/matrix-js-sdk/pull/3045)).
## 🐛 Bug Fixes
* Add null check for our own member event ([\#3082](https://github.com/matrix-org/matrix-js-sdk/pull/3082)).
* Handle group call getting initialised twice in quick succession ([\#3078](https://github.com/matrix-org/matrix-js-sdk/pull/3078)). Fixes vector-im/element-call#847.
* Correctly handle limited sync responses by resetting the thread timeline ([\#3056](https://github.com/matrix-org/matrix-js-sdk/pull/3056)). Fixes vector-im/element-web#23952. Contributed by @justjanne.
* Fix failure to start in firefox private browser ([\#3058](https://github.com/matrix-org/matrix-js-sdk/pull/3058)). Fixes vector-im/element-web#24216.
* Fix spurious "Decryption key withheld" messages ([\#3061](https://github.com/matrix-org/matrix-js-sdk/pull/3061)). Fixes vector-im/element-web#23803.
* Fix browser entrypoint ([\#3051](https://github.com/matrix-org/matrix-js-sdk/pull/3051)). Fixes #3013.
Changes in [23.1.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v23.1.1) (2023-01-20)
==================================================================================================
## 🐛 Bug Fixes
* Fix backwards compability for environment not support Array.prototype.at ([\#3080](https://github.com/matrix-org/matrix-js-sdk/pull/3080)).
Changes in [23.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v23.1.0) (2023-01-18)
==================================================================================================
## 🦖 Deprecations
* Remove extensible events v1 field population on legacy events ([\#3040](https://github.com/matrix-org/matrix-js-sdk/pull/3040)).
## ✨ Features
* Improve hasUserReadEvent and getUserReadUpTo realibility with threads ([\#3031](https://github.com/matrix-org/matrix-js-sdk/pull/3031)). Fixes vector-im/element-web#24164.
* Remove video track when muting video ([\#3028](https://github.com/matrix-org/matrix-js-sdk/pull/3028)). Fixes vector-im/element-call#209.
* Make poll start event type available (PSG-962) ([\#3034](https://github.com/matrix-org/matrix-js-sdk/pull/3034)).
* Add alt event type matching in Relations model ([\#3018](https://github.com/matrix-org/matrix-js-sdk/pull/3018)).
* Remove usage of v1 Identity Server API ([\#3003](https://github.com/matrix-org/matrix-js-sdk/pull/3003)).
* Add `device_id` to `/account/whoami` types ([\#3005](https://github.com/matrix-org/matrix-js-sdk/pull/3005)).
* Implement MSC3912: Relation-based redactions ([\#2954](https://github.com/matrix-org/matrix-js-sdk/pull/2954)).
* Introduce a mechanism for using the rust-crypto-sdk ([\#2969](https://github.com/matrix-org/matrix-js-sdk/pull/2969)).
* Support MSC3391: Account data deletion ([\#2967](https://github.com/matrix-org/matrix-js-sdk/pull/2967)).
## 🐛 Bug Fixes
* Fix threaded cache receipt when event holds multiple receipts ([\#3026](https://github.com/matrix-org/matrix-js-sdk/pull/3026)).
* Fix false key requests after verifying new device ([\#3029](https://github.com/matrix-org/matrix-js-sdk/pull/3029)). Fixes vector-im/element-web#24167 and vector-im/element-web#23333.
* Avoid triggering decryption errors when decrypting redacted events ([\#3004](https://github.com/matrix-org/matrix-js-sdk/pull/3004)). Fixes vector-im/element-web#24084.
* bugfix: upload OTKs in sliding sync mode ([\#3008](https://github.com/matrix-org/matrix-js-sdk/pull/3008)).
* Apply edits discovered from sync after thread is initialised ([\#3002](https://github.com/matrix-org/matrix-js-sdk/pull/3002)). Fixes vector-im/element-web#23921.
* Sliding sync: Fix issue where no unsubs are sent when switching rooms ([\#2991](https://github.com/matrix-org/matrix-js-sdk/pull/2991)).
* Threads are missing from the timeline ([\#2996](https://github.com/matrix-org/matrix-js-sdk/pull/2996)). Fixes vector-im/element-web#24036.
* Close all streams when a call ends ([\#2992](https://github.com/matrix-org/matrix-js-sdk/pull/2992)). Fixes vector-im/element-call#742.
* Resume to-device message queue after resumed sync ([\#2920](https://github.com/matrix-org/matrix-js-sdk/pull/2920)). Fixes matrix-org/element-web-rageshakes#17170.
* Fix browser entrypoint ([\#3051](https://github.com/matrix-org/matrix-js-sdk/pull/3051)). Fixes #3013.
* Fix failure to start in firefox private browser ([\#3058](https://github.com/matrix-org/matrix-js-sdk/pull/3058)). Fixes vector-im/element-web#24216.
* Correctly handle limited sync responses by resetting the thread timeline ([\#3056](https://github.com/matrix-org/matrix-js-sdk/pull/3056)). Fixes vector-im/element-web#23952.
Changes in [23.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v23.0.0) (2022-12-21)
==================================================================================================
## 🚨 BREAKING CHANGES
* Process `m.room.encryption` events before emitting `RoomMember` events ([\#2914](https://github.com/matrix-org/matrix-js-sdk/pull/2914)). Fixes vector-im/element-web#23819.
* Don't expose `calls` on `GroupCall` ([\#2941](https://github.com/matrix-org/matrix-js-sdk/pull/2941)).
## ✨ Features
* Support MSC3391: Account data deletion ([\#2967](https://github.com/matrix-org/matrix-js-sdk/pull/2967)).
* Add a message ID on each to-device message ([\#2938](https://github.com/matrix-org/matrix-js-sdk/pull/2938)).
* Enable multiple users' power levels to be set at once ([\#2892](https://github.com/matrix-org/matrix-js-sdk/pull/2892)). Contributed by @GoodGuyMarco.
* Include pending events in thread summary and count again ([\#2922](https://github.com/matrix-org/matrix-js-sdk/pull/2922)). Fixes vector-im/element-web#23642.
* Make GroupCall work better with widgets ([\#2935](https://github.com/matrix-org/matrix-js-sdk/pull/2935)).
* Add method to get outgoing room key requests for a given event ([\#2930](https://github.com/matrix-org/matrix-js-sdk/pull/2930)).
## 🐛 Bug Fixes
* Fix messages loaded during initial fetch ending up out of order ([\#2971](https://github.com/matrix-org/matrix-js-sdk/pull/2971)). Fixes vector-im/element-web#23972.
* Fix #23919: Root message for new thread loaded from network ([\#2965](https://github.com/matrix-org/matrix-js-sdk/pull/2965)). Fixes vector-im/element-web#23919.
* Fix #23916: Prevent edits of the last message in a thread getting lost ([\#2951](https://github.com/matrix-org/matrix-js-sdk/pull/2951)). Fixes vector-im/element-web#23916 and vector-im/element-web#23942.
* Fix infinite loop when restoring cached read receipts ([\#2963](https://github.com/matrix-org/matrix-js-sdk/pull/2963)). Fixes vector-im/element-web#23951.
* Don't swallow errors coming from the shareSession call ([\#2962](https://github.com/matrix-org/matrix-js-sdk/pull/2962)). Fixes vector-im/element-web#23792.
* Make sure that MegolmEncryption.setupPromise always resolves ([\#2960](https://github.com/matrix-org/matrix-js-sdk/pull/2960)).
* Do not calculate highlight notifs for threads unknown to the room ([\#2957](https://github.com/matrix-org/matrix-js-sdk/pull/2957)).
* Cache read receipts for unknown threads ([\#2953](https://github.com/matrix-org/matrix-js-sdk/pull/2953)).
* bugfix: sliding sync initial room timelines shouldn't notify ([\#2933](https://github.com/matrix-org/matrix-js-sdk/pull/2933)).
* Redo key sharing after own device verification ([\#2921](https://github.com/matrix-org/matrix-js-sdk/pull/2921)). Fixes vector-im/element-web#23333.
* Move updated threads to the end of the thread list ([\#2923](https://github.com/matrix-org/matrix-js-sdk/pull/2923)). Fixes vector-im/element-web#23876.
* Fix highlight notifications increasing when total notification is zero ([\#2937](https://github.com/matrix-org/matrix-js-sdk/pull/2937)). Fixes vector-im/element-web#23885.
* Fix synthesizeReceipt ([\#2916](https://github.com/matrix-org/matrix-js-sdk/pull/2916)). Fixes vector-im/element-web#23827 vector-im/element-web#23754 and vector-im/element-web#23847.
Changes in [22.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v22.0.0) (2022-12-06)
==================================================================================================
## 🚨 BREAKING CHANGES
* Enable users to join group calls from multiple devices ([\#2902](https://github.com/matrix-org/matrix-js-sdk/pull/2902)).
## 🦖 Deprecations
* Deprecate a function containing a typo ([\#2904](https://github.com/matrix-org/matrix-js-sdk/pull/2904)).
## ✨ Features
* sliding sync: add receipts extension ([\#2912](https://github.com/matrix-org/matrix-js-sdk/pull/2912)).
* Define a spec support policy for the js-sdk ([\#2882](https://github.com/matrix-org/matrix-js-sdk/pull/2882)).
* Further improvements to e2ee logging ([\#2900](https://github.com/matrix-org/matrix-js-sdk/pull/2900)).
* sliding sync: add support for typing extension ([\#2893](https://github.com/matrix-org/matrix-js-sdk/pull/2893)).
* Improve logging on Olm session errors ([\#2885](https://github.com/matrix-org/matrix-js-sdk/pull/2885)).
* Improve logging of e2ee messages ([\#2884](https://github.com/matrix-org/matrix-js-sdk/pull/2884)).
## 🐛 Bug Fixes
* Fix 3pid invite acceptance not working due to mxid being sent in body ([\#2907](https://github.com/matrix-org/matrix-js-sdk/pull/2907)). Fixes vector-im/element-web#23823.
* Don't hang up calls that haven't started yet ([\#2898](https://github.com/matrix-org/matrix-js-sdk/pull/2898)).
* Read receipt accumulation for threads ([\#2881](https://github.com/matrix-org/matrix-js-sdk/pull/2881)).
* Make GroupCall work better with widgets ([\#2935](https://github.com/matrix-org/matrix-js-sdk/pull/2935)).
* Fix highlight notifications increasing when total notification is zero ([\#2937](https://github.com/matrix-org/matrix-js-sdk/pull/2937)). Fixes vector-im/element-web#23885.
* Fix synthesizeReceipt ([\#2916](https://github.com/matrix-org/matrix-js-sdk/pull/2916)). Fixes vector-im/element-web#23827 vector-im/element-web#23754 and vector-im/element-web#23847.
Changes in [21.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v21.2.0) (2022-11-22)
==================================================================================================
## ✨ Features
* Make calls go back to 'connecting' state when media lost ([\#2880](https://github.com/matrix-org/matrix-js-sdk/pull/2880)).
* Add ability to send unthreaded receipt ([\#2878](https://github.com/matrix-org/matrix-js-sdk/pull/2878)).
* Add way to abort search requests ([\#2877](https://github.com/matrix-org/matrix-js-sdk/pull/2877)).
* sliding sync: add custom room subscriptions support ([\#2834](https://github.com/matrix-org/matrix-js-sdk/pull/2834)).
* webrtc: add advanced audio settings ([\#2434](https://github.com/matrix-org/matrix-js-sdk/pull/2434)). Contributed by @MrAnno.
* Add support for group calls using MSC3401 ([\#2553](https://github.com/matrix-org/matrix-js-sdk/pull/2553)).
* Make the js-sdk conform to tsc --strict ([\#2835](https://github.com/matrix-org/matrix-js-sdk/pull/2835)). Fixes #2112 #2116 and #2124.
* Let leave requests outlive the window ([\#2815](https://github.com/matrix-org/matrix-js-sdk/pull/2815)). Fixes vector-im/element-call#639.
* Add event and message capabilities to RoomWidgetClient ([\#2797](https://github.com/matrix-org/matrix-js-sdk/pull/2797)).
* Misc fixes for group call widgets ([\#2657](https://github.com/matrix-org/matrix-js-sdk/pull/2657)).
* Support nested Matrix clients via the widget API ([\#2473](https://github.com/matrix-org/matrix-js-sdk/pull/2473)).
* Set max average bitrate on PTT calls ([\#2499](https://github.com/matrix-org/matrix-js-sdk/pull/2499)). Fixes vector-im/element-call#440.
* Add config option for e2e group call signalling ([\#2492](https://github.com/matrix-org/matrix-js-sdk/pull/2492)).
* Enable DTX on audio tracks in calls ([\#2482](https://github.com/matrix-org/matrix-js-sdk/pull/2482)).
* Don't ignore call member events with a distant future expiration date ([\#2466](https://github.com/matrix-org/matrix-js-sdk/pull/2466)).
* Expire call member state events after 1 hour ([\#2446](https://github.com/matrix-org/matrix-js-sdk/pull/2446)).
* Emit unknown device errors for group call participants without e2e ([\#2447](https://github.com/matrix-org/matrix-js-sdk/pull/2447)).
* Mute disconnected peers in PTT mode ([\#2421](https://github.com/matrix-org/matrix-js-sdk/pull/2421)).
* Add support for sending encrypted to-device events with OLM ([\#2322](https://github.com/matrix-org/matrix-js-sdk/pull/2322)). Contributed by @robertlong.
* Support for PTT group call mode ([\#2338](https://github.com/matrix-org/matrix-js-sdk/pull/2338)).
## 🐛 Bug Fixes
* Fix registration add phone number not working ([\#2876](https://github.com/matrix-org/matrix-js-sdk/pull/2876)). Contributed by @bagvand.
* Use an underride rule for Element Call notifications ([\#2873](https://github.com/matrix-org/matrix-js-sdk/pull/2873)). Fixes vector-im/element-web#23691.
* Fixes unwanted highlight notifications with encrypted threads ([\#2862](https://github.com/matrix-org/matrix-js-sdk/pull/2862)).
* Extra insurance that we don't mix events in the wrong timelines - v2 ([\#2856](https://github.com/matrix-org/matrix-js-sdk/pull/2856)). Contributed by @MadLittleMods.
* Hide pending events in thread timelines ([\#2843](https://github.com/matrix-org/matrix-js-sdk/pull/2843)). Fixes vector-im/element-web#23684.
* Fix pagination token tracking for mixed room timelines ([\#2855](https://github.com/matrix-org/matrix-js-sdk/pull/2855)). Fixes vector-im/element-web#23695.
* Extra insurance that we don't mix events in the wrong timelines ([\#2848](https://github.com/matrix-org/matrix-js-sdk/pull/2848)). Contributed by @MadLittleMods.
* Do not freeze state in `initialiseState()` ([\#2846](https://github.com/matrix-org/matrix-js-sdk/pull/2846)).
* Don't remove our own member for a split second when entering a call ([\#2844](https://github.com/matrix-org/matrix-js-sdk/pull/2844)).
* Resolve races between `initLocalCallFeed` and `leave` ([\#2826](https://github.com/matrix-org/matrix-js-sdk/pull/2826)).
* Add throwOnFail to groupCall.setScreensharingEnabled ([\#2787](https://github.com/matrix-org/matrix-js-sdk/pull/2787)).
* Fix connectivity regressions ([\#2780](https://github.com/matrix-org/matrix-js-sdk/pull/2780)).
* Fix screenshare failing after several attempts ([\#2771](https://github.com/matrix-org/matrix-js-sdk/pull/2771)). Fixes vector-im/element-call#625.
* Don't block muting/unmuting on network requests ([\#2754](https://github.com/matrix-org/matrix-js-sdk/pull/2754)). Fixes vector-im/element-call#592.
* Fix ICE restarts ([\#2702](https://github.com/matrix-org/matrix-js-sdk/pull/2702)).
* Target widget actions at a specific room ([\#2670](https://github.com/matrix-org/matrix-js-sdk/pull/2670)).
* Add tests for ice candidate sending ([\#2674](https://github.com/matrix-org/matrix-js-sdk/pull/2674)).
* Prevent exception when muting ([\#2667](https://github.com/matrix-org/matrix-js-sdk/pull/2667)). Fixes vector-im/element-call#578.
* Fix race in creating calls ([\#2662](https://github.com/matrix-org/matrix-js-sdk/pull/2662)).
* Add client.waitUntilRoomReadyForGroupCalls() ([\#2641](https://github.com/matrix-org/matrix-js-sdk/pull/2641)).
* Wait for client to start syncing before making group calls ([\#2632](https://github.com/matrix-org/matrix-js-sdk/pull/2632)). Fixes #2589.
* Add GroupCallEventHandlerEvent.Room ([\#2631](https://github.com/matrix-org/matrix-js-sdk/pull/2631)).
* Add missing events from reemitter to GroupCall ([\#2527](https://github.com/matrix-org/matrix-js-sdk/pull/2527)). Contributed by @toger5.
* Prevent double mute status changed events ([\#2502](https://github.com/matrix-org/matrix-js-sdk/pull/2502)).
* Don't mute the remote side immediately in PTT calls ([\#2487](https://github.com/matrix-org/matrix-js-sdk/pull/2487)). Fixes vector-im/element-call#425.
* Fix some MatrixCall leaks and use a shared AudioContext ([\#2484](https://github.com/matrix-org/matrix-js-sdk/pull/2484)). Fixes vector-im/element-call#412.
* Don't block muting on determining whether the device exists ([\#2461](https://github.com/matrix-org/matrix-js-sdk/pull/2461)).
* Only clone streams on Safari ([\#2450](https://github.com/matrix-org/matrix-js-sdk/pull/2450)). Fixes vector-im/element-call#267.
* Set PTT mode on call correctly ([\#2445](https://github.com/matrix-org/matrix-js-sdk/pull/2445)). Fixes vector-im/element-call#382.
* Wait for mute event to send in PTT mode ([\#2401](https://github.com/matrix-org/matrix-js-sdk/pull/2401)).
* Handle other members having no e2e keys ([\#2383](https://github.com/matrix-org/matrix-js-sdk/pull/2383)). Fixes vector-im/element-call#338.
* Fix races when muting/unmuting ([\#2370](https://github.com/matrix-org/matrix-js-sdk/pull/2370)).
Changes in [21.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v21.1.0) (2022-11-08)
==================================================================================================
## ✨ Features
* Loading threads with server-side assistance ([\#2735](https://github.com/matrix-org/matrix-js-sdk/pull/2735)). Contributed by @justjanne.
* Support sign in + E2EE set up using QR code implementing MSC3886, MSC3903 and MSC3906 ([\#2747](https://github.com/matrix-org/matrix-js-sdk/pull/2747)). Contributed by @hughns.
## 🐛 Bug Fixes
* Replace `instanceof Array` with `Array.isArray` ([\#2812](https://github.com/matrix-org/matrix-js-sdk/pull/2812)). Fixes #2811.
* Emit UnreadNotification event on notifications reset ([\#2804](https://github.com/matrix-org/matrix-js-sdk/pull/2804)). Fixes vector-im/element-web#23590.
* Fix incorrect prevEv being sent in ClientEvent.AccountData events ([\#2794](https://github.com/matrix-org/matrix-js-sdk/pull/2794)).
* Fix build error caused by wrong ts-strict improvements ([\#2783](https://github.com/matrix-org/matrix-js-sdk/pull/2783)). Contributed by @justjanne.
* Encryption should not hinder verification ([\#2734](https://github.com/matrix-org/matrix-js-sdk/pull/2734)).
Changes in [21.0.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v21.0.1) (2022-11-01)
==================================================================================================
## 🐛 Bug Fixes
* Fix default behavior of Room.getBlacklistUnverifiedDevices ([\#2830](https://github.com/matrix-org/matrix-js-sdk/pull/2830)). Contributed by @duxovni.
* Catch server versions API call exception when starting the client ([\#2828](https://github.com/matrix-org/matrix-js-sdk/pull/2828)). Fixes vector-im/element-web#23634.
* Fix authedRequest including `Authorization: Bearer undefined` for password resets ([\#2822](https://github.com/matrix-org/matrix-js-sdk/pull/2822)). Fixes vector-im/element-web#23655.
Changes in [21.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v21.0.0) (2022-10-25)
==================================================================================================
+1 -3
View File
@@ -1,5 +1,3 @@
Contributing code to matrix-js-sdk
==================================
# Contributing code to matrix-js-sdk
matrix-js-sdk follows the same pattern as https://github.com/vector-im/element-web/blob/develop/CONTRIBUTING.md
+155 -160
View File
@@ -6,31 +6,26 @@
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=matrix-js-sdk&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=matrix-js-sdk)
[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=matrix-js-sdk&metric=bugs)](https://sonarcloud.io/summary/new_code?id=matrix-js-sdk)
Matrix Javascript SDK
=====================
# Matrix JavaScript SDK
This is the [Matrix](https://matrix.org) Client-Server r0 SDK for
JavaScript. This SDK can be run in a browser or in Node.js.
This is the [Matrix](https://matrix.org) Client-Server SDK for JavaScript and TypeScript. This SDK can be run in a
browser or in Node.js.
Quickstart
==========
#### Minimum Matrix server version: v1.1
In a browser
------------
Download the browser version from
https://github.com/matrix-org/matrix-js-sdk/releases/latest and add that as a
``<script>`` to your page. There will be a global variable ``matrixcs``
attached to ``window`` through which you can access the SDK. See below for how to
include libolm to enable end-to-end-encryption.
The Matrix specification is constantly evolving - while this SDK aims for maximum backwards compatibility, it only
guarantees that a feature will be supported for at least 4 spec releases. For example, if a feature the js-sdk supports
is removed in v1.4 then the feature is _eligible_ for removal from the SDK when v1.8 is released. This SDK has no
guarantee on implementing all features of any particular spec release, currently. This can mean that the SDK will call
endpoints from before Matrix 1.1, for example.
The browser bundle supports recent versions of browsers. Typically this is ES2015
or `> 0.5%, last 2 versions, Firefox ESR, not dead` if using
[browserlists](https://github.com/browserslist/browserslist).
# Quickstart
Please check [the working browser example](examples/browser) for more information.
## In a browser
In Node.js
----------
### Note, the browserify build has been removed. Please use a bundler like webpack or vite instead.
## In Node.js
Ensure you have the latest LTS version of Node.js installed.
This library relies on `fetch` which is available in Node from v18.0.0 - it should work fine also with polyfills.
@@ -39,30 +34,32 @@ If you wish to use a ponyfill or adapter of some sort then pass it as `fetchFn`
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``
`yarn add matrix-js-sdk`
```javascript
import * as sdk from "matrix-js-sdk";
const client = sdk.createClient("https://matrix.org");
client.publicRooms(function(err, data) {
import * as sdk from "matrix-js-sdk";
const client = sdk.createClient({ baseUrl: "https://matrix.org" });
client.publicRooms(function (err, data) {
console.log("Public Rooms: %s", JSON.stringify(data));
});
});
```
See below for how to include libolm to enable end-to-end-encryption. Please check
[the Node.js terminal app](examples/node) for a more complex example.
You can also use the sdk with [Deno](https://deno.land/) (`import npm:matrix-js-sdk`) but its not officialy supported.
To start the client:
```javascript
await client.startClient({initialSyncLimit: 10});
await client.startClient({ initialSyncLimit: 10 });
```
You can perform a call to `/sync` to get the current state of the client:
```javascript
client.once('sync', function(state, prevState, res) {
if(state === 'PREPARED') {
client.once("sync", function (state, prevState, res) {
if (state === "PREPARED") {
console.log("prepared");
} else {
console.log(state);
@@ -75,8 +72,8 @@ To send a message:
```javascript
const content = {
"body": "message text",
"msgtype": "m.text"
body: "message text",
msgtype: "m.text",
};
client.sendEvent("roomId", "m.room.message", content, "", (err, res) => {
console.log(err);
@@ -86,11 +83,11 @@ client.sendEvent("roomId", "m.room.message", content, "", (err, res) => {
To listen for message events:
```javascript
client.on("Room.timeline", function(event, room, toStartOfTimeline) {
if (event.getType() !== "m.room.message") {
return; // only use messages
}
console.log(event.event.content.body);
client.on("Room.timeline", function (event, room, toStartOfTimeline) {
if (event.getType() !== "m.room.message") {
return; // only use messages
}
console.log(event.event.content.body);
});
```
@@ -98,73 +95,70 @@ By default, the `matrix-js-sdk` client uses the `MemoryStore` to store events as
```javascript
Object.keys(client.store.rooms).forEach((roomId) => {
client.getRoom(roomId).timeline.forEach(t => {
console.log(t.event);
});
client.getRoom(roomId).timeline.forEach((t) => {
console.log(t.event);
});
});
```
What does this SDK do?
----------------------
## What does this SDK do?
This SDK provides a full object model around the Matrix Client-Server API and emits
events for incoming data and state changes. Aside from wrapping the HTTP API, it:
- Handles syncing (via `/initialSync` and `/events`)
- Handles the generation of "friendly" room and member names.
- Handles historical `RoomMember` information (e.g. display names).
- Manages room member state across multiple events (e.g. it handles typing, power
levels and membership changes).
- Exposes high-level objects like `Rooms`, `RoomState`, `RoomMembers` and `Users`
which can be listened to for things like name changes, new messages, membership
changes, presence changes, and more.
- Handle "local echo" of messages sent using the SDK. This means that messages
that have just been sent will appear in the timeline as 'sending', until it
completes. This is beneficial because it prevents there being a gap between
hitting the send button and having the "remote echo" arrive.
- Mark messages which failed to send as not sent.
- Automatically retry requests to send messages due to network errors.
- Automatically retry requests to send messages due to rate limiting errors.
- Handle queueing of messages.
- Handles pagination.
- Handle assigning push actions for events.
- Handles room initial sync on accepting invites.
- Handles WebRTC calling.
- Handles syncing (via `/initialSync` and `/events`)
- Handles the generation of "friendly" room and member names.
- Handles historical `RoomMember` information (e.g. display names).
- Manages room member state across multiple events (e.g. it handles typing, power
levels and membership changes).
- Exposes high-level objects like `Rooms`, `RoomState`, `RoomMembers` and `Users`
which can be listened to for things like name changes, new messages, membership
changes, presence changes, and more.
- Handle "local echo" of messages sent using the SDK. This means that messages
that have just been sent will appear in the timeline as 'sending', until it
completes. This is beneficial because it prevents there being a gap between
hitting the send button and having the "remote echo" arrive.
- Mark messages which failed to send as not sent.
- Automatically retry requests to send messages due to network errors.
- Automatically retry requests to send messages due to rate limiting errors.
- Handle queueing of messages.
- Handles pagination.
- Handle assigning push actions for events.
- Handles room initial sync on accepting invites.
- Handles WebRTC calling.
Later versions of the SDK will:
- Expose a `RoomSummary` which would be suitable for a recents page.
- Provide different pluggable storage layers (e.g. local storage, database-backed)
Usage
=====
- Expose a `RoomSummary` which would be suitable for a recents page.
- Provide different pluggable storage layers (e.g. local storage, database-backed)
# Usage
Conventions
-----------
## Conventions
### Emitted events
The SDK will emit events using an ``EventEmitter``. It also
emits object models (e.g. ``Rooms``, ``RoomMembers``) when they
The SDK will emit events using an `EventEmitter`. It also
emits object models (e.g. `Rooms`, `RoomMembers`) when they
are updated.
```javascript
// Listen for low-level MatrixEvents
client.on("event", function(event) {
// Listen for low-level MatrixEvents
client.on("event", function (event) {
console.log(event.getType());
});
});
// Listen for typing changes
client.on("RoomMember.typing", function(event, member) {
// Listen for typing changes
client.on("RoomMember.typing", function (event, member) {
if (member.typing) {
console.log(member.name + " is typing...");
console.log(member.name + " is typing...");
} else {
console.log(member.name + " stopped typing.");
}
else {
console.log(member.name + " stopped typing.");
}
});
});
// start the client to setup the connection to the server
client.startClient();
// start the client to setup the connection to the server
client.startClient();
```
### Promises and Callbacks
@@ -181,11 +175,11 @@ The typical usage is something like:
});
```
Alternatively, if you have a Node.js-style ``callback(err, result)`` function,
Alternatively, if you have a Node.js-style `callback(err, result)` function,
you can pass the result of the promise into it with something like:
```javascript
matrixClient.someMethod(arg1, arg2).nodeify(callback);
matrixClient.someMethod(arg1, arg2).nodeify(callback);
```
The main thing to note is that it is problematic to discard the result of a
@@ -193,61 +187,65 @@ promise-returning function, as that will cause exceptions to go unobserved.
Methods which return a promise show this in their documentation.
Many methods in the SDK support *both* Node.js-style callbacks *and* Promises,
via an optional ``callback`` argument. The callback support is now deprecated:
new methods do not include a ``callback`` argument, and in the future it may be
Many methods in the SDK support _both_ Node.js-style callbacks _and_ Promises,
via an optional `callback` argument. The callback support is now deprecated:
new methods do not include a `callback` argument, and in the future it may be
removed from existing methods.
Examples
--------
## Examples
This section provides some useful code snippets which demonstrate the
core functionality of the SDK. These examples assume the SDK is setup like this:
```javascript
import * as sdk from "matrix-js-sdk";
const myUserId = "@example:localhost";
const myAccessToken = "QGV4YW1wbGU6bG9jYWxob3N0.qPEvLuYfNBjxikiCjP";
const matrixClient = sdk.createClient({
baseUrl: "http://localhost:8008",
accessToken: myAccessToken,
userId: myUserId
});
import * as sdk from "matrix-js-sdk";
const myUserId = "@example:localhost";
const myAccessToken = "QGV4YW1wbGU6bG9jYWxob3N0.qPEvLuYfNBjxikiCjP";
const matrixClient = sdk.createClient({
baseUrl: "http://localhost:8008",
accessToken: myAccessToken,
userId: myUserId,
});
```
### Automatically join rooms when invited
```javascript
matrixClient.on("RoomMember.membership", function(event, member) {
if (member.membership === "invite" && member.userId === myUserId) {
matrixClient.joinRoom(member.roomId).then(function() {
console.log("Auto-joined %s", member.roomId);
});
}
});
matrixClient.on("RoomMember.membership", function (event, member) {
if (member.membership === "invite" && member.userId === myUserId) {
matrixClient.joinRoom(member.roomId).then(function () {
console.log("Auto-joined %s", member.roomId);
});
}
});
matrixClient.startClient();
matrixClient.startClient();
```
### Print out messages for all rooms
```javascript
matrixClient.on("Room.timeline", function(event, room, toStartOfTimeline) {
if (toStartOfTimeline) {
return; // don't print paginated results
}
if (event.getType() !== "m.room.message") {
return; // only print messages
}
console.log(
// the room name will update with m.room.name events automatically
"(%s) %s :: %s", room.name, event.getSender(), event.getContent().body
);
});
matrixClient.on("Room.timeline", function (event, room, toStartOfTimeline) {
if (toStartOfTimeline) {
return; // don't print paginated results
}
if (event.getType() !== "m.room.message") {
return; // only print messages
}
console.log(
// the room name will update with m.room.name events automatically
"(%s) %s :: %s",
room.name,
event.getSender(),
event.getContent().body,
);
});
matrixClient.startClient();
matrixClient.startClient();
```
Output:
```
(My Room) @megan:localhost :: Hello world
(My Room) @megan:localhost :: how are you?
@@ -259,27 +257,24 @@ Output:
### Print out membership lists whenever they are changed
```javascript
matrixClient.on("RoomState.members", function(event, state, member) {
const room = matrixClient.getRoom(state.roomId);
if (!room) {
return;
}
const memberList = state.getMembers();
console.log(room.name);
console.log(Array(room.name.length + 1).join("=")); // underline
for (var i = 0; i < memberList.length; i++) {
console.log(
"(%s) %s",
memberList[i].membership,
memberList[i].name
);
}
});
matrixClient.on("RoomState.members", function (event, state, member) {
const room = matrixClient.getRoom(state.roomId);
if (!room) {
return;
}
const memberList = state.getMembers();
console.log(room.name);
console.log(Array(room.name.length + 1).join("=")); // underline
for (var i = 0; i < memberList.length; i++) {
console.log("(%s) %s", memberList[i].membership, memberList[i].name);
}
});
matrixClient.startClient();
matrixClient.startClient();
```
Output:
```
My Room
=======
@@ -289,36 +284,34 @@ Output:
(invite) @charlie:localhost
```
API Reference
=============
# API Reference
A hosted reference can be found at
http://matrix-org.github.io/matrix-js-sdk/index.html
This SDK uses JSDoc3 style comments. You can manually build and
This SDK uses [Typedoc](https://typedoc.org/guides/doccomments) doc comments. You can manually build and
host the API reference from the source files like this:
```
$ yarn gendoc
$ cd .jsdoc
$ python -m SimpleHTTPServer 8005
$ cd _docs
$ python -m http.server 8005
```
Then visit ``http://localhost:8005`` to see the API docs.
Then visit `http://localhost:8005` to see the API docs.
End-to-end encryption support
=============================
# End-to-end encryption support
The SDK supports end-to-end encryption via the Olm and Megolm protocols, using
[libolm](https://gitlab.matrix.org/matrix-org/olm). It is left up to the
application to make libolm available, via the ``Olm`` global.
application to make libolm available, via the `Olm` global.
It is also necessary to call ``await matrixClient.initCrypto()`` after creating a new
``MatrixClient`` (but **before** calling ``matrixClient.startClient()``) to
It is also necessary to call `await matrixClient.initCrypto()` after creating a new
`MatrixClient` (but **before** calling `matrixClient.startClient()`) to
initialise the crypto layer.
If the ``Olm`` global is not available, the SDK will show a warning, as shown
below; ``initCrypto()`` will also fail.
If the `Olm` global is not available, the SDK will show a warning, as shown
below; `initCrypto()` will also fail.
```
Unable to load crypto module: crypto will be disabled: Error: global.Olm is not defined
@@ -330,46 +323,48 @@ specification.
To provide the Olm library in a browser application:
* download the transpiled libolm (from https://packages.matrix.org/npm/olm/).
* load ``olm.js`` as a ``<script>`` *before* ``browser-matrix.js``.
- download the transpiled libolm (from https://packages.matrix.org/npm/olm/).
- load `olm.js` as a `<script>` _before_ `browser-matrix.js`.
To provide the Olm library in a node.js application:
* ``yarn add https://packages.matrix.org/npm/olm/olm-3.1.4.tgz``
(replace the URL with the latest version you want to use from
- `yarn add https://packages.matrix.org/npm/olm/olm-3.1.4.tgz`
(replace the URL with the latest version you want to use from
https://packages.matrix.org/npm/olm/)
* ``global.Olm = require('olm');`` *before* loading ``matrix-js-sdk``.
- `global.Olm = require('olm');` _before_ loading `matrix-js-sdk`.
If you want to package Olm as dependency for your node.js application, you can
use ``yarn add https://packages.matrix.org/npm/olm/olm-3.1.4.tgz``. If your
application also works without e2e crypto enabled, add ``--optional`` to mark it
use `yarn add https://packages.matrix.org/npm/olm/olm-3.1.4.tgz`. If your
application also works without e2e crypto enabled, add `--optional` to mark it
as an optional dependency.
# Contributing
Contributing
============
*This section is for people who want to modify the SDK. If you just
want to use this SDK, skip this section.*
_This section is for people who want to modify the SDK. If you just
want to use this SDK, skip this section._
First, you need to pull in the right build tools:
```
$ yarn install
```
Building
--------
## Building
To build a browser version from scratch when developing:
To build a browser version from scratch when developing::
```
$ yarn build
```
To run tests (Jasmine)::
To run tests (Jest):
```
$ yarn test
```
To run linting:
```
$ yarn lint
```
+9
View File
@@ -0,0 +1,9 @@
# Summary
- [Introduction](../README.md)
# Deep dive
- [Release Process](release.md)
- [Storage notes](storage-notes.md)
- [Unverified devices](warning-on-unverified-devices.md)
+24
View File
@@ -0,0 +1,24 @@
# Release Process
## Hotfix and off-cycle releases
1. Prepare the `staging` branch by using the backport automation and manually merging
2. Go to [Releasing](#Releasing)
## Release candidates
1. Prepare the `staging` branch by running the [branch cut automation](https://github.com/vector-im/element-web/actions/workflows/release_prepare.yml)
2. Go to [Releasing](#Releasing)
## Releasing
1. Open the [Releases page](https://github.com/matrix-org/matrix-js-sdk/releases) and inspect the draft release there
2. Make any modifications to the release notes and tag/version as required
3. Run [workflow](https://github.com/matrix-org/matrix-js-sdk/actions/workflows/release.yml) with the type set appropriately
## Artifacts
Releasing the Matrix JS SDK has just two artifacts:
- Package published to [npm](https://github.com/matrix-org/matrix-js-sdk)
- Docs published to [Github Pages](https://matrix-org.github.io/matrix-js-sdk/)
+27 -27
View File
@@ -20,19 +20,19 @@ blurrier.
When we are low on disk space overall or near the group limit / origin quota:
* Chrome
* Log database may fail to start with AbortError
* IndexedDB fails to start for crypto: AbortError in connect from
indexeddb-store-worker
* When near the quota, QuotaExceededError is used more consistently
* Firefox
* The first error will be QuotaExceededError
* Future write attempts will fail with various errors when space is low,
including nonsense like "InvalidStateError: A mutation operation was
attempted on a database that did not allow mutations."
* Once you start getting errors, the DB is effectively wedged in read-only
mode
* Can revive access if you reopen the DB
- Chrome
- Log database may fail to start with AbortError
- IndexedDB fails to start for crypto: AbortError in connect from
indexeddb-store-worker
- When near the quota, QuotaExceededError is used more consistently
- Firefox
- The first error will be QuotaExceededError
- Future write attempts will fail with various errors when space is low,
including nonsense like "InvalidStateError: A mutation operation was
attempted on a database that did not allow mutations."
- Once you start getting errors, the DB is effectively wedged in read-only
mode
- Can revive access if you reopen the DB
## Cache Eviction
@@ -41,9 +41,9 @@ limited by a single quota, in practice, browsers appear to handle `localStorage`
separately from the others, so it has a separate quota limit and isn't evicted
when low on space.
* Chrome, Firefox
* IndexedDB for origin deleted
* Local Storage remains in place
- Chrome, Firefox
- IndexedDB for origin deleted
- Local Storage remains in place
## Persistent Storage
@@ -51,20 +51,20 @@ Storage Standard offers a `navigator.storage.persist` API that can be used to
request persistent storage that won't be deleted by the browser because of low
space.
* Chrome
* Chrome 75 seems to grant this without any prompt based on [interaction
criteria](https://developers.google.com/web/updates/2016/06/persistent-storage)
* Firefox
* Firefox 67 shows a prompt to grant
* Reverting persistent seems to require revoking permission _and_ clearing
site data
- Chrome
- Chrome 75 seems to grant this without any prompt based on [interaction
criteria](https://developers.google.com/web/updates/2016/06/persistent-storage)
- Firefox
- Firefox 67 shows a prompt to grant
- Reverting persistent seems to require revoking permission _and_ clearing
site data
## Storage Estimation
Storage Standard offers a `navigator.storage.estimate` API to get some clue of
how much space remains.
* Chrome, Firefox
* Can run this at any time to request an estimate of space remaining
* Firefox
* Returns `0` for `usage` if a site is persisted
- Chrome, Firefox
- Can run this at any time to request an estimate of space remaining
- Firefox
- Returns `0` for `usage` if a site is persisted
@@ -1,31 +1,29 @@
Random notes from Matthew on the two possible approaches for warning users about unexpected
unverified devices popping up in their rooms....
Original idea...
================
# Original idea...
Warn when an existing user adds an unknown device to a room.
Warn when a user joins the room with unverified or unknown devices.
Warn when you initial sync if the room has any unverified devices in it.
^ this is good enough if we're doing local storage.
OR, better:
^ this is good enough if we're doing local storage.
OR, better:
Warn when you initial sync if the room has any new undefined devices since you were last there.
=> This means persisting the rooms that devices are in, across initial syncs.
=> This means persisting the rooms that devices are in, across initial syncs.
Updated idea...
===============
# Updated idea...
Warn when the user tries to send a message:
- If the room has unverified devices which the user has not yet been told about in the context of this room
...or in the context of this user? currently all verification is per-user, not per-room.
- If the room has unverified devices which the user has not yet been told about in the context of this room
...or in the context of this user? currently all verification is per-user, not per-room.
...this should be good enough.
- so track whether we have warned the user or not about unverified devices - blocked, unverified, verified, unverified_warned.
- so track whether we have warned the user or not about unverified devices - blocked, unverified, verified, unverified_warned.
throw an error when trying to encrypt if there are pure unverified devices there
app will have to search for the devices which are pure unverified to warn about them - have to do this from MembersList anyway?
- or megolm could warn which devices are causing the problems.
- or megolm could warn which devices are causing the problems.
Why do we wait to establish outbound sessions? It just makes a horrible pause when we first try to send a message... but could otherwise unnecessarily consume resources?
Why do we wait to establish outbound sessions? It just makes a horrible pause when we first try to send a message... but could otherwise unnecessarily consume resources?
-9
View File
@@ -1,9 +0,0 @@
To try it out, **you must build the SDK first** and then host this folder:
```
$ npm run build
$ cd examples/browser
$ python -m SimpleHTTPServer 8003
```
Then visit ``http://localhost:8003``.
-13
View File
@@ -1,13 +0,0 @@
console.log("Loading browser sdk");
var client = matrixcs.createClient("https://matrix.org");
client.publicRooms(function (err, data) {
if (err) {
console.error("err %s", JSON.stringify(err));
return;
}
console.log("data %s [...]", JSON.stringify(data).substring(0, 100));
console.log("Congratulations! The SDK is working on the browser!");
var result = document.getElementById("result");
result.innerHTML = "<p>The SDK appears to be working correctly.</p>";
});
-18
View File
@@ -1,18 +0,0 @@
<html lang="en">
<head>
<title>Test</title>
<meta charset="utf-8"/>
<link rel="icon" href="data:,">
<script src="lib/matrix.js"></script>
<script src="browserTest.js"></script>
</head>
<body>
Sanity Testing (check the console) : This example is here to make sure that
the SDK works inside a browser. It simply does a GET /publicRooms on
matrix.org
<br/>
You should see a message confirming that the SDK works below:
<br/>
<div id="result"></div>
</body>
</html>
-1
View File
@@ -1 +0,0 @@
../../../dist/browser-matrix.js
-2
View File
@@ -1,2 +0,0 @@
olm.js
olm.wasm
-1
View File
@@ -1 +0,0 @@
../../../dist/browser-matrix.js
@@ -1,59 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Test Crypto in Browser</title>
<script src="lib/olm.js"></script>
<script src="lib/matrix.js"></script>
</head>
<body>
<h1>Testing export/import of Olm devices in the browser</h1>
<ul>
<li>
Make sure you built the current version of the Matrix JS SDK
(<code>yarn build</code>)
</li>
<li>
copy <code>olm.js</code> and <code>olm.wasm</code>
from a recent release of Olm (was tested with version 3.1.4)
in directory <code>lib/</code>
</li>
<li>start a local Matrix homeserver (on port 8008, or change the port in the code)</li>
<li>Serve this HTML file (e.g. <code>python3 -m http.server</code>) and go to it through your browser</li>
<li>
in the JS console, do:
<pre>
aliceMatrixClient = await newMatrixClient("alice-"+randomHex());
await aliceMatrixClient.exportDevice();
await aliceMatrixClient.getAccessToken();
</pre>
</li>
<li>
copy the result of <code>exportDevice</code> and <code>getAccessToken</code> somewhere
(<strong>not</strong> in a JS variable as it will be destroyed when you refresh the page)
</li>
<li><strong>refresh the page (F5)</strong> to make sure the client is destroyed</li>
<li>
Do the following, replacing <code>ALICE_ID</code>
with the user ID of Alice (you can find it in the exported data)
<pre>
bobMatrixClient = await newMatrixClient("bob-"+randomHex());
roomId = await bobMatrixClient.createEncryptedRoom([ALICE_ID]);
await bobMatrixClient.sendTextMessage('Hi Alice!', roomId);
</pre>
</li>
<li>Again, <strong>refresh the page (F5)</strong>. You may want to clear your console as well.</li>
<li>
Now do the following, using the exported data and the access token you saved previously:
<pre>
aliceMatrixClient = await importMatrixClient(EXPORTED_DATA, ACCESS_TOKEN);
</pre>
</li>
<li>You should see the message sent by Bob printed in the console.</li>
</ul>
<script src="olm-device-export-import.js"></script>
</body>
</html>
@@ -1,122 +0,0 @@
if (!Olm) {
console.error(
"global.Olm does not seem to be present."
+ " Did you forget to add olm in the lib/ directory?"
);
}
const BASE_URL = 'http://localhost:8008';
const ROOM_CRYPTO_CONFIG = { algorithm: 'm.megolm.v1.aes-sha2' };
const PASSWORD = 'password';
// useful to create new usernames
window.randomHex = () => Math.floor(Math.random() * (10**6)).toString(16);
window.newMatrixClient = async function (username) {
const registrationClient = matrixcs.createClient(BASE_URL);
const userRegisterResult = await registrationClient.register(
username,
PASSWORD,
null,
{ type: 'm.login.dummy' }
);
const matrixClient = matrixcs.createClient({
baseUrl: BASE_URL,
userId: userRegisterResult.user_id,
accessToken: userRegisterResult.access_token,
deviceId: userRegisterResult.device_id,
sessionStore: new matrixcs.WebStorageSessionStore(window.localStorage),
cryptoStore: new matrixcs.MemoryCryptoStore(),
});
extendMatrixClient(matrixClient);
await matrixClient.initCrypto();
await matrixClient.startClient();
return matrixClient;
}
window.importMatrixClient = async function (exportedDevice, accessToken) {
const matrixClient = matrixcs.createClient({
baseUrl: BASE_URL,
deviceToImport: exportedDevice,
accessToken,
sessionStore: new matrixcs.WebStorageSessionStore(window.localStorage),
cryptoStore: new matrixcs.MemoryCryptoStore(),
});
extendMatrixClient(matrixClient);
await matrixClient.initCrypto();
await matrixClient.startClient();
return matrixClient;
}
function extendMatrixClient(matrixClient) {
// automatic join
matrixClient.on('RoomMember.membership', async (event, member) => {
if (member.membership === 'invite' && member.userId === matrixClient.getUserId()) {
await matrixClient.joinRoom(member.roomId);
// setting up of room encryption seems to be triggered automatically
// but if we don't wait for it the first messages we send are unencrypted
await matrixClient.setRoomEncryption(member.roomId, { algorithm: 'm.megolm.v1.aes-sha2' })
}
});
matrixClient.onDecryptedMessage = message => {
console.log('Got encrypted message: ', message);
}
matrixClient.on('Event.decrypted', (event) => {
if (event.getType() === 'm.room.message'){
matrixClient.onDecryptedMessage(event.getContent().body);
} else {
console.log('decrypted an event of type', event.getType());
console.log(event);
}
});
matrixClient.createEncryptedRoom = async function(usersToInvite) {
const {
room_id: roomId,
} = await this.createRoom({
visibility: 'private',
invite: usersToInvite,
});
// matrixClient.setRoomEncryption() only updates local state
// but does not send anything to the server
// (see https://github.com/matrix-org/matrix-js-sdk/issues/905)
// so we do it ourselves with 'sendStateEvent'
await this.sendStateEvent(
roomId, 'm.room.encryption', ROOM_CRYPTO_CONFIG,
);
await this.setRoomEncryption(
roomId, ROOM_CRYPTO_CONFIG,
);
// Marking all devices as verified
let room = this.getRoom(roomId);
let members = (await room.getEncryptionTargetMembers()).map(x => x["userId"])
let memberkeys = await this.downloadKeys(members);
for (const userId in memberkeys) {
for (const deviceId in memberkeys[userId]) {
await this.setDeviceVerified(userId, deviceId);
}
}
return roomId;
}
matrixClient.sendTextMessage = async function(message, roomId) {
return matrixClient.sendMessage(
roomId,
{
body: message,
msgtype: 'm.text',
}
)
}
}
+1 -2
View File
@@ -1,6 +1,5 @@
This is a functional terminal app which allows you to see the room list for a user, join rooms, send messages and view room membership lists.
To try it out, you will need to edit `app.js` to configure it for your `homeserver`, `access_token` and `user_id`. Then run:
```
@@ -24,7 +23,7 @@ Room list index commands:
Room commands:
'/exit' Return to the room list index.
'/members' Show the room member list.
$ /enter 2
[2015-06-12 15:14:54] Megan2 <<< herro
+140 -152
View File
@@ -5,7 +5,7 @@ var clc = require("cli-color");
var matrixClient = sdk.createClient({
baseUrl: "http://localhost:8008",
accessToken: myAccessToken,
userId: myUserId
userId: myUserId,
});
// Data structures
@@ -14,15 +14,15 @@ var viewingRoom = null;
var numMessagesToShow = 20;
// Reading from stdin
var CLEAR_CONSOLE = '\x1B[2J';
var CLEAR_CONSOLE = "\x1B[2J";
var readline = require("readline");
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
completer: completer
completer: completer,
});
rl.setPrompt("$ ");
rl.on('line', function(line) {
rl.on("line", function (line) {
if (line.trim().length === 0) {
rl.prompt();
return;
@@ -37,14 +37,11 @@ rl.on('line', function(line) {
if (line === "/exit") {
viewingRoom = null;
printRoomList();
}
else if (line === "/members") {
} else if (line === "/members") {
printMemberList(viewingRoom);
}
else if (line === "/roominfo") {
} else if (line === "/roominfo") {
printRoomInfo(viewingRoom);
}
else if (line === "/resend") {
} else if (line === "/resend") {
// get the oldest not sent event.
var notSentEvent;
for (var i = 0; i < viewingRoom.timeline.length; i++) {
@@ -54,76 +51,84 @@ rl.on('line', function(line) {
}
}
if (notSentEvent) {
matrixClient.resendEvent(notSentEvent, viewingRoom).then(function() {
printMessages();
rl.prompt();
}, function(err) {
printMessages();
print("/resend Error: %s", err);
rl.prompt();
});
matrixClient.resendEvent(notSentEvent, viewingRoom).then(
function () {
printMessages();
rl.prompt();
},
function (err) {
printMessages();
print("/resend Error: %s", err);
rl.prompt();
},
);
printMessages();
rl.prompt();
}
}
else if (line.indexOf("/more ") === 0) {
} else if (line.indexOf("/more ") === 0) {
var amount = parseInt(line.split(" ")[1]) || 20;
matrixClient.scrollback(viewingRoom, amount).then(function(room) {
printMessages();
rl.prompt();
}, function(err) {
print("/more Error: %s", err);
});
}
else if (line.indexOf("/invite ") === 0) {
matrixClient.scrollback(viewingRoom, amount).then(
function (room) {
printMessages();
rl.prompt();
},
function (err) {
print("/more Error: %s", err);
},
);
} else if (line.indexOf("/invite ") === 0) {
var userId = line.split(" ")[1].trim();
matrixClient.invite(viewingRoom.roomId, userId).then(function() {
printMessages();
rl.prompt();
}, function(err) {
print("/invite Error: %s", err);
});
}
else if (line.indexOf("/file ") === 0) {
matrixClient.invite(viewingRoom.roomId, userId).then(
function () {
printMessages();
rl.prompt();
},
function (err) {
print("/invite Error: %s", err);
},
);
} else if (line.indexOf("/file ") === 0) {
var filename = line.split(" ")[1].trim();
var stream = fs.createReadStream(filename);
matrixClient.uploadContent({
stream: stream,
name: filename
}).then(function(url) {
var content = {
msgtype: "m.file",
body: filename,
url: JSON.parse(url).content_uri
};
matrixClient.sendMessage(viewingRoom.roomId, content);
});
}
else {
matrixClient.sendTextMessage(viewingRoom.roomId, line).finally(function() {
matrixClient
.uploadContent({
stream: stream,
name: filename,
})
.then(function (url) {
var content = {
msgtype: "m.file",
body: filename,
url: JSON.parse(url).content_uri,
};
matrixClient.sendMessage(viewingRoom.roomId, content);
});
} else {
matrixClient.sendTextMessage(viewingRoom.roomId, line).finally(function () {
printMessages();
rl.prompt();
});
// print local echo immediately
printMessages();
}
}
else {
} else {
if (line.indexOf("/join ") === 0) {
var roomIndex = line.split(" ")[1];
viewingRoom = roomList[roomIndex];
if (viewingRoom.getMember(myUserId).membership === "invite") {
// join the room first
matrixClient.joinRoom(viewingRoom.roomId).then(function(room) {
setRoomList();
viewingRoom = room;
printMessages();
rl.prompt();
}, function(err) {
print("/join Error: %s", err);
});
}
else {
matrixClient.joinRoom(viewingRoom.roomId).then(
function (room) {
setRoomList();
viewingRoom = room;
printMessages();
rl.prompt();
},
function (err) {
print("/join Error: %s", err);
},
);
} else {
printMessages();
}
}
@@ -133,18 +138,18 @@ rl.on('line', function(line) {
// ==== END User input
// show the room list after syncing.
matrixClient.on("sync", function(state, prevState, data) {
matrixClient.on("sync", function (state, prevState, data) {
switch (state) {
case "PREPARED":
setRoomList();
printRoomList();
printHelp();
rl.prompt();
break;
}
setRoomList();
printRoomList();
printHelp();
rl.prompt();
break;
}
});
matrixClient.on("Room", function() {
matrixClient.on("Room", function () {
setRoomList();
if (!viewingRoom) {
printRoomList();
@@ -153,7 +158,7 @@ matrixClient.on("Room", function() {
});
// print incoming messages.
matrixClient.on("Room.timeline", function(event, room, toStartOfTimeline) {
matrixClient.on("Room.timeline", function (event, room, toStartOfTimeline) {
if (toStartOfTimeline) {
return; // don't print paginated results
}
@@ -165,20 +170,19 @@ matrixClient.on("Room.timeline", function(event, room, toStartOfTimeline) {
function setRoomList() {
roomList = matrixClient.getRooms();
roomList.sort(function(a,b) {
roomList.sort(function (a, b) {
// < 0 = a comes first (lower index) - we want high indexes = newer
var aMsg = a.timeline[a.timeline.length-1];
var aMsg = a.timeline[a.timeline.length - 1];
if (!aMsg) {
return -1;
}
var bMsg = b.timeline[b.timeline.length-1];
var bMsg = b.timeline[b.timeline.length - 1];
if (!bMsg) {
return 1;
}
if (aMsg.getTs() > bMsg.getTs()) {
return 1;
}
else if (aMsg.getTs() < bMsg.getTs()) {
} else if (aMsg.getTs() < bMsg.getTs()) {
return -1;
}
return 0;
@@ -189,16 +193,15 @@ function printRoomList() {
print(CLEAR_CONSOLE);
print("Room List:");
var fmts = {
"invite": clc.cyanBright,
"leave": clc.blackBright
invite: clc.cyanBright,
leave: clc.blackBright,
};
for (var i = 0; i < roomList.length; i++) {
var msg = roomList[i].timeline[roomList[i].timeline.length-1];
var msg = roomList[i].timeline[roomList[i].timeline.length - 1];
var dateStr = "---";
var fmt;
if (msg) {
dateStr = new Date(msg.getTs()).toISOString().replace(
/T/, ' ').replace(/\..+/, '');
dateStr = new Date(msg.getTs()).toISOString().replace(/T/, " ").replace(/\..+/, "");
}
var myMembership = roomList[i].getMyMembership();
if (myMembership) {
@@ -207,9 +210,10 @@ function printRoomList() {
var roomName = fixWidth(roomList[i].name, 25);
print(
"[%s] %s (%s members) %s",
i, fmt ? fmt(roomName) : roomName,
i,
fmt ? fmt(roomName) : roomName,
roomList[i].getJoinedMembers().length,
dateStr
dateStr,
);
}
}
@@ -230,12 +234,12 @@ function printHelp() {
}
function completer(line) {
var completions = [
"/help", "/join ", "/exit", "/members", "/more ", "/resend", "/invite"
];
var hits = completions.filter(function(c) { return c.indexOf(line) == 0 });
var completions = ["/help", "/join ", "/exit", "/members", "/more ", "/resend", "/invite"];
var hits = completions.filter(function (c) {
return c.indexOf(line) == 0;
});
// show all completions if none found
return [hits.length ? hits : completions, line]
return [hits.length ? hits : completions, line];
}
function printMessages() {
@@ -252,14 +256,14 @@ function printMessages() {
function printMemberList(room) {
var fmts = {
"join": clc.green,
"ban": clc.red,
"invite": clc.blue,
"leave": clc.blackBright
join: clc.green,
ban: clc.red,
invite: clc.blue,
leave: clc.blackBright,
};
var members = room.currentState.getMembers();
// sorted based on name.
members.sort(function(a, b) {
members.sort(function (a, b) {
if (a.name > b.name) {
return -1;
}
@@ -268,21 +272,24 @@ function printMemberList(room) {
}
return 0;
});
print("Membership list for room \"%s\"", room.name);
print('Membership list for room "%s"', room.name);
print(new Array(room.name.length + 28).join("-"));
room.currentState.getMembers().forEach(function(member) {
room.currentState.getMembers().forEach(function (member) {
if (!member.membership) {
return;
}
var fmt = fmts[member.membership] || function(a){return a;};
var membershipWithPadding = (
member.membership + new Array(10 - member.membership.length).join(" ")
);
var fmt =
fmts[member.membership] ||
function (a) {
return a;
};
var membershipWithPadding = member.membership + new Array(10 - member.membership.length).join(" ");
print(
"%s"+fmt(" :: ")+"%s"+fmt(" (")+"%s"+fmt(")"),
membershipWithPadding, member.name,
(member.userId === myUserId ? "Me" : member.userId),
fmt
"%s" + fmt(" :: ") + "%s" + fmt(" (") + "%s" + fmt(")"),
membershipWithPadding,
member.name,
member.userId === myUserId ? "Me" : member.userId,
fmt,
);
});
}
@@ -292,38 +299,31 @@ function printRoomInfo(room) {
var eTypeHeader = " Event Type(state_key) ";
var sendHeader = " Sender ";
// pad content to 100
var restCount = (
100 - "Content".length - " | ".length - " | ".length -
eTypeHeader.length - sendHeader.length
);
var padSide = new Array(Math.floor(restCount/2)).join(" ");
var restCount = 100 - "Content".length - " | ".length - " | ".length - eTypeHeader.length - sendHeader.length;
var padSide = new Array(Math.floor(restCount / 2)).join(" ");
var contentHeader = padSide + "Content" + padSide;
print(eTypeHeader+sendHeader+contentHeader);
print(eTypeHeader + sendHeader + contentHeader);
print(new Array(100).join("-"));
eventMap.keys().forEach(function(eventType) {
if (eventType === "m.room.member") { return; } // use /members instead.
eventMap.keys().forEach(function (eventType) {
if (eventType === "m.room.member") {
return;
} // use /members instead.
var eventEventMap = eventMap.get(eventType);
eventEventMap.keys().forEach(function(stateKey) {
var typeAndKey = eventType + (
stateKey.length > 0 ? "("+stateKey+")" : ""
);
eventEventMap.keys().forEach(function (stateKey) {
var typeAndKey = eventType + (stateKey.length > 0 ? "(" + stateKey + ")" : "");
var typeStr = fixWidth(typeAndKey, eTypeHeader.length);
var event = eventEventMap.get(stateKey);
var sendStr = fixWidth(event.getSender(), sendHeader.length);
var contentStr = fixWidth(
JSON.stringify(event.getContent()), contentHeader.length
);
print(typeStr+" | "+sendStr+" | "+contentStr);
var contentStr = fixWidth(JSON.stringify(event.getContent()), contentHeader.length);
print(typeStr + " | " + sendStr + " | " + contentStr);
});
})
});
}
function printLine(event) {
var fmt;
var name = event.sender ? event.sender.name : event.getSender();
var time = new Date(
event.getTs()
).toISOString().replace(/T/, ' ').replace(/\..+/, '');
var time = new Date(event.getTs()).toISOString().replace(/T/, " ").replace(/\..+/, "");
var separator = "<<<";
if (event.getSender() === myUserId) {
name = "Me";
@@ -331,8 +331,7 @@ function printLine(event) {
if (event.status === sdk.EventStatus.SENDING) {
separator = "...";
fmt = clc.xterm(8);
}
else if (event.status === sdk.EventStatus.NOT_SENT) {
} else if (event.status === sdk.EventStatus.NOT_SENT) {
separator = " x ";
fmt = clc.redBright;
}
@@ -341,69 +340,58 @@ function printLine(event) {
var maxNameWidth = 15;
if (name.length > maxNameWidth) {
name = name.slice(0, maxNameWidth-1) + "\u2026";
name = name.slice(0, maxNameWidth - 1) + "\u2026";
}
if (event.getType() === "m.room.message") {
body = event.getContent().body;
}
else if (event.isState()) {
} else if (event.isState()) {
var stateName = event.getType();
if (event.getStateKey().length > 0) {
stateName += " ("+event.getStateKey()+")";
stateName += " (" + event.getStateKey() + ")";
}
body = (
"[State: "+stateName+" updated to: "+JSON.stringify(event.getContent())+"]"
);
body = "[State: " + stateName + " updated to: " + JSON.stringify(event.getContent()) + "]";
separator = "---";
fmt = clc.xterm(249).italic;
}
else {
} else {
// random message event
body = (
"[Message: "+event.getType()+" Content: "+JSON.stringify(event.getContent())+"]"
);
body = "[Message: " + event.getType() + " Content: " + JSON.stringify(event.getContent()) + "]";
separator = "---";
fmt = clc.xterm(249).italic;
}
if (fmt) {
print(
"[%s] %s %s %s", time, name, separator, body, fmt
);
}
else {
print("[%s] %s %s %s", time, name, separator, body, fmt);
} else {
print("[%s] %s %s %s", time, name, separator, body);
}
}
function print(str, formatter) {
if (typeof arguments[arguments.length-1] === "function") {
if (typeof arguments[arguments.length - 1] === "function") {
// last arg is the formatter so get rid of it and use it on each
// param passed in but not the template string.
var newArgs = [];
var i = 0;
for (i=0; i<arguments.length-1; i++) {
for (i = 0; i < arguments.length - 1; i++) {
newArgs.push(arguments[i]);
}
var fmt = arguments[arguments.length-1];
for (i=0; i<newArgs.length; i++) {
var fmt = arguments[arguments.length - 1];
for (i = 0; i < newArgs.length; i++) {
newArgs[i] = fmt(newArgs[i]);
}
console.log.apply(console.log, newArgs);
}
else {
} else {
console.log.apply(console.log, arguments);
}
}
function fixWidth(str, len) {
if (str.length > len) {
return str.substring(0, len-2) + "\u2026";
}
else if (str.length < len) {
return str.substring(0, len - 2) + "\u2026";
} else if (str.length < len) {
return str + new Array(len - str.length).join(" ");
}
return str;
}
matrixClient.startClient(numMessagesToShow); // messages for each room.
matrixClient.startClient(numMessagesToShow); // messages for each room.
+12 -12
View File
@@ -1,14 +1,14 @@
{
"name": "example-app",
"version": "0.0.0",
"description": "",
"main": "app.js",
"scripts": {
"preinstall": "npm install ../.."
},
"author": "",
"license": "Apache 2.0",
"dependencies": {
"cli-color": "^1.0.0"
}
"name": "example-app",
"version": "0.0.0",
"description": "",
"main": "app.js",
"scripts": {
"preinstall": "npm install ../.."
},
"author": "",
"license": "Apache 2.0",
"dependencies": {
"cli-color": "^1.0.0"
}
}
+1 -1
View File
@@ -6,4 +6,4 @@ To try it out, **you must build the SDK first** and then host this folder:
$ python -m SimpleHTTPServer 8003
```
Then visit ``http://localhost:8003``.
Then visit `http://localhost:8003`.
+26 -23
View File
@@ -9,7 +9,7 @@ const client = matrixcs.createClient({
baseUrl: BASE_URL,
accessToken: TOKEN,
userId: USER_ID,
deviceId: DEVICE_ID
deviceId: DEVICE_ID,
});
let call;
@@ -21,18 +21,16 @@ function disableButtons(place, answer, hangup) {
function addListeners(call) {
let lastError = "";
call.on("hangup", function() {
call.on("hangup", function () {
disableButtons(false, true, true);
document.getElementById("result").innerHTML = (
"<p>Call ended. Last error: "+lastError+"</p>"
);
document.getElementById("result").innerHTML = "<p>Call ended. Last error: " + lastError + "</p>";
});
call.on("error", function(err) {
call.on("error", function (err) {
lastError = err.message;
call.hangup();
disableButtons(false, true, true);
});
call.on("feeds_changed", function(feeds) {
call.on("feeds_changed", function (feeds) {
const localFeed = feeds.find((feed) => feed.isLocal());
const remoteFeed = feeds.find((feed) => !feed.isLocal());
@@ -51,33 +49,38 @@ function addListeners(call) {
});
}
window.onload = function() {
window.onload = function () {
document.getElementById("result").innerHTML = "<p>Please wait. Syncing...</p>";
document.getElementById("config").innerHTML = "<p>" +
"Homeserver: <code>"+BASE_URL+"</code><br/>"+
"Room: <code>"+ROOM_ID+"</code><br/>"+
"User: <code>"+USER_ID+"</code><br/>"+
document.getElementById("config").innerHTML =
"<p>" +
"Homeserver: <code>" +
BASE_URL +
"</code><br/>" +
"Room: <code>" +
ROOM_ID +
"</code><br/>" +
"User: <code>" +
USER_ID +
"</code><br/>" +
"</p>";
disableButtons(true, true, true);
};
client.on("sync", function(state, prevState, data) {
client.on("sync", function (state, prevState, data) {
switch (state) {
case "PREPARED":
syncComplete();
break;
}
syncComplete();
break;
}
});
function syncComplete() {
document.getElementById("result").innerHTML = "<p>Ready for calls.</p>";
disableButtons(false, true, true);
document.getElementById("call").onclick = function() {
document.getElementById("call").onclick = function () {
console.log("Placing call...");
call = matrixcs.createNewMatrixCall(
client, ROOM_ID
);
call = matrixcs.createNewMatrixCall(client, ROOM_ID);
console.log("Call => %s", call);
addListeners(call);
call.placeVideoCall();
@@ -85,14 +88,14 @@ function syncComplete() {
disableButtons(true, true, false);
};
document.getElementById("hangup").onclick = function() {
document.getElementById("hangup").onclick = function () {
console.log("Hanging up call...");
console.log("Call => %s", call);
call.hangup();
document.getElementById("result").innerHTML = "<p>Hungup call.</p>";
};
document.getElementById("answer").onclick = function() {
document.getElementById("answer").onclick = function () {
console.log("Answering call...");
console.log("Call => %s", call);
call.answer();
@@ -100,7 +103,7 @@ function syncComplete() {
document.getElementById("result").innerHTML = "<p>Answered call.</p>";
};
client.on("Call.incoming", function(c) {
client.on("Call.incoming", function (c) {
console.log("Call ringing");
disableButtons(true, false, false);
document.getElementById("result").innerHTML = "<p>Incoming call...</p>";
+19 -21
View File
@@ -1,25 +1,23 @@
<html>
<head>
<title>VoIP Test</title>
<script src="lib/matrix.js"></script>
<script src="browserTest.js"></script>
</head>
<head>
<title>VoIP Test</title>
<script src="lib/matrix.js"></script>
<script src="browserTest.js"></script>
</head>
<body>
You can place and receive calls with this example. Make sure to edit the
constants in <code>browserTest.js</code> first.
<div id="config"></div>
<div id="result"></div>
<button id="call">Place Call</button>
<button id="answer">Answer Call</button>
<button id="hangup">Hangup Call</button>
<div id="videoBackground" class="video-background">
<video class="video-element" id="local"></video>
<video class="video-element" id="remote"></video>
</div>
</body>
<body>
You can place and receive calls with this example. Make sure to edit the constants in
<code>browserTest.js</code> first.
<div id="config"></div>
<div id="result"></div>
<button id="call">Place Call</button>
<button id="answer">Answer Call</button>
<button id="hangup">Hangup Call</button>
<div id="videoBackground" class="video-background">
<video class="video-element" id="local"></video>
<video class="video-element" id="remote"></video>
</div>
</body>
</html>
<style>
@@ -31,4 +29,4 @@
.video-element {
height: 100%;
}
</style>
</style>
+47
View File
@@ -0,0 +1,47 @@
/* Copyright 2023 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 type { Config } from "jest";
import { env } from "process";
const config: Config = {
testEnvironment: "node",
testMatch: ["<rootDir>/spec/**/*.spec.{js,ts}"],
setupFilesAfterEnv: ["<rootDir>/spec/setupTests.ts"],
collectCoverageFrom: ["<rootDir>/src/**/*.{js,ts}"],
coverageReporters: ["text-summary", "lcov"],
testResultsProcessor: "@casualbot/jest-sonar-reporter",
// Always print out a summary if there are any failing tests. Normally
// a summary is only printed if there are more than 20 test *suites*.
reporters: [["default", { summaryThreshold: 0 }]],
};
// if we're running under GHA, enable the GHA reporter
if (env["GITHUB_ACTIONS"] !== undefined) {
const reporters: Config["reporters"] = [
["github-actions", { silent: false }],
// as above: always show a summary if there were any failing tests.
["summary", { summaryThreshold: 0 }],
];
// if we're running against the develop branch, also enable the slow test reporter
if (env["GITHUB_REF"] == "refs/heads/develop") {
reporters.push("<rootDir>/spec/slowReporter.js");
}
config.reporters = reporters;
}
export default config;
-30
View File
@@ -1,30 +0,0 @@
{
"tags": {
"allowUnknownTags": true
},
"plugins": [
"node_modules/better-docs/category",
"node_modules/better-docs/typescript"
],
"source": {
"include": [
"src"
],
"includePattern": ".(ts|js)$"
},
"opts": {
"encoding": "utf8",
"destination": ".jsdoc",
"readme": "README.md",
"recurse": true,
"verbose": true,
"template": "node_modules/docdash"
},
"docdash": {
"static": true,
"private": false,
"search": true,
"collapse": true,
"typedefs": true
}
}
+133 -130
View File
@@ -1,134 +1,137 @@
{
"name": "matrix-js-sdk",
"version": "21.0.0",
"description": "Matrix Client-Server SDK for Javascript",
"engines": {
"node": ">=16.0.0"
},
"scripts": {
"prepublishOnly": "yarn build",
"start": "echo THIS IS FOR LEGACY PURPOSES ONLY. && babel src -w -s -d lib --verbose --extensions \".ts,.js\"",
"dist": "echo 'This is for the release script so it can make assets (browser bundle).' && yarn build",
"clean": "rimraf lib dist",
"build": "yarn build:dev && yarn build:compile-browser && yarn build:minify-browser",
"build:dev": "yarn clean && git rev-parse HEAD > git-revision.txt && yarn build:compile && yarn build:types",
"build:types": "tsc -p tsconfig-build.json --emitDeclarationOnly",
"build:compile": "babel -d lib --verbose --extensions \".ts,.js\" src",
"build:compile-browser": "mkdirp dist && browserify -d src/browser-index.js -p [ tsify -p ./tsconfig-build.json ] -t [ babelify --sourceMaps=inline --presets [ @babel/preset-env @babel/preset-typescript ] ] | exorcist dist/browser-matrix.js.map > dist/browser-matrix.js",
"build:minify-browser": "terser dist/browser-matrix.js --compress --mangle --source-map --output dist/browser-matrix.min.js",
"gendoc": "jsdoc -c jsdoc.json -P package.json",
"lint": "yarn lint:types && yarn lint:js",
"lint:js": "eslint --max-warnings 0 src spec",
"lint:js-fix": "eslint --fix src spec",
"lint:types": "tsc --noEmit",
"test": "jest",
"test:watch": "jest --watch",
"coverage": "yarn test --coverage"
},
"repository": {
"type": "git",
"url": "https://github.com/matrix-org/matrix-js-sdk"
},
"keywords": [
"matrix-org"
],
"main": "./lib/index.js",
"browser": "./lib/browser-index.js",
"matrix_src_main": "./src/index.ts",
"matrix_src_browser": "./src/browser-index.js",
"matrix_lib_main": "./lib/index.js",
"matrix_lib_typings": "./lib/index.d.ts",
"author": "matrix.org",
"license": "Apache-2.0",
"files": [
"dist",
"lib",
"src",
"git-revision.txt",
"CHANGELOG.md",
"CONTRIBUTING.rst",
"LICENSE",
"README.md",
"package.json",
"release.sh"
],
"dependencies": {
"@babel/runtime": "^7.12.5",
"another-json": "^0.2.0",
"bs58": "^5.0.0",
"content-type": "^1.0.4",
"loglevel": "^1.7.1",
"matrix-events-sdk": "^0.0.1-beta.7",
"p-retry": "4",
"qs": "^6.9.6",
"unhomoglyph": "^1.0.6"
},
"devDependencies": {
"@babel/cli": "^7.12.10",
"@babel/core": "^7.12.10",
"@babel/eslint-parser": "^7.12.10",
"@babel/eslint-plugin": "^7.12.10",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-numeric-separator": "^7.12.7",
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-typescript": "^7.12.7",
"@babel/register": "^7.12.10",
"@matrix-org/olm": "https://gitlab.matrix.org/api/v4/projects/27/packages/npm/@matrix-org/olm/-/@matrix-org/olm-3.2.13.tgz",
"@types/bs58": "^4.0.1",
"@types/content-type": "^1.1.5",
"@types/domexception": "^4.0.0",
"@types/jest": "^29.0.0",
"@types/node": "16",
"@typescript-eslint/eslint-plugin": "^5.6.0",
"@typescript-eslint/parser": "^5.6.0",
"allchange": "^1.0.6",
"babel-jest": "^29.0.0",
"babelify": "^10.0.0",
"better-docs": "^2.4.0-beta.9",
"browserify": "^17.0.0",
"docdash": "^1.2.0",
"domexception": "^4.0.0",
"eslint": "8.24.0",
"eslint-config-google": "^0.14.0",
"eslint-import-resolver-typescript": "^3.5.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-matrix-org": "^0.6.0",
"exorcist": "^2.0.0",
"fake-indexeddb": "^4.0.0",
"jest": "^29.0.0",
"jest-localstorage-mock": "^2.4.6",
"jest-mock": "^27.5.1",
"jest-sonar-reporter": "^2.0.0",
"jsdoc": "^3.6.6",
"matrix-mock-request": "^2.5.0",
"rimraf": "^3.0.2",
"terser": "^5.5.1",
"tsify": "^5.0.2",
"typescript": "^4.5.3"
},
"jest": {
"testEnvironment": "node",
"testMatch": [
"<rootDir>/spec/**/*.spec.{js,ts}"
"name": "matrix-js-sdk",
"version": "30.2.0",
"description": "Matrix Client-Server SDK for Javascript",
"engines": {
"node": ">=18.0.0"
},
"scripts": {
"prepublishOnly": "yarn build",
"start": "echo THIS IS FOR LEGACY PURPOSES ONLY. && babel src -w -s -d lib --verbose --extensions \".ts,.js\"",
"clean": "rimraf lib",
"build": "yarn build:dev",
"build:dev": "yarn clean && git rev-parse HEAD > git-revision.txt && yarn build:compile && yarn build:types",
"build:types": "tsc -p tsconfig-build.json --emitDeclarationOnly",
"build:compile": "babel -d lib --verbose --extensions \".ts,.js\" src",
"gendoc": "typedoc",
"lint": "yarn lint:types && yarn lint:js && yarn lint:workflows",
"lint:js": "eslint --max-warnings 0 src spec && prettier --check .",
"lint:js-fix": "prettier --loglevel=warn --write . && eslint --fix src spec",
"lint:types": "tsc --noEmit",
"lint:workflows": "find .github/workflows -type f \\( -iname '*.yaml' -o -iname '*.yml' \\) | xargs -I {} sh -c 'echo \"Linting {}\"; action-validator \"{}\"'",
"test": "jest",
"test:watch": "jest --watch",
"coverage": "yarn test --coverage"
},
"repository": {
"type": "git",
"url": "https://github.com/matrix-org/matrix-js-sdk"
},
"keywords": [
"matrix-org"
],
"setupFilesAfterEnv": [
"<rootDir>/spec/setupTests.ts"
"main": "./lib/index.js",
"browser": "./lib/browser-index.js",
"matrix_src_main": "./src/index.ts",
"matrix_src_browser": "./src/browser-index.ts",
"matrix_lib_main": "./lib/index.js",
"matrix_lib_browser": "./lib/browser-index.js",
"matrix_lib_typings": "./lib/index.d.ts",
"author": "matrix.org",
"license": "Apache-2.0",
"files": [
"lib",
"src",
"git-revision.txt",
"CHANGELOG.md",
"CONTRIBUTING.rst",
"LICENSE",
"README.md",
"package.json",
"release.sh"
],
"collectCoverageFrom": [
"<rootDir>/src/**/*.{js,ts}"
],
"coverageReporters": [
"text-summary",
"lcov"
],
"testResultsProcessor": "jest-sonar-reporter"
},
"jestSonar": {
"reportPath": "coverage",
"sonar56x": true
},
"typings": "./lib/index.d.ts"
"dependencies": {
"@babel/runtime": "^7.12.5",
"@matrix-org/matrix-sdk-crypto-wasm": "^3.1.0",
"another-json": "^0.2.0",
"bs58": "^5.0.0",
"content-type": "^1.0.4",
"jwt-decode": "^3.1.2",
"loglevel": "^1.7.1",
"matrix-events-sdk": "0.0.1",
"matrix-widget-api": "^1.6.0",
"oidc-client-ts": "^2.2.4",
"p-retry": "4",
"sdp-transform": "^2.14.1",
"unhomoglyph": "^1.0.6",
"uuid": "9"
},
"devDependencies": {
"@action-validator/cli": "^0.5.3",
"@action-validator/core": "^0.5.3",
"@babel/cli": "^7.12.10",
"@babel/core": "^7.12.10",
"@babel/eslint-parser": "^7.12.10",
"@babel/eslint-plugin": "^7.12.10",
"@babel/plugin-proposal-class-properties": "^7.12.1",
"@babel/plugin-proposal-numeric-separator": "^7.12.7",
"@babel/plugin-proposal-object-rest-spread": "^7.12.1",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/plugin-transform-runtime": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-typescript": "^7.12.7",
"@babel/register": "^7.12.10",
"@casualbot/jest-sonar-reporter": "2.2.7",
"@matrix-org/olm": "3.2.15",
"@types/bs58": "^4.0.1",
"@types/content-type": "^1.1.5",
"@types/debug": "^4.1.7",
"@types/domexception": "^4.0.0",
"@types/jest": "^29.0.0",
"@types/node": "18",
"@types/sdp-transform": "^2.4.5",
"@types/uuid": "9",
"@typescript-eslint/eslint-plugin": "^5.45.0",
"@typescript-eslint/parser": "^5.45.0",
"allchange": "^1.0.6",
"babel-jest": "^29.0.0",
"debug": "^4.3.4",
"domexception": "^4.0.0",
"eslint": "8.53.0",
"eslint-config-google": "^0.14.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.5.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jest": "^27.1.6",
"eslint-plugin-jsdoc": "^46.0.0",
"eslint-plugin-matrix-org": "^1.0.0",
"eslint-plugin-tsdoc": "^0.2.17",
"eslint-plugin-unicorn": "^49.0.0",
"fake-indexeddb": "^5.0.0",
"fetch-mock": "9.11.0",
"fetch-mock-jest": "^1.5.1",
"husky": "^8.0.3",
"jest": "^29.0.0",
"jest-environment-jsdom": "^29.0.0",
"jest-localstorage-mock": "^2.4.6",
"jest-mock": "^29.0.0",
"lint-staged": "^15.0.2",
"matrix-mock-request": "^2.5.0",
"prettier": "2.8.8",
"rimraf": "^5.0.0",
"ts-node": "^10.9.1",
"typedoc": "^0.24.0",
"typedoc-plugin-coverage": "^2.1.0",
"typedoc-plugin-mdn-links": "^3.0.3",
"typedoc-plugin-missing-exports": "^2.0.0",
"typedoc-plugin-versions": "^0.2.3",
"typedoc-plugin-versions-cli": "^0.1.12",
"typescript": "^5.0.0"
},
"@casualbot/jest-sonar-reporter": {
"outputDirectory": "coverage",
"outputName": "jest-sonar-report.xml",
"relativePaths": true
},
"typings": "./lib/index.d.ts"
}
+1 -23
View File
@@ -10,28 +10,6 @@ set -e
jq --version > /dev/null || (echo "jq is required: please install it"; kill $$)
if [ "$(git branch -lr | grep origin/develop -c)" -ge 1 ]; then
# When merging to develop, we need revert the `main` and `typings` fields if we adjusted them previously.
for i in main typings
do
# If a `lib` prefixed value is present, it means we adjusted the field
# earlier at publish time, so we should revert it now.
if [ "$(jq -r ".matrix_lib_$i" package.json)" != "null" ]; then
# If there's a `src` prefixed value, use that, otherwise delete.
# This is used to delete the `typings` field and reset `main` back
# to the TypeScript source.
src_value=$(jq -r ".matrix_src_$i" package.json)
if [ "$src_value" != "null" ]; then
jq ".$i = .matrix_src_$i" package.json > package.json.new && mv package.json.new package.json
else
jq "del(.$i)" package.json > package.json.new && mv package.json.new package.json
fi
fi
done
if [ -n "$(git ls-files --modified package.json)" ]; then
echo "Committing develop package.json"
git commit package.json -m "Resetting package fields for development"
fi
"$(dirname "$0")/scripts/release/post-merge-master.sh"
git push origin develop
fi
+3 -14
View File
@@ -130,7 +130,7 @@ fi
# global cache here to ensure we get the right thing.
yarn cache clean
# Ensure all dependencies are updated
yarn install --ignore-scripts --pure-lockfile
yarn install --ignore-scripts --frozen-lockfile
# ignore leading v on release
release="${1#v}"
@@ -175,18 +175,7 @@ echo "yarn version"
# manually commit the result.
yarn version --no-git-tag-version --new-version "$release"
# For the published and dist versions of the package, we copy the
# `matrix_lib_main` and `matrix_lib_typings` fields to `main` and `typings` (if
# they exist). This small bit of gymnastics allows us to use the TypeScript
# source directly for development without needing to build before linting or
# testing.
for i in main typings
do
lib_value=$(jq -r ".matrix_lib_$i" package.json)
if [ "$lib_value" != "null" ]; then
jq ".$i = .matrix_lib_$i" package.json > package.json.new && mv package.json.new package.json
fi
done
"$(dirname "$0")/scripts/release/pre-release.sh"
# commit yarn.lock if it exists, is versioned, and is modified
if [[ -f yarn.lock && $(git status --porcelain yarn.lock | grep '^ M') ]];
@@ -225,7 +214,7 @@ if [ $dodist -eq 0 ]; then
pushd "$builddir"
git clone "$projdir" .
git checkout "$rel_branch"
yarn install --pure-lockfile
yarn install --frozen-lockfile
# We haven't tagged yet, so tell the dist script what version
# it's building
DIST_VERSION="$tag" yarn dist
+1 -1
View File
@@ -15,4 +15,4 @@ for line in sys.stdin:
break
found_first_header = True
elif not re.match(r"^=+$", line) and len(line) > 0:
print line
print(line)
+104
View File
@@ -0,0 +1,104 @@
#!/usr/bin/env node
const fs = require("fs");
async function getRelease(github, dependency) {
let owner;
let repo;
let tag;
if (dependency.includes("/") && dependency.includes("@")) {
owner = dependency.split("/")[0];
repo = dependency.split("/")[1].split("@")[0];
tag = dependency.split("@")[1];
} else {
const upstreamPackageJson = JSON.parse(fs.readFileSync(`./node_modules/${dependency}/package.json`, "utf8"));
[owner, repo] = upstreamPackageJson.repository.url.split("/").slice(-2);
tag = `v${upstreamPackageJson.version}`;
}
const response = await github.rest.repos.getReleaseByTag({
owner,
repo,
tag,
});
return response.data;
}
const HEADING_PREFIX = "## ";
const main = async ({ github, releaseId, dependencies }) => {
const { GITHUB_REPOSITORY } = process.env;
const [owner, repo] = GITHUB_REPOSITORY.split("/");
const sections = new Map();
let heading = null;
for (const dependency of dependencies) {
const release = await getRelease(github, dependency);
for (const line of release.body.split("\n")) {
if (line.startsWith(HEADING_PREFIX)) {
heading = line.trim();
sections.set(heading, []);
continue;
}
if (heading && line) {
sections.get(heading).push(line.trim());
}
}
}
const { data: release } = await github.rest.repos.getRelease({
owner,
repo,
release_id: releaseId,
});
const headings = ["🚨 BREAKING CHANGES", "🦖 Deprecations", "✨ Features", "🐛 Bug Fixes", "🧰 Maintenance"].map(
(h) => HEADING_PREFIX + h,
);
heading = null;
const output = [];
for (const line of [...release.body.split("\n"), null]) {
if (line === null || line.startsWith(HEADING_PREFIX)) {
// If we have a heading, and it's not the first in the list of pending headings, output the section.
// If we're processing the last line (null) then output all remaining sections.
while (headings.length > 0 && (line === null || (heading && headings[0] !== heading))) {
const heading = headings.shift();
if (sections.has(heading)) {
output.push(heading);
output.push(...sections.get(heading));
}
}
if (heading && sections.has(heading)) {
const lastIsBlank = !output.at(-1)?.trim();
if (lastIsBlank) output.pop();
output.push(...sections.get(heading));
if (lastIsBlank) output.push("");
}
heading = line;
}
output.push(line);
}
return output.join("\n");
};
// This is just for testing locally
// Needs environment variables GITHUB_TOKEN & GITHUB_REPOSITORY
if (require.main === module) {
const { Octokit } = require("@octokit/rest");
const github = new Octokit({ auth: process.env.GITHUB_TOKEN });
if (process.argv.length < 4) {
// eslint-disable-next-line no-console
console.error("Usage: node merge-release-notes.js owner/repo:release_id npm-package-name ...");
process.exit(1);
}
const [releaseId, ...dependencies] = process.argv.slice(2);
main({ github, releaseId, dependencies }).then((output) => {
// eslint-disable-next-line no-console
console.log(output);
});
}
module.exports = main;
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
# When merging to develop, we need revert the `main` and `typings` fields if we adjusted them previously.
for i in main typings browser
do
# If a `lib` prefixed value is present, it means we adjusted the field earlier at publish time, so we should revert it now.
if [ "$(jq -r ".matrix_lib_$i" package.json)" != "null" ]; then
# If there's a `src` prefixed value, use that, otherwise delete.
# This is used to delete the `typings` field and reset `main` back to the TypeScript source.
src_value=$(jq -r ".matrix_src_$i" package.json)
if [ "$src_value" != "null" ]; then
jq ".$i = .matrix_src_$i" package.json > package.json.new && mv package.json.new package.json && yarn prettier --write package.json
else
jq "del(.$i)" package.json > package.json.new && mv package.json.new package.json && yarn prettier --write package.json
fi
fi
done
if [ -n "$(git ls-files --modified package.json)" ]; then
echo "Committing develop package.json"
git commit package.json -m "Resetting package fields for development"
fi
+14
View File
@@ -0,0 +1,14 @@
#!/bin/bash
# For the published and dist versions of the package,
# we copy the `matrix_lib_main` and `matrix_lib_typings` fields to `main` and `typings` (if they exist).
# This small bit of gymnastics allows us to use the TypeScript source directly for development without
# needing to build before linting or testing.
for i in main typings browser
do
lib_value=$(jq -r ".matrix_lib_$i" package.json)
if [ "$lib_value" != "null" ]; then
jq ".$i = .matrix_lib_$i" package.json > package.json.new && mv package.json.new package.json && yarn prettier --write package.json
fi
done
+6 -6
View File
@@ -1,14 +1,14 @@
#!/usr/bin/env node
const fsProm = require('fs/promises');
const fsProm = require("fs/promises");
const PKGJSON = 'package.json';
const PKGJSON = "package.json";
async function main() {
const pkgJson = JSON.parse(await fsProm.readFile(PKGJSON, 'utf8'));
for (const field of ['main', 'typings']) {
if (pkgJson["matrix_lib_"+field] !== undefined) {
pkgJson[field] = pkgJson["matrix_lib_"+field];
const pkgJson = JSON.parse(await fsProm.readFile(PKGJSON, "utf8"));
for (const field of ["main", "typings"]) {
if (pkgJson["matrix_lib_" + field] !== undefined) {
pkgJson[field] = pkgJson["matrix_lib_" + field];
}
}
await fsProm.writeFile(PKGJSON, JSON.stringify(pkgJson, null, 2));
+1 -1
View File
@@ -11,6 +11,6 @@ sonar.exclusions=docs,examples,git-hooks
sonar.typescript.tsconfigPath=./tsconfig.json
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.coverage.exclusions=spec/**/*
sonar.testExecutionReportPaths=coverage/test-report.xml
sonar.testExecutionReportPaths=coverage/jest-sonar-report.xml
sonar.lang.patterns.ts=**/*.ts,**/*.tsx
+95 -71
View File
@@ -16,30 +16,37 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
// `expect` is allowed in helper functions which are called within `test`/`it` blocks
/* eslint-disable jest/no-standalone-expect */
// load olm before the sdk if possible
import './olm-loader';
import "./olm-loader";
import MockHttpBackend from 'matrix-mock-request';
import MockHttpBackend from "matrix-mock-request";
import { LocalStorageCryptoStore } from '../src/crypto/store/localStorage-crypto-store';
import { logger } from '../src/logger';
import type { IDeviceKeys, IOneTimeKey } from "../src/@types/crypto";
import type { IE2EKeyReceiver } from "./test-utils/E2EKeyReceiver";
import { LocalStorageCryptoStore } from "../src/crypto/store/localStorage-crypto-store";
import { logger } from "../src/logger";
import { syncPromise } from "./test-utils/test-utils";
import { createClient } from "../src/matrix";
import { createClient, IStartClientOpts } from "../src/matrix";
import { ICreateClientOpts, IDownloadKeyResult, MatrixClient, PendingEventOrdering } from "../src/client";
import { MockStorageApi } from "./MockStorageApi";
import { encodeUri } from "../src/utils";
import { IDeviceKeys, IOneTimeKey } from "../src/crypto/dehydration";
import { IKeyBackupSession } from "../src/crypto/keybackup";
import { IKeysUploadResponse, IUploadKeysRequest } from '../src/client';
import { IKeysUploadResponse, IUploadKeysRequest } from "../src/client";
import { ISyncResponder } from "./test-utils/SyncResponder";
/**
* Wrapper for a MockStorageApi, MockHttpBackend and MatrixClient
*
* @deprecated Avoid using this; it is tied too tightly to matrix-mock-request and is generally inconvenient to use.
* Instead, construct a MatrixClient manually, use fetch-mock-jest to intercept the HTTP requests, and
* use things like {@link E2EKeyReceiver} and {@link SyncResponder} to manage the requests.
*/
export class TestClient {
export class TestClient implements IE2EKeyReceiver, ISyncResponder {
public readonly httpBackend: MockHttpBackend;
public readonly client: MatrixClient;
public deviceKeys: IDeviceKeys;
public oneTimeKeys: Record<string, IOneTimeKey>;
public deviceKeys?: IDeviceKeys | null;
public oneTimeKeys?: Record<string, IOneTimeKey>;
constructor(
public readonly userId?: string,
@@ -73,15 +80,18 @@ export class TestClient {
}
public toString(): string {
return 'TestClient[' + this.userId + ']';
return "TestClient[" + this.userId + "]";
}
/**
* start the client, and wait for it to initialise.
*/
public start(): Promise<void> {
logger.log(this + ': starting');
this.httpBackend.when("GET", "/versions").respond(200, {});
public start(opts: IStartClientOpts = {}): Promise<void> {
logger.log(this + ": starting");
this.httpBackend.when("GET", "/versions").respond(200, {
// we have tests that rely on support for lazy-loading members
versions: ["v1.1"],
});
this.httpBackend.when("GET", "/pushrules").respond(200, {});
this.httpBackend.when("POST", "/filter").respond(200, { filter_id: "fid" });
this.expectDeviceKeyUpload();
@@ -93,19 +103,18 @@ export class TestClient {
this.client.startClient({
// set this so that we can get hold of failed events
pendingEventOrdering: PendingEventOrdering.Detached,
...opts,
});
return Promise.all([
this.httpBackend.flushAllExpected(),
syncPromise(this.client),
]).then(() => {
logger.log(this + ': started');
return Promise.all([this.httpBackend.flushAllExpected(), syncPromise(this.client)]).then(() => {
logger.log(this + ": started");
});
}
/**
* stop the client
* @return {Promise} Resolves once the mock http backend has finished all pending flushes
* @returns Promise which resolves once the mock http backend has finished all pending flushes
*/
public async stop(): Promise<void> {
this.client.stopClient();
@@ -113,20 +122,30 @@ export class TestClient {
}
/**
* Set up expectations that the client will upload device keys.
* Set up expectations that the client will upload device keys (and possibly one-time keys)
*/
public expectDeviceKeyUpload() {
this.httpBackend.when("POST", "/keys/upload")
this.httpBackend
.when("POST", "/keys/upload")
.respond<IKeysUploadResponse, IUploadKeysRequest>(200, (_path, content) => {
expect(content.one_time_keys).toBe(undefined);
expect(content.device_keys).toBeTruthy();
logger.log(this + ': received device keys');
logger.log(this + ": received device keys");
// we expect this to happen before any one-time keys are uploaded.
expect(Object.keys(this.oneTimeKeys).length).toEqual(0);
expect(Object.keys(this.oneTimeKeys!).length).toEqual(0);
this.deviceKeys = content.device_keys;
return { one_time_key_counts: { signed_curve25519: 0 } };
// the first batch of one-time keys may be uploaded at the same time.
if (content.one_time_keys) {
logger.log(`${this}: received ${Object.keys(content.one_time_keys).length} one-time keys`);
this.oneTimeKeys = content.one_time_keys;
}
return {
one_time_key_counts: {
signed_curve25519: Object.keys(this.oneTimeKeys!).length,
},
};
});
}
@@ -135,40 +154,45 @@ export class TestClient {
* set up an expectation that the keys will be uploaded, and wait for
* that to happen.
*
* @returns {Promise} for the one-time keys
* @returns Promise for the one-time keys
*/
public awaitOneTimeKeyUpload(): Promise<Record<string, IOneTimeKey>> {
if (Object.keys(this.oneTimeKeys).length != 0) {
if (Object.keys(this.oneTimeKeys!).length != 0) {
// already got one-time keys
return Promise.resolve(this.oneTimeKeys);
return Promise.resolve(this.oneTimeKeys!);
}
this.httpBackend.when("POST", "/keys/upload")
this.httpBackend
.when("POST", "/keys/upload")
.respond<IKeysUploadResponse, IUploadKeysRequest>(200, (_path, content: IUploadKeysRequest) => {
expect(content.device_keys).toBe(undefined);
expect(content.one_time_keys).toBe(undefined);
return { one_time_key_counts: {
signed_curve25519: Object.keys(this.oneTimeKeys).length,
} };
return {
one_time_key_counts: {
signed_curve25519: Object.keys(this.oneTimeKeys!).length,
},
};
});
this.httpBackend.when("POST", "/keys/upload")
this.httpBackend
.when("POST", "/keys/upload")
.respond<IKeysUploadResponse, IUploadKeysRequest>(200, (_path, content: IUploadKeysRequest) => {
expect(content.device_keys).toBe(undefined);
expect(content.one_time_keys).toBeTruthy();
expect(content.one_time_keys).not.toEqual({});
logger.log('%s: received %i one-time keys', this,
Object.keys(content.one_time_keys).length);
logger.log("%s: received %i one-time keys", this, Object.keys(content.one_time_keys!).length);
this.oneTimeKeys = content.one_time_keys;
return { one_time_key_counts: {
signed_curve25519: Object.keys(this.oneTimeKeys).length,
} };
return {
one_time_key_counts: {
signed_curve25519: Object.keys(this.oneTimeKeys!).length,
},
};
});
// this can take ages
return this.httpBackend.flush('/keys/upload', 2, 1000).then((flushed) => {
return this.httpBackend.flush("/keys/upload", 2, 1000).then((flushed) => {
expect(flushed).toEqual(2);
return this.oneTimeKeys;
return this.oneTimeKeys!;
});
}
@@ -177,57 +201,57 @@ export class TestClient {
*
* We check that the query contains each of the users in `response`.
*
* @param {Object} response response to the query.
* @param response - response to the query.
*/
public expectKeyQuery(response: IDownloadKeyResult) {
this.httpBackend.when('POST', '/keys/query').respond<IDownloadKeyResult>(
200, (_path, content) => {
Object.keys(response.device_keys).forEach((userId) => {
expect(content.device_keys[userId]).toEqual([]);
});
return response;
this.httpBackend.when("POST", "/keys/query").respond<IDownloadKeyResult>(200, (_path, content) => {
Object.keys(response.device_keys).forEach((userId) => {
expect((content.device_keys! as Record<string, any>)[userId]).toEqual([]);
});
}
/**
* Set up expectations that the client will query key backups for a particular session
*/
public expectKeyBackupQuery(roomId: string, sessionId: string, status: number, response: IKeyBackupSession) {
this.httpBackend.when('GET', encodeUri("/room_keys/keys/$roomId/$sessionId", {
$roomId: roomId,
$sessionId: sessionId,
})).respond(status, response);
return response;
});
}
/**
* get the uploaded curve25519 device key
*
* @return {string} base64 device key
* @returns base64 device key
*/
public getDeviceKey(): string {
const keyId = 'curve25519:' + this.deviceId;
return this.deviceKeys.keys[keyId];
const keyId = "curve25519:" + this.deviceId;
return this.deviceKeys!.keys[keyId];
}
/**
* get the uploaded ed25519 device key
*
* @return {string} base64 device key
* @returns base64 device key
*/
public getSigningKey(): string {
const keyId = 'ed25519:' + this.deviceId;
return this.deviceKeys.keys[keyId];
const keyId = "ed25519:" + this.deviceId;
return this.deviceKeys!.keys[keyId];
}
/** Next time we see a sync request (or immediately, if there is one waiting), send the given response
*
* Calling this will register a response for `/sync`, and then, in the background, flush a single `/sync` request.
* Try calling {@link syncPromise} to wait for the sync to complete.
*
* @param response - response to /sync request
*/
public sendOrQueueSyncResponse(syncResponse: object): void {
this.httpBackend.when("GET", "/sync").respond(200, syncResponse);
this.httpBackend.flush("/sync", 1);
}
/**
* flush a single /sync request, and wait for the syncing event
*
* @deprecated: prefer to use {@link #sendOrQueueSyncResponse} followed by {@link syncPromise}.
*/
public flushSync(): Promise<void> {
logger.log(`${this}: flushSync`);
return Promise.all([
this.httpBackend.flush('/sync', 1),
syncPromise(this.client),
]).then(() => {
return Promise.all([this.httpBackend.flush("/sync", 1), syncPromise(this.client)]).then(() => {
logger.log(`${this}: flushSync completed`);
});
}
@@ -237,6 +261,6 @@ export class TestClient {
}
public getUserId(): string {
return this.userId;
return this.userId!;
}
}
-106
View File
@@ -1,106 +0,0 @@
/*
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 HttpBackend from "matrix-mock-request";
import "./setupTests";
import "../../dist/browser-matrix"; // uses browser-matrix instead of the src
import type { MatrixClient, ClientEvent } from "../../src";
const USER_ID = "@user:test.server";
const DEVICE_ID = "device_id";
const ACCESS_TOKEN = "access_token";
const ROOM_ID = "!room_id:server.test";
declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace NodeJS {
interface Global {
matrixcs: {
MatrixClient: typeof MatrixClient;
ClientEvent: typeof ClientEvent;
};
}
}
}
describe("Browserify Test", function() {
let client: MatrixClient;
let httpBackend: HttpBackend;
beforeEach(() => {
httpBackend = new HttpBackend();
client = new global.matrixcs.MatrixClient({
baseUrl: "http://test.server",
userId: USER_ID,
accessToken: ACCESS_TOKEN,
deviceId: DEVICE_ID,
fetchFn: httpBackend.fetchFn as typeof global.fetch,
});
httpBackend.when("GET", "/versions").respond(200, {});
httpBackend.when("GET", "/pushrules").respond(200, {});
httpBackend.when("POST", "/filter").respond(200, { filter_id: "fid" });
});
afterEach(async () => {
client.stopClient();
client.http.abort();
httpBackend.verifyNoOutstandingRequests();
httpBackend.verifyNoOutstandingExpectation();
await httpBackend.stop();
});
it("Sync", async () => {
const event = {
type: "m.room.member",
room_id: ROOM_ID,
content: {
membership: "join",
name: "Displayname",
},
event_id: "$foobar",
};
const syncData = {
next_batch: "batch1",
rooms: {
join: {},
},
};
syncData.rooms.join[ROOM_ID] = {
timeline: {
events: [
event,
],
limited: false,
},
};
httpBackend.when("GET", "/sync").respond(200, syncData);
httpBackend.when("GET", "/sync").respond(200, syncData);
const syncPromise = new Promise(r => client.once(global.matrixcs.ClientEvent.Sync, r));
const unexpectedErrorFn = jest.fn();
client.once(global.matrixcs.ClientEvent.SyncUnexpectedError, unexpectedErrorFn);
client.startClient();
await httpBackend.flushAllExpected();
await syncPromise;
expect(unexpectedErrorFn).not.toHaveBeenCalled();
}, 20000); // additional timeout as this test can take quite a while
});
+342
View File
@@ -0,0 +1,342 @@
/*
Copyright 2023 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 fetchMock from "fetch-mock-jest";
import "fake-indexeddb/auto";
import { IDBFactory } from "fake-indexeddb";
import { CRYPTO_BACKENDS, InitCrypto, syncPromise } from "../../test-utils/test-utils";
import { AuthDict, createClient, CryptoEvent, MatrixClient } from "../../../src";
import { mockInitialApiRequests, mockSetupCrossSigningRequests } from "../../test-utils/mockEndpoints";
import { encryptAES } from "../../../src/crypto/aes";
import { CryptoCallbacks, CrossSigningKey } from "../../../src/crypto-api";
import { SECRET_STORAGE_ALGORITHM_V1_AES } from "../../../src/secret-storage";
import { ISyncResponder, SyncResponder } from "../../test-utils/SyncResponder";
import { E2EKeyReceiver } from "../../test-utils/E2EKeyReceiver";
import {
MASTER_CROSS_SIGNING_PRIVATE_KEY_BASE64,
SELF_CROSS_SIGNING_PRIVATE_KEY_BASE64,
SELF_CROSS_SIGNING_PUBLIC_KEY_BASE64,
SIGNED_CROSS_SIGNING_KEYS_DATA,
USER_CROSS_SIGNING_PRIVATE_KEY_BASE64,
} from "../../test-utils/test-data";
import { E2EKeyResponder } from "../../test-utils/E2EKeyResponder";
afterEach(() => {
// reset fake-indexeddb after each test, to make sure we don't leak connections
// cf https://github.com/dumbmatter/fakeIndexedDB#wipingresetting-the-indexeddb-for-a-fresh-state
// eslint-disable-next-line no-global-assign
indexedDB = new IDBFactory();
});
const TEST_USER_ID = "@alice:localhost";
const TEST_DEVICE_ID = "xzcvb";
/**
* Integration tests for cross-signing functionality.
*
* These tests work by intercepting HTTP requests via fetch-mock rather than mocking out bits of the client, so as
* to provide the most effective integration tests possible.
*/
describe.each(Object.entries(CRYPTO_BACKENDS))("cross-signing (%s)", (backend: string, initCrypto: InitCrypto) => {
// newBackendOnly is the opposite to `oldBackendOnly`: it will skip the test if we are running against the legacy
// backend. Once we drop support for legacy crypto, it will go away.
const newBackendOnly = backend === "rust-sdk" ? test : test.skip;
let aliceClient: MatrixClient;
/** an object which intercepts `/sync` requests from {@link #aliceClient} */
let syncResponder: ISyncResponder;
/** an object which intercepts `/keys/query` requests on the test homeserver */
let e2eKeyResponder: E2EKeyResponder;
// Encryption key used to encrypt cross signing keys
const encryptionKey = new Uint8Array(32);
/**
* Create the {@link CryptoCallbacks}
*/
function createCryptoCallbacks(): CryptoCallbacks {
return {
getSecretStorageKey: (keys, name) => {
return Promise.resolve<[string, Uint8Array]>(["key_id", encryptionKey]);
},
};
}
beforeEach(async () => {
// anything that we don't have a specific matcher for silently returns a 404
fetchMock.catch(404);
fetchMock.config.warnOnFallback = false;
const homeserverUrl = "https://alice-server.com";
aliceClient = createClient({
baseUrl: homeserverUrl,
userId: TEST_USER_ID,
accessToken: "akjgkrgjs",
deviceId: TEST_DEVICE_ID,
cryptoCallbacks: createCryptoCallbacks(),
});
syncResponder = new SyncResponder(homeserverUrl);
e2eKeyResponder = new E2EKeyResponder(homeserverUrl);
/** an object which intercepts `/keys/upload` requests on the test homeserver */
new E2EKeyReceiver(homeserverUrl);
await initCrypto(aliceClient);
});
afterEach(async () => {
await aliceClient.stopClient();
fetchMock.mockReset();
});
/**
* Create cross-signing keys and publish the keys
*
* @param authDict - The parameters to as the `auth` dict in the key upload request.
* @see https://spec.matrix.org/v1.6/client-server-api/#authentication-types
*/
async function bootstrapCrossSigning(authDict: AuthDict): Promise<void> {
await aliceClient.getCrypto()?.bootstrapCrossSigning({
authUploadDeviceSigningKeys: (makeRequest) => makeRequest(authDict).then(() => undefined),
});
}
describe("bootstrapCrossSigning (before initialsync completes)", () => {
it("publishes keys if none were yet published", async () => {
mockSetupCrossSigningRequests();
// provide a UIA callback, so that the cross-signing keys are uploaded
const authDict = { type: "test" };
await bootstrapCrossSigning(authDict);
// check the cross-signing keys upload
expect(fetchMock.called("upload-keys")).toBeTruthy();
const [, keysOpts] = fetchMock.lastCall("upload-keys")!;
const keysBody = JSON.parse(keysOpts!.body as string);
expect(keysBody.auth).toEqual(authDict); // check uia dict was passed
// there should be a key of each type
// master key is signed by the device
expect(keysBody).toHaveProperty(`master_key.signatures.[${TEST_USER_ID}].[ed25519:${TEST_DEVICE_ID}]`);
const masterKeyId = Object.keys(keysBody.master_key.keys)[0];
// ssk and usk are signed by the master key
expect(keysBody).toHaveProperty(`self_signing_key.signatures.[${TEST_USER_ID}].[${masterKeyId}]`);
expect(keysBody).toHaveProperty(`user_signing_key.signatures.[${TEST_USER_ID}].[${masterKeyId}]`);
const sskId = Object.keys(keysBody.self_signing_key.keys)[0];
// check the publish call
expect(fetchMock.called("upload-sigs")).toBeTruthy();
const [, sigsOpts] = fetchMock.lastCall("upload-sigs")!;
const body = JSON.parse(sigsOpts!.body as string);
// there should be a signature for our device, by our self-signing key.
expect(body).toHaveProperty(
`[${TEST_USER_ID}].[${TEST_DEVICE_ID}].signatures.[${TEST_USER_ID}].[${sskId}]`,
);
});
newBackendOnly("get cross signing keys from secret storage and import them", async () => {
// Return public cross signing keys
e2eKeyResponder.addCrossSigningData(SIGNED_CROSS_SIGNING_KEYS_DATA);
mockInitialApiRequests(aliceClient.getHomeserverUrl());
// Encrypt the private keys and return them in the /sync response as if they are in Secret Storage
const masterKey = await encryptAES(
MASTER_CROSS_SIGNING_PRIVATE_KEY_BASE64,
encryptionKey,
"m.cross_signing.master",
);
const selfSigningKey = await encryptAES(
SELF_CROSS_SIGNING_PRIVATE_KEY_BASE64,
encryptionKey,
"m.cross_signing.self_signing",
);
const userSigningKey = await encryptAES(
USER_CROSS_SIGNING_PRIVATE_KEY_BASE64,
encryptionKey,
"m.cross_signing.user_signing",
);
syncResponder.sendOrQueueSyncResponse({
next_batch: 1,
account_data: {
events: [
{
type: "m.cross_signing.master",
content: {
encrypted: {
key_id: masterKey,
},
},
},
{
type: "m.cross_signing.self_signing",
content: {
encrypted: {
key_id: selfSigningKey,
},
},
},
{
type: "m.cross_signing.user_signing",
content: {
encrypted: {
key_id: userSigningKey,
},
},
},
{
type: "m.secret_storage.key.key_id",
content: {
key: "key_id",
algorithm: SECRET_STORAGE_ALGORITHM_V1_AES,
},
},
],
},
});
await aliceClient.startClient();
await syncPromise(aliceClient);
// we expect a request to upload signatures for our device ...
fetchMock.post({ url: "path:/_matrix/client/v3/keys/signatures/upload", name: "upload-sigs" }, {});
// we expect the UserTrustStatusChanged event to be fired after the cross signing keys import
const userTrustStatusChangedPromise = new Promise<string>((resolve) =>
aliceClient.on(CryptoEvent.UserTrustStatusChanged, resolve),
);
const authDict = { type: "test" };
await bootstrapCrossSigning(authDict);
// Check if the UserTrustStatusChanged event was fired
expect(await userTrustStatusChangedPromise).toBe(aliceClient.getUserId());
// Expect the signature to be uploaded
expect(fetchMock.called("upload-sigs")).toBeTruthy();
const [, sigsOpts] = fetchMock.lastCall("upload-sigs")!;
const body = JSON.parse(sigsOpts!.body as string);
// the device should have a signature with the public self cross signing keys.
expect(body).toHaveProperty(
`[${TEST_USER_ID}].[${TEST_DEVICE_ID}].signatures.[${TEST_USER_ID}].[ed25519:${SELF_CROSS_SIGNING_PUBLIC_KEY_BASE64}]`,
);
});
});
describe("getCrossSigningStatus()", () => {
it("should return correct values without bootstrapping cross-signing", async () => {
mockSetupCrossSigningRequests();
const crossSigningStatus = await aliceClient.getCrypto()!.getCrossSigningStatus();
// Expect the cross signing keys to be unavailable
expect(crossSigningStatus).toStrictEqual({
publicKeysOnDevice: false,
privateKeysInSecretStorage: false,
privateKeysCachedLocally: { masterKey: false, userSigningKey: false, selfSigningKey: false },
});
});
it("should return correct values after bootstrapping cross-signing", async () => {
mockSetupCrossSigningRequests();
// provide a UIA callback, so that the cross-signing keys are uploaded
const authDict = { type: "test" };
await bootstrapCrossSigning(authDict);
const crossSigningStatus = await aliceClient.getCrypto()!.getCrossSigningStatus();
// Expect the cross signing keys to be available
expect(crossSigningStatus).toStrictEqual({
publicKeysOnDevice: true,
privateKeysInSecretStorage: false,
privateKeysCachedLocally: { masterKey: true, userSigningKey: true, selfSigningKey: true },
});
});
});
describe("isCrossSigningReady()", () => {
it("should return false if cross-signing is not bootstrapped", async () => {
mockSetupCrossSigningRequests();
const isCrossSigningReady = await aliceClient.getCrypto()!.isCrossSigningReady();
expect(isCrossSigningReady).toBeFalsy();
});
it("should return true after bootstrapping cross-signing", async () => {
mockSetupCrossSigningRequests();
await bootstrapCrossSigning({ type: "test" });
const isCrossSigningReady = await aliceClient.getCrypto()!.isCrossSigningReady();
expect(isCrossSigningReady).toBeTruthy();
});
});
describe("getCrossSigningKeyId", () => {
/**
* Intercept /keys/device_signing/upload request and return the cross signing keys
* https://spec.matrix.org/v1.7/client-server-api/#post_matrixclientv3keysdevice_signingupload
*
* @returns the cross signing keys
*/
function awaitCrossSigningKeysUpload() {
return new Promise<any>((resolve) => {
fetchMock.post(
// legacy crypto uses /unstable/; /v3/ is correct
{
url: new RegExp("/_matrix/client/(unstable|v3)/keys/device_signing/upload"),
name: "upload-keys",
},
(url, options) => {
const content = JSON.parse(options.body as string);
resolve(content);
return {};
},
// Override the routes define in `mockSetupCrossSigningRequests`
{ overwriteRoutes: true },
);
});
}
it("should return the cross signing key id for each cross signing key", async () => {
mockSetupCrossSigningRequests();
// Intercept cross signing keys upload
const crossSigningKeysPromise = awaitCrossSigningKeysUpload();
// provide a UIA callback, so that the cross-signing keys are uploaded
const authDict = { type: "test" };
await bootstrapCrossSigning(authDict);
// Get the cross signing keys
const crossSigningKeys = await crossSigningKeysPromise;
const getPubKey = (crossSigningKey: any) => Object.values(crossSigningKey!.keys)[0];
const masterKeyId = await aliceClient.getCrypto()!.getCrossSigningKeyId();
expect(masterKeyId).toBe(getPubKey(crossSigningKeys.master_key));
const selfSigningKeyId = await aliceClient.getCrypto()!.getCrossSigningKeyId(CrossSigningKey.SelfSigning);
expect(selfSigningKeyId).toBe(getPubKey(crossSigningKeys.self_signing_key));
const userSigningKeyId = await aliceClient.getCrypto()!.getCrossSigningKeyId(CrossSigningKey.UserSigning);
expect(userSigningKeyId).toBe(getPubKey(crossSigningKeys.user_signing_key));
});
});
});
File diff suppressed because it is too large Load Diff
+903
View File
@@ -0,0 +1,903 @@
/*
Copyright 2022 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 fetchMock from "fetch-mock-jest";
import "fake-indexeddb/auto";
import { IDBFactory } from "fake-indexeddb";
import { createClient, CryptoEvent, ICreateClientOpts, MatrixClient, TypedEventEmitter } from "../../../src";
import { SyncResponder } from "../../test-utils/SyncResponder";
import { E2EKeyReceiver } from "../../test-utils/E2EKeyReceiver";
import { E2EKeyResponder } from "../../test-utils/E2EKeyResponder";
import { mockInitialApiRequests } from "../../test-utils/mockEndpoints";
import {
advanceTimersUntil,
awaitDecryption,
CRYPTO_BACKENDS,
InitCrypto,
syncPromise,
} from "../../test-utils/test-utils";
import * as testData from "../../test-utils/test-data";
import { KeyBackupInfo } from "../../../src/crypto-api/keybackup";
import { IKeyBackup } from "../../../src/crypto/backup";
import { flushPromises } from "../../test-utils/flushPromises";
const ROOM_ID = testData.TEST_ROOM_ID;
/** The homeserver url that we give to the test client, and where we intercept /sync, /keys, etc requests. */
const TEST_HOMESERVER_URL = "https://alice-server.com";
const TEST_USER_ID = "@alice:localhost";
const TEST_DEVICE_ID = "xzcvb";
afterEach(() => {
// reset fake-indexeddb after each test, to make sure we don't leak connections
// cf https://github.com/dumbmatter/fakeIndexedDB#wipingresetting-the-indexeddb-for-a-fresh-state
// eslint-disable-next-line no-global-assign
indexedDB = new IDBFactory();
});
enum MockKeyUploadEvent {
KeyUploaded = "KeyUploaded",
}
type MockKeyUploadEventHandlerMap = {
[MockKeyUploadEvent.KeyUploaded]: (roomId: string, sessionId: string, backupVersion: string) => void;
};
/*
* Test helper. Returns an event emitter that will emit an event every time fetchmock sees a request to backup a key.
*/
function mockUploadEmitter(
expectedVersion: string,
): TypedEventEmitter<MockKeyUploadEvent, MockKeyUploadEventHandlerMap> {
const emitter = new TypedEventEmitter();
fetchMock.put(
"path:/_matrix/client/v3/room_keys/keys",
(url, request) => {
const version = new URLSearchParams(new URL(url).search).get("version");
if (version != expectedVersion) {
return {
status: 403,
body: {
current_version: expectedVersion,
errcode: "M_WRONG_ROOM_KEYS_VERSION",
error: "Wrong backup version.",
},
};
}
const uploadPayload: IKeyBackup = JSON.parse(request.body?.toString() ?? "{}");
let count = 0;
for (const [roomId, value] of Object.entries(uploadPayload.rooms)) {
for (const sessionId of Object.keys(value.sessions)) {
emitter.emit(MockKeyUploadEvent.KeyUploaded, roomId, sessionId, version);
count++;
}
}
return {
status: 200,
body: {
count: count,
etag: "abcdefg",
},
};
},
{
overwriteRoutes: true,
},
);
return emitter;
}
describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backend: string, initCrypto: InitCrypto) => {
// oldBackendOnly is an alternative to `it` or `test` which will skip the test if we are running against the
// Rust backend. Once we have full support in the rust sdk, it will go away.
// const oldBackendOnly = backend === "rust-sdk" ? test.skip : test;
// const newBackendOnly = backend === "libolm" ? test.skip : test;
let aliceClient: MatrixClient;
/** an object which intercepts `/sync` requests on the test homeserver */
let syncResponder: SyncResponder;
/** an object which intercepts `/keys/upload` requests on the test homeserver */
let e2eKeyReceiver: E2EKeyReceiver;
/** an object which intercepts `/keys/query` requests on the test homeserver */
let e2eKeyResponder: E2EKeyResponder;
beforeEach(async () => {
jest.useFakeTimers();
// anything that we don't have a specific matcher for silently returns a 404
fetchMock.catch(404);
fetchMock.config.warnOnFallback = false;
mockInitialApiRequests(TEST_HOMESERVER_URL);
syncResponder = new SyncResponder(TEST_HOMESERVER_URL);
e2eKeyReceiver = new E2EKeyReceiver(TEST_HOMESERVER_URL);
e2eKeyResponder = new E2EKeyResponder(TEST_HOMESERVER_URL);
e2eKeyResponder.addDeviceKeys(testData.SIGNED_TEST_DEVICE_DATA);
e2eKeyResponder.addKeyReceiver(TEST_USER_ID, e2eKeyReceiver);
});
afterEach(async () => {
if (aliceClient !== undefined) {
await aliceClient.stopClient();
}
// Allow in-flight things to complete before we tear down the test
await jest.runAllTimersAsync();
fetchMock.mockReset();
jest.restoreAllMocks();
});
async function initTestClient(opts: Partial<ICreateClientOpts> = {}): Promise<MatrixClient> {
const client = createClient({
baseUrl: TEST_HOMESERVER_URL,
userId: TEST_USER_ID,
accessToken: "akjgkrgjs",
deviceId: TEST_DEVICE_ID,
...opts,
});
await initCrypto(client);
return client;
}
describe("Key backup check on UTD message", () => {
// sync response which contains an encrypted event
const SYNC_RESPONSE = {
next_batch: 1,
rooms: { join: { [ROOM_ID]: { timeline: { events: [testData.ENCRYPTED_EVENT] } } } },
};
const EXPECTED_URL =
[
"https://alice-server.com/_matrix/client/v3/room_keys/keys",
encodeURIComponent(testData.TEST_ROOM_ID),
encodeURIComponent(testData.MEGOLM_SESSION_DATA.session_id),
].join("/") + "?version=1";
/** Flush promises enough times to get the crypto stacks to make the backup request */
async function flushBackupRequest() {
// we have to run flushPromises lots of times. It seems like each time the rust code touches indexeddb,
// it needs another round of flushPromises to progress, or something.
for (let i = 0; i < 10; i++) {
await flushPromises();
}
}
beforeEach(async () => {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
// ignore requests to send room key requests
fetchMock.put("express:/_matrix/client/v3/sendToDevice/m.room_key_request/:request_id", {});
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceCrypto.storeSessionBackupPrivateKey(
Buffer.from(testData.BACKUP_DECRYPTION_KEY_BASE64, "base64"),
testData.SIGNED_BACKUP_DATA.version!,
);
// start after saving the private key
await aliceClient.startClient();
// tell Alice to trust the dummy device that signed the backup, and re-check the backup.
// XXX: should we automatically re-check after a device becomes verified?
await waitForDeviceList();
await aliceClient.getCrypto()!.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
await aliceClient.getCrypto()!.checkKeyBackupAndEnable();
});
it("Alice checks key backups when receiving a message she can't decrypt", async () => {
fetchMock.get("express:/_matrix/client/v3/room_keys/keys/:room_id/:session_id", (url, request) => {
// check that the version is correct
const version = new URLSearchParams(new URL(url).search).get("version");
if (version == "1") {
return testData.CURVE25519_KEY_BACKUP_DATA;
} else {
return {
status: 403,
body: {
current_version: "1",
errcode: "M_WRONG_ROOM_KEYS_VERSION",
error: "Wrong backup version.",
},
};
}
});
// Send Alice a message that she won't be able to decrypt, and check that she fetches the key from the backup.
syncResponder.sendOrQueueSyncResponse(SYNC_RESPONSE);
await syncPromise(aliceClient);
const room = aliceClient.getRoom(ROOM_ID)!;
const event = room.getLiveTimeline().getEvents()[0];
await advanceTimersUntil(awaitDecryption(event, { waitOnDecryptionFailure: true }));
expect(event.getContent()).toEqual(testData.CLEAR_EVENT.content);
});
it("handles error on backup query gracefully", async () => {
jest.spyOn(console, "error").mockImplementation(() => {});
fetchMock.get(
"express:/_matrix/client/v3/room_keys/keys/:room_id/:session_id",
{ status: 404, body: { errcode: "M_NOT_FOUND" } },
{ name: "getKey" },
);
// Send Alice a message that she won't be able to decrypt
syncResponder.sendOrQueueSyncResponse(SYNC_RESPONSE);
await flushBackupRequest();
const calls = fetchMock.calls("getKey");
expect(calls.length).toEqual(1);
expect(calls[0][0]).toEqual(EXPECTED_URL);
await flushBackupRequest();
// we should not have logged an error.
// eslint-disable-next-line no-console
expect(console.error).not.toHaveBeenCalled();
});
it("Only queries once", async () => {
fetchMock.get(
"express:/_matrix/client/v3/room_keys/keys/:room_id/:session_id",
{ status: 404, body: { errcode: "M_NOT_FOUND" } },
{ name: "getKey" },
);
// Send Alice a message that she won't be able to decrypt
syncResponder.sendOrQueueSyncResponse(SYNC_RESPONSE);
await flushBackupRequest();
const calls = fetchMock.calls("getKey");
expect(calls.length).toEqual(1);
expect(calls[0][0]).toEqual(EXPECTED_URL);
fetchMock.resetHistory();
// another message
const event2 = { ...testData.ENCRYPTED_EVENT, event_id: "$event2" };
const syncResponse2 = {
next_batch: 1,
rooms: { join: { [ROOM_ID]: { timeline: { events: [event2] } } } },
};
syncResponder.sendOrQueueSyncResponse(syncResponse2);
await flushBackupRequest();
expect(fetchMock.calls("getKey").length).toEqual(0);
});
});
describe("recover from backup", () => {
it("can restore from backup (Curve25519 version)", async function () {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
// tell Alice to trust the dummy device that signed the backup
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
const fullBackup = {
rooms: {
[ROOM_ID]: {
sessions: {
[testData.MEGOLM_SESSION_DATA.session_id]: testData.CURVE25519_KEY_BACKUP_DATA,
},
},
},
};
fetchMock.get("express:/_matrix/client/v3/room_keys/keys", fullBackup);
const check = await aliceCrypto.checkKeyBackupAndEnable();
let onKeyCached: () => void;
const awaitKeyCached = new Promise<void>((resolve) => {
onKeyCached = resolve;
});
const result = await advanceTimersUntil(
aliceClient.restoreKeyBackupWithRecoveryKey(
testData.BACKUP_DECRYPTION_KEY_BASE58,
undefined,
undefined,
check!.backupInfo!,
{
cacheCompleteCallback: () => onKeyCached(),
},
),
);
expect(result.imported).toStrictEqual(1);
await awaitKeyCached;
// The key should be now cached
const afterCache = await advanceTimersUntil(
aliceClient.restoreKeyBackupWithCache(undefined, undefined, check!.backupInfo!),
);
expect(afterCache.imported).toStrictEqual(1);
});
it("recover specific session from backup", async function () {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
// tell Alice to trust the dummy device that signed the backup
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
fetchMock.get(
"express:/_matrix/client/v3/room_keys/keys/:room_id/:session_id",
testData.CURVE25519_KEY_BACKUP_DATA,
);
const check = await aliceCrypto.checkKeyBackupAndEnable();
const result = await advanceTimersUntil(
aliceClient.restoreKeyBackupWithRecoveryKey(
testData.BACKUP_DECRYPTION_KEY_BASE58,
ROOM_ID,
testData.MEGOLM_SESSION_DATA.session_id,
check!.backupInfo!,
),
);
expect(result.imported).toStrictEqual(1);
});
it("Fails on bad recovery key", async function () {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
// tell Alice to trust the dummy device that signed the backup
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
const fullBackup = {
rooms: {
[ROOM_ID]: {
sessions: {
[testData.MEGOLM_SESSION_DATA.session_id]: testData.CURVE25519_KEY_BACKUP_DATA,
},
},
},
};
fetchMock.get("express:/_matrix/client/v3/room_keys/keys", fullBackup);
const check = await aliceCrypto.checkKeyBackupAndEnable();
await expect(
aliceClient.restoreKeyBackupWithRecoveryKey(
"EsTx A7Xn aNFF k3jH zpV3 MQoN LJEg mscC HecF 982L wC77 mYQD",
undefined,
undefined,
check!.backupInfo!,
),
).rejects.toThrow();
});
});
describe("backupLoop", () => {
it("Alice should upload known keys when backup is enabled", async function () {
// 404 means that there is no active backup
fetchMock.get("path:/_matrix/client/v3/room_keys/version", 404);
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
// tell Alice to trust the dummy device that signed the backup
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
// check that signalling is working
const remainingZeroPromise = new Promise<void>((resolve, reject) => {
aliceClient.on(CryptoEvent.KeyBackupSessionsRemaining, (remaining) => {
if (remaining == 0) {
resolve();
}
});
});
const someRoomKeys = testData.MEGOLM_SESSION_DATA_ARRAY;
const uploadMockEmitter = mockUploadEmitter(testData.SIGNED_BACKUP_DATA.version!);
const uploadPromises = someRoomKeys.map((data) => {
new Promise<void>((resolve) => {
uploadMockEmitter.on(MockKeyUploadEvent.KeyUploaded, (roomId, sessionId, version) => {
if (
data.room_id == roomId &&
data.session_id == sessionId &&
version == testData.SIGNED_BACKUP_DATA.version
) {
resolve();
}
});
});
});
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA, {
overwriteRoutes: true,
});
const result = await aliceCrypto.checkKeyBackupAndEnable();
expect(result).toBeTruthy();
await aliceCrypto.importRoomKeys(someRoomKeys);
// The backup loop is waiting a random amount of time to avoid different clients firing at the same time.
jest.runAllTimers();
await Promise.all(uploadPromises);
// Wait until all keys are backed up to ensure that when a new key is received the loop is restarted
await remainingZeroPromise;
// A new key import should trigger a new upload.
const newKey = testData.MEGOLM_SESSION_DATA;
const newKeyUploadPromise = new Promise<void>((resolve) => {
uploadMockEmitter.on(MockKeyUploadEvent.KeyUploaded, (roomId, sessionId, version) => {
if (
newKey.room_id == roomId &&
newKey.session_id == sessionId &&
version == testData.SIGNED_BACKUP_DATA.version
) {
resolve();
}
});
});
await aliceCrypto.importRoomKeys([newKey]);
jest.runAllTimers();
await newKeyUploadPromise;
});
it("Alice should re-upload all keys if a new trusted backup is available", async function () {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
// tell Alice to trust the dummy device that signed the backup
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
// check that signalling is working
const remainingZeroPromise = new Promise<void>((resolve) => {
aliceClient.on(CryptoEvent.KeyBackupSessionsRemaining, (remaining) => {
if (remaining == 0) {
resolve();
}
});
});
const someRoomKeys = testData.MEGOLM_SESSION_DATA_ARRAY;
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA, {
overwriteRoutes: true,
});
const result = await aliceCrypto.checkKeyBackupAndEnable();
expect(result).toBeTruthy();
mockUploadEmitter(testData.SIGNED_BACKUP_DATA.version!);
await aliceCrypto.importRoomKeys(someRoomKeys);
// The backup loop is waiting a random amount of time to avoid different clients firing at the same time.
jest.runAllTimers();
// wait for all keys to be backed up
await remainingZeroPromise;
const newBackupVersion = "2";
const uploadMockEmitter = mockUploadEmitter(newBackupVersion);
const newBackup = JSON.parse(JSON.stringify(testData.SIGNED_BACKUP_DATA));
newBackup.version = newBackupVersion;
// Let's simulate that a new backup is available by returning error code on key upload
fetchMock.get("path:/_matrix/client/v3/room_keys/version", newBackup, {
overwriteRoutes: true,
});
// If we import a new key the loop will try to upload to old version, it will
// fail then check the current version and switch if trusted
const uploadPromises = someRoomKeys.map((data) => {
new Promise<void>((resolve) => {
uploadMockEmitter.on(MockKeyUploadEvent.KeyUploaded, (roomId, sessionId, version) => {
if (data.room_id == roomId && data.session_id == sessionId && version == newBackupVersion) {
resolve();
}
});
});
});
const disableOldBackup = new Promise<void>((resolve) => {
aliceClient.on(CryptoEvent.KeyBackupFailed, (errCode) => {
if (errCode == "M_WRONG_ROOM_KEYS_VERSION") {
resolve();
}
});
});
const enableNewBackup = new Promise<void>((resolve) => {
aliceClient.on(CryptoEvent.KeyBackupStatus, (enabled) => {
if (enabled) {
resolve();
}
});
});
// A new key import should trigger a new upload.
const newKey = testData.MEGOLM_SESSION_DATA;
const newKeyUploadPromise = new Promise<void>((resolve) => {
uploadMockEmitter.on(MockKeyUploadEvent.KeyUploaded, (roomId, sessionId, version) => {
if (newKey.room_id == roomId && newKey.session_id == sessionId && version == newBackupVersion) {
resolve();
}
});
});
await aliceCrypto.importRoomKeys([newKey]);
jest.runAllTimers();
await disableOldBackup;
await enableNewBackup;
jest.runAllTimers();
await Promise.all(uploadPromises);
await newKeyUploadPromise;
});
it("Backup loop should be resistant to network failures", async function () {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
// tell Alice to trust the dummy device that signed the backup
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA, {
overwriteRoutes: true,
});
// on the first key upload attempt, simulate a network failure
const failurePromise = new Promise((resolve) => {
fetchMock.put(
"path:/_matrix/client/v3/room_keys/keys",
() => {
resolve(undefined);
throw new TypeError(`Failed to fetch`);
},
{
overwriteRoutes: true,
},
);
});
// kick the import loop off and wait for the failed request
const someRoomKeys = testData.MEGOLM_SESSION_DATA_ARRAY;
await aliceCrypto.importRoomKeys(someRoomKeys);
const result = await aliceCrypto.checkKeyBackupAndEnable();
expect(result).toBeTruthy();
jest.runAllTimers();
await failurePromise;
// Fix the endpoint to do successful uploads
const successPromise = new Promise((resolve) => {
fetchMock.put(
"path:/_matrix/client/v3/room_keys/keys",
() => {
resolve(undefined);
return {
status: 200,
body: {
count: 2,
etag: "abcdefg",
},
};
},
{
overwriteRoutes: true,
},
);
});
// check that a `KeyBackupSessionsRemaining` event is emitted with `remaining == 0`
const allKeysUploadedPromise = new Promise((resolve) => {
aliceClient.on(CryptoEvent.KeyBackupSessionsRemaining, (remaining) => {
if (remaining == 0) {
resolve(undefined);
}
});
});
// run the timers, which will make the backup loop redo the request
await jest.runAllTimersAsync();
await successPromise;
await allKeysUploadedPromise;
});
});
it("getActiveSessionBackupVersion() should give correct result", async function () {
// 404 means that there is no active backup
fetchMock.get("express:/_matrix/client/v3/room_keys/version", 404);
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
// tell Alice to trust the dummy device that signed the backup
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
await aliceCrypto.checkKeyBackupAndEnable();
// At this point there is no backup
let backupStatus: string | null;
backupStatus = await aliceCrypto.getActiveSessionBackupVersion();
expect(backupStatus).toBeNull();
// Serve a backup with no trusted signature
const unsignedBackup = JSON.parse(JSON.stringify(testData.SIGNED_BACKUP_DATA));
delete unsignedBackup.auth_data.signatures;
fetchMock.get("express:/_matrix/client/v3/room_keys/version", unsignedBackup, {
overwriteRoutes: true,
});
const checked = await aliceCrypto.checkKeyBackupAndEnable();
expect(checked?.backupInfo?.version).toStrictEqual(unsignedBackup.version);
expect(checked?.trustInfo?.trusted).toBeFalsy();
backupStatus = await aliceCrypto.getActiveSessionBackupVersion();
expect(backupStatus).toBeNull();
// Add a valid signature to the backup
fetchMock.get("express:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA, {
overwriteRoutes: true,
});
// check that signalling is working
const backupPromise = new Promise<void>((resolve, reject) => {
aliceClient.on(CryptoEvent.KeyBackupStatus, (enabled) => {
if (enabled) {
resolve();
}
});
});
const validCheck = await aliceCrypto.checkKeyBackupAndEnable();
expect(validCheck?.trustInfo?.trusted).toStrictEqual(true);
await backupPromise;
backupStatus = await aliceCrypto.getActiveSessionBackupVersion();
expect(backupStatus).toStrictEqual(testData.SIGNED_BACKUP_DATA.version);
});
describe("isKeyBackupTrusted", () => {
it("does not trust a backup signed by an untrusted device", async () => {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
// download the device list, to match the trusted case
await aliceClient.startClient();
await waitForDeviceList();
const result = await aliceCrypto.isKeyBackupTrusted(testData.SIGNED_BACKUP_DATA);
expect(result).toEqual({ trusted: false, matchesDecryptionKey: false });
});
it("trusts a backup signed by a trusted device", async () => {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
// tell Alice to trust the dummy device that signed the backup
await aliceClient.startClient();
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
const result = await aliceCrypto.isKeyBackupTrusted(testData.SIGNED_BACKUP_DATA);
expect(result).toEqual({ trusted: true, matchesDecryptionKey: false });
});
it("recognises a backup which matches the decryption key", async () => {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
await aliceCrypto.storeSessionBackupPrivateKey(
Buffer.from(testData.BACKUP_DECRYPTION_KEY_BASE64, "base64"),
testData.SIGNED_BACKUP_DATA.version!,
);
const result = await aliceCrypto.isKeyBackupTrusted(testData.SIGNED_BACKUP_DATA);
expect(result).toEqual({ trusted: false, matchesDecryptionKey: true });
});
it("is not fooled by a backup which matches the decryption key but uses a different algorithm", async () => {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
await aliceCrypto.storeSessionBackupPrivateKey(
Buffer.from(testData.BACKUP_DECRYPTION_KEY_BASE64, "base64"),
testData.SIGNED_BACKUP_DATA.version!,
);
const backup: KeyBackupInfo = JSON.parse(JSON.stringify(testData.SIGNED_BACKUP_DATA));
backup.algorithm = "m.megolm_backup.v1.aes-hmac-sha2";
const result = await aliceCrypto.isKeyBackupTrusted(backup);
expect(result).toEqual({ trusted: false, matchesDecryptionKey: false });
});
});
describe("checkKeyBackupAndEnable", () => {
it("enables a backup signed by a trusted device", async () => {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
// tell Alice to trust the dummy device that signed the backup
await aliceClient.startClient();
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
const result = await aliceCrypto.checkKeyBackupAndEnable();
expect(result).toBeTruthy();
expect(result!.trustInfo).toEqual({ trusted: true, matchesDecryptionKey: false });
expect(await aliceCrypto.getActiveSessionBackupVersion()).toEqual(testData.SIGNED_BACKUP_DATA.version);
});
it("does not enable a backup signed by an untrusted device", async () => {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
// download the device list, to match the trusted case
await aliceClient.startClient();
await waitForDeviceList();
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
const result = await aliceCrypto.checkKeyBackupAndEnable();
expect(result).toBeTruthy();
expect(result!.trustInfo).toEqual({ trusted: false, matchesDecryptionKey: false });
expect(await aliceCrypto.getActiveSessionBackupVersion()).toBeNull();
});
it("disables backup when a new untrusted backup is available", async () => {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
// tell Alice to trust the dummy device that signed the backup
await aliceClient.startClient();
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
const result = await aliceCrypto.checkKeyBackupAndEnable();
expect(result).toBeTruthy();
expect(await aliceCrypto.getActiveSessionBackupVersion()).toEqual(testData.SIGNED_BACKUP_DATA.version);
const unsignedBackup = JSON.parse(JSON.stringify(testData.SIGNED_BACKUP_DATA));
delete unsignedBackup.auth_data.signatures;
unsignedBackup.version = "2";
fetchMock.get("path:/_matrix/client/v3/room_keys/version", unsignedBackup, {
overwriteRoutes: true,
});
await aliceCrypto.checkKeyBackupAndEnable();
expect(await aliceCrypto.getActiveSessionBackupVersion()).toBeNull();
});
it("switches backup when a new trusted backup is available", async () => {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
// tell Alice to trust the dummy device that signed the backup
await aliceClient.startClient();
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
const result = await aliceCrypto.checkKeyBackupAndEnable();
expect(result).toBeTruthy();
expect(await aliceCrypto.getActiveSessionBackupVersion()).toEqual(testData.SIGNED_BACKUP_DATA.version);
const newBackupVersion = "2";
const newBackup = JSON.parse(JSON.stringify(testData.SIGNED_BACKUP_DATA));
newBackup.version = newBackupVersion;
fetchMock.get("path:/_matrix/client/v3/room_keys/version", newBackup, {
overwriteRoutes: true,
});
await aliceCrypto.checkKeyBackupAndEnable();
expect(await aliceCrypto.getActiveSessionBackupVersion()).toEqual(newBackupVersion);
});
it("Disables when backup is deleted", async () => {
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
// tell Alice to trust the dummy device that signed the backup
await aliceClient.startClient();
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
const result = await aliceCrypto.checkKeyBackupAndEnable();
expect(result).toBeTruthy();
expect(await aliceCrypto.getActiveSessionBackupVersion()).toEqual(testData.SIGNED_BACKUP_DATA.version);
fetchMock.get(
"path:/_matrix/client/v3/room_keys/version",
{
status: 404,
body: {
errcode: "M_NOT_FOUND",
error: "No backup found",
},
},
{
overwriteRoutes: true,
},
);
const noResult = await aliceCrypto.checkKeyBackupAndEnable();
expect(noResult).toBeNull();
expect(await aliceCrypto.getActiveSessionBackupVersion()).toBeNull();
});
});
/** make sure that the client knows about the dummy device */
async function waitForDeviceList(): Promise<void> {
// Completing the initial sync will make the device list download outdated device lists (of which our own
// user will be one).
syncResponder.sendOrQueueSyncResponse({});
// DeviceList has a sleep(5) which we need to make happen
await jest.advanceTimersByTimeAsync(10);
// The client should now know about the dummy device
const devices = await aliceClient.getCrypto()!.getUserDeviceInfo([TEST_USER_ID]);
expect(devices.get(TEST_USER_ID)!.keys()).toContain(TEST_DEVICE_ID);
}
});
@@ -22,18 +22,20 @@ limitations under the License.
*
* Note that megolm (group) conversation is not tested here.
*
* See also `megolm.spec.js`.
* See also `crypto.spec.js`.
*/
// load olm before the sdk if possible
import '../olm-loader';
import "../../olm-loader";
import { logger } from '../../src/logger';
import * as testUtils from "../test-utils/test-utils";
import { TestClient } from "../TestClient";
import { CRYPTO_ENABLED, IUploadKeysRequest } from "../../src/client";
import { ClientEvent, IContent, ISendEventResponse, MatrixClient, MatrixEvent } from "../../src/matrix";
import { DeviceInfo } from '../../src/crypto/deviceinfo';
import type { Session } from "@matrix-org/olm";
import type { IDeviceKeys, IOneTimeKey } from "../../../src/@types/crypto";
import { logger } from "../../../src/logger";
import * as testUtils from "../../test-utils/test-utils";
import { TestClient } from "../../TestClient";
import { CRYPTO_ENABLED, IClaimKeysRequest, IQueryKeysRequest, IUploadKeysRequest } from "../../../src/client";
import { ClientEvent, IContent, ISendEventResponse, MatrixClient, MatrixEvent } from "../../../src/matrix";
import { DeviceInfo } from "../../../src/crypto/deviceinfo";
let aliTestClient: TestClient;
const roomId = "!room:localhost";
@@ -47,39 +49,31 @@ const bobAccessToken = "fewgfkuesa";
let aliMessages: IContent[];
let bobMessages: IContent[];
// IMessage isn't exported by src/crypto/algorithms/olm.ts
interface OlmPayload {
type: number;
body: string;
}
type OlmPayload = ReturnType<Session["encrypt"]>;
async function bobUploadsDeviceKeys(): Promise<void> {
bobTestClient.expectDeviceKeyUpload();
await Promise.all([
bobTestClient.client.uploadKeys(),
bobTestClient.httpBackend.flushAllExpected(),
]);
expect(Object.keys(bobTestClient.deviceKeys).length).not.toEqual(0);
await bobTestClient.httpBackend.flushAllExpected();
expect(Object.keys(bobTestClient.deviceKeys!).length).not.toEqual(0);
}
/**
* Set an expectation that querier will query uploader's keys; then flush the http request.
*
* @return {promise} resolves once the http request has completed.
* @returns resolves once the http request has completed.
*/
function expectQueryKeys(querier: TestClient, uploader: TestClient): Promise<number> {
// can't query keys before bob has uploaded them
expect(uploader.deviceKeys).toBeTruthy();
const uploaderKeys = {};
uploaderKeys[uploader.deviceId!] = uploader.deviceKeys;
querier.httpBackend.when("POST", "/keys/query")
.respond(200, function(_path, content: IUploadKeysRequest) {
expect(content.device_keys![uploader.userId!]).toEqual([]);
const result = {};
result[uploader.userId!] = uploaderKeys;
return { device_keys: result };
});
const uploaderKeys: Record<string, IDeviceKeys> = {};
uploaderKeys[uploader.deviceId!] = uploader.deviceKeys!;
querier.httpBackend.when("POST", "/keys/query").respond(200, function (_path, content: IQueryKeysRequest) {
expect(content.device_keys![uploader.userId!]).toEqual([]);
const result: Record<string, Record<string, IDeviceKeys>> = {};
result[uploader.userId!] = uploaderKeys;
return { device_keys: result };
});
return querier.httpBackend.flush("/keys/query", 1);
}
const expectAliQueryKeys = () => expectQueryKeys(aliTestClient, bobTestClient);
@@ -88,24 +82,22 @@ const expectBobQueryKeys = () => expectQueryKeys(bobTestClient, aliTestClient);
/**
* Set an expectation that ali will claim one of bob's keys; then flush the http request.
*
* @return {promise} resolves once the http request has completed.
* @returns resolves once the http request has completed.
*/
async function expectAliClaimKeys(): Promise<void> {
const keys = await bobTestClient.awaitOneTimeKeyUpload();
aliTestClient.httpBackend.when(
"POST", "/keys/claim",
).respond(200, function(_path, content: IUploadKeysRequest) {
aliTestClient.httpBackend.when("POST", "/keys/claim").respond(200, function (_path, content: IClaimKeysRequest) {
const claimType = content.one_time_keys![bobUserId][bobDeviceId];
expect(claimType).toEqual("signed_curve25519");
let keyId = '';
let keyId = "";
for (keyId in keys) {
if (bobTestClient.oneTimeKeys.hasOwnProperty(keyId)) {
if (bobTestClient.oneTimeKeys!.hasOwnProperty(keyId)) {
if (keyId.indexOf(claimType + ":") === 0) {
break;
}
}
}
const result = {};
const result: Record<string, Record<string, Record<string, IOneTimeKey>>> = {};
result[bobUserId] = {};
result[bobUserId][bobDeviceId] = {};
result[bobUserId][bobDeviceId][keyId] = keys[keyId];
@@ -137,9 +129,8 @@ async function aliDownloadsKeys(): Promise<void> {
// @ts-ignore - protected
aliTestClient.client.cryptoStore.getEndToEndDeviceData(null, (data) => {
const devices = data!.devices[bobUserId]!;
expect(devices[bobDeviceId].keys).toEqual(bobTestClient.deviceKeys.keys);
expect(devices[bobDeviceId].verified).
toBe(DeviceInfo.DeviceVerification.UNVERIFIED);
expect(devices[bobDeviceId].keys).toEqual(bobTestClient.deviceKeys!.keys);
expect(devices[bobDeviceId].verified).toBe(DeviceInfo.DeviceVerification.UNVERIFIED);
});
}
@@ -156,15 +147,13 @@ const bobEnablesEncryption = () => clientEnablesEncryption(bobTestClient.client)
* Ali sends a message, first claiming e2e keys. Set the expectations and
* check the results.
*
* @return {promise} which resolves to the ciphertext for Bob's device.
* @returns which resolves to the ciphertext for Bob's device.
*/
async function aliSendsFirstMessage(): Promise<OlmPayload> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_, ciphertext] = await Promise.all([
sendMessage(aliTestClient.client),
expectAliQueryKeys()
.then(expectAliClaimKeys)
.then(expectAliSendMessageRequest),
expectAliQueryKeys().then(expectAliClaimKeys).then(expectAliSendMessageRequest),
]);
return ciphertext;
}
@@ -173,14 +162,11 @@ async function aliSendsFirstMessage(): Promise<OlmPayload> {
* Ali sends a message without first claiming e2e keys. Set the expectations
* and check the results.
*
* @return {promise} which resolves to the ciphertext for Bob's device.
* @returns which resolves to the ciphertext for Bob's device.
*/
async function aliSendsMessage(): Promise<OlmPayload> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_, ciphertext] = await Promise.all([
sendMessage(aliTestClient.client),
expectAliSendMessageRequest(),
]);
const [_, ciphertext] = await Promise.all([sendMessage(aliTestClient.client), expectAliSendMessageRequest()]);
return ciphertext;
}
@@ -188,14 +174,13 @@ async function aliSendsMessage(): Promise<OlmPayload> {
* Bob sends a message, first querying (but not claiming) e2e keys. Set the
* expectations and check the results.
*
* @return {promise} which resolves to the ciphertext for Ali's device.
* @returns which resolves to the ciphertext for Ali's device.
*/
async function bobSendsReplyMessage(): Promise<OlmPayload> {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [_, ciphertext] = await Promise.all([
sendMessage(bobTestClient.client),
expectBobQueryKeys()
.then(expectBobSendMessageRequest),
expectBobQueryKeys().then(expectBobSendMessageRequest),
]);
return ciphertext;
}
@@ -203,7 +188,7 @@ async function bobSendsReplyMessage(): Promise<OlmPayload> {
/**
* Set an expectation that Ali will send a message, and flush the request
*
* @return {promise} which resolves to the ciphertext for Bob's device.
* @returns which resolves to the ciphertext for Bob's device.
*/
async function expectAliSendMessageRequest(): Promise<OlmPayload> {
const content = await expectSendMessageRequest(aliTestClient.httpBackend);
@@ -217,13 +202,13 @@ async function expectAliSendMessageRequest(): Promise<OlmPayload> {
/**
* Set an expectation that Bob will send a message, and flush the request
*
* @return {promise} which resolves to the ciphertext for Bob's device.
* @returns which resolves to the ciphertext for Bob's device.
*/
async function expectBobSendMessageRequest(): Promise<OlmPayload> {
const content = await expectSendMessageRequest(bobTestClient.httpBackend);
bobMessages.push(content);
const aliKeyId = "curve25519:" + aliDeviceId;
const aliDeviceCurve25519Key = aliTestClient.deviceKeys.keys[aliKeyId];
const aliDeviceCurve25519Key = aliTestClient.deviceKeys!.keys[aliKeyId];
expect(Object.keys(content.ciphertext)).toEqual([aliDeviceCurve25519Key]);
const ciphertext = content.ciphertext[aliDeviceCurve25519Key];
expect(ciphertext).toBeTruthy();
@@ -231,15 +216,13 @@ async function expectBobSendMessageRequest(): Promise<OlmPayload> {
}
function sendMessage(client: MatrixClient): Promise<ISendEventResponse> {
return client.sendMessage(
roomId, { msgtype: "m.text", body: "Hello, World" },
);
return client.sendMessage(roomId, { msgtype: "m.text", body: "Hello, World" });
}
async function expectSendMessageRequest(httpBackend: TestClient["httpBackend"]): Promise<IContent> {
const path = "/send/m.room.encrypted/";
const prom = new Promise<IContent>((resolve) => {
httpBackend.when("PUT", path).respond(200, function(_path, content) {
httpBackend.when("PUT", path).respond(200, function (_path, content) {
resolve(content);
return {
event_id: "asdfgh",
@@ -254,16 +237,12 @@ async function expectSendMessageRequest(httpBackend: TestClient["httpBackend"]):
function aliRecvMessage(): Promise<void> {
const message = bobMessages.shift()!;
return recvMessage(
aliTestClient.httpBackend, aliTestClient.client, bobUserId, message,
);
return recvMessage(aliTestClient.httpBackend, aliTestClient.client, bobUserId, message);
}
function bobRecvMessage(): Promise<void> {
const message = aliMessages.shift()!;
return recvMessage(
bobTestClient.httpBackend, bobTestClient.client, aliUserId, message,
);
return recvMessage(bobTestClient.httpBackend, bobTestClient.client, aliUserId, message);
}
async function recvMessage(
@@ -276,32 +255,30 @@ async function recvMessage(
next_batch: "x",
rooms: {
join: {
[roomId]: {
timeline: {
events: [
testUtils.mkEvent({
type: "m.room.encrypted",
room: roomId,
content: message,
sender: sender,
}),
],
},
},
},
},
};
syncData.rooms.join[roomId] = {
timeline: {
events: [
testUtils.mkEvent({
type: "m.room.encrypted",
room: roomId,
content: message,
sender: sender,
}),
],
},
};
httpBackend.when("GET", "/sync").respond(200, syncData);
const eventPromise = new Promise<MatrixEvent>((resolve) => {
const onEvent = function(event: MatrixEvent) {
const onEvent = function (event: MatrixEvent) {
// ignore the m.room.member events
if (event.getType() == "m.room.member") {
return;
}
logger.log(client.credentials.userId + " received event",
event);
logger.log(client.credentials.userId + " received event", event);
client.removeListener(ClientEvent.Event, onEvent);
resolve(event);
@@ -327,32 +304,32 @@ async function recvMessage(
* Send an initial sync response to the client (which just includes the member
* list for our test room).
*
* @param {TestClient} testClient
* @returns {Promise} which resolves when the sync has been flushed.
* @returns which resolves when the sync has been flushed.
*/
function firstSync(testClient: TestClient): Promise<void> {
// send a sync response including our test room.
const syncData = {
next_batch: "x",
rooms: {
join: { },
},
};
syncData.rooms.join[roomId] = {
state: {
events: [
testUtils.mkMembership({
mship: "join",
user: aliUserId,
}),
testUtils.mkMembership({
mship: "join",
user: bobUserId,
}),
],
},
timeline: {
events: [],
join: {
[roomId]: {
state: {
events: [
testUtils.mkMembership({
mship: "join",
user: aliUserId,
}),
testUtils.mkMembership({
mship: "join",
user: bobUserId,
}),
],
},
timeline: {
events: [],
},
},
},
},
};
@@ -385,6 +362,13 @@ describe("MatrixClient crypto", () => {
it("Bob uploads device keys", bobUploadsDeviceKeys);
it("handles failures to upload device keys", async () => {
// since device keys are uploaded asynchronously, there's not really much to do here other than fail the
// upload.
bobTestClient.httpBackend.when("POST", "/keys/upload").fail(0, new Error("bleh"));
await bobTestClient.httpBackend.flushAllExpected();
});
it("Ali downloads Bobs device keys", async () => {
await bobUploadsDeviceKeys();
await aliDownloadsKeys();
@@ -393,13 +377,10 @@ describe("MatrixClient crypto", () => {
it("Ali gets keys with an invalid signature", async () => {
await bobUploadsDeviceKeys();
// tamper bob's keys
const bobDeviceKeys = bobTestClient.deviceKeys;
const bobDeviceKeys = bobTestClient.deviceKeys!;
expect(bobDeviceKeys.keys["curve25519:" + bobDeviceId]).toBeTruthy();
bobDeviceKeys.keys["curve25519:" + bobDeviceId] += "abc";
await Promise.all([
aliTestClient.client.downloadKeys([bobUserId]),
expectAliQueryKeys(),
]);
await Promise.all([aliTestClient.client.downloadKeys([bobUserId]), expectAliQueryKeys()]);
const devices = aliTestClient.client.getStoredDevicesForUser(bobUserId);
// should get an empty list
expect(devices).toEqual([]);
@@ -409,26 +390,24 @@ describe("MatrixClient crypto", () => {
const eveUserId = "@eve:localhost";
const bobDeviceKeys = {
algorithms: ['m.olm.v1.curve25519-aes-sha2', 'm.megolm.v1.aes-sha2'],
device_id: 'bvcxz',
algorithms: ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
device_id: "bvcxz",
keys: {
'ed25519:bvcxz': 'pYuWKMCVuaDLRTM/eWuB8OlXEb61gZhfLVJ+Y54tl0Q',
'curve25519:bvcxz': '7Gni0loo/nzF0nFp9847RbhElGewzwUXHPrljjBGPTQ',
"ed25519:bvcxz": "pYuWKMCVuaDLRTM/eWuB8OlXEb61gZhfLVJ+Y54tl0Q",
"curve25519:bvcxz": "7Gni0loo/nzF0nFp9847RbhElGewzwUXHPrljjBGPTQ",
},
user_id: '@eve:localhost',
user_id: "@eve:localhost",
signatures: {
'@eve:localhost': {
'ed25519:bvcxz': 'CliUPZ7dyVPBxvhSA1d+X+LYa5b2AYdjcTwG' +
'0stXcIxjaJNemQqtdgwKDtBFl3pN2I13SEijRDCf1A8bYiQMDg',
"@eve:localhost": {
"ed25519:bvcxz":
"CliUPZ7dyVPBxvhSA1d+X+LYa5b2AYdjcTwG" + "0stXcIxjaJNemQqtdgwKDtBFl3pN2I13SEijRDCf1A8bYiQMDg",
},
},
};
const bobKeys = {};
const bobKeys: Record<string, typeof bobDeviceKeys> = {};
bobKeys[bobDeviceId] = bobDeviceKeys;
aliTestClient.httpBackend.when(
"POST", "/keys/query",
).respond(200, { device_keys: { [bobUserId]: bobKeys } });
aliTestClient.httpBackend.when("POST", "/keys/query").respond(200, { device_keys: { [bobUserId]: bobKeys } });
await Promise.all([
aliTestClient.client.downloadKeys([bobUserId, eveUserId]),
@@ -445,26 +424,24 @@ describe("MatrixClient crypto", () => {
it("Ali gets keys with an incorrect deviceId", async () => {
const bobDeviceKeys = {
algorithms: ['m.olm.v1.curve25519-aes-sha2', 'm.megolm.v1.aes-sha2'],
device_id: 'bad_device',
algorithms: ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
device_id: "bad_device",
keys: {
'ed25519:bad_device': 'e8XlY5V8x2yJcwa5xpSzeC/QVOrU+D5qBgyTK0ko+f0',
'curve25519:bad_device': 'YxuuLG/4L5xGeP8XPl5h0d7DzyYVcof7J7do+OXz0xc',
"ed25519:bad_device": "e8XlY5V8x2yJcwa5xpSzeC/QVOrU+D5qBgyTK0ko+f0",
"curve25519:bad_device": "YxuuLG/4L5xGeP8XPl5h0d7DzyYVcof7J7do+OXz0xc",
},
user_id: '@bob:localhost',
user_id: "@bob:localhost",
signatures: {
'@bob:localhost': {
'ed25519:bad_device': 'fEFTq67RaSoIEVBJ8DtmRovbwUBKJ0A' +
'me9m9PDzM9azPUwZ38Xvf6vv1A7W1PSafH4z3Y2ORIyEnZgHaNby3CQ',
"@bob:localhost": {
"ed25519:bad_device":
"fEFTq67RaSoIEVBJ8DtmRovbwUBKJ0A" + "me9m9PDzM9azPUwZ38Xvf6vv1A7W1PSafH4z3Y2ORIyEnZgHaNby3CQ",
},
},
};
const bobKeys = {};
const bobKeys: Record<string, typeof bobDeviceKeys> = {};
bobKeys[bobDeviceId] = bobDeviceKeys;
aliTestClient.httpBackend.when(
"POST", "/keys/query",
).respond(200, { device_keys: { [bobUserId]: bobKeys } });
aliTestClient.httpBackend.when("POST", "/keys/query").respond(200, { device_keys: { [bobUserId]: bobKeys } });
await Promise.all([
aliTestClient.client.downloadKeys([bobUserId]),
@@ -479,7 +456,7 @@ describe("MatrixClient crypto", () => {
await bobTestClient.start();
const keys = await bobTestClient.awaitOneTimeKeyUpload();
expect(Object.keys(keys).length).toEqual(5);
expect(Object.keys(bobTestClient.deviceKeys).length).not.toEqual(0);
expect(Object.keys(bobTestClient.deviceKeys!).length).not.toEqual(0);
});
it("Ali sends a message", async () => {
@@ -495,7 +472,7 @@ describe("MatrixClient crypto", () => {
aliTestClient.expectKeyQuery({ device_keys: { [aliUserId]: {} }, failures: {} });
await aliTestClient.start();
await bobTestClient.start();
bobTestClient.client.crypto!.deviceList.downloadKeys = () => Promise.resolve({});
bobTestClient.client.crypto!.deviceList.downloadKeys = () => Promise.resolve(new Map());
await firstSync(aliTestClient);
await aliEnablesEncryption();
await aliSendsFirstMessage();
@@ -506,7 +483,7 @@ describe("MatrixClient crypto", () => {
aliTestClient.expectKeyQuery({ device_keys: { [aliUserId]: {} }, failures: {} });
await aliTestClient.start();
await bobTestClient.start();
bobTestClient.client.crypto!.deviceList.downloadKeys = () => Promise.resolve({});
bobTestClient.client.crypto!.deviceList.downloadKeys = () => Promise.resolve(new Map());
await firstSync(aliTestClient);
await aliEnablesEncryption();
await aliSendsFirstMessage();
@@ -515,26 +492,25 @@ describe("MatrixClient crypto", () => {
next_batch: "x",
rooms: {
join: {
[roomId]: {
timeline: {
events: [
testUtils.mkEvent({
type: "m.room.encrypted",
room: roomId,
content: message,
sender: "@bogus:sender",
}),
],
},
},
},
},
};
syncData.rooms.join[roomId] = {
timeline: {
events: [
testUtils.mkEvent({
type: "m.room.encrypted",
room: roomId,
content: message,
sender: "@bogus:sender",
}),
],
},
};
bobTestClient.httpBackend.when("GET", "/sync").respond(200, syncData);
const eventPromise = new Promise<MatrixEvent>((resolve) => {
const onEvent = function(event: MatrixEvent) {
const onEvent = function (event: MatrixEvent) {
logger.log(bobUserId + " received event", event);
resolve(event);
};
@@ -558,11 +534,10 @@ describe("MatrixClient crypto", () => {
await aliDownloadsKeys();
aliTestClient.client.setDeviceBlocked(bobUserId, bobDeviceId, true);
const p1 = sendMessage(aliTestClient.client);
const p2 = expectSendMessageRequest(aliTestClient.httpBackend)
.then(function(sentContent) {
// no unblocked devices, so the ciphertext should be empty
expect(sentContent.ciphertext).toEqual({});
});
const p2 = expectSendMessageRequest(aliTestClient.httpBackend).then(function (sentContent) {
// no unblocked devices, so the ciphertext should be empty
expect(sentContent.ciphertext).toEqual({});
});
await Promise.all([p1, p2]);
});
@@ -570,7 +545,7 @@ describe("MatrixClient crypto", () => {
aliTestClient.expectKeyQuery({ device_keys: { [aliUserId]: {} }, failures: {} });
await aliTestClient.start();
await bobTestClient.start();
bobTestClient.client.crypto!.deviceList.downloadKeys = () => Promise.resolve({});
bobTestClient.client.crypto!.deviceList.downloadKeys = () => Promise.resolve(new Map());
await firstSync(aliTestClient);
await aliEnablesEncryption();
await aliSendsFirstMessage();
@@ -588,9 +563,7 @@ describe("MatrixClient crypto", () => {
await firstSync(bobTestClient);
await aliEnablesEncryption();
await aliSendsFirstMessage();
bobTestClient.httpBackend.when('POST', '/keys/query').respond(
200, {},
);
bobTestClient.httpBackend.when("POST", "/keys/query").respond(200, {});
await bobRecvMessage();
await bobEnablesEncryption();
const ciphertext = await bobSendsReplyMessage();
@@ -605,28 +578,28 @@ describe("MatrixClient crypto", () => {
await aliTestClient.start();
await firstSync(aliTestClient);
const syncData = {
next_batch: '2',
next_batch: "2",
rooms: {
join: {},
},
};
syncData.rooms.join[roomId] = {
state: {
events: [
testUtils.mkEvent({
type: 'm.room.encryption',
skey: '',
content: {
algorithm: 'm.olm.v1.curve25519-aes-sha2',
join: {
[roomId]: {
state: {
events: [
testUtils.mkEvent({
type: "m.room.encryption",
skey: "",
content: {
algorithm: "m.olm.v1.curve25519-aes-sha2",
},
}),
],
},
}),
],
},
},
},
};
aliTestClient.httpBackend.when('GET', '/sync').respond(
200, syncData);
await aliTestClient.httpBackend.flush('/sync', 1);
aliTestClient.httpBackend.when("GET", "/sync").respond(200, syncData);
await aliTestClient.httpBackend.flush("/sync", 1);
aliTestClient.expectKeyQuery({
device_keys: {
[bobUserId]: {},
@@ -649,7 +622,7 @@ describe("MatrixClient crypto", () => {
// enqueue expectations:
// * Sync with empty one_time_keys => upload keys
logger.log(aliTestClient + ': starting');
logger.log(aliTestClient + ": starting");
httpBackend.when("GET", "/versions").respond(200, {});
httpBackend.when("GET", "/pushrules").respond(200, {});
httpBackend.when("POST", "/filter").respond(200, { filter_id: "fid" });
@@ -659,24 +632,61 @@ describe("MatrixClient crypto", () => {
// it will upload one-time keys.
httpBackend.when("GET", "/sync").respond(200, syncDataEmpty);
await Promise.all([
aliTestClient.client.startClient({}),
httpBackend.flushAllExpected(),
]);
logger.log(aliTestClient + ': started');
httpBackend.when("POST", "/keys/upload")
.respond(200, (_path, content: IUploadKeysRequest) => {
expect(content.one_time_keys).toBeTruthy();
expect(content.one_time_keys).not.toEqual({});
expect(Object.keys(content.one_time_keys!).length).toBeGreaterThanOrEqual(1);
// cancel futher calls by telling the client
// we have more than we need
return {
one_time_key_counts: {
signed_curve25519: 70,
},
};
});
await Promise.all([aliTestClient.client.startClient({}), httpBackend.flushAllExpected()]);
logger.log(aliTestClient + ": started");
httpBackend.when("POST", "/keys/upload").respond(200, (_path, content: IUploadKeysRequest) => {
expect(content.one_time_keys).toBeTruthy();
expect(content.one_time_keys).not.toEqual({});
expect(Object.keys(content.one_time_keys!).length).toBeGreaterThanOrEqual(1);
// cancel futher calls by telling the client
// we have more than we need
return {
one_time_key_counts: {
signed_curve25519: 70,
},
};
});
await httpBackend.flushAllExpected();
});
it("Checks for outgoing room key requests for a given event's session", async () => {
const eventA0 = new MatrixEvent({
sender: "@bob:example.com",
room_id: "!someroom",
content: {
algorithm: "m.megolm.v1.aes-sha2",
session_id: "sessionid",
sender_key: "senderkey",
},
});
const eventA1 = new MatrixEvent({
sender: "@bob:example.com",
room_id: "!someroom",
content: {
algorithm: "m.megolm.v1.aes-sha2",
session_id: "sessionid",
sender_key: "senderkey",
},
});
const eventB = new MatrixEvent({
sender: "@bob:example.com",
room_id: "!someroom",
content: {
algorithm: "m.megolm.v1.aes-sha2",
session_id: "othersessionid",
sender_key: "senderkey",
},
});
const nonEncryptedEvent = new MatrixEvent({
sender: "@bob:example.com",
room_id: "!someroom",
content: {},
});
aliTestClient.client.crypto?.onSyncCompleted({});
await aliTestClient.client.cancelAndResendEventRoomKeyRequest(eventA0);
expect(await aliTestClient.client.getOutgoingRoomKeyRequest(eventA1)).not.toBeNull();
expect(await aliTestClient.client.getOutgoingRoomKeyRequest(eventB)).toBeNull();
expect(await aliTestClient.client.getOutgoingRoomKeyRequest(nonEncryptedEvent)).toBeNull();
});
});
+408
View File
@@ -0,0 +1,408 @@
/*
Copyright 2016-2023 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 Olm from "@matrix-org/olm";
import anotherjson from "another-json";
import { IContent, IDeviceKeys, IDownloadKeyResult, IEvent, Keys, MatrixClient, SigningKeys } from "../../../src";
import { IE2EKeyReceiver } from "../../test-utils/E2EKeyReceiver";
import { ISyncResponder } from "../../test-utils/SyncResponder";
import { syncPromise } from "../../test-utils/test-utils";
import { KeyBackupInfo } from "../../../src/crypto-api";
/**
* @module
*
* A set of utilities for creating Olm accounts and sessions, and encrypting/decrypting with Olm/Megolm.
*/
/** Create an Olm Account object */
export async function createOlmAccount(): Promise<Olm.Account> {
await Olm.init();
const testOlmAccount = new Olm.Account();
testOlmAccount.create();
return testOlmAccount;
}
/**
* Get the device keys for the test Olm Account
*
* @param olmAccount - Test olm account
* @param userId - The user ID to present the keys as belonging to
*/
export function getTestOlmAccountKeys(olmAccount: Olm.Account, userId: string, deviceId: string): IDeviceKeys {
const testE2eKeys = JSON.parse(olmAccount.identity_keys());
const testDeviceKeys: IDeviceKeys = {
algorithms: ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
device_id: deviceId,
keys: {
[`curve25519:${deviceId}`]: testE2eKeys.curve25519,
[`ed25519:${deviceId}`]: testE2eKeys.ed25519,
},
user_id: userId,
};
const j = anotherjson.stringify(testDeviceKeys);
const sig = olmAccount.sign(j);
testDeviceKeys.signatures = { [userId]: { [`ed25519:${deviceId}`]: sig } };
return testDeviceKeys;
}
/**
* Bootstrap cross signing for the given Olm account.
*
* Will generate the cross signing keys and sign them with the master key, and returns the `IDownloadKeyResult`
* that can be directly fed into a test e2eKeyResponder.
*
* The cross-signing keys are randomly generated, similar to how the olm account keys are generated. There may not
* be any value in using static vectors, as the device keys change at every test run.
*
* If some `KeyBackupInfo` are provided, the `auth_data` of each backup info will be signed with the
* master key, meaning the backups will be then trusted after verification.
*
* @param olmAccount - The Olm account object to use for signing the device keys.
* @param userId - The user ID to associate with the device keys.
* @param deviceId - The device ID to associate with the device keys.
* @param keyBackupInfo - Optional key backup infos to sign with the master key.
* @returns A valid keys/query response that can be fed into a test e2eKeyResponder.
*/
export function bootstrapCrossSigningTestOlmAccount(
olmAccount: Olm.Account,
userId: string,
deviceId: string,
keyBackupInfo: KeyBackupInfo[] = [],
): Partial<IDownloadKeyResult> {
const olmAliceMSK = new global.Olm.PkSigning();
const masterPrivkey = olmAliceMSK.generate_seed();
const masterPubkey = olmAliceMSK.init_with_seed(masterPrivkey);
const olmAliceUSK = new global.Olm.PkSigning();
const userPrivkey = olmAliceUSK.generate_seed();
const userPubkey = olmAliceUSK.init_with_seed(userPrivkey);
const olmAliceSSK = new global.Olm.PkSigning();
const sskPrivkey = olmAliceSSK.generate_seed();
const sskPubkey = olmAliceSSK.init_with_seed(sskPrivkey);
const mskInfo: Keys = {
user_id: userId,
usage: ["master"],
keys: {
["ed25519:" + masterPubkey]: masterPubkey,
},
};
const sskInfo: Partial<SigningKeys> = {
user_id: userId,
usage: ["self_signing"],
keys: {
["ed25519:" + sskPubkey]: sskPubkey,
},
};
// sign the ssk with the msk
const sskSig = olmAliceMSK.sign(anotherjson.stringify(sskInfo));
sskInfo.signatures = {
[userId]: {
["ed25519:" + masterPubkey]: sskSig,
},
};
const uskInfo: Partial<SigningKeys> = {
user_id: userId,
usage: ["user_signing"],
keys: {
["ed25519:" + userPubkey]: userPubkey,
},
};
// sign the usk with the msk
const uskSig = olmAliceMSK.sign(anotherjson.stringify(uskInfo));
uskInfo.signatures = {
[userId]: {
["ed25519:" + masterPubkey]: uskSig,
},
};
// get the device keys and sign them with the ssk (the device is then cross signed)
const deviceKeys = getTestOlmAccountKeys(olmAccount, userId, deviceId);
const copy = Object.assign({}, deviceKeys);
delete copy.signatures;
const crossSignature = olmAliceSSK.sign(anotherjson.stringify(copy));
// add the signature
deviceKeys.signatures![userId]["ed25519:" + sskPubkey] = crossSignature;
// if we have some key backup info, sign them with the msk
keyBackupInfo.forEach((info) => {
const unsignedAuthData = Object.assign({}, info.auth_data);
delete unsignedAuthData.signatures;
const backupSignature = olmAliceMSK.sign(anotherjson.stringify(unsignedAuthData));
info.auth_data.signatures = {
[userId]: {
["ed25519:" + masterPubkey]: backupSignature,
},
};
});
// clean the olm resources as we don't need them anymore
olmAliceMSK.free();
olmAliceSSK.free();
olmAliceUSK.free();
return {
master_keys: { [userId]: mskInfo },
user_signing_keys: { [userId]: uskInfo as SigningKeys },
self_signing_keys: { [userId]: sskInfo as SigningKeys },
device_keys: { [userId]: { [deviceId]: deviceKeys } },
};
}
/** start an Olm session with a given recipient */
export async function createOlmSession(
olmAccount: Olm.Account,
recipientTestClient: IE2EKeyReceiver,
): Promise<Olm.Session> {
const keys = await recipientTestClient.awaitOneTimeKeyUpload();
const otkId = Object.keys(keys)[0];
const otk = keys[otkId];
const session = new global.Olm.Session();
session.create_outbound(olmAccount, recipientTestClient.getDeviceKey(), otk.key);
return session;
}
// IToDeviceEvent isn't exported by src/sync-accumulator.ts
export interface ToDeviceEvent {
content: IContent;
sender: string;
type: string;
}
/** encrypt an event with an existing olm session */
export function encryptOlmEvent(opts: {
/** the sender's user id */
sender?: string;
/** the sender's curve25519 key */
senderKey: string;
/** the sender's ed25519 key */
senderSigningKey: string;
/** the olm session to use for encryption */
p2pSession: Olm.Session;
/** the recipient's user id */
recipient: string;
/** the recipient's curve25519 key */
recipientCurve25519Key: string;
/** the recipient's ed25519 key */
recipientEd25519Key: string;
/** the payload of the message */
plaincontent?: object;
/** the event type of the payload */
plaintype?: string;
}): ToDeviceEvent {
expect(opts.senderKey).toBeTruthy();
expect(opts.p2pSession).toBeTruthy();
expect(opts.recipient).toBeTruthy();
const plaintext = {
content: opts.plaincontent || {},
recipient: opts.recipient,
recipient_keys: {
ed25519: opts.recipientEd25519Key,
},
keys: {
ed25519: opts.senderSigningKey,
},
sender: opts.sender || "@bob:xyz",
type: opts.plaintype || "m.test",
};
return {
content: {
algorithm: "m.olm.v1.curve25519-aes-sha2",
ciphertext: {
[opts.recipientCurve25519Key]: opts.p2pSession.encrypt(JSON.stringify(plaintext)),
},
sender_key: opts.senderKey,
},
sender: opts.sender || "@bob:xyz",
type: "m.room.encrypted",
};
}
// encrypt an event with megolm
export function encryptMegolmEvent(opts: {
senderKey: string;
groupSession: Olm.OutboundGroupSession;
plaintext?: Partial<IEvent>;
room_id?: string;
}): IEvent {
expect(opts.senderKey).toBeTruthy();
expect(opts.groupSession).toBeTruthy();
const plaintext = opts.plaintext || {};
if (!plaintext.content) {
plaintext.content = {
body: "42",
msgtype: "m.text",
};
}
if (!plaintext.type) {
plaintext.type = "m.room.message";
}
if (!plaintext.room_id) {
expect(opts.room_id).toBeTruthy();
plaintext.room_id = opts.room_id;
}
return encryptMegolmEventRawPlainText({
senderKey: opts.senderKey,
groupSession: opts.groupSession,
plaintext,
});
}
export function encryptMegolmEventRawPlainText(opts: {
senderKey: string;
groupSession: Olm.OutboundGroupSession;
plaintext: Partial<IEvent>;
origin_server_ts?: number;
}): IEvent {
return {
event_id: "$test_megolm_event_" + Math.random(),
sender: opts.plaintext.sender ?? "@not_the_real_sender:example.com",
origin_server_ts: opts.plaintext.origin_server_ts ?? 1672944778000,
content: {
algorithm: "m.megolm.v1.aes-sha2",
ciphertext: opts.groupSession.encrypt(JSON.stringify(opts.plaintext)),
device_id: "testDevice",
sender_key: opts.senderKey,
session_id: opts.groupSession.session_id(),
},
type: "m.room.encrypted",
unsigned: {},
};
}
/** build an encrypted room_key event to share a group session, using an existing olm session */
export function encryptGroupSessionKey(opts: {
/** recipient's user id */
recipient: string;
/** the recipient's curve25519 key */
recipientCurve25519Key: string;
/** the recipient's ed25519 key */
recipientEd25519Key: string;
/** sender's olm account */
olmAccount: Olm.Account;
/** sender's olm session with the recipient */
p2pSession: Olm.Session;
groupSession: Olm.OutboundGroupSession;
room_id?: string;
}): ToDeviceEvent {
const senderKeys = JSON.parse(opts.olmAccount.identity_keys());
return encryptOlmEvent({
senderKey: senderKeys.curve25519,
senderSigningKey: senderKeys.ed25519,
recipient: opts.recipient,
recipientCurve25519Key: opts.recipientCurve25519Key,
recipientEd25519Key: opts.recipientEd25519Key,
p2pSession: opts.p2pSession,
plaincontent: {
algorithm: "m.megolm.v1.aes-sha2",
room_id: opts.room_id,
session_id: opts.groupSession.session_id(),
session_key: opts.groupSession.session_key(),
},
plaintype: "m.room_key",
});
}
/**
* Test utility to correctly encrypt a secret send event to a test device using the provided p2p session.
*
* @param opts - the options for the secret send event
* @returns the to-device event, ready to be returned in a sync response for the test device.
*/
export function encryptSecretSend(opts: {
/** the sender's user id */
sender: string;
/** recipient's user id */
recipient: string;
/** the recipient's curve25519 key */
recipientCurve25519Key: string;
/** the recipient's ed25519 key */
recipientEd25519Key: string;
/** sender's olm account */
olmAccount: Olm.Account;
/** sender's olm session with the recipient */
p2pSession: Olm.Session;
/** The requestId of the secret request that this secret send is replying. */
requestId: string;
/** The secret value */
secret: string;
}): ToDeviceEvent {
const senderKeys = JSON.parse(opts.olmAccount.identity_keys());
return encryptOlmEvent({
sender: opts.sender,
senderKey: senderKeys.curve25519,
senderSigningKey: senderKeys.ed25519,
recipient: opts.recipient,
recipientCurve25519Key: opts.recipientCurve25519Key,
recipientEd25519Key: opts.recipientEd25519Key,
p2pSession: opts.p2pSession,
plaincontent: {
request_id: opts.requestId,
secret: opts.secret,
},
plaintype: "m.secret.send",
});
}
/**
* Establish an Olm Session with the test user
*
* Waits for the test user to upload their keys, then sends a /sync response with a to-device message which will
* establish an Olm session.
*
* @param testClient - the MatrixClient under test, which we expect to upload account keys, and to make a
* /sync request which we will respond to.
* @param keyReceiver - an IE2EKeyReceiver which will intercept the /keys/upload request from the client under test
* @param syncResponder - an ISyncResponder which will intercept /sync requests from the client under test
* @param peerOlmAccount: an OlmAccount which will be used to initiate the Olm session.
*/
export async function establishOlmSession(
testClient: MatrixClient,
keyReceiver: IE2EKeyReceiver,
syncResponder: ISyncResponder,
peerOlmAccount: Olm.Account,
): Promise<Olm.Session> {
const peerE2EKeys = JSON.parse(peerOlmAccount.identity_keys());
const p2pSession = await createOlmSession(peerOlmAccount, keyReceiver);
const olmEvent = encryptOlmEvent({
senderKey: peerE2EKeys.curve25519,
senderSigningKey: peerE2EKeys.ed25519,
recipient: testClient.getUserId()!,
recipientCurve25519Key: keyReceiver.getDeviceKey(),
recipientEd25519Key: keyReceiver.getSigningKey(),
p2pSession: p2pSession,
});
syncResponder.sendOrQueueSyncResponse({
next_batch: 1,
to_device: { events: [olmEvent] },
});
await syncPromise(testClient);
return p2pSession;
}
+124
View File
@@ -0,0 +1,124 @@
/*
Copyright 2022 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 "fake-indexeddb/auto";
import { IDBFactory } from "fake-indexeddb";
import { createClient } from "../../../src";
afterEach(() => {
// reset fake-indexeddb after each test, to make sure we don't leak connections
// cf https://github.com/dumbmatter/fakeIndexedDB#wipingresetting-the-indexeddb-for-a-fresh-state
// eslint-disable-next-line no-global-assign
indexedDB = new IDBFactory();
});
describe("MatrixClient.initRustCrypto", () => {
it("should raise if userId or deviceId is unknown", async () => {
const unknownUserClient = createClient({
baseUrl: "http://test.server",
deviceId: "aliceDevice",
});
await expect(() => unknownUserClient.initRustCrypto()).rejects.toThrow("unknown userId");
const unknownDeviceClient = createClient({
baseUrl: "http://test.server",
userId: "@alice:test",
});
await expect(() => unknownDeviceClient.initRustCrypto()).rejects.toThrow("unknown deviceId");
});
it("should create the indexed db", async () => {
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: "@alice:localhost",
deviceId: "aliceDevice",
});
// No databases.
expect(await indexedDB.databases()).toHaveLength(0);
await matrixClient.initRustCrypto();
// should have an indexed db now
const databaseNames = (await indexedDB.databases()).map((db) => db.name);
expect(databaseNames).toEqual(expect.arrayContaining(["matrix-js-sdk::matrix-sdk-crypto"]));
});
it("should create the meta db if given a pickleKey", async () => {
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: "@alice:localhost",
deviceId: "aliceDevice",
pickleKey: "testKey",
});
// No databases.
expect(await indexedDB.databases()).toHaveLength(0);
await matrixClient.initRustCrypto();
// should have two indexed dbs now
const databaseNames = (await indexedDB.databases()).map((db) => db.name);
expect(databaseNames).toEqual(
expect.arrayContaining(["matrix-js-sdk::matrix-sdk-crypto", "matrix-js-sdk::matrix-sdk-crypto-meta"]),
);
});
it("should ignore a second call", async () => {
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: "@alice:localhost",
deviceId: "aliceDevice",
});
await matrixClient.initRustCrypto();
await matrixClient.initRustCrypto();
});
});
describe("MatrixClient.clearStores", () => {
it("should clear the indexeddbs", async () => {
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: "@alice:localhost",
deviceId: "aliceDevice",
pickleKey: "testKey",
});
await matrixClient.initRustCrypto();
expect(await indexedDB.databases()).toHaveLength(2);
await matrixClient.stopClient();
await matrixClient.clearStores();
expect(await indexedDB.databases()).toHaveLength(0);
});
it("should not fail in environments without indexedDB", async () => {
// eslint-disable-next-line no-global-assign
indexedDB = undefined!;
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: "@alice:localhost",
deviceId: "aliceDevice",
});
await matrixClient.stopClient();
await matrixClient.clearStores();
// No error thrown in clearStores
});
});
File diff suppressed because it is too large Load Diff
+264 -259
View File
@@ -16,9 +16,9 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { TestClient } from '../TestClient';
import * as testUtils from '../test-utils/test-utils';
import { logger } from '../../src/logger';
import { TestClient } from "../TestClient";
import * as testUtils from "../test-utils/test-utils";
import { logger } from "../../src/logger";
const ROOM_ID = "!room:id";
@@ -26,26 +26,24 @@ const ROOM_ID = "!room:id";
* get a /sync response which contains a single e2e room (ROOM_ID), with the
* members given
*
* @param {string[]} roomMembers
*
* @return {object} sync response
* @returns sync response
*/
function getSyncResponse(roomMembers) {
function getSyncResponse(roomMembers: string[]) {
const stateEvents = [
testUtils.mkEvent({
type: 'm.room.encryption',
skey: '',
type: "m.room.encryption",
skey: "",
content: {
algorithm: 'm.megolm.v1.aes-sha2',
algorithm: "m.megolm.v1.aes-sha2",
},
}),
];
Array.prototype.push.apply(
stateEvents,
roomMembers.map(
(m) => testUtils.mkMembership({
mship: 'join',
roomMembers.map((m) =>
testUtils.mkMembership({
mship: "join",
sender: m,
}),
),
@@ -67,24 +65,22 @@ function getSyncResponse(roomMembers) {
return syncResponse;
}
describe("DeviceList management:", function() {
describe("DeviceList management:", function () {
if (!global.Olm) {
logger.warn('not running deviceList tests: Olm not present');
logger.warn("not running deviceList tests: Olm not present");
return;
}
let sessionStoreBackend;
let aliceTestClient;
let aliceTestClient: TestClient;
let sessionStoreBackend: Storage;
async function createTestClient() {
const testClient = new TestClient(
"@alice:localhost", "xzcvb", "akjgkrgjs", sessionStoreBackend,
);
const testClient = new TestClient("@alice:localhost", "xzcvb", "akjgkrgjs", sessionStoreBackend);
await testClient.client.initCrypto();
return testClient;
}
beforeEach(async function() {
beforeEach(async function () {
// we create our own sessionStoreBackend so that we can use it for
// another TestClient.
sessionStoreBackend = new testUtils.MockStorageApi();
@@ -92,305 +88,314 @@ describe("DeviceList management:", function() {
aliceTestClient = await createTestClient();
});
afterEach(function() {
afterEach(function () {
return aliceTestClient.stop();
});
it("Alice shouldn't do a second /query for non-e2e-capable devices", function() {
aliceTestClient.expectKeyQuery({ device_keys: { '@alice:localhost': {} } });
return aliceTestClient.start().then(function() {
const syncResponse = getSyncResponse(['@bob:xyz']);
aliceTestClient.httpBackend.when('GET', '/sync').respond(200, syncResponse);
return aliceTestClient.flushSync();
}).then(function() {
logger.log("Forcing alice to download our device keys");
aliceTestClient.httpBackend.when('POST', '/keys/query').respond(200, {
device_keys: {
'@bob:xyz': {},
},
});
return Promise.all([
aliceTestClient.client.downloadKeys(['@bob:xyz']),
aliceTestClient.httpBackend.flush('/keys/query', 1),
]);
}).then(function() {
logger.log("Telling alice to send a megolm message");
aliceTestClient.httpBackend.when(
'PUT', '/send/',
).respond(200, {
event_id: '$event_id',
});
return Promise.all([
aliceTestClient.client.sendTextMessage(ROOM_ID, 'test'),
// the crypto stuff can take a while, so give the requests a whole second.
aliceTestClient.httpBackend.flushAllExpected({
timeout: 1000,
}),
]);
it("Alice shouldn't do a second /query for non-e2e-capable devices", function () {
aliceTestClient.expectKeyQuery({
device_keys: { "@alice:localhost": {} },
failures: {},
});
return aliceTestClient
.start()
.then(function () {
const syncResponse = getSyncResponse(["@bob:xyz"]);
aliceTestClient.httpBackend.when("GET", "/sync").respond(200, syncResponse);
return aliceTestClient.flushSync();
})
.then(function () {
logger.log("Forcing alice to download our device keys");
aliceTestClient.httpBackend.when("POST", "/keys/query").respond(200, {
device_keys: {
"@bob:xyz": {},
},
});
return Promise.all([
aliceTestClient.client.downloadKeys(["@bob:xyz"]),
aliceTestClient.httpBackend.flush("/keys/query", 1),
]);
})
.then(function () {
logger.log("Telling alice to send a megolm message");
aliceTestClient.httpBackend.when("PUT", "/send/").respond(200, {
event_id: "$event_id",
});
return Promise.all([
aliceTestClient.client.sendTextMessage(ROOM_ID, "test"),
// the crypto stuff can take a while, so give the requests a whole second.
aliceTestClient.httpBackend.flushAllExpected({
timeout: 1000,
}),
]);
});
});
it.skip("We should not get confused by out-of-order device query responses", () => {
// 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(
200, getSyncResponse(['@bob:xyz', '@chris:abc']));
return aliceTestClient.flushSync();
}).then(() => {
// to make sure the initial device queries are flushed out, we
// attempt to send a message.
aliceTestClient.httpBackend.when('POST', '/keys/query').respond(
200, {
device_keys: {
'@bob:xyz': {},
'@chris:abc': {},
},
},
);
aliceTestClient.httpBackend.when('PUT', '/send/').respond(
200, { event_id: '$event1' });
return Promise.all([
aliceTestClient.client.sendTextMessage(ROOM_ID, 'test'),
aliceTestClient.httpBackend.flush('/keys/query', 1).then(
() => aliceTestClient.httpBackend.flush('/send/', 1),
),
aliceTestClient.client.crypto.deviceList.saveIfDirty(),
]);
}).then(() => {
aliceTestClient.client.cryptoStore.getEndToEndDeviceData(null, (data) => {
expect(data.syncToken).toEqual(1);
});
// invalidate bob's and chris's device lists in separate syncs
aliceTestClient.httpBackend.when('GET', '/sync').respond(200, {
next_batch: '2',
device_lists: {
changed: ['@bob:xyz'],
},
});
aliceTestClient.httpBackend.when('GET', '/sync').respond(200, {
next_batch: '3',
device_lists: {
changed: ['@chris:abc'],
},
});
// flush both syncs
return aliceTestClient.flushSync().then(() => {
return aliceTestClient.flushSync();
});
}).then(() => {
// check that we don't yet have a request for chris's devices.
aliceTestClient.httpBackend.when('POST', '/keys/query', {
device_keys: {
'@chris:abc': {},
},
token: '3',
}).respond(200, {
device_keys: { '@chris:abc': {} },
});
return aliceTestClient.httpBackend.flush('/keys/query', 1);
}).then((flushed) => {
expect(flushed).toEqual(0);
return aliceTestClient.client.crypto.deviceList.saveIfDirty();
}).then(() => {
aliceTestClient.client.cryptoStore.getEndToEndDeviceData(null, (data) => {
const bobStat = data.trackingStatus['@bob:xyz'];
if (bobStat != 1 && bobStat != 2) {
throw new Error('Unexpected status for bob: wanted 1 or 2, got ' +
bobStat);
}
const chrisStat = data.trackingStatus['@chris:abc'];
if (chrisStat != 1 && chrisStat != 2) {
throw new Error(
'Unexpected status for chris: wanted 1 or 2, got ' + chrisStat,
);
}
});
// now add an expectation for a query for bob's devices, and let
// it complete.
aliceTestClient.httpBackend.when('POST', '/keys/query', {
device_keys: {
'@bob:xyz': {},
},
token: '2',
}).respond(200, {
device_keys: { '@bob:xyz': {} },
});
return aliceTestClient.httpBackend.flush('/keys/query', 1);
}).then((flushed) => {
expect(flushed).toEqual(1);
// wait for the client to stop processing the response
return aliceTestClient.client.downloadKeys(['@bob:xyz']);
}).then(() => {
return aliceTestClient.client.crypto.deviceList.saveIfDirty();
}).then(() => {
aliceTestClient.client.cryptoStore.getEndToEndDeviceData(null, (data) => {
const bobStat = data.trackingStatus['@bob:xyz'];
expect(bobStat).toEqual(3);
const chrisStat = data.trackingStatus['@chris:abc'];
if (chrisStat != 1 && chrisStat != 2) {
throw new Error(
'Unexpected status for chris: wanted 1 or 2, got ' + bobStat,
);
}
});
// now let the query for chris's devices complete.
return aliceTestClient.httpBackend.flush('/keys/query', 1);
}).then((flushed) => {
expect(flushed).toEqual(1);
// wait for the client to stop processing the response
return aliceTestClient.client.downloadKeys(['@chris:abc']);
}).then(() => {
return aliceTestClient.client.crypto.deviceList.saveIfDirty();
}).then(() => {
aliceTestClient.client.cryptoStore.getEndToEndDeviceData(null, (data) => {
const bobStat = data.trackingStatus['@bob:xyz'];
const chrisStat = data.trackingStatus['@bob:xyz'];
expect(bobStat).toEqual(3);
expect(chrisStat).toEqual(3);
expect(data.syncToken).toEqual(3);
});
aliceTestClient.expectKeyQuery({
device_keys: { "@alice:localhost": {} },
failures: {},
});
return aliceTestClient
.start()
.then(() => {
aliceTestClient.httpBackend
.when("GET", "/sync")
.respond(200, getSyncResponse(["@bob:xyz", "@chris:abc"]));
return aliceTestClient.flushSync();
})
.then(() => {
// to make sure the initial device queries are flushed out, we
// attempt to send a message.
aliceTestClient.httpBackend.when("POST", "/keys/query").respond(200, {
device_keys: {
"@bob:xyz": {},
"@chris:abc": {},
},
});
aliceTestClient.httpBackend.when("PUT", "/send/").respond(200, { event_id: "$event1" });
return Promise.all([
aliceTestClient.client.sendTextMessage(ROOM_ID, "test"),
aliceTestClient.httpBackend
.flush("/keys/query", 1)
.then(() => aliceTestClient.httpBackend.flush("/send/", 1)),
aliceTestClient.client.crypto!.deviceList.saveIfDirty(),
]);
})
.then(() => {
// @ts-ignore accessing a protected field
aliceTestClient.client.cryptoStore!.getEndToEndDeviceData(null, (data) => {
expect(data!.syncToken).toEqual(1);
});
// invalidate bob's and chris's device lists in separate syncs
aliceTestClient.httpBackend.when("GET", "/sync").respond(200, {
next_batch: "2",
device_lists: {
changed: ["@bob:xyz"],
},
});
aliceTestClient.httpBackend.when("GET", "/sync").respond(200, {
next_batch: "3",
device_lists: {
changed: ["@chris:abc"],
},
});
// flush both syncs
return aliceTestClient.flushSync().then(() => {
return aliceTestClient.flushSync();
});
})
.then(() => {
// check that we don't yet have a request for chris's devices.
aliceTestClient.httpBackend
.when("POST", "/keys/query", {
device_keys: {
"@chris:abc": {},
},
token: "3",
})
.respond(200, {
device_keys: { "@chris:abc": {} },
});
return aliceTestClient.httpBackend.flush("/keys/query", 1);
})
.then((flushed) => {
expect(flushed).toEqual(0);
return aliceTestClient.client.crypto!.deviceList.saveIfDirty();
})
.then(() => {
// @ts-ignore accessing a protected field
aliceTestClient.client.cryptoStore!.getEndToEndDeviceData(null, (data) => {
const bobStat = data!.trackingStatus["@bob:xyz"];
if (bobStat != 1 && bobStat != 2) {
throw new Error("Unexpected status for bob: wanted 1 or 2, got " + bobStat);
}
const chrisStat = data!.trackingStatus["@chris:abc"];
if (chrisStat != 1 && chrisStat != 2) {
throw new Error("Unexpected status for chris: wanted 1 or 2, got " + chrisStat);
}
});
// now add an expectation for a query for bob's devices, and let
// it complete.
aliceTestClient.httpBackend
.when("POST", "/keys/query", {
device_keys: {
"@bob:xyz": {},
},
token: "2",
})
.respond(200, {
device_keys: { "@bob:xyz": {} },
});
return aliceTestClient.httpBackend.flush("/keys/query", 1);
})
.then((flushed) => {
expect(flushed).toEqual(1);
// wait for the client to stop processing the response
return aliceTestClient.client.downloadKeys(["@bob:xyz"]);
})
.then(() => {
return aliceTestClient.client.crypto!.deviceList.saveIfDirty();
})
.then(() => {
// @ts-ignore accessing a protected field
aliceTestClient.client.cryptoStore!.getEndToEndDeviceData(null, (data) => {
const bobStat = data!.trackingStatus["@bob:xyz"];
expect(bobStat).toEqual(3);
const chrisStat = data!.trackingStatus["@chris:abc"];
if (chrisStat != 1 && chrisStat != 2) {
throw new Error("Unexpected status for chris: wanted 1 or 2, got " + bobStat);
}
});
// now let the query for chris's devices complete.
return aliceTestClient.httpBackend.flush("/keys/query", 1);
})
.then((flushed) => {
expect(flushed).toEqual(1);
// wait for the client to stop processing the response
return aliceTestClient.client.downloadKeys(["@chris:abc"]);
})
.then(() => {
return aliceTestClient.client.crypto!.deviceList.saveIfDirty();
})
.then(() => {
// @ts-ignore accessing a protected field
aliceTestClient.client.cryptoStore!.getEndToEndDeviceData(null, (data) => {
const bobStat = data!.trackingStatus["@bob:xyz"];
const chrisStat = data!.trackingStatus["@bob:xyz"];
expect(bobStat).toEqual(3);
expect(chrisStat).toEqual(3);
expect(data!.syncToken).toEqual(3);
});
});
});
// https://github.com/vector-im/element-web/issues/4983
describe("Alice should know she has stale device lists", () => {
beforeEach(async function() {
beforeEach(async function () {
await aliceTestClient.start();
aliceTestClient.httpBackend.when('GET', '/sync').respond(
200, getSyncResponse(['@bob:xyz']));
aliceTestClient.httpBackend.when("GET", "/sync").respond(200, getSyncResponse(["@bob:xyz"]));
await aliceTestClient.flushSync();
aliceTestClient.httpBackend.when('POST', '/keys/query').respond(
200, {
device_keys: {
'@bob:xyz': {},
},
aliceTestClient.httpBackend.when("POST", "/keys/query").respond(200, {
device_keys: {
"@bob:xyz": {},
},
);
await aliceTestClient.httpBackend.flush('/keys/query', 1);
await aliceTestClient.client.crypto.deviceList.saveIfDirty();
});
await aliceTestClient.httpBackend.flush("/keys/query", 1);
await aliceTestClient.client.crypto!.deviceList.saveIfDirty();
aliceTestClient.client.cryptoStore.getEndToEndDeviceData(null, (data) => {
const bobStat = data.trackingStatus['@bob:xyz'];
// @ts-ignore accessing a protected field
aliceTestClient.client.cryptoStore!.getEndToEndDeviceData(null, (data) => {
const bobStat = data!.trackingStatus["@bob:xyz"];
// Alice should be tracking bob's device list
expect(bobStat).toBeGreaterThan(
0,
);
expect(bobStat).toBeGreaterThan(0);
});
});
it("when Bob leaves", async function() {
aliceTestClient.httpBackend.when('GET', '/sync').respond(
200, {
next_batch: 2,
device_lists: {
left: ['@bob:xyz'],
},
rooms: {
join: {
[ROOM_ID]: {
timeline: {
events: [
testUtils.mkMembership({
mship: 'leave',
sender: '@bob:xyz',
}),
],
},
it("when Bob leaves", async function () {
aliceTestClient.httpBackend.when("GET", "/sync").respond(200, {
next_batch: 2,
device_lists: {
left: ["@bob:xyz"],
},
rooms: {
join: {
[ROOM_ID]: {
timeline: {
events: [
testUtils.mkMembership({
mship: "leave",
sender: "@bob:xyz",
}),
],
},
},
},
},
);
});
await aliceTestClient.flushSync();
await aliceTestClient.client.crypto.deviceList.saveIfDirty();
await aliceTestClient.client.crypto!.deviceList.saveIfDirty();
aliceTestClient.client.cryptoStore.getEndToEndDeviceData(null, (data) => {
const bobStat = data.trackingStatus['@bob:xyz'];
// @ts-ignore accessing a protected field
aliceTestClient.client.cryptoStore!.getEndToEndDeviceData(null, (data) => {
const bobStat = data!.trackingStatus["@bob:xyz"];
// Alice should have marked bob's device list as untracked
expect(bobStat).toEqual(
0,
);
expect(bobStat).toEqual(0);
});
});
it("when Alice leaves", async function() {
aliceTestClient.httpBackend.when('GET', '/sync').respond(
200, {
next_batch: 2,
device_lists: {
left: ['@bob:xyz'],
},
rooms: {
leave: {
[ROOM_ID]: {
timeline: {
events: [
testUtils.mkMembership({
mship: 'leave',
sender: '@bob:xyz',
}),
],
},
it("when Alice leaves", async function () {
aliceTestClient.httpBackend.when("GET", "/sync").respond(200, {
next_batch: 2,
device_lists: {
left: ["@bob:xyz"],
},
rooms: {
leave: {
[ROOM_ID]: {
timeline: {
events: [
testUtils.mkMembership({
mship: "leave",
sender: "@bob:xyz",
}),
],
},
},
},
},
);
});
await aliceTestClient.flushSync();
await aliceTestClient.client.crypto.deviceList.saveIfDirty();
await aliceTestClient.client.crypto!.deviceList.saveIfDirty();
aliceTestClient.client.cryptoStore.getEndToEndDeviceData(null, (data) => {
const bobStat = data.trackingStatus['@bob:xyz'];
// @ts-ignore accessing a protected field
aliceTestClient.client.cryptoStore!.getEndToEndDeviceData(null, (data) => {
const bobStat = data!.trackingStatus["@bob:xyz"];
// Alice should have marked bob's device list as untracked
expect(bobStat).toEqual(
0,
);
expect(bobStat).toEqual(0);
});
});
it("when Bob leaves whilst Alice is offline", async function() {
it("when Bob leaves whilst Alice is offline", async function () {
aliceTestClient.stop();
const anotherTestClient = await createTestClient();
try {
await anotherTestClient.start();
anotherTestClient.httpBackend.when('GET', '/sync').respond(
200, getSyncResponse([]));
anotherTestClient.httpBackend.when("GET", "/sync").respond(200, getSyncResponse([]));
await anotherTestClient.flushSync();
await anotherTestClient.client?.crypto?.deviceList?.saveIfDirty();
// @ts-ignore accessing private property
anotherTestClient.client.cryptoStore.getEndToEndDeviceData(null, (data) => {
const bobStat = data!.trackingStatus['@bob:xyz'];
const bobStat = data!.trackingStatus["@bob:xyz"];
// Alice should have marked bob's device list as untracked
expect(bobStat).toEqual(
0,
);
expect(bobStat).toEqual(0);
});
} finally {
anotherTestClient.stop();
+118 -93
View File
@@ -29,7 +29,7 @@ import {
import * as utils from "../test-utils/test-utils";
import { TestClient } from "../TestClient";
describe("MatrixClient events", function() {
describe("MatrixClient events", function () {
const selfUserId = "@alice:localhost";
const selfAccessToken = "aseukfgwef";
let client: MatrixClient | undefined;
@@ -46,23 +46,25 @@ describe("MatrixClient events", function() {
return [client!, httpBackend];
};
beforeEach(function() {
beforeEach(function () {
[client!, httpBackend] = setupTests();
});
afterEach(function() {
afterEach(function () {
httpBackend?.verifyNoOutstandingExpectation();
client?.stopClient();
return httpBackend?.stop();
});
describe("emissions", function() {
describe("emissions", function () {
const SYNC_DATA = {
next_batch: "s_5_3",
presence: {
events: [
utils.mkPresence({
user: "@foo:bar", name: "Foo Bar", presence: "online",
user: "@foo:bar",
name: "Foo Bar",
presence: "online",
}),
],
},
@@ -72,7 +74,9 @@ describe("MatrixClient events", function() {
timeline: {
events: [
utils.mkMessage({
room: "!erufh:bar", user: "@foo:bar", msg: "hmmm",
room: "!erufh:bar",
user: "@foo:bar",
msg: "hmmm",
}),
],
prev_batch: "s",
@@ -80,14 +84,15 @@ describe("MatrixClient events", function() {
state: {
events: [
utils.mkMembership({
room: "!erufh:bar", mship: "join", user: "@foo:bar",
room: "!erufh:bar",
mship: "join",
user: "@foo:bar",
}),
utils.mkEvent({
type: "m.room.create", room: "!erufh:bar",
type: "m.room.create",
room: "!erufh:bar",
user: "@foo:bar",
content: {
creator: "@foo:bar",
},
content: {},
}),
],
},
@@ -103,18 +108,23 @@ describe("MatrixClient events", function() {
timeline: {
events: [
utils.mkMessage({
room: "!erufh:bar", user: "@foo:bar",
room: "!erufh:bar",
user: "@foo:bar",
msg: "ello ello",
}),
utils.mkMessage({
room: "!erufh:bar", user: "@foo:bar", msg: ":D",
room: "!erufh:bar",
user: "@foo:bar",
msg: ":D",
}),
],
},
ephemeral: {
events: [
utils.mkEvent({
type: "m.typing", room: "!erufh:bar", content: {
type: "m.typing",
room: "!erufh:bar",
content: {
user_ids: ["@foo:bar"],
},
}),
@@ -125,50 +135,49 @@ describe("MatrixClient events", function() {
},
};
it("should emit events from both the first and subsequent /sync calls",
function() {
httpBackend!.when("GET", "/sync").respond(200, SYNC_DATA);
httpBackend!.when("GET", "/sync").respond(200, NEXT_SYNC_DATA);
it("should emit events from both the first and subsequent /sync calls", function () {
httpBackend!.when("GET", "/sync").respond(200, SYNC_DATA);
httpBackend!.when("GET", "/sync").respond(200, NEXT_SYNC_DATA);
let expectedEvents: Partial<IEvent>[] = [];
expectedEvents = expectedEvents.concat(
SYNC_DATA.presence.events,
SYNC_DATA.rooms.join["!erufh:bar"].timeline.events,
SYNC_DATA.rooms.join["!erufh:bar"].state.events,
NEXT_SYNC_DATA.rooms.join["!erufh:bar"].timeline.events,
NEXT_SYNC_DATA.rooms.join["!erufh:bar"].ephemeral.events,
);
let expectedEvents: Partial<IEvent>[] = [];
expectedEvents = expectedEvents.concat(
SYNC_DATA.presence.events,
SYNC_DATA.rooms.join["!erufh:bar"].timeline.events,
SYNC_DATA.rooms.join["!erufh:bar"].state.events,
NEXT_SYNC_DATA.rooms.join["!erufh:bar"].timeline.events,
NEXT_SYNC_DATA.rooms.join["!erufh:bar"].ephemeral.events,
);
client!.on(ClientEvent.Event, function(event) {
let found = false;
for (let i = 0; i < expectedEvents.length; i++) {
if (expectedEvents[i].event_id === event.getId()) {
expectedEvents.splice(i, 1);
found = true;
break;
}
client!.on(ClientEvent.Event, function (event) {
let found = false;
for (let i = 0; i < expectedEvents.length; i++) {
if (expectedEvents[i].event_id === event.getId()) {
expectedEvents.splice(i, 1);
found = true;
break;
}
expect(found).toBe(true);
});
client!.startClient();
return Promise.all([
// wait for two SYNCING events
utils.syncPromise(client!).then(() => {
return utils.syncPromise(client!);
}),
httpBackend!.flushAllExpected(),
]).then(() => {
expect(expectedEvents.length).toEqual(0);
});
}
expect(found).toBe(true);
});
it("should emit User events", function(done) {
client!.startClient();
return Promise.all([
// wait for two SYNCING events
utils.syncPromise(client!).then(() => {
return utils.syncPromise(client!);
}),
httpBackend!.flushAllExpected(),
]).then(() => {
expect(expectedEvents.length).toEqual(0);
});
});
it("should emit User events", async () => {
httpBackend!.when("GET", "/sync").respond(200, SYNC_DATA);
httpBackend!.when("GET", "/sync").respond(200, NEXT_SYNC_DATA);
let fired = false;
client!.on(UserEvent.Presence, function(event, user) {
client!.on(UserEvent.Presence, function (event, user) {
fired = true;
expect(user).toBeTruthy();
expect(event).toBeTruthy();
@@ -177,59 +186,81 @@ describe("MatrixClient events", function() {
}
expect(event.event).toEqual(SYNC_DATA.presence.events[0]);
expect(user.presence).toEqual(
SYNC_DATA.presence.events[0]?.content?.presence,
);
expect(user.presence).toEqual(SYNC_DATA.presence.events[0]?.content?.presence);
});
client!.startClient();
httpBackend!.flushAllExpected().then(function() {
expect(fired).toBe(true);
done();
});
await httpBackend!.flushAllExpected();
expect(fired).toBe(true);
});
it("should emit Room events", function() {
it("should emit User events when presence data is absent in first sync", async () => {
const MODIFIED_SYNC_DATA: any = structuredClone(SYNC_DATA);
delete MODIFIED_SYNC_DATA["presence"];
const MODIFIED_NEXT_SYNC_DATA: any = structuredClone(NEXT_SYNC_DATA);
MODIFIED_NEXT_SYNC_DATA.presence = {
events: [
utils.mkPresence({
user: "@foo:bar",
name: "Foo Bar",
presence: "online",
}),
],
};
httpBackend!.when("GET", "/sync").respond(200, MODIFIED_SYNC_DATA);
httpBackend!.when("GET", "/sync").respond(200, MODIFIED_NEXT_SYNC_DATA);
let fired = false;
client!.on(UserEvent.Presence, function (event, user) {
fired = true;
expect(user).toBeTruthy();
expect(event).toBeTruthy();
if (!user || !event) {
return;
}
expect(event.event).toEqual(MODIFIED_NEXT_SYNC_DATA.presence.events[0]);
expect(user.presence).toEqual(MODIFIED_NEXT_SYNC_DATA.presence.events[0]?.content?.presence);
});
client!.startClient();
await httpBackend!.flushAllExpected();
expect(fired).toBe(true);
});
it("should emit Room events", function () {
httpBackend!.when("GET", "/sync").respond(200, SYNC_DATA);
httpBackend!.when("GET", "/sync").respond(200, NEXT_SYNC_DATA);
let roomInvokeCount = 0;
let roomNameInvokeCount = 0;
let timelineFireCount = 0;
client!.on(ClientEvent.Room, function(room) {
client!.on(ClientEvent.Room, function (room) {
roomInvokeCount++;
expect(room.roomId).toEqual("!erufh:bar");
});
client!.on(RoomEvent.Timeline, function(event, room) {
client!.on(RoomEvent.Timeline, function (event, room) {
timelineFireCount++;
expect(room?.roomId).toEqual("!erufh:bar");
});
client!.on(RoomEvent.Name, function(room) {
client!.on(RoomEvent.Name, function (room) {
roomNameInvokeCount++;
});
client!.startClient();
return Promise.all([
httpBackend!.flushAllExpected(),
utils.syncPromise(client!, 2),
]).then(function() {
return Promise.all([httpBackend!.flushAllExpected(), utils.syncPromise(client!, 2)]).then(function () {
expect(roomInvokeCount).toEqual(1);
expect(roomNameInvokeCount).toEqual(1);
expect(timelineFireCount).toEqual(3);
});
});
it("should emit RoomState events", function() {
it("should emit RoomState events", function () {
httpBackend!.when("GET", "/sync").respond(200, SYNC_DATA);
httpBackend!.when("GET", "/sync").respond(200, NEXT_SYNC_DATA);
const roomStateEventTypes = [
"m.room.member", "m.room.create",
];
const roomStateEventTypes = ["m.room.member", "m.room.create"];
let eventsInvokeCount = 0;
let membersInvokeCount = 0;
let newMemberInvokeCount = 0;
client!.on(RoomStateEvent.Events, function(event, state) {
client!.on(RoomStateEvent.Events, function (event, state) {
eventsInvokeCount++;
const index = roomStateEventTypes.indexOf(event.getType());
expect(index).not.toEqual(-1);
@@ -237,13 +268,13 @@ describe("MatrixClient events", function() {
roomStateEventTypes.splice(index, 1);
}
});
client!.on(RoomStateEvent.Members, function(event, state, member) {
client!.on(RoomStateEvent.Members, function (event, state, member) {
membersInvokeCount++;
expect(member.roomId).toEqual("!erufh:bar");
expect(member.userId).toEqual("@foo:bar");
expect(member.membership).toEqual("join");
});
client!.on(RoomStateEvent.NewMember, function(event, state, member) {
client!.on(RoomStateEvent.NewMember, function (event, state, member) {
newMemberInvokeCount++;
expect(member.roomId).toEqual("!erufh:bar");
expect(member.userId).toEqual("@foo:bar");
@@ -252,17 +283,14 @@ describe("MatrixClient events", function() {
client!.startClient();
return Promise.all([
httpBackend!.flushAllExpected(),
utils.syncPromise(client!, 2),
]).then(function() {
return Promise.all([httpBackend!.flushAllExpected(), utils.syncPromise(client!, 2)]).then(function () {
expect(membersInvokeCount).toEqual(1);
expect(newMemberInvokeCount).toEqual(1);
expect(eventsInvokeCount).toEqual(2);
});
});
it("should emit RoomMember events", function() {
it("should emit RoomMember events", function () {
httpBackend!.when("GET", "/sync").respond(200, SYNC_DATA);
httpBackend!.when("GET", "/sync").respond(200, NEXT_SYNC_DATA);
@@ -270,27 +298,24 @@ describe("MatrixClient events", function() {
let powerLevelInvokeCount = 0;
let nameInvokeCount = 0;
let membershipInvokeCount = 0;
client!.on(RoomMemberEvent.Name, function(event, member) {
client!.on(RoomMemberEvent.Name, function (event, member) {
nameInvokeCount++;
});
client!.on(RoomMemberEvent.Typing, function(event, member) {
client!.on(RoomMemberEvent.Typing, function (event, member) {
typingInvokeCount++;
expect(member.typing).toBe(true);
});
client!.on(RoomMemberEvent.PowerLevel, function(event, member) {
client!.on(RoomMemberEvent.PowerLevel, function (event, member) {
powerLevelInvokeCount++;
});
client!.on(RoomMemberEvent.Membership, function(event, member) {
client!.on(RoomMemberEvent.Membership, function (event, member) {
membershipInvokeCount++;
expect(member.membership).toEqual("join");
});
client!.startClient();
return Promise.all([
httpBackend!.flushAllExpected(),
utils.syncPromise(client!, 2),
]).then(function() {
return Promise.all([httpBackend!.flushAllExpected(), utils.syncPromise(client!, 2)]).then(function () {
expect(typingInvokeCount).toEqual(1);
expect(powerLevelInvokeCount).toEqual(0);
expect(nameInvokeCount).toEqual(0);
@@ -298,36 +323,36 @@ describe("MatrixClient events", function() {
});
});
it("should emit Session.logged_out on M_UNKNOWN_TOKEN", function() {
const error = { errcode: 'M_UNKNOWN_TOKEN' };
it("should emit Session.logged_out on M_UNKNOWN_TOKEN", function () {
const error = { errcode: "M_UNKNOWN_TOKEN" };
httpBackend!.when("GET", "/sync").respond(401, error);
let sessionLoggedOutCount = 0;
client!.on(HttpApiEvent.SessionLoggedOut, function(errObj) {
client!.on(HttpApiEvent.SessionLoggedOut, function (errObj) {
sessionLoggedOutCount++;
expect(errObj.data).toEqual(error);
});
client!.startClient();
return httpBackend!.flushAllExpected().then(function() {
return httpBackend!.flushAllExpected().then(function () {
expect(sessionLoggedOutCount).toEqual(1);
});
});
it("should emit Session.logged_out on M_UNKNOWN_TOKEN (soft logout)", function() {
const error = { errcode: 'M_UNKNOWN_TOKEN', soft_logout: true };
it("should emit Session.logged_out on M_UNKNOWN_TOKEN (soft logout)", function () {
const error = { errcode: "M_UNKNOWN_TOKEN", soft_logout: true };
httpBackend!.when("GET", "/sync").respond(401, error);
let sessionLoggedOutCount = 0;
client!.on(HttpApiEvent.SessionLoggedOut, function(errObj) {
client!.on(HttpApiEvent.SessionLoggedOut, function (errObj) {
sessionLoggedOutCount++;
expect(errObj.data).toEqual(error);
});
client!.startClient();
return httpBackend!.flushAllExpected().then(function() {
return httpBackend!.flushAllExpected().then(function () {
expect(sessionLoggedOutCount).toEqual(1);
});
});
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+84 -70
View File
@@ -1,13 +1,13 @@
import HttpBackend from "matrix-mock-request";
import * as utils from "../test-utils/test-utils";
import { MatrixClient } from "../../src/matrix";
import { ClientEvent, MatrixClient } from "../../src/matrix";
import { MatrixScheduler } from "../../src/scheduler";
import { MemoryStore } from "../../src/store/memory";
import { MatrixError } from "../../src/http-api";
import { IStore } from "../../src/store";
describe("MatrixClient opts", function() {
describe("MatrixClient opts", function () {
const baseUrl = "http://localhost.or.something";
let httpBackend = new HttpBackend();
const userId = "@alice:localhost";
@@ -19,11 +19,14 @@ describe("MatrixClient opts", function() {
presence: {},
rooms: {
join: {
"!foo:bar": { // roomId
"!foo:bar": {
// roomId
timeline: {
events: [
utils.mkMessage({
room: roomId, user: userB, msg: "hello",
room: roomId,
user: userB,
msg: "hello",
}),
],
prev_batch: "f_1_1",
@@ -31,22 +34,30 @@ describe("MatrixClient opts", function() {
state: {
events: [
utils.mkEvent({
type: "m.room.name", room: roomId, user: userB,
type: "m.room.name",
room: roomId,
user: userB,
content: {
name: "Old room name",
},
}),
utils.mkMembership({
room: roomId, mship: "join", user: userB, name: "Bob",
room: roomId,
mship: "join",
user: userB,
name: "Bob",
}),
utils.mkMembership({
room: roomId, mship: "join", user: userId, name: "Alice",
room: roomId,
mship: "join",
user: userId,
name: "Alice",
}),
utils.mkEvent({
type: "m.room.create", room: roomId, user: userId,
content: {
creator: userId,
},
type: "m.room.create",
room: roomId,
user: userId,
content: {},
}),
],
},
@@ -55,18 +66,18 @@ describe("MatrixClient opts", function() {
},
};
beforeEach(function() {
beforeEach(function () {
httpBackend = new HttpBackend();
});
afterEach(function() {
afterEach(function () {
httpBackend.verifyNoOutstandingExpectation();
return httpBackend.stop();
});
describe("without opts.store", function() {
let client;
beforeEach(function() {
describe("without opts.store", function () {
let client: MatrixClient;
beforeEach(function () {
client = new MatrixClient({
fetchFn: httpBackend.fetchFn as typeof global.fetch,
store: undefined,
@@ -77,34 +88,34 @@ describe("MatrixClient opts", function() {
});
});
afterEach(function() {
afterEach(function () {
client.stopClient();
});
it("should be able to send messages", function(done) {
it("should be able to send messages", async () => {
const eventId = "$flibble:wibble";
httpBackend.when("PUT", "/txn1").respond(200, {
event_id: eventId,
});
client.sendTextMessage("!foo:bar", "a body", "txn1").then(function(res) {
expect(res.event_id).toEqual(eventId);
done();
});
httpBackend.flush("/txn1", 1);
const [res] = await Promise.all([
client.sendTextMessage("!foo:bar", "a body", "txn1"),
httpBackend.flush("/txn1", 1),
]);
expect(res.event_id).toEqual(eventId);
});
it("should be able to sync / get new events", async function() {
const expectedEventTypes = [ // from /initialSync
"m.room.message", "m.room.name", "m.room.member", "m.room.member",
it("should be able to sync / get new events", async function () {
const expectedEventTypes = [
// from /initialSync
"m.room.message",
"m.room.name",
"m.room.member",
"m.room.member",
"m.room.create",
];
client.on("event", function(event) {
expect(expectedEventTypes.indexOf(event.getType())).not.toEqual(
-1,
);
expectedEventTypes.splice(
expectedEventTypes.indexOf(event.getType()), 1,
);
client.on(ClientEvent.Event, function (event) {
expect(expectedEventTypes.indexOf(event.getType())).not.toEqual(-1);
expectedEventTypes.splice(expectedEventTypes.indexOf(event.getType()), 1);
});
httpBackend.when("GET", "/versions").respond(200, {});
httpBackend.when("GET", "/pushrules").respond(200, {});
@@ -114,19 +125,14 @@ describe("MatrixClient opts", function() {
await httpBackend.flush("/versions", 1);
await httpBackend.flush("/pushrules", 1);
await httpBackend.flush("/filter", 1);
await Promise.all([
httpBackend.flush("/sync", 1),
utils.syncPromise(client),
]);
expect(expectedEventTypes.length).toEqual(
0,
);
await Promise.all([httpBackend.flush("/sync", 1), utils.syncPromise(client)]);
expect(expectedEventTypes.length).toEqual(0);
});
});
describe("without opts.scheduler", function() {
let client;
beforeEach(function() {
describe("without opts.scheduler", function () {
let client: MatrixClient;
beforeEach(function () {
client = new MatrixClient({
fetchFn: httpBackend.fetchFn as typeof global.fetch,
store: new MemoryStore() as IStore,
@@ -137,25 +143,25 @@ describe("MatrixClient opts", function() {
});
});
afterEach(function() {
afterEach(function () {
client.stopClient();
});
it("shouldn't retry sending events", function(done) {
httpBackend.when("PUT", "/txn1").respond(500, new MatrixError({
errcode: "M_SOMETHING",
error: "Ruh roh",
}));
client.sendTextMessage("!foo:bar", "a body", "txn1").then(function(res) {
expect(false).toBe(true);
}, function(err) {
expect(err.errcode).toEqual("M_SOMETHING");
done();
});
httpBackend.flush("/txn1", 1);
it("shouldn't retry sending events", async () => {
httpBackend.when("PUT", "/txn1").respond(
500,
new MatrixError({
errcode: "M_SOMETHING",
error: "Ruh roh",
}),
);
await expect(
Promise.all([client.sendTextMessage("!foo:bar", "a body", "txn1"), httpBackend.flush("/txn1", 1)]),
).rejects.toThrow("MatrixError: [500] Unknown message");
});
it("shouldn't queue events", function(done) {
it("shouldn't queue events", async () => {
httpBackend.when("PUT", "/txn1").respond(200, {
event_id: "AAA",
});
@@ -164,30 +170,38 @@ describe("MatrixClient opts", function() {
});
let sentA = false;
let sentB = false;
client.sendTextMessage("!foo:bar", "a body", "txn1").then(function(res) {
const messageASendPromise = client.sendTextMessage("!foo:bar", "a body", "txn1").then(function (res) {
sentA = true;
// We expect messageB to be sent before messageA to ensure as we're
// testing that there is no queueing that blocks each other
expect(sentB).toBe(true);
});
client.sendTextMessage("!foo:bar", "b body", "txn2").then(function(res) {
const messageBSendPromise = client.sendTextMessage("!foo:bar", "b body", "txn2").then(function (res) {
sentB = true;
// We expect messageB to be sent before messageA to ensure as we're
// testing that there is no queueing that blocks each other
expect(sentA).toBe(false);
});
httpBackend.flush("/txn2", 1).then(function() {
httpBackend.flush("/txn1", 1).then(function() {
done();
});
});
// Allow messageB to succeed first
await httpBackend.flush("/txn2", 1);
// Then allow messageA to succeed
await httpBackend.flush("/txn1", 1);
// Now await the message send promises to
await messageBSendPromise;
await messageASendPromise;
});
it("should be able to send messages", function(done) {
it("should be able to send messages", async () => {
httpBackend.when("PUT", "/txn1").respond(200, {
event_id: "foo",
});
client.sendTextMessage("!foo:bar", "a body", "txn1").then(function(res) {
expect(res.event_id).toEqual("foo");
done();
});
httpBackend.flush("/txn1", 1);
const [res] = await Promise.all([
client.sendTextMessage("!foo:bar", "a body", "txn1"),
httpBackend.flush("/txn1", 1),
]);
expect(res.event_id).toEqual("foo");
});
});
});
+28 -39
View File
@@ -29,13 +29,7 @@ describe("MatrixClient relations", () => {
const setupTests = (): [MatrixClient, HttpBackend] => {
const scheduler = new MatrixScheduler();
const testClient = new TestClient(
userId,
"DEVICE",
accessToken,
undefined,
{ scheduler },
);
const testClient = new TestClient(userId, "DEVICE", accessToken, undefined, { scheduler });
const httpBackend = testClient.httpBackend;
const client = testClient.client;
@@ -52,76 +46,71 @@ describe("MatrixClient relations", () => {
});
it("should read related events with the default options", async () => {
const response = client!.relations(roomId, '$event-0', null, null);
const response = client!.relations(roomId, "$event-0", null, null);
httpBackend!.when("GET", "/rooms/!room%3Ahere/event/%24event-0").respond(200, null);
httpBackend!
.when("GET", "/rooms/!room%3Ahere/relations/%24event-0?dir=b")
.respond(200, { chunk: [], next_batch: 'NEXT' });
.when("GET", "/_matrix/client/v1/rooms/!room%3Ahere/relations/%24event-0?dir=b")
.respond(200, { chunk: [], next_batch: "NEXT" });
await httpBackend!.flushAllExpected();
expect(await response).toEqual({ "events": [], "nextBatch": "NEXT" });
expect(await response).toEqual({ events: [], nextBatch: "NEXT", originalEvent: null, prevBatch: null });
});
it("should read related events with relation type", async () => {
const response = client!.relations(roomId, '$event-0', 'm.reference', null);
const response = client!.relations(roomId, "$event-0", "m.reference", null);
httpBackend!.when("GET", "/rooms/!room%3Ahere/event/%24event-0").respond(200, null);
httpBackend!
.when("GET", "/rooms/!room%3Ahere/relations/%24event-0/m.reference?dir=b")
.respond(200, { chunk: [], next_batch: 'NEXT' });
.when("GET", "/_matrix/client/v1/rooms/!room%3Ahere/relations/%24event-0/m.reference?dir=b")
.respond(200, { chunk: [], next_batch: "NEXT" });
await httpBackend!.flushAllExpected();
expect(await response).toEqual({ "events": [], "nextBatch": "NEXT" });
expect(await response).toEqual({ events: [], nextBatch: "NEXT", originalEvent: null, prevBatch: null });
});
it("should read related events with relation type and event type", async () => {
const response = client!.relations(roomId, '$event-0', 'm.reference', 'm.room.message');
const response = client!.relations(roomId, "$event-0", "m.reference", "m.room.message");
httpBackend!.when("GET", "/rooms/!room%3Ahere/event/%24event-0").respond(200, null);
httpBackend!
.when(
"GET",
"/rooms/!room%3Ahere/relations/%24event-0/m.reference/m.room.message?dir=b",
)
.respond(200, { chunk: [], next_batch: 'NEXT' });
.when("GET", "/_matrix/client/v1/rooms/!room%3Ahere/relations/%24event-0/m.reference/m.room.message?dir=b")
.respond(200, { chunk: [], next_batch: "NEXT" });
await httpBackend!.flushAllExpected();
expect(await response).toEqual({ "events": [], "nextBatch": "NEXT" });
expect(await response).toEqual({ events: [], nextBatch: "NEXT", originalEvent: null, prevBatch: null });
});
it("should read related events with custom options", async () => {
const response = client!.relations(roomId, '$event-0', null, null, {
const response = client!.relations(roomId, "$event-0", null, null, {
dir: Direction.Forward,
from: 'FROM',
from: "FROM",
limit: 10,
to: 'TO',
to: "TO",
});
httpBackend!.when("GET", "/rooms/!room%3Ahere/event/%24event-0").respond(200, null);
httpBackend!
.when(
"GET",
"/rooms/!room%3Ahere/relations/%24event-0?dir=f&from=FROM&limit=10&to=TO",
)
.respond(200, { chunk: [], next_batch: 'NEXT' });
.when("GET", "/_matrix/client/v1/rooms/!room%3Ahere/relations/%24event-0?dir=f&from=FROM&limit=10&to=TO")
.respond(200, { chunk: [], next_batch: "NEXT" });
await httpBackend!.flushAllExpected();
expect(await response).toEqual({ "events": [], "nextBatch": "NEXT" });
expect(await response).toEqual({ events: [], nextBatch: "NEXT", originalEvent: null, prevBatch: null });
});
it('should use default direction in the fetchRelations endpoint', async () => {
const response = client!.fetchRelations(roomId, '$event-0', null, null);
it("should use default direction in the fetchRelations endpoint", async () => {
const response = client!.fetchRelations(roomId, "$event-0", null, null);
httpBackend!
.when(
"GET",
"/rooms/!room%3Ahere/relations/%24event-0?dir=b",
)
.respond(200, { chunk: [], next_batch: 'NEXT' });
.when("GET", "/rooms/!room%3Ahere/relations/%24event-0?dir=b")
.respond(200, { chunk: [], next_batch: "NEXT" });
await httpBackend!.flushAllExpected();
expect(await response).toEqual({ "chunk": [], "next_batch": "NEXT" });
expect(await response).toEqual({ chunk: [], next_batch: "NEXT" });
});
});
+45 -59
View File
@@ -20,7 +20,7 @@ import { EventStatus, RoomEvent, MatrixClient, MatrixScheduler } from "../../src
import { Room } from "../../src/models/room";
import { TestClient } from "../TestClient";
describe("MatrixClient retrying", function() {
describe("MatrixClient retrying", function () {
const userId = "@alice:localhost";
const accessToken = "aseukfgwef";
const roomId = "!room:here";
@@ -30,13 +30,7 @@ describe("MatrixClient retrying", function() {
const setupTests = (): [MatrixClient, HttpBackend, Room] => {
const scheduler = new MatrixScheduler();
const testClient = new TestClient(
userId,
"DEVICE",
accessToken,
undefined,
{ scheduler },
);
const testClient = new TestClient(userId, "DEVICE", accessToken, undefined, { scheduler });
const httpBackend = testClient.httpBackend;
const client = testClient.client;
const room = new Room(roomId, client, userId);
@@ -45,49 +39,46 @@ describe("MatrixClient retrying", function() {
return [client, httpBackend, room];
};
beforeEach(function() {
beforeEach(function () {
[client, httpBackend, room] = setupTests();
});
afterEach(function() {
afterEach(function () {
httpBackend!.verifyNoOutstandingExpectation();
return httpBackend!.stop();
});
xit("should retry according to MatrixScheduler.retryFn", function() {
it.skip("should retry according to MatrixScheduler.retryFn", function () {});
});
it.skip("should queue according to MatrixScheduler.queueFn", function () {});
xit("should queue according to MatrixScheduler.queueFn", function() {
it.skip("should mark events as EventStatus.NOT_SENT when giving up", function () {});
});
it.skip("should mark events as EventStatus.QUEUED when queued", function () {});
xit("should mark events as EventStatus.NOT_SENT when giving up", function() {
});
xit("should mark events as EventStatus.QUEUED when queued", function() {
});
it("should mark events as EventStatus.CANCELLED when cancelled", function() {
it("should mark events as EventStatus.CANCELLED when cancelled", function () {
// send a couple of events; the second will be queued
const p1 = client!.sendMessage(roomId, {
"msgtype": "m.text",
"body": "m1",
}).then(function() {
// we expect the first message to fail
throw new Error('Message 1 unexpectedly sent successfully');
}, () => {
// this is expected
});
const p1 = client!
.sendMessage(roomId, {
msgtype: "m.text",
body: "m1",
})
.then(
function () {
// we expect the first message to fail
throw new Error("Message 1 unexpectedly sent successfully");
},
() => {
// this is expected
},
);
// XXX: it turns out that the promise returned by this message
// never gets resolved.
// https://github.com/matrix-org/matrix-js-sdk/issues/496
client!.sendMessage(roomId, {
"msgtype": "m.text",
"body": "m2",
msgtype: "m.text",
body: "m2",
});
// both events should be in the timeline at this point
@@ -100,20 +91,23 @@ describe("MatrixClient retrying", function() {
expect(ev2.status).toEqual(EventStatus.SENDING);
// the first message should get sent, and the second should get queued
httpBackend!.when("PUT", "/send/m.room.message/").check(function() {
// ev2 should now have been queued
expect(ev2.status).toEqual(EventStatus.QUEUED);
httpBackend!
.when("PUT", "/send/m.room.message/")
.check(function () {
// ev2 should now have been queued
expect(ev2.status).toEqual(EventStatus.QUEUED);
// now we can cancel the second and check everything looks sane
client!.cancelPendingEvent(ev2);
expect(ev2.status).toEqual(EventStatus.CANCELLED);
expect(tl.length).toEqual(1);
// now we can cancel the second and check everything looks sane
client!.cancelPendingEvent(ev2);
expect(ev2.status).toEqual(EventStatus.CANCELLED);
expect(tl.length).toEqual(1);
// shouldn't be able to cancel the first message yet
expect(function() {
client!.cancelPendingEvent(ev1);
}).toThrow();
}).respond(400); // fail the first message
// shouldn't be able to cancel the first message yet
expect(function () {
client!.cancelPendingEvent(ev1);
}).toThrow();
})
.respond(400); // fail the first message
// wait for the localecho of ev1 to be updated
const p3 = new Promise<void>((resolve, reject) => {
@@ -122,7 +116,7 @@ describe("MatrixClient retrying", function() {
resolve();
}
});
}).then(function() {
}).then(function () {
expect(ev1.status).toEqual(EventStatus.NOT_SENT);
expect(tl.length).toEqual(1);
@@ -132,19 +126,11 @@ describe("MatrixClient retrying", function() {
expect(tl.length).toEqual(0);
});
return Promise.all([
p1,
p3,
httpBackend!.flushAllExpected(),
]);
return Promise.all([p1, p3, httpBackend!.flushAllExpected()]);
});
describe("resending", function() {
xit("should be able to resend a NOT_SENT event", function() {
});
xit("should be able to resend a sent event", function() {
});
describe("resending", function () {
it.skip("should be able to resend a NOT_SENT event", function () {});
it.skip("should be able to resend a sent event", function () {});
});
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,162 @@
/*
Copyright 2023 Holi Moli GmbH
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 "fake-indexeddb/auto";
import fetchMock from "fetch-mock-jest";
import { MatrixClient, ClientEvent, createClient, SyncState } from "../../src";
const makeQueryablePromise = <T = void>(promise: Promise<T>) => {
let resolved = false;
let rejected = false;
// Observe the promise, saving the fulfillment in a closure scope.
const newPromise = promise.then(
(value) => {
resolved = true;
return value;
},
(error) => {
rejected = true;
throw error;
},
);
const isFulfilled = () => {
return resolved || rejected;
};
const isResolved = () => {
return resolved;
};
const isRejected = () => {
return rejected;
};
return { promise: newPromise, isFulfilled, isResolved, isRejected };
};
const queryablePromise = <T = void>() => {
let resolve!: (value: T | PromiseLike<T>) => void;
let reject!: (reason?: any) => void;
const promise = makeQueryablePromise<T>(
new Promise<T>((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
}),
);
return { resolve, reject, ...promise };
};
describe("MatrixClient syncing errors", () => {
const selfUserId = "@alice:localhost";
const selfAccessToken = "aseukfgwef";
const unknownTokenErrorData = {
status: 401,
body: {
errcode: "M_UNKNOWN_TOKEN",
error: "Invalid access token passed.",
soft_logout: false,
},
};
let client: MatrixClient | undefined;
beforeEach(() => {
client = createClient({
baseUrl: "http://tocal.test.server",
userId: selfUserId,
accessToken: selfAccessToken,
deviceId: "myDevice",
});
});
it("should retry, until errors are solved.", async () => {
jest.useFakeTimers();
fetchMock.config.overwriteRoutes = false;
fetchMock
.getOnce("end:versions", {}) // first version check without credentials needs to succeed
.getOnce("end:versions", 429) // second version check fails with 429 triggering another retry
.get("end:versions", {}) // further version checks succeed
.getOnce("end:pushrules/", 429) // first pushrules check fails starting retry
.get("end:pushrules/", {}) // further pushrules check succeed
.catch({}); // all other calls succeed
const syncEvents = Array.from({ length: 5 }, queryablePromise<SyncState>);
client!.on(ClientEvent.Sync, (state: SyncState, lastState: SyncState | null) => {
let i = 0;
for (; i < syncEvents.length && syncEvents[i].isFulfilled(); i++) {
// find index of first unfulfilled promise
}
syncEvents[i].resolve(state);
});
await client!.startClient();
expect(await syncEvents[0].promise).toBe(SyncState.Error);
jest.runAllTimers(); // this will skip forward to trigger the keepAlive/sync
expect(await syncEvents[1].promise).toBe(SyncState.Error);
jest.runAllTimers(); // this will skip forward to trigger the keepAlive/sync
expect(await syncEvents[2].promise).toBe(SyncState.Prepared);
jest.runAllTimers(); // this will skip forward to trigger the keepAlive/sync
expect(await syncEvents[3].promise).toBe(SyncState.Syncing);
jest.runAllTimers(); // this will skip forward to trigger the keepAlive/sync
expect(await syncEvents[4].promise).toBe(SyncState.Syncing);
});
it("should stop sync keep alive when client is stopped.", async () => {
jest.useFakeTimers();
fetchMock.config.overwriteRoutes = false;
fetchMock
.getOnce("end:versions", {}) // first version check without credentials needs to succeed
.get("end:versions", unknownTokenErrorData) // further version checks fails with 401
.get("end:pushrules/", 401) // fails with 401 without an error. This does happen in practice e.g. with Synapse
.post("end:logout", unknownTokenErrorData) // just to keep up a consistent scenario. Does not have a real effect for this testcase
.post("end:filter", 401); // just to keep up a consistent scenario. Does not have a real effect for this testcase
const firstSyncEvent = queryablePromise<SyncState>();
const secondSyncEvent = queryablePromise<SyncState>();
client!.on(ClientEvent.Sync, (state: SyncState, lastState: SyncState | null) => {
if (firstSyncEvent.isFulfilled()) secondSyncEvent.resolve(state);
firstSyncEvent.resolve(state);
});
await client!.startClient();
const logoutDone = queryablePromise();
client!
.logout(true)
.then(() => {
logoutDone.resolve();
})
.catch((e) => {
logoutDone.resolve();
});
const syntState = await firstSyncEvent.promise;
expect(syntState).toBe(SyncState.Error);
jest.runAllTimers(); // this will skip forward to trigger the keepAlive
jest.useRealTimers(); // we need real timer for the setTimout below to work
const timeoutPromise = makeQueryablePromise(new Promise<void>((res) => setTimeout(res, 1)));
await Promise.race([secondSyncEvent.promise, timeoutPromise.promise]);
// when syncing stopped, then the secondSyncEvent will never happen and the promise will not be resolved,
/// so the timeoutPromise will be resolved instead
expect(timeoutPromise.isFulfilled()).toBe(true);
expect(secondSyncEvent.isFulfilled()).toBe(false);
await logoutDone.promise; // wait for the logout to finish to prevent processing and logging after the test is done.
});
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,383 @@
/*
Copyright 2023 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 "fake-indexeddb/auto";
import HttpBackend from "matrix-mock-request";
import {
Category,
ClientEvent,
EventType,
ISyncResponse,
MatrixClient,
MatrixEvent,
NotificationCountType,
RelationType,
Room,
} from "../../src";
import { TestClient } from "../TestClient";
import { ReceiptType } from "../../src/@types/read_receipts";
import { mkThread } from "../test-utils/thread";
import { SyncState } from "../../src/sync";
describe("MatrixClient syncing", () => {
const userA = "@alice:localhost";
const userB = "@bob:localhost";
const selfUserId = userA;
const selfAccessToken = "aseukfgwef";
let client: MatrixClient | undefined;
let httpBackend: HttpBackend | undefined;
const setupTestClient = (): [MatrixClient, HttpBackend] => {
const testClient = new TestClient(selfUserId, "DEVICE", selfAccessToken);
const httpBackend = testClient.httpBackend;
const client = testClient.client;
httpBackend!.when("GET", "/versions").respond(200, {});
httpBackend!.when("GET", "/pushrules").respond(200, {});
httpBackend!.when("POST", "/filter").respond(200, { filter_id: "a filter id" });
return [client, httpBackend];
};
beforeEach(() => {
[client, httpBackend] = setupTestClient();
});
afterEach(() => {
httpBackend!.verifyNoOutstandingExpectation();
client!.stopClient();
return httpBackend!.stop();
});
it("reactions in thread set the correct timeline to unread", async () => {
const roomId = "!room:localhost";
// start the client, and wait for it to initialise
httpBackend!.when("GET", "/sync").respond(200, {
next_batch: "s_5_3",
rooms: {
[Category.Join]: {},
[Category.Leave]: {},
[Category.Invite]: {},
},
});
client!.startClient({ threadSupport: true });
await Promise.all([
httpBackend?.flushAllExpected(),
new Promise<void>((resolve) => {
client!.on(ClientEvent.Sync, (state) => state === SyncState.Syncing && resolve());
}),
]);
const room = new Room(roomId, client!, selfUserId);
jest.spyOn(client!, "getRoom").mockImplementation((id) => (id === roomId ? room : null));
const thread = mkThread({ room, client: client!, authorId: selfUserId, participantUserIds: [selfUserId] });
const threadReply = thread.events.at(-1)!;
await room.addLiveEvents([thread.rootEvent]);
// Initialize read receipt datastructure before testing the reaction
room.addReceiptToStructure(thread.rootEvent.getId()!, ReceiptType.Read, selfUserId, { ts: 1 }, false);
thread.thread.addReceiptToStructure(
threadReply.getId()!,
ReceiptType.Read,
selfUserId,
{ thread_id: thread.thread.id, ts: 1 },
false,
);
expect(room.getReadReceiptForUserId(selfUserId, false)?.eventId).toEqual(thread.rootEvent.getId());
expect(thread.thread.getReadReceiptForUserId(selfUserId, false)?.eventId).toEqual(threadReply.getId());
const reactionEventId = `$9-${Math.random()}-${Math.random()}`;
let lastEvent: MatrixEvent | null = null;
jest.spyOn(client! as any, "sendEventHttpRequest").mockImplementation((event) => {
lastEvent = event as MatrixEvent;
return { event_id: reactionEventId };
});
await client!.sendEvent(roomId, EventType.Reaction, {
"m.relates_to": {
rel_type: RelationType.Annotation,
event_id: threadReply.getId(),
key: "",
},
});
expect(lastEvent!.getId()).toEqual(reactionEventId);
room.handleRemoteEcho(new MatrixEvent(lastEvent!.event), lastEvent!);
// Our ideal state after this is the following:
//
// Room: [synthetic: threadroot, actual: threadroot]
// Thread: [synthetic: threadreaction, actual: threadreply]
//
// The reaction and reply are both in the thread, and their receipts should be isolated to the thread.
// The reaction has not been acknowledged in a dedicated read receipt message, so only the synthetic receipt
// should be updated.
// Ensure the synthetic receipt for the room has not been updated
expect(room.getReadReceiptForUserId(selfUserId, false)?.eventId).toEqual(thread.rootEvent.getId());
expect(room.getEventReadUpTo(selfUserId, false)).toEqual(thread.rootEvent.getId());
// Ensure the actual receipt for the room has not been updated
expect(room.getReadReceiptForUserId(selfUserId, true)?.eventId).toEqual(thread.rootEvent.getId());
expect(room.getEventReadUpTo(selfUserId, true)).toEqual(thread.rootEvent.getId());
// Ensure the synthetic receipt for the thread has been updated
expect(thread.thread.getReadReceiptForUserId(selfUserId, false)?.eventId).toEqual(reactionEventId);
expect(thread.thread.getEventReadUpTo(selfUserId, false)).toEqual(reactionEventId);
// Ensure the actual receipt for the thread has not been updated
expect(thread.thread.getReadReceiptForUserId(selfUserId, true)?.eventId).toEqual(threadReply.getId());
expect(thread.thread.getEventReadUpTo(selfUserId, true)).toEqual(threadReply.getId());
});
describe("Stuck unread notifications integration tests", () => {
const ROOM_ID = "!room:localhost";
const syncData = getSampleStuckNotificationSyncResponse(ROOM_ID);
it("resets notifications if the last event originates from the logged in user", async () => {
httpBackend!
.when("GET", "/sync")
.check((req) => {
expect(req.queryParams!.filter).toEqual("a filter id");
})
.respond(200, syncData);
client!.store.getSavedSyncToken = jest.fn().mockResolvedValue("this-is-a-token");
client!.startClient({ initialSyncLimit: 1 });
await httpBackend!.flushAllExpected();
const room = client?.getRoom(ROOM_ID);
expect(room).toBeInstanceOf(Room);
expect(room?.getUnreadNotificationCount(NotificationCountType.Total)).toBe(0);
});
});
function getSampleStuckNotificationSyncResponse(roomId: string): Partial<ISyncResponse> {
return {
next_batch: "batch_token",
rooms: {
[Category.Join]: {
[roomId]: {
timeline: {
events: [
{
content: {
room_version: "9",
},
origin_server_ts: 1,
sender: userB,
state_key: "",
type: "m.room.create",
event_id: "$event1",
},
{
content: {
avatar_url: "",
displayname: userB,
membership: "join",
},
origin_server_ts: 2,
sender: userB,
state_key: userB,
type: "m.room.member",
event_id: "$event2",
},
{
content: {
ban: 50,
events: {
"m.room.avatar": 50,
"m.room.canonical_alias": 50,
"m.room.encryption": 100,
"m.room.history_visibility": 100,
"m.room.name": 50,
"m.room.power_levels": 100,
"m.room.server_acl": 100,
"m.room.tombstone": 100,
},
events_default: 0,
historical: 100,
invite: 0,
kick: 50,
redact: 50,
state_default: 50,
users: {
[userA]: 100,
[userB]: 100,
},
users_default: 0,
},
origin_server_ts: 3,
sender: userB,
state_key: "",
type: "m.room.power_levels",
event_id: "$event3",
},
{
content: {
join_rule: "invite",
},
origin_server_ts: 4,
sender: userB,
state_key: "",
type: "m.room.join_rules",
event_id: "$event4",
},
{
content: {
history_visibility: "shared",
},
origin_server_ts: 5,
sender: userB,
state_key: "",
type: "m.room.history_visibility",
event_id: "$event5",
},
{
content: {
guest_access: "can_join",
},
origin_server_ts: 6,
sender: userB,
state_key: "",
type: "m.room.guest_access",
unsigned: {
age: 1651569,
},
event_id: "$event6",
},
{
content: {
algorithm: "m.megolm.v1.aes-sha2",
},
origin_server_ts: 7,
sender: userB,
state_key: "",
type: "m.room.encryption",
event_id: "$event7",
},
{
content: {
avatar_url: "",
displayname: userA,
is_direct: true,
membership: "invite",
},
origin_server_ts: 8,
sender: userB,
state_key: userA,
type: "m.room.member",
event_id: "$event8",
},
{
content: {
msgtype: "m.text",
body: "hello",
},
origin_server_ts: 9,
sender: userB,
type: "m.room.message",
event_id: "$event9",
},
{
content: {
avatar_url: "",
displayname: userA,
membership: "join",
},
origin_server_ts: 10,
sender: userA,
state_key: userA,
type: "m.room.member",
event_id: "$event10",
},
{
content: {
msgtype: "m.text",
body: "world",
},
origin_server_ts: 11,
sender: userA,
type: "m.room.message",
event_id: "$event11",
},
],
prev_batch: "123",
limited: false,
},
state: {
events: [],
},
account_data: {
events: [
{
type: "m.fully_read",
content: {
event_id: "$dER5V1RCMxzAhHXQJoMjqyuoxpPtK2X6hCb9T8Jg2wU",
},
},
],
},
ephemeral: {
events: [
{
type: "m.receipt",
content: {
$event9: {
"m.read": {
[userA]: {
ts: 100,
},
},
"m.read.private": {
[userA]: {
ts: 100,
},
},
},
dER5V1RCMxzAhHXQJoMjqyuoxpPtK2X6hCb9T8Jg2wU: {
"m.read": {
[userB]: {
ts: 666,
},
},
},
},
},
],
},
unread_notifications: {
notification_count: 1,
highlight_count: 0,
},
summary: {
"m.joined_member_count": 2,
"m.invited_member_count": 0,
"m.heroes": [userB],
},
},
},
[Category.Leave]: {},
[Category.Invite]: {},
[Category.Knock]: {},
},
};
}
});
-170
View File
@@ -1,170 +0,0 @@
/*
Copyright 2022 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 { Account } from "@matrix-org/olm";
import { logger } from "../../src/logger";
import { decodeRecoveryKey } from "../../src/crypto/recoverykey";
import { IKeyBackupInfo, IKeyBackupSession } from "../../src/crypto/keybackup";
import { TestClient } from "../TestClient";
import { IEvent } from "../../src";
import { MatrixEvent, MatrixEventEvent } from "../../src/models/event";
const ROOM_ID = '!ROOM:ID';
const SESSION_ID = 'o+21hSjP+mgEmcfdslPsQdvzWnkdt0Wyo00Kp++R8Kc';
const ENCRYPTED_EVENT: Partial<IEvent> = {
type: 'm.room.encrypted',
content: {
algorithm: 'm.megolm.v1.aes-sha2',
sender_key: 'SENDER_CURVE25519',
session_id: SESSION_ID,
ciphertext: 'AwgAEjD+VwXZ7PoGPRS/H4kwpAsMp/g+WPvJVtPEKE8fmM9IcT/N'
+ 'CiwPb8PehecDKP0cjm1XO88k6Bw3D17aGiBHr5iBoP7oSw8CXULXAMTkBl'
+ 'mkufRQq2+d0Giy1s4/Cg5n13jSVrSb2q7VTSv1ZHAFjUCsLSfR0gxqcQs',
},
room_id: '!ROOM:ID',
event_id: '$event1',
origin_server_ts: 1507753886000,
};
const CURVE25519_KEY_BACKUP_DATA: IKeyBackupSession = {
first_message_index: 0,
forwarded_count: 0,
is_verified: false,
session_data: {
ciphertext: '2z2M7CZ+azAiTHN1oFzZ3smAFFt+LEOYY6h3QO3XXGdw'
+ '6YpNn/gpHDO6I/rgj1zNd4FoTmzcQgvKdU8kN20u5BWRHxaHTZ'
+ 'Slne5RxE6vUdREsBgZePglBNyG0AogR/PVdcrv/v18Y6rLM5O9'
+ 'SELmwbV63uV9Kuu/misMxoqbuqEdG7uujyaEKtjlQsJ5MGPQOy'
+ 'Syw7XrnesSwF6XWRMxcPGRV0xZr3s9PI350Wve3EncjRgJ9IGF'
+ 'ru1bcptMqfXgPZkOyGvrphHoFfoK7nY3xMEHUiaTRfRIjq8HNV'
+ '4o8QY1qmWGnxNBQgOlL8MZlykjg3ULmQ3DtFfQPj/YYGS3jzxv'
+ 'C+EBjaafmsg+52CTeK3Rswu72PX450BnSZ1i3If4xWAUKvjTpe'
+ 'Ug5aDLqttOv1pITolTJDw5W/SD+b5rjEKg1CFCHGEGE9wwV3Nf'
+ 'QHVCQL+dfpd7Or0poy4dqKMAi3g0o3Tg7edIF8d5rREmxaALPy'
+ 'iie8PHD8mj/5Y0GLqrac4CD6+Mop7eUTzVovprjg',
mac: '5lxYBHQU80M',
ephemeral: '/Bn0A4UMFwJaDDvh0aEk1XZj3k1IfgCxgFY9P9a0b14',
},
};
const CURVE25519_BACKUP_INFO: IKeyBackupInfo = {
algorithm: "m.megolm_backup.v1.curve25519-aes-sha2",
version: "1",
auth_data: {
public_key: "hSDwCYkwp1R0i33ctD73Wg2/Og0mOBr066SpjqqbTmo",
},
};
const RECOVERY_KEY = "EsTc LW2K PGiF wKEA 3As5 g5c4 BXwk qeeJ ZJV8 Q9fu gUMN UE4d";
/**
* start an Olm session with a given recipient
*/
function createOlmSession(olmAccount: Olm.Account, recipientTestClient: TestClient): Promise<Olm.Session> {
return recipientTestClient.awaitOneTimeKeyUpload().then((keys) => {
const otkId = Object.keys(keys)[0];
const otk = keys[otkId];
const session = new global.Olm.Session();
session.create_outbound(
olmAccount, recipientTestClient.getDeviceKey(), otk.key,
);
return session;
});
}
describe("megolm key backups", function() {
if (!global.Olm) {
logger.warn('not running megolm tests: Olm not present');
return;
}
const Olm = global.Olm;
let testOlmAccount: Olm.Account;
let aliceTestClient: TestClient;
const setupTestClient = (): [Account, TestClient] => {
const aliceTestClient = new TestClient(
"@alice:localhost", "xzcvb", "akjgkrgjs",
);
const testOlmAccount = new Olm.Account();
testOlmAccount!.create();
return [testOlmAccount, aliceTestClient];
};
beforeAll(function() {
return Olm.init();
});
beforeEach(async function() {
[testOlmAccount, aliceTestClient] = setupTestClient();
await aliceTestClient!.client.initCrypto();
aliceTestClient!.client.crypto!.backupManager.backupInfo = CURVE25519_BACKUP_INFO;
});
afterEach(function() {
return aliceTestClient!.stop();
});
it("Alice checks key backups when receiving a message she can't decrypt", function() {
const syncResponse = {
next_batch: 1,
rooms: {
join: {},
},
};
syncResponse.rooms.join[ROOM_ID] = {
timeline: {
events: [ENCRYPTED_EVENT],
},
};
return aliceTestClient!.start().then(() => {
return createOlmSession(testOlmAccount, aliceTestClient);
}).then(() => {
const privkey = decodeRecoveryKey(RECOVERY_KEY);
return aliceTestClient!.client!.crypto!.storeSessionBackupPrivateKey(privkey);
}).then(() => {
aliceTestClient!.httpBackend.when("GET", "/sync").respond(200, syncResponse);
aliceTestClient!.expectKeyBackupQuery(
ROOM_ID,
SESSION_ID,
200,
CURVE25519_KEY_BACKUP_DATA,
);
return aliceTestClient!.httpBackend.flushAllExpected();
}).then(function(): Promise<MatrixEvent> {
const room = aliceTestClient!.client.getRoom(ROOM_ID)!;
const event = room.getLiveTimeline().getEvents()[0];
if (event.getContent()) {
return Promise.resolve(event);
}
return new Promise((resolve, reject) => {
event.once(MatrixEventEvent.Decrypted, (ev) => {
logger.log(`${Date.now()} event ${event.getId()} now decrypted`);
resolve(ev);
});
});
}).then((event) => {
expect(event.getContent()).toEqual('testytest');
});
});
});
File diff suppressed because it is too large Load Diff
+436 -162
View File
@@ -20,16 +20,29 @@ import { fail } from "assert";
import { SlidingSync, SlidingSyncEvent, MSC3575RoomData, SlidingSyncState, Extension } from "../../src/sliding-sync";
import { TestClient } from "../TestClient";
import { IRoomEvent, IStateEvent } from "../../src/sync-accumulator";
import { IRoomEvent, IStateEvent } from "../../src";
import {
MatrixClient, MatrixEvent, NotificationCountType, JoinRule, MatrixError,
EventType, IPushRules, PushRuleKind, TweakName, ClientEvent, RoomMemberEvent,
MatrixClient,
MatrixEvent,
NotificationCountType,
JoinRule,
MatrixError,
EventType,
IPushRules,
PushRuleKind,
TweakName,
ClientEvent,
RoomMemberEvent,
RoomEvent,
Room,
IRoomTimelineData,
} from "../../src";
import { SlidingSyncSdk } from "../../src/sliding-sync-sdk";
import { SyncState } from "../../src/sync";
import { IStoredClientOpts } from "../../src/client";
import { SyncApiOptions, SyncState } from "../../src/sync";
import { IStoredClientOpts } from "../../src";
import { logger } from "../../src/logger";
import { emitPromise } from "../test-utils/test-utils";
import { defer } from "../../src/utils";
describe("SlidingSyncSdk", () => {
let client: MatrixClient | undefined;
@@ -40,10 +53,9 @@ describe("SlidingSyncSdk", () => {
const selfAccessToken = "aseukfgwef";
const mockifySlidingSync = (s: SlidingSync): SlidingSync => {
s.getList = jest.fn();
s.getListParams = jest.fn();
s.getListData = jest.fn();
s.getRoomSubscriptions = jest.fn();
s.listLength = jest.fn();
s.modifyRoomSubscriptionInfo = jest.fn();
s.modifyRoomSubscriptions = jest.fn();
s.registerExtension = jest.fn();
@@ -67,7 +79,7 @@ describe("SlidingSyncSdk", () => {
event_id: "$" + eventIdCounter,
};
};
const mkOwnStateEvent = (evType: string, content: object, stateKey = ''): IStateEvent => {
const mkOwnStateEvent = (evType: string, content: object, stateKey = ""): IStateEvent => {
eventIdCounter++;
return {
type: evType,
@@ -97,19 +109,20 @@ describe("SlidingSyncSdk", () => {
};
// assign client/httpBackend globals
const setupClient = async (testOpts?: Partial<IStoredClientOpts&{withCrypto: boolean}>) => {
const setupClient = async (testOpts?: Partial<IStoredClientOpts & { withCrypto: boolean }>) => {
testOpts = testOpts || {};
const syncOpts: SyncApiOptions = {};
const testClient = new TestClient(selfUserId, "DEVICE", selfAccessToken);
httpBackend = testClient.httpBackend;
client = testClient.client;
mockSlidingSync = mockifySlidingSync(new SlidingSync("", [], {}, client, 0));
mockSlidingSync = mockifySlidingSync(new SlidingSync("", new Map(), {}, client, 0));
if (testOpts.withCrypto) {
httpBackend!.when("GET", "/room_keys/version").respond(404, {});
await client!.initCrypto();
testOpts.crypto = client!.crypto;
syncOpts.cryptoCallbacks = syncOpts.crypto = client!.crypto;
}
httpBackend!.when("GET", "/_matrix/client/r0/pushrules").respond(200, {});
sdk = new SlidingSyncSdk(mockSlidingSync, client, testOpts);
httpBackend!.when("GET", "/_matrix/client/v3/pushrules").respond(200, {});
sdk = new SlidingSyncSdk(mockSlidingSync, client, testOpts, syncOpts);
};
// tear down client/httpBackend globals
@@ -119,13 +132,13 @@ describe("SlidingSyncSdk", () => {
};
// find an extension on a SlidingSyncSdk instance
const findExtension = (name: string): Extension => {
const findExtension = (name: string): Extension<any, any> => {
expect(mockSlidingSync!.registerExtension).toHaveBeenCalled();
const mockFn = mockSlidingSync!.registerExtension as jest.Mock;
// find the extension
for (let i = 0; i < mockFn.mock.calls.length; i++) {
const calledExtension = mockFn.mock.calls[i][0] as Extension;
if (calledExtension && calledExtension.name() === name) {
const calledExtension = mockFn.mock.calls[i][0] as Extension<any, any>;
if (calledExtension?.name() === name) {
return calledExtension;
}
}
@@ -141,11 +154,11 @@ describe("SlidingSyncSdk", () => {
const hasSynced = sdk!.sync();
await httpBackend!.flushAllExpected();
await hasSynced;
expect(mockSlidingSync!.start).toBeCalled();
expect(mockSlidingSync!.start).toHaveBeenCalled();
});
it("can stop()", async () => {
sdk!.stop();
expect(mockSlidingSync!.stop).toBeCalled();
expect(mockSlidingSync!.stop).toHaveBeenCalled();
});
});
@@ -170,11 +183,12 @@ describe("SlidingSyncSdk", () => {
const roomE = "!e_with_invite:localhost";
const roomF = "!f_calc_room_name:localhost";
const roomG = "!g_join_invite_counts:localhost";
const roomH = "!g_num_live:localhost";
const data: Record<string, MSC3575RoomData> = {
[roomA]: {
name: "A",
required_state: [
mkOwnStateEvent(EventType.RoomCreate, { creator: selfUserId }, ""),
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnStateEvent(EventType.RoomName, { name: "A" }, ""),
@@ -189,12 +203,11 @@ describe("SlidingSyncSdk", () => {
name: "B",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, { creator: selfUserId }, ""),
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello B" }),
mkOwnEvent(EventType.RoomMessage, { body: "world B" }),
],
initial: true,
},
@@ -202,7 +215,7 @@ describe("SlidingSyncSdk", () => {
name: "C",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, { creator: selfUserId }, ""),
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello C" }),
@@ -215,7 +228,7 @@ describe("SlidingSyncSdk", () => {
name: "D",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, { creator: selfUserId }, ""),
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello D" }),
@@ -251,7 +264,7 @@ describe("SlidingSyncSdk", () => {
[roomF]: {
name: "#foo:localhost",
required_state: [
mkOwnStateEvent(EventType.RoomCreate, { creator: selfUserId }, ""),
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnStateEvent(EventType.RoomCanonicalAlias, { alias: "#foo:localhost" }, ""),
@@ -267,7 +280,7 @@ describe("SlidingSyncSdk", () => {
name: "G",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, { creator: selfUserId }, ""),
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
],
@@ -275,74 +288,111 @@ describe("SlidingSyncSdk", () => {
invited_count: 2,
initial: true,
},
[roomH]: {
name: "H",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "live event" }),
],
initial: true,
num_live: 1,
},
};
it("can be created with required_state and timeline", () => {
it("can be created with required_state and timeline", async () => {
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomA, data[roomA]);
await emitPromise(client!, ClientEvent.Room);
const gotRoom = client!.getRoom(roomA);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(gotRoom.name).toEqual(data[roomA].name);
expect(gotRoom.getMyMembership()).toEqual("join");
assertTimelineEvents(gotRoom.getLiveTimeline().getEvents().slice(-2), data[roomA].timeline);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.name).toEqual(data[roomA].name);
expect(gotRoom!.getMyMembership()).toEqual("join");
assertTimelineEvents(gotRoom!.getLiveTimeline().getEvents().slice(-2), data[roomA].timeline);
});
it("can be created with timeline only", () => {
it("can be created with timeline only", async () => {
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomB, data[roomB]);
await emitPromise(client!, ClientEvent.Room);
const gotRoom = client!.getRoom(roomB);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(gotRoom.name).toEqual(data[roomB].name);
expect(gotRoom.getMyMembership()).toEqual("join");
assertTimelineEvents(gotRoom.getLiveTimeline().getEvents().slice(-5), data[roomB].timeline);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.name).toEqual(data[roomB].name);
expect(gotRoom!.getMyMembership()).toEqual("join");
assertTimelineEvents(gotRoom!.getLiveTimeline().getEvents().slice(-5), data[roomB].timeline);
});
it("can be created with a highlight_count", () => {
it("can be created with a highlight_count", async () => {
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomC, data[roomC]);
await emitPromise(client!, ClientEvent.Room);
const gotRoom = client!.getRoom(roomC);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(
gotRoom.getUnreadNotificationCount(NotificationCountType.Highlight),
).toEqual(data[roomC].highlight_count);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.getUnreadNotificationCount(NotificationCountType.Highlight)).toEqual(
data[roomC].highlight_count,
);
});
it("can be created with a notification_count", () => {
it("can be created with a notification_count", async () => {
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomD, data[roomD]);
await emitPromise(client!, ClientEvent.Room);
const gotRoom = client!.getRoom(roomD);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(
gotRoom.getUnreadNotificationCount(NotificationCountType.Total),
).toEqual(data[roomD].notification_count);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.getUnreadNotificationCount(NotificationCountType.Total)).toEqual(
data[roomD].notification_count,
);
});
it("can be created with an invited/joined_count", () => {
it("can be created with an invited/joined_count", async () => {
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomG, data[roomG]);
await emitPromise(client!, ClientEvent.Room);
const gotRoom = client!.getRoom(roomG);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(gotRoom.getInvitedMemberCount()).toEqual(data[roomG].invited_count);
expect(gotRoom.getJoinedMemberCount()).toEqual(data[roomG].joined_count);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.getInvitedMemberCount()).toEqual(data[roomG].invited_count);
expect(gotRoom!.getJoinedMemberCount()).toEqual(data[roomG].joined_count);
});
it("can be created with invite_state", () => {
it("can be created with live events", async () => {
const seenLiveEventDeferred = defer<boolean>();
const listener = (
ev: MatrixEvent,
room?: Room,
toStartOfTimeline?: boolean,
deleted?: boolean,
timelineData?: IRoomTimelineData,
) => {
if (timelineData?.liveEvent) {
assertTimelineEvents([ev], data[roomH].timeline.slice(-1));
seenLiveEventDeferred.resolve(true);
}
};
client!.on(RoomEvent.Timeline, listener);
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomH, data[roomH]);
await emitPromise(client!, ClientEvent.Room);
client!.off(RoomEvent.Timeline, listener);
const gotRoom = client!.getRoom(roomH);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.name).toEqual(data[roomH].name);
expect(gotRoom!.getMyMembership()).toEqual("join");
// check the entire timeline is correct
assertTimelineEvents(gotRoom!.getLiveTimeline().getEvents(), data[roomH].timeline);
await expect(seenLiveEventDeferred.promise).resolves.toBeTruthy();
});
it("can be created with invite_state", async () => {
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomE, data[roomE]);
await emitPromise(client!, ClientEvent.Room);
const gotRoom = client!.getRoom(roomE);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(gotRoom.getMyMembership()).toEqual("invite");
expect(gotRoom.currentState.getJoinRule()).toEqual(JoinRule.Invite);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.getMyMembership()).toEqual("invite");
expect(gotRoom!.currentState.getJoinRule()).toEqual(JoinRule.Invite);
});
it("uses the 'name' field to caluclate the room name", () => {
it("uses the 'name' field to caluclate the room name", async () => {
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomF, data[roomF]);
await emitPromise(client!, ClientEvent.Room);
const gotRoom = client!.getRoom(roomF);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(
gotRoom.name,
).toEqual(data[roomF].name);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.name).toEqual(data[roomF].name);
});
describe("updating", () => {
@@ -354,29 +404,33 @@ describe("SlidingSyncSdk", () => {
name: data[roomA].name,
});
const gotRoom = client!.getRoom(roomA);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(gotRoom).toBeTruthy();
if (gotRoom == null) {
return;
}
const newTimeline = data[roomA].timeline;
newTimeline.push(newEvent);
assertTimelineEvents(gotRoom.getLiveTimeline().getEvents().slice(-3), newTimeline);
assertTimelineEvents(gotRoom!.getLiveTimeline().getEvents().slice(-3), newTimeline);
});
it("can update with a new required_state event", async () => {
let gotRoom = client!.getRoom(roomB);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(gotRoom.getJoinRule()).toEqual(JoinRule.Invite); // default
expect(gotRoom).toBeTruthy();
if (gotRoom == null) {
return;
}
expect(gotRoom!.getJoinRule()).toEqual(JoinRule.Invite); // default
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomB, {
required_state: [
mkOwnStateEvent("m.room.join_rules", { join_rule: "restricted" }, ""),
],
required_state: [mkOwnStateEvent("m.room.join_rules", { join_rule: "restricted" }, "")],
timeline: [],
name: data[roomB].name,
});
gotRoom = client!.getRoom(roomB);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(gotRoom.getJoinRule()).toEqual(JoinRule.Restricted);
expect(gotRoom).toBeTruthy();
if (gotRoom == null) {
return;
}
expect(gotRoom!.getJoinRule()).toEqual(JoinRule.Restricted);
});
it("can update with a new highlight_count", async () => {
@@ -387,11 +441,11 @@ describe("SlidingSyncSdk", () => {
highlight_count: 1,
});
const gotRoom = client!.getRoom(roomC);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(
gotRoom.getUnreadNotificationCount(NotificationCountType.Highlight),
).toEqual(1);
expect(gotRoom).toBeTruthy();
if (gotRoom == null) {
return;
}
expect(gotRoom!.getUnreadNotificationCount(NotificationCountType.Highlight)).toEqual(1);
});
it("can update with a new notification_count", async () => {
@@ -402,11 +456,11 @@ describe("SlidingSyncSdk", () => {
notification_count: 1,
});
const gotRoom = client!.getRoom(roomD);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(
gotRoom.getUnreadNotificationCount(NotificationCountType.Total),
).toEqual(1);
expect(gotRoom).toBeTruthy();
if (gotRoom == null) {
return;
}
expect(gotRoom!.getUnreadNotificationCount(NotificationCountType.Total)).toEqual(1);
});
it("can update with a new joined_count", () => {
@@ -417,9 +471,11 @@ describe("SlidingSyncSdk", () => {
joined_count: 1,
});
const gotRoom = client!.getRoom(roomG);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(gotRoom.getJoinedMemberCount()).toEqual(1);
expect(gotRoom).toBeTruthy();
if (gotRoom == null) {
return;
}
expect(gotRoom!.getJoinedMemberCount()).toEqual(1);
});
// Regression test for a bug which caused the timeline entries to be out-of-order
@@ -441,16 +497,25 @@ describe("SlidingSyncSdk", () => {
initial: true, // e.g requested via room subscription
});
const gotRoom = client!.getRoom(roomA);
expect(gotRoom).toBeDefined();
if (gotRoom == null) { return; }
expect(gotRoom).toBeTruthy();
if (gotRoom == null) {
return;
}
logger.log("want:", oldTimeline.map((e) => (e.type + " : " + (e.content || {}).body)));
logger.log("got:", gotRoom.getLiveTimeline().getEvents().map(
(e) => (e.getType() + " : " + e.getContent().body)),
logger.log(
"want:",
oldTimeline.map((e) => e.type + " : " + (e.content || {}).body),
);
logger.log(
"got:",
gotRoom
.getLiveTimeline()
.getEvents()
.map((e) => e.getType() + " : " + e.getContent().body),
);
// we expect the timeline now to be oldTimeline (so the old events are in fact old)
assertTimelineEvents(gotRoom.getLiveTimeline().getEvents(), oldTimeline);
assertTimelineEvents(gotRoom!.getLiveTimeline().getEvents(), oldTimeline);
});
});
});
@@ -466,43 +531,56 @@ describe("SlidingSyncSdk", () => {
const FAILED_SYNC_ERROR_THRESHOLD = 3; // would be nice to export the const in the actual class...
it("emits SyncState.Reconnecting when < FAILED_SYNC_ERROR_THRESHOLD & SyncState.Error when over", async () => {
mockSlidingSync!.emit(
SlidingSyncEvent.Lifecycle, SlidingSyncState.Complete,
{ pos: "h", lists: [], rooms: {}, extensions: {} }, null,
);
mockSlidingSync!.emit(SlidingSyncEvent.Lifecycle, SlidingSyncState.Complete, {
pos: "h",
lists: {},
rooms: {},
extensions: {},
});
expect(sdk!.getSyncState()).toEqual(SyncState.Syncing);
mockSlidingSync!.emit(
SlidingSyncEvent.Lifecycle, SlidingSyncState.RequestFinished, null, new Error("generic"),
SlidingSyncEvent.Lifecycle,
SlidingSyncState.RequestFinished,
null,
new Error("generic"),
);
expect(sdk!.getSyncState()).toEqual(SyncState.Reconnecting);
for (let i = 0; i < FAILED_SYNC_ERROR_THRESHOLD; i++) {
mockSlidingSync!.emit(
SlidingSyncEvent.Lifecycle, SlidingSyncState.RequestFinished, null, new Error("generic"),
SlidingSyncEvent.Lifecycle,
SlidingSyncState.RequestFinished,
null,
new Error("generic"),
);
}
expect(sdk!.getSyncState()).toEqual(SyncState.Error);
});
it("emits SyncState.Syncing after a previous SyncState.Error", async () => {
mockSlidingSync!.emit(
SlidingSyncEvent.Lifecycle,
SlidingSyncState.Complete,
{ pos: "i", lists: [], rooms: {}, extensions: {} },
null,
);
mockSlidingSync!.emit(SlidingSyncEvent.Lifecycle, SlidingSyncState.Complete, {
pos: "i",
lists: {},
rooms: {},
extensions: {},
});
expect(sdk!.getSyncState()).toEqual(SyncState.Syncing);
});
it("emits SyncState.Error immediately when receiving M_UNKNOWN_TOKEN and stops syncing", async () => {
expect(mockSlidingSync!.stop).not.toBeCalled();
mockSlidingSync!.emit(SlidingSyncEvent.Lifecycle, SlidingSyncState.RequestFinished, null, new MatrixError({
errcode: "M_UNKNOWN_TOKEN",
message: "Oh no your access token is no longer valid",
}));
expect(mockSlidingSync!.stop).not.toHaveBeenCalled();
mockSlidingSync!.emit(
SlidingSyncEvent.Lifecycle,
SlidingSyncState.RequestFinished,
null,
new MatrixError({
errcode: "M_UNKNOWN_TOKEN",
message: "Oh no your access token is no longer valid",
}),
);
expect(sdk!.getSyncState()).toEqual(SyncState.Error);
expect(mockSlidingSync!.stop).toBeCalled();
expect(mockSlidingSync!.stop).toHaveBeenCalled();
});
});
@@ -524,7 +602,7 @@ describe("SlidingSyncSdk", () => {
name: "Room with Invite",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, { creator: selfUserId }, ""),
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "invite" }, invitee),
@@ -533,16 +611,17 @@ describe("SlidingSyncSdk", () => {
await httpBackend!.flush("/profile", 1, 1000);
await emitPromise(client!, RoomMemberEvent.Name);
const room = client!.getRoom(roomId)!;
expect(room).toBeDefined();
expect(room).toBeTruthy();
const inviteeMember = room.getMember(invitee)!;
expect(inviteeMember).toBeDefined();
expect(inviteeMember).toBeTruthy();
expect(inviteeMember.getMxcAvatarUrl()).toEqual(inviteeProfile.avatar_url);
expect(inviteeMember.name).toEqual(inviteeProfile.displayname);
});
});
describe("ExtensionE2EE", () => {
let ext: Extension;
let ext: Extension<any, any>;
beforeAll(async () => {
await setupClient({
withCrypto: true,
@@ -552,56 +631,52 @@ describe("SlidingSyncSdk", () => {
await hasSynced;
ext = findExtension("e2ee");
});
afterAll(async () => {
// needed else we do some async operations in the background which can cause Jest to whine:
// "Cannot log after tests are done. Did you forget to wait for something async in your test?"
// Attempted to log "Saving device tracking data null"."
client!.crypto!.stop();
});
it("gets enabled on the initial request only", () => {
expect(ext.onRequest(true)).toEqual({
enabled: true,
});
expect(ext.onRequest(false)).toEqual(undefined);
});
it("can update device lists", () => {
client!.crypto!.processDeviceLists = jest.fn();
ext.onResponse({
device_lists: {
changed: ["@alice:localhost"],
left: ["@bob:localhost"],
},
});
// TODO: more assertions?
expect(client!.crypto!.processDeviceLists).toHaveBeenCalledWith({
changed: ["@alice:localhost"],
left: ["@bob:localhost"],
});
});
it("can update OTK counts", () => {
client!.crypto!.updateOneTimeKeyCount = jest.fn();
it("can update OTK counts and unused fallback keys", () => {
client!.crypto!.processKeyCounts = jest.fn();
ext.onResponse({
device_one_time_keys_count: {
signed_curve25519: 42,
},
});
expect(client!.crypto!.updateOneTimeKeyCount).toHaveBeenCalledWith(42);
ext.onResponse({
device_one_time_keys_count: {
not_signed_curve25519: 42,
// missing field -> default to 0
},
});
expect(client!.crypto!.updateOneTimeKeyCount).toHaveBeenCalledWith(0);
});
it("can update fallback keys", () => {
ext.onResponse({
device_unused_fallback_key_types: ["signed_curve25519"],
});
expect(client!.crypto!.getNeedsNewFallback()).toEqual(false);
ext.onResponse({
device_unused_fallback_key_types: ["not_signed_curve25519"],
});
expect(client!.crypto!.getNeedsNewFallback()).toEqual(true);
expect(client!.crypto!.processKeyCounts).toHaveBeenCalledWith({ signed_curve25519: 42 }, [
"signed_curve25519",
]);
});
});
describe("ExtensionAccountData", () => {
let ext: Extension;
let ext: Extension<any, any>;
beforeAll(async () => {
await setupClient();
const hasSynced = sdk!.sync();
@@ -609,12 +684,14 @@ describe("SlidingSyncSdk", () => {
await hasSynced;
ext = findExtension("account_data");
});
it("gets enabled on the initial request only", () => {
expect(ext.onRequest(true)).toEqual({
enabled: true,
});
expect(ext.onRequest(false)).toEqual(undefined);
});
it("processes global account data", async () => {
const globalType = "global_test";
const globalContent = {
@@ -631,20 +708,20 @@ describe("SlidingSyncSdk", () => {
],
});
globalData = client!.getAccountData(globalType)!;
expect(globalData).toBeDefined();
expect(globalData).toBeTruthy();
expect(globalData.getContent()).toEqual(globalContent);
});
it("processes rooms account data", async () => {
const roomId = "!room:id";
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomId, {
name: "Room with account data",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, { creator: selfUserId }, ""),
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello" }),
],
initial: true,
});
@@ -652,6 +729,7 @@ describe("SlidingSyncSdk", () => {
foo: "bar",
};
const roomType = "test";
await emitPromise(client!, ClientEvent.Room);
ext.onResponse({
rooms: {
[roomId]: [
@@ -663,11 +741,12 @@ describe("SlidingSyncSdk", () => {
},
});
const room = client!.getRoom(roomId)!;
expect(room).toBeDefined();
expect(room).toBeTruthy();
const event = room.getAccountData(roomType)!;
expect(event).toBeDefined();
expect(event).toBeTruthy();
expect(event.getContent()).toEqual(roomContent);
});
it("doesn't crash for unknown room account data", async () => {
const unknownRoomId = "!unknown:id";
const roomType = "tester";
@@ -687,22 +766,25 @@ describe("SlidingSyncSdk", () => {
expect(room).toBeNull();
expect(client!.getAccountData(roomType)).toBeUndefined();
});
it("can update push rules via account data", async () => {
const roomId = "!foo:bar";
const pushRulesContent: IPushRules = {
global: {
[PushRuleKind.RoomSpecific]: [{
enabled: true,
default: true,
pattern: "monkey",
actions: [
{
set_tweak: TweakName.Sound,
value: "default",
},
],
rule_id: roomId,
}],
[PushRuleKind.RoomSpecific]: [
{
enabled: true,
default: true,
pattern: "monkey",
actions: [
{
set_tweak: TweakName.Sound,
value: "default",
},
],
rule_id: roomId,
},
],
},
};
let pushRule = client!.getRoomPushRule("global", roomId);
@@ -719,8 +801,10 @@ describe("SlidingSyncSdk", () => {
expect(pushRule).toEqual(pushRulesContent.global[PushRuleKind.RoomSpecific]![0]);
});
});
describe("ExtensionToDevice", () => {
let ext: Extension;
let ext: Extension<any, any>;
beforeAll(async () => {
await setupClient();
const hasSynced = sdk!.sync();
@@ -728,12 +812,14 @@ describe("SlidingSyncSdk", () => {
await hasSynced;
ext = findExtension("to_device");
});
it("gets enabled with a limit on the initial request only", () => {
const reqJson: any = ext.onRequest(true);
expect(reqJson.enabled).toEqual(true);
expect(reqJson.limit).toBeGreaterThan(0);
expect(reqJson.since).toBeUndefined();
});
it("updates the since value", async () => {
ext.onResponse({
next_batch: "12345",
@@ -743,12 +829,14 @@ describe("SlidingSyncSdk", () => {
since: "12345",
});
});
it("can handle missing fields", async () => {
ext.onResponse({
next_batch: "23456",
// no events array
});
});
it("emits to-device events on the client", async () => {
const toDeviceType = "custom_test";
const toDeviceContent = {
@@ -771,17 +859,16 @@ describe("SlidingSyncSdk", () => {
});
expect(called).toBe(true);
});
it("can cancel key verification requests", async () => {
const seen: Record<string, boolean> = {};
client!.on(ClientEvent.ToDeviceEvent, (ev) => {
const evType = ev.getType();
expect(seen[evType]).toBeFalsy();
seen[evType] = true;
if (evType === "m.key.verification.start" || evType === "m.key.verification.request") {
expect(ev.isCancelled()).toEqual(true);
} else {
expect(ev.isCancelled()).toEqual(false);
}
expect(ev.isCancelled()).toEqual(
evType === "m.key.verification.start" || evType === "m.key.verification.request",
);
});
ext.onResponse({
next_batch: "45678",
@@ -810,4 +897,191 @@ describe("SlidingSyncSdk", () => {
});
});
});
describe("ExtensionTyping", () => {
let ext: Extension<any, any>;
beforeAll(async () => {
await setupClient();
const hasSynced = sdk!.sync();
await httpBackend!.flushAllExpected();
await hasSynced;
ext = findExtension("typing");
});
it("gets enabled on the initial request only", () => {
expect(ext.onRequest(true)).toEqual({
enabled: true,
});
expect(ext.onRequest(false)).toEqual(undefined);
});
it("processes typing notifications", async () => {
const roomId = "!room:id";
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomId, {
name: "Room with typing",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello" }),
],
initial: true,
});
await emitPromise(client!, ClientEvent.Room);
const room = client!.getRoom(roomId)!;
expect(room).toBeTruthy();
expect(room.getMember(selfUserId)?.typing).toEqual(false);
ext.onResponse({
rooms: {
[roomId]: {
type: EventType.Typing,
content: {
user_ids: [selfUserId],
},
},
},
});
expect(room.getMember(selfUserId)?.typing).toEqual(true);
ext.onResponse({
rooms: {
[roomId]: {
type: EventType.Typing,
content: {
user_ids: [],
},
},
},
});
expect(room.getMember(selfUserId)?.typing).toEqual(false);
});
it("gracefully handles missing rooms and members when typing", async () => {
const roomId = "!room:id";
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomId, {
name: "Room with typing",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello" }),
],
initial: true,
});
const room = client!.getRoom(roomId)!;
expect(room).toBeTruthy();
expect(room.getMember(selfUserId)?.typing).toEqual(false);
ext.onResponse({
rooms: {
[roomId]: {
type: EventType.Typing,
content: {
user_ids: ["@someone:else"],
},
},
},
});
expect(room.getMember(selfUserId)?.typing).toEqual(false);
ext.onResponse({
rooms: {
"!something:else": {
type: EventType.Typing,
content: {
user_ids: [selfUserId],
},
},
},
});
expect(room.getMember(selfUserId)?.typing).toEqual(false);
});
});
describe("ExtensionReceipts", () => {
let ext: Extension<any, any>;
const generateReceiptResponse = (
userId: string,
roomId: string,
eventId: string,
recType: string,
ts: number,
) => {
return {
rooms: {
[roomId]: {
type: EventType.Receipt,
content: {
[eventId]: {
[recType]: {
[userId]: {
ts: ts,
},
},
},
},
},
},
};
};
beforeAll(async () => {
await setupClient();
const hasSynced = sdk!.sync();
await httpBackend!.flushAllExpected();
await hasSynced;
ext = findExtension("receipts");
});
it("gets enabled on the initial request only", () => {
expect(ext.onRequest(true)).toEqual({
enabled: true,
});
expect(ext.onRequest(false)).toEqual(undefined);
});
it("processes receipts", async () => {
const roomId = "!room:id";
const alice = "@alice:alice";
const lastEvent = mkOwnEvent(EventType.RoomMessage, { body: "hello" });
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomId, {
name: "Room with receipts",
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
{
type: EventType.RoomMember,
state_key: alice,
content: { membership: "join" },
sender: alice,
origin_server_ts: Date.now(),
event_id: "$alice",
},
lastEvent,
],
initial: true,
});
await emitPromise(client!, ClientEvent.Room);
const room = client!.getRoom(roomId)!;
expect(room).toBeTruthy();
expect(room.getReadReceiptForUserId(alice, true)).toBeNull();
ext.onResponse(generateReceiptResponse(alice, roomId, lastEvent.event_id, "m.read", 1234567));
const receipt = room.getReadReceiptForUserId(alice);
expect(receipt).toBeTruthy();
expect(receipt?.eventId).toEqual(lastEvent.event_id);
expect(receipt?.data.ts).toEqual(1234567);
expect(receipt?.data.thread_id).toBeFalsy();
});
it("gracefully handles missing rooms when receiving receipts", async () => {
const roomId = "!room:id";
const alice = "@alice:alice";
const eventId = "$something";
ext.onResponse(generateReceiptResponse(alice, roomId, eventId, "m.read", 1234567));
// we expect it not to crash
});
});
});
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -15,13 +15,13 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { logger } from '../src/logger';
import { logger } from "../src/logger";
// try to load the olm library.
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
global.Olm = require('@matrix-org/olm');
logger.log('loaded libolm');
globalThis.Olm = require("@matrix-org/olm");
logger.log("loaded libolm");
} catch (e) {
logger.warn("unable to run crypto tests: libolm not available");
logger.warn("unable to run crypto tests: libolm not available", e);
}
+7 -1
View File
@@ -16,4 +16,10 @@ limitations under the License.
import DOMException from "domexception";
global.DOMException = DOMException;
global.DOMException = DOMException as typeof global.DOMException;
jest.mock("../src/http-api/utils", () => ({
...jest.requireActual("../src/http-api/utils"),
// We mock timeoutSignal otherwise it causes tests to leave timers running
timeoutSignal: () => new AbortController().signal,
}));
+100
View File
@@ -0,0 +1,100 @@
/*
Copyright 2022 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.
*/
/* eslint-disable no-console */
class JestSlowTestReporter {
constructor(globalConfig, options) {
this._globalConfig = globalConfig;
this._options = options;
this._slowTests = [];
this._slowTestSuites = [];
}
onRunComplete() {
const displayResult = (result, isTestSuite) => {
if (!isTestSuite) console.log();
result.sort((a, b) => b.duration - a.duration);
const rootPathRegex = new RegExp(`^${process.cwd()}`);
const slowestTests = result.slice(0, this._options.numTests || 10);
const slowTestTime = this._slowTestTime(slowestTests);
const allTestTime = this._allTestTime(result);
const percentTime = (slowTestTime / allTestTime) * 100;
if (isTestSuite) {
console.log(
`Top ${slowestTests.length} slowest test suites (${slowTestTime / 1000} seconds,` +
` ${percentTime.toFixed(1)}% of total time):`,
);
} else {
console.log(
`Top ${slowestTests.length} slowest tests (${slowTestTime / 1000} seconds,` +
` ${percentTime.toFixed(1)}% of total time):`,
);
}
for (let i = 0; i < slowestTests.length; i++) {
const duration = slowestTests[i].duration;
const filePath = slowestTests[i].filePath.replace(rootPathRegex, ".");
if (isTestSuite) {
console.log(` ${duration / 1000} seconds ${filePath}`);
} else {
const fullName = slowestTests[i].fullName;
console.log(` ${fullName}`);
console.log(` ${duration / 1000} seconds ${filePath}`);
}
}
console.log();
};
displayResult(this._slowTests);
displayResult(this._slowTestSuites, true);
}
onTestResult(test, testResult) {
this._slowTestSuites.push({
duration: testResult.perfStats.runtime,
filePath: testResult.testFilePath,
});
for (let i = 0; i < testResult.testResults.length; i++) {
this._slowTests.push({
duration: testResult.testResults[i].duration,
fullName: testResult.testResults[i].fullName,
filePath: testResult.testFilePath,
});
}
}
_slowTestTime(slowestTests) {
let slowTestTime = 0;
for (let i = 0; i < slowestTests.length; i++) {
slowTestTime += slowestTests[i].duration;
}
return slowTestTime;
}
_allTestTime(result) {
let allTestTime = 0;
for (let i = 0; i < result.length; i++) {
allTestTime += result[i].duration;
}
return allTestTime;
}
}
module.exports = JestSlowTestReporter;
+164
View File
@@ -0,0 +1,164 @@
/*
Copyright 2023 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 debugFunc from "debug";
import { Debugger } from "debug";
import fetchMock from "fetch-mock-jest";
import type { IDeviceKeys, IOneTimeKey } from "../../src/@types/crypto";
/** Interface implemented by classes that intercept `/keys/upload` requests from test clients to catch the uploaded keys
*
* Common interface implemented by {@link TestClient} and {@link E2EKeyReceiver}
*/
export interface IE2EKeyReceiver {
/**
* get the uploaded ed25519 device key
*
* @returns base64 device key
*/
getSigningKey(): string;
/**
* get the uploaded curve25519 device key
*
* @returns base64 device key
*/
getDeviceKey(): string;
/**
* Wait for one-time-keys to be uploaded, then return them.
*
* @returns Promise for the one-time keys
*/
awaitOneTimeKeyUpload(): Promise<Record<string, IOneTimeKey>>;
}
/** E2EKeyReceiver: An object which intercepts `/keys/uploads` fetches via fetch-mock.
*
* It stashes the uploaded keys for use elsewhere in the tests.
*/
export class E2EKeyReceiver implements IE2EKeyReceiver {
private readonly debug: Debugger;
private deviceKeys: IDeviceKeys | null = null;
private oneTimeKeys: Record<string, IOneTimeKey> = {};
private readonly oneTimeKeysPromise: Promise<void>;
/**
* Construct a new E2EKeyReceiver.
*
* It will immediately register an intercept of `/keys/uploads` requests for the given homeserverUrl.
* Only /upload requests made to this server will be intercepted: this allows a single test to use more than one
* client and have the keys collected separately.
*
* @param homeserverUrl - the Homeserver Url of the client under test.
*/
public constructor(homeserverUrl: string) {
this.debug = debugFunc(`e2e-key-receiver:[${homeserverUrl}]`);
// set up a listener for /keys/upload.
this.oneTimeKeysPromise = new Promise((resolveOneTimeKeys) => {
const listener = (url: string, options: RequestInit) =>
this.onKeyUploadRequest(resolveOneTimeKeys, options);
fetchMock.post(new URL("/_matrix/client/v3/keys/upload", homeserverUrl).toString(), listener);
});
}
private async onKeyUploadRequest(onOnTimeKeysUploaded: () => void, options: RequestInit): Promise<object> {
const content = JSON.parse(options.body as string);
// device keys may only be uploaded once
if (content.device_keys && Object.keys(content.device_keys).length > 0) {
if (this.deviceKeys) {
throw new Error("Application attempted to upload E2E device keys multiple times");
}
this.debug(`received device keys`);
this.deviceKeys = content.device_keys;
}
if (content.one_time_keys && Object.keys(content.one_time_keys).length > 0) {
// this is a one-time-key upload
// if we already have a batch of one-time keys, then slow-roll the response,
// otherwise the client ends up tight-looping one-time-key-uploads and filling the logs with junk.
if (Object.keys(this.oneTimeKeys).length > 0) {
this.debug(`received second batch of one-time keys: blocking response`);
await new Promise(() => {});
}
this.debug(`received ${Object.keys(content.one_time_keys).length} one-time keys`);
Object.assign(this.oneTimeKeys, content.one_time_keys);
onOnTimeKeysUploaded();
}
return {
one_time_key_counts: {
signed_curve25519: Object.keys(this.oneTimeKeys).length,
},
};
}
/** Get the uploaded Ed25519 key
*
* If device keys have not yet been uploaded, throws an error
*/
public getSigningKey(): string {
if (!this.deviceKeys) {
throw new Error("Device keys not yet uploaded");
}
const keyIds = Object.keys(this.deviceKeys.keys).filter((v) => v.startsWith("ed25519:"));
if (keyIds.length != 1) {
throw new Error(`Expected exactly 1 ed25519 key uploaded, got ${keyIds}`);
}
return this.deviceKeys.keys[keyIds[0]];
}
/** Get the uploaded Curve25519 key
*
* If device keys have not yet been uploaded, throws an error
*/
public getDeviceKey(): string {
if (!this.deviceKeys) {
throw new Error("Device keys not yet uploaded");
}
const keyIds = Object.keys(this.deviceKeys.keys).filter((v) => v.startsWith("curve25519:"));
if (keyIds.length != 1) {
throw new Error(`Expected exactly 1 curve25519 key uploaded, got ${keyIds}`);
}
return this.deviceKeys.keys[keyIds[0]];
}
/**
* If the device keys have already been uploaded, return them. Else return null.
*/
public getUploadedDeviceKeys(): IDeviceKeys | null {
return this.deviceKeys;
}
/**
* If one-time keys have already been uploaded, return them. Otherwise,
* set up an expectation that the keys will be uploaded, and wait for
* that to happen.
*
* @returns Promise for the one-time keys
*/
public async awaitOneTimeKeyUpload(): Promise<Record<string, IOneTimeKey>> {
await this.oneTimeKeysPromise;
return this.oneTimeKeys;
}
}
+119
View File
@@ -0,0 +1,119 @@
/*
Copyright 2023 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 fetchMock from "fetch-mock-jest";
import { MapWithDefault } from "../../src/utils";
import { IDownloadKeyResult } from "../../src";
import { IDeviceKeys } from "../../src/@types/crypto";
import { E2EKeyReceiver } from "./E2EKeyReceiver";
/**
* An object which intercepts `/keys/query` fetches via fetch-mock.
*/
export class E2EKeyResponder {
private deviceKeysByUserByDevice = new MapWithDefault<string, Map<string, any>>(() => new Map());
private e2eKeyReceiversByUser = new Map<string, E2EKeyReceiver>();
private masterKeysByUser: Record<string, any> = {};
private selfSigningKeysByUser: Record<string, any> = {};
private userSigningKeysByUser: Record<string, any> = {};
/**
* Construct a new E2EKeyResponder.
*
* It will immediately register an intercept of `/keys/query` requests for the given homeserverUrl.
* Only /query requests made to this server will be intercepted: this allows a single test to use more than one
* client and have the keys collected separately.
*
* @param homeserverUrl - the Homeserver Url of the client under test.
*/
public constructor(homeserverUrl: string) {
// set up a listener for /keys/query.
const listener = (url: string, options: RequestInit) => this.onKeyQueryRequest(options);
fetchMock.post(new URL("/_matrix/client/v3/keys/query", homeserverUrl).toString(), listener);
}
private onKeyQueryRequest(options: RequestInit) {
const content = JSON.parse(options.body as string);
const usersToReturn = Object.keys(content["device_keys"]);
const response = {
device_keys: {} as { [userId: string]: any },
master_keys: {} as { [userId: string]: any },
self_signing_keys: {} as { [userId: string]: any },
user_signing_keys: {} as { [userId: string]: any },
failures: {} as { [serverName: string]: any },
};
for (const user of usersToReturn) {
const userKeys = this.deviceKeysByUserByDevice.get(user);
if (userKeys !== undefined) {
response.device_keys[user] = Object.fromEntries(userKeys.entries());
}
const e2eKeyReceiver = this.e2eKeyReceiversByUser.get(user);
if (e2eKeyReceiver !== undefined) {
const deviceKeys = e2eKeyReceiver.getUploadedDeviceKeys();
if (deviceKeys !== null) {
response.device_keys[user] ??= {};
response.device_keys[user][deviceKeys.device_id] = deviceKeys;
}
}
if (this.masterKeysByUser.hasOwnProperty(user)) {
response.master_keys[user] = this.masterKeysByUser[user];
}
if (this.selfSigningKeysByUser.hasOwnProperty(user)) {
response.self_signing_keys[user] = this.selfSigningKeysByUser[user];
}
if (this.userSigningKeysByUser.hasOwnProperty(user)) {
response.user_signing_keys[user] = this.userSigningKeysByUser[user];
}
}
return response;
}
/**
* Add a set of device keys for return by a future `/keys/query`, as if they had been `/upload`ed
*
* @param keys - device keys for this device.
*/
public addDeviceKeys(keys: IDeviceKeys) {
this.deviceKeysByUserByDevice.getOrCreate(keys.user_id).set(keys.device_id, keys);
}
/** Add a set of cross-signing keys for return by a future `/keys/query`, as if they had been `/keys/device_signing/upload`ed
*
* @param data cross-signing data
*/
public addCrossSigningData(
data: Pick<IDownloadKeyResult, "master_keys" | "self_signing_keys" | "user_signing_keys">,
) {
Object.assign(this.masterKeysByUser, data.master_keys);
Object.assign(this.selfSigningKeysByUser, data.self_signing_keys);
Object.assign(this.userSigningKeysByUser, data.user_signing_keys);
}
/**
* Add an E2EKeyReceiver to poll for uploaded keys
*
* Any keys which have been uploaded to the given `E2EKeyReceiver` at the time of the `/keys/query` request will
* be added to the response.
*
* @param e2eKeyReceiver
*/
public addKeyReceiver(userId: string, e2eKeyReceiver: E2EKeyReceiver) {
this.e2eKeyReceiversByUser.set(userId, e2eKeyReceiver);
}
}
+131
View File
@@ -0,0 +1,131 @@
/*
Copyright 2023 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 debugFunc from "debug";
import { Debugger } from "debug";
import fetchMock from "fetch-mock-jest";
import { MockResponse } from "fetch-mock";
/** Interface implemented by classes that intercept `/sync` requests from test clients
*
* Common interface implemented by {@link TestClient} and {@link SyncResponder}
*/
export interface ISyncResponder {
/** Next time we see a sync request (or immediately, if there is one waiting), send the given response
*
* @param response - response to /sync request
*/
sendOrQueueSyncResponse(response: object): void;
}
enum SyncResponderState {
IDLE,
WAITING_FOR_REQUEST,
WAITING_FOR_RESPONSE,
}
/** SyncResponder: An object which intercepts `/sync` fetches via fetch-mock.
*
* Two modes are possible:
* * A response can be queued up; the next call to `/sync` will return it.
* * If a call to `/sync` arrives before a response is queued, it will block until a call to {@link #sendOrQueueSyncResponse}.
*/
export class SyncResponder implements ISyncResponder {
private readonly debug: Debugger;
private state: SyncResponderState = SyncResponderState.IDLE;
/*
* properties that are only valid in WAITING_FOR_REQUEST
*/
/** the response to be sent when the request is made */
private pendingResponse: object | null = null;
/*
* properties that are only valid in WAITING_FOR_RESPONSE
*/
/** a callback to be called with a response once one is registered.
*
* It will release the /sync request and update the state.
*/
private onResponseReceived: ((response: object) => void) | null = null;
/**
* Construct a new SyncResponder.
*
* It will immediately register an intercept of `/sync` requests for the given homeserverUrl.
* Only /sync requests made to this server will be intercepted: this allows a single test to use more than one
* client and have overlapping /sync requests.
*
* @param homeserverUrl - the Homeserver Url of the client under test.
*/
public constructor(homeserverUrl: string) {
this.debug = debugFunc(`sync-responder:[${homeserverUrl}]`);
fetchMock.get("begin:" + new URL("/_matrix/client/v3/sync?", homeserverUrl).toString(), (_url, _options) =>
this.onSyncRequest(),
);
}
private async onSyncRequest(): Promise<MockResponse> {
switch (this.state) {
case SyncResponderState.IDLE: {
this.debug("Got /sync request: waiting for response to be ready");
const res = await new Promise<object>((resolve) => {
this.onResponseReceived = resolve;
this.state = SyncResponderState.WAITING_FOR_RESPONSE;
});
this.debug("Responding to /sync");
this.state = SyncResponderState.IDLE;
this.onResponseReceived = null;
return res;
}
case SyncResponderState.WAITING_FOR_REQUEST: {
this.debug("Got /sync request: responding immediately with queued response");
const res = this.pendingResponse!;
this.state = SyncResponderState.IDLE;
this.pendingResponse = null;
return res;
}
default:
// we must already be in WAITING_FOR_RESPONSE, ie we already have a /sync request in progress
throw new Error(`Got unexpected /sync request in state ${this.state}`);
}
}
/** Next time we see a sync request (or immediately, if there is one waiting), send the given response
*
* @param response - response to /sync request
*/
public sendOrQueueSyncResponse(response: object): void {
switch (this.state) {
case SyncResponderState.IDLE:
this.pendingResponse = response;
this.state = SyncResponderState.WAITING_FOR_REQUEST;
break;
case SyncResponderState.WAITING_FOR_RESPONSE:
this.onResponseReceived!(response);
break;
default:
// we already have a response queued
throw new Error(`Cannot queue more than one /sync response`);
}
}
}
+12 -21
View File
@@ -17,10 +17,7 @@ limitations under the License.
import { MatrixEvent } from "../../src";
import { M_BEACON, M_BEACON_INFO } from "../../src/@types/beacon";
import { LocationAssetType } from "../../src/@types/location";
import {
makeBeaconContent,
makeBeaconInfoContent,
} from "../../src/content-helpers";
import { makeBeaconContent, makeBeaconInfoContent } from "../../src/content-helpers";
type InfoContentProps = {
timeout: number;
@@ -44,13 +41,7 @@ export const makeBeaconInfoEvent = (
contentProps: Partial<InfoContentProps> = {},
eventId?: string,
): MatrixEvent => {
const {
timeout,
isLive,
description,
assetType,
timestamp,
} = {
const { timeout, isLive, description, assetType, timestamp } = {
...DEFAULT_INFO_CONTENT_PROPS,
...contentProps,
};
@@ -77,9 +68,9 @@ type ContentProps = {
description?: string;
};
const DEFAULT_CONTENT_PROPS: ContentProps = {
uri: 'geo:-36.24484561954707,175.46884959563613;u=10',
uri: "geo:-36.24484561954707,175.46884959563613;u=10",
timestamp: 123,
beaconInfoId: '$123',
beaconInfoId: "$123",
};
/**
@@ -87,10 +78,7 @@ const DEFAULT_CONTENT_PROPS: ContentProps = {
* all required properties are mocked
* override with contentProps
*/
export const makeBeaconEvent = (
sender: string,
contentProps: Partial<ContentProps> = {},
): MatrixEvent => {
export const makeBeaconEvent = (sender: string, contentProps: Partial<ContentProps> = {}): MatrixEvent => {
const { uri, timestamp, beaconInfoId, description } = {
...DEFAULT_CONTENT_PROPS,
...contentProps,
@@ -107,10 +95,13 @@ export const makeBeaconEvent = (
* Create a mock geolocation position
* defaults all required properties
*/
export const makeGeolocationPosition = (
{ timestamp, coords }:
{ timestamp?: number, coords: Partial<GeolocationCoordinates> },
): GeolocationPosition => ({
export const makeGeolocationPosition = ({
timestamp,
coords,
}: {
timestamp?: number;
coords: Partial<GeolocationCoordinates>;
}): GeolocationPosition => ({
timestamp: timestamp ?? 1647256791840,
coords: {
accuracy: 1,
+7 -8
View File
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import { MethodKeysOf, mocked, MockedObject } from "jest-mock";
import { MethodLikeKeys, mocked, MockedObject } from "jest-mock";
import { ClientEventHandlerMap, EmittedEvents, MatrixClient } from "../../src/client";
import { TypedEventEmitter } from "../../src/models/typed-event-emitter";
@@ -26,7 +26,7 @@ import { User } from "../../src/models/user";
* to MatrixClient events
*/
export class MockClientWithEventEmitter extends TypedEventEmitter<EmittedEvents, ClientEventHandlerMap> {
constructor(mockProperties: Partial<Record<MethodKeysOf<MatrixClient>, unknown>> = {}) {
constructor(mockProperties: Partial<Record<MethodLikeKeys<MatrixClient>, unknown>> = {}) {
super();
Object.assign(this, mockProperties);
}
@@ -44,7 +44,7 @@ export class MockClientWithEventEmitter extends TypedEventEmitter<EmittedEvents,
* ```
*/
export const getMockClientWithEventEmitter = (
mockProperties: Partial<Record<MethodKeysOf<MatrixClient>, unknown>>,
mockProperties: Partial<Record<MethodLikeKeys<MatrixClient>, unknown>>,
): MockedObject<MatrixClient> => {
const mock = mocked(new MockClientWithEventEmitter(mockProperties) as unknown as MatrixClient);
return mock;
@@ -58,11 +58,12 @@ export const getMockClientWithEventEmitter = (
});
* ```
*/
export const mockClientMethodsUser = (userId = '@alice:domain') => ({
export const mockClientMethodsUser = (userId = "@alice:domain") => ({
getUserId: jest.fn().mockReturnValue(userId),
getSafeUserId: jest.fn().mockReturnValue(userId),
getUser: jest.fn().mockReturnValue(new User(userId)),
isGuest: jest.fn().mockReturnValue(false),
mxcUrlToHttp: jest.fn().mockReturnValue('mock-mxcUrlToHttp'),
mxcUrlToHttp: jest.fn().mockReturnValue("mock-mxcUrlToHttp"),
credentials: { userId },
getThreePids: jest.fn().mockResolvedValue({ threepids: [] }),
getAccessToken: jest.fn(),
@@ -84,11 +85,9 @@ export const mockClientMethodsEvents = () => ({
/**
* Returns basic mocked client methods related to server support
*/
export const mockClientMethodsServer = (): Partial<Record<MethodKeysOf<MatrixClient>, unknown>> => ({
doesServerSupportSeparateAddAndBind: jest.fn(),
export const mockClientMethodsServer = (): Partial<Record<MethodLikeKeys<MatrixClient>, unknown>> => ({
getIdentityServerUrl: jest.fn(),
getHomeserverUrl: jest.fn(),
getCapabilities: jest.fn().mockReturnValue({}),
doesServerSupportUnstableFeature: jest.fn().mockResolvedValue(false),
});
+28
View File
@@ -0,0 +1,28 @@
/*
Copyright 2022 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.
*/
// Jest now uses @sinonjs/fake-timers which exposes tickAsync() and a number of
// other async methods which break the event loop, letting scheduled promise
// callbacks run. Unfortunately, Jest doesn't expose these, so we have to do
// it manually (this is what sinon does under the hood). We do both in a loop
// until the thing we expect happens: hopefully this is the least flakey way
// and avoids assuming anything about the app's behaviour.
const realSetTimeout = setTimeout;
export function flushPromises() {
return new Promise((r) => {
realSetTimeout(r, 1);
});
}
+92
View File
@@ -0,0 +1,92 @@
/*
Copyright 2023 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 fetchMock from "fetch-mock-jest";
import { KeyBackupInfo } from "../../src/crypto-api";
/**
* Mock out the endpoints that the js-sdk calls when we call `MatrixClient.start()`.
*
* @param homeserverUrl - the homeserver url for the client under test
*/
export function mockInitialApiRequests(homeserverUrl: string) {
fetchMock.getOnce(new URL("/_matrix/client/versions", homeserverUrl).toString(), { versions: ["v1.1"] });
fetchMock.getOnce(new URL("/_matrix/client/v3/pushrules/", homeserverUrl).toString(), {});
fetchMock.postOnce(new URL("/_matrix/client/v3/user/%40alice%3Alocalhost/filter", homeserverUrl).toString(), {
filter_id: "fid",
});
}
/**
* Mock the requests needed to set up cross signing
*
* Return 404 error for `GET _matrix/client/v3/user/:userId/account_data/:type` request
* Return `{}` for `POST _matrix/client/v3/keys/signatures/upload` request (named `upload-sigs` for fetchMock check)
* Return `{}` for `POST /_matrix/client/(unstable|v3)/keys/device_signing/upload` request (named `upload-keys` for fetchMock check)
*/
export function mockSetupCrossSigningRequests(): void {
// have account_data requests return an empty object
fetchMock.get("express:/_matrix/client/v3/user/:userId/account_data/:type", {
status: 404,
body: { errcode: "M_NOT_FOUND", error: "Account data not found." },
});
// we expect a request to upload signatures for our device ...
fetchMock.post({ url: "path:/_matrix/client/v3/keys/signatures/upload", name: "upload-sigs" }, {});
// ... and one to upload the cross-signing keys (with UIA)
fetchMock.post(
// legacy crypto uses /unstable/; /v3/ is correct
{
url: new RegExp("/_matrix/client/(unstable|v3)/keys/device_signing/upload"),
name: "upload-keys",
},
{},
);
}
/**
* Mock out requests to `/room_keys/version`.
*
* Returns `404 M_NOT_FOUND` for GET requests until `POST room_keys/version` is called.
* Once the POST is done, `GET /room_keys/version` will return the posted backup
* instead of 404.
*
* @param backupVersion - The backup version that will be returned by `POST room_keys/version`.
*/
export function mockSetupMegolmBackupRequests(backupVersion: string): void {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", {
status: 404,
body: {
errcode: "M_NOT_FOUND",
error: "No current backup version",
},
});
fetchMock.post("path:/_matrix/client/v3/room_keys/version", (url, request) => {
const backupData: KeyBackupInfo = JSON.parse(request.body?.toString() ?? "{}");
backupData.version = backupVersion;
backupData.count = 0;
backupData.etag = "zer";
fetchMock.get("path:/_matrix/client/v3/room_keys/version", backupData, {
overwriteRoutes: true,
});
return {
version: backupVersion,
};
});
}
+53
View File
@@ -0,0 +1,53 @@
/*
Copyright 2023 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 { OidcClientConfig } from "../../src";
import { ValidatedIssuerMetadata } from "../../src/oidc/validate";
/**
* Makes a valid OidcClientConfig with minimum valid values
* @param issuer used as the base for all other urls
* @returns OidcClientConfig
*/
export const makeDelegatedAuthConfig = (issuer = "https://auth.org/"): OidcClientConfig => {
const metadata = mockOpenIdConfiguration(issuer);
return {
issuer,
account: issuer + "account",
registrationEndpoint: metadata.registration_endpoint,
authorizationEndpoint: metadata.authorization_endpoint,
tokenEndpoint: metadata.token_endpoint,
metadata,
};
};
/**
* Useful for mocking <issuer>/.well-known/openid-configuration
* @param issuer used as the base for all other urls
* @returns ValidatedIssuerMetadata
*/
export const mockOpenIdConfiguration = (issuer = "https://auth.org/"): ValidatedIssuerMetadata => ({
issuer,
revocation_endpoint: issuer + "revoke",
token_endpoint: issuer + "token",
authorization_endpoint: issuer + "auth",
registration_endpoint: issuer + "registration",
jwks_uri: issuer + "jwks",
response_types_supported: ["code"],
grant_types_supported: ["authorization_code", "refresh_token"],
code_challenge_methods_supported: ["S256"],
});
+1
View File
@@ -0,0 +1 @@
/env

Some files were not shown because too many files have changed in this diff Show More