Compare commits

...

802 Commits

Author SHA1 Message Date
RiotRobot 4d7616bd68 v36.2.0 2025-02-11 14:23:11 +00:00
ElementRobot 6d7699cb4a feat(event): deprecate parameter and functions using legacy crypto (#4697) (#4700)
(cherry picked from commit 6b93e11e2c)

Co-authored-by: Florian D <florianduros@element.io>
2025-02-06 14:53:08 +00:00
RiotRobot 6b0d2a4ad3 v36.2.0-rc.0 2025-02-04 12:29:59 +00:00
Michael Telatynski 72519a0eb4 Make sonarcloud.yml more reusable (#4681)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-02-03 14:25:56 +00:00
Will Hunt 624b8a242e Fix topic types (#4678) 2025-02-03 09:03:58 +00:00
Michael Telatynski 5be104a35c Fix types around Terms (#4674) 2025-02-03 08:48:00 +00:00
Will Hunt c93128ed39 Handle empty m.room.topic (#4673)
* Define topic as optional.

* Change isProvided so that types work better.

* allow makeTopicContent and parseTopicContent to handle optional values for plain text

* linting

* Remove usage of optional

* Topic key may only contain legacy key.

* Add tests for other branches.
2025-02-03 08:13:44 +00:00
Hubert Chathi cc238c24ab Provide more options for starting dehydration (#4664)
* provide more options for starting dehydration

* improve doc comments and tests
2025-01-30 18:22:23 +00:00
RiotRobot 8175683d4b Merge branch 'master' into develop 2025-01-28 13:21:56 +00:00
RiotRobot 4e54b7aab4 v36.1.0 2025-01-28 13:21:25 +00:00
Valere a2fd06bdf9 Add API to withdraw verification requirement CryptoAPI.withdrawVerificationRequirement (#4646)
* API to withdraw verification `CryptoAPi.withdrawVerificationRequirement`

* review: use set up function instead of beforeEach
2025-01-28 10:41:37 +00:00
Valere 7d8cbd6ef0 Device Dehydration | js-sdk: store/load dehydration key (#4599)
* feat(dehydrated): Use the dehydrated key cache API

* feat(dehydrated): Add signalling to device dehydration manager

* feat(dehydrated): fix unneeded call getCachedKey

* Upgrade to `matrix-sdk-crypto-wasm` v13.0.0

* review: quick fix and doc

* apply changes from review

* apply changes from review

* fix comment

* add some tests and emit an event on rehydration failure

* factor out event counter into a test util, since it may be useful elsewhere

* adjust test to cover a few more lines

* fix documentation

* Apply suggestions from code review

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

* fix missing bracket

* add test for getting the dehydration key from SSSS

---------

Co-authored-by: Hubert Chathi <hubertc@matrix.org>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2025-01-27 22:05:23 +00:00
David Baker 44158bc843 Add unspecced backup disable flag (#4661)
* Add unspecced backup disable flag

* Add comment
2025-01-27 19:51:28 +00:00
ElementRobot e4590cac94 Revert "Distinguish room state and timeline events in embedded clients (#4574)" (#4656) (#4657)
Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>
2025-01-27 10:36:17 +00:00
Hugh Nimmo-Smith fd9a44e701 Revert "Distinguish room state and timeline events in embedded clients (#4574)" (#4656)
This reverts commit bdd4d82cb3.
2025-01-27 10:04:03 +00:00
Hubert Chathi df492800b4 Fix test that will break with matrix-sdk-crypto-wasm 13.0.0 (#4635)
* fix test that will break with matrix-sdk-crypto-wasm 13.0.0

* this test requires using a real timer
2025-01-24 16:47:45 +00:00
Michael Telatynski 161da05972 Tidy up some main exports (#4649)
Fix knip config

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-01-23 15:41:29 +00:00
Florian Duros ed397d99ed CryptoApi.resetEncryption should always create a new key backup (#4648)
* fix(crypto api): `resetEncryption` always calls `resetKeyBackup`

* test(crypto api): update `resetEncryption` tests

* chore(crypto api): add logging in `resetEncryption`
2025-01-23 15:35:37 +00:00
Michael Telatynski c0e30ceca0 Switch OIDC primarily to new /auth_metadata API (#4626) 2025-01-22 13:48:27 +00:00
Florian Duros 61375ef38a Add CryptoApi.resetEncryption (#4614)
* feat(crypto api): Add `CryptoApi#resetEncryption`

* docs(crypto api): Review changes

* test(crypto api): Cleaner way to handle key backup removal
2025-01-22 10:53:50 +00:00
renovate[bot] e5fda72884 Update dependency @stylistic/eslint-plugin to v2.13.0 (#4642)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 16:05:16 +00:00
renovate[bot] acfc619f31 Update dependency @types/node to v18.19.71 (#4637)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 15:47:02 +00:00
renovate[bot] 7a0af07bf7 Update all non-major dependencies (#4640)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 15:37:01 +00:00
renovate[bot] ad1afbc45b Update guibranco/github-status-action-v2 digest to ecd54a0 (#4636)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 14:56:15 +00:00
renovate[bot] b4ce4ce184 Update dependency @babel/eslint-parser to v7.26.5 (#4641)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 14:55:12 +00:00
renovate[bot] ddbc66b905 Update typescript-eslint monorepo to v8.20.0 (#4643)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 14:53:48 +00:00
renovate[bot] ad1c67e33e Update dependency typescript to v5.7.3 (#4639)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 14:53:09 +00:00
renovate[bot] d473e16df7 Update dependency typedoc-plugin-mdn-links to v4.0.8 (#4638)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-21 14:53:05 +00:00
RiotRobot 806538828e v36.1.0-rc.0 2025-01-21 14:40:56 +00:00
David Baker 424c258a07 Merge pull request #4621 from matrix-org/dbkr/secure_random_string
Change randomString et al to be secure
2025-01-21 13:54:50 +00:00
David Baker ea67d3977e Fix tsdoc formatting & consistency
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2025-01-21 13:32:28 +00:00
David Baker 8bffa39eb9 Add link
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2025-01-21 13:29:44 +00:00
David Baker f13967aaec Use modulo arithmetic instead
also I think this was just wrong in that it was subtracting 1
unnercessarily because we already used < rather than <= below.
2025-01-21 09:50:55 +00:00
Richard van der Hoff b496601712 Add an extra consistency check in bootstrapCrossSigning (#4629)
* Add an extra consistency check in `bootstrapCrossSigning`

check that `importCrossSigningKeys` has actually worked

* Update src/rust-crypto/CrossSigningIdentity.ts

* declare type in @types, instead of in source
2025-01-20 21:21:05 +00:00
Richard van der Hoff ce60162827 Deprecate MatrixClient.login and replace with loginRequest (#4632)
`MatrixClient.login` has some very unintuitive behaviour where it
stashes the access token, but not the device id, refresh token, etc etc, which
led people to imagine that they had a functional `MatrixClient` when they
didn't. In practice, you have to create a *new* `MatrixClient` given the `LoginResponse`.

As the first step for sorting this out, this deprecates the broken method and
replaces it with one that has sensible behaviour.
2025-01-20 21:18:51 +00:00
David Baker 1f1d6f0bc8 Document exports 2025-01-20 18:27:40 +00:00
David Baker 35fe7bc60a Use a random impl with rejection sampling 2025-01-20 18:13:26 +00:00
Richard van der Hoff b45d51a131 Fix documentation on CryptoEvent (#4628)
* Fix documentation on `CryptoEvent`

`CryptoApi` itself does not emit events (or at least, its public type
information does not allow you to listen for events emitted by CryptoApi).

* fix link
2025-01-20 17:04:17 +00:00
Florian Duros a6fd28b03d feat(sliding sync): Use SyncCryptoCallback api instead of legacy crypto (#4624) 2025-01-17 11:45:13 +00:00
Florian Duros 78e7e2af31 Use rust crypto instead of legacy crypto in sync tests (#4623) 2025-01-16 17:27:33 +00:00
David Baker 86494c3a96 Change randomString et al to be secure
...and renames them, removing the special lowercase and uppercase
versions and exporting the underlying function instead.

Any apps that use these will either need to take the speed hit from
secure random functions and use the new ones, or write their own
insecure versions.

The lowercase and uppercasde verisons were used exactly once each
in element-web and never in js-sdk itself. The underlying function
is very simple and exporting just this gives more flexibility with
fewer exports.
2025-01-16 14:48:36 +00:00
Robin bdd4d82cb3 Distinguish room state and timeline events in embedded clients (#4574)
* Distinguish room state and timeline events in embedded clients

This change enables room widget clients to take advantage of the more reliable method of communicating room state over the widget API provided by a recent update to MSC2762.

* Add missing awaits

* Upgrade matrix-widget-api
2025-01-15 18:14:05 +00:00
Florian Duros 5babcaf4b3 feat(secret storage): keyId in SecretStorage.setDefaultKeyId can be set at null in order to delete an exising recovery key (#4615) 2025-01-15 12:29:02 +00:00
m004 ffbb4716c4 Add authenticated media to getAvatarURL in room and room-member models (#4616) 2025-01-15 09:49:18 +00:00
RiotRobot 07f97d724f Merge branch 'master' into develop 2025-01-14 14:09:25 +00:00
RiotRobot 72ee5504d5 v36.0.0 2025-01-14 14:08:54 +00:00
Timo 9134471dc7 MatrixRTC: refactor MatrixRTCSession media encryption key logic into EncryptionManager (#4612)
* move Encryption logic from MatrixRTCSession into EncryptionManager

* review

* review 2
2025-01-14 10:20:51 +00:00
Timo f22d5e9d47 MatrixRTC: additional TS docs for IMembershipManager interface (#4613)
* docstrings for IMembershipManager interface

* more details and cleanup

* timeout docs
2025-01-13 18:29:50 +00:00
Timo ffb228bf5a MatrixRTC: refactor MatrixRTCSession MemberManager API (#4610)
* update join and leave internal api.

* rename onMembershipUpdate and triggerCallMembershipEventUpdate to onMembershipsUpdate
This makes it more clear that we do not talk about our own membership but all memberships in the session

* cleanup MembershipManager
 - add comments and interface how to test this class.
 - sort methods by public/private
 - make triggerCallMembershipEventUpdate private

* docstrings for getFocusInUse and getActiveFocus

* simplify tests and make them only use MembershipManagerInterface methods.
This allows to exchange the membershipManager with a different implementation.

* convert interface to abstract class.

* review (implement interface, make interface internal, dont change public api.)

* Make the interface an actual interface.
The actual constructor of the class now contains the `Pick` to define what it needs from the client.

* move update condition into MembershipManager

* renaming public api

* Update src/matrixrtc/MatrixRTCSession.ts

Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>

* Update src/matrixrtc/MatrixRTCSession.ts

Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>

---------

Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>
2025-01-13 13:20:54 +00:00
David Baker bed4e9579e Mark MSC3981 as stable in Matrix 1.10 (#4023)
So we will send the 'recurse' parameter unprefixed for servers that
support 1.10 (when it's released).
2025-01-13 09:49:15 +00:00
Timo 7697338c7e MatrixRTC: move MatrixRTCSession logic into LocalMembershipManager (#4608)
* split joinConfig
 - myMembership related properties get moved into its own interface

* Add MyMembershipManager

* Remove methods and functions that are from MatrixRTCSession (they now live in MyMembershipManager)

* Refactor MatrixRTCSession to use myMembershipManager

* fix tests

* review

* get rid of more memberhsip manager usage in tests

* review - fix tests using private membershipManager props

* fix circular import
2025-01-10 10:46:28 +00:00
Michael Telatynski 1da26b5cd1 Fix issue with sentinels being incorrect on m.room.member events (#4609)
* Fix issue with sentinels being incorrect on m.room.member events

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

* Iterate

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

* Simplify change

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

* Add test

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2025-01-10 10:16:45 +00:00
renovate[bot] 5b85ae491e Update typescript-eslint monorepo to v8.19.0 (#4607)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-07 14:02:30 +00:00
renovate[bot] 2024b070b0 Update typedoc (#4604)
* Update typedoc

* Make typedoc happier

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>
2025-01-07 13:39:07 +00:00
renovate[bot] eef964f07d Update dependency @stylistic/eslint-plugin to v2.12.1 (#4606)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-07 13:16:07 +00:00
renovate[bot] 1e9c119159 Update dependency @types/node to v18.19.69 (#4603)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-07 12:55:34 +00:00
renovate[bot] fd894309f2 Update guibranco/github-status-action-v2 digest to 56cd38c (#4602)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-07 12:54:50 +00:00
renovate[bot] 75486b72a6 Update all non-major dependencies (#4605)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-07 12:53:53 +00:00
RiotRobot 38816589f5 v36.0.0-rc.0 2025-01-07 12:43:09 +00:00
Timo 6f743bfa1f MatrixRTC: Implement expiry logic for CallMembership and additional test coverage (#4587)
* remove all legacy call related code and adjust tests.
We actually had a bit of tests just for legacy and not for session events. All those tests got ported over so we do not remove any tests.

* dont adjust tests but remove legacy tests

* Remove deprecated CallMembership.getLocalExpiry()

* Remove references to legacy in test case names

* Clean up SessionMembershipData tsdoc

* Remove CallMembership.expires

* Use correct expire duration.

* make expiration methods not return optional values and update docstring

* add docs to `SessionMembershipData`

* Add new tests for session type member events that before only existed for legacy member events.

This reverts commit 795a3cffb61d672941c49e8139eb1d7b15c87d73.

* remove code we do not need yet.

* Cleanup

---------

Co-authored-by: Hugh Nimmo-Smith <hughns@matrix.org>
2025-01-07 10:14:09 +00:00
Timo ffd3c9575e Remove support for "legacy" MSC3898 group calling in MatrixRTCSession and CallMembership (#4583)
* remove all legacy call related code and adjust tests.
We actually had a bit of tests just for legacy and not for session events. All those tests got ported over so we do not remove any tests.

* dont adjust tests but remove legacy tests

* Remove deprecated CallMembership.getLocalExpiry()

* Remove references to legacy in test case names

* Clean up SessionMembershipData tsdoc

* Remove CallMembership.expires

* Use correct expire duration.

* make expiration methods not return optional values and update docstring

* add docs to `SessionMembershipData`

* Use `MSC4143` (instaed of `non-legacy`) wording in comment

Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>

* Incorporate feedback from review

* Fix test name

---------

Co-authored-by: Hugh Nimmo-Smith <hughns@matrix.org>
Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>
2025-01-06 17:23:16 +00:00
David Baker 7678923e04 Don't retry on 4xx responses (#4601)
* Don't retry on 4xx responses

I'm not sure why this was limited to a small set of 4xx responses.
Nominally, no 4xx request should be retried (in fact the comment
below says this, but then the code didn't quite match it).

This was causing key backup requests to be retried even when the
server responded 404 because the backup in question had been deleted,
meaning the client would retry uselessly and it would take longer for
the client to prompt the user for action.

* Exclude 429s
2025-01-06 13:25:29 +00:00
Johannes Marbach 6f7c74f9ea Add syntax & type check for Node.js example on CI (#4410)
* Add syntax & type check for Node.js example on CI

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>

* Fix quotes

---------

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Co-authored-by: Florian Duros <florianduros@element.io>
2025-01-03 18:49:57 +00:00
Michael Telatynski 3fcc56601b Use mapped types for account data content (#4590)
* Use mapped types around account data events

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

* Iterate

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

* Iterate

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

* Iterate

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

* Iterate

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

* Iterate

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

* Harden types for reading account data too

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

* Correct empty object type

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

* Update src/secret-storage.ts

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

* Iterate

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

* Iterate

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-12-19 22:53:58 +00:00
Andy Balaam bcf3d56bd5 Upgrade matrix-sdk-crypto-wasm to 12.1.0 (#4596)
... to fix https://github.com/matrix-org/matrix-rust-sdk/issues/4424
2024-12-19 14:33:25 +00:00
RiotRobot 647a2a1a19 Merge branch 'master' into develop 2024-12-18 14:11:02 +00:00
RiotRobot 1bf8533c03 v35.1.0 2024-12-18 14:10:31 +00:00
David Baker fb2f2dd6d4 Merge pull request #4593 from matrix-org/rav/migration-for-previouslyverified
Upgrade matrix-sdk-crypto-wasm to 1.11.0
2024-12-18 14:01:18 +00:00
Richard van der Hoff d33350ff26 Upgrade matrix-sdk-crypto-wasm to 1.11.0
... to fix https://github.com/matrix-org/matrix-rust-sdk/issues/4424
2024-12-18 13:29:05 +00:00
RiotRobot 349a86c119 Merge branch 'master' into develop 2024-12-17 13:22:36 +00:00
RiotRobot bee65ff13f v35.0.0 2024-12-17 13:22:10 +00:00
Hugh Nimmo-Smith e4182eb752 Update matrix-sdk-crypto-wasm to 12.0.0 (#4589)
It appears to "just work"... but I might be missing something
2024-12-17 11:24:46 +00:00
David Baker 3219aefc92 Avoid key prompts when resetting crypto (#4586)
* Avoid key prompts when resetting crypto

Attempting to get the backup key out of secret storage can cause
the user to be prompted for their key, which is not helpful if this
is being done as part of a reset. This check was redundant anyway
and we can just overwrite the key with the same value.

Also fix docs and remove check for active backup.

* Fix doc
2024-12-17 09:22:31 +00:00
Richard van der Hoff aba4e690af Improve documentation on various secret-storage related methods (#4585)
* Improve documentation on various secret-storage related methods

* fix link

* Apply suggestions from code review
2024-12-16 13:00:18 +00:00
Liam Diprose 693bb22ba1 Handle when aud OIDC claim is an Array (#4584)
* Handle when `aud` OIDC claim is an Array

The `aud` claim of OIDC id_tokens [can be an array](https://github.com/authts/oidc-client-ts/blob/ce6d694639c58e6a1c80904efdac5eda82b82042/src/Claims.ts#L92) but the existing logic
incorrectly assumes `aud` is always a string.

This PR adds the necessary check.

* Clarify `aud` OIDC claim check

* Fix for prettier

---------

Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2024-12-16 11:38:34 +00:00
renovate[bot] 315e81b7de Update typescript-eslint monorepo to v8.17.0 (#4581)
* Update typescript-eslint monorepo to v8.17.0

* Fix lint errors

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2024-12-12 17:45:39 +00:00
David Baker a0502c5ee5 Save the key backup key to 4S during bootstrapCrossSigning (#4542)
* Save the key backup key to secret storage

When setting up secret storage, if we have a key backup key in cache
(like we do for the cross signing secrets).

* Add test

* Get the key directly from the olmMachine

saves converting it needlessly into a buffer to turn it back into
a base64 string

* Overwrite backup keyin storage if different

* Fix test

* Add integ test

* Test failure case for sonar

* Unused import

* Missed return

* Also check active backup version
2024-12-12 15:03:19 +00:00
Timo d1de32ea27 Only re-prepare MatrixrRTC delayed disconnection event on 404 (#4575)
* Set retry counts of event updating to 1000 (from 1)

 With it being set to one the following issue could occur:

```
// If sending state cancels your own delayed state, prepare another delayed state
// TODO: Remove this once MSC4140 is stable & doesn't cancel own delayed state
if (this.disconnectDelayId !== undefined) {
    try {
        const knownDisconnectDelayId = this.disconnectDelayId;
        await resendIfRateLimited(
            () =>
                this.client._unstable_updateDelayedEvent(
                    knownDisconnectDelayId,
                    UpdateDelayedEventAction.Restart,
                ),
            1000,
        );
    } catch (e) {
        logger.warn("Failed to update delayed disconnection event, prepare it again:", e);
        this.disconnectDelayId = undefined;
        await prepareDelayedDisconnection();
    }
}
```
This code looks like the `catch(e)` could never be triggered with 429 (rate limit) because they would be caught by `await resendIfRateLimited`. EXCEPT that this is only happening once: `resendIfRateLimited<T>(func: () => Promise<T>, numRetriesAllowed: number = 1)`. So as soon as the server sends two rate limits in a row we get the following:
 - we get into the `catch(e)`  because of the rate limit
 - we forget about `this.disconnectDelayId = undefined`
 - we start a new delayed event `await prepareDelayedDisconnection();`
 - we do not anymore update the old delayed event which is still running!
 - the running delay event will make us disconnect from the call (call member becomes `{}`)
 - we get into our outher error catching mechanism that resends the new state event
 - this cancels the newly created delay leave event (`await prepareDelayedDisconnection();`)
 - and create another delay leave event.
 - but if we are still reate limited (chances are really high due to the reconnect), this loop will REPEAT

* also check for M_NOT_FOUND

* Leave retry at current level

---------

Co-authored-by: Hugh Nimmo-Smith <hughns@matrix.org>
2024-12-12 14:58:50 +00:00
renovate[bot] 3ae25427a8 Update dependency @types/node to v18.19.67 (#4578)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-11 09:53:08 +00:00
renovate[bot] 8155b0acfc Update mheap/github-action-required-labels digest to 388fd6a (#4577)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-10 22:11:53 +00:00
renovate[bot] 413c156624 Update guibranco/github-status-action-v2 digest to d469d49 (#4576)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-10 18:12:27 +00:00
renovate[bot] e78a3cec9f Update all non-major dependencies (#4579)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-10 16:50:03 +00:00
renovate[bot] 5998de365d Update dependency @babel/cli to v7.26.4 (#4580)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-10 16:31:44 +00:00
RiotRobot 3de2b9bf80 v35.0.0-rc.0 2024-12-10 15:43:43 +00:00
Hubert Chathi ded87290ce Update matrix-sdk-crypto-wasm to 11.0.0 (#4566)
* Update matrix-sdk-crypto-wasm to 11.0.0

* use `backend` variable to test for rust crypto

* apply changes from review
2024-12-09 23:11:02 +00:00
renovate[bot] cf39595bd7 Update dependency typedoc to v0.27.3 (#4573)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-05 19:21:39 +00:00
Stanislav Demydiuk c90ea985c6 Fix age field check in event echo processing (#3635)
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2024-12-05 16:08:41 +00:00
Florian Duros c54ca29aa8 Rename initCrypto into initLegacyCrypto (#4567) 2024-12-05 11:08:38 +00:00
Michael Telatynski beb3721e7a Avoid use of Buffer as it does not exist in the Web natively (#4569) 2024-12-04 22:32:09 +00:00
Richard van der Hoff 1cad6f4451 Add multiprocess health warnings to initRustCrypto (#4571) 2024-12-04 14:38:48 +00:00
RiotRobot c4ea57d42d Merge branch 'master' into develop 2024-12-03 12:24:07 +00:00
RiotRobot d3f5526ec0 v34.13.0 2024-12-03 12:23:40 +00:00
renovate[bot] b8e332b53d Update dependency typescript to v5.7.2 (#4553)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-03 11:47:14 +00:00
renovate[bot] ab78acc7da Update typedoc (#4568)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-03 11:19:56 +00:00
Michael Telatynski 051f4e2ab9 Fix release-checks to not use reserved name GITHUB_TOKEN
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-02 10:47:35 +00:00
Michael Telatynski 8863e42e35 More typescript linting (#3310)
* More typescript linting

* Improve types

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

* Discard changes to src/models/MSC3089TreeSpace.ts

* Discard changes to src/realtime-callbacks.ts

* Fix tests

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

* Improve coverage

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-02 09:56:52 +00:00
Michael Telatynski bc5246970c Extract release sanity checks to reusable workflow (#4546)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-12-02 09:14:45 +00:00
Florian Duros edac6a9983 Replace deprecate imports (#4565)
* Replace deprecate imports

* Deprecate `CryptoBackend.getEventEncryptionInfo`

* Add deprecated alternative
2024-11-29 10:04:20 +00:00
Florian Duros 97ef1dc6df Remove deprecated calls of MatrixClient (#4563) 2024-11-29 09:49:52 +00:00
Florian Duros 125e45c24d Deprecate remaining legacy functions and move CryptoEvent.LegacyCryptoStoreMigrationProgress handler (#4560)
* Deprecate legacy functions in `MatrixClient`

* Move `CryptoEvent.LegacyCryptoStoreMigrationProgress` handler in rust crypto

* Remove `olmLib` usage in `MatrixClient`
2024-11-29 09:49:32 +00:00
Hugh Nimmo-Smith 3781b6ebfa Re-send MatrixRTC media encryption keys for a new joiner even if a rotation is in progress (#4561) 2024-11-28 12:05:39 +00:00
Michael Telatynski 8fc77c595a Move bump downstreams to js-sdk specific release workflow (#4547)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-27 14:15:51 +00:00
David Baker 5bcd26e506 Support MSC4222 state_after (#4487)
* WIP support for state_after

* Fix sliding sync sdk / embedded tests

* Allow both state & state_after to be undefined

Since it must have allowed state to be undefined previously: the test
had it as such.

* Fix limited sync handling

* Need to use state_after being undefined

if state can be undefined anyway

* Make sliding sync sdk tests pass

* Remove deprecated interfaces & backwards-compat code

* Remove useless assignment

* Use updates unstable prefix

* Clarify docs

* Remove additional semi-backwards compatible overload

* Update unstable prefixes

* Iterate

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

* Iterate

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

* Fix test

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

* Iterate

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

* Iterate

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

* Add test for MSC4222 behaviour

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

* Improve coverage

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

* Iterate

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

* Fix tests

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

* Iterate

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

* Tidy

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

* Add comments to explain why things work as they are.

* Fix sync accumulator for state_after sync handling

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

* Add tests

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

* Revert "Fix room state being updated with old (now overwritten) state and emitting for those updates. (#4242)"

This reverts commit 957329b218.

* Fix Sync Accumulator toJSON putting start timeline state in state_after field

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

* Update tests

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

* Add test case

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

* Iterate

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: Hugh Nimmo-Smith <hughns@matrix.org>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: Timo <toger5@hotmail.de>
2024-11-27 11:40:41 +00:00
Timo 66f099b2e7 Revert "Fix room state being updated with old (now overwritten) state and emitting for those updates. (#4242)" (#4532)
This reverts commit 957329b218.
2024-11-27 10:49:29 +00:00
renovate[bot] b1445d7457 Update all non-major dependencies (#4558)
* Update all non-major dependencies

* Prettier

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>
2024-11-27 09:22:49 +00:00
Michael Telatynski b3794760c6 Merge remote-tracking branch 'origin/develop' into develop 2024-11-27 09:10:52 +00:00
Michael Telatynski fbdcc597b6 Fix workflow permissions
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-27 07:44:35 +00:00
renovate[bot] 8ac32b7894 Update dependency typedoc-plugin-coverage to v3.4.0 (#4559)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 18:51:22 +00:00
renovate[bot] b27c6de78d Update guibranco/github-status-action-v2 digest to 66088c4 (#4548)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 18:23:16 +00:00
renovate[bot] c8e0987774 Update dependency typedoc-plugin-missing-exports to v3.0.2 (#4550)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 17:41:22 +00:00
renovate[bot] 849fcd3341 Update dependency @types/node to v18.19.65 (#4549)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 17:33:27 +00:00
renovate[bot] 8df8266e4a Update dependency @stylistic/eslint-plugin to v2.11.0 (#4552)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 17:16:47 +00:00
renovate[bot] cba4edfd84 Update dependency typedoc-plugin-mdn-links to v4 (#4556)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 17:14:18 +00:00
renovate[bot] 4f50290cd6 Update all non-major dependencies (#4551)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 16:35:48 +00:00
renovate[bot] 35e31f02ac Update typescript-eslint monorepo to v8.15.0 (#4554)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-26 16:35:13 +00:00
Hubert Chathi 69647a33b6 Use shield status codes from Rust rather than string matching (#4529) 2024-11-26 15:06:57 +00:00
RiotRobot 13df897896 v34.13.0-rc.0 2024-11-26 13:42:27 +00:00
Michael Telatynski 006929ac0c Fix release workflow permissions
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-26 13:41:14 +00:00
dependabot[bot] 405a6fbb92 Bump smol-toml from 1.3.0 to 1.3.1 (#4544)
Bumps [smol-toml](https://github.com/squirrelchat/smol-toml) from 1.3.0 to 1.3.1.
- [Release notes](https://github.com/squirrelchat/smol-toml/releases)
- [Commits](https://github.com/squirrelchat/smol-toml/commits)

---
updated-dependencies:
- dependency-name: smol-toml
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-26 09:59:55 +00:00
Michael Telatynski d6f3262e12 Prevent releases when release blockers exist (#4543)
* Prevent releases when release blockers exist

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

* Fix

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

* Add permissions

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-26 09:59:41 +00:00
Michael Telatynski 8b32f3eb7f Ensure we disambiguate display names which look like MXIDs (#4540)
* Ensure we disambiguate display names which look like MXIDs

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

* Make tests clearer

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-22 15:52:50 +00:00
Michael Telatynski 1e9934a69d Fix docs-pr-netlify.yaml permissions
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-22 11:35:04 +00:00
Michael Telatynski a6d342d3a4 Switch away from deprecated github-status-action (#4539)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-21 17:04:22 +00:00
Michael Telatynski 4b9a1bd53f Fix coverage check
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-21 16:05:38 +00:00
Michael Telatynski 26248f85d5 Additional check to ensure artifacts are downloaded
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-21 16:00:30 +00:00
Michael Telatynski ae2ae483db We have to explicitly specify github-token even though it is the default for this to work in theory
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-21 15:59:17 +00:00
Michael Telatynski c87692d0aa Tighten GITHUB_TOKEN permissions (#4538)
* Tighten GITHUB_TOKEN permissions

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

* Tighten GITHUB_TOKEN permissions

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

* Iterate

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

* Fix permission

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-21 14:01:45 +00:00
Florian Duros 2dd4334e20 Fix RustBackupManager remaining values after current backup removal. #4534 (#4537) 2024-11-21 13:21:37 +00:00
dependabot[bot] 2210255d6f Bump cross-spawn from 7.0.3 to 7.0.6 (#4536)
Bumps [cross-spawn](https://github.com/moxystudio/node-cross-spawn) from 7.0.3 to 7.0.6.
- [Changelog](https://github.com/moxystudio/node-cross-spawn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moxystudio/node-cross-spawn/compare/v7.0.3...v7.0.6)

---
updated-dependencies:
- dependency-name: cross-spawn
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-20 13:28:48 +00:00
RiotRobot 544ac86d20 Merge branch 'master' into develop 2024-11-19 14:18:23 +00:00
RiotRobot cf06547063 v34.12.0 2024-11-19 14:17:48 +00:00
Florian Duros 781c3b05e5 Add CryptoApi.getBackupInfo (#4512)
* Add `CryptoApi.getBackupInfo`

* improve doc
2024-11-18 13:31:35 +00:00
Timo 325dace437 Fix local echo in embedded mode (#4498)
* fix local echo

* dont use custome event emitter anymore

* move logic into updateTxId

* temp testing

* use generic eventEmtitter names

* add tests

---------

Co-authored-by: Robin <robin@robin.town>
Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>
2024-11-14 13:21:20 +00:00
Michael Telatynski 5c894b34b3 Add downstream tsc for element-web (#4508)
* Add downstream tsc for element-web

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

* Update static_analysis.yml

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-13 14:16:37 +00:00
Florian Duros f5f4091a00 Deprecate MatrixClient.isEventSenderVerified (#4527) 2024-11-13 11:10:38 +00:00
Florian Duros 52bdb57a47 Use crypto api import for CryptoCallbacks instead of legacy crypto (#4526) 2024-11-13 10:47:02 +00:00
Richard van der Hoff 3c23eb69b5 Remove reference to libolm from readme (#4525)
* Remove reference to libolm from readme

* README: fix link to node example
2024-11-13 10:24:49 +00:00
Florian Duros c93b7ce188 Add restoreKeybackup to CryptoApi. (#4476)
* First draft of moving out restoreKeyBackup out of MatrixClient

* Deprecate `restoreKeyBackup*` in `MatrixClient`

* Move types

* Handle only the room keys response

* Renaming and refactor `keysCountInBatch` & `getTotalKeyCount`

* Fix `importRoomKeysAsJson` tsdoc

* Fix typo

* Move `backupDecryptor.free()``

* Comment and simplify a bit `handleDecryptionOfAFullBackup`

* Fix decryption crash by moving`backupDecryptor.free`

* Use new api in `megolm-backup.spec.ts`

* Add tests to get recovery key from secret storage

* Add doc to `KeyBackupRestoreOpts` & `KeyBackupRestoreResult`

* Add doc to `restoreKeyBackupWithKey`

* Add doc to `backup.ts`

* Apply comment suggestions

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

* - Decryption key is recovered from the cache in `RustCrypto.restoreKeyBackup`
- Add `CryptoApi.getSecretStorageBackupPrivateKey` to get the decryption key from the secret storage.

* Add `CryptoApi.restoreKeyBackup` to `ImportRoomKeyProgressData` doc.

* Add deprecated symbol to all the `restoreKeyBackup*` overrides.

* Update tests

* Move `RustBackupManager.getTotalKeyCount` to `backup#calculateKeyCountInKeyBackup`

* Fix `RustBackupManager.restoreKeyBackup` tsdoc

* Move `backupDecryptor.free` in rust crypto.

* Move `handleDecryptionOfAFullBackup` in `importKeyBackup`

* Rename `calculateKeyCountInKeyBackup` to `countKeystInBackup`

* Fix `passphrase` typo

* Rename `backupInfoVersion` to `backupVersion`

* Complete restoreKeyBackup* methods documentation

* Add `loadSessionBackupPrivateKeyFromSecretStorage`

* Remove useless intermediary result variable.

* Check that decryption key matchs key backup info in `loadSessionBackupPrivateKeyFromSecretStorage`

* Get backup info from a specific version

* Fix typo in `countKeysInBackup`

* Improve documentation and naming

* Use `RustSdkCryptoJs.BackupDecryptionKey` as `decryptionKeyMatchesKeyBackupInfo` parameter.

* Call directly `olmMachine.getBackupKeys` in `restoreKeyBackup`

* Last review changes

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-11-13 09:17:32 +00:00
Florian Duros 705b6336cf Update e2e doc in README.md (#4503)
* Update e2e doc in `README.md`

* Update `ICreateClientOpts.cryptoStore` doc

* Apply first batch of suggestion

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

* Fix `cryptoStore` tsdoc in `client.ts`

* Changes in Initialization chapter.

* Add doc about deprecated methods in `MatrixClient`.

* Update SecretStorage doc

* Fis typos

* Improve e2e docs

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-11-12 16:51:01 +00:00
renovate[bot] 7c41e3fb06 Update all non-major dependencies (#4519)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 15:47:11 +00:00
renovate[bot] a314e612fa Update dependency @stylistic/eslint-plugin to v2.10.1 (#4520)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 15:07:51 +00:00
renovate[bot] ac6cad2852 Update babel monorepo (#4517)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 14:29:01 +00:00
renovate[bot] 906390f0bf Update shogo82148/actions-upload-release-asset digest to 8482bd7 (#4516)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 14:10:31 +00:00
renovate[bot] 795497fafa Update crazy-max/ghaction-import-gpg digest to cb9bde2 (#4515)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 14:10:01 +00:00
renovate[bot] ffb777d118 Update typescript-eslint monorepo to v8.13.0 (#4521)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 14:08:01 +00:00
renovate[bot] fbba8a2d71 Update typedoc (#4518)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 14:08:00 +00:00
renovate[bot] 053c5741b0 Update actions/checkout digest to 11bd719 (#4514)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-12 14:07:59 +00:00
RiotRobot 620dc2f6e2 v34.12.0-rc.0 2024-11-12 13:59:57 +00:00
Michael Telatynski 00d78077b0 Fix tests after security patches (#4513)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-12 11:16:03 +00:00
RiotRobot 23d2d03912 Merge branch 'master' into develop 2024-11-12 09:30:35 +00:00
RiotRobot b4c4355d1a v34.11.1 2024-11-12 09:30:01 +00:00
Michael Telatynski 142c0a65e6 Merge remote-tracking branch 'origin/develop' into develop 2024-11-12 09:27:54 +00:00
Michael Telatynski b9aacea1cb Fix release scripts
Regressed by https://github.com/matrix-org/matrix-js-sdk/pull/4496

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-12 09:27:44 +00:00
RiotRobot 76e653b7ee Merge branch 'master' into develop 2024-11-12 09:13:57 +00:00
RiotRobot 4d4ff4c3f2 v34.11.0 2024-11-12 09:13:26 +00:00
Michael Telatynski 00aba742e4 Merge commit from fork
to avoid path traversal attacks
and remove the legacy allowance for fragments in MXCs

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-12 09:08:00 +00:00
Andrew Ferrazzutti 35d862ebd3 Handle M_MAX_DELAY_EXCEEDED errors (#4511)
* Handle M_MAX_DELAY_EXCEEDED errors

Use a lower delay time if the server rejects a delay as too long.

* Add test

* Lint test

* Update src/matrixrtc/MatrixRTCSession.ts

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

* Test computed expiry timeout value

---------

Co-authored-by: Robin <robin@robin.town>
2024-11-11 20:48:53 +00:00
Hugh Nimmo-Smith 581b3209ab Allow configuration of MatrixRTC timers when calling joinRoomSession() (#4510) 2024-11-11 15:35:05 +00:00
Andrew Ferrazzutti 6855ace642 When state says you've left ongoing call, rejoin (#4342)
* When state says you've left ongoing call, rejoin

When receiving a state change that says you are no longer a member of a
RTC session that you are actually still participating in, send another
state event to put yourself back in the session membership.

This can happen when an administrator overwrites your call membership
event (which is allowed even with MSC3757's restrictions on state), or
if your delayed disconnection event (via MSC4140) timed out before your
client could send a heartbeat to delay it further.

* Don't emit state changed on join recovery
2024-11-11 15:07:33 +00:00
Florian Duros 5033d48013 Fix tsdoc error in rust-crypto folder (#4504) 2024-11-11 13:15:46 +00:00
Andrew Ferrazzutti 4c53836a13 Remove redundant type arguments in function call (#4507)
as the types can be deduced by the function arguments.
2024-11-11 11:19:48 +00:00
Andrew Ferrazzutti 10a4fd8328 MatrixRTCSession: handle rate limit errors (#4494)
* MatrixRTCSession: handle rate limit errors

* Lint

* Handle ratelimiting for non-legacy state setting

Each request must be retried, as the non-legacy flow involves a sequence
of requests that must resolve in order.

* Fix broken test

* Check for MSC3757 instead of the unmerged MSC3779

* Move helper out of beforeEach

* Test ratelimit errors
2024-11-11 02:55:42 +00:00
Andrew Ferrazzutti 98f7637683 Send/receive error details with widgets (#4492)
* Send/receive error details with widgets

* Fix embedded client tests

* Use all properties of error responses

* Lint

* Rewrite ternary expression as if statement

* Put typehints on overridden functions

* Lint

* Update matrix-widget-api

* Don't @link across packages

as gendoc fails when doing so.

* Add a missing docstring

* Set widget response error string to correct value

* Test conversion to/from widget error payloads

* Test processing errors thrown by widget transport

* Lint

* Test processing errors from transport.sendComplete
2024-11-09 07:29:04 +00:00
Florian Duros 0df8e81da4 Deprecate MatrixClient.getKeyBackupVersion (#4505) 2024-11-08 09:06:09 +00:00
Florian Duros 30b1894f37 Deprecate unused callback in CryptoCallbacks (#4501) 2024-11-06 15:38:15 +00:00
Richard van der Hoff fbbdb6e766 Remove dead release scripts (#4496)
* Remove redundant `pre-release.sh` script

This is now a no-op (there are no `matrix_lib` fields in package.json), so we
may as well remove it.

* Remove redundant `post-merge-master` script

Just as pre-release is a no-op, so is this

* Remove redundant switch_package_to_release script

Once more: this script is a no-op.
2024-11-05 16:38:13 +00:00
RiotRobot 5a1488ebd5 Merge branch 'master' into develop 2024-11-05 13:49:42 +00:00
RiotRobot c4048d985d v34.10.0 2024-11-05 13:49:13 +00:00
David Baker 794f044dda Make doc clearer on getCrossSigningKeyId (#4477)
* Make doc clearer on getCrossSigningKeyId

I was trying to work out why this was being used in a check. It
turns out it only returns the key ID if the private part is stored
locally, which seems very much non-obvious.

* Better doc

* Formatting & clarity

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>
2024-11-04 10:53:30 +00:00
Michael Telatynski a197afe8aa Refactor MatrixClient::forget to not abuse membershipChange API (#4490)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-11-04 09:49:27 +00:00
Florian Duros 1061b93b29 Remove remaining legacy crypto imports in new crypto and tests (#4491)
* Use `CryptoCallbacks` from `CryptoApi` instead of legacy crypto.

* Use `KeyBackup` from rust crypto instead of `IKeyBackup` from legacy crypto
2024-11-04 08:55:32 +00:00
Hugh Nimmo-Smith 6528a59fc1 Reduce cognitive complexity of Room.addLiveEvents() (#4493) 2024-11-01 17:38:08 +00:00
Will Hunt f6a169b5a5 Replace usages of global with globalThis (#4489)
* Update src with globalThis

* Update spec with globalThis

* Replace in more spec/ places

* More changes to src/

* Add a linter rule for global

* Prettify

* lint
2024-11-01 09:15:21 +00:00
renovate[bot] d04135cc1c Update dependency uuid to v11 (#4482)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-31 11:39:59 +00:00
Andrew Ferrazzutti 546047a050 Capture HTTP error response headers & handle Retry-After header (MSC4041) (#4471)
* Include HTTP response headers in MatrixError

* Lint

* Support MSC4041 / Retry-After header

* Fix tests

* Remove redundant MatrixError parameter properties

They are inherited from HTTPError, so there is no need to mark them as
parameter properties.

* Comment that retry_after_ms is deprecated

* Properly handle colons in XHR header values

Also remove the negation in the if-condition for better readability

* Improve Retry-After parsing and docstring

* Revert ternary operator to if statements

for readability

* Reuse resolved Headers for Content-Type parsing

* Treat empty Content-Type differently from null

* Add MatrixError#isRateLimitError

This is separate from MatrixError#getRetryAfterMs because it's possible
for a rate-limit error to have no Retry-After time, and having separate
methods to check each makes that more clear.

* Ignore HTTP status code when getting Retry-After

because status codes other than 429 may have Retry-After

* Catch Retry-After parsing errors

* Add test coverage for HTTP error headers

* Update license years

* Move safe Retry-After lookup to global function

so it can more conveniently check if an error is a MatrixError

* Lint

* Inline Retry-After header value parsing

as it is only used in one place and doesn't need to be exported

* Update docstrings

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

* Use bare catch

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

* Give HTTPError methods for rate-limit checks

and make MatrixError inherit them

* Cover undefined errcode in rate-limit check

* Update safeGetRetryAfterMs docstring

Be explicit that errors that don't look like rate-limiting errors will
not pull a retry delay value from the error.

* Use rate-limit helper functions in more places

* Group the header tests

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-10-30 15:52:34 +00:00
Florian Duros 16153e5d82 Replace legacy keyBackup types (#4486) 2024-10-30 13:12:27 +00:00
Hugh Nimmo-Smith fd73d5068c Add RoomWidgetClient.sendToDeviceViaWidgetApi() (#4475) 2024-10-30 09:36:44 +00:00
Richard van der Hoff e72859a44a Update codeowners for crypto-api (#4478)
Obviously, the crypto api is owned by the (web) crypto team!
2024-10-29 17:02:14 +00:00
RiotRobot a8f8a9c14d v34.10.0-rc.0 2024-10-29 12:55:48 +00:00
Florian Duros 0e2f73d7a7 Deprecate CreateSecretStorageOpts.keyBackupInfo used in CryptoApi.bootstrapSecretStorage. (#4474) 2024-10-28 12:00:39 +00:00
Hugh Nimmo-Smith 31aeb3044f Add CryptoApi.encryptToDeviceMessages() and deprecate Crypto.encryptAndSendToDevices() (#4380)
* Add CryptoApi. encryptToDeviceMessages

Deprecate Crypto. encryptAndSendToDevices and MatrixClient. encryptAndSendToDevices

* Overload MatrixClient. encryptAndSendToDevices instead of deprecating

* Revert "Overload MatrixClient. encryptAndSendToDevices instead of deprecating"

This reverts commit 6a0d8e26385c34d40e8c2ed1e34cb5119c12456c.

* Feedback from code review

* Use temporary pre-release build of @matrix-org/matrix-sdk-crypto-wasm

* Deduplicate user IDs

* Test for RustCrypto implementation

* Use ensureSessionsForUsers()

* Encrypt to-device messages in parallel

* Use release version of matrix-sdk-crypto-wasm

* Upgrade matrix-sdk-crypto-wasm to v8

* Sync with develop

* Add test for olmlib CryptoApi

* Fix link

* Feedback from review

* Move libolm implementation to better place in file

* FIx doc

* Integration test

* Make sure test device is known to client

* Feedback from review
2024-10-28 11:32:17 +00:00
Hugh Nimmo-Smith 0a29063bc9 Do not rotate MatrixRTC media encryption key when a new member joins a session (#4472)
* Do not rotate MatrixRTC media encryption key when a new member joins a call

This change reverts https://github.com/matrix-org/matrix-js-sdk/pull/4422.

Instead, the rotation when a new member joins will be reintroduced as part of supporting to-device based MatrixRTC encryption key distribution.

* Improve function name
2024-10-25 13:32:44 +00:00
Richard van der Hoff 3cc3bd0728 Avoid <sender>|<session> notation in log messages (#4473)
We used to use the notation `<sender key>|<megolm session id>` fairly widely in
log messages, but since the transition to rust crypto, it's unusual and now
somewhat confusing. Make the log messages more explicit.
2024-10-25 12:48:44 +00:00
Michael Telatynski f891fe4423 Fix gitflow workflow not handling edge case (#4463)
of not needing to reset package to `#develop`

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-10-25 11:15:00 +00:00
Andrew Ferrazzutti b99ff83785 Refactor/simplify Promises in MatrixRTCSession (#4466)
* Refactor/simplify Promises in MatrixRTCSession

* Update src/matrixrtc/MatrixRTCSession.ts

Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>

* Fix+document+test leaveRoomSession's return value

* Throw instead of using expect in teardown

because lint rules forbid using expect outside of test functions

---------

Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>
2024-10-25 09:24:52 +00:00
Michael Telatynski 23c4c9fd8a Remove abandoned MSC3886, MSC3903, MSC3906 implementations (#4469)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-10-24 13:19:29 +00:00
RiotRobot 8b8ee91210 Merge branch 'master' into develop 2024-10-22 11:58:31 +00:00
RiotRobot d8c431f23e v34.9.0 2024-10-22 11:58:01 +00:00
Hugh Nimmo-Smith a6fb7530cb Organise MatrixRTCSession tests (#4453)
None of the tests themselves should have changed
2024-10-21 16:24:02 +00:00
Florian Duros b5c3f15a67 Deprecate MatrixClient.getDehydratedDevice (#4467) 2024-10-21 13:21:05 +00:00
renovate[bot] 91f6f0f9c5 Update typescript-eslint monorepo to v8 (major) (#4388)
* Update typescript-eslint monorepo to v8

* Migrate to stylistic

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

* Iterate

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>
2024-10-21 13:17:20 +00:00
renovate[bot] 88cf5eb769 Update actions/checkout digest to eef6144 (#4464)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-18 13:54:33 +00:00
Andrew Ferrazzutti 13a967ae8f Prepare delayed call leave events more reliably (#4447)
* Prepare delayed call leave events more reliably

- Try sending call join after preparing delayed leave
- On leave, send delayed leave instead of a new event

* Don't rely on errcodes for retry logic

because they are unavailable in widget mode

* Make arrow method readonly

SonarCloud rule typescript:S2933

* Test coverage for restarting delayed call leave

* Remove unneeded unstable_features mock

It's unneeded because all affected methods are mocked
2024-10-17 17:41:18 +00:00
Michael Telatynski 66c80949e8 Pin GHA runner versions (#4461)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-10-17 09:04:19 +00:00
renovate[bot] 3d51e31da8 Update babel monorepo (#4454)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-16 14:27:13 +00:00
renovate[bot] 86c190fa0d Update dependency @types/node to v18.19.55 (#4455)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-16 14:21:56 +00:00
renovate[bot] e9a9280e3c Update all non-major dependencies (#4458)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-16 13:34:51 +00:00
renovate[bot] fabdd6da64 Update dependency eslint-plugin-unicorn to v56 (#4459)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-16 13:30:52 +00:00
renovate[bot] ab5d95102c Update dependency typescript to v5.6.3 (#4456)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-16 12:51:13 +00:00
renovate[bot] b4556d6552 Update typedoc (#4457)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-16 12:50:55 +00:00
renovate[bot] 6c22da9a96 Update dependency eslint to v8.57.1 (#4437)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-10-16 12:50:08 +00:00
renovate[bot] d29329bddb Replace dependency eslint-plugin-node with eslint-plugin-n ^14.0.0 (#4416)
* Replace dependency eslint-plugin-node with eslint-plugin-n ^14.0.0

* Update eslint config

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>
2024-10-16 12:49:22 +00:00
Michael Telatynski 68b06d7b60 Update workflows referencing matrix-react-sdk to use only element-web (#4451) 2024-10-16 13:48:21 +01:00
Andrew Ferrazzutti 5f599ee978 Fix DelayedEventInfo type (#4446)
* Fix DelayedEventInfo type

for MSC4140's GET /delayed_events

* Satisfy linter while avoiding unaligned indents

* Remove transaction_id from DelayedEventInfo

See matrix-org/matrix-spec-proposals@883e6b5d
2024-10-15 21:06:36 +00:00
Florian Duros aabd558bce Deprecate top level crypto event re-export (#4444) 2024-10-15 15:00:43 +00:00
Florian Duros 662b772c73 Add crypto events to crypto-api (#4443)
* Move used Crypto event into crypto api

* Use new crypto events in rust crypto

* Remove `WillUpdateDevices` event from CryptoApi

* Use new crypto events in old crypto events

* Compute type of CryptoEvent enum

* Rename CryptoEvent and CryptoEventHandlerMap as legacy

* - Rename `RustCryptoEvent` as `CryptoEvent`
- Declare `CryptoEventHandlerMap` into the crypto api

* Add `WillUpdateDevices` back to new crypto events to avoid circular imports between old crypto and the cryto api

* Extends old crypto handler map with the new crypto map

* Review fixes

* Add more explicit documentations
2024-10-15 14:38:33 +00:00
RiotRobot b240c44128 v34.9.0-rc.0 2024-10-15 14:31:37 +00:00
RiotRobot 5508993d79 Merge branch 'master' into develop 2024-10-15 10:53:49 +00:00
RiotRobot c9b43ab251 v34.8.0 2024-10-15 10:53:23 +00:00
David Baker 2fb1e659c8 Merge commit from fork
Remove insecure MatrixClient.sendSharedHistoryKeys method
2024-10-15 11:48:16 +01:00
RiotRobot b842192a34 Merge branch 'master' into develop 2024-10-08 12:23:01 +00:00
RiotRobot 868bbfcb31 v34.7.0 2024-10-08 12:22:28 +00:00
Saul 860161bdd2 Fix the rust crypto import in esm environments. (#4445)
* Configure babel to fix the rust import in esm environments.

* Add lockfile changes.

* Cleanup rust-crypto import and babel config.
2024-10-08 10:34:01 +00:00
Florian Duros 0c9d82e40a Deprecate the crypto events which are not used by the rust-crypto (#4442)
* Deprecate crypto event not used by the rust-crypto

* Deprecate `Crypto.WillUpdateDevices` for `Crypto.DevicesUpdated`
2024-10-07 12:26:56 +00:00
Richard van der Hoff 73ab7c342a Expose crypto-api as its own typedoc module (#4439)
Currently the crypto-api hierarchy is exposed only as a `Crypto` namespace
under the "matrix" entrypoint in the documentation.

This isn't really right: it's meant to be a separate entrypoint (in the same
way as `types`, `testing` and `utils` are). This PR fixes that problem.
2024-10-07 11:38:28 +00:00
Hugh Nimmo-Smith 3386c66b98 Fix MatrixRTC sender key wrapping (#4441) 2024-10-07 10:34:23 +00:00
Florian Duros da044820d7 Clean AES export and move back calculateKeyCheck to secret-storage.ts (#4440) 2024-10-03 13:20:56 +00:00
renovate[bot] 9f40f32b3e Update dependency @types/node to v18.19.54 (#4436)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-01 16:37:25 +00:00
renovate[bot] f679942584 Update all non-major dependencies (#4438)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-01 16:16:22 +00:00
RiotRobot c1b4f97372 v34.7.0-rc.0 2024-10-01 14:54:58 +00:00
Florian Duros 5f3b89990d Move out crypto/aes (#4431)
* Move `SecretEncryptedPayload` in `src/utils/@types`

* Move `encryptAES` to a dedicated file. Moved in a utils folder.

* Move `deriveKeys` to a dedicated file in order to share it

* Move `decryptAES` to a dedicated file. Moved in a utils folder.

* Move `calculateKeyCheck` to a dedicated file. Moved in a utils folder.

* Remove AES functions in `aes.ts` and export new ones for backward compatibility

* Update import to use new functions

* Add `src/utils` entrypoint in `README.md`

* - Rename `SecretEncryptedPayload` to `AESEncryptedSecretStoragePayload`.
- Move into `src/@types`

* Move `calculateKeyCheck` into `secret-storage.ts`.

* Move `deriveKeys` into `src/utils/internal` folder.

* - Rename `encryptAES` on `encryptAESSecretStorageItem`
- Change named export by default export

* - Rename `decryptAES` on `decryptAESSecretStorageItem`
- Change named export by default export

* Update documentation

* Update `decryptAESSecretStorageItem` doc

* Add lnk to spec for `calculateKeyCheck`

* Fix downstream tests
2024-10-01 13:52:59 +00:00
Richard van der Hoff 866fd6f4a3 Bump matrix-rust-sdk to 9.1.0 (#4435)
Mostly, to pick up https://github.com/matrix-org/matrix-rust-sdk/pull/3985
2024-09-30 16:46:33 +00:00
Valere 9ecb66e695 crypto: configure key sharing strategy based on DeviceIsolationMode (#4425)
* crypto: configure key sharing strategy based on deviceIsolationMode

fix eslint import error

cryptoMode was renamed to deviceIsolationMode

post rebase fix: Device Isolation mode name changes

* Fix outdated docs referring to old cryptomode

* code review: better comment for globalBlacklistUnverifiedDevices option

* RoomEncryptor: Use appropriate default for getBlacklistUnverifiedDevices

* do not provide a default value for DeviceIsolationMode for encryption

* Update src/rust-crypto/RoomEncryptor.ts

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-09-30 14:26:34 +00:00
Hugh Nimmo-Smith baa6d13506 RTCSession cleanup: deprecate getKeysForParticipant() and getEncryption(); add emitEncryptionKeys() (#4427)
* RTCSession cleanup: deprecate getKeysForParticipant() and getEncryption(); add emitEncryptionKeys()

* Clarify comment

* Feedback from code review

* Update src/matrixrtc/MatrixRTCSession.ts

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>

* Fix test

---------

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>
2024-09-27 15:55:07 +00:00
Hugh Nimmo-Smith 2d6230f199 Rotate RTC key when a new member joins (#4422) 2024-09-27 15:54:48 +00:00
Tulir Asokan 825d85f18d Update media event content types to include captions (#4403)
Signed-off-by: Tulir Asokan <tulir@maunium.net>
2024-09-26 16:06:59 +00:00
Richard van der Hoff 1dcb7a6e75 Remove insecure MatrixClient.sendSharedHistoryKeys method
This method is impossible to use securely, and so is being removed. (It also
didn't work under Rust cryptography.)

In future, this functionality may be re-introduced in a safer way, but doing so
will probably require updates to the MSC.
2024-09-26 12:03:45 +01:00
Richard van der Hoff 823316b2ff Remove use of insecure sendSharedHistoryKeys in MSC3089 impl 2024-09-26 12:01:51 +01:00
renovate[bot] d56fa197d0 Update dependency typescript to v5.6.2 (#4420)
* Update dependency typescript to v5.6.2

* Fix TS errors

* Update minimal version of TS to `5.4.2` since the code is not compliant with an older version.

* Review fixes

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Florian Duros <florian.duros@ormaz.fr>
Co-authored-by: Florian Duros <florianduros@element.io>
2024-09-26 08:23:38 +00:00
Michael Telatynski f7229bfff0 Update OIDC registration types to match latest MSC2966 state (#4432)
* Update OIDC registration types to match latest MSC2966 state

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

* Add comment

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-09-25 16:30:13 +00:00
Valere 538717c23e crypto: Replace cryptoMode with DeviceIsolationMode concept (#4429)
* crypto: Replace cryptoMode with DeviceIsolationMode concept

* use enum instead of string for the IsolationMode kind

* Code review - Cleaning, renaming

* review: unneeded @see in doc

* review: Rename IsolationMode with better names

* review: quick cleaning and doc
2024-09-25 13:33:02 +00:00
Richard van der Hoff 1a8ea3d685 Add CryptoApi.pinCurrentUserIdentity and UserIdentity.needsUserApproval (#4415)
* Implement `UserVerificationStatus.needsUserApproval`

Expose the `identityNeedsUserApproval` flag from the rust crypto crate.

* Add CryptoApi.pinCurrentUserIdentity

Expose `pinCurrentMasterKey` from the rust crypto api.

* Test data: add second cross-signing key for Bob

* Add tests for verification status
2024-09-24 16:38:18 +00:00
Florian Duros d0890d9450 Update sonarcloud action to use v3.3 matrix-org/sonarcloud-workflow-action (#4430) 2024-09-24 15:35:40 +00:00
RiotRobot 42ec17b977 Merge branch 'master' into develop 2024-09-24 12:37:47 +00:00
RiotRobot 82e9eefce6 v34.6.0 2024-09-24 12:37:19 +00:00
renovate[bot] f8208b1891 Update typedoc (#4419)
* Update typedoc

* Don't link a private method in tsdoc of a public method

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Florian Duros <florian.duros@ormaz.fr>
2024-09-23 13:47:49 +00:00
Richard van der Hoff 092a59af66 Throw clearer error if createSecretStorageKey misbehaves (#4412)
https://github.com/element-hq/element-web/issues/27888 shows a slightly
mysterious error message, but the problem is `createSecretStorageKey`
returning the wrong thing.
2024-09-23 10:25:42 +00:00
renovate[bot] dbd7d26968 Update dependency @types/node to v18.19.50 (#4418)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-19 15:26:50 +00:00
renovate[bot] 4fda9e8419 Update all non-major dependencies (#4417)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-19 13:38:54 +00:00
RiotRobot a13e0389db v34.6.0-rc.0 2024-09-18 13:31:13 +00:00
Hubert Chathi dbb4828eda Add crypto mode setting for invisible crypto, and apply it to decrypting events (#4407)
Adds a global "crypto mode" setting to the crypto API (only works with Rust crypto), and changes the decryption settings based on that.
2024-09-18 12:53:07 +01:00
Hugh Nimmo-Smith 414ac9d8cc Don't share full key history for RTC per-participant encryption (#4406)
* Don't share full key history for RTC per-participant encryption

Also record stats for how many keys have been sent/received and age of those received

* Update src/matrixrtc/MatrixRTCSession.ts

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

* Add comment about why we track total age of events

---------

Co-authored-by: Robin <robin@robin.town>
2024-09-18 08:57:26 +00:00
Johannes Marbach 30058a4bdc Add ESLint rule to ensure .ts extensions on imports (#4409)
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2024-09-18 07:40:01 +00:00
Florian Duros fab9cab3df Move crypto/key_passphrase.ts to crypto-api/key-passphrase.ts (#4401)
* Move `crypto/key_passphrase.ts` to `crypto-api/key-passphrase.ts`

* Re-export `crypto-api/key-passphrase` into `crypto/key_passphrase.ts`

* Add doc

* Deprecate `MatrixClient.keyBackupKeyFromPassword`

* Move `keyFromAuthData` to `common-crypto/key-passphrase.ts`

* Fix faulty import

* Keep `keyFromPassphrase` in old crypto

* - Rename `deriveKey` into `deriveRecoveryKeyFromPassphrase`
- Call `deriveRecoveryKeyFromPassphrase` into `RustCrypto.createRecoveryKeyFromPassphrase` instead of using `keyFromPassphrase`

* Remove alternative in `keyBackupKeyFromPassword` deprecation.

* Add tests for `keyFromAuthData`

* Deprecate `keyFromAuthData`

* Review changes
2024-09-17 13:05:47 +00:00
Johannes Marbach 53b599f8fe Export membership types (#4405)
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2024-09-14 10:44:51 +00:00
Timo 17f6cc733e Fix redact sending over in embedded (widget) mode (#4398) 2024-09-13 16:07:44 +00:00
Johannes Marbach c8403f39aa Fix build failure in node.js example (#4394)
* Fix node.js example

Relates to: element-hq/element-web#26922
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>

* Update examples/node/app.js

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

* Update examples/node/package.json

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

* Move imports to the top of the file

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-09-13 15:35:45 +00:00
Florian Duros 8cf5df73ee Move crypto/recoverykey.ts to crypto-api/recovery-key.ts (#4399)
* Move `crypto/recoverykey.ts` to `crypto-api/recovery-key.ts`

* Re-export `crypto-api/recovery-key` into `crypto/recoverykey`

* Add a bit of doc

* Deprecate `MatrixClient.isValidRecoveryKey` and `MatrixClient.keyBackupKeyFromRecoveryKey`

* Import `index.ts` directly

* Update `recovery-key.ts` doc

* Add tests for `decodeRecoveryKey`

* Move `recovery-key.spec.ts` file
2024-09-13 13:26:30 +00:00
Florian Duros febe27ddcc Replace matrix.org/matrix-react-sdk by element-hq/matrix-react-sdk (#4404) 2024-09-13 13:03:31 +00:00
Hubert Chathi 7987ce76ec Bump dependency on rust-sdk-crypto-wasm to v8.0.0 (#4396) 2024-09-13 10:22:33 +01:00
Richard van der Hoff 60cedf2fdb Improve documentation on {encrypt,decrypt}AES (#4397) 2024-09-11 14:13:12 +00:00
Robin ed44514974 Expose the event ID of a call membership (#4395)
This is in line with the other information we're already exposing, such as the event's sender and timestamp. We want this in order to play around with adding reactions to the membership event.
2024-09-10 20:15:07 +00:00
RiotRobot 9f8c1ee953 Merge branch 'master' into develop 2024-09-10 12:31:32 +00:00
RiotRobot 593a57fc2b v34.5.0 2024-09-10 12:30:54 +00:00
Will Hunt e8128d34a1 MSC4133 - Extended profiles (#4391)
* Add MSC4133 functionality.

* Add MSC4133 capability.

* Tidy

* Add tests for extended profiles.

* improve docs

* undefined

* Add a prefix function to reduce reptitiveness

* Add a docstring
2024-09-09 12:06:38 +00:00
Richard van der Hoff ba7bd06295 Element-R: Mark unsupported MatrixClient methods as deprecated (#4389)
Slap a `@deprecated` tag on all the MatrixClient methods which no longer work
with rust crypto.
2024-09-05 13:37:08 +00:00
Richard van der Hoff e4db6008b8 Minor improvements to logging in device verification (#4390)
A grab-bag of small logging improvements in the Rust crypto wrapper.
2024-09-05 10:22:54 +00:00
Johannes Marbach 52f35409ec Stabilise MSC4156 (#4381)
* Stabilise MSC4156

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>

* Add deprecation comments

* Add minimum Matrix version

---------

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2024-09-04 12:01:33 +00:00
renovate[bot] f50aab37c3 Update babel monorepo (#4387)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-03 21:29:21 +00:00
renovate[bot] df0f817f83 Update dependency typedoc-plugin-mdn-links to v3.2.10 (#4386)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-03 21:20:01 +00:00
renovate[bot] 7efa6352f8 Update shogo82148/actions-upload-release-asset digest to aac270e (#4385)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-03 20:32:50 +00:00
renovate[bot] f74614705e Update mheap/github-action-required-labels digest to d25134c (#4384)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-03 20:32:29 +00:00
renovate[bot] 169e8f8613 Update dependency @types/node to v18.19.47 (#4383)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-03 15:22:51 +00:00
renovate[bot] f2f77bd1f7 Update all non-major dependencies (#4382)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-03 13:51:09 +00:00
RiotRobot 5a1c70ad19 v34.5.0-rc.0 2024-09-03 12:31:16 +00:00
David Baker 27cb16ffe4 Merge pull request #4379 from matrix-org/renovate/matrix-org
Update dependency matrix-widget-api to v1.9.0
2024-08-30 17:05:06 +01:00
renovate[bot] 9be0b3e701 Update dependency matrix-widget-api to v1.9.0 2024-08-30 15:54:06 +00:00
Johannes Marbach 05ba27f36b Change imports for Node.js compatibility (#4377)
* Change imports for Node.js compatibility

Fixes: #4287
Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>

* Run prettier

* Run prettier (again)

* Add comment

* Update babel.config.cjs

---------

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-08-29 15:56:32 +00:00
David Baker e6acfdf275 Rename merge release notes script to cjs (#4361)
and update the corresponding workflow file
2024-08-28 10:40:16 +00:00
RiotRobot 2a6612c73a Merge branch 'master' into develop 2024-08-27 12:38:13 +00:00
RiotRobot 2f8b05b0da v34.4.0 2024-08-27 12:37:46 +00:00
Hugh Nimmo-Smith fe984ede6e Use prefixed loggers for MatrixRTC (#4378) 2024-08-23 19:04:22 +00:00
Richard van der Hoff 3f74b9a0cc Deprecate unused CryptoCallbacks (#4376) 2024-08-23 14:00:27 +00:00
David Baker 802b996b10 Set web team as codeowner for the scripts dir (#4354)
The scripts in here are used in the release, and from the develop
branch too (because it's the main branch and github actions does this)
so it's critical for the release process.
2024-08-23 12:46:27 +00:00
renovate[bot] 8d44f9d665 Update dependency eslint-plugin-unicorn to v55 (#4371)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-22 12:32:26 +00:00
renovate[bot] a72a1b294a Update dependency eslint-plugin-jsdoc to v50 (#4370)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-22 11:22:35 +00:00
renovate[bot] ab5f32f984 Update typedoc (#4367)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-22 10:46:01 +00:00
renovate[bot] 6a21d812ab Update typescript-eslint monorepo to v7.18.0 (#4368)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-22 10:41:47 +00:00
Richard van der Hoff ee94e93354 set entrypoints to use ./lib rather than ./src (#4357)
Currently, we replace the entrypoints in package.json during the release
cycle. I think. historically, this was done to make matrix-react-sdk and
element-web development easier, but neither of those projects actually use
these entrypoints (instead they import from `src`).

Accordingly, I think the switcheroo is unnecessary; furthermore it causes a
whole bunch of confusion by making the development environment different from
the release environment, and it complicates our CI and release process.

In short, the switcheroo has to die.
2024-08-21 18:31:05 +00:00
renovate[bot] 31c4786a96 Update dependency fetch-mock to v11 (#4369)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-21 16:14:39 +00:00
renovate[bot] 17b6e59819 Update shogo82148/actions-upload-release-asset digest to 6d4fd50 (#4366)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-21 15:47:42 +00:00
renovate[bot] 42510022a1 Update dependency typescript to v5.5.4 (#4365)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-21 15:08:24 +00:00
renovate[bot] 5f0978ac3f Update babel monorepo (#4363)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-21 14:41:16 +00:00
renovate[bot] cd6787e0ac Update dependency @types/node to v18.19.44 (#4364)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-21 14:22:08 +00:00
renovate[bot] 03baa3e358 Update all non-major dependencies (#4362)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-21 13:51:57 +00:00
RiotRobot 658563e2a7 v34.4.0-rc.1 2024-08-21 12:56:47 +00:00
David Baker 26d3033b17 Merge pull request #4358 from matrix-org/backport-4356-to-staging
[Backport staging] Rename slowReporter to reflect that it is CommonJS
2024-08-21 13:01:49 +01:00
David Baker a4bd7dc7d7 Merge branch 'staging' into backport-4356-to-staging 2024-08-21 12:53:16 +01:00
David Baker 1f48544b38 Merge pull request #4359 from matrix-org/dbkr/backport_4355
Move `type:module` declaration into package.json. (Backport 4355)
2024-08-21 12:46:40 +01:00
Richard van der Hoff 7ef4062f59 Move type:module declaration into package.json. (#4355)
* Rename `switch_package_to_release.js` to `.cjs`

Slightly surprisingly, the symlink is enough to make `node
switch_package_to_release.js` work.

* Rename .eslintrc.js to .cjs

Again, declare this as commonjs

* Move `type:module` declaration into package.json.

matrix-js-sdk is built into ECMAScript modules, and we should declare it as
such. See https://nodejs.org/api/packages.html#type. Failure to do so causes
problems for javascript projects attempting to build against matrix-js-sdk: see https://github.com/matrix-org/matrix-js-sdk/issues/4347.

Previously, we did this as part of the package.json switcheroo, but that is
unnecessarily fragile.

matrix-react-sdk, element-web, etc are unaffected by this, because they use the
typescript files directly, by importing `matrix-js-sdk/src/...`.
2024-08-21 12:04:59 +01:00
Richard van der Hoff 968bc51a35 Rename slowReporter to reflect that it is CommonJS (#4356)
Fix tests failing as a result of
https://github.com/matrix-org/matrix-js-sdk/pull/4355. This wasn't detected in
CI because the slowReporter is only enabled when building against develop.

(cherry picked from commit d413f5042e)
2024-08-21 09:39:52 +00:00
Richard van der Hoff d413f5042e Rename slowReporter to reflect that it is CommonJS (#4356)
Fix tests failing as a result of
https://github.com/matrix-org/matrix-js-sdk/pull/4355. This wasn't detected in
CI because the slowReporter is only enabled when building against develop.
2024-08-20 20:48:27 +00:00
Richard van der Hoff b8e8b14375 Move type:module declaration into package.json. (#4355)
* Rename `switch_package_to_release.js` to `.cjs`

Slightly surprisingly, the symlink is enough to make `node
switch_package_to_release.js` work.

* Rename .eslintrc.js to .cjs

Again, declare this as commonjs

* Move `type:module` declaration into package.json.

matrix-js-sdk is built into ECMAScript modules, and we should declare it as
such. See https://nodejs.org/api/packages.html#type. Failure to do so causes
problems for javascript projects attempting to build against matrix-js-sdk: see https://github.com/matrix-org/matrix-js-sdk/issues/4347.

Previously, we did this as part of the package.json switcheroo, but that is
unnecessarily fragile.

matrix-react-sdk, element-web, etc are unaffected by this, because they use the
typescript files directly, by importing `matrix-js-sdk/src/...`.
2024-08-20 16:23:03 +00:00
RiotRobot 43e58871de v34.4.0-rc.0 2024-08-20 13:40:49 +00:00
Richard van der Hoff 2544c14032 Unrevert prerelease fix, and fix release error (#4353)
* Reapply "Add "type" = "module" to ensure it is present (#4350)" (#4352)

This reverts commit 8214fd7156.

* Mark prettier config file as CommonJS

I *think* this will fix a problem with the release process in which we saw an
error:

```
Error:  Invalid configuration for file "/home/runner/work/matrix-js-sdk/matrix-js-sdk/package.json":
Error:  module is not defined in ES module scope
Error:  This file is being treated as an ES module because it has a '.js' file extension and '/home/runner/work/matrix-js-sdk/matrix-js-sdk/package.json' contains "type": "module". To treat it as a CommonJS script, rename it to use the '.cjs' file extension.
```
2024-08-20 13:16:44 +00:00
RiotRobot 8d19782c57 Merge branch 'master' into develop 2024-08-20 11:30:12 +00:00
RiotRobot 340bbe1a8f v34.3.1 2024-08-20 11:29:48 +00:00
David Baker 8214fd7156 Revert "Add "type" = "module" to ensure it is present (#4350)" (#4352)
This reverts commit d6080398db.
2024-08-20 11:10:15 +00:00
David Baker a0efed8b88 Merge commit from fork
Detect cycles when looking for predecessor rooms
2024-08-20 11:27:28 +01:00
Hugh Nimmo-Smith c408c0d1d5 Retry event decryption failures on first failure (#4346)
* Retry event decryption failures on first failure

* Suggestion from code review

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>

---------

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>
2024-08-19 13:35:45 +00:00
BLCK d6080398db Add "type" = "module" to ensure it is present (#4350) 2024-08-15 14:50:05 +00:00
Hugh Nimmo-Smith 467908703b Don't attempt to adjust for clock skews when calculating group call membership expiry (#4340)
* Use origin server timestamp for calculating group call membership expiry

* Fix tests

* Docs

* Refactor comments to reflect that the logic hasn't changed

* Make comment maintainable

* Fix up merge

* Fix test
2024-08-15 09:11:06 +00:00
Hugh Nimmo-Smith 87eddaf51a Handle MatrixRTC encryption keys arriving out of order (#4345)
* Handle MatrixRTC encryption keys arriving out of order

* Apply suggestions from code review

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>

* Suggestion from code review

---------

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>
2024-08-15 07:58:36 +00:00
Hugh Nimmo-Smith c65ef03567 Resend MatrixRTC encryption keys if a membership has changed (#4343)
* Resend MatrixRTC encryption keys if a membership has changed

* JSDoc

* Update src/matrixrtc/MatrixRTCSession.ts

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>

* Add note about using Set. symmetricDifference() when available

* Always store latest fingerprints

Should reduce unnecessary retransmits

* Refactor

---------

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>
2024-08-14 14:08:52 +00:00
RiotRobot 78cbf7cd28 Resetting package fields for development 2024-08-13 12:06:18 +00:00
RiotRobot dc7c1a4fef Merge branch 'master' into develop 2024-08-13 12:06:17 +00:00
RiotRobot 1ae0c2f3ee v34.3.0 2024-08-13 12:05:45 +00:00
Hugh Nimmo-Smith affaa95fb4 delayBeforeuse => delayBeforeUse for consistency (#4344) 2024-08-09 14:34:13 +00:00
Andrew Ferrazzutti 9176d3a671 Use non-legacy calls if any are found (#4337)
Akin to how legacy call events should be sent in rooms where there is
any ongoing legacy call, send non-legacy events in rooms where there are
only non-legacy calls; else fall back to the config preference.
2024-08-07 15:44:44 +00:00
RiotRobot de50129a53 v34.3.0-rc.1 2024-08-06 12:26:55 +00:00
Michael Telatynski 5568dfdd41 Move olm to dependencies as its types are needed downstream
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-08-06 13:25:55 +01:00
RiotRobot 39216d44ed v34.3.0-rc.0 2024-08-06 12:03:46 +00:00
Michael Telatynski 8c3b249567 Re-add olm dependency which is needed for types
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-08-06 12:00:30 +01:00
Michael Telatynski b8e40ad2a8 Resetting package fields for development 2024-08-06 11:46:18 +01:00
Michael Telatynski 4e2831764d Merge branch 'master' into develop 2024-08-06 11:46:05 +01:00
Michael Telatynski 09780672aa Fix release-gitflow.yml node version 2024-08-06 11:42:35 +01:00
Andrew Ferrazzutti 0fe53876ec Bump matrix-widget-api (#4336) 2024-08-02 12:10:24 +00:00
Michael Telatynski dfec3dc33c Make code tsc es2022 compliant (#4335)
* Remove redundant global.d.ts definitions

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

* Remove roomId overload

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

* Update base.ts

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-08-01 15:16:59 +00:00
Andrew Ferrazzutti fbdd78b428 Also check for MSC3757 for session state keys (#4334)
Do not prefix the non-legacy session membership state keys with an
underscore for rooms using MSC3757 (in addtion to MSC3779).
2024-08-01 14:57:29 +00:00
Andrew Ferrazzutti e10c362ef0 Support MSC4157: delayed events via Widget API (#4311) 2024-08-01 14:17:52 +00:00
David Baker 89a9a7fa38 Fix hashed ID server lookups with no Olm (#4333)
* Fix hashed ID server lookups with no Olm

It used the hash function from Olm (presumably to work cross-platform)
but subtle crypto is available on node nowadays so we can just use
that.

Refactor existing code that did this out to a common function, add
tests.

* Test the code when crypto is available

* Test case of no crypto available

* Move digest file to src to get it out of the way of the olm / e2e stuff

* Fix import

* Fix error string & doc

* subtle crypto, not webcrypto

* Extract the base64 part

* Fix test

* Move test file too

* Add more doc

* Fix imports
2024-08-01 10:55:23 +00:00
Andrew Ferrazzutti 687d08dc9d Support MSC4140: Delayed events (#4294)
and use them for more reliable MatrixRTC session membership events.

Also implement "parent" delayed events, which were in a previous version
of the MSC and may be reintroduced or be part of a new MSC later.

NOTE: Still missing is support for sending encrypted delayed events.
2024-07-30 12:43:25 +00:00
RiotRobot 7f91db83d0 v34.2.0 2024-07-30 12:37:58 +00:00
Michael Telatynski 0300d6343f Remove flaky test (#4332)
Fixes https://github.com/matrix-org/matrix-js-sdk/issues/4331
2024-07-29 13:42:07 +00:00
David Baker e0ef467d7d break instead of return 2024-07-29 13:55:08 +01:00
Richard van der Hoff dc1cccfecc Handle late-arriving m.room_key.withheld messages (#4310)
* Restructure eventsPendingKey to remove sender key

For withheld notices, we don't necessarily receive the sender key, so we'll
jhave to do without it.

* Re-decrypt events when we receive a withheld notice

* Extend test to cover late-arriving withheld notices

* update unit tests
2024-07-29 12:11:37 +00:00
David Baker 79299891fd Detect cycles when looking for predecessor rooms 2024-07-29 11:14:58 +01:00
Hubert Chathi d32f398345 Fix comment for useAuthorizationHeader config. (#4330) 2024-07-28 02:25:34 +00:00
Timo 0f08c00c07 Be specific about what is considered a MSC4143 call member event. (#4328)
* Be specific about what is considered a MSC4143 call member event.

* review

* check for empty event first

* Optimize for new session type events
If its a session type event we do not want to run two "key in" checks. We expect legacy events to be the less comment type going forward.

* awkward but necessary key count optimization
2024-07-25 10:57:27 +00:00
Timo 6b261b98c9 Add index.ts for matrixrtc module (#4314) 2024-07-25 10:00:11 +00:00
renovate[bot] 99f157a0f1 Update all non-major dependencies (#4323)
* Update all non-major dependencies

* Prettier

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

* Fix types for widget API update

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>
2024-07-24 16:40:51 +00:00
renovate[bot] f9f6d81346 Lock file maintenance (#4327)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-24 14:42:05 +00:00
renovate[bot] 46604abe7b Update dependency matrix-widget-api to v1.7.0 (#4326)
* Update dependency matrix-widget-api to v1.7.0

* Fix types

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>
2024-07-24 13:26:04 +00:00
Valere 553758e713 Bump rust sdk wasm version to 7.0.0 (#4316) 2024-07-24 11:53:36 +00:00
renovate[bot] 509e64cfc1 Update dependency typescript to v5.5.4 (#4321)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-24 10:32:17 +00:00
renovate[bot] 60c2e9b3ed Update babel monorepo (#4318)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-24 09:45:56 +00:00
renovate[bot] cfb21fa80a Update typescript-eslint monorepo to v7.16.1 (#4322)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-24 09:27:51 +00:00
renovate[bot] c3d7f4e730 Update dependency typedoc-plugin-mdn-links to v3.2.5 (#4320)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-24 09:17:18 +00:00
renovate[bot] aa97beae44 Update dependency @types/node to v18.19.41 (#4319)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-24 09:10:23 +00:00
RiotRobot 5feab37166 v34.2.0-rc.0 2024-07-23 11:58:56 +00:00
Michael Telatynski 1a02835ab2 Merge branch 'develop' of github.com:matrix-org/matrix-js-sdk into staging 2024-07-23 12:51:48 +01:00
David Baker 6f63ff1711 Remove the compare function from utils (#4315)
* Remove the compare function from utils

and change the one use of it to just intantiate a collator and use
it.

This was marked as internal module so this shouldn't be a breaking change.
Of course, react-sdk was using it.

Requires: https://github.com/matrix-org/matrix-react-sdk/pull/12782

* Add simple not-a-perf-test test

* recalculate repeatedly

otherwise we aren't testing anything different

* Use fewer members as it was making the test take a bit too long
2024-07-17 14:18:46 +00:00
RiotRobot 4d90fecb6a v34.1.0 2024-07-16 12:20:13 +00:00
Richard van der Hoff 30a26813ec Deprecate CreateSecretStorageOpts.getKeyBackupPassphrase (#4313)
it doesn't work in rust crypto, and we have no plans to fix it
(https://github.com/element-hq/element-web/issues/27455)
2024-07-13 10:19:14 +00:00
renovate[bot] f17a4fedb9 Lock file maintenance (#4199)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-10 16:31:06 +00:00
renovate[bot] 94e393c9a6 Update dependency typedoc to v0.26.4 (#4309)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-10 08:01:38 +00:00
Richard van der Hoff 53201688a6 Element-R: detect "withheld key" UTD errors, and mark them as such (#4302)
Partial fix to element-hq/element-web#27653
2024-07-09 21:42:58 +01:00
renovate[bot] 996663bf64 Update dependency rimraf to v6 (#4307)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-09 17:12:10 +00:00
renovate[bot] d6e4338a37 Update all non-major dependencies (#4305)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-09 16:48:22 +00:00
renovate[bot] b2665f2128 Update typedoc (#4304)
* Update typedoc

* Update README.md

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-07-09 15:30:34 +00:00
renovate[bot] af4b6bc126 Update typescript-eslint monorepo to v7.15.0 (#4306)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-09 14:16:29 +00:00
renovate[bot] 565bb0ef7c Update dependency typescript to v5.5.3 (#4303)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-09 14:15:37 +00:00
Michael Telatynski fe0edcd081 Stop testing on Node 21 as it is EOL (#4308)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-07-09 14:32:07 +00:00
RiotRobot 6520e0f54f v34.1.0-rc.3 2024-07-09 13:15:09 +00:00
Michael Telatynski ed7b314e6a Promote olm to a real dep given the types refer to it
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-07-09 14:13:50 +01:00
RiotRobot 24eff501e4 v34.1.0-rc.2 2024-07-09 12:17:59 +00:00
Michael Telatynski 51544f25a7 Fix bump-downstreams using incompatible Node version
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-07-09 13:17:11 +01:00
RiotRobot a0d73dfaca v34.1.0-rc.1 2024-07-09 12:12:53 +00:00
Michael Telatynski 5d2500b7a7 Fix bump-downstreams using incompatible Node version
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-07-09 13:11:25 +01:00
RiotRobot eff52b82e8 v34.1.0-rc.0 2024-07-09 12:04:20 +00:00
Michael Telatynski 2868308079 Prettier 2024-07-08 16:46:14 +01:00
RiotRobot a5ef569717 Resetting package fields for development 2024-07-08 12:18:34 +00:00
RiotRobot c06b22ae7c Merge branch 'master' into develop 2024-07-08 12:18:34 +00:00
RiotRobot 7a51798acb v34.0.0 2024-07-08 12:18:02 +00:00
Richard van der Hoff 712ba617de Remove crypto shims (#4292)
* Inline subtlecrypto shim

The presence of this thing just makes code more confusing.

* Remove pre-node-20 webcrypto hack

Until node 20.0, the webcrypto API lived at `crypto.webCrypto`. It's now
available at the same place as in web -- `globalThis.crypto`.

See: https://nodejs.org/docs/latest-v20.x/api/webcrypto.html#web-crypto-api

* oidc auth test: Clean up mocking

THe previous reset code wasn't really resetting the right thing. Let's just
re-init `window.crypto` on each test.

* Remove `crypto` shim

This isn't very useful any more.
2024-07-05 09:42:06 +00:00
Timo 957329b218 Fix room state being updated with old (now overwritten) state and emitting for those updates. (#4242)
* Fix room state being updated with old (now overwritten) state and emitting for those updates.

* remove timestamp condition

Add configuration for toStartOfTimeline

* fix timeline tests

* only skip event adding if event_id and replaces_state is set.

* fix room tests

* test skipping insertion

* rename back to lastStateEvent

* store if a state is at the start of a timeline in the RoomState class

* make `isStartTimelineState` a `public readonly` and fix condition.
2024-07-05 09:16:59 +00:00
Richard van der Hoff 1733ec7b7f Remove redundant checks on global.Olm (#4301)
These routines don't use Olm, and we shouldn't be checking for it.
2024-07-04 15:49:56 +00:00
RiotRobot 24c589923b v34.0.0-rc.1 2024-07-04 12:49:22 +00:00
Richard van der Hoff 03ed4f5dd7 Bump node.js requirement to 20. (#4293)
According to
https://github.com/matrix-org/matrix-js-sdk?tab=readme-ov-file#supported-platforms,
we *only* supprt the latest LTS release (which is currenly https://github.com/nodejs/release#release-schedule), so this should be safe.
2024-07-04 12:27:31 +00:00
Joel 6e641a28c0 Add ability to choose how many timeline events to sync when peeking (#4300)
* Add ability to choose how many timeline events to sync when peeking.

* Add a test that covers the new method parameter.

* Formatting.

---------

Co-authored-by: Joel <joel.garplind+github@gmail.com>
2024-07-04 12:14:14 +00:00
ElementRobot 1586de44bd [Backport staging] Fix "Unable to restore session" error (#4299)
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Fixes https://github.com/element-hq/element-web/issues/27666
2024-07-03 20:56:40 +01:00
Richard van der Hoff b36682cb99 Bump matrix-rust-sdk to 6.2.1 (#4298)
Fixes https://github.com/element-hq/element-web/issues/27666
2024-07-03 19:31:23 +00:00
David Baker 04ea2a4e5d Merge pull request #4297 from matrix-org/backport-4296-to-staging
[Backport staging] Fix error when sending encrypted messages in large rooms
2024-07-03 15:22:31 +01:00
Richard van der Hoff b71099d0f8 Bump matrix-rust-sdk to 6.2.0 (#4296)
Fixes https://github.com/element-hq/element-web/issues/27658

(cherry picked from commit ccc2fb5663)
2024-07-03 14:04:38 +00:00
Richard van der Hoff ccc2fb5663 Bump matrix-rust-sdk to 6.2.0 (#4296)
Fixes https://github.com/element-hq/element-web/issues/27658
2024-07-03 13:45:38 +00:00
David Langley 0a7f7efd9d Sync labels with element-meta and add local labels yml for others. (#4295) 2024-07-03 13:36:40 +00:00
Richard van der Hoff ae58d0c8eb Rust crypto: Clean up handling of verification events (#4288)
We had both an `onIncomingKeyVerificationRequest` and an
`onKeyVerificationRequest` which did different, but related, things.

Improve the documentation and reduce the duplication.
2024-07-01 11:32:09 +00:00
Richard van der Hoff 20a6704497 Remove redundant TextEncoder shim (#4290)
I believe the only reason we had this was that, before Node v11.0,
`TextEncoder` wasn't available in the global object. Nowadays it is (see
https://nodejs.org/api/util.html#class-utiltextencoder), so let's get rid of
it.
2024-07-01 09:15:01 +00:00
Kegan Dougal 3337bda752 Remove useless log line (#4289)
- it was spammy: https://github.com/element-hq/element-web/issues/27031
- it didn't actually log the duration, because the `block` function didn't
  `await` the inner promise.
2024-06-28 15:49:52 +00:00
Richard van der Hoff d90292bff5 Use prebuilt js-sdk for node example (#4286)
This example seems to have been broken by the switch to Typescript. We can't
just symlink in `../..` because that gives us the typescript version of the
source, which, obviously, doesn't work in node.

Instead, make sure we use a prebuilt version of the js-sdk.

It's actually even more broken as of js-sdk 33.0.0, thanks to the switch to ES
modules (#4187), but we'll get to that later.
2024-06-27 16:58:26 +00:00
Richard van der Hoff 3de0c02757 Remove redundant hack for using the old pickle key in rust crypto (#4282)
* Remove redundant hack for using the old pickle key in rust crypto

* Fix tests
2024-06-27 15:43:54 +00:00
Richard van der Hoff 65b9c31f9b Rename crypto-api.ts -> crypto-api/index.ts (#4283)
I found it quite confusing having `CryptoApi` be defined so far from the
`crypto-api` folder.
2024-06-26 21:02:40 +00:00
Richard van der Hoff d629a685c2 Declare matrix-js-sdk as an ES module (#4285)
* Declare matrix-js-sdk as an ES module

* Rename `babel.config.js` to show it is a CommonJS module

... otherwise it gets broken by `scripts/switch_package_to_release.js`
2024-06-26 17:11:29 +00:00
Timo 0210106be2 Add fetching the well known in embedded mode. (#4259)
* Add fetching the well known in embedded mode.

This is used to load the focus from the well known in elment-call.

* revert what we dont want in this PR.

* Update src/client.ts

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>

---------

Co-authored-by: Andrew Ferrazzutti <andrewf@element.io>
2024-06-26 09:29:11 +00:00
renovate[bot] 3e05a71068 Update dependency typedoc-plugin-coverage to v3.3.0 (#4281)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 22:21:51 +00:00
renovate[bot] c755810d9c Update dependency typedoc-plugin-mdn-links to v3.2.0 (#4279)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 17:06:31 +00:00
renovate[bot] 2d492f60a0 Update dependency typescript to v5.5.2 (#4280)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 16:49:31 +00:00
renovate[bot] 16db2c5f9a Update dependency @types/node to v18.19.39 (#4278)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 16:30:40 +00:00
renovate[bot] 29c02d8c37 Update all non-major dependencies (#4268)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 16:30:03 +00:00
Michael Telatynski 0f98df158c Fix ingest of release notes wiping out the parent notes (#4266)
* Fix ingest of release notes wiping out the parent notes

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

* Remove redundant reusable workflow input

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-25 16:24:13 +00:00
renovate[bot] 2ea4ce0bb6 Update dependency bs58 to v6 (#4274)
* Update dependency bs58 to v6

* Update import

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

* prettier

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>
2024-06-25 16:02:43 +00:00
renovate[bot] 3e0017fecf Update actions/checkout digest to 692973e (#4267)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 15:25:04 +00:00
renovate[bot] a0073ddaaf Update typescript-eslint monorepo to v7.14.1 (#4272)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 14:36:52 +00:00
renovate[bot] c29e116c0c Update dependency typescript to v5.5.2 (#4271)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 14:36:11 +00:00
renovate[bot] d9f372ca79 Update dependency eslint-plugin-unicorn to v54 (#4275)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 13:54:38 +00:00
renovate[bot] 6417f4fac7 Update dependency fetch-mock to v10 (#4276)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-25 16:02:45 +01:00
renovate[bot] 4bae83f59f Update dependency @types/uuid to v10 (#4273)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 13:53:11 +00:00
renovate[bot] b8c68eb102 Update dependency @types/node to v18.19.39 (#4269)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-25 13:50:33 +00:00
renovate[bot] 8790cde6d4 Update dependency typedoc to ^0.26.0 (#4270)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-25 15:21:27 +01:00
RiotRobot ab6260074d v34.0.0-rc.0 2024-06-25 12:50:01 +00:00
Andrew Ferrazzutti 25a7c9e140 Prefix the user+device state key if needed (#4262)
* Prefix the user+device state key if needed

No need to prefix it for rooms that use MSC3779.
Otherwise, prefix it to bypass the auth rule for state events with keys
starting with @.

* Use RegExp.exec() method instead

Sonar typescript:S6594

* Split nested ternary operator into method

Sonar typescript:S3358

* Add test coverage
2024-06-21 17:31:42 +00:00
Michael Telatynski 78b6b878bd Remove domexception polyfill, has been native in NodeJS since v17 (#4253)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-21 14:15:54 +00:00
Richard van der Hoff 4ccb72c0f2 Element-R: Fix resource leaks in verification logic (#4263)
* Move `RustVerificationRequest.onChange` out to a method

The only reason it was an inner function in the first place was to avoid
storing a reference in the class to `outgoingRequestProcessor`. That changed
with d1dec4cd08.

* Fix reference cycles in rust verification code
2024-06-21 12:55:43 +00:00
Richard van der Hoff 9f1aebbdcb Bump ES target version to ES2022 (#4264)
* Bump ES target version to ES2022

I want to be able to use `WeakRef`, and per
https://github.com/element-hq/element-web/issues/24913#issuecomment-2182448007,
I believe this should be safe.

* room.ts: Fix initialisation order

It seems that ES2022 causes typescript to change the initialization order of
regular properties vs parameter properties
(https://github.com/microsoft/TypeScript/issues/45995), so we need to rearrange
the initializations to avoid an error.

In practice, it might be fine because we have enabled
`babel-plugin-transform-class-properties`, which moves the initialization back
after the parameter property, but we shoudn't rely on that, and anyway it
upsets the linter.
2024-06-21 11:50:28 +00:00
Andrew Ferrazzutti 6a15e8f1a0 Use legacy call membership if anyone else is (#4260)
* Use legacy call membership if anyone else is

* Convert nullish to boolean

* Update tests

* Lint

* Use computed decision to use legacy events or not

* Check if discovered legacy sessions are ongoing

* Lint

* Lint again

* Increase test coverage
2024-06-21 11:40:27 +00:00
Richard van der Hoff 238eea0ef5 Upgrade Rust Crypto SDK to 6.1.0 (#4261)
Fixes https://github.com/element-hq/element-web/issues/27590
2024-06-20 08:28:17 +00:00
Michael Telatynski ab6f86536f Replace deprecated babel proposal plugins (#4254)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-19 15:11:38 +00:00
David Baker 819fc75202 Fetch capabilities in the background (#4246)
* Fetch capabilities in the background

& keep them up to date

* Add missed await

* Replace some more runAllTimers

and round down the wait time for sanity

* Remove double comment

* Typo

* Add a method back that will fetch capabilities if they're not already there

* Add tests

* Catch exception here too

* Add test for room version code
2024-06-19 10:24:56 +00:00
renovate[bot] c70aa33367 Update typescript-eslint monorepo to v7.13.1 (#4257)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-19 09:50:23 +00:00
renovate[bot] 240b43b652 Update typedoc (#4258)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-19 08:57:01 +00:00
renovate[bot] 697d5d31d1 Update all non-major dependencies (#4256)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-19 08:54:29 +00:00
Robin b1701ff571 Correctly transform base64 with multiple instances of + or / (#4252)
String.replace only replaces a single instance of the search pattern by default; we need a regex in g mode if we want to replace them all.
2024-06-18 14:58:16 +00:00
Michael Telatynski c55289ec65 Use server name instead of homeserver url to allow well-known lookups during QR OIDC reciprocation (#4233)
* Use server name instead of homeserver url to allow well-known lookups during QR OIDC reciprocation

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

* Iterate

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

* Iterate

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

* Iterate

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

* Iterate

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-18 13:03:14 +00:00
RiotRobot 987ec1e62f Resetting package fields for development 2024-06-18 11:55:23 +00:00
RiotRobot 76b240cf57 Merge branch 'master' into develop 2024-06-18 11:55:21 +00:00
RiotRobot a4c4e7e275 v33.1.0 2024-06-18 11:54:47 +00:00
Johannes Marbach 3f5a994a24 Add via parameter for MSC4156 (#4247)
* Add via parameter for MSC4156

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>

* Always include both parameters

* Fix tests

---------

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2024-06-18 08:14:48 +00:00
Timo d754392410 Make the js-sdk compatible with MSC preferred foci and active focus. (#4195)
* Refactor to preferred and active foci.

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

* make the sdk compatible with MSC4143 but still be backwards compatible

* comment fixes

* also fallback to legacy if the current member event is legacy

* use XOR types

* use EitherAnd

* make livekit Foucs types simpler

* review

* fix tests

* test work

* more review + more tests

* remove unnecassary await that is in conflict with the comment

* make joinRoomSession sync

* Update src/matrixrtc/MatrixRTCSession.ts

Co-authored-by: Andrew Ferrazzutti <af_0_af@hotmail.com>

* review

* fix

* test

* review

* review

* comment clarification

* typo

---------

Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Andrew Ferrazzutti <af_0_af@hotmail.com>
2024-06-17 13:02:29 +00:00
Michael Telatynski 7ecaa53e34 Work around spec bug for m.room.avatar state event content type (#4245)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-17 09:30:13 +00:00
RiotRobot 222e95d33f v33.1.0-rc.1 2024-06-14 12:18:37 +00:00
ElementRobot 2ee43cade7 [Backport staging] Fix screen sharing in recent Chrome (#4243)
Co-authored-by: David Baker <dbkr@users.noreply.github.com>
2024-06-13 20:54:53 +01:00
David Baker 9218f6380c Fix screen sharing in recent Chrome (#4241)
* Fix screen sharing in recent Chrome

Dreadful hack to work around a bug in recent chrome/electron's
WebRTC, as explained.

I'm not sure which is the least hideous out of this (ie. repeatedly
calling setCodecPreferences and seeing if it crashes each time) or
hardcoding the bad codec and skipping it. Opinions welcome.

* Unused import

* Remove commented line
2024-06-13 18:44:30 +00:00
Travis Ralston 661ba76763 Use stable endpoints for MSC3916 (#4239)
* Use stable endpoints for MSC3916

* appease the linter
2024-06-13 17:03:25 +00:00
Michael Telatynski 4cb851c51a Replace usages of setImmediate with setTimeout for wider compatibility (#4240)
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-06-13 16:01:33 +01:00
renovate[bot] 5a3d24abc2 Update typescript-eslint monorepo to v7.12.0 (#4237)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-11 13:15:29 +00:00
renovate[bot] 3eed74f1a6 Update dependency uuid to v10 (#4238)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-11 12:26:43 +00:00
renovate[bot] 10e7a2d997 Update dependency typedoc-plugin-mdn-links to v3.1.28 (#4236)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-11 12:17:02 +00:00
renovate[bot] 969ecdb6fb Update dependency @types/node to v18.19.34 (#4235)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-11 12:16:52 +00:00
renovate[bot] e8b91f2729 Update babel monorepo to v7.24.7 (#4234)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-11 12:16:38 +00:00
renovate[bot] f80366ff30 Update all non-major dependencies (#4229)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-11 12:09:01 +00:00
RiotRobot 395c3cfcd6 v33.1.0-rc.0 2024-06-11 12:06:39 +00:00
Hubert Chathi f95954c233 Add support for stable name for MSC4115 (#4232)
* add support for stable name for MSC4115

* fix types issues

* prettier

* actually, it still returns `undefined`
2024-06-07 08:47:17 +00:00
Michael Telatynski fa5f2d389a Fix incorrect assumptions about required fields in /search response (#4228)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-06 21:01:16 +00:00
Michael Telatynski 9fc557fc6b Fix typo
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-06 12:11:16 +01:00
Michael Telatynski 6436fbb99f MSC4108 support OIDC QR code login (#4134)
Co-authored-by: Hugh Nimmo-Smith <hughns@users.noreply.github.com>
Co-authored-by: Hugh Nimmo-Smith <hughns@matrix.org>
2024-06-06 09:57:26 +01:00
Michael Telatynski 87c2ac3ffa Use LegacyRendezvousFailureReason over RendezvousFailureReason (#4231)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-05 15:56:37 +00:00
Richard van der Hoff 43022d5b2f RustCrypto: fix ordering of methods (#4230)
* RustCrypto: Move CryptoBackend impl to CryptoBackend impl section

Given there is a `CryptoBackend implementation` section, the methods
implementing CryptoBackend should be there.

* RustCrypto: Fix documentation on dehydration methods

* RustCrypto: reunite `resetKeyBackup` with its helper

A couple of new methods had snuck into the middle.
2024-06-05 12:02:45 +00:00
renovate[bot] a0fadeb4ec Update babel monorepo to v7.24.6 (#4221)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-05 10:14:04 +00:00
Michael Telatynski a3cea8ce7d Add crypto methods for export and import of secrets bundle (#4227)
* Add crypto methods for OIDC QR code login

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

* Improve test

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

* Revert test due to hang inside Rust.

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

* Iterate

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

* Update test name

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

* Update test name

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-06-05 09:27:20 +00:00
renovate[bot] c88487da07 Update all non-major dependencies (#4226)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-06-04 17:21:20 +00:00
RiotRobot 89875b8e31 Resetting package fields for development 2024-06-04 13:18:49 +00:00
RiotRobot 9c94393d76 Merge branch 'master' into develop 2024-06-04 13:18:48 +00:00
RiotRobot 7850294a4b v33.0.0 2024-06-04 13:18:11 +00:00
renovate[bot] 131e81401a Update typescript-eslint monorepo to v7.10.0 (#4223)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-30 16:21:12 +00:00
David Baker 5c27e30302 Fix the queueToDevice tests for the new fakeindexeddb (#4225)
https://github.com/dumbmatter/fakeIndexedDB/pull/93 causes a bunch
of tests to start failing because the fake timers need running in
order for fake indexeddb to work. It also seems to cause failures
to bleed between tests somehow if fake timers are enabled/disabled.
This keeps all the fake timer tests in one suite and all the others
in another, which appears to work.

This should allow https://github.com/matrix-org/matrix-js-sdk/pull/4224
to be merged.
2024-05-30 15:16:42 +00:00
renovate[bot] 8dfb6de3cc Update all non-major dependencies (#4220)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-30 14:10:12 +00:00
renovate[bot] 042610310f Update dependency typedoc-plugin-mdn-links to v3.1.27 (#4222)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-30 13:42:20 +00:00
renovate[bot] 8535604200 Update actions/checkout digest to a5ac7e5 (#4219)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-30 11:45:14 +00:00
Hugh Nimmo-Smith 3ee64722c5 Add note about MSC3886, MSC3903 and MSC3906 being closed (#4189)
* Add note about MSC3886, MSC3903 and MSC3906 being closed

* Move comments in to jsdoc

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-05-30 11:23:24 +00:00
RiotRobot 9d6210b3f9 v33.0.0-rc.0 2024-05-29 12:54:25 +00:00
Andy Balaam 909caab74e Don't run migration for Rust crypto if the legacy store is empty (#4218)
* Don't run migration for Rust crypto if the legacy store is empty

Fixes https://github.com/element-hq/element-web/issues/27447

* Add copyright for the TypeScript files in legacy DB dumps

* Provide a type for the accountPickle we check for before migration

* Remove redundant backup response

This is unused

* Simplify keys response

* Downgrade log message.

---------

Co-authored-by: Richard van der Hoff <richard@matrix.org>
2024-05-28 17:43:25 +00:00
Michael Telatynski 7c87625157 Remove more deprecated methods, fields, and exports (#4217) 2024-05-28 09:12:55 +01:00
Richard van der Hoff b19817bb73 Bump matrix-sdk-crypto-wasm to 5.0.0 (#4216)
Slightly more involved than normal because it requires us to pass a backup version into OlmMachine.importBackedUpRoomKeys.

On the other hand we can now re-enable the test that was disabled in #4214 due to matrix-org/matrix-rust-sdk#3447

Fixes: element-hq/element-web#27165
2024-05-24 12:10:52 +01:00
Richard van der Hoff 36196ea422 initRustCrypto: allow app to pass in the store key directly (#4210)
* `initRustCrypto`: allow app to pass in the store key directly

... instead of using the pickleKey. This allows us to avoid a slow PBKDF
operation.

* Fix link in doc-comment
2024-05-24 09:52:34 +00:00
renovate[bot] a81adf542e Update dependency @matrix-org/matrix-sdk-crypto-wasm to v4.10.0 (#4214)
* Update dependency @matrix-org/matrix-sdk-crypto-wasm to v4.10.0

* Disable affected test

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>
2024-05-23 11:19:41 +00:00
RiotRobot a49bc3ddf4 Merge branch 'master' into develop 2024-05-22 12:04:33 +00:00
RiotRobot a86d4ceb49 v32.4.0 2024-05-22 12:04:07 +00:00
R Midhun Suresh 8c3be2a56a Update organization (#4212) 2024-05-21 15:55:49 +00:00
RiotRobot 38898a60c7 v32.3.0 2024-05-21 12:24:52 +00:00
Bayyr Oorjak fd3a4d4403 Preserve ESM for async imports to work correctly (#4187)
* fix: fix lazy rust crypto import

* test: use "commonjs" for tests because of circular deps

* chore: revert commonjs for "module"

* refactor: remove unnecessary example

* refactor: add comments

Signed-off-by: Bayyr Oorjak <the.bayyr.oorjak@gmail.com>

* refactor: improve comment

Signed-off-by: Bayyr Oorjak <the.bayyr.oorjak@gmail.com>

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

* Update babel.config.js

---------

Signed-off-by: Bayyr Oorjak <the.bayyr.oorjak@gmail.com>
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-05-21 11:48:00 +00:00
RiotRobot 93d96281fd Resetting package fields for development 2024-05-21 12:25:26 +00:00
RiotRobot 944dc51c58 Merge branch 'master' into develop 2024-05-21 12:25:25 +00:00
renovate[bot] c6b43dd176 Update dependency eslint-plugin-unicorn to v53 (#4209)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 16:56:22 +00:00
Michael Telatynski f03dd7b7bc Remove deprecated methods and fields (#4201)
* Remove legacy `threepidCreds` field

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

* Remove deprecated shouldUpgradeToVersion

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

* Remove `added` legacy login request field

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

* Remove deprecated re-exports

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

* Remove `home_server` field

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

* Update imports in tests

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-05-15 15:23:04 +00:00
Michael Telatynski 51fa1866a9 Wire up verification cancel & mismatch for rust crypto (#4202)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-05-15 14:58:24 +00:00
renovate[bot] d76fb2baa0 Update all non-major dependencies (#4207)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 11:51:51 +00:00
renovate[bot] 3feafc9c17 Update dependency typedoc-plugin-mdn-links to v3.1.25 (#4206)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 11:28:29 +00:00
Michael Telatynski c9075b3dba Only pass id_server if we had one to begin with (#4200)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-05-15 10:59:42 +00:00
renovate[bot] 69c474dda7 Update dependency @types/node to v18.19.33 (#4205)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 10:54:21 +00:00
renovate[bot] 73ce51065f Update mheap/github-action-required-labels digest to 5847eef (#4204)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 10:26:32 +00:00
renovate[bot] 5d0407d0a6 Update actions/checkout digest to 0ad4b8f (#4203)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-15 10:23:58 +00:00
RiotRobot 3a4b02d8e6 v32.3.0-rc.0 2024-05-15 09:04:25 +00:00
Kegan Dougal d421e7f829 Run complement-crypto in CI (#4197)
* Maybe run complement-crypto

* Use existing checkout

* Test that things fail if crypto breaks

* Fix test; run only on merge queue

* Prettier

* Maybe get it working in a merge queue
2024-05-13 10:26:27 +00:00
Michael Telatynski 9fd051af33 Update downstream-end-to-end-tests.yml 2024-05-13 11:20:47 +01:00
Michael Telatynski b78a1ad889 Hotfix types export point
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-05-10 13:26:07 +01:00
Michael Telatynski a25cdcecaa Fix state_events.ts types (#4196)
* Fix state_events.ts types

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

* Iterate

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-05-10 10:55:44 +00:00
RiotRobot 2a716bd076 Resetting package fields for development 2024-05-07 12:16:24 +00:00
RiotRobot ef1db8d664 Merge branch 'master' into develop 2024-05-07 12:16:23 +00:00
RiotRobot 22865fd834 v32.2.0 2024-05-07 12:15:48 +00:00
Michael Telatynski c4fe564855 Simplify OIDC types & export decodeIdToken (#4193)
* Fix types

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

* Export `decodeIdToken`

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-05-07 10:21:57 +00:00
Michael Telatynski 9ecb1a0381 Fix sendEventHttpRequest for m.room.redaction events without redacts (#4192)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-05-07 08:50:37 +00:00
Travis Ralston ef9490c7b1 Add missing (and common-ish) HTTP method verbs to types (#4188) 2024-05-02 23:09:15 +00:00
Travis Ralston 402adfbe8a Add helpers for authenticated media, and associated documentation (#4185)
* Add helpers for authenticated media, and associated documentation

* Appease the linter
2024-05-02 21:11:09 +00:00
renovate[bot] 41e8c2af34 Update dependency typedoc-plugin-coverage to v3.1.1 (#4186)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-05-01 10:23:17 +00:00
renovate[bot] 4843b40296 Update dependency typedoc-plugin-mdn-links to v3.1.22 (#4182)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-30 13:18:45 +00:00
renovate[bot] bc2c870152 Update babel monorepo to v7.24.5 (#4181)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-30 13:17:37 +00:00
renovate[bot] 7c7b2817d3 Update all non-major dependencies (#4184)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-30 13:16:31 +00:00
renovate[bot] 9f78202ecd Update typescript-eslint monorepo to v7.7.1 (#4183)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-04-30 14:40:57 +01:00
RiotRobot abc9911e95 v32.2.0-rc.0 2024-04-30 12:02:20 +00:00
David Baker efdae0d66f Remove spammy RTCSession log line (#4180)
This can get quite spammy in rooms with legacy calls and isn't really
neccesary: remove it to cut down on the log spam.
2024-04-30 10:43:20 +00:00
David Baker 2bf554761c Add some comments to the release drafter workflows (#4140)
* Add some comments to the release drafter workflows

* Rename component workflow so they have different names

* Fix comment

---------

Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-04-30 09:38:07 +00:00
Michael Telatynski c2687643b5 Update downstream-end-to-end-tests.yml 2024-04-30 10:30:19 +01:00
Michael Telatynski a33758eda6 Update downstream-end-to-end-tests.yml 2024-04-30 10:28:44 +01:00
Michael Telatynski 8faed02cc5 Update sonarcloud.yml 2024-04-29 17:22:32 +01:00
Michael Telatynski 3ae0dab47a Update sonarcloud.yml 2024-04-29 16:59:55 +01:00
Michael Telatynski 95394e4cbe Update sonarcloud.yml 2024-04-29 16:52:54 +01:00
Michael Telatynski 8c9bbc01fc Update downstream-end-to-end-tests.yml 2024-04-29 16:20:24 +01:00
Michael Telatynski eb888791a3 Pass all args to Sonar via sonar-project.properties file (#4179)
* Pass all args to Sonar via sonar-project.properties file

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

* Update Sonarcloud action to v3.1

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

* Apply suggestions from code review

Co-authored-by: davidegirardi <16451191+davidegirardi@users.noreply.github.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: davidegirardi <16451191+davidegirardi@users.noreply.github.com>
2024-04-29 15:12:00 +00:00
Michael Telatynski 6c0b2f55e1 Delete .github/workflows/downstream-artifacts.yml 2024-04-29 10:53:12 +01:00
Michael Telatynski c9a5eaece3 Simplify Playwright CI (#4178) 2024-04-29 08:49:00 +01:00
Hubert Chathi 64505de36b Use a different error code for UTDs when user was not in the room (#4172)
* use a different error code for UTDs when user was not in the room

* if user is invited, treat it as unexpected UTD
2024-04-26 13:38:10 +00:00
Valere 65d858f9a3 Fix rust migration when ssss secret not encrypted (#4168) 2024-04-26 12:59:17 +00:00
RiotRobot 1da5e8f56a Resetting package fields for development 2024-04-23 12:34:26 +00:00
RiotRobot 5efd4c2915 Merge branch 'master' into develop 2024-04-23 12:34:25 +00:00
RiotRobot bc03950f8a v32.1.0 2024-04-23 12:33:56 +00:00
Travis Ralston c09da9a23f Modernize window.crypto access constants (#4169)
* Force service worker-safe crypto when operating under a service worker

* Fix tests/unsafe execution

* Further fix tests?

* Docs would probably be good

* Define a type guard function

https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards

* Use `@types` repo

* Maybe don't modify tsconfig, I guess

* Revert "Use `@types` repo"

This reverts commit db46bcf1db4b94fbc7e0c97a20d5d800fcb2768b.

* Use a different type for Window

* Simplify the crypto accessors
2024-04-22 19:44:01 +00:00
Andrew Ferrazzutti e874468ba3 Improve compliance with MSC3266 (#4155)
* Fix fields of MSC 3266 summary object

Also remove redundant room_type field which is inherited from elsewhere

* Export the MSC 3266 summary type

* Use proper endpoint for MSC 3266 summary lookup

Use the endpoint recommended by the MSC

* Rename newly-exported symbol to not start with I

* Use "export type"

* Lint

* Fix type of "encryption" field

* Add TSDoc documentation

* Add basic integration test for getRoomSummary

* Lint

* Use fallback endpoint for MSC3266

* Improve test coverage

* Lint

* Refactor async catch to satisfy linter

* Increase test coverage
2024-04-22 17:39:10 +00:00
Johannes Marbach 6fedda91f9 Use encoded URI components when storing sessions in memory crypto store (#4170)
* Use encoded URI components when storing sessions in memory crypto store

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>

* Add URI en-/decoding to missing methods

* Extract convenience functions

---------

Signed-off-by: Johannes Marbach <n0-0ne+github@mailbox.org>
2024-04-22 08:12:54 +00:00
Valere d22a39f5d7 Element R: fix isCrossSigningReady not checking identity trust (#4156)
* Fix inconsistency between rust and legacy

* Add tests

* Review: better comment

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

* review: Better doc

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

* Simplify test data and some comments

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-04-17 13:36:52 +00:00
Timo 4fc6ba884e add comment to make clear that RoomStateEvent.Events does not update related objects in the js-sdk (#4152)
Signed-off-by: Timo K <toger5@hotmail.de>
2024-04-17 10:28:40 +00:00
Richard van der Hoff c30e498013 Crypto: use a new error code for UTDs from device-relative historical events (#4139)
* Add `PerSessionKeyBackupDownloader.isKeyBackupDownloadConfigured()`

* Add new `RustBackupManager.getServerBackupInfo`

... and a convenience method in PerSessionKeyBackupDownloader to access it.

* Crypto.spec: move `useRealTimers` to global `afterEach`

... so that we don't need to remember to do it everywhere.

* Use fake timers for UTD error code tests

This doesn't have any effect on the tests, but *does* stop jest from hanging
when you run the tests in in-band mode. It shouldn't *really* be needed, but
using fake timers gives more reproducible tests, and I don't have the
time/patience to debug why it is needed.

* Use new error codes for UTDs from historical events
2024-04-17 10:26:41 +00:00
renovate[bot] 8240bf0ae7 Update shogo82148/actions-upload-release-asset digest to 8f032ef (#4157)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-16 15:59:04 +00:00
renovate[bot] 2321c44687 Update typedoc (#4162)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-16 15:22:17 +00:00
renovate[bot] 0137e9d5a8 Update dependency eslint-plugin-unicorn to v52 (#4166)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-16 14:29:48 +00:00
renovate[bot] 28bbc51752 Update dependency @types/node to v18.19.31 (#4160)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-16 14:06:49 +00:00
renovate[bot] 0db3ac9b43 Update dependency eslint-plugin-jest to v28 (#4165)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-16 13:56:50 +00:00
renovate[bot] 53039b78ee Update all non-major dependencies (#4158)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-16 13:25:06 +00:00
renovate[bot] 2a06d19431 Update babel monorepo to v7.24.4 (#4159)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-16 13:24:46 +00:00
renovate[bot] a747eef04c Update dependency typescript to v5.4.5 (#4161)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-16 13:24:27 +00:00
renovate[bot] 583823c2ef Update dependency knip to v5 (#4167)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-16 13:21:14 +00:00
renovate[bot] 26d13c15c3 Update typescript-eslint monorepo to v7.6.0 (#4163)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-16 13:20:45 +00:00
RiotRobot c850ca3179 v32.1.0-rc.0 2024-04-16 12:16:13 +00:00
Valere 8438533532 Validate backup private key before migrating it (#4114)
* Migrate own identity trust to rust crypto

* Fix gendoc not happy if msk of IDownloadKeyResult has a signature

* add missing mock

* code review

* Code review

* Review gh suggestion

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

* Review gh suggestion

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

* Review gh suggestion

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

* Review gh suggestion

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

* review move function down in file

* Review gh suggestion

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

* Review gh suggestion

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

* Review: Cleaning tests, renaming

* Review: better comment

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

* Comment paragraphs

* retry until initial  key query is successfull

* Validate backup private key before migrating it

* post merge fix

* Fix test, missing mock

* Use crypto wasm instead of lib olm to check backup key

* typo

* code review

* quick lint

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-04-15 07:17:14 +00:00
David Baker 475f82c5ce Update git-get-release action (#4148)
which appears to be breaking renovate somehow, and could probably use
and update anyway.
2024-04-11 09:36:07 +00:00
Hubert Chathi 936e7c3072 Add support for device dehydration v2 (Element R) (#4062)
* initial implementation of device dehydration

* add dehydrated flag for devices

* add missing dehydration.ts file, add test, add function to schedule dehydration

* add more dehydration utility functions

* stop scheduled dehydration when crypto stops

* bump matrix-crypto-sdk-wasm version, and fix tests

* adding dehydratedDevices member to mock OlmDevice isn't necessary any more

* fix yarn lock file

* more tests

* fix test

* more tests

* fix typo

* fix logic for checking if dehydration supported

* make changes from review

* add missing file

* move setup into another function

* apply changes from review

* implement simpler API

* fix type and move the code to the right spot

* apply suggestions from review

* make sure that cross-signing and secret storage are set up
2024-04-11 04:01:47 +00:00
RiotRobot 82ed7bd86a Resetting package fields for development 2024-04-09 10:07:09 +00:00
RiotRobot cb67eae858 Merge branch 'master' into develop 2024-04-09 10:07:07 +00:00
RiotRobot e4937e6222 v32.0.0 2024-04-09 10:06:41 +00:00
Michael Telatynski 5cdd524da7 OIDC improvements in prep of OIDC-QR reciprocation (#4149)
* Add `device_authorization_endpoint` field to OIDC issuer well-known metadata

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

* Allow `validateIdToken` to skip handling nonce when none is present

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

* Tweak registerOidcClient to check OIDC grant_types_supported before registration

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-04-08 14:07:00 +00:00
Michael Telatynski 0ff0093380 Add knip unused code & dependency analyser (#4013) 2024-04-08 11:04:40 +01:00
Valere b352405c89 ElementR| Retry query backup until it works during migration to avoid spurious correption error popup (#4113)
* retry query backup until it works during migration

* Add log line when fails to get backup during migration
2024-04-08 07:11:06 +00:00
renovate[bot] 0d73d0c6c7 Update typescript-eslint monorepo to v7.4.0 (#4146)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-03 09:49:35 +00:00
renovate[bot] d2f76d4956 Update dependency typescript to v5.4.3 (#4145)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-03 09:23:09 +00:00
renovate[bot] c680dd7eb2 Update dependency @types/node to v18.19.28 (#4144)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-03 08:37:32 +00:00
renovate[bot] e24bb0f50c Update babel monorepo to v7.24.3 (#4143)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-03 08:36:51 +00:00
renovate[bot] 1ed3b13f0d Update all non-major dependencies (#4142)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-02 17:58:13 +00:00
renovate[bot] 4f628bf64c Update mheap/github-action-required-labels digest to 132879b (#4141)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-04-02 17:08:08 +00:00
RiotRobot 7d5c003716 v32.0.0-rc.0 2024-04-02 16:15:04 +00:00
Richard van der Hoff dbab185f9d Refactoring and simplification in decryption error handling (#4138)
* Clean up decryption failure integ tests

* Fix the names
* Stop waiting as soon as the event is decrypted, even if code is wrong (so
  tests fail rather than time out if the code is wrong)

* Bump timeouts on some tests

These tend to fail due to slow init of wasm artifacts

* Factor out `onDecryptionKeyMissingError` call

* Factor out `onMegolmDecryptionError`
2024-04-02 13:39:49 +00:00
Richard van der Hoff cfcd191cbf Update matrix-rust-sdk-crypto-wasm to 4.9.0 (#4137) 2024-04-02 13:09:59 +00:00
RiotRobot 514633c5fa Merge branch 'master' into develop 2024-03-28 16:45:10 +00:00
RiotRobot 5bffb7df4f v31.6.1 2024-03-28 16:44:30 +00:00
David Baker 9e1897dcd0 Merge pull request #4136 from matrix-org/backport-4135-to-staging
Fix merging of default push rules (backport)
2024-03-28 16:35:36 +00:00
David Baker 5f3ddc37a1 Merge pull request #4135 from matrix-org/t3chguy/fix/27173
Fix merging of default push rules

(cherry picked from commit 78a225795b)
2024-03-28 16:28:33 +00:00
David Baker 78a225795b Merge pull request #4135 from matrix-org/t3chguy/fix/27173
Fix merging of default push rules
2024-03-28 16:23:58 +00:00
Michael Telatynski 467b49a0dc Add test
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-28 15:52:12 +00:00
Michael Telatynski 06e083874a Iterate
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-28 14:59:52 +00:00
Michael Telatynski 0f25429849 Iterate
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-28 13:41:31 +00:00
Michael Telatynski 32ddf2813d Iterate
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-28 12:55:44 +00:00
Michael Telatynski 1ed082f3d4 Fix merging of default push rules
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-28 11:58:52 +00:00
RiotRobot 706002cdcb Resetting package fields for development 2024-03-26 16:26:09 +00:00
RiotRobot 731de1108c Merge branch 'master' into develop 2024-03-26 16:26:07 +00:00
RiotRobot 2da6c0c605 v31.6.0 2024-03-26 16:25:15 +00:00
Richard van der Hoff 9f1d0c3896 Add new decryptExistingEvent test helper (#4133)
* grammar fix

* IEncryptionResult -> EncryptionResult

These are the same thing; the former is the old name.

* Support setting event IDs

* Helper for decrypting existing decryption failures
2024-03-25 14:10:58 +00:00
Gabri 0b290fffa1 Improve types for IPowerLevelsContent and hasSufficientPowerLevelFor (#4128)
Signed-off-by: Gabriele Messina <56839513+galash13@users.noreply.github.com>
2024-03-25 13:58:38 +00:00
Michael Telatynski 97844f0e47 Improve types for sendEvent (#4108) 2024-03-25 12:48:49 +00:00
Michael Telatynski 85a55c79cd Remove various deprecated methods & re-exports (#4125) 2024-03-25 12:21:11 +00:00
Johannes Marbach 63d4195453 Use RoomEvent.MyMembership in auto-join example (#4130)
This seems easier / more efficient than listening to all membership events and then filtering by user ID.
2024-03-25 09:10:42 +00:00
Richard van der Hoff d5a35f8a99 Add new enum for verification methods. (#4129)
* Define constants for the verification methods.

* Remove some confusing references to the *old* `VerificationMethod`
2024-03-22 17:17:31 +00:00
Richard van der Hoff d1259b241c Clean up code for handling decryption failures (#4126)
Various improvements, including:

* Defining an enum for decryption failure reasons
* Exposing the reason code as a property on Event
2024-03-22 17:15:27 +00:00
David Langley a573727662 Remove the logic that throws when the lazy loading options has changed. (#4124)
* remove InvalidStoreState and the logic that checks for the change in the lazyLoading client option

* lint
2024-03-22 16:36:23 +00:00
Richard van der Hoff dce8acbf17 Add some test utils in a new entrypoint (#4127)
* Clean up README a little

This just removes some of the most egregious lies and outdated stuff. There's a
*lot* more that can be done here.

* Add some test utils in a new entrypoint

* Fix comment

* Update src/testing.ts
2024-03-22 14:10:55 +00:00
David Baker 4ba1341f8f Fix highlights from threads disappearing on new messages (#4106)
* Fix highlights from threads disappearing on new messages

This changes interface of Room, so this is a BREAKING CHANGE.

Correctly mirrors the logic we use for room notifications for thread
notifications, ie. set only the total notifications count from the
server if it's zero.

I'm not delighted with this since it ends up with function on room
whose contract is to do something frankly, deeply weird and
unintuitive. However, this is the hack we use for room notifications
and it, empirically, works well enough. To do better, we'd need much
more complex logic to overlay notification counts for decrypted messages.

Fixes https://github.com/element-hq/element-web/issues/25523

* Add tests for the special notification behaviour in syncing

* Correctly copy the room logic for reseting notifications

We were always ignoring the highlight count, even for encrypted rooms,
which was broken because we don't do the local calculation for unencrypted
rooms.
2024-03-21 16:29:00 +00:00
David Baker e517d009bf Extend logic for local notification processing to threads (#4111)
* Move code for processing our own receipts to Room

This is some code to process our own receipts and recalculate our
notification counts.

There was no reason for this to be in client. Room is still rather
large, but at least it makes somewhat more sense there.

Moving as a refactor before I start work on it.

* Add test for the client-side e2e notifications code

* Extend logic for local notification processing to threads

There's collection of logic for for processing receipts and recomputing
notifications for encrypted rooms, but we didn't do the same for threads.
As a reasult, when I tried pulling some of the logic over in
https://github.com/matrix-org/matrix-js-sdk/pull/4106
clearing notifications on threads just broke.

This extends the logic of reprocessing local notifications when a receipt
arrives to threads.

Based on https://github.com/matrix-org/matrix-js-sdk/pull/4109

* simplify object literal

* Add tests & null guard

* Remove unused imports

* Add another skipped test

* Unused import

* enable tests

* Fix thread support nightmare

* Try this way

* Unused import

* Comment the bear trap

* expand comment
2024-03-21 12:22:19 +00:00
Ajay Bura dc2d03dea5 fix public rooms post request search params and body (#4110) 2024-03-21 10:29:51 +00:00
David Baker d5bb9e7600 Move code for processing our own receipts to Room (#4109)
* Move code for processing our own receipts to Room

This is some code to process our own receipts and recalculate our
notification counts.

There was no reason for this to be in client. Room is still rather
large, but at least it makes somewhat more sense there.

Moving as a refactor before I start work on it.

* Add test for the client-side e2e notifications code

* simplify object literal
2024-03-20 15:20:47 +00:00
Michael Telatynski d908036f50 Improve types for sendStateEvent (#4105) 2024-03-20 14:27:27 +00:00
David Baker afc3c6213b Fix bugs with the first reply to a thread (#4104)
* WIP fix for bugs first-thread-reply bugs

* Add re-emitter before we start adding events, as per comment

* Add test for notification bug

* Test for the bug that caused the dot to be the wrong colour

* Add comment

* elaborate

* Fix outdated comment

* Also fix this comment

* Fix another comment

* Fix typo

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

* Clarify comment

* More comment

* so much comment

also reformat (the bit that's actually added is s/it/this.addEvents/)

* The comments

* Maybe make comment clearer.

* Add comment about potential race

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-03-20 11:14:25 +00:00
Michael Telatynski 7884c22e41 Fix permissions for deploying docs to github pages (#4122)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-19 17:57:33 +00:00
renovate[bot] 887d8a7663 Update dependency typescript to v5.4.2 (#4123)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 17:25:31 +00:00
renovate[bot] 2c68ee2254 Update babel monorepo to v7.24.1 (#4119)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 16:33:19 +00:00
renovate[bot] d445823d0b Update typescript-eslint monorepo to v7.2.0 (#4121)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 16:25:50 +00:00
renovate[bot] abe4630687 Update typedoc (#4118)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 16:25:07 +00:00
renovate[bot] 8664b66238 Update dependency @matrix-org/matrix-sdk-crypto-wasm to v4.7.0 (#4120)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 16:24:49 +00:00
renovate[bot] 596826ab4d Update all non-major dependencies (#4116)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 16:22:03 +00:00
renovate[bot] c8ec5421c7 Update dependency @types/node to v18.19.24 (#4117)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-19 16:21:55 +00:00
RiotRobot b8078f9916 v31.6.0-rc.0 2024-03-19 15:05:53 +00:00
Andy Balaam 92342c07ed Introduce Membership TS type (take 2) (#4107)
* Introduce Membership TS type

* Adapt the Membership TS type to be an enum

* Add docstrings for KnownMembership and Membership

* Move Membership types into a separate file, exported from types.ts

---------

Co-authored-by: Stanislav Demydiuk <s.demydiuk@gmail.com>
2024-03-18 12:47:23 +00:00
Valere 3e989006aa Migrate own identity local trust to rust crypto (#4090)
* Migrate own identity trust to rust crypto

* Fix gendoc not happy if msk of IDownloadKeyResult has a signature

* add missing mock

* code review

* Code review

* Review gh suggestion

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

* Review gh suggestion

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

* Review gh suggestion

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

* Review gh suggestion

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

* review move function down in file

* Review gh suggestion

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

* Review gh suggestion

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

* Review: Cleaning tests, renaming

* Review: better comment

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

* Comment paragraphs

* retry until initial  key query is successfull

* review quick nits

* missing mock in test

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-03-18 08:57:53 +00:00
Kim Brose 8e0ef5ff2c fix automatic DM avatar with functional members (#4017)
* fix automatic DM avatar with functional members

* update comments

* lint

* add tests for functional members

* keep functional members out of the public API

- remove public API for functional members, reverting most of 0ce2d82, f9b41f6, e65fb24
- remove tests for functional members public API c114bf5
- add shared functional members getter for both room name and avatar fallback generation

* filter functional members from more candidates

- remove from hero(es)
- remove from previous members

* add tests for fallback avatars with functional members

* Add docstring for getFunctionalMembers

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

* inline getInvitedAndJoinedFunctionalMemberCount

* update comments for getAvatarFallbackMember

* use correct list of heroes in getAvatarFallbackMember

* remove redundant type annotation

* optimize performance of invitedAndJoinedFunctionalMemberCount

* calculate nonFunctionalMemberCount in one step

instead of iterating redundantly

* clean up functional member tests with review feedback

* lint

* Update src/models/room.ts

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

* apply feedback about comments

* non-functional per review, lint

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-03-13 17:01:11 +00:00
Michael Telatynski 78d05942a3 Merge remote-tracking branch 'origin/develop' into develop 2024-03-12 18:53:54 +00:00
Michael Telatynski c22a6858c8 Temporarily disable broken step in the release process
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-12 18:53:44 +00:00
RiotRobot 461aeae281 Resetting package fields for development 2024-03-12 18:34:34 +00:00
RiotRobot 0511e313d3 Merge branch 'master' into develop 2024-03-12 18:34:33 +00:00
RiotRobot da3d5c4a43 v31.5.0 2024-03-12 18:33:38 +00:00
renovate[bot] 4c26b55c9a Update dependency typedoc to v0.25.11 (#4102)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-12 13:38:32 +00:00
Michael Telatynski 3711ad7e61 Export types describing all specced media event formats (#4092)
* Export types describing all specced media event formats

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

* Iterate PR

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

* Move types to a dedicated export

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

* Iterate

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

* Add readme entry

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-08 21:07:26 +00:00
Michael Telatynski 3031152444 Add .m.rule.is_room_mention push rule to DEFAULT_OVERRIDE_RULES (#4100)
* Add intentional mentions push rules to DEFAULT_OVERRIDE_RULES

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

* Iterate

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

* Iterate

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

* Iterate

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

* Iterate

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-08 20:21:12 +00:00
Daniel Salinas 51ebd2fcde Fix race condition with sliding sync extensions (#4089)
* Fix race condition with sliding sync extensions

* Fix types on sliding-sync spec test

* Prettier fixes
2024-03-07 23:56:36 +00:00
David Baker 27dd856778 Don't re-fetch thread root if we already have it (#4088)
The root event of a thread used to arrive with the pagination request, but this was unspecced and so got changed to simply fetch the root event. In many (almost all) cases this shouldn't be necessary because the thread should already have its root event: re-use it if it's already there. This is only in pagination, so there's no reason to believe that the root event would have changed and needs to be re-fetched.

This removes a number of duplicate calls to the /event/ endpoint from the tests.
2024-03-06 14:10:35 +00:00
renovate[bot] 7fee37680f Update typedoc (#4098)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-06 08:49:16 +00:00
renovate[bot] 2541ca04c2 Update all non-major dependencies (#4096)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-05 17:54:30 +00:00
Richard van der Hoff d55c6a36df PR template: reminder to document your stuff (#4081)
* PR template: reminder to document your stuff

* link to tsdoc, not typedoc

* add full stops
2024-03-05 17:10:33 +00:00
Timo 8c0736a719 Make sending ContentLoaded optional for a widgetClient (#4086)
* add sendContentLoaded option to widgetClient

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

* review

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

* add tests

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

* another try to get the coverage up

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

* self review

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

---------

Signed-off-by: Timo K <toger5@hotmail.de>
2024-03-05 16:59:07 +00:00
renovate[bot] 50b042d1ff Update tspascoal/get-user-teams-membership digest to 57e9f42 (#4094)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 16:14:15 +00:00
renovate[bot] a818dc1e9d Update shogo82148/actions-upload-release-asset digest to 5bd52f0 (#4093)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 15:56:46 +00:00
renovate[bot] d8dae65a4d Update typescript-eslint monorepo to v7.1.0 (#4099)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 15:43:37 +00:00
renovate[bot] 8be286308c Update dependency @types/node to v18.19.21 (#4095)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 15:16:30 +00:00
renovate[bot] 84498bf77d Update babel monorepo to v7.24.0 (#4097)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-03-05 14:50:28 +00:00
Michael Telatynski a1f4b07b7d Fix bad string split destructuring
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-05 14:31:57 +00:00
RiotRobot ee8413beff v31.5.0-rc.0 2024-03-05 14:03:49 +00:00
Michael Telatynski e4d4628cc8 When merging release notes, allow considering later versions in the same release cycle (#4085)
* When merging release notes, allow considering later versions in the same major.minor.patch set

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

* Tweak comments

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-03-05 09:34:09 +00:00
David Langley b2e09250d9 Add job to automate adding new issues to the new project (#4087)
* add job to automate adding new issues to the new project

* missing jobs:
2024-02-29 12:20:53 +00:00
RiotRobot 6176faef48 Resetting package fields for development 2024-02-27 12:51:20 +00:00
RiotRobot 453cdd9eda Merge branch 'master' into develop 2024-02-27 12:51:18 +00:00
RiotRobot 6529f02c28 v31.4.0 2024-02-27 12:50:27 +00:00
Valere d3dfcd9242 Add basic retry for rust crypto outgoing requests (#4061)
* Add basic retry for outgoing requests

* Update doc

* Remove 504 from retryable

* Retry all 5xx and clarify client timeouts

* code review cleaning

* do not retry rust request if M_TOO_LARGE

* refactor use common retry alg between scheduler and rust requests

* Code review, cleaning and doc
2024-02-26 14:07:28 +00:00
Michael Telatynski a26fc46ed4 Update MSC2965 OIDC Discovery implementation (#4064) 2024-02-23 16:43:11 +00:00
renovate[bot] be3913e8a5 Update typedoc (#3958)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-22 17:30:14 +00:00
renovate[bot] c1e0192baf Update dependency eslint-plugin-unicorn to v51 (#4083)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-22 17:06:12 +00:00
Andy Balaam 8123e9a3f1 Bump matrix-react-sdk-crypto-wasm to v4.6.0 (#4082)
To reduce memory usage during export - see https://github.com/matrix-org/matrix-rust-sdk-crypto-wasm/pull/105
2024-02-22 11:55:27 +00:00
Michael Telatynski 0425f4e5c8 Merge remote-tracking branch 'origin/develop' into develop 2024-02-22 10:49:07 +00:00
Michael Telatynski 5b74b446d4 Prune broken docs symlinks
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-22 10:48:50 +00:00
renovate[bot] 624914a565 Update dependency husky to v9 (#4051)
* Update dependency husky to v9

* Iterate

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>
2024-02-22 09:46:30 +00:00
renovate[bot] 4da9627727 Update all non-major dependencies (#4076)
* Update all non-major dependencies

* Prettier

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>
2024-02-22 09:35:20 +00:00
renovate[bot] 1cb30bfe9b Update typescript-eslint monorepo to v7 (#4078)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-22 09:04:17 +00:00
renovate[bot] 12308b4c07 Update dependency @types/node to v18.19.17 (#4075)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-22 09:02:45 +00:00
Michael Telatynski 7f25162725 Update pull_request.yaml 2024-02-21 21:31:43 +00:00
David Baker 4826868a8f Update stale comment (#4080)
And remove line that set it for it to just get overwritten
2024-02-21 19:01:16 +00:00
renovate[bot] 91bde6afa1 Update dependency typedoc-plugin-coverage to v3 (#4077)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-21 18:45:39 +00:00
RiotRobot 95842c2b91 v31.4.0-rc.0 2024-02-21 17:56:16 +00:00
Michael Telatynski c27c357688 Validate account_management_uri and account_management_actions_supported from OIDC Issuer well-known (#4074)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-21 14:56:11 +00:00
renovate[bot] b474439256 Update dependency oidc-client-ts to v3 (#4052)
* Update dependency oidc-client-ts to v3

* Update jwt-decode so that oidc-client-ts doesn't run its own and thus we can mock

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

* Merge

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

* delint

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

* Sort package.json

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

* Ensure oidc-client-ts 3.0.1 to drop crypto-js

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>
2024-02-19 17:20:56 +00:00
Michael Telatynski 42dc498359 Update pull_request.yaml 2024-02-19 13:49:48 +00:00
Michael Telatynski ca914c97e0 Allow specifying OIDC url state parameter for passing data to callback (#4068)
* Allow specifying more OIDC client metadata for dynamic registration

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

* Allow specifying url_state for dynamic oidc client registration

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

* Export NonEmptyArray type

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

* Allow specifying more OIDC client metadata for dynamic registration

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

* Export NonEmptyArray type

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

* Fix test

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-19 13:03:53 +00:00
Michael Telatynski f96dac1e5b Saner releases clean up (#4072)
* Remove allchange dependency

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

* Remove stale release scripts

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

* Update pull request template to remove allchange behaviours

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

* Update label check automation

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

* mheap

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

* Re-add node-fetch which was previously transitive via allchange

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

* Use node-fetch@^2

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-19 12:32:26 +00:00
Michael Telatynski 7e0d92cbe0 Add getAuthIssuer method for MSC2965 (#4071)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-19 12:25:24 +00:00
Michael Telatynski fe46fec161 Allow specifying more OIDC client metadata for dynamic registration (#4070) 2024-02-16 14:43:52 +00:00
David Baker 2cf7d819d9 Add unread marker event type (#4069)
* Add unread marker event type

To support setting the 'marked unread' flag

* Await encrypted messages (#4063)

* await encrypted messages
+ fix comments

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

* fix Tests

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

* fix test

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

* make sonar happy

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

---------

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

* Ignore memberships of users that are not in the call (#4065)

* ignore memberships of users that are not in the call

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

* recompute memberships on room member change.

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

* fix Tests and add test for left member

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

* fix event type

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

* fix import desaster

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

* fix mocks

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

---------

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

---------

Signed-off-by: Timo K <toger5@hotmail.de>
Co-authored-by: Timo <16718859+toger5@users.noreply.github.com>
2024-02-16 10:34:15 +00:00
Timo 74c109adac Ignore memberships of users that are not in the call (#4065)
* ignore memberships of users that are not in the call

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

* recompute memberships on room member change.

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

* fix Tests and add test for left member

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

* fix event type

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

* fix import desaster

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

* fix mocks

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

---------

Signed-off-by: Timo K <toger5@hotmail.de>
2024-02-14 13:04:40 +00:00
Timo 5d7218476a Await encrypted messages (#4063)
* await encrypted messages
+ fix comments

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

* fix Tests

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

* fix test

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

* make sonar happy

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

---------

Signed-off-by: Timo K <toger5@hotmail.de>
2024-02-14 11:25:43 +00:00
RiotRobot d03db17405 Resetting package fields for development 2024-02-13 14:56:34 +00:00
RiotRobot 7520340c46 Merge branch 'master' into develop 2024-02-13 14:56:33 +00:00
RiotRobot b63845a413 v31.3.0 2024-02-13 14:55:35 +00:00
Andy Balaam 1b7695cdca Add AsJson forms of the key import/export methods (#4057) 2024-02-08 13:25:22 +00:00
Valere f4a796ca2f ElementR | Ensure own user and device trust are updated after migration before giving back control to the app. (#4059)
* Ensure own trust after olm migration

* Check legacy store contains data
2024-02-07 16:28:17 +00:00
Andy Balaam 58a5d09aed Bump matrix-sdk-crypto-wasm to 4.5.0 (#4060)
Fixes https://github.com/element-hq/element-web/issues/26948
2024-02-07 15:11:04 +00:00
RiotRobot bc620796c3 v31.3.0-rc.4 2024-02-06 15:36:22 +00:00
David Baker b1cfed1b21 Merge pull request #4056 from matrix-org/backport-4055-to-staging
[Backport staging] Add utility to check for non migrated legacy db
2024-02-06 14:09:14 +00:00
Valere c700d8daa2 Add utility to check for non migrated legacy db (#4055)
* Add utility to check for non migrated legacy db

* code review changes

* add unit tests for existsAndIsNotMigrated

* ensure indexeddb is clean for each state

(cherry picked from commit f94dbdec0f)
2024-02-06 13:18:48 +00:00
Valere f94dbdec0f Add utility to check for non migrated legacy db (#4055)
* Add utility to check for non migrated legacy db

* code review changes

* add unit tests for existsAndIsNotMigrated

* ensure indexeddb is clean for each state
2024-02-05 14:59:02 +00:00
renovate[bot] 173d9c331a Update dependency @types/jest to v29.5.12 (#4049)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-02 17:39:51 +00:00
renovate[bot] 04ebcf7be7 Update peter-evans/repository-dispatch action to v3 (#4053)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-02 17:10:27 +00:00
renovate[bot] 5e185ae1e7 Update typescript-eslint monorepo to v6.20.0 (#4050)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-02 17:08:12 +00:00
renovate[bot] 322cc6da10 Update babel monorepo to v7.23.9 (#4047)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-02 16:56:15 +00:00
renovate[bot] 014e674a4e Update definitelyTyped (#4048)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-02 16:55:59 +00:00
renovate[bot] 87acd9dd88 Update all non-major dependencies (#4046)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-02-02 16:55:36 +00:00
Michael Telatynski bbccb98c06 Fix tag_name
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-02 16:26:40 +00:00
Michael Telatynski ca835a7cf7 Work around github actions id clash issue on release
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-02 16:22:15 +00:00
Michael Telatynski b8fb10a1d1 Fix merge-release-notes.js
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-02 16:09:44 +00:00
Michael Telatynski 5e9d2e064e Debug logging
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-02 16:07:20 +00:00
Michael Telatynski d2753a9aea Debug logging
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-02 16:03:52 +00:00
Michael Telatynski c6eda55110 Fix badly typed output
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-02 15:58:48 +00:00
Michael Telatynski 7ce243110f github-script is broken =(
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-02 15:55:14 +00:00
Michael Telatynski 20d26db37d Roll back to github-script v6 due to bugs
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-02 15:48:58 +00:00
Michael Telatynski a2a25e71ac Revert "Use ELEMENT_BOT_TOKEN for release-drafter-workflow.yml"
This reverts commit 1e7bc2f31c.
2024-02-02 15:44:43 +00:00
Michael Telatynski 1e7bc2f31c Use ELEMENT_BOT_TOKEN for release-drafter-workflow.yml
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-02 15:41:16 +00:00
Michael Telatynski eec5040bd0 Update release-drafter-workflow.yml 2024-02-02 15:36:57 +00:00
Michael Telatynski 24174c9233 Update release-drafter-workflow.yml 2024-02-02 15:33:38 +00:00
Michael Telatynski 8a2cd3f43c Update release-drafter-workflow.yml 2024-02-02 15:31:36 +00:00
Michael Telatynski eebf40590f Update release-drafter-workflow.yml 2024-02-02 15:21:54 +00:00
Michael Telatynski f5e0b3007b Update release-drafter-workflow.yml 2024-02-02 15:18:37 +00:00
RiotRobot 0d5b6138ae v31.3.0-rc.3 2024-02-02 15:00:42 +00:00
Michael Telatynski 45b02fed5a Update release-npm.yml 2024-02-02 14:59:30 +00:00
RiotRobot 4f63b47134 v31.3.0-rc.2 2024-02-02 14:53:13 +00:00
Michael Telatynski 6edf3990f6 Update release-make.yml 2024-02-02 14:51:49 +00:00
RiotRobot c89f220e52 v31.3.0-rc.1 2024-02-02 14:50:08 +00:00
Michael Telatynski 9675a1584d Update release-make.yml 2024-02-02 14:48:19 +00:00
RiotRobot c81199b9d5 v31.3.0-rc.0 2024-02-02 14:45:44 +00:00
Michael Telatynski 6bdb087883 Update release-drafter.yml 2024-02-02 14:40:39 +00:00
Michael Telatynski 7da620c5be Update release-drafter.yml 2024-02-02 14:40:28 +00:00
Michael Telatynski c4f00895b1 Update release-drafter.yml 2024-02-02 14:38:34 +00:00
Michael Telatynski f8c3973efd Add waits for post-release steps for improved visibility (#4045) 2024-02-02 14:29:43 +00:00
Michael Telatynski 0c0775c0bf Saner releases: improve drafts, handle offcycle releases, bump downstream projects (#4044)
* Switch prepublishOnly to prepack to catch errors earlier

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

* Fix merge-release-notes.js parsing

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

* Improve release drafts and make release-drafter handle offcycle releases better

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

* Tweak release-drafter config

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

* Automate downstream dependency bumping

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

* Remove duplicated docs

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

* Delint

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-01 17:48:44 +00:00
Valere 70edf0f34d WebR: migrate the megolm session imported flag (#4037)
* WebR: migrate the megolm session imported flag

* review: Better doc

Co-authored-by: Denis Kasak <dkasak@termina.org.uk>

---------

Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
2024-02-01 15:40:07 +00:00
Michael Telatynski b46b31563e Saner Releases - improve changelog merging & allow pre-public testing (pack) (#4043)
* Switch prepublishOnly to prepack to catch errors earlier

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

* Fix merge-release-notes.js parsing

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

* Discard changes to yarn.lock

* Update package.json

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-02-01 11:26:01 +00:00
Hubert Chathi 8007bc5fe8 ElementR: fix emoji verification stalling when both ends hit start at the same time (#4004)
* Rust crypto: handle the SAS verifier being replaced

* lint

* make changes from review

* apply changes from code review

* remove useless assertions

* wrap acceptance inside a try-catch, and factor out acceptance into a function

* fix bugs

* we don't actually need the .accept variable

* move setInner to inside SAS class, and rename to replaceInner

* use defer to avoid using a closure

* lint

* prettier

* use the right name

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

* combine onChangeCallback with onChange

* apply changes from review

* add test for QR code verification, and try changing order in onChange

* lint

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-01-31 20:07:34 +00:00
Hubert Chathi d178fbf9cd Element R: emit events when devices have changed (#4019)
* emit events when Rust crypto wasm tells us devices have changed

* lint

* add missing stub function

* apply workaround for queueMicrotask
2024-01-31 14:31:28 +00:00
Valere f81036346f bump wasm bindings version (#4042) 2024-01-31 14:25:42 +00:00
RiotRobot 1a364c93c3 Resetting package fields for development 2024-01-31 14:38:47 +00:00
RiotRobot 1cd6fe7775 Merge branch 'master' into develop 2024-01-31 14:38:46 +00:00
RiotRobot 89d0133c61 v31.2.0 2024-01-31 14:37:57 +00:00
Hugh Nimmo-Smith a8b3369dd0 Sign in with QR (MSC3906) compatibility with Rust Crypto (#3761)
* Make MSC3906 implementation compatible with Rust Crypto

* Verify using CryptoApi but no cross-signing (yet)

* Use new crossSignDevice() function

* Mock crossSignDevice() function

* Fix type of parameter in mock

* review:  cleaning

* review: Remove unneeded defensive coding

* review: fix outdated documentation

* QR login: review, cleaning

* QR login | review: use getSafeUserId

---------

Co-authored-by: Valere <bill.carson@valrsoft.com>
2024-01-30 12:25:45 +00:00
Timo 99600e87f1 Add expire_ts compatibility to matrixRTC (#4032)
* add expire_ts compatibility to matrixRTC

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

* add expire_ts

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

* rename expire_ts -> expires_ts

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

* allow events without `expires`

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

* fix test for expires_ts

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

* comment clarification

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

* add comment where one needs to use the origin_server_ts

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

* add additional expires_ts tests

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

* fix fake timer

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

* change priority order to favor expires

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

---------

Signed-off-by: Timo K <toger5@hotmail.de>
2024-01-29 14:46:02 +00:00
Richard van der Hoff 7cf59d64e6 Element-R: support for migration of the room list from legacy crypto (#4036)
* Support for migration of the room list from legacy crypto

* fix migration for empty legacy store
2024-01-26 17:24:33 +00:00
Hubert Chathi 5967c670d8 Element R: Add test that requests are encoded properly (#4033)
* add test that requests are encoded properly

* fix variable name
2024-01-26 17:06:01 +00:00
Hubert Chathi 2fe35fed13 ElementR: report invalid keys rather than failing to restore from backup (#4006)
* rust-crypto: allow reporting failures when restoring keys

* add test and catch more invalid keys

* remove checks for room_id and session_id as they are guaranteed to be set

* remove obsolete comment
2024-01-26 16:46:35 +00:00
Florian Duros 2d1308c733 Make timeline a getter (#4022) 2024-01-26 13:40:45 +00:00
Richard van der Hoff 11348f9532 Element-R: check persistent room list for encryption config (#4035)
* crypto.spec: make `keyResponder` a local var

it is never used between functions, so making it external was confusing

* Persist encryption state to the rust room list.

* `MatrixClient.shouldEncryptEventForRoom`: fix for rust crypto

Previously, we were not bothering to ask the Rust Crypto stack if it thought we
should be encrypting for a given room. This adds a new method to `CryptoApi`,
wires it up for legacy and Rust crypto, and calls it.

* Tests for persistent room list
2024-01-26 12:41:18 +00:00
Richard van der Hoff 869576747c Refactor MatrixClient.encryptAndSendEvent (#4031)
* Replace `pendingEventEncryption` with a Set

We don't actually need the promise, so no need to save it.

This also fixes a resource leak, where we would leak a Promise and a HashMap
entry on each encrypted event.

* Convert `encryptEventIfNeeded` to async function

This means that it will always return a promise, so `encryptAndSendEvent` can't
tell if we are actually encrypting or not. Hence, also move the
`updatePendingEventStatus` into `encryptEventIfNeeded`.

* Simplify `encryptAndSendEvent`

Rewrite this as async.

* Factor out `MatrixClient.shouldEncryptEventForRoom`

* Inline a call to `isRoomEncrypted`

I want to deprecate this thing
2024-01-26 10:21:33 +00:00
Richard van der Hoff 35ea144bca Update matrix-rust-sdk-crypto-wasm to 4.1.0 (#4034)
I have some other changes in the pipeline which will depend on this.
2024-01-26 09:47:49 +00:00
Jan Jurzitza 5bf29ef543 fix IndexedDBStore API documentation (#3987)
* fix IndexedDBStore API documentation

changes the changelog entry to include since when this change is needed

fix #3986

Signed-off-by: Jan Jurzitza <gh@webfreak.org>

* retroactively add breaking change note to changelog entry

Signed-off-by: Jan Jurzitza <gh@webfreak.org>

---------

Signed-off-by: Jan Jurzitza <gh@webfreak.org>
2024-01-25 09:47:27 +00:00
Richard van der Hoff 99b3cf2279 Introduce Room.hasEncryptionStateEvent (#4030)
... and replace a lot of calls to `MatrixClient.isRoomEncrypted` with it.

This is a lesser check (since it can be tricked by servers withholding the
state event), but for most cases it is sufficient. At the end of the day, if
the server witholds the state, the room is pretty much bricked anyway. The one
thing we *mustn't* do is allow users to send *unencrypted* events to the room.
2024-01-25 08:38:02 +00:00
Hubert Chathi 5e2acb558b Implement getting verification cancellation info in Rust crypto (#3947)
* implement verification cancellation info in Rust crypto

* fix type info

* use string cancel code and add test

* simplify code

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>
2024-01-25 03:43:50 +00:00
Richard van der Hoff 19494e093b Fix crypto migration for megolm sessions with no sender key (#4024)
Fixes https://github.com/element-hq/element-web/issues/26894

Requires https://github.com/matrix-org/matrix-rust-sdk-crypto-wasm/pull/89 (or
rather, an update to a version of matrix-rust-sdk-crypto-wasm) which includes
it).
2024-01-24 14:47:13 +00:00
Travis Ralston ab217bdc35 Support optional MSC3860 redirects (#4007)
* Support optional MSC3860 redirects

See `allow_redirect` across the media endpoints: https://spec.matrix.org/v1.9/client-server-api/#client-behaviour-7

* Update the tests

* Appease the linter

* Add test to appease SonarCloud

* Only add `allow_redirect` if the parameter is specified rather than defaulting to `false`

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-01-24 10:30:51 +00:00
Richard van der Hoff c4d32a3292 Bump matrix-sdk-crypto-wasm to 4.0.1 (#4025)
* Bump matrix-sdk-crypto-wasm to 4.0.1

* Fix some tests

* more test fixes

* yet more fixes

* update comments
2024-01-24 09:35:35 +00:00
renovate[bot] 8e01b654bc Update all non-major dependencies (#4027)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-01-24 09:23:28 +00:00
renovate[bot] dc406ee2e8 Update dependency @types/node to v18.19.8 (#4028)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-23 21:10:43 +00:00
renovate[bot] be8b769542 Update typescript-eslint monorepo to v6.19.0 (#4029)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-23 19:34:25 +00:00
RiotRobot 5973a15f68 v31.2.0-rc.0 2024-01-23 18:26:23 +00:00
Richard van der Hoff 3c28cfc96a Fix type error introduced by crypto-wasm 4.0.0 (#4026)
* Fix type error introduced by crypto-wasm 4.0.0

* fix imports
2024-01-23 12:52:53 +00:00
Valere c99378501b ElementR | backup: call expensive roomKeyCounts less often (#4015)
* ElementR | backup: call expensive `roomKeyCounts` less often

* review: Improve doc

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

* review: Improve loop

* review: Add comment regarding slightly outdated remaining count

* Review: doc fix typo

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

* review: refactor code order, count after doing the request

* review: Missing await on sleep for limit exceeded

* review: Comment | add a note for when performance drops

* Backup: add upload loop test for rust

* test: quick fix backup loop tests

* test: quick fix imports backup loop tests

* review: improve comment

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

* Review improve comment

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

* Review: Clean and improve tests

* fix: wrong test name

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-01-22 19:06:22 +00:00
Valere b10a804a03 Element R: Bump matrix-rust-sdk-crypto-wasm to version 4.0.0 (#4021)
* bump wasm bindings version 4.0.0

* fix test compilation with initFromStore

* Fix test due to change in wasm handling of Vec<>

* review: Better doc

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

* review: Better doc

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

* review: revert userIdentity free removal

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2024-01-22 15:17:53 +00:00
RiotRobot 2337d5a7af Merge branch 'master' into develop 2024-01-19 13:44:53 +00:00
RiotRobot 5a49ed4ebb v31.1.0 2024-01-19 13:44:03 +00:00
Valere 22db9eb245 logs: improve logging (#4018) 2024-01-19 12:22:41 +00:00
Valere 4cddc7397d Decrypt and Import full backups in chunk with progress (#4005)
* Decrypt and Import full backups in chunk with progress

* backup chunk decryption jsdoc

* Review: fix capitalization

* review: better var name

* review: fix better iterate on object

* review: extract utility function

* review: Improve test, ensure mock calls

* review: Add more test for decryption or import failures

* Review: fix typo

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

---------

Co-authored-by: Andy Balaam <andy.balaam@matrix.org>
2024-01-19 10:08:45 +00:00
Michael Telatynski 418b69914a Fix issues caused by the artifacts v4 upgrade
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-01-19 09:30:15 +00:00
Michael Telatynski 0082964345 Iterate sonarcloud reusable action
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-01-19 09:27:05 +00:00
Michael Telatynski 96b3c79566 Iterate sonarcloud reusable action
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-01-19 09:12:43 +00:00
Michael Telatynski 41a6f18125 Fix Sonarcloud artifact downloading
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-01-19 09:03:07 +00:00
Michael Telatynski a2b2e8dbdf Use Github Artifacts v4 (#4011) 2024-01-19 08:54:45 +00:00
ElementRobot abd920f0f4 [Backport staging] Broaden spec version support (#4016)
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
Fixes https://github.com/matrix-org/matrix-js-sdk/issues/3915.
2024-01-18 17:40:07 +00:00
Matthew Hodgson 5333d0e0ba drop 'malformed member event' log level, given all TR rooms are malformed like this (#3975) 2024-01-18 16:55:28 +00:00
Richard van der Hoff c885542628 Broaden spec version support (#4014)
This commit does two things:

 * It puts the "minimum supported matrix version" from v1.5 back down to
   v1.1. In other words, it is a partial revert of
   https://github.com/matrix-org/matrix-js-sdk/pull/3970. (Partial, because we
   don't need to update the tests.)

   We're doing this largely because
   https://github.com/matrix-org/matrix-js-sdk/pull/3970 was introduced without
   a suitable announcement and deprecation policy. We haven't yet decided if
   the js-sdk's spec support policy needs to change, or if we will re-introduce
   this change in future in a more graceful manner.

 * It increases the "maximum supported matrix version" from v1.5 up to
   v1.9. Previously, the two concepts were tied together, but as discussed at
   length in
   https://github.com/matrix-org/matrix-js-sdk/issues/3915#issuecomment-1865221366,
   this is incorrect.

   Unfortunately, we have no real way of testing whether it is true that the
   js-sdk actually works with a server which supports *only* v1.9, but as per
   the comment above, we can't do much about that.

Fixes https://github.com/matrix-org/matrix-js-sdk/issues/3915.
2024-01-18 16:34:01 +00:00
David Baker 81b58388ee Fix new threads not appearing. (#4009)
* Fix new threads not appearing.

We try to update the thread roots when creating a thread, but a thread
can take some time to be ready after being created so we were calling it
too soon. Add a listener for the Update event to update the thread roots
once it's ready.

Fixes https://github.com/element-hq/element-web/issues/26799

* Don't recreate the event when we update

and also add a comment to the test

* Hopefully make sonarcloud happy
2024-01-17 15:20:11 +00:00
Richard van der Hoff 0d486eaade Add CODEOWNERS entries for crypot stuff (#4012) 2024-01-17 10:49:03 +00:00
RiotRobot 76b9c3950b Resetting package fields for development 2024-01-16 17:37:37 +00:00
RiotRobot 6176cb6d7b Merge branch 'master' into develop 2024-01-16 17:37:35 +00:00
RiotRobot b9a107f9ff v31.0.0 2024-01-16 17:36:41 +00:00
Richard van der Hoff 06e8cea63d Emit events during migration from libolm (#3982)
* Fix `CryptoStore.countEndToEndSessions`

This was apparently never tested, and was implemented incorrectly.

* Add `CryptoStore.countEndToEndInboundGroupSessions`

* Emit events to indicate migration progress
2024-01-16 13:31:21 +00:00
Richard van der Hoff 815c36e075 Support for migration from from libolm (#3978)
* Use a `StoreHandle` to init OlmMachine

This will be faster if we need to prepare the store.

* Include "needsBackup" flag in inbound group session batches

* On startup, import data from libolm cryptostore

* ISessionExtended -> SessionExtended
2024-01-16 12:00:22 +00:00
Michael Telatynski d355073d10 Stop running react-sdk Cypress tests (#4008)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2024-01-16 08:19:14 +00:00
renovate[bot] 2ef3ebb466 Update dependency eslint-plugin-jest to v27.6.2 (#4003)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-11 11:16:21 +00:00
renovate[bot] 92f7481fdd Update crazy-max/ghaction-import-gpg digest to 01dd5d3 (#4002)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-11 11:10:35 +00:00
Andy Balaam 8df30ed068 Revert "Revert "Bump matrix-sdk-crypto-wasm to 3.6.0 (#3989)" (#3991)" (#4001)
This reverts commit a597a9d660.
2024-01-10 16:30:59 +00:00
renovate[bot] 49624d5d73 Update all non-major dependencies (#3995)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 10:19:12 +00:00
renovate[bot] 8e5128ad3c Update dependency eslint-plugin-unicorn to v50 (#4000)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 02:20:22 +00:00
renovate[bot] 8ac2f2a78d Update dependency eslint-plugin-jsdoc to v48 (#3999)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 02:20:21 +00:00
renovate[bot] 630440c59c Update babel monorepo to v7.23.7 (#3993)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 02:20:17 +00:00
renovate[bot] 6932437360 Update dawidd6/action-download-artifact action to v3 (#3998)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 02:20:14 +00:00
renovate[bot] f381dfe991 Update dependency @types/node to v18.19.4 (#3994)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 02:20:11 +00:00
renovate[bot] 6a98b835a8 Update typescript-eslint monorepo to v6.18.0 (#3996)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-01-10 02:20:09 +00:00
RiotRobot ae01c0915c v31.0.0-rc.0 2024-01-09 17:46:58 +00:00
Andy Balaam a597a9d660 Revert "Bump matrix-sdk-crypto-wasm to 3.6.0 (#3989)" (#3991)
This reverts commit 533070c603.
2024-01-08 16:35:30 +00:00
Richard van der Hoff 9661cdecf2 bump fake-indexeddb (#3990)
To pick up fix to https://github.com/dumbmatter/fakeIndexedDB/issues/94
2024-01-08 15:34:49 +00:00
Richard van der Hoff 533070c603 Bump matrix-sdk-crypto-wasm to 3.6.0 (#3989) 2024-01-08 14:13:51 +00:00
David Langley eae1c2d48b Update teams names in CODEOWNERS (#3988)
* update teams names in CODEOWNERS

* Revert unintentional commit to client.ts
2024-01-08 14:08:47 +00:00
Richard van der Hoff 070a89d89d Bump minimum spec version to v1.5 (#3970)
* Update minimum spec version

* Update README.md

* fix autodiscovery tests
2024-01-08 12:33:13 +00:00
Rashmit Pankhania ffc9fb34d0 #22606 Fix "Remove" button to users without "m.room.redaction" (#3981)
* #22606 Fix "Remove" button  to users without "m.room.redaction" permission

This change makes the remove button NOT available to users without permissions

* Fix lint

Signed-off-by: Rashmit Pankhania <rashmitpankhania@gmail.com>

---------

Signed-off-by: Rashmit Pankhania <rashmitpankhania@gmail.com>
2024-01-03 12:21:38 +00:00
Richard van der Hoff d030c83cee Groundwork for supporting migration from libolm to rust crypto. (#3977)
* `getOwnDeviceKeys`: use `olmMachine.identityKeys`

This is simpler, and doesn't rely on us having done a device query to work.

* Factor out `requestKeyBackupVersion` utility

* Factor out `makeMatrixHttpApi` function

* Convert `initRustCrypto` to take a params object

* Improve logging in startup

... to help figure out what is taking so long.
2024-01-03 11:09:17 +00:00
renovate[bot] c115e055c6 Update typescript-eslint monorepo to v6 (major) (#3984)
* Update typescript-eslint monorepo to v6

* Fix typo

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>
2024-01-02 17:49:30 +00:00
renovate[bot] 0f65088fd9 Update dependency prettier to v3 (#3983)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Telatynski <7t3chguy@gmail.com>
2024-01-02 17:56:06 +00:00
Valere a1ff63adcb ElementR: Ensure Encryption order per room (#3973)
* add test for order bug

* Ensure encryption order per room

* Remove unneeded fake timers

* review

* put back log duration

* fix wrong call

* code review

* Update src/rust-crypto/RoomEncryptor.ts

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

* Update src/rust-crypto/RoomEncryptor.ts

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

* Update src/rust-crypto/RoomEncryptor.ts

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

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

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

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

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

* Update src/rust-crypto/RoomEncryptor.ts

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

* Update src/rust-crypto/RoomEncryptor.ts

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

* fix link syntax

* remove xxx comment

* fix comment order

* Improve comment

* add log duration

* fix comment

* Update src/rust-crypto/RoomEncryptor.ts

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

* 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>
2024-01-02 12:50:46 +00:00
Lars Karbo 31fc5f23be Use enums for event listeners in the readme (#3979) 2024-01-02 11:32:07 +00:00
Hubert Chathi febef3fc7c Element-R: fix bootstrapSecretStorage not resetting key backup when requested (#3976)
* pull resetKeyBackup outside of if statement

* fix broken conflict resolution

* prettier
2023-12-29 14:19:11 +00:00
Michael Telatynski f2625348d8 Move sonarcloud shard support into reusable workflow (#3962)
* Fix typo in jest CI

Caused versions to clobber each other's LCOV

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

* Move sonarcloud shard support into reusable workflow

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

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-12-20 08:56:48 +00:00
David Baker 6d1d04782a Send authenticated /versions request (#3968)
* Send authenticated /versions request

Implements [MSC4026](https://github.com/matrix-org/matrix-spec-proposals/pull/4026).

I believe this probably is as simple as this: it will mean that the versions
response can obviously change after logging in, but since the client is
constructed again with an access token, this should just work (?)

A remaining question is whether this needs to be optional. Opening the PR
to prompt the discussion. Apps might not expect it, but it's just the same
auth that we're sending to other endpoints on the same server.

* Fix tests

* Clear /versions cache on access token set
2023-12-19 17:27:08 +00:00
Richard van der Hoff 5e67a173c8 Add new methods to CryptoStore for Rust Crypto migration (#3969)
* Add `CryptoStore.containsData`

* add `CryptoStore.{get,set}MigrationState`

* Implement `CryptoStore.getEndToEnd{,InboundGroup}SessionsBatch`

* Implement `CryptoStore.deleteEndToEnd{,InboundGroup}SessionsBatch`

* fix typedoc errors
2023-12-19 15:25:54 +00:00
RiotRobot 9780643ce7 Resetting package fields for development 2023-12-19 15:48:49 +00:00
RiotRobot 608c6ece56 Merge branch 'master' into develop 2023-12-19 15:48:48 +00:00
RiotRobot 3a55efb476 v30.3.0 2023-12-19 15:47:50 +00:00
Valere 48d4f1b0cc ElementR: Fix missing key check values in 4S key storage (#3950)
* fix missing key check in key storage

* code review

* fix tests

* add recovery keys test for both backends

* fix api break on GeneratedSecretStorageKey

* fix test

* fix test

* Update src/crypto-api.ts

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

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

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

* Update src/crypto-api.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-12-18 15:05:28 +00:00
Valere a80e90b42d Add some perfomance logs (#3965)
* Add some perfomance logs

* missing return
2023-12-18 14:35:45 +00:00
Valere 2c13e133b7 ElementR: Ensure there is only one call to shareRoomKeys in flight at once (#3948)
* shareRoomKeys lock

* cleaning

* add test for lock
2023-12-18 09:26:00 +00:00
Andy Balaam 68898aeff2 Bump matrix-sdk-crypto-wasm to 3.5.0 (#3961) 2023-12-15 14:47:37 +00:00
David Baker f604ab2f63 Remove m.thread filter from relations API call (#3959)
* Remove m.thread filter from relations API call

We used MSC3981 to pass the recurse param to the /relations
endpoint so that we could get relations to events in a thread, but
we kept the rel_type filter on (as m.thread) so no second-order relations
would ever have been returned (a nested thread isn't a thing).

This removes the filter and does some filtering on the client side to
remove any events that shouldn't live in the threaded timeline (ie.
non-thread relations to the thread root event).

This should help fix stuck unreads because it will avoid the event that
the receipt refers to going missing (but only on HSes that support MSC3981).

For https://github.com/vector-im/element-web/issues/26718

* Fix import cycle

* Remove params from expected calls in tests to match

* Unused import
2023-12-14 10:39:43 +00:00
renovate[bot] b7d45e83f8 Update all non-major dependencies (#3955)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-13 20:25:50 +00:00
renovate[bot] db0e3cfbb0 Update babel monorepo to v7.23.5 (#3953)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-13 08:55:36 +00:00
renovate[bot] 87b90cc983 Update dawidd6/action-download-artifact digest to f29d1b6 (#3952)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-12 17:29:52 +00:00
renovate[bot] cc9545e313 Update dependency @types/jest to v29.5.11 (#3954)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-12 17:28:48 +00:00
renovate[bot] ed2792e6d8 Update dependency @types/node to v18.19.3 (#3956)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-12-12 17:27:07 +00:00
RiotRobot dd53ec722f v30.3.0-rc.0 2023-12-12 16:56:48 +00:00
Andy Balaam b03dc6ac43 Move roomList out of MatrixClient, into legacy Crypto (#3944)
* Comment explaining the purpose of RoomList

* Fix incorrect return type declaration on RoomList.getRoomEncryption

* Move RoomList out of MatrixClient, into legacy Crypto

* Initialise RoomList inside Crypto.init to allow us to await it
2023-12-11 10:30:27 +00:00
Valere 13c7e0ebda Element-R: Refactor per-session key backup download (#3929)
* initial commit

* new interation test

* more comments

* fix test, quick refactor on request version

* cleaning and logs

* fix type

* cleaning

* remove delegate stuff

* remove events and use timer mocks

* fix import

* ts ignore in tests

* Quick cleaning

* code review

* Use Errors instead of Results

* cleaning

* review

* remove forceCheck as not useful

* bad naming

* inline pauseLoop

* mark as paused in finally

* code review

* post merge fix

* rename KeyDownloadRateLimit

* use same config in loop and pass along
2023-12-08 14:21:07 +00:00
David Baker 2cd63ca4b9 Fix notifications appearing for old events (#3946)
A method that we use for fetching recursive related events on homeservers
without MSC3981 support injects events into the timeline in timestamp
order using a special method on event-timeline-set. Injecting events using
this method could cause on-screen notifications because it incorrectly set
the 'liveEvent' flag to true if the events were added tio the live timeline.
These events are never live though as the point is that we're fetching them.
2023-12-07 17:03:01 +00:00
Richard van der Hoff 479c4278a6 Element-R: disable sending room key requests (#3939) 2023-12-07 16:17:21 +00:00
David Baker 636fc3daaa Include event & room ID in log line (#3945)
...for when we ignore events that don't appear in the room timeline
2023-12-07 13:41:43 +00:00
Hubert Chathi 1d1309870a Don't back up keys that we got from backup (#3934)
* don't back up keys that we got from backup

* lint

* lint again

* remove key source struct and add function for importing from backup

* apply changes from review

---------

Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-12-07 11:32:27 +00:00
Jakub Onderka 13b8f01062 Fix upload with empty Content-Type (#3918)
Fixes #3917

Signed-off-by: Jakub Onderka <ahoj@jakubonderka.cz>
Co-authored-by: Florian Duros <florianduros@element.io>
2023-12-06 17:07:19 +00:00
David Baker cd672ec4cf Log if event ID is not foudn in the room (#3943) 2023-12-06 16:30:48 +00:00
David Baker 2363703b64 Prevent phantom notifications from events not in a room's timeline (#3942)
* Test whether an event not in a room's timeline causes notification count increase

Commited separately to demonstrate test failing before.

* Don't fix up notification counts if event isn't in the room

As explained by the comment, hopefully.

* Fix other test
2023-12-06 16:25:10 +00:00
Andy Balaam 1250bb8833 Call scheduleAllGroupSessionsForBackup during resetKeyBackup (#3935)
since its equivalent is done automatically in Rust crypto when we call
resetKeyBackup.
2023-12-06 15:09:31 +00:00
Richard van der Hoff 016ef12c4a Fix "mark_skipped" action again
Yet another go at this. The name is actually coming from an explicit
`github-status-action` action in the called workflows.
2023-12-06 15:00:41 +00:00
Richard van der Hoff 84d193a9a2 Fix "mark_skipped" action again
Turns out that the name we need is the key of the job in the workflow
definition; *not* the `name` property.
2023-12-06 14:53:11 +00:00
Richard van der Hoff 9d5f1bb4fc Fix "mark_skipped" action for end-to-end tests (#3940)
This seems to have been broken by
https://github.com/matrix-org/matrix-js-sdk/pull/3914, which changed the name
of the status check that is updated.
2023-12-06 11:41:50 +00:00
Richard van der Hoff 228131edf3 Bump matrix-sdk-crypto-wasm to 3.4.0 (#3938) 2023-12-05 16:57:38 +00:00
Michael Telatynski 23ad637aad Update cypress.yml 2023-12-05 15:01:08 +00:00
RiotRobot 103617c70e Resetting package fields for development 2023-12-05 13:35:58 +00:00
RiotRobot 8d84621b07 Merge branch 'master' into develop 2023-12-05 13:35:57 +00:00
Richard van der Hoff 41878c7a43 Element-R: await /keys/query during Verification requests (#3932) 2023-12-05 11:18:12 +00:00
Michael Telatynski f31e83fd03 Run matrix-react-sdk playwright tests downstream (#3914)
* Run matrix-react-sdk playwright tests downstream

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

* Update .github/workflows/cypress.yml

Co-authored-by: R Midhun Suresh <hi@midhun.dev>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
Co-authored-by: R Midhun Suresh <hi@midhun.dev>
2023-12-04 10:55:57 +00:00
Richard van der Hoff b515cdbdbb Rust-crypto: fix bootstrapCrossSigning on second call (#3912)
* Rust-crypto: fix `bootstrapCrossSigning` on second call

Currently, `bootstrapCrossSigning` raises an exception if it is called a second
time before secret storage is set up. It is easily fixed by checking that 4S is
set up before trying to export to 4S.

Also a few logging fixes while we're in the area.

* Factor out an `AccountDataAccumulator`

* Another test for bootstrapCrossSigning
2023-12-01 14:39:04 +00:00
Richard van der Hoff f4b6f91ee2 Bump matrix-rust-sdk-crypto-wasm to v3.2.0 (#3933)
* Bump `matrix-rust-sdk-crypto-wasm` to v3.2.0

* Reinstate timeout on `getUserDevices` call

Turns out that this used to have a timeout of 1 second in the wasm
bindings, which it no longer does. Reinstate it here.
2023-12-01 12:05:13 +00:00
Michael Telatynski df4536492c Update Sibz/github-status-action to use node16 to silence warning (#3910)
Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
2023-12-01 10:08:10 +00:00
Valere 2e98da4224 Signal key backup in cache (#3928)
* Signal key backup in cache

* code review

* quick doc

* code review
2023-11-30 08:15:37 +00:00
Valere 48d9d9b4c9 move get device key API from client to crypto (#3899)
MatrixClient API was exposing two methods that only worked for legacy crypto:
- getDeviceEd25519Key
- getDeviceCurve25519Key

=> These are used in the react-sdk for some functionality (rageshake, sentry, rendez-vous).

I have deprecated those calls from MatrixClient and created a new API in CryptoApi (where it belongs):

getOwnDeviceKeys(): Promise<OwnDeviceKeys>
2023-11-29 17:54:06 +00:00
Richard van der Hoff d90ae11e2b Expose new method CryptoApi.crossSignDevice (#3930) 2023-11-29 14:45:26 +00:00
Valere 3f246c6080 fix uncaught exceptions in Backup Loop for rust sdk (#3907)
* fix uncaught exceptions

* Update src/rust-crypto/backup.ts

Co-authored-by: Florian Duros <florianduros@element.io>

---------

Co-authored-by: Florian Duros <florianduros@element.io>
2023-11-29 09:07:56 +00:00
renovate[bot] 68911520d3 Update babel monorepo to v7.23.4 (#3921)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 08:37:12 +00:00
renovate[bot] 393a8d0cdb Update dependency @types/node to v18.18.13 (#3923)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 08:36:35 +00:00
renovate[bot] 51b63092b4 Update all non-major dependencies (#3920)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 08:36:30 +00:00
renovate[bot] b49c9639b9 Update dependency @types/jest to v29.5.10 (#3922)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 08:36:25 +00:00
renovate[bot] c588611fc0 Update matrix-org/netlify-pr-preview action to v3 (#3926)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 08:36:21 +00:00
renovate[bot] 5b34e4beaf Update typedoc (#3925)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-29 08:35:46 +00:00
Johannes Marbach 91f16e5e8e Merge pull request #3927 from matrix-org/midhun/fix-broken-ci 2023-11-29 08:37:33 +01:00
R Midhun Suresh 9cf257da0e Use new commit hash 2023-11-29 12:36:00 +05:30
R Midhun Suresh 188de3c4c8 Use new secret 2023-11-29 11:15:19 +05:30
renovate[bot] 67019a3486 Update matrix-org/matrix-react-sdk digest to e76a37e (#3919)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-28 18:21:56 +00:00
Richard van der Hoff a39b1203f2 Add guards against MatrixClient.stopClient calls (#3913)
If we call methods on `OlmMachine` after `MatrixClient.stopClient` is called,
we will end up with a "use of moved value" error. We can turn these into
something more useful with judicious use of `getOlmMachineOrThrow`.

Alternatively, we can sidestep the issue by bailing out sooner.
2023-11-28 16:30:18 +00:00
Andy Balaam c49a527e5e Rewrite receipt-handling code (#3901)
* Rewrite receipt-handling code

* Add tests around dangling receipts

* Fix mark as read for some rooms

* Add missing word

---------

Co-authored-by: Florian Duros <florian.duros@ormaz.fr>
Co-authored-by: Florian Duros <florianduros@element.io>
2023-11-28 14:43:48 +00:00
423 changed files with 107833 additions and 15459 deletions
-22
View File
@@ -1,22 +0,0 @@
{
"sourceMaps": true,
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": 10
},
"modules": "commonjs"
}
],
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-proposal-numeric-separator",
"@babel/plugin-proposal-class-properties",
"@babel/plugin-proposal-object-rest-spread",
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-transform-runtime"
]
}
+1
View File
@@ -0,0 +1 @@
_docs
+32 -8
View File
@@ -1,5 +1,5 @@
module.exports = {
plugins: ["matrix-org", "import", "jsdoc"],
plugins: ["matrix-org", "import", "jsdoc", "n"],
extends: ["plugin:matrix-org/babel", "plugin:matrix-org/jest", "plugin:import/typescript"],
parserOptions: {
project: ["./tsconfig.json"],
@@ -49,6 +49,26 @@ module.exports = {
},
],
"no-restricted-properties": [
"error",
{
object: "window",
property: "setImmediate",
message: "Use setTimeout instead.",
},
],
"no-restricted-globals": [
"error",
{
name: "setImmediate",
message: "Use setTimeout instead.",
},
{
name: "global",
message: "Use globalThis instead.",
},
],
"import/no-restricted-paths": [
"error",
{
@@ -92,10 +112,8 @@ module.exports = {
"@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"],
// We do this sometimes to brand interfaces
"@typescript-eslint/no-empty-object-type": "off",
"quotes": "off",
// We use a `logger` intermediary module
@@ -103,11 +121,8 @@ module.exports = {
},
},
{
// 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",
@@ -115,6 +130,15 @@ module.exports = {
// These need a bit more work before we can enable
// "jsdoc/check-param-names": "error",
// "jsdoc/check-indentation": "error",
// Ensure .ts extension on imports outside of tests
"n/file-extension-in-import": [
"error",
"always",
{
tryExtensions: [".ts"],
},
],
"no-extra-boolean-cast": "error",
},
},
{
+13 -4
View File
@@ -1,8 +1,17 @@
* @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
* @matrix-org/element-web-reviewers
/.github/workflows/** @matrix-org/element-web-team
/package.json @matrix-org/element-web-team
/yarn.lock @matrix-org/element-web-team
/scripts/** @matrix-org/element-web-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
/src/crypto-api @matrix-org/element-crypto-web-reviewers
/src/crypto @matrix-org/element-crypto-web-reviewers
/src/rust-crypto @matrix-org/element-crypto-web-reviewers
/spec/integ/crypto @matrix-org/element-crypto-web-reviewers
/spec/unit/crypto.spec.ts @matrix-org/element-crypto-web-reviewers
/spec/unit/crypto @matrix-org/element-crypto-web-reviewers
/spec/unit/rust-crypto @matrix-org/element-crypto-web-reviewers
+4 -9
View File
@@ -2,12 +2,7 @@
## 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))
<!--
If you would like to specify text for the changelog entry other than your PR title, add the following:
Notes: Add super cool feature
-->
- [ ] Tests written for new code (and old code if feasible).
- [ ] New or updated `public`/`exported` symbols have accurate [TSDoc](https://tsdoc.org/) documentation.
- [ ] 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)).
@@ -22,7 +22,7 @@ runs:
- name: Upload tarball signature
if: ${{ inputs.upload-url }}
uses: shogo82148/actions-upload-release-asset@dccd6d23e64fd6a746dce6814c0bde0a04886085 # v1
uses: shogo82148/actions-upload-release-asset@8482bd769644976d847e96fb4b9354228885e7b4 # v1
with:
upload_url: ${{ inputs.upload-url }}
asset_path: ${{ env.VERSION }}.tar.gz.asc
@@ -29,13 +29,13 @@ runs:
- name: Upload asset signatures
if: inputs.gpg-fingerprint
uses: shogo82148/actions-upload-release-asset@dccd6d23e64fd6a746dce6814c0bde0a04886085 # v1
uses: shogo82148/actions-upload-release-asset@8482bd769644976d847e96fb4b9354228885e7b4 # v1
with:
upload_url: ${{ inputs.upload-url }}
asset_path: ${{ inputs.asset-path }}.asc
- name: Upload assets
uses: shogo82148/actions-upload-release-asset@dccd6d23e64fd6a746dce6814c0bde0a04886085 # v1
uses: shogo82148/actions-upload-release-asset@8482bd769644976d847e96fb4b9354228885e7b4 # v1
with:
upload_url: ${{ inputs.upload-url }}
asset_path: ${{ inputs.asset-path }}
+43
View File
@@ -0,0 +1,43 @@
- name: "A-Element-R"
description: "Issues affecting the port of Element's crypto layer to Rust"
color: "bfd4f2"
- name: "A-Packaging"
description: "Packaging, signing, releasing"
color: "bfd4f2"
- name: "A-Technical-Debt"
color: "bfd4f2"
- name: "A-Testing"
description: "Testing, code coverage, etc."
color: "bfd4f2"
- name: "backport staging"
description: "Label to automatically backport PR to staging branch"
color: "B60205"
- name: "Dependencies"
description: "Pull requests that update a dependency file"
color: "0366d6"
- name: "Easy"
color: "5dc9f7"
- name: "Sponsored"
color: "ffc8f4"
- name: "T-Deprecation"
description: "A pull request that makes something deprecated"
color: "98e6ae"
- name: "T-Other"
description: "Questions, user support, anything else"
color: "98e6ae"
- name: "X-Blocked"
color: "ff7979"
- name: "X-Breaking-Change"
color: "ff7979"
- name: "X-Reverted"
description: "PR has been reverted"
color: "F68AA3"
- name: "X-Upcoming-Release-Blocker"
description: "This does not affect the current release cycle but will affect the next one"
color: "e99695"
- name: "Z-Community-PR"
description: "Issue is solved by a community member's PR"
color: "ededed"
- name: "Z-Flaky-Test"
description: "A test is raising false alarms"
color: "ededed"
+4
View File
@@ -22,10 +22,14 @@ version-resolver:
exclude-labels:
- "T-Task"
- "X-Reverted"
- "backport staging"
exclude-contributors:
- "RiotRobot"
template: |
$CHANGES
#no-changes-template: ""
prerelease: true
prerelease-identifier: rc
include-pre-releases: false
stable-ref: master
staging-ref: staging
+3 -1
View File
@@ -7,10 +7,12 @@ on:
branches:
- develop
permissions: {} # We use ELEMENT_BOT_TOKEN instead
jobs:
backport:
name: Backport
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
# 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: >
-58
View File
@@ -1,58 +0,0 @@
# 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 }}"
+9 -8
View File
@@ -5,24 +5,25 @@ on:
workflows: ["Static Analysis"]
types:
- completed
permissions: {}
jobs:
netlify:
if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'pull_request'
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
permissions:
actions: read
deployments: write
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
uses: actions/download-artifact@v4
with:
workflow: static_analysis.yml
run_id: ${{ github.event.workflow_run.id }}
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
name: docs
path: docs
- name: 📤 Deploy to Netlify
uses: matrix-org/netlify-pr-preview@v2
uses: matrix-org/netlify-pr-preview@v3
with:
path: docs
owner: ${{ github.event.workflow_run.head_repository.owner.login }}
@@ -1,26 +0,0 @@
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
@@ -0,0 +1,33 @@
# Triggers after the "Downstream artifacts" build has finished, to run the
# matrix-react-sdk playwright tests (with access to repo secrets)
name: matrix-react-sdk End to End Tests
on:
merge_group:
types: [checks_requested]
pull_request: {}
# For now at least, we don't run this or the downstream-end-to-end-tests against pushes
# to develop or master.
#
#push:
# branches: [develop, master]
permissions: {} # No permissions required
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.run_id }}
cancel-in-progress: ${{ github.event.workflow_run.event == 'pull_request' }}
jobs:
playwright:
name: Playwright
uses: element-hq/element-web/.github/workflows/end-to-end-tests.yaml@develop
permissions:
actions: read
issues: read
pull-requests: read
with:
matrix-js-sdk-sha: ${{ github.sha }}
# We only want to run the playwright tests on merge queue to prevent regressions
# from creeping in. They take a long time to run and consume multiple concurrent runners.
skip: ${{ github.event_name != 'merge_group' }}
+4 -5
View File
@@ -3,6 +3,7 @@ on:
push:
branches: [develop]
concurrency: ${{ github.workflow }}-${{ github.ref }}
permissions: {} # We use ELEMENT_BOT_TOKEN instead
jobs:
notify-downstream:
# Only respect triggers from our develop branch, ignore that of forks
@@ -12,15 +13,13 @@ jobs:
fail-fast: false
matrix:
include:
- repo: vector-im/element-web
- repo: element-hq/element-web
event: element-web-notify
- repo: matrix-org/matrix-react-sdk
event: upstream-sdk-notify
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
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
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3
with:
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
repository: ${{ matrix.repo }}
+20 -9
View File
@@ -9,20 +9,28 @@ on:
ELEMENT_BOT_TOKEN:
required: true
concurrency: ${{ github.workflow }}-${{ github.event.pull_request.head.ref || github.head_ref || github.ref }}
permissions: {} # We use ELEMENT_BOT_TOKEN instead
jobs:
changelog:
name: Preview Changelog
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: matrix-org/allchange@main
- uses: mheap/github-action-required-labels@388fd6af37b34cdfe5a23b37060e763217e58b03 # v5
if: github.event_name != 'merge_group'
with:
ghToken: ${{ secrets.GITHUB_TOKEN }}
requireLabel: true
labels: |
X-Breaking-Change
T-Deprecation
T-Enhancement
T-Defect
T-Task
Dependencies
mode: minimum
count: 1
prevent-blocked:
name: Prevent Blocked
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
permissions:
pull-requests: read
steps:
@@ -35,11 +43,14 @@ jobs:
community-prs:
name: Label Community PRs
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
if: github.event.action == 'opened'
permissions:
pull-requests: write
steps:
- name: Check membership
uses: tspascoal/get-user-teams-membership@ba78054988f58bea69b7c6136d563236f8ed2fc0 # v3
if: github.event.pull_request.user.login != 'renovate[bot]'
uses: tspascoal/get-user-teams-membership@57e9f42acd78f4d0f496b3be4368fc5f62696662 # v3
id: teams
with:
username: ${{ github.event.pull_request.user.login }}
@@ -48,7 +59,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
- name: Add label
if: ${{ steps.teams.outputs.isTeamMember == 'false' }}
if: steps.teams.outputs.isTeamMember == 'false'
uses: actions/github-script@v7
with:
script: |
@@ -61,7 +72,7 @@ jobs:
close-if-fork-develop:
name: Forbid develop branch fork contributions
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
if: >
github.event.action == 'opened' &&
github.event.pull_request.head.ref == 'develop' &&
+38
View File
@@ -0,0 +1,38 @@
name: Release Sanity checks
on:
workflow_call:
secrets:
ELEMENT_BOT_TOKEN:
required: false
inputs:
repository:
type: string
required: false
default: ${{ github.repository }}
description: "The repository (in form owner/repo) to check for release blockers"
permissions: {}
jobs:
checks:
name: Sanity checks
runs-on: ubuntu-24.04
steps:
- name: Check for X-Release-Blocker label on any open issues or PRs
uses: actions/github-script@v7
env:
REPO: ${{ inputs.repository }}
with:
github-token: ${{ secrets.ELEMENT_BOT_TOKEN || secrets.GITHUB_TOKEN }}
script: |
const { REPO } = process.env;
const { data } = await github.rest.search.issuesAndPullRequests({
q: `repo:${REPO} label:X-Release-Blocker is:open`,
per_page: 50,
});
if (data.total_count) {
data.items.forEach(item => {
core.error(`Release blocker: ${item.html_url}`);
});
core.setFailed(`Found release blockers!`);
}
@@ -0,0 +1,92 @@
# Workflow used by other workflows to generate draft releases.
name: Release Drafter Reusable
on:
workflow_call:
inputs:
include-changes:
description: Project to include changelog entries from in this release.
type: string
required: false
concurrency: release-drafter-action
permissions: {}
jobs:
draft:
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- name: 🧮 Checkout code
uses: actions/checkout@v4
with:
ref: staging
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version-file: package.json
cache: "yarn"
- name: Install Deps
run: "yarn install --frozen-lockfile"
- uses: t3chguy/release-drafter@105e541c2c3d857f032bd522c0764694758fabad
id: draft-release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
disable-autolabeler: true
- 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: Ingest upstream changes
if: inputs.include-changes
uses: actions/github-script@v7
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_ID: ${{ steps.draft-release.outputs.id }}
DEPENDENCY: ${{ inputs.include-changes }}
VERSION: ${{ steps.draft-release.outputs.tag_name }}
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.cjs");
let deps = [];
if (DEPENDENCY.includes("/")) {
deps.push(DEPENDENCY.replace("$VERSION", VERSION))
} else {
const fromVersion = JSON.parse((await github.request(`https://raw.githubusercontent.com/${owner}/${repo}/master/package.json`)).data).dependencies[DEPENDENCY];
const toVersion = require("./package.json").dependencies[DEPENDENCY];
if (toVersion.endsWith("#develop")) {
core.warning(`${DEPENDENCY} will be kept at ${fromVersion}`, { title: "Develop dependency found" });
} else {
deps.push([DEPENDENCY, fromVersion, toVersion]);
}
}
if (deps.length) {
const notes = await script({
github,
releaseId,
dependencies: deps,
});
await github.rest.repos.updateRelease({
owner,
repo,
release_id: releaseId,
body: notes,
tag_name: VERSION,
});
}
+9 -14
View File
@@ -1,21 +1,16 @@
# Generates the draft release for the js-sdk
# Normally triggered whenever anything is merged to the staging branch, but
# also has a workflow dispatch trigger in case it needs running manually due
# to failures / workflow updates etc.
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
workflow_dispatch: {}
concurrency: ${{ github.workflow }}
permissions: {}
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 }}
permissions:
contents: write
uses: matrix-org/matrix-js-sdk/.github/workflows/release-drafter-workflow.yml@develop
+7 -8
View File
@@ -13,12 +13,14 @@ on:
type: string
required: false
concurrency: ${{ github.workflow }}
permissions: {} # Uses ELEMENT_BOT_TOKEN
jobs:
merge:
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
# We will be pushing to this branch and want the CI to run after we do so we cannot use the GITHUB_TOKEN
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
fetch-depth: 0
@@ -34,6 +36,7 @@ jobs:
- uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: package.json
- name: Install Deps
run: "yarn install --frozen-lockfile"
@@ -48,9 +51,6 @@ jobs:
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: |
@@ -60,26 +60,25 @@ jobs:
CURRENT_VERSION=$(cat package.json | jq -r .dependencies[\"$PACKAGE\"])
echo "Current $PACKAGE version is $CURRENT_VERSION"
if [ "$CURRENT_VERSION" == "null" ]
if [[ "$CURRENT_VERSION" == "null" ]]
then
echo "Unable to find $PACKAGE in package.json"
exit 1
fi
if [ "$CURRENT_VERSION" == "develop" ]
if [[ "$CURRENT_VERSION" == *"#develop" ]]
then
echo "Not updating dependency $PACKAGE"
continue
fi
echo "Resetting $1 to develop branch..."
echo "Resetting $PACKAGE 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
+59 -99
View File
@@ -20,16 +20,6 @@ on:
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
@@ -44,24 +34,39 @@ on:
description: The number of expected assets, including signatures, excluding generated zip & tarball.
type: number
required: false
outputs:
npm-id:
description: "The npm package@version string we published"
value: ${{ jobs.npm.outputs.id }}
permissions: {}
jobs:
checks:
name: Sanity checks
permissions:
issues: read
pull-requests: read
uses: matrix-org/matrix-js-sdk/.github/workflows/release-checks.yml@develop
release:
name: Release
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
environment: Release
needs: checks
permissions:
contents: write
steps:
- name: Load GPG key
id: gpg
if: inputs.gpg-fingerprint
uses: crazy-max/ghaction-import-gpg@82a020f1f7f605c65dd2449b392a52c3fcfef7ef # v6
uses: crazy-max/ghaction-import-gpg@cb9bde2e2525e640591a934b1fd28eef1dcaf5e5 # 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
id: draft-release
uses: cardinalby/git-get-release-action@5172c3a026600b1d459b117738c605fabc9e4e44 # v1
env:
GITHUB_TOKEN: ${{ github.token }}
with:
@@ -71,6 +76,7 @@ jobs:
- uses: actions/checkout@v4
with:
ref: staging
# We will be pushing to this branch and want the CI to run after we do so we cannot use the GITHUB_TOKEN
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
fetch-depth: 0
@@ -88,18 +94,12 @@ jobs:
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 }}
VERSION: ${{ steps.draft-release.outputs.tag_name }}
- name: Finalise version
if: inputs.final
@@ -128,79 +128,29 @@ jobs:
- uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: package.json
- 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
- name: Handle develop 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
cat package.json | jq -r '.dependencies | to_entries | .[] | "\(.key) \(.value)"' | grep '#develop$' | while read -r dep ; do
IFS=" "
PACKAGE=${dep[0]}
VERSION=${dep[1]}
echo "::warning title=Develop dependency found::$DEPENDENCY will be kept at $VERSION"
yarn upgrade "$PACKAGE@$VERSION" --exact
git add -u
git commit -m "Keep $PACKAGE at $VERSION"
done
- 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);
run: |
yarn version --no-git-tag-version --new-version "${VERSION#v}"
git add package.json
- name: Add to CHANGELOG.md
if: inputs.final
@@ -219,11 +169,8 @@ jobs:
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
env:
RELEASE_NOTES: ${{ steps.draft-release.outputs.body }}
- name: Commit changes
run: git commit -m "$VERSION"
@@ -237,7 +184,7 @@ jobs:
uses: ./.action-repo/.github/actions/upload-release-assets
with:
gpg-fingerprint: ${{ inputs.gpg-fingerprint }}
upload-url: ${{ steps.release.outputs.upload_url }}
upload-url: ${{ steps.draft-release.outputs.upload_url }}
asset-path: ${{ inputs.asset-path }}
- name: Create signed tag
@@ -252,7 +199,7 @@ jobs:
uses: ./.action-repo/.github/actions/sign-release-tarball
with:
gpg-fingerprint: ${{ inputs.gpg-fingerprint }}
upload-url: ${{ steps.release.outputs.upload_url }}
upload-url: ${{ steps.draft-release.outputs.upload_url }}
# We defer pushing changes until after the release assets are built,
# signed & uploaded to improve the atomicity of this action.
@@ -273,7 +220,7 @@ jobs:
if: inputs.expected-asset-count
uses: actions/github-script@v7
env:
RELEASE_ID: ${{ steps.release.outputs.id }}
RELEASE_ID: ${{ steps.draft-release.outputs.id }}
EXPECTED_ASSET_COUNT: ${{ inputs.expected-asset-count }}
with:
retries: 3
@@ -301,7 +248,7 @@ jobs:
- name: Publish release
uses: actions/github-script@v7
env:
RELEASE_ID: ${{ steps.release.outputs.id }}
RELEASE_ID: ${{ steps.draft-release.outputs.id }}
FINAL: ${{ inputs.final }}
with:
retries: 3
@@ -335,15 +282,18 @@ jobs:
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
update-labels:
name: Advance release blocker labels
post-release:
name: Post release steps
needs: release
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
permissions:
issues: write
steps:
- id: repository
run: echo "REPO=${GITHUB_REPOSITORY#*/}" >> $GITHUB_OUTPUT
- uses: garganshu/github-label-updater@3770d15ebfed2fe2cb06a241047bc340f774a7d1 # v1.0.0
- name: Advance release blocker labels
uses: garganshu/github-label-updater@3770d15ebfed2fe2cb06a241047bc340f774a7d1 # v1.0.0
with:
owner: ${{ github.repository_owner }}
repo: ${{ steps.repository.outputs.REPO }}
@@ -351,3 +301,13 @@ jobs:
filter-labels: X-Upcoming-Release-Blocker
remove-labels: X-Upcoming-Release-Blocker
add-labels: X-Release-Blocker
# - name: Wait for master->develop gitflow merge
# if: inputs.final
# uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork
# with:
# ref: master
# repo-token: ${{ secrets.GITHUB_TOKEN }}
# wait-interval: 10
# check-name: merge
# allowed-conclusions: success
+14 -2
View File
@@ -4,10 +4,17 @@ on:
secrets:
NPM_TOKEN:
required: true
outputs:
id:
description: "The npm package@version string we published"
value: ${{ jobs.npm.outputs.id }}
permissions: {} # No permissions required
jobs:
npm:
name: Publish to npm
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
outputs:
id: ${{ steps.npm-publish.outputs.id }}
steps:
- name: 🧮 Checkout code
uses: actions/checkout@v4
@@ -19,19 +26,24 @@ jobs:
with:
cache: "yarn"
registry-url: "https://registry.npmjs.org"
node-version-file: package.json
- name: 🔨 Install dependencies
run: "yarn install --frozen-lockfile"
- name: 🚀 Publish to npm
id: npm-publish
uses: JS-DevTools/npm-publish@4b07b26a2f6e0a51846e1870223e545bae91c552 # v3.0.1
uses: JS-DevTools/npm-publish@19c28f1ef146469e409470805ea4279d47c3d35c # v3.1.1
with:
token: ${{ secrets.NPM_TOKEN }}
access: public
tag: next
ignore-scripts: false
- name: Check npm package was published
if: steps.npm-publish.outputs.id == ''
run: exit 1
- 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
+58 -26
View File
@@ -21,56 +21,88 @@ on:
type: boolean
default: true
concurrency: ${{ github.workflow }}
permissions: {} # No permissions required
jobs:
release:
uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop
permissions:
contents: write
issues: write
pull-requests: read
secrets: inherit
with:
final: ${{ inputs.mode == 'final' }}
npm: ${{ inputs.npm }}
bump-downstreams:
name: Update npm dependency in downstream projects
needs: release
runs-on: ubuntu-24.04
strategy:
matrix:
repo:
- element-hq/element-web
steps:
- uses: actions/checkout@v4
with:
repository: ${{ matrix.repo }}
ref: staging
token: ${{ secrets.ELEMENT_BOT_TOKEN }}
- uses: actions/setup-node@v4
with:
cache: "yarn"
node-version: "lts/*"
- name: Bump dependency
env:
DEPENDENCY: ${{ needs.release.outputs.npm-id }}
run: |
git config --global user.email "releases@riot.im"
git config --global user.name "RiotRobot"
yarn upgrade "$DEPENDENCY" --exact
git add package.json yarn.lock
git commit -am"Upgrade dependency to $DEPENDENCY"
git push origin staging
docs:
name: Publish Documentation
needs: release
if: inputs.docs
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- name: 🧮 Checkout code
uses: actions/checkout@v4
- name: 🧮 Checkout gh-pages
uses: actions/checkout@v4
with:
ref: gh-pages
path: _docs
- name: 🔧 Yarn cache
uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: package.json
- name: 🔨 Install dependencies
run: "yarn install --frozen-lockfile"
- name: 🔨 Install symlinks
run: |
sudo apt-get update
sudo apt-get install -y symlinks
- name: 📖 Generate docs
run: |
yarn tpv purge --yes --out _docs --stale --major 10
yarn gendoc
symlinks -rc _docs
run: yarn gendoc
- name: 🔨 Set up git
run: |
git config --global user.email "releases@riot.im"
git config --global user.name "RiotRobot"
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
with:
path: _docs
- name: 🚀 Deploy
run: |
git add . --all
git commit -m "Update docs"
git push
working-directory: _docs
docs-deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-24.04
needs: docs
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
+59 -14
View File
@@ -5,19 +5,29 @@ on:
secrets:
SONAR_TOKEN:
required: true
inputs:
extra_args:
type: string
# No longer used
ELEMENT_BOT_TOKEN:
required: false
description: "Extra args to pass to SonarCloud"
inputs:
sharded:
type: boolean
required: false
description: "Whether to combine multiple LCOV and jest-sonar-report files in coverage artifact"
permissions: {}
jobs:
sonarqube:
runs-on: ubuntu-latest
if: github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-24.04
if: |
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event != 'merge_group'
permissions:
actions: read
statuses: write
id-token: write # sonar
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
# This provides an easy link to this workflow_run from the PR before Sonarcloud is done.
- uses: guibranco/github-status-action-v2@ecd54a02cf761e85a8fb328fe937710fd4227cda
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
state: pending
@@ -25,24 +35,59 @@ jobs:
sha: ${{ github.event.workflow_run.head_sha }}
target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
- name: "🧮 Checkout code"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
repository: ${{ github.event.workflow_run.head_repository.full_name }}
ref: ${{ github.event.workflow_run.head_branch }} # checkout commit that triggered this workflow
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: 📥 Download artifact
uses: actions/download-artifact@v4
if: ${{ !inputs.sharded }}
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
name: coverage
path: coverage
- name: 📥 Download sharded artifacts
uses: actions/download-artifact@v4
if: inputs.sharded
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}
pattern: coverage-*
path: coverage
merge-multiple: true
- name: Check coverage artifact
run: |
if [ ! -d coverage ]; then
echo "Coverage not found. Exiting with failure."
exit 1
fi
- id: extra_args
run: |
coverage=$(find coverage -type f -name '*lcov.info' -printf '%h/%f,' | tr -d '\r\n' | sed 's/,$//g')
echo "sonar.javascript.lcov.reportPaths=$coverage" >> sonar-project.properties
reports=$(find coverage -type f -name '*sonar-report*.xml' -printf '%h/%f,' | tr -d '\r\n' | sed 's/,$//g')
echo "sonar.testExecutionReportPaths=$reports" >> sonar-project.properties
- name: "🩻 SonarCloud Scan"
id: sonarcloud
uses: matrix-org/sonarcloud-workflow-action@v2.7
uses: matrix-org/sonarcloud-workflow-action@v3.3
# 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:
skip_checkout: true
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
- uses: guibranco/github-status-action-v2@ecd54a02cf761e85a8fb328fe937710fd4227cda
if: always()
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
+7 -28
View File
@@ -7,39 +7,18 @@ on:
concurrency:
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }}
cancel-in-progress: true
permissions: {}
jobs:
# 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
permissions:
actions: read
statuses: write
id-token: write # sonar
uses: matrix-org/matrix-js-sdk/.github/workflows/sonarcloud.yml@develop
secrets:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
with:
extra_args: -Dsonar.javascript.lcov.reportPaths=${{ needs.prepare.outputs.reportPaths }} -Dsonar.testExecutionReportPaths=${{ needs.prepare.outputs.testExecutionReportPaths }}
sharded: true
+98 -24
View File
@@ -8,16 +8,18 @@ on:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions: {} # No permissions needed
jobs:
ts_lint:
name: "Typescript Syntax Check"
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: package.json
- name: Install Deps
run: "yarn install"
@@ -25,25 +27,16 @@ jobs:
- 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: Typecheck (release mode)
run: "yarn run lint:types"
js_lint:
name: "ESLint"
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: package.json
- name: Install Deps
run: "yarn install"
@@ -51,8 +44,8 @@ jobs:
- name: Run Linter
run: "yarn run lint:js"
workflow_lint:
name: "Workflow Lint"
node_example_lint:
name: "Node.js example"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
@@ -60,6 +53,42 @@ jobs:
- uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: package.json
- name: Install Deps
run: "yarn install"
- name: Build Types
run: "yarn build:types"
- uses: actions/setup-node@v4
with:
cache: "npm"
node-version-file: "examples/node/package.json"
# cache-dependency-path: '**/package-lock.json'
- name: Install Example Deps
run: "npm install"
working-directory: "examples/node"
- name: Check Syntax
run: "node --check app.js"
working-directory: "examples/node"
- name: Typecheck
run: "npx tsc"
working-directory: "examples/node"
workflow_lint:
name: "Workflow Lint"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: package.json
- name: Install Deps
run: "yarn install --frozen-lockfile"
@@ -69,31 +98,76 @@ jobs:
docs:
name: "JSDoc Checker"
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: package.json
- name: Install Deps
run: "yarn install"
- 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
run: "yarn run gendoc --treatWarningsAsErrors --suppressCommentWarningsInDeclarationFiles"
- name: Upload Artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: docs
path: _docs
# We'll only use this in a workflow_run, then we're done with it
retention-days: 1
analyse_dead_code:
name: "Analyse Dead Code"
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
cache: "yarn"
node-version-file: package.json
- name: Install Deps
run: "yarn install --frozen-lockfile"
- name: Run linter
run: "yarn run lint:knip"
element-web:
name: Downstream tsc element-web
if: github.event_name == 'merge_group'
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
with:
repository: element-hq/element-web
- uses: actions/setup-node@v4
with:
cache: "yarn"
node-version: "lts/*"
- name: Install Dependencies
run: "./scripts/layered.sh"
env:
# tell layered.sh to check out the right sha of the JS-SDK
JS_SDK_GITHUB_BASE_REF: ${{ github.sha }}
- name: Typecheck
run: "yarn run lint:types"
# Hook for branch protection to skip downstream typechecking outside of merge queues
downstream:
name: Downstream Typescript Syntax Check
runs-on: ubuntu-24.04
if: always()
needs:
- element-web
steps:
- if: needs.element-web.result != 'skipped' && needs.element-web.result != 'success'
run: exit 1
+22
View File
@@ -0,0 +1,22 @@
name: Sync labels
on:
workflow_dispatch: {}
schedule:
- cron: "0 1 * * *" # 1am every day
push:
branches:
- develop
paths:
- .github/labels.yml
permissions: {} # We use ELEMENT_BOT_TOKEN instead
jobs:
sync-labels:
uses: element-hq/element-meta/.github/workflows/sync-labels.yml@develop
with:
LABELS: |
element-hq/element-meta
.github/labels.yml
DELETE: true
WET: true
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
+46 -12
View File
@@ -10,15 +10,16 @@ concurrency:
cancel-in-progress: true
env:
ENABLE_COVERAGE: ${{ github.event_name != 'merge_group' }}
permissions: {} # No permissions required
jobs:
jest:
name: "Jest [${{ matrix.specs }}] (Node ${{ matrix.node == '*' && 'latest' || matrix.node }})"
runs-on: ubuntu-latest
runs-on: ubuntu-24.04
timeout-minutes: 10
strategy:
matrix:
specs: [integ, unit]
node: [18, "lts/*", 21]
node: ["lts/*", 22]
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -52,37 +53,70 @@ jobs:
- 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
run: mv coverage/lcov.info coverage/${{ steps.setupNode.outputs.node-version }}-${{ matrix.specs }}.lcov.info
- name: Upload Artifact
if: env.ENABLE_COVERAGE == 'true'
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: coverage
name: coverage-${{ matrix.specs }}-${{ matrix.node == 'lts/*' && 'lts' || matrix.node }}
path: |
coverage
!coverage/lcov-report
matrix-react-sdk:
name: Downstream test matrix-react-sdk
# Dummy completion job to simplify branch protections
jest-complete:
name: Jest tests
needs: jest
if: always()
runs-on: ubuntu-24.04
steps:
- if: needs.jest.result != 'skipped' && needs.jest.result != 'success'
run: exit 1
element-web:
name: Downstream test element-web
if: github.event_name == 'merge_group'
uses: matrix-org/matrix-react-sdk/.github/workflows/tests.yml@develop
uses: element-hq/element-web/.github/workflows/tests.yml@develop
permissions:
statuses: write
with:
disable_coverage: true
matrix-js-sdk-sha: ${{ github.sha }}
complement-crypto:
name: "Run Complement Crypto tests"
if: github.event_name == 'merge_group'
permissions: read-all
uses: matrix-org/complement-crypto/.github/workflows/single_sdk_tests.yml@main
with:
use_js_sdk: "."
# we need this so the job is reported properly when run in a merge queue
downstream-complement-crypto:
name: Downstream Complement Crypto tests
runs-on: ubuntu-24.04
if: always()
needs:
- complement-crypto
steps:
- if: needs.complement-crypto.result != 'skipped' && needs.complement-crypto.result != 'success'
run: exit 1
# 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
runs-on: ubuntu-24.04
if: always()
needs:
- matrix-react-sdk
- element-web
permissions:
statuses: write
steps:
- name: Skip SonarCloud on merge queues
if: env.ENABLE_COVERAGE == 'false'
uses: Sibz/github-status-action@faaa4d96fecf273bd762985e0e7f9f933c774918 # v1
uses: guibranco/github-status-action-v2@ecd54a02cf761e85a8fb328fe937710fd4227cda
with:
authToken: ${{ secrets.GITHUB_TOKEN }}
state: success
@@ -91,5 +125,5 @@ jobs:
sha: ${{ github.sha }}
target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
- if: needs.matrix-react-sdk.result != 'skipped' && needs.matrix-react-sdk.result != 'success'
- if: needs.element-web.result != 'skipped' && needs.element-web.result != 'success'
run: exit 1
+14
View File
@@ -0,0 +1,14 @@
name: Move new issues into Issue triage board
on:
issues:
types: [opened]
permissions: {} # We use ELEMENT_BOT_TOKEN instead
jobs:
automate-project-columns-next:
runs-on: ubuntu-24.04
steps:
- uses: actions/add-to-project@main
with:
project-url: https://github.com/orgs/element-hq/projects/120
github-token: ${{ secrets.ELEMENT_BOT_TOKEN }}
+2 -2
View File
@@ -3,9 +3,9 @@ name: Move labelled issues to correct projects
on:
issues:
types: [labeled]
permissions: {} # We use ELEMENT_BOT_TOKEN instead
jobs:
call-triage-labelled:
uses: vector-im/element-web/.github/workflows/triage-labelled.yml@develop
uses: element-hq/element-web/.github/workflows/triage-labelled.yml@develop
secrets:
ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }}
-1
View File
@@ -1,4 +1,3 @@
#!/usr/bin/env sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged
+2 -1
View File
@@ -25,5 +25,6 @@ out
# This file is owned, parsed, and generated by allchange, which doesn't comply with prettier
/CHANGELOG.md
# This file is also autogenerated
# These files are also autogenerated
/spec/test-utils/test-data/index.ts
/spec/test-utils/test_indexeddb_cryptostore_dump/dump.json
View File
+551
View File
@@ -1,3 +1,553 @@
Changes in [36.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v36.2.0) (2025-02-11)
==================================================================================================
## 🦖 Deprecations
* [Backport staging] Deprecate parameter and functions using legacy crypto in `models/event.ts` ([#4700](https://github.com/matrix-org/matrix-js-sdk/pull/4700)). Contributed by @RiotRobot.
## ✨ Features
* Improve types around Terms ([#4674](https://github.com/matrix-org/matrix-js-sdk/pull/4674)). Contributed by @t3chguy.
* Provide more options for starting dehydration ([#4664](https://github.com/matrix-org/matrix-js-sdk/pull/4664)). Contributed by @uhoreg.
* Device Dehydration | js-sdk: store/load dehydration key ([#4599](https://github.com/matrix-org/matrix-js-sdk/pull/4599)). Contributed by @BillCarsonFr.
* Add unspecced backup disable flag ([#4661](https://github.com/matrix-org/matrix-js-sdk/pull/4661)). Contributed by @dbkr.
* Switch OIDC primarily to new `/auth_metadata` API ([#4626](https://github.com/matrix-org/matrix-js-sdk/pull/4626)). Contributed by @t3chguy.
* Add `CryptoApi.resetEncryption` ([#4614](https://github.com/matrix-org/matrix-js-sdk/pull/4614)). Contributed by @florianduros.
## 🐛 Bug Fixes
* Fix topic types ([#4678](https://github.com/matrix-org/matrix-js-sdk/pull/4678)). Contributed by @Half-Shot.
* Handle empty m.room.topic ([#4673](https://github.com/matrix-org/matrix-js-sdk/pull/4673)). Contributed by @Half-Shot.
* `CryptoApi.resetEncryption` should always create a new key backup ([#4648](https://github.com/matrix-org/matrix-js-sdk/pull/4648)). Contributed by @florianduros.
Changes in [36.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v36.1.0) (2025-01-28)
==================================================================================================
## ✨ Features
* Deprecate `MatrixClient.login` and replace with `loginRequest` ([#4632](https://github.com/matrix-org/matrix-js-sdk/pull/4632)). Contributed by @richvdh.
* Use `SyncCryptoCallback` api instead of legacy crypto in sliding sync ([#4624](https://github.com/matrix-org/matrix-js-sdk/pull/4624)). Contributed by @florianduros.
* Distinguish room state and timeline events in embedded clients ([#4574](https://github.com/matrix-org/matrix-js-sdk/pull/4574)). Contributed by @robintown.
* Allow setting default secret storage key id to null ([#4615](https://github.com/matrix-org/matrix-js-sdk/pull/4615)). Contributed by @florianduros.
* Add authenticated media to getAvatarUrl in room and room-member models ([#4616](https://github.com/matrix-org/matrix-js-sdk/pull/4616)). Contributed by @m004.
* Send MSC3981 'recurse' param on `/relations` endpoint on Matrix 1.10 servers ([#4023](https://github.com/matrix-org/matrix-js-sdk/pull/4023)). Contributed by @dbkr.
## 🐛 Bug Fixes
* [Backport staging] Revert "Distinguish room state and timeline events in embedded clients (#4574)" ([#4657](https://github.com/matrix-org/matrix-js-sdk/pull/4657)). Contributed by @RiotRobot.
* Change randomString et al to be secure ([#4621](https://github.com/matrix-org/matrix-js-sdk/pull/4621)). Contributed by @dbkr.
* Fix issue with sentinels being incorrect on m.room.member events ([#4609](https://github.com/matrix-org/matrix-js-sdk/pull/4609)). Contributed by @t3chguy.
Changes in [36.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v36.0.0) (2025-01-14)
==================================================================================================
## 🚨 BREAKING CHANGES
* Remove support for "legacy" MSC3898 group calling in MatrixRTCSession and CallMembership ([#4583](https://github.com/matrix-org/matrix-js-sdk/pull/4583)). Contributed by @toger5.
## ✨ Features
* MatrixRTC: Implement expiry logic for CallMembership and additional test coverage ([#4587](https://github.com/matrix-org/matrix-js-sdk/pull/4587)). Contributed by @toger5.
## 🐛 Bug Fixes
* Don't retry on 4xx responses ([#4601](https://github.com/matrix-org/matrix-js-sdk/pull/4601)). Contributed by @dbkr.
* Upgrade matrix-sdk-crypto-wasm to 12.1.0 ([#4596](https://github.com/matrix-org/matrix-js-sdk/pull/4596)). Contributed by @andybalaam.
* Avoid key prompts when resetting crypto ([#4586](https://github.com/matrix-org/matrix-js-sdk/pull/4586)). Contributed by @dbkr.
* Handle when aud OIDC claim is an Array ([#4584](https://github.com/matrix-org/matrix-js-sdk/pull/4584)). Contributed by @liamdiprose.
* Save the key backup key to 4S during `bootstrapSecretStorage ` ([#4542](https://github.com/matrix-org/matrix-js-sdk/pull/4542)). Contributed by @dbkr.
* Only re-prepare MatrixrRTC delayed disconnection event on 404 ([#4575](https://github.com/matrix-org/matrix-js-sdk/pull/4575)). Contributed by @toger5.
Changes in [35.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v35.1.0) (2024-12-18)
==================================================================================================
This release updates matrix-sdk-crypto-wasm to fix a bug which could prevent loading stored crypto state from storage.
## 🐛 Bug Fixes
* Upgrade matrix-sdk-crypto-wasm to 1.11.0 ([#4593](https://github.com/matrix-org/matrix-js-sdk/pull/4593)).
Changes in [35.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v35.0.0) (2024-12-17)
==================================================================================================
## 🚨 BREAKING CHANGES
This release contains several breaking changes which will need code changes in your app. Most notably, `initCrypto()`
no longer exists and has been moved to `initLegacyCrypto()` in preparation for the eventual removal of Olm. You can
continue to use legacy Olm crypto for now by calling `initLegacyCrypto()` instead.
You may also need to make further changes if you use more advanced APIs. See the individual PRs (listed in order of size of change) for specific APIs changed and how to migrate.
* Rename `MatrixClient.initCrypto` into `MatrixClient.initLegacyCrypto` ([#4567](https://github.com/matrix-org/matrix-js-sdk/pull/4567)). Contributed by @florianduros.
* Support MSC4222 `state_after` ([#4487](https://github.com/matrix-org/matrix-js-sdk/pull/4487)). Contributed by @dbkr.
* Avoid use of Buffer as it does not exist in the Web natively ([#4569](https://github.com/matrix-org/matrix-js-sdk/pull/4569)). Contributed by @t3chguy.
## 🦖 Deprecations
* Deprecate remaining legacy functions and move `CryptoEvent.LegacyCryptoStoreMigrationProgress` handler ([#4560](https://github.com/matrix-org/matrix-js-sdk/pull/4560)). Contributed by @florianduros.
## ✨ Features
* Rename `MatrixClient.initCrypto` into `MatrixClient.initLegacyCrypto` ([#4567](https://github.com/matrix-org/matrix-js-sdk/pull/4567)). Contributed by @florianduros.
* Avoid use of Buffer as it does not exist in the Web natively ([#4569](https://github.com/matrix-org/matrix-js-sdk/pull/4569)). Contributed by @t3chguy.
* Re-send MatrixRTC media encryption keys for a new joiner even if a rotation is in progress ([#4561](https://github.com/matrix-org/matrix-js-sdk/pull/4561)). Contributed by @hughns.
* Support MSC4222 `state_after` ([#4487](https://github.com/matrix-org/matrix-js-sdk/pull/4487)). Contributed by @dbkr.
* Revert "Fix room state being updated with old (now overwritten) state and emitting for those updates. (#4242)" ([#4532](https://github.com/matrix-org/matrix-js-sdk/pull/4532)). Contributed by @toger5.
## 🐛 Bug Fixes
* Fix age field check in event echo processing ([#3635](https://github.com/matrix-org/matrix-js-sdk/pull/3635)). Contributed by @stas-demydiuk.
Changes in [34.13.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.13.0) (2024-12-03)
====================================================================================================
## 🦖 Deprecations
* Deprecate `MatrixClient.isEventSenderVerified` ([#4527](https://github.com/matrix-org/matrix-js-sdk/pull/4527)). Contributed by @florianduros.
* Add `restoreKeybackup` to `CryptoApi`. ([#4476](https://github.com/matrix-org/matrix-js-sdk/pull/4476)). Contributed by @florianduros.
## ✨ Features
* Ensure we disambiguate display names which look like MXIDs ([#4540](https://github.com/matrix-org/matrix-js-sdk/pull/4540)). Contributed by @t3chguy.
* Add `CryptoApi.getBackupInfo` ([#4512](https://github.com/matrix-org/matrix-js-sdk/pull/4512)). Contributed by @florianduros.
* Fix local echo in embedded mode ([#4498](https://github.com/matrix-org/matrix-js-sdk/pull/4498)). Contributed by @toger5.
* Add `restoreKeybackup` to `CryptoApi`. ([#4476](https://github.com/matrix-org/matrix-js-sdk/pull/4476)). Contributed by @florianduros.
## 🐛 Bug Fixes
* Fix `RustBackupManager` remaining values after current backup removal ([#4537](https://github.com/matrix-org/matrix-js-sdk/pull/4537)). Contributed by @florianduros.
Changes in [34.12.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.12.0) (2024-11-19)
====================================================================================================
## 🦖 Deprecations
* Deprecate `MatrixClient.getKeyBackupVersion` ([#4505](https://github.com/matrix-org/matrix-js-sdk/pull/4505)). Contributed by @florianduros.
* Deprecate unused callbacks in `CryptoCallbacks` ([#4501](https://github.com/matrix-org/matrix-js-sdk/pull/4501)). Contributed by @florianduros.
## ✨ Features
* Handle M\_MAX\_DELAY\_EXCEEDED errors ([#4511](https://github.com/matrix-org/matrix-js-sdk/pull/4511)). Contributed by @AndrewFerr.
* Allow configuration of MatrixRTC timers when calling joinRoomSession() ([#4510](https://github.com/matrix-org/matrix-js-sdk/pull/4510)). Contributed by @hughns.
* When state says you've left ongoing call, rejoin ([#4342](https://github.com/matrix-org/matrix-js-sdk/pull/4342)). Contributed by @AndrewFerr.
* Remove redundant type arguments in function call ([#4507](https://github.com/matrix-org/matrix-js-sdk/pull/4507)). Contributed by @AndrewFerr.
* MatrixRTCSession: handle rate limit errors ([#4494](https://github.com/matrix-org/matrix-js-sdk/pull/4494)). Contributed by @AndrewFerr.
* Send/receive error details with widgets ([#4492](https://github.com/matrix-org/matrix-js-sdk/pull/4492)). Contributed by @AndrewFerr.
* Capture HTTP error response headers \& handle Retry-After header (MSC4041) ([#4471](https://github.com/matrix-org/matrix-js-sdk/pull/4471)). Contributed by @AndrewFerr.
* Add RoomWidgetClient.sendToDeviceViaWidgetApi() ([#4475](https://github.com/matrix-org/matrix-js-sdk/pull/4475)). Contributed by @hughns.
Changes in [34.11.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.11.1) (2024-11-12)
====================================================================================================
# Security
- Fixes for [CVE-2024-50336](https://nvd.nist.gov/vuln/detail/CVE-2024-50336) / [GHSA-xvg8-m4x3-w6xr](https://github.com/matrix-org/matrix-js-sdk/security/advisories/GHSA-xvg8-m4x3-w6xr).
Changes in [34.11.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.11.0) (2024-11-12)
====================================================================================================
# Security
- Fixes for [CVE-2024-50336](https://nvd.nist.gov/vuln/detail/CVE-2024-50336) / [GHSA-xvg8-m4x3-w6xr](https://github.com/matrix-org/matrix-js-sdk/security/advisories/GHSA-xvg8-m4x3-w6xr).
Changes in [34.10.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.10.0) (2024-11-05)
====================================================================================================
## 🦖 Deprecations
* Deprecate `CreateSecretStorageOpts.keyBackupInfo` used in `CryptoApi.bootstrapSecretStorage.` ([#4474](https://github.com/matrix-org/matrix-js-sdk/pull/4474)). Contributed by @florianduros.
* Add CryptoApi.encryptToDeviceMessages() and deprecate Crypto.encryptAndSendToDevices() ([#4380](https://github.com/matrix-org/matrix-js-sdk/pull/4380)). Contributed by @hughns.
* Remove abandoned MSC3886, MSC3903, MSC3906 experimental implementations ([#4469](https://github.com/matrix-org/matrix-js-sdk/pull/4469)). Contributed by @t3chguy.
* Deprecate `MatrixClient.getDehydratedDevice` ([#4467](https://github.com/matrix-org/matrix-js-sdk/pull/4467)). Contributed by @florianduros.
* Deprecate top level crypto events re-export ([#4444](https://github.com/matrix-org/matrix-js-sdk/pull/4444)). Contributed by @florianduros.
## ✨ Features
* Add CryptoApi.encryptToDeviceMessages() and deprecate Crypto.encryptAndSendToDevices() ([#4380](https://github.com/matrix-org/matrix-js-sdk/pull/4380)). Contributed by @hughns.
* Do not rotate MatrixRTC media encryption key when a new member joins a session ([#4472](https://github.com/matrix-org/matrix-js-sdk/pull/4472)). Contributed by @hughns.
* Avoid `<sender>|<session>` notation in log messages ([#4473](https://github.com/matrix-org/matrix-js-sdk/pull/4473)). Contributed by @richvdh.
* Refactor/simplify Promises in MatrixRTCSession ([#4466](https://github.com/matrix-org/matrix-js-sdk/pull/4466)). Contributed by @AndrewFerr.
* Prepare delayed call leave events more reliably ([#4447](https://github.com/matrix-org/matrix-js-sdk/pull/4447)). Contributed by @AndrewFerr.
## 🐛 Bug Fixes
* Fix DelayedEventInfo type ([#4446](https://github.com/matrix-org/matrix-js-sdk/pull/4446)). Contributed by @AndrewFerr.
Changes in [34.9.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.9.0) (2024-10-22)
==================================================================================================
## 🦖 Deprecations
* Deprecate the crypto events which are not used by the rust-crypto ([#4442](https://github.com/matrix-org/matrix-js-sdk/pull/4442)). Contributed by @florianduros.
## 🐛 Bug Fixes
* Fix the rust crypto import in esm environments. ([#4445](https://github.com/matrix-org/matrix-js-sdk/pull/4445)). Contributed by @saul-jb.
* Fix MatrixRTC sender key wrapping ([#4441](https://github.com/matrix-org/matrix-js-sdk/pull/4441)). Contributed by @hughns.
Changes in [34.8.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.8.0) (2024-10-15)
==================================================================================================
This release removes insecure functionality, resolving CVE-2024-47080 / GHSA-4jf8-g8wp-cx7c.
Changes in [34.7.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.7.0) (2024-10-08)
==================================================================================================
## 🦖 Deprecations
* RTCSession cleanup: deprecate getKeysForParticipant() and getEncryption(); add emitEncryptionKeys() ([#4427](https://github.com/matrix-org/matrix-js-sdk/pull/4427)). Contributed by @hughns.
## ✨ Features
* Bump matrix-rust-sdk to 9.1.0 ([#4435](https://github.com/matrix-org/matrix-js-sdk/pull/4435)). Contributed by @richvdh.
* Rotate Matrix RTC media encryption key when a new member joins a call for Post Compromise Security ([#4422](https://github.com/matrix-org/matrix-js-sdk/pull/4422)). Contributed by @hughns.
* Update media event content types to include captions ([#4403](https://github.com/matrix-org/matrix-js-sdk/pull/4403)). Contributed by @tulir.
* Update OIDC registration types to match latest MSC2966 state ([#4432](https://github.com/matrix-org/matrix-js-sdk/pull/4432)). Contributed by @t3chguy.
* Add `CryptoApi.pinCurrentUserIdentity` and `UserIdentity.needsUserApproval` ([#4415](https://github.com/matrix-org/matrix-js-sdk/pull/4415)). Contributed by @richvdh.
Changes in [34.6.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.6.0) (2024-09-24)
==================================================================================================
## 🦖 Deprecations
* Element-R: Mark unsupported MatrixClient methods as deprecated ([#4389](https://github.com/matrix-org/matrix-js-sdk/pull/4389)). Contributed by @richvdh.
## ✨ Features
* Add crypto mode setting for invisible crypto, and apply it to decrypting events ([#4407](https://github.com/matrix-org/matrix-js-sdk/pull/4407)). Contributed by @uhoreg.
* Don't share full key history for RTC per-participant encryption ([#4406](https://github.com/matrix-org/matrix-js-sdk/pull/4406)). Contributed by @hughns.
* Export membership types ([#4405](https://github.com/matrix-org/matrix-js-sdk/pull/4405)). Contributed by @Johennes.
* Fix sending redacts in embedded (widget) mode ([#4398](https://github.com/matrix-org/matrix-js-sdk/pull/4398)). Contributed by @toger5.
* Expose the event ID of a call membership ([#4395](https://github.com/matrix-org/matrix-js-sdk/pull/4395)). Contributed by @robintown.
* MSC4133 - Extended profiles ([#4391](https://github.com/matrix-org/matrix-js-sdk/pull/4391)). Contributed by @Half-Shot.
Changes in [34.5.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.5.0) (2024-09-10)
==================================================================================================
## 🦖 Deprecations
* Deprecate unused callback hooks `CryptoCallbacks.onSecretRequested` and `CryptoCallbacks.getDehydrationKey` ([#4376](https://github.com/matrix-org/matrix-js-sdk/pull/4376)). Contributed by @richvdh.
Changes in [34.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.4.0) (2024-08-27)
==================================================================================================
## ✨ Features
* Use non-legacy calls if any are found ([#4337](https://github.com/matrix-org/matrix-js-sdk/pull/4337)). Contributed by @AndrewFerr.
## 🐛 Bug Fixes
* Retry event decryption failures on first failure ([#4346](https://github.com/matrix-org/matrix-js-sdk/pull/4346)). Contributed by @hughns.
* Ensure "type" = "module" ES declaration in pre-release.sh ([#4350](https://github.com/matrix-org/matrix-js-sdk/pull/4350)). Contributed by @BLCK-B.
* Handle MatrixRTC encryption keys arriving out of order ([#4345](https://github.com/matrix-org/matrix-js-sdk/pull/4345)). Contributed by @hughns.
* Resend MatrixRTC encryption keys if a membership has changed ([#4343](https://github.com/matrix-org/matrix-js-sdk/pull/4343)). Contributed by @hughns.
Changes in [34.3.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.3.1) (2024-08-20)
==================================================================================================
# Security
- Fixes for [CVE-2024-42369](https://nvd.nist.gov/vuln/detail/CVE-2024-42369) / [GHSA-vhr5-g3pm-49fm](https://github.com/matrix-org/matrix-js-sdk/security/advisories/GHSA-vhr5-g3pm-49fm).
Changes in [34.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.3.0) (2024-08-13)
==================================================================================================
## ✨ Features
* Bump matrix-widget-api ([#4336](https://github.com/matrix-org/matrix-js-sdk/pull/4336)). Contributed by @AndrewFerr.
* Also check for MSC3757 for session state keys ([#4334](https://github.com/matrix-org/matrix-js-sdk/pull/4334)). Contributed by @AndrewFerr.
* Support Futures via widgets ([#4311](https://github.com/matrix-org/matrix-js-sdk/pull/4311)). Contributed by @AndrewFerr.
* Support MSC4140: Delayed events (Futures) ([#4294](https://github.com/matrix-org/matrix-js-sdk/pull/4294)). Contributed by @AndrewFerr.
* Handle late-arriving `m.room_key.withheld` messages ([#4310](https://github.com/matrix-org/matrix-js-sdk/pull/4310)). Contributed by @richvdh.
* Be specific about what is considered a MSC4143 call member event. ([#4328](https://github.com/matrix-org/matrix-js-sdk/pull/4328)). Contributed by @toger5.
* Add index.ts for matrixrtc module ([#4314](https://github.com/matrix-org/matrix-js-sdk/pull/4314)). Contributed by @toger5.
## 🐛 Bug Fixes
* Fix hashed ID server lookups with no Olm ([#4333](https://github.com/matrix-org/matrix-js-sdk/pull/4333)). Contributed by @dbkr.
Changes in [34.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.2.0) (2024-07-30)
==================================================================================================
## 🐛 Bug Fixes
* Element-R: detect "withheld key" UTD errors, and mark them as such ([#4302](https://github.com/matrix-org/matrix-js-sdk/pull/4302)). Contributed by @richvdh.
Changes in [34.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.1.0) (2024-07-16)
==================================================================================================
## ✨ Features
* Add ability to choose how many timeline events to sync when peeking ([#4300](https://github.com/matrix-org/matrix-js-sdk/pull/4300)). Contributed by @jgarplind.
* Remove redundant hack for using the old pickle key in rust crypto ([#4282](https://github.com/matrix-org/matrix-js-sdk/pull/4282)). Contributed by @richvdh.
* Add fetching the well known in embedded mode. ([#4259](https://github.com/matrix-org/matrix-js-sdk/pull/4259)). Contributed by @toger5.
## 🐛 Bug Fixes
* Fix room state being updated with old (now overwritten) state and emitting for those updates. ([#4242](https://github.com/matrix-org/matrix-js-sdk/pull/4242)). Contributed by @toger5.
* Fix incorrect "Olm is not available" errors ([#4301](https://github.com/matrix-org/matrix-js-sdk/pull/4301)). Contributed by @richvdh.
* Fix build for example script ([#4286](https://github.com/matrix-org/matrix-js-sdk/pull/4286)). Contributed by @richvdh.
* Declare matrix-js-sdk as an ES module ([#4285](https://github.com/matrix-org/matrix-js-sdk/pull/4285)). Contributed by @richvdh.
Changes in [34.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v34.0.0) (2024-07-08)
==================================================================================================
## 🚨 BREAKING CHANGES
* Fetch capabilities in the background ([#4246](https://github.com/matrix-org/matrix-js-sdk/pull/4246)). Contributed by @dbkr.
## ✨ Features
* Prefix the user+device state key if needed ([#4262](https://github.com/matrix-org/matrix-js-sdk/pull/4262)). Contributed by @AndrewFerr.
* Use legacy call membership if anyone else is ([#4260](https://github.com/matrix-org/matrix-js-sdk/pull/4260)). Contributed by @AndrewFerr.
* Fetch capabilities in the background ([#4246](https://github.com/matrix-org/matrix-js-sdk/pull/4246)). Contributed by @dbkr.
* Use server name instead of homeserver url to allow well-known lookups during QR OIDC reciprocation ([#4233](https://github.com/matrix-org/matrix-js-sdk/pull/4233)). Contributed by @t3chguy.
* Add via parameter for MSC4156 ([#4247](https://github.com/matrix-org/matrix-js-sdk/pull/4247)). Contributed by @Johennes.
* Make the js-sdk compatible with MSC preferred foci and active focus. ([#4195](https://github.com/matrix-org/matrix-js-sdk/pull/4195)). Contributed by @toger5.
* Replace usages of setImmediate with setTimeout for wider compatibility ([#4240](https://github.com/matrix-org/matrix-js-sdk/pull/4240)). Contributed by @t3chguy.
## 🐛 Bug Fixes
* [Backport staging] Fix "Unable to restore session" error ([#4299](https://github.com/matrix-org/matrix-js-sdk/pull/4299)). Contributed by @RiotRobot.
* [Backport staging] Fix error when sending encrypted messages in large rooms ([#4297](https://github.com/matrix-org/matrix-js-sdk/pull/4297)). Contributed by @RiotRobot.
* Element-R: Fix resource leaks in verification logic ([#4263](https://github.com/matrix-org/matrix-js-sdk/pull/4263)). Contributed by @richvdh.
* Upgrade Rust Crypto SDK to 6.1.0 ([#4261](https://github.com/matrix-org/matrix-js-sdk/pull/4261)). Contributed by @richvdh.
* Correctly transform base64 with multiple instances of + or / ([#4252](https://github.com/matrix-org/matrix-js-sdk/pull/4252)). Contributed by @robintown.
* Work around spec bug for m.room.avatar state event content type ([#4245](https://github.com/matrix-org/matrix-js-sdk/pull/4245)). Contributed by @t3chguy.
Changes in [33.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v33.1.0) (2024-06-18)
==================================================================================================
## ✨ Features
* MSC4108 support OIDC QR code login ([#4134](https://github.com/matrix-org/matrix-js-sdk/pull/4134)). Contributed by @t3chguy.
* Add crypto methods for export and import of secrets bundle ([#4227](https://github.com/matrix-org/matrix-js-sdk/pull/4227)). Contributed by @t3chguy.
## 🐛 Bug Fixes
* Fix screen sharing in recent Chrome ([#4243](https://github.com/matrix-org/matrix-js-sdk/pull/4243)). Contributed by @RiotRobot.
* Fix incorrect assumptions about required fields in /search response ([#4228](https://github.com/matrix-org/matrix-js-sdk/pull/4228)). Contributed by @t3chguy.
* Fix the queueToDevice tests for the new fakeindexeddb ([#4225](https://github.com/matrix-org/matrix-js-sdk/pull/4225)). Contributed by @dbkr.
Changes in [33.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v33.0.0) (2024-06-04)
==================================================================================================
## 🚨 BREAKING CHANGES
* Remove more deprecated methods, fields, and exports ([#4217](https://github.com/matrix-org/matrix-js-sdk/pull/4217)). Contributed by @t3chguy.
* Remove deprecated methods and fields ([#4201](https://github.com/matrix-org/matrix-js-sdk/pull/4201)). Contributed by @t3chguy.
## 🦖 Deprecations
* Remove more deprecated methods, fields, and exports ([#4217](https://github.com/matrix-org/matrix-js-sdk/pull/4217)). Contributed by @t3chguy.
* Remove deprecated methods and fields ([#4201](https://github.com/matrix-org/matrix-js-sdk/pull/4201)). Contributed by @t3chguy.
## ✨ Features
* `initRustCrypto`: allow app to pass in the store key directly ([#4210](https://github.com/matrix-org/matrix-js-sdk/pull/4210)). Contributed by @richvdh.
* Preserve ESM for async imports to work correctly ([#4187](https://github.com/matrix-org/matrix-js-sdk/pull/4187)). Contributed by @ms-dosx86.
## 🐛 Bug Fixes
* Don't run migration for Rust crypto if the legacy store is empty ([#4218](https://github.com/matrix-org/matrix-js-sdk/pull/4218)). Contributed by @andybalaam.
* Bump matrix-sdk-crypto-wasm to 5.0.0 ([#4216](https://github.com/matrix-org/matrix-js-sdk/pull/4216)). Contributed by @richvdh.
* Wire up verification cancel \& mismatch for rust crypto ([#4202](https://github.com/matrix-org/matrix-js-sdk/pull/4202)). Contributed by @t3chguy.
* Only pass id\_server if we had one to begin with ([#4200](https://github.com/matrix-org/matrix-js-sdk/pull/4200)). Contributed by @t3chguy.
Changes in [32.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v32.4.0) (2024-05-22)
==================================================================================================
* No changes
Changes in [32.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v32.3.0) (2024-05-21)
==================================================================================================
## ✨ Features
* Simplify OIDC types \& export `decodeIdToken` ([#4193](https://github.com/matrix-org/matrix-js-sdk/pull/4193)). Contributed by @t3chguy.
* Add helpers for authenticated media, and associated documentation ([#4185](https://github.com/matrix-org/matrix-js-sdk/pull/4185)). Contributed by @turt2live.
## 🐛 Bug Fixes
* Fix state\_events.ts types ([#4196](https://github.com/matrix-org/matrix-js-sdk/pull/4196)). Contributed by @t3chguy.
* Fix sendEventHttpRequest for `m.room.redaction` events without `redacts` ([#4192](https://github.com/matrix-org/matrix-js-sdk/pull/4192)). Contributed by @t3chguy.
Changes in [32.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v32.2.0) (2024-05-07)
==================================================================================================
## ✨ Features
* Use a different error code for UTDs when user was not in the room ([#4172](https://github.com/matrix-org/matrix-js-sdk/pull/4172)). Contributed by @uhoreg.
* Modernize window.crypto access constants ([#4169](https://github.com/matrix-org/matrix-js-sdk/pull/4169)). Contributed by @turt2live.
* Improve compliance with MSC3266 ([#4155](https://github.com/matrix-org/matrix-js-sdk/pull/4155)). Contributed by @AndrewFerr.
* Add comment to make clear that RoomStateEvent.Events does not update related objects in the js-sdk ([#4152](https://github.com/matrix-org/matrix-js-sdk/pull/4152)). Contributed by @toger5.
* Crypto: use a new error code for UTDs from device-relative historical events ([#4139](https://github.com/matrix-org/matrix-js-sdk/pull/4139)). Contributed by @richvdh.
## 🐛 Bug Fixes
* Element-R: Fix rust migration when ssss secret are stored not encryted in cache (old legacy behavior) ([#4168](https://github.com/matrix-org/matrix-js-sdk/pull/4168)). Contributed by @BillCarsonFr.
Changes in [32.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v32.1.0) (2024-04-23)
==================================================================================================
## ✨ Features
* Add support for device dehydration v2 (Element R) ([#4062](https://github.com/matrix-org/matrix-js-sdk/pull/4062)). Contributed by @uhoreg.
* OIDC improvements in prep of OIDC-QR reciprocation ([#4149](https://github.com/matrix-org/matrix-js-sdk/pull/4149)). Contributed by @t3chguy.
## 🐛 Bug Fixes
* Validate backup private key before migrating it ([#4114](https://github.com/matrix-org/matrix-js-sdk/pull/4114)). Contributed by @BillCarsonFr.
* ElementR| Retry query backup until it works during migration to avoid spurious correption error popup ([#4113](https://github.com/matrix-org/matrix-js-sdk/pull/4113)). Contributed by @BillCarsonFr.
Changes in [32.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v32.0.0) (2024-04-09)
==================================================================================================
## 🚨 BREAKING CHANGES
* Remove various deprecated methods \& re-exports ([#4125](https://github.com/matrix-org/matrix-js-sdk/pull/4125)). Contributed by @t3chguy.
* Remove the logic that throws when the lazy loading options has changed. ([#4124](https://github.com/matrix-org/matrix-js-sdk/pull/4124)). Contributed by @langleyd.
* Fix highlights from threads disappearing on new messages ([#4106](https://github.com/matrix-org/matrix-js-sdk/pull/4106)). Contributed by @dbkr.
## ✨ Features
* Add new `decryptExistingEvent` test helper ([#4133](https://github.com/matrix-org/matrix-js-sdk/pull/4133)). Contributed by @richvdh.
* Improve types for `sendEvent` ([#4108](https://github.com/matrix-org/matrix-js-sdk/pull/4108)). Contributed by @t3chguy.
* Remove various deprecated methods \& re-exports ([#4125](https://github.com/matrix-org/matrix-js-sdk/pull/4125)). Contributed by @t3chguy.
* Add new enum for verification methods. ([#4129](https://github.com/matrix-org/matrix-js-sdk/pull/4129)). Contributed by @richvdh.
* Add some test utils in a new entrypoint ([#4127](https://github.com/matrix-org/matrix-js-sdk/pull/4127)). Contributed by @richvdh.
* Improve types for `sendStateEvent` ([#4105](https://github.com/matrix-org/matrix-js-sdk/pull/4105)). Contributed by @t3chguy.
## 🐛 Bug Fixes
* Improve types for `IPowerLevelsContent` and `hasSufficientPowerLevelFor` ([#4128](https://github.com/matrix-org/matrix-js-sdk/pull/4128)). Contributed by @galash13.
* Remove the logic that throws when the lazy loading options has changed. ([#4124](https://github.com/matrix-org/matrix-js-sdk/pull/4124)). Contributed by @langleyd.
* Fix highlights from threads disappearing on new messages ([#4106](https://github.com/matrix-org/matrix-js-sdk/pull/4106)). Contributed by @dbkr.
* Extend logic for local notification processing to threads ([#4111](https://github.com/matrix-org/matrix-js-sdk/pull/4111)). Contributed by @dbkr.
* Fix public rooms post request search params and body ([#4110](https://github.com/matrix-org/matrix-js-sdk/pull/4110)). Contributed by @ajbura.
* Fix bugs with the first reply to a thread ([#4104](https://github.com/matrix-org/matrix-js-sdk/pull/4104)). Contributed by @dbkr.
Changes in [31.6.1](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v31.6.1) (2024-03-28)
==================================================================================================
## 🐛 Bug Fixes
* Fix merging of default push rules ([#4136](https://github.com/matrix-org/matrix-js-sdk/pull/4136)).
Changes in [31.6.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v31.6.0) (2024-03-26)
==================================================================================================
## ✨ Features
* Introduce Membership TS type (take 2) ([#4107](https://github.com/matrix-org/matrix-js-sdk/pull/4107)). Contributed by @andybalaam.
* fix automatic DM avatar with functional members ([#4017](https://github.com/matrix-org/matrix-js-sdk/pull/4017)). Contributed by @HarHarLinks.
* Export types describing all specced media event formats ([#4092](https://github.com/matrix-org/matrix-js-sdk/pull/4092)). Contributed by @t3chguy.
* Add `.m.rule.is_room_mention` push rule to DEFAULT\_OVERRIDE\_RULES ([#4100](https://github.com/matrix-org/matrix-js-sdk/pull/4100)). Contributed by @t3chguy.
* Make sending ContentLoaded optional for a widgetClient ([#4086](https://github.com/matrix-org/matrix-js-sdk/pull/4086)). Contributed by @toger5.
## 🐛 Bug Fixes
* Migrate own identity local trust to rust crypto ([#4090](https://github.com/matrix-org/matrix-js-sdk/pull/4090)). Contributed by @BillCarsonFr.
* Fix race condition with sliding sync extensions ([#4089](https://github.com/matrix-org/matrix-js-sdk/pull/4089)). Contributed by @zzorba.
Changes in [31.5.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v31.5.0) (2024-03-12)
==================================================================================================
## ✨ Features
* Update MSC2965 OIDC Discovery implementation ([#4064](https://github.com/matrix-org/matrix-js-sdk/pull/4064)). Contributed by @t3chguy.
## 🐛 Bug Fixes
* Add basic retry for rust crypto outgoing requests ([#4061](https://github.com/matrix-org/matrix-js-sdk/pull/4061)). Contributed by @BillCarsonFr.
Changes in [31.4.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v31.4.0) (2024-02-27)
==================================================================================================
## ✨ Features
* Validate `account_management_uri` and `account_management_actions_supported` from OIDC Issuer well-known ([#4074](https://github.com/matrix-org/matrix-js-sdk/pull/4074)). Contributed by @t3chguy.
* Allow specifying OIDC url state parameter for passing data to callback ([#4068](https://github.com/matrix-org/matrix-js-sdk/pull/4068)). Contributed by @t3chguy.
* Add getAuthIssuer method for MSC2965 ([#4071](https://github.com/matrix-org/matrix-js-sdk/pull/4071)). Contributed by @t3chguy.
* Allow specifying more OIDC client metadata for dynamic registration ([#4070](https://github.com/matrix-org/matrix-js-sdk/pull/4070)). Contributed by @t3chguy.
* Add unread marker event type ([#4069](https://github.com/matrix-org/matrix-js-sdk/pull/4069)). Contributed by @dbkr.
* Add "AsJson" forms of the key import/export methods ([#4057](https://github.com/matrix-org/matrix-js-sdk/pull/4057)). Contributed by @andybalaam.
## 🐛 Bug Fixes
* Ignore memberships of users that are not in the call ([#4065](https://github.com/matrix-org/matrix-js-sdk/pull/4065)). Contributed by @toger5.
* Await encrypted messages ([#4063](https://github.com/matrix-org/matrix-js-sdk/pull/4063)). Contributed by @toger5.
* ElementR | Ensure own user and device trust are updated after migration before giving back control to the app. ([#4059](https://github.com/matrix-org/matrix-js-sdk/pull/4059)). Contributed by @BillCarsonFr.
* Bump matrix-sdk-crypto-wasm to 4.5.0 ([#4060](https://github.com/matrix-org/matrix-js-sdk/pull/4060)). Contributed by @andybalaam.
Changes in [31.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v31.3.0) (2024-02-13)
==================================================================================================
## ✨ Features
* Add expire\_ts compatibility to matrixRTC ([#4032](https://github.com/matrix-org/matrix-js-sdk/pull/4032)). Contributed by @toger5.
* Element-R: support for migration of the room list from legacy crypto ([#4036](https://github.com/matrix-org/matrix-js-sdk/pull/4036)). Contributed by @richvdh.
* Element-R: check persistent room list for encryption config ([#4035](https://github.com/matrix-org/matrix-js-sdk/pull/4035)). Contributed by @richvdh.
* Support optional MSC3860 redirects ([#4007](https://github.com/matrix-org/matrix-js-sdk/pull/4007)). Contributed by @turt2live.
## 🐛 Bug Fixes
* WebR: migrate the megolm session imported flag ([#4037](https://github.com/matrix-org/matrix-js-sdk/pull/4037)). Contributed by @BillCarsonFr.
* ElementR: fix emoji verification stalling when both ends hit start at the same time ([#4004](https://github.com/matrix-org/matrix-js-sdk/pull/4004)). Contributed by @uhoreg.
* Dependencies: Bump wasm bindings version to 4.3.0 ([#4042](https://github.com/matrix-org/matrix-js-sdk/pull/4042)). Contributed by @BillCarsonFr.
* Element R: emit events when devices have changed ([#4019](https://github.com/matrix-org/matrix-js-sdk/pull/4019)). Contributed by @uhoreg.
* ElementR: report invalid keys rather than failing to restore from backup ([#4006](https://github.com/matrix-org/matrix-js-sdk/pull/4006)). Contributed by @uhoreg.
* Make `timeline` a getter ([#4022](https://github.com/matrix-org/matrix-js-sdk/pull/4022)). Contributed by @florianduros.
* Implement getting verification cancellation info in Rust crypto ([#3947](https://github.com/matrix-org/matrix-js-sdk/pull/3947)). Contributed by @uhoreg.
* Fix crypto migration for megolm sessions with no sender key ([#4024](https://github.com/matrix-org/matrix-js-sdk/pull/4024)). Contributed by @richvdh.
Changes in [31.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v31.2.0) (2024-01-31)
==================================================================================================
## ✨ Features
* Emit events during migration from libolm ([#3982](https://github.com/matrix-org/matrix-js-sdk/pull/3982)). Contributed by @richvdh.
* Support for migration from from libolm ([#3978](https://github.com/matrix-org/matrix-js-sdk/pull/3978)). Contributed by @richvdh.
## 🐛 Bug Fixes
* ElementR | backup: call expensive `roomKeyCounts` less often ([#4015](https://github.com/matrix-org/matrix-js-sdk/pull/4015)). Contributed by @BillCarsonFr.
* Decrypt and Import full backups in chunk with progress ([#4005](https://github.com/matrix-org/matrix-js-sdk/pull/4005)). Contributed by @BillCarsonFr.
* Fix new threads not appearing. ([#4009](https://github.com/matrix-org/matrix-js-sdk/pull/4009)). Contributed by @dbkr.
Changes in [31.1.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v31.1.0) (2024-01-19)
==================================================================================================
## ✨ Features
* Broaden spec version support ([#4016](https://github.com/matrix-org/matrix-js-sdk/pull/4016)). Contributed by @RiotRobot.
Changes in [31.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v31.0.0) (2024-01-16)
==================================================================================================
## 🚨 BREAKING CHANGES
* Bump minimum spec version to v1.5 ([#3970](https://github.com/matrix-org/matrix-js-sdk/pull/3970)). Contributed by @richvdh.
## ✨ Features
* Bump minimum spec version to v1.5 ([#3970](https://github.com/matrix-org/matrix-js-sdk/pull/3970)). Contributed by @richvdh.
* Send authenticated /versions request ([#3968](https://github.com/matrix-org/matrix-js-sdk/pull/3968)). Contributed by @dbkr.
## 🐛 Bug Fixes
* Revert "Bump matrix-sdk-crypto-wasm to 3.6.0" ([#3991](https://github.com/matrix-org/matrix-js-sdk/pull/3991)). Contributed by @andybalaam.
* #22606 Fix "Remove" button to users without "m.room.redaction" ([#3981](https://github.com/matrix-org/matrix-js-sdk/pull/3981)). Contributed by @rashmitpankhania.
* ElementR: Ensure Encryption order per room ([#3973](https://github.com/matrix-org/matrix-js-sdk/pull/3973)). Contributed by @BillCarsonFr.
* Element-R: fix `bootstrapSecretStorage` not resetting key backup when requested ([#3976](https://github.com/matrix-org/matrix-js-sdk/pull/3976)). Contributed by @uhoreg.
Changes in [30.3.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v30.3.0) (2023-12-19)
==================================================================================================
## ✨ Features
* Element-R: disable sending room key requests ([#3939](https://github.com/matrix-org/matrix-js-sdk/pull/3939)). Contributed by @richvdh.
## 🐛 Bug Fixes
* Fix notifications appearing for old events ([#3946](https://github.com/matrix-org/matrix-js-sdk/pull/3946)). Contributed by @dbkr.
* Don't back up keys that we got from backup ([#3934](https://github.com/matrix-org/matrix-js-sdk/pull/3934)). Contributed by @uhoreg.
* Fix upload with empty Content-Type ([#3918](https://github.com/matrix-org/matrix-js-sdk/pull/3918)). Contributed by @JakubOnderka.
* Prevent phantom notifications from events not in a room's timeline ([#3942](https://github.com/matrix-org/matrix-js-sdk/pull/3942)). Contributed by @dbkr.
Changes in [30.2.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v30.2.0) (2023-12-05)
==================================================================================================
## ✨ Features
@@ -36,6 +586,7 @@ Changes in [30.0.0](https://github.com/matrix-org/matrix-js-sdk/releases/tag/v30
## 🚨 BREAKING CHANGES
* Refactor & make base64 functions browser-safe ([\#3818](https://github.com/matrix-org/matrix-js-sdk/pull/3818)).
* `IndexedDBStore.startup()` must be called after using it on `sdk.createClient` now.
## 🦖 Deprecations
* Deprecate `MatrixEvent.toJSON` ([\#3801](https://github.com/matrix-org/matrix-js-sdk/pull/3801)).
+199 -108
View File
@@ -21,15 +21,9 @@ endpoints from before Matrix 1.1, for example.
# Quickstart
## In a browser
### 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.
If you wish to use a ponyfill or adapter of some sort then pass it as `fetchFn` to the MatrixClient constructor options.
> [!IMPORTANT]
> Servers may require or use authenticated endpoints for media (images, files, avatars, etc). See the
> [Authenticated Media](#authenticated-media) section for information on how to enable support for this.
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.
@@ -44,10 +38,8 @@ client.publicRooms(function (err, 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.
See [below](#end-to-end-encryption-support) for how to enable end-to-end-encryption, or check
[the Node.js terminal app](https://github.com/matrix-org/matrix-js-sdk/tree/develop/examples/node) for a more complex example.
To start the client:
@@ -58,7 +50,7 @@ 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) {
client.once(ClientEvent.sync, function (state, prevState, res) {
if (state === "PREPARED") {
console.log("prepared");
} else {
@@ -83,7 +75,7 @@ client.sendEvent("roomId", "m.room.message", content, "", (err, res) => {
To listen for message events:
```javascript
client.on("Room.timeline", function (event, room, toStartOfTimeline) {
client.on(RoomEvent.Timeline, function (event, room, toStartOfTimeline) {
if (event.getType() !== "m.room.message") {
return; // only use messages
}
@@ -101,55 +93,83 @@ Object.keys(client.store.rooms).forEach((roomId) => {
});
```
## Authenticated media
Servers supporting [MSC3916](https://github.com/matrix-org/matrix-spec-proposals/pull/3916) (Matrix 1.11) will require clients, like
yours, to include an `Authorization` header when `/download`ing or `/thumbnail`ing media. For NodeJS environments this
may be as easy as the following code snippet, though web browsers may need to use [Service Workers](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API)
to append the header when using the endpoints in `<img />` elements and similar.
```javascript
const downloadUrl = client.mxcUrlToHttp(
/*mxcUrl=*/ "mxc://example.org/abc123", // the MXC URI to download/thumbnail, typically from an event or profile
/*width=*/ undefined, // part of the thumbnail API. Use as required.
/*height=*/ undefined, // part of the thumbnail API. Use as required.
/*resizeMethod=*/ undefined, // part of the thumbnail API. Use as required.
/*allowDirectLinks=*/ false, // should generally be left `false`.
/*allowRedirects=*/ true, // implied supported with authentication
/*useAuthentication=*/ true, // the flag we're after in this example
);
const img = await fetch(downloadUrl, {
headers: {
Authorization: `Bearer ${client.getAccessToken()}`,
},
});
// Do something with `img`.
```
> [!WARNING]
> In future the js-sdk will _only_ return authentication-required URLs, mandating population of the `Authorization` header.
## 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.
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)
- Handles syncing (via `/sync`)
- 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.
# Usage
## Conventions
## Supported platforms
### Emitted events
`matrix-js-sdk` can be used in either Node.js applications (ensure you have the latest LTS version of Node.js installed),
or in browser applications, via a bundler such as Webpack or Vite.
The SDK will emit events using an `EventEmitter`. It also
emits object models (e.g. `Rooms`, `RoomMembers`) when they
are updated.
You can also use the sdk with [Deno](https://deno.land/) (`import npm:matrix-js-sdk`) but its not officialy supported.
## Emitted events
The SDK raises notifications to the application using
[`EventEmitter`s](https://nodejs.org/api/events.html#class-eventemitter). The `MatrixClient` itself
implements `EventEmitter`, as do many of the high-level abstractions such as `Room` and `RoomMember`.
```javascript
// Listen for low-level MatrixEvents
client.on("event", function (event) {
client.on(ClientEvent.Event, function (event) {
console.log(event.getType());
});
// Listen for typing changes
client.on("RoomMember.typing", function (event, member) {
client.on(RoomMemberEvent.Typing, function (event, member) {
if (member.typing) {
console.log(member.name + " is typing...");
} else {
@@ -161,41 +181,22 @@ client.on("RoomMember.typing", function (event, member) {
client.startClient();
```
### Promises and Callbacks
## Entry points
Most of the methods in the SDK are asynchronous: they do not directly return a
result, but instead return a [Promise](http://documentup.com/kriskowal/q/)
which will be fulfilled in the future.
As well as the primary entry point (`matrix-js-sdk`), there are several other entry points which may be useful:
The typical usage is something like:
```javascript
matrixClient.someMethod(arg1, arg2).then(function(result) {
...
});
```
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);
```
The main thing to note is that it is problematic to discard the result of a
promise-returning function, as that will cause exceptions to go unobserved.
Methods which return a promise show this in their documentation.
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.
| Entry point | Description |
| ------------------------------ | --------------------------------------------------------------------------------------------------- |
| `matrix-js-sdk` | Primary entry point. High-level functionality, and lots of historical clutter in need of a cleanup. |
| `matrix-js-sdk/lib/crypto-api` | Cryptography functionality. |
| `matrix-js-sdk/lib/types` | Low-level types, reflecting data structures defined in the Matrix spec. |
| `matrix-js-sdk/lib/testing` | Test utilities, which may be useful in test code but should not be used in production code. |
| `matrix-js-sdk/lib/utils/*.js` | A set of modules exporting standalone functions (and their types). |
## 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:
core functionality of the SDK. These examples assume the SDK is set up like this:
```javascript
import * as sdk from "matrix-js-sdk";
@@ -211,10 +212,10 @@ const matrixClient = sdk.createClient({
### 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(RoomEvent.MyMembership, function (room, membership, prevMembership) {
if (membership === KnownMembership.Invite) {
matrixClient.joinRoom(room.roomId).then(function () {
console.log("Auto-joined %s", room.roomId);
});
}
});
@@ -225,7 +226,7 @@ matrixClient.startClient();
### Print out messages for all rooms
```javascript
matrixClient.on("Room.timeline", function (event, room, toStartOfTimeline) {
matrixClient.on(RoomEvent.Timeline, function (event, room, toStartOfTimeline) {
if (toStartOfTimeline) {
return; // don't print paginated results
}
@@ -257,7 +258,7 @@ Output:
### Print out membership lists whenever they are changed
```javascript
matrixClient.on("RoomState.members", function (event, state, member) {
matrixClient.on(RoomStateEvent.Members, function (event, state, member) {
const room = matrixClient.getRoom(state.roomId);
if (!room) {
return;
@@ -294,7 +295,7 @@ host the API reference from the source files like this:
```
$ yarn gendoc
$ cd _docs
$ cd docs
$ python -m http.server 8005
```
@@ -302,41 +303,131 @@ Then visit `http://localhost:8005` to see the API docs.
# 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.
`matrix-js-sdk`'s end-to-end encryption support is based on the [WebAssembly bindings](https://github.com/matrix-org/matrix-rust-sdk-crypto-wasm) of the Rust [matrix-sdk-crypto](https://github.com/matrix-org/matrix-rust-sdk/tree/main/crates/matrix-sdk-crypto) library.
It is also necessary to call `await matrixClient.initCrypto()` after creating a new
`MatrixClient` (but **before** calling `matrixClient.startClient()`) to
initialise the crypto layer.
## Initialization
If the `Olm` global is not available, the SDK will show a warning, as shown
below; `initCrypto()` will also fail.
**Do not use `matrixClient.initLegacyCrypto()`. This method is deprecated and no longer maintained.**
```
Unable to load crypto module: crypto will be disabled: Error: global.Olm is not defined
To initialize the end-to-end encryption support in the matrix client:
```javascript
// Create a new matrix client
const matrixClient = sdk.createClient({
baseUrl: "http://localhost:8008",
accessToken: myAccessToken,
userId: myUserId,
});
// Initialize to enable end-to-end encryption support.
await matrixClient.initRustCrypto();
```
If the crypto layer is not (successfully) initialised, the SDK will continue to
work for unencrypted rooms, but it will not support the E2E parts of the Matrix
specification.
After calling `initRustCrypto`, you can obtain a reference to the [`CryptoApi`](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoApi.html) interface, which is the main entry point for end-to-end encryption, by calling [`MatrixClient.getCrypto`](https://matrix-org.github.io/matrix-js-sdk/classes/matrix.MatrixClient.html#getCrypto).
To provide the Olm library in a browser application:
**WARNING**: the cryptography stack is not thread-safe. Having multiple `MatrixClient` instances connected to the same Indexed DB will cause data corruption and decryption failures. The application layer is responsible for ensuring that only one `MatrixClient` issue is instantiated at a time.
- download the transpiled libolm (from https://packages.matrix.org/npm/olm/).
- load `olm.js` as a `<script>` _before_ `browser-matrix.js`.
## Secret storage
To provide the Olm library in a node.js application:
You should normally set up [secret storage](https://spec.matrix.org/v1.12/client-server-api/#secret-storage) before using the end-to-end encryption. To do this, call [`CryptoApi.bootstrapSecretStorage`](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoApi.html#bootstrapSecretStorage).
`bootstrapSecretStorage` can be called unconditionally: it will only set up the secret storage if it is not already set up (unless you use the `setupNewSecretStorage` parameter).
- `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`.
```javascript
const matrixClient = sdk.createClient({
...,
cryptoCallbacks: {
getSecretStorageKey: async (keys) => {
// This function should prompt the user to enter their secret storage key.
return mySecretStorageKeys;
},
},
});
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
as an optional dependency.
matrixClient.getCrypto().bootstrapSecretStorage({
// This function will be called if a new secret storage key (aka recovery key) is needed.
// You should prompt the user to save the key somewhere, because they will need it to unlock secret storage in future.
createSecretStorageKey: async () => {
return mySecretStorageKey;
},
});
```
The example above will create a new secret storage key if secret storage was not previously set up.
The secret storage data will be encrypted using the secret storage key returned in [`createSecretStorageKey`](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CreateSecretStorageOpts.html#createSecretStorageKey).
We recommend that you prompt the user to re-enter this key when [`CryptoCallbacks.getSecretStorageKey`](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoCallbacks.html#getSecretStorageKey) is called (when the secret storage access is needed).
## Set up cross-signing
To set up cross-signing to verify devices and other users, call
[`CryptoApi.bootstrapCrossSigning`](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoApi.html#bootstrapCrossSigning):
```javascript
matrixClient.getCrypto().bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (makeRequest) => {
return makeRequest(authDict);
},
});
```
The [`authUploadDeviceSigningKeys`](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.BootstrapCrossSigningOpts.html#authUploadDeviceSigningKeys)
callback is required in order to upload newly-generated public cross-signing keys to the server.
## Key backup
If the user doesn't already have a [key backup](https://spec.matrix.org/v1.12/client-server-api/#server-side-key-backups) you should create one:
```javascript
// Check if we have a key backup.
// If checkKeyBackupAndEnable returns null, there is no key backup.
const hasKeyBackup = (await matrixClient.getCrypto().checkKeyBackupAndEnable()) !== null;
// Create the key backup
await matrixClient.getCrypto().resetKeyBackup();
```
## Verify a new device
Once the cross-signing is set up on one of your devices, you can verify another device with two methods:
1. Use `CryptoApi.bootstrapCrossSigning`.
`bootstrapCrossSigning` will call the [CryptoCallbacks.getSecretStorageKey](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoCallbacks.html#getSecretStorageKey) callback. The device is verified with the private cross-signing keys fetched from the secret storage.
2. Request an interactive verification against existing devices, by calling [CryptoApi.requestOwnUserVerification](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoApi.html#requestOwnUserVerification).
## Migrating from the legacy crypto stack to Rust crypto
If your application previously used the legacy crypto stack, (i.e, it called `MatrixClient.initLegacyCrypto()`), you will
need to migrate existing devices to the Rust crypto stack.
This migration happens automatically when you call `initRustCrypto()` instead of `initLegacyCrypto()`,
but you need to provide the legacy [`cryptoStore`](https://matrix-org.github.io/matrix-js-sdk/interfaces/matrix.ICreateClientOpts.html#cryptoStore) and [`pickleKey`](https://matrix-org.github.io/matrix-js-sdk/interfaces/matrix.ICreateClientOpts.html#pickleKey) to [`createClient`](https://matrix-org.github.io/matrix-js-sdk/functions/matrix.createClient.html):
```javascript
// You should provide the legacy crypto store and the pickle key to the matrix client in order to migrate the data.
const matrixClient = sdk.createClient({
cryptoStore: myCryptoStore,
pickleKey: myPickleKey,
baseUrl: "http://localhost:8008",
accessToken: myAccessToken,
userId: myUserId,
});
// The migration will be done automatically when you call `initRustCrypto`.
await matrixClient.initRustCrypto();
```
To follow the migration progress, you can listen to the [`CryptoEvent.LegacyCryptoStoreMigrationProgress`](https://matrix-org.github.io/matrix-js-sdk/enums/crypto_api.CryptoEvent.html#LegacyCryptoStoreMigrationProgress) event:
```javascript
// When progress === total === -1, the migration is finished.
matrixClient.on(CryptoEvent.LegacyCryptoStoreMigrationProgress, (progress, total) => {
...
});
```
The Rust crypto stack is not supported in a lot of deprecated methods of [`MatrixClient`](https://matrix-org.github.io/matrix-js-sdk/classes/matrix.MatrixClient.html). If you use them, you should migrate to the [`CryptoApi`](https://matrix-org.github.io/matrix-js-sdk/interfaces/crypto_api.CryptoApi.html). Also, the legacy `MatrixClient.crypto` object is not available any more: you should use `MatrixClient.getCrypto()` instead.
# Contributing
+52
View File
@@ -0,0 +1,52 @@
module.exports = {
sourceMaps: true,
presets: [
[
"@babel/preset-env",
{
targets: {
esmodules: true,
},
// We want to output ES modules for the final build (mostly to ensure that
// async imports work correctly). However, jest doesn't support ES modules very
// well yet (see https://github.com/jestjs/jest/issues/9430), so we use commonjs
// when testing.
modules: process.env.NODE_ENV === "test" ? "commonjs" : false,
},
],
[
"@babel/preset-typescript",
{
// When using the transpiled javascript in `lib`, Node.js requires `.js` extensions on any `import`
// specifiers. However, Jest uses the TS source (via babel) and fails to resolve the `.js` names.
// To resolve this,we use the `.ts` names in the source, and rewrite the `import` specifiers to use
// `.js` during transpilation, *except* when we are targetting Jest.
rewriteImportExtensions: process.env.NODE_ENV !== "test",
},
],
],
plugins: [
"@babel/plugin-transform-numeric-separator",
"@babel/plugin-transform-class-properties",
"@babel/plugin-transform-object-rest-spread",
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-transform-runtime",
[
"search-and-replace",
{
// Since rewriteImportExtensions doesn't work on dynamic imports (yet), we need to manually replace
// the dynamic rust-crypto import.
// (see https://github.com/babel/babel/issues/16750)
rules:
process.env.NODE_ENV !== "test"
? [
{
search: "./rust-crypto/index.ts",
replace: "./rust-crypto/index.js",
},
]
: [],
},
],
],
};
+3 -4
View File
@@ -1,9 +1,8 @@
# Summary
- [Introduction](../README.md)
- [Introduction](../README.md)
# Deep dive
- [Release Process](release.md)
- [Storage notes](storage-notes.md)
- [Unverified devices](warning-on-unverified-devices.md)
- [Storage notes](storage-notes.md)
- [Unverified devices](warning-on-unverified-devices.md)
-24
View File
@@ -1,24 +0,0 @@
# 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
+7 -7
View File
@@ -17,13 +17,13 @@ Warn when you initial sync if the room has any new undefined devices since you w
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.
...this should be good enough.
- 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.
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.
- 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.
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?
+25 -26
View File
@@ -1,9 +1,15 @@
import clc from "cli-color";
import fs from "fs";
import readline from "readline";
import sdk, { ClientEvent, EventType, MsgType, RoomEvent } from "matrix-js-sdk";
import { KnownMembership } from "matrix-js-sdk/lib/@types/membership.js";
var myHomeServer = "http://localhost:8008";
var myUserId = "@example:localhost";
var myAccessToken = "QGV4YW1wbGU6bG9jYWxob3N0.qPEvLuYfNBjxikiCjP";
var sdk = require("matrix-js-sdk");
var clc = require("cli-color");
var matrixClient = sdk.createClient({
baseUrl: "http://localhost:8008",
baseUrl: myHomeServer,
accessToken: myAccessToken,
userId: myUserId,
});
@@ -15,7 +21,6 @@ var numMessagesToShow = 20;
// Reading from stdin
var CLEAR_CONSOLE = "\x1B[2J";
var readline = require("readline");
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
@@ -89,20 +94,14 @@ rl.on("line", function (line) {
);
} 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);
let buffer = fs.readFileSync("./your_file_name");
matrixClient.uploadContent(new Blob([buffer])).then(function (response) {
matrixClient.sendMessage(viewingRoom.roomId, {
msgtype: MsgType.File,
body: filename,
url: response.content_uri,
});
});
} else {
matrixClient.sendTextMessage(viewingRoom.roomId, line).finally(function () {
printMessages();
@@ -115,7 +114,7 @@ rl.on("line", function (line) {
if (line.indexOf("/join ") === 0) {
var roomIndex = line.split(" ")[1];
viewingRoom = roomList[roomIndex];
if (viewingRoom.getMember(myUserId).membership === "invite") {
if (viewingRoom.getMember(myUserId).membership === KnownMembership.Invite) {
// join the room first
matrixClient.joinRoom(viewingRoom.roomId).then(
function (room) {
@@ -138,7 +137,7 @@ rl.on("line", function (line) {
// ==== END User input
// show the room list after syncing.
matrixClient.on("sync", function (state, prevState, data) {
matrixClient.on(ClientEvent.Sync, function (state, prevState, data) {
switch (state) {
case "PREPARED":
setRoomList();
@@ -149,7 +148,7 @@ matrixClient.on("sync", function (state, prevState, data) {
}
});
matrixClient.on("Room", function () {
matrixClient.on(ClientEvent.Room, function () {
setRoomList();
if (!viewingRoom) {
printRoomList();
@@ -158,11 +157,11 @@ matrixClient.on("Room", function () {
});
// print incoming messages.
matrixClient.on("Room.timeline", function (event, room, toStartOfTimeline) {
matrixClient.on(RoomEvent.Timeline, function (event, room, toStartOfTimeline) {
if (toStartOfTimeline) {
return; // don't print paginated results
}
if (!viewingRoom || viewingRoom.roomId !== room.roomId) {
if (!viewingRoom || viewingRoom.roomId !== room?.roomId) {
return; // not viewing a room or viewing the wrong room.
}
printLine(event);
@@ -305,7 +304,7 @@ function printRoomInfo(room) {
print(eTypeHeader + sendHeader + contentHeader);
print(new Array(100).join("-"));
eventMap.keys().forEach(function (eventType) {
if (eventType === "m.room.member") {
if (eventType === EventType.RoomMember) {
return;
} // use /members instead.
var eventEventMap = eventMap.get(eventType);
@@ -343,7 +342,7 @@ function printLine(event) {
name = name.slice(0, maxNameWidth - 1) + "\u2026";
}
if (event.getType() === "m.room.message") {
if (event.getType() === EventType.RoomMessage) {
body = event.getContent().body;
} else if (event.isState()) {
var stateName = event.getType();
@@ -381,7 +380,7 @@ function print(str, formatter) {
}
console.log.apply(console.log, newArgs);
} else {
console.log.apply(console.log, arguments);
console.log.apply(console.log, [...arguments]);
}
}
@@ -394,4 +393,4 @@ function fixWidth(str, len) {
return str;
}
matrixClient.startClient(numMessagesToShow); // messages for each room.
matrixClient.startClient({ initialSyncLimit: numMessagesToShow });
+10 -4
View File
@@ -3,12 +3,18 @@
"version": "0.0.0",
"description": "",
"main": "app.js",
"scripts": {
"preinstall": "npm install ../.."
},
"author": "",
"license": "Apache 2.0",
"type": "module",
"dependencies": {
"cli-color": "^1.0.0"
"cli-color": "^1.0.0",
"matrix-js-sdk": "^34.5.0"
},
"devDependencies": {
"@types/cli-color": "^2.0.6",
"typescript": "^5.6.2"
},
"engines": {
"node": ">=20.0.0"
}
}
+14
View File
@@ -0,0 +1,14 @@
{
"compilerOptions": {
"target": "es2022",
"module": "commonjs",
"esModuleInterop": true,
"noImplicitAny": false,
"noEmit": true,
"skipLibCheck": true,
"allowJs": true,
"checkJs": true,
"strict": true
},
"include": ["app.js"]
}
+1 -1
View File
@@ -39,7 +39,7 @@ if (env["GITHUB_ACTIONS"] !== undefined) {
// 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");
reporters.push("<rootDir>/spec/slowReporter.cjs");
}
config.reporters = reporters;
}
+48
View File
@@ -0,0 +1,48 @@
import { KnipConfig } from "knip";
export default {
entry: [
"src/index.ts",
"src/types.ts",
"src/browser-index.ts",
"src/indexeddb-worker.ts",
"src/crypto-api/index.ts",
"src/testing.ts",
"src/matrix.ts",
"scripts/**",
"spec/**",
// XXX: these look entirely unused
"src/crypto/aes.ts",
"src/crypto/crypto.ts",
"src/crypto/recoverykey.ts",
// XXX: these should be re-exported by one of the supported exports
"src/matrixrtc/index.ts",
"src/sliding-sync.ts",
"src/webrtc/groupCall.ts",
"src/webrtc/stats/media/mediaTrackStats.ts",
"src/rendezvous/RendezvousChannel.ts",
],
project: ["**/*.{js,ts}"],
ignore: ["examples/**"],
ignoreDependencies: [
// Required for `action-validator`
"@action-validator/*",
// Used for git pre-commit hooks
"husky",
// Used in script which only runs in environment with `@octokit/rest` installed
"@octokit/rest",
// Used by jest
"jest-environment-jsdom",
"babel-jest",
"ts-node",
// Used by `@babel/plugin-transform-runtime`
"@babel/runtime",
],
ignoreBinaries: [
// Used when available by reusable workflow `.github/workflows/release-make.yml`
"dist",
],
ignoreExportsUsedInFile: true,
includeEntryExports: false,
exclude: ["enumMembers"],
} satisfies KnipConfig;
+46 -49
View File
@@ -1,12 +1,12 @@
{
"name": "matrix-js-sdk",
"version": "30.2.0",
"version": "36.2.0",
"description": "Matrix Client-Server SDK for Javascript",
"engines": {
"node": ">=18.0.0"
"node": ">=20.0.0"
},
"scripts": {
"prepublishOnly": "yarn build",
"prepack": "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",
@@ -16,9 +16,10 @@
"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:js-fix": "prettier --log-level=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 \"{}\"'",
"lint:knip": "knip",
"test": "jest",
"test:watch": "jest --watch",
"coverage": "yarn test --coverage"
@@ -30,13 +31,10 @@
"keywords": [
"matrix-org"
],
"type": "module",
"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",
"typings": "./lib/index.d.ts",
"author": "matrix.org",
"license": "Apache-2.0",
"files": [
@@ -52,86 +50,85 @@
],
"dependencies": {
"@babel/runtime": "^7.12.5",
"@matrix-org/matrix-sdk-crypto-wasm": "^3.1.0",
"@matrix-org/matrix-sdk-crypto-wasm": "^13.0.0",
"@matrix-org/olm": "3.2.15",
"another-json": "^0.2.0",
"bs58": "^5.0.0",
"bs58": "^6.0.0",
"content-type": "^1.0.4",
"jwt-decode": "^3.1.2",
"jwt-decode": "^4.0.0",
"loglevel": "^1.7.1",
"matrix-events-sdk": "0.0.1",
"matrix-widget-api": "^1.6.0",
"oidc-client-ts": "^2.2.4",
"matrix-widget-api": "^1.10.0",
"oidc-client-ts": "^3.0.1",
"p-retry": "4",
"sdp-transform": "^2.14.1",
"unhomoglyph": "^1.0.6",
"uuid": "9"
"uuid": "11"
},
"devDependencies": {
"@action-validator/cli": "^0.5.3",
"@action-validator/core": "^0.5.3",
"@action-validator/cli": "^0.6.0",
"@action-validator/core": "^0.6.0",
"@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-class-properties": "^7.12.1",
"@babel/plugin-transform-numeric-separator": "^7.12.7",
"@babel/plugin-transform-object-rest-spread": "^7.12.1",
"@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",
"@peculiar/webcrypto": "^1.4.5",
"@stylistic/eslint-plugin": "^2.9.0",
"@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",
"@types/uuid": "10",
"@typescript-eslint/eslint-plugin": "^8.0.0",
"@typescript-eslint/parser": "^8.0.0",
"babel-jest": "^29.0.0",
"babel-plugin-search-and-replace": "^1.1.1",
"debug": "^4.3.4",
"domexception": "^4.0.0",
"eslint": "8.53.0",
"eslint": "8.57.1",
"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",
"eslint-plugin-jest": "^28.0.0",
"eslint-plugin-jsdoc": "^50.0.0",
"eslint-plugin-matrix-org": "^2.0.1",
"eslint-plugin-n": "^14.0.0",
"eslint-plugin-tsdoc": "^0.4.0",
"eslint-plugin-unicorn": "^56.0.0",
"fake-indexeddb": "^5.0.2",
"fetch-mock": "11.1.5",
"fetch-mock-jest": "^1.5.1",
"husky": "^8.0.3",
"husky": "^9.0.0",
"jest": "^29.0.0",
"jest-environment-jsdom": "^29.0.0",
"jest-localstorage-mock": "^2.4.6",
"jest-mock": "^29.0.0",
"knip": "^5.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"
"node-fetch": "^2.7.0",
"prettier": "3.4.2",
"rimraf": "^6.0.0",
"ts-node": "^10.9.2",
"typedoc": "^0.27.0",
"typedoc-plugin-coverage": "^3.0.0",
"typedoc-plugin-mdn-links": "^4.0.0",
"typedoc-plugin-missing-exports": "^3.0.0",
"typescript": "^5.4.2"
},
"@casualbot/jest-sonar-reporter": {
"outputDirectory": "coverage",
"outputName": "jest-sonar-report.xml",
"relativePaths": true
},
"typings": "./lib/index.d.ts"
}
}
-15
View File
@@ -1,15 +0,0 @@
#!/bin/bash
#
# Script to perform a post-release steps of matrix-js-sdk.
#
# Requires:
# jq; install from your distribution's package manager (https://stedolan.github.io/jq/)
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
"$(dirname "$0")/scripts/release/post-merge-master.sh"
git push origin develop
fi
-346
View File
@@ -1,346 +0,0 @@
#!/bin/bash
#
# Script to perform a release of matrix-js-sdk and downstream projects.
#
# Requires:
# jq; install from your distribution's package manager (https://stedolan.github.io/jq/)
# hub; install via brew (macOS) or source/pre-compiled binaries (debian) (https://github.com/github/hub) - Tested on v2.2.9
# yarn; install via brew (macOS) or similar (https://yarnpkg.com/docs/install/)
#
# Note: this script is also used to release matrix-react-sdk, element-web, and element-desktop.
set -e
jq --version > /dev/null || (echo "jq is required: please install it"; kill $$)
if [[ $(command -v hub) ]] && [[ $(hub --version) =~ hub[[:space:]]version[[:space:]]([0-9]*).([0-9]*) ]]; then
HUB_VERSION_MAJOR=${BASH_REMATCH[1]}
HUB_VERSION_MINOR=${BASH_REMATCH[2]}
if [[ $HUB_VERSION_MAJOR -lt 2 ]] || [[ $HUB_VERSION_MAJOR -eq 2 && $HUB_VERSION_MINOR -lt 5 ]]; then
echo "hub version 2.5 is required, you have $HUB_VERSION_MAJOR.$HUB_VERSION_MINOR installed"
exit
fi
else
echo "hub is required: please install it"
exit
fi
yarn --version > /dev/null || (echo "yarn is required: please install it"; kill $$)
USAGE="$0 [-x] [-c changelog_file] vX.Y.Z"
help() {
cat <<EOF
$USAGE
-c changelog_file: specify name of file containing changelog
-x: skip updating the changelog
EOF
}
if ! git diff-index --quiet --cached HEAD; then
echo "this git checkout has staged (uncommitted) changes. Refusing to release."
exit
fi
if ! git diff-files --quiet; then
echo "this git checkout has uncommitted changes. Refusing to release."
exit
fi
skip_changelog=
changelog_file="CHANGELOG.md"
while getopts hc:x f; do
case $f in
h)
help
exit 0
;;
c)
changelog_file="$OPTARG"
;;
x)
skip_changelog=1
;;
esac
done
shift $(expr $OPTIND - 1)
if [ $# -ne 1 ]; then
echo "Usage: $USAGE" >&2
exit 1
fi
function check_dependency {
local depver=$(cat package.json | jq -r .dependencies[\"$1\"])
if [ "$depver" == "null" ]; then return 0; fi
echo "Checking version of $1..."
local latestver=$(yarn info -s "$1" dist-tags.next)
if [ "$depver" != "$latestver" ]
then
echo "The latest version of $1 is $latestver but package.json depends on $depver."
echo -n "Type 'u' to auto-upgrade, 'c' to continue anyway, or 'a' to abort:"
read resp
if [ "$resp" != "u" ] && [ "$resp" != "c" ]
then
echo "Aborting."
exit 1
fi
if [ "$resp" == "u" ]
then
echo "Upgrading $1 to $latestver..."
yarn add -E "$1@$latestver"
git add -u
git commit -m "Upgrade $1 to $latestver"
fi
fi
}
function reset_dependency {
local depver=$(cat package.json | jq -r .dependencies[\"$1\"])
if [ "$depver" == "null" ]; then return 0; fi
echo "Resetting $1 to develop branch..."
yarn add "github:matrix-org/$1#develop"
git add -u
git commit -m "Reset $1 back to develop branch"
}
has_subprojects=0
if [ -f release_config.yaml ]; then
subprojects=$(cat release_config.yaml | python -c "import yaml; import sys; print(' '.join(list(yaml.load(sys.stdin)['subprojects'].keys())))" 2> /dev/null)
if [ "$?" -eq 0 ]; then
has_subprojects=1
echo "Checking subprojects for upgrades"
for proj in $subprojects; do
check_dependency "$proj"
done
fi
fi
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
# We use Git branch / commit dependencies for some packages, and Yarn seems
# to have a hard time getting that right. See also
# https://github.com/yarnpkg/yarn/issues/4734. As a workaround, we clean the
# global cache here to ensure we get the right thing.
yarn cache clean
# Ensure all dependencies are updated
yarn install --ignore-scripts --frozen-lockfile
# ignore leading v on release
release="${1#v}"
tag="v${release}"
prerelease=0
# We check if this build is a prerelease by looking to
# see if the version has a hyphen in it. Crude,
# but semver doesn't support postreleases so anything
# with a hyphen is a prerelease.
echo $release | grep -q '-' && prerelease=1
if [ $prerelease -eq 1 ]; then
echo Making a PRE-RELEASE
else
read -p "Making a FINAL RELEASE, press enter to continue " REPLY
fi
rel_branch=$(git symbolic-ref --short HEAD)
if [ -z "$skip_changelog" ]; then
echo "Generating changelog"
yarn run allchange "$release"
read -p "Edit $changelog_file manually, or press enter to continue " REPLY
if [ -n "$(git ls-files --modified $changelog_file)" ]; then
echo "Committing updated changelog"
git commit "$changelog_file" -m "Prepare changelog for $tag"
fi
fi
latest_changes=$(mktemp)
cat "${changelog_file}" | "$(dirname "$0")/scripts/changelog_head.py" > "${latest_changes}"
set -x
# Bump package.json and build the dist
echo "yarn version"
# yarn version will automatically commit its modification
# and make a release tag. We don't want it to create the tag
# because it can only sign with the default key, but we can
# only turn off both of these behaviours, so we have to
# manually commit the result.
yarn version --no-git-tag-version --new-version "$release"
"$(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') ]];
then
pkglock='yarn.lock'
else
pkglock=''
fi
git commit package.json $pkglock -m "$tag"
# figure out if we should be signing this release
signing_id=
if [ -f release_config.yaml ]; then
result=$(cat release_config.yaml | python -c "import yaml; import sys; print(yaml.load(sys.stdin)['signing_id'])" 2> /dev/null || true)
if [ "$?" -eq 0 ]; then
signing_id=$result
fi
fi
# If there is a 'dist' script in the package.json,
# run it in a separate checkout of the project, then
# upload any files in the 'dist' directory as release
# assets.
# We make a completely separate checkout to be sure
# we're using released versions of the dependencies
# (rather than whatever we're pulling in from yarn link)
assets=''
dodist=0
jq -e .scripts.dist package.json 2> /dev/null || dodist=$?
if [ $dodist -eq 0 ]; then
projdir=$(pwd)
builddir=$(mktemp -d 2>/dev/null || mktemp -d -t 'mytmpdir')
echo "Building distribution copy in $builddir"
pushd "$builddir"
git clone "$projdir" .
git checkout "$rel_branch"
yarn install --frozen-lockfile
# We haven't tagged yet, so tell the dist script what version
# it's building
DIST_VERSION="$tag" yarn dist
popd
for i in "$builddir"/dist/*; do
assets="$assets -a $i"
if [ -n "$signing_id" ]
then
gpg -u "$signing_id" --armor --output "$i".asc --detach-sig "$i"
assets="$assets -a $i.asc"
fi
done
fi
if [ -n "$signing_id" ]; then
# make a signed tag
# gnupg seems to fail to get the right tty device unless we set it here
GIT_COMMITTER_EMAIL="$signing_id" GPG_TTY=$(tty) git tag -u "$signing_id" -F "${latest_changes}" "$tag"
else
git tag -a -F "${latest_changes}" "$tag"
fi
# push the tag and the release branch
git push origin "$rel_branch" "$tag"
if [ -n "$signing_id" ]; then
# make a signature for the source tarball.
#
# github will make us a tarball from the tag - we want to create a
# signature for it, which means that first of all we need to check that
# it's correct.
#
# we can't deterministically build exactly the same tarball, due to
# differences in gzip implementation - but we *can* build the same tar - so
# the easiest way to check the validity of the tarball from git is to unzip
# it and compare it with our own idea of what the tar should look like.
# This uses git archive which seems to be what github uses. Specifically,
# the header fields are set in the same way: same file mode, uid & gid
# both zero and mtime set to the timestamp of the commit that the tag
# references. Also note that this puts the commit into the tar headers
# and can be extracted with gunzip -c foo.tar.gz | git get-tar-commit-id
# the name of the sig file we want to create
source_sigfile="${tag}-src.tar.gz.asc"
tarfile="$tag.tar.gz"
gh_project_url=$(git remote get-url origin |
sed -e 's#^git@github\.com:#https://github.com/#' \
-e 's#^git\+ssh://git@github\.com/#https://github.com/#' \
-e 's/\.git$//')
project_name="${gh_project_url##*/}"
curl -L "${gh_project_url}/archive/${tarfile}" -o "${tarfile}"
# unzip it and compare it with the tar we would generate
if ! cmp --silent <(gunzip -c $tarfile) \
<(git archive --format tar --prefix="${project_name}-${release}/" "$tag"); then
# we don't bail out here, because really it's more likely that our comparison
# screwed up and it's super annoying to abort the script at this point.
cat >&2 <<EOF
!!!!!!!!!!!!!!!!!
!!!! WARNING !!!!
Mismatch between our own tarfile and that generated by github: not signing
source tarball.
To resolve, determine if $tarfile is correct, and if so sign it with gpg and
attach it to the release as $source_sigfile.
!!!!!!!!!!!!!!!!!
EOF
else
gpg -u "$signing_id" --armor --output "$source_sigfile" --detach-sig "$tarfile"
assets="$assets -a $source_sigfile"
fi
fi
hubflags=''
if [ $prerelease -eq 1 ]; then
hubflags='-p'
fi
release_text=$(mktemp)
echo "$tag" > "${release_text}"
echo >> "${release_text}"
cat "${latest_changes}" >> "${release_text}"
hub release create $hubflags $assets -F "${release_text}" "$tag"
if [ $dodist -eq 0 ]; then
rm -rf "$builddir"
fi
rm "${release_text}"
rm "${latest_changes}"
# if it is a pre-release, leave it on the release branch for now.
if [ $prerelease -eq 1 ]; then
git checkout "$rel_branch"
exit 0
fi
# merge release branch to master
echo "updating master branch"
git checkout master
git pull
git merge "$rel_branch" --no-edit
# push master to github
git push origin master
# finally, merge master back onto develop (if it exists)
if [ "$(git branch -lr | grep origin/develop -c)" -ge 1 ]; then
git checkout develop
git pull
git merge master --no-edit
git push origin develop
fi
[ -x ./post-release.sh ] && ./post-release.sh
if [ $has_subprojects -eq 1 ] && [ $prerelease -eq 0 ]; then
echo "Resetting subprojects to develop"
for proj in $subprojects; do
reset_dependency "$proj"
done
git push origin develop
fi
+165
View File
@@ -0,0 +1,165 @@
#!/usr/bin/env node
const fs = require("fs");
async function listReleases(github, owner, repo) {
const response = await github.rest.repos.listReleases({
owner,
repo,
per_page: 100,
});
// Filters out draft releases
return response.data.filter((release) => !release.draft);
}
// Dependency can be a tuple of dependency, from version, to version, in which case a list of releases in that range (to inclusive) will be returned
// Or it can be a string in the form accepted by `getRelease`
async function getReleases(github, dependency) {
if (Array.isArray(dependency)) {
const [dep, fromVersion, toVersion] = dependency;
const upstreamPackageJson = getDependencyPackageJson(dep);
const [owner, repo] = upstreamPackageJson.repository.url.split("/").slice(-2);
const unfilteredReleases = await listReleases(github, owner, repo);
// Only include non-draft & non-prerelease releases, unless the to-release is a pre-release, include that one
const releases = unfilteredReleases.filter(
(release) => !release.prerelease || release.tag_name === `v${toVersion}`,
);
const fromVersionIndex = releases.findIndex((release) => release.tag_name === `v${fromVersion}`);
const toVersionIndex = releases.findIndex((release) => release.tag_name === `v${toVersion}`);
return releases.slice(toVersionIndex, fromVersionIndex);
}
return [await getRelease(github, dependency)];
}
// Dependency can be the name of an entry in package.json, in which case the owner, repo & version will be looked up in its own package.json
// Or it can be a string in the form owner/repo@tag - in this case the tag is used exactly to find the release
// Or it can be a string in the form owner/repo~tag - in this case the latest tag in the same major.minor.patch set is used to find the release
async function getRelease(github, dependency) {
let owner;
let repo;
let tag;
if (dependency.includes("/")) {
let rest;
[owner, rest] = dependency.split("/");
if (dependency.includes("@")) {
[repo, tag] = rest.split("@");
} else if (dependency.includes("~")) {
[repo, tag] = rest.split("~");
if (tag.includes("-rc.")) {
// If the tag is an RC, find the latest matching RC in the set
try {
const releases = await listReleases(github, owner, repo);
const baseVersion = tag.split("-rc.")[0];
const release = releases.find((release) => release.tag_name.startsWith(baseVersion));
if (release) return release;
} catch (e) {
// Fall back to getReleaseByTag
}
}
}
} else {
const upstreamPackageJson = getDependencyPackageJson(dependency);
[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;
}
function getDependencyPackageJson(dependency) {
return JSON.parse(fs.readFileSync(`./node_modules/${dependency}/package.json`, "utf8"));
}
const HEADING_PREFIX = "## ";
const categories = [
"🔒 SECURITY FIXES",
"🚨 BREAKING CHANGESd",
"🦖 Deprecations",
"✨ Features",
"🐛 Bug Fixes",
"🧰 Maintenance",
];
const parseReleaseNotes = (body, sections) => {
let heading = null;
for (const line of body.split("\n")) {
const trimmed = line.trim();
if (trimmed.startsWith(HEADING_PREFIX)) {
heading = trimmed.slice(HEADING_PREFIX.length);
if (!categories.includes(heading)) heading = null;
continue;
}
if (heading && trimmed) {
sections[heading].push(trimmed);
}
}
};
const main = async ({ github, releaseId, dependencies }) => {
const { GITHUB_REPOSITORY } = process.env;
const [owner, repo] = GITHUB_REPOSITORY.split("/");
const { data: release } = await github.rest.repos.getRelease({
owner,
repo,
release_id: releaseId,
});
const sections = Object.fromEntries(categories.map((cat) => [cat, []]));
parseReleaseNotes(release.body, sections);
for (const dependency of dependencies) {
const releases = await getReleases(github, dependency);
for (const release of releases) {
parseReleaseNotes(release.body, sections);
}
}
const intro = release.body.split(HEADING_PREFIX, 2)[0].trim();
let output = "";
if (intro) {
output = intro + "\n\n";
}
for (const section in sections) {
const lines = sections[section];
if (!lines.length) continue;
output += HEADING_PREFIX + section + "\n\n";
output += lines.join("\n");
output += "\n\n";
}
return output;
};
// 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;
-104
View File
@@ -1,104 +0,0 @@
#!/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
@@ -1,22 +0,0 @@
#!/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
@@ -1,14 +0,0 @@
#!/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
-17
View File
@@ -1,17 +0,0 @@
#!/usr/bin/env node
const fsProm = require("fs/promises");
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];
}
}
await fsProm.writeFile(PKGJSON, JSON.stringify(pkgJson, null, 2));
}
main();
+1 -1
View File
@@ -66,7 +66,7 @@ export class TestClient implements IE2EKeyReceiver, ISyncResponder {
userId: userId,
accessToken: accessToken,
deviceId: deviceId,
fetchFn: this.httpBackend.fetchFn as typeof global.fetch,
fetchFn: this.httpBackend.fetchFn as typeof globalThis.fetch,
...options,
};
if (!fullOptions.cryptoStore) {
+188 -22
View File
@@ -21,7 +21,7 @@ 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 encryptAESSecretStorageItem from "../../../src/utils/encryptAESSecretStorageItem.ts";
import { CryptoCallbacks, CrossSigningKey } from "../../../src/crypto-api";
import { SECRET_STORAGE_ALGORITHM_V1_AES } from "../../../src/secret-storage";
import { ISyncResponder, SyncResponder } from "../../test-utils/SyncResponder";
@@ -31,9 +31,12 @@ import {
SELF_CROSS_SIGNING_PRIVATE_KEY_BASE64,
SELF_CROSS_SIGNING_PUBLIC_KEY_BASE64,
SIGNED_CROSS_SIGNING_KEYS_DATA,
SIGNED_TEST_DEVICE_DATA,
USER_CROSS_SIGNING_PRIVATE_KEY_BASE64,
} from "../../test-utils/test-data";
import * as testData from "../../test-utils/test-data";
import { E2EKeyResponder } from "../../test-utils/E2EKeyResponder";
import { AccountDataAccumulator } from "../../test-utils/AccountDataAccumulator";
afterEach(() => {
// reset fake-indexeddb after each test, to make sure we don't leak connections
@@ -78,27 +81,37 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("cross-signing (%s)", (backend: s
};
}
beforeEach(async () => {
// anything that we don't have a specific matcher for silently returns a 404
fetchMock.catch(404);
fetchMock.config.warnOnFallback = false;
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(),
});
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);
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);
});
// Silence warnings from the backup manager
fetchMock.getOnce(new URL("/_matrix/client/v3/room_keys/version", homeserverUrl).toString(), {
status: 404,
body: { errcode: "M_NOT_FOUND" },
});
await initCrypto(aliceClient);
},
/* it can take a while to initialise the crypto library on the first pass, so bump up the timeout. */
10000,
);
afterEach(async () => {
await aliceClient.stopClient();
@@ -156,17 +169,17 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("cross-signing (%s)", (backend: s
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(
const masterKey = await encryptAESSecretStorageItem(
MASTER_CROSS_SIGNING_PRIVATE_KEY_BASE64,
encryptionKey,
"m.cross_signing.master",
);
const selfSigningKey = await encryptAES(
const selfSigningKey = await encryptAESSecretStorageItem(
SELF_CROSS_SIGNING_PRIVATE_KEY_BASE64,
encryptionKey,
"m.cross_signing.self_signing",
);
const userSigningKey = await encryptAES(
const userSigningKey = await encryptAESSecretStorageItem(
USER_CROSS_SIGNING_PRIVATE_KEY_BASE64,
encryptionKey,
"m.cross_signing.user_signing",
@@ -236,6 +249,53 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("cross-signing (%s)", (backend: s
`[${TEST_USER_ID}].[${TEST_DEVICE_ID}].signatures.[${TEST_USER_ID}].[ed25519:${SELF_CROSS_SIGNING_PUBLIC_KEY_BASE64}]`,
);
});
it("can bootstrapCrossSigning twice", async () => {
mockSetupCrossSigningRequests();
const authDict = { type: "test" };
await bootstrapCrossSigning(authDict);
// a second call should do nothing except GET requests
fetchMock.mockClear();
await bootstrapCrossSigning(authDict);
const calls = fetchMock.calls((url, opts) => opts.method != "GET");
expect(calls.length).toEqual(0);
});
newBackendOnly("will upload existing cross-signing keys to an established secret storage", async () => {
// This rather obscure codepath covers the case that:
// - 4S is set up and working
// - our device has private cross-signing keys, but has not published them to 4S
//
// To arrange that, we call `bootstrapCrossSigning` on our main device, and then (pretend to) set up 4S from
// a *different* device. Then, when we call `bootstrapCrossSigning` again, it should do the honours.
mockSetupCrossSigningRequests();
const accountDataAccumulator = new AccountDataAccumulator();
accountDataAccumulator.interceptGetAccountData();
const authDict = { type: "test" };
await bootstrapCrossSigning(authDict);
// Pretend that another device has uploaded a 4S key
accountDataAccumulator.accountDataEvents.set("m.secret_storage.default_key", { key: "key_id" });
accountDataAccumulator.accountDataEvents.set("m.secret_storage.key.key_id", {
key: "keykeykey",
algorithm: SECRET_STORAGE_ALGORITHM_V1_AES,
});
// Prepare for the cross-signing keys
const p = accountDataAccumulator.interceptSetAccountData(":type(m.cross_signing..*)");
await bootstrapCrossSigning(authDict);
await p;
// The cross-signing keys should have been uploaded
expect(accountDataAccumulator.accountDataEvents.has("m.cross_signing.master")).toBeTruthy();
expect(accountDataAccumulator.accountDataEvents.has("m.cross_signing.self_signing")).toBeTruthy();
expect(accountDataAccumulator.accountDataEvents.has("m.cross_signing.user_signing")).toBeTruthy();
});
});
describe("getCrossSigningStatus()", () => {
@@ -287,6 +347,67 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("cross-signing (%s)", (backend: s
expect(isCrossSigningReady).toBeTruthy();
});
it("should return false if identity is not trusted, even if the secrets are in 4S", async () => {
e2eKeyResponder.addCrossSigningData(SIGNED_CROSS_SIGNING_KEYS_DATA);
// Complete initial sync, to get the 4S account_data events stored
mockInitialApiRequests(aliceClient.getHomeserverUrl());
// For this test we need to have a well-formed 4S setup.
const mockSecretInfo = {
encrypted: {
// Don't care about the actual values here, just need to be present for validation
KeyId: {
iv: "IVIVIVIVIVIVIV",
ciphertext: "CIPHERTEXTB64",
mac: "MACMACMAC",
},
},
};
syncResponder.sendOrQueueSyncResponse({
next_batch: 1,
account_data: {
events: [
{
type: "m.secret_storage.key.KeyId",
content: {
algorithm: "m.secret_storage.v1.aes-hmac-sha2",
// iv and mac not relevant for this test
},
},
{
type: "m.secret_storage.default_key",
content: {
key: "KeyId",
},
},
{
type: "m.cross_signing.master",
content: mockSecretInfo,
},
{
type: "m.cross_signing.user_signing",
content: mockSecretInfo,
},
{
type: "m.cross_signing.self_signing",
content: mockSecretInfo,
},
],
},
});
await aliceClient.startClient();
await syncPromise(aliceClient);
// Sanity: ensure that the secrets are in 4S
const status = await aliceClient.getCrypto()!.getCrossSigningStatus();
expect(status.privateKeysInSecretStorage).toBeTruthy();
const isCrossSigningReady = await aliceClient.getCrypto()!.isCrossSigningReady();
expect(isCrossSigningReady).toBeFalsy();
});
});
describe("getCrossSigningKeyId", () => {
@@ -339,4 +460,49 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("cross-signing (%s)", (backend: s
expect(userSigningKeyId).toBe(getPubKey(crossSigningKeys.user_signing_key));
});
});
describe("crossSignDevice", () => {
beforeEach(async () => {
// We want to use fake timers, but the wasm bindings of matrix-sdk-crypto rely on a working `queueMicrotask`.
jest.useFakeTimers({ doNotFake: ["queueMicrotask"] });
// make sure that there is another device which we can sign
e2eKeyResponder.addDeviceKeys(SIGNED_TEST_DEVICE_DATA);
// Complete initialsync, to get the outgoing requests going
mockInitialApiRequests(aliceClient.getHomeserverUrl());
syncResponder.sendOrQueueSyncResponse({ next_batch: 1 });
await aliceClient.startClient();
await syncPromise(aliceClient);
// Wait for legacy crypto to find the device
await jest.advanceTimersByTimeAsync(10);
const devices = await aliceClient.getCrypto()!.getUserDeviceInfo([aliceClient.getSafeUserId()]);
expect(devices.get(aliceClient.getSafeUserId())!.has(testData.TEST_DEVICE_ID)).toBeTruthy();
});
afterEach(async () => {
jest.useRealTimers();
});
it("fails for an unknown device", async () => {
await expect(aliceClient.getCrypto()!.crossSignDevice("unknown")).rejects.toThrow("Unknown device");
});
it("cross-signs the device", async () => {
mockSetupCrossSigningRequests();
await aliceClient.getCrypto()!.bootstrapCrossSigning({});
fetchMock.mockClear();
await aliceClient.getCrypto()!.crossSignDevice(testData.TEST_DEVICE_ID);
// check that a sig for the device was uploaded
const calls = fetchMock.calls("upload-sigs");
expect(calls.length).toEqual(1);
const body = JSON.parse(calls[0][1]!.body as string);
const deviceSig = body[aliceClient.getSafeUserId()][testData.TEST_DEVICE_ID];
expect(deviceSig).toHaveProperty("signatures");
});
});
});
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,227 @@
/*
Copyright 2024 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 fetchMock from "fetch-mock-jest";
import { ClientEvent, createClient, MatrixClient, MatrixEvent } from "../../../src";
import { CryptoEvent } from "../../../src/crypto-api/index";
import { RustCrypto } from "../../../src/rust-crypto/rust-crypto";
import { AddSecretStorageKeyOpts } from "../../../src/secret-storage";
import { E2EKeyReceiver } from "../../test-utils/E2EKeyReceiver";
import { E2EKeyResponder } from "../../test-utils/E2EKeyResponder";
import { emitPromise, EventCounter } from "../../test-utils/test-utils";
describe("Device dehydration", () => {
it("should rehydrate and dehydrate a device", async () => {
jest.useFakeTimers({ doNotFake: ["queueMicrotask"] });
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: "@alice:localhost",
deviceId: "aliceDevice",
cryptoCallbacks: {
getSecretStorageKey: async (keys: any, name: string) => {
return [[...Object.keys(keys.keys)][0], new Uint8Array(32)];
},
},
});
await initializeSecretStorage(matrixClient, "@alice:localhost", "http://test.server");
const creationEventCounter = new EventCounter(matrixClient, CryptoEvent.DehydratedDeviceCreated);
const dehydrationKeyCachedEventCounter = new EventCounter(matrixClient, CryptoEvent.DehydrationKeyCached);
const rehydrationStartedCounter = new EventCounter(matrixClient, CryptoEvent.RehydrationStarted);
const rehydrationCompletedCounter = new EventCounter(matrixClient, CryptoEvent.RehydrationCompleted);
const rehydrationProgressCounter = new EventCounter(matrixClient, CryptoEvent.RehydrationProgress);
// count the number of times the dehydration key gets set
let setDehydrationCount = 0;
matrixClient.on(ClientEvent.AccountData, (event: MatrixEvent) => {
if (event.getType() === "org.matrix.msc3814") {
setDehydrationCount++;
}
});
const crypto = matrixClient.getCrypto()!;
fetchMock.config.overwriteRoutes = true;
// start dehydration -- we start with no dehydrated device, and we
// store the dehydrated device that we create
fetchMock.get("path:/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device", {
status: 404,
body: {
errcode: "M_NOT_FOUND",
error: "Not found",
},
});
let dehydratedDeviceBody: any;
let dehydrationCount = 0;
let resolveDehydrationPromise: () => void;
fetchMock.put("path:/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device", (_, opts) => {
dehydratedDeviceBody = JSON.parse(opts.body as string);
dehydrationCount++;
if (resolveDehydrationPromise) {
resolveDehydrationPromise();
}
return {};
});
await crypto.startDehydration();
expect(dehydrationCount).toEqual(1);
expect(creationEventCounter.counter).toEqual(1);
expect(dehydrationKeyCachedEventCounter.counter).toEqual(1);
// a week later, we should have created another dehydrated device
const dehydrationPromise = new Promise<void>((resolve, reject) => {
resolveDehydrationPromise = resolve;
});
jest.advanceTimersByTime(7 * 24 * 60 * 60 * 1000);
await dehydrationPromise;
expect(dehydrationKeyCachedEventCounter.counter).toEqual(1);
expect(dehydrationCount).toEqual(2);
expect(creationEventCounter.counter).toEqual(2);
// restart dehydration -- rehydrate the device that we created above,
// and create a new dehydrated device. We also set `createNewKey`, so
// a new dehydration key will be set
fetchMock.get("path:/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device", {
device_id: dehydratedDeviceBody.device_id,
device_data: dehydratedDeviceBody.device_data,
});
const eventsResponse = jest.fn((url, opts) => {
// rehydrating should make two calls to the /events endpoint.
// The first time will return a single event, and the second
// time will return no events (which will signal to the
// rehydration function that it can stop)
const body = JSON.parse(opts.body as string);
const nextBatch = body.next_batch ?? "0";
const events = nextBatch === "0" ? [{ sender: "@alice:localhost", type: "m.dummy", content: {} }] : [];
return {
events,
next_batch: nextBatch + "1",
};
});
fetchMock.post(
`path:/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device/${encodeURIComponent(dehydratedDeviceBody.device_id)}/events`,
eventsResponse,
);
await crypto.startDehydration(true);
expect(dehydrationCount).toEqual(3);
expect(setDehydrationCount).toEqual(2);
expect(eventsResponse.mock.calls).toHaveLength(2);
expect(rehydrationStartedCounter.counter).toEqual(1);
expect(rehydrationCompletedCounter.counter).toEqual(1);
expect(creationEventCounter.counter).toEqual(3);
expect(rehydrationProgressCounter.counter).toEqual(1);
expect(dehydrationKeyCachedEventCounter.counter).toEqual(2);
// test that if we get an error when we try to rotate, it emits an event
fetchMock.put("path:/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device", {
status: 500,
body: {
errcode: "M_UNKNOWN",
error: "Unknown error",
},
});
const rotationErrorEventPromise = emitPromise(matrixClient, CryptoEvent.DehydratedDeviceRotationError);
jest.advanceTimersByTime(7 * 24 * 60 * 60 * 1000);
await rotationErrorEventPromise;
// Restart dehydration, but return an error for GET /dehydrated_device so that rehydration fails.
fetchMock.get("path:/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device", {
status: 500,
body: {
errcode: "M_UNKNOWN",
error: "Unknown error",
},
});
fetchMock.put("path:/_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_device", (_, opts) => {
return {};
});
const rehydrationErrorEventPromise = emitPromise(matrixClient, CryptoEvent.RehydrationError);
await crypto.startDehydration(true);
await rehydrationErrorEventPromise;
matrixClient.stopClient();
});
});
/** create a new secret storage and cross-signing keys */
async function initializeSecretStorage(
matrixClient: MatrixClient,
userId: string,
homeserverUrl: string,
): Promise<void> {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", {
status: 404,
body: {
errcode: "M_NOT_FOUND",
error: "Not found",
},
});
const e2eKeyReceiver = new E2EKeyReceiver(homeserverUrl);
const e2eKeyResponder = new E2EKeyResponder(homeserverUrl);
e2eKeyResponder.addKeyReceiver(userId, e2eKeyReceiver);
fetchMock.post("path:/_matrix/client/v3/keys/device_signing/upload", {});
fetchMock.post("path:/_matrix/client/v3/keys/signatures/upload", {});
const accountData: Map<string, object> = new Map();
fetchMock.get("glob:http://*/_matrix/client/v3/user/*/account_data/*", (url, opts) => {
const name = url.split("/").pop()!;
const value = accountData.get(name);
if (value) {
return value;
} else {
return {
status: 404,
body: {
errcode: "M_NOT_FOUND",
error: "Not found",
},
};
}
});
fetchMock.put("glob:http://*/_matrix/client/v3/user/*/account_data/*", (url, opts) => {
const name = url.split("/").pop()!;
const value = JSON.parse(opts.body as string);
accountData.set(name, value);
matrixClient.emit(ClientEvent.AccountData, new MatrixEvent({ type: name, content: value }));
return {};
});
await matrixClient.initRustCrypto();
const crypto = matrixClient.getCrypto()! as RustCrypto;
// we need to process a sync so that the OlmMachine will upload keys
await crypto.preprocessToDeviceMessages([]);
await crypto.onSyncCompleted({});
// create initial secret storage
async function createSecretStorageKey() {
return {
keyInfo: {} as AddSecretStorageKeyOpts,
privateKey: new Uint8Array(32),
};
}
await matrixClient.bootstrapCrossSigning({ setupNewCrossSigning: true });
await matrixClient.bootstrapSecretStorage({
createSecretStorageKey,
setupNewSecretStorage: true,
setupNewKeyBackup: false,
});
}
+488 -55
View File
@@ -17,8 +17,18 @@ limitations under the License.
import fetchMock from "fetch-mock-jest";
import "fake-indexeddb/auto";
import { IDBFactory } from "fake-indexeddb";
import { Mocked } from "jest-mock";
import { createClient, CryptoEvent, ICreateClientOpts, MatrixClient, TypedEventEmitter } from "../../../src";
import {
createClient,
Crypto,
encodeBase64,
ICreateClientOpts,
IEvent,
IMegolmSessionData,
MatrixClient,
TypedEventEmitter,
} from "../../../src";
import { SyncResponder } from "../../test-utils/SyncResponder";
import { E2EKeyReceiver } from "../../test-utils/E2EKeyReceiver";
import { E2EKeyResponder } from "../../test-utils/E2EKeyResponder";
@@ -31,9 +41,11 @@ import {
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 { KeyBackupInfo, KeyBackupSession } from "../../../src/crypto-api/keybackup";
import { flushPromises } from "../../test-utils/flushPromises";
import { defer, IDeferred } from "../../../src/utils";
import { decodeRecoveryKey, DecryptionFailureCode, CryptoEvent } from "../../../src/crypto-api";
import { KeyBackup } from "../../../src/rust-crypto/backup.ts";
const ROOM_ID = testData.TEST_ROOM_ID;
@@ -79,7 +91,7 @@ function mockUploadEmitter(
},
};
}
const uploadPayload: IKeyBackup = JSON.parse(request.body?.toString() ?? "{}");
const uploadPayload: KeyBackup = JSON.parse((request.body as string) ?? "{}");
let count = 0;
for (const [roomId, value] of Object.entries(uploadPayload.rooms)) {
for (const sessionId of Object.keys(value.sessions)) {
@@ -105,8 +117,10 @@ function mockUploadEmitter(
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;
const oldBackendOnly = backend === "rust-sdk" ? test.skip : test;
const newBackendOnly = backend === "libolm" ? test.skip : test;
const isNewBackend = backend === "rust-sdk";
let aliceClient: MatrixClient;
/** an object which intercepts `/sync` requests on the test homeserver */
@@ -118,7 +132,8 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
let e2eKeyResponder: E2EKeyResponder;
beforeEach(async () => {
jest.useFakeTimers();
// We want to use fake timers, but the wasm bindings of matrix-sdk-crypto rely on a working `queueMicrotask`.
jest.useFakeTimers({ doNotFake: ["queueMicrotask"] });
// anything that we don't have a specific matcher for silently returns a 404
fetchMock.catch(404);
@@ -180,28 +195,31 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
}
}
beforeEach(async () => {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
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", {});
// 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!,
);
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();
// 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();
});
// 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 can take a while to initialise the crypto library on the first pass, so bump up the timeout. */,
10000,
);
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) => {
@@ -227,8 +245,17 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
const room = aliceClient.getRoom(ROOM_ID)!;
const event = room.getLiveTimeline().getEvents()[0];
await advanceTimersUntil(awaitDecryption(event, { waitOnDecryptionFailure: true }));
// On the first decryption attempt, decryption fails.
await awaitDecryption(event);
expect(event.decryptionFailureReason).toEqual(
isNewBackend
? DecryptionFailureCode.HISTORICAL_MESSAGE_WORKING_BACKUP
: DecryptionFailureCode.MEGOLM_UNKNOWN_INBOUND_SESSION_ID,
);
// Eventually, decryption succeeds.
await awaitDecryption(event, { waitOnDecryptionFailure: true });
expect(event.getContent()).toEqual(testData.CLEAR_EVENT.content);
});
@@ -285,17 +312,25 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
});
describe("recover from backup", () => {
it("can restore from backup (Curve25519 version)", async function () {
let aliceCrypto: Crypto.CryptoApi;
beforeEach(async () => {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
fetchMock.get(
`path:/_matrix/client/v3/room_keys/version/${testData.SIGNED_BACKUP_DATA.version}`,
testData.SIGNED_BACKUP_DATA,
);
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
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);
});
it("can restore from backup (Curve25519 version)", async function () {
const fullBackup = {
rooms: {
[ROOM_ID]: {
@@ -315,20 +350,29 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
onKeyCached = resolve;
});
await aliceCrypto.storeSessionBackupPrivateKey(
decodeRecoveryKey(testData.BACKUP_DECRYPTION_KEY_BASE58),
check!.backupInfo!.version!,
);
const result = await advanceTimersUntil(
aliceClient.restoreKeyBackupWithRecoveryKey(
testData.BACKUP_DECRYPTION_KEY_BASE58,
undefined,
undefined,
check!.backupInfo!,
{
cacheCompleteCallback: () => onKeyCached(),
},
),
isNewBackend
? aliceCrypto.restoreKeyBackup()
: aliceClient.restoreKeyBackupWithRecoveryKey(
testData.BACKUP_DECRYPTION_KEY_BASE58,
undefined,
undefined,
check!.backupInfo!,
{
cacheCompleteCallback: () => onKeyCached(),
},
),
);
expect(result.imported).toStrictEqual(1);
if (isNewBackend) return;
await awaitKeyCached;
// The key should be now cached
@@ -339,17 +383,212 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
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);
/**
* Creates a mock backup response of a GET `room_keys/keys` with a given number of keys per room.
* @param keysPerRoom The number of keys per room
*/
function createBackupDownloadResponse(keysPerRoom: number[]) {
const response: {
rooms: {
[roomId: string]: {
sessions: {
[sessionId: string]: KeyBackupSession;
};
};
};
} = { rooms: {} };
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
const expectedTotal = keysPerRoom.reduce((a, b) => a + b, 0);
for (let i = 0; i < keysPerRoom.length; i++) {
const roomId = `!room${i}:example.com`;
response.rooms[roomId] = { sessions: {} };
for (let j = 0; j < keysPerRoom[i]; j++) {
const sessionId = `session${j}`;
// Put the same fake session data, not important for that test
response.rooms[roomId].sessions[sessionId] = testData.CURVE25519_KEY_BACKUP_DATA;
}
}
return { response, expectedTotal };
}
// tell Alice to trust the dummy device that signed the backup
await waitForDeviceList();
await aliceCrypto.setDeviceVerified(testData.TEST_USER_ID, testData.TEST_DEVICE_ID);
it("Should import full backup in chunks", async function () {
const importMockImpl = jest.fn();
if (isNewBackend) {
// @ts-ignore - mock a private method for testing purpose
jest.spyOn(aliceCrypto.backupManager, "importBackedUpRoomKeys").mockImplementation(importMockImpl);
} else {
// @ts-ignore - mock a private method for testing purpose
jest.spyOn(aliceCrypto, "importBackedUpRoomKeys").mockImplementation(importMockImpl);
}
// We need several rooms with several sessions to test chunking
const { response, expectedTotal } = createBackupDownloadResponse([45, 300, 345, 12, 130]);
fetchMock.get("express:/_matrix/client/v3/room_keys/keys", response);
const check = await aliceCrypto.checkKeyBackupAndEnable();
await aliceCrypto.storeSessionBackupPrivateKey(
decodeRecoveryKey(testData.BACKUP_DECRYPTION_KEY_BASE58),
check!.backupInfo!.version!,
);
const progressCallback = jest.fn();
const result = await (isNewBackend
? aliceCrypto.restoreKeyBackup({
progressCallback,
})
: aliceClient.restoreKeyBackupWithRecoveryKey(
testData.BACKUP_DECRYPTION_KEY_BASE58,
undefined,
undefined,
check!.backupInfo!,
{
progressCallback,
},
));
expect(result.imported).toStrictEqual(expectedTotal);
// Should be called 5 times: 200*4 plus one chunk with the remaining 32
expect(importMockImpl).toHaveBeenCalledTimes(5);
for (let i = 0; i < 4; i++) {
expect(importMockImpl.mock.calls[i][0].length).toEqual(200);
}
expect(importMockImpl.mock.calls[4][0].length).toEqual(32);
expect(progressCallback).toHaveBeenCalledWith({
stage: "fetch",
});
// Should be called 4 times and report 200/400/600/800
for (let i = 0; i < 4; i++) {
expect(progressCallback).toHaveBeenCalledWith({
total: expectedTotal,
successes: (i + 1) * 200,
stage: "load_keys",
failures: 0,
});
}
// The last chunk
expect(progressCallback).toHaveBeenCalledWith({
total: expectedTotal,
successes: 832,
stage: "load_keys",
failures: 0,
});
});
it("Should continue to process backup if a chunk import fails and report failures", async function () {
const importMockImpl = jest
.fn()
.mockImplementationOnce(() => {
// Fail to import first chunk
throw new Error("test error");
})
// Ok for other chunks
.mockResolvedValue(undefined);
if (isNewBackend) {
// @ts-ignore - mock a private method for testing purpose
jest.spyOn(aliceCrypto.backupManager, "importBackedUpRoomKeys").mockImplementation(importMockImpl);
} else {
// @ts-ignore - mock a private method for testing purpose
jest.spyOn(aliceCrypto, "importBackedUpRoomKeys").mockImplementation(importMockImpl);
}
const { response, expectedTotal } = createBackupDownloadResponse([100, 300]);
fetchMock.get("express:/_matrix/client/v3/room_keys/keys", response);
const check = await aliceCrypto.checkKeyBackupAndEnable();
await aliceCrypto.storeSessionBackupPrivateKey(
decodeRecoveryKey(testData.BACKUP_DECRYPTION_KEY_BASE58),
check!.backupInfo!.version!,
);
const progressCallback = jest.fn();
const result = await (isNewBackend
? aliceCrypto.restoreKeyBackup({ progressCallback })
: aliceClient.restoreKeyBackupWithRecoveryKey(
testData.BACKUP_DECRYPTION_KEY_BASE58,
undefined,
undefined,
check!.backupInfo!,
{
progressCallback,
},
));
expect(result.total).toStrictEqual(expectedTotal);
// A chunk failed to import
expect(result.imported).toStrictEqual(200);
expect(progressCallback).toHaveBeenCalledWith({
total: expectedTotal,
successes: 0,
stage: "load_keys",
failures: 200,
});
expect(progressCallback).toHaveBeenCalledWith({
total: expectedTotal,
successes: 200,
stage: "load_keys",
failures: 200,
});
});
it("Should continue if some keys fails to decrypt", async function () {
// @ts-ignore - mock a private method for testing purpose
aliceCrypto.importBackedUpRoomKeys = jest.fn();
const decryptionFailureCount = 2;
const mockDecryptor = {
// DecryptSessions does not reject on decryption failure, but just skip the key
decryptSessions: jest.fn().mockImplementation((sessions) => {
// simulate fail to decrypt 2 keys out of all
const decrypted = [];
const keys = Object.keys(sessions);
for (let i = 0; i < keys.length - decryptionFailureCount; i++) {
decrypted.push({
session_id: keys[i],
} as unknown as Mocked<IMegolmSessionData>);
}
return decrypted;
}),
free: jest.fn(),
};
// @ts-ignore - mock a private method for testing purpose
aliceCrypto.getBackupDecryptor = jest.fn().mockResolvedValue(mockDecryptor);
const { response, expectedTotal } = createBackupDownloadResponse([100]);
fetchMock.get("express:/_matrix/client/v3/room_keys/keys", response);
const check = await aliceCrypto.checkKeyBackupAndEnable();
await aliceCrypto.storeSessionBackupPrivateKey(
decodeRecoveryKey(testData.BACKUP_DECRYPTION_KEY_BASE58),
check!.backupInfo!.version!,
);
const result = await (isNewBackend
? aliceCrypto.restoreKeyBackup()
: aliceClient.restoreKeyBackupWithRecoveryKey(
testData.BACKUP_DECRYPTION_KEY_BASE58,
undefined,
undefined,
check!.backupInfo!,
));
expect(result.total).toStrictEqual(expectedTotal);
// A chunk failed to import
expect(result.imported).toStrictEqual(expectedTotal - decryptionFailureCount);
});
oldBackendOnly("recover specific session from backup", async function () {
fetchMock.get(
"express:/_matrix/client/v3/room_keys/keys/:room_id/:session_id",
testData.CURVE25519_KEY_BACKUP_DATA,
@@ -369,17 +608,33 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
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);
newBackendOnly(
"Should get the decryption key from the secret storage and restore the key backup",
async function () {
// @ts-ignore - mock a private method for testing purpose
jest.spyOn(aliceCrypto.secretStorage, "get").mockResolvedValue(testData.BACKUP_DECRYPTION_KEY_BASE64);
aliceClient = await initTestClient();
const aliceCrypto = aliceClient.getCrypto()!;
await aliceClient.startClient();
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);
// 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.loadSessionBackupPrivateKeyFromSecretStorage();
const decryptionKey = await aliceCrypto.getSessionBackupPrivateKey();
expect(encodeBase64(decryptionKey!)).toStrictEqual(testData.BACKUP_DECRYPTION_KEY_BASE64);
const result = await aliceCrypto.restoreKeyBackup();
expect(result.imported).toStrictEqual(1);
},
);
oldBackendOnly("Fails on bad recovery key", async function () {
const fullBackup = {
rooms: {
[ROOM_ID]: {
@@ -403,6 +658,10 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
),
).rejects.toThrow();
});
newBackendOnly("Should throw an error if the decryption key is not found in cache", async () => {
await expect(aliceCrypto.restoreKeyBackup()).rejects.toThrow("No decryption key found in crypto store");
});
});
describe("backupLoop", () => {
@@ -615,7 +874,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
const result = await aliceCrypto.checkKeyBackupAndEnable();
expect(result).toBeTruthy();
jest.runAllTimers();
jest.advanceTimersByTime(10 * 60 * 1000);
await failurePromise;
// Fix the endpoint to do successful uploads
@@ -648,7 +907,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
});
// run the timers, which will make the backup loop redo the request
await jest.runAllTimersAsync();
await jest.advanceTimersByTimeAsync(10 * 60 * 1000);
await successPromise;
await allKeysUploadedPromise;
});
@@ -709,6 +968,40 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
expect(backupStatus).toStrictEqual(testData.SIGNED_BACKUP_DATA.version);
});
newBackendOnly("getKeyBackupInfo() should not return a backup if the active backup has been deleted", async () => {
// 404 means that there is no active backup
fetchMock.get("express:/_matrix/client/v3/room_keys/version", 404);
fetchMock.delete(`express:/_matrix/client/v3/room_keys/version/${testData.SIGNED_BACKUP_DATA.version}`, {});
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
expect(await aliceCrypto.getKeyBackupInfo()).toBeNull();
// Return now the backup
fetchMock.get("express:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA, {
overwriteRoutes: true,
});
expect(await aliceCrypto.getKeyBackupInfo()).toStrictEqual(testData.SIGNED_BACKUP_DATA);
// Delete the backup and we are expecting the key backup to be disabled
const keyBackupStatus = defer<boolean>();
aliceClient.once(CryptoEvent.KeyBackupStatus, (enabled) => keyBackupStatus.resolve(enabled));
await aliceCrypto.deleteKeyBackupVersion(testData.SIGNED_BACKUP_DATA.version!);
expect(await keyBackupStatus.promise).toBe(false);
// The backup info should not be available anymore
expect(await aliceCrypto.getKeyBackupInfo()).toBeNull();
});
describe("isKeyBackupTrusted", () => {
it("does not trust a backup signed by an untrusted device", async () => {
aliceClient = await initTestClient();
@@ -888,6 +1181,146 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("megolm-keys backup (%s)", (backe
});
});
describe("Backup Changed from other sessions", () => {
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();
});
// let aliceClient: MatrixClient;
const SYNC_RESPONSE = {
next_batch: 1,
rooms: { join: { [ROOM_ID]: { timeline: { events: [testData.ENCRYPTED_EVENT] } } } },
};
it("If current backup has changed, the manager should switch to the new one on UTD", async () => {
// =====
// First ensure that the client checks for keys using the backup version 1
/// =====
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.",
},
};
}
},
{ overwriteRoutes: true },
);
// 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);
// =====
// Second suppose now that the backup has changed to version 2
/// =====
const newBackup = {
...testData.SIGNED_BACKUP_DATA,
version: "2",
};
fetchMock.get("path:/_matrix/client/v3/room_keys/version", newBackup, { overwriteRoutes: true });
// suppose the new key is now known
const aliceCrypto = aliceClient.getCrypto()!;
await aliceCrypto.storeSessionBackupPrivateKey(
Buffer.from(testData.BACKUP_DECRYPTION_KEY_BASE64, "base64"),
newBackup.version,
);
// A check backup should happen at some point
await aliceCrypto.checkKeyBackupAndEnable();
const awaitHasQueriedNewBackup: IDeferred<void> = defer<void>();
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 == newBackup.version) {
awaitHasQueriedNewBackup.resolve();
return testData.CURVE25519_KEY_BACKUP_DATA;
} else {
// awaitHasQueriedOldBackup.resolve();
return {
status: 403,
body: {
current_version: "2",
errcode: "M_WRONG_ROOM_KEYS_VERSION",
error: "Wrong backup version.",
},
};
}
},
{ overwriteRoutes: true },
);
// Send Alice a message that she won't be able to decrypt, and check that she fetches the key from the new backup.
const newMessage: Partial<IEvent> = {
type: "m.room.encrypted",
room_id: "!room:id",
sender: "@alice:localhost",
content: {
algorithm: "m.megolm.v1.aes-sha2",
ciphertext:
"AwgAEpABKvf9FqPW52zeHfeVTn90a3jlBLlx7g6VDEkc2089RQUJoWpSJRiK13E83rN41wgGFJccyfoCr7ZDGJeuGYMGETTrgnLQhLs6JmyPf37JYkzxW8uS8rGUKEqTFQriKhibHVLvVacOlSIObUiKU/V3r176XuixqZF/4eyK9A22JNpInbgI10ZUT6LnApH9LR3FpZbE2zImf1uNPuvp7r0xQbW7CcJjqpH+qTPBD5zFdFnMkc2SnbXCsIOaX11Dm0krWfQz7iA26ZnI1nyZnyh7XPrCnJCRsuQH",
device_id: "WVMJGTSSVB",
sender_key: "E5RiY/YCIrHWaF4u416CqvblC6udK2jt9SJ/h1QeLS0",
session_id: "ybnW+LGdUhoS4fHm1DAEphukO3sZ1GCqZD7UQz7L+GA",
},
event_id: "$event2",
origin_server_ts: 1507753887000,
};
const nextSyncResponse = {
next_batch: 2,
rooms: { join: { [ROOM_ID]: { timeline: { events: [newMessage] } } } },
};
syncResponder.sendOrQueueSyncResponse(nextSyncResponse);
await syncPromise(aliceClient);
await awaitHasQueriedNewBackup.promise;
});
});
/** 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
+7 -6
View File
@@ -34,8 +34,9 @@ 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 { ClientEvent, IContent, ISendEventResponse, MatrixClient, MatrixEvent, MsgType } from "../../../src/matrix";
import { DeviceInfo } from "../../../src/crypto/deviceinfo";
import { KnownMembership } from "../../../src/@types/membership";
let aliTestClient: TestClient;
const roomId = "!room:localhost";
@@ -216,7 +217,7 @@ 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: MsgType.Text, body: "Hello, World" });
}
async function expectSendMessageRequest(httpBackend: TestClient["httpBackend"]): Promise<IContent> {
@@ -316,11 +317,11 @@ function firstSync(testClient: TestClient): Promise<void> {
state: {
events: [
testUtils.mkMembership({
mship: "join",
mship: KnownMembership.Join,
user: aliUserId,
}),
testUtils.mkMembership({
mship: "join",
mship: KnownMembership.Join,
user: bobUserId,
}),
],
@@ -344,10 +345,10 @@ describe("MatrixClient crypto", () => {
beforeEach(async () => {
aliTestClient = new TestClient(aliUserId, aliDeviceId, aliAccessToken);
await aliTestClient.client.initCrypto();
await aliTestClient.client.initLegacyCrypto();
bobTestClient = new TestClient(bobUserId, bobDeviceId, bobAccessToken);
await bobTestClient.client.initCrypto();
await bobTestClient.client.initLegacyCrypto();
aliMessages = [];
bobMessages = [];
+4 -4
View File
@@ -85,15 +85,15 @@ export function bootstrapCrossSigningTestOlmAccount(
deviceId: string,
keyBackupInfo: KeyBackupInfo[] = [],
): Partial<IDownloadKeyResult> {
const olmAliceMSK = new global.Olm.PkSigning();
const olmAliceMSK = new globalThis.Olm.PkSigning();
const masterPrivkey = olmAliceMSK.generate_seed();
const masterPubkey = olmAliceMSK.init_with_seed(masterPrivkey);
const olmAliceUSK = new global.Olm.PkSigning();
const olmAliceUSK = new globalThis.Olm.PkSigning();
const userPrivkey = olmAliceUSK.generate_seed();
const userPubkey = olmAliceUSK.init_with_seed(userPrivkey);
const olmAliceSSK = new global.Olm.PkSigning();
const olmAliceSSK = new globalThis.Olm.PkSigning();
const sskPrivkey = olmAliceSSK.generate_seed();
const sskPubkey = olmAliceSSK.init_with_seed(sskPrivkey);
@@ -181,7 +181,7 @@ export async function createOlmSession(
const otkId = Object.keys(keys)[0];
const otk = keys[otkId];
const session = new global.Olm.Session();
const session = new globalThis.Olm.Session();
session.create_outbound(olmAccount, recipientTestClient.getDeviceKey(), otk.key);
return session;
}
+359 -6
View File
@@ -16,8 +16,16 @@ limitations under the License.
import "fake-indexeddb/auto";
import { IDBFactory } from "fake-indexeddb";
import fetchMock from "fetch-mock-jest";
import { createClient } from "../../../src";
import { createClient, CryptoEvent, IndexedDBCryptoStore } from "../../../src";
import { populateStore } from "../../test-utils/test_indexeddb_cryptostore_dump";
import { MSK_NOT_CACHED_DATASET } from "../../test-utils/test_indexeddb_cryptostore_dump/no_cached_msk_dump";
import { IDENTITY_NOT_TRUSTED_DATASET } from "../../test-utils/test_indexeddb_cryptostore_dump/unverified";
import { FULL_ACCOUNT_DATASET } from "../../test-utils/test_indexeddb_cryptostore_dump/full_account";
import { EMPTY_ACCOUNT_DATASET } from "../../test-utils/test_indexeddb_cryptostore_dump/empty_account";
jest.setTimeout(15000);
afterEach(() => {
// reset fake-indexeddb after each test, to make sure we don't leak connections
@@ -58,18 +66,36 @@ describe("MatrixClient.initRustCrypto", () => {
expect(databaseNames).toEqual(expect.arrayContaining(["matrix-js-sdk::matrix-sdk-crypto"]));
});
it("should create the meta db if given a pickleKey", async () => {
it("should create the meta db if given a storageKey", 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();
await matrixClient.initRustCrypto({ storageKey: new Uint8Array(32) });
// 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 create the meta db if given a storagePassword", async () => {
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: "@alice:localhost",
deviceId: "aliceDevice",
});
// No databases.
expect(await indexedDB.databases()).toHaveLength(0);
await matrixClient.initRustCrypto({ storagePassword: "the cow is on the moon" });
// should have two indexed dbs now
const databaseNames = (await indexedDB.databases()).map((db) => db.name);
@@ -88,6 +114,334 @@ describe("MatrixClient.initRustCrypto", () => {
await matrixClient.initRustCrypto();
await matrixClient.initRustCrypto();
});
describe("Libolm Migration", () => {
beforeEach(() => {
fetchMock.reset();
});
it("should migrate from libolm", async () => {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", FULL_ACCOUNT_DATASET.backupResponse);
fetchMock.post("path:/_matrix/client/v3/keys/query", FULL_ACCOUNT_DATASET.keyQueryResponse);
const testStoreName = "test-store";
await populateStore(testStoreName, FULL_ACCOUNT_DATASET.dumpPath);
const cryptoStore = new IndexedDBCryptoStore(indexedDB, testStoreName);
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: FULL_ACCOUNT_DATASET.userId,
deviceId: FULL_ACCOUNT_DATASET.deviceId,
cryptoStore,
pickleKey: FULL_ACCOUNT_DATASET.pickleKey,
});
const progressListener = jest.fn();
matrixClient.addListener(CryptoEvent.LegacyCryptoStoreMigrationProgress, progressListener);
await matrixClient.initRustCrypto();
const verificationStatus = await matrixClient
.getCrypto()!
.getDeviceVerificationStatus(FULL_ACCOUNT_DATASET.userId, FULL_ACCOUNT_DATASET.deviceId);
// Check that the current device and identity trust is migrated correctly just after migration
expect(verificationStatus).toBeDefined();
expect(verificationStatus!.crossSigningVerified).toEqual(true);
expect(verificationStatus!.signedByOwner).toEqual(true);
// Do some basic checks on the imported data
const deviceKeys = await matrixClient.getCrypto()!.getOwnDeviceKeys();
expect(deviceKeys.curve25519).toEqual("LKv0bKbc0EC4h0jknbemv3QalEkeYvuNeUXVRgVVTTU");
expect(deviceKeys.ed25519).toEqual("qK70DEqIXq7T+UU3v/al47Ab4JkMEBLpNrTBMbS5rrw");
expect(await matrixClient.getCrypto()!.getActiveSessionBackupVersion()).toEqual("7");
expect(await matrixClient.getCrypto()!.isEncryptionEnabledInRoom("!CWLUCoEWXSFyTCOtfL:matrix.org")).toBe(
true,
);
// check the progress callback
expect(progressListener.mock.calls.length).toBeGreaterThan(50);
// The first call should have progress == 0
const [firstProgress, totalSteps] = progressListener.mock.calls[0];
expect(totalSteps).toBeGreaterThan(3000);
expect(firstProgress).toEqual(0);
for (let i = 1; i < progressListener.mock.calls.length - 1; i++) {
const [progress, total] = progressListener.mock.calls[i];
expect(total).toEqual(totalSteps);
expect(progress).toBeGreaterThan(progressListener.mock.calls[i - 1][0]);
expect(progress).toBeLessThanOrEqual(totalSteps);
}
// The final call should have progress == total == -1
expect(progressListener).toHaveBeenLastCalledWith(-1, -1);
}, 60000);
describe("Private key backup migration", () => {
it("should not migrate the backup private key if backup has changed", async () => {
// Here we have a new backup server side, and the migrated account has the previous backup key.
fetchMock.get("path:/_matrix/client/v3/room_keys/version", MSK_NOT_CACHED_DATASET.newBackupResponse);
fetchMock.post("path:/_matrix/client/v3/keys/query", MSK_NOT_CACHED_DATASET.keyQueryResponse);
await populateStore("test-store", MSK_NOT_CACHED_DATASET.dumpPath);
const cryptoStore = new IndexedDBCryptoStore(indexedDB, "test-store");
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: MSK_NOT_CACHED_DATASET.userId,
deviceId: MSK_NOT_CACHED_DATASET.deviceId,
cryptoStore,
pickleKey: MSK_NOT_CACHED_DATASET.pickleKey,
});
await matrixClient.initRustCrypto();
const privateBackupKey = await matrixClient.getCrypto()?.getSessionBackupPrivateKey();
expect(privateBackupKey).toBeNull();
});
it("should not migrate the backup private key if backup has unknown algorithm", async () => {
// Here we have a new backup server side, and the migrated account has the previous backup key.
const backupResponse = {
...MSK_NOT_CACHED_DATASET.backupResponse,
algorithm: "m.megolm_backup.v8",
};
fetchMock.get("path:/_matrix/client/v3/room_keys/version", backupResponse);
fetchMock.post("path:/_matrix/client/v3/keys/query", MSK_NOT_CACHED_DATASET.keyQueryResponse);
await populateStore("test-store", MSK_NOT_CACHED_DATASET.dumpPath);
const cryptoStore = new IndexedDBCryptoStore(indexedDB, "test-store");
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: MSK_NOT_CACHED_DATASET.userId,
deviceId: MSK_NOT_CACHED_DATASET.deviceId,
cryptoStore,
pickleKey: MSK_NOT_CACHED_DATASET.pickleKey,
});
await matrixClient.initRustCrypto();
const privateBackupKey = await matrixClient.getCrypto()?.getSessionBackupPrivateKey();
expect(privateBackupKey).toBeNull();
});
it("should not migrate the backup private key if the backup has been deleted", async () => {
// The old backup has been deleted server side.
fetchMock.get("path:/_matrix/client/v3/room_keys/version", {
status: 404,
body: {
errcode: "M_NOT_FOUND",
error: "No backup found",
},
});
fetchMock.post("path:/_matrix/client/v3/keys/query", MSK_NOT_CACHED_DATASET.keyQueryResponse);
await populateStore("test-store", MSK_NOT_CACHED_DATASET.dumpPath);
const cryptoStore = new IndexedDBCryptoStore(indexedDB, "test-store");
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: MSK_NOT_CACHED_DATASET.userId,
deviceId: MSK_NOT_CACHED_DATASET.deviceId,
cryptoStore,
pickleKey: MSK_NOT_CACHED_DATASET.pickleKey,
});
await matrixClient.initRustCrypto();
const privateBackupKey = await matrixClient.getCrypto()?.getSessionBackupPrivateKey();
expect(privateBackupKey).toBeNull();
});
it("should migrate the backup private key if the backup matches", async () => {
// The old backup has been deleted server side.
fetchMock.get("path:/_matrix/client/v3/room_keys/version", MSK_NOT_CACHED_DATASET.backupResponse);
fetchMock.post("path:/_matrix/client/v3/keys/query", MSK_NOT_CACHED_DATASET.keyQueryResponse);
await populateStore("test-store", MSK_NOT_CACHED_DATASET.dumpPath);
const cryptoStore = new IndexedDBCryptoStore(indexedDB, "test-store");
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: MSK_NOT_CACHED_DATASET.userId,
deviceId: MSK_NOT_CACHED_DATASET.deviceId,
cryptoStore,
pickleKey: MSK_NOT_CACHED_DATASET.pickleKey,
});
await matrixClient.initRustCrypto();
const privateBackupKey = await matrixClient.getCrypto()?.getSessionBackupPrivateKey();
expect(privateBackupKey).toBeDefined();
});
});
it("should not migrate if account data is missing", async () => {
// See https://github.com/element-hq/element-web/issues/27447
// Given we have an almost-empty legacy account in the database
fetchMock.get("path:/_matrix/client/v3/room_keys/version", {
status: 404,
body: { errcode: "M_NOT_FOUND", error: "No backup found" },
});
fetchMock.post("path:/_matrix/client/v3/keys/query", EMPTY_ACCOUNT_DATASET.keyQueryResponse);
const testStoreName = "test-store";
await populateStore(testStoreName, EMPTY_ACCOUNT_DATASET.dumpPath);
const cryptoStore = new IndexedDBCryptoStore(indexedDB, testStoreName);
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: EMPTY_ACCOUNT_DATASET.userId,
deviceId: EMPTY_ACCOUNT_DATASET.deviceId,
cryptoStore,
pickleKey: EMPTY_ACCOUNT_DATASET.pickleKey,
});
// When we start Rust crypto, potentially triggering an upgrade
const progressListener = jest.fn();
matrixClient.addListener(CryptoEvent.LegacyCryptoStoreMigrationProgress, progressListener);
await matrixClient.initRustCrypto();
// Then no error occurs, and no upgrade happens
expect(progressListener.mock.calls.length).toBe(0);
}, 60000);
describe("Legacy trust migration", () => {
async function populateAndStartLegacyCryptoStore(dumpPath: string): Promise<IndexedDBCryptoStore> {
const testStoreName = "test-store";
await populateStore(testStoreName, dumpPath);
const cryptoStore = new IndexedDBCryptoStore(indexedDB, testStoreName);
await cryptoStore.startup();
return cryptoStore;
}
it("should not revert to untrusted if legacy was trusted but msk not in cache, big account", async () => {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", {
status: 404,
body: {
errcode: "M_NOT_FOUND",
error: "No backup found",
},
});
fetchMock.post("path:/_matrix/client/v3/keys/query", FULL_ACCOUNT_DATASET.keyQueryResponse);
const cryptoStore = await populateAndStartLegacyCryptoStore(FULL_ACCOUNT_DATASET.dumpPath);
// Remove the master key from the cache
await cryptoStore.doTxn("readwrite", [IndexedDBCryptoStore.STORE_ACCOUNT], (txn) => {
const objectStore = txn.objectStore("account");
objectStore.delete(`ssss_cache:master`);
});
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: FULL_ACCOUNT_DATASET.userId,
deviceId: FULL_ACCOUNT_DATASET.deviceId,
cryptoStore,
pickleKey: FULL_ACCOUNT_DATASET.pickleKey,
});
await matrixClient.initRustCrypto();
const verificationStatus = await matrixClient
.getCrypto()!
.getUserVerificationStatus(FULL_ACCOUNT_DATASET.userId);
expect(verificationStatus.isCrossSigningVerified()).toBe(true);
}, 60000);
it("should not revert to untrusted if legacy was trusted but msk not in cache", async () => {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", MSK_NOT_CACHED_DATASET.backupResponse);
fetchMock.post("path:/_matrix/client/v3/keys/query", MSK_NOT_CACHED_DATASET.keyQueryResponse);
const cryptoStore = await populateAndStartLegacyCryptoStore(MSK_NOT_CACHED_DATASET.dumpPath);
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: MSK_NOT_CACHED_DATASET.userId,
deviceId: MSK_NOT_CACHED_DATASET.deviceId,
cryptoStore,
pickleKey: MSK_NOT_CACHED_DATASET.pickleKey,
});
await matrixClient.initRustCrypto();
const verificationStatus = await matrixClient
.getCrypto()!
.getUserVerificationStatus("@migration:localhost");
expect(verificationStatus.isCrossSigningVerified()).toBe(true);
});
it("should not migrate local trust if key has changed", async () => {
fetchMock.get("path:/_matrix/client/v3/room_keys/version", MSK_NOT_CACHED_DATASET.backupResponse);
fetchMock.post("path:/_matrix/client/v3/keys/query", MSK_NOT_CACHED_DATASET.rotatedKeyQueryResponse);
const cryptoStore = await populateAndStartLegacyCryptoStore(MSK_NOT_CACHED_DATASET.dumpPath);
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: MSK_NOT_CACHED_DATASET.userId,
deviceId: MSK_NOT_CACHED_DATASET.deviceId,
cryptoStore,
pickleKey: MSK_NOT_CACHED_DATASET.pickleKey,
});
await matrixClient.initRustCrypto();
const verificationStatus = await matrixClient
.getCrypto()!
.getUserVerificationStatus("@migration:localhost");
expect(verificationStatus.isCrossSigningVerified()).toBe(false);
});
it("should not migrate local trust if was not trusted in legacy", async () => {
// Just 404 here for the test
fetchMock.get("path:/_matrix/client/v3/room_keys/version", {
status: 404,
body: {
errcode: "M_NOT_FOUND",
error: "No backup found",
},
});
fetchMock.post("path:/_matrix/client/v3/keys/query", IDENTITY_NOT_TRUSTED_DATASET.keyQueryResponse);
const cryptoStore = await populateAndStartLegacyCryptoStore(IDENTITY_NOT_TRUSTED_DATASET.dumpPath);
const matrixClient = createClient({
baseUrl: "http://test.server",
userId: IDENTITY_NOT_TRUSTED_DATASET.userId,
deviceId: IDENTITY_NOT_TRUSTED_DATASET.deviceId,
cryptoStore,
pickleKey: IDENTITY_NOT_TRUSTED_DATASET.pickleKey,
});
await matrixClient.initRustCrypto();
const verificationStatus = await matrixClient
.getCrypto()!
.getUserVerificationStatus("@untrusted:localhost");
expect(verificationStatus.isCrossSigningVerified()).toBe(false);
});
});
});
});
describe("MatrixClient.clearStores", () => {
@@ -96,10 +450,9 @@ describe("MatrixClient.clearStores", () => {
baseUrl: "http://test.server",
userId: "@alice:localhost",
deviceId: "aliceDevice",
pickleKey: "testKey",
});
await matrixClient.initRustCrypto();
await matrixClient.initRustCrypto({ storagePassword: "testKey" });
expect(await indexedDB.databases()).toHaveLength(2);
await matrixClient.stopClient();
@@ -0,0 +1,152 @@
/*
Copyright 2024 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, getSyncResponse, InitCrypto, syncPromise } from "../../test-utils/test-utils";
import { createClient, MatrixClient } from "../../../src";
import * as testData from "../../test-utils/test-data";
import { E2EKeyResponder } from "../../test-utils/E2EKeyResponder";
import { SyncResponder } from "../../test-utils/SyncResponder";
import { E2EKeyReceiver } from "../../test-utils/E2EKeyReceiver";
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();
});
/**
* Integration tests for to-device messages 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))("to-device-messages (%s)", (backend: string, initCrypto: InitCrypto) => {
let aliceClient: MatrixClient;
/** an object which intercepts `/keys/query` requests on the test homeserver */
let e2eKeyResponder: E2EKeyResponder;
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://server.com";
aliceClient = createClient({
baseUrl: homeserverUrl,
userId: testData.TEST_USER_ID,
accessToken: "akjgkrgjsalice",
deviceId: testData.TEST_DEVICE_ID,
});
e2eKeyResponder = new E2EKeyResponder(homeserverUrl);
new E2EKeyReceiver(homeserverUrl);
const syncResponder = new SyncResponder(homeserverUrl);
// add bob as known user
syncResponder.sendOrQueueSyncResponse(getSyncResponse([testData.BOB_TEST_USER_ID]));
// Silence warnings from the backup manager
fetchMock.getOnce(new URL("/_matrix/client/v3/room_keys/version", homeserverUrl).toString(), {
status: 404,
body: { errcode: "M_NOT_FOUND" },
});
fetchMock.get(new URL("/_matrix/client/v3/pushrules/", homeserverUrl).toString(), {});
fetchMock.get(new URL("/_matrix/client/versions/", homeserverUrl).toString(), {});
fetchMock.post(
new URL(
`/_matrix/client/v3/user/${encodeURIComponent(testData.TEST_USER_ID)}/filter`,
homeserverUrl,
).toString(),
{ filter_id: "fid" },
);
await initCrypto(aliceClient);
},
/* it can take a while to initialise the crypto library on the first pass, so bump up the timeout. */
10000,
);
afterEach(async () => {
aliceClient.stopClient();
fetchMock.mockReset();
});
describe("encryptToDeviceMessages", () => {
it("returns empty batch for device that is not known", async () => {
await aliceClient.startClient();
const toDeviceBatch = await aliceClient
.getCrypto()
?.encryptToDeviceMessages(
"m.test.event",
[{ userId: testData.BOB_TEST_USER_ID, deviceId: testData.BOB_TEST_DEVICE_ID }],
{
some: "content",
},
);
expect(toDeviceBatch).toBeDefined();
const { batch, eventType } = toDeviceBatch!;
expect(eventType).toBe("m.room.encrypted");
expect(batch.length).toBe(0);
});
it("returns encrypted batch for known device", async () => {
await aliceClient.startClient();
e2eKeyResponder.addDeviceKeys(testData.BOB_SIGNED_TEST_DEVICE_DATA);
fetchMock.post("express:/_matrix/client/v3/keys/claim", () => ({
one_time_keys: testData.BOB_ONE_TIME_KEYS,
}));
await syncPromise(aliceClient);
const toDeviceBatch = await aliceClient
.getCrypto()
?.encryptToDeviceMessages(
"m.test.event",
[{ userId: testData.BOB_TEST_USER_ID, deviceId: testData.BOB_TEST_DEVICE_ID }],
{
some: "content",
},
);
expect(toDeviceBatch?.batch.length).toBe(1);
expect(toDeviceBatch?.eventType).toBe("m.room.encrypted");
const { deviceId, payload, userId } = toDeviceBatch!.batch[0];
expect(deviceId).toBe(testData.BOB_TEST_DEVICE_ID);
expect(userId).toBe(testData.BOB_TEST_USER_ID);
expect(payload.algorithm).toBe("m.olm.v1.curve25519-aes-sha2");
expect(payload.sender_key).toEqual(expect.any(String));
expect(payload.ciphertext).toEqual(
expect.objectContaining({
[testData.BOB_SIGNED_TEST_DEVICE_DATA.keys[`curve25519:${testData.BOB_TEST_DEVICE_ID}`]]: {
body: expect.any(String),
type: 0,
},
}),
);
// for future: check that bob's device can decrypt the ciphertext?
});
});
});
+48 -32
View File
@@ -17,7 +17,7 @@ limitations under the License.
import "fake-indexeddb/auto";
import anotherjson from "another-json";
import { MockResponse } from "fetch-mock";
import FetchMock from "fetch-mock";
import fetchMock from "fetch-mock-jest";
import { IDBFactory } from "fake-indexeddb";
import { createHash } from "crypto";
@@ -78,6 +78,7 @@ import {
encryptGroupSessionKey,
encryptMegolmEvent,
encryptSecretSend,
getTestOlmAccountKeys,
ToDeviceEvent,
} from "./olm-utils";
import { KeyBackupInfo } from "../../../src/crypto-api";
@@ -85,15 +86,17 @@ import { encodeBase64 } from "../../../src/base64";
// The verification flows use javascript timers to set timeouts. We tell jest to use mock timer implementations
// to ensure that we don't end up with dangling timeouts.
jest.useFakeTimers();
// But the wasm bindings of matrix-sdk-crypto rely on a working `queueMicrotask`.
jest.useFakeTimers({ doNotFake: ["queueMicrotask"] });
beforeAll(async () => {
// we use the libolm primitives in the test, so init the Olm library
await global.Olm.init();
await globalThis.Olm.init();
});
// load the rust library. This can take a few seconds on a slow GH worker.
beforeAll(async () => {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const RustSdkCryptoJs = await require("@matrix-org/matrix-sdk-crypto-wasm");
await RustSdkCryptoJs.initAsync();
}, 10000);
@@ -262,7 +265,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
// The dummy device makes up a curve25519 keypair and sends the public bit back in an `m.key.verification.key'
// We use the Curve25519, HMAC and HKDF implementations in libolm, for now
const olmSAS = new global.Olm.SAS();
const olmSAS = new globalThis.Olm.SAS();
returnToDeviceMessageFromSync(buildSasKeyMessage(transactionId, olmSAS.get_pubkey()));
// alice responds with a 'key' ...
@@ -356,7 +359,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
// The dummy device makes up a curve25519 keypair and uses the hash in an 'm.key.verification.accept'
// We use the Curve25519, HMAC and HKDF implementations in libolm, for now
const olmSAS = new global.Olm.SAS();
const olmSAS = new globalThis.Olm.SAS();
const commitmentStr = olmSAS.get_pubkey() + anotherjson.stringify(toDeviceMessage);
sendToDevicePromise = expectSendToDeviceMessage("m.key.verification.key");
@@ -471,21 +474,23 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
expect(request.phase).toEqual(VerificationPhase.Ready);
// we should now have QR data we can display
const qrCodeBuffer = (await request.generateQRCode())!;
expect(qrCodeBuffer).toBeTruthy();
const rawQrCodeBuffer = (await request.generateQRCode())!;
expect(rawQrCodeBuffer).toBeTruthy();
const qrCodeBuffer = new Uint8Array(rawQrCodeBuffer);
const textDecoder = new TextDecoder();
// https://spec.matrix.org/v1.7/client-server-api/#qr-code-format
expect(qrCodeBuffer.subarray(0, 6).toString("latin1")).toEqual("MATRIX");
expect(qrCodeBuffer.readUint8(6)).toEqual(0x02); // version
expect(qrCodeBuffer.readUint8(7)).toEqual(0x02); // mode
const txnIdLen = qrCodeBuffer.readUint16BE(8);
expect(qrCodeBuffer.subarray(10, 10 + txnIdLen).toString("utf-8")).toEqual(transactionId);
expect(textDecoder.decode(qrCodeBuffer.slice(0, 6))).toEqual("MATRIX");
expect(qrCodeBuffer[6]).toEqual(0x02); // version
expect(qrCodeBuffer[7]).toEqual(0x02); // mode
const txnIdLen = (qrCodeBuffer[8] << 8) + qrCodeBuffer[9];
expect(textDecoder.decode(qrCodeBuffer.slice(10, 10 + txnIdLen))).toEqual(transactionId);
// Alice's device's public key comes next, but we have nothing to do with it here.
// const aliceDevicePubKey = qrCodeBuffer.subarray(10 + txnIdLen, 32 + 10 + txnIdLen);
expect(qrCodeBuffer.subarray(42 + txnIdLen, 32 + 42 + txnIdLen)).toEqual(
Buffer.from(MASTER_CROSS_SIGNING_PUBLIC_KEY_BASE64, "base64"),
// const aliceDevicePubKey = qrCodeBuffer.slice(10 + txnIdLen, 32 + 10 + txnIdLen);
expect(encodeUnpaddedBase64(qrCodeBuffer.slice(42 + txnIdLen, 32 + 42 + txnIdLen))).toEqual(
MASTER_CROSS_SIGNING_PUBLIC_KEY_BASE64,
);
const sharedSecret = qrCodeBuffer.subarray(74 + txnIdLen);
const sharedSecret = qrCodeBuffer.slice(74 + txnIdLen);
// we should still be "Ready" and have no verifier
expect(request.phase).toEqual(VerificationPhase.Ready);
@@ -743,6 +748,8 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
expect(toDeviceMessage.transaction_id).toEqual(transactionId);
expect(toDeviceMessage.code).toEqual("m.user");
expect(request.phase).toEqual(VerificationPhase.Cancelled);
expect(request.cancellationCode).toEqual("m.user");
expect(request.cancellingUserId).toEqual("@alice:localhost");
});
it("can cancel during the SAS phase", async () => {
@@ -801,7 +808,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
// we should now have QR data we can display
const qrCodeBuffer = (await request.generateQRCode())!;
expect(qrCodeBuffer).toBeTruthy();
const sharedSecret = qrCodeBuffer.subarray(74 + transactionId.length);
const sharedSecret = qrCodeBuffer.slice(74 + transactionId.length);
// the dummy device "scans" the displayed QR code and acknowledges it with a "m.key.verification.start"
returnToDeviceMessageFromSync(buildReciprocateStartMessage(transactionId, sharedSecret));
@@ -986,6 +993,18 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
aliceClient.setGlobalErrorOnUnknownDevices(false);
syncResponder.sendOrQueueSyncResponse(getSyncResponse([BOB_TEST_USER_ID]));
await syncPromise(aliceClient);
// Rust crypto requires the sender's device keys before it accepts a
// verification request.
if (backend === "rust-sdk") {
const crypto = aliceClient.getCrypto()!;
const bobDeviceKeys = getTestOlmAccountKeys(testOlmAccount, BOB_TEST_USER_ID, "BobDevice");
e2eKeyResponder.addDeviceKeys(bobDeviceKeys);
syncResponder.sendOrQueueSyncResponse({ device_lists: { changed: [BOB_TEST_USER_ID] } });
await syncPromise(aliceClient);
await crypto.getUserDeviceInfo([BOB_TEST_USER_ID]);
}
});
/**
@@ -1259,14 +1278,11 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
const requestId = await requestPromises.get("m.megolm_backup.v1");
const keyBackupIsCached = emitPromise(aliceClient, CryptoEvent.KeyBackupDecryptionKeyCached);
await sendBackupGossipAndExpectVersion(requestId!, BACKUP_DECRYPTION_KEY_BASE64, matchingBackupInfo);
// We are lacking a way to signal that the secret has been received, so we wait a bit..
jest.useRealTimers();
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
jest.useFakeTimers();
await keyBackupIsCached;
// the backup secret should be cached
const cachedKey = await aliceClient.getCrypto()!.getSessionBackupPrivateKey();
@@ -1288,7 +1304,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
jest.useFakeTimers();
jest.useFakeTimers({ doNotFake: ["queueMicrotask"] });
// the backup secret should not be cached
const cachedKey = await aliceClient.getCrypto()!.getSessionBackupPrivateKey();
@@ -1312,7 +1328,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
jest.useFakeTimers();
jest.useFakeTimers({ doNotFake: ["queueMicrotask"] });
// the backup secret should not be cached
const cachedKey = await aliceClient.getCrypto()!.getSessionBackupPrivateKey();
@@ -1337,7 +1353,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
jest.useFakeTimers();
jest.useFakeTimers({ doNotFake: ["queueMicrotask"] });
// the backup secret should not be cached
const cachedKey = await aliceClient.getCrypto()!.getSessionBackupPrivateKey();
@@ -1358,7 +1374,7 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("verification (%s)", (backend: st
await new Promise((resolve) => {
setTimeout(resolve, 500);
});
jest.useFakeTimers();
jest.useFakeTimers({ doNotFake: ["queueMicrotask"] });
// the backup secret should not be cached
const cachedKey = await aliceClient.getCrypto()!.getSessionBackupPrivateKey();
@@ -1511,7 +1527,7 @@ function expectSendToDeviceMessage(msgtype: string): Promise<{ messages: any }>
return new Promise((resolve) => {
fetchMock.putOnce(
new RegExp(`/_matrix/client/(r0|v3)/sendToDevice/${escapeRegExp(msgtype)}`),
(url: string, opts: RequestInit): MockResponse => {
(url: string, opts: RequestInit): FetchMock.MockResponse => {
resolve(JSON.parse(opts.body as string));
return {};
},
@@ -1535,7 +1551,7 @@ function mockSecretRequestAndGetPromises(): Map<string, Promise<string>> {
fetchMock.put(
new RegExp(`/_matrix/client/(r0|v3)/sendToDevice/m.secret.request`),
(url: string, opts: RequestInit): MockResponse => {
(url: string, opts: RequestInit): FetchMock.MockResponse => {
const messages = JSON.parse(opts.body as string).messages[TEST_USER_ID];
// rust crypto broadcasts to all devices, old crypto to a specific device, take the first one
const content = Object.values(messages)[0] as any;
@@ -1626,7 +1642,7 @@ function buildReadyMessage(
}
/** build an m.key.verification.start to-device message suitable for the m.reciprocate.v1 flow, originating from the dummy device */
function buildReciprocateStartMessage(transactionId: string, sharedSecret: Uint8Array) {
function buildReciprocateStartMessage(transactionId: string, sharedSecret: ArrayBuffer) {
return {
type: "m.key.verification.start",
content: {
@@ -1722,7 +1738,7 @@ function buildQRCode(
key2Base64: string,
sharedSecret: string,
mode = 0x02,
): Uint8Array {
): Uint8ClampedArray {
// https://spec.matrix.org/v1.7/client-server-api/#qr-code-format
const qrCodeBuffer = Buffer.alloc(150); // oversize
@@ -1738,5 +1754,5 @@ function buildQRCode(
idx += qrCodeBuffer.write(sharedSecret, idx);
// truncate to the right length
return qrCodeBuffer.subarray(0, idx);
return new Uint8ClampedArray(qrCodeBuffer.subarray(0, idx));
}
+6 -5
View File
@@ -19,6 +19,7 @@ limitations under the License.
import { TestClient } from "../TestClient";
import * as testUtils from "../test-utils/test-utils";
import { logger } from "../../src/logger";
import { KnownMembership } from "../../src/@types/membership";
const ROOM_ID = "!room:id";
@@ -43,7 +44,7 @@ function getSyncResponse(roomMembers: string[]) {
stateEvents,
roomMembers.map((m) =>
testUtils.mkMembership({
mship: "join",
mship: KnownMembership.Join,
sender: m,
}),
),
@@ -66,7 +67,7 @@ function getSyncResponse(roomMembers: string[]) {
}
describe("DeviceList management:", function () {
if (!global.Olm) {
if (!globalThis.Olm) {
logger.warn("not running deviceList tests: Olm not present");
return;
}
@@ -76,7 +77,7 @@ describe("DeviceList management:", function () {
async function createTestClient() {
const testClient = new TestClient("@alice:localhost", "xzcvb", "akjgkrgjs", sessionStoreBackend);
await testClient.client.initCrypto();
await testClient.client.initLegacyCrypto();
return testClient;
}
@@ -323,7 +324,7 @@ describe("DeviceList management:", function () {
timeline: {
events: [
testUtils.mkMembership({
mship: "leave",
mship: KnownMembership.Leave,
sender: "@bob:xyz",
}),
],
@@ -357,7 +358,7 @@ describe("DeviceList management:", function () {
timeline: {
events: [
testUtils.mkMembership({
mship: "leave",
mship: KnownMembership.Leave,
sender: "@bob:xyz",
}),
],
@@ -28,6 +28,7 @@ import {
} from "../../src";
import * as utils from "../test-utils/test-utils";
import { TestClient } from "../TestClient";
import { KnownMembership } from "../../src/@types/membership";
describe("MatrixClient events", function () {
const selfUserId = "@alice:localhost";
@@ -85,7 +86,7 @@ describe("MatrixClient events", function () {
events: [
utils.mkMembership({
room: "!erufh:bar",
mship: "join",
mship: KnownMembership.Join,
user: "@foo:bar",
}),
utils.mkEvent({
@@ -272,7 +273,7 @@ describe("MatrixClient events", function () {
membersInvokeCount++;
expect(member.roomId).toEqual("!erufh:bar");
expect(member.userId).toEqual("@foo:bar");
expect(member.membership).toEqual("join");
expect(member.membership).toEqual(KnownMembership.Join);
});
client!.on(RoomStateEvent.NewMember, function (event, state, member) {
newMemberInvokeCount++;
@@ -310,7 +311,7 @@ describe("MatrixClient events", function () {
});
client!.on(RoomMemberEvent.Membership, function (event, member) {
membershipInvokeCount++;
expect(member.membership).toEqual("join");
expect(member.membership).toEqual(KnownMembership.Join);
});
client!.startClient();
+17 -44
View File
@@ -33,9 +33,10 @@ import {
import { logger } from "../../src/logger";
import { encodeParams, encodeUri, QueryDict, replaceParam } from "../../src/utils";
import { TestClient } from "../TestClient";
import { FeatureSupport, Thread, THREAD_RELATION_TYPE, ThreadEvent } from "../../src/models/thread";
import { FeatureSupport, Thread, ThreadEvent } from "../../src/models/thread";
import { emitPromise } from "../test-utils/test-utils";
import { Feature, ServerSupport } from "../../src/feature";
import { KnownMembership } from "../../src/@types/membership";
const userId = "@alice:localhost";
const userName = "Alice";
@@ -63,7 +64,7 @@ const buildRelationPaginationQuery = (params: QueryDict): string => {
const USER_MEMBERSHIP_EVENT = utils.mkMembership({
room: roomId,
mship: "join",
mship: KnownMembership.Join,
user: userId,
name: userName,
event: false,
@@ -98,7 +99,7 @@ const INITIAL_SYNC_DATA = {
events: [
withoutRoomId(ROOM_NAME_EVENT),
utils.mkMembership({
mship: "join",
mship: KnownMembership.Join,
user: otherUserId,
name: "Bob",
event: false,
@@ -607,11 +608,6 @@ describe("MatrixClient event timelines", function () {
await client.stopClient(); // we don't need the client to be syncing at this time
const room = client.getRoom(roomId)!;
httpBackend
.when("GET", "/rooms/!foo%3Abar/event/" + encodeURIComponent(THREAD_ROOT.event_id!))
.respond(200, function () {
return THREAD_ROOT;
});
httpBackend
.when("GET", "/rooms/!foo%3Abar/event/" + encodeURIComponent(THREAD_ROOT.event_id!))
.respond(200, function () {
@@ -623,9 +619,7 @@ describe("MatrixClient event timelines", function () {
"GET",
"/rooms/!foo%3Abar/relations/" +
encodeURIComponent(THREAD_ROOT.event_id!) +
"/" +
encodeURIComponent(THREAD_RELATION_TYPE.name) +
buildRelationPaginationQuery({ dir: Direction.Backward, limit: 1 }),
buildRelationPaginationQuery({ dir: Direction.Backward }),
)
.respond(200, function () {
return {
@@ -1150,21 +1144,18 @@ describe("MatrixClient event timelines", function () {
const prom = emitPromise(room, ThreadEvent.Update);
// Assume we're seeing the reply while loading backlog
await room.addLiveEvents([THREAD_REPLY2]);
await room.addLiveEvents([THREAD_REPLY2], { addToState: false });
httpBackend
.when(
"GET",
"/_matrix/client/v1/rooms/!foo%3Abar/relations/" +
encodeURIComponent(THREAD_ROOT_UPDATED.event_id!) +
"/" +
encodeURIComponent(THREAD_RELATION_TYPE.name),
"/_matrix/client/v1/rooms/!foo%3Abar/relations/" + encodeURIComponent(THREAD_ROOT_UPDATED.event_id!),
)
.respond(200, {
chunk: [THREAD_REPLY3.event, THREAD_REPLY2.event, THREAD_REPLY],
});
await flushHttp(prom);
// but while loading the metadata, a new reply has arrived
await room.addLiveEvents([THREAD_REPLY3]);
await room.addLiveEvents([THREAD_REPLY3], { addToState: false });
const thread = room.getThread(THREAD_ROOT_UPDATED.event_id!)!;
// then the events should still be all in the right order
expect(thread.events.map((it) => it.getId())).toEqual([
@@ -1256,17 +1247,14 @@ describe("MatrixClient event timelines", function () {
const prom = emitPromise(room, ThreadEvent.Update);
// Assume we're seeing the reply while loading backlog
await room.addLiveEvents([THREAD_REPLY2]);
await room.addLiveEvents([THREAD_REPLY2], { addToState: false });
httpBackend
.when(
"GET",
"/_matrix/client/v1/rooms/!foo%3Abar/relations/" +
encodeURIComponent(THREAD_ROOT_UPDATED.event_id!) +
"/" +
encodeURIComponent(THREAD_RELATION_TYPE.name) +
buildRelationPaginationQuery({
dir: Direction.Backward,
limit: 3,
recurse: true,
}),
)
@@ -1275,7 +1263,7 @@ describe("MatrixClient event timelines", function () {
});
await flushHttp(prom);
// but while loading the metadata, a new reply has arrived
await room.addLiveEvents([THREAD_REPLY3]);
await room.addLiveEvents([THREAD_REPLY3], { addToState: false });
const thread = room.getThread(THREAD_ROOT_UPDATED.event_id!)!;
// then the events should still be all in the right order
expect(thread.events.map((it) => it.getId())).toEqual([
@@ -1321,11 +1309,7 @@ describe("MatrixClient event timelines", function () {
function respondToThread(root: Partial<IEvent>, replies: Partial<IEvent>[]): ExpectedHttpRequest {
const request = httpBackend.when(
"GET",
"/_matrix/client/v1/rooms/!foo%3Abar/relations/" +
encodeURIComponent(root.event_id!) +
"/" +
encodeURIComponent(THREAD_RELATION_TYPE.name) +
"?dir=b&limit=1",
"/_matrix/client/v1/rooms/!foo%3Abar/relations/" + encodeURIComponent(root.event_id!) + "?dir=b",
);
request.respond(200, function () {
return {
@@ -1557,9 +1541,7 @@ describe("MatrixClient event timelines", function () {
expect(timelineSets).not.toBeNull();
respondToThreads(threadsResponse);
respondToThreads(threadsResponse);
respondToEvent(THREAD_ROOT);
respondToEvent(THREAD2_ROOT);
respondToThread(THREAD_ROOT, [THREAD_REPLY]);
respondToThread(THREAD2_ROOT, [THREAD2_REPLY]);
await flushHttp(room.fetchRoomThreads());
const threadIds = room.getThreads().map((thread) => thread.id);
@@ -1567,7 +1549,7 @@ describe("MatrixClient event timelines", function () {
expect(threadIds).toContain(THREAD2_ROOT.event_id);
const [allThreads] = timelineSets!;
const timeline = allThreads.getLiveTimeline()!;
// Test threads are in chronological order
// Test threads are in chronological order (first thread should be first because it has a more recent reply)
expect(timeline.getEvents().map((it) => it.event.event_id)).toEqual([
THREAD_ROOT.event_id,
THREAD2_ROOT.event_id,
@@ -1578,8 +1560,7 @@ describe("MatrixClient event timelines", function () {
thread.initialEventsFetched = true;
const prom = emitPromise(room, ThreadEvent.NewReply);
respondToEvent(THREAD_ROOT_UPDATED);
respondToEvent(THREAD2_ROOT);
await room.addLiveEvents([THREAD_REPLY2]);
await room.addLiveEvents([THREAD_REPLY2], { addToState: false });
await httpBackend.flushAllExpected();
await prom;
expect(thread.length).toBe(2);
@@ -1655,7 +1636,7 @@ describe("MatrixClient event timelines", function () {
...THREAD_ROOT.unsigned!["m.relations"],
"io.element.thread": {
...THREAD_ROOT.unsigned!["m.relations"]!["io.element.thread"],
count: 2,
count: 1,
latest_event: THREAD_REPLY,
},
},
@@ -1704,8 +1685,7 @@ describe("MatrixClient event timelines", function () {
thread.initialEventsFetched = true;
const prom = emitPromise(room, ThreadEvent.Update);
respondToEvent(THREAD_ROOT_UPDATED);
respondToEvent(THREAD2_ROOT);
await room.addLiveEvents([THREAD_REPLY_REACTION]);
await room.addLiveEvents([THREAD_REPLY_REACTION], { addToState: false });
await httpBackend.flushAllExpected();
await prom;
expect(thread.length).toBe(1); // reactions don't count towards the length of a thread
@@ -1942,7 +1922,7 @@ describe("MatrixClient event timelines", function () {
// a state event, followed by a redaction thereof
const event = utils.mkMembership({
mship: "join",
mship: KnownMembership.Join,
user: otherUserId,
});
const redaction = utils.mkEvent({
@@ -2019,11 +1999,6 @@ describe("MatrixClient event timelines", function () {
},
},
});
httpBackend
.when("GET", "/rooms/!foo%3Abar/event/" + encodeURIComponent(THREAD_ROOT.event_id!))
.respond(200, function () {
return THREAD_ROOT;
});
httpBackend
.when("GET", "/rooms/!foo%3Abar/event/" + encodeURIComponent(THREAD_ROOT.event_id!))
.respond(200, function () {
@@ -2034,9 +2009,7 @@ describe("MatrixClient event timelines", function () {
"GET",
"/_matrix/client/v1/rooms/!foo%3Abar/relations/" +
encodeURIComponent(THREAD_ROOT.event_id!) +
"/" +
encodeURIComponent(THREAD_RELATION_TYPE.name) +
buildRelationPaginationQuery({ dir: Direction.Backward, limit: 1 }),
buildRelationPaginationQuery({ dir: Direction.Backward }),
)
.respond(200, function () {
return {
+266 -62
View File
@@ -19,7 +19,16 @@ import { Mocked } from "jest-mock";
import * as utils from "../test-utils/test-utils";
import { CRYPTO_ENABLED, IStoredClientOpts, MatrixClient } from "../../src/client";
import { MatrixEvent } from "../../src/models/event";
import { Filter, KnockRoomOpts, MemoryStore, Method, Room, SERVICE_TYPES } from "../../src/matrix";
import {
Filter,
JoinRule,
KnockRoomOpts,
MemoryStore,
Method,
Room,
RoomSummary,
SERVICE_TYPES,
} from "../../src/matrix";
import { TestClient } from "../TestClient";
import { THREAD_RELATION_TYPE } from "../../src/models/thread";
import { IFilterDefinition } from "../../src/filter";
@@ -27,6 +36,7 @@ import { ISearchResults } from "../../src/@types/search";
import { IStore } from "../../src/store";
import { CryptoBackend } from "../../src/common-crypto/CryptoBackend";
import { SetPresence } from "../../src/sync";
import { KnownMembership } from "../../src/@types/membership";
describe("MatrixClient", function () {
const userId = "@alice:localhost";
@@ -158,14 +168,17 @@ describe("MatrixClient", function () {
type: "test",
content: {},
});
room.addLiveEvents([
utils.mkMembership({
user: userId,
room: roomId,
mship: "join",
event: true,
}),
]);
room.addLiveEvents(
[
utils.mkMembership({
user: userId,
room: roomId,
mship: KnownMembership.Join,
event: true,
}),
],
{ addToState: true },
);
httpBackend.verifyNoOutstandingRequests();
store.storeRoom(room);
@@ -178,14 +191,17 @@ describe("MatrixClient", function () {
const roomId = "!roomId:server";
const roomAlias = "#my-fancy-room:server";
const room = new Room(roomId, client, userId);
room.addLiveEvents([
utils.mkMembership({
user: userId,
room: roomId,
mship: "join",
event: true,
}),
]);
room.addLiveEvents(
[
utils.mkMembership({
user: userId,
room: roomId,
mship: KnownMembership.Join,
event: true,
}),
],
{ addToState: true },
);
store.storeRoom(room);
// The method makes a request to resolve the alias
@@ -247,7 +263,7 @@ describe("MatrixClient", function () {
.when("POST", "/knock/" + encodeURIComponent(roomId))
.check((request) => {
expect(request.data).toEqual({ reason: opts.reason });
expect(request.queryParams).toEqual({ server_name: opts.viaServers });
expect(request.queryParams).toEqual({ server_name: opts.viaServers, via: opts.viaServers });
})
.respond(200, { room_id: roomId });
@@ -265,14 +281,17 @@ describe("MatrixClient", function () {
content: {},
});
room.addLiveEvents([
utils.mkMembership({
user: userId,
room: roomId,
mship: "knock",
event: true,
}),
]);
room.addLiveEvents(
[
utils.mkMembership({
user: userId,
room: roomId,
mship: KnownMembership.Knock,
event: true,
}),
],
{ addToState: true },
);
httpBackend.verifyNoOutstandingRequests();
store.storeRoom(room);
@@ -631,9 +650,9 @@ describe("MatrixClient", function () {
}
beforeEach(function () {
// running initCrypto should trigger a key upload
// running initLegacyCrypto should trigger a key upload
httpBackend.when("POST", "/keys/upload").respond(200, {});
return Promise.all([client.initCrypto(), httpBackend.flush("/keys/upload", 1)]);
return Promise.all([client.initLegacyCrypto(), httpBackend.flush("/keys/upload", 1)]);
});
afterEach(() => {
@@ -1283,18 +1302,109 @@ describe("MatrixClient", function () {
});
describe("getCapabilities", () => {
it("should cache by default", async () => {
it("should return cached capabilities if present", async () => {
const capsObject = {
"m.change_password": false,
};
httpBackend!.when("GET", "/versions").respond(200, {});
httpBackend!.when("GET", "/pushrules").respond(200, {});
httpBackend!.when("POST", "/filter").respond(200, { filter_id: "a filter id" });
httpBackend.when("GET", "/capabilities").respond(200, {
capabilities: {
"m.change_password": false,
},
capabilities: capsObject,
});
const prom = httpBackend.flushAllExpected();
const capabilities1 = await client.getCapabilities();
const capabilities2 = await client.getCapabilities();
client.startClient();
await httpBackend!.flushAllExpected();
expect(await client.getCapabilities()).toEqual(capsObject);
});
it("should fetch capabilities if cache not present", async () => {
const capsObject = {
"m.change_password": false,
};
httpBackend.when("GET", "/capabilities").respond(200, {
capabilities: capsObject,
});
const capsPromise = client.getCapabilities();
await httpBackend!.flushAllExpected();
expect(await capsPromise).toEqual(capsObject);
});
});
describe("getCachedCapabilities", () => {
it("should return cached capabilities or undefined", async () => {
const capsObject = {
"m.change_password": false,
};
httpBackend!.when("GET", "/versions").respond(200, {});
httpBackend!.when("GET", "/pushrules").respond(200, {});
httpBackend!.when("POST", "/filter").respond(200, { filter_id: "a filter id" });
httpBackend.when("GET", "/capabilities").respond(200, {
capabilities: capsObject,
});
expect(client.getCachedCapabilities()).toBeUndefined();
client.startClient();
await httpBackend!.flushAllExpected();
expect(client.getCachedCapabilities()).toEqual(capsObject);
});
});
describe("fetchCapabilities", () => {
const capsObject = {
"m.change_password": false,
};
beforeEach(() => {
httpBackend.when("GET", "/capabilities").respond(200, {
capabilities: capsObject,
});
});
afterEach(() => {
jest.useRealTimers();
});
it("should always fetch capabilities and then cache", async () => {
const prom = client.fetchCapabilities();
await httpBackend.flushAllExpected();
const caps = await prom;
expect(caps).toEqual(capsObject);
});
it("should write-through the cache", async () => {
httpBackend!.when("GET", "/versions").respond(200, {});
httpBackend!.when("GET", "/pushrules").respond(200, {});
httpBackend!.when("POST", "/filter").respond(200, { filter_id: "a filter id" });
client.startClient();
await httpBackend!.flushAllExpected();
expect(client.getCachedCapabilities()).toEqual(capsObject);
const newCapsObject = {
"m.change_password": true,
};
httpBackend.when("GET", "/capabilities").respond(200, {
capabilities: newCapsObject,
});
const prom = client.fetchCapabilities();
await httpBackend.flushAllExpected();
await prom;
expect(capabilities1).toStrictEqual(capabilities2);
expect(client.getCachedCapabilities()).toEqual(newCapsObject);
});
});
@@ -1709,6 +1819,124 @@ describe("MatrixClient", function () {
await Promise.all([client.unbindThreePid("email", "alice@server.com"), httpBackend.flushAllExpected()]);
});
});
describe("getRoomSummary", () => {
const roomId = "!foo:bar";
const encodedRoomId = encodeURIComponent(roomId);
const roomSummary: RoomSummary = {
"room_id": roomId,
"name": "My Room",
"avatar_url": "",
"topic": "My room topic",
"world_readable": false,
"guest_can_join": false,
"num_joined_members": 1,
"room_type": "",
"join_rule": JoinRule.Public,
"membership": "leave",
"im.nheko.summary.room_version": "6",
"im.nheko.summary.encryption": "algo",
};
const prefix = "/_matrix/client/unstable/im.nheko.summary/";
const suffix = `summary/${encodedRoomId}`;
const deprecatedSuffix = `rooms/${encodedRoomId}/summary`;
const errorUnrecogStatus = 404;
const errorUnrecogBody = {
errcode: "M_UNRECOGNIZED",
error: "Unsupported endpoint",
};
const errorBadreqStatus = 400;
const errorBadreqBody = {
errcode: "M_UNKNOWN",
error: "Invalid request",
};
it("should respond with a valid room summary object", () => {
httpBackend.when("GET", prefix + suffix).respond(200, roomSummary);
const prom = client.getRoomSummary(roomId).then((response) => {
expect(response).toEqual(roomSummary);
});
httpBackend.flush("");
return prom;
});
it("should allow fallback to the deprecated endpoint", () => {
httpBackend.when("GET", prefix + suffix).respond(errorUnrecogStatus, errorUnrecogBody);
httpBackend.when("GET", prefix + deprecatedSuffix).respond(200, roomSummary);
const prom = client.getRoomSummary(roomId).then((response) => {
expect(response).toEqual(roomSummary);
});
httpBackend.flush("");
return prom;
});
it("should respond to unsupported path with error", () => {
httpBackend.when("GET", prefix + suffix).respond(errorUnrecogStatus, errorUnrecogBody);
httpBackend.when("GET", prefix + deprecatedSuffix).respond(errorUnrecogStatus, errorUnrecogBody);
const prom = client.getRoomSummary(roomId).then(
function (response) {
throw Error("request not failed");
},
function (error) {
expect(error.httpStatus).toEqual(errorUnrecogStatus);
expect(error.errcode).toEqual(errorUnrecogBody.errcode);
expect(error.message).toEqual(`MatrixError: [${errorUnrecogStatus}] ${errorUnrecogBody.error}`);
},
);
httpBackend.flush("");
return prom;
});
it("should respond to invalid path arguments with error", () => {
httpBackend.when("GET", prefix).respond(errorBadreqStatus, errorBadreqBody);
const prom = client.getRoomSummary("notAroom").then(
function (response) {
throw Error("request not failed");
},
function (error) {
expect(error.httpStatus).toEqual(errorBadreqStatus);
expect(error.errcode).toEqual(errorBadreqBody.errcode);
expect(error.message).toEqual(`MatrixError: [${errorBadreqStatus}] ${errorBadreqBody.error}`);
},
);
httpBackend.flush("");
return prom;
});
});
describe("getDomain", () => {
it("should return null if no userId is set", () => {
const client = new MatrixClient({ baseUrl: "http://localhost" });
expect(client.getDomain()).toBeNull();
});
it("should return the domain of the userId", () => {
expect(client.getDomain()).toBe("localhost");
});
});
describe("getUserIdLocalpart", () => {
it("should return null if no userId is set", () => {
const client = new MatrixClient({ baseUrl: "http://localhost" });
expect(client.getUserIdLocalpart()).toBeNull();
});
it("should return the localpart of the userId", () => {
expect(client.getUserIdLocalpart()).toBe("alice");
});
});
});
function withThreadId(event: MatrixEvent, newThreadId: string): MatrixEvent {
@@ -1719,7 +1947,6 @@ function withThreadId(event: MatrixEvent, newThreadId: string): MatrixEvent {
const buildEventMessageInThread = (root: MatrixEvent) =>
new MatrixEvent({
age: 80098509,
content: {
"algorithm": "m.megolm.v1.aes-sha2",
"ciphertext": "ENCRYPTEDSTUFF",
@@ -1740,12 +1967,10 @@ const buildEventMessageInThread = (root: MatrixEvent) =>
sender: "@andybalaam-test1:matrix.org",
type: "m.room.encrypted",
unsigned: { age: 80098509 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventPollResponseReference = () =>
new MatrixEvent({
age: 80098509,
content: {
"algorithm": "m.megolm.v1.aes-sha2",
"ciphertext": "ENCRYPTEDSTUFF",
@@ -1763,7 +1988,6 @@ const buildEventPollResponseReference = () =>
sender: "@andybalaam-test1:matrix.org",
type: "m.room.encrypted",
unsigned: { age: 80106237 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventReaction = (event: MatrixEvent) =>
@@ -1803,7 +2027,6 @@ const buildEventRedaction = (event: MatrixEvent) =>
const buildEventPollStartThreadRoot = () =>
new MatrixEvent({
age: 80108647,
content: {
algorithm: "m.megolm.v1.aes-sha2",
ciphertext: "ENCRYPTEDSTUFF",
@@ -1817,12 +2040,10 @@ const buildEventPollStartThreadRoot = () =>
sender: "@andybalaam-test1:matrix.org",
type: "m.room.encrypted",
unsigned: { age: 80108647 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventReply = (target: MatrixEvent) =>
new MatrixEvent({
age: 80098509,
content: {
"algorithm": "m.megolm.v1.aes-sha2",
"ciphertext": "ENCRYPTEDSTUFF",
@@ -1841,12 +2062,10 @@ const buildEventReply = (target: MatrixEvent) =>
sender: "@andybalaam-test1:matrix.org",
type: "m.room.encrypted",
unsigned: { age: 80098509 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventRoomName = () =>
new MatrixEvent({
age: 80123249,
content: {
name: "1 poll, 1 vote, 1 thread",
},
@@ -1857,12 +2076,10 @@ const buildEventRoomName = () =>
state_key: "",
type: "m.room.name",
unsigned: { age: 80123249 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventEncryption = () =>
new MatrixEvent({
age: 80123383,
content: {
algorithm: "m.megolm.v1.aes-sha2",
},
@@ -1873,12 +2090,10 @@ const buildEventEncryption = () =>
state_key: "",
type: "m.room.encryption",
unsigned: { age: 80123383 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventGuestAccess = () =>
new MatrixEvent({
age: 80123473,
content: {
guest_access: "can_join",
},
@@ -1889,12 +2104,10 @@ const buildEventGuestAccess = () =>
state_key: "",
type: "m.room.guest_access",
unsigned: { age: 80123473 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventHistoryVisibility = () =>
new MatrixEvent({
age: 80123556,
content: {
history_visibility: "shared",
},
@@ -1905,14 +2118,12 @@ const buildEventHistoryVisibility = () =>
state_key: "",
type: "m.room.history_visibility",
unsigned: { age: 80123556 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventJoinRules = () =>
new MatrixEvent({
age: 80123696,
content: {
join_rule: "invite",
join_rule: KnownMembership.Invite,
},
event_id: "$6JDDeDp7fEc0F6YnTWMruNcKWFltR3e9wk7wWDDJrAU",
origin_server_ts: 1643815441191,
@@ -1921,12 +2132,10 @@ const buildEventJoinRules = () =>
state_key: "",
type: "m.room.join_rules",
unsigned: { age: 80123696 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventPowerLevels = () =>
new MatrixEvent({
age: 80124105,
content: {
ban: 50,
events: {
@@ -1957,16 +2166,14 @@ const buildEventPowerLevels = () =>
state_key: "",
type: "m.room.power_levels",
unsigned: { age: 80124105 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventMember = () =>
new MatrixEvent({
age: 80125279,
content: {
avatar_url: "mxc://matrix.org/aNtbVcFfwotudypZcHsIcPOc",
displayname: "andybalaam-test1",
membership: "join",
membership: KnownMembership.Join,
},
event_id: "$Ex5eVmMs_ti784mo8bgddynbwLvy6231lCycJr7Cl9M",
origin_server_ts: 1643815439608,
@@ -1975,12 +2182,10 @@ const buildEventMember = () =>
state_key: "@andybalaam-test1:matrix.org",
type: "m.room.member",
unsigned: { age: 80125279 },
user_id: "@andybalaam-test1:matrix.org",
});
const buildEventCreate = () =>
new MatrixEvent({
age: 80126105,
content: {
room_version: "6",
},
@@ -1991,7 +2196,6 @@ const buildEventCreate = () =>
state_key: "",
type: "m.room.create",
unsigned: { age: 80126105 },
user_id: "@andybalaam-test1:matrix.org",
});
function assertObjectContains(obj: Record<string, any>, expected: any): void {
+5 -4
View File
@@ -6,6 +6,7 @@ import { MatrixScheduler } from "../../src/scheduler";
import { MemoryStore } from "../../src/store/memory";
import { MatrixError } from "../../src/http-api";
import { IStore } from "../../src/store";
import { KnownMembership } from "../../src/@types/membership";
describe("MatrixClient opts", function () {
const baseUrl = "http://localhost.or.something";
@@ -43,13 +44,13 @@ describe("MatrixClient opts", function () {
}),
utils.mkMembership({
room: roomId,
mship: "join",
mship: KnownMembership.Join,
user: userB,
name: "Bob",
}),
utils.mkMembership({
room: roomId,
mship: "join",
mship: KnownMembership.Join,
user: userId,
name: "Alice",
}),
@@ -79,7 +80,7 @@ describe("MatrixClient opts", function () {
let client: MatrixClient;
beforeEach(function () {
client = new MatrixClient({
fetchFn: httpBackend.fetchFn as typeof global.fetch,
fetchFn: httpBackend.fetchFn as typeof globalThis.fetch,
store: undefined,
baseUrl: baseUrl,
userId: userId,
@@ -134,7 +135,7 @@ describe("MatrixClient opts", function () {
let client: MatrixClient;
beforeEach(function () {
client = new MatrixClient({
fetchFn: httpBackend.fetchFn as typeof global.fetch,
fetchFn: httpBackend.fetchFn as typeof globalThis.fetch,
store: new MemoryStore() as IStore,
baseUrl: baseUrl,
userId: userId,
+3 -3
View File
@@ -16,7 +16,7 @@ limitations under the License.
import HttpBackend from "matrix-mock-request";
import { EventStatus, RoomEvent, MatrixClient, MatrixScheduler } from "../../src/matrix";
import { EventStatus, MatrixClient, MatrixScheduler, MsgType, RoomEvent } from "../../src/matrix";
import { Room } from "../../src/models/room";
import { TestClient } from "../TestClient";
@@ -60,7 +60,7 @@ describe("MatrixClient retrying", function () {
// send a couple of events; the second will be queued
const p1 = client!
.sendMessage(roomId, {
msgtype: "m.text",
msgtype: MsgType.Text,
body: "m1",
})
.then(
@@ -77,7 +77,7 @@ describe("MatrixClient retrying", function () {
// never gets resolved.
// https://github.com/matrix-org/matrix-js-sdk/issues/496
client!.sendMessage(roomId, {
msgtype: "m.text",
msgtype: MsgType.Text,
body: "m2",
});
+14 -13
View File
@@ -30,6 +30,7 @@ import {
Room,
} from "../../src";
import { TestClient } from "../TestClient";
import { KnownMembership } from "../../src/@types/membership";
describe("MatrixClient room timelines", function () {
const userId = "@alice:localhost";
@@ -42,7 +43,7 @@ describe("MatrixClient room timelines", function () {
const USER_MEMBERSHIP_EVENT = utils.mkMembership({
room: roomId,
mship: "join",
mship: KnownMembership.Join,
user: userId,
name: userName,
});
@@ -76,7 +77,7 @@ describe("MatrixClient room timelines", function () {
ROOM_NAME_EVENT,
utils.mkMembership({
room: roomId,
mship: "join",
mship: KnownMembership.Join,
user: otherUserId,
name: "Bob",
}),
@@ -316,7 +317,7 @@ describe("MatrixClient room timelines", function () {
// make an m.room.member event for alice's join
const joinMshipEvent = utils.mkMembership({
mship: "join",
mship: KnownMembership.Join,
user: userId,
room: roomId,
name: "Old Alice",
@@ -326,16 +327,16 @@ describe("MatrixClient room timelines", function () {
// make an m.room.member event with prev_content for alice's nick
// change
const oldMshipEvent = utils.mkMembership({
mship: "join",
mship: KnownMembership.Join,
user: userId,
room: roomId,
name: userName,
url: "mxc://some/url",
});
oldMshipEvent.prev_content = {
oldMshipEvent.unsigned!.prev_content = {
displayname: "Old Alice",
avatar_url: undefined,
membership: "join",
membership: KnownMembership.Join,
};
// set the list of events to return on scrollback (/messages)
@@ -487,7 +488,7 @@ describe("MatrixClient room timelines", function () {
utils.mkMembership({
user: userId,
room: roomId,
mship: "join",
mship: KnownMembership.Join,
name: "New Name",
}),
utils.mkMessage({ user: userId, room: roomId }),
@@ -554,13 +555,13 @@ describe("MatrixClient room timelines", function () {
utils.mkMembership({
user: userC,
room: roomId,
mship: "join",
mship: KnownMembership.Join,
name: "C",
}),
utils.mkMembership({
user: userC,
room: roomId,
mship: "invite",
mship: KnownMembership.Invite,
skey: userD,
}),
];
@@ -571,9 +572,9 @@ describe("MatrixClient room timelines", function () {
return Promise.all([httpBackend!.flush("/sync", 1), utils.syncPromise(client!)]).then(function () {
expect(room.currentState.getMembers().length).toEqual(4);
expect(room.currentState.getMember(userC)!.name).toEqual("C");
expect(room.currentState.getMember(userC)!.membership).toEqual("join");
expect(room.currentState.getMember(userC)!.membership).toEqual(KnownMembership.Join);
expect(room.currentState.getMember(userD)!.name).toEqual(userD);
expect(room.currentState.getMember(userD)!.membership).toEqual("invite");
expect(room.currentState.getMember(userD)!.membership).toEqual(KnownMembership.Invite);
});
});
});
@@ -598,9 +599,9 @@ describe("MatrixClient room timelines", function () {
expect(room.timeline[0].event).toEqual(eventData[0]);
expect(room.currentState.getMembers().length).toEqual(2);
expect(room.currentState.getMember(userId)!.name).toEqual(userName);
expect(room.currentState.getMember(userId)!.membership).toEqual("join");
expect(room.currentState.getMember(userId)!.membership).toEqual(KnownMembership.Join);
expect(room.currentState.getMember(otherUserId)!.name).toEqual("Bob");
expect(room.currentState.getMember(otherUserId)!.membership).toEqual("join");
expect(room.currentState.getMember(otherUserId)!.membership).toEqual(KnownMembership.Join);
});
});
});
@@ -105,13 +105,13 @@ describe("MatrixClient syncing errors", () => {
await client!.startClient();
expect(await syncEvents[0].promise).toBe(SyncState.Error);
jest.runAllTimers(); // this will skip forward to trigger the keepAlive/sync
jest.advanceTimersByTime(60 * 1000); // 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
jest.advanceTimersByTime(60 * 1000); // 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
jest.advanceTimersByTime(60 * 1000); // 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
jest.advanceTimersByTime(60 * 1000); // this will skip forward to trigger the keepAlive/sync
expect(await syncEvents[4].promise).toBe(SyncState.Syncing);
});
@@ -119,6 +119,7 @@ describe("MatrixClient syncing errors", () => {
jest.useFakeTimers();
fetchMock.config.overwriteRoutes = false;
fetchMock
.get("end:capabilities", {})
.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
File diff suppressed because it is too large Load Diff
@@ -28,32 +28,71 @@ import {
NotificationCountType,
RelationType,
Room,
fixNotificationCountOnDecryption,
} from "../../src";
import { TestClient } from "../TestClient";
import { ReceiptType } from "../../src/@types/read_receipts";
import { mkThread } from "../test-utils/thread";
import { SyncState } from "../../src/sync";
import { KnownMembership } from "../../src/@types/membership";
const userA = "@alice:localhost";
const userB = "@bob:localhost";
const selfUserId = userA;
const selfAccessToken = "aseukfgwef";
function 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];
}
describe("Notification count fixing", () => {
let client: MatrixClient | undefined;
beforeEach(() => {
[client] = setupTestClient();
});
it("doesn't increment notification count for events that can't be found in a room", async () => {
const roomId = "!room:localhost";
client!.startClient({ threadSupport: true });
const room = new Room(roomId, client!, selfUserId);
jest.spyOn(client!, "getRoom").mockImplementation((id) => (id === roomId ? room : null));
const event = new MatrixEvent({
room_id: roomId,
type: "m.reaction",
event_id: "$foo",
content: {
"m.relates_to": {
rel_type: RelationType.Annotation,
event_id: "$foo",
key: "x",
},
},
});
jest.spyOn(event, "getPushActions").mockReturnValue({
notify: true,
tweaks: {},
});
fixNotificationCountOnDecryption(client!, event);
expect(room.getUnreadNotificationCount(NotificationCountType.Total)).toBe(0);
});
});
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();
});
@@ -89,7 +128,7 @@ describe("MatrixClient syncing", () => {
const thread = mkThread({ room, client: client!, authorId: selfUserId, participantUserIds: [selfUserId] });
const threadReply = thread.events.at(-1)!;
await room.addLiveEvents([thread.rootEvent]);
await room.addLiveEvents([thread.rootEvent], { addToState: false });
// Initialize read receipt datastructure before testing the reaction
room.addReceiptToStructure(thread.rootEvent.getId()!, ReceiptType.Read, selfUserId, { ts: 1 }, false);
@@ -113,7 +152,7 @@ describe("MatrixClient syncing", () => {
await client!.sendEvent(roomId, EventType.Reaction, {
"m.relates_to": {
rel_type: RelationType.Annotation,
event_id: threadReply.getId(),
event_id: threadReply.getId()!,
key: "",
},
});
@@ -191,7 +230,7 @@ describe("MatrixClient syncing", () => {
content: {
avatar_url: "",
displayname: userB,
membership: "join",
membership: KnownMembership.Join,
},
origin_server_ts: 2,
sender: userB,
@@ -232,7 +271,7 @@ describe("MatrixClient syncing", () => {
},
{
content: {
join_rule: "invite",
join_rule: KnownMembership.Invite,
},
origin_server_ts: 4,
sender: userB,
@@ -278,7 +317,7 @@ describe("MatrixClient syncing", () => {
avatar_url: "",
displayname: userA,
is_direct: true,
membership: "invite",
membership: KnownMembership.Invite,
},
origin_server_ts: 8,
sender: userB,
@@ -300,7 +339,7 @@ describe("MatrixClient syncing", () => {
content: {
avatar_url: "",
displayname: userA,
membership: "join",
membership: KnownMembership.Join,
},
origin_server_ts: 10,
sender: userA,
@@ -0,0 +1,354 @@
/*
Copyright 2024 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 { QrCodeData, QrCodeMode } from "@matrix-org/matrix-sdk-crypto-wasm";
import { mocked } from "jest-mock";
import fetchMock from "fetch-mock-jest";
import {
MSC4108FailureReason,
MSC4108RendezvousSession,
MSC4108SecureChannel,
MSC4108SignInWithQR,
PayloadType,
RendezvousError,
} from "../../../src/rendezvous";
import { defer } from "../../../src/utils";
import {
ClientPrefix,
DEVICE_CODE_SCOPE,
IHttpOpts,
IMyDevice,
MatrixClient,
MatrixError,
MatrixHttpApi,
} from "../../../src";
import { makeDelegatedAuthConfig } from "../../test-utils/oidc";
function makeMockClient(opts: { userId: string; deviceId: string; msc4108Enabled: boolean }): MatrixClient {
const baseUrl = "https://example.com";
const crypto = {
exportSecretsForQrLogin: jest.fn(),
};
const client = {
doesServerSupportUnstableFeature(feature: string) {
return Promise.resolve(opts.msc4108Enabled && feature === "org.matrix.msc4108");
},
getUserId() {
return opts.userId;
},
getDeviceId() {
return opts.deviceId;
},
baseUrl,
getDomain: () => "example.com",
getDevice: jest.fn(),
getCrypto: jest.fn(() => crypto),
getAuthMetadata: jest.fn().mockResolvedValue(makeDelegatedAuthConfig("https://issuer/", [DEVICE_CODE_SCOPE])),
} as unknown as MatrixClient;
client.http = new MatrixHttpApi<IHttpOpts & { onlyData: true }>(client, {
baseUrl: client.baseUrl,
prefix: ClientPrefix.Unstable,
onlyData: true,
});
return client;
}
describe("MSC4108SignInWithQR", () => {
beforeEach(() => {
fetchMock.get("https://issuer/jwks", {
status: 200,
headers: {
"Content-Type": "application/json",
},
keys: [],
});
});
afterEach(() => {
fetchMock.reset();
});
const url = "https://fallbackserver/rz/123";
const deviceId = "DEADB33F";
const verificationUri = "https://example.com/verify";
const verificationUriComplete = "https://example.com/verify/complete";
it("should generate qr code data as expected", async () => {
const session = new MSC4108RendezvousSession({
url,
});
const channel = new MSC4108SecureChannel(session);
const login = new MSC4108SignInWithQR(channel, false);
await login.generateCode();
const code = login.code;
expect(code).toHaveLength(71);
const text = new TextDecoder().decode(code);
expect(text.startsWith("MATRIX")).toBeTruthy();
expect(text.endsWith(url)).toBeTruthy();
// Assert that the code is stable
await login.generateCode();
expect(login.code).toEqual(code);
});
describe("should be able to connect as a reciprocating device", () => {
let client: MatrixClient;
let ourLogin: MSC4108SignInWithQR;
let opponentLogin: MSC4108SignInWithQR;
beforeEach(async () => {
let ourData = defer<string>();
let opponentData = defer<string>();
const ourMockSession = {
send: jest.fn(async (newData) => {
ourData.resolve(newData);
}),
receive: jest.fn(() => {
const prom = opponentData.promise;
prom.then(() => {
opponentData = defer();
});
return prom;
}),
url,
cancelled: false,
cancel: () => {
// @ts-ignore
ourMockSession.cancelled = true;
ourData.resolve("");
},
} as unknown as MSC4108RendezvousSession;
const opponentMockSession = {
send: jest.fn(async (newData) => {
opponentData.resolve(newData);
}),
receive: jest.fn(() => {
const prom = ourData.promise;
prom.then(() => {
ourData = defer();
});
return prom;
}),
url,
} as unknown as MSC4108RendezvousSession;
client = makeMockClient({ userId: "@alice:example.com", deviceId: "alice", msc4108Enabled: true });
const ourChannel = new MSC4108SecureChannel(ourMockSession);
const qrCodeData = QrCodeData.fromBytes(
await ourChannel.generateCode(QrCodeMode.Reciprocate, client.getDomain()!),
);
const opponentChannel = new MSC4108SecureChannel(opponentMockSession, qrCodeData.publicKey);
ourLogin = new MSC4108SignInWithQR(ourChannel, true, client);
opponentLogin = new MSC4108SignInWithQR(opponentChannel, false);
});
it("should be able to connect with opponent and share server name & check code", async () => {
await Promise.all([
expect(ourLogin.negotiateProtocols()).resolves.toEqual({}),
expect(opponentLogin.negotiateProtocols()).resolves.toEqual({ serverName: client.getDomain() }),
]);
expect(ourLogin.checkCode).toBe(opponentLogin.checkCode);
});
it("should be able to connect with opponent and share verificationUri", async () => {
await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]);
mocked(client.getDevice).mockRejectedValue(new MatrixError({ errcode: "M_NOT_FOUND" }, 404));
await Promise.all([
expect(ourLogin.deviceAuthorizationGrant()).resolves.toEqual({
verificationUri: verificationUriComplete,
}),
// We don't have the new device side of this flow implemented at this time so mock it
// @ts-ignore
opponentLogin.send({
type: PayloadType.Protocol,
protocol: "device_authorization_grant",
device_authorization_grant: {
verification_uri: verificationUri,
verification_uri_complete: verificationUriComplete,
},
device_id: deviceId,
}),
]);
});
it("should abort if device already exists", async () => {
await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]);
mocked(client.getDevice).mockResolvedValue({} as IMyDevice);
await Promise.all([
expect(ourLogin.deviceAuthorizationGrant()).rejects.toThrow("Specified device ID already exists"),
// We don't have the new device side of this flow implemented at this time so mock it
// @ts-ignore
opponentLogin.send({
type: PayloadType.Protocol,
protocol: "device_authorization_grant",
device_authorization_grant: {
verification_uri: verificationUri,
},
device_id: deviceId,
}),
]);
});
it("should abort on unsupported protocol", async () => {
await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]);
await Promise.all([
expect(ourLogin.deviceAuthorizationGrant()).rejects.toThrow(
"Received a request for an unsupported protocol",
),
// We don't have the new device side of this flow implemented at this time so mock it
// @ts-ignore
opponentLogin.send({
type: PayloadType.Protocol,
protocol: "device_authorization_grant_v2",
device_authorization_grant: {
verification_uri: verificationUri,
},
device_id: deviceId,
}),
]);
});
it("should be able to connect with opponent and share secrets", async () => {
await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]);
// We don't have the new device side of this flow implemented at this time so mock it
// @ts-ignore
ourLogin.expectingNewDeviceId = "DEADB33F";
const ourProm = ourLogin.shareSecrets();
// Consume the ProtocolAccepted message which would normally be handled by step 4 which we do not have here
// @ts-ignore
await opponentLogin.receive();
mocked(client.getDevice).mockResolvedValue({} as IMyDevice);
const secrets = {
cross_signing: { master_key: "mk", user_signing_key: "usk", self_signing_key: "ssk" },
};
client.getCrypto()!.exportSecretsBundle = jest.fn().mockResolvedValue(secrets);
const payload = {
secrets: expect.objectContaining(secrets),
};
await Promise.all([
expect(ourProm).resolves.toEqual(payload),
expect(opponentLogin.shareSecrets()).resolves.toEqual(payload),
]);
});
it("should abort if device doesn't come up by timeout", async () => {
jest.spyOn(globalThis, "setTimeout").mockImplementation((fn) => {
fn();
// TODO: mock timers properly
return -1 as any;
});
jest.spyOn(Date, "now").mockImplementation(() => {
return 12345678 + mocked(setTimeout).mock.calls.length * 1000;
});
await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]);
// We don't have the new device side of this flow implemented at this time so mock it
// @ts-ignore
ourLogin.expectingNewDeviceId = "DEADB33F";
// @ts-ignore
await opponentLogin.send({
type: PayloadType.Success,
});
mocked(client.getDevice).mockRejectedValue(new MatrixError({ errcode: "M_NOT_FOUND" }, 404));
const ourProm = ourLogin.shareSecrets();
await expect(ourProm).rejects.toThrow("New device not found");
});
it("should abort on unexpected errors", async () => {
await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]);
// We don't have the new device side of this flow implemented at this time so mock it
// @ts-ignore
ourLogin.expectingNewDeviceId = "DEADB33F";
// @ts-ignore
await opponentLogin.send({
type: PayloadType.Success,
});
mocked(client.getDevice).mockRejectedValue(
new MatrixError({ errcode: "M_UNKNOWN", error: "The message" }, 500),
);
await expect(ourLogin.shareSecrets()).rejects.toThrow("The message");
});
it("should abort on declined login", async () => {
await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]);
await ourLogin.declineLoginOnExistingDevice();
await expect(opponentLogin.shareSecrets()).rejects.toThrow(
new RendezvousError("Failed", MSC4108FailureReason.UserCancelled),
);
});
it("should not send secrets if user cancels", async () => {
jest.spyOn(globalThis, "setTimeout").mockImplementation((fn) => {
fn();
// TODO: mock timers properly
return -1 as any;
});
await Promise.all([ourLogin.negotiateProtocols(), opponentLogin.negotiateProtocols()]);
// We don't have the new device side of this flow implemented at this time so mock it
// @ts-ignore
ourLogin.expectingNewDeviceId = "DEADB33F";
const ourProm = ourLogin.shareSecrets();
const opponentProm = opponentLogin.shareSecrets();
// Consume the ProtocolAccepted message which would normally be handled by step 4 which we do not have here
// @ts-ignore
await opponentLogin.receive();
const deferred = defer<IMyDevice>();
mocked(client.getDevice).mockReturnValue(deferred.promise);
ourLogin.cancel(MSC4108FailureReason.UserCancelled).catch(() => {});
deferred.resolve({} as IMyDevice);
const secrets = {
cross_signing: { master_key: "mk", user_signing_key: "usk", self_signing_key: "ssk" },
};
client.getCrypto()!.exportSecretsBundle = jest.fn().mockResolvedValue(secrets);
await Promise.all([
expect(ourProm).rejects.toThrow("User cancelled"),
expect(opponentProm).rejects.toThrow("Unexpected message received"),
]);
});
});
});
+42 -40
View File
@@ -43,12 +43,22 @@ import { IStoredClientOpts } from "../../src";
import { logger } from "../../src/logger";
import { emitPromise } from "../test-utils/test-utils";
import { defer } from "../../src/utils";
import { KnownMembership } from "../../src/@types/membership";
import { SyncCryptoCallbacks } from "../../src/common-crypto/CryptoBackend";
declare module "../../src/@types/event" {
interface AccountDataEvents {
global_test: {};
tester: {};
}
}
describe("SlidingSyncSdk", () => {
let client: MatrixClient | undefined;
let httpBackend: MockHttpBackend | undefined;
let sdk: SlidingSyncSdk | undefined;
let mockSlidingSync: SlidingSync | undefined;
let syncCryptoCallback: SyncCryptoCallbacks | undefined;
const selfUserId = "@alice:localhost";
const selfAccessToken = "aseukfgwef";
@@ -118,8 +128,9 @@ describe("SlidingSyncSdk", () => {
mockSlidingSync = mockifySlidingSync(new SlidingSync("", new Map(), {}, client, 0));
if (testOpts.withCrypto) {
httpBackend!.when("GET", "/room_keys/version").respond(404, {});
await client!.initCrypto();
syncOpts.cryptoCallbacks = syncOpts.crypto = client!.crypto;
await client!.initRustCrypto({ useIndexedDB: false });
syncCryptoCallback = client!.getCrypto() as unknown as SyncCryptoCallbacks;
syncOpts.cryptoCallbacks = syncCryptoCallback;
}
httpBackend!.when("GET", "/_matrix/client/v3/pushrules").respond(200, {});
sdk = new SlidingSyncSdk(mockSlidingSync, client, testOpts, syncOpts);
@@ -189,7 +200,7 @@ describe("SlidingSyncSdk", () => {
name: "A",
required_state: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnStateEvent(EventType.RoomName, { name: "A" }, ""),
],
@@ -204,7 +215,7 @@ describe("SlidingSyncSdk", () => {
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello B" }),
mkOwnEvent(EventType.RoomMessage, { body: "world B" }),
@@ -216,7 +227,7 @@ describe("SlidingSyncSdk", () => {
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello C" }),
mkOwnEvent(EventType.RoomMessage, { body: "world C" }),
@@ -229,7 +240,7 @@ describe("SlidingSyncSdk", () => {
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello D" }),
mkOwnEvent(EventType.RoomMessage, { body: "world D" }),
@@ -244,7 +255,7 @@ describe("SlidingSyncSdk", () => {
invite_state: [
{
type: EventType.RoomMember,
content: { membership: "invite" },
content: { membership: KnownMembership.Invite },
state_key: selfUserId,
sender: "@bob:localhost",
event_id: "$room_e_invite",
@@ -265,7 +276,7 @@ describe("SlidingSyncSdk", () => {
name: "#foo:localhost",
required_state: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnStateEvent(EventType.RoomCanonicalAlias, { alias: "#foo:localhost" }, ""),
mkOwnStateEvent(EventType.RoomName, { name: "This should be ignored" }, ""),
@@ -281,7 +292,7 @@ describe("SlidingSyncSdk", () => {
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
],
joined_count: 5,
@@ -293,7 +304,7 @@ describe("SlidingSyncSdk", () => {
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "live event" }),
],
@@ -308,7 +319,7 @@ describe("SlidingSyncSdk", () => {
const gotRoom = client!.getRoom(roomA);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.name).toEqual(data[roomA].name);
expect(gotRoom!.getMyMembership()).toEqual("join");
expect(gotRoom!.getMyMembership()).toEqual(KnownMembership.Join);
assertTimelineEvents(gotRoom!.getLiveTimeline().getEvents().slice(-2), data[roomA].timeline);
});
@@ -318,7 +329,7 @@ describe("SlidingSyncSdk", () => {
const gotRoom = client!.getRoom(roomB);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.name).toEqual(data[roomB].name);
expect(gotRoom!.getMyMembership()).toEqual("join");
expect(gotRoom!.getMyMembership()).toEqual(KnownMembership.Join);
assertTimelineEvents(gotRoom!.getLiveTimeline().getEvents().slice(-5), data[roomB].timeline);
});
@@ -372,7 +383,7 @@ describe("SlidingSyncSdk", () => {
const gotRoom = client!.getRoom(roomH);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.name).toEqual(data[roomH].name);
expect(gotRoom!.getMyMembership()).toEqual("join");
expect(gotRoom!.getMyMembership()).toEqual(KnownMembership.Join);
// check the entire timeline is correct
assertTimelineEvents(gotRoom!.getLiveTimeline().getEvents(), data[roomH].timeline);
await expect(seenLiveEventDeferred.promise).resolves.toBeTruthy();
@@ -383,7 +394,7 @@ describe("SlidingSyncSdk", () => {
await emitPromise(client!, ClientEvent.Room);
const gotRoom = client!.getRoom(roomE);
expect(gotRoom).toBeTruthy();
expect(gotRoom!.getMyMembership()).toEqual("invite");
expect(gotRoom!.getMyMembership()).toEqual(KnownMembership.Invite);
expect(gotRoom!.currentState.getJoinRule()).toEqual(JoinRule.Invite);
});
@@ -600,13 +611,13 @@ describe("SlidingSyncSdk", () => {
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomId, {
initial: true,
name: "Room with Invite",
required_state: [],
timeline: [
required_state: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "invite" }, invitee),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Invite }, invitee),
],
timeline: [],
});
await httpBackend!.flush("/profile", 1, 1000);
await emitPromise(client!, RoomMemberEvent.Name);
@@ -632,13 +643,6 @@ describe("SlidingSyncSdk", () => {
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,
@@ -647,28 +651,28 @@ describe("SlidingSyncSdk", () => {
});
it("can update device lists", () => {
client!.crypto!.processDeviceLists = jest.fn();
syncCryptoCallback!.processDeviceLists = jest.fn();
ext.onResponse({
device_lists: {
changed: ["@alice:localhost"],
left: ["@bob:localhost"],
},
});
expect(client!.crypto!.processDeviceLists).toHaveBeenCalledWith({
expect(syncCryptoCallback!.processDeviceLists).toHaveBeenCalledWith({
changed: ["@alice:localhost"],
left: ["@bob:localhost"],
});
});
it("can update OTK counts and unused fallback keys", () => {
client!.crypto!.processKeyCounts = jest.fn();
syncCryptoCallback!.processKeyCounts = jest.fn();
ext.onResponse({
device_one_time_keys_count: {
signed_curve25519: 42,
},
device_unused_fallback_key_types: ["signed_curve25519"],
});
expect(client!.crypto!.processKeyCounts).toHaveBeenCalledWith({ signed_curve25519: 42 }, [
expect(syncCryptoCallback!.processKeyCounts).toHaveBeenCalledWith({ signed_curve25519: 42 }, [
"signed_curve25519",
]);
});
@@ -719,7 +723,7 @@ describe("SlidingSyncSdk", () => {
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello" }),
],
@@ -920,13 +924,12 @@ describe("SlidingSyncSdk", () => {
const roomId = "!room:id";
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomId, {
name: "Room with typing",
required_state: [],
timeline: [
required_state: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello" }),
],
timeline: [mkOwnEvent(EventType.RoomMessage, { body: "hello" })],
initial: true,
});
await emitPromise(client!, ClientEvent.Room);
@@ -961,13 +964,12 @@ describe("SlidingSyncSdk", () => {
const roomId = "!room:id";
mockSlidingSync!.emit(SlidingSyncEvent.RoomData, roomId, {
name: "Room with typing",
required_state: [],
timeline: [
required_state: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
mkOwnEvent(EventType.RoomMessage, { body: "hello" }),
],
timeline: [mkOwnEvent(EventType.RoomMessage, { body: "hello" })],
initial: true,
});
const room = client!.getRoom(roomId)!;
@@ -1050,12 +1052,12 @@ describe("SlidingSyncSdk", () => {
required_state: [],
timeline: [
mkOwnStateEvent(EventType.RoomCreate, {}, ""),
mkOwnStateEvent(EventType.RoomMember, { membership: "join" }, selfUserId),
mkOwnStateEvent(EventType.RoomMember, { membership: KnownMembership.Join }, selfUserId),
mkOwnStateEvent(EventType.RoomPowerLevels, { users: { [selfUserId]: 100 } }, ""),
{
type: EventType.RoomMember,
state_key: alice,
content: { membership: "join" },
content: { membership: KnownMembership.Join },
sender: alice,
origin_server_ts: Date.now(),
event_id: "$alice",
+5 -5
View File
@@ -107,8 +107,8 @@ describe("SlidingSync", () => {
onRequest: (initial) => {
return { initial: initial };
},
onResponse: (res) => {
return {};
onResponse: async (res) => {
return;
},
when: () => ExtensionState.PreProcess,
};
@@ -1572,7 +1572,7 @@ describe("SlidingSync", () => {
onPreExtensionRequest = () => {
return extReq;
};
onPreExtensionResponse = (resp) => {
onPreExtensionResponse = async (resp) => {
extensionOnResponseCalled = true;
callbackOrder.push("onPreExtensionResponse");
expect(resp).toEqual(extResp);
@@ -1613,7 +1613,7 @@ describe("SlidingSync", () => {
return undefined;
};
let responseCalled = false;
onPreExtensionResponse = (resp) => {
onPreExtensionResponse = async (resp) => {
responseCalled = true;
};
httpBackend!
@@ -1649,7 +1649,7 @@ describe("SlidingSync", () => {
};
let responseCalled = false;
const callbackOrder: string[] = [];
onPostExtensionResponse = (resp) => {
onPostExtensionResponse = async (resp) => {
expect(resp).toEqual(extResp);
responseCalled = true;
callbackOrder.push("onPostExtensionResponse");
+1 -1
View File
@@ -19,7 +19,7 @@ import { logger } from "../src/logger";
// try to load the olm library.
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
// eslint-disable-next-line @typescript-eslint/no-require-imports
globalThis.Olm = require("@matrix-org/olm");
logger.log("loaded libolm");
} catch (e) {
-4
View File
@@ -14,10 +14,6 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import DOMException from "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
+110
View File
@@ -0,0 +1,110 @@
/*
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 { ISyncResponder } from "./SyncResponder";
/**
* An object which intercepts `account_data` get and set requests via fetch-mock.
*/
export class AccountDataAccumulator {
/**
* The account data events to be returned by the sync.
* Will be updated when fetchMock intercepts calls to PUT `/_matrix/client/v3/user/:userId/account_data/`.
* Will be used by `sendSyncResponseWithUpdatedAccountData`
*/
public accountDataEvents: Map<string, any> = new Map();
/**
* Intercept requests to set a particular type of account data.
*
* Once it is set, its data is stored (for future return by `interceptGetAccountData` etc) and the resolved promise is
* resolved.
*
* @param accountDataType - type of account data to be intercepted
* @param opts - options to pass to fetchMock
* @returns a Promise which will resolve (with the content of the account data) once it is set.
*/
public interceptSetAccountData(
accountDataType: string,
opts?: Parameters<(typeof fetchMock)["put"]>[2],
): Promise<any> {
return new Promise((resolve) => {
// Called when the cross signing key is uploaded
fetchMock.put(
`express:/_matrix/client/v3/user/:userId/account_data/${accountDataType}`,
(url: string, options: RequestInit) => {
const content = JSON.parse(options.body as string);
const type = url.split("/").pop();
// update account data for sync response
this.accountDataEvents.set(type!, content);
resolve(content);
return {};
},
opts,
);
});
}
/**
* Intercept all requests to get account data
*/
public interceptGetAccountData(): void {
fetchMock.get(
`express:/_matrix/client/v3/user/:userId/account_data/:type`,
(url) => {
const type = url.split("/").pop();
const existing = this.accountDataEvents.get(type!);
if (existing) {
// return it
return {
status: 200,
body: existing,
};
} else {
// 404
return {
status: 404,
body: { errcode: "M_NOT_FOUND", error: "Account data not found." },
};
}
},
{ overwriteRoutes: true },
);
}
/**
* Send a sync response the current account data events.
*/
public sendSyncResponseWithUpdatedAccountData(syncResponder: ISyncResponder): void {
try {
syncResponder.sendOrQueueSyncResponse({
next_batch: 1,
account_data: {
events: Array.from(this.accountDataEvents, ([type, content]) => ({
type: type,
content: content,
})),
},
});
} catch {
// Might fail with "Cannot queue more than one /sync response" if called too often.
// It's ok if it fails here, the sync response is cumulative and will contain
// the latest account data.
}
}
}
+2 -2
View File
@@ -17,7 +17,7 @@ limitations under the License.
import debugFunc from "debug";
import { Debugger } from "debug";
import fetchMock from "fetch-mock-jest";
import { MockResponse } from "fetch-mock";
import FetchMock from "fetch-mock";
/** Interface implemented by classes that intercept `/sync` requests from test clients
*
@@ -80,7 +80,7 @@ export class SyncResponder implements ISyncResponder {
);
}
private async onSyncRequest(): Promise<MockResponse> {
private async onSyncRequest(): Promise<FetchMock.MockResponse> {
switch (this.state) {
case SyncResponderState.IDLE: {
this.debug("Got /sync request: waiting for response to be ready");
+15 -5
View File
@@ -101,9 +101,8 @@ export const makeGeolocationPosition = ({
}: {
timestamp?: number;
coords: Partial<GeolocationCoordinates>;
}): GeolocationPosition => ({
timestamp: timestamp ?? 1647256791840,
coords: {
}): GeolocationPosition => {
const { toJSON, ...coordsJSON } = {
accuracy: 1,
latitude: 54.001927,
longitude: -8.253491,
@@ -112,5 +111,16 @@ export const makeGeolocationPosition = ({
heading: null,
speed: null,
...coords,
},
});
};
const posJSON = {
timestamp: timestamp ?? 1647256791840,
coords: {
toJSON: () => coordsJSON,
...coordsJSON,
},
};
return {
toJSON: () => posJSON,
...posJSON,
};
};
+1 -1
View File
@@ -88,6 +88,6 @@ export const mockClientMethodsEvents = () => ({
export const mockClientMethodsServer = (): Partial<Record<MethodLikeKeys<MatrixClient>, unknown>> => ({
getIdentityServerUrl: jest.fn(),
getHomeserverUrl: jest.fn(),
getCapabilities: jest.fn().mockReturnValue({}),
getCachedCapabilities: jest.fn().mockReturnValue({}),
doesServerSupportUnstableFeature: jest.fn().mockResolvedValue(false),
});
+16 -6
View File
@@ -24,11 +24,21 @@ import { KeyBackupInfo } from "../../src/crypto-api";
* @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",
});
fetchMock.getOnce(
new URL("/_matrix/client/versions", homeserverUrl).toString(),
{ versions: ["v1.1"] },
{ overwriteRoutes: true },
);
fetchMock.getOnce(
new URL("/_matrix/client/v3/pushrules/", homeserverUrl).toString(),
{},
{ overwriteRoutes: true },
);
fetchMock.postOnce(
new URL("/_matrix/client/v3/user/%40alice%3Alocalhost/filter", homeserverUrl).toString(),
{ filter_id: "fid" },
{ overwriteRoutes: true },
);
}
/**
@@ -78,7 +88,7 @@ export function mockSetupMegolmBackupRequests(backupVersion: string): void {
});
fetchMock.post("path:/_matrix/client/v3/room_keys/version", (url, request) => {
const backupData: KeyBackupInfo = JSON.parse(request.body?.toString() ?? "{}");
const backupData: KeyBackupInfo = JSON.parse((request.body as string) ?? "{}");
backupData.version = backupVersion;
backupData.count = 0;
backupData.etag = "zer";
+1 -37
View File
@@ -14,40 +14,4 @@ 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"],
});
export { makeDelegatedAuthConfig, mockOpenIdConfiguration } from "../../src/testing.ts";
@@ -66,6 +66,7 @@ BOB_DATA = {
"TEST_DEVICE_CURVE_PRIVATE_KEY_BYTES": b"Deadmuledeadmuledeadmuledeadmule",
"MASTER_CROSS_SIGNING_PRIVATE_KEY_BYTES": b"Doyouspeakwhaaaaaaaaaaaaaaaaaale",
"ALT_MASTER_CROSS_SIGNING_PRIVATE_KEY_BYTES": b"DoYouSpeakWhaaaaaaaaaaaaaaaaaale",
"USER_CROSS_SIGNING_PRIVATE_KEY_BYTES": b"Useruseruseruseruseruseruseruser",
"SELF_CROSS_SIGNING_PRIVATE_KEY_BYTES": b"Selfselfselfselfselfselfselfself",
@@ -208,7 +209,7 @@ def build_test_data(user_data, prefix = "") -> str:
backup_recovery_key = export_recovery_key(user_data["B64_BACKUP_DECRYPTION_KEY"])
return f"""\
result = f"""\
export const {prefix}TEST_USER_ID = "{user_data['TEST_USER_ID']}";
export const {prefix}TEST_DEVICE_ID = "{user_data['TEST_DEVICE_ID']}";
export const {prefix}TEST_ROOM_ID = "{user_data['TEST_ROOM_ID']}";
@@ -239,7 +240,7 @@ export const {prefix}USER_CROSS_SIGNING_PRIVATE_KEY_BASE64 = "{b64_user_signing_
/** Signed cross-signing keys data, also suitable for returning from a `/keys/query` call */
export const {prefix}SIGNED_CROSS_SIGNING_KEYS_DATA: Partial<IDownloadKeyResult> = {
json.dumps(build_cross_signing_keys_data(user_data), indent=4)
json.dumps(build_cross_signing_keys_data(user_data, user_data["MASTER_CROSS_SIGNING_PRIVATE_KEY_BYTES"]), indent=4)
};
/** Signed OTKs, returned by `POST /keys/claim` */
@@ -279,12 +280,20 @@ export const {prefix}CLEAR_EVENT: Partial<IEvent> = {json.dumps(clear_event, ind
export const {prefix}ENCRYPTED_EVENT: Partial<IEvent> = {json.dumps(encrypted_event, indent=4)};
"""
alt_master_key = user_data.get("ALT_MASTER_CROSS_SIGNING_PRIVATE_KEY_BYTES")
if alt_master_key is not None:
result += f"""
/** A second set of signed cross-signing keys data, also suitable for returning from a `/keys/query` call */
export const {prefix}ALT_SIGNED_CROSS_SIGNING_KEYS_DATA: Partial<IDownloadKeyResult> = {
json.dumps(build_cross_signing_keys_data(user_data, alt_master_key), indent=4)
};
"""
def build_cross_signing_keys_data(user_data) -> dict:
return result
def build_cross_signing_keys_data(user_data, master_key_bytes) -> dict:
"""Build the signed cross-signing-keys data for return from /keys/query"""
master_private_key = ed25519.Ed25519PrivateKey.from_private_bytes(
user_data["MASTER_CROSS_SIGNING_PRIVATE_KEY_BYTES"]
)
master_private_key = ed25519.Ed25519PrivateKey.from_private_bytes(master_key_bytes)
b64_master_public_key = encode_base64(
master_private_key.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)
)
+47
View File
@@ -449,3 +449,50 @@ export const BOB_ENCRYPTED_EVENT: Partial<IEvent> = {
"origin_server_ts": 1507753886000
};
/** A second set of signed cross-signing keys data, also suitable for returning from a `/keys/query` call */
export const BOB_ALT_SIGNED_CROSS_SIGNING_KEYS_DATA: Partial<IDownloadKeyResult> = {
"master_keys": {
"@bob:xyz": {
"keys": {
"ed25519:MCYxU7myKVkoQ55VYw/rXdg5cEupRfDdHmFPJUmR5+E": "MCYxU7myKVkoQ55VYw/rXdg5cEupRfDdHmFPJUmR5+E"
},
"user_id": "@bob:xyz",
"usage": [
"master"
]
}
},
"self_signing_keys": {
"@bob:xyz": {
"keys": {
"ed25519:DaScI3WulBvDjf/d2vdyP5Cgjdypn1c/PSDX23MgN+A": "DaScI3WulBvDjf/d2vdyP5Cgjdypn1c/PSDX23MgN+A"
},
"user_id": "@bob:xyz",
"usage": [
"self_signing"
],
"signatures": {
"@bob:xyz": {
"ed25519:MCYxU7myKVkoQ55VYw/rXdg5cEupRfDdHmFPJUmR5+E": "eDZETBRUw9yW0WJnBZ7vxo12TW09Yb7/47qBPKZzPZzZEvs9M82dnAOtWUv00mcTdp2K9GpeFYDQJ6qLQgxaCA"
}
}
}
},
"user_signing_keys": {
"@bob:xyz": {
"keys": {
"ed25519:lXP89FP6zvFH9TSbU1S8uSdAsVawm1NmV6z+Rfr3lEw": "lXP89FP6zvFH9TSbU1S8uSdAsVawm1NmV6z+Rfr3lEw"
},
"user_id": "@bob:xyz",
"usage": [
"user_signing"
],
"signatures": {
"@bob:xyz": {
"ed25519:MCYxU7myKVkoQ55VYw/rXdg5cEupRfDdHmFPJUmR5+E": "Q1CbIXvp2BxBsu3F/eZ1ZpuR5rXIt0+FrrA/l6itskpW748xwMoIKxQRVQqs87kh7pCsWEoTy6FzIL8nV+P6BQ"
}
}
}
}
};
+25 -9
View File
@@ -19,6 +19,7 @@ import {
import { SyncState } from "../../src/sync";
import { eventMapperFor } from "../../src/event-mapper";
import { TEST_ROOM_ID } from "./test-data";
import { KnownMembership, Membership } from "../../src/@types/membership";
/**
* Return a promise that is resolved when the client next emits a
@@ -85,9 +86,9 @@ export function getSyncResponse(roomMembers: string[], roomId = TEST_ROOM_ID): I
};
for (let i = 0; i < roomMembers.length; i++) {
roomResponse.state.events.push(
roomResponse.state!.events.push(
mkMembershipCustom({
membership: "join",
membership: KnownMembership.Join,
sender: roomMembers[i],
}),
);
@@ -126,7 +127,7 @@ export function mock<T>(constr: { new (...args: any[]): T }, name: string): T {
if (constr.prototype[key] instanceof Function) {
result[key] = jest.fn();
}
} catch (ex) {
} catch {
// Direct access to some non-function fields of DOM prototypes may
// cause exceptions.
// Overwriting will not work either in that case.
@@ -172,8 +173,10 @@ export function mkEvent(opts: IEventOpts & { event?: boolean }, client?: MatrixC
room_id: opts.room,
sender: opts.sender || opts.user, // opts.user for backwards-compat
content: opts.content,
prev_content: opts.prev_content,
unsigned: opts.unsigned || {},
unsigned: {
...opts.unsigned,
prev_content: opts.prev_content,
},
event_id: "$" + testEventIndex++ + "-" + Math.random() + "-" + Math.random(),
txn_id: "~" + Math.random(),
redacts: opts.redacts,
@@ -251,7 +254,7 @@ export function mkPresence(opts: IPresenceOpts & { event?: boolean }): Partial<I
interface IMembershipOpts {
room?: string;
mship: string;
mship: Membership;
sender?: string;
user?: string;
skey?: string;
@@ -297,7 +300,7 @@ export function mkMembership(opts: IMembershipOpts & { event?: boolean }): Parti
}
export function mkMembershipCustom<T>(
base: T & { membership: string; sender: string; content?: IContent },
base: T & { membership: Membership; sender: string; content?: IContent },
): T & { type: EventType; sender: string; state_key: string; content: IContent } & GeneratedMetadata {
const content = base.content || {};
return mkEventCustom({
@@ -557,12 +560,25 @@ export const CRYPTO_BACKENDS: Record<string, InitCrypto> = {};
export type InitCrypto = (_: MatrixClient) => Promise<void>;
CRYPTO_BACKENDS["rust-sdk"] = (client: MatrixClient) => client.initRustCrypto();
if (global.Olm) {
CRYPTO_BACKENDS["libolm"] = (client: MatrixClient) => client.initCrypto();
if (globalThis.Olm) {
CRYPTO_BACKENDS["libolm"] = (client: MatrixClient) => client.initLegacyCrypto();
}
export const emitPromise = (e: EventEmitter, k: string): Promise<any> => new Promise((r) => e.once(k, r));
/**
* Counts the number of times that an event was emitted.
*/
export class EventCounter {
public counter;
constructor(emitter: EventEmitter, event: string) {
this.counter = 0;
emitter.on(event, () => {
this.counter++;
});
}
}
/**
* Advance the fake timers in a loop until the given promise resolves or rejects.
*
@@ -0,0 +1,55 @@
## Dumps of libolm indexeddb cryptostore
This directory contains several dumps of real indexeddb stores from a session using
libolm crypto.
Each directory contains, in dump.json, a dump of data created by pasting the following
code into the browser console; and in index.ts, details of the user, pickle key,
and corresponding key query and backup responses (`DumpDataSetInfo`).
The dump is created by pasting the following into the browser console:
```javascript
async function exportIndexedDb(name) {
const db = await new Promise((resolve, reject) => {
const dbReq = indexedDB.open(name);
dbReq.onerror = reject;
dbReq.onsuccess = () => resolve(dbReq.result);
});
const storeNames = db.objectStoreNames;
const exports = {};
for (const store of storeNames) {
exports[store] = [];
const txn = db.transaction(store, "readonly");
const objectStore = txn.objectStore(store);
await new Promise((resolve, reject) => {
const cursorReq = objectStore.openCursor();
cursorReq.onerror = reject;
cursorReq.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
const entry = { value: cursor.value };
if (!objectStore.keyPath) {
entry.key = cursor.key;
}
exports[store].push(entry);
cursor.continue();
} else {
resolve();
}
};
});
}
return exports;
}
window.saveAs(
new Blob([JSON.stringify(await exportIndexedDb("matrix-js-sdk:crypto"), null, 2)], {
type: "application/json;charset=utf-8",
}),
"dump.json",
);
```
The pickle key is extracted via `mxMatrixClientPeg.get().crypto.olmDevice.pickleKey`.
@@ -0,0 +1,10 @@
## Dump of an empty libolm indexeddb cryptostore to test skipping migration
A dump of an account which is almost completely empty, and totally unsuitable
for use as a real account.
This dump was manually created by copying and editing full_account.
Created to test
["Unable to restore session" error due due to half-initialised legacy indexeddb crypto store #27447](https://github.com/element-hq/element-web/issues/27447).
We should not launch the Rust migration code when we find a DB in this state.
@@ -0,0 +1,14 @@
{
"account": [],
"device_data": [],
"inbound_group_sessions": [],
"inbound_group_sessions_withheld": [],
"notified_error_devices": [],
"outgoingRoomKeyRequests": [],
"parked_shared_history": [],
"rooms": [],
"session_problems": [],
"sessions": [],
"sessions_needing_backup": [],
"shared_history_inbound_group_sessions": []
}
@@ -0,0 +1,35 @@
/*
Copyright 2024 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 { DumpDataSetInfo } from "../index";
/**
* A key query response containing the current keys of the tested user.
* To be used during tests with fetchmock.
*/
const KEYS_QUERY_RESPONSE = { device_keys: { "@emptyuser:example.com": {} } };
/**
* A dataset containing the information for the tested user.
* To be used during tests.
*/
export const EMPTY_ACCOUNT_DATASET: DumpDataSetInfo = {
userId: "@emptyuser:example.com",
deviceId: "EMPTYDEVIC",
pickleKey: "+/bcdefghijklmnopqrstu1/zyxvutsrqponmlkjih2",
keyQueryResponse: KEYS_QUERY_RESPONSE,
dumpPath: "spec/test-utils/test_indexeddb_cryptostore_dump/empty_account/dump.json",
};
@@ -0,0 +1,4 @@
## Dump of a libolm indexeddb cryptostore to test migration of a full account
A dump of an account containing a complete set of data to migrate.
The data set is substantial enough to allow for testing of chunking mechanisms and progress reporting during the migration process.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,125 @@
/*
Copyright 2024 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 { DumpDataSetInfo } from "../index";
/**
* A key query response containing the current keys of the tested user.
* To be used during tests with fetchmock.
*/
const KEYS_QUERY_RESPONSE: any = {
device_keys: {
"@vdhtest200713:matrix.org": {
KMFSTJSMLB: {
algorithms: ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
device_id: "KMFSTJSMLB",
keys: {
"curve25519:KMFSTJSMLB": "LKv0bKbc0EC4h0jknbemv3QalEkeYvuNeUXVRgVVTTU",
"ed25519:KMFSTJSMLB": "qK70DEqIXq7T+UU3v/al47Ab4JkMEBLpNrTBMbS5rrw",
},
user_id: "@vdhtest200713:matrix.org",
signatures: {
"@vdhtest200713:matrix.org": {
"ed25519:KMFSTJSMLB":
"aE+PdxLAdwQ/xfJwLmqebvt/lrT97fZas2SQFFrM+dPmHxQtjyS8csm88BLfGRjJKK1B/vWev3AaKqQZwLTUAw",
"ed25519:lDvg6vi3P80L9XFNpUSU+5Y87m3p6yHcC83jhSU4Q5k":
"lCd4SA/JT1nnxsgN9yQaLJQhH5hkLMVVx6ba5JAjL1wpWVqyPxzMJHImX6vTztk6S8rybcdfYkea5W/Ii+4HCQ",
},
},
},
},
},
master_keys: {
"@vdhtest200713:matrix.org": {
user_id: "@vdhtest200713:matrix.org",
usage: ["master"],
keys: {
"ed25519:gh9fGr39eNZUdWynEMJ/q/WZq/Pk/foFxHXFBFm18ZI": "gh9fGr39eNZUdWynEMJ/q/WZq/Pk/foFxHXFBFm18ZI",
},
signatures: {
"@vdhtest200713:matrix.org": {
"ed25519:MWOGVUTXZN":
"stOu1aHbhsWB/Aj5M/HqBR83QzME+682C995Uc8JxSmmyrlWmgG8QrnoUDG2OFR1t6zNQ+QLEilU4WNEOV73DQ",
},
},
},
},
self_signing_keys: {
"@vdhtest200713:matrix.org": {
user_id: "@vdhtest200713:matrix.org",
usage: ["self_signing"],
keys: {
"ed25519:lDvg6vi3P80L9XFNpUSU+5Y87m3p6yHcC83jhSU4Q5k": "lDvg6vi3P80L9XFNpUSU+5Y87m3p6yHcC83jhSU4Q5k",
},
signatures: {
"@vdhtest200713:matrix.org": {
"ed25519:gh9fGr39eNZUdWynEMJ/q/WZq/Pk/foFxHXFBFm18ZI":
"HKTC7NoBhAkfJtmemmkn/HvCCgBQViWZ0uH7aGPRaWMDFgD8T7Q+y1j3FKZv4mhSopR85Fq3FRyXsG8OVvGeBA",
},
},
},
},
user_signing_keys: {
"@vdhtest200713:matrix.org": {
user_id: "@vdhtest200713:matrix.org",
usage: ["user_signing"],
keys: {
"ed25519:YShqO/3u5vQ0uucojraWrtoLrek0CYrurN/vH/YPMg8": "YShqO/3u5vQ0uucojraWrtoLrek0CYrurN/vH/YPMg8",
},
signatures: {
"@vdhtest200713:matrix.org": {
"ed25519:gh9fGr39eNZUdWynEMJ/q/WZq/Pk/foFxHXFBFm18ZI":
"u8VOi4IaeRJwDgy2ftK02NJQPdBijy8f/0+WnHGG72yfOvMthwWzEw8SrRSNG8glBNrfHinKwCyJJzAJwyepCQ",
},
},
},
},
};
/**
* A `/room_keys/version` response containing the current server-side backup info.
* To be used during tests with fetchmock.
*/
const BACKUP_RESPONSE: any = {
auth_data: {
public_key: "q+HZiJdHl2Yopv9GGvv7EYSzDMrAiRknK4glSdoaomI",
signatures: {
"@vdhtest200713:matrix.org": {
"ed25519:gh9fGr39eNZUdWynEMJ/q/WZq/Pk/foFxHXFBFm18ZI":
"reDp6Mu+j+tfUL3/T6f5OBT3N825Lzpc43vvG+RvjX6V+KxXzodBQArgCoeEHLtL9OgSBmNrhTkSOX87MWCKAw",
"ed25519:KMFSTJSMLB":
"F8tyV5W6wNi0GXTdSg+gxSCULQi0EYxdAAqfkyNq58KzssZMw5i+PRA0aI2b+D7NH/aZaJrtiYNHJ0gWLSQvAw",
},
},
},
version: "7",
algorithm: "m.megolm_backup.v1.curve25519-aes-sha2",
etag: "1",
count: 79,
};
/**
* A dataset containing the information for the tested user.
* To be used during tests.
*/
export const FULL_ACCOUNT_DATASET: DumpDataSetInfo = {
userId: "@vdhtest200713:matrix.org",
deviceId: "KMFSTJSMLB",
pickleKey: "+1k2Ppd7HIisUY824v7JtV3/oEE4yX0TqtmNPyhaD7o",
backupResponse: BACKUP_RESPONSE,
keyQueryResponse: KEYS_QUERY_RESPONSE,
dumpPath: "spec/test-utils/test_indexeddb_cryptostore_dump/full_account/dump.json",
};
@@ -0,0 +1,154 @@
/*
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 { readFile } from "node:fs/promises";
import { resolve } from "node:path";
/**
* Populate an IndexedDB store with a set of test data.
*
* @param name - Name of the IndexedDB database to create.
* @param dumpPath - The path to the dump file to import.
*/
export async function populateStore(name: string, dumpPath: string): Promise<IDBDatabase> {
const req = indexedDB.open(name, 11);
const db = await new Promise<IDBDatabase>((resolve, reject) => {
req.onupgradeneeded = (ev): void => {
const db = req.result;
const oldVersion = ev.oldVersion;
upgradeDatabase(oldVersion, db);
};
req.onerror = (ev): void => {
reject(req.error);
};
req.onsuccess = (): void => {
const db = req.result;
resolve(db);
};
});
await importData(db, dumpPath);
return db;
}
/** Create the schema for the indexed db store */
function upgradeDatabase(oldVersion: number, db: IDBDatabase) {
if (oldVersion < 1) {
const outgoingRoomKeyRequestsStore = db.createObjectStore("outgoingRoomKeyRequests", { keyPath: "requestId" });
outgoingRoomKeyRequestsStore.createIndex("session", ["requestBody.room_id", "requestBody.session_id"]);
outgoingRoomKeyRequestsStore.createIndex("state", "state");
}
if (oldVersion < 2) {
db.createObjectStore("account");
}
if (oldVersion < 3) {
const sessionsStore = db.createObjectStore("sessions", { keyPath: ["deviceKey", "sessionId"] });
sessionsStore.createIndex("deviceKey", "deviceKey");
}
if (oldVersion < 4) {
db.createObjectStore("inbound_group_sessions", { keyPath: ["senderCurve25519Key", "sessionId"] });
}
if (oldVersion < 5) {
db.createObjectStore("device_data");
}
if (oldVersion < 6) {
db.createObjectStore("rooms");
}
if (oldVersion < 7) {
db.createObjectStore("sessions_needing_backup", { keyPath: ["senderCurve25519Key", "sessionId"] });
}
if (oldVersion < 8) {
db.createObjectStore("inbound_group_sessions_withheld", { keyPath: ["senderCurve25519Key", "sessionId"] });
}
if (oldVersion < 9) {
const problemsStore = db.createObjectStore("session_problems", { keyPath: ["deviceKey", "time"] });
problemsStore.createIndex("deviceKey", "deviceKey");
db.createObjectStore("notified_error_devices", { keyPath: ["userId", "deviceId"] });
}
if (oldVersion < 10) {
db.createObjectStore("shared_history_inbound_group_sessions", { keyPath: ["roomId"] });
}
if (oldVersion < 11) {
db.createObjectStore("parked_shared_history", { keyPath: ["roomId"] });
}
}
async function importData(db: IDBDatabase, dumpPath: string) {
const path = resolve(dumpPath);
const json: Record<string, Array<{ key?: any; value: any }>> = JSON.parse(
await readFile(path, { encoding: "utf8" }),
);
for (const [storeName, data] of Object.entries(json)) {
await new Promise((resolve, reject) => {
const store = db.transaction(storeName, "readwrite").objectStore(storeName);
function putEntry(idx: number) {
if (idx >= data.length) {
resolve(undefined);
return;
}
const { key, value } = data[idx];
try {
const putReq = store.put(value, key);
putReq.onsuccess = (_) => putEntry(idx + 1);
putReq.onerror = (_) => reject(putReq.error);
} catch (e) {
throw new Error(
`Error populating '${storeName}' with key ${JSON.stringify(key)}, value ${JSON.stringify(
value,
)}: ${e}`,
);
}
}
putEntry(0);
});
}
}
export interface DumpDataSetInfo {
/** The user ID to use for the test.*/
userId: string;
/** The device ID to use for the test.*/
deviceId: string;
/** The path to the dump file to import via {@link populateStore}.*/
dumpPath: string;
/** The pickle key to use for the dumped account.*/
pickleKey: string;
/** The response to use for the keys query. */
keyQueryResponse: any;
/** The response to use for the backup query.*/
backupResponse?: any;
/** Additional dump info specific for some tests.*/
[key: string]: any;
}
@@ -0,0 +1,4 @@
## Dump of a libolm indexeddb cryptostore where the msk is not cached
A dump simulating an account where the identity was verified, but the msk was not in cache.
Used to test that the owner identity local trust is migrated correctly.
File diff suppressed because one or more lines are too long
@@ -0,0 +1,299 @@
/*
Copyright 2024 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 { KeyBackupInfo } from "../../../../src/crypto-api/keybackup";
import { DumpDataSetInfo } from "../index";
/**
* A key query response containing the current keys of the tested user.
* To be used during tests with fetchmock.
*/
const KEY_QUERY_RESPONSE: any = {
device_keys: {
"@migration:localhost": {
CBGTADUILV: {
algorithms: ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
device_id: "CBGTADUILV",
keys: {
"curve25519:CBGTADUILV": "gqhFlc7Wzc1wmmmAu3ySIEe4LtDcBK/bdzrtZg+mMSg",
"ed25519:CBGTADUILV": "q1q3L1Il4l61c/6TmI4fYWMsseNMJJYE2Y0r+5ajKQI",
},
signatures: {
"@migration:localhost": {
"ed25519:CBGTADUILV":
"ppSmA0slyQ7RJOFn+qZSLCGeHN6/jAmqKvUZo5Q1hWk0ugkKycRoSUi9TOfbfAVSf8xvFirXy2VGXQbEVPJqAA",
"ed25519:d+4HhsodR2Zqv4Z5V0VxPfy8zbjLjUCdCyv5qme5Ygc":
"cFLWl1fjehLrzrEn3UnmZMIgy3C23WMgGRsn4e6Z/55vmen4KMs8bLpgZaDoWhIdn/8siHRWafA5sFdzK2NsBQ",
"ed25519:bmFmNcVPvaqrlNzmyKn9uU+QRHyx2QRbn/bUAlTH760":
"C6EeqNPcaQyuZgo8+HOUywc/TMkW5IMjg7aoxyu93X//KcNNXKRfj1banYP6XqyPuQITLamBYc1089Jpt9g4Cw",
"ed25519:RkQzi0+aKIL9Y+GzsN23xMz3i3QRkH03G5aqqEbbuy4":
"YwBN/SbCxO8hPgv1B9JY2WVFK4LNK9vq1UNVrkF2j0ZDw9LrvaOws72mbmzZ0nbD3ohcEZ8rXsEosxEVr5r7AQ",
},
},
user_id: "@migration:localhost",
unsigned: {
device_display_name: "localhost:8080: Chrome on macOS",
},
},
TMWBMDZPFT: {
algorithms: ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
device_id: "TMWBMDZPFT",
keys: {
"curve25519:TMWBMDZPFT": "oYP9EXvHMbliFdfk8jPvUw0KhAd0+PBqdMslJAt/ZGQ",
"ed25519:TMWBMDZPFT": "IyfPT67JutFWJsUxrxSqEWxgRjKn9B/w78uKU4OBj1E",
},
signatures: {
"@migration:localhost": {
"ed25519:TMWBMDZPFT":
"IWIuuDag4ZMDhMObYV63X7dBYEUYNHYR0Yu/bwLvQh5ieDjQSrZSLOzDrgCyPCM4hkc4JlhneQpJsYo1lUH7DA",
"ed25519:d+4HhsodR2Zqv4Z5V0VxPfy8zbjLjUCdCyv5qme5Ygc":
"iEcTKElQu4CAsQIXmBaZmXwfB6Diut+4ZXakP1ob7OIDMrCYBcgXsBFYg6GuxwL0LCTVcUgbUw7VuPKSvM8UAA",
"ed25519:MYgcP5P7P6KucWjLvTRofY5PWxsf+WDj2BiXtqOO5Gw":
"KcBLDWkCwZyIzlBkC29PNzHxx7Br14TYlhBfREEEQo/Rd34ZZUYwbQ8iPhB8S1GVq3YwgAV6piYIcxpQin+dBA",
"ed25519:HGN9m99VprMuQBDA3o+KZKcEYTaGmiaujrkygjScMnY":
"VqrvA148Uxib9TNFI1rc9r8qpwTojCkqLofEz9dMLc/XV3U14WD5/LDEhMuCwNu6wsu/uO+dS4AmJlJnN/iAAg",
"ed25519:Nt0L/p+UVHMx603sYHXwXja+VyQIUVFvu0vDBYn56Zk":
"D1COHzROOTNlCn8b1zI9+6phUtF0OVqWxLfOLnX5t14H2oENYV2ASgaxsdmXcSZPrGzaJkmSOginHHzsabe5CA",
"ed25519:bmFmNcVPvaqrlNzmyKn9uU+QRHyx2QRbn/bUAlTH760":
"SFSDrsi3GQ9jjBYUc2aUSzf777/0NfQWrOBi2CK+v5VQY3FkyHBln3K4YzvxIKSVIhOaQtBlEDtfQb33kwTgDg",
"ed25519:RkQzi0+aKIL9Y+GzsN23xMz3i3QRkH03G5aqqEbbuy4":
"BtJkzQe0YFAa8gJiYXYtzGtktl9vZMNYl5jd4DA8Toi4VxgosJNZQE7lT5qpYU0BrlFn46QIs/38X8JhSt+wAQ",
},
},
user_id: "@migration:localhost",
unsigned: {
device_display_name: "localhost:8080: Chrome on macOS",
},
},
},
},
failures: {},
master_keys: {
"@migration:localhost": {
keys: {
"ed25519:cFjUBAhAZ2tjYF1TpQtYNA3x9XRzTiIdP2N2EvRaOH4": "cFjUBAhAZ2tjYF1TpQtYNA3x9XRzTiIdP2N2EvRaOH4",
},
signatures: {
"@migration:localhost": {
"ed25519:TMWBMDZPFT":
"RrPUnYoekK7wZGrLNXshgoupF8v53S/vJyvkBJi+q9THh4Qrf3CieuVJFx8mwtmEZgGoA2tSroAVnRqvEQ+IBQ",
"ed25519:cFjUBAhAZ2tjYF1TpQtYNA3x9XRzTiIdP2N2EvRaOH4":
"o4CbtdU3IqJK90UXAEBtxps2m4XBYvWJI2nbVlzBaGRr+Xt/3vtwDMlc5G970kPQWBbs/koYJh8MSaE7Fm1mAg",
"ed25519:CBGTADUILV":
"AgZoG+ix8aW3FAW6v+/Xu+QJpxzvsx5itbB8RyqMet9YlNqX90vYIbBV7IoV2WFY2WdANYEffX2CE0FpR6NnCg",
},
},
usage: ["master"],
user_id: "@migration:localhost",
},
},
self_signing_keys: {
"@migration:localhost": {
keys: {
"ed25519:RkQzi0+aKIL9Y+GzsN23xMz3i3QRkH03G5aqqEbbuy4": "RkQzi0+aKIL9Y+GzsN23xMz3i3QRkH03G5aqqEbbuy4",
},
signatures: {
"@migration:localhost": {
"ed25519:cFjUBAhAZ2tjYF1TpQtYNA3x9XRzTiIdP2N2EvRaOH4":
"hs8VqoTfipDjC2pzFdmzb1aENhDjVV+gc86fuYftczaCcsXUWop/NPwoF51Ie6Nb3YL0N7ZZAUrycuJP5hFbDg",
},
},
usage: ["self_signing"],
user_id: "@migration:localhost",
},
},
user_signing_keys: {
"@migration:localhost": {
keys: {
"ed25519:WNJ2G3Ig5EdC4wYiRKcK7bhLP2+I4wI6V7SKgJTXdw8": "WNJ2G3Ig5EdC4wYiRKcK7bhLP2+I4wI6V7SKgJTXdw8",
},
signatures: {
"@migration:localhost": {
"ed25519:cFjUBAhAZ2tjYF1TpQtYNA3x9XRzTiIdP2N2EvRaOH4":
"Vlba5rJQxG+ussVLoycvHcin7Ghv0uUeClDqDbM+RPF+jx9w4ozbcuEOTJdyzyPA+GxN9Kzh2lmVFMMQGyvNAw",
},
},
usage: ["user_signing"],
user_id: "@migration:localhost",
},
},
};
/**
* A new key query response for the same user simulating a cross-signing key reset.
* To be used during tests with fetchmock.
*/
const ROTATED_KEY_QUERY_RESPONSE: any = {
device_keys: {
"@migration:localhost": {
TMWBMDZPFT: {
algorithms: ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
device_id: "TMWBMDZPFT",
keys: {
"curve25519:TMWBMDZPFT": "oYP9EXvHMbliFdfk8jPvUw0KhAd0+PBqdMslJAt/ZGQ",
"ed25519:TMWBMDZPFT": "IyfPT67JutFWJsUxrxSqEWxgRjKn9B/w78uKU4OBj1E",
},
signatures: {
"@migration:localhost": {
"ed25519:TMWBMDZPFT":
"IWIuuDag4ZMDhMObYV63X7dBYEUYNHYR0Yu/bwLvQh5ieDjQSrZSLOzDrgCyPCM4hkc4JlhneQpJsYo1lUH7DA",
"ed25519:d+4HhsodR2Zqv4Z5V0VxPfy8zbjLjUCdCyv5qme5Ygc":
"iEcTKElQu4CAsQIXmBaZmXwfB6Diut+4ZXakP1ob7OIDMrCYBcgXsBFYg6GuxwL0LCTVcUgbUw7VuPKSvM8UAA",
"ed25519:MYgcP5P7P6KucWjLvTRofY5PWxsf+WDj2BiXtqOO5Gw":
"KcBLDWkCwZyIzlBkC29PNzHxx7Br14TYlhBfREEEQo/Rd34ZZUYwbQ8iPhB8S1GVq3YwgAV6piYIcxpQin+dBA",
"ed25519:HGN9m99VprMuQBDA3o+KZKcEYTaGmiaujrkygjScMnY":
"VqrvA148Uxib9TNFI1rc9r8qpwTojCkqLofEz9dMLc/XV3U14WD5/LDEhMuCwNu6wsu/uO+dS4AmJlJnN/iAAg",
"ed25519:Nt0L/p+UVHMx603sYHXwXja+VyQIUVFvu0vDBYn56Zk":
"D1COHzROOTNlCn8b1zI9+6phUtF0OVqWxLfOLnX5t14H2oENYV2ASgaxsdmXcSZPrGzaJkmSOginHHzsabe5CA",
"ed25519:bmFmNcVPvaqrlNzmyKn9uU+QRHyx2QRbn/bUAlTH760":
"SFSDrsi3GQ9jjBYUc2aUSzf777/0NfQWrOBi2CK+v5VQY3FkyHBln3K4YzvxIKSVIhOaQtBlEDtfQb33kwTgDg",
"ed25519:RkQzi0+aKIL9Y+GzsN23xMz3i3QRkH03G5aqqEbbuy4":
"BtJkzQe0YFAa8gJiYXYtzGtktl9vZMNYl5jd4DA8Toi4VxgosJNZQE7lT5qpYU0BrlFn46QIs/38X8JhSt+wAQ",
},
},
user_id: "@migration:localhost",
unsigned: {
device_display_name: "localhost:8080: Chrome on macOS",
},
},
XFZFSCUOFL: {
algorithms: ["m.olm.v1.curve25519-aes-sha2", "m.megolm.v1.aes-sha2"],
device_id: "XFZFSCUOFL",
keys: {
"curve25519:XFZFSCUOFL": "aN2Ty+0rutNkrRtxhV+ciI8GhF4epSxzL7bAOr8zfkc",
"ed25519:XFZFSCUOFL": "V7CPhXdfLFk+qAOFivrpFskmunVTeuM+EOM3DMlDxkI",
},
signatures: {
"@migration:localhost": {
"ed25519:XFZFSCUOFL":
"4Pqc2FWJ5p/L/tSlfUBIlcQzLmN5CksJriAibY8LSDAXdGYiQJ7hvKqneEuVhrMYwqyIxb4bAad+r6wnY0/7Cg",
"ed25519:RkQzi0+aKIL9Y+GzsN23xMz3i3QRkH03G5aqqEbbuy4":
"yH8pKnD+E8YaawS+1NCjwy0cf2WzBRff9BBNX4YnAuTyc6s5b1QqNfu9DP5qblw8TZ7hZmaziePZKsjRiqJLBg",
"ed25519:OEv0wHLusJx7zTCc0h3HbNIHLIxlGZKh63tc2ptKb+Y":
"M8SfAiEUzd7AsWp8InS7BxV3cRqV3MjMxks4DwSxsVxvkCco2JWybKgev+vTZyM6XDg930o0FObQOxWm4+CkBw",
},
},
user_id: "@migration:localhost",
unsigned: {
device_display_name: "localhost:8080: Chrome on macOS",
},
},
},
},
failures: {},
master_keys: {
"@migration:localhost": {
user_id: "@migration:localhost",
usage: ["master"],
keys: {
"ed25519:rXCrBin/+xyh+yW//vWte+2UV0et1ZHTWfalp/Ekack": "rXCrBin/+xyh+yW//vWte+2UV0et1ZHTWfalp/Ekack",
},
signatures: {
"@migration:localhost": {
"ed25519:XFZFSCUOFL":
"C8aswtyUABWvj2DInehVoh2P/EDbwRhlIk51LtV3L71POUCh7pZuyXRMMWKZeyRvHRmEllXBtRkH1iol/p56Bg",
},
},
},
},
self_signing_keys: {
"@migration:localhost": {
user_id: "@migration:localhost",
usage: ["self_signing"],
keys: {
"ed25519:OEv0wHLusJx7zTCc0h3HbNIHLIxlGZKh63tc2ptKb+Y": "OEv0wHLusJx7zTCc0h3HbNIHLIxlGZKh63tc2ptKb+Y",
},
signatures: {
"@migration:localhost": {
"ed25519:rXCrBin/+xyh+yW//vWte+2UV0et1ZHTWfalp/Ekack":
"dH596pGp8+f8dlwd81UrKDWoRDd24yAqqMSLqR4fJHyfszbn7qCvQA6LYZ023TLmk33FKcJqRtd2v/ykTmS3Bg",
},
},
},
},
user_signing_keys: {
"@migration:localhost": {
user_id: "@migration:localhost",
usage: ["user_signing"],
keys: {
"ed25519:8XHpC3MeMReIfYneWIRX8c4ANgJuQ1+oFrktBcLka4o": "8XHpC3MeMReIfYneWIRX8c4ANgJuQ1+oFrktBcLka4o",
},
signatures: {
"@migration:localhost": {
"ed25519:rXCrBin/+xyh+yW//vWte+2UV0et1ZHTWfalp/Ekack":
"FX6ylagvx3IG1zMf/ayYgDb/1+x0/F28pHQqzQMGGssAmc15nat/R6AF0QO7Qg7uqTAf04ohuZtWax3dTwjNDQ",
},
},
},
},
};
/**
* A `/room_keys/version` response containing the current server-side backup info.
* To be used during tests with fetchmock.
*/
const BACKUP_RESPONSE: KeyBackupInfo = {
auth_data: {
public_key: "2ffIfIB4oryqZpsJQjQNUaxgCzxliC6A4PJvnrN+XAA",
signatures: {
"@migration:localhost": {
"ed25519:TMWBMDZPFT":
"qBvalid/G4hnSF3hAeX4TtRN6/BqprgiYnLEtDuatyQ5WxWr0s4uSOyvHSglsRdpoo32FDBHfTIZkCOVxSLwAA",
},
},
},
version: "2",
algorithm: "m.megolm_backup.v1.curve25519-aes-sha2",
etag: "0",
count: 0,
};
/**
* This was generated by doing a backup reset on the account.
* This is a new valid backup for this account.
*/
const NEW_BACKUP_RESPONSE: KeyBackupInfo = {
auth_data: {
public_key: "CkDxWALi3lcChgjEZFEM6clYq5x768XBwsL++eaOzTI",
signatures: {
"@migration:localhost": {
"ed25519:YVEGEYPYWX":
"ZSYuQDdwgB9WKXQ+z5aWWfqSolBCGRw53kur1Vy956gFefgzCBkMbw5M0I2UgfU2Cukri7jZ4ig201zmLNmaAA",
"ed25519:rXCrBin/+xyh+yW//vWte+2UV0et1ZHTWfalp/Ekack":
"+UQ8EA507LoIqgK9rPsqPoGrj+iRBJeY2Oz0mMtXmVf8c1y8G0KWJNUWqvOysnOhsoJf1bt8ey48CxjjtSQ2AA",
},
},
},
version: "3",
algorithm: "m.megolm_backup.v1.curve25519-aes-sha2",
etag: "0",
count: 0,
};
/**
* A dataset containing the information for the tested user.
* To be used during tests.
*/
export const MSK_NOT_CACHED_DATASET: DumpDataSetInfo = {
userId: "@migration:localhost",
deviceId: "CBGTADUILV",
pickleKey: "qEURMepfkMvoBQGaWlI9MZKYnDMsSAiW8aFTKXaeDV0",
keyQueryResponse: KEY_QUERY_RESPONSE,
rotatedKeyQueryResponse: ROTATED_KEY_QUERY_RESPONSE,
backupResponse: BACKUP_RESPONSE,
newBackupResponse: NEW_BACKUP_RESPONSE,
dumpPath: "spec/test-utils/test_indexeddb_cryptostore_dump/no_cached_msk_dump/dump.json",
};
@@ -0,0 +1,4 @@
## Dump of a libolm indexeddb cryptostore where the identity is not trusted.
A dump of an account where the identity was not verified.
Used as a test case for migration of the identity local trust.

Some files were not shown because too many files have changed in this diff Show More