Compare commits

...

2379 Commits

Author SHA1 Message Date
Richard van der Hoff bf1595309c matrix-sdk-crypto-js v0.1.2
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 30s
2023-07-10 12:03:32 +01:00
Richard van der Hoff caa70db31b Prepare changelog for v0.1.2 2023-07-10 12:03:12 +01:00
aringenbach 89aa2916c7 ui/ffi: Add timestamp to reactions 2023-07-10 10:13:53 +00:00
Benjamin Bouvier 2225e8ad80 feat: make it possible to configure the state store as an in-memory store in FFI 2023-07-10 12:04:52 +02:00
Richard van der Hoff 708a7d95a7 Add Qr.state() 2023-07-10 11:45:33 +02:00
Richard van der Hoff 0ccb1efded Enable rust-sdk tracing for device tests
... because knowing why your tests are failing is nice
2023-07-10 11:45:33 +02:00
Richard van der Hoff 0a5ef29c34 device.test: Stop pretending we have independent tests
This file claimed to have lots of tests, but actually they are not independent
- they are just one big test.

It's not ideal to have one massive test like this, but I don't really have time
to rewrite them and we should stop pretending.
2023-07-10 11:45:33 +02:00
Damir Jelić 9f68b3838f Merge pull request #2142 from matrix-org/andybalaam/cache-last-event-in-roominfo
Store the last timeline event in RoomInfo
2023-07-10 11:30:13 +02:00
Jonas Platte 0a6234f40a ffi: Send initial back-pagination status to subscriber immediately
… right as the subscriber is registered.
2023-07-10 11:07:43 +02:00
Kévin Commaille 4e52125551 ui: Allow to filter events added to the Timeline
To avoid to deal with events we are not interested in in the stream.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-07-07 22:20:14 +02:00
Richard van der Hoff 0bf99d5c73 Fix handling of SAS start events once we have shown a QR code (#2242)
Fixes #2237

Also a couple of other cleanups while I'm in the area.
2023-07-07 17:55:13 +01:00
Andy Balaam bac555d31b More CI fixes 2023-07-07 16:19:38 +01:00
Andy Balaam ff0cd7c592 Fix one more JS test 2023-07-07 15:55:29 +01:00
Andy Balaam 96098e8f8b More feature flag fiddling 2023-07-07 15:44:16 +01:00
Andy Balaam 6e84f969ad More feature flag fiddling 2023-07-07 15:42:52 +01:00
Andy Balaam 9bcc1e9e00 More JavaScript test updates 2023-07-07 15:31:09 +01:00
Andy Balaam 31e9572d42 Allow unused code for read_only 2023-07-07 15:22:45 +01:00
Andy Balaam b525491bd5 Fix warnings from CI 2023-07-07 15:20:41 +01:00
Andy Balaam c9a11a58bf Format JavaScript 2023-07-07 15:11:00 +01:00
Andy Balaam 82c7a05f01 Fixes for problems found through CI 2023-07-07 15:05:48 +01:00
Nicolas Mauri fa4c1ef00b ffi: expose the notification settings (#2223) 2023-07-07 15:07:31 +02:00
Andy Balaam a2ca168573 Provide path for a doc link 2023-07-07 13:22:28 +01:00
Andy Balaam 6cb3afe6fd Merge branch 'main' into andybalaam/cache-last-event-in-roominfo 2023-07-07 13:14:52 +01:00
Andy Balaam 3fd1542a25 Fetch sender profile when returning latest event 2023-07-07 12:59:49 +01:00
Benjamin Bouvier 1f47e165ab chore: remove a few useless async 2023-07-07 13:04:31 +02:00
Benjamin Bouvier 4e065ccee9 feat: don't recreate the cross-process lock if it already existed 2023-07-07 13:04:16 +02:00
Jonas Platte 0ef819bca7 ffi: Use proc-macros for SessionVerificationControllerDelegate 2023-07-06 18:26:40 +02:00
Jonas Platte 6f295e2571 Upgrade UniFFI 2023-07-06 18:26:40 +02:00
Jonas Platte 07a82c841f ui: Spawn a background task for decryption retrying 2023-07-06 17:55:05 +02:00
Andy Balaam 98882b9c23 Store the last timeline event in RoomInfo
and the latest few encrypted events in Room.
Use the latest event to provide a room preview, and use the encrypted
events to replace the laest event when they are decrypted.
2023-07-06 16:48:27 +01:00
Florian Duros c600c64b95 BindingsJS: Release v0.1.1 (#2234) 2023-07-06 17:25:02 +02:00
Ivan Enderlin 61ddf047e0 fix(sqlite): Prevent reaching the maximum number of parameters in an SQL statement
fix(sqlite): Prevent reaching the maximum number of parameters in an SQL statement
2023-07-06 17:07:23 +02:00
Ivan Enderlin a70e79420c fix(sqlite): Ensure there is free space for static parameters, in chunk_large_query_over. 2023-07-06 16:46:35 +02:00
Ivan Enderlin 4e20dc5047 chore(sqlite): To make a friend smile. 2023-07-06 16:27:32 +02:00
Ivan Enderlin 23dae0612d chore(sqlite): Use itertools in repeat_vars. 2023-07-06 16:22:37 +02:00
Jonas Platte fe189fda06 bindings: Rename subscribe_to_back_pagination_{status => state}
For consistency with the UI crate.
2023-07-06 15:55:49 +02:00
Florian Duros 0384a52f1e Expose the verify method for the Device in the bindings (#2229) 2023-07-06 15:46:52 +02:00
Ivan Enderlin d33e2aff2e doc(sqlite): Fix a typo. 2023-07-06 15:18:41 +02:00
Ivan Enderlin 380bce0604 fix(sqlite): Prevent reaching the maximum number of parameters in an SQL statement.
This patch introduces a new `chunk_large_query_over` function. Imagine
there is a _dynamic_ query that runs potentially large number of
parameters, so much that the maximum of parameters can be hit. Then,
this function is for you. It will execute the query on chunks of
parameters.

`chunk_large_query_over` uses `Vec::split_off` to avoid cloning `Key`s
as much as possible. It's difficult to use references here because of
the async nature of `SqliteObjectExt::prepare`.

This patch updates `get_kv_blobs`, `get_room_infos`,
`get_maybe_stripped_state_events_for_keys`, `get_profiles`,
`get_user_ids`, and `get_display_names` to use this new function.

This patch finally adds the `repeat_vars` function to replace in a
more efficient way the `vec!["?"; n].join(", ")` pattern. There is less
memory allocations.
2023-07-06 15:11:42 +02:00
Jonas Platte ae17273a37 ui: Replace loading indicator and timeline start virtual timeline items
… with a BackPaginationState observable.
2023-07-06 13:57:40 +02:00
Damir Jelić 75dbfb4d46 Remove an unnecessary unwrap in the crypto crate (#2226) 2023-07-06 12:40:04 +02:00
Ivan Enderlin f2d53a272b Merge pull request #2222 from Hywan/chore-ffi-sliding-sync-bye-bye 2023-07-06 10:11:30 +02:00
Jonas Platte 438c0076f7 ui: Remove NewEventTimelineItem 2023-07-05 17:47:06 +02:00
Jonas Platte b9f98846c8 ci: Upgrade typos 2023-07-05 17:47:06 +02:00
Ivan Enderlin 6cca4ab3e5 chore(ffi): Bye bye Sliding Sync bindings!
The `RoomList` and `EncryptionSync` API provide a better developer
experience and address concrete needs. Nobody no longer uses the Sliding
Sync bindings, so we can remove them.
2023-07-05 15:05:08 +02:00
Ivan Enderlin 96ef45afe8 feat: Immediately fail if a sliding sync request failed (follow up of #2209)
feat: Immediately fail if a sliding sync request failed (follow up of #2209)
2023-07-05 14:47:54 +02:00
Ivan Enderlin 9493c8a75d chore(sdk): Feedbacks. 2023-07-05 14:29:16 +02:00
Ivan Enderlin 1ccc0c3df3 feat(sdk): Ensure that the task sending E2EE requests cannot be detached. 2023-07-05 13:35:52 +02:00
Benjamin Bouvier 1cd87ca15d feat: Immediately fail if a sliding sync request failed
For sliding sync that starts both the actual sliding sync request along the e2ee requests,
we need to make sure that, in case of failure of sliding sync, we reset `pos` as soon as possible.
With the code before this patch, the sliding sync response might be available, but the whole
processing could be waiting for the e2ee requests to finish. In the updated version, we spawn
the e2ee requests in a background task, then run the sliding sync request immediately and fail
if it failed.

Another nice benefit is that the e2ee requests won't be interrupted in the middle of processing,
if the sliding sync changed parameters and we cancelled the whole sync a bit too early.

Fixes #2206.
2023-07-05 13:13:51 +02:00
Jonas Platte afeb5dab24 sdk: Remove questionable use of assign! macro 2023-07-05 12:16:30 +02:00
Jonas Platte 206accb5fb Bump serde_html_form 2023-07-05 11:34:50 +02:00
Jonas Platte 0b24df991e Bump bs58 2023-07-05 11:34:50 +02:00
Jonas Platte dd2fefa2f3 Bump indexmap 2023-07-05 11:34:50 +02:00
Jonas Platte 2b72df7c06 Bump itertools 2023-07-05 11:34:50 +02:00
Jonas Platte 71f7f7c69e Remove mentions of labs crates
There are none at the moment.
2023-07-05 11:34:50 +02:00
Jonas Platte 4ae63caa56 Bump bitflags dependency
2.3.3 contains some bug fixes, might be relevant.
2023-07-05 11:34:50 +02:00
Ivan Enderlin b6908c0611 feat(ui): Change all_rooms batch size to 200
feat(ui): Change `all_rooms` batch size to 200
2023-07-05 10:46:01 +02:00
Ivan Enderlin 36419a7a1f chore: get rid of previous locking crypto-store methods
chore: get rid of previous locking crypto-store methods
2023-07-05 10:35:33 +02:00
Ivan Enderlin 12a1f25ec3 feat(ui): Change all_rooms batch size to 200.
`RoomListServer` defines an `all_room` sliding sync list. This list
starts in selective sync-mode, then it switches to growing sync-mode.
The previous batch size of the growing sync-mode was 50. This patch
updates it to 200, because empirically it seems a better value for
perceived performance.

This patch also rewrites how `State::next` is written. No change in the
code, just comestic.
2023-07-05 10:28:02 +02:00
Ivan Enderlin a0f40606d4 Merge pull request #2208 from bnjbvr/only-restart-growing-on-errors
feat: Only restart growing the allRooms list in case of errors
2023-07-05 10:01:58 +02:00
Jonas Platte da43d81095 ui: Keep loading indicator at the top when processing timeline events 2023-07-05 09:52:59 +02:00
Jonas Platte 5fa293b8ed crypto: Use HashMap inside DashMap
… instead of nesting DashMaps.
The previous type was tracking mutability at very fine-grained level for
no clear reason.
2023-07-04 19:50:45 +02:00
Jonas Platte 87782e9567 ffi: Expose EventTimelineItem::origin 2023-07-04 19:50:08 +02:00
Jonas Platte f344aa7669 sdk: Add EventTimelineItem::origin 2023-07-04 19:50:08 +02:00
Mauro Romito f4929fd064 joined members is now in the notification 2023-07-04 19:39:43 +02:00
Jonas Platte cb2e97f06a Upgrade eyeball to 0.8 2023-07-04 16:22:45 +00:00
Nicolas Mauri 3db72101f3 sdk: Allow to update notification settings (#2135)
* sdk: Allow to update notification settings

* Add an event listener for push rule events

* Fix: simplify insertion and deletion of rules

* Fix: Limit rules cloning

* Fix: Unit tests

* Fix: set_room_notification_mode

* Fix: potential race condition when updating the local ruleset

* Refactor RuleCommands

* RuleCommands Unit Tests

* Fix: limit lock usage

* nit: use expression assignment by default

* nit: pass Ruleset by ownership in RuleCommands' ctor

* a few nits: use to_owned() for &str -> String; use free function for notify actions; use clone() where it's more obvious

and use explicit variants so we know we have to consider this match if we were to add a new variant later

* nit: rename RuleCommands::set_enabled to set_enabled_internal

* nit: test modules don't need to be publicized

* tidy tests

* nit: pass an owned RuleCommands in Rules::apply

* add comments/questions in Rules tests

* nit: no need to publicize the tests module

* tweak NotificationSettings tests too

* rustfmt

---------

Co-authored-by: Benjamin Bouvier <public@benj.me>
2023-07-04 15:29:57 +00:00
Benjamin Bouvier bb34f69662 chore: get rid of previous locking crypto-store methods 2023-07-04 17:19:01 +02:00
Benjamin Bouvier e8a306132a feat: Only restart growing the allRooms list in case of errors
When the sync has been terminated and restarts (e.g. an app is going from the background to the foreground), then
the sliding sync is always restarting in growing mode, independently of the previous state of the sync (error or normal
termination). This is something the current sliding sync proxy can't handle nicely, because it prioritizes a change in
parameters over live data; as a matter of fact, to alleviate the burden of the proxy, we can try to only restart in
growing mode if we ran into an error (and not if we had a normal termination).
2023-07-04 13:06:49 +02:00
Jonas Platte 7bcc886429 Re-format with latest rustfmt 2023-07-03 18:57:05 +02:00
Jonas Platte 37023fe90b Fix new clippy lint 2023-07-03 18:57:05 +02:00
Jonas Platte cd4288391e Bump nightly toolchain version 2023-07-03 18:57:05 +02:00
Jonas Platte b681f234a3 Upgrade criterion, pprof 2023-07-03 18:08:01 +02:00
Alfonso Grillo 147cd970c4 Map MSC3488 fields for UniFFI (#2187)
* Update ruma

* Refactor send_location

* Add timeline parser

* Fix code format

* Add zoom_level

* Update ruma

* Map zoom_level

* Format code

* Cleanup

* Refactor LocationContent

* Apply suggestion

* Fix format issue
2023-07-03 13:34:07 +00:00
Ivan Enderlin 10c9a47f01 Merge pull request #2197 from Hywan/test-ui-room-list-assert-equal 2023-07-03 13:36:55 +02:00
Ivan Enderlin 746b13071e Merge pull request #2198 from Hywan/test-integration-fix 2023-07-03 13:36:06 +02:00
Ivan Enderlin c955de8331 test: Change the installer for setup-matrix-synapse.
There is a bug in Synapse and changing the installer seems to fix the
problem.
2023-07-03 12:47:24 +02:00
Ivan Enderlin 0c13b76d27 test(ui): Do strict assert comparison in some tests of RoomList.
It ensures that we know exactly what's happening here. Tests are still
valid without any changes in the expected data, but it prevents a
potential breaking.
2023-07-03 11:13:45 +02:00
Ivan Enderlin 4f84e33457 fix(ui): Add bump_event_types onto visible_rooms
fix(ui): Add `bump_event_types` onto `visible_rooms`
2023-07-03 10:04:31 +02:00
Ivan Enderlin 37ad562b4b test(sdk): Use async_test instead of tokio::test. 2023-07-03 09:36:45 +02:00
Ivan Enderlin ed2d3bc5b3 chore(ui) Use a function to configure all_rooms and visible_rooms.
The Sliding Sync list `all_rooms` and `visible_rooms` of the `RoomList`
must have the exact same configurations for `sort`, `filters`, and
`bump_event_types`. Instead of maintaining the same code, this patch
adds a new function: `configure_all_or_visible_rooms_list` that
configures the lists exactly the same. This function also explicitely
configures `sort` so that we do no rely on the default values from
`SlidingSyncListBuilder`.
2023-07-03 09:22:32 +02:00
Ivan Enderlin 627a1613df fix(ui): Add bump_event_types onto visible_rooms.
This patch configures the same `bump_event_types` for the
`visible_rooms` list than for the `all_rooms` list, so that we may be
sure that the sorting/ordering is the same between the two lists.
2023-06-30 21:48:30 +02:00
Ivan Enderlin f82fd896f9 chore(ui): Rename room_list module to room_list_service
chore(ui): Rename `room_list` module to `room_list_service`
2023-06-30 21:45:10 +02:00
Ivan Enderlin 9f90b6d4a8 chore(ui): Rename room_list module to room_list_service. 2023-06-30 19:59:13 +02:00
jonnyandrew 3180a1ba7c ffi: Expose proxy and insecure SSL settings (#2191)
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
2023-06-30 15:31:20 +02:00
Benjamin Bouvier 4fbb3d2b63 xtask: add --features testing to most testing tasks 2023-06-30 12:41:04 +02:00
Benjamin Bouvier 66e1b94d31 test: add test for the generational counter invalidation 2023-06-30 12:41:04 +02:00
Benjamin Bouvier d642c22db7 feat: implement a generation counter for the CryptoStore lock 2023-06-30 12:41:04 +02:00
Benjamin Bouvier d72fd34325 Make pending local echoes sticky, take 2 (#2189)
* ui: Move EventSendState into timeline::event_item::local module

* [WIP] ui: Make pending local echoes stick to the bottom of the timeline

* test: update more test expectations

* chore: tweak comment to slightly better reflect reality

* nit: remove else after return

* fix: the item's insert position is insert_idx, not `items.len()` anymore

* fix: look for remote echo before local echo when processing send state

Previous code assumed that the latest timeline items would be the most recent, and that
if there was a remote echo, it would always be after the local echo, because of that.
That's not the case anymore, so we must look for possibly a remote echo first, and then
if we find it, apply the late update process.

Also, there might remain a day divider added by the local echo, if it were inserted last.
I'm not sure it covers all the cases, but I've now made it so that the day divider is removed
if it was the last element.

* feat: switch strategy; keep on pushing if there's nothing in the timeline yet

* Revert "test: update more test expectations"

This reverts commit 400cc93ba7c98042a28b5e8d5042899e854f6cff.

* test: reset test expectations

* Address review comments

* fix: don't mix up latest event with any status, with latest non-failed event index

---------

Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-06-30 09:37:49 +00:00
Richard van der Hoff 5348e7cc12 Airplane -> Aeroplane
For verification-by-emoji, the spec uses the word "Aeroplane" rather than
"Airplane". Element-web expects us to use the specced words (and will otherwise
complain about the lack of i18n data).

It seems like following the spec will help maintain consistency.
2023-06-30 10:45:52 +02:00
jonnyandrew f508109d0c Fix reaction response resolution 2023-06-30 10:26:41 +02:00
Benjamin Bouvier 77290ff2c1 feat: Get rid of "common extensions"
Common extensions are confusing, and they've included `e2ee` and `to-device` by default. This is not a sane default anymore,
now that there's the concept of `EncryptionSync`: it's either we have the encryption sync that enables e2ee and to-device +
a room list sync that doesn't, OR we have a single room list that has both.

Room List was misconfigured to always use `e2ee` and `to-device`, which was incorrect when it's running with the `EncryptionSync`
in the background. This is now removed, and properly tested.
2023-06-30 09:56:29 +02:00
Richard van der Hoff 48a6bffc1e Merge branch 'release-matrix-sdk-crypto-js-0.1.0' 2023-06-29 17:02:40 +01:00
Ivan Enderlin 1958df22a9 fix(sdk): Change how SlidingSyncList::update_room_list handles updates for out of list rooms
fix(sdk): Change how `SlidingSyncList::update_room_list` handles updates for out of list rooms
2023-06-29 15:48:39 +02:00
Ivan Enderlin 91bf84714d feat(ffi): Add methods on RoomListItem so that full_room isn't necessary
feat(ffi): Add methods on `RoomListItem` so that `full_room` isn't necessary
2023-06-29 15:39:45 +02:00
Richard van der Hoff 757716c924 matrix-sdk-crypto-js v0.1.0 2023-06-29 15:22:00 +02:00
Richard van der Hoff 1b2b6c011b update changelog 2023-06-29 15:22:00 +02:00
Ivan Enderlin bd148fd422 chore(ffi): RoomListItem::is_direct returns a bool. 2023-06-29 15:14:53 +02:00
Ivan Enderlin 363b0d9ee6 doc(ffi): Add some precisions. 2023-06-29 15:07:46 +02:00
Benjamin Bouvier 73ad51879a feat: implement time lease based locks for the CryptoStore (#2140)
This implements a new time lease based lock for the `CryptoStore`, that doesn't require explicit unlocking, so that's more robust in the context of #1928, where any process may die because the device is running out of battery, or unexpected flows cause a lock to not be released properly in one or the other process.

```
//! This is a per-process lock that may be used only for very specific use
//! cases, where multiple processes might concurrently write to the same
//! database at the same time; this would invalidate crypto store caches, so
//! that should be done mindfully. Such a lock can be acquired multiple times by
//! the same process, and it remains active as long as there's at least one user
//! in a given process.
//!
//! The lock is implemented using time-based leases to values inserted in a
//! crypto store. The store maintains the lock identifier (key), who's the
//! current holder (value), and an expiration timestamp on the side; see also
//! `CryptoStore::try_take_leased_lock` for more details.
//!
//! The lock is initially acquired for a certain period of time (namely, the
//! duration of a lease, aka `LEASE_DURATION_MS`), and then a "heartbeat" task
//! renews the lease to extend its duration, every so often (namely, every
//! `EXTEND_LEASE_EVERY_MS`). Since the tokio scheduler might be busy, the
//! extension request should happen way more frequently than the duration of a
//! lease, in case a deadline is missed. The current values have been chosen to
//! reflect that, with a ratio of 1:10 as of 2023-06-23.
//!
//! Releasing the lock happens naturally, by not renewing a lease. It happens
//! automatically after the duration of the last lease, at most.
```

---

* feat: implement a time lease based lock for the crypto store
* feat: switch the crypto-store lock a time-leased based one
* chore: fix CI, don't use unixepoch in sqlite and do time math in rust
* chore: dummy implementation in indexeddb, don't run lease locks tests there
* feat: in NSE, wait the duration of a lease if first attempt to unlock failed
* feat: immediately release the lock when there are no more holders
* chore: clippy
* chore: add comment about atomic sanity
* chore: increase sleeps in timeline queue tests?
* feat: lower lease and renew durations
* feat: keep track of the extend-lease task
* fix: increment num_holders when acquiring the lock for the first time
* chore: reduce indent + abort prev renew task on non-wasm + add logs
2023-06-29 13:05:44 +00:00
Ivan Enderlin 0cd0ade2bc feat(ffi): Add methods on RoomListItem so that full_room isn't necessary.
Calling `RoomListItem::full_room` creates its associated `Timeline`.

ElementX calls `full_room` to get the `is_direct`, `avatar_url` and
`canonical_alias` values for _all_ rooms in the room list. Instead of
doing so, let's add those methods directly in `RoomListItem` so that the
`Timeline` isn't created for _all_ rooms.
2023-06-29 14:48:37 +02:00
Ivan Enderlin eab1f8783a chore(ui): Remove unecessary qualification
chore(ui): Remove unecessary qualification
2023-06-29 14:18:09 +02:00
Richard van der Hoff 9a2f6b8fb9 matrix-sdk-crypto-js v0.1.0
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 1m35s
2023-06-29 13:10:16 +01:00
Richard van der Hoff 082d166502 update changelog 2023-06-29 13:09:51 +01:00
Ivan Enderlin 717063eaa8 feat(common): Implement RingBuffer::drain
feat(common): Implement `RingBuffer::drain`
2023-06-29 13:49:37 +02:00
Ivan Enderlin 9b4d06272c chore(ui): Remove unecessary qualification. 2023-06-29 13:37:45 +02:00
Ivan Enderlin 6d67375f8e fix(ffi): Simplify Room::add_timeline_listener
fix(ffi): Simplify `Room::add_timeline_listener`
2023-06-29 13:24:05 +02:00
Ivan Enderlin e96097a085 feat(common): Implement RingBuffer::drain.
This patch implements `RingBuffefr::drain` because it's going to be
useful soon.
2023-06-29 13:22:43 +02:00
Richard van der Hoff 506d7c6f9b Add accessor for remaining time to VerificationRequest. (#2178) 2023-06-29 11:49:31 +01:00
Benjamin Bouvier 459b689953 tests: add unit tests for the CryptoStoreLock 2023-06-29 12:34:53 +02:00
Ivan Enderlin 61b7335dce chore(sdk): Log SlidingSync list updates
chore(sdk): Log SlidingSync list updates
2023-06-29 11:34:04 +02:00
Ivan Enderlin 62315d726f feat(ui): Do not update the viewport of the room list if it hasn't changed
feat(ui): Do not update the viewport of the room list if it hasn't changed
2023-06-29 11:33:45 +02:00
Ivan Enderlin 9bae039629 fix(sdk): Change how SlidingSyncList::update_room_list handles updates for out of list rooms.
So. `SlidingSyncList::update_room_list()` does the following:

1. It adjust room list entries,
2. It updates the `maximum_number_of_rooms`,
3. It applies the sync operations on the `room_list` entries,
4. It updates the `room_list` entries for rooms outside the sync
   operations.

SlidingSync answers with a `lists` and `rooms`. The `room_list` entries
is updated as follows: either a sync operation from `lists` has been
applied and the entries are updated, or `rooms` contains rooms that
are not updated by `lists` but that receive new events, and thus must
trigger an update in the `room_list` entries.

This patch changes a little bit the last part of this. Initially,
we were updating rooms that are part of `rooms` but absent of
`lists` sync operations, only **for the current list's ranges**.
But that's wrong! First, we have noticed a bug here: the
correct code wasn't `skip(start).take(end.saturating_add(1))` but
`skip(start).take(end.saturating_add(1) - start)`. Note a big deal, we
were iterating on more entries like it was necessary, but everything
was filtered later, so no bug, just useless computations. Second,
this `skip` and `take` is actually… useless. A room to which we have
subscribed can be out of any range, but we still want `room_list`
entries to receive an update for that particular room.

This patch fixes that once and for all.

In practise, the bug wasn't happening because if someone subscribes
to a room, its timeline is likely to be fetched, and updates will be
received, but still, this is better now from a SlidingSync strict point
of view.
2023-06-29 11:21:31 +02:00
Ivan Enderlin d01725dedb fix(ffi): Simplify Room::add_timeline_listener.
This patch does the following:

1. changes `add_timeline_listener` to be async, thus removing one
  `RUNTIME.block_on`.
2. simplifies the logic by adopting a more classical pattern we use
   elsewhere:
  * removes one `spawn_blocking`,
  * let's move the `listener` into the task as a `Box` instead of
    cloning it as an `Arc`.
2023-06-29 10:31:04 +02:00
Ivan Enderlin 111071c034 chore(sdk): Log SlidingSync list updates.
This patch removes an old log and adds a better one with more context.
2023-06-29 09:47:39 +02:00
Ivan Enderlin af4ebd8422 feat(ffi): Update RoomListService::apply_input to always return (). 2023-06-29 09:21:14 +02:00
Ivan Enderlin de09b781ec feat(ui): Do not update the viewport of the room list if it hasn't changed.
Imagine the room list has the viewport set to the range `0..=19`. The
user scrolls quickly to `50..=69` to see something below and immediately
scrolls back to its initial position, without stopping the scroll
at any moment in between. The app using this API might update the
viewport from `0..=19` to… `0..=19`. Updating the viewport, updates the
`visible_rooms` sliding sync list. Since a list is modified, the current
sync-loop iteration is skipped over and a new one restarts, i.e. the
current in-flight request is cancelled… for nothing.

This patch prevents this situation. The current viewport ranges is
stored in `RoomListService`. `RoomListService::apply_input` used to
return `Result<(), Error>`, now it returns `Result<InputResult, Error>`.
The `InputResult` enum is a new type. It represents whether an input has
been applied or ignored, which must be differentiate from errors.

So now, if the viewport changes and it's not different from the previous
value, `InputResult::Ignored` is returned.
2023-06-29 09:21:14 +02:00
Richard van der Hoff 5d9cc6be15 use assert_matches instead of manual panics 2023-06-28 16:32:07 +02:00
Richard van der Hoff c0c7c598b5 When refusing a verification, send cancel to the originating device
According to the spec, when a device receives a verification request and wants
to refuse it, it should send the `m.key.verification.cancel` to the originating
device, rather than broadcasting it.
2023-06-28 16:32:07 +02:00
Andy Balaam 33243cb9fb Fix comment wrongly referring to vector.
Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-06-28 14:07:10 +02:00
Andy Balaam 785eccc004 Add capacity to RingBuffer 2023-06-28 14:07:10 +02:00
Andy Balaam 13c7f5b0c6 Implement Default for RingBuffer 2023-06-28 14:07:10 +02:00
Richard van der Hoff 3f2eb5828c crypto-js: wait for device updates in getIdentity
We previously did something similar for `getUserDevices` in 0da8e56a. Turns out
it's useful for `getIdentity` too.
2023-06-28 13:33:23 +02:00
Jonas Platte e732b3630a ffi: Add SendAttachmentJoinHandle 2023-06-28 12:55:56 +02:00
Jonas Platte b088339710 Revert "crypto: Add Store::room_keys_for_room_received_stream"
This reverts commit e87b3def02.
2023-06-28 12:32:18 +02:00
Jonas Platte 90e39f7be2 Revert "sdk: Re-export room_keys[_for_room]_received_stream from Encryption"
This reverts commit 04d56130c3.
2023-06-28 12:32:18 +02:00
Jonas Platte fd5b28bb51 Revert "sdk: Add room::Joined::room_keys_received_stream"
This reverts commit 9f72e2cf16.
2023-06-28 12:32:18 +02:00
Jonas Platte b53eba5ec9 Revert "ui: Use new room_key stream for retrying decryption in Timeline"
This reverts commit 06600ac53f.
2023-06-28 12:32:18 +02:00
Ivan Enderlin 07b7885915 chore(sdk): Add missingn newline. 2023-06-28 11:10:53 +02:00
Jonas Platte 06600ac53f ui: Use new room_key stream for retrying decryption in Timeline 2023-06-28 10:14:59 +02:00
Jonas Platte 9f72e2cf16 sdk: Add room::Joined::room_keys_received_stream 2023-06-28 10:14:59 +02:00
Jonas Platte 04d56130c3 sdk: Re-export room_keys[_for_room]_received_stream from Encryption 2023-06-28 10:14:59 +02:00
Jonas Platte e87b3def02 crypto: Add Store::room_keys_for_room_received_stream 2023-06-28 10:14:59 +02:00
Ivan Enderlin 07700abf75 feat: Cache the RoomListService's rooms
feat: Cache the `RoomListService`'s rooms
2023-06-28 08:58:45 +02:00
Ivan Enderlin 9ab4fa0a8b chore(sdk): Log the SyncOps
chore(sdk): Log the `SyncOp`s
2023-06-28 08:41:00 +02:00
Andy Balaam 86fe3364ed Add serialization, clear and extend to RingBuffer 2023-06-27 17:25:25 +00:00
Jonas Platte 81ca1c5072 ui: Add a test for thread message reply fallback 2023-06-27 19:23:14 +02:00
Jonas Platte 4ec8bec2fc ui: Treat thread fallback the same as a regular reply
… for now, until we add proper support for threads.
2023-06-27 19:23:14 +02:00
Benjamin Bouvier 98fed1d2eb chore: use smaller critical sections
This opens up a possible race condition where an embedder calls the method twice, generating two new rooms,
but then it's fine as long as they don't cache them somewhere, which we expect they don't.
2023-06-27 16:29:35 +02:00
Benjamin Bouvier e3df97421b chore: remove useless async 2023-06-27 16:27:31 +02:00
Jonas Platte b08480baea ui: Move message-sending loop start log event
… such that it gets the timeline builder's tracing span.
2023-06-27 16:18:04 +02:00
Benjamin Bouvier ccd5e877eb feat: Cache the RoomListService's rooms
That avoids recreating a timeline object every time a user calls `RoomListService::room()` with the same room id, so that should speed up
operations like fetching the latest event for rooms we've already entered before.
2023-06-27 16:05:26 +02:00
Damir Jelić fed583c5c6 Emit room keys after they have been persisted, not before. 2023-06-27 14:30:08 +02:00
Doug d4252c4e4a feat(bindings): Add user_agent parameter to authentication_service. 2023-06-27 12:59:22 +02:00
Ivan Enderlin 61202ec19a feat(common): Propose a simple RingBuffer implementation
feat(common): Propose a simple `RingBuffer` implementation
2023-06-26 19:52:57 +02:00
Ivan Enderlin ad1b9056ae feat(common): Add RingBuffer::is_empty. 2023-06-26 19:30:27 +02:00
aringenbach 47030e7883 ffi: Use toggle_reaction and update API 2023-06-26 16:08:50 +00:00
Ivan Enderlin d69be5ee75 feat(common): Propose a simple RingBuffer implementation.
This patch propose a very simple `RingBuffer` implementation based on
`std::collections::VecDeque`.
2023-06-26 17:49:41 +02:00
jonnyandrew 7e7996d43d ui: Add local echoes for reactions to Timeline 2023-06-26 15:17:48 +00:00
Ivan Enderlin 04580f75a8 chore(sdk): Log the SyncOps. 2023-06-26 16:04:11 +02:00
Jonas Platte 49b1e8732c Upgrade most of our dependencies
Still holding back js-sys and web-sys due to unresolved wasm-bindgen issues.
2023-06-26 14:32:24 +02:00
Ivan Enderlin ba422f861e fix(sdk): Change SlidingSyncList::room_list's capacity
fix(sdk): Change `SlidingSyncList::room_list`'s capacity
2023-06-26 14:16:05 +02:00
Ivan Enderlin 749911af60 fix(sdk): Change SlidingSyncList::room_list's capacity.
This patch changes the capacity of the internal buffer of
`ObservableVector` for `SlidingSyncList::room_list` from 16 to 4096.
With an increased capacity, we reduce the probability to send a
`VectorDiff::Reset` to subscribers. `Reset` are happening quite often
for apps using `matrix-sdk`, and it impacts their performance. This
patch tries to improve this situation. This `room-list` contains
`RoomListEntry`, which is can cheap in terms of memory, compared to the
impact of sending `Reset`s too often. That's a tradeoff.
2023-06-26 13:52:15 +02:00
Jonas Platte 0e1f74f617 Increase other sleep in test a bit 2023-06-26 11:36:24 +02:00
Jonas Platte b6353f82a8 ui: Improve logging for message-sending queue 2023-06-26 11:36:24 +02:00
Benjamin Bouvier 171c1cf25b chore: fix documentation
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-26 11:22:38 +02:00
Benjamin Bouvier b442d30848 feat: remove the in-memory cache for to_device_token in sliding sync
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-26 11:22:38 +02:00
Benjamin Bouvier 94fa888b7b feat: always enable the SS cache by default
This makes sure that the to-device prev_batch/since token is already saved to and reloaded from disk.

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-26 11:22:38 +02:00
Benjamin Bouvier 69932adb7e chore: remove unreachable UI notifications module
Remnant from a bad merge/renaming.

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-26 11:22:38 +02:00
Mauro 2c58c65add ffi: Allow disabling local notification filtering using push rules 2023-06-26 08:49:06 +00:00
Ivan Enderlin 8916eb6409 test(ui): Replace sleep by yield_now
test(ui): Replace `sleep` by `yield_now`
2023-06-23 16:37:00 +02:00
Jonas Platte 44ef302bc7 Increase sleep in test a bit
since it seems flaky in CI
2023-06-23 16:17:21 +02:00
Ivan Enderlin 40db35abe7 test(ui): Replace sleep by yield_now.
Eh, removing `sleep` from the tests is always a pleasure right?
2023-06-23 16:15:57 +02:00
Jonas Platte 9b802998b3 ui: Put retries in the message-sending queue 2023-06-23 14:03:27 +02:00
Jonas Platte 0a37ce50a8 ui: Allow retrying cancelled local echoes 2023-06-23 14:03:27 +02:00
Alfonso Grillo e72bae1a8f ffi: Add send_location api 2023-06-23 11:29:01 +00:00
Jonas Platte 4c24007cb8 ui: Add a queue to serialize message sending requests 2023-06-23 09:41:07 +02:00
Jonas Platte cb6d3c3c47 ui: Add a failing test for message ordering 2023-06-23 09:41:07 +02:00
David Langley 19ba18d788 ffi: Expose the senders of reactions 2023-06-23 08:56:16 +02:00
Ivan Enderlin 73de71bd42 feat(ui): Welcome to RoomListService
feat(ui): Welcome to `RoomListService`
2023-06-22 17:36:05 +02:00
Ivan Enderlin 1c6ad4a082 chore(ui): Address feedbacks. 2023-06-22 17:16:25 +02:00
Ivan Enderlin 9eadbc302f feat(ffi): Rename Client::room_list to Client::room_list_service. 2023-06-22 17:08:30 +02:00
Ivan Enderlin 93d619249c test(ui): Reduce latency of the tests. 2023-06-22 15:37:25 +02:00
Ivan Enderlin 35ee6db152 fix(ffi): Eh UniFFI, we want Tokio compat. 2023-06-22 14:59:51 +02:00
jonnyandrew 7fd5068faa ui: Deduplicate reaction senders in timeline 2023-06-22 12:42:49 +00:00
Ivan Enderlin 1631b5ba18 chore(ui): Use matrix_sdk::executor instead of tokio. 2023-06-22 14:15:10 +02:00
Valere 3fd55c0ab1 bindings: Ignore silently malformed userId in migration of tracked users (#2130)
* bindings: Ignore silently malformed userId in migration of tracked users
* Clean: collect will now never fail

Co-authored-by: Benjamin Bouvier <public@benj.me>
2023-06-22 12:11:06 +00:00
Ivan Enderlin 083a79a408 doc(ui): Fix intra-links. 2023-06-22 14:08:09 +02:00
Ivan Enderlin f9fe7450ce Merge branch 'main' into feat-ui-roomlist-service 2023-06-22 13:48:00 +02:00
Ivan Enderlin d43d5b515e chore: Make Clippy happy. 2023-06-22 13:39:00 +02:00
Damir Jelić daa3944593 Bump Ruma 2023-06-22 13:20:37 +02:00
Benjamin Bouvier 679ec70200 feat: implement the full EncryptionSync (#2110)
* crypto: implement more primitives for the MemoryStore to work in tests

* crypto: change the shape of the `CryptoStoreLock` API

In particular:

- make the lock work across multiple threads of the same process trying to acquire it,
using `num_holders`.
- add a mechanism to get the lock only once (for the NSE process, in case the main app
had acquired the lock before).

* client: add a cross-process crypto store lock, enable it with `Encryption::enable_cross_process_store_lock`
* client: make `preshare_room_key` a critical section of the cross-process lock
* sliding sync: make it possible to define different timeouts for a `SlidingSyncInstance`

This will be handy for the NSE process on iOS, which has very little time to wait for the proxy's responses.

* feat: implement the `EncryptionSync` API (renamed from `Notification` API)
* fixup! client: add a cross-process crypto store lock, enable it with `Encryption::enable_cross_process_store_lock`
* feat: allow disabling e2ee / to-device in the RoomList API
* feat: use same SS id for main/NSE process, reload to-device token from disk before each encryption sync
* fix: better error handling if restoring the to-device token failed
* feat: add logs for the locking functions
* test: add a few tests for encryption sync
* feat: add `reload_caches` method in the `EncryptionSync` + FFI bindings
* chore: clean up FFI loop
* encryption sync: Remove unused errors, specialize some errors
* feat: include termination reason in the encryption sync loop
* feat: add more logs
* chore: fmt + clippy + doc
* comment: precise only in the presence of another process
* Tweak `room_list` APIs to include `_with_encryption` variants
* chore: rustfmt
2023-06-22 12:50:45 +02:00
Ivan Enderlin eb2213467a feat(ffi): Implement RoomList::loading_state. 2023-06-22 12:12:45 +02:00
Ivan Enderlin 398f70c9de feat(ui): Implement RoomListLoadingState.
The type is well documented. Go check it out :-).
2023-06-22 11:43:38 +02:00
Kévin Commaille 2b3d1080dc sdk: Allow to support several authentication APIs
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-22 11:21:50 +02:00
Kévin Commaille 7298df0db6 sdk: Move Session and SessionTokens to matrix_auth
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-22 11:21:50 +02:00
Kévin Commaille d6f9f08e30 sdk: Split Matrix authentication methods in a separate API
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-22 11:21:50 +02:00
Mauro Romito 528607f079 feat(bindings): get_notification_item filters out notifications given the push context 2023-06-22 11:09:45 +02:00
Ivan Enderlin c9e3d7988f feat(ui): Change how room_list::State is updated.
Instead of broadcasting an intermediate update for the `State`, it's
updated once after the sync.
2023-06-22 10:23:45 +02:00
aringenbach 726c1bca2c ui: Filter redacted reactions from the timeline 2023-06-21 16:21:39 +00:00
Ivan Enderlin d77a48cc2c feat(ffi): Implement RoomList::room. 2023-06-21 17:20:05 +02:00
Ivan Enderlin 40602e7bba chore(ffi): Update according to previous commits. 2023-06-21 17:11:26 +02:00
Ivan Enderlin b774110235 chore(ui): Move methods from RoomListService inside RoomList.
This patch moves `RoomListService::entries` and `::filtered_entries`
inside `RoomList`. It also implements `RoomList::new`. Finally,
it implements `RoomListService::all_rooms` and re-implement
`RoomListService::invites`.

Basically:

```rust
// 1.
room_list.entries().await?
// 2.
room_list.invites().await?
```

becomes:

```rust
// 1.
room_list.all_rooms().await?.entries()
// 2.
room_list.invites().await?.entries()
```

`all_rooms` and `invites` both return a `RoomList`.
2023-06-21 17:00:30 +02:00
Jonas Platte dccf0c29bf Update reldbg profile to optimize our own packages too
… and enable incremental compilation for it.
2023-06-21 16:36:40 +02:00
Ivan Enderlin b01bbe7e92 chore: Add missing copyright headers. 2023-06-21 16:29:55 +02:00
Ivan Enderlin dc061308bd chore(ui): Rename RoomList to RoomListService. 2023-06-21 16:29:03 +02:00
Ivan Enderlin 12a6f12461 feat(ui): Implement RoomList::stop_sync
feat(ui): Implement `RoomList::stop_sync`
2023-06-21 16:23:06 +02:00
Jonas Platte 895669e39b sdk: Upload thumbnail and attachment in parallel 2023-06-21 14:56:22 +02:00
Jonas Platte 54288cb4cb Fix clippy lints 2023-06-21 14:56:22 +02:00
Jonas Platte b883ec000a sdk: Clean up imports in encryption module 2023-06-21 14:56:22 +02:00
Jonas Platte 8a7da622d8 Rewrap comment 2023-06-21 14:56:22 +02:00
Ivan Enderlin e9c19c2110 doc(crypto-nodejs): Add docs on how to use tracing for local Node dev
Add docs on how to use tracing for local Node dev
2023-06-21 14:29:32 +02:00
Ivan Enderlin 9c62b3459f Merge pull request #2119 from matrix-org/valere/quick_fix_doc
Fix js binding bad comment
2023-06-21 14:17:46 +02:00
Ivan Enderlin f9452959a0 doc(ui): Fix a typo. 2023-06-21 13:52:14 +02:00
Ivan Enderlin 4ec917ca48 feat(ffi): Implement RoomList::is_syncing. 2023-06-21 11:58:44 +02:00
Ivan Enderlin 54fc0f38ea feat(ui): RoomList::sync no longer returns a TaskHandle.
Because there is `RoomList::stop_sync` now, which is better than dealing
with the `TaskHandle`.
2023-06-21 11:54:51 +02:00
Ivan Enderlin fe0b458403 chore(ffi): Update according to previous commits. 2023-06-21 11:53:58 +02:00
Ivan Enderlin 6e8e4bb39c feat(ui): Differentiate between error and termination in room_list::State.
This patch introduces `State::Error`, which replaces
`State::Termianted`. And a “new” `State::Terminated` state is added.

They do the same, but their semantics is different. `Error` is when an
error happened, and it's fine to restart the sync again. `Terminated`
is when a termination has been reached (either because SS sync-loop
has ended naturally, or because `RoomList::stop_sync` has been called),
in this case, it may not be fine to restart the sync automatically for
example.
2023-06-21 11:37:00 +02:00
Ivan Enderlin 7073e6f9e3 feat(ui): Remove the State::CarryOn state.
This patch removes the `State::CarryOn`. It turns out that `Running` and
`CarryOn` are doing exactly the same thing. So one of them is useless.
2023-06-21 11:14:29 +02:00
Ivan Enderlin f0bc6d6698 chore(ui): Rename State::FirstRooms and State::AllRooms.
This patch renames `State::FirstRooms` to `State::SettingUp`, and
`State::Running` as requested by users.

It hides the “inner Sliding Sync logic”, the Sliding Sync lists etc.
2023-06-21 11:12:51 +02:00
Ivan Enderlin a78ad89fdd feat(ffi): Implement RoomList::stop_sync.
This patch implements `RoomList::stop_sync` on the FFI bindings.

Technically, it's no more useful to store the `TaskHandle` of the
`sync`, but it's still here, in case of.
2023-06-21 09:22:50 +02:00
Ivan Enderlin ec5c1a3c70 feat(ui): Implement RoomList::stop_sync.
This patch implements `RoomList::stop_sync`. The goal is twofold:

1. It forces to stop the syncing, thus putting the state-machine into
   the `Terminated` state, which is semantically better than “stop
   polling the `sync`'s `Stream`”.

2. It literally forces to stop the syncing. It cancels pending futures,
   it cancels in-flight HTTP requests etc. It's a more robust way to
   stop the `RoomList` sync.
2023-06-21 09:20:44 +02:00
valere 1cc90c8ec0 Fix js binding bad comment 2023-06-21 09:11:09 +02:00
Valere 8a8074cada Add first_time_seen timestamp to devices 2023-06-21 08:49:44 +02:00
Ivan Enderlin 644410afe9 feat(ui): TimelineBuilder::build logs more data
feat(ui): `TimelineBuilder::build` logs more data
2023-06-20 21:12:55 +02:00
Ivan Enderlin 9755af5a9a Revert parts of #2111 because name is already cached in RoomInfo
Revert parts of #2111 because name is already cached in RoomInfo
2023-06-20 21:09:11 +02:00
Alfonso Grillo 673ac33579 ffi: Add location message type 2023-06-20 16:51:12 +00:00
Andy Balaam 5a0c35edb2 Revert parts of #2111 because name is already cached in RoomInfo 2023-06-20 14:58:17 +01:00
Nicolas Mauri 3f3fd58770 sdk: Add a Rules utility struct to manipulate a Ruleset 2023-06-20 14:56:33 +02:00
Ivan Enderlin a496471cf3 test(base): Tests for finding DM rooms
Tests for finding DM rooms
2023-06-20 12:37:47 +02:00
Andy Balaam 2a2ce5f05c Already-passing tests for get_dm_room including left rooms 2023-06-20 11:05:37 +01:00
Andy Balaam 40aab0c426 Already-passing tests for keeping users in direct_targets when they leave a DM 2023-06-20 11:05:37 +01:00
Andy Balaam 0e5d8bc904 Fix double-clone 2023-06-20 11:25:29 +02:00
Andy Balaam 02449a73ea Fix clippy warnings 2023-06-20 11:25:29 +02:00
Andy Balaam 7f8bc8f1c2 Avoid holding a lock over an await 2023-06-20 11:25:29 +02:00
Andy Balaam 149a9d4099 Cache room display name if it comes in from sync 2023-06-20 11:25:29 +02:00
Andy Balaam 75eb94357e Split out tests for room display names 2023-06-20 11:25:29 +02:00
Andy Balaam d84c8d91b5 Fix typo in comment 2023-06-20 11:25:29 +02:00
Jonas Platte 5273fa6f42 sdk: Move target-specific HTTP code into new submodules 2023-06-20 11:16:13 +02:00
Jonas Platte 4c1a351ead sdk: Remove HttpSend in favor of allowing reqwest customization 2023-06-20 11:16:13 +02:00
Jonas Platte ba9d8294b4 ffi: Make upload progress observable 2023-06-20 11:16:13 +02:00
Jonas Platte ac140c192a Make upload progress observable 2023-06-20 11:16:13 +02:00
Jonas Platte a668822fec Simplify HttpClient::send_request signature 2023-06-20 11:16:13 +02:00
Richard van der Hoff 6fc90609b6 Release crypto-js 0.1.0-alpha.11 (#2112) 2023-06-19 18:09:52 +00:00
Jonas Platte 93c911add3 ui: Use method syntax for shared::Observable methods 2023-06-19 16:46:43 +02:00
Benjamin Bouvier 55aad67338 Remove the sqlite-lock binary from the main repo
Will move it to a personal repository of mine.

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-19 15:42:58 +02:00
Andrew Ferrazzutti c618094c19 Retitle tracing section 2023-06-19 09:11:15 -04:00
Ivan Enderlin 16a2121291 feat(ui): TimelineBuilder::build logs more data.
This patch updates `tracing::instrument` on `TimelineBuilder::build` so
that we can detect the circumstance of slow cases.
2023-06-19 15:06:55 +02:00
Andrew Ferrazzutti 1f141fc372 Format README.md 2023-06-19 08:25:27 -04:00
Kévin Commaille 6b40db4669 sdk: Keep all the discovered AuthenticationServerInfo
It has an account field besides the issuer field.
Also store it as immutable, the data used for authentication will be
stored in another variable.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-19 13:08:45 +02:00
Kévin Commaille 2b70d1c8c6 sdk: Export Invite
It's the type returned from Invited::invite_details() but it is not
available publicly.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-19 13:02:17 +02:00
Ivan Enderlin d105b72554 fix(sdk): Remove the Sliding Sync retry mechanism on M_UNKNOWN_POS
fix(sdk): Remove the Sliding Sync retry mechanism on `M_UNKNOWN_POS`
2023-06-19 12:37:48 +02:00
Ivan Enderlin 67ade0a2da doc(crypto): Fix a typo
doc(crypto): Fix a typo
2023-06-19 12:35:14 +02:00
Ivan Enderlin 0c85b178ac test(ui): Fix Notification test. 2023-06-19 12:16:26 +02:00
Ivan Enderlin 87a8ac7420 doc(crypto): Fix a typo. 2023-06-19 12:06:51 +02:00
Ivan Enderlin 30b7c4bd7f fix(sdk): Remove the Sliding Sync retry mechanism on M_UNKNOWN_POS.
`SlidingSync::sync` had a legacy behaviour when a `M_UNKNOWN_POS`
error was received from the server: It was resetting `pos` and sticky
parameters before re-running a sync-loop iteration, hoping to get a
valid response from the server after that. This retrying
mechanism was running up to 3 times in row (represented by the
`MAXIMUM_SLIDING_SYNC_SESSION_EXPIRATION` constant) before stopping the
`sync` for real.

While it seemed a good idea, it actually brings numerous problems:

1. Each iteration in the sync-loop generates a new request, thus making
   the `ranges` of the requests to move forwards. For `SlidingSyncList`
   that are in `Selective` sync-mode, there is no problem, but for
   `Growing` or `Paging` sync-modes, the `ranges` increased. Thus,
   when a `SlidingSync` session expires, instead of returning to
   the caller to do something clever (like what `RoomList` does: start
   again with a small range so that the “first” sync after a session
   expiration is guaranteed to be fast), it was running larger and
   larger requests, up to 3 times.
2. `M_UNKNOWN_POS` _is_ an error. Yes, `SlidingSync` must reset `pos`
   and must invalidate sticky parameters, but the `sync` must be
   stopped, and the error must be returned so that the caller can do
   something about it. Until now, this error was likely to be missed by
   the caller.
3. This legacy mechanism was forbidding `SlidingSync::sync`'s caller to
   do something with this special error. And since the caller was blind to
   this error, it disallowed more smart error management.

This patch removes this legacy retry mechanism entirely. When
`M_UNKNOWN_POS` is received from the server, `pos` is reset and sticky
parameters are invalidated as before, but the error is returned like any
other error.

This patch renames and updates an existing test that was testing sticky
parameters invalidation on `M_UNKNOWN_POS`, to include some assertions
on `pos` and to ensure that the sync-loop is stopped accordingly.
2023-06-19 11:43:27 +02:00
Benjamin Bouvier 4d3ca15be3 feat(ui): Implement Notification API (#2023)
This is the first PR for splitting the sync loop into two. This offers a new high-level API, `NotificationApi`, that makes use of a separate `SlidingSync` instance which sole role is to listen to to-device events and e2ee; it's pre-configured to do so. That means we're not force-enabling e2ee and to-device by default for every sliding sync instance, and as such we won't either generate Olm requests to the home server in general.

In the future, this new high-level API will hide some low-level dirty details so that its can be instantiated in multiple processes at the same time (lock across process, invalidate and refill crypto caches, etc.).

An embedder who would want to make use of this would need the following:

- a main sliding sync instance, without e2ee and to-device. Using the `matrix_sdk_ui::RoomList` would be the best bet, at this time.
- an instance of this `matrix_sdk_ui::NotificationApi`, with a different identifier.

Note that this is not ready to be used in an external process; or it will cause the same kind of issues that we're seeing as of today: invalid crypto caches resulting in UTD, etc.

Fixes https://github.com/matrix-org/matrix-rust-sdk/issues/1961.
2023-06-19 08:56:58 +00:00
Damir Jelić 7c393d73c4 Merge branch 'openqrnch/main' 2023-06-19 09:40:14 +02:00
Damir Jelić 75cf572968 Fix the formatting of the sync_with_result_callbac() docstring 2023-06-19 09:39:34 +02:00
Jan Danielsson bccd3412c1 Add a missing backtick in sync_with_result_callback() documentation. 2023-06-18 15:29:58 +02:00
Ivan Enderlin 6d4874e147 doc(ui): Fix a typo. 2023-06-18 09:20:57 +02:00
Andrew Ferrazzutti bb1bfbcb48 Add docs on how to use tracing for local Node dev 2023-06-16 11:51:10 -04:00
Richard van der Hoff ef0c230bd3 crypto-js: Simplify response type of Sas::confirm (#2066)
On the javascript side, everything is just an `OutgoingRequest`, so we may
as well return a single array rather than a tuple.
2023-06-16 16:19:35 +01:00
Damir Jelić bddc88472a Clarify the comment about creating a Olm session twice
Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
2023-06-16 16:56:09 +02:00
Damir Jelić aab3d00246 Log if a session was created using a fallback key 2023-06-16 16:56:09 +02:00
Damir Jelić a94e2f06ee Ensure that we're not creating the same session twice
Usually it's impossible to create a Olm session from a pre-key message
twice. The one-time key that should be used for the 3DH step will be
used up and we're going to throw a `MissingOneTimeKey` error.

This used to be true and unproblematic until we added fallback keys,
these keys will not get discarded immediately after they have been used
once.

This means that a pre-key message, for which we already have a Session,
but decryption for it fails, might create a new Session overwriting the
existing one which will essentially reset the ratchet.
2023-06-16 16:56:09 +02:00
Damir Jelić 817dcde4d8 Test that we're not able to decrypt replayed messages 2023-06-16 16:56:09 +02:00
Benjamin Bouvier 76ed3511b5 Add a value-based lock in the CryptoStores (#2049)
This implements a value-based lock in the crypto stores. The intent is to use that for multiple processes to be able to make writes into the store concurrently, while still cooperating on who does them. In particular, we need this for #1928, since we may have up to two different processes trying to write into the crypto store at the same time.

## New methods in the `CryptoStore` trait

The idea is to introduce two new methods touching **custom values** in the crypto store:

- one to atomically insert a value, only if it was missing (so, not following the semantics of `upsert` used in the `set_custom_value`) 
- one to atomically remove a custom value

Those two operations match the semantics we want:

- take the lock only if it ain't taken already == insert an entry only if it was missing
- release the lock = remove the entry

By looking at the number of lines affected by the query, we can infer whether the insert/remove happened or not, that is, if we managed to take the lock or not.

## High-level APIs

I've also added an high-level API, `CryptoStoreLock`, that helps managing such a lock, and adds some niceties on top of that:

- exponential backoff to retry attempts at acquiring the lock, when it was already taken
- attempt to gracefully recover when the lock has been taken by an app that's been killed by the environment
- full configuration of the key / value / backoff parameters

While it'd be nice to have something like a `CryptoStoreLockGuard`, it's hard to implement without being racy, because of the `async` statements that would happen in the `Drop` method (and async drop isn't stable yet).

## Test program

There's also a test program in which I shamelessly show my rudimentary unix skills; I've put it in the `labs/` directory but this could as well be a large integration test. A parent program initially fills a custom crypto store, then creates a `pipe()` for 1-way communication with a child created with `fork()`; then the parent sends commands to the child. These commands consist in reading and writing into the crypto store, using a lock. And while the child attempts to perform these operations, the parent tries hard to get the lock at the same time. This helps figuring out a few issues and making sure that cross-process locking would work as intended.
2023-06-16 13:05:54 +00:00
Ivan Enderlin 1660c71dfd feat(ui): Add bump_event_types for all_rooms in RoomList
feat(ui): Add `bump_event_types` for `all_rooms` in `RoomList`
2023-06-16 14:52:10 +02:00
Ivan Enderlin 646fb35b3a feat(ui): Add bump_event_types for all_rooms in RoomList.
This patch configures the `bump_event_types` paramter for the
`all_rooms` list in `RoomList`.
2023-06-16 14:49:08 +02:00
Benjamin Bouvier bae1a71c81 feat: make OlmMachine resettable (#2091)
* feat: make `OlmMachine` resettable by making it an Arc<RwLock> instead of a OnceCell
* chore: fix e2e-encryption scoping
2023-06-16 12:39:08 +00:00
Ivan Enderlin 3d859674a8 fix(ui): Enable SS caching on RoomList
fix(ui): Enable SS caching on `RoomList`
2023-06-16 14:36:21 +02:00
Ivan Enderlin a75808e338 fix(ui): Enable SS caching on RoomList. 2023-06-16 14:31:45 +02:00
Ivan Enderlin dc06893130 fix(sdk): Disable the receipts extension temporarily
fix(sdk): Disable the `receipts` extension temporarily
2023-06-16 14:06:29 +02:00
Ivan Enderlin 489898fd40 fix(sdk): Disable the receipts extension temporarily.
Please see https://github.com/matrix-org/matrix-rust-sdk/issues/2037.
2023-06-16 13:40:38 +02:00
Ivan Enderlin 85b6eaa4c7 feat(ffi): Implement RoomList::invites
feat(ffi): Implement `RoomList::invites`
2023-06-16 13:31:53 +02:00
Ivan Enderlin 305d55d551 feat(base) In Sliding Sync, find out which rooms we have left from state events
In Sliding Sync, find out which rooms we have left from state events
2023-06-16 13:27:28 +02:00
Ivan Enderlin bae6fc71d0 test(ui): Add a test specifically for RoomList::invites. 2023-06-16 13:10:36 +02:00
Ivan Enderlin 7a1d59e9a2 feat(ffi): Implement RoomList::invites. 2023-06-16 12:43:36 +02:00
Ivan Enderlin e09a44831b feat(ui): Implement RoomList::invites. 2023-06-16 12:43:12 +02:00
Ivan Enderlin 5d82d5db89 feat(ui): Add the invites list in the RoomList.
The `invites` list is added when the first rooms are loaded, so that it
doesn't slow the first initial start up.
2023-06-16 12:28:42 +02:00
Richard van der Hoff 6199ca069c crypto-js: Add register_changes_callback methods to the verification classes (#2067) 2023-06-16 11:25:50 +01:00
Ivan Enderlin c9a9a5c20a fix(ui): SlidingSync::subscribe_to_room marks room as having missing members
fix(ui): `SlidingSync::subscribe_to_room` marks room as having missing members
2023-06-16 11:45:37 +02:00
Ivan Enderlin a99a7b4a5a test(sdk): Test that room subscription makes members not synced. 2023-06-16 11:23:11 +02:00
Ivan Enderlin c515643442 doc(sdk): Fix typos. 2023-06-16 10:35:32 +02:00
Ivan Enderlin d45f871106 doc(sdk): Fix intralink. 2023-06-16 10:34:48 +02:00
Ivan Enderlin 3a70b2e8ab fix(ui): SlidingSync::subscribe_to_room marks room as having missing members.
Fix https://github.com/matrix-org/matrix-rust-sdk/issues/2004.
2023-06-16 09:44:36 +02:00
Jonas Platte db5c9d8c4b ffi: Add Room::get_timeline_event_content_by_event_id 2023-06-15 17:24:18 +02:00
Ivan Enderlin ec1172c353 feat(ui+ffi): Implement RoomList::entries_loading_state
feat(ui+ffi): Implement `RoomList::entries_loading_state`
2023-06-15 17:20:42 +02:00
Ivan Enderlin 61d4850a66 chore: Make Clippy happy. 2023-06-15 16:18:08 +02:00
Ivan Enderlin 1f6a0b23f0 fix(ui): Set visible_rooms with a default range
fix(ui): Set `visible_rooms` with a default range
2023-06-15 16:08:17 +02:00
Ivan Enderlin 5673422831 test(ui): Use stream_assert to simplify the code. 2023-06-15 15:58:08 +02:00
Ivan Enderlin d935f52c86 doc(sdk): Update documentation of SlidingSyncList::state_stream. 2023-06-15 15:53:06 +02:00
Ivan Enderlin 0ff9073a14 feat(ffi): Implement RoomList::entries_loading_state.
This patch implements `RoomList::entries_loading_state`.
2023-06-15 15:50:21 +02:00
Ivan Enderlin a073c1422c test(ui): Test RoomList::entries_loading_state. 2023-06-15 15:45:30 +02:00
Ivan Enderlin 4e92738c28 feat(ui): Implement RoomList::entries_loading_state.
This patch implements `RoomList::entries_loading_state`, which
is a basic forwarding from the `all_rooms` sliding sync list'
`state_stream()` result.
2023-06-15 15:45:30 +02:00
Ivan Enderlin db6798321c feat(sdk): SlidingSyncList::state_stream returns a tuple.
This patch updates `SlidingSyncList::state_stream` to return
a tuple `(SlidingSyncListLoadingState, impl Stream<Item =
SlidingSyncListLoadingState>)`.
2023-06-15 15:45:30 +02:00
Ivan Enderlin f10f0d017d feat(sdk): Rename SlidingSyncState to SlidingSyncListLoadingState.
This patch renames `SlidingSyncState` to `SlidingSyncListLoadingState`
because:

1. It's about a list information,
2. It's about the loading state, not a generic state.
2023-06-15 15:45:28 +02:00
Ivan Enderlin 1c480398d2 fix(ui): Set visible_rooms with a default range.
The MSC3575 says that if no `ranges` for a list is provided, it defaults
to `0..=99`. We don't want that! This patch sets the default value to
`0..=19` for the `visible_rooms`.
2023-06-15 15:37:35 +02:00
Jonas Platte 52d2fa1a72 ffi: Clean up 2023-06-15 15:20:46 +02:00
Jonas Platte 12df1f38ed ffi: Remove remaining callback interfaces from UDL 2023-06-15 15:20:46 +02:00
Jonas Platte 899c0d59e6 ffi: Remove sliding sync things from UDL 2023-06-15 15:20:46 +02:00
Jonas Platte 867b3665d2 ffi: Remove re-exports from timeline module 2023-06-15 15:20:46 +02:00
Jonas Platte daf59356cb ffi: Remove room list from UDL 2023-06-15 15:20:46 +02:00
Jonas Platte 53ae4362f6 ffi: Remove unused public Rust API 2023-06-15 15:20:46 +02:00
Jonas Platte b789b9e063 ffi: Remove room / timeline things from UDL 2023-06-15 15:20:46 +02:00
Jonas Platte b1c8859eb9 Upgrade UniFFI 2023-06-15 15:20:46 +02:00
Jonas Platte 0e618bea5c ui: Don't use TryFutureExt where not necessary 2023-06-15 14:37:40 +02:00
Ivan Enderlin 31d834048f feat(fii): Implement RoomList::apply_input
feat(fii): Implement `RoomList::apply_input`
2023-06-15 13:22:09 +02:00
Benjamin Bouvier 1fd039c64f sliding sync: lazily generate and include the transaction id, only if it's useful (#2063)
* feat: lazily generate and include the transaction id, only if it's useful
* chore: add a small `LazyTransactionId` wrapper that ensures it's only created once

---------

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-15 10:30:24 +00:00
Kévin Commaille 16a63d352c base: Remove the session field from StateChanges
It is never set nor used.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-15 11:12:40 +02:00
Ivan Enderlin 59565657fa feat(ffi): Implement RoomList::apply_input.
This patch implements `RoomList::apply_input`. Usage example:

```rust
room_list.apply_input(RoomListInput::Viewport { ranges: vec![RoomListRange { start: 10, end_inclusive: 20 }]}).await?;
```
2023-06-15 11:12:17 +02:00
Ivan Enderlin ea9a85395a chore(ui): Add missing trailing commas. 2023-06-15 11:11:48 +02:00
Jonas Platte 78135fcce9 ffi: Add message_event_content_new 2023-06-15 10:44:40 +02:00
Jonas Platte 7feba6f814 ffi: Use Duration instead of u64
Resolves FIXME comment.
2023-06-15 10:44:40 +02:00
Andy Balaam 7ca3686aea Fix formatting after merge 2023-06-15 09:37:27 +01:00
Ivan Enderlin 7756b6d725 feat(ui): Implement room subscriptions in RoomList + notification counts
feat(ui): Implement room subscriptions in `RoomList` + notification counts
2023-06-15 10:28:04 +02:00
Ivan Enderlin c07bb0ec39 test(ui): Test that RoomList receives State updates even if the same.
`RoomList::state` provides a `Subscriber` to the `State`. This patch
modifies the way the state is tested, to ensure that there is always
an update broadcasted even if the state is the same (e.g. if the state
moves from `CarryOn` to `CarryOn`).
2023-06-15 09:55:57 +02:00
Ivan Enderlin ddffa00589 test(ui): Test Room::*unread_notifications(). 2023-06-15 09:40:55 +02:00
Ivan Enderlin 6e1de8a5ee fix(ffi): RoomListItem::full_room returns a Room with a Timeline. 2023-06-15 09:26:33 +02:00
Ivan Enderlin 23d5655901 feat(ui): room_list::RoomInner holds Arc to Timeline.
This patch updates `RoomInner::timeline` and `::sneaky_timeline` to
`AsyncOnceCell<Arc<Timeline>>`. Adding `Arc` allows to copy the timeline
if necessary more easily.
2023-06-15 09:24:47 +02:00
Richard van der Hoff 6b45749e17 crypto-js: Add new methods to VerificationRequest (#2068)
A couple of useful methods for accessing things in `VerificationRequest`.
2023-06-14 15:46:36 +01:00
Andy Balaam e9e1afb5a5 Merge main into andybalaam/sliding-sync-reinvite (using imerge) 2023-06-14 15:39:26 +01:00
Andy Balaam 22fd44df10 Fix comments from review feedback 2023-06-14 15:31:25 +01:00
Jonas Platte b4cd0c71bf ui: Add loading indicator before waiting for prev_batch token
… in Timeline::paginate_backwards.
2023-06-14 14:00:58 +02:00
Kévin Commaille b4fdfee7f0 base: Use batch methods in Room::get_members
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 13:51:52 +02:00
Kévin Commaille 38fc1f7b15 base: Add method to construct RoomMember from parts
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 13:51:52 +02:00
Kévin Commaille e32e9b5a22 base: Add state store method to fetch several display_names at once
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 13:51:52 +02:00
Kévin Commaille 7cba6d0849 base: Add state store method to fetch several presence events at once
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 13:51:52 +02:00
Kévin Commaille b8abd1c022 base: Add state store method to fetch several profiles at once
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 13:51:52 +02:00
Kévin Commaille 4103d1b3e3 sdk: Add room method to fetch several state events at once
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 13:51:52 +02:00
Kévin Commaille f740195eb6 base: Add state store method to fetch several state events at once
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 13:51:52 +02:00
Jonas Platte ae4ead5550 Upgrade typos CI action
… and update the config file to reduce check flakiness.
2023-06-14 12:31:32 +02:00
Jonas Platte 820d3aff65 Rewrap base64 test strings 2023-06-14 12:31:32 +02:00
Jonas Platte b3017a1073 Fix typos 2023-06-14 12:31:32 +02:00
Ivan Enderlin b9c27b5c63 feat(ui): Implement Room::*unread_notifications. 2023-06-14 12:15:16 +02:00
Ivan Enderlin 1bc455f75b feat(ffi): Room:add_timeline_listener returns a …Result.
This patch updates `Room::add_timeline_listener` to return a `RoomTimelineListenerResult`, a new type defined as:

```rust
pub RoomTimelineListenerResult {
    items: Vec<Arc<TimelineItem>>,
    items_stream: TaskHandle,
}
```

It is not possible to cancel the `items_stream` by cancelling the
`TaskHandle`. Without this, dropping `Room` won't drop the `Timeline`,
as a clone is moved inside the spawned task. As a consequence, it will
endlessly call the listener.
2023-06-14 11:56:07 +02:00
Ivan Enderlin 97e4a5cab0 chore(ffi): Remove RoomListItem::timeline.
What the FFI user wants is to subscribe a listener to the
timeline updates. This feature is already supported by
`room_item.full_room().add_timeline_listener()`.  So we can safely
remove `RoomListItem::timeline` as we are sure it's never going to be
used for now.
2023-06-14 11:13:06 +02:00
Ivan Enderlin 192b9ce808 feat(ui+ffi): Implement Room::id as a shortcut.
It's possible to do `room.inner_room().room_id()` but it's just simpler
to call `room.id()`. This patch adds this shortcut.

It's especially useful for FFI users, where creating a “full
room” (`room_item.full_room().room_id()`) may be expensive.
2023-06-14 10:59:03 +02:00
Ivan Enderlin dba397d470 feat(ffi): Add RoomListItem::subscribe and ::unsubscribe. 2023-06-14 10:56:59 +02:00
Ivan Enderlin 712b395310 feat(ui): Add Room::subscribe and ::unsubscribe.
This patch adds the `subscribe` and `unsubscribe` method on `Room`.

To achieve that, `Room` receives an `Arc<SlidingSync>`, as the
subscription methods are on `SlidingSync`. It's just easier to put them
on `Room` for the API consumer. It makes the API also more elegant.

Finally, the patch adds the appropriate test.
2023-06-14 10:51:37 +02:00
Kévin Commaille eb5af4287f sdk: Allow to get rooms filtered by room state
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 10:45:37 +02:00
Kévin Commaille c978fa6d40 base: Deprecate BaseClient::get_stripped_rooms
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 10:45:37 +02:00
Kévin Commaille ac8ea4786c base: Deprecate StateStore::get_stripped_room_infos
It is now unused.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 10:45:37 +02:00
Kévin Commaille 281870b33f base: Remove stripped rooms list from Store
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 10:45:37 +02:00
Kévin Commaille bcd7e92a94 base: Allow to get rooms filtered by state
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 10:45:37 +02:00
Kévin Commaille ea219d836e base: Do not separate stripped room info
Since stripped and non-stripped room infos use the same types,
the separation is not necessary anymore.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-14 10:45:37 +02:00
Damir Jelić f67c592259 Properly support the hkdf-hmac-sha256.v2 MAC method for the SAS verification (#2064) 2023-06-14 10:17:22 +02:00
Ivan Enderlin 0db5a6a25d Merge branch 'main' into pr/2058 2023-06-14 09:55:31 +02:00
Ivan Enderlin 2c871807a3 feat(ui+ffi): Add various features to RoomList
feat(ui+ffi): Add various features to `RoomList`
2023-06-14 09:22:24 +02:00
Ivan Enderlin f55c1021c4 Merge pull request #2065 from matrix-org/rav/fix-docs
crypto-js: improvements to the documentation
2023-06-14 08:35:59 +02:00
Richard van der Hoff f78a2951e4 more doc fixes 2023-06-13 22:10:48 +01:00
Richard van der Hoff a8468cba59 crypto-js: improvements to the documentation
... mostly, writing down what things actually return.
2023-06-13 21:54:19 +01:00
Damir Jelić 48a24a6aed Use the short auth strings from the start content when accepting a verification (#2061)
Co-authored-by: Benjamin Bouvier <public@benj.me>
2023-06-13 17:33:57 +00:00
Benjamin Bouvier a79d519ff9 sliding sync: always fall back to the auto-discovered proxy URL, if any
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-13 19:33:30 +02:00
Jonas Platte 47a67d1d67 Upgrade Ruma 2023-06-13 18:33:28 +02:00
Jonas Platte adb9e60fbe common: Add executor::JoinHandle
… and simplify wasm spawn implementation.

This reduces the differences on wasm vs. non-wasm. Of course it's still
possible to rely on details of the different error types, but at least
both implement a few common traits:
`Debug`, `Display`, `Error`.
2023-06-13 16:50:33 +02:00
Andy Balaam 240a7f7aae Make set_state public to avoid unused warning 2023-06-13 13:43:46 +01:00
Andy Balaam f36a5b8cd7 Deserialise events early so we don't have to do it multiple times
We pass the already-deserialised event in to handle_state and
process_sliding_sync_room_membership, to avoid deserialising inside both
of them.
2023-06-13 13:05:14 +01:00
Andy Balaam 451398612a In Sliding Sync, find out which rooms we have left from state events
Look through m.room.member events when processing Sliding Sync
responses, finding those that refer to our user's membership, so that we
can recognise which rooms we have left.
2023-06-13 13:05:14 +01:00
Benjamin Bouvier 8aa12c929a chore: group GossipMachine fields inside an Arc-struct
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-13 12:28:37 +02:00
Andy Balaam 5c8a5466cf Use async_test to mark sliding sync tests 2023-06-13 12:15:49 +02:00
Andy Balaam 9a3060793c Extract a function for processing misc properties of a room in sliding sync 2023-06-13 12:15:49 +02:00
Andy Balaam 085c9767f0 Extract a function for processing membership of a room in sliding sync 2023-06-13 12:15:49 +02:00
Jonas Platte 2c71556ef2 Upgrade opentelemetry dependencies 2023-06-13 11:08:45 +02:00
Jonas Platte e78dbaf7c6 ffi: Don't require native-tls 2023-06-13 10:33:52 +02:00
Ivan Enderlin 15199316d3 doc(ui): Fix an intra-link. 2023-06-13 01:30:49 +02:00
Ivan Enderlin 1c8772848a feat(ui): Add the required state m.room.power_levels for all_rooms in RoomList. 2023-06-13 01:24:43 +02:00
Ivan Enderlin 9f6bc7d35f feat(ui): Configure filters for RoomList lists. 2023-06-13 01:24:43 +02:00
Ivan Enderlin 65959b07a4 feat(ui): Configure required_state for all_rooms in RoomList. 2023-06-13 01:24:43 +02:00
Ivan Enderlin 901deaf8e0 feat(ui): Enable common extensions on RoomList. 2023-06-13 01:24:43 +02:00
Ivan Enderlin 370083ee03 feat(ui,ffi): Add getter for matrix_sdk(_ffi)::Room. 2023-06-13 01:24:43 +02:00
Ivan Enderlin 5c01917f42 chore(ui): Split matrix_sdk_ui::room_list::mod.rs into smaller modules.
No code changes. This patch is just moving things around.
2023-06-13 01:24:43 +02:00
Ivan Enderlin 3547bd2f54 feat(ffi): Implement RoomList API
feat(ffi): Implement `RoomList` API
2023-06-13 01:23:24 +02:00
Ivan Enderlin 742ccea5ef doc(ffi): Fix a typo. 2023-06-13 00:37:14 +02:00
Ivan Enderlin 0233d65f02 In sliding sync, do all the same processing on an invited room as a joined one
In sliding sync, do all the same processing on an invited room as a joined one
2023-06-13 00:28:11 +02:00
Ivan Enderlin c65e98895a test(ui): Fix a test. 2023-06-13 00:27:26 +02:00
Ivan Enderlin d5211445a5 chore: Make Clippy happy. 2023-06-13 00:21:50 +02:00
Ivan Enderlin 235efaa85c fix(ffi): Do not overwrite Client's sliding_sync_proxy everytime.
The comment explains the fix correctly.
2023-06-13 00:12:41 +02:00
Ivan Enderlin b85dff347a chore(ffi): Simplify code and remove one method. 2023-06-12 23:36:35 +02:00
Ivan Enderlin dec1129106 chore(ffi): Remove Client::sliding_sync_proxy.
Instead of storing `sliding_sync_proxy` inside the `Client`, this patch
updates the code to store it inside `matrix_sdk::Client` directly.

That way, there is unique place where to store the sliding sync proxy
URL.
2023-06-12 23:29:23 +02:00
Ivan Enderlin 9bcc50fe2f feat(sdk): Client::sliding_sync_proxy is a StdRwLock.
This patch changes `matrix_sdk::Client::sliding_sync_proxy` to be a
`std::sync::RwLock<Option<Url>>` instead of `tokio::sync::RwLock<_>`.
It means that all methods reading or writing this field are sync instead
of async, which makes the code a lot more easier. Having an async-aware
lock wasn't necessary here.
2023-06-12 23:15:03 +02:00
Ivan Enderlin 7636a069b7 fix(ffi): Rollback how Sliding Sync proxy URL is computed.
I guess I know what's happening but I rollback some previous commits to
be sure it comes back on track.
2023-06-12 17:07:59 +02:00
Ivan Enderlin 8f102af801 chore: Make Clippy happy. 2023-06-12 16:47:22 +02:00
Ivan Enderlin 069743f3e1 feat(sdk): Change how Client::sliding_sync_proxy is represented. 2023-06-12 16:47:22 +02:00
Ivan Enderlin 38f8ebb6b9 feat(ffi): Add ability to force a Sliding Sync proxy URL from a restored session. 2023-06-12 16:47:22 +02:00
Andy Balaam f6d707cce8 Merge main into andybalaam/sliding-sync-process-unify-invited (using imerge) 2023-06-12 13:40:07 +01:00
Jonas Platte f883826db0 ffi: Add Room::cancel_send 2023-06-12 14:20:51 +02:00
Jonas Platte 4541ef6b90 sdk: Add Timeline::cancel_send 2023-06-12 14:20:51 +02:00
Benjamin Bouvier 29ddeb45d9 feat(sdk): implement sticky parameters (#1948)
* chore: add comments explaining what the position markers are
* feat(sdk): add scaffolding for sticky parameters
* test(sdk): add tests for the sticky parameters API
* feat(sdk): include the bump_event_types in the sticky parameters
* WIP: add TODO comments for deeply nested sticky parameters
* test(sdk): add extra test for sticky parameters
* feat: add extensions in the sticky parameters + test request generation + test since token
* chore: fix merge + get rid of unused inner extensions
* feat: use sticky parameters for lists too
* chore: Introduce the StickyManager, a reusable way to manage per-data sticky parameters
* chore: move the sticky scaffolding to its own module
* chore: clippy + fmt
* chore: get rid of `update_to_device_token`
* review: append SlidingSync prefix to Stick* data structures
* address review comments
* Replace nbsp with regular space
* Get rid of a write-access to a lock (because thanks inner mutability!)
* Add an integration test when losing `pos` in sticky parameters, and avoid `block_on`

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-12 10:46:13 +00:00
Ivan Enderlin 790dc47fca feat(ffi): Make RoomList.room non-async. 2023-06-12 12:41:12 +02:00
Ivan Enderlin 199f5708c0 chore(sdk): Tidy sliding sync processing code
Tidy sliding sync processing code
2023-06-12 11:37:40 +02:00
Andy Balaam f4aed74fb1 Fix formatting 2023-06-12 09:50:04 +01:00
Andy Balaam 323aaffe34 Merge main into andybalaam/sliding-sync-process-tidy (using imerge) 2023-06-12 09:37:37 +01:00
Andy Balaam 9a5291b2a9 Test canonical aliases in invited rooms via sliding sync 2023-06-12 10:34:04 +02:00
Andy Balaam 1e24542dd3 Handle required state in invited rooms as well as normal 2023-06-12 10:34:04 +02:00
Andy Balaam dcd5a27a2f Rename room_to_add->room_to_store 2023-06-12 10:34:04 +02:00
Andy Balaam dafee483fa Refactor process_sliding_sync to extract a method for dealing with rooms 2023-06-12 10:34:04 +02:00
Andy Balaam 0b4fba81d8 Test for adding an invited room to the client and invite list 2023-06-12 10:34:04 +02:00
Andy Balaam 34a56a70a0 Test for finding avatars in invite rooms 2023-06-12 10:34:04 +02:00
Andy Balaam 76a7ad0cbf Test for finding an avatar in a room via sliding sync 2023-06-12 10:34:04 +02:00
Ivan Enderlin 81628d15b8 doc(ffi): Fix a link. 2023-06-12 10:06:57 +02:00
Ivan Enderlin 39a4d039dd chore(ffi): Remove ability to use a custom sliding sync proxy URL. 2023-06-12 09:58:33 +02:00
Ivan Enderlin d24a1d8d6d feat(ui): Update the Sliding Sync proxy URL when creating RoomList. 2023-06-12 09:21:08 +02:00
Ivan Enderlin 2f433138dd chore(ffi): Make Clippy happy. 2023-06-12 09:07:39 +02:00
Ivan Enderlin 6301f32ee5 chore(ffi): Rename RoomListRoom to RoomListItem. 2023-06-12 09:07:39 +02:00
Ivan Enderlin 7ae8ee14eb feat(ffi): RoomListRoom::name and ::latest_event are non-async. 2023-06-12 09:07:39 +02:00
Ivan Enderlin 070965fc87 feat(ffi): Implement RoomList::rooms.
This patch implements `RoomList::rooms` to fetch one room. The type
name is `RoomListRoom` to avoid any collision with an existing `Room`
type already.

`RoomListRoom` implements `name`, `timeline` and `latest_event`.
2023-06-12 09:07:39 +02:00
Ivan Enderlin e2480be47f feat(ffi): Make RoomList::entries async.
Because we can!
2023-06-12 09:07:39 +02:00
Ivan Enderlin cb51c766a8 feat(ffi): Rename “observer” to “listener”. 2023-06-12 09:07:39 +02:00
Ivan Enderlin 68c19f4129 feat(ffi): First step for RoomList in FFI bindings. 2023-06-12 09:07:39 +02:00
Ivan Enderlin 5416ba06f5 feat(ui): Merge RoomList::state and RoomList::state_stream.
By returning a `Subscriber`, one can call `Subscriber::get` to get the
inner value. Thus, having `state` and `state_stream` is useless. It's
possible to return have `state` which returns `Subscriber`, and we get
one value for two usages.
2023-06-12 09:07:39 +02:00
Ivan Enderlin 623332b931 feat(ffi): Extract TaskHandle into itw own module. 2023-06-12 09:07:39 +02:00
Ivan Enderlin d4e983e559 feat(ui): Rename State::Enjoy to State::CarryOn. 2023-06-12 09:07:39 +02:00
Mauro 6444848511 docs: updated readme - rust version (#2047)
* docs: update readme
* removing error
2023-06-09 13:16:09 +00:00
Andy Balaam 11adcf425c In sliding sync, do all the same processing on an invited room as a joined one
The example in MSC3575 shows a room with invite_state property, but also
timeline, joined_count etc. properties. That may or may not be very
likely in practice, but I think it makes sense to check for all these
properties even when the room is an invite, and use them if they are
present.
2023-06-09 13:25:04 +01:00
Andy Balaam 7e197ec8d4 Simplify invited room sliding sync processing
Added some comments based on my understanding of MSC3575. Previously we
had a FIXME about how we were setting the room state to invite or join
based on the presence or absence of the invite_state property. I think
this behaviour is correct, so I added some comments explaining why.

The functional change here is to note that we call
store.get_or_create_stripped_room to find/create the stripped room, and
this actually deletes any room of this ID that is in the store, so our
later call to store.get_room would always fall back to getting the
stripped room, which we already have, so there was no need to do the
get_room call at all.
2023-06-09 13:14:58 +01:00
Andy Balaam 9d943e7c62 Clarify in tests that invite_state contains very minimal JSON 2023-06-09 13:14:58 +01:00
Andy Balaam 8c2cc522bc Test canonical aliases in invited rooms via sliding sync 2023-06-09 12:54:43 +01:00
Andy Balaam 4a04c70c45 Handle required state in invited rooms as well as normal 2023-06-09 12:54:43 +01:00
Andy Balaam ee8f94cb95 Rename room_to_add->room_to_store 2023-06-09 12:54:43 +01:00
Andy Balaam 24ff62befc Refactor process_sliding_sync to extract a method for dealing with rooms 2023-06-09 12:54:43 +01:00
Andy Balaam a85c481368 Test for adding an invited room to the client and invite list 2023-06-09 12:52:26 +01:00
Andy Balaam 5545c98a85 Test for finding avatars in invite rooms 2023-06-09 12:52:26 +01:00
Andy Balaam ac7c6ba84c Test for finding an avatar in a room via sliding sync 2023-06-09 12:52:26 +01:00
Kévin Commaille ae2f834345 sqlite: Return an error when DB version is invalid or missing (#2038)
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-09 11:02:33 +00:00
Andy Balaam 0e30d85df4 Provide no event_id for the name state event when it comes via update_name
Also respond to a couple of minor review comments
2023-06-08 18:30:20 +02:00
Andy Balaam 02d03c55f2 Update the name of a room during sliding sync processing 2023-06-08 18:30:20 +02:00
Andy Balaam 0cff8f3697 Allow updating the name in a RoomInfo 2023-06-08 18:30:20 +02:00
Andy Balaam 0f5906a0fa Tests for processing sliding sync responses 2023-06-08 18:30:20 +02:00
Jonas Platte a977b3a8d5 ui: Use stream_assert for timeline unit tests 2023-06-08 12:25:58 +02:00
Jonas Platte 6c6c43e709 ui: Filter virtual timeline items for some tests 2023-06-08 12:25:58 +02:00
Benjamin Bouvier 43bac4995f chore: rename homeserver to sliding_sync_proxy in sliding sync
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-08 11:13:40 +02:00
Jonas Platte c8b74bec0d ci: Fixes to toolchain installation 2023-06-07 17:25:24 +02:00
Jonas Platte b5339ceaba ui: Activate sdk's testing feature for unit tests
Fixes running `cargo test` without any flags from the crate root.
2023-06-07 17:25:24 +02:00
Jonas Platte 0898c76bb7 crypto: Simplify is_cross_signing_trusted 2023-06-07 17:25:24 +02:00
Jonas Platte c19d72f0f4 Use Option::is_some_and where applicable 2023-06-07 17:25:24 +02:00
Jonas Platte 0b9c082e11 ffi: Add EventTimelineItem::transaction_id 2023-06-07 16:40:14 +02:00
Jonas Platte aa3adbd53d ui: Don't wait on prev_batch token for more than 3s 2023-06-07 16:21:48 +02:00
Jonas Platte 87510a5bc2 ffi: Add wait_for_token to PaginationOptions 2023-06-07 16:21:48 +02:00
Jonas Platte af870fcff3 ui: Allow waiting for token before starting pagination 2023-06-07 16:21:48 +02:00
Jonas Platte 1e10a54d3d ui: Fix clippy lints 2023-06-07 16:21:48 +02:00
Jonas Platte bfce4d1006 ui: Merge timeline::room_ext module into timeline::traits 2023-06-07 16:21:48 +02:00
Jonas Platte 2bcc70beb9 ui: Move timeline-internal traits into separate module 2023-06-07 16:21:48 +02:00
Damir Jelić 7552f4f72a Merge pull request #2028 from matrix-org/release-matrix-sdk-crypto-js-v0.1.0-alpha.10
Bindings JS: New release `matrix-sdk-crypto-js v0.1.0-alpha.10`
2023-06-07 15:51:24 +02:00
Jonas Platte 415c13fa90 ui: Add a test for retrying a failed send 2023-06-07 13:29:42 +02:00
Jonas Platte 0ca8369a76 ui: Fix clippy warnings 2023-06-07 13:29:42 +02:00
Jonas Platte dc05d17330 Upgrade eyeball-im-util 2023-06-07 13:29:42 +02:00
Jonas Platte 9505ace8e2 ffi: Add Room::retry_send 2023-06-07 13:29:42 +02:00
Jonas Platte df7beb4afd ui: Add Timeline::retry_send 2023-06-07 13:29:42 +02:00
Jonas Platte f1e62b0bb8 ci: Run coverage when PR is ready for review 2023-06-07 11:31:39 +02:00
Ivan Enderlin 4e29e6e347 feat(ui): Disable caching and make Timelines lazy
feat(ui): Disable caching and make `Timeline`s lazy
2023-06-07 11:29:22 +02:00
Florian Duros 81d4dc8b6e matrix-sdk-crypto-js v0.1.0-alpha.10
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 36s
2023-06-07 10:07:05 +02:00
Florian Duros 65bdb1a2e3 Update CHANGELOG.md 2023-06-07 10:06:51 +02:00
Damir Jelić 0e5e8a205c Merge pull request #2020 from matrix-org/florianduros/bindings/add-missing-key-identity
Bindings JS: Add missing keys to `UserIdentity` and `OwnUserIdentity`
2023-06-07 10:00:20 +02:00
Ivan Enderlin 5c182a0d03 sliding sync: enable read-receipts in the common extensions
sliding sync: enable read-receipts in the common extensions
2023-06-07 09:58:27 +02:00
Ivan Enderlin 3acb56aa31 feat(ui): Make Room::timeline and ::sneaky_timeline lazy.
This patch uses a new `async-once-cell` crate to make `Room::timeline`
and `Room::sneaky_timeline` by making them lazy. Their values are
computed lazily, on-demand, when calling the `Room::timeline` method or
`Room::latest_event`.
2023-06-07 09:51:56 +02:00
Ivan Enderlin a2cefedf73 RoomList API: enable account_data extension by default
`RoomList` API: enable `account_data` extension by default
2023-06-07 09:35:04 +02:00
Ivan Enderlin 169038504d fix(ui): Disable Sliding Sync caching in RoomList. 2023-06-07 09:31:52 +02:00
Benjamin Bouvier d3ddfabaef sliding sync: enable read-receipts in the common extensions
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-06 20:09:03 +02:00
Benjamin Bouvier 027db88078 sliding sync: have the RoomApi use add_list instead of add_cached_list until the perf issue of reloading has been fixed
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-06 19:36:42 +02:00
Benjamin Bouvier 3b10c235ab sliding sync: enable account data extension in room list API
This extension was enabled by both ElementX apps by default, along with the e2ee / to-device extensions that will be handled
by the new Notification API. To maintain the current behavior, it's important to re-enable this extension before getting
RoomList in production.

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-06 19:35:20 +02:00
Florian Duros 198c8f6901 Prettier fix 2023-06-06 17:26:57 +02:00
Florian Duros 721a704540 Add tests 2023-06-06 17:23:16 +02:00
Florian Duros d0f3f1e657 Review fixes 2023-06-06 17:21:27 +02:00
Benjamin Bouvier f84ff148da feat(sdk): add an optional temporary directory to get_media_file
By default, get_media_file will attempt to use a default directory
for temporary files and directories. Unfortunately, there might not be
such a thing on some older Android devices, which use per-application
directories.

For this specific case, an optional temporary directory parameter
is added to the `get_media_files` parameters, so one can provide their own
temporary directory path.

This new parameter is expected to be set at least on Android; other platforms
should work just fine without it.

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-06 15:20:06 +02:00
Florian Duros b4c440a5e7 Update CHANGELOG.md 2023-06-06 15:16:30 +02:00
Florian Duros b760c0e6ce Add keys to UserIdentity and OwnUserIdentity 2023-06-06 15:05:28 +02:00
Kévin Commaille 407375ad17 base: Move StateStore::get_member_event to StateStoreExt
It is a wrapper around get_state_event_static_for_key

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-06 11:56:11 +02:00
Kévin Commaille b690bcfbaf sdk: Re-export store traits
The store is exposed with `Client::store()` but the traits are not.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-06 11:56:11 +02:00
Benjamin Bouvier d1a1a0f5c5 Reuse upstream Ruma repository
This was a temporary replacement I've made, waiting for a PR of mine to be merged, and it's been merged since then. Oh well.

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-06 10:04:20 +02:00
Ivan Enderlin f61fdcbdbe feat(ui): RoomList, step 1: the Foundation
feat(ui): `RoomList`, step 1: the Foundation
2023-06-05 20:50:25 +02:00
Ivan Enderlin 16932abeaa chore: Make Tarpaulin happy. 2023-06-05 20:17:19 +02:00
Ivan Enderlin e6fdcfdf52 chore: Make Clippy happy. 2023-06-05 20:05:46 +02:00
Ivan Enderlin 42df0d0e21 fix: Fix merge commit. 2023-06-05 19:43:32 +02:00
Ivan Enderlin d1bccacef9 chore: Make CI happy. 2023-06-05 19:40:51 +02:00
Ivan Enderlin 08559b58b6 Merge branch 'main' into feat-ui-roomlist 2023-06-05 19:22:33 +02:00
Ivan Enderlin ac7a576035 chore(ui): Address feedbacks. 2023-06-05 19:13:48 +02:00
Jonas Platte 9148eaaea1 sdk: Add a test for room update channels 2023-06-05 17:46:22 +02:00
Jonas Platte adb91262e0 ui: Do fully-read tracking in room update processing
… instead of separate event handlers.
2023-06-05 17:46:22 +02:00
Jonas Platte a916ef468e ui: Make some free functions TimelineInnerState methods instead 2023-06-05 17:46:22 +02:00
Jonas Platte 4986f98aa3 ui: Batch timeline object updates from sync response 2023-06-05 17:46:22 +02:00
Jonas Platte e59562725d ui: Move gappy sync response handling out of FFI 2023-06-05 17:46:22 +02:00
Jonas Platte 945a1228d0 ui: Use room subscription instead of event handler for timeline events 2023-06-05 17:46:22 +02:00
Jonas Platte 9489720386 Add Client::subscribe_to_room_updates
… and `room::Common::subscribe_to_updates` which does the same thing,
but more conveniently if one already has a room object.
2023-06-05 17:46:22 +02:00
Jonas Platte 63f7f4a903 Update event handler functions to take Option<&_> instead of &Option<_> 2023-06-05 17:46:22 +02:00
Jonas Platte 2c2285b5d7 ui: Deduplicate local and remote echo by event ID when it comes in late 2023-06-05 17:33:11 +02:00
Jonas Platte ede6bed948 ui: Move echo integration test into separate module 2023-06-05 17:33:11 +02:00
Jonas Platte 185fc9aa3c ui: Add copyright headers to integration tests 2023-06-05 17:33:11 +02:00
Jonas Platte 62817a8ef8 ui: Move pagination integration tests into separate module 2023-06-05 17:33:11 +02:00
Jonas Platte 3a5f83d9dc ffi: Include causes when stringifying anyhow::Error 2023-06-05 17:29:53 +02:00
Benjamin Bouvier 61c3a2a2c7 sliding sync: infer the storage key from the loop id and user id (#2008)
* sliding sync: infer the storage key from the loop id and user id
* chore: rename `sync_id` to `id`
* chore: check that the sliding sync id is less than 16 chars
* chore: rejigger the storage key creation logic

Now the prefix is visible only in the `format_storage_key_prefix` function, and other `format_storage_key` function will be based off that.

* chore: update sliding sync README with API updates and fix outdated information
* chore: clippy + fix test

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-05 14:51:40 +00:00
Ivan Enderlin 4a62949b6c test(sdk): Simplify a test. 2023-06-05 15:19:18 +02:00
Ivan Enderlin ad8d7caecb feat(ui): Handle RoomList's State::Terminated properly.
This patch handles errors from the Sliding Sync loop properly.

When an error is received, the `RoomList` state machine enters the
`Terminated` state. Immediately after that, the sync stream is stopped.

When the sync stream is restarted, the next state will be calculated.
When the current state is `Terminated`, the next state is the state
that led to the `Terminated` state. To avoid having a “first” huge sync
(imagine a room list of 1000 rooms, you don't want to “resume” from an
error with a first sync for 1000 rooms), lists are partially “reset”
depending of the state where the machine is in.

An important test has been added to test all possibles cases with errors
and list' states.
2023-06-05 15:09:10 +02:00
Ivan Enderlin 4bfc48b4ae feat(sdk): Simplify returned values of SlidingSync::sync.
First off, `SlidingSync::sync_once` no longer returns
`Option<UpdateSummary>` but `UpdateSummary`. It simplifies the rest of
the patch.

Next, `SlidingSync::sync` returns either `Ok(…)` and continues to sync,
or it returns `Err(…)` and it stops the sync stream immediately. No more
error could be returned with the stream to continue syncing.

Finally, the `UnknownPos` error no longer emits an err, but silently
skip over the sync-loop until the threshold is reached; which in this
case will generate a proper error.
2023-06-05 15:05:42 +02:00
Ivan Enderlin c1a24cf033 feat(ui): Implement Room::timeline and ::latest_event.
This patch changes `RoomInner` to have an `room:
Option<matrix_sdk::room::Room>` field to `room: matrix_sdk::room::Room`.
`room` is not longer an `Option`.

Then, it's easier to have a new `timeline: Timeline` field, along with a
`sneaky_timeline: Timeline` field. Both are used by the new
`Room::timeline()` and `Room::latest_event()` method.
2023-06-02 22:38:48 +02:00
Ivan Enderlin 67ef42f4c5 feat(ui): Implement RoomList::room.
This patch implements `RoomList::room`, which returns a `Result<Room>`:
the room ay or may not exist.

A new `Room` type is created. It wraps an `Arc<RoomInner>` type, so that
it's cheap to clone it.

The `RoomInner` type owns a `SlidingSyncRoom` and
`matrix_sdk::room::Room` type. If some API or data are missing on
the former, the latter acts as a backup. This is the case for the
`Room::name` method which makes it best to return a name to the caller.
2023-06-02 21:28:45 +02:00
Ivan Enderlin 537f95b683 feat(sdk): SlidingSync::get_rooms? are now async. 2023-06-02 20:59:26 +02:00
Ivan Enderlin dcad897084 test(ui): Ensure the timeline_limit is not reset. 2023-06-02 20:49:33 +02:00
Ivan Enderlin c6dae678bd sliding sync: move the bump_event_types to be per-list
sliding sync: move the `bump_event_types` to be per-list
2023-06-02 20:29:10 +02:00
Ivan Enderlin e18728aa5f feat(ui): Set timeline_limit for all_rooms and visible_rooms. 2023-06-02 20:06:50 +02:00
Ivan Enderlin 8ee84be839 doc(ui): Write documentation for RoomList. 2023-06-02 20:06:31 +02:00
Kévin Commaille 588b58c616 crypto: Remove unnecessary to_owned
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-02 12:22:26 +02:00
Kévin Commaille 3ab171ca2d chore: Update log dependency
Fixes compilation of value-bag crate with Rust nightly

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-02 12:22:26 +02:00
Benjamin Bouvier 28c8e5df71 feat(sdk): move bump_event_types to the list sub-request
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-01 18:57:45 +02:00
Benjamin Bouvier 6a58be38ca Temporarily use bnjbvr's repository for bump-event-types change in ruma
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-06-01 18:51:53 +02:00
Ivan Enderlin 2f68c86796 feat(ui): Add the RoomList Input API.
This patch lands the first design of the `Input` API. An `Input` is
something external that can be understood by the `RoomList` state
machine. The first inpuput is `Viewport` to change the “viewport” of the
`RoomList`, which translates to the change of the ranges of one specific
Sliding Sync list.
2023-06-01 16:55:29 +02:00
Ivan Enderlin 13d38993f8 feat(sdk): Expose the Range and Ranges type in matrix_sdk::sliding_sync. 2023-06-01 16:52:16 +02:00
Ivan Enderlin e2d2cf787d test(sdk): Fix according to previous commits. 2023-06-01 16:52:09 +02:00
Ivan Enderlin f5c950c54a fix(ffi): Update according to last commits. 2023-06-01 15:58:58 +02:00
Ivan Enderlin c2d082ca8d test(ui): Update the tests according to previous commits. 2023-06-01 15:58:12 +02:00
Ivan Enderlin 553b5c6db3 Merge pull request #1 from matrix-org/feat-ui-roomlist
Feat UI roomlist
2023-06-01 15:46:00 +02:00
Jonas Platte 5106255911 On-demand stream creation 2023-06-01 15:40:39 +02:00
Jonas Platte 58e8c0a7ac Fix warning 2023-06-01 15:34:13 +02:00
Jonas Platte db0217d093 Box internally 2023-06-01 15:34:07 +02:00
Ivan Enderlin 048b054a65 feat(ui): Implement RoomList::update_entries_stream_filter.
This patch implements `RoomList::update_entries_stream_filter` which
allows to… change the… entries stream filter. This patch also provides a
test for that. How nice it is.
2023-06-01 14:55:53 +02:00
Ivan Enderlin 0a1c0547b4 test(ui): Add test to ensure RoomList::sync resumes from current state. 2023-06-01 14:18:47 +02:00
Ivan Enderlin fbe1603190 feat(ui): Rethink the state machine of RoomList. 2023-06-01 14:06:02 +02:00
Damir Jelić d6d19d9111 Don't re-encode the plaintext after decrypting a backup 2023-06-01 12:56:18 +02:00
Jonas Platte 3e2bc3a514 Drop matrix-sdk-sled 2023-06-01 12:06:35 +02:00
Kévin Commaille 7cd8898f5f indexeddb: Use parentheses for the impl_state_store macro
Allows rustfmt to do its thing.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-01 11:54:29 +02:00
Kévin Commaille 83e7afab5d sdk: Allow to get stripped state events from the store
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-01 11:13:24 +02:00
Kévin Commaille 645af31c59 base: Use generic types for (Raw)MemberEvent
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-06-01 11:13:24 +02:00
Ivan Enderlin a090a070ee chore(cargo): Add missing EOF. 2023-06-01 10:08:59 +02:00
Ivan Enderlin 697c92beb1 test(ui): Test RoomList::entries_stream with more cases. 2023-06-01 09:48:54 +02:00
Ivan Enderlin 954d798ac3 test(ui): Write an assert_entries_stream macro. 2023-06-01 09:48:54 +02:00
Ivan Enderlin a3c96dcb62 feat(ui): Implement RoomList::entries_stream. 2023-06-01 09:48:53 +02:00
Ivan Enderlin 1caa8b1aa6 chore(ui): Polish after the rebase. 2023-06-01 09:48:53 +02:00
Ivan Enderlin 4557c2a7b2 feat(ui): Add RoomList::entries.
This patch implements the `RoomList::entries` method, which allows
to get a stream of `VectorDiff` over the room list, and that can be
filtered.
2023-06-01 09:48:53 +02:00
Ivan Enderlin f058c59582 feat(sdk): Add SlidingSyncList::room_list_filtered_stream.
This patch adds a new method on `SlidingSyncList` named
`room_list_filtered_stream`, which uses the new `eyeball-im-util` crate
with its new `FilteredSubscriber` type.
2023-06-01 09:48:53 +02:00
Ivan Enderlin aa70c85e02 test(ui): Test RoomList sync from Init to Enjoy. 2023-06-01 09:48:53 +02:00
Ivan Enderlin 1173636b35 feat(ui): Add room_list::Error. 2023-06-01 09:48:53 +02:00
Ivan Enderlin 61f903a5a9 test(ui): Clean up a test. 2023-06-01 09:48:53 +02:00
Ivan Enderlin 4d6a6ac17f feat(ui) Add State::Terminated in RoomList. 2023-06-01 09:48:53 +02:00
Ivan Enderlin 26a764d9dd test(ui): Test all RoomList actions. 2023-06-01 09:48:53 +02:00
Ivan Enderlin bd175d9f66 test(sdk): Store the sync-mode in SlidingSyncListInner only for tests. 2023-06-01 09:48:53 +02:00
Ivan Enderlin f89060bbe9 chore(ui): Update after the rebase. 2023-06-01 09:48:53 +02:00
Ivan Enderlin 01366a08df !foo 2023-06-01 09:48:53 +02:00
Ivan Enderlin 4e07ac1c76 test(ui): Improve testability of RoomList. 2023-06-01 09:48:53 +02:00
Ivan Enderlin d1708ececf feat(ui): Update according to the last patch. 2023-06-01 09:48:53 +02:00
Ivan Enderlin 4fa38d23d4 feat(sdk): SlidingSync has more non-blocking API.
This patch does several things.

First, `SlidingSync::on_list` is now async, and accept async closures.

Second, `SlidingSync::lists` and `::rooms` are behind an `AsyncRwLock`
instead of a `StdRwLock`. The rest of the patch updates the consequence
of this.
2023-06-01 09:48:53 +02:00
Ivan Enderlin 5f81d829c4 feat(ui): Create an Init state, and add state observer for RoomList. 2023-06-01 09:48:52 +02:00
Ivan Enderlin 92c3003535 !baz 2023-06-01 09:48:52 +02:00
Ivan Enderlin f47c2ba125 !bar 2023-06-01 09:48:52 +02:00
Ivan Enderlin 7706b0096b !foo 2023-06-01 09:48:52 +02:00
Ivan Enderlin 5f58438389 feat(ui): Oh, a roomlist module. 2023-06-01 09:48:51 +02:00
Ivan Enderlin 81d158889a fix(sdk): Replace a panic by a log in Sliding Sync
fix(sdk): Replace a panic by a log in Sliding Sync
2023-06-01 09:47:50 +02:00
Ivan Enderlin 29346b11f3 test(ui): Use FutureExt::now_or_never instead of .await
test(ui): Use `FutureExt::now_or_never` instead of `.await`
2023-06-01 09:41:56 +02:00
Damir Jelić 036d9bf261 Add a test to check that the backup decryption works 2023-06-01 09:31:31 +02:00
Damir Jelić 811369ba28 Fix the argument order when decoding a PkMessage 2023-06-01 09:31:31 +02:00
Ivan Enderlin 06680a284a fix(sdk): Replace a panic by a log in Sliding Sync.
This patch replaces a panic (`Option::expect`) by a `tracing::error`
log.

Imagine the Sliding Sync proxy responds with the following payload:

```json
{
    "pos": …,
    "lists": {
        …: {
            "count": …,
            "ops": [
                {
                    "op": "INSERT",
                    "index": 0,
                    "room_id": !foo:bar.org",
                }
            ]
        }
    },
    "rooms": []
}
```

It's an invalid response, as it will update the room list entry (because
it's present in `lists.$list.ops`), but the room won't be created (it's
absent in the `rooms`).

This situation creates a panic in the patched code. We don't want to
crash if the server replies with invalid data.

Ultimately, we should check that the sync operations are valid regarding
the rooms' updates.
2023-06-01 09:18:20 +02:00
Ivan Enderlin fbe8826159 test(ui): Use FutureExt::now_or_never instead of .await.
This patch uses `FutureExt::now_or_never` so that we don't wait on the
future to be resolved to get a result. If we have a bug in our code and
the test expects a value, the test will hang forever, which is not a
desired behavior. With `now_or_never`, this situation cannot happen.
2023-06-01 08:39:44 +02:00
Ivan Enderlin c82c0e46be feat(sdk): Ensure SlidingSync::sync “drains” its internal channel
feat(sdk): Ensure `SlidingSync::sync` “drains” its internal channel
2023-05-31 18:08:06 +02:00
Ivan Enderlin ae25ad557a Merge branch 'main' into fix-sdk-sliding-sync-drain-internal-channel 2023-05-31 17:34:48 +02:00
Jonas Platte d27ae257ec ffi: Remove unnecessary Deref implementations 2023-05-31 17:32:46 +02:00
Ivan Enderlin f9322c5de8 test(sdk): Ensure SlidingSync starts after it has been stopped manually
test(sdk): Ensure `SlidingSync` starts after it has been stopped manually
2023-05-31 17:30:56 +02:00
Ivan Enderlin d0d23afa5c feat(sdk): Introduce SlidingSync::internal_channel_send_if_possible.
The only reason why a sender can fail to send a message is because there
is no receiver. In the current design of `SlidingSync`, there is only
one receiver active per sync-loop. Thus, calling `SlidingSync::add_list`
may fail if `sync` has not been started. Hence the need for a new
`internal_channel_send_if_possible` method which will never fail: it
will send a message is possible, otherwise it won't do anything.

This turns more functions infallible.
2023-05-31 16:53:03 +02:00
Ivan Enderlin 875f379035 feat(sdk): Change SlidingSync's internal channel to MPMC.
`tokio::sync::broadcast` is interesting as it's possible to
generate receivers per subscribers. Being able to do that allows
us to remove the new for an `AsyncLock` around the receiver in
`SlidingSync::internal_channel`, and it can even remove the need to hold
a receiver entirely!

Another improvement is that new receivers can't receive past messages,
so we no longer need to drain the internal channel.

Another improvement is that the sender' `send` method is synchronous!
Which helps to make many functions no longer `async`.
2023-05-31 16:41:50 +02:00
Ivan Enderlin 9da1a2f48b feat(sdk): Ensure SlidingSync::sync drains its internal channel.
Something weird is happening with ElementX iOS. When
`SlidingSync::stop_sync` is called, the internal message `SyncLoopStop`
has time to be sent in the internal channel, but iOS decides to suspend
the code before the sync-loop processes it. When ElementX decides to
start the sync-loop again, it immediately processes the `SyncLoopStop`
message, and… stops the sync-loop.

This patch ensures that `SlidingSync::sync` drains the internal channel
before starting the sync-loop for real. `tokio::sync::mpsc::Receiver`
type has no `drain` method, so this patch implements its
own logic by calling `try_recv` in a loop, until it returns
`Err(TryRecvError::Empty)`.
2023-05-31 15:29:13 +02:00
Damir Jelić 2fa4410dc6 Bump the vodozemac version 2023-05-31 11:52:47 +02:00
Ivan Enderlin 70525e4612 test(sdk): Ensure SlidingSync starts after it has been stopped manually. 2023-05-31 11:18:55 +02:00
Ivan Enderlin 85b37bfcc4 chore: Remove sliding sync dead tests
chore: Remove sliding sync dead tests
2023-05-31 09:22:05 +02:00
Benjamin Bouvier 4ca8d61c56 feat(ffi): expose set_sync_mode on the sliding sync list
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-30 17:20:05 +02:00
Benjamin Bouvier 623ff6fa83 chore(sliding sync): remove useless mutex around ExtensionsConfig
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-29 17:18:42 +02:00
Benjamin Bouvier 90d7ff764c Remove dead tests
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-29 12:46:50 +02:00
Benjamin Bouvier ce9a079882 feat(sdk): use the builder pattern for the other sliding sync mode too
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-26 15:08:21 +02:00
Benjamin Bouvier fa25e4d9fc sliding sync: Rejigger the range API (#1955)
* feat: introduce SlidingSyncSelectiveModeBuilder
* feat: get rid of `CannotModifyRanges` \o/
* chore: rustfmt
* chore: remove scope in test
* chore: move request generator update to its own mod, gets rid of `set_ranges`
* chore: add comments on the request generator methods
* chore: sink one range_end definition into the match arm that matters
* ffi: remove unused `add_range` method
* test: update incorrect test expectation
* chore: make clippy happy
* address first review comments
* review: don't reuse the ranges field for two things
* chore: use a builder pattern for sliding sync selective mode
* address review comments + CI

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-26 13:40:46 +02:00
Damir Jelić df6d0aaa87 Log the one-time keys we received 2023-05-26 10:34:07 +00:00
Jonas Platte 84917bb59d Fix clippy lints 2023-05-26 12:26:00 +02:00
Jonas Platte ebe97623aa Upgrade Ruma 2023-05-26 12:26:00 +02:00
Damir Jelić def53962e4 Make the withheld reason part of the error message 2023-05-25 16:57:58 +02:00
Damir Jelić 1b2ba33039 Record the sender key when decrypting room events
This used to be the case previously, but it seems that things got lost
when we reshuffled the code here.
2023-05-25 16:57:58 +02:00
Benjamin Bouvier 631b51f43b chore: update sliding sync's README.md too
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-25 16:17:46 +02:00
Benjamin Bouvier 829eb30e7e chore: get rid of SlidingSync::reset_lists as it's unused
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-25 16:17:46 +02:00
Benjamin Bouvier 8d1b3b5b73 chore: get rid of SlidingSyncList::set_ranges, replace with SlidingSyncList::set_range (singular) in testing
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-25 16:17:46 +02:00
Benjamin Bouvier 9c1919ab4c chore: get rid of SlidingSyncListBuilder::set_range and replace it with add_range in tests
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-25 16:17:46 +02:00
Benjamin Bouvier dbd491383f chore: get rid of SlidingSyncListBuilder::reset_ranges
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-25 16:17:46 +02:00
Benjamin Bouvier 40a0459cb9 chore: get rid of SlidingSyncListBuilder::ranges(), replace with add_range
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-25 16:17:46 +02:00
Damir Jelić 8c9a54e6c8 Time out user/device pairs who have invalid one-time keys 2023-05-25 14:52:05 +02:00
Damir Jelić ac816ca1c6 Fix an indentation issue 2023-05-25 14:51:25 +02:00
Damir Jelić 2c696ae210 Fix the deserialization of encrypted m.dummy events. 2023-05-25 14:51:25 +02:00
Jonas Platte 5197e263a0 Revert "bindings: Use native async support for latest_room_message"
This reverts commit 2660e7bcf1.
2023-05-25 13:33:43 +02:00
Benjamin Bouvier 992b6b604b test: address review comments + add basic tests for to-device token
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-25 11:26:32 +02:00
Benjamin Bouvier 9762c63dbc chore: remove Observable wrappers for the position markers
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-25 11:26:32 +02:00
Benjamin Bouvier 0afe616e17 feat: put the to_device_token along the other position markers in sliding sync
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-25 11:26:32 +02:00
Benjamin Bouvier b4c192509b chore: remove unused FFI add_common_extensions
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-25 11:26:32 +02:00
Damir Jelić 5e3a114830 Log the message id when we share a room key 2023-05-24 12:29:15 +02:00
Damir Jelić 2e09bf63a6 Add a message id to our encrypted to-device events 2023-05-24 12:29:15 +02:00
Damir Jelić 19ca9478b7 Clean up some room key forwarding logs 2023-05-24 12:29:15 +02:00
Ivan Enderlin 17f4ba5c9b fix(sdk): Client::sliding_sync doesn't need to be async
fix(sdk): `Client::sliding_sync` doesn't need to be `async`
2023-05-24 12:26:33 +02:00
Ivan Enderlin a2a1b35622 fix(sdk): Client::sliding_sync doesn't need to be async.
The `Client::sliding_sync` method was declared as async. However, it's
not necessary as everything happening here is sync.
2023-05-24 11:56:38 +02:00
Ivan Enderlin b60a317174 feat(sdk): Implement SlidingSync::stop_sync
feat(sdk): Implement `SlidingSync::stop_sync`
2023-05-24 11:52:19 +02:00
Jonas Platte ac106c7059 bindings: Use native async for SessionVerificationController 2023-05-24 11:31:33 +02:00
Jonas Platte 2660e7bcf1 bindings: Use native async support for latest_room_message 2023-05-24 11:31:33 +02:00
Jonas Platte ffc8453c63 bindings: Use async-compat tokio runtime 2023-05-24 11:31:33 +02:00
Jonas Platte 587c5b05b1 Upgrade UniFFI 2023-05-24 11:31:33 +02:00
Ivan Enderlin 728cd5db86 fix(sdk): Restore the size of the SS channel.
Because it doesn't solve any problem, it just postpones it, making the
whole thing more difficult to debug.
2023-05-24 11:02:06 +02:00
Ivan Enderlin 512a5e77cd feat(sdk): Log when messages are sent internally by SlidingSync. 2023-05-24 11:01:42 +02:00
Ivan Enderlin e9bbf366ba chore(sdk): Simplify code. 2023-05-24 09:19:12 +02:00
Ivan Enderlin 849f83adb7 chore(sdk): Remove an allow(unused). 2023-05-24 09:06:32 +02:00
Ivan Enderlin 415778d44d feat(ffi): Implement SlidingSync::stop_sync. 2023-05-24 09:03:03 +02:00
Ivan Enderlin 47922f7f50 test(sdk): Test SlidingSync::stop_sync_loop. 2023-05-24 08:59:28 +02:00
Ivan Enderlin 7bde2cfd4a feat(sdk): Add log in SlidingSync when an internal message is received. 2023-05-24 08:44:51 +02:00
Ivan Enderlin 99bbf2a42b feat(sdk): Implement SlidingSync::stop_sync.
In case it's not obvious to drop the `Stream` returned by
`SlidingSync::sync` immediately to “stop” the sync-loop, one can use the
new `stop_sync` method to do achieve the same result.
2023-05-24 08:42:12 +02:00
Ivan Enderlin b8580b76f7 feat(sdk): Rename SlidingSync::stream to ::sync.
Because it doesn't start a stream, but a sync-loop.
2023-05-24 08:20:29 +02:00
Damir Jelić c042e1e63c Disable automatic-key-forwarding for the matrix-sdk-ffi bindings
Not completely sure why disabling this didn't work the first time. The
feature is now disabled by default in the matrix-sdk-crypto crate.
2023-05-23 16:42:34 +02:00
Damir Jelić 3db90fbe02 Use the new VerificationRequest signalling in the emoji example 2023-05-23 16:10:05 +02:00
Damir Jelić b07718b5d5 Expose the VerificationRequest signalling and states in the main crate 2023-05-23 16:10:05 +02:00
Damir Jelić e9c3aa1a2e Add a state for the VerificationRequest for when a request transitions
The `VerificationRequest` object is used to control the flow of the
verification but only up to a certain point.

Once we start handling of different specific verification flows (i.e.
SAS or QR code verification) the `VerificationRequest` object creates a
child object of the Verification type.

This patch adds a new `VerificationRequestState` variant called
`Transitioned` which holds the child verification object as associated
data.

This makes it much simpler to go through the whole verification flow by
allowing users to just listen to the `VerificationRequest::changes()`
method.
2023-05-23 16:10:05 +02:00
Florian Renaud 2cce236f4d feat(bindings): exposed set_name in Room 2023-05-22 17:58:14 +02:00
Jonas Platte 2f243bce55 Stop unconditionally enabling native-tls from matrix-sdk-ffi 2023-05-22 16:26:40 +02:00
Ivan Enderlin d27754cb61 Replace the libolm backup encryption code with a native Rust version
Replace the libolm backup encryption code with a native Rust version
2023-05-22 14:56:21 +02:00
Ivan Enderlin cc10f995ff feat(sdk): Implement SlidingSyncList::set_sync_mode
feat(sdk): Implement `SlidingSyncList::set_sync_mode`
2023-05-22 14:38:01 +02:00
Benjamin Bouvier befb5dbdb8 chore: add log when exiting the sync loop's stream
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-22 14:13:13 +02:00
Benjamin Bouvier 5c785be7dd fix(sdk): increase the internal channel receiver size up from 8 to 256
We suspect that there might be too many internal messages being pushed, causing a deadlock on the senders' side.
This attempts to increase the value of the buffer to give it more leeway.

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-22 14:13:13 +02:00
Ivan Enderlin 322f5495ac fix(sdk): SlidingSyncListInner::timeline_limit and ranges are no longer observable
fix(sdk): `SlidingSyncListInner::timeline_limit` and `ranges` are no longer observable
2023-05-22 12:05:45 +02:00
Ivan Enderlin 4eee60dc9e chore(sdk): Make Clippy happy. 2023-05-22 11:32:54 +02:00
Ivan Enderlin abf8a50c0d chore(sdk): Make Clippy happy. 2023-05-22 11:24:11 +02:00
Ivan Enderlin e9399eb635 doc(sdk): Do no link to a private function. 2023-05-22 10:54:36 +02:00
Ivan Enderlin 4e00d04611 fix(sdk): SlidingSyncListInner::timeline_limit and ranges are no longer observable.
The `SlidingSyncListInner::timeline_limit` and `::ranges` fields were
observable (behind `eyeball::Observable`). It was actually useless
as those fields were never exposed to the public API, thus it was
impossible to subscribe to them.

This patch cleans up that. `timeline_limit` and `ranges` are no longer
observable.
2023-05-22 10:50:26 +02:00
Ivan Enderlin fee1a50f38 doc(sdk): Improve documentation of next_request. 2023-05-22 09:39:43 +02:00
Ivan Enderlin 6e77804070 feat(sdk): SlidingSyncList::set_sync_mode sends an internal message.
This patch updates `SlidingSyncList::set_sync_mode` to send a
`SyncLoopSkipOverCurrentIteration` internal message to the sync loop.
2023-05-22 09:38:42 +02:00
Ivan Enderlin 82f5768df3 feat(sdk): Rename SlidingSyncInternalMessage variants.
This patch renames the variant to be more explicit about what they do
instead of re-using the “for loop vocabulary”.
2023-05-22 09:37:32 +02:00
Ivan Enderlin 4ee2f2a44b chore(sdk): Run rustfmt. 2023-05-22 08:43:10 +02:00
Ivan Enderlin f37945da13 chore(comment): fix the comment for Error::CannotModifyRanges
chore(comment): fix the comment for `Error::CannotModifyRanges`
2023-05-20 18:05:13 +02:00
Ivan Enderlin 88ebd89937 doc(sdk): Fix a typo.
Co-authored-by: Benjamin Bouvier <public@benj.me>
2023-05-20 17:57:21 +02:00
Ivan Enderlin 2f29664fb8 doc(sdk): Fix a typo.
Co-authored-by: Benjamin Bouvier <public@benj.me>
2023-05-20 17:57:11 +02:00
Benjamin Bouvier da73229e8d chore(comment): fix the comment for Error::CannotModifyRanges
The comment and the check in the code were contradicting each other; the comment was wrong, and the code was right, so there's that.

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-19 16:03:59 +02:00
Damir Jelić 34aed2f939 Replace the libolm backup encryption code with a native Rust version
This patch removes our dependency to libolm completely. This should
allow WASM targets to use the backups_v1 feature of the
matrix-sdk-crypto crate as well.
2023-05-18 10:52:51 +02:00
Ivan Enderlin ff1d784e70 fix(ci): Fix path to matrix-sdk-crypto-js and allow pushd to return an error
fix(ci): Fix path to `matrix-sdk-crypto-js` and allow `pushd` to return an error
2023-05-17 20:18:03 +02:00
Ivan Enderlin 9912a4a6db doc(sdk): Fix a typo. 2023-05-17 20:16:01 +02:00
Ivan Enderlin 7b0336bb29 doc(sdk): Fix a typo. 2023-05-17 20:07:12 +02:00
Ivan Enderlin d86647db77 chore(ci): Give pushd's result a name so that it's not dropped. 2023-05-17 20:00:33 +02:00
Jonas Platte d13d41951f Silence clippy warning from macro-generated code 2023-05-17 17:20:55 +02:00
Jonas Platte f68fd6c7cf Use workspace dependencies for futures-core 2023-05-17 17:20:55 +02:00
Jonas Platte 78838e67c1 Upgrade dependencies 2023-05-17 17:20:55 +02:00
Jonas Platte 59b1fa00df Replace futures dependencies with futures-* dependencies 2023-05-17 17:20:55 +02:00
Jonas Platte 18d12b2f10 crypto: Simplify a test 2023-05-17 17:20:55 +02:00
Jonas Platte a39a6fba51 sdk: Use tokio::sync instead of futures::channel in tests
… for consistency.
2023-05-17 17:20:55 +02:00
Ivan Enderlin fc37f337fb fix(ci): Fix path to matrix-sdk-crypto-js and allow pushd to return an error.
First off, this patch changes `pushd(…)` to `pushd(…)?` so that errors
are propagated.

Second, instead of assuming that all crates live in `crates/`, let's
allow to precise a prefix, like `crates/` or `bindings/` directly in the
“folder” path of `args`.
2023-05-17 17:12:52 +02:00
Ivan Enderlin f01e8dc992 test(sdk): Test SlidingSyncList::set_sync_mode. 2023-05-17 17:10:55 +02:00
Ivan Enderlin 8bb04ed40b test(sdk): Use the Rust inclusive range syntax for ranges. 2023-05-17 17:10:55 +02:00
Ivan Enderlin d99957d370 feat(sdk): Implement SlidingSyncList::set_sync_mode.
Changing the sync-mode of a list on-the-fly is necessary to optimise the
new `RoomList` API. For example, we can start with a list in a selective
mode, a range of `0..=50` and a `timeline_limit=0` to fetch the
beginning of the room list, and then _change_ the sync-mode to growing
to continue to sync the room list in the background.

Today, this is done with 2 lists and a merge of the lists, but
(i) this is error-prone, (ii) this is not optimal. Thank to
`SlidingSyncList::set_sync_mode`, merging lists is no more necessary,
thus removing a class of bugs in client's code.
2023-05-17 17:10:55 +02:00
Ivan Enderlin 51e6e80b3b feat(sdk): SlidingSyncMode has richer variants
feat(sdk): `SlidingSyncMode` has richer variants
2023-05-17 17:10:26 +02:00
Ivan Enderlin 6dde00ebcf chore(sdk): Simplify code with a matches!. 2023-05-17 16:50:00 +02:00
Ivan Enderlin 74430e127f doc(sdk): Do not use helper constructors in the documentation. 2023-05-17 16:50:00 +02:00
Ivan Enderlin 1c175df6b3 chore(sdk): Move From impl on SSListRequestGenerator as proper constructor. 2023-05-17 16:37:11 +02:00
Ivan Enderlin ddc8d915cb doc(sdk): Fix syntax error. 2023-05-17 16:34:12 +02:00
Ivan Enderlin f8e12f6aaf doc(sdk): Update documentation according to last commits. 2023-05-17 15:42:30 +02:00
Ivan Enderlin 63feec1433 test(sdk): Test impl From<SlidingSyncMode> for …RequestGenerator`. 2023-05-17 15:32:35 +02:00
Ivan Enderlin 1a60983e8f feat(ffi): Add SlidingSyncListBuilder::sync_mode_*.
This patch replaces `sync_mode` on `SlidingSyncListBuilder` by
`sync_mode_selective`, `sync_mode_paging` and `sync_mode_growing`, which
removes the need to use `SlidingSyncMode` directly.

This patch also removes `batch_size`, `room_limit` and `no_room_limit`
as it's now arguments of `sync_mode_paging` and `sync_mode_growing`.
2023-05-17 15:18:51 +02:00
Ivan Enderlin 41c09a5ec5 feat(sdk): SlidingSyncMode has richer variants.
`SlidingSyncMode` was previously declared as:

```rust
enum SlidingSyncMode {
    Selective,
    Paging,
    Growing,
}
```

Now, the new declaration is:

```rust
enum SlidingSyncMode {
    Selective,
    Paging {
        batch_size: u32,
        maximum_number_of_rooms_to_fetch: Option<u32>,
    },
    Growing {
        batch_size: u32,
        maximum_number_of_rooms_to_fetch: Option<u32>,
    }
}
```

First off, it helps to remove the `full_sync_batch_size` and
`full_sync_maximum_number_of_rooms_to_fetch` methods and fields from
`SlidingSyncListBuilder`. It was containing default values in case of.
That was useless and needed to be fixed. Also, calling a `full_sync_*`
method with the `Selective` mode had no effect, which could disturb
the user. Well, now everything is clean on that front.

Second, `SlidingSyncListRequestGenerator` no longer has constructors,
but a `From<SlidingSyncMode>` implementation. However, the constructors
now live in `SlidingSyncMode` with `new_selective`, `new_paging` and
`new_growing` methods which are helpers. All in all, it makes creating a
`SlidingSyncListRequestGeneator` simpler: just call `sync_mode.into()`
and boom.

Finally, this patch removes the `default_with_fullsync` list builder
helper, which makes no sense at all.
2023-05-17 14:49:55 +02:00
Jonas Platte 12a02f0458 Make examples section name consistent in docs 2023-05-17 14:45:24 +02:00
Ivan Enderlin c618b03f12 feat(sdk): SlidingSync::add_list has an immediate effect
feat(sdk): `SlidingSync::add_list` has an immediate effect
2023-05-17 13:56:35 +02:00
Jonas Platte f12e827a67 Don't use block_on in no_run doctests
… and clean up formatting around the affected ones.
2023-05-17 13:49:14 +02:00
Ivan Enderlin 64cea091f9 chore(sdk): Clean up test code. 2023-05-17 13:23:21 +02:00
Ivan Enderlin 5ce9790c94 doc(sdk): Fix rebase missing doc. 2023-05-17 13:20:31 +02:00
Ivan Enderlin 39aba1dd95 fix(sdk): Rename SlidingSyncSubscribeResult to SlidingSyncAddTimelineListenerResult. 2023-05-17 13:13:17 +02:00
Ivan Enderlin b85b585bd7 feat(ffi): Make some methods async.
`SlidingSync::subscribe`, `::unsubscribe` and `::add_list` are
now async. `subscribe` has been renamed to `subscribe_to_room` and
`unsubscribe` to `unsubscribe_from_room`.

`SlidingSyncRoom::subscribe_and_add_timeline_listener` has
been removed, and replaced by a new `::subscribe_to_room` and
`::unsubscribe_from_room` methods (the `::add_timeline_listener` method
already exists).

`TaskHandle::finalizer` is no longer necessary, thus this code has been
cleaned up.
2023-05-17 13:13:17 +02:00
Ivan Enderlin 63257e6226 fix(sdk): Remove room unsubscriptions once the server has received them
fix(sdk): Remove room unsubscriptions once the server has received them
2023-05-17 11:59:16 +02:00
Ivan Enderlin 53c20fcf1a feat(sdk): SlidingSync::add_list has an immediate effect.
`SlidingSync::add_list` sends `ContinueSyncLoop` on the internal channel.
2023-05-17 11:35:53 +02:00
Damir Jelić 1510576ce1 Expose the git description and commit hash in the crypto-ffi bindings
Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-05-17 09:31:52 +00:00
Ivan Enderlin 501b990248 chore(sdk): Rename SlidingSync::unsubscribe_to_room to …_from_room. 2023-05-17 11:29:26 +02:00
Valere 405db06495 refactor(crypto): get_or_load never returns crypto error 2023-05-17 09:20:37 +00:00
Jonas Platte be7e162ce1 Restore timeline integration tests
The directory had the wrong name, so it wasn't detected by Cargo.
2023-05-17 11:14:16 +02:00
Ivan Enderlin b7374a78e9 doc(sdk): Update documentation for SlidingSync::(un)subscribe_to_room. 2023-05-17 11:10:03 +02:00
Ivan Enderlin d8a9408efe fix(sdk): Remove room unsubscriptions once the server has received them.
This bug has been found by @bnjbvr, all the credits go to him. I've just
added some comments around his code.

Prior to this patch, the room unsubscription buffer
(`SlidingSync::room_unsubscriptions`) was reset before the request was
sent. So if something went wrong, the next request would not include the
room unsubscriptions.

This patch updates this behavior. First, it replaces `Vec` by `HashSet`
to avoid a O(n^2) look up.

Second, a copy of room unsubscriptions used by the request is kept, so
that it can be used to cherry-pick which room unsubscription to remove
from the buffer once a response from the server is received. It's
important to not clear the entire room unsubscriptions buffer as more
unsubscriptions could have been inserted meanwhile.
2023-05-17 10:14:34 +02:00
Ivan Enderlin 9b7122768f chore(sdk): Rename SlidingSync room subscriptions and unsubscriptions API.
Notably, this patch renames `SlidingSync::subscribe` and `::unsubscribe`
to `subscribe_to_room` and `unsubscribe_to_room`.
2023-05-17 10:01:55 +02:00
Jonas Platte 5fa2fff8e5 ui: Re-export TLS features 2023-05-17 09:58:31 +02:00
Jonas Platte 31e32c307f ui: Add missing copyright headers 2023-05-17 09:58:31 +02:00
Jonas Platte d620f83e0d Enable syntax highlighting in sliding_sync README 2023-05-17 09:58:31 +02:00
Jonas Platte cfc8effa66 Move timeline API into a new crate
… aimed at interactive user interfaces.
2023-05-17 09:58:31 +02:00
Jonas Platte 91d97cd588 sdk: Re-export matrix_sdk_base::crypto 2023-05-17 09:58:31 +02:00
Jonas Platte 910022bca6 sdk: Make useful push related methods public 2023-05-17 09:58:31 +02:00
Jonas Platte a6fe0bb34d sdk: Merge identical ensure_members, sync_members methods 2023-05-17 09:58:31 +02:00
Damir Jelić 0144826884 crypto: Log if and which fallback key got removed 2023-05-16 16:25:20 +02:00
Damir Jelić 35a0f3af25 crypto: Improve some logs around Olm decryption and encryption 2023-05-16 16:25:20 +02:00
Damir Jelić 9f1ec9ac3a crypto: Log the result of one-time key generation 2023-05-16 16:25:20 +02:00
Jonas Platte c796302a98 ffi: Fix typo in variant name 2023-05-16 11:32:15 +02:00
Richard van der Hoff 1c8d2a1225 Merge pull request #1923 from matrix-org/release-matrix-sdk-crypto-js-0.1.0-alpha.9
matrix-sdk-crypto-js v0.1.0-alpha.9
2023-05-15 19:50:53 +01:00
Ivan Enderlin df8242a23e test(sdk): New Sliding Sync integration test suite for a mocked server
test(sdk): New Sliding Sync integration test suite for a mocked server
2023-05-15 20:30:23 +02:00
Ivan Enderlin 5b55145a1c Merge branch 'main' into test-sliding-sync-room-timeline 2023-05-15 20:06:42 +02:00
Ivan Enderlin d24a3922a0 test(sdk): Avoid ambiguity in pos. 2023-05-15 20:03:02 +02:00
Richard van der Hoff 6c0afae0f4 Merge remote-tracking branch 'origin/main' into release-matrix-sdk-crypto-js-0.1.0-alpha.9
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 36s
2023-05-15 18:59:52 +01:00
Richard van der Hoff 923d425585 crypto-js: expose a constructor for SigningKeysUploadRequest (#1925)
... to help with testing.
2023-05-15 18:58:38 +01:00
Richard van der Hoff 89bf7f27f3 fix typo 2023-05-15 18:42:58 +01:00
Benjamin Bouvier 58dbe1e252 feat: add add_cached_list to SlidingSyncBuilder and SlidingSync (#1876)
This has slightly drifted from the initial design I thought about in the issue.

Instead of having `build()` be fallible and mutably borrow some substate (namely `BTreeMap<OwnedRoomId, SlidingSyncRoom>`) from `SlidingSync` (that may or may not already exist), I've introduced a new `add_cached_list` method on `SlidingSync` and `SlidingSyncBuilder`. This method hides all the underlying machinery, and injects the room data read from the list cache into the sliding sync room map.

In particular, with these changes:

- any list added with `add_list` **won't** be loaded from/written to the cache storage,
- any list added with `add_cached_list` will be cached, and an attempt to reload it from the cache will be done during this call (hence `async` + `Result`).
- `SlidingSyncBuilder::build()` now only fetches the `SlidingSync` data from the cache (assuming the storage key has been defined), not that of the lists anymore.

Fixes #1737.

Signed-off-by: Benjamin Bouvier <public@benj.me>
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
2023-05-15 16:17:45 +00:00
Benjamin Bouvier c404e378a2 test: sliding sync list fields reloaded from the cache are observable in streams
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-15 17:46:04 +02:00
Jonas Platte 549edeb73b sdk: Instrument sliding response handling task 2023-05-15 17:24:02 +02:00
Benjamin Bouvier b6302aca5c bench: add benchmarks for encrypted stores too
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-15 17:11:50 +02:00
Benjamin Bouvier 3928259bb5 bench: add restore session benchmark
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-15 17:11:50 +02:00
Richard van der Hoff 3049328078 matrix-sdk-crypto-js v0.1.0-alpha.9 2023-05-15 15:07:14 +01:00
Richard van der Hoff 3df473a56d update CHANGELOG 2023-05-15 15:07:03 +01:00
Ivan Enderlin 89384775ff chore(cargo): Update lockfile. 2023-05-15 16:04:17 +02:00
Ivan Enderlin d2e9347be4 test(sdk): Put sliding_sync behind its feature flag. 2023-05-15 16:03:54 +02:00
Richard van der Hoff 18954a6ba5 crypto-js: fix body of SignatureUploadRequest (#1917)
Currently, the `body` of a `SignatureUploadRequest` includes a spurious
`signed_keys: {...}` property in which the actual content is wrapped. Fix that.
2023-05-15 15:02:01 +01:00
Chris Smith 3449dad89b feat(bindings): expose getting member by id
Allow for retrieving a single room member by their ID.
2023-05-15 15:26:45 +02:00
Ivan Enderlin 07267767fc test(sdk): New Sliding Sync integration test suite for a mocked server. 2023-05-15 15:19:45 +02:00
Ivan Enderlin dca7800a88 chore(cargo): uuid is no longer needed. 2023-05-15 15:19:37 +02:00
Ivan Enderlin caaeb8130d feat(sdk): Remove txn_id from requests sent by SlidingSync.
We were using `txn_id` as a way to identify the running stream. Now
things are cleaner so we can remove this “debug tool”. This class of
problems should not appear anymore. For the record, the biggest problem
was the following: It was possible to start multiple `stream`s at the
same time, and thus a stream could receive a response sent by another
stream. Since we no longer need to restart SlidingSync anymore (i.e. no
need to start multiple `stream`s at the same time), this problem should
not happen.
2023-05-15 15:16:40 +02:00
Ivan Enderlin 94d5d5187f test(sdk): Rename a test about SlidingSyncRoom. 2023-05-15 15:14:58 +02:00
Ivan Enderlin d973ac1e93 doc(sdk): Add missing documentation. 2023-05-15 15:14:23 +02:00
Ivan Enderlin 6185b4050a feat(sdk): Process SlidingSync response inside handle_response.
Prior to this patch, the `v4::Response`, aka the SlidingSync response,
was processed by the client and transformed into a `SyncResponse` into
`sync_once` before being passed to `handle_response`. Now it's done in
`handle_response`.

This is not mandatory _now_, but it will be helpful in a close future.
2023-05-15 15:12:20 +02:00
Jonas Platte ee87ec7b46 Improve logs for pagination 2023-05-15 13:06:30 +02:00
Jonas Platte ab7aa68c5b Fix lints 2023-05-15 13:06:30 +02:00
Benjamin Bouvier fc8dd5a1cc Update crates/matrix-sdk/src/room/timeline/inner.rs
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
2023-05-15 10:29:27 +02:00
Benjamin Bouvier c0f8e31e79 chore: add tracing spans for code in TimelineBuilder suspected to be slow
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-15 10:29:27 +02:00
Stefan Ceriu 7ff125dae1 chore(xtask): clean apple generated bindings directory before building new ones 2023-05-12 16:27:14 +02:00
Stefan Ceriu 593c99d377 ffi: add method for getting the build time git short sha value (#1909) 2023-05-11 18:32:09 +02:00
Ivan Enderlin 9d0c40c207 feat(sdk): Clean up and test SlidingSyncRoom
feat(sdk): Clean up and test `SlidingSyncRoom`
2023-05-11 18:03:30 +02:00
Jonas Platte 870d6d6ca3 Make timeline event Debug impls less verbose 2023-05-11 18:00:17 +02:00
Jonas Platte 1d2e45191d Make Debug impl for RequestConfig less verbose
… for the common case, and more verbose for some uncommon options that
were just never printed before.
2023-05-11 18:00:17 +02:00
Jonas Platte 30eee70e9d Add DebugStructExt helper for writing less verbose Debug impls 2023-05-11 18:00:17 +02:00
Ivan Enderlin f23fd1809b Merge branch 'main' into feat-sliding-sync-room 2023-05-11 17:47:08 +02:00
Ivan Enderlin ab96a696ae test(sdk): Add test cases for SlidingSyncRoom::update.
Test when a `SlidingSyncRoom` has received a non-empty update, and then
receives an empty-update.
2023-05-11 17:45:14 +02:00
Benjamin Bouvier 149950cc29 sliding sync: Use RangeInclusive<u32> instead of raw start/end UInt values (#1877)
* chore: use RangeInclusive instead of raw start/end integers for ranges in sliding sync
* chore: have timeline_limit use a u32 instead of a Ruma UInt
* chore: Remove all the `Into<u32>` generics on timeline_limit and ranges APIs
* chore: introduce a `Bound` type alias for u32

Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-11 14:27:46 +02:00
Jonas Platte a84960787d Fix remaining sync response Debug event content leaks
… for real this time.
2023-05-11 13:50:20 +02:00
Jonas Platte dab4cdd863 ffi: Add MediaSource::{from_json, to_json} 2023-05-11 11:06:06 +00:00
Benjamin Bouvier d6100915df bench: add sled back to the crypto benchmarks
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-11 12:31:58 +02:00
Benjamin Bouvier 5f228f408e bench: set up a Tokio context when dropping the sqlite store
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-11 12:31:58 +02:00
Kévin Commaille 93f5562343 Only send verifications requests to devices that are cross-signed (#1884)
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-11 11:59:59 +02:00
Mauro Romito 18971e8b11 fix for notification item to get sender in invited rooms 2023-05-11 10:49:42 +02:00
Ivan Enderlin 68337d58f7 chore(ffi): Update according to last commit. 2023-05-11 09:18:43 +02:00
Ivan Enderlin 873bc6b2a4 Just to trigger the CI, after Github issues. 2023-05-11 09:01:32 +02:00
Jonas Platte 9842645377 Fix struct name for DebugNotification output 2023-05-10 23:42:32 +02:00
Jonas Platte 176934e359 Fix debug output for raw events
It was looking for an "event_type" field rather than just "type".
The code was also more complex than necessary.
2023-05-10 21:50:12 +02:00
Ivan Enderlin 75f3bbcf63 chore(ffi): Update according to last commit. 2023-05-10 15:57:43 +02:00
Ivan Enderlin 02cfee68c4 feat(sdk): SlidingSyncRoom is cheap to clone.
This patch changes `SlidingSyncRoom` to move all its fields inside an
inner type `SlidingSyncRoom` behind an `Arc`, so that cloning is cheap,
and all clones are sharing the same state.
2023-05-10 15:53:21 +02:00
Ivan Enderlin 09bb0fcdd3 test(sdk): Testing FrozenSlidingSyncRoom receives a subset of the timeline queue. 2023-05-10 14:42:00 +02:00
Ivan Enderlin 54bc774d62 test(sdk): Clarify a test with json! instead of a string. 2023-05-10 14:15:07 +02:00
Ivan Enderlin e2af4ccfe6 fix(ffi): Fix types. 2023-05-10 14:01:29 +02:00
Ivan Enderlin 1a50afe167 feat(sdk): Rethink the SlidingSyncList::state after a reset
feat(sdk): Rethink the `SlidingSyncList::state` after a reset
2023-05-10 13:56:57 +02:00
Ivan Enderlin 3a25608a6e feat(sdk): Rethink the SlidingSyncList::state after a reset.
A `SlidingSyncList` has a state, which can be either `NotLoaded`,
`Preloaded`, `PartiallyLoaded`, or `FullyLoaded`.

A `SlidingSyncList` can be reset, either manually when
`SlidingSyncList::reset` is called, or when a range is updated for
example.

Resetting a list is modifying its state. Prior to this patch, the state
was set to `NotLoaded`. However, it's not entirely true. This patch
updates this behavior to the following rules:

* When the state is `NotLoaded`, it's kept at this state as nothing has
  happened yet,
* When the state is `Preloaded`, the list is restored from the cache,
  but nothing has happened yet too, so it's kept at this state,
* When the state is `PartiallyLoaded` or `FullyLoaded`, it means some
  (or all) updates have been done, so the new state is `PartiallyLoaded`
  after the reset.

The list' state is used mostly by the client to know whether a loader
should be prompted to the users. The ranges are modified when the
users scroll inside the room list for example: scrolling in the room
list doesn't imply the state should go to `NotLoaded`. Some data
have potentially be loaded, so changing the ranges should result in a
`PartiallyLoaded` state. It seems more logical once explained like this.
2023-05-10 13:31:52 +02:00
Ivan Enderlin 22b2e54aca test(sdk): Test SlidingSyncRoom::update, esp. the timeline_queue. 2023-05-10 13:17:09 +02:00
Ivan Enderlin 7c21f8851c test(sdk): Test SlidingSyncRoom::state. 2023-05-10 09:35:45 +02:00
Ivan Enderlin c00b2db51b test(sdk): Test SlidingSyncRoom::prev_batch. 2023-05-10 09:35:45 +02:00
Ivan Enderlin e7e66dc17e test(sdk): Test SlidingSyncRoom::required_state. 2023-05-10 09:35:45 +02:00
Ivan Enderlin d688918036 feat(sdk): Don't update invite_state in SlidingSyncRoom.
`invite_state` is managed when the Sliding Sync response is processed/
handled by the `Client`. Inside `SlidingSyncRoom`, it's not necessary to
maintain it.
2023-05-10 09:35:45 +02:00
Ivan Enderlin bafcaa9c85 test(sdk): Test SlidingSyncRoom::*unread_notifications. 2023-05-10 09:35:45 +02:00
Ivan Enderlin 379c9d6520 test(sdk): Test SlidingSyncRoom::is_dm and ::is_initial_response. 2023-05-10 09:35:45 +02:00
Ivan Enderlin 04feb7a2a2 test(sdk): Test SlidingSyncRoom::name. 2023-05-10 09:35:45 +02:00
Ivan Enderlin de373c07a6 feat(sdk): Add a constant to represent the max number of timeline events to put in the cache.
This patch creates a constant to represent the
maximum number of timeline event to put in the cache:
`NUMBER_OF_TIMELINE_EVENTS_TO_KEEP_FOR_THE_CACHE`. Verbose, but easily
understandable.

This patch also renames a few variables.
2023-05-10 09:35:45 +02:00
Ivan Enderlin 39590c4e07 chore(sdk): Re-order methods on SlidingSyncRoom. 2023-05-10 09:35:45 +02:00
Ivan Enderlin 3a0ebbd271 doc(sdk): Update documentation. 2023-05-10 09:35:45 +02:00
Ivan Enderlin 32ef2f7c61 feat(sdk): Simplify SlidingSyncRoom::timeline_queue.
This patch simplifies `SlidingSyncRoom::timeline_queue` from

```rust
Arc<RwLock<ObservableVector<SyncTimelineEvent>>>
```

to

```rust
Vector<SyncTimelineEvent>
```

First, we don't need to be observable. It's never observed since
it's private, and even privately, it's never observed, there is no
subscriber.

Second, no lock is required as updates happen synchronously.

Third, `Arc` is not necessary. We want each clone of `SlidingSyncRoom`
to not share any state across them.

Finally, this patch simplifies the iterator + `.push_back` by a simple
`.extend` to update the `timeline_queue`. Behind the scene, `impl Extend
for Vector` actually does an iterate + `.push_back`; let's keep our code
simple though.
2023-05-10 09:35:45 +02:00
Ivan Enderlin 6afca5367d feat(sdk): Replace SlidingSyncRoom::is_cold by a real state enum.
`SlidingSyncRoom::is_cold` is not well-named. This patch introduces an
enum, named `SlidingSyncRoomState` which contains more detailed state:
`NotLoaded`, `Preloaded`, and `Loaded`.

The use of `AtomicBool` is also removed. Thus, we no longer need an
`Arc` for the state, which makes `Clone` more obvious: the state is not
shared across clones anymore.
2023-05-10 09:35:45 +02:00
Ivan Enderlin ef9bf87d89 chore(sdk): Write imports at the correct place. 2023-05-10 09:35:41 +02:00
Ivan Enderlin 349c7c3f68 feat(sdk): Remove SlidingSyncRoom::prev_batch.
A `SlidingSyncRoom` receives an Ruma
`api::client::sync::sync_events::v4:SlidingSyncRoom`. This value is
stored in the `SlidingSyncRoom::inner` field. From here, some getters
like `name()`, `is_dm()` etc. are using the `inner` field to compute a
result. There was one exception though: `prev_batch`. This value is part
of `v4::SlidingSyncRoom` but it was copied and updated in its own field:
`SlidingSyncRoom::prev_batch`.

I was wondering why. Turns out, there is no reason. Its getter
`prev_batch()` is public, but it's not used by the FFI bindings, so
basically nobody uses it (as this project is experimental as the time of
writing, we know our users).

This patch removes the `SlidingSyncRoom::prev_batch` field.

This patch also removes the `SlidingSyncRoom::prev_batch()` getter.

This patch finally removes the `FrozenSlidingSyncRoom::prev_batch` field
too.
2023-05-10 09:34:39 +02:00
Ivan Enderlin cb2bb84d88 fix(sdk): Remove SlidingSyncRoom::is_loading_more.
First, this field is not used by ElementX.

Second, this field is never updated, so it always returns `false`, which
seems… buggy and useless.
2023-05-10 09:34:38 +02:00
Ivan Enderlin 4132571270 doc(sdk): Write documentation for SlidingSyncRoom. 2023-05-10 09:34:38 +02:00
Ivan Enderlin 0038a0389a chore(sdk): Create one block for rooms, one block for lists.
This patch moves the code into dedicated blocks: one for updating the
rooms, one for updating the lists.
2023-05-10 09:34:27 +02:00
Ivan Enderlin 3e6dd1cecb feat(sdk): Don't remove and re-insert a room when it exists.
Prior to this patch, to check a room exists, it was removed from the
collection, then re-added if it exists. Instead of doing this `remove`
+ `insert` dance, we can simply use `get_mut`, which also returns an
`Option`. This patch does that, in addition to rewrite the code to use a
`match` instead of a `if` + `else`.
2023-05-10 09:21:20 +02:00
Mauro 6eeee8ee53 ffi: Expose EventTimelineItem::read_receipts and the NotificationItem#room_canonical_alias 2023-05-09 15:26:07 +00:00
Jonas Platte 2de786c516 Rename fetch_event_details to fetch_details_for_event 2023-05-09 17:25:39 +02:00
Jonas Platte 159b999485 Update call_event_handlers span to default level of info 2023-05-09 16:53:17 +02:00
Jonas Platte b6453772c3 Fix remaining sync response Debug event content leaks 2023-05-09 16:51:08 +02:00
Jonas Platte 0aa1f599c5 common: Make debug module public
… and remove re-exports of its contents from crate root.
2023-05-09 16:51:08 +02:00
Jonas Platte 1f01555e4e sdk: Add more logging and a new branch to fetch_in_reply_to_details 2023-05-09 16:26:52 +02:00
Jonas Platte c9d35a8fe5 sdk: Clean up spans for sliding sync_once 2023-05-09 12:49:43 +02:00
Benjamin Bouvier b257d0dacd chore: add the --workspace flag back in the documentation CI task
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-09 10:21:48 +02:00
Benjamin Bouvier 1aff90a96f chore: fix doc comments in code and READMEs
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-09 10:21:48 +02:00
Jonas Platte 1380e9c4ec Inline sync response structs with a single field 2023-05-09 10:08:34 +02:00
Jonas Platte 40c0f0896e Add some missing copyright headers 2023-05-09 10:08:34 +02:00
Jonas Platte aa3b2d4698 base: Don't log raw event for notifications 2023-05-09 10:08:34 +02:00
Jonas Platte 935dc6ec41 base: Remove presence events from debug output
We shouldn't be logging raw events, and there's not really a useful
subset we could include.
2023-05-09 10:08:34 +02:00
Jonas Platte ae4518c1a7 base: Remove unused Deserialize, Serialize impls 2023-05-09 10:08:34 +02:00
Jonas Platte 2d1f514a13 Box fields to reduce stack size of structs 2023-05-08 18:47:01 +02:00
Jonas Platte ce3c818156 Box futures to reduce composed future's sizes 2023-05-08 18:47:01 +02:00
Jonas Platte 1bc99a62a5 Make Store::save_changes non-lazy 2023-05-08 18:47:01 +02:00
Jonas Platte 3a74e8647b Reduce amount of local variables before .await in async fn 2023-05-08 18:47:01 +02:00
Jonas Platte c3d7a0704a A little bit of cleanup 2023-05-08 18:47:01 +02:00
Jonas Platte a8fb54ee67 Replace qualified name with use 2023-05-08 18:47:01 +02:00
Jonas Platte c5decd2294 crypto: Pass AnyToDeviceEventContent by reference
… in a few places where it doesn't need to be moved.
2023-05-08 18:47:01 +02:00
Jonas Platte 9c4cce5fd0 crypto: Clean up OlmMachine::with_store
- Remove an unnecessary else {}
- Reorder logging instructions
2023-05-08 18:47:01 +02:00
Jonas Platte 37ed3d0a59 sdk: Don't skip event reordering when re-receiving redacted event 2023-05-08 18:12:53 +02:00
Jonas Platte 3013c911fd sdk: Fix log message 2023-05-08 18:12:53 +02:00
Alfonso Grillo 7ac6ebfb7f Add invited and joined counts 2023-05-08 18:12:12 +02:00
Ivan Enderlin 43b28e6087 feat(sdk): Remove the need to “restart” SlidingSync
feat(sdk): Remove the need to “restart” `SlidingSync`
2023-05-08 17:24:36 +02:00
Ivan Enderlin 6c8a19cf01 chore: Make Clippy happy. 2023-05-08 16:58:00 +02:00
Ivan Enderlin bfcedcd49c feat(sdk): SlidingSync::*subscribe will cancel in-flight requests.
`SlidingSync::subscribe` and `SlidingSync::unsubscribe` will cancel in-
flight requests, i.e. the `SlidingSyncInternalMessage::ContinueSyncLoop`
will be sent in the internal channel, just like what `SlidingSyncList`s
already do when a parameter is changed.
2023-05-08 16:44:49 +02:00
Ivan Enderlin 748ae86a88 feat(sdk): Cloning SlidingSyncListBuilder clones the once_built closure. 2023-05-08 15:24:58 +02:00
Ivan Enderlin cfa2f1d049 chore: Make Clippy happy. 2023-05-08 14:20:18 +02:00
Ivan Enderlin 87f481ce7d !fixup 2023-05-08 14:17:39 +02:00
Ivan Enderlin 281944696a Merge branch 'main' into feat-sdk-sliding-sync-cancellation-token 2023-05-08 14:11:20 +02:00
Ivan Enderlin 673d51a9d9 test(sdk): Test SlidingSyncListBuilder::once_built. 2023-05-08 14:10:27 +02:00
Kévin Commaille f92c3649e9 ffi: Use SQLite state store
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-08 12:11:10 +02:00
Kévin Commaille c9fde8cf89 sdk: Add bundled-sqlite Cargo feature
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-08 12:11:10 +02:00
Kévin Commaille 991a42d8d6 sled: Add docsrs feature for docs generation
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-08 12:11:10 +02:00
Kévin Commaille d7e47501e3 benchmarks: Replace sled with SQLite
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-08 12:11:10 +02:00
Kévin Commaille ea826a257d sdk: Replace Sled with SQLite as defaut store
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-08 12:11:10 +02:00
Kévin Commaille 09e446b1d5 sqlite: Fix doc error
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-08 12:11:10 +02:00
Kévin Commaille 6bae0793f9 codecov: Add SQLite store as default crate
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-08 12:11:10 +02:00
Jonas Platte 32fafe7be3 Pin rust nightly version
Works around https://github.com/rust-lang/rust/issues/111320.
2023-05-08 10:44:14 +02:00
Ivan Enderlin 0dab71e94b fix(sdk): Fix previous merge. 2023-05-08 10:16:03 +02:00
Ivan Enderlin 150df1d6ce fix(sdk): Fix previous merge. 2023-05-08 10:07:32 +02:00
Ivan Enderlin cdb992e3b2 Merge branch 'main' into feat-sdk-sliding-sync-cancellation-token 2023-05-08 09:55:02 +02:00
Kévin Commaille 69c8b9f049 sdk: Add method to check if device is verified with cross-signing
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-06 20:06:40 +02:00
Kévin Commaille 2c3664c2b3 sdk: Document when a created room is set as direct
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-06 19:50:42 +02:00
Jonas Platte 33c84b9ffd crypto: Reduce stack size of OlmMachine 2023-05-05 14:24:44 +02:00
Jonas Platte e5375a475e crypto: Reduce stack size of Store
… and make it cheaper to clone.

Reduces the stack size of OlmMachine from 3632 bytes to 832 bytes.
2023-05-05 14:24:44 +02:00
Jonas Platte 794ab8bc9f crypto: Borrow InboundGroupSession for async fn's that don't need to own
Reduces the size of the returned futures.
2023-05-05 12:39:50 +02:00
Jonas Platte 70c2cf6fe4 sdk: Reduce size of futures in http_client 2023-05-05 12:39:50 +02:00
Jonas Platte 88580d95bf Consistently use Ruma's Owned*Id types
… for simplicity; instead of `Arc<*Id>`.
2023-05-05 12:34:15 +02:00
Mauro b9cc0b5249 ffi: Add Client::get_notification_item
… and remove NotificationService.
2023-05-05 11:27:56 +02:00
Jonas Platte 848de833cc sdk: Fill in replied-to event from timeline items when available 2023-05-05 10:54:01 +02:00
Jonas Platte 10d441f580 sdk: Log redactions of already-redacted events 2023-05-05 10:18:13 +02:00
Marcel 211690ab44 Add missing const to make epilogue.js work in ECMAScript Module compatibility mode
Signed-off-by: Marcel Radzio <mtrnord [AT] nordgedanken.dev>
2023-05-05 10:17:36 +02:00
Jonas Platte c6c5e7fca6 Add CODEOWNERS file for automatic review requests 2023-05-04 16:41:04 +02:00
Ivan Enderlin a91cd93a77 Merge pull request #1860 from bnjbvr/make-builder-build-infallible
Make `SlidingSyncListBuilder::build` infallible
2023-05-04 16:00:40 +02:00
Benjamin Bouvier e05f8001cf Mandate a Client when creating a SlidingSyncBuilder
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-04 15:42:35 +02:00
Benjamin Bouvier fd480b3a8d review: remove useless Result in FFI layer too (thanks hywan!)
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-04 15:42:35 +02:00
Benjamin Bouvier 0962b03a75 Get rid of the name() function builders?
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-04 15:42:35 +02:00
Benjamin Bouvier 3e811d5246 Make SlidingSyncListBuilder::build infallible by mandating a name in ctor
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-04 15:42:35 +02:00
Jonas Platte 3eaacaba55 sdk: Add / update copyright headers 2023-05-04 14:21:24 +02:00
Jonas Platte c5d7022272 sdk: Add a redaction test
including a check that we discard the original event if it's somehow
received again after the redaction.
2023-05-04 14:21:24 +02:00
Jonas Platte 443e729f5b sdk: Fix redaction regression 2023-05-04 14:21:24 +02:00
Jonas Platte 749b57f30a sdk: Fix logs around redactions
No need to log redaction event ID as it's already part of the span.
2023-05-04 14:21:24 +02:00
Jonas Platte 18a0c836af sdk: Move timeline redaction test to new file 2023-05-04 14:21:24 +02:00
Jonas Platte 878ab7f0e3 sdk: Don't add original form of redacted events to the timeline
If the redaction already happened server-side, it is a bug for the
server to even still have access to the non-redacted form.
We don't accept the server data in this case, and also log a warning.
2023-05-04 12:30:19 +02:00
Benjamin Bouvier 2d2874f3c0 Remove unused SlidingSyncList::new_builder
Signed-off-by: Benjamin Bouvier <public@benj.me>
2023-05-04 11:40:26 +02:00
Ivan Enderlin 769fd9cad6 Merge pull request #1844 from matrix-org/rav/signing_keys_upload_response
crypto-js: extend `mark_request_as_sent` to accept SigningKeysUploadResponses
2023-05-04 10:34:27 +02:00
Mauro 709bea839e ffi: Expose active_members_count 2023-05-04 10:31:36 +02:00
Mauro a0cebfcba2 ffi: Fix is_noisy calculation 2023-05-04 09:13:33 +02:00
Richard van der Hoff 5c9fdc51f6 fix lint 2023-05-03 14:36:39 +01:00
Richard van der Hoff c1c1b1047d Apply suggestions from code review
Co-authored-by: Ivan Enderlin <ivan@mnt.io>
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
2023-05-03 14:16:56 +01:00
Ivan Enderlin d703380f85 chore(ffi): Re-order methods. 2023-05-03 14:03:12 +02:00
Ivan Enderlin cc365215c8 feat(sdk): Introduce SlidingSyncListBuilder::once_built.
`on_built` is a method that registers a closure. This closure is called
when a list is built by `SlidingSyncListBuilder::build`. It receives
a `SlidingSyncList` and returns a `SlidingSyncList`, the list can be
updated or returned as is. It allows to configure a `SlidingSyncList`
right after it's built. `SlidingSyncBuilder::build` is responsible to
finalize the configuration, and to build all the lists. Once they are
built, the state is restored from the cache. If one wants to configure
a list before the state is restored from the cache, `once_built` will
serve well.
2023-05-03 13:42:27 +02:00
Kévin Commaille 581b4e02a1 sdk: Add timeline tests for aggregated edits, removing reply fallbacks and sanitizing HTML
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-03 13:18:36 +02:00
Kévin Commaille d6401e51c2 sdk: Move edit timeline unit tests to a separate module
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-03 13:18:36 +02:00
Kévin Commaille 4fa2c13d44 sdk: Sanitize timeline HTML input and remove reply fallbacks
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-03 13:18:36 +02:00
Kévin Commaille e8375a3770 sdk: Add constructor from m.room.message event for Message
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-05-03 13:18:36 +02:00
Stefan Ceriu 45cb5f0c2c Use a indermediary directory for attachment names that might cause conflicts 2023-05-03 13:00:56 +02:00
Stefan Ceriu 2d464cf2f7 fix(ffi): Generate correct temporary file names for media attachments 2023-05-03 13:00:56 +02:00
Alfonso Grillo 9f3e4e809c ffi: Expose power levels related APIs 2023-05-03 10:43:47 +00:00
Jonas Platte e6cdf4d753 Work around new rustfmt bug 2023-05-03 11:42:50 +02:00
Jonas Platte dddec7e7ee Revert "Add "opaque interface declarations""
This reverts commit 396e0a3567.
2023-05-03 11:42:50 +02:00
Jonas Platte 37be24ee19 sqlite: Fix compiler warnings 2023-05-03 11:42:50 +02:00
Jonas Platte e1db33e6fa Upgrade UniFFI 2023-05-03 11:42:50 +02:00
Mauro 2f413af0a8 ffi: Correct timestamp value and remove is_read flag
The timestamp value of the Notification was not reliable since it was the
timestamp in which it was generated internally, not the timestamp of when the
event was sent, now we instead expose the `origin_server_ts` of the
TimelineEvent.

`is_read` is also very unreliable, so it's just removed for now.
2023-05-02 15:00:05 +00:00
Benjamin Bouvier be41dcf300 Remove unused dependencies 2023-05-02 15:06:46 +02:00
Stefan Ceriu 17fd4dd5ca ffi: Support sending image attachments through the timeline 2023-05-02 14:54:01 +02:00
Jonas Platte 557d27a1a3 sdk: Add more convenient power level action checks to RoomMember 2023-05-02 12:59:28 +02:00
Damir Jelić 9e21678ce3 Merge pull request #1846 from matrix-org/release-matrix-sdk-crypto-js-v0.1.0-alpha.8
matrix-sdk-crypto-js v0.1.0-alpha.8
2023-05-02 12:52:06 +02:00
Damir Jelić b0ca52b203 Merge pull request #1839 from matrix-org/florianduros/tech/js-bindings-missing-dependencies-lockfile
JS Bindings: add typescript missing devDependencies and lockfile
2023-05-02 11:58:24 +02:00
Richard van der Hoff 584cd5963c Merge branch 'main' into rav/signing_keys_upload_response 2023-05-02 10:54:52 +01:00
Florian Duros 61312e53d8 Merge branch 'main' into release-matrix-sdk-crypto-js-v0.1.0-alpha.8
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 42s
2023-05-02 11:43:07 +02:00
Richard van der Hoff 8f332fddc2 crypto-js: Make importCrossSigningKeys take strings (#1843)
Currently this takes a `CrossSigningKeyExport`, but that's not a class you can
construct from the JS side. Instead, let's just pass in the individual keys.
2023-05-02 09:42:16 +00:00
Florian Duros 4df887823b Update bindings/matrix-sdk-crypto-js/README.md
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-05-02 11:35:50 +02:00
Florian Duros b9920ab477 bindings: Fix Wasm conversion into base64 2023-05-02 11:35:44 +02:00
Mauro 87b938b8fe ffi: Add timestamp field to NotificationItem 2023-05-02 11:16:43 +02:00
Mauro 034aa04076 ffi: Add is_read field to NotificationItem 2023-04-28 18:04:42 +02:00
Simon Farre 396e0a3567 Add "opaque interface declarations"
Using the #[derive(uniffi::Object)] on certain types make them not show up
in the .aar file when building for Android. Could not determine why that is,
but removing the derive macro, and adding the empty interface declarations
inside the UDL, makes them show up.

We can still use #[uniffi::export] and #[uniffi::constructor].

Signed-off-by: Simon Farre <simon.farre.cx@gmail.com>
2023-04-28 17:58:41 +02:00
Jonas Platte 7ef6accab8 base: Clean up sliding sync processing a bit 2023-04-28 13:36:37 +02:00
Jonas Platte d7421b3f85 base: Clean up ephemeral event handling
Log deserialization failing, and visit all events (though there should
never be two receipt events for one room in a single sync response).
2023-04-28 13:36:37 +02:00
Jonas Platte daf611b290 base: Add spans to some medium to large BaseClient methods 2023-04-28 13:36:37 +02:00
Kévin Commaille 640e74c76a chore: Update Ruma
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-28 13:12:38 +02:00
Florian Duros 8ba80fc13a matrix-sdk-crypto-js v0.1.0-alpha.8 2023-04-28 11:38:56 +02:00
Damir Jelić e6f2f65ffa Merge pull request #1838 from matrix-org/florianduros/feat/optional-unused-fallback-keys-js-bindings
JS Bindings: make `unused_fallback_keys` as optional in `machine.rs/receive_sync_changes`
2023-04-28 11:33:24 +02:00
Jonas Platte cca8ac7aea ci: Only save caches from main branch
Caches saved from a PR can't be loaded from other unrelated PRs, wasting
space and possibly getting older previously-saved caches evicted first.
2023-04-28 11:17:19 +02:00
Jonas Platte 4ee4198e83 ci: Remove build caching for infrequently used release workflows 2023-04-28 11:17:19 +02:00
Jonas Platte b4faef7867 bindings: Use proc-macros for types no longer referenced in UDL 2023-04-28 11:07:47 +02:00
Jonas Platte 34d2a20b15 ffi: Use proc-macros for constructors 2023-04-28 11:07:47 +02:00
Jonas Platte 6b8ec09365 crypto-ffi: Use proc-macros for constructors 2023-04-28 11:07:47 +02:00
Jonas Platte 8aad6156bc Upgrade UniFFI 2023-04-28 11:07:47 +02:00
Richard van der Hoff fc384367ec Update bindings/matrix-sdk-crypto-js/CHANGELOG.md 2023-04-27 20:00:21 +01:00
Richard van der Hoff 8a8c29a3b5 crypto-js: extend mark_request_sent to accept SigningKeysUploadResponses
Currently, we can't pass the response to a `SigningKeysUploadRequest` into
`mark_request_sent`, which apparently we should be able to do.

So, we need to make `SigningKeysUploadRequest` have a `type` like the other
`OutgoingRequest`s, and  add support for `SigningKeysUploadResponse` to
`OwnedResponse`.
2023-04-27 19:57:31 +01:00
Jonas Platte bafcf23a29 sdk: Use new_content of edits instead of content
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-27 19:08:28 +02:00
Florian Duros 75870dd607 Run clippy 2023-04-27 17:57:30 +02:00
Florian Duros 2de2a14ee6 Run rustfmt 2023-04-27 17:42:19 +02:00
Mauro d919642dd6 ffi: Exposing register_notification_handler in bindings 2023-04-27 17:35:46 +02:00
Florian Duros 31b81cbf6a Run prettier 2023-04-27 17:30:55 +02:00
Florian Duros cea29dbea1 Update README.md 2023-04-27 17:07:00 +02:00
Florian Duros c74ecc449e Add yarn.lock file 2023-04-27 17:04:54 +02:00
Florian Duros 643bd328d7 Add typescript as devDependencies 2023-04-27 17:04:43 +02:00
Florian Duros 2b3d5e09e2 Update changelog 2023-04-27 17:02:53 +02:00
Florian Duros 404d5003f3 unused_fallback_keys is optional in machine.rs 2023-04-27 17:00:28 +02:00
Kévin Commaille d54b4a1d5a sdk: Use new_content of edits instead of content
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-27 16:02:40 +02:00
Ivan Enderlin dbdfe560e1 doc: Fix examples. 2023-04-27 14:39:15 +02:00
Ivan Enderlin cbfa134087 feat(sdk): Remove hacks for Sliding Sync ranges
feat(sdk): Remove hacks for Sliding Sync ranges
2023-04-27 14:35:05 +02:00
Ivan Enderlin 4b51a19564 chore: Clean up tests. 2023-04-27 14:26:51 +02:00
Ivan Enderlin 58bb2dc21e chore: Fix PR feedbacks. 2023-04-27 14:16:48 +02:00
Ivan Enderlin 3a8b6696f7 test: Install SS proxy v0.99.2. 2023-04-27 14:07:39 +02:00
Ivan Enderlin 5e6720b63c feat(ffi): SlidingSync::reset_lists returns a SlidingSyncError. 2023-04-27 10:53:16 +02:00
Ivan Enderlin a719f35a3e test: Use the latest Sliding Sync proxy version. 2023-04-27 10:21:04 +02:00
Ivan Enderlin 13088dff72 test: Use the latest Sliding Sync proxy version. 2023-04-27 10:02:50 +02:00
Ivan Enderlin deeefdfe90 Revert "fix(sdk): Try to find a workaround for a bug in the SS Proxy."
This reverts commit f269202ece.
2023-04-27 09:03:12 +02:00
Kévin Commaille 6ca6a9a84a Implement SQLite state store
Co-authored-by: Jonas Platte <jplatte@matrix.org>
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 17:51:11 +02:00
Kévin Commaille 4bf15a4694 base: Implement Clone for StateChanges
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 17:51:11 +02:00
Kévin Commaille 78655bd9e2 base: Allow to get RoomMemberships as a list of MembershipStates
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 17:51:11 +02:00
Kévin Commaille 91da155b55 sqlite: Change signatures of SqliteObjectExt methods
Allows to pass owned strings as well as static strings

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 17:51:11 +02:00
Jonas Platte 40272c5989 refactor: Move sqlite crypto store migrations in new subdirectory 2023-04-26 17:51:11 +02:00
Ivan Enderlin 3b9c98d1b1 Revert "fix(sdk): Try to find workarounds about the bug in SlidingSync Proxy."
This reverts commit bd6075f6b4.
2023-04-26 17:31:47 +02:00
Ivan Enderlin 2032a9fbfb test(sdk): Fix tests and examples. 2023-04-26 17:11:47 +02:00
Kévin Commaille 1a20733225 indexeddb: Avoid unnecessary clones when deserializing events
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 16:17:38 +02:00
Ivan Enderlin 576fac99db feat(sdk): Update the FFI layer to latest commits. 2023-04-26 16:08:06 +02:00
Ivan Enderlin 4b70407bcd feat(sdk): SlidingSyncBuilder implements Clone. 2023-04-26 16:05:03 +02:00
Kévin Commaille bc240951d6 crypto: Enable decoding padded base64
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 15:56:03 +02:00
Ivan Enderlin a7659f1fcb Build Node bindings against Ubuntu 20.04
Build Node bindings against Ubuntu 20.04
2023-04-26 15:12:39 +02:00
Andrew Ferrazzutti 8e0559963e Restore "Install musl-gcc for linux-musl nodejs releases"
This reverts commit cfc6ec2c0d.
2023-04-26 20:25:57 +09:00
Ivan Enderlin f26b9fb66c Merge branch 'main' into feat-sdk-sliding-sync-cancellation-token 2023-04-26 12:19:02 +02:00
Ivan Enderlin 5d0b42c42b test(sdk): Disable SlidingSync integration tests temporarily.
Because since SlidingSync no longer restarts, the behaviour is really
different. The current way the tests are written cannot assert the full
behaviour. We need to rewrite this test suite entirely.
2023-04-26 12:08:16 +02:00
Andrew Ferrazzutti 4bbea71d51 Add comment to explain why to use Ubuntu LTS-1 2023-04-26 18:45:18 +09:00
Andrew Ferrazzutti 80de0f0bbe Build Node bindings against Ubuntu 20.04
Fixes #1808
2023-04-26 18:45:16 +09:00
Ivan Enderlin f17003f00e chore(sdk): SlidingSync::stream takes a &self. 2023-04-26 11:19:11 +02:00
Ivan Enderlin bb049489ef feat(sdk): SlidingSyncList::on_list can return a value. 2023-04-26 11:18:38 +02:00
Kévin Commaille 51a2d101b6 base: Remove RoomMemberships::UNKNOWN/KNOWN
The unknown filter can be difficult to match with MembershipState,
depending on the store implementation.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 10:12:22 +02:00
Kévin Commaille f7e8b22646 memory-store: indexeddb: Store memberships as MembershipState
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 10:12:22 +02:00
Kévin Commaille 252f4cb9a2 sled: Store memberships as strings
Storing as bitset is not future-proof.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 10:12:22 +02:00
Kévin Commaille a511500e6e indexeddb: Store memberships as strings
Storing as bitset is not future-proof.
Just fix the latest migration. We assume no-one used it yet.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 10:12:22 +02:00
Kévin Commaille 3081dabb66 base: Add method to match RoomMemberships with MembershipState
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-26 10:12:22 +02:00
Ivan Enderlin 1709089e6d feat(sdk): SlidingSync sync loop can be controled via internal messages.
The MPSC channel that has been introduced in recent commits is now used
in this patch. The `SlidingSync::stream` method can be controlled via
the `internal_channel`.

This patch updates `SlidingSync::stream` to use the `tokio::select!
` macro to select any future that resolves first between the
`internal_channel` receiver, or `SlidingSync::sync_once`. Fairness is
biaised as the `internal_channel` has the priority.

This mechanism is already used by this patch: `SlidingSyncList::reset`
will send the `SlidingSyncInternalMessage::ContinueSyncLoop` to
“continue”… well… the sync loop, i.e. it will cancel in-flight waiting
for a response.

This entire mechanism removes the need to “stop” and “start”, i.e.
“restart” the `SlidingSync::stream` method manually, which was the
source of many bugs. Now everything is controlled internally.
2023-04-26 09:50:11 +02:00
Ivan Enderlin 770d50e2ce Merge pull request #1822 from AndrewFerr/af/update-nodejs-version
Update supported Node.js versions
2023-04-26 08:37:20 +02:00
Kévin Commaille ae79fd0af5 sdk: Deprecate Common::(active/joined)_members(_no_sync)
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-25 18:03:53 +02:00
Kévin Commaille b8f06ec4a1 sdk-base: Deprecate Room::(active/joined)_members
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-25 18:03:53 +02:00
Kévin Commaille fe6424f48c sdk: Implement Common::(active/joined)_members_no_sync with members_no_sync
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-25 18:03:53 +02:00
Kévin Commaille 2010c180a8 base-sdk: Implement Room::(active/joined)_members with members
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-25 18:03:53 +02:00
Kévin Commaille e98fbfce9a sdk: Allow to filter Common::members(_no_sync) by membership state
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-25 18:03:53 +02:00
Kévin Commaille f68b45aa49 base-sdk:Allow to filter Room::members by membership state
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-25 18:03:53 +02:00
Kévin Commaille 81a543e15b sdk-base: Deprecate get_invited_user_ids and get_joined_user_ids
get_user_ids can be used instead

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-25 18:03:53 +02:00
Kévin Commaille 4ffa20abde sdk-base: Allow to filter get_user_ids results by any membership state
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-25 18:03:53 +02:00
Kévin Commaille 58a1ad1b93 base: Use single map for all user IDs in memory store
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-25 18:03:53 +02:00
Andrew Ferrazzutti 564549e8af Update Node bindings' "engines"
Signed-off-by: Andrew Ferrazzutti <andrewf@element.io>
2023-04-25 23:59:22 +09:00
Andrew Ferrazzutti 46f69f7efd Update supported Node.js versions
Signed-off-by: Andrew Ferrazzutti <andrewf@element.io>
2023-04-25 23:51:53 +09:00
Jonas Platte c897f0ccaf ffi: Print location for tracing events 2023-04-25 12:19:55 +02:00
Jonas Platte bd3a37791b Distinguish events from live sync and sync cache in debug string 2023-04-25 11:50:06 +02:00
Simon Farre b105359b27 Expose fetch_event_details to FFI
Signed-off-by: Simon Farre <simon.farre.cx@gmail.com>
2023-04-24 20:50:06 +00:00
Ivan Enderlin c5c8ac8a7c feat(sdk): Add support for bump_event_types in SlidingSync
feat(sdk): Add support for `bump_event_types` in `SlidingSync`
2023-04-24 20:23:27 +02:00
Ivan Enderlin 2a912f7422 Merge pull request #1817 from matrix-org/revert-1779-af/nodejs-musl-gcc
Revert "Install musl-gcc for linux-musl nodejs releases"
2023-04-24 19:59:23 +02:00
Ivan Enderlin cfc6ec2c0d Revert "Install musl-gcc for linux-musl nodejs releases" 2023-04-24 19:59:01 +02:00
Ivan Enderlin 7e243c5a5b Merge branch 'main' into fix-issue-1728 2023-04-24 19:46:56 +02:00
Kévin Commaille 910c35b699 sled: Return all user IDs in get_user_ids
It would only return joined and invited user IDs,
since those are the only ones that were stored.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-24 18:54:29 +02:00
Kévin Commaille 3f1a596c8c indexeddb: Return all user IDs in get_user_ids
It would only return joined and invited user IDs,
since those are the only ones that were stored.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-24 18:54:29 +02:00
Kévin Commaille 493db9dd3f sdk-test: Add room member ban sync event
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-24 18:54:29 +02:00
Ivan Enderlin 5d63f0b215 chore(sdk): Move variables in a smaller scope to clarify the code. 2023-04-24 15:14:11 +02:00
Ivan Enderlin 304d1f445b feat(sdk): SlidingSync types share a channel to talk to each other.
`SlidingSync` has a `Receiver`, `SlidingSyncList` has a `Sender`.
2023-04-24 14:17:33 +02:00
Ivan Enderlin 30abbe3cd4 feat(sdk): SlidingSync::add_list takes a SlidingSyncListBuilder.
Prior to this patch, `SlidingSync::add_list` was taking a
`SlidingSyncList`. However, we need to inject more data when building
the list, so let's modify `add_list` to take a `SlidingSyncListBuilder`
instead. It's even better for the user as calling `build()` isn't
necessary anymore.
2023-04-24 14:14:47 +02:00
Ivan Enderlin 7f5e61831e chore(sdk): Remove a useless import. 2023-04-24 14:11:36 +02:00
Ivan Enderlin 3b8ce5c9b1 feat(sdk): Create SlidingSync::on_list. 2023-04-24 14:11:36 +02:00
Ivan Enderlin e21d1fcb93 feat(sdk): SlidingSyncList no longer implement Clone.
It's not possible to clone a `SlidingSyncList` anymore. Why? Because
it's not correct. Prior to this patch, it was possible to add a list
to a `SlidingSync` instance, then add a clone of the same list to
another `SlidingSync` instance. Weird behaviors could happen, but more
importantly, for the next Sliding Sync design we are working on, it
could lead to gigantic bugs.

Removing `Clone` from `SlidingSyncList` makes the code simpler.
For example, `SlidingSyncList.inner` no longer needs an `Arc`, or
`SlidingSync::stream` no longer needs to clone all the lists.
2023-04-24 14:11:12 +02:00
Ivan Enderlin f4e577bbe0 feat(sdk): Remove SlidingSync::pop_list.
This method is used by nobody. It's safe to remove it.
2023-04-24 14:07:27 +02:00
Jonas Platte e5f4bbdc47 Upgrade dependencies 2023-04-24 13:59:01 +02:00
Jonas Platte e15e21a3d7 ffi: Use UniFFI proc-macros for SessionVerificationController type 2023-04-24 12:42:27 +02:00
Jonas Platte 3954cab2ab ffi: Use UniFFI proc-macros for Room type 2023-04-24 12:42:27 +02:00
Jonas Platte e1a727a27f ffi: Use UniFFI proc-macros for some misellaneousc symbols 2023-04-24 12:42:27 +02:00
Jonas Platte 75e7289ede ffi: Use UniFFI proc-macros for last parts of the Client type 2023-04-24 12:42:27 +02:00
Jonas Platte 00b3057e06 ffi: Use UniFFI proc-macros for ClientBuilder::build 2023-04-24 12:42:27 +02:00
Jonas Platte 5f802c1348 ffi: Use UniFFI proc-macros as much as possible for sliding sync 2023-04-24 12:42:27 +02:00
Jonas Platte 7ab14d9428 Enable Ruma's compat-user-id feature 2023-04-24 12:42:03 +02:00
Jonas Platte d527dd37b1 Upgrade Ruma 2023-04-24 12:42:03 +02:00
Jonas Platte 24a903ccb0 Fix Cargo.lock 2023-04-24 11:17:05 +02:00
Ivan Enderlin 8aad30ea4f Merge pull request #1779 from matrix-org/af/nodejs-musl-gcc
Install musl-gcc for linux-musl nodejs releases
2023-04-24 10:51:00 +02:00
Jonas Platte c6f491861e crypto-ffi: Use proc-macros for types no longer referenced in UDL 2023-04-24 10:31:12 +02:00
Jonas Platte 055f0ff988 crypto-ffi: Use proc-macros for Verification type and methods 2023-04-24 10:31:12 +02:00
Jonas Platte 058d27e0a3 crypto-ffi: Use proc-macros for Sas methods 2023-04-24 10:31:12 +02:00
Jonas Platte cb216044e1 crypto-ffi: Use proc-macros for OlmMachine methods 2023-04-24 10:31:12 +02:00
Jonas Platte 693ced4f4d crypto-ffi: Remove unused function 2023-04-24 10:31:12 +02:00
Jonas Platte 27cf710009 crypto-ffi: Use proc-macros for VerificationRequest methods 2023-04-24 10:31:12 +02:00
Jonas Platte 5202e3e1b9 crypto-ffi: Use proc-macros for QrCode methods 2023-04-24 10:31:12 +02:00
Jonas Platte d90d7b519b crypto-ffi: Use proc-macros for types not referenced in UDL 2023-04-24 10:31:12 +02:00
Jonas Platte d15447a2c1 crypto-ffi: Use proc-macro for exporting free functions 2023-04-24 10:31:12 +02:00
Ivan Enderlin be7b79b4e5 feat(ffi): Add binding for SlidingSyncBuilder::bump_event_types.
This patch adds a new binding on `SlidingSyncBuilder` to
`matrix_sdk::SlidingSyncBuilder::bump_event_types`.
2023-04-24 10:05:00 +02:00
Ivan Enderlin 7b2b3fa78f feat(sdk): Add support for bump_event_types in SlidingSync.
The `SlidingSyncBuilder` now has a new method: `bump_event_types`, to
configure the `bump_event_types` HTTP request parameter. This value
is passed to `SlidingSync`, which is used to build the `SlidingSync`
request.
2023-04-24 10:05:00 +02:00
Ivan Enderlin 1c2e7d8c0d chore: Update Cargo.lock. 2023-04-24 09:56:55 +02:00
Valere f8e4e3d7d5 fix(bindings): Withheld code mapping 2023-04-22 21:10:56 +02:00
Jonas Platte 9ffcb8bc8a ffi: Move error type into its own module 2023-04-20 18:24:47 +02:00
Jonas Platte 4f316a130f Remove uniffi_types modules 2023-04-20 18:24:47 +02:00
Jonas Platte 7e58e72671 Upgrade UniFFI 2023-04-20 18:24:47 +02:00
Florian Duros fd739a3676 matrix-sdk-crypto-js v0.1.0-alpha.7 2023-04-20 18:24:36 +02:00
Jonas Platte 167d81e36a ci: Simplify test-all-crates job 2023-04-20 14:52:34 +02:00
Richard van der Hoff 0a0da040d2 account.rs: add some comments (#1799) 2023-04-20 13:01:44 +01:00
Jonas Platte f2d2a20987 ffi: Change make_span to be a constructor, write docs 2023-04-20 11:43:45 +02:00
Jonas Platte 29068265db ffi: Add filtering of tracing events and spans 2023-04-20 11:43:45 +02:00
Jonas Platte 50f29e5a11 ffi: Add Span::is_none 2023-04-20 11:43:45 +02:00
Jonas Platte 54bd26d683 ffi: Add Span::current 2023-04-20 11:43:45 +02:00
Jonas Platte b532d35d21 Remove root_span from Client 2023-04-20 11:43:45 +02:00
Jonas Platte bb05ac7dac ffi: Add basic tracing bindings 2023-04-20 11:43:45 +02:00
Richard van der Hoff 0da8e56a68 crypto-js: wait for device updates in getUserDevices (#1790)
Wait for up to a second for any in-flight device list updates to complete.
2023-04-20 08:58:26 +01:00
Richard van der Hoff a88f53ee85 crypto-js: Expose more data on Device (#1786)
Implement Device.algorithms and Device.isSignedByOwner for the js bindings.
2023-04-20 08:57:54 +01:00
Jonas Platte 530fceb40d Fix some rustdoc warnings 2023-04-20 09:02:28 +02:00
Jonas Platte 7d5908beef sdk: Add more data to RemoteEventTimelineItem Debug string 2023-04-20 09:02:09 +02:00
Anderas 5d94a5d2f4 Update iOS Crypto SDK docs
… and add local podspec.
2023-04-19 18:09:21 +02:00
Jonas Platte 0e08d0f9ef sdk: Make EventTimelineItem's fields pub(super)
… and avoid an unnecessary clone.
2023-04-19 14:17:16 +02:00
Jonas Platte 3f6c9956ab sdk: Move timestamp to EventTimelineItem
… from Local/RemoteEventTimelineItem.
2023-04-19 14:17:16 +02:00
Jonas Platte c97d8afa58 sdk: Remove extra visibility boundary on {Local,Remote}EventTimelineItem 2023-04-19 14:17:16 +02:00
Jonas Platte abd508676e sdk: Remove {Local,Remote}EventTimelineItem from public API 2023-04-19 14:17:16 +02:00
Jonas Platte 7376198dfa sdk: Move sender, sender_profile, content to EventTimelineItem
… from Local/RemoteEventTimelineItem.
2023-04-19 14:17:16 +02:00
Jonas Platte 2960aafe3d sdk: Make EventTimelineItem an opaque struct instead of an enum 2023-04-19 14:17:16 +02:00
Jonas Platte 4daf31f5b1 Fix clippy lint 2023-04-19 14:17:16 +02:00
Jonas Platte bf4349ffb3 base-sdk: Don't separate member events from other state events
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-19 14:04:53 +02:00
Kévin Commaille b87a4e8c20 base-sdk: Don't separate member events from other state events
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-19 13:16:55 +02:00
Alfonso Grillo 3b1ed1403d sdk: Add DM invitation to m.direct account data upon accepting it 2023-04-18 18:05:48 +02:00
Alfonso Grillo fe10bcc814 base: Use member event is_direct field for is_direct() on invited rooms 2023-04-18 18:05:48 +02:00
Jonas Platte be67c91a6b Use regular backticks in matrix-sdk-ffi/README.md 2023-04-18 15:20:51 +02:00
Jonas Platte 89c06568dd Remove unneeded explicit lifetime 2023-04-18 15:20:51 +02:00
Alfonso Grillo dffa1b16c3 sdk: Skip user's own ID when marking a room as DM 2023-04-18 13:41:34 +02:00
Jonas Platte 5bc20669c2 sdk: Implement MSC3925 for the timeline
https://github.com/matrix-org/matrix-spec-proposals/blob/main/proposals/3925-replace-aggregation-with-full-event.md
Implemented in Synapse 1.79.0:
https://github.com/matrix-org/synapse/releases/tag/v1.79.0
2023-04-18 13:14:33 +02:00
Jonas Platte 86930581a5 Upgrade Ruma 2023-04-18 13:14:33 +02:00
Jonas Platte 40c1252f48 sdk: Simplify handling of bundled relations in timeline 2023-04-18 13:14:33 +02:00
Alfonso Grillo cfdc9b2a82 Expose accept_invitation to UniFFI 2023-04-18 12:45:30 +02:00
Jorge Martin Espinosa c5919e3e63 Add workaround for building Android bindings with supported NDK versions (r23+) 2023-04-17 16:06:46 +00:00
Andrew Ferrazzutti 4fbdd70a53 Use local reference to workflow file 2023-04-14 20:20:59 +09:00
Andrew Ferrazzutti a78b260857 Install musl-gcc for linux-musl nodejs releases 2023-04-14 17:43:42 +09:00
Damir Jelić cd865d21c3 Drop outbound group sessions in the SQLite store
The format of the outbound group session struct has changed. We nowadays correctly rotate the group session if we can't restore it, but it's still good to avoid logging the error in this case.
2023-04-13 14:48:14 +00:00
Damir Jelić 8137c39f3a Don't log the raw Ruma sliding sync response 2023-04-13 16:14:47 +02:00
Jonas Platte f21946ef06 sdk: Avoid raw JSON in debug strings 2023-04-13 16:00:50 +02:00
Damir Jelić 730b66e26c Add withheld code support 2023-04-13 11:46:19 +02:00
Damir Jelić 316b29c95f Merge branch 'main' into valere/msc_2399 2023-04-13 10:59:05 +02:00
Jonas Platte 1e737208e5 sdk: Handle ephemeral events after timeline events 2023-04-12 16:15:35 +02:00
Jonas Platte 36b9064e51 sdk: Reduce indentation in read receipt handling code
… by factoring out a function.
2023-04-12 15:24:52 +02:00
Jonas Platte 086106a96d sdk: Simplify return type of fetch_in_reply_to_details 2023-04-12 13:16:36 +02:00
Simon Farre b9fba69dc7 ffi: Fix kotlin build failure
Workaround for https://github.com/mozilla/uniffi-rs/issues/1434
2023-04-12 10:11:07 +00:00
Simon Farre 8bad59bbe1 ffi: Add avatar_url getter for SlidingSyncRoom
Signed-off-by: Simon Farre <simon.farre.cx@gmail.com>
2023-04-11 15:47:40 +00:00
Damir Jelić 972d5cefdb If we can't load an outbound group session from the store, rotate it
An error is currently thrown if loading an outbound group session fails.
This error may only affect loading outbound group sessions, while other
store operations continue to work fine. As a result, the user is unable
to send messages, but can still use the application without any problems.

Since outbound group sessions are rotated frequently, we can simply
rotate the session if loading fails. However, if the error is related to
a more serious storage issue, persisting the newly rotated outbound group
session will also fail. If the error is specific to outbound group
sessions, the user will be able to continue using the application without
interruption.
2023-04-11 10:08:06 +02:00
Damir Jelić c73aeef2ed Fix the serialization of outbound group sessions in the SQLite store
The SQLite crypto store uses rmp_serde to serialize all the data we're
going to store. This works nicely for most things, one exception to this
is the OutboundGroupSession type.

The OutboundGroupSession type stores to-device requests to ensure that
the session doesn't get used before it is shared with the whole group
and to ensure that the to-device requests get restored if the
session gets restored after an application restart.

The to-device requests type critically contain `Raw<AnyToDeviceEvent>`,
the `Raw` type here being the serde_json::Raw type. rmp_serde seems to
serialize this just fine, but later deserialization fails.

We're avoiding the issue by using serde_json to serialize the
OutboundGroupSession.
2023-04-11 10:08:06 +02:00
Damir Jelić 0f8da0b723 Test that to-device requests in the group session can get deserialized 2023-04-11 10:08:06 +02:00
Kévin Commaille a1cfb4bcf1 sdk: Re-export CrossSigningStatus
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-04-08 21:47:10 +02:00
Ivan Enderlin f6fb082dc9 chore(sdk): Remove unused methods in sliding_sync
chore(sdk): Remove unused methods in `sliding_sync`
2023-04-06 18:02:08 +02:00
Ivan Enderlin df9f48dc38 chore(sdk): Replace to_string by to_owned. 2023-04-06 18:01:45 +02:00
Ivan Enderlin 0b4c94961d test(sdk): Fix a test. 2023-04-06 17:42:28 +02:00
Ivan Enderlin 41d44f0d49 chore(sdk): Remove unused methods.
Those methods are public, but never used by our current users.

Moreover, there is some big overlaps. For example, `storage_key`,
`cold_cache` and `no_cache` do the same thing: They update the
`storage_key` field. Or `add_fullsync_list` is just a helper that is
never used except in the tests etc.
2023-04-06 16:29:38 +02:00
Jonas Platte 29255781cc Fix comments in Cargo.toml 2023-04-06 15:49:09 +02:00
Ivan Enderlin 1756aabe35 fix(sdk): SlidingSyncList.room_list emits updates for non-moving rooms
fix(sdk): `SlidingSyncList.room_list` emits updates for non-moving rooms
2023-04-06 15:08:47 +02:00
Ivan Enderlin 4ee4906536 chore(sdk): Make Clippy happy. 2023-04-06 11:36:37 +02:00
Ivan Enderlin fbe162a1bc test(sdk): Fix an integration test in Sliding Sync.
The test does the following:

1. Create 2 (identical) lists,
2. Do a sync.
3. Assert that the 1st and 2nd lists are receiving an update,
4. Add a 3rd (identical) list,
5. Do a new sync,
6. Assert that 3rd list is receiving an update.

This last step is wrong. All lists should receive an update as they
are identical.
2023-04-06 11:29:10 +02:00
Damir Jelić cebeca85d0 fixup! Minor fixes to the withheld handling 2023-04-06 11:23:27 +02:00
Damir Jelić 8c23b6e7b2 Minor fixes to the withheld handling 2023-04-06 11:18:14 +02:00
Ivan Enderlin eb0e97b902 test(sdk): Test that SlidingSyncList.room_list receives “diff”.
This patch updates a test to ensure that `room_list` receives “diff”
for rooms that are modified by a sync operations, but also by another
updates (like a new event).
2023-04-06 11:14:09 +02:00
Ivan Enderlin 828e36e3af test(sdk): Test apply_sync_operations removes rooms that have been updated. 2023-04-06 11:14:09 +02:00
Ivan Enderlin d68a22c378 fix(sdk): SlidingSyncList.room_list emits updates for non-moving room.
The `SlidingSyncList.room_list` field is used to store the list of rooms
for a particular Sliding Sync list. It's used by the user to receive
“diff”s when a room sees its position modified. For example when a new
room receives a message, it “climbs back up” the entire room list to
be at the top place. Another example is when a new room is created,
some rooms will move around to give the new room a space. All those
moves will create “diff”.

However, the user also expects to receive a “diff” when a room has
received some updates, even if it's position doesn't change. For
example, when a room is already at the top of the list but receives a
new message: It has received an update, but its position stays the same.

This specific latter feature was implemented before, but it has been
removed by accident in https://github.com/matrix-org/matrix-rust-sdk/
pull/1699 (more specifically in https://github.com/matrix-org/matrix-
rust-sdk/pull/1699/commits/861a05be69a566d9a4ad125dc6ecb418d2b3210f).
At that time, it was not clear why the code was filtering for specific
filled room entires, to set the filled room entries, at the same
position. Zero comment, zero test. I didn't consider this as a feature
but as a bug.

So this patch re-introduces this feature. Hopefully in a more optimal
way. If a room has already triggered a first “diff” because of a
position change, it won't trigger a second “diff” because it has
received an update (which was the case before).

The `SlidingSyncList::handle_response` method has also been renamed
`update`, as it does update, whenever it comes from.

The code has been commented and documented to explain this feature.

Existing tests have been updated, especially for `apply_sync_operations`
which now ensure the `rooms_that_have_received_an_update` collections is
updated accordingly. Another test has been updated specifically to test
the “diff”s received by `room_list`.
2023-04-06 11:09:55 +02:00
Ivan Enderlin a71970d3de chore(sdk): Rephrase a panic message. 2023-04-06 10:50:20 +02:00
Ivan Enderlin c07b060080 feat(sdk): Create vectors with correct capacity to avoid reallocations.
`updated_rooms` and `updated_lists` can be created with an initial
capacity. Doing so will avoid reallocations if the vector is too small.
2023-04-06 10:49:15 +02:00
Jonas Platte b033508e9b Fix clippy lints 2023-04-06 09:57:37 +02:00
Damir Jelić ba95a7bfd8 Use BTreeMap instead of HashMap
We use BTreeMap everywhere else, so let's be consistent with that
choice.
2023-04-05 14:38:25 +02:00
Damir Jelić 64d76308c6 Use as_ref() instead of stars and ampersands 2023-04-05 14:29:49 +02:00
Damir Jelić 52fef9f373 Don't use a Result return type in the withheld handling method 2023-04-05 14:27:00 +02:00
Damir Jelić c3437ac4cf Apply suggestions from code review
Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-04-05 14:22:19 +02:00
Damir Jelić 6fd129dcfa Remove some commented out code and fix some formatting 2023-04-05 13:22:41 +02:00
Damir Jelić 1f8c67bbb2 Use the atomic bool seralizer for the no_olm flag 2023-04-05 13:15:51 +02:00
Damir Jelić 82a4b53cf9 fixup! Apply suggestions from code review 2023-04-05 13:15:38 +02:00
Damir Jelić 673db38a72 Apply suggestions from code review
Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-04-05 13:14:07 +02:00
Damir Jelić 50d477b91c More clippy fixes 2023-04-05 11:54:29 +02:00
Damir Jelić 1c2964f3f3 Update crates/matrix-sdk-crypto/src/types/events/room_key_withheld.rs
Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-04-05 11:52:25 +02:00
Damir Jelić 92202e20e7 Fix some clippy warnings 2023-04-05 11:45:50 +02:00
Damir Jelić c032609f4d Fix the js tests now that we bumped our DB version 2023-04-05 11:34:28 +02:00
Olivier Wilkinson (reivilibre) 9c54de1817 Downgrade memory store 'Saved changes in <time>' to debug
It doesn't seem very interesting since a memory store will be fast anyway. In practice, this fills the console quickly.
2023-04-05 11:31:37 +02:00
Damir Jelić d606bd3e9f Document the new withheld content enums 2023-04-05 11:18:50 +02:00
Ivan Enderlin 7c578dccb9 fix(sdk): SlidingSync uses the same storage keys for storing *and* restoring
fix(sdk): `SlidingSync` uses the same storage keys for storing *and* restoring
2023-04-05 11:11:47 +02:00
Ivan Enderlin 5563213106 chore(test): Make Clippy happy. 2023-04-05 10:56:08 +02:00
Jonas Platte 91dc87808d ffi: Add InReplyToDetails 2023-04-05 10:50:08 +02:00
Jonas Platte 1217067f74 ffi: Rename ProfileTimelineDetails to ProfileDetails 2023-04-05 10:50:08 +02:00
Jonas Platte 5b512f020e sdk: Rename details field to event in InReplyToDetails 2023-04-05 10:50:08 +02:00
Ivan Enderlin 042d6bab72 test(sdk): Test SlidingSync is store and restored correctly. 2023-04-05 10:06:59 +02:00
Jonas Platte ef3ffda2d3 ffi: Replace EventTimelineItem::{raw, fmt_debug} by debug_info 2023-04-05 09:56:00 +02:00
Jonas Platte 3ac6b10daa sdk: Add RemoteEventTimelineItem::latest_edit_json
… and rename raw to original_json to disambiguate.
2023-04-05 09:56:00 +02:00
Ivan Enderlin be631849e8 fix(sdk): Move SlidingSync::cache_to_storage to cache.
This patch also re-uses the `format_storage_key_*` functions to use the
same key as the `restore_sliding_sync_state` function. It fixes a bug
where the keys were mismatching.
2023-04-05 09:17:54 +02:00
Ivan Enderlin fc8b9d7de4 feat(sdk): Extract SlidingSync cache functions into their own module. 2023-04-05 09:05:03 +02:00
Jonas Platte 2c38c6c371 sdk: Log in_reply_to field in timeline::Message Debug impl 2023-04-04 18:09:08 +02:00
Damir Jelić 81e2725b6f Remove DirectWithheldCode 2023-04-04 13:30:29 +02:00
Simon Farre fc56ae3dcf Expose invite_user_by_id over the FFI
This PR is self explanatory.

Exposes said function to the FFI. Defined in the .adl file,
and defined to throw `ClientError`

Signed-off-by: Simon Farre <simon.farre.cx@gmail.com>
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
2023-04-04 09:04:54 +00:00
Chris Smith e8c56f8163 feat: expose inviter to ffi
This allows us to know who has invited us to rooms
2023-04-04 10:29:04 +02:00
Ivan Enderlin 690c3b1977 Merge pull request #1699 from Hywan/feat-sdk-sliding-sync-list-revamp-sync-mode
feat(sdk) Revamp Sliding Sync List state lifetime
2023-04-03 15:04:21 +02:00
Ivan Enderlin ac800180a7 Merge branch 'main' into feat-sdk-sliding-sync-list-revamp-sync-mode 2023-04-03 14:36:26 +02:00
Damir Jelić b7a78c865c Ensure correct Olm session selection for encrypted messages
In some cases, restoring client state from backups may cause Olm sessions
to become corrupted, resulting in a backward ratchet. As a consequence,
the receiving side is unable to decrypt messages. To address this issue,
the failed side initiates a new Olm session and sends a dummy encrypted
message.

However, this dummy message also creates a new Olm session on the
sender's side. To ensure that both sides use the same new session, we
must sort sessions by their creation timestamp before encrypting new
messages.

Although the session list was sorted correctly previously, we selected
the wrong side of the list, resulting in an outdated session being
selected instead of the newest one. This patch resolves the issue by
selecting the newest Olm session and adds a test to the session getter
logic to prevent reintroduction of this bug.
2023-04-03 13:03:09 +02:00
Ivan Enderlin aeda2d363c Merge pull request #1736 from Hywan/feat-sliding-sync-storage 2023-04-03 12:54:49 +02:00
Ivan Enderlin 69af5b3c6f feat(sdk): When a SlidingSync cache is obsolete, let's remove it.
Prior to this patch, when `SlidingSync` was built with a storage key,
the storage was read to find a previous `SlidingSync` version that
was in a cache. To put a `SlidingSync` instance in the cache, it
was serialized to JSON. When one reads from the cache, the value is
deserialized. A problem happens when the internal representation of
`SlidingSync` and other types (e.g. `SlidingSyncList`) have changed (due
to an SDK update for example): Loading a previous state from the cache
results in an error.

After discussion with the teams, clients don't want to deal with
obsolete cache values. In such a scenario, (i) they cannot interact
with the cache to remove the obsolete entry, and (ii) their only
possibility is to log out and log in the user again. What an unfriendly
user experience!

This patch modifies this behaviour. When loading a `SlidingSync` type or
a `SlidingSyncList` type from the cache, 3 cases are now handled:

1. The cache entry exists and has been successfully deserialized: in
   this case, we do our business.
2. The cache entry exists, but it wasn't possible to deserialize it: the
   cache entry is declared as obsolete, and the entire `SlidingSync`
   cache is cleaned up, so all entries for `SlidingSync` and
   `SlidingSyncList` are removed from the storage,
3. The cache entry doesn't exist: we do nothing particular.

Note that if one cache is obsolete, all cache entries are removed.
2023-04-03 12:10:50 +02:00
Ivan Enderlin 56a7854b53 Merge branch 'main' into feat-sdk-sliding-sync-list-revamp-sync-mode 2023-04-03 10:10:31 +02:00
Ivan Enderlin 60d4ac14b7 Merge pull request #1725 from Hywan/feat-remove-jack-in
feat(labs): Remove `jack-in`
2023-04-01 13:27:20 +02:00
Richard van der Hoff 78b9758377 Merge pull request #1721 from matrix-org/rav/crypto-js-releases
Fixes and documentation for crypto-js releases
2023-03-31 11:22:50 +01:00
Richard van der Hoff a5fd71a251 prettify markdown 2023-03-31 11:08:26 +01:00
Alfonso Grillo 7958a20fc1 Add short_retry on get_profile 2023-03-30 22:00:09 +02:00
Jonas Platte 6878f52885 Upgrade UniFFI 2023-03-30 21:53:02 +02:00
Ivan Enderlin ea5b4c98c1 feat(labs): Remove jack-in.
This was a fun ride, but nobody uses it, and we don't need it anymore.

Thanks for all the fishes.
2023-03-30 18:03:38 +02:00
Ivan Enderlin 60432abe0d feat(ffi): Add SlidingSync::reset_lists. 2023-03-30 18:01:17 +02:00
Ivan Enderlin 2d537e5211 feat(sdk): Add SlidingSync::reset_lists.
The `SlidingSync::stream` method no longer resets the lists everytime
it is called. If one wants to reset the lists, they need to call
`SlidingSync::reset_lists`.
2023-03-30 18:01:16 +02:00
Jonas Platte 7dd086fcdc Make sqlite bundling optional 2023-03-30 17:59:51 +02:00
Ivan Enderlin bd6075f6b4 fix(sdk): Try to find workarounds about the bug in SlidingSync Proxy.
It still about https://github.com/matrix-org/sliding-sync/issues/52. We
try to rebuilt a valid `range`. Hopefully, the bug will be fixed soon,
and we will be able to clean that temporary code.
2023-03-30 17:52:33 +02:00
Kévin Commaille 48b67759ed sdk: Make PaginationOption's custom variant's strategy return a ControlFlow
It is semantically more correct than an Option.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-30 14:39:08 +00:00
Richard van der Hoff f60c678af8 Apply suggestions from code review
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
2023-03-30 15:38:42 +01:00
innocent fish a35d96c15e Update swift.rs 2023-03-30 16:08:06 +02:00
Alfonso Grillo ade7fabb6b Add Client::get_profile 2023-03-30 15:44:27 +02:00
Ivan Enderlin dd4cb9c793 test(sdk): Fix SlidingSync doctests. 2023-03-30 15:10:17 +02:00
Ivan Enderlin 2ace220366 chore(sdk): Rename rooms_list to room_list. 2023-03-30 15:06:19 +02:00
Richard van der Hoff 4f3f9c7af8 Fixes and documentation for crypto-js releases
The tags are supposed *not* to contain `v`, for consistency with the other
crates.
2023-03-30 13:57:15 +01:00
Richard van der Hoff 43d4e7b46a Merge pull request #1719 from matrix-org/release-matrix-sdk-crypto-js-0.1.0-alpha.6
matrix-sdk-crypto-js v0.1.0-alpha.6
2023-03-30 13:53:39 +01:00
Ivan Enderlin 4be02d0e99 test(sdk): Wait longer on the server to reply. 2023-03-30 14:43:33 +02:00
Ivan Enderlin e34708862d test(sdk): Remove a useless SS test. 2023-03-30 14:31:52 +02:00
Ivan Enderlin f269202ece fix(sdk): Try to find a workaround for a bug in the SS Proxy.
See https://github.com/matrix-org/sliding-sync/issues/52 for the
explanation. And this patch has comments explaining how I try to work
around this.
2023-03-30 14:23:59 +02:00
Kévin Commaille 408f966a50 sdk: Rename flag to update fully-read marker
Its meaning has changed since it is used in more cases.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-30 14:23:57 +02:00
Kévin Commaille 553ffe97a8 sdk: Never insert read marker in last position in timeline
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-30 14:23:57 +02:00
Ivan Enderlin 23f16f065b fix(sdk): Make out-of-bounds DELETE a no-op. 2023-03-30 13:37:31 +02:00
Richard van der Hoff f246296ff9 matrix-sdk-crypto-js v0.1.0-alpha.6
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 34s
2023-03-30 12:26:29 +01:00
Mauro ca6faffc72 bindings: Reset the timeline when the user's ignore list is updated 2023-03-30 11:22:06 +00:00
Ivan Enderlin 4c42205633 chore(labs): Update to the latest SS version. 2023-03-30 12:57:24 +02:00
Richard van der Hoff f9881065c1 Add an API to notify apps when a megolm key is received
This is useful for applications which want to have another go at decryption
when some room keys arrive.
2023-03-30 12:29:39 +02:00
Ivan Enderlin 1af1504ef3 feat(ffi): Update to the latest Sliding Sync version. 2023-03-30 11:42:22 +02:00
Damir Jelić 7fd1c93e1a Document the fact that we require protoc to build the bindings 2023-03-30 11:06:15 +02:00
Doug a33d2ad28f bindings: Add ignore_user 2023-03-30 08:59:19 +00:00
Ivan Enderlin bd8a97cfd7 feat(sdk): Update the SyncOp::Delete operation.
It seems that the `DELETE` operation actually deletes an entry. So
let's update the code to reflect that :-).
2023-03-30 10:35:27 +02:00
Ivan Enderlin ce94fcc2e2 feat(sdk): Update the SyncOp::Insert operation.
It seems that the `INSERT` operation actually inserts a new entry. So
let's update the code to reflect that :-).
2023-03-30 10:00:21 +02:00
Ivan Enderlin a442ca1893 Merge branch 'main' into feat-sdk-sliding-sync-list-revamp-sync-mode 2023-03-29 17:29:15 +02:00
Ivan Enderlin db7746062f doc(sdk): Write more doc. 2023-03-29 17:23:37 +02:00
Ivan Enderlin bc9d5016dc chore(sdk): Move maximum_number_of_rooms's update a little bit above. 2023-03-29 17:15:07 +02:00
Ivan Enderlin 581c02307e fix(sdk): Rewrite SyncOp::Invalidate entirely.
`SyncOp::Invalidate` means _invalidating_ a particular range. When a
room is `Filled`, it becomes `Invalidated`, when it is `Invalidated` it
stays `Invalidated`, and when it is `Empty` it stays `Empty`.

Before this patch, `Empty` was becoming `Invalidated`, which apparently
is a bug.

This patch also fixes out-of-bound accesses, and adds many tests.

Finally, this patch renames `update_state` to `update_room_lists`.
2023-03-29 17:11:01 +02:00
Ivan Enderlin a4f8c35efc fix(sdk): Rewrite SyncOp::Insert entirely.
`SyncOp::Insert` means _inserting_ a new room ID. The `rooms_list`
contains all possible rooms (based on `maximum_number_of_rooms`, a value
returned by the server). Here, inserting = setting
`RoomListEntry::Filled` at a particular index of `rooms_list`, that's
it.

The previous code was doing very complex stuff, like removing things
around the `index` if something etc. It was using the requested ranges
(the range passed to the request) etc.

Applying `SyncOp` should be simple and is focused on updating
`rooms_list` only: the requested ranges have nothing to do here.

This patch also prevents against out-of-bounds acccesses, which wasn't
the case before.
2023-03-29 16:30:06 +02:00
Ivan Enderlin 2878148b0e fix(sdk): Prevent ouf of bounds accesses for SyncOp::Delete.
This patch prevents out of bounds acceses for `SyncOp::Delete`, and adds
more tests.

This patch also removes a cast from `UInt` to `u32` to `usize`. It's now
from `UInt` to `usize` directly.
2023-03-29 16:10:44 +02:00
Ivan Enderlin d6cfd871c4 feat(sdk): Protect against invalid responses from the server. 2023-03-29 15:55:02 +02:00
Ivan Enderlin 18597f8f63 fix(sdk): Fix out-of-bounds and re-implement SlidingOp::Sync handler.
First off, this patch renames `ops` to `sync_operations` and `room_ops`
to `apply_sync_operations`.

Second, the `SlidingOp::Sync` was creating an out-of-bounds access
depending of the range present in the server's response. For example, if
the `rooms_list` contains 5 elements (because the
`maximum_number_of_rooms` is set to 5), and the server replies with:

```json
{
    "op": "SYNC",
    "ranges": [3, 17],
    "room_ids": […]
}
```

the previous code was setting a new `RoomListEntry` at indices `3..=17`,
whilst the `rooms_list` contains only indices from `0..=4`. That's
annoying.

The previous code was also counting the number of `room_ids` for
nothing, just to execute the iterator that was applying the actual
changes in a `map`. Well, everything was fishy.

This patch updates the code to protect against an unexpected server's
reply by raising an `Err`. This patch also adds tests.
2023-03-29 15:30:10 +02:00
Jonas Platte 6b5f0b8ec3 Reset visible timeline when a gappy sync arrives 2023-03-29 14:00:33 +02:00
Damir Jelić 172867fd4d Simplify the withheld code receiving 2023-03-29 13:44:28 +02:00
Jonas Platte 50cc356c7b Use Observable for sliding_sync_reset_broadcast_tx 2023-03-29 13:23:24 +02:00
Jonas Platte 2ac192f307 Use str::to_owned instead of str::to_string
Expresses intent more clearly.
2023-03-29 13:23:24 +02:00
Damir Jelić 03aba95e1e Switch the FFI bindings to use the SQLite cryptostore 2023-03-29 11:44:33 +02:00
Ivan Enderlin 616e57eb1c test(sdk): Update integration test suite for SS. 2023-03-29 11:05:02 +02:00
Ivan Enderlin 5c695bbf8f feat(ffi): Update add_range calling. 2023-03-29 10:55:14 +02:00
Ivan Enderlin 861a05be69 feat(sdk): Remove updated_rooms from SlidingSyncListInner::update_state.
The `updated_rooms` argument was passed to `find_rooms_in_list` to
update the `room_list`: the update is setting the filtered room list
entry to `RoomListEntry::Filled`.

_But_, `find_rooms_in_list` was already filtering rooms which are
`Filled`. So it does… nothing: it filters rooms which are `Filled` to
update them to `Filled`.

So we can remove `find_rooms_in_list` because it becomes useless. And we
can remove `updated_rooms` too.

The `rooms_list` is updated by `rooms_ops` itself. Let's keep
modifications in one unique place.
2023-03-29 10:51:33 +02:00
Damir Jelić cf17a05ecc Restructure the withheld code types 2023-03-29 10:45:26 +02:00
Ivan Enderlin 385dd9113b feat(sdk): Simplify SlidingSyncListInner::update_state.
The `update_state` method of `SlidingSyncListInner` has basically
2 cases:

1. For an initial response,
2. For other responses.

The code between the 2 cases were almost identical. Or, they could be
identical. The few exceptions are:

* In the first case, the `rooms_list` updates were taking the
  form of a `VectorDiff::Append`, while the second case, it was a
  `VectorDiff::PushBack`.
* In the first case, the `is_cold` flag was set to `false`.

It's fine for the clients to receive only a `VectorDiff::Append` event
only. So let's make it uniform.

And it appears that the `is_cold` field is now private, and never read
anywhere else. So… it's… basically useless. We can remove it! It was
previously used here to know which flow to use, but since we can make
both flows identical, its role becomes insignificant.
2023-03-29 09:52:58 +02:00
Ivan Enderlin 3f4f9c1fbd chore(sdk): Remove a useless reference. 2023-03-29 09:52:05 +02:00
Ivan Enderlin bf163ef5ad feat(sdk): Replace checked_sub + unwrap_or_default by saturating_sub. 2023-03-29 09:23:47 +02:00
Ivan Enderlin 83cf820508 chore(sdk): More code in blocks to remove mutable variables with larger scopes. 2023-03-29 09:23:10 +02:00
Jonas Platte d680b331d0 Make tokio a workspace dependency 2023-03-28 21:08:57 +02:00
Jonas Platte cd33d8ca38 Always use RwLock and Mutex from tokio
… instead of async-lock, which we previously used on wasm.
2023-03-28 21:08:57 +02:00
Jonas Platte 9bfd88cec4 sdk: Always use tokio OnceCell
Tokio's sync module works on wasm as well.
2023-03-28 21:08:57 +02:00
Damir Jelić d5fba19655 Don't allow the no_olm withheld code sent flag to be reset 2023-03-28 14:31:55 +02:00
Ivan Enderlin ab29e1b319 !debug 2023-03-27 14:32:11 +02:00
Ivan Enderlin a2dbeda758 feat(sdk): SlidingSyncList cannot be removed from SlidingSync.
`create_range` and `SlidingSyncList::next_request` return a `Result`
instead of an `Option`. It was a legacy from the old `impl Iterator` of
`SlidingSyncListRequestGenerator`. But actually, when `create_range`
fails, it must return a `Err` value, not a `None` value.

And since it's a regular error, `sync_once` can propagate the
error. Thus, it is no longer necessary to “update” the list of
`SlidingSyncList`. It's not necessary to remove some items in this list
when the `next_request` method can no return a value: it always returns
a value, except when a error happens.
2023-03-27 14:25:40 +02:00
Damir Jelić 0d3fd31893 Clean up the withheld code types 2023-03-27 09:21:48 +02:00
dependabot[bot] 8b5de47acb chore(deps): bump openssl from 0.10.45 to 0.10.48 (#1706)
Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.45 to 0.10.48.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.45...openssl-v0.10.48)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-03-25 21:12:52 +01:00
Kévin Commaille 5a7ea607c6 sdk: Use new filter constructor to enable room members lazy-loading
* sdk: Use new filter constructor to enable room members lazy-loading

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-25 21:12:09 +01:00
Flescio 09fc258f9a ffi: Make name parameter optional in CreateRoomParameters 2023-03-23 16:56:52 +00:00
Ivan Enderlin fdba90587a feat(sdk): Reset the SlidingSyncList when starting a stream. 2023-03-23 17:44:25 +01:00
Ivan Enderlin 63ed675158 doc(sdk): Extract the giant SS doc inside a README.md file.
Why? Because it takes forever to scroll to the code when opening
`sliding_sync/mod.rs` :-p.
2023-03-23 17:38:20 +01:00
Ivan Enderlin 767e9b3cf2 feat(sdk) Reset SlidingSyncList when a range is modified. 2023-03-23 16:32:53 +01:00
Ivan Enderlin 8d4ceac21f test(sdk): Continue to fix, test and clean up SlidingSyncList
test(sdk): Continue to fix, test and clean up `SlidingSyncList`
2023-03-23 13:18:09 +01:00
Ivan Enderlin d1616d5654 chore(sdk): Remove a useless comma. 2023-03-23 13:17:54 +01:00
Ivan Enderlin 492e08598c feat(sdk): Revamp SlidingSyncList::*range*.
First off, `set_ranges`, `set_range`, `add_range` and `reset_ranges`
take a `&[(U, U)]` instead of a `Vec<(U, U)>` when a vector was needed,
or takes a `(U, U)` instead of 2 arguments when it was needed.

Second, all those methods now return a `Result<(), Error>`. The
`Error::CannotModifyRanges` is raised if the chosen `SlidingSyncMode`
doesn't allow to modify ranges. Basically, `Selective` does allow a
user to modufy the ranges, but there is no real ranges with `Growing` or
`Paging`. Let's make it an explicit error.

Finally, `SlidingSyncListInner` has 2 methods: `set_ranges` and
`add_range`, but without any “ranges check”; `SlidingSyncList` does call
the inner methods, but does the checks.
2023-03-23 12:34:48 +01:00
Ivan Enderlin 6716939b6d chore(sdk): Re-order fields in SlidingSyncListInner. 2023-03-23 11:56:08 +01:00
Ivan Enderlin 73959e023b feat(sdk): Remove for FullSync suffix to sync modes. 2023-03-23 11:53:39 +01:00
Ivan Enderlin ec02d462ea feat(sdk): The SlidingSyncList.full_sync_* fields are no longer useful.
They are unused. Let's remove them.
2023-03-23 11:50:38 +01:00
Ivan Enderlin 0eee472829 feat(sdk): Remove send_updates_for_items.
This field is always set to `true` by all the clients. So let's consider
that something we always want, and let's remove code complexity.
2023-03-23 11:46:56 +01:00
Ivan Enderlin 296328e8e0 feat(sdk): Don't rename SlidingSyncState's variants when serialization.
We are going to introduce a BC break. So let's take the opportunity to
get rid off of this renamings too.
2023-03-23 11:37:53 +01:00
Ivan Enderlin 831090c92c feat(sdk): Export RoomListEntry into its own module. 2023-03-23 11:24:30 +01:00
Ivan Enderlin fa361aea16 chore(sdk): Make Clippy happy. 2023-03-23 11:18:09 +01:00
Ivan Enderlin 91e9942fcd feat(sdk): Export FrozenSlidingSyncList into its own module. 2023-03-23 11:15:24 +01:00
Kévin Commaille 5eeea83c19 sdk: Get push actions of retried decrypted events in the timeline
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-23 10:59:55 +01:00
Kévin Commaille 98386cf527 sdk: Get push actions of decrypted events
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-23 10:59:55 +01:00
Kévin Commaille a3667a21c9 sdk: Simplify e2ee branching of Common::event
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-23 10:59:55 +01:00
Kévin Commaille fae10ae7f3 sdk: Add private method to get the current push rules
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-23 10:59:55 +01:00
Ivan Enderlin 1db8084c4f chore(sdk): Make Clippy happy. 2023-03-23 10:38:37 +01:00
Ivan Enderlin b544639187 chore(sdk): Re-ordering methods inside SlidingSyncList. 2023-03-23 10:07:19 +01:00
Ivan Enderlin 5e1fda9834 test(sdk): Update the assert_ranges macro to be able to define the first list state. 2023-03-23 10:05:34 +01:00
Ivan Enderlin 5bae1a2a4e chore(sdk): rooms_ops takes a &[(UInt, UInt)] for the ranges. 2023-03-22 16:59:45 +01:00
Ivan Enderlin defe48bf3c test(sdk): Test SlidingSyncList::get_room_id. 2023-03-22 16:45:53 +01:00
Ivan Enderlin caf55308a5 feat(sdk): Remove SlidingSyncList::rooms_updated_broadcast_stream.
This method is never used by the clients, so it's basically public dead
code. It doesn't fulfill a particular requirement nor a need, so let's
remove it.

Fixes https://github.com/matrix-org/matrix-rust-sdk/issues/1694.
2023-03-22 16:40:06 +01:00
Ivan Enderlin f2aebcb983 test(sdk): (Re)write a test for SlidingSyncListInnner::find_rooms_in_list. 2023-03-22 16:40:06 +01:00
Ivan Enderlin 2840242331 chore(sdk): Use &[…] instead of &Vec<…>.
One less pointer indirection.
2023-03-22 16:40:06 +01:00
Ivan Enderlin 69a779a7eb feat(sdk): Improve SlidingSyncListInner::find_rooms_in_list.
The `SlidingSyncListInner::find_rooms_in_list` method can be greatly
improved by using the `Iterator` API.

It was already using `Iterator::skip`, great! Let's continue by using
`Iterator::take` instead of using a stop index.

And let's use `Iterator::enumerate` to avoid using a mutable index.
2023-03-22 16:40:06 +01:00
Ivan Enderlin b7da197846 doc(sdk): Add missing documentation. 2023-03-22 16:40:06 +01:00
Ivan Enderlin 0b9b01727e feat(sdk): Remove find_rooms?_in_list from the public API.
`SlidingSyncList::find_room_in_list` and
`SlidingSyncList::find_rooms_in_list` aren't useful (and never used) by
the public consumer of this API. Let's remove it. They are only used for
internal purposes.
2023-03-22 16:40:06 +01:00
Ivan Enderlin 0d58695e39 feat(sdk): SlidingSyncListInner::update_request_generator_state returns a Result.
Before, the `update_request_generator_state` method was emitting an
`error!` log, but not an error. But that's clearly an error!

This patch updates the method to return a `Result<(), Error>`, and adds
a new variant to `Error`.
2023-03-22 16:40:06 +01:00
Ivan Enderlin f5ba7ddc4a fix(sdk): Prevent bugs, remove expensive clones, and simplify SlidingSyncList
fix(sdk): Prevent bugs, remove expensive clones, and simplify `SlidingSyncList`
2023-03-22 16:39:30 +01:00
Ivan Enderlin 7052e9ff64 doc(sdk): Fix typos. 2023-03-22 16:38:45 +01:00
Ivan Enderlin 8796bfe874 doc(sdk): Fix typos. 2023-03-22 16:16:33 +01:00
Ivan Enderlin 9e7c6c3632 feat(sdk): Remove deduplication logic from Sliding Sync
feat(sdk): Remove deduplication logic from Sliding Sync
2023-03-22 14:44:45 +01:00
Ivan Enderlin 6617e94a9d Merge pull request #1632 from Hywan/doc-sdk-sliding-sync
doc(sdk): Rephrase the Quick refreshing Section
2023-03-22 14:19:46 +01:00
Ivan Enderlin 7e8c8b1a14 chore(sdk): Make Clippy happy. 2023-03-22 13:31:48 +01:00
Ivan Enderlin 9078a30e28 chore(sdk): Move code around, and remove pub on fields of a private struct. 2023-03-22 13:17:52 +01:00
Ivan Enderlin 485ca402f4 test: Use available setter. 2023-03-22 13:17:52 +01:00
Ivan Enderlin d41293879a test(sdk): Move tests from list/request_generator.rs to list/mod.rs. 2023-03-22 13:17:52 +01:00
Ivan Enderlin d5babfbb88 test(sdk): Test SlidingSyncList::(set_)timeline_limit. 2023-03-22 13:17:52 +01:00
Ivan Enderlin b842b2f96d feat(sdk): Add getters and setters on SlidingSyncList. 2023-03-22 13:17:52 +01:00
Ivan Enderlin 32e83a942d fix(sdk): Prevent bugs, remove expensive clones, and simplify SlidingSyncList.
There are problems with `SlidingSyncListRequestGenerator`:

* It's part of the module API,
* It contains a clone of `SlidingSyncList`.

To create a `SlidingSyncListRequestGenerator`, one has to
call `SlidingSyncList::request_generator`. It was done in
`SlidingSync::stream`. The problem is that it clones `SlidingSyncList`.
So theoritically it is possible to create multiple request generators
for the _same_ list, and use them to send many requests and to update
the _same_ list with multiple responses. This is utterly error-prone and
can lead to really complex bugs to discover.

Moreover, it's a lot of clones. Cloning a
`SlidingSyncListRequestGenerator` isn't cheap as it means cloning a
`SlidingSyncList`. Moreover, cloning a `SlidingSyncList` isn't cheap as
it means cloning the entire struct.

Having `SlidingSyncListRequestGenerator` inside the module API also
makes the code of `SlidingSync` more complex (why having to deal with
lists and request generators at the same time? we must be very careful
to maintain both side by side? what if a list is removed but not its
request generator? and so on).

So. This patch simplifies all that.

First off, it extracts all the fields of `SlidingSyncList` into a
`SlidingSyncListInner` struct. Then, `SlidingSyncList` has only one
field: `Arc<SlidingSyncListInner>`. Boom, it's now cheap to clone it.

Second, `SlidingSyncListRequestGenerator` is only a
struct with constructors, but there is no extra methods.
`SlidingSyncListRequestGenerator` _no longer_ contains a
`SlidingSyncList`, and doesn't no need a list at all to work. It's just
values.

Third, `SlidingSyncList` holds a `SlidingSyncListRequestGenerator`, and
only one.

Fourth, `SlidingSyncList` (and `SlidingSyncListInner`) now has methods
to handle the internal request generator. The initial `impl Iterator for
SlidingSyncListRequestGenerator` becomes a simple
`SlidingSyncList::next_request` method.

Fifth, previously, the `SlidingSyncList::handle_response`
was never called directly by `SlidingSync`. It was called by
`SlidingSyncListRequestGenerator`! How confusing! `SlidingSync` called
`SlidingSyncListRequestGenerator::handle_response` which was calling
`SlidingSyncList::handle_response`. Now, the flow is more natural:
`SlidingSync` calls `SlidingSyncList::handle_response` and that's it.

Sixth, the `SlidingSyncList::handle_response` is now composed of 2
parts: updating the list itself, and updating the request generator. It
was kind of the case before, but onto two different types.
It was unclear which types were updating `SlidingSyncList`.
For example, `SlidingSyncList::state` was updated by…
`SlidingSyncListRequestGenerator`. Now `SlidingSyncList` is responsible
to update itself, and no one else.

Finally, `SlidingSync` no longer have to deal with
`SlidingSyncListRequestGenerator`. All it has is a set of
`SlidingSyncList`, and that's it!

The tests are still passing, hurray.
2023-03-22 13:17:50 +01:00
Ivan Enderlin d81e6a18f9 chore(sdk): Format a comment. 2023-03-22 13:15:50 +01:00
Ivan Enderlin e514415642 test(sdk): Write test suites for SlidingSyncList and siblings
test(sdk): Write test suites for `SlidingSyncList` and siblings
2023-03-22 12:29:27 +01:00
Ivan Enderlin d9096cc64c chore(sdk): Make Clippy happy. 2023-03-22 12:14:04 +01:00
Ivan Enderlin f085289d05 chore(sdk): Make Clippy happy. 2023-03-22 11:37:51 +01:00
Damir Jelić ef81168434 Fix some doc links in the send_attachment docs 2023-03-22 11:36:02 +01:00
Ivan Enderlin 1f04353668 test(sdk): Use vector! from imbl, not im. 2023-03-22 11:20:07 +01:00
Alfonso Grillo f70b6f5ecf Expose 'search users' to UniFFI (#1689) 2023-03-22 11:15:03 +01:00
Ivan Enderlin ee7dc2a7ab chore(sdk): Address PR feedback. 2023-03-22 11:06:21 +01:00
Ivan Enderlin 1256052134 chore(sdk): Clean up. 2023-03-22 11:06:21 +01:00
Ivan Enderlin 28eebe2043 doc(sdk): Explain what SlidingSyncList::handle_response does and does not. 2023-03-22 11:06:21 +01:00
Ivan Enderlin bb54ff7991 chore(sdk): Move and document the SlidingSyncList::request_generator method. 2023-03-22 11:06:21 +01:00
Ivan Enderlin aa75d02ae3 feat(sdk): SlidingSyncList::handle_response must be pub(self).
This method must be only visible to the current module, not from the
upper/super module.

Note: `pub(self)` is equivalent to no `pub` at all.
2023-03-22 11:06:21 +01:00
Ivan Enderlin eefef9a81b test(sdk): Move test to appropriate files. 2023-03-22 11:06:21 +01:00
Ivan Enderlin 15646ec1d6 test(sdk): Fix how TimelineEvent is constructed. 2023-03-22 11:06:21 +01:00
Ivan Enderlin 10380596cd chore(sdk): Format a comment. 2023-03-22 11:06:21 +01:00
Ivan Enderlin c4df1cb9aa chore(sdk): Rename an argument. 2023-03-22 11:06:21 +01:00
Ivan Enderlin c509b6c76a test(sdk): Add tests for SlidingSyncList.set_range, add_range and reset_ranges. 2023-03-22 11:06:21 +01:00
Ivan Enderlin 9c2e2238ed test(sdk): Add a test for SlidingSyncList::ranges. 2023-03-22 11:06:21 +01:00
Ivan Enderlin 2edb5d845e feat(sdk): SlidingSyncList.ranges & co. takes a Into<UInt>.
In `SlidingSyncListBuilder`, the `ranges`, `set_range`, and `add_range`
methods do not take a `u32` but a `U: Into<UInt>`. That's great!

However, in `SlidingSyncList`, the same methods take a `u32`. It makes
the API inconsistent.

This patch fixes that.
2023-03-22 11:06:18 +01:00
Ivan Enderlin 147e5f8f03 fix(sdk): Rename SlidingSyncList.set_ranges to ranges.
This patch renames `SlidingSyncList.set_ranges` to `ranges` so that
it matches the same terminology of the `SlidingSyncListBuilder` with
`ranges`, `set_range`, `add_range` and `reset_ranges`.

Consistency is important here.
2023-03-22 10:59:23 +01:00
Ivan Enderlin 8e9cabcbf9 test(sdk): Add test for SlidingSyncList::new_builder. 2023-03-22 10:59:23 +01:00
Ivan Enderlin 42af266806 fix(sdk): Fix SlidingSyncList::new_builder.
The `SlidingSyncList::new_builder` method creates a new builder from a
`SlidingSyncList`. This method was missing some configurations, like
`full_sync_maximum_numbre_of_rooms_to_fetch`, `send_updates_for_items`,
`filters`, `ranges` and `timeline_limit`.

This patchs adds those missing configurations.
2023-03-22 10:59:23 +01:00
Ivan Enderlin 7a1fb0b368 fix(sdk): Remove useless fields on SlidingSyncListBuilder.
The `SlidingSyncListBuilder` struct has a `state` and a `rooms_list`
fields. Those fields are never updated and no setters or getters exist
to use them. There are just set with defaults, and passed to the final
`SlidingSyncList` type within the `build` method.

If a field is present in a builder type, it means they can be modified,
but it's not the case. So this patch removes them.
2023-03-22 10:59:17 +01:00
Ivan Enderlin 3f72b10831 test(sdk): Write a test case for FrozenSlidingSyncList when serialized. 2023-03-22 10:58:40 +01:00
Ivan Enderlin 6bd95057b6 test(sdk): Write a test case for RoomListEntry when serialized. 2023-03-22 10:58:40 +01:00
Ivan Enderlin 859317a0f6 test(sdk): Write test suites for SlidingSyncState and SlidingSyncMode. 2023-03-22 10:58:40 +01:00
Ivan Enderlin ace3ff3754 test(sdk): Write test suites for RoomListEntry. 2023-03-22 10:58:40 +01:00
Ivan Enderlin 60b627c2ca feat(sdk): Rename RoomListEntry.freeze to .freeze_by_ref. 2023-03-22 10:58:40 +01:00
Ivan Enderlin 41615840dc feat(sdk): Remove deduplication logic from Sliding Sync.
Event deduplication is supposed to be handled by the `Timeline`. Sliding
Sync is not responsible to de-duplicate the events, in our model. Having
two different de-duplication logics (one in Sliding Sync, and one in the
Timeline) could create weird situations, and hard to debug issues.

We give it a try by removing the deduplication from Sliding Sync.
2023-03-22 10:53:23 +01:00
Ivan Enderlin d07b389f4b chore(sdk): Rename some variables. 2023-03-22 10:52:56 +01:00
Damir Jelić b2a35fc9cf Merge branch 'main' into valere/msc_2399 2023-03-21 16:41:55 +01:00
Damir Jelić 900a4f848c Don't log verification requests as sent if the request id doesn't match 2023-03-21 15:57:16 +01:00
Damir Jelić c4d73c9901 fixup! Don't send m.no_olm withheld codes out if another session is doing so 2023-03-21 15:56:58 +01:00
Damir Jelić eb9dd8fb0d Don't send m.no_olm withheld codes out if another session is doing so
The `m.no_olm` withheld code is supposed to be sent out only once for a
given device.

This patch prevents double sending of m.no_olm withheld code by adding
a test that ensures only one group session will send it out.

Previously, the logic for sharing group sessions was mostly correct, but
an edge case was forgotten where two group sessions attempted to share
the withheld code concurrently.

Although there's still a possibility for multiple m.no_olm withheld codes
to be sent out. This may happen during the propagation of the flag
remembering the fact that the `m.no_olm` code has been sent from the
OutboundGroupSession to Device. This scenario is likely unrealistic and
the consequences of sending things twice aren't problematic.
2023-03-21 15:45:32 +01:00
Jonas Platte a134cc378d Sort sliding-sync-integration-test dependencies 2023-03-21 13:31:58 +01:00
Jonas Platte a32fce6cdf Make all sliding-sync-integration-test dependencies dev-dependencies 2023-03-21 13:31:58 +01:00
Jonas Platte 9ee2d04a41 Feature-gate everything in sliding-sync-integration-test 2023-03-21 12:24:14 +01:00
Mauro 1ce1c5636e Add support for (un)ignoring users 2023-03-21 12:23:17 +01:00
Damir Jelić 8652cdf752 Test the VerificationState migration 2023-03-21 12:02:31 +01:00
Damir Jelić 32e2ea0288 Allow the old VerificationState enum to be deserialized into the new one 2023-03-21 12:02:31 +01:00
Damir Jelić 7263914f67 Remove the Apple specific auth service tests
These tests are doing real network requests towards hosts that are not
under our control.
2023-03-21 12:00:43 +01:00
Florian Renaud 76763a80fe ffi: Add binding for get_dm_room 2023-03-20 16:30:25 +00:00
Jonas Platte 72ae9dd885 Upgrade eyeball-im 2023-03-20 16:51:28 +01:00
Jonas Platte 816e722807 ffi: Inline uniffi_api modules
include_scaffolding! is expected to be used at the crate root now, and
clippy seems happy with the generated code right now.
2023-03-20 15:42:38 +01:00
Jonas Platte 1a1fe97d00 Use Rust conventions for variable names in UDL 2023-03-20 15:42:38 +01:00
Jonas Platte 16687f24f9 sdk: Fix documentation of create_room 2023-03-20 13:56:43 +01:00
Jonas Platte ea41076c82 sdk: Rename create_dm_room to create_dm and make it public 2023-03-20 13:56:43 +01:00
Jonas Platte 130dc58a5d Remove redundant cfg attributes
The whole encryption module is only enabled with e2e-encryption.
2023-03-20 13:56:43 +01:00
Jonas Platte 9d6e192b9f sdk: Move create_dm_room out of encryption module
Creating DM rooms makes sense for non-encryption-capable client as well.
2023-03-20 13:56:43 +01:00
Jonas Platte 82d1d64f85 sdk: Simplify create_dm_room
It doesn't need to call mark_as_dm itself as create_room will do that.
2023-03-20 13:56:43 +01:00
Jonas Platte 39a4dc911f Remove event contents from (Sync)TimelineEvent Debug impls 2023-03-20 13:21:41 +01:00
Alfonso Grillo a7ed8e0b45 Update account_data when creating a new dm room 2023-03-20 12:08:21 +01:00
Ivan Enderlin e64ab6cf9c Merge pull request #1677 from matrix-org/rav/update-js-bindings-prefix
matrix-sdk-crypto-js: drop `v` from release tags
2023-03-20 09:23:29 +01:00
Damir Jelić 43d883da9c Refactor the room key sharing logic 2023-03-16 19:40:30 +01:00
Richard van der Hoff 42dce635de matrix-sdk-crypto-js: drop v from release tags
Currently, the tags used for releases of this binding have the format:
"matrix-sdk-crypto-js-v0.1.0-alpha.5". This is inconsistent with tags used for
other parts of the project, which omit the `v` prefix.
2023-03-16 17:49:52 +00:00
Richard van der Hoff 7794b230e1 Merge pull request #1675 from matrix-org/release-matrix-sdk-crypto-js-v0.1.0-alpha.5
matrix-sdk-crypto-js: prepare v0.1.0-alpha.5
2023-03-16 17:38:33 +00:00
Ivan Enderlin 2d56f550aa fix(sdk): Fix, test, and clean up SlidingSyncListRequestGenerator
fix(sdk): Fix, test, and clean up `SlidingSyncListRequestGenerator`
2023-03-16 17:04:05 +01:00
Ivan Enderlin b39a224be8 doc(sdk): Use the Rust range notation to avoid ambiguity. 2023-03-16 17:03:25 +01:00
Richard van der Hoff e6bf74b7db matrix-sdk-crypto-js v0.1.0-alpha.5
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 41s
2023-03-16 13:47:55 +00:00
Ivan Enderlin 5f06dc8229 doc(sdk): Fix a typo. 2023-03-16 11:53:01 +01:00
Kévin Commaille 46d8d26b71 sdk: Fix a typo
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-16 11:40:47 +01:00
Kévin Commaille e23be44345 sdk: Store OIDC issuer as a String rather than a Url
The url crate normalizes the string, but during OIDC verification steps,
the issuer verification must be made against the exact string that was
provided.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-16 11:40:47 +01:00
Ivan Enderlin 57fb659b86 Merge pull request #1666 from zecakeh/indexeddb-crypto-version
indexeddb: Use u32 to represent version of crypto store
2023-03-16 11:12:27 +01:00
Ivan Enderlin 1933fe7a8f doc(sdk): Fix a typo. 2023-03-16 11:04:18 +01:00
Ivan Enderlin 6a6d94a065 Re-expose the vodozemac and matrix-sdk-crypto versions in the bindings
Re-expose the vodozemac and matrix-sdk-crypto versions in the bindings
2023-03-16 10:56:51 +01:00
Ivan Enderlin ccfb66c576 chore(crypto-nodejs): Fix a lint. 2023-03-16 10:39:43 +01:00
Ivan Enderlin c2d3afffff feat(crypto-nodejs): Make Versions a class, not a JS object. 2023-03-16 10:33:41 +01:00
Ivan Enderlin e1f6fd8a1e feat(ffi): Create the version and vodozemac_version functions. 2023-03-16 09:53:39 +01:00
Damir Jelić 2f377d536a fixup! Re-expose the vodozemac and matrix-sdk-crypto versions in the bindings 2023-03-16 09:53:39 +01:00
Damir Jelić 26789f22b0 fixup! Re-expose the vodozemac and matrix-sdk-crypto versions in the bindings 2023-03-16 09:53:39 +01:00
Damir Jelić 3aa1c30f5c Re-expose the vodozemac and matrix-sdk-crypto versions in the bindings 2023-03-16 09:53:37 +01:00
Ivan Enderlin 5e23bd09bc feat(ci): aarch64-apple-ios should work on rustc stable. 2023-03-16 09:01:14 +01:00
Ivan Enderlin c8bad4b86e doc(sdk): Fix a typo. 2023-03-16 08:55:25 +01:00
Ivan Enderlin 07c366983d doc(sdk): Fix a typo. 2023-03-16 08:24:05 +01:00
Ivan Enderlin 51abedda59 feat(ffi): Update SlidingStateState variants. 2023-03-16 08:21:11 +01:00
Ivan Enderlin 9d5a1fda3c doc(sdk): Fix typos or improve. 2023-03-16 08:11:45 +01:00
Damir Jelić 61ea15eb39 Merge branch 'main' into valere/msc_2399 2023-03-15 19:31:04 +01:00
Kévin Commaille fe69948926 sdk: Add a method to change the room name
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-15 17:28:08 +00:00
Valere 248b8db309 Extended verification states
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
2023-03-15 18:16:31 +01:00
Ivan Enderlin ca5cabb7e1 doc(sdk): Fix a typo. 2023-03-15 18:08:19 +01:00
Ivan Enderlin 7a2b1e6e1f doc(sdk): Fix a typo. 2023-03-15 17:59:11 +01:00
Ivan Enderlin c0f84bb8da test(sdk): Fix tests and improve speed.
To improve the speed, we simply reduce the numbers of rooms involved in
the test.
2023-03-15 17:54:39 +01:00
Kévin Commaille 9a9b142630 indexeddb: Use u32 to represent version of crypto store
Like for the state store, the bindings expose the version as an f64
while the web API expects an unsigned integer.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-15 17:08:33 +01:00
Ivan Enderlin a2dcfa905f fix(sdk): Fix, test, and clean up SlidingSyncList.
This patch should ideally be split into multiple smaller ones, but life
is life.

This main purpose of this patch is to fix and to test
`SlidingSyncListRequestGenerator`. This quest has led me to rename
mutiple fields in `SlidingSyncList` and `SlidingSyncListBuilder`, like:

* `rooms_count` becomes `maximum_number_of_rooms`, it's not something
  the _client_ counts, but it's a maximum number given by the server,

* `batch_size` becomes `full_sync_batch_size`, so that now, it
  emphasizes that it's about full-sync only,

* `limit` becomes `full_sync_maximum_number_of_rooms_to_fetch`, so that
  now, it also emphasizes that it's about ful-sync only _and_ what the
  limit is about!

This quest has continued with the renaming of the `SlidingSyncMode`
variants. After a discussion with the ElementX team, we've agreed on the
following renamings:

* `Cold` becomes `NotLoaded`,
* `Preload` becomes `Preloaded`,
* `CatchingUp` becomes `PartiallyLoaded`,
* `Live` becomes `FullyLoaded`.

Finally, _le plat de résistance_.

In `SlidingSyncListRequestGenerator`, the `make_request_for_ranges`
has been renamed to `build_request` and no longer takes a `&mut self`
but a simpler `&self`! It didn't make sense to me that something
that make/build a request was modifying `Self`. Because the type of
`SlidingSyncListRequestGenerator::ranges` has changed, all ranges now
have a consistent type (within this module at least). Consequently, this
method no longer need to do a type conversion.

Still on the same type, the `update_state` method is much more
documented, and errors on range bounds (offset by 1) are now all fixed.

The creation of new ranges happens in a new dedicated pure function,
`create_range`. It returns an `Option` because it's possible to not be
able to compute a range (previously, invalid ranges were considered
valid). It's used in the `Iterator` implementation. This `Iterator`
implementation contains a liiiittle bit more code, but at least now
we understand what it does, and it's clear what `range_start` and
`desired_size` we calculate. By the way, the `prefetch_request` method
has been removed: it's not a prefetch, it's a regular request; it was
calculating the range. But now there is `create_range`, and since it's
pure, we can unit test it!

_Pour le dessert_, this patch adds multiple tests. It is now
possible because of the previous refactoring. First off, we test the
`create_range` in many configurations. It's pretty clear to understand,
and since it's core to `SlidingSyncListRequestGenerator`, I'm pretty
happy with how it ends. Second, we test paging-, growing- and selective-
mode with a new macro: `assert_request_and_response`, which allows to
“send” requests, and to “receive” responses. The design of `SlidingSync`
allows to mimic requests and responses, that's great. We don't really
care about the responses here, but we care about the requests' `ranges`,
and the `SlidingSyncList.state` after a response is received. It also
helps to see how ranges behaves when the state is `PartiallyLoaded`
or `FullyLoaded`.
2023-03-15 16:57:29 +01:00
Kévin Commaille 1e1e0d7e6d ci: Make sure all rendered docs examples are compiling
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-15 14:42:12 +01:00
Kévin Commaille 5d1a738162 sdk: Fix generate_image_thumbnail example in docs
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-15 14:42:12 +01:00
Jonas Platte e4e9efb7d9 ffi: Put CreateRoomParameters back into the UDL file
… to restore the default values of some fields.
2023-03-15 13:09:54 +01:00
Doug b1074e400e sdk: Add get_media_file function 2023-03-15 09:22:53 +00:00
Ivan Enderlin 9574f93320 feat(sdk): Add more Sliding Sync logs
feat(sdk): Add more Sliding Sync logs
2023-03-15 09:58:02 +01:00
Ivan Enderlin c3bcbf8952 chore(sdk): Rephrase logs a little bit. 2023-03-15 09:41:39 +01:00
Jonas Platte 739dd8cf93 Fix clippy complaint 2023-03-14 18:34:23 +01:00
Jonas Platte c7e1d617ec ffi: Use UniFFI derives for types no longer referenced in UDL 2023-03-14 18:34:23 +01:00
Jonas Platte ae85e18588 ffi: Use UniFFI proc-macros for more Client methods 2023-03-14 18:34:23 +01:00
Damir Jelić 516d849ef2 Allow room key forwarding to be enabled and disabled (#1365)
Co-authored-by: Ivan Enderlin <ivan@mnt.io>
2023-03-14 18:23:39 +01:00
Damir Jelić eb2bf61236 Merge pull request #1657 from matrix-org/poljar/session-creator-info
Improve the docs of the inbound group session type
2023-03-14 17:33:24 +01:00
Damir Jelić 0985043a6a Apply suggestions from code review
Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
2023-03-14 17:01:03 +01:00
Damir Jelić 36b739b830 Improve the docs of the inbound group session type 2023-03-14 15:50:03 +01:00
Doug eeea4f23bc fix(bindings): More authentication service server name fixes
- Trim any trailing slashes
- If server name parsing fails, try as a URL instead of throwing
- Add tests
- Fix typo & clippy
2023-03-14 14:40:19 +00:00
Alfonso Grillo c9a6898c73 Add a guide for contributing to UniFFI bindings 2023-03-14 15:39:09 +01:00
Damir Jelić 18c33aefa1 Merge pull request #1633 from matrix-org/rav/fix_wait_if_user_pending
Fix races in `wait_if_user_pending`
2023-03-14 14:59:20 +01:00
Damir Jelić 2c7c251e47 Silence an invalid clippy warning 2023-03-14 14:45:19 +01:00
Damir Jelić f3ee6c735b Fix some formatting issue where cargo fmt failed to take care of things 2023-03-14 14:28:34 +01:00
Damir Jelić 4f9cb48ef8 Use a Display implementation to record the SequenceNumber in logs 2023-03-14 14:28:27 +01:00
Damir Jelić 9880619d81 Merge branch 'main' into rav/fix_wait_if_user_pending 2023-03-14 14:26:28 +01:00
Mauro a8204987be Add convenience methods for updating a room's avatar 2023-03-14 13:03:52 +00:00
Kévin Commaille cc585974e0 sdk: Get push actions of events received via back pagination
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-14 14:02:01 +01:00
Kévin Commaille aebd5fe4eb sdk: Fix timeline highlight test
Update Ruma to fix the server default push rules.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-14 14:02:01 +01:00
Mauro 7ab134233e bindings: Set pusher from client + notification service stub
Co-authored-by: ismailgulek <ismailg@matrix.org>
2023-03-14 13:36:36 +01:00
Kévin Commaille 0f54877b31 feat(sdk): Add methods to only send receipts newer than the current ones in the timeline
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-14 13:32:30 +01:00
Kévin Commaille 1c9aa7c907 refactor(sdk): Add private method to get the fully-read event for a timeline.
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-14 13:32:30 +01:00
Damir Jelić 4041c875d1 Merge pull request #1460 from matrix-org/andy/enhance_store
Store encryption settings
2023-03-14 12:36:42 +01:00
Andy Uhnak d226738d15 More pub(crate) methods 2023-03-14 10:43:40 +00:00
Andy Uhnak 404b95ab84 Missing migration method in UDL 2023-03-14 10:28:41 +00:00
Andy Uhnak 0d082f6b96 Update js tests 2023-03-14 10:28:15 +00:00
Andy Uhnak 5bf9182549 Fix issues after rebase 2023-03-14 10:28:15 +00:00
Andy Uhnak 1177bdd394 Indexdb migration 2023-03-14 10:28:15 +00:00
Andy Uhnak 98ca774118 Constrain store methods 2023-03-14 10:28:12 +00:00
Andy Uhnak 8f13023333 Missing stores 2023-03-14 10:27:11 +00:00
Andy Uhnak 51b3bf4c75 Add room settings migration 2023-03-14 10:27:11 +00:00
Andy Uhnak 283137f190 Introduce RoomSettings 2023-03-14 10:27:11 +00:00
Andy Uhnak 33b348c376 Constrain new api to Store struct 2023-03-14 10:27:11 +00:00
Andy Uhnak 7e7c91699f Generic key-value API 2023-03-14 10:27:11 +00:00
Andy Uhnak b4b111f91f Store encryption settings 2023-03-14 10:27:11 +00:00
Jonas Platte 0f7d839c49 Undo room_type => room_state rename in serialized form of RoomInfo 2023-03-13 16:45:44 +01:00
Jonas Platte ee6c0d9486 Simplify TimelineEvent construction 2023-03-13 16:31:19 +01:00
Jonas Platte 7121179b6a sdk: Make test code less repetitive 2023-03-13 16:31:19 +01:00
Jonas Platte 59edc22a35 Use Action covenience methods
Now Action::Coalesce will also generate a notification.
2023-03-13 16:31:19 +01:00
Jonas Platte e9058f58be Upgrade Ruma 2023-03-13 16:31:19 +01:00
Jonas Platte 7dee9648cf sdk: Clone VerificationRequest twice in generate_qr_code method again
… required for the returned Future to be Send.
2023-03-13 15:34:14 +01:00
Alfonso Grillo 786e9b5db9 Add createRoom UniFFI binding 2023-03-13 15:33:18 +01:00
valere e20db574ec Merge branch 'main' into valere/msc_2399 2023-03-13 14:51:23 +01:00
Ivan Enderlin c6c259144a chore(sdk): Rename enum variants to be consistent across all the modules. 2023-03-13 14:29:12 +01:00
Damir Jelić 58e99a645f Don't use a type alias for the sequence number
Using a wrapper type allows us to hide the internals a bit better and
we're now implementing Ord which is used in the comparison.
2023-03-13 14:17:12 +01:00
Damir Jelić 5d6cf2d33a Remove some clones when creating a /keys/query request
The part of code that converts a list of users to the actual
/keys/query request uses the chunks() method. This method operates on
the slice. Our list/vec of users gets dereferenced into a slice before
we create our chunks. The chunks can't take ownership of the data, which
in turn requires us to clone the user IDs for them to be put into the
request.

Itertools has a chunks() method which operates on an iterator which we
can utilize to remove, not only the clone, but also a collect call.

At the same time, let's make the conversion step a simple functional
mapping and document what's going on.
2023-03-13 14:17:12 +01:00
Damir Jelić 5f1a22e26f Remove some useless ? -> Ok invocations
We can just return the result directly instead of doing the error
conversion dance using the question mark operator
2023-03-13 14:17:12 +01:00
Damir Jelić 6afb6f1e27 Use an Option for the KeysQueryDetails instead of a default value
The Option conveys our intention a bit better compared to the default
value. While nothing bad can happen, since the request IDs map will be
empty by default, it's a bit scary to have a valid sequence number since
an i64 defaults to 0.
2023-03-13 14:17:12 +01:00
Ivan Enderlin 032356566e chore(sdk): Rewrite a small part of the code to make it clearer. 2023-03-13 14:07:36 +01:00
Ivan Enderlin d7468ec158 Update crates/matrix-sdk/src/sliding_sync/mod.rs
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
2023-03-13 13:49:21 +01:00
Kévin Commaille 929538608a timeline: Expose if an event should be highlighted
Only events received via sync.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-13 13:47:06 +01:00
Kévin Commaille d5a56bcbc7 sdk: Expose calculated push actions for event handlers
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-13 13:47:06 +01:00
Kévin Commaille 84ff8980f3 sdk-base: Expose calculated push actions on event
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-13 13:47:06 +01:00
Jonas Platte 84d83dda0a base: Add RoomInfo::state accessor 2023-03-13 13:17:15 +01:00
Jonas Platte fb4b347433 base: Rename RoomType to RoomState 2023-03-13 13:17:15 +01:00
Richard van der Hoff e1c6ac9787 Merge branch 'main' into rav/fix_wait_if_user_pending 2023-03-13 11:52:11 +00:00
Ivan Enderlin 35bb18a1e8 feat(sdk): Add more Sliding Sync logs.
This patch adds more logs around `SlidingSync` to ease debugging sessions.
2023-03-13 11:41:20 +01:00
Ivan Enderlin 483bef0748 Merge pull request #1645 from Hywan/fix-sdk-fixme 2023-03-13 11:21:17 +01:00
Ivan Enderlin 3c25ad1489 doc(sdk): Remove a FIXME that is actually fixed.
The #1386 issue is closed. Yepee.
2023-03-13 09:05:32 +01:00
Jonas Platte 8d83a996a6 Handle another new clippy lint
Issue about false positives:
https://github.com/rust-lang/rust-clippy/issues/10482
2023-03-11 13:13:50 +01:00
Jonas Platte 595e34aad5 Silence new clippy lint for generated code 2023-03-11 13:13:50 +01:00
Jonas Platte cc35ee72b8 Upgrade eyeball to 0.4.0 2023-03-11 13:13:50 +01:00
Jonas Platte b148ea2fb1 Bump locked version of clap
To work around this clippy bug:
https://github.com/rust-lang/rust-clippy/issues/10421
2023-03-11 13:13:50 +01:00
Mauro 2bb66f0f2e bindings: Expose leave and reject_invitation functions to FFI 2023-03-10 18:07:13 +01:00
valere 8057a3691f unused import 2023-03-10 16:00:22 +01:00
valere 057cf0bde7 unneeded trait impl 2023-03-10 08:57:56 +01:00
valere c43d9d3e43 post rebase fix 2023-03-09 17:27:34 +01:00
Ivan Enderlin 331ea35be6 fix(sdk): SlidingSync has a lock for both pos _and_ delta_token
fix(sdk): `SlidingSync` has a lock for both `pos` _and_ `delta_token`
2023-03-09 17:10:42 +01:00
Richard van der Hoff fc9dbae23b fixup! Rewrite wait_if_user_pending to fix races 2023-03-09 16:06:37 +00:00
valere 9733d9842a Merge branch 'main' into valere/msc_2399 2023-03-09 17:04:21 +01:00
Ivan Enderlin b9fd451d54 feat(sdk): Move Client.root_span inside ClientInner
feat(sdk): Move `Client.root_span` inside `ClientInner`
2023-03-09 17:03:27 +01:00
Ivan Enderlin 3511a4a053 fix(sdk): SlidingSync has a lock for both pos _and_ delta_token.
This patch updates `SlidingSync.pos` and `.delta_token`. Each field has their
own lock. It's annoying because they must updated at the same time to not be
out-of-sync.

So a new field `SlidingSync.position` of type `SlidingSyncPositionMarkers` is
created. It holds `pos` and `delta_token. This new field is behind a single
`RwLock`.
2023-03-09 16:47:11 +01:00
Ivan Enderlin 7f52292e92 chore(sdk): Remove useless comment. 2023-03-09 16:43:41 +01:00
valere 980c9cb4f5 report partially withheld error as MissingRoomKey 2023-03-09 16:39:02 +01:00
valere 2368ac74de feat(withheld) expose withheld code in error binding 2023-03-09 16:38:38 +01:00
Ivan Enderlin cc69efc3f8 feat(sdk): Move Client.root_span inside ClientInner. 2023-03-09 15:12:11 +01:00
Richard van der Hoff 5a06c11ac0 Move UserKeyQueryResult to store
Now that `wait_if_user_key_query_pending` is in Store, it makes more sense that
the result type be in the same module.
2023-03-09 13:11:34 +00:00
Richard van der Hoff d2fdc20733 Rip out redundant KeysQueryListener 2023-03-09 13:11:34 +00:00
Richard van der Hoff 16871d1dcd Rewrite wait_if_user_pending to fix races 2023-03-09 13:11:34 +00:00
Richard van der Hoff 508f1bc976 Fix races between /sync and /keys/queries (#1619)
The comments in the code should explain the general approach, but to give an overview:

We assign a unique sequence number to each device-list-invalidation notice, and keep track 
of the sequence number at which each user was most recently invalidated. Then, when we 
build a `/keys/query` request, we take note of the current sequence number. Finally, when 
we get the response from that `/keys/query` request, we compare that sequence number
with the most-recent-invalidation of each user that is now supposedly up-to-date. All 
of that means that we can see if the user has been invalidated *since* we built the 
`/keys/query` request, in which case our request may have raced against the new device,
so we do not mark the user as up-to-date.

To make that work, we need to keep track of the sequence number for in-flight `/keys/query`
requests; we do that in the `IdentityManager`. Since there should only ever be at most one
batch of requests in flight, that is relatively easy; however, we also record the request ids
just to check that the application isn't doing something weird.

There is no need to persist the sequence numbers to permanent storage: provided the
`IdentityManager` and `Store` objects have a lifetime at least as long as an in-flight
`/keys/query` request, it is sufficient just to retain the `dirty` bit in permanent storage,
and then, when we reload the ephemeral `Store` cache, to treat everything with a `dirty`
bit as a "new" invalidation.

Fixes: #1386.
2023-03-09 10:57:20 +00:00
Ivan Enderlin 0419967158 doc(sdk): Rephrase the Quick refreshing Section.
With https://github.com/matrix-org/matrix-rust-sdk/pull/1601, it's safer to
cancel a stream at any time, as any `Future` cancellation. This documentation
section of `SlidingSync` is no longer relevant as is, and can be rephrased.
2023-03-09 11:56:33 +01:00
Ivan Enderlin da5c79482b feat(ffi): Rethink TaskHandle
feat(ffi): Rethink `TaskHandle`
2023-03-08 17:21:52 +01:00
Ivan Enderlin 4996a19b31 feat(ffi): Rethink TaskHandle.
With https://github.com/matrix-org/matrix-rust-sdk/pull/1601,
`TaskHandle::with_callback` is no longer necessary.

This patch updates `TaskHandle` as follows:

1. Before, the `handle` and `callback` fields were not mutually exclusive!
   Indeed, the `callback` field was used as an abort mechanism, but _also_ as a
   finalizer, i.e. a code that runs _after_ the cancellation of `handle`. Now
   that the callback-based solution is no longer used, we can keep one usage for
   this field and rename it `finalizer`.
2. The `handle` field is no longer optional, as it will always be set.
3. The `with_callback` method is renamed `new` as it's now the only constructor.
4. The `set_callback` method is renamed `set_finalizer`.

Tadaaa.
2023-03-08 17:09:47 +01:00
Ivan Enderlin d720861fbd fix(bindings): SlidingSync.sync returns an immediately cancellable TaskHandle
fix(bindings): `SlidingSync.sync` returns an immediately cancellable `TaskHandle`
2023-03-08 16:39:09 +01:00
Ivan Enderlin c517f38ec8 sliding-sync: process receipt extension response
sliding-sync: process receipt extension response
2023-03-08 16:29:56 +01:00
Ivan Enderlin ac863409bb doc(sdk): Remove notion of fairness. 2023-03-08 16:20:50 +01:00
Kegan Dougal 417008cc87 Clippy 2023-03-08 15:14:59 +00:00
Ivan Enderlin 5dd404d2f1 doc(sdk): Precise in which order SS responses will be handled. 2023-03-08 16:09:05 +01:00
Kegan Dougal 2c0466a8cc Unbreak tests; don't shadow 2023-03-08 15:03:41 +00:00
kegsay aec65c818b Update testing/sliding-sync-integration-test/src/lib.rs
Co-authored-by: Ivan Enderlin <ivan@mnt.io>
2023-03-08 14:51:26 +00:00
Jonas Platte 0d9d130833 Replace StateStoreDataKey::encoding_key by associated constants 2023-03-08 15:51:13 +01:00
Jonas Platte 26e259455a Adhere to module naming conventions 2023-03-08 15:51:13 +01:00
Ivan Enderlin 2f637cda6f doc(sdk): Add note about fairness of the SS lock. 2023-03-08 15:33:40 +01:00
Ivan Enderlin 64ae77ec70 feat(sdk): Run SS response handling in a single non-cancellable block. 2023-03-08 15:15:16 +01:00
Jonas Platte 932cf2ad99 Fix experimental features not compiling without encryption 2023-03-08 15:03:20 +01:00
Jonas Platte 68f8ed5a92 Add futures-util as a workspace dependency
… and always activate its `alloc` feature.
Fixes building matrix-sdk without the e2e-encryption feature.
2023-03-08 15:03:20 +01:00
Kegan Dougal 4670142a83 Clippy 2023-03-08 13:21:56 +00:00
Kegan Dougal 9a53602d73 Formatting 2023-03-08 12:58:48 +00:00
Kegan Dougal 48bf20fcca Add integration test for receipts in sliding sync 2023-03-08 12:53:23 +00:00
Mauro be6c7c8b4c Add user avatar URL caching 2023-03-08 13:30:46 +01:00
Ivan Enderlin 832146b43d feat(sdk): Create SlidingSyncInner.
Move all `SlidingSync`'s fields into a new `SlidingSyncInner` type, and then
update `SlidingSync` to contain a single `inner: Arc<SlidingSyncInner>` field.

First off, it's much simpler to understand what's behind an `Arc` for
“clonability” of `SlidingSync`, and what's not. We don't need to worry about
adding a new field that is not behind an `Arc` for a specific reason or
anything. The pattern is clear now.

Second, this is required for next commits.
2023-03-08 12:12:58 +01:00
Ivan Enderlin 66d4ced90f chore: Add some inline documentation. 2023-03-08 12:01:57 +01:00
Jonas Platte 5c2915bb6a crypto-ffi: Use uniffi derives for types no longer referenced in UDL 2023-03-08 11:12:11 +01:00
Jonas Platte fb23cbff97 crypto-ffi: Use UniFFI proc-macros for more OlmMachine methods 2023-03-08 11:12:11 +01:00
Jonas Platte 9fe880d05d Clean up formatting of olm.udl 2023-03-08 11:12:11 +01:00
Jonas Platte 7af2bea2fc Upgrade UniFFI 2023-03-08 11:12:11 +01:00
Kegan Dougal f1829faa99 Merge branch 'main' into kegan/receipts-ss 2023-03-08 09:33:48 +00:00
valere a767187ff6 add more tests 2023-03-08 10:06:46 +01:00
Ivan Enderlin 7369010964 feat(sdk): Make SlidingSync::handle_response _sync_, no more _async_.
The idea is to group all async and await points in `sync_once`. It's easier to
think about it.
2023-03-08 09:41:32 +01:00
Ivan Enderlin 07f6a3b345 chore: Remove warnings. 2023-03-08 09:35:47 +01:00
Ivan Enderlin 8f6f20bbe7 fix(bindings): SlidingSync.sync returns an immediately cancellable TaskHandle.
Before this patch, `SlidingSync::sync` was returning a callback-based
`TaskHandle`. It was waiting on the “stream loop” to finish (since it's a long-
poll, it means waiting 2*30s, cf. our code), before checking an atomic flag has
some value to decide whether it was time to leave the loop or not. So when the
user is cancelling this `TaskHandle`, a response (if any) was always handled.
But in the meantime, it was possible to start a new `sync`, and it seems like
it creates bugs.

After this patch, `SlidingSync::sync` now returns a handle-based `TaskHandle`.
It means that cancelling it will cancel the “stream loop” immediately. If
no response was in-flight from the server, that's perfect, no problem. If a
response was in-flight, the inner `pos` of the `SlidingSync` instance won't be
updated as the response won't be handled. So the server will re-send the same
response with the next sync request.

I guess it's better this way. Thoughts?
2023-03-08 09:35:47 +01:00
Ivan Enderlin 6a9cf1f9ce feat(sdk): SlidingSync::stream can match expected responses
feat(sdk): `SlidingSync::stream` can match expected responses
2023-03-08 09:14:32 +01:00
Ivan Enderlin f8ce49cc49 chore: Add documentation. 2023-03-08 08:56:38 +01:00
Ivan Enderlin 46d71acb44 chore: Update ruma to a specific revision. 2023-03-08 08:56:38 +01:00
Ivan Enderlin 9f0563eb95 feat(sdk): SlidingSync::stream can match expected responses.
This patch adds a new feature.

Each call to `SlidingSync::stream` generates a unique `stream_id`. This
`stream_id` is passed to requests as a `txn_id` field. Returned responses must
hold the same `txn_id`, otherwise it means `stream` has received unexpected
responses from another `stream` or something else.

So far, when the `txn_id` field of the response and the `stream_id` don't
match, a log with the `ERROR` level is raised. Should we do more, like ignoring
the response entirely? Not sure yet.
2023-03-08 08:56:32 +01:00
valere bd48cae28d unused import 2023-03-07 19:24:50 +01:00
valere 69749ab8fe feat(withheld) fix experimental-algorithms 2023-03-07 19:07:27 +01:00
valere 97b5a3a61b feat(withheld) cleaning 2023-03-07 19:04:44 +01:00
valere 0ec3aca727 refactor(withheld) store withheld as ShareInfo
and store no_olm sent in device
2023-03-07 18:46:52 +01:00
Kévin Commaille 18e6f10367 examples: Also handle SSO login in the login example
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-07 15:12:33 +01:00
Kévin Commaille d77efd7327 state-store: Replace methods to get and set key-value data
Avoid to make the API bigger when we want to add new key-value data
in the store.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-07 13:52:37 +01:00
Kévin Commaille 5b28c69cfc sled: Rename session store to kv
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-07 13:52:37 +01:00
Kévin Commaille 61796a2725 sled: Move state store keys into keys module
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-07 13:52:37 +01:00
Kévin Commaille f538b5e595 sled: Move the state store migrations to a separate file
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-07 13:52:37 +01:00
Kévin Commaille 4d1363e683 indexeddb: Merge session and sync_token stores into new kv store
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-07 13:52:37 +01:00
Damir Jelić 9324702b04 feat(bindings): Add a method to partially migrate data 2023-03-07 13:29:00 +01:00
Jonas Platte 0c4c73084d Appease clippy 2023-03-07 12:53:32 +01:00
Jonas Platte 6ce51b5890 Remove unnecessary allow attribute 2023-03-07 12:53:32 +01:00
Jonas Platte 3ff1844da4 base: Remove unused Deserialize implementation 2023-03-07 12:53:32 +01:00
Jonas Platte 99cbf3122b ci: Work around frequent codecov upload errors 2023-03-07 11:08:09 +01:00
Kévin Commaille e09ec389d1 indexeddb: Fix migration of state store
The IndexedDB API expects an unsigned integer for the version.
The web-sys bindings expose it as a f64 so versions like 1.1 and 1.2
were used. The were converted back to uint in JS which means the version
was always 1.0 and no real upgrade was processed

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-07 10:04:09 +01:00
Kévin Commaille 2aec3d0502 indexeddb: Move the state store migrations to a separate file
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-07 10:04:09 +01:00
Damir Jelić 2f974c11f7 Simplify handling of sliding sync extensions
Simplify handling of sliding sync extensions

This patch simplifies the logic for handling sliding sync extensions.
These extensions are sticky, meaning that once enabled in one request,
they do not need to be repeatedly enabled for subsequent requests.

However, the previous logic tried to accommodate the case where the
extensions were initially disabled to reduce the size and processing
time of the initial response. This resulted in complex and error-prone
code.

With this patch, we have removed support for disabling to-device events
and streamlined the handling of sync extensions.

Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-03-07 08:48:05 +01:00
Richard van der Hoff 79ee4b59ee matrix-sdk-crypto: enable tracing for in-crate tests 2023-03-06 19:25:47 +01:00
Jonas Platte 01a66d4874 Fix unnecessary cfg(all()) 2023-03-06 18:25:16 +01:00
valere 1ddcc97f84 refactor(withheld) collect_session_recipient result struct 2023-03-06 12:23:10 +01:00
valere c6a12304ba refactor(msc2399) avoid iterating twice on devices 2023-03-06 11:46:37 +01:00
Jonas Platte 50114f4e74 Mention changelogs in PR template 2023-03-06 10:41:18 +01:00
Jonas Platte 792b60c501 Remove most mentions of conventional commits 2023-03-06 10:41:18 +01:00
Jonas Platte d8465a2c1e Add a very basic changelog to crates/matrix-sdk 2023-03-06 10:41:18 +01:00
Damir Jelić 8550eaeed0 Make sure that syncing members is only happening if they aren't already synced 2023-03-06 10:00:00 +01:00
Damir Jelić 071ba2376e Make the majority of fields of the RoomInfo private 2023-03-06 10:00:00 +01:00
Damir Jelić 7ec98ff721 Remove a race condition when fetching members and sending out room keys 2023-03-06 10:00:00 +01:00
Florian Renaud f03f7c8d1a Fix a typo in the integration tests readme 2023-03-06 09:29:23 +01:00
Stefan Ceriu 0dd2b12141 chore(ffi): Remove now unnecessarly stored is_soft_logout session and client state property. The did_receive_auth_error(is_soft_logout) client delegate is enough. 2023-03-03 18:10:57 +01:00
Stefan Ceriu d513cb9a47 chore(ffi): remove now unused start_sync method and related properties 2023-03-03 18:10:57 +01:00
Stefan Ceriu e550c16c14 Broadcast UnknownToken API client errors, handle them on the FFI client side and send a did_receive_auth_error delegate call 2023-03-03 12:13:26 +01:00
Sam Wedgwood 0da29057f8 feat(sdk): Expose prepare_encrypted_file function
Signed-off-by: Sam Wedgwood <sam@wedgwood.dev>
2023-03-03 09:27:10 +00:00
Kegan Dougal 5881503a6a Clippy 2023-03-02 14:49:16 +00:00
kegsay e261d37756 Apply suggestions from code review
Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-03-02 14:48:00 +00:00
Richard van der Hoff a2da63758c Use a separate GHA cache for each matrix build (#1605)
You can't update a GHA cache once you create it, so if we use the same cache
for each job in a matrix build, then we end up populating it for the first job
that completes, so any slower jobs don't get their dependencies cached.

On the other hand, if we create 20 500MB cache items on each build, we're going
to exhaust the cache storage as soon as we do a build. So, instead, let's just
do the caching for the main branch, and hope that other branches can still
benefit from it.
2023-03-02 14:10:53 +00:00
Richard van der Hoff a86754a317 Minor tweaks to the github actions configurations (#1606)
* Replace custom cancellation action with `concurrency`

* Improve step names

... so don't have three steps with the same name

* Bump version of checkout action

checkout@v2 uses an old version of nodejs, which is deprecated.
2023-03-02 14:04:59 +00:00
Kegan Dougal 5c3d02cb89 sliding-sync: process receipt extension response
Needs some kind of tests, but this should do the trick.
2023-03-02 13:53:11 +00:00
Kévin Commaille e84a43dbaa Split StateStore integration tests into a trait
To declare the tests, the macro is still used but the content of the
tests is moved in the StateStoreIntegrationTests trait.

Allows to get the proper line reported when a panic occurs,
and have linting, formatting and IDE suggestions.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-03-02 14:35:51 +01:00
Richard van der Hoff 2fe08a90c5 Reinstate protoc for a couple of GHA jobs (#1607)
Looks like #1604 broke the build :(
2023-03-02 12:47:58 +00:00
Richard van der Hoff bdb9d274ce Skip installing protoc where it is unneeded (#1604)
This seems to have been cargo-culted to lots of places where it is redundant.
2023-03-01 22:17:36 +00:00
Ivan Enderlin 862b4a3df7 chore(bindings): Clean up and code simplification on matrix_sdk_ffi::sliding_sync
chore(bindings): Clean up and code simplification on `matrix_sdk_ffi::sliding_sync`
2023-03-01 20:12:45 +01:00
Ivan Enderlin 1dccea8735 doc: Fix a typo. 2023-03-01 19:59:55 +01:00
Ivan Enderlin e1fe1279c2 Merge pull request #1598 from Hywan/chore-sdk-sliding-sync-list-cleanup
chore(sdk): Various clean up on Sliding Sync (List)
2023-03-01 16:56:57 +01:00
Richard van der Hoff 15513b0ada Clean up the way we build xtask in CI (#1600)
Currently, the cache of the xtask binary isn't working terribly well:

* we seem to build it on each run anyway, presumably because we don't cache any of the intermediate build
   artifacts. Running the binary directly rather than indirecting via "cargo" prevents this.
* There is no sharing of the cache between the "rust" and "bindings" CI, because we use different cache keys.

This PR addresses both problems, and hopefully speeds up CI a bit as a result.
2023-03-01 15:50:31 +00:00
Jonas Platte c9e6d3e2dc Make RemoteEventTimelineItem fields private, provide methods instead 2023-03-01 16:45:43 +01:00
Jonas Platte 400879c819 Make LocalEventTimelineItem fields private, provide methods instead 2023-03-01 16:45:43 +01:00
Jonas Platte aac9d9c29b Move TimelineItemContent and related types into a new submodule 2023-03-01 16:45:43 +01:00
Jonas Platte 770a67678c Move RemoteEventTimelineItem into its own module 2023-03-01 16:45:43 +01:00
Jonas Platte 1452a2124f Move LocalEventTimelineItem into its own module 2023-03-01 16:45:43 +01:00
Jonas Platte daa3b80870 Re-export and document LocalEventTimelineItem, RemoteEventTimelineItem 2023-03-01 16:45:43 +01:00
Ivan Enderlin ccd9ad7b49 chore(bindings): Simplify the code.
Rust is a beautiful language. Let's use all the great constructions it gives to
us to write pretty code.
2023-03-01 16:42:47 +01:00
Ivan Enderlin 4212980f32 chore(bindings): Remove a From<JoinHandle> for TaskHandle impl.
This implementation is never used.
2023-03-01 16:42:09 +01:00
Ivan Enderlin 9b1c5079e6 chore: cargo fmt. 2023-03-01 15:58:22 +01:00
Ivan Enderlin a341caa773 chore(sdk): Continue the move from view to list in Sliding Sync. 2023-03-01 15:46:40 +01:00
Ivan Enderlin b4bf544676 test: Continue the move from view to list in Sliding Sync. 2023-03-01 15:43:59 +01:00
Ivan Enderlin bfb55d782f chore(sdk): Clean up rooms_ops. 2023-03-01 15:38:15 +01:00
Ivan Enderlin 3bad2a84ad chore(sdk): Remove SlidingSyncListRequestGenerator::live_request. 2023-03-01 15:17:53 +01:00
Ivan Enderlin 866c91ffbc chore(sdk): Simplify code of Sliding Sync request generator. 2023-03-01 15:17:31 +01:00
Ivan Enderlin c03ba55f24 chore(sdk): Rename InnerSlidingSyncListRequestGenerator to GeneratorKind. 2023-03-01 15:04:37 +01:00
Ivan Enderlin 1f5c4feafc chore(sdk): Extract Sliding Sync request generators into their own module. 2023-03-01 15:01:02 +01:00
Ivan Enderlin 6d2055449d chore(bindings): Continue to rename view to list in Sliding Sync. 2023-03-01 14:51:34 +01:00
Ivan Enderlin f5cc6feccd chore(sdk): Split the list.rs module into list/mod.rs and list/builder.rs. 2023-03-01 14:43:58 +01:00
Ivan Enderlin c5d5deba8e chore: Continue the renaming from view to list for Sliding Sync. 2023-03-01 14:39:09 +01:00
Ivan Enderlin d829fd3376 chore(bindings): Continue the renaming from view to list for Sliding Sync. 2023-03-01 14:38:43 +01:00
Ivan Enderlin 50a248c18b chore(sdk): Continue the renaming from view to list for Sliding Sync. 2023-03-01 14:38:26 +01:00
Ivan Enderlin c366eadf33 chore(sdk): Rename variables, clean up code, improve documentation… 2023-03-01 14:35:46 +01:00
Jonas Platte 318ede131d refactor(indexeddb): Use IndexeddbStateStoreError in StateStore impl 2023-03-01 14:30:13 +01:00
Jonas Platte 146db59370 refactor(base): Add an Error type to StateStore trait 2023-03-01 14:30:13 +01:00
Ivan Enderlin 97dd68e7fc fix(sdk): Deal with missing data in Sliding Sync's responses
fix(sdk): Deal with missing data in Sliding Sync's responses
2023-03-01 14:24:24 +01:00
Ivan Enderlin 4e4c745032 chore(sdk): Update all mentions to view as list in SlidingSyncList. 2023-03-01 14:20:44 +01:00
Ivan Enderlin f03767318f chore(sdk): Update all mentions to view as list in SlidingSync and SlidingSyncBuilder. 2023-03-01 14:18:40 +01:00
Ivan Enderlin cf83112bf0 chore(sdk): Move FrozenSlidingSyncList lower in the file. 2023-03-01 13:58:55 +01:00
Ivan Enderlin 575eea4701 fix(sdk): Deal with missing data in Sliding Sync's responses.
The Sliding Sync server might not send some parts of the response, because they
were sent before and the server wants to save bandwidth. So let's update values
only when they exist.
2023-03-01 12:19:30 +01:00
Ivan Enderlin 5377bb7ecf fix(sdk): Rename SlidingSyncView to SlidingSyncList.
The specification describes “list”, not “view”. Consistency is important, so
let's rename this type!
2023-03-01 12:09:34 +01:00
Ivan Enderlin 629b74e4f5 chore(sdk): Rename the sliding_sync::view module to …::list. 2023-03-01 11:56:01 +01:00
Ivan Enderlin 9475bb4d53 chore(indexeddb): Update version of uuid
chore(indexeddb): Update version of `uuid`
2023-03-01 09:09:15 +01:00
Ivan Enderlin 452588a18e chore(indexeddb): Update version of uuid. 2023-03-01 08:26:28 +01:00
Stefan Ceriu ff5dedbb07 fix(sliding_sync): Prevent PagingFullSync and GrowingFullSync from going over the total room count 2023-02-28 18:32:11 +01:00
valere 6539dc3060 quick typo 2023-02-28 17:53:54 +01:00
valere 7b8608e4c5 refactor(withheld) better type for no_olm 2023-02-28 17:38:37 +01:00
Stefan Ceriu 5c3972938e chore: Add platform versions for swift CI tests 2023-02-28 15:06:23 +01:00
Jonas Platte b936d3e32d chore: Remove workaround for clippy bug that was fixed 2023-02-28 12:36:08 +01:00
Kévin Commaille da8d74ccc1 feat(sdk): Keep track of events read receipts in the timeline API
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-28 09:44:35 +01:00
Kévin Commaille 6aad2a661d refactor(sdk): Rename ProfileProvider to RoomDataProvider
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-28 09:44:35 +01:00
Kévin Commaille 3139204f4b fix(examples): Don't use the sled store if the session is not persisted
Running the same example twice
borks encryption.
Instead point to an example that shows how to do it.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-28 09:20:53 +01:00
Kévin Commaille 1684dbe0a1 feat(examples): Add example to persist a session
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-28 09:20:53 +01:00
Doug 9531dc195a fix(bindings): Fix double quotes when replying to a reply. 2023-02-27 18:23:49 +01:00
Sam Wedgwood abab6dcf0f docs(crypto): Fix typo
Signed-off-by: Sam Wedgwood <sam@wedgwood.dev>
2023-02-27 15:39:01 +00:00
Ivan Enderlin d699161981 chore(sdk): Code reorganization of the sliding_sync module + doc improvement
chore(sdk): Code reorganization of the `sliding_sync` module + doc improvement
2023-02-27 15:27:08 +01:00
Ivan Enderlin 927c44bec3 doc(sdk): Fix doctests + remove mentions to futures-signals. 2023-02-27 15:08:13 +01:00
Ivan Enderlin 96248248ca chore(sdk): Move UpdateSummary at the bottom of the module. 2023-02-27 13:56:04 +01:00
Ivan Enderlin b7b86fa95b fix(sdk): Few fixes and cleans up of SlidingSync itself
fix+chore(sdk): Few fixes and cleans up of `SlidingSync` itself
2023-02-27 13:50:48 +01:00
Ivan Enderlin 4f7186a840 chore(sdk): Simplify the implementation of RoomListEntry. 2023-02-27 13:49:34 +01:00
Ivan Enderlin 9b062fa782 chore(sdk): Move RoomListEntry into the sliding_sync::view module. 2023-02-27 13:43:40 +01:00
Ivan Enderlin 4d8c3172a4 chore(sdk): Extract Error into its own module. 2023-02-27 13:42:01 +01:00
Ivan Enderlin b1c9ea9aa3 chore(sdk): Move SlidingSyncMode into the sliding_sync::view module. 2023-02-27 13:38:54 +01:00
Ivan Enderlin 49eee14665 chore(sdk): Move SlidingSyncState into the sliding_sync::view module. 2023-02-27 13:38:09 +01:00
Ivan Enderlin 6cec946401 chore(sdk): Improve documentation of SlidingSync. 2023-02-27 13:36:08 +01:00
Jonas Platte d06e8ccfc5 refactor: Upgrade eyeball and use SharedObservable
… but not in sliding sync yet, where some planned refactorings might
conflict with this.
2023-02-27 13:29:28 +01:00
Ivan Enderlin ac1d5afac3 doc(sdk): Improve inline documentation with link to an issue. 2023-02-27 13:29:03 +01:00
Ivan Enderlin f51b51b19e chore(sdk): Avoid mapping to a function returning (). 2023-02-27 12:14:01 +01:00
Ivan Enderlin 16c9845a47 chore(sdk): Rename SlidingSync.failure_count to .reset_counter.
This patch cleans up the `SlidingSync::stream` method. It renames variables,
improves log messages etc.

This patch also creates a new `MAXIMUM_SLIDING_SYNC_SESSION_EXPIRATION`
constant. This value was previously hardcoded and lost in the code, now it's
easier to spot it for further updates.

This patch finally renames the `failure_count` field to `reset_counter`,
because it doesn't count the number of failure, but the number of
`ErrorKind::UnknownPos` exactly, i.e. the number of times we reset the
`SlidingSync` state.
2023-02-27 12:09:14 +01:00
Ivan Enderlin 4dbd1a7db4 fix(sdk): Fix join in SlidingSync::sync_once.
This patch cleans up the `SlidingSync::sync_once` method by renaming variables,
adding more comments, simplifying the code by reducing the number of variables
etc.

This patch also changes `futures_util::join!` to `futures_util::future::join`.
It does the same but the macro needs the `async-await-macros` feature to be
turned on, while the second works without any features.

Finally, this patch improves the log messages by making them more clear for a
new reader.
2023-02-27 11:56:16 +01:00
Ivan Enderlin e5c85410a8 doc(sdk): Fix documentation, add links etc. 2023-02-27 11:54:48 +01:00
Ivan Enderlin 98ea3f096b chore(sdk): Clean up code of SlidingSync::cache_to_storage. 2023-02-27 11:54:13 +01:00
Anderas f0986643ce chore(crypto): Log Olm session identifiers
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
2023-02-27 10:59:30 +01:00
valere f4d4d96c8e support migration for outbound after withheld addtition 2023-02-27 09:56:56 +01:00
Ivan Enderlin b214a0e098 feat(sdk): Remove clones of large responses in Sliding Sync
feat(sdk): Remove clones of large responses in Sliding Sync
2023-02-27 09:47:26 +01:00
Ivan Enderlin 70380a6ee4 doc(sdk): Improve documentation of SlidingSync::handle_response. 2023-02-27 09:30:50 +01:00
valere 39997376af fix js binding test 2023-02-25 16:33:16 +01:00
valere 58fa9d7767 fix ci 2023-02-25 16:18:06 +01:00
valere ad18ecc2c1 cleaning 2023-02-25 10:50:37 +01:00
valere ff500fc707 fix unused result 2023-02-25 10:39:17 +01:00
valere 76a286c91d feat(withheld) sled store support 2023-02-25 10:31:23 +01:00
valere 6cc31a0e13 fix clippy 2023-02-24 17:15:51 +01:00
valere 228b963f74 feat(withheld) fix indexeddb test 2023-02-24 16:39:37 +01:00
Jonas Platte 1783cd7738 test: Remove unused constant 2023-02-24 12:39:55 +01:00
Jonas Platte 32e8cb76b0 ci: Remove unused FeatureSet variant 2023-02-24 12:39:55 +01:00
valere 81c9f57e02 clippy fix 2023-02-23 18:02:45 +01:00
Benjamin Kampmann e162c99074 feat: Handy function to update power levels of a room 2023-02-23 17:53:48 +01:00
Benjamin Kampmann 6465398322 feat: expose power_levels.user_can_do on RoomMember 2023-02-23 17:53:48 +01:00
valere 6b948711b9 feat(withheld) Integration tests 2023-02-23 17:47:57 +01:00
Ivan Enderlin f803e58e36 chore(sdk): Keep to_remove inside its own scope. 2023-02-23 16:53:16 +01:00
Ivan Enderlin 23b3e3aa10 chore(sdk): Format code a little bit. 2023-02-23 16:40:48 +01:00
Ivan Enderlin fcfdf5c57c chore(sdk): Rename a variable in SlidingSync::handle_response. 2023-02-23 16:40:48 +01:00
Ivan Enderlin 3b01e4f9a6 chore(sdk): Use T::default instead of Default::default. 2023-02-23 16:39:56 +01:00
Ivan Enderlin 3c44f87bee doc(sdk): Simplify one documentation. 2023-02-23 16:39:39 +01:00
Ivan Enderlin af6cd85cf4 chore(sdk): SlidingSyncRoom::new no longer needs a mutable inner. 2023-02-23 16:27:19 +01:00
Ivan Enderlin 54654aa0c7 chore(sdk): Simplify references, thanks Clippy. 2023-02-23 16:03:11 +01:00
Ivan Enderlin 778d1211c7 feat(bindings): Replace many scripts by one xtask
Ganfra/kotlin binding scripts
2023-02-23 15:58:40 +01:00
Ivan Enderlin c69d28ef79 feat(sdk): Remove clones of large responses in Sliding Sync.
I admit this patch is quite tricky. Please try to follow me.

So, first off, in `SlidingSyncRoom::new`, we were clearing the timeline,
because somehow it exists twice in memory at this step.

Which led me to understand how `SlidingSync::handle_response` was working.
I've clarified how this part of the code works. We are dealing with 2 kind of
responses for a specific reason: `SyncResponse` and `v4::Response`, now it's
documented and I hope it's clearer.

Then, I notice that we were passing a clone of the entire sliding sync
response (`v4::Response`) to `Client::process_sliding_sync`. I thought it was
suboptimal, so I've updated the code to take a reference. It led me to update
`BaseClient::process_sliding_sync`. It was a little bit tricky, but I reckon we
have less clones now than before.

And now, back to `SlidingSync::handle_response`, I was able to compute the
`timeline` correctly by draining it from the `v4::Response`, or by moving it
from `SyncResponse`. So it's no longer necessary to have this clearing code
inside `SlidingSyncRoom::new`. Honestly it has nothing to do at this place
before.

To conclude: We have cleaner code, and less clones.

What thing I reckon could be optimized, is that the entire `timeline`
(`Vec<TimelineEvent>`) is cloned to be passed to `Client::handle_timeline`. So
this timeline exists in 2 places: in Sliding Sync, and somewhere else. I don't
believe it's a problem now, that's how it works, but we must be aware of that.
2023-02-23 15:21:21 +01:00
Jonas Platte d0c8ec7a22 refactor: Replace remaining usage of futures-signal with eyeball(-im) 2023-02-23 15:08:41 +01:00
Doug 01e3a31a11 fix(bindings): Verify entered homeserver before proxy availability
The reported errors weren't that helpful to the user.
Additionally attempt discovery when a URL is entered before falling back to the URL directly.
2023-02-23 12:12:53 +00:00
ganfra 83dcb0eb48 xtask kotlin : fix formatting 2023-02-23 11:53:32 +01:00
Jonas Platte 6c92bf8745 refactor(sdk): Remove unused dependency 2023-02-23 11:47:51 +01:00
Jonas Platte ba6fc794b0 refactor(base): Replace futures-signals with eyeball 2023-02-23 11:47:51 +01:00
Jonas Platte 17b86b7c38 refactor(crypto): Replace futures-signals with eyeball 2023-02-23 11:47:51 +01:00
valere 9894d3c72d feature(withheld) indexeddb store implem 2023-02-23 10:13:32 +01:00
boxdot d5154577a0 feat(sdk): Add custom login method
The `Client::login_custom` allows to login by using a custom login
method. In particular, it is possible to login to Synapse which supports
JWT authentication.

Signed-off-by: boxdot <d@zerovolt.org>
2023-02-23 08:16:04 +01:00
Ivan Enderlin 5be00d5950 chore(sdk): Many clean ups in SlidingSync
chore(sdk): Many clean ups in `SlidingSync`
2023-02-22 20:16:54 +01:00
Ivan Enderlin f3928e8d35 chore(sdk): Remove an unnecessary clone in SlidingSyncRoom::update. 2023-02-22 20:03:11 +01:00
Ivan Enderlin c766d8b3ef chore(sdk): Address PR feedback. 2023-02-22 20:00:49 +01:00
Ivan Enderlin 4d33fe1c31 chore(sdk): Rename some variable inside FrozenSlidingSyncRoom. 2023-02-22 19:59:57 +01:00
Ivan Enderlin e80713e933 chore(sdk): SlidingSyncRoom::update takes ownership of room_data.
First off, it's not necessary for `SlidingSyncRoom::update` to take a reference
to `room_data: v4::SlidingSyncRoom`. When `update` is called, the iterator owns
its items.

Second, by taking ownership of `room_data`, we no longer need to clone all the
data we need to assign to `self.inner`.
2023-02-22 19:59:57 +01:00
Ivan Enderlin 5d356ca1b5 feat(sdk): Avoid locking prev_batch in SlidingSyncRoom::timeline_builder. 2023-02-22 19:59:57 +01:00
Ivan Enderlin 56daa6cb8f chore(sdk): Rename SlidingSyncRoom pub(crate) from to pub(super) new.
First off, `SlidingSyncRoom.from` doesn't need to be visible to the entire
crate, only to `crate::sliding_sync.

Second, it's a constructor, so let's call it `new`.
2023-02-22 19:59:43 +01:00
Kévin Commaille bcc04bdf35 feat(sdk): Add conversion from EventTimelineItem and VirtualTimelineItem to TimelineItem
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-22 16:59:22 +00:00
Ivan Enderlin ebe8ce3177 feat(sdk): Make SlidingSync.pos already private
feat(sdk): Make SlidingSync.pos already private
2023-02-22 17:42:30 +01:00
Ivan Enderlin 1d02515186 chore(sdk): Re-organizing the code inside sliding_sync::room.
1. Put `FrozenSlidingSyncRoom` at the bottom of the module.
2. Put merge 2 `impl SlidingSyncRoom` together.
3. Remove the `AliveRoomTimeline` type alias.
4. Improve the documentation.
2023-02-22 17:38:37 +01:00
Ivan Enderlin 0abef77408 doc(sdk): Improve documentation of SlidingSyncBuilder. 2023-02-22 17:29:40 +01:00
Jonas Platte fe7f157253 refactor(bindings): Use UniFFI proc-macros for CrossSigningStatus 2023-02-22 17:21:21 +01:00
Ivan Enderlin 5a62ec3fc1 chore(ffi) Rename StoppableSpawn to TaskHandle
chore(ffi) Rename `StoppableSpawn` to `TaskHandle`
2023-02-22 17:11:36 +01:00
Ivan Enderlin 5727726e5d feat(sdk): Make SlidingSync.pos already private.
So far, the `SlidingSync.pos` field was public to the crate. In order to avoid
breaking the internal state of this type, its visibility is now private.

However, we need to be able to change the value when testing the
`SlidingSync` type itself. To achieve that, this patch removes the old
`force_sliding_sync_pos` function, and implements 2 new functions: `set_pos`
and `pos` directly on `SlidingSync` only when `#[cfg(any(test, feature ="testing"))]`.
2023-02-22 17:07:50 +01:00
Ivan Enderlin dec4b2122b doc(sdk): Improve documentation of SlidingSyncMode. 2023-02-22 16:51:42 +01:00
Ivan Enderlin cfcafc8425 chore(ffi) Rename StoppableSpawn to TaskHandle.
Because it is what it is.
2023-02-22 16:48:46 +01:00
valere 42934ea7e4 feature(withheld) ffi bindings 2023-02-22 15:46:56 +01:00
kegsay 7e64c15145 fix: look for the right list when waiting for updates
Otherwise it will time out after 30s and then continue executing,
causing a slow test.
2023-02-22 14:42:32 +00:00
valere e56d380f65 fix store after rebase 2023-02-22 14:28:20 +01:00
ganfra f72d9c2016 Merge branch 'main' into ganfra/kotlin_binding_scripts 2023-02-22 13:31:56 +01:00
Jonas Platte 95f1867816 chore: Delete sled-state-inspector
The sled store is on its way out and nobody is using this.
2023-02-22 13:17:01 +01:00
Jonas Platte b1062a67e0 fix(sdk): Rewrite decryption retrying to fix invalid index bug
Previously, it was possible for us to use invalid indices when:

- We retried decrypting multiple events at once
- One of them (not the last) was an edit or reaction

This lead to a situation where we would remove the UTD item once
decryption for it was successfully retried, but not account for the
resulting index shift for all later timeline items.
2023-02-22 12:44:11 +01:00
Janne Heß 02a213c1b5 feat(sdk): Add support to change display names of devices
Signed-off-by: Janne Heß <janne.hess@helsinki-systems.de>
2023-02-22 10:55:54 +00:00
Archit Bhonsle 64ec5ec561 feat(crypto): Expose and re-expose the version of the matrix-sdk-crypto crate 2023-02-22 10:21:48 +00:00
ganfra 953d4c0ef7 Remove kotlin bindings for now 2023-02-22 11:00:05 +01:00
Ivan Enderlin 1469e9033c feat(crypto-nodejs): OlmMachine.initialize takes a new optional store type
feat(crypto-nodejs): `OlmMachine.initialize` takes a new optional store type
2023-02-22 10:33:26 +01:00
ganfra 260e7c2d5e Update kotlin xtask to not build aar 2023-02-22 10:28:08 +01:00
Archit Bhonsle ae4ed2e7c8 feat(crypto): Re-expose the version of vodozemac 2023-02-22 09:45:25 +01:00
valere 28fadb875a Post rebase fix 2023-02-21 17:48:05 +01:00
valere 3dbad4229a feat(withheld): sql store support 2023-02-21 15:05:14 +01:00
valere c497efc27a feat(withheld): handle incoming withheld + report error 2023-02-21 15:04:58 +01:00
valere 0154cccd4b feat(withheld) Remember no_olm and implement in memory store 2023-02-21 15:03:04 +01:00
valere 99232f2340 refactor(withheld) 2023-02-21 15:00:34 +01:00
valere 592be5bd57 feat(withheld) basic no_olm 2023-02-21 15:00:34 +01:00
valere dc0fe35103 feat(withheld) balcklist + refactoring 2023-02-21 15:00:34 +01:00
valere 7accfdc2ef feat(withheld) Implement MSC2399 2023-02-21 15:00:34 +01:00
Damir Jelić 655d7d00d0 chore(crypto): Add support for encrypted m.dummy events
This mostly just silences an incorrect log warning that we received an unsupported event.

Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-02-21 14:33:14 +01:00
Jonas Platte ac5b439249 chore(sdk): Add an extra trace event to TimelineEventHandler::add 2023-02-21 12:11:03 +01:00
Jonas Platte f76bc16a10 fix(sdk): Lock timeline state once for decryption retrying
Before, we were releasing the lock and re-obtaining it between obtaining
item indices and using them for decryption retrying.
2023-02-21 12:11:03 +01:00
Jonas Platte a89a12701a refactor(sdk): Remove unneeded Arc around MutableVec 2023-02-21 10:20:11 +01:00
Jonas Platte 843fe6a239 refactor(sdk): Remove derive_builder 2023-02-21 10:20:11 +01:00
Jonas Platte cb06feea22 refactor(sled): Remove derive_builder
… and use owned Builder pattern like for Client.
2023-02-21 10:20:11 +01:00
Jonas Platte b0e7f3d031 refactor(indexeddb): Remove derive_builder
… and use owned Builder pattern like for Client.
2023-02-21 10:20:11 +01:00
Jonas Platte b96532878b refactor(sdk): Replace futures-signals with eyeball-im in the timeline 2023-02-20 18:01:31 +01:00
Ivan Enderlin b439d60b1f feat(sdk): SlidingSyncView.state, .rooms_list and .rooms_count are now private
feat(sdk): `SlidingSyncView.state`, `.rooms_list` and `.rooms_count` are now private
2023-02-20 16:25:02 +01:00
Ivan Enderlin e8af3e2d60 chore(clippy): Make Clippy happy. 2023-02-20 15:39:23 +01:00
Ivan Enderlin 1f3b8048c7 chore(jack-in): Use the latest SS API. 2023-02-20 15:39:23 +01:00
Ivan Enderlin 48257ac7cd test(sdk): SS integration test suites use the new API. 2023-02-20 15:39:23 +01:00
Matteo Ludwig dffc65007c feat(bindings): Add AudioInfo & AudioMessageContent to matrix-sdk-ffi
Signed-off-by: Matteo Ludwig <ludwig@silpion.de>
2023-02-20 14:01:06 +00:00
Ivan Enderlin 3796469a29 doc(sdk): Fix Sliding Sync examples. 2023-02-20 14:24:38 +01:00
Ivan Enderlin d49ceddfd5 feat(sdk): SlidingSyncView.state, .rooms_list and .rooms_count are now private.
Before this patch, `SlidingSyncView` has the following fields that were public:
`state`, `rooms_list` and `rooms_count`. Since they are `Mutable`, they can be
changed from the outside, and then will break the internal state of the view.
This problem is mentioned in https://github.com/matrix-org/matrix-rust-sdk/
issues/1474.

This patch solves this by making them prviate. Phew. That was simple!

But wait, we have a problem now. `matrix-sdk-ffi` was relying on them. So
this patch adds “helpers” methods on `SlidingSyncView`, like `state_stream`,
`rooms_list`, `rooms_list_stream`, `rooms_count` and `rooms_count_stream`.
Let's add new ones when it's necessary.
2023-02-20 14:22:42 +01:00
Ivan Enderlin 03c3f66c9a doc(sdk): Fix Sliding Sync examples. 2023-02-20 14:20:22 +01:00
Ivan Enderlin 7b06822687 chore(sdk): Group impl blocks for the same SlidingSyncView in a single impl block. 2023-02-20 14:15:20 +01:00
Jonas Platte 1f128c1dd6 refactor(sdk): Remove Mutable<_> around SlidingSyncView#sync_mode 2023-02-20 13:20:33 +01:00
Jonas Platte e92841d6bc refactor(sdk): Inline Mutable type aliases 2023-02-20 13:20:33 +01:00
Jonas Platte a112076664 refactor(sdk): Remove usage of MutableBTreeMap
No instance was ever subscribed to, so we can just use a regular shared RwLock.
2023-02-20 13:20:33 +01:00
Jonas Platte 2f9106a6d0 refactor(sdk): Make SlidingSync fields private 2023-02-20 13:20:33 +01:00
Ivan Enderlin 8a70df80b2 doc(sdk): Fix Sliding Sync module documentation.
doc(sdk): Fix Sliding Sync module documentation.
2023-02-20 12:23:10 +01:00
Jonas Platte cbcfd5d531 refactor(bindings): Fix SlidingSyncRoom timeline listener return type
It's an error if the room was not found, so it should be surfaced as such.
2023-02-20 12:10:13 +01:00
Ivan Enderlin b451460d8d doc(sdk): Improve Sliding Sync documentation
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
2023-02-20 12:06:20 +01:00
Ivan Enderlin 772a94cc8c doc(sdk): Fix Sliding Sync module documentation. 2023-02-20 11:49:35 +01:00
Jonas Platte 0f077ffcd3 fix(sdk): Don't overwrite parallel updates when fetching reply details 2023-02-20 11:15:23 +01:00
Jonas Platte 9eefe9377e refactor(sdk): Move timeline functionality into TimelineInner 2023-02-20 11:15:23 +01:00
Ivan Enderlin b35f2669d2 chore(sdk): Split the sliding_sync module into smaller ones
chore(sdk): Split the `sliding_sync` module into smaller ones
2023-02-20 11:09:05 +01:00
Ivan Enderlin 4102d25ebe chore(sdk): Split the sliding_sync module into smaller ones.
It's an strict copy-paste. Nothing has changed, except the
`SlidingSyncConfigBuilder::subscriptions` method that is now public within
the crate.
2023-02-20 10:43:05 +01:00
Ivan Enderlin 177fa140fc fix(sdk): FrozenSlidingSyncRoom.timeline_queue must serialize to timeline
fix(sdk): `FrozenSlidingSyncRoom.timeline_queue` must serialize to `timeline`
2023-02-17 19:46:50 +01:00
Ivan Enderlin e0eeba21ff fix(sdk): FrozenSlidingSyncRoom.timeline_queue must serialize to timeline.
In https://github.com/matrix-org/matrix-rust-sdk/pull/1478, I've introduced
a regression. The FrozenSlidingSyncRoom.timeline` field has been renamed to
`timeline_queue`.

I didn't notice that this type can be serialized and deserialized. That's
actually a breaking change because this type is stored somewhere once
serialized. So with #1478, it was impossible to deserialize them!

This patch fixes that. It also adds a test to ensure the serialization form of
`FrozenSlidingSyncRoom` doesn't change.
2023-02-17 19:24:39 +01:00
Jonas Platte e4f94f3174 chore: Fix warnings 2023-02-17 11:30:13 +01:00
Jonas Platte c2f529ed71 chore: Run cargo update
To pull in the latest Ruma release with a bugfix for content reporting.
2023-02-17 11:30:13 +01:00
Jonas Platte 0b91ec29a4 Allow to get or send any type of receipt 2023-02-17 10:54:03 +01:00
Kévin Commaille 362a394a11 feat(sdk)!: Allow to send private read receipts and receipts in threads
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-17 10:33:09 +01:00
Kévin Commaille 6ddb22d6ab feat(sdk): Expose methods to get a user or an event's receipts
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-17 10:29:22 +01:00
Kévin Commaille a3f289c6fc feat(base)!: Allow to get any receipt type for a user or event
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-17 10:29:21 +01:00
Jonas Platte 44d8f99bc4 docs(sdk): Remove outdated documentation 2023-02-17 09:56:29 +01:00
Ivan Enderlin eb3fb6986d doc(sdk): Fix links to examples and to matrix_sdk_base
doc(sdk): Fix links to examples and to `matrix_sdk_base`
2023-02-17 08:53:00 +01:00
Ivan Enderlin b6fb25fdfa test(sliding-sync): ensure unknown pos does recover the room subscription properly
test(sliding-sync): ensure unknown pos does recover the room subscription properly
2023-02-16 18:24:17 +01:00
Mauro 679d3084aa feat(bindings): Add Room::report_content 2023-02-16 17:18:18 +00:00
Ivan Enderlin 94b60f915f test(sdk): Address feedbacks. 2023-02-16 17:54:28 +01:00
Ivan Enderlin 3bf1060705 Merge branch 'main' into ben-fix-resubscribe-problem 2023-02-16 17:44:26 +01:00
Ivan Enderlin d600af7c0e feat(crypto-nodejs): OlmMachine.initialize takes a new optional store type.
This patch allows an `OlmMachine` to use a different store than Sled, like SQLite.

A new enum is introduced: `StoreType` which 2 variants: `Sled` (the default), and `Sqlite`.

The `OlmMachine.initialize` constructor now takes a new optional `store_type:
Option<StoreType>` argument. If no value is passed, the default `StoreType`
variant will be used (as mentioned: `StoreType.Sled`).

The code has been rewritten a little bit to make the type system happy without
introducing too much type indirections.

This patch finally adds a parameterized tests that exhaustively test: no store
type, `Sled` and `Sqlite`.
2023-02-16 16:26:06 +01:00
Damir Jelić 9649100adb feat(sdk): Add a root span to our client 2023-02-16 15:31:38 +01:00
Damir Jelić 292a9831f5 refactor(crypto): Move the usage specific cross signing types into the types module 2023-02-16 14:39:07 +01:00
Damir Jelić 04d8348477 refactor(crypto): Split out the cross signing key handling method 2023-02-16 14:39:07 +01:00
Ivan Enderlin 7049bd9183 doc(sdk): Improve Sliding Sync documentation
Sliding Sync API docs & minor fixes around API accessibility
2023-02-16 14:12:45 +01:00
Ivan Enderlin 1c7ffedf1a Merge branch 'main' into ben-sliding-sync-docs 2023-02-16 14:00:56 +01:00
Ivan Enderlin 7cc06cb76d chore(sdk): Small cleans up when reading the Sliding Sync code
chore(sdk): Small cleans up when reading the Sliding Sync code
2023-02-16 13:38:04 +01:00
Ivan Enderlin 9479f23f4b fix(sdk): Reconciliate events in the timeline queue in Sliding Sync when new updates arrive
fix(sdk): Reconciliate events in the timeline queue in Sliding Sync when new updates arrive
2023-02-16 12:35:35 +01:00
Ivan Enderlin c719d6d22e doc(sdk): Fix links to examples and to matrix_sdk_base. 2023-02-16 12:08:42 +01:00
Ivan Enderlin 6aa766efd0 chore(sdk): Address PR feedback. 2023-02-16 11:58:07 +01:00
Richard van der Hoff a0807cb337 crypto-js: support npm run build:dev (#1510)
Building the crypto-js bindings in release mode is very slow and not really
necessary for local development.

`--release` is the default, so there is no need to specify it
explicitly. Instead, allow `wasm-pack` args to be specified by an env var, and
add a `build:debug` npm script which will build in debug mode.
2023-02-16 10:51:37 +00:00
Richard van der Hoff 480800b996 crypto-js: have share_room_key return ToDeviceRequests (#1516)
We already have support for proper `ToDeviceRequest` objects in
`outgoing_requests`, so let's use it in `share_room_key` as well. It's much
easier for the application to work with the proper object than an untyped json
blob.
2023-02-16 10:51:15 +00:00
Ivan Enderlin 1c0288e42b chore(sdk): Simplify code by removing a map.
In the code `if let Some(global_data) = account_data.as_ref().map(|a|
&a.global)`, the `map` is not purely necessary. This patch simplifies the code
to remove the `map` and read the `global` field later on.
2023-02-16 11:49:21 +01:00
Ivan Enderlin 0a97ac8316 chore(sdk): Address PR feedback. 2023-02-16 11:45:10 +01:00
Ivan Enderlin 46006cf108 chore(sdk): Address PR feedback. 2023-02-16 11:43:25 +01:00
Ivan Enderlin 10adb6d26b chore(sdk): Use appropriate type to remove the need of a comment.
By using `Default::default` for the parameter value, we don't know which type
we are passing to the function. Hence the useful comment `room_info.ephemeral`.
This patch changes this to `Ephemeral::default`, so that we now know what we
pass without the need of a comment.
2023-02-16 11:23:05 +01:00
Richard van der Hoff 5abab932db ci: Fail coverage job if the coverage report can't be uploaded (#1515) 2023-02-16 09:36:43 +00:00
Damir Jelić abef9fae1a chore(bindings): Use tracing-android instead of android-logger 2023-02-16 09:59:16 +01:00
Ivan Enderlin b05d6874c0 test(sdk): Update the timeline inspection when the timeline_limit is modified. 2023-02-16 09:49:36 +01:00
Jonas Platte 3f2b12c996 chore(base): Remove unused futures-channel dependency 2023-02-16 08:59:41 +01:00
Ivan Enderlin 838488702f Merge branch 'main' into test-sliding-sync-timeline-limit-duplication 2023-02-16 08:45:22 +01:00
Ivan Enderlin 6c62b5f637 test(sdk): Restore the sliding-sync Docker image to v0.99.0. 2023-02-16 08:16:03 +01:00
Richard van der Hoff 826dc46ddf Merge pull request #1511 from matrix-org/rav/trace-to-debug
crypto-js: log trace messages at debug
2023-02-15 18:13:06 +00:00
Richard van der Hoff d9e455ab82 crypto-nodejs, crypto-js: prettify the javascript codebase (#1509) 2023-02-15 17:47:32 +00:00
kegsay 19b8ab409d test: Add depends_on block for the sliding sync proxy
This prevents the proxy starting before postgres is ready, which
causes the proxy to panic.
2023-02-15 17:32:57 +00:00
Richard van der Hoff 99b61ef660 Remove redundant log_trace 2023-02-15 17:06:46 +00:00
kegsay fb467b75e0 ci: Update sliding sync integration tests job 2023-02-15 17:03:29 +00:00
Jonas Platte 9e2fa13b9c fix(sdk): Respect new server ordering when receiving duplicate events 2023-02-15 17:40:16 +01:00
Jonas Platte 38e2d0bdcd fix(sdk): Fix day divider removal logic in timeline 2023-02-15 17:40:16 +01:00
Jonas Platte e8d5d29d2c chore(sdk): Improve tracing in TimelineEventHandler::add 2023-02-15 17:40:16 +01:00
Jonas Platte 88376e85cd test(sdk): Remove TestTimeline::with_initial_events
It's not general enough for further inital event tests.
2023-02-15 17:40:16 +01:00
Ivan Enderlin b1bfb868ab chore(sdk): Make Clippy happy. 2023-02-15 17:15:03 +01:00
Ivan Enderlin 6b3a550b22 chore(sdk): Fix lints. 2023-02-15 17:08:30 +01:00
Ivan Enderlin d9f9ed9d68 fix(sdk): Reconciliate timeline queue in SlidingSync when new updates arrive.
The code is self-documented. Please read it.
2023-02-15 16:50:40 +01:00
Jonas Platte 188aaecde3 feat(sdk): Keep Timeline event handlers around longer
… if the Timeline object itself is dropped, but something is still
subscribed to its changes.
2023-02-15 15:29:04 +01:00
Richard van der Hoff d41753ea17 crypto-js: log trace messages at debug
Javascript's `console.trace` is not a good equivalent for Rust's
`Level::TRACE`.

In particular:
 * `console.trace` causes a stacktrace to be written with each message
 * Under nodejs, `console.trace` writes the message to `stderr`, while
   `console.debug` writes to stdout

`console.trace` is therefore somewhat analogous to `console.error`.

Since we already include the log level in the message, we might as well just
send trace messages to `console.debug` rather than `console.trace`.
2023-02-15 12:50:42 +00:00
Richard van der Hoff e16c113db0 crypto-js, crypto-nodejs: Run prettier in CI 2023-02-15 12:39:54 +00:00
Richard van der Hoff 3f8590f86d crypto-nodejs, crypto-js: Run prettier on source code 2023-02-15 12:39:54 +00:00
Ivan Enderlin a0bd88aefc feat(crypto-nodejs) Implement OlmMachine.close
feat(crypto-nodejs) Implement `OlmMachine.close`
2023-02-15 12:48:45 +01:00
Jonas Platte 74056de8d7 fix(sdk): Deduplicate events coming from back-pagination 2023-02-15 12:41:26 +01:00
Jonas Platte 4f14728c91 chore(sdk): Add more spans and trace events to the timeline 2023-02-15 11:08:20 +01:00
Ivan Enderlin 57b810d70c test(sdk): Test changing the sliding sync limit on-the-fly. 2023-02-15 10:13:03 +01:00
Ivan Enderlin b3fedda90c chore(sdk): Clean up useless code.
The `experimental-timeline` feature is always enabled by `experimental-sliding-
sync`. Thus we can clean up the code.
2023-02-15 10:12:56 +01:00
Jonas Platte 20e082d416 refactor(sdk): Add a Date type for day divider logic 2023-02-15 10:08:05 +01:00
Jonas Platte 9e0ff4b9a9 fix(sdk): Handle remote echo on the first message of the day correctly 2023-02-15 10:08:05 +01:00
Jonas Platte b57bd55204 refactor(sdk): Use .rev().find_map() instead of .rfind().and_then() 2023-02-15 10:08:05 +01:00
Jonas Platte 4cad934a6b refactor(sdk): Simplify day divider timestamp conversion 2023-02-15 10:08:05 +01:00
Jonas Platte aa2b2dfff4 test(sdk): Fix reference to renamed test case 2023-02-15 09:31:42 +01:00
Jonas Platte 6c2a9dae55 test(sdk): Use u64 instead of u32 for next_ts
It seems weird to artificially limit the number range to 32 bits there,
panicking inside a test on too large values is fine.
2023-02-15 09:31:42 +01:00
Jonas Platte 360864841e test(sdk): Allow tests to set the next TS, use for day divider test 2023-02-15 09:31:42 +01:00
Jonas Platte 563ba884eb test(sdk): Make next_ts part of TestTimeline 2023-02-15 09:31:42 +01:00
Jonas Platte 13ffadc32a test(sdk): Add handle_live_redacted_message_event 2023-02-15 09:31:42 +01:00
Jonas Platte e246735866 test(sdk): Shorten some method names 2023-02-15 09:31:42 +01:00
Ivan Enderlin 6593f61556 doc(crypto-nodejs): Add safety comment for OlmMachine.close. 2023-02-15 09:15:31 +01:00
Jonas Platte 423d6ace83 fix(sdk): Attempt to EX-android crash with more hacks 2023-02-14 17:53:21 +01:00
Jonas Platte ce315a5229 chore: Use fully-qualified Docker image names
This brings us closer to being able to use our Docker setup with podman too.
2023-02-14 10:19:06 +01:00
Jonas Platte ca1163c9cc test: Remove trailing spaces from docker-compose.yml 2023-02-14 10:19:06 +01:00
Jonas Platte e576af8267 test: Fix docker-compose.yml error
Seems to be accepted by some older versions of docker-compose, but not
by current ones.
2023-02-14 10:19:06 +01:00
Jonas Platte 118497f9ec test: Remove unused dependency 2023-02-13 16:59:45 +01:00
Jonas Platte ac06172cf2 test(sdk): Add timeline items accessor 2023-02-13 16:21:30 +01:00
Damir Jelić 2654e909be feat(store-encryption): Add support to export/import the cipher using a key
This is useful for platforms which might want to avoid the cost of
password based key-derivation and have the ability to securely store an
encryption key.

Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
2023-02-13 14:08:45 +00:00
Damir Jelić a1b1862479 docs(crypto): Explain a bit better what it means that a Device owns a room key
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2023-02-13 15:00:15 +01:00
Ivan Enderlin 5001cef372 Merge pull request #1375 from Hywan/feat-crypto-nodejs-requests-more-types 2023-02-13 14:46:47 +01:00
Kévin Commaille a6f74fa22c fix(sled): Use proper table name for encoding key when redacting
Contrary to other tables that use their own name to encode their keys,
the `ROOM_INFO` table uses the `ROOM` table name to encode its keys.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-13 14:07:06 +01:00
Damir Jelić 56cfa8f4f9 fix(crypto): Always mark your own device as verified 2023-02-13 14:01:31 +01:00
Richard van der Hoff 8d642784bb fix: remove dependency on broken wasm_timer crate
`wasm_timer` doesn't work outside the browser, which prevents it being used in
tests.

We can replace it with `gloo-timers` wich uses the standard Javascript
`setTimeout`.
2023-02-13 12:41:36 +01:00
enterprisey e45bf9f9bd docs(sdk): Improve read receipt/marker explanation 2023-02-13 12:05:35 +01:00
Jonas Platte 3a516a5fce refactor(sqlite): Use internal Error in CryptoStore impl 2023-02-13 12:05:04 +01:00
Jonas Platte 9fc7d1c78b refactor(indexeddb): Use IndexeddbCryptoStoreError in CryptoStore impl 2023-02-13 12:05:04 +01:00
Jonas Platte c6f0e47077 refactor(crypto)!: Add an error type to the CryptoStore trait
This makes it easier to implement it. However, using a different error
type than CryptoStoreError is a non-trivial change, so left for the
coming commits for all stores except the memory store.
2023-02-13 12:05:04 +01:00
Kévin Commaille 96c796bb0e ci: Silence clippy::extra_unused_type_parameters in affected crates
Triggers false positives.
See discussion in https://github.com/rust-lang/rust-clippy/issues/10319.
Possibly fixed in https://github.com/rust-lang/rust-clippy/pull/10321.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-13 11:57:05 +01:00
Kévin Commaille 63fa645cea fix(indexeddb): Fix implementation of SafeEncode for tuple of 5 elements
Regression introduced by merging commit 9707d73 after efdeba7

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-13 11:57:05 +01:00
Kévin Commaille 0d4fac5962 test(base): Test collision between threaded and unthreaded receipts in store
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-12 11:04:26 +01:00
Kévin Commaille 2e497198f8 fix(stores): Separate receipts by thread
The key encoding in key-value stores is backwards-compatible so
old receipts are counted as unthreaded receipts.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-12 11:04:26 +01:00
Kévin Commaille 9707d73ead fix(indexeddb): Fix broken raw redacted state events
A fix for (de)serialization of redacted state events in Ruma made
old events undeserializable.
Bump the DB version.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-11 22:54:38 +01:00
Kévin Commaille 5ae84a9a80 fix(sled): Fix broken raw redacted state events
A fix for (de)serialization of redacted state events in Ruma made
old events undeserializable.
Bump the DB version.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-11 22:54:38 +01:00
Jonas Platte 57c3224b6b ci: Work around not being able to use matrix variables inside uses 2023-02-10 13:58:41 +01:00
Jonas Platte 4a5a0293a9 ci: Replace unmaintained actions-rs/cargo action
… we really didn't need it and can use run instead.
2023-02-10 13:58:41 +01:00
Jonas Platte 3f16b324d7 ci: Use taiki-e/install-action to install cargo-tarpaulin 2023-02-10 13:58:41 +01:00
Jonas Platte a5bfab1d55 ci: Replace unmaintained actions-rs/toolchain action
… with dtolnay/rust-toolchain.
2023-02-10 13:58:41 +01:00
Jonas Platte e430f65ce8 ci: Exclude Debug implementations from coverage reports
We don't really want to check for exact representations, and otherwise
they are really just invoked in tests that fail.
2023-02-10 13:46:00 +01:00
Jonas Platte 441626bf68 ci: Exclude uniffi-bindgen from coverage checks 2023-02-10 13:02:31 +01:00
Jonas Platte 02e51a9cb9 ci: Test sqlite crypto store in coverage check 2023-02-10 13:02:31 +01:00
Jonas Platte 4492df6fc6 test(sdk): Add a test for retrying edit decryption 2023-02-10 12:41:05 +01:00
Jonas Platte 573b672470 fix(sdk): Fix handling of UTD "insivible" events
(ones which don't produce a timeline item on their own)
2023-02-10 12:41:05 +01:00
Jonas Platte fe3c73602f refactor(sdk): Always add UTD events to the timeline
… as currently this is the only way decryption can be retried.
2023-02-10 12:41:05 +01:00
Jonas Platte fd2dc18746 refactor(sdk): Retry event decryption in timeline item order
This works better for relations.
2023-02-10 12:41:05 +01:00
Jonas Platte 55549f61be test(sdk): Split timeline tests into smaller modules 2023-02-10 12:41:05 +01:00
Jonas Platte cf359dede5 chore: Upgrade rust-cache GitHub action 2023-02-10 12:16:06 +01:00
Ivan Enderlin 13f50fbf6c fix(sdk): Remove Deref impl for SlidingSyncRoom
fix(sdk): Remove `Deref` impl for `SlidingSyncRoom`
2023-02-09 16:32:31 +01:00
Ivan Enderlin 0f7646ade1 chore: Make Clippy happy. 2023-02-09 16:16:31 +01:00
Ivan Enderlin 4e1fe3bec4 chore: Fix a function renaming. 2023-02-09 15:49:55 +01:00
Ivan Enderlin c6d99305d5 fix(labs): Fix jack-in. 2023-02-09 15:46:08 +01:00
Ivan Enderlin c86ebaddd2 Update crates/matrix-sdk/src/sliding_sync.rs
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
2023-02-09 15:36:13 +01:00
Benjamin Kampmann 048d6a774c docs(sliding-sync): improved language
Co-authored-by: Ivan Enderlin <ivan@mnt.io>
2023-02-09 14:13:41 +01:00
Ivan Enderlin 43f2f60bfd fix(sdk): Remove Deref impl for SlidingSyncRoom.
This implementation is wrong in the sense of its semantics is not about
dereferencing a thin pointer to something, but just to give access to one
specific field of the entire structure. That's not how `Deref` is supposed to
be used.

Moreover, it creates conflict between the `SlidingSyncRoom.timeline` field,
and `SlidingSyncRoom.inner.timeline` field, which both exist, but not for the
same purposes. It creates confusion in the code.

Finally, it's better to expose proper getters to the outside world, so that we
control _and_ test _and_ know exactly what API we provide.
2023-02-09 13:09:22 +01:00
Gabriel Féron 12cbff2688 refactor(sdk): Use spawn_blocking when generating attachment thumbnails 2023-02-09 09:54:43 +01:00
Jonas Platte bdab40a772 refactor: Fix clippy lint str_to_string in sliding sync tests 2023-02-08 17:52:31 +01:00
Jonas Platte 87de9c7453 refactor(sled): Remove unused re-export 2023-02-08 17:52:31 +01:00
Benjamin Kampmann 765959758b docs(sliding-sync): Document cold-cache, reactive-api and bot-mode 2023-02-08 16:54:06 +01:00
Jonas Platte efdeba79f9 chore: Upgrade workspace dependencies 2023-02-08 16:04:29 +01:00
Jonas Platte e25061f8cb refactor(crypto)!: Unwrap unused Result 2023-02-08 16:04:29 +01:00
Jonas Platte 345f4f39f4 refactor(sqlite): Make Error more precise / useful 2023-02-08 15:44:17 +01:00
Jonas Platte e12b9e3027 refactor(sqlite): Encode olm hashes with rmp instead of serde_json
… like everything else in the sqlite crypto store.
2023-02-08 15:44:17 +01:00
Jonas Platte a22529344a refactor(sqlite): Inline inherent methods that duplicate trait methods 2023-02-08 15:44:17 +01:00
Jonas Platte 64b7c4eb59 refactor(sqlite): Make OpenStoreError more precise / useful 2023-02-08 15:44:17 +01:00
Jonas Platte 1988d1e9a3 refactor(sqlite): Move sqlite extension traits to utils module 2023-02-08 15:44:17 +01:00
Jonas Platte efc2397267 refactor(sqlite): Always use rusqlite::Error for sqlite extension traits 2023-02-08 15:44:17 +01:00
Jonas Platte ecb521205f refactor(sqlite): Move error types into new error module 2023-02-08 15:44:17 +01:00
Jonas Platte 7db40746bb refactor(sqlite): Start cleaning up cfg attributes 2023-02-08 15:44:17 +01:00
Benjamin Kampmann 3639215d53 docs(sliding-sync): long polling and quick refreshing explained 2023-02-08 13:29:38 +01:00
Benjamin Kampmann d51e9694f6 fix(sliding-sync): Set as default view mode 2023-02-08 12:43:32 +01:00
Jonas Platte ae21a56be2 chore: Add missing copyright headers 2023-02-08 11:15:02 +01:00
Kévin Commaille c252b984e0 refactor(sdk): Use a builder pattern to construct Timeline
`Timeline::with_fully_read_tracking` was public although all public
Timeline constructors enable it by default.
It is also meant to be called when constructing the timeline so
using a builder pattern makes sense.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-08 10:46:59 +01:00
Benjamin Kampmann 300fdec83f docs(sliding-sync): First half of sliding sync API docs 2023-02-07 22:41:58 +01:00
Jonas Platte ee9d47f647 refactor(crypto): Remove confusing explicit Sized bound
The bound is there by default, no need to put it in explicitly.
2023-02-07 18:45:32 +01:00
Jonas Platte 2e80073f28 refactor(crypto): Use IntoCryptoStore for OlmMachine::with_store 2023-02-07 18:45:32 +01:00
Jonas Platte c3d5932a0f refactor(crypto): Move store::{CryptoStoreError, Result} into new module 2023-02-07 18:45:32 +01:00
Doug 7fdccfcea4 chore(bindings): Rename property and use feature flag. 2023-02-07 15:22:39 +00:00
Doug 630836b3c7 chore(bindings): Store the proxy URL directly in Client. 2023-02-07 15:22:39 +00:00
Doug 3705925a22 chore(bindings): Persist the sliding sync proxy.
Added to the Session for automatic restoration.
2023-02-07 15:22:39 +00:00
Doug b7a3ab7c5b feat(ffi): Sliding sync proxy discovery. 2023-02-07 15:22:39 +00:00
Jonas Platte 5692480112 refactor(crypto): Remove unused method 2023-02-07 15:59:19 +01:00
Jonas Platte 5b63bd4cf1 refactor(crypto): Reduce direct visibility of some internal types
They weren't being exported from any public modules before.
This helps human readers as well as some compiler lints.
2023-02-07 15:59:19 +01:00
Jonas Platte 9711e1b2f5 refactor(crypto): Move (Into)CryptoStore traits into a new module 2023-02-07 15:59:19 +01:00
Damir Jelić a17346158f docs(sdk): Fix the sliding sync builder example 2023-02-07 14:26:33 +01:00
Damir Jelić 30ddbab686 refactor(sdk): Move the bulk of the sliding sync logic into a sync_once method 2023-02-07 14:26:33 +01:00
Jonas Platte b436918cb3 fix(sqlite): Fix Debug output for SqliteCryptoStore 2023-02-06 17:08:21 +01:00
Jonas Platte b20424b8b5 chore(sqlite): Undo weird formatting of TOML file 2023-02-06 17:08:21 +01:00
Ivan Enderlin 5f933b1033 feat(sdk): Simplify code by using std::cmp::min
feat(sdk): Simplify code by using `std::cmp::min`
2023-02-06 14:46:46 +01:00
Ivan Enderlin 5e8224f19c feat(sdk): Simplify code by using std::cmp::min. 2023-02-06 13:43:01 +01:00
Damir Jelić e68134dd53 chore(crypto): Improve the logs for the OlmMachine constructor 2023-02-06 13:31:00 +01:00
Damir Jelić 945c16a7fb feat(crypto): Throw an error if our user/device pair isn't what we have in the store 2023-02-06 13:31:00 +01:00
dependabot[bot] fc8cd2e7e5 chore(deps): bump tokio from 1.24.1 to 1.24.2
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.24.1 to 1.24.2.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/commits)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-04 08:27:50 +01:00
Damir Jelić 4115975135 fix(bindings): Expose the OpenTelemetry logging for other platforms as well 2023-02-03 22:30:11 +01:00
Damir Jelić 35a26be7b0 chore(sdk): Record the sliding sync pos in our logs 2023-02-03 16:51:33 +01:00
Jonas Platte 052832b4d3 fix: Don't log raw events that fail deserialization
… but do log relevant parts to allow debugging.
2023-02-03 14:35:10 +01:00
Richard van der Hoff e516e15d2b matrix-sdk-crypto-js v0.1.0-alpha.4
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 31s
2023-02-03 12:17:37 +01:00
Ivan Enderlin 2bc9407563 feat(sdk): Remove SlidingSyncView.rooms
feat(sdk): Remove `SlidingSyncView.rooms`
2023-02-03 11:51:25 +01:00
Jonas Platte 47f8b6cb79 feat(ffi): Add Room::fetch_members 2023-02-02 17:48:26 +01:00
Jonas Platte e11dd099d8 feat(sdk): Add Timeline::fetch_members 2023-02-02 17:48:26 +01:00
Jonas Platte c294a376e8 refactor(sdk): Use TimelineDetails for sender profile 2023-02-02 17:48:26 +01:00
Jonas Platte ffa0190517 refactor(sdk): Add missing feature-gate
… for fn that is only used from sliding-sync.
2023-02-02 17:48:26 +01:00
Jonas Platte 3a863fa8fb refactor(sdk): Remove unnecessary inner block in function 2023-02-02 17:48:26 +01:00
ganfra 75d396e2ec Merge branch 'main' into ganfra/kotlin_binding_scripts 2023-02-02 17:10:34 +01:00
Ivan Enderlin 672a640854 chore(labs): Update to later changes. 2023-02-02 15:27:18 +01:00
Ivan Enderlin 40010cd511 Merge branch 'main' into feat-sliding-sync-view-rooms 2023-02-02 15:26:30 +01:00
Ivan Enderlin a6d33fcd16 feat(labs): Update jack-in to the new sliding sync room API. 2023-02-02 15:22:41 +01:00
Ivan Enderlin d08606e3b9 feat(sdk): SlidingSync::get_room now takes a ref to OwnedRoomId
feat(sdk): `SlidingSync::get_room` now takes a ref to `OwnedRoomId`.
2023-02-02 14:06:14 +01:00
Ivan Enderlin ae8a8c6cc3 feat(sdk): SldingSync::get_room takes a &RoomId. 2023-02-02 13:36:32 +01:00
Ivan Enderlin 0d87d0f786 feat(sdk): Remove SlidingSyncView.rooms.
`SlidingSyncView` exposes a `room` field. Problem: It's not updated
correctly and leads to error. The canonical way to get a room is by using
`SlidingSync::get_room`. This patch thus removes `SlidingSyncView.rooms`
entirely.
2023-02-02 13:31:46 +01:00
Ivan Enderlin a9ba2dd546 feat(sdk): SlidingSync::get_room now takes a ref to OwnedRoomId.
Before this patch, `SlidingSync::get_room` was taking ownership of an
`OwnedRoomId`, to only use it as a reference. Thus, calling this method was
creating useless clones.

This patch updates `SlidingSync::get_room` to receive a reference to
`OwnedRoomId`.
2023-02-02 13:25:36 +01:00
Kévin Commaille 00638ba74c feat(sdk): Allow to fetch replied to messages
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-02-02 13:06:11 +01:00
ganfra 6a7b28c085 Merge branch 'main' into ganfra/kotlin_binding_scripts 2023-02-02 11:52:32 +01:00
ganfra 1bcd8c7aae Comment remove gradle_build 2023-02-02 11:50:47 +01:00
Jonas Platte ce973b35e9 chore: Upgrade uniffi to 0.23.0 2023-02-02 10:15:05 +01:00
Jonas Platte 8a1b1eccd6 doc(sdk): Fix docs that refer to TimelineKey 2023-02-02 10:15:05 +01:00
Jonas Platte e068b4987e doc(sdk): Document what happens when timeline event sending fails 2023-02-02 10:14:23 +01:00
Jonas Platte 3a1eb62c38 refactor(sdk): Expose event sending errors through timeline item
… instead of through the return value of Timeline::send.
2023-02-02 10:14:23 +01:00
Jonas Platte c8021cf2ba refactor(sdk): Move LocalEventTimelineItem#event_id into send_state 2023-02-02 10:14:23 +01:00
Jonas Platte a48fd77c4a refactor(sdk): Rename LocalEventTimelineItemSendState => EventSendState 2023-02-02 10:14:23 +01:00
Damir Jelić ab0e27622e feat(bindings): Add support to setup a OpenTracing based logger 2023-02-01 22:55:47 +01:00
Damir Jelić 7b044ef5dd fix(crypto): Ignore the usage and signatures when comparing cross signing keys
Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
2023-02-01 18:25:48 +01:00
Benjamin Kampmann 8a9b72ae6c test(sliding-sync): ensure unknown pos does recover the room subscription properly 2023-02-01 17:37:16 +01:00
Anderas e9cef35f99 Add matrix-sdk-sqlite with a CryptoStore implementation
Note about "Write-Ahead Log" (WAL) mode: The SQLite WAL mode has a
bunch of advantages that are quite nice to have:

1. WAL is significantly faster in most scenarios.
2. WAL provides more concurrency as readers do not block writers and a
   writer does not block readers. Reading and writing can proceed
   concurrently.
3. Disk I/O operations tends to be more sequential using WAL.
4. WAL uses many fewer fsync() operations and is thus less vulnerable
   to problems on systems where the fsync() system call is broken.

The downsides of WAL mode don't really affect us. So let's turn it on.

More info: https://www.sqlite.org/wal.html

Co-authored-by: Jonas Platte <jplatte@matrix.org>
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
2023-02-01 15:06:59 +01:00
Damir Jelić 3a183b4c22 chore(sdk): Tweak the instrumentation for some encryption related methods 2023-02-01 10:16:14 +01:00
Richard van der Hoff 5dbee7dcdc fix(indexeddb): correctly encode Olm session keys
When we store an Olm session in the database, we encode the sender key and
session ID using the store cipher. That means that we also need to encode them
when we look them up, otherwise we won't find them.
2023-01-31 16:59:22 +01:00
Benjamin Kampmann b9b00743c9 fix(sliding-sync): catching up on new count for full-sync views 2023-01-31 15:02:19 +00:00
Benjamin Kampmann 14be1f888a test(sliding-sync): integration test for UnknownPos 2023-01-31 15:02:19 +00:00
Benjamin Kampmann a77295120a fix(sliding-sync): fixing restarting growing view 2023-01-31 15:02:19 +00:00
Benjamin Kampmann a6ad0e35b3 style(sliding-sync): improved style and docs 2023-01-31 14:03:43 +00:00
Benjamin Kampmann 5b3ec33ddc chore: Update to specific, supported ruma and sliding-sync-proxy-version. 2023-01-31 14:03:43 +00:00
Benjamin Kampmann aa10e70851 feat(sliding-sync): enable gzip when enabling sliding-sync 2023-01-31 14:03:43 +00:00
Benjamin Kampmann 826b2874ec ffi: expose sliding sync extension enabling 2023-01-31 14:03:43 +00:00
Benjamin Kampmann 8f17b6c38d feat(sliding-sync): add Receipt and Typing extension config 2023-01-31 14:03:43 +00:00
Benjamin Kampmann 9ae9c98340 test(sliding-sync): activate live views test 2023-01-31 14:03:43 +00:00
Benjamin Kampmann f6da282557 feat(sliding-sync): add delta-token support 2023-01-31 14:03:43 +00:00
Benjamin Kampmann 9ad34e8565 chore(sliding-sync): update to latest sliding-sync JSON layout 2023-01-31 14:03:43 +00:00
Benjamin Kampmann a973c372e6 chore: use local volumes for testing server 2023-01-31 14:03:43 +00:00
Ivan Enderlin 00e93e08e7 feat(sdk): Add EventTimelineItem::unique_identifier. 2023-01-31 13:21:19 +01:00
Kévin Commaille 75a2d2d92c fix(sdk): Aggregate reactions locally
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-01-31 12:11:44 +00:00
Jonas Platte e066346b16 feat(bindings): Clear the timeline when sliding-sync loop is reset 2023-01-31 11:49:25 +01:00
Jonas Platte 754453c135 refactor: Import tracing macros instead of using qualified paths 2023-01-31 11:49:25 +01:00
Jonas Platte c481caf060 refactor: Clean up format strings 2023-01-31 11:49:25 +01:00
Jonas Platte 6d868908cb refactor(sdk): Remove unused Result 2023-01-31 11:49:25 +01:00
Jonas Platte d2678e2f01 refactor(sdk): Remove unused async 2023-01-31 11:49:25 +01:00
Jonas Platte c24316e5e3 refactor(sdk): Remove unused lifetime parameter 2023-01-31 11:49:25 +01:00
Jonas Platte 48bc5b9b7e refactor(sdk): Work around receiving event with txn-id multiple times 2023-01-30 20:12:44 +01:00
Jonas Platte 01c828ed4b chore(sdk): Remove weird space 2023-01-30 20:12:44 +01:00
Benjamin Kampmann 102994b030 feat(sliding-sync): allow updating the timeline limit at runtime 2023-01-30 16:05:19 +00:00
Ivan Enderlin 38dfa90441 feat(sdk): LocalEventTimelineItem has a new send_state field
feat(sdk): `LocalEventTimelineItem` has a new `send_state` field
2023-01-30 14:08:47 +01:00
Ivan Enderlin 274bc20603 doc(sdk): Fix typos. 2023-01-30 13:58:00 +01:00
Ivan Enderlin c8d561d17d feat(ffi): Add LocalEventTimelineItemSendState + EventTimelineItem::local_send_state. 2023-01-30 13:51:29 +01:00
Ivan Enderlin 8ea2cef55d feat(sdk): LocalEventTimelineItem has a new send_state field.
This patch is trying to resolve the following issue:

When a local event is sent to the server, in case of an error, the
`Timeline::send` method just returned the error but it wasn't reflected inside
the `LocalEventTimelineItem` type itself. It's easy to loss this information.

So now, there is a new enum: `LocalEventTimelineItemSendState` with 3 states:

1. `NotSentYet`, when the local event has not been sent yet, it's theorically
   the initial state,
2. `SendingFailed`, when the local event has been sent but it's failed!
3. `Sent`, when the local event has been sent successfully.

Therefore, the `LocalEventTimelineItem` struct has a new field: `send_state`.

The send state is managed by its `with_event_id` method which now receives an
`Option<OwnedEventId>` (prev. `OwnedEventId` directly):

* If it's `Some(_)`, then it means we got a successful response from the server
  after the sending, so the send state is set to `Sent`,
* If it's `None`, then it means we got an error response from the server, so
  the send state is set to `SentFailed`.

(A small change: The method `TimelineInner::add_event_id` has been renamed
`TimelineInner::update_event_id_of_local_event`.)

The `Timeline::send` still returns a `Result`, but the server's response is
passed to a new method: `TimelinerInner::handle_local_event_send_response`
(it's logically named after the `handle_local_event` method), which is
responsible to call `TimelineInner:update_event_id_of_local_event` (which was
previously called directly by `Timeline::send`).

And `TimelineInner::update_event_id_of_local_event` was already calling
`LocalEventTimelineItem::with_event_id`. So everything works like a charm here.

The local send state is closely managed by `LocalEventTimelineItem`, I hope it
will avoid state breakage as much as possible.
2023-01-30 11:47:38 +01:00
Ivan Enderlin 4086492ef9 feat(sdk): EventTimelineItem is now an enum … { Local(…), Remote(…) }
feat(sdk): `EventTimelineItem` is now an `enum … { Local(…), Remote(…) }`
2023-01-30 11:03:49 +01:00
Ivan Enderlin 6bfa3df691 chore(sdk): Replace ref by &. 2023-01-30 10:20:44 +01:00
Ivan Enderlin f4607146e2 chore(sdk): Replace ref by &. 2023-01-30 10:13:54 +01:00
Ivan Enderlin 0a7193de62 chore(sdk): Remove useless custom Debug impl. 2023-01-30 09:30:12 +01:00
Ivan Enderlin 5c2e6b2743 chore(sdk): Simplify code. 2023-01-30 08:58:26 +01:00
Ivan Enderlin 47256eb4f9 chore(sdk): Remove a warning for an unused variable. 2023-01-30 08:50:47 +01:00
Ivan Enderlin 1c8d57321c chore(sdk): Remove Flow.timestamp and .raw_event. 2023-01-30 08:50:08 +01:00
Ivan Enderlin 322aa776f2 feat(sdk): Remove LocalEventTimelineItem.encryption_info and .raw, and Remote….raw is no more an Option. 2023-01-30 08:49:48 +01:00
ganfra 517b71cb06 kotlin bindings: replace shell by xtask scripts 2023-01-27 16:29:44 +01:00
Ivan Enderlin 17a9c4829d chore(sdk): Make Clippy happy. 2023-01-27 15:25:37 +01:00
Ivan Enderlin 59a5805af7 chore(sdk): Remove commented code. 2023-01-27 15:14:10 +01:00
Ivan Enderlin 882f3cad25 chore(sdk): Simplify code by using Into<EventTimelineItem> for LocalEventTimelineItem`. 2023-01-27 15:12:38 +01:00
Ivan Enderlin 5ce3c45637 chore(sdk): Simplify code by importing a type. 2023-01-27 15:07:42 +01:00
Ivan Enderlin ab617ddda0 chore(sdk): Fix a typo in an error message. 2023-01-27 15:05:27 +01:00
Ivan Enderlin 3a1c5580e7 chore(sdk): Fix a typo in an error message. 2023-01-27 15:03:49 +01:00
Ivan Enderlin 8486976804 feat(ffi): Update EventTimelineItem::reactions to return an Option. 2023-01-27 14:59:47 +01:00
Ivan Enderlin 8f13bb5ca5 feat(ffi): Add the EventTimelineItem::is_local and is_remote method. 2023-01-27 14:59:27 +01:00
Ivan Enderlin 7257cff5fe docs: Add the ffi scope. 2023-01-27 14:58:54 +01:00
Ivan Enderlin eb47869a45 feat(ffi): Remote TimelineKey. 2023-01-27 14:58:34 +01:00
Ivan Enderlin 636f4f8f8d feat(sdk): Remove the TimelineKey type. 2023-01-27 14:41:01 +01:00
Damir Jelić 819f962419 fix(sdk): Retry decryption if you initialize a Timeline with some events
The sliding sync logic has another room type called `SlidingSyncRoom`.

This room type stores a limited amount of events in something called
`AliveRoomTimeline` in a in-memory cache. This room also gets persisted
to the store via another room type called `FrozenSyncRoom`.

These types are used when clients restore their view of the room, i.e.
when the user enters the room to look at messages.

When the client enters a room, a `Timeline` object will be created, but
it will be initially populated with events coming from
`AliveRoomTimeline`.

In a hot potato contest of who should be responsible to decrypt injected
events, everybody claims to be allergic to potatoes.

This patch modifies the `Timeline` constructor that populates the
timeline with events from the `AliveTimeline` to retry decryption on the
events that the `AliveTimeline` pushes into the `Timeline`.

Note that, because the `AliveRoomTimeline` never replaces encrypted
events with decrypted ones, every time the client enters/exits the room
events well get re-decrypted.
2023-01-27 14:07:41 +01:00
Ivan Enderlin 3c9e84397a test(sdk): Update tests since the new EventTimelineItem type. 2023-01-27 14:00:41 +01:00
Ivan Enderlin f7bf6ba220 feat(sdk): Rewrite EventTimelineItem as an enum: Local and Remote. 2023-01-27 13:26:31 +01:00
Denis Kasak 539cbee087 test(crypto): Test failure when deserializing cross-signing keys with incorrect usage. 2023-01-26 17:01:00 +01:00
Damir Jelić d442cac936 refactor!(crypto): Directly deserialize into per usage cross signing key type
This moves the usage checking directly into our deserialization path.
2023-01-26 17:01:00 +01:00
Damir Jelić 72ed024303 fix(crypto): Make sure the master key self-signs as well
This is an omission from the spec where the subkeys are supposed to be
signed by the master key, but signing the master key wasn't mentioned.

This is still fine, since we always treated the master key and their
subkeys as a whole and never accepted one without the others.
2023-01-26 17:01:00 +01:00
Damir Jelić 148c4907b5 fix(crypto): Inspect the key usage when receiving cross signing keys 2023-01-26 17:01:00 +01:00
Ivan Enderlin 8c91314b58 feat(sdk): Move EventTimelineItem.event_id into TimelineKey::TransactionId
feat(sdk): Move `EventTimelineItem.event_id` into `TimelineKey::TransactionId`
2023-01-26 15:07:40 +01:00
Ivan Enderlin 9006bd1bba chore(sdk): Address review feedback. 2023-01-26 14:55:16 +01:00
Kévin Commaille 32e7209c66 refactor(sdk): Split room member events between membership and profile change
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-01-26 14:24:59 +01:00
Ivan Enderlin 4dfa41ce8f doc(sdk): Simplify if let into let
doc(sdk): Simplify `if let` into `let`
2023-01-26 14:24:35 +01:00
Ivan Enderlin 1a5ead58f6 feat(sdk): Move EventTimelineItem.event_id into TimelineKey::TransactionId.
To create an event next to the server, the event must be accompanied by
a transaction ID. When the server receives the event creation request, it
responds with a new event ID (which we will name `event_id_1`). Later on, when
a sync is done to the server, the server may respond with the transaction ID
and a new event ID (which we will name `event_id_2`).

The transaction ID is used to update the state of the local event. The event
ID received from the sync may ideally be the same as the one received by the
creation request's response.

Knowing that…

`EventTimelineItem` had a field: `event_id: Option<OwnedEventId>`. It was
`Some(event_id)` where `event_id` is the event ID responded by the server when
an event was created, i.e. it's `event_id_1`; otherwise it was `None`. This is
never `event_id_2`. Why?

Because `EventTimelineItem` has an other field: `key: TimelineKey`, which
represents the following states:

* `TimelineKey::TransactionId(OwnedTransactionId)`,
* `TimelineKey::EventId(OwnedEventId)`, where the event ID is `event_id_2`!

So it becomes obvious that `event_id_1` should be part of `TimelineKey`, not
`EventTimelineItem`. `TimelineKey` is where this transaction ID and event ID
logic is managed.

This patch updates `TimelineyKey::TransactionId` to be defined as:

* `TimelineKey::TransactionId { txn_id: OwnedTransactionId, event_id: Option<OwnedEventId> }`.

Why an `Option`? Because before receiving `event_id_1`, we may still want to
create a `TimelineKey`, the API must reflect that state.

So basically, `EventTimelineItem.event_id` is moved inside
`TimelineyKey::TransactionId`.
2023-01-26 11:36:42 +01:00
Jonas Platte 220617fd04 fix(sdk): Update add_event_id logs to make more sense 2023-01-26 10:59:28 +01:00
Jonas Platte a37ce68eae fix(sdk): Only look for local echoes for events appended to the timeline
… rather than prepended, or added at a specific point as replacement for
an existing timeline item.
Previously, we would log lots of useless tracing events when retrying to
decrypt UTD items.
2023-01-26 10:55:41 +01:00
Ivan Enderlin 0c4ca84eec test(sdk): Improve m.fully_read test coverage and documentation
test(sdk): Improve `m.fully_read` test coverage and documentation
2023-01-26 10:16:48 +01:00
Ivan Enderlin 77b7451f59 doc(sdk): Fix a typo. 2023-01-26 10:06:11 +01:00
Ivan Enderlin bac105a9aa doc(crypto-nodejs): Fix a typo. 2023-01-26 09:59:15 +01:00
Ivan Enderlin 832bba8a2b test(sdk): Improve m.fully_read test coverage and documentation. 2023-01-26 09:46:47 +01:00
Jonas Platte 0e39a7cbf2 chore: Upgrade Ruma 2023-01-25 18:01:12 +01:00
Jonas Platte db11940f8f test(sdk): Fix clippy warning 2023-01-25 18:01:12 +01:00
Damir Jelić 4ef654f1d1 chore: Bump the Ruma version 2023-01-25 18:01:12 +01:00
Ivan Enderlin 793e18e44f Merge pull request #1388 from matrix-org/release-matrix-sdk-crypto-js-v0.1.0-alpha.3
Release matrix-sdk-crypto-js v0.1.0-alpha.3
2023-01-25 12:56:41 +01:00
Ivan Enderlin 578b446ea4 chore(sdk): Rename a variable to clarify its content. 2023-01-25 11:00:03 +01:00
Ivan Enderlin 3fe5f13df4 doc(sdk): Simplify if let into let. 2023-01-25 10:58:46 +01:00
Ivan Enderlin 54f00dc05a feat(crypto-nodejs) Implement OlmMachine.close.
This patch fixes https://github.com/matrix-org/matrix-rust-sdk/issues/1379/.

This is similar to https://github.com/matrix-org/matrix-rust-sdk/pull/1197/.
We need to close the `OlmMachine`. Problem, `napi-rs` doesn't allow methods to
take ownership of `self`, so the following code:

```rs
fn close(self) {}
````

isn't allowed. There an [`ObjectFinalize`](https://docs.rs/napi/latest/napi/bindgen_prelude/trait.ObjectFinalize.html)
trait, but it's only called when the JS value is being collected by the GC.
It's not possible to force call `finalize` here.

This patch then introduces a new type:

```rs
enum OlmMachineInner {
  Opened(matrix_sdk_crypto::OlmMachine),
  Closed
}
```

that derefs to `matrix_sdk_crypto::OlmMachine` when its variant is `Opened`,
otherwise it panics. Calling the new `OlmMachine::close` method will change the
inner state from `Opened` to `Closed`.

Ideally, I wanted to throw an error instead of panicking, but `napi_env`
(used to build an `Env`, used to throw an error) is neither `Sync` nor `Send`.
Honestly, my knowledge of NodeJS and NAPI is too weak to implement `Sync`
and `Send` for `*mut napi_env__` safely. Especially because it can be executed
from various threads within `async fn` functions, that are driven by Tokio in
`napi-rs`. So, yeah, for the moment, it panics!
2023-01-25 09:56:21 +01:00
Benjamin Kampmann 464e40bc32 fix(ffi): add erroneously removed loop 2023-01-24 15:41:12 +00:00
Benjamin Kampmann f22660d5e9 chore(sliding-sync): more logging information 2023-01-24 15:41:12 +00:00
Andy Uhnak 2db1bc75c1 Expose MissingRoomKey decryption error 2023-01-24 16:27:02 +01:00
Damir Jelić 18ec101719 refactor!(crypto): Move some caches out of the CryptoStore implementations
This moves the caches we have for tracked users out of the Sled, and
IndexedDB, CryptoStore into the Store struct. The Store struct is a
wrapper for the CryptoStore trait, so this is the natural place where
these caches should live.

Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-01-24 15:26:33 +00:00
Doug a762b2027f feat(bindings): Expose aliases to the FFI. 2023-01-24 16:12:39 +01:00
Jonas Platte 934181be44 refactor(sdk): Update confusing variable names 2023-01-24 13:43:55 +01:00
Jonas Platte 3d34743ae9 fix(sdk): Respect server ordering for remote echoes 2023-01-24 13:43:55 +01:00
Kévin Commaille 718864bfdd refactor(sdk): Provide day divider as a timestamp
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-01-24 12:29:15 +01:00
Benjamin Kampmann 24ac5b9f16 feat(sliding-sync): add configuration to inform about room changes without positional update 2023-01-24 10:30:07 +00:00
Benjamin Kampmann cc835da347 fix(sliding-sync): refresh timeline if server told us we are limited 2023-01-24 10:30:07 +00:00
Benjamin Kampmann 933eec2d1d fix(sliding-sync): switch Atomic Ordering from Relaxed to SeqCst 2023-01-24 10:30:07 +00:00
Benjamin Kampmann de4a8e3e7a chore(base): additional tracing information for sliding sync responses 2023-01-24 10:30:07 +00:00
Benjamin Kampmann b08c740181 fix(ffi): don't cancel the actual spawn, instead ensure it finishes processing before stopping the loop 2023-01-24 10:30:07 +00:00
Benjamin Kampmann 950bb83f8d style: use trace! instead of tracing::trace! 2023-01-24 10:30:07 +00:00
Benjamin Kampmann a06aa43dd1 feat(sliding-sync): cache room data next to view for selective unfreezing 2023-01-24 10:30:07 +00:00
Benjamin Kampmann a572f61edf tests: additional ignored tests for future scenarios 2023-01-24 10:30:07 +00:00
Benjamin Kampmann a964585e35 fix(sliding-sync): have views go live right at response processing 2023-01-24 10:30:07 +00:00
Benjamin Kampmann 71407a636c fix(sliding-sync): use single replace on cold and empty views
Before we'd push one empty entry at a time, which lead to a lot of vecdiff updates pushed. With this
we now only push one  event after the entire operation set has been applied on the fresh
or cold view.
2023-01-24 10:30:07 +00:00
Benjamin Kampmann b7a8a93a73 chore(sliding-sync): additional tracing around unfreezing from cold cache 2023-01-24 10:30:07 +00:00
Damir Jelić 600fd62dc5 crypto(fix): Fail to decrypt if there's a key mismatch
A mismatch between the recorded Ed25519 and Curve25519 keys of the room
key and the identity keys of a Device used to be just a warning.

Considering that many clients will aggressively try to hide E2EE related
warnings let's upgrade this clear error into a full blown decryption
failure.

Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
2023-01-24 09:14:42 +01:00
Damir Jelić 00d1437e5a chore(crypto): Log the full error messages when decrypting room events 2023-01-23 15:03:03 +01:00
Damir Jelić f774159e15 chore(crypto): Record the event id when decrypting a room event 2023-01-23 15:03:03 +01:00
Damir Jelić a1fba86f75 chore(crypto): Log the session id when we receive a room key 2023-01-23 15:03:03 +01:00
Damir Jelić 3c4d1cfb47 fix(sled): Don't load the tracked users with the Account
We might have a lot of tracked users, clients will usually have 1-10
thousand tracked users. This might slow down client startup if there are
so many tracked users.

We don't need the tracked users until we sync or try to send a message,
so load them lazily when they are first needed.
2023-01-23 13:35:51 +01:00
Damir Jelić 3ab95c74c7 refactor!(crypto): Make the methods related to tracked users async 2023-01-23 13:35:51 +01:00
Damir Jelić 8c1a81eebc chore: Fix the conventional commit type for documentation
The conventional commit specification recommends the "docs" type for
documentation related changes. This also matches the initial usage of
this type in our commit history.

While the default git-cliff config does specify a regex "^doc", where I
suspect our types have been taken from, this regex actually allows "doc"
as well as "docs" for the type.

Nevertheless, let's specify that we're using the one recommended in the
spec.
2023-01-20 20:30:06 +01:00
Richard van der Hoff acfa8a4190 docs(bindings): Fix return type documentation for get_missing_sessions 2023-01-20 20:09:42 +01:00
Richard van der Hoff 0771d73543 matrix-sdk-crypto-js v0.1.0-alpha.3
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 46s
2023-01-20 17:37:49 +00:00
Richard van der Hoff 92546acc85 chore(crypto-js): configuration for 'yarn version' 2023-01-20 17:37:40 +00:00
Richard van der Hoff c7f258d8b0 doc: Improve the documentation of "tracked users"
I had no idea what a tracked user was, so I've attempted to clarify this
somewhat for future readers.

Co-authored-by: Damir Jelić <poljar@termina.org.uk>
2023-01-20 14:02:02 +01:00
Jonas Platte 1e2fd02478 doc(base): Explain purpose of BaseClient#crypto_store 2023-01-20 10:56:09 +01:00
Stefan Ceriu b0c70dc606 chore(bindings): Exclude the target folder from the debug swift package
… to improve package loading time.
2023-01-20 09:00:36 +00:00
Benjamin Kampmann 0fea33de4d feat(ffi): expose server_versions on ClientBuilder 2023-01-19 21:31:57 +00:00
Damir Jelić 053b609899 chore(sdk): Add a prefix to the request id to make it easier to grep for them 2023-01-19 15:47:08 +01:00
Damir Jelić a54a421f91 chore(sdk): Log the response/request sizes as well 2023-01-19 15:46:49 +01:00
Ivan Enderlin 78147e0d33 doc(crypto-js): Fix wording. 2023-01-18 17:22:02 +01:00
Ivan Enderlin 430c573494 feat(crypto-nodejs): Request types have more fields.
Instead of putting all request fields inside a single `body` JSON-
encoded string  field, there is now more types. There is less need to call
`JSON.parse`, and the type system will be able to catch more things.

For example, `ToDeviceRequest` now has 2 more fields: `event_type` and
`txn_id`.
2023-01-18 17:21:52 +01:00
Ivan Enderlin 9db09e22b2 feat(crypto-js): Request types have fields extracted from their “body” directly
feat(crypto-js): Request types have fields extracted from their “body” directly
2023-01-18 13:41:14 +01:00
Ivan Enderlin 94fadf74b9 feat(crypto-js): Rename RoomMessageRequest.content to .body. 2023-01-18 13:31:26 +01:00
Ivan Enderlin 7c01f8490f test(crypto-js): Test `RoomMessageRequest.content. 2023-01-18 13:14:06 +01:00
Ivan Enderlin ca00112804 test(crypto-js): Add test for in-room verification (w/ RoomMessageRequest). 2023-01-18 11:42:34 +01:00
Benjamin Kampmann 6c0ef2db51 refactor(ffi): refactor stoppable spawn to be more token-oriented 2023-01-18 10:08:58 +00:00
Benjamin Kampmann 938a03867b feat(ffi): add subscribe_and_add_timeline_listener helper fn
re-applying the fixes from ##1346
2023-01-18 10:08:58 +00:00
Ivan Enderlin 90cce1a47c chore(crypto-js): Improve documentation, and do a little clean up. 2023-01-18 10:58:59 +01:00
Ivan Enderlin c427caf473 feat(crypto-js): Rename requests extra field to body. 2023-01-18 10:58:59 +01:00
Ivan Enderlin 3ad675db5c feat(crypto-js): Extract RoomMessageRequest.event_type from EventContent. 2023-01-18 10:58:59 +01:00
Ivan Enderlin efde81646b feat(crypto-js): Extract RoomMessageRequest.content as a JSON-encoded string. 2023-01-18 10:58:59 +01:00
Ivan Enderlin 8f9859c41c feat(crypto-js): Rename the body fields to extra to avoid confusion with HTTP terminology. 2023-01-18 10:58:58 +01:00
Ivan Enderlin 6248e2bc68 test(crypto-js): Update tests according to previous commit. 2023-01-18 10:58:58 +01:00
Ivan Enderlin c0ccd55df8 feat(crypto-js): request! differentiates “extracted” and “grouped” fields. 2023-01-18 10:58:58 +01:00
Ivan Enderlin b125b2e9da test(crypto-js): Update tests according to previous commit. 2023-01-18 10:58:58 +01:00
Ivan Enderlin 3c838b2f4a feat(crypto-js): Request types have fields from their “body” directly. 2023-01-18 10:58:58 +01:00
Jonas Platte f4fba3efb7 fix(bindings): Add user_id to RoomMembership
Without that, it is useless.
2023-01-18 09:58:36 +01:00
Jonas Platte e64b2f65da Revert "refactor(bindings): Fetch latest event earlier"
This reverts commit 7d1372195cf2af56c3d8ef95ac1b183ace8a5eec.
2023-01-18 09:31:45 +01:00
Doug 9e12a88e03 feat(bindings): Allow setting the store passphrase in the bindings
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
2023-01-18 06:45:21 +00:00
Anderas 0af38d9a76 fix(crypto): Mark our own identity as verified if we have the private part of the identity
Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
Co-authored-by: Damir Jelić <poljar@termina.org.uk>
2023-01-17 18:41:00 +00:00
Damir Jelić ade3a09848 chore(base): Remove a leftover unwrap 2023-01-17 19:13:29 +01:00
Damir Jelić 3641e0d540 docs(crypto): Note that the in-room verification events need to be decrypted 2023-01-17 18:11:53 +01:00
Damir Jelić e1d8c72d3a chore(crypto): Improve some docs
Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-01-17 18:11:53 +01:00
Damir Jelić c8d9581f8b refactor!(crypto): Don't process in-room verification implicitly 2023-01-17 18:11:53 +01:00
Kévin Commaille 8cc632ffd1 feat(sdk): Add support for state events in the timeline
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-01-17 12:10:19 +01:00
Kévin Commaille 1b7f4b4b42 fix(test): Fix position of prev_content in JSON
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-01-17 12:10:19 +01:00
Damir Jelić 928871d16e chore(sdk): Log the request body for sliding sync requests 2023-01-16 17:02:46 +01:00
Damir Jelić 87f5b251f5 chore(sdk): Add a request id counter to our HTTP client
This solves the issue of correlating different log lines that are talking
about the same request/response cycle. Plaintext logs would show this as
a flat structure, while something like Jaeger would show you a nice
tree. This allows you to reconstruct the tree in plaintext logs.
2023-01-16 17:02:46 +01:00
Damir Jelić e76272a68b chore(sdk): Improve the HTTP request sending logs 2023-01-16 17:02:46 +01:00
Damir Jelić b30c74cb01 chore(crypto): Bump the to-device event logging to debug 2023-01-16 16:23:58 +01:00
Jonas Platte 686541155f feat(sdk): Add display_name_ambiguous to timeline::Profile 2023-01-16 15:35:29 +01:00
Jonas Platte b256b6f625 refactor(bindings): Fetch latest event earlier
Does this crash?
2023-01-16 15:35:29 +01:00
Jonas Platte 7b913a0759 feat(bindings): Add EventTimelineItem::sender_profile 2023-01-16 15:35:29 +01:00
Jonas Platte 9e60a9dd3f feat(sdk): Attach profile information to timeline items 2023-01-16 15:35:29 +01:00
Jonas Platte 00bdb08973 refactor(sdk): Move locking of timeline_items into handle_remote_event 2023-01-16 15:35:29 +01:00
Jonas Platte ed70ccb988 refactor(sdk): Add trait ProfileProvider for use in TimelineInner 2023-01-16 15:35:29 +01:00
Jonas Platte e52af8a315 refactor(sdk): Make TimelineInner fields private 2023-01-16 15:35:29 +01:00
Jonas Platte b5450ee5ad test(sdk): Simplify TestTimeline construction 2023-01-16 15:35:29 +01:00
Jonas Platte b105b34cf6 refactor(sdk): Use regular struct update syntax for EventTimelineItem
The previous solution was annoying to maintain and only more efficient
without compiler optimizations.
2023-01-16 15:35:29 +01:00
Jonas Platte e0b0b632ec chore: Fix a typo 2023-01-16 11:31:03 +01:00
Jonas Platte 4febe45364 refactor(base): Make AmbiguityChange(s) non-exhaustive
They are meant to be consumed, but not created, by other crates.
2023-01-16 11:31:03 +01:00
Jonas Platte 70de11a73a refactor: Remove unused Deserialize, Serialize implementations 2023-01-16 11:31:03 +01:00
Jonas Platte 58f2d53293 doc(sdk): Update spec link 2023-01-16 11:31:03 +01:00
Doug 6540b9bb49 feat(bindings): Expose read receipts to FFI 2023-01-16 10:58:40 +01:00
Jonas Platte 6c53842599 chore: Bump ruma, vodozemac 2023-01-16 10:34:06 +01:00
Jonas Platte 663d043abb refactor: Always use Debug for logging enum or identifier values 2023-01-16 10:34:06 +01:00
Damir Jelić 386cbce344 Revert "feat(ffi): add subscribe_and_add_timeline_listener helper fn"
This reverts commit ba4e304cad.
2023-01-13 14:55:39 +01:00
Damir Jelić ece9252a3d chore(crypto): Add the sender and event type to the to-device handling span 2023-01-13 12:46:07 +01:00
Damir Jelić c13cb4957e chore(crypto): Don't use a JsOption needlessly. 2023-01-13 12:46:07 +01:00
Damir Jelić 1f34a016e5 chore(crypto): Add the to-device message id to the logs if there is one 2023-01-13 11:58:42 +01:00
Damir Jelić b8dd704658 refactor(crypto): Move the to-device event handling into a separate method 2023-01-13 11:58:42 +01:00
Benjamin Kampmann 273e96265f Merge pull request #1335 from gnunicorn/ben-sliding-sync-integration-test
Various smaller fixes on sliding-sync for elem-x:

 - Infrastructure and smoke test only for integration testing sliding-sync
 - Expose Pop and Clear on VecDiff
 - Expose adding views during sliding sync live runtime incl integration tests
 - bug fix on replacing only in-window-items in the insert-code (was leading to a wrong list setting), including integration test
2023-01-13 10:11:30 +00:00
Jonas Platte 0e3ea58aa4 Revert unrelated change 2023-01-13 10:51:52 +01:00
Benjamin Kampmann ba4e304cad feat(ffi): add subscribe_and_add_timeline_listener helper fn 2023-01-13 08:09:10 +00:00
Benjamin Kampmann 723e3a3135 tests(sliding-sync): minor style improvements 2023-01-12 19:53:57 +01:00
Kévin Commaille 1c754e663d fix(sdk): Make pagination strategy implement Send
Required when `PaginationOptions` must implement `Send`,
e.g. with `tokio::runtime::Runtime::spawn`.

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-01-12 19:24:47 +01:00
Damir Jelić 846844e67b fixup! chore(sdk): Re-export the AmbiguityChange type 2023-01-12 19:12:01 +01:00
Damir Jelić 51d96213ba chore(sdk): Re-export the AmbiguityChange type
This was forgotten to be re-exposed after it was moved to the base
crate.
2023-01-12 19:12:01 +01:00
Damir Jelić 80868919ae fix(crypto): Make the device update logic a bit more strict and obvious
When updating a device after we receive new device keys from a
/keys/query call we implicitly check that the user and device id match
since we need to fetch the device using the mentioned ids.

This moves the check into the update method as well to make it more
explicit. We also prevent upgrades of the Ed25519 key since we don't
support any different key type anyways.
2023-01-12 17:55:06 +01:00
Damir Jelić e3e9898f88 fixup! test(crypto): Check that we sign and verify fallback keys properly 2023-01-12 17:53:22 +01:00
Damir Jelić f2055f8069 test(crypto): Check that we sign and verify fallback keys properly 2023-01-12 17:53:22 +01:00
Damir Jelić 151f87a417 chore(crypto): Improve some docs
Co-authored-by: Denis Kasak <dkasak@termina.org.uk>
2023-01-12 17:37:06 +01:00
Damir Jelić 0e4f4d69b8 feat(crypto): Handle the failures field in the /keys/claim response 2023-01-12 17:37:06 +01:00
Damir Jelić 8db84a3c9e feat(crypto): Handle the failures field in the /keys/query response 2023-01-12 17:37:06 +01:00
Damir Jelić 1b18402707 feat(crypto): Add a TTL-cache that will handle failures for some requests 2023-01-12 17:37:06 +01:00
Benjamin Kampmann 6ec8ff6363 ci(coverage): ignore new sliding-sync-integration-tests for now 2023-01-12 13:51:59 +01:00
Benjamin Kampmann 906c09987f style(sliding-sync): minor style refinements 2023-01-12 13:24:16 +01:00
Benjamin Kampmann c93a9ef9a3 fix(sliding-sync): Simply room_range checking
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
2023-01-12 13:24:16 +01:00
Benjamin Kampmann 51f2e773a0 fix(ffi): add Pop and Clear to VecDiff for sliding-sync 2023-01-12 13:24:16 +01:00
Benjamin Kampmann 3c6c5f4fae ci: disable broken sliding-sync-integration-test-runs 2023-01-12 13:24:16 +01:00
Benjamin Kampmann a8d49b86df feat(sliding-sync): adding views on live sliding-sync 2023-01-12 13:24:16 +01:00
Benjamin Kampmann 2949dcc773 docs: Add a Readme to explain usage 2023-01-12 13:24:16 +01:00
Benjamin Kampmann b790bf9397 test(sliding-sync): add integration test covering #1333 2023-01-12 13:24:16 +01:00
Benjamin Kampmann 91941a5360 fix(sliding-sync): ensure we are only replacing items in the requested range 2023-01-12 13:24:16 +01:00
Benjamin Kampmann fabf0d40bc test: add test for moving window and rooms 2023-01-12 13:24:16 +01:00
Benjamin Kampmann 08bec243ff ci(sliding-sync): add sliding sync integration test 2023-01-12 13:24:16 +01:00
Benjamin Kampmann 60d82fde38 test: add sliding-sync integration-testing facilities 2023-01-12 13:24:16 +01:00
Jonas Platte 866158f6ff chore(sdk): Add logging for when timeline events are not handled 2023-01-11 17:14:09 +01:00
Kévin Commaille f883293168 chore: Update Ruma
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-01-11 16:05:02 +01:00
Damir Jelić c6e883da68 fix(sdk): Pass in to-device events to the OlmMachine unconditionally
The sliding sync proxy seems to have started to omit the e2ee extension
completely if no changes happened to the one-time key counts.

Our sync response processing assumed that, if there are some to-device
events that need to be passed to the OlmMachine, then we'll have some
data in the e2ee extension of the response as well. In other words, it
wouldn't pass in the to-device events to the OlmMachine if the e2ee
field of the sync response is `None`.

Since the assumption isn't true, we're going to pass in default values
for the one-time key counts when the e2ee extension field of the
response is `None`.
2023-01-11 14:18:40 +01:00
Damir Jelić cdfb51a606 refactor!(sdk): Add the experimental prefix to the sliding-sync feature 2023-01-11 11:54:32 +01:00
Damir Jelić 3e88905518 chore(sdk): Make the timeline feature a dependency of the sliding sync one 2023-01-11 11:54:32 +01:00
Damir Jelić 156c351023 chore(crypto): Instrument the receive_sync_changes method
This is mainly done so we create a span with the name of the function,
since we can filter logs by the name of the span we're now able to
enable logs for this method only.
2023-01-11 11:17:58 +01:00
Jonas Platte a98c1fd00d chore: Update Cargo.lock 2023-01-10 10:19:02 +01:00
Jonas Platte f4bfbdf97d chore: Upgrade base64 2023-01-10 10:19:02 +01:00
Jonas Platte 2e30e11101 refactor: Use workspace dependencies for more crates 2023-01-10 10:19:02 +01:00
Jonas Platte 3af6ba245c refactor: Fully replace matches crate with assert_matches 2023-01-10 10:19:02 +01:00
Benjamin Kampmann db1d31c9cc fix(sliding-sync): Do not implictly activate to-device extension upon unfreeze
Previously, when we found a since-token in the frozen state, we'd always activate the to-device extensions
regardless of whether the user had activated it in their builder or didn't. With this change we are only
setting the since parameter from cache if the user actually activated the to-device extension.
2023-01-10 10:04:31 +01:00
Jonas Platte 444a82fd9e fix(sdk): Small documentation update 2023-01-10 10:01:26 +01:00
Jonas Platte 6e218bdebc feat(sdk): Make pagination more flexible and smarter
- Don't actually fire off a request when the top of the timeline has
  already been reached
- Allow making multiple requests without removing the loading indicator
  in between
2023-01-10 10:01:26 +01:00
Jonas Platte 9b3bf5a4fa feat(sdk): Add TimelineStart virtual timeline item 2023-01-10 10:01:26 +01:00
Jonas Platte 237edcd747 refactor(sdk): Move day_divider constructor to TimelineItem 2023-01-10 10:01:26 +01:00
Jonas Platte 271e925adc refactor(sdk): Add and use TimelineItem::{read_marker, is_read_marker} 2023-01-10 10:01:26 +01:00
Benjamin Kampmann 514530c19a fix(sliding-sync): ensure last index is also invalidated
Index ranges are inclusive, but our loop would stop one short. This particuarly
tricky when the selective view is moved, as we didn't properly invalidate all items.
2023-01-09 22:48:57 +00:00
Benjamin Kampmann 58aec0d126 feat(uniffi): Add support to set list filters on sliding sync view builders (#1296)
* feat(uniffi): Add support to set list filters on sliding sync view builders
* fix: expose SlidingSyncRequestListFilters via proc-macros
2023-01-09 14:45:35 +00:00
dependabot[bot] 63c8696cac chore(deps): bump tokio from 1.22.0 to 1.23.1
Bumps [tokio](https://github.com/tokio-rs/tokio) from 1.22.0 to 1.23.1.
- [Release notes](https://github.com/tokio-rs/tokio/releases)
- [Commits](https://github.com/tokio-rs/tokio/compare/tokio-1.22.0...tokio-1.23.1)

---
updated-dependencies:
- dependency-name: tokio
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-07 14:06:32 +01:00
Damir Jelić 6aff4fc2c0 Update the bindings to use the SAS signalling (#1300)
* feat(bindings): Expose support for manually starting SAS verifications

Co-authored-by: Stefan Ceriu <stefanc@matrix.org>
2023-01-06 10:20:40 +01:00
Jonas Platte 8375c47f42 feat(sdk): Add pagination loading indicator as a virtual timeline item 2023-01-06 09:48:44 +01:00
Jonas Platte 1b2387bcb2 refactor(sdk): Enforce no pagination overlap in timeline
… by locking the pagination token for the entire duration of the API call.
2023-01-06 09:48:44 +01:00
Jonas Platte 1e71036b19 refactor(sdk): Simplify day divider matching 2023-01-06 09:48:44 +01:00
Jonas Platte e0f5dc97a5 refactor(bindings): Avoid single letter type aliases 2023-01-05 10:53:56 +01:00
Jonas Platte 64f367d474 feat(bindings): Expose all TimelineItemContent variants 2023-01-05 10:53:56 +01:00
Jonas Platte bb39c2aa9d feat(sdk): Persist sliding-sync to-device extension since value 2023-01-04 19:05:37 +01:00
Jonas Platte b82cd7fa5a refactor(common): Simplify wasm timeout implementation
… and remove an infinitely-recursive From impl in the process.
2023-01-04 18:59:11 +01:00
Jonas Platte 6780dc0312 refactor(sdk): Increase default request timeout to 30s 2023-01-04 17:55:18 +01:00
Damir Jelić 72519b7386 chore(labs): Use clap instead of structopt for jack-in
Update to clap v4 in jack-in
2023-01-04 12:49:50 +01:00
Jonas Platte c7b41e3fca test(sdk): Add a test for TimelineInner::add_initial_events 2023-01-04 12:44:51 +01:00
Marcel Kräml 5852d751bd Updated jack-in README.md for full-sync-mode lowercase options
Signed-off-by: Marcel Kräml <m.kraeml@kraeml.it>
2023-01-04 12:38:54 +01:00
Marcel Kräml cda596ebed Changed full_sync_mode to lowercase
Signed-off-by: Marcel Kräml <m.kraeml@kraeml.it>
2023-01-04 12:21:14 +01:00
Jonas Platte a5e17be3a1 refactor(bindings): Only create a timeline for SlidingSyncRoom if needed 2023-01-04 11:44:07 +01:00
Jonas Platte 33cdc108b5 chore(sdk): Log number of events in add_initial_events 2023-01-04 11:44:07 +01:00
Jonas Platte c3dfd2e744 refactor(sdk): Only lock timeline items if needed in add_initial_events 2023-01-04 11:44:07 +01:00
Jonas Platte 8ab5bb7fca refactor(sdk): Use HttpError::client_api_error_kind 2023-01-04 11:44:07 +01:00
Jonas Platte 80d8a8f41f refactor: Import tracing macros 2023-01-04 11:44:07 +01:00
Jonas Platte 46fe998a33 refactor(crypto): Improve logging 2023-01-03 13:09:09 +01:00
Jonas Platte 7efbba5d8b refactor(sdk): Improve logging in timeline::event_handler 2023-01-03 13:09:09 +01:00
Jonas Platte 907d50f773 refactor(sdk): Move TimelineInnerMetadata definition to timeline::inner 2023-01-03 13:09:09 +01:00
Jonas Platte 9cba98ae1b feat(sdk): Add num_updates to timeline PaginationOutcome 2023-01-03 09:44:23 +01:00
Jonas Platte 108950c706 refactor(sdk): Remove update_timeline_item
… inlining it into its only call site.
2023-01-03 09:44:23 +01:00
Jonas Platte 4452e15489 refactor(sdk): Rename TimelineEventHandler#event_added to item_created 2023-01-03 09:44:23 +01:00
Matthew Hodgson b026d90bcf fix(sdk): Handle to-device sliding sync extension correctly
Co-authored-by: Jonas Platte <jplatte@matrix.org>
2023-01-02 18:00:38 +00:00
Jonas Platte aa5f74ffb1 fix(sdk): Fix clippy lint 2023-01-02 12:45:50 +01:00
Jonas Platte 469c6cf104 fix(sdk): Don't log raw JSON which can contain personal data 2023-01-02 12:45:50 +01:00
Jonas Platte 3c5b005aae fix(sdk): Remove message contents from TimelineItem debug string 2023-01-02 12:45:50 +01:00
Marcel Kräml eef0bf4b91 Fixed clap for jack-in and update README.md
Signed-off-by: Marcel Kräml <m.kraeml@kraeml.it>
2022-12-23 11:29:21 +01:00
Marcel Kräml ad1011ec53 Replace structopt with clap in jack-in
Signed-off-by: Marcel Kräml <m.kraeml@kraeml.it>
2022-12-23 11:17:02 +01:00
Jonas Platte c215ac1f4b ci: Specify which version of wasm-pack we want 2022-12-22 16:06:48 +01:00
Jonas Platte 187696aa62 ci: Use latest version of wasm-pack-action 2022-12-22 16:06:48 +01:00
Jonas Platte e1e094f2f4 chore(sdk): Lower log level of event ID duplication event 2022-12-22 14:45:41 +01:00
Damir Jelić e2d4be2050 chore: Fix our build badge 2022-12-22 11:26:29 +01:00
Jonas Platte 7dc4d47d3c refactor(sdk): Store timeline event handler handles in a Vec
… instead of individual EventHandlerDropGuard's that each individually
hold a copy of Client.
2022-12-22 10:32:03 +01:00
Jonas Platte 9bad6faedd feat(sdk): Retry event decryption on forwarded room keys 2022-12-22 08:37:17 +01:00
Jonas Platte 3a715ea822 refactor(sdk): Move timeline m.room_key handler into new module 2022-12-22 08:37:17 +01:00
Jonas Platte f58f3fe055 chore(sdk): Add more logging to decryption retrying 2022-12-22 08:37:17 +01:00
Benjamin Kampmann 6eda742fff style(sliding-sync): explain why we limit the timeline items in freeze 2022-12-21 12:51:12 +00:00
Jonas Platte 14f451c6dd feat(bindings): Add decryption retrying to matrix-sdk-ffi 2022-12-21 13:35:27 +01:00
Benjamin Kampmann 562087a70e fix(sliding-sync): properly handle rooms_count == 1. fixes #1285 2022-12-21 10:13:39 +00:00
Benjamin Kampmann e3e0eb9144 fix(sliding-sync): sync view state for selective views.
Fixes ##1284
2022-12-21 10:13:39 +00:00
Benjamin Kampmann b6d48cb31a fix(sliding-sync): limit cold storage of timeline items to 10 and drop prev-batch token in case we'd store too many 2022-12-21 10:13:39 +00:00
Ivan Enderlin e4257f9aff feat(crypto-js): Make our promises reject with Error.
feat(crypto-js): Make our promises reject with `Error`.
2022-12-21 09:49:30 +01:00
Richard van der Hoff 6b871b0a48 matrix-sdk-crypto-js: Make our promises reject with Error
It's not a hard-and-fast-rule that Javascript exceptions should be `Error`
instances, but it's certainly a convention, and one that is going to reduce
surprises if we follow.
2022-12-20 22:36:42 +00:00
Jonas Platte 561fb97a7b feat(bindings): Add virtual timeline items to matrix-sdk-ffi 2022-12-19 13:54:55 +01:00
Jonas Platte a5080b6ed9 chore: Upgrade Ruma 2022-12-19 13:50:02 +01:00
Jonas Platte 8034ac20f9 refactor(base): Keep redaction events as Raw inside StateChanges 2022-12-19 13:50:02 +01:00
Jonas Platte f5c0ea4605 doc(bindings): Update docs for Apple platforms 2022-12-19 13:44:00 +01:00
Doug ddf448aa02 doc(bindings): Update docs for Apple platforms.
Remove old bash scripts now we have the xtask.
2022-12-19 12:31:29 +00:00
Kévin Commaille b960c372ac feat(sdk): Add support for stickers in the timeline 2022-12-19 08:39:07 +00:00
Jonas Platte 05e4bc0557 refactor: Don't reserialize member events before storing them 2022-12-15 18:19:35 +01:00
Jonathan de Jong d79c70177b Lab: The Setup Pattern 2022-12-15 16:48:55 +01:00
Kateřina Churanová db7eafb7d0 fix(doc): Fix unresolved link in documentation
Signed-off-by: Kateřina Churanová <k.churanova@famedly.com>
2022-12-14 22:00:25 +01:00
Anderas 9239470c1c feat(crypto): Add signalling to the verification requests and qr code verification 2022-12-14 19:15:22 +01:00
Benjamin Kampmann dab20638f9 fix(sliding-sync): new limit should default to None in builder 2022-12-14 14:06:31 +01:00
Benjamin Kampmann 273d0a0edf feat(sliding-sync): Growing window and limit count full sync (#1270)
Add a second full-sync-up mode to sliding sync. Previously - and still the default for backwards compatibility, but now named `PagingFullSync` - was to page through the list by the page-size, de-validating the previous page of items. The newly added `GrowingFullSync` instead grows the window by the given number `batch_size` per request, starting and keeping it from `0`. In the latter we might be pushing more data over the connection and are slightly slower, but the top always stays active and thus reactive to changes.

Furthermore the developer can now configure an optional maximum number to grow/paginate the full-sync up to (so stopping before actually having reached `count` whatever is smaller). This is already exposed via FFI, too.

- [x] add new full-sync-mode
- [x] add limited sync-up mode (similar to full sync but only to a limit `n`)
- [x] implement sync-up in jack-in
2022-12-14 13:50:35 +01:00
Jonas Platte 1c12b23e4c refactor(sdk): Move PaginationOutcome out of event_item module 2022-12-14 12:38:48 +01:00
Kévin Commaille 37bea19ab5 feat(sdk): Add day dividers to the experimental timeline 2022-12-14 12:29:24 +01:00
Jonas Platte eb0c3449fa refactor(bindings): Use proc-macro frontend more in sdk-ffi 2022-12-14 12:03:13 +01:00
Jonas Platte b3f146c932 refactor(bindings): Use proc-macro frontend more in crypto-ffi 2022-12-14 12:03:13 +01:00
Jonas Platte 34d458d3a3 chore: Upgrade UniFFI 2022-12-14 12:03:13 +01:00
Benjamin Kampmann 1c55565403 Merge pull request #1255 from gnunicorn/ben-update-jack-in
Sliding Sync updates

- expose timeline listener via FFI on slidingsyncroom, too - returning a stoppable spawn
- connect room timeline and sliding-sync-room timeline together
- increase HTTP timeout on jack-in
- add jack-in support for actual timeline items.
2022-12-13 15:14:57 +00:00
Richard van der Hoff c8da05125e Merge remote-tracking branch 'origin/main' 2022-12-12 18:41:30 +00:00
Richard van der Hoff 9ec9a59509 Release 0.1.0-alpha.2
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 34s
2022-12-12 18:02:21 +00:00
Richard van der Hoff 4f9452c9b0 Fix yet another typo in package.json 2022-12-12 17:51:10 +00:00
Richard van der Hoff dfed2f1b3a Bump version
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 36s
2022-12-12 17:35:54 +00:00
Richard van der Hoff 5850ff4cfc Fix filenames in package.json 2022-12-12 17:31:54 +00:00
Doug e64a8113e9 feat(bindings): Generate a Package.swift in xtask 2022-12-12 18:04:15 +01:00
Richard van der Hoff 2a4b83b5e6 Switch to npm-publish GHA script
Release `crypto-js` / Publish 🕸 [m]-crypto-js (push) Failing after 57s
Mostly because, as of #1167, we no longer have a `publish` script.
2022-12-12 16:17:32 +00:00
Benjamin Kampmann 799447f481 Merge remote-tracking branch 'origin/main' into ben-update-jack-in 2022-12-12 15:15:14 +01:00
Benjamin Kampmann 1a0b90291c fix(jack-in): rendering formatting improvements 2022-12-12 15:14:18 +01:00
Valere 9a058b9ea0 feat(crypto): Request room keys if the decryption failure is an unknown message index
We automatically request room keys to be forwarded from our other trusted devices if a decryption failure happens because the room key is missing.

This patch introduces automatic room key requests for decryption failures if the room key is available but has been ratcheted forward. In other words, we will now request a better version of the given room key automatically as well.

Co-authored-by: Damir Jelić <poljar@termina.org.uk>
2022-12-12 13:09:45 +01:00
Erwan Bousse 1ef645d285 feat(bindings): Use HTTPS proxy when provided as environment variable 2022-12-09 16:01:02 +01:00
valere 57e09c07dc Git Ignore generated files from kotlin bindings 2022-12-09 13:12:50 +01:00
Benjamin Kampmann 1e4c16b9a9 Merge remote-tracking branch 'origin/main' into ben-update-jack-in 2022-12-07 16:31:32 +01:00
Benjamin Kampmann 26486fc905 feat: add kotlin bindings
Merge pull request #1239 from matrix-org/ganfra/kotlin_bindings
2022-12-07 14:50:38 +00:00
Benjamin Kampmann c4884887ef fix(sliding-sync): set views to preload if we've recovered from frozen 2022-12-07 13:59:50 +00:00
Jonas Platte ddde87f14b fix(sdk): Fix remote echo event_id check
The send-event response sets the event_id field, not the timeline key.
The previous error branch wasn't actually reachable.
2022-12-07 12:32:44 +01:00
Jonas Platte 3e1fddccfd fix(sdk): De-duplicate local echoes with remote echoes without txn ID 2022-12-07 12:32:44 +01:00
Jonas Platte c1949e3fc6 refactor(sdk): Move timeline::add_event_id to TimelineInner 2022-12-07 12:32:44 +01:00
Juliette 63bc004e26 feat(bindings): Add uploading media and setting display name to FFI
Co-authored-by: Jonas Platte <jplatte@matrix.org>
2022-12-07 10:40:15 +00:00
Jonas Platte e99341df69 chore(bindings): Move bindings around to work around rustfmt bug 2022-12-07 11:16:25 +01:00
Jonas Platte 7667f0c429 refactor(sled): Use open_with_database for SledCryptoStore::open 2022-12-07 11:16:25 +01:00
Jonas Platte d0609822bc refactor(sled)!: Rename SledCryptoStore::{open_with_passphrase => open}
`open_with_db` also has the passphrase parameter without mentioning it
in its name. The old name also sounded like the passphrase was required
when it's actually optional.
2022-12-07 11:16:25 +01:00
Jonas Platte 262fe5630f feat(sdk): Implement IntoFuture for LoginBuilder and SsoLoginBuilder 2022-12-07 11:13:44 +01:00
Andrew Ferrazzutti 2176b7ee39 Revise example of machine.receiveSyncChanges
Clarify that the JSON-encoded `toDeviceEvents` passed to
`OlmMachine.receiveSyncChanges` must be the list of events themselves,
instead of a wrapper object that contains the event list.

Signed-off-by: Andrew Ferrazzutti <andrewf@element.io>
2022-12-07 11:00:22 +01:00
Benjamin Kampmann 2bc738be8c feat(jack-in): sending messages via timeline API 2022-12-06 14:28:34 +01:00
Jonas Platte f5b59c3de2 refactor(sdk)!: Remove impl Into<_> around Ruma request types
The SDK used to have builder types for these request types, but they
were removed long ago.
2022-12-06 14:00:33 +01:00
ismailgulek 31e5d4d663 feat(bindings): Add members accessor to Room
Co-authored-by: Doug <douglase@element.io>
2022-12-06 12:58:30 +00:00
Jonas Platte 6a386ca5fb feat(bindings): Add sending of reactions to matrix-sdk-ffi 2022-12-06 12:48:06 +01:00
Jonas Platte a18919bf50 chore: Add a PR template 2022-12-05 14:58:33 +01:00
Jonas Platte f92153757b chore: Add CONTRIBUTING.md
… and move the testing section from README.md into it.
2022-12-05 14:58:33 +01:00
Benjamin Kampmann 83d0abc6d7 feat(sliding-sync): properly handle all timeline event types 2022-12-05 14:52:38 +01:00
Benjamin Kampmann f919ee3b7d fix(ffi): clean up sliding sync timeline API 2022-12-05 14:52:38 +01:00
Benjamin Kampmann 0bfa63b31e fix(sliding-sync): return a stoppable spawn to allow listener cancellation 2022-12-05 14:52:38 +01:00
Benjamin Kampmann 229e6b28a5 fix(ffi): connect timelines together 2022-12-05 14:52:38 +01:00
Benjamin Kampmann fee9d52dde feat(ffi): expose sliding-sync timeline 2022-12-05 14:52:38 +01:00
Benjamin Kampmann d4890807f9 fix(jack-in): bump http timeout to 90seconds 2022-12-05 14:52:38 +01:00
Damir Jelić 58f92e59fe fix(bindings): Change the is_syncing method to read the correct value 2022-12-05 14:16:01 +01:00
Damir Jelić 1f38becdd9 chore: Fix a clippy warning 2022-12-05 14:16:01 +01:00
Ivan Enderlin 2d9e8170fe feat(indexeddb): Update to indexed_db_futures 0.3.0.
It removes the fork we have introduced in https://github.com/matrix-org/matrix-rust-sdk/pull/1068
(all our patches have been merged and are part of this 0.3.0 release).
2022-12-05 14:16:01 +01:00
Kévin Commaille aeb419207a refactor(sdk): Split restore_session into two parts at the Client level (#1246)
Tokens are not necessary for the restoration of the crypto/store, only
the meta. Required for OpenID Connect support where we need the tokens to get the
meta.
2022-12-05 13:19:35 +01:00
Flix ee713d42ae chore: Bump axum 2022-12-01 13:26:07 +01:00
ganfra 97578e418c Merge branch 'main' into ganfra/kotlin_bindings 2022-11-30 20:39:42 +01:00
Benjamin Kampmann 7d69fb2314 fix(sliding-sync): fallback to invite-room if regular room can't be found (#1249)
Co-authored-by: Jonas Platte <jplatte+git@posteo.de>
2022-11-30 13:59:25 +00:00
Jonas Platte 32cc477f54 refactor(sdk): Remove media caching from in-memory state store 2022-11-30 10:21:24 +01:00
Andy Uhnak 457c5f4fa3 Add cancel methods and rename callback method 2022-11-30 10:18:47 +01:00
Damir Jelić c604e59dcc feat(bindings): Expose the Sas::changes method over the FFI 2022-11-30 10:18:47 +01:00
Damir Jelić 026659ef68 refactor!(bindings): Return objects for the verification support
When the verification support was initially bound, Uniffi did not
support objects (the OlmMachine) returning other objects (our
verification objects). Instead we converted all the verification objects
into pure data structs which the other side had to poll for changes.

Now that Uniffi supports returning objects we can refactor this and make
the API on the other side the same as on the Rust side.
2022-11-30 10:18:47 +01:00
Jonas Platte 195ade911e refactor(sdk): Simplify signature of handle_back_paginated_event 2022-11-29 23:55:33 +01:00
Jonas Platte a881dad529 refactor(sdk): Make Timeline construction non-async 2022-11-29 23:55:33 +01:00
Jonas Platte 090b4495ea refactor(sdk): Simplify signature of handle_remote_event 2022-11-29 23:55:33 +01:00
Jonas Platte 3dfc60506f feat(sdk): Add SlidingSyncRoom::latest_event 2022-11-29 23:55:33 +01:00
Jonas Platte d4b67de9c3 refactor: Replace Timeline::latest with Timeline::latest_event 2022-11-29 23:55:33 +01:00
Jonas Platte 78e621010d refactor(sdk): Make tracking of fully-read marker in Timeline optional 2022-11-29 23:55:33 +01:00
Jonas Platte 1b0849a20c refactor(sdk): Move TimelineInner into its own module 2022-11-29 23:55:33 +01:00
Jonas Platte 32bf3143c7 doc: Hint towards test execution 2022-11-29 23:38:31 +01:00
Jonas Platte 3d22b6d5a4 chore: Upgrade Ruma 2022-11-29 15:37:18 +01:00
Flix bc29bcef38 doc: Hint towards test execution 2022-11-29 15:29:41 +01:00
Jonas Platte 859b12fca9 feat(sdk): Add debug logs for aggregated event handler execution times 2022-11-29 09:46:43 +01:00
Jonas Platte c564696a8a feat(sdk): Add tracing info to call_event_handlers 2022-11-29 09:46:43 +01:00
Benjamin Kampmann d3ff402813 feat(sliding-sync): Offline caching for Sliding Sync & session recovery (#1193)
With these changes, the user of sliding sync can configure the SlidingSync-Builder to store and recover the state from storage. For that they should call cold_cache("my-sliding-sync-key") with their preferred storage location during setup time on SlidingSyncBuilder. If a cached version is found under that key, the internal state of the rooms-list as well as each view found (identified by their name) will be set from storage immediately - allowing the user to show the last cached state. The Builder then also uses the same key to store its latest state after every update received from remote.

👉 Note on room list:
As we store a disconnected state, we are saving all RoomList entries as either Empty or Invalidated. This allows for an easier updating when the server comes back with results, as we don't track the ranges in cache - in the view of the server, we haven't seen anything yet.

👉 Note on timeline events:
This does store all existing timeline events - initial and seen during the session (as we keep track of them right now) - and will recover that state. However, as we can't be sure wether we have gaps in the timeline, the timeline items are reset upon receiving updates for them from the server.

👉 Note on (full-sync-)view:
While we are caching the server returned results (view list, room count and room info) as is, we are not caching the internal state (whether we are catching up) nor the ranges (as they are likely to be out of date) - those will be acting the same way you configured them, just with preloaded results. So for a full-sync-view, it will still do requests in batches and replace the corresponding set of rooms. Which could mean you might see the same room appear twice, though the cached one would be marked as invalidated. This might be problematic if the list the UI shows is longer than the batches fetched, but would be resolved quickly when catching up.

👉 On recovery:
When the sliding sync receives a M_UNKNOWN_POS, indicating the server has expired our session, sliding sync now transparently retries with up to three times to restart the sliding sync with full set of extensions and the latest views at their existing windows, the current room state is held. For full sync this starts a new sync-up with the existing room list staying intact. This also works from the offline at start.
2022-11-28 18:01:04 +00:00
Kateřina Churanová 08951e1c56 fix(ci): Fix unused import warnings on macos 2022-11-28 15:08:01 +01:00
Jonas Platte afda63f9e2 fix(sdk): Only retry requests on M_LIMIT_EXCEEDED or HTTP 5xx 2022-11-28 14:13:03 +01:00
Jonas Platte d7e6dd22e6 refactor(sdk): Simplify RumaApiError again
by folding Uiaa(UiaaResponse::MatrixError) into RumaApiError::ClientApi.
2022-11-28 14:13:03 +01:00
ganfra 68a6d2707f Fix naming of generated crypto .so files 2022-11-28 11:47:59 +01:00
ganfra 6666cd7a79 Use the generate .a file from cargo build as it's not stripped (instead of new target) 2022-11-25 19:20:54 +01:00
ganfra 75bb44bebf Add script to generate only crypto-ffi crate 2022-11-25 11:59:27 +01:00
ganfra 0504240878 Merge branch 'main' into ganfra/kotlin_bindings 2022-11-25 10:19:19 +01:00
Jonas Platte c0910a3693 chore: Fix a typo, upgrade typo check action 2022-11-24 22:36:46 +01:00
Kévin Commaille 183d4595aa fix(sdk): Make sure read marker can't go backwards 2022-11-24 22:15:36 +01:00
Kévin Commaille 580861cd1c fix(sdk): Rename read marker functions and variables for clarity 2022-11-24 22:15:36 +01:00
Kévin Commaille 1f761f3c13 test(sdk): Add read marker case when fully read event wasn't found 2022-11-24 18:17:43 +01:00
Kévin Commaille 5dc6416a76 fix(sdk): Fix logic if read marker event was not in the timeline 2022-11-24 18:17:43 +01:00
Jonas Platte c808a72914 feat(sdk): Add FailedToParse timeline items 2022-11-24 14:35:49 +01:00
Jonas Platte 6a1edf133d refactor(sdk): Add NewEventTimelineItem::from_content 2022-11-24 14:35:49 +01:00
Jonas Platte d0f0b650bd chore: Move impl for type after its definition 2022-11-24 14:35:49 +01:00
Jonas Platte d027005e87 chore(sdk): Rewrap info! invocation 2022-11-24 14:35:49 +01:00
Jonas Platte 43f0ba7711 chore: Appease clippy 2022-11-24 13:43:09 +01:00
Jonas Platte 8ce216974f test(sdk): Add a regression test for read marker updates 2022-11-24 13:43:09 +01:00
Jonas Platte f7d4129607 fix(sdk): Fix logic for updating an existing read marker 2022-11-24 13:43:09 +01:00
Stefan Ceriu 1107f27c3d fix(ffi): Use the right path for generated source files and only copy the generated folder contents (#1226) 2022-11-22 14:21:58 +00:00
Damir Jelić 3113f6698f chore: Don't use the term check for signature verification 2022-11-22 13:21:33 +01:00
Damir Jelić 38c38bc9f0 feat!(bindings): Expose the improved result of the verify_backup method 2022-11-22 13:21:33 +01:00
Jonas Platte de71d7e434 refactor(base): Simplify default memory store initialization 2022-11-22 11:03:45 +01:00
Jonas Platte 57a1743566 chore: Update Cargo.lock 2022-11-22 11:01:23 +01:00
Stefan Ceriu 1025d42624 fix(ffi): Fix xcframework release script, add missing module map 2022-11-22 09:55:46 +01:00
Jonas Platte fcb37b6962 feat: Support creating Timeline with initial items from sliding sync
Co-authored-by: Benjamin Kampmann <ben@gnunicorn.org>
2022-11-21 14:52:02 +01:00
bitfriend 2ab697328f fix(sdk): Make handle_back_paginated_event future Send 2022-11-18 20:57:36 +00:00
Damir Jelić eb20abe7b8 chore: The encryption feature was renamed 2022-11-18 19:53:07 +01:00
Jonas Platte fa71122e7d ci: Add sliding-sync and experimental-timeline to clippy check 2022-11-18 15:05:48 +01:00
Jonas Platte 785a3349ab refactor(sdk)!: Make sync_token accessor private 2022-11-18 14:02:41 +01:00
Jonas Platte 6329dbe6c2 refactor!: Split SyncResponse into two types
- matrix_sdk_base::sync::SyncResponse is the internal representation that
  we can update to account for sliding sync
- matrix_sdk::sync::SyncResponse is `/v3/`-specific and should not change
2022-11-18 14:02:41 +01:00
Jonas Platte ec5306978e refactor(sdk): Simplify signature of handle_sync_response 2022-11-18 14:02:41 +01:00
Jonas Platte 6b363120ef fix(sdk): Fix errors & warnings w/ experimental-timeline, w/o e2e-encryption 2022-11-18 13:39:51 +01:00
Jonas Platte 4bafb3818b feat(sdk): Add Timeline::retry_decryption 2022-11-18 13:39:51 +01:00
Jonas Platte 317965995a test(sdk): Add a test for retrying decryption of timeline items 2022-11-18 13:39:51 +01:00
Jonas Platte 74e9209e95 feat(sdk): Retry decryption of UTD timeline items 2022-11-18 13:39:51 +01:00
Jonas Platte da76a2700d refactor(sdk): Use an async lock for TimelineInnerMetadata 2022-11-18 13:39:51 +01:00
Jonas Platte ac33ca5fa0 refactor(sdk): Hold locks for the full lifetime of TimelineEventHandler
Not really necessary now, but required for thread-safe bulk updates like
we want for retrying decryption.
2022-11-18 13:39:51 +01:00
Jonas Platte 2bc0ac8fd7 refactor(sdk): Merge mutexes in TimelineInner into one 2022-11-18 13:39:51 +01:00
Damir Jelić 5a108f53cc refactor(crypto): Only use the Mutable for the inner SAS object
This patch makes the SAS signalling more robust, it ensures that we
can't forget to signal changes to the state.
2022-11-18 09:26:20 +01:00
Damir Jelić 1f2cdfc601 chore(contrib): Mitmproxy 9 has removed the HTTP prefix from the Response type 2022-11-17 12:43:56 +01:00
Jonas Platte 02165f7a05 refactor(sdk)!: Move retrying out of HttpSend trait 2022-11-17 12:32:45 +01:00
Benjamin Kampmann 98600e4c1e feat(jack-in): sending messages (#1156) 2022-11-17 11:18:27 +00:00
Jonas Platte bb6145d581 refactor!: Move large parts of deserialized_responses to matrix-sdk-base 2022-11-17 11:33:37 +01:00
Jonas Platte 975626a4f8 refactor(common)!: Remove unused TimelineSlice type 2022-11-17 11:33:37 +01:00
Jonas Platte c3aa03e486 chore: Add reldbg profile and use it for matrix-sdk-ffi iOS builds 2022-11-16 09:59:06 +01:00
Jonas Platte 51798e90bd chore: Add dbg profile and improve profile comments 2022-11-16 09:59:06 +01:00
Jonas Platte 5fa6f34e41 refactor(sdk): Use ErrorKind for get_state_events_for_key response check 2022-11-15 16:06:21 +01:00
Jonas Platte f9d2d32337 fix(xtask): Fix clippy warning 2022-11-15 16:06:21 +01:00
Jonas Platte 2dd2763d39 refactor(base): Unify identical branches and erase empty branches 2022-11-15 16:06:21 +01:00
Johannes Becker bb6cf83a39 refactor(appservice)!: Rename virtual user to appservice user 2022-11-15 15:57:31 +01:00
Damir Jelić a7dd690189 refactor(crypto): Split out the room key forwarding logic into a separate method 2022-11-15 14:57:46 +01:00
Jonas Platte e060606331 refactor(crypto): Move some code into a new method 2022-11-15 14:57:46 +01:00
Jonas Platte a30e40ed3a refactor: Introduce more early returns to reduce rightwards drift 2022-11-15 14:57:46 +01:00
Jonas Platte e59acfe28c refactor: Use let-else to remove boilerplate code 2022-11-15 14:57:46 +01:00
Jonas Platte d312aaecec refactor(crypto): Replace ? on if-else by early return 2022-11-15 14:57:46 +01:00
Jonas Platte 2528a5501b refactor(crypto): Remove unnecessary ref mut in patterns 2022-11-15 14:57:46 +01:00
Jonas Platte cf241d8c32 refactor(crypto): Merge matches and reflow comments in accept_secret 2022-11-15 14:57:46 +01:00
Jonas Platte db5d34e385 refactor(crypto): Reduce rightwards drift in test_device_signatures 2022-11-15 14:57:46 +01:00
Jonas Platte 7d2865f004 refactor(bindings): Shorten is_transaction_id_valid method 2022-11-15 14:57:46 +01:00
Jonas Platte 826705c174 chore: Bump MSRV to 1.65 2022-11-15 14:57:46 +01:00
Jonas Platte 5a1e347333 ci: Install stable toolchain for test-uniffi-codegen
The xtask is explicitly using the stable, and there is no reason to use
a less stable toolchain for this job.
2022-11-15 14:57:46 +01:00
Benjamin Kampmann 882b206144 feat(xtask): build xcframework
* Move swift build scripts into xtask (#1201)
* fix(ffi): use target_path from `cargo metadata` rather than guessing
* ci(ffi): install necessary target arch for build-framework test
* feat(xtask): copy to target without rsync.
2022-11-15 13:06:33 +01:00
Flix 8d89037296 fix: Missing ServerError after ruma update 2022-11-15 12:32:20 +01:00
Flix deb8ef801b fix: Remove the condition to only set new members in get_members 2022-11-15 12:32:20 +01:00
Flix 0a45e401e3 test: Use MemoryStore to fix problems in coverage tests 2022-11-15 12:32:20 +01:00
Flix 456e00e953 fix: Add missing not_found errors 2022-11-15 12:32:20 +01:00
Flix ab846f79f1 test: Add encryption state mock to tests where it is needed 2022-11-15 12:32:20 +01:00
Flix b1c2da9a68 fix: Don't mark encryption state to be synced on sync
As it appears, the first sync for a room might not include the
encryption state, so we cannot set the encryption state to be synced on
incoming syncs. That way, we always fetch the encryption state manually.
2022-11-15 12:32:20 +01:00
Flix 1ab33a28c9 fix: Make sure room.sync_up works under all conditions 2022-11-15 12:32:20 +01:00
Flix a3a9858bf4 refactor: Make if branches instead of early return 2022-11-15 12:32:20 +01:00
Flix 6951f7f5bf fix: Review comments 2022-11-15 12:32:20 +01:00
Flix fb8045b254 fix: Fix UDL or is_encrypted 2022-11-15 12:32:20 +01:00
Flix be7c3239a8 refactor: Adjust create_dm_room to new room API 2022-11-15 12:32:20 +01:00
Flix 956e270941 feat: Implement room sync_up method 2022-11-15 12:32:20 +01:00
Flix 65721aafb9 fix: Lock syncing to the store to avoid races 2022-11-15 12:32:20 +01:00
Flix 9d150e5cc6 fix: Adjust repeated_join test to new changes 2022-11-15 12:32:20 +01:00
Flix 43dd4452cd fix: Check encryption state in intermediate rooms 2022-11-15 12:32:20 +01:00
Flix 4abb08c4a1 feat!: Make intermediate rooms available right after joining/leaving
Co-Authored-By: Jonas Platte <jplatte@matrix.org>
Co-Authored-By: Benjamin Kampmann <ben@gnunicorn.org>
2022-11-15 12:32:20 +01:00
Jonas Platte 544da0d324 fix(sdk): Fix broken intra-doc link 2022-11-15 11:54:53 +01:00
ismailgulek 29aa9a78c3 feat(ffi): Expose file messages
Expose file messages (#1203)
2022-11-14 15:56:38 +00:00
Jonas Platte 4dc0e0ef3c chore: Upgrade Ruma 2022-11-14 15:01:53 +01:00
Gabriel Féron 680ef6b93a feat(sdk): Allow using an existing sled::Db with SledStateStore 2022-11-12 13:04:34 +00:00
Benjamin Kampmann 078855b4c9 feat(ffi): logging support for android (#1199)
* split logger into platform specific implementations
* logging support for android
* use platform independent wrapper for uniffi:exports
* activate colors for ansi-terminals
2022-11-11 12:20:19 +00:00
Damir Jelić 0d80c0e3fe chore(crypto): Improve the log for the one-time key signature error 2022-11-10 19:03:14 +01:00
ganfra 0901243440 Merge branch 'main' into ganfra/kotlin_bindings 2022-11-10 15:34:32 +01:00
ganfra fc76cc443e Fix build script 2022-11-10 15:34:00 +01:00
Jonas Platte 45cf32dfab test(sdk): Add a test for an undecryptable event 2022-11-10 13:43:46 +01:00
Jonas Platte aa4dbe4bc6 test(sdk): Add a test for editing a redacted event 2022-11-10 13:43:46 +01:00
Jonas Platte b550e9ba14 test(sdk): Add a test for an invalid edit 2022-11-10 13:43:46 +01:00
Jonas Platte 79db05cffb test(sdk): Add a unit test for redacting a reaction 2022-11-10 13:43:46 +01:00
Richard van der Hoff e45c57d8fe feat(crypto-js): allow async load of webassembly (#1198)
It turns out that Google Chrome refuses to initialise the wasm via the
synchronous `WebAssembly.Module` constructor, complaining that it is too
big. To be fair, it has a point.

Anyway, that means we need to provide a way to load the wasm
asynchronously. So, we introduce an `initAsync()` function which applications
can call before they do anything else, to load the wasm in the background.

If the app *doesn't* call `initAsync()`, then we load the wasm synchronously
the first time a function that accesses the wasm is called.
2022-11-10 11:51:37 +00:00
Ivan Enderlin 2eefb3a090 fix(indexeddb) + feat(crypto-js): Releasing IDBDatabase so that we can delete them
fix(indexeddb) + feat(crypto-js): Releasing `IDBDatabase` so that we can delete them
2022-11-10 10:40:16 +01:00
Ivan Enderlin 6754defb9b doc(crypto-js): Improve documentation of OlmMachine.close. 2022-11-10 10:21:48 +01:00
Damir Jelić 078a75ea27 chore(crypto): Log the protocols we accepted for a SAS verification 2022-11-09 16:56:23 +01:00
Damir Jelić 0d74189cde feat(crypto): Implement MSC3783
This commit adds support for the message authentication code calculation
that is using valid base64 when encoding the MAC.
2022-11-09 16:56:23 +01:00
Ivan Enderlin 196dfaea03 test(crypto-js): Test OlmMachine.close + IndexedDB clean up. 2022-11-09 14:48:37 +01:00
Ivan Enderlin f6496d01c7 feat(crypto-js): Add OlmMachine.close.
This new `OlmMachine.close` forces to drop/close the `OlmMachine` without
waiting on the JavaScript garbage collector to collect it.

`wasm-bindgen` generates the following JS glue code:

```js
close() {
    const ptr = this.__destroy_into_raw();
    wasm.olmachine_close(ptr);
}
```

And, `__destroy_into_raw` looks like this:

```js
__destroy_into_raw() {
    const ptr = this.ptr;
    this.ptr = 0;
    OlmMachineFinalization.unregister(this);
    return ptr;
}
```

It unregisters itself from the `FinalizationRegistry` correctly. We are
protected from a double-free.
2022-11-09 14:48:37 +01:00
Jonas Platte ca515997f1 feat(bindings): Expose video messages in matrix-sdk-ffi 2022-11-09 14:45:31 +01:00
Ivan Enderlin 3fe63c328f fix(indexeddb): Call IDBDatabase.close manually.
Surprisingly, `indexed_db_futures::IdbDatabase` is not closed when dropped.
Hopefully, there is a [`IdbDatabase::close(&self)`][close] method, which calls
`web_sys::IdbDatabase.close`, aka [`IDBDatabase.close`][websys-close], so let's
use it!

`IDBDatabase.close` returns immediately and closes the connection in a separate
thread. The connection isn't actually closed until all transactions created
using this connection are complete. No new transactions can be created for this
connection once this method is called. Methods that create transactions throw
an exception if a closing operation is pending.

[close]: https://github.com/Alorel/rust-indexed-db/blob/8c106eb418aecdba2f3fde80d91a4673a875fdf6/src/idb_database.rs#L73-L77
[websys-close]: https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/close
2022-11-09 14:45:00 +01:00
ismailgulek 26d690a21c Fix clippy 2022-11-09 16:34:41 +03:00
ismailgulek 045d6647b2 feat(bindings): Add support for editing messages 2022-11-09 14:15:19 +01:00
ismailgulek 7f54e4592f Expose video messages 2022-11-09 16:02:40 +03:00
ganfra 4899f98f7f Merge main into ganfra/kotlin_bindings 2022-11-08 17:25:57 +01:00
Kévin Commaille 93be96c85c feat(sdk): Add read marker logic to the timeline API 2022-11-08 13:16:09 +01:00
Jonas Platte c014f980cb chore(sdk): Remove invalid comment
I have tried for hours and have concluded it is probably not possible
even with GATs to have RawEvent borrow its inner value.
It is also not a commonly-used feature, so removing the unnecessary
clones is not that important.
2022-11-04 15:17:01 +01:00
Jonas Platte 5601435449 refactor(sdk): Simplify bounds on event handler registration methods
… by introducing a hidden trait that constrains the output type of the
associated type EventHandler::Future.
2022-11-04 15:17:01 +01:00
Jonas Platte 5b919fc9df refactor: Fix clippy lints 2022-11-04 15:17:01 +01:00
Stefan Ceriu d57666c0b8 fix(sliding_sync): remove server versions fetch
before being able to use the sliding sync builder; the versions are still fetched but at a later date (#1183)
2022-11-04 12:03:17 +00:00
Jonas Platte ce966ed6ce chore: Upgrade criterion, pprof 2022-11-04 11:14:13 +01:00
Jonas Platte 3a6d048b9f refactor(sdk)!: Rename uiaa_response methods to as_uiaa_response 2022-11-03 18:05:04 +01:00
Jonas Platte cf779822fe refactor(sdk): Merge impl blocks 2022-11-03 18:05:04 +01:00
Jonas Platte c8dd5c42e9 docs(sdk): Add more doc links to as_ruma_api_error methods 2022-11-03 18:05:04 +01:00
Jonas Platte 128c74ace5 refactor(sdk): Use server-supplied retry time when when available 2022-11-03 18:05:04 +01:00
Jonas Platte 85ea9554e5 feat(sdk): Add {RumaApiError,HttpError,Error}::as_client_api_error 2022-11-03 18:05:04 +01:00
Ivan Enderlin 5b25b8967c feat(crypto-js): Encode the WASM as base64 for portability
feat(crypto-js): Encode the WASM as base64 for portability
2022-11-03 16:44:16 +01:00
Damir Jelić 3b755fc15e chore(crypto): Fix some spelling
Co-authored-by: Jonas Platte <jplatte@matrix.org>
2022-11-03 16:18:15 +01:00
Damir Jelić da61005ee4 chore(crypto): Improve the logs for the SAS state transitions 2022-11-03 16:18:15 +01:00
Damir Jelić 7a263433c7 refactor!(crypto): Add a new SAS state that waits for a key to be sent
This patch adds a couple more states to the SAS verification state
machine. Namely we add the following states:

* KeySent
* KeysExchanged

This prevents users from confirming that the short auth string matches
before they have sent out a m.key.verification.key event, which is
necessary for the other side to present the short auth string.

The KeysExchanged state functionally replaces the KeyReceived state.
Meaning that the short auth string can only presented once we
transitioned into the KeysExchanged state.

We can transition into the KeysExchanged state from the KeyReceived
state or from the KeySent state, depending on if we first receive a
m.key.verification.key event or if we first send out our own
m.key.verification.key event.

This means that, if the transition into the KeysExchanged state happens
through the KeySent state, users won't be able to tell if the transition
happened. In other words, listening to `m.key.verification` events
doesn't work anymore, users will need to use the new `Sas::changes()`
API to listen to a stream of state changes.
2022-11-03 16:18:15 +01:00
Ivan Enderlin ee27c19bf7 chore: Removing trailing spaces. 2022-11-03 15:57:20 +01:00
Ivan Enderlin 6d21df6d29 !debug off 2022-11-03 15:37:54 +01:00
Ivan Enderlin e989bc2377 fix(crypto-js): scan_qr_code takes a reference to QrCodeScan. 2022-11-03 15:37:21 +01:00
Jonas Platte 28b44a7f03 refactor!: Rename restore_login to restore_session 2022-11-03 15:34:31 +01:00
Ivan Enderlin 265ac1f97b chore(crypto-js): Configure a profiling profile for wasm-pack. 2022-11-03 14:59:22 +01:00
Ivan Enderlin d044565caa test(crypto-js): Keep qr.toBytes() local, to avoid weird GC collection. 2022-11-03 14:57:07 +01:00
Ivan Enderlin aa7d225867 feat(crypto-js): Qr.to_bytes returns a Uint8ClampedArray. 2022-11-03 13:58:17 +01:00
Stefan Ceriu af2de2d8ef chore(ffi): Reduce the log level for some not so useful logs 2022-11-03 13:26:32 +01:00
Jonas Platte a28a664302 refactor(bindings)!: Replace RestoreToken string with Session dictionary 2022-11-03 12:58:34 +01:00
Jonas Platte c1423e9326 refactor(bindings)!: Remove is_guest
It's not used by anything and should be re-introduced in the main Rust
first if it's needed.
2022-11-03 12:58:34 +01:00
Jonas Platte 8bfc186595 feat(bindings): Add TimelineItemContent::as_unable_to_decrypt 2022-11-03 12:03:33 +01:00
Jonas Platte 0cf5356f15 feat(sdk): Add UnableToDecrypt as a variant of TimelineItemContent 2022-11-03 12:03:33 +01:00
Jonas Platte c03940e6d5 chore(sdk): Reword log messages 2022-11-03 12:03:33 +01:00
Jonas Platte f93170323b refactor(sdk): Remove unnecessary pub(crate) 2022-11-03 12:03:33 +01:00
Ivan Enderlin a3cdd31713 fix(crypto-nodejs): Pass secrets to the release workflow
fix(crypto-nodejs): Pass secrets to the release workflow
2022-11-03 11:58:59 +01:00
Ivan Enderlin fb89de8267 fix(crypto-nodejs): Pass secrets to the release workflow.
See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idsecrets.
2022-11-03 11:30:10 +01:00
Ivan Enderlin 223e65fc26 !debug 2022-11-03 11:08:52 +01:00
Jonas Platte b5b2eafbec refactor(base): Remove unused Error variants 2022-11-03 10:52:11 +01:00
Jonas Platte 27b0ea1aa0 refactor(crypto): Move EncryptionNotEnabled out of MegolmError
… into matrix_sdk_base::Error because it is never constructed in the
matrix_sdk_crypto crate that defines MegolmError.
2022-11-03 10:52:11 +01:00
Jonas Platte 4c4b1f3abc refactor(bindings): Use uniffi proc-macros more in sdk-ffi 2022-11-03 09:48:41 +01:00
Jonas Platte 99e621a82b chore: Upgrade UniFFI 2022-11-03 09:48:41 +01:00
ganfra 4eedbfbc11 Merge branch 'main' into ganfra/kotlin_bindings 2022-11-02 19:06:07 +01:00
Richard van der Hoff 898265b257 Clean up build script 2022-11-02 17:22:00 +00:00
Richard van der Hoff 9d400a7494 fix JS syntax 2022-11-02 17:13:58 +00:00
Ivan Enderlin a4ca6dbf38 !debug 2022-11-02 17:25:13 +01:00
Ivan Enderlin b23d30c951 fix(indexeddb): Fix wasm_bindgen::JsValue::(from|to)_serde warnings
fix(indexeddb): Fix `wasm_bindgen::JsValue::(from|to)_serde` warnings
2022-11-02 16:58:09 +01:00
Ivan Enderlin bb96ab89f8 fix(crypto-js): Make build.sh cross-platform-ish. 2022-11-02 16:57:26 +01:00
Ivan Enderlin 4cd8a8400f chore: Reorder dep names. 2022-11-02 16:38:01 +01:00
Ivan Enderlin 28d4a69552 !fixup 2022-11-02 16:32:20 +01:00
Jonas Platte a6ca114bac chore: Upgrade UniFFI 2022-11-02 16:21:16 +01:00
Ivan Enderlin 6497d6d676 feat(crypto-js): Make scripts/build.sh compatible with macOS.
This patch also improves the “phrasing”, simplifies the code a little bit etc.
Small stuff.
2022-11-02 16:19:17 +01:00
Ivan Enderlin da93cf7dc4 fix(indexeddb): Fix wasm_bindgen::JsValue::(from|to)_serde warnings.
`wasm_bindgen::JsValue::(from|to)_serde` now emit warnings because of a
circular dependency. To solve this problem, this patch now uses `gloo-utils`,
see https://rustwasm.github.io/wasm-bindgen/reference/arbitrary-data-with-serde.html#an-alternative-approach---using-json.

Ideally, we would like to use `serde_wasm_bindgen` but the behaviour isn't
the same. `gloo-utils` serializes and deserialized through JSON, whilst
`serde_wasm_bindgen` manipulates the `JsValue` directly which can be better or
worst dependending of the case. This patch conserves the JSON approach as it
was the previous and tested one.
2022-11-02 08:59:37 +01:00
Ivan Enderlin 2b4f4b17c3 chore: Update wasm-bindgen's ecosystem to latest versions. 2022-11-02 08:59:21 +01:00
Richard van der Hoff 0f104c7433 Fix unbase64 loading 2022-11-01 13:47:44 +00:00
Jonas Platte 726e4b9aa0 fix(appservice): Fix nesting of AppServiceRouter in axum::Router 2022-11-01 11:37:16 +01:00
Jonas Platte f227f583e0 chore: Upgrade ruma-client-api 2022-11-01 11:34:05 +01:00
Jonas Platte 36444cd3a0 chore: Clean up TOML formatting 2022-11-01 11:34:05 +01:00
Jonas Platte 9c489b398d chore: Upgrade clap dependency of xtask 2022-11-01 11:34:05 +01:00
Richard van der Hoff ce03f016b9 Copy unbase64.js into the right place 2022-11-01 10:19:13 +00:00
Richard van der Hoff 4557494da6 Optimise unbase64
Use a lookup table instead of a function with if statements
2022-11-01 10:18:44 +00:00
Richard van der Hoff 093856671a Encode the WASM as base64
Some nasty hackery to get around the nastiness of the JS ecosystem
2022-10-31 22:39:44 +00:00
Ivan Enderlin 471ac07c88 fix(crypto-nodejs): Set KeepAlive to false since Node.js v19
Disable keepAlive in download-lib.js, allowing node bindings to work on Node.JS 19
2022-10-31 14:35:57 +01:00
Will Hunt f4f3ca4b25 A newline 2022-10-31 13:18:16 +00:00
Will Hunt c009f54ba9 Tidy 2022-10-31 13:17:48 +00:00
Will Hunt 546dc9a652 Run CI against 19 2022-10-31 13:04:05 +00:00
Will Hunt 717f86332f Disable keepalive to prevent hanging connections 2022-10-31 12:39:23 +00:00
Jonas Platte 6c975b01b5 Revert #1151
This reverts the commits

- cacb20e3ef
- 01cc896dab
2022-10-31 12:03:23 +01:00
Ivan Enderlin 182733e984 feat(crypto-js): OlmMachine.initialize is the new constructor
feat(crypto-js): `OlmMachine.initialize` is the new constructor
2022-10-31 11:41:50 +01:00
Andy Uhnak e4964b92a2 Local trust 2022-10-31 11:14:04 +01:00
Ivan Enderlin bdf460cd91 doc(crypto-js): Rephase something.
Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
2022-10-31 11:07:21 +01:00
Ivan Enderlin 0276552c72 feat(crypto-js): Use WeakRef to avoid calling free manually
feat(crypto-js): Use `WeakRef` to avoid calling `free` manually
2022-10-31 11:06:45 +01:00
Ivan Enderlin 3441c6cf9a feat(crypto-js): Use WeakRef to avoid calling free manually.
By asking `wasm-bindgen` to generate JS glue code for `WeakRef` support,
it removes the need to call `free` manually to free objects, thus we reduce
potential memory leaks inside Rust. See https:// rustwasm.github.io/docs/wasm-
bindgen/reference/weak-references.html to learn more.

It uses [`FinalizationRegistry`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry)
under the hood, I reckon it's quite common and fits into Matrix's clients needs
in terms of browser support.
2022-10-28 21:02:35 +02:00
Ivan Enderlin a07f89e340 feat(crypto-js): OlmMachine.initialize is the new constructor.
While technically a type constructor can return a `Promise`, it's not
considered as idiomatic JavaScript to do that. We are changing `new OlmMachine`
to `OlmMachine.initialize`. The rest of the code is strictly the same.
2022-10-28 20:37:46 +02:00
Benjamin Kampmann cacb20e3ef fix(ffi): Remove duplicate RequireState definition, left over after #1151 (#1155) 2022-10-28 13:38:21 +02:00
Benjamin Kampmann 255d3b7a18 Merge pull request #1154 from matrix-org/stefan/sessionVerificationFixes
Sliding Sync FFI and DevEx fixes
2022-10-28 11:40:33 +02:00
Jonas Platte 6ad7d29364 refactor(sdk): When processing remote events, check for duplicates 2022-10-28 11:30:32 +02:00
Jonas Platte 333c4f0644 refactor(sdk): Move timeline event origin_server_ts and raw_event fields
… from TimelineEventMetadata to Flow because they always exist for
remote events, and never for local echoes.
2022-10-28 11:30:32 +02:00
Jonas Platte 6ce23b17a6 refactor(sdk): Update tracing event for local echo not being found 2022-10-28 11:30:32 +02:00
Benjamin Kampmann 0cb34f7c86 fix: style fixes 2022-10-28 11:01:54 +02:00
Jonas Platte 0d84cf7b74 refactor(sdk): Make Debug format of EventTimelineItem less noisy 2022-10-28 10:56:28 +02:00
Jonas Platte f2ea72224d feat(bindings): Add {TimelineItem,EventTimelineItem}::fmt_debug 2022-10-28 10:56:28 +02:00
Jonas Platte 01cc896dab refactor(bindings): Use uniffi proc-macros a little more in sdk-ffi 2022-10-28 10:55:46 +02:00
Benjamin Kampmann 278c6059ae perf(sliding-sync): run outgoing e2ee requests and sync in parallel.
And continue the loop if even we hit an error in between
2022-10-27 15:59:02 +01:00
Benjamin Kampmann d164165c7c fix(ffi): remove extra to-device processing 2022-10-27 15:57:36 +01:00
ganfra 5a9b75c3ff kotlin-bindings: remove sample 2022-10-27 14:38:17 +02:00
ganfra c7c63fa41c Merge branch 'main' into ganfra/kotlin_bindings 2022-10-27 14:37:53 +02:00
Benjamin Kampmann 0e59078211 fix(ffi): call process_sync_error of client for sliding-sync errors. break if wnated 2022-10-27 12:32:49 +01:00
Benjamin Kampmann 120d5edb03 feat(sliding-sync): Replace anyhow with proper Error type 2022-10-27 12:32:05 +01:00
Benjamin Kampmann afc33e616c revert start_sync removal 2022-10-27 12:06:06 +01:00
Jonas Platte 324411201e fix(sdk): Enable required ruma features for experimental-timeline 2022-10-27 12:56:51 +02:00
Jonas Platte e1ecc9de0d chore: Bump versions of matrix-sdk, matrix-sdk-base
… to bring them up to the released ones from the v0.6.x branch.
All changes from those versions are already present on main.
2022-10-27 12:56:37 +02:00
Jonas Platte c9c4473cd4 ci: Cache xtask for bindings checks 2022-10-27 11:58:42 +02:00
Jonas Platte 41be4c5209 ci: Test bindings generation 2022-10-27 11:58:42 +02:00
Jonas Platte 426f60a6a2 ci: Add bindings check to xtask 2022-10-27 11:58:42 +02:00
Jonas Platte eddf202a76 chore: Upgrade UniFFI 2022-10-27 11:27:28 +02:00
Stefan Ceriu d4cd8710a4 Refactor the SessionVerification flows and get them working through sliding sync 2022-10-27 10:45:05 +03:00
Benjamin Kampmann a443e7277d feat: Add sliding sync timeline events and extensions (#1054)
Add general extension framework for sliding sync, implementing the e2ee, to-device and account-data extensions as per existing proxy implementation. Add a new (ffi exposed) function to use activate the extensions.

Also extends jack-in to have permanent login and storage support now, rather than posting an access token and expose messages inside the sliding-sync layer to actually use the decrypted messages if given. Contains a lot of fixes around these aspects, too, like uploading any remaining messages from the olm-machine on every sliding-sync-request or processing even if no room data is present (which can happen now as processing only extensions might takes place).
2022-10-25 13:42:43 +02:00
Jonas Platte 2232092f11 refactor(sdk): Move timeline event handling fns to TimelineInner 2022-10-25 13:03:52 +02:00
Damir Jelić 2547d6ed64 fix(crypto): Don't create an infinite amount of streams in the SAS examples 2022-10-25 13:00:27 +02:00
Damir Jelić 6cb37520ce docs(bindings): Document the EncryptionSettings a bit better 2022-10-25 12:44:18 +02:00
Jonas Platte 50a5ec89e9 chore: Fix more clippy lints 2022-10-25 12:20:07 +02:00
Jonas Platte 285dc129c3 chore(crypto): Clean up SecretInfo::as_key implementation 2022-10-25 12:20:07 +02:00
Jonas Platte a59fdc08bb chore: Fix clippy lints
Automated with cargo clippy --fix.
2022-10-25 12:20:07 +02:00
Jonas Platte 9de98dfa65 fix(sdk): Remove token field from SyncSettings Debug output 2022-10-24 13:14:30 +02:00
Damir Jelić c03c90c1cf feat(bindings)!: Allow passing the E2EE settings when sharing a room key 2022-10-24 09:50:57 +02:00
Damir Jelić 4a6208f808 feat(crypto): Add signaling to the SAS verification
This patch adds a way for users to listen to changes in the state of a
SAS verification.

This makes it much more pleasant to go through the verification flow and
incidentally easier to document it.
2022-10-24 09:50:17 +02:00
Jonas Platte 1aa48beca9 Revert "refactor(bindings): Use new uniffi::Enum derive macro in crypto-ffi"
This reverts commit 6b9075aa42.
2022-10-20 17:41:16 +02:00
Jonas Platte e05444554d chore: Fix typo in comment 2022-10-20 14:14:18 +02:00
Jonas Platte 411095425c refactor(sdk): Make ClientBuilder::{sled_store, indexeddb_store} simple setters 2022-10-20 13:35:06 +02:00
Jonas Platte 6b9075aa42 refactor(bindings): Use new uniffi::Enum derive macro in crypto-ffi 2022-10-20 12:53:09 +02:00
Jonas Platte 01dc166293 chore: Upgrade UniFFI 2022-10-20 12:53:09 +02:00
Jonas Platte 584a82b19b fix(sdk): Remove Debug implementation for SessionTokens 2022-10-20 11:25:54 +02:00
Jonas Platte 0aba22855b fix(sdk): Don't include access and refresh token in Debug output of Session 2022-10-20 11:25:54 +02:00
Jonas Platte a50743874f chore(base): Merge consecutive impls for the same type 2022-10-20 11:25:54 +02:00
Flix 7851eefb61 refactor(base)!: Get rid of String in StoreError 2022-10-19 16:28:27 +02:00
Stefan Ceriu 8470b494f4 chore(bindings): Replace various expectations with anyhow contexts 2022-10-19 13:18:19 +02:00
Andy Uhnak c92d946777 Set local trust 2022-10-19 09:38:16 +02:00
Jonas Platte 0cfc7540cf refactor: Use workspace dependencies for tracing 2022-10-18 19:24:22 +02:00
Jonas Platte 6990c1ca5c test(base): Use tracing-subscriber for test debugging
… same as in our other crates.
2022-10-18 19:24:22 +02:00
Jonas Platte 0ee63344da chore(base): Sort dev-dependencies 2022-10-18 19:24:22 +02:00
Jonas Platte 3daaa457e1 fix(bindings): Make tracing dependency for crypto-js optional 2022-10-18 19:24:22 +02:00
Jonas Platte 7a826fb7d6 ci: Cancel all CI jobs for old commits when pushing to a PR branch 2022-10-18 17:06:42 +02:00
Jonas Platte 95dfedb70a Another test commit 2022-10-18 16:52:01 +02:00
Jonas Platte eb58dcc556 Try to make it work 2022-10-18 16:51:07 +02:00
Damir Jelić 57e9b36fac chore(bindings): Don't mention that the OlmMachine is a memory-only one 2022-10-18 15:49:09 +02:00
Damir Jelić 90865e2a0a chore(bindings): Clarify the OlmMachine constructor in the WASM bindings 2022-10-18 15:49:09 +02:00
Damir Jelić 52d96ceb60 fix(bindings): Allow setting the store without a passphrase 2022-10-18 15:49:09 +02:00
Damir Jelić 8a720af215 feat(crypto): Support transitioning from a QR verification into a SAS or scanning QR one 2022-10-18 15:18:51 +02:00
Jonas Platte bac95f4494 ci: Upgrade cancel-workflow-action 2022-10-18 15:00:35 +02:00
Jonas Platte 31293c6c2b Testing with empty commit 2022-10-18 14:39:47 +02:00
Jonas Platte 089f92d238 ci: Cancel all CI jobs for old commits when pushing to a PR branch
(not just jobs from the ci workflow file)
2022-10-18 14:23:21 +02:00
Andy Uhnak 1a466eb667 Add flow_id to logs 2022-10-18 13:09:12 +01:00
Andy Uhnak 8bbdd28a8b Use cfg-if and debug logs 2022-10-18 13:09:11 +01:00
Andy Uhnak 61452ad190 Replace QR with SAS verification 2022-10-18 13:08:47 +01:00
Flix 4816d93e96 docs: Improve documentation for custom event handler context 2022-10-18 13:39:08 +02:00
Jonas Platte f25af209e1 refactor: Use workspace dependencies for zeroize 2022-10-18 13:38:05 +02:00
Jonas Platte e6891addfb refactor: Use workspace dependencies for vodozemac 2022-10-18 13:38:05 +02:00
Jonas Platte f57b7782f4 refactor: Use workspace dependencies for ruma 2022-10-18 13:38:05 +02:00
Jonas Platte e91cee7154 fix(sdk): Always send an access token for get_profile 2022-10-18 13:31:59 +02:00
Jonas Platte 5b46fa73e1 fix(sdk): Always send an access token for get_display_name 2022-10-18 11:19:32 +02:00
Jonas Platte b309441dec fix(sdk): Don't log the access token in HttpClient::send 2022-10-17 20:04:49 +02:00
Jonas Platte 391efcec12 feat(appservice): Return a concrete type from AppService::service 2022-10-17 17:03:37 +02:00
Jonas Platte 4e583bcb8a chore: Exclude xtask from tarpaulin coverage collection 2022-10-17 15:38:42 +01:00
Benjamin Kampmann 5e621b7132 fix!: Switch to uniffi 0.21.0 and workspace-wide dependencies
Upgrade MSRV to 1.64, the first stable release to support workspace-wide depenendencies:
https://blog.rust-lang.org/2022/09/22/Rust-1.64.0.html#cargo-improvements-workspace-inheritance-and-multi-target-builds
2022-10-17 15:38:04 +01:00
Benjamin Kampmann ab796cb32c ci(xtask): switch to using uniffi as a lib rather than globally installed binary 2022-10-17 15:38:04 +01:00
Richard van der Hoff dd82e0b8fc chore: Update bindings/README 2022-10-17 13:24:09 +00:00
Doug 7125730917 ci(xtask): Switch to xtask for swift; run swift tasks on macOS
Merge pull request #1023 from matrix-org/doug/swift-linux: Run Swift tests on macOS
2022-10-17 14:12:43 +02:00
Jonas Platte db2771bd17 feat(bindings): New timeline API 2022-10-17 13:40:35 +02:00
Jonas Platte 95face4aa4 chore(bindings): Delete unused code left over from old timeline API 2022-10-17 13:40:35 +02:00
Jonas Platte a7cb80df1b refactor(appservice): Clean up implementation of user_id_is_in_namespace 2022-10-13 12:13:56 +02:00
ganfra e7d5b44343 Kotlin bindings: add matrix-rust-sdk.aar file to sample 2022-10-12 18:24:30 +02:00
ganfra 47478702b2 Kotlin bindings: create build_sdk script 2022-10-12 18:24:30 +02:00
ganfra 648895e2b0 Kotlin bindings: add uniffi.toml 2022-10-12 18:24:30 +02:00
ganfra c8bddea6e1 Kotlin bindings: update Cargo.toml for kotlin generation 2022-10-12 18:24:30 +02:00
ganfra f42215180e Kotlin bindings: create project with sample, crypto and sdk modules 2022-10-12 18:24:12 +02:00
Jonas Platte 1e77e91ec4 refactor(appservice): Replace warp with axum 2022-10-12 17:32:31 +02:00
Jonas Platte 95613be6c9 chore: Remove redundant cfg attribute 2022-10-12 17:32:31 +02:00
Jonas Platte b83e6be01e refactor(sdk): Use lower-level libraries for builtin SSO server 2022-10-12 17:32:31 +02:00
Damir Jelić 086b6127e2 feat: Improve the timeline example 2022-10-12 16:12:06 +02:00
Jonas Platte 54fd40d8f5 feat(sdk): Add new timeline API 2022-10-12 16:12:06 +02:00
Damir Jelić 67d968d4fa refactor(crypto): Remove the device ID from the megolm v2 m.room.encrypted content 2022-10-12 14:37:05 +02:00
Damir Jelić 7e14857239 test(crypto): Test that megolm v2 key forwards work 2022-10-12 14:37:05 +02:00
Damir Jelić 2425cd99cf fix(crypto): Introduce the proper megolm v2 forwarded room key content 2022-10-12 14:37:05 +02:00
Damir Jelić 7c97c27441 feat(crypto): Start sending out megolm v2 room key requests 2022-10-12 14:37:05 +02:00
Damir Jelić cbadd90eff feat(crypto): Start responding to megolm v2 room key requests 2022-10-12 14:37:05 +02:00
Jonas Platte d18b57dcdd refactor: Make use of as_ruma_api_error internally 2022-10-12 12:34:09 +02:00
Jonas Platte 23c5929cfa feat(sdk): Add Error::as_ruma_api_error 2022-10-12 12:34:09 +02:00
Jonas Platte 7bfa622a57 feat(sdk): Add HttpError::as_ruma_api_error 2022-10-12 12:34:09 +02:00
Jonas Platte f4e0cab11f feat(sdk)!: Merge HttpError::UiaaError into HttpError::Api 2022-10-12 12:34:09 +02:00
Jonas Platte f07735291e Fix warnings from generated code 2022-10-10 19:24:56 +02:00
Anderas d4e7076e1d Compile Crypto FFI for MacOS 2022-10-10 18:59:25 +02:00
Jonas Platte 61e95abaf2 refactor: Use Box::default
… as suggested by clippy.
2022-10-10 18:52:59 +02:00
Damir Jelić 8763a2468c fix(crypto): Take more data into account when comparing sessions 2022-10-10 15:20:25 +02:00
Damir Jelić 8f6e3033e3 fix(crypto): Check for existing room keys when receiving a new one.
Now that we're not scoping the room keys by the Curve25519 sender key
we're opening the door of multiple devices trying to insert the same
room key into our store.

This patch changes our logic so we only store room keys from an
m.room_key event if we don't have one already or if the new key is
a better version of the one we already have.

This mostly assumes that the first room key with a given session id
is coming from the creator of the room key.
2022-10-10 15:20:25 +02:00
Damir Jelić 2f94886663 refactor(crypto)!: Don't use the Curve25519 sender key to store room keys 2022-10-10 15:20:25 +02:00
Jonas Platte 8b728d4ada ci: Pin typos version
Currently, master is broken: https://github.com/crate-ci/typos/issues/590
2022-10-06 17:27:55 +02:00
Jonas Platte 26faf0d4c0 feat(bindings): Add custom kotlin package name for crypto-ffi 2022-10-06 17:27:55 +02:00
Jonas Platte a3113bd125 refactor(bindings): Start using #[uniffi::export] for matrix-sdk-crypto-ffi 2022-10-06 17:27:55 +02:00
Jonas Platte a75d7171f8 refactor(bindings): Rename crypto-ffi UniFFI namespace
… from olm to matrix_crypto_ffi to match the lib name.
Names need to match for integration of UniFFI's proc-macro frontend.
2022-10-06 17:27:55 +02:00
Jonas Platte c3eaa864dd refactor(bindings): Unset custom lib name for crypto-ffi 2022-10-06 17:27:55 +02:00
Jonas Platte 6a561c20e2 refactor(bindings): Use uniffi::export for most of ClientBuilder's API 2022-10-06 10:56:22 +02:00
Jonas Platte 0581b8a884 refactor: Derive Default for enums 2022-10-06 10:55:49 +02:00
Jonas Platte bdfdaeb0ae chore: Upgrade async-once-cell 2022-10-06 10:55:49 +02:00
Jonas Platte c24c20f7f1 Raise MSRV to 1.62 2022-10-06 10:55:49 +02:00
Jonas Platte 6b3acf1bf7 chore(sdk): Use inline tables more in Cargo.toml
Makes the file a little more comprehensible.
2022-10-06 10:55:49 +02:00
Jonas Platte 822cdae8f3 chore(sdk): Only include derive_builder dependency for sliding-sync feature 2022-10-06 10:55:49 +02:00
Jonas Platte 4fcbb61145 refactor!: Delete the store module
It was very confusing that matrix_sdk::store::make_store_config's first
argument was either a path or a database name depending on the build
configuration. ClientBuilder::{sled_store, indexeddb_store} are also
easier to use.
2022-10-05 13:49:12 +02:00
Jonas Platte 4628481d0e refactor(bindings): Use UniFFI proc-macro frontend more 2022-10-05 12:21:44 +02:00
Jonas Platte e05de8d4ce chore: Upgrade UniFFI 2022-10-05 12:21:44 +02:00
Johannes Marbach 6bc79b04cf feat(bindings): Allow clients using matrix-sdk-ffi to set the user agent 2022-10-05 09:18:52 +02:00
Damir Jelić fa88751548 fix(crypto): Ignore duplicate verification requests 2022-10-04 13:38:07 +02:00
Andy Uhnak 09c906b1d7 Debug message 2022-10-04 11:50:16 +01:00
Andy Uhnak 6fab6ef318 Ignore duplicate verification requests 2022-10-04 11:38:08 +01:00
Lautaro Bustos d5728f235d feat(sdk): Allow configuring the presence in the SyncSettings 2022-10-03 11:52:23 +02:00
Johannes Marbach 6827c70886 chore: Ignore Swift's .build folder 2022-09-30 21:54:09 +02:00
Jonas Platte ab1a6a6b37 chore: Remove experimental-timeline Cargo feature 2022-09-30 13:48:17 +02:00
Jonas Platte 3c9c7290ae chore: Remove deprecated functions 2022-09-30 10:40:56 +00:00
Benjamin Kampmann 530f8057cc Merge pull request #1071 from matrix-org/ben-releasing-0.6
chore: crates.io only accepts versioned git deps
2022-09-29 15:02:10 +02:00
Ivan Enderlin 8e0e752f12 Merge pull request #1075 from Hywan/fix-crypto-nodejs-release-script-npm-token
fix(crypto-nodejs): Hopefully it will make `NPM_TOKEN` available in the script
2022-09-29 11:52:30 +02:00
Ivan Enderlin b1493c5217 fix(crypto-nodejs): Hopefully it will make NPM_TOKEN available in the script.
We hope that adding this to the workflow will make `NPM_TOKEN`
available from within the script.
2022-09-29 11:36:29 +02:00
Ivan Enderlin 7988dc6cf3 Mergfix(crypto-nodejs): Fix the prep release script
fix(crypto-nodejs): Fix the prep release script
2022-09-28 17:48:43 +02:00
Ivan Enderlin 180796c747 fix(crypto-nodejs): Fix the prep release script. 2022-09-28 17:46:56 +02:00
481 changed files with 78043 additions and 28710 deletions
+1
View File
@@ -10,6 +10,7 @@ target-applies-to-host = false
[alias]
xtask = "run --package xtask --"
uniffi-bindgen = "run --package uniffi-bindgen --"
[doc.extern-map.registries]
crates-io = "https://docs.rs/"
+1
View File
@@ -0,0 +1 @@
* @matrix-org/rust
+7
View File
@@ -0,0 +1,7 @@
<!-- description of the changes in this PR -->
- [ ] Public API changes documented in changelogs (optional)
<!-- Sign-off, if not part of the commits -->
<!-- See CONTRIBUTING.md if you don't know what this is -->
Signed-off-by:
+2 -4
View File
@@ -15,12 +15,10 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
toolchain: nightly-2023-07-03
components: rustfmt
profile: minimal
override: true
- name: Run Benchmarks
run: cargo bench | tee benchmark-output.txt
+110 -43
View File
@@ -12,12 +12,80 @@ on:
- synchronize
- ready_for_review
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
MATRIX_SDK_CRYPTO_NODEJS_PATH: bindings/matrix-sdk-crypto-nodejs
MATRIX_SDK_CRYPTO_JS_PATH: bindings/matrix-sdk-crypto-js
jobs:
xtask:
uses: ./.github/workflows/xtask.yml
test-uniffi-codegen:
name: Test UniFFI bindings generation
needs: xtask
if: github.event_name == 'push' || !github.event.pull_request.draft
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Load cache
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Get xtask
uses: actions/cache/restore@v3
with:
path: target/debug/xtask
key: "${{ needs.xtask.outputs.cachekey-linux }}"
fail-on-cache-miss: true
- name: Build library & generate bindings
run: target/debug/xtask ci bindings
lint-js-bindings:
strategy:
fail-fast: true
matrix:
include:
- name: "[m]-crypto-nodejs"
path: "bindings/matrix-sdk-crypto-nodejs"
- name: "[m]-crypto-js"
path: "bindings/matrix-sdk-crypto-js"
name: lint ${{ matrix.name }}
runs-on: ubuntu-latest
steps:
- name: Checkout the repo
uses: actions/checkout@v3
- name: Install Node.js
uses: actions/setup-node@v3
- name: Install NPM dependencies
working-directory: ${{ matrix.path }}
run: npm install
- name: run lint
working-directory: ${{ matrix.path }}
run: npm run lint
test-matrix-sdk-crypto-nodejs:
name: ${{ matrix.os-name }} [m]-crypto-nodejs, v${{ matrix.node-version }}
if: github.event_name == 'push' || !github.event.pull_request.draft
@@ -26,17 +94,18 @@ jobs:
strategy:
fail-fast: true
matrix:
os: [ubuntu-latest]
node-version: [14.0, 16.0, 18.0]
# Use Ubuntu LTS-1 for broader glibc compatibility.
os: [ubuntu-20.04]
node-version: [16.0, 18.0, 19.0, 20.0]
include:
- os: ubuntu-latest
- os: ubuntu-20.04
os-name: 🐧
- os: macos-latest
os-name: 🍏
node-version: 18.0
node-version: 20.0
- node-version: 18.0
- node-version: 20.0
build-doc: true
steps:
@@ -44,14 +113,12 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
uses: dtolnay/rust-toolchain@stable
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install Node.js
uses: actions/setup-node@v3
@@ -102,20 +169,19 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
target: wasm32-unknown-unknown
profile: minimal
override: true
targets: wasm32-unknown-unknown
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18.0
node-version: 20.0
- name: Install NPM dependencies
working-directory: ${{ env.MATRIX_SDK_CRYPTO_JS_PATH }}
@@ -135,43 +201,44 @@ jobs:
test-apple:
name: matrix-rust-components-swift
needs: xtask
runs-on: macos-12
if: github.event_name == 'push' || !github.event.pull_request.draft
steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v3
# install protoc in case we end up rebuilding opentelemetry-proto
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: nightly
profile: minimal
override: true
uses: dtolnay/rust-toolchain@stable
- name: Install targets
run: |
rustup target add aarch64-apple-ios-sim --toolchain nightly
rustup target add x86_64-apple-ios --toolchain nightly
- name: Install aarch64-apple-ios target
run: rustup target install aarch64-apple-ios
- name: Load cache
uses: Swatinem/rust-cache@v1
- name: Install Uniffi
uses: actions-rs/cargo@v1
uses: Swatinem/rust-cache@v2
with:
command: install
# keep in sync with uniffi dependency in Cargo.toml's
args: uniffi_bindgen --git https://github.com/mozilla/uniffi-rs --rev 091c3561656e72e1a4160412c83b36d98e556d06
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Generate .xcframework
working-directory: bindings/apple
run: sh ./debug_build_xcframework.sh x86_64 ci
- name: Get xtask
uses: actions/cache/restore@v3
with:
path: target/debug/xtask
key: "${{ needs.xtask.outputs.cachekey-macos }}"
fail-on-cache-miss: true
- name: Build library & bindings
run: target/debug/xtask swift build-library
- name: Run XCTests
working-directory: bindings/apple
run: |
xcodebuild test \
-scheme MatrixRustSDK \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 13'
run: swift test
- name: Build Framework
run: target/debug/xtask swift build-framework --only-target=aarch64-apple-ios
+194 -150
View File
@@ -12,46 +12,16 @@ on:
- synchronize
- ready_for_review
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
cancel-others:
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.9.1
with:
access_token: ${{ github.token }}
xtask:
runs-on: ubuntu-latest
steps:
- name: Checkout repo
uses: actions/checkout@v2
- name: Check xtask cache
uses: actions/cache@v3
id: xtask-cache
with:
path: target/debug/xtask
key: xtask-${{ hashFiles('xtask/**') }}
- name: Install rust stable toolchain
if: steps.xtask-cache.outputs.cache-hit != 'true'
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: stable
override: true
- name: Build
if: steps.xtask-cache.outputs.cache-hit != 'true'
uses: actions-rs/cargo@v1
with:
command: build
args: -p xtask
uses: ./.github/workflows/xtask.yml
test-matrix-sdk-features:
name: 🐧 [m], ${{ matrix.name }}
@@ -64,9 +34,9 @@ jobs:
matrix:
name:
- no-encryption
- no-sled
- no-encryption-and-sled
- sled-cryptostore
- no-sqlite
- no-encryption-and-sqlite
- sqlite-cryptostore
- rustls-tls
- markdown
- socks
@@ -74,32 +44,35 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
uses: dtolnay/rust-toolchain@stable
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
# use a separate cache for each job to work around
# https://github.com/Swatinem/rust-cache/issues/124
key: "${{ matrix.name }}"
# ... but only save the cache on the main branch
# cf https://github.com/Swatinem/rust-cache/issues/95
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install nextest
uses: taiki-e/install-action@nextest
- name: Get xtask
uses: actions/cache@v3
uses: actions/cache/restore@v3
with:
path: target/debug/xtask
key: xtask-${{ hashFiles('xtask/**') }}
key: "${{ needs.xtask.outputs.cachekey-linux }}"
fail-on-cache-miss: true
- name: Test
uses: actions-rs/cargo@v1
with:
command: run
args: -p xtask -- ci test-features ${{ matrix.name }}
run: |
target/debug/xtask ci test-features ${{ matrix.name }}
test-matrix-sdk-examples:
name: 🐧 [m]-examples
@@ -112,29 +85,26 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
uses: dtolnay/rust-toolchain@stable
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install nextest
uses: taiki-e/install-action@nextest
- name: Get xtask
uses: actions/cache@v3
uses: actions/cache/restore@v3
with:
path: target/debug/xtask
key: xtask-${{ hashFiles('xtask/**') }}
key: "${{ needs.xtask.outputs.cachekey-linux }}"
fail-on-cache-miss: true
- name: Test
uses: actions-rs/cargo@v1
with:
command: run
args: -p xtask -- ci examples
run: |
target/debug/xtask ci examples
test-matrix-sdk-crypto:
name: 🐧 [m]-crypto
@@ -147,29 +117,26 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
uses: dtolnay/rust-toolchain@stable
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install nextest
uses: taiki-e/install-action@nextest
- name: Get xtask
uses: actions/cache@v3
uses: actions/cache/restore@v3
with:
path: target/debug/xtask
key: xtask-${{ hashFiles('xtask/**') }}
key: "${{ needs.xtask.outputs.cachekey-linux }}"
fail-on-cache-miss: true
- name: Test
uses: actions-rs/cargo@v1
with:
command: run
args: -p xtask -- ci test-crypto
run: |
target/debug/xtask ci test-crypto
test-all-crates:
name: ${{ matrix.name }}
@@ -194,32 +161,34 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
profile: minimal
override: true
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install nextest
uses: taiki-e/install-action@nextest
- name: Test
uses: actions-rs/cargo@v1
with:
command: nextest
args: run --workspace --exclude matrix-sdk-integration-testing
run: |
cargo nextest run --workspace \
--exclude matrix-sdk-integration-testing --exclude sliding-sync-integration-test --features testing
- name: Test documentation
uses: actions-rs/cargo@v1
with:
command: test
args: --doc
run: |
cargo test --doc --features docsrs
test-wasm:
name: 🕸️ ${{ matrix.name }}
@@ -264,42 +233,44 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
target: wasm32-unknown-unknown
targets: wasm32-unknown-unknown
components: clippy
profile: minimal
override: true
- name: Install wasm-pack
uses: jetli/wasm-pack-action@v0.3.0
uses: jetli/wasm-pack-action@v0.4.0
with:
version: latest
version: v0.10.3
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
# use a separate cache for each job to work around
# https://github.com/Swatinem/rust-cache/issues/124
key: "${{ matrix.cmd }}"
# ... but only save the cache on the main branch
# cf https://github.com/Swatinem/rust-cache/issues/95
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install nextest
uses: taiki-e/install-action@nextest
- name: Get xtask
uses: actions/cache@v3
uses: actions/cache/restore@v3
with:
path: target/debug/xtask
key: xtask-${{ hashFiles('xtask/**') }}
key: "${{ needs.xtask.outputs.cachekey-linux }}"
fail-on-cache-miss: true
- name: Rust Check
uses: actions-rs/cargo@v1
with:
command: run
args: -p xtask -- ci wasm ${{ matrix.cmd }}
run: |
target/debug/xtask ci wasm ${{ matrix.cmd }}
- name: Wasm-Pack test
uses: actions-rs/cargo@v1
with:
command: run
args: -p xtask -- ci wasm-pack ${{ matrix.cmd }}
run: |
target/debug/xtask ci wasm-pack ${{ matrix.cmd }}
test-appservice:
name: ${{ matrix.os-name }} [m]-appservice
@@ -313,38 +284,37 @@ jobs:
include:
- os: ubuntu-latest
os-name: 🐧
xtask-cachekey: "${{ needs.xtask.outputs.cachekey-linux }}"
- os: macos-latest
os-name: 🍏
xtask-cachekey: "${{ needs.xtask.outputs.cachekey-macos }}"
steps:
- name: Checkout
uses: actions/checkout@v1
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
uses: dtolnay/rust-toolchain@stable
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install nextest
uses: taiki-e/install-action@nextest
- name: Get xtask
uses: actions/cache@v3
uses: actions/cache/restore@v3
with:
path: target/debug/xtask
key: xtask-${{ hashFiles('xtask/**') }}
key: "${{ matrix.xtask-cachekey }}"
fail-on-cache-miss: true
- name: Run checks
uses: actions-rs/cargo@v1
with:
command: run
args: -p xtask -- ci test-appservice
run: |
target/debug/xtask ci test-appservice
formatting:
name: Check Formatting
@@ -356,18 +326,14 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
toolchain: nightly-2023-07-03
components: rustfmt
profile: minimal
override: true
- name: Cargo fmt
uses: actions-rs/cargo@v1
with:
command: fmt
args: -- --check
run: |
cargo fmt -- --check
typos:
name: Spell Check with Typos
@@ -379,7 +345,7 @@ jobs:
uses: actions/checkout@v3
- name: Check the spelling of the files in our repo
uses: crate-ci/typos@master
uses: crate-ci/typos@v1.15.10
clippy:
name: Run clippy
@@ -391,28 +357,32 @@ jobs:
- name: Checkout the repo
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
toolchain: nightly
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2023-07-03
components: clippy
profile: minimal
override: true
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Get xtask
uses: actions/cache@v3
uses: actions/cache/restore@v3
with:
path: target/debug/xtask
key: xtask-${{ hashFiles('xtask/**') }}
key: "${{ needs.xtask.outputs.cachekey-linux }}"
fail-on-cache-miss: true
- name: Clippy
uses: actions-rs/cargo@v1
with:
command: run
args: -p xtask -- ci clippy
run: |
target/debug/xtask ci clippy
integration-tests:
name: Integration test
@@ -425,14 +395,12 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
uses: dtolnay/rust-toolchain@stable
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install nextest
uses: taiki-e/install-action@nextest
@@ -443,12 +411,88 @@ jobs:
- uses: michaelkaye/setup-matrix-synapse@main
with:
installer: poetry
uploadLogs: true
httpPort: 8228
disableRateLimiting: true
- name: Test
uses: actions-rs/cargo@v1
run: |
cargo nextest run -p matrix-sdk-integration-testing
sliding-sync-integration-tests:
name: Sliding Sync Integration test
if: github.event_name == 'push' || !github.event.pull_request.draft
runs-on: ubuntu-latest
# run several docker containers with the same networking stack so the hostname 'postgres'
# maps to the postgres container, etc.
services:
# sliding sync needs a postgres container
postgres:
# Docker Hub image
image: postgres
# Provide the password for postgres
env:
POSTGRES_PASSWORD: postgres
POSTGRES_USER: postgres
POSTGRES_DB: syncv3
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 5432 on service container to the host
- 5432:5432
# run sliding sync and point it at the postgres container and synapse container.
# the postgres container needs to be above this to make sure it has started prior to this service.
slidingsync:
image: "ghcr.io/matrix-org/sliding-sync:v0.99.2"
env:
SYNCV3_SERVER: "http://synapse:8008"
SYNCV3_SECRET: "SUPER_CI_SECRET"
SYNCV3_BINDADDR: ":8118"
SYNCV3_DB: "user=postgres password=postgres dbname=syncv3 sslmode=disable host=postgres"
ports:
- 8118:8118
# tests need a synapse: this is a service and not michaelkaye/setup-matrix-synapse@main as the
# latter does not provide networking for services to communicate with it.
synapse:
# Custom image built from https://github.com/matrix-org/synapse/tree/v1.72.0/docker/complement
# with a dummy /complement/ca set
image: ghcr.io/matrix-org/synapse-service:v1.72.0
env:
SYNAPSE_COMPLEMENT_DATABASE: sqlite
SERVER_NAME: synapse
ports:
- 8008:8008
steps:
- name: Checkout the repo
uses: actions/checkout@v3
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Load cache
uses: Swatinem/rust-cache@v2
with:
command: nextest
args: run -p matrix-sdk-integration-testing
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install nextest
uses: taiki-e/install-action@nextest
- uses: actions/setup-python@v4
with:
python-version: 3.8
- name: Test
env:
RUST_LOG: "hyper=trace"
HOMESERVER_URL: "http://localhost:8008"
HOMESERVER_DOMAIN: "synapse"
SLIDING_SYNC_PROXY_URL: "http://localhost:8118"
run: |
cargo nextest run -p sliding-sync-integration-test
+26 -14
View File
@@ -5,6 +5,15 @@ on:
branches: [main]
pull_request:
branches: [main]
types:
- opened
- reopened
- synchronize
- ready_for_review
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
@@ -22,38 +31,41 @@ jobs:
ref: ${{ github.event.pull_request.head.sha }}
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
uses: dtolnay/rust-toolchain@stable
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
- name: Install tarpaulin
uses: actions-rs/cargo@v1
uses: taiki-e/install-action@v2
with:
command: install
args: cargo-tarpaulin
tool: cargo-tarpaulin
# set up backend for integration tests
- uses: actions/setup-python@v4
with:
python-version: 3.8
- uses: gnunicorn/setup-matrix-synapse@main
- uses: michaelkaye/setup-matrix-synapse@main
with:
installer: poetry
uploadLogs: true
httpPort: 8228
disableRateLimiting: true
serverName: "matrix-sdk.rs"
- name: Run tarpaulin
uses: actions-rs/cargo@v1
with:
command: tarpaulin
args: --out Xml
run: |
cargo tarpaulin --out Xml -e sliding-sync-integration-test --features testing
- name: Upload to codecov.io
uses: codecov/codecov-action@v3
with:
# Work around frequent upload errors, for runs inside the main repo (not PRs from forks).
# Otherwise not required for public repos.
token: ${{ secrets.CODECOV_UPLOAD_TOKEN }}
# The upload sometimes fails due to https://github.com/codecov/codecov-action/issues/837.
# To make sure that the failure gets flagged clearly in the UI, fail the action.
fail_ci_if_error: true
+18 -11
View File
@@ -5,6 +5,10 @@ on:
branches: [main]
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
docs:
name: All crates
@@ -15,31 +19,34 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
- name: Install Protoc
uses: arduino/setup-protoc@v1
with:
profile: minimal
toolchain: nightly
override: true
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly-2023-07-03
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18
node-version: 20
- name: Load cache
uses: Swatinem/rust-cache@v1
uses: Swatinem/rust-cache@v2
with:
save-if: ${{ github.ref == 'refs/head/main' }}
# Keep in sync with xtask docs
- name: Build rust documentation
uses: actions-rs/cargo@v1
env:
# Work around https://github.com/rust-lang/cargo/issues/10744
CARGO_TARGET_APPLIES_TO_HOST: "true"
RUSTDOCFLAGS: "--enable-index-page -Zunstable-options --cfg docsrs -Dwarnings"
with:
command: doc
args: --no-deps --features docsrs
run:
cargo doc --no-deps --workspace --features docsrs
- name: Build `matrix-sdk-crypto-nodejs` doc
run: |
@@ -61,7 +61,7 @@ jobs:
uses: orhun/git-cliff-action@v1
with:
config: "${{ env.PKG_PATH }}/cliff.toml"
args: "${{ inputs.previous_version }}..HEAD"
args: "${{env.TAG_PREFIX}}${{ inputs.previous_version }}..HEAD"
env:
GIT_CLIFF_TAG: "${{ inputs.version }}"
GIT_CLIFF_PREPEND: "${{ env.PKG_PATH }}/CHANGELOG.md"
@@ -110,8 +110,10 @@ jobs:
trigger-release:
# and trigger the tagging release workflow
uses: matrix-org/matrix-rust-sdk/.github/workflows/release-crypto-nodejs.yml@main
uses: ./.github/workflows/release-crypto-nodejs.yml
needs: ['prepare-release']
name: "Trigger release Workflow"
with:
tag: ${{needs.prepare-release.outputs.tag}}
secrets:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
+16 -16
View File
@@ -27,6 +27,10 @@ on:
description: "The tag to build with"
required: true
type: string
secrets:
NPM_TOKEN:
required: true
jobs:
upload-assets:
name: "Upload prebuilt libraries"
@@ -35,19 +39,21 @@ jobs:
matrix:
include:
# ----------------------------------- Linux
# Use Ubuntu LTS-1 for broader glibc compatibility.
- target: x86_64-unknown-linux-gnu
os: ubuntu-latest
os: ubuntu-20.04
- target: i686-unknown-linux-gnu
apt_install: gcc-i686-linux-gnu g++-i686-linux-gnu
os: ubuntu-latest
os: ubuntu-20.04
- target: aarch64-unknown-linux-gnu
os: ubuntu-latest
os: ubuntu-20.04
apt_install: gcc-aarch64-linux-gnu g++-aarch64-linux-gnu
- target: arm-unknown-linux-gnueabihf
os: ubuntu-latest
os: ubuntu-20.04
apt_install: gcc-arm-linux-gnueabihf
- target: x86_64-unknown-linux-musl
os: ubuntu-latest
os: ubuntu-20.04
apt_install: musl-tools
# ----------------------------------- macOS
- target: aarch64-apple-darwin
os: macos-latest
@@ -72,16 +78,12 @@ jobs:
- uses: actions/checkout@v3
if: "${{ !inputs.tag }}"
- name: Install Rust
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
profile: minimal
target: ${{ matrix.target }}
override: true
toolchain: nightly-2023-07-03
targets: ${{ matrix.target }}
- name: Install Node.js
uses: actions/setup-node@v3
- name: Load cache
uses: Swatinem/rust-cache@v1
- if: ${{ matrix.apt_install }}
run: |
sudo apt-get update
@@ -113,11 +115,9 @@ jobs:
- uses: actions/checkout@v3
if: "${{ !inputs.tag }}"
- name: Install Rust
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
profile: minimal
override: true
toolchain: nightly-2023-07-03
- name: Install Node.js
uses: actions/setup-node@v3
- name: Build lib
+12 -19
View File
@@ -1,9 +1,9 @@
# This workflow releases the `matrix-sdk-crypto-js` project.
#
# It is triggered when a new tag appears that matches
# `matrix-sdk-crypto-js-v[0-9]+.*`. This workflow builds the package
# for the binding, run its tests to ensure everything is still
# correct, and publish the package on NPM and on a newly created
# `matrix-sdk-crypto-js-[0-9]+.*`. This workflow builds the package
# for the bindings, runs its tests to ensure everything is still
# correct, and publishes the package on NPM and on a newly created
# Github release.
@@ -16,7 +16,7 @@ env:
on:
push:
tags:
- matrix-sdk-crypto-js-v[0-9]+.*
- matrix-sdk-crypto-js-[0-9]+.*
jobs:
publish-matrix-sdk-crypto-js:
@@ -29,32 +29,25 @@ jobs:
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
target: wasm32-unknown-unknown
profile: minimal
override: true
- name: Load cache
uses: Swatinem/rust-cache@v1
targets: wasm32-unknown-unknown
- name: Install Node.js
uses: actions/setup-node@v3
with:
node-version: 18.0
node-version: 20.0
- name: Install NPM dependencies
working-directory: ${{ env.PKG_PATH }}
run: npm install
- name: Configure NPM auth token
working-directory: ${{ env.PKG_PATH }}
run: npm set "//registry.npmjs.org/:_authToken" "${{ secrets.NPM_TOKEN }}"
- name: Publish the WebAssembly + JavaScript binding (imply building + testing)
working-directory: ${{ env.PKG_PATH }}
run: npm run publish
uses: JS-DevTools/npm-publish@v1
with:
package: ${{env.PKG_PATH}}/package.json
access: public
token: ${{ secrets.NPM_TOKEN }}
- name: Create the Github release
uses: softprops/action-gh-release@v1
+76
View File
@@ -0,0 +1,76 @@
# A reusable github actions workflow that will build xtask, if it is not
# already cached.
#
# It will create a pair of GHA cache entries, if they do not already exist.
# The cache keys take the form `xtask-{os}-{hash}`, where "{os}" is "linux"
# or "macos", and "{hash}" is the hash of the xtask# directory.
#
# The cache keys are written to output variables named "cachekey-{os}".
#
name: Build xtask if necessary
on:
workflow_call:
outputs:
cachekey-linux:
description: "The cache key for the linux build artifact"
value: "${{ jobs.xtask.outputs.cachekey-linux }}"
cachekey-macos:
description: "The cache key for the macos build artifact"
value: "${{ jobs.xtask.outputs.cachekey-macos }}"
env:
CARGO_TERM_COLOR: always
jobs:
xtask:
name: "xtask-${{ matrix.os-name }}"
strategy:
fail-fast: true
matrix:
include:
- os: ubuntu-latest
os-name: 🐧
cachekey-id: linux
- os: macos-12
os-name: 🍏
cachekey-id: macos
runs-on: "${{ matrix.os }}"
steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Calculate cache key
id: cachekey
# set a step output variable "cachekey-{os}" that can be referenced in
# the job outputs below.
run: |
echo "cachekey-${{ matrix.cachekey-id }}=xtask-${{ matrix.cachekey-id }}-${{ hashFiles('Cargo.toml', 'xtask/**') }}" >> $GITHUB_OUTPUT
- name: Check xtask cache
uses: actions/cache@v3
id: xtask-cache
with:
path: target/debug/xtask
# use the cache key calculated in the step above. Bit of an awkard
# syntax
key: |
${{ steps.cachekey.outputs[format('cachekey-{0}', matrix.cachekey-id)] }}
- name: Install Rust stable toolchain
if: steps.xtask-cache.outputs.cache-hit != 'true'
uses: dtolnay/rust-toolchain@stable
- name: Build
if: steps.xtask-cache.outputs.cache-hit != 'true'
run: |
cargo build -p xtask
outputs:
"cachekey-linux": "${{ steps.cachekey.outputs.cachekey-linux }}"
"cachekey-macos": "${{ steps.cachekey.outputs.cachekey-macos }}"
+8
View File
@@ -4,6 +4,9 @@ master.zip
emsdk-*
.idea/
.env
.build
.swiftpm
/Package.swift
## User settings
xcuserdata/
@@ -11,3 +14,8 @@ xcuserdata/
## OS garbage
.DS_Store
## Kotlin bindings generated files
bindings/kotlin/.gradle/
bindings/kotlin/buildSrc/build/
bindings/kotlin/buildSrc/.gradle/
+17 -12
View File
@@ -1,15 +1,20 @@
[default.extend-words]
# Remove this once base64 gets correctly ignored by typos
# Or if we're able to ignore certain lines.
Fo = "Fo"
BA = "BA"
UE = "UE"
Ure = "Ure"
Ot = "Ot"
# This is the thead html tag, remove this once typos is updated in the github
# action. 1.3.1 seems to work correctly, while 1.11.0 on the CI seems to get
# this wrong
thead = "thead"
[default]
extend-ignore-re = [
# base 58 strings with spaces every four chars.
# this would also match regular sentence parts with eight or more words of
# exactly four characters in row, but that doesn't really happen.
"[1-9A-Za-z]{4}( [1-9A-Za-z]{4}){7,}",
# some heuristics for base64 strings with no false matches found at the
# time of writing.
"[A-Za-z0-9+=]{72,}",
"([A-Za-z0-9+=]|\\\\\\s\\*){72,}",
"[0-9+][A-Za-z0-9+]{30,}[a-z0-9+]",
"\\$[A-Z0-9+][A-Za-z0-9+]{6,}[a-z0-9+]",
"\\b[a-z0-9+/=][A-Za-z0-9+/=]{7,}[a-z0-9+/=][A-Z]\\b",
]
[default.extend-identifiers]
WeeChat = "WeeChat"
[files]
# Our json files contain a bunch of base64 encoded ed25519 keys which aren't
+102
View File
@@ -0,0 +1,102 @@
# Contributing to matrix-rust-sdk
## Chat rooms
In addition to our [main Matrix room], we have a development room at
[#matrix-rust-sdk-dev:flipdot.org]. Please use it to discuss potential changes,
the overall direction of development and related topics.
[main Matrix room]: https://matrix.to/#/#matrix-rust-sdk:matrix.org
[#matrix-rust-sdk-dev:flipdot.org]: https://matrix.to/#/#matrix-rust-sdk-dev:flipdot.org
## Testing
You can run most of the tests that also happen in CI also using
`cargo xtask ci`. This needs a few dependencies to be installed, as it also runs
automatic WASM tests:
```bash
rustup component add clippy
cargo install cargo-nextest typos-cli wasm-pack
```
If you want to execute only one part of CI, there are a few sub-commands (see
`cargo xtask ci --help`).
Some tests are not automatically run in `cargo xtask ci`, for example the
integration tests that need a running synapse instance. These tests reside in
`./testing/matrix-sdk-integration-testing`. See its
[README](./testing/matrix-sdk-integration-testing/README.md) to easily set up a
synapse for testing purposes.
## Sign off
In order to have a concrete record that your contribution is intentional
and you agree to license it under the same terms as the project's license, we've
adopted the same lightweight approach that the Linux Kernel
(https://www.kernel.org/doc/Documentation/SubmittingPatches), Docker
(https://github.com/docker/docker/blob/master/CONTRIBUTING.md), and many other
projects use: the DCO (Developer Certificate of Origin:
http://developercertificate.org/). This is a simple declaration that you wrote
the contribution or otherwise have the right to contribute it to Matrix:
```
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
660 York Street, Suite 102,
San Francisco, CA 94110 USA
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```
If you agree to this for your contribution, then all that's needed is to
include the line in your commit or pull request comment:
```
Signed-off-by: Your Name <your@email.example.org>
```
We accept contributions under a legally identifiable name, such as your name on
government documentation or common-law names (names claimed by legitimate usage
or repute). Unfortunately, we cannot accept anonymous contributions at this
time.
Git allows you to add this signoff automatically when using the `-s` flag to
`git commit`, which uses the name and email set in your `user.name` and
`user.email` git configs.
If you forgot to sign off your commits before making your pull request and are
on Git 2.17+ you can mass signoff using rebase:
```
git rebase --signoff origin/main
```
-120
View File
@@ -1,120 +0,0 @@
# Conventional Commits
This project uses [Conventional
Commits](https://www.conventionalcommits.org/). Read the
[Summary](https://www.conventionalcommits.org/en/v1.0.0/#summary) or
the [Full
Specification](https://www.conventionalcommits.org/en/v1.0.0/#specification)
to learn more.
## Types
Conventional Commits defines _type_ (as in `type(scope):
message`). This section aims at listing the types used inside this
project:
| Type | Definition |
|-|-|
| `feat` | About a new feature. |
| `fix` | About a bug fix. |
| `test` | About a test (suite, case, runner…). |
| `doc` | About a documentation modification. |
| `refactor` | About a refactoring. |
| `ci` | About a Continuous Integration modification. |
| `chore` | About some cleanup, or regular tasks. |
## Scopes
Conventional Commits defines _scope_ (as in `type(scope): message`). This
section aims at listing all the scopes used inside this project:
<table>
<thead>
<tr>
<th>Group</th>
<th>Scope</th>
<th>Definition</th>
</tr>
</thead>
<tbody>
<tr>
<td rowspan="10">Crates</td>
<td><code>sdk</code></td>
<td>About the <code>matrix-sdk</code> crate.</td>
</tr>
<tr>
<td><code>appservice</code></td>
<td>About the <code>matrix-sdk-appservice</code> crate.</td>
</tr>
<tr>
<td><code>base</code></td>
<td>About the <code>matrix-sdk-base</code> crate.</td>
</tr>
<tr>
<td><code>common</code></td>
<td>About the <code>matrix-sdk-common</code> crate.</td>
</tr>
<tr>
<td><code>crypto</code></td>
<td>About the <code>matrix-sdk-crypto</code> crate.</td>
</tr>
<tr>
<td><code>indexeddb</code></td>
<td>About the <code>matrix-sdk-indexeddb</code> crate.</td>
</tr>
<tr>
<td><code>qrcode</code></td>
<td>About the <code>matrix-sdk-qrcode</code> crate.</td>
</tr>
<tr>
<td><code>sled</code></td>
<td>About the <code>matrix-sdk-sled</code> crate.</td>
</tr>
<tr>
<td><code>store-encryption</code></td>
<td>About the <code>matrix-sdk-store-encryption</code> crate.</td>
</tr>
<tr>
<td><code>test</code></td>
<td>About the <code>matrix-sdk-test</code> and <code>matrix-sdk-test-macros</code> crate.</td>
</tr>
<tr>
<td rowspan="4">Bindings</td>
<td><code>apple</code></td>
<td>About the <code>matrix-rust-components-swift</code> binding.</td>
</tr>
<tr>
<td><code>crypto-nodejs</code></td>
<td>About the <code>matrix-sdk-crypto-nodejs</code> binding.</td>
</tr>
<tr>
<td><code>crypto-js</code></td>
<td>About the <code>matrix-sdk-crypto-js</code> binding.</td>
</tr>
<tr>
<td><code>crypto-ffi</code></td>
<td>About the <code>matrix-sdk-crypto-ffi</code> binding.</td>
</tr>
<tr>
<td>Labs</td>
<td><code>sled-state-inspector</code></td>
<td>About the <code>sled-state-inspector</code> project.</td>
</tr>
<tr>
<td>Continuous Integration</td>
<td><code>xtask</code></td>
<td>About the <code>xtask</code> project.</td>
</tr>
</tbody>
</table>
## Generating `CHANGELOG.md`
The [`git-cliff`](https://github.com/orhun/git-cliff) project is used
to generate `CHANGELOG.md` automatically. Hence the various
`cliff.toml` files that are present in this project, or the
`package.metadata.git-cliff` sections in various `Cargo.toml` files.
Its companion,
[`git-cliff-action`](https://github.com/orhun/git-cliff-action)
project, is used inside Github Action workflows.
Generated
+2272 -1586
View File
File diff suppressed because it is too large Load Diff
+55 -5
View File
@@ -8,20 +8,56 @@ members = [
"crates/*",
"testing/*",
"examples/*",
"labs/*",
"uniffi-bindgen",
"xtask",
]
# xtask, labs, testing and the bindings should only be built when invoked explicitly.
# xtask, testing and the bindings should only be built when invoked explicitly.
default-members = ["benchmarks", "crates/*"]
resolver = "2"
[workspace.package]
rust-version = "1.70"
[workspace.dependencies]
anyhow = "1.0.68"
assert_matches = "1.5.0"
async-stream = "0.3.3"
async-trait = "0.1.60"
base64 = "0.21.0"
byteorder = "1.4.3"
ctor = "0.2.0"
dashmap = "5.2.0"
eyeball = "0.8.3"
eyeball-im = "0.2.0"
eyeball-im-util = "0.2.1"
futures-core = "0.3.28"
futures-executor = "0.3.21"
futures-util = { version = "0.3.26", default-features = false, features = ["alloc"] }
http = "0.2.6"
itertools = "0.11.0"
ruma = { git = "https://github.com/ruma/ruma", rev = "5fde57460aaa71e16ac68f79376843089f9c3dfc", features = ["client-api-c", "compat-user-id"] }
ruma-common = { git = "https://github.com/ruma/ruma", rev = "5fde57460aaa71e16ac68f79376843089f9c3dfc" }
once_cell = "1.16.0"
serde = "1.0.151"
serde_html_form = "0.2.0"
serde_json = "1.0.91"
thiserror = "1.0.38"
tokio = { version = "1.24", default-features = false, features = ["sync"] }
tracing = { version = "0.1.36", default-features = false, features = ["std"] }
tracing-core = "0.1.30"
uniffi = { git = "https://github.com/mozilla/uniffi-rs", rev = "41b91c8df67d8324be3da883591f82692d9b8596" }
uniffi_bindgen = { git = "https://github.com/mozilla/uniffi-rs", rev = "41b91c8df67d8324be3da883591f82692d9b8596" }
vodozemac = "0.4.0"
zeroize = "1.3.0"
# Default release profile, select with `--release`
[profile.release]
lto = true
# Default development profile; default for most Cargo commands, otherwise
# selected with `--debug`
[profile.dev]
# Copied from rust-analyzer. Saves a lot of disk space and hopefully
# compilation time / mem usage too, at the expense of potentially having to
# change this setting here when you want to use a debugger.
# Saves a lot of disk space. If symbols are needed, use the dbg profile.
debug = 0
[profile.dev.package]
@@ -29,3 +65,17 @@ debug = 0
# for the extra time of optimizing it for a clean build of matrix-sdk-ffi.
quote = { opt-level = 2 }
sha2 = { opt-level = 2 }
# Custom profile with full debugging info, use `--profile dbg` to select
[profile.dbg]
inherits = "dev"
debug = 2
# Custom profile for use in (debug) builds of the binding crates, use
# `--profile reldbg` to select
[profile.reldbg]
inherits = "dev"
opt-level = 3
[patch.crates-io]
async-compat = { git = "https://github.com/jplatte/async-compat", rev = "b83b197622d8b5756d3594ce73b720896b07faae" }
+2 -2
View File
@@ -1,4 +1,4 @@
![Build Status](https://img.shields.io/github/workflow/status/matrix-org/matrix-rust-sdk/CI?style=flat-square)
![Build Status](https://img.shields.io/github/actions/workflow/status/matrix-org/matrix-rust-sdk/ci.yml?style=flat-square)
[![codecov](https://img.shields.io/codecov/c/github/matrix-org/matrix-rust-sdk/main.svg?style=flat-square)](https://codecov.io/gh/matrix-org/matrix-rust-sdk)
[![License](https://img.shields.io/badge/License-Apache%202.0-yellowgreen.svg?style=flat-square)](https://opensource.org/licenses/Apache-2.0)
[![#matrix-rust-sdk](https://img.shields.io/badge/matrix-%23matrix--rust--sdk-blue?style=flat-square)](https://matrix.to/#/#matrix-rust-sdk:matrix.org)
@@ -26,7 +26,7 @@ The rust-sdk consists of multiple crates that can be picked at your convenience:
## Minimum Supported Rust Version (MSRV)
These crates are built with the Rust language version 2021 and require a minimum compiler version of `1.60`
These crates are built with the Rust language version 2021 and require a minimum compiler version of `1.70`.
## Status
+1 -1
View File
@@ -51,7 +51,7 @@ You can stay informed about updates on the access token by listening to `client.
- [`MessageOptions`][message options] has been updated to Matrix 1.3 by making the `from` parameter optional (and function signatures have been updated, too). You can now request the server sends you messages from the first one you are allowed to have received.
- `client.user_id()` is not a `future` anymore. Remove any `.await` you had behind it.
- `verified()`, `blacklisted()` and `deleted()` on `matrix_sdk::encryption::identities::Device` have been renamed with a `is_` prefix.
- `verified()` on `matrix_sdk::encryption::identities::UserIdentity`, too has been prefixed with `is_` and thus is onw called `is_verified()`.
- `verified()` on `matrix_sdk::encryption::identities::UserIdentity`, too has been prefixed with `is_` and thus is now called `is_verified()`.
- The top-level crypto and state-store types of Indexeddb and Sled have been renamed to unique types>
- `state_store` and `crypto_store` do not need to be boxed anymore when passed to the [`StoreConfig`][store config]
- Indexeddb's `SerializationError` is now `IndexedDBStoreError`
+13 -7
View File
@@ -3,23 +3,29 @@ name = "benchmarks"
description = "Matrix SDK benchmarks"
edition = "2021"
license = "Apache-2.0"
rust-version = "1.56"
rust-version = { workspace = true }
version = "1.0.0"
publish = false
[dependencies]
criterion = { version = "0.3.5", features = ["async", "async_tokio", "html_reports"] }
criterion = { version = "0.5.1", features = ["async", "async_tokio", "html_reports"] }
matrix-sdk-base = { path = "../crates/matrix-sdk-base" }
matrix-sdk-crypto = { path = "../crates/matrix-sdk-crypto", version = "0.6.0"}
matrix-sdk-sled = { path = "../crates/matrix-sdk-sled", version = "0.2.0", default-features = false, features = ["crypto-store"] }
matrix-sdk-sqlite = { path = "../crates/matrix-sdk-sqlite", version = "0.1.0", default-features = false, features = ["crypto-store"] }
matrix-sdk-test = { path = "../testing/matrix-sdk-test", version = "0.6.0"}
ruma = "0.7.0"
serde_json = "1.0.79"
matrix-sdk = { path = "../crates/matrix-sdk" }
ruma = { workspace = true }
serde_json = { workspace = true }
tempfile = "3.3.0"
tokio = { version = "1.17.0", default-features = false, features = ["rt-multi-thread"] }
tokio = { version = "1.24.2", default-features = false, features = ["rt-multi-thread"] }
[target.'cfg(target_os = "linux")'.dependencies]
pprof = { version = "0.10.0", features = ["flamegraph", "criterion"] }
pprof = { version = "0.12.0", features = ["flamegraph", "criterion"] }
[[bench]]
name = "crypto_bench"
harness = false
[[bench]]
name = "store_bench"
harness = false
+45 -11
View File
@@ -2,7 +2,7 @@ use std::{ops::Deref, sync::Arc};
use criterion::*;
use matrix_sdk_crypto::{EncryptionSettings, OlmMachine};
use matrix_sdk_sled::SledCryptoStore;
use matrix_sdk_sqlite::SqliteCryptoStore;
use matrix_sdk_test::response_from_file;
use ruma::{
api::{
@@ -65,21 +65,30 @@ pub fn keys_query(c: &mut Criterion) {
let name = format!("{count} device and cross signing keys");
// Benchmark memory store.
group.bench_with_input(BenchmarkId::new("memory store", &name), &response, |b, response| {
b.to_async(&runtime)
.iter(|| async { machine.mark_request_as_sent(&txn_id, response).await.unwrap() })
});
// Benchmark sqlite store.
let dir = tempfile::tempdir().unwrap();
let store = Arc::new(SledCryptoStore::open_with_passphrase(dir.path(), None).unwrap());
let store = Arc::new(runtime.block_on(SqliteCryptoStore::open(dir.path(), None)).unwrap());
let machine =
runtime.block_on(OlmMachine::with_store(alice_id(), alice_device_id(), store)).unwrap();
group.bench_with_input(BenchmarkId::new("sled store", &name), &response, |b, response| {
group.bench_with_input(BenchmarkId::new("sqlite store", &name), &response, |b, response| {
b.to_async(&runtime)
.iter(|| async { machine.mark_request_as_sent(&txn_id, response).await.unwrap() })
});
{
let _guard = runtime.enter();
drop(machine);
}
group.finish()
}
@@ -108,18 +117,21 @@ pub fn keys_claiming(c: &mut Criterion) {
(machine, &runtime, &txn_id)
},
move |(machine, runtime, txn_id)| {
runtime.block_on(machine.mark_request_as_sent(txn_id, response)).unwrap()
runtime.block_on(async {
machine.mark_request_as_sent(txn_id, response).await.unwrap();
drop(machine);
})
},
BatchSize::SmallInput,
)
});
group.bench_with_input(BenchmarkId::new("sled store", &name), &response, |b, response| {
group.bench_with_input(BenchmarkId::new("sqlite store", &name), &response, |b, response| {
b.iter_batched(
|| {
let dir = tempfile::tempdir().unwrap();
let store =
Arc::new(SledCryptoStore::open_with_passphrase(dir.path(), None).unwrap());
Arc::new(runtime.block_on(SqliteCryptoStore::open(dir.path(), None)).unwrap());
let machine = runtime
.block_on(OlmMachine::with_store(alice_id(), alice_device_id(), store))
@@ -130,7 +142,10 @@ pub fn keys_claiming(c: &mut Criterion) {
(machine, &runtime, &txn_id)
},
move |(machine, runtime, txn_id)| {
runtime.block_on(machine.mark_request_as_sent(txn_id, response)).unwrap()
runtime.block_on(async {
machine.mark_request_as_sent(txn_id, response).await.unwrap();
drop(machine)
})
},
BatchSize::SmallInput,
)
@@ -160,6 +175,8 @@ pub fn room_key_sharing(c: &mut Criterion) {
group.throughput(Throughput::Elements(count as u64));
let name = format!("{count} devices");
// Benchmark memory store.
group.bench_function(BenchmarkId::new("memory store", &name), |b| {
b.to_async(&runtime).iter(|| async {
let requests = machine
@@ -180,15 +197,18 @@ pub fn room_key_sharing(c: &mut Criterion) {
machine.invalidate_group_session(room_id).await.unwrap();
})
});
// Benchmark sqlite store.
let dir = tempfile::tempdir().unwrap();
let store = Arc::new(SledCryptoStore::open_with_passphrase(dir.path(), None).unwrap());
let store = Arc::new(runtime.block_on(SqliteCryptoStore::open(dir.path(), None)).unwrap());
let machine =
runtime.block_on(OlmMachine::with_store(alice_id(), alice_device_id(), store)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&txn_id, &keys_query_response)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&txn_id, &response)).unwrap();
group.bench_function(BenchmarkId::new("sled store", &name), |b| {
group.bench_function(BenchmarkId::new("sqlite store", &name), |b| {
b.to_async(&runtime).iter(|| async {
let requests = machine
.share_room_key(
@@ -209,6 +229,11 @@ pub fn room_key_sharing(c: &mut Criterion) {
})
});
{
let _guard = runtime.enter();
drop(machine);
}
group.finish()
}
@@ -229,26 +254,35 @@ pub fn devices_missing_sessions_collecting(c: &mut Criterion) {
runtime.block_on(machine.mark_request_as_sent(&txn_id, &response)).unwrap();
// Benchmark memory store.
group.bench_function(BenchmarkId::new("memory store", &name), |b| {
b.to_async(&runtime).iter_with_large_drop(|| async {
machine.get_missing_sessions(users.iter().map(Deref::deref)).await.unwrap()
})
});
// Benchmark sqlite store.
let dir = tempfile::tempdir().unwrap();
let store = Arc::new(SledCryptoStore::open_with_passphrase(dir.path(), None).unwrap());
let store = Arc::new(runtime.block_on(SqliteCryptoStore::open(dir.path(), None)).unwrap());
let machine =
runtime.block_on(OlmMachine::with_store(alice_id(), alice_device_id(), store)).unwrap();
runtime.block_on(machine.mark_request_as_sent(&txn_id, &response)).unwrap();
group.bench_function(BenchmarkId::new("sled store", &name), |b| {
group.bench_function(BenchmarkId::new("sqlite store", &name), |b| {
b.to_async(&runtime).iter(|| async {
machine.get_missing_sessions(users.iter().map(Deref::deref)).await.unwrap()
})
});
{
let _guard = runtime.enter();
drop(machine);
}
group.finish()
}
+123
View File
@@ -0,0 +1,123 @@
use criterion::*;
use matrix_sdk::{
config::StoreConfig,
matrix_auth::{Session, SessionTokens},
Client, RoomInfo, RoomState, StateChanges,
};
use matrix_sdk_base::{store::MemoryStore, SessionMeta, StateStore as _};
use matrix_sdk_sqlite::SqliteStateStore;
use ruma::{device_id, user_id, RoomId};
use tokio::runtime::Builder;
fn criterion() -> Criterion {
#[cfg(target_os = "linux")]
let criterion = Criterion::default().with_profiler(pprof::criterion::PProfProfiler::new(
100,
pprof::criterion::Output::Flamegraph(None),
));
#[cfg(not(target_os = "linux"))]
let criterion = Criterion::default();
criterion
}
/// Number of joined rooms in the benchmark.
const NUM_JOINED_ROOMS: usize = 10000;
/// Number of stripped rooms in the benchmark.
const NUM_STRIPPED_JOINED_ROOMS: usize = 10000;
pub fn restore_session(c: &mut Criterion) {
let runtime = Builder::new_multi_thread().build().expect("Can't create runtime");
// Create a fake list of changes, and a session to recover from.
let mut changes = StateChanges::default();
for i in 0..NUM_JOINED_ROOMS {
let room_id = RoomId::parse(format!("!room{i}:example.com")).unwrap().to_owned();
changes.add_room(RoomInfo::new(&room_id, RoomState::Joined));
}
for i in 0..NUM_STRIPPED_JOINED_ROOMS {
let room_id = RoomId::parse(format!("!strippedroom{i}:example.com")).unwrap().to_owned();
changes.add_room(RoomInfo::new(&room_id, RoomState::Invited));
}
let session = Session {
meta: SessionMeta {
user_id: user_id!("@somebody:example.com").to_owned(),
device_id: device_id!("DEVICE_ID").to_owned(),
},
tokens: SessionTokens { access_token: "OHEY".to_owned(), refresh_token: None },
};
// Start the benchmark.
let mut group = c.benchmark_group("Client reload");
group.throughput(Throughput::Elements(100));
const NAME: &str = "restore a session";
// Memory
let mem_store = MemoryStore::new();
runtime.block_on(mem_store.save_changes(&changes)).expect("initial filling of mem failed");
group.bench_with_input(BenchmarkId::new("memory store", NAME), &mem_store, |b, store| {
b.to_async(&runtime).iter(|| async {
let client = Client::builder()
.homeserver_url("https://matrix.example.com")
.store_config(StoreConfig::new().state_store(store.clone()))
.build()
.await
.expect("Can't build client");
client.restore_session(session.clone()).await.expect("couldn't restore session");
})
});
for encryption_password in [None, Some("hunter2")] {
let encrypted_suffix = if encryption_password.is_some() { "encrypted" } else { "clear" };
// Sqlite
let sqlite_dir = tempfile::tempdir().unwrap();
let sqlite_store = runtime
.block_on(SqliteStateStore::open(sqlite_dir.path(), encryption_password))
.unwrap();
runtime
.block_on(sqlite_store.save_changes(&changes))
.expect("initial filling of sqlite failed");
group.bench_with_input(
BenchmarkId::new(format!("sqlite store {encrypted_suffix}"), NAME),
&sqlite_store,
|b, store| {
b.to_async(&runtime).iter(|| async {
let client = Client::builder()
.homeserver_url("https://matrix.example.com")
.store_config(StoreConfig::new().state_store(store.clone()))
.build()
.await
.expect("Can't build client");
client
.restore_session(session.clone())
.await
.expect("couldn't restore session");
})
},
);
{
let _guard = runtime.enter();
drop(sqlite_store);
}
}
group.finish()
}
criterion_group! {
name = benches;
config = criterion();
targets = restore_session
}
criterion_main!(benches);
+41
View File
@@ -0,0 +1,41 @@
## Introduction
**matrix-rust-sdk** leverages [UniFFI](https://mozilla.github.io/uniffi-rs/) to generate bindings for host languages (eg. Swift and Kotlin).
Rust code related with bindings live in the [matrix-rust-sdk/bindings](https://github.com/matrix-org/matrix-rust-sdk/tree/main/bindings) folder.
Developers can expose Rust code to UniFFI using two different approaches:
- Using an `.udl` file. When a crate has one, you find it under the `src` folder (an example is [here](https://github.com/matrix-org/matrix-rust-sdk/blob/main/bindings/matrix-sdk-ffi/src/api.udl)).
- Add UniFFI directivies as Rust attributes. In this case Rust source files (`.rs`) contain attributes related to UniFFI (e.g. `#[uniffi::export]`). Attributes are preferred, where applicable.
## Expose Rust definitions to UniFFI
### Check if the API is already on UniFFI
First of all check if the Rust definition you are looking for exists on UniFFI already. Most of exposed matrix definitions are collected in the crate [matrix-sdk-ffi](https://github.com/matrix-org/matrix-rust-sdk/tree/main/bindings/matrix-sdk-ffi).
This crate contains mainly small Rust wrappers around the actual Rust SDK (e.g. the crate [matrix-sdk](https://github.com/matrix-org/matrix-rust-sdk/tree/main/crates/matrix-sdk))
If the Rust definition is on UniFFI already, you either:
- find it in a `.udl` file like [matrix-sdk-ffi/src/api.udl](https://github.com/matrix-org/matrix-rust-sdk/blob/main/bindings/matrix-sdk-ffi/src/api.udl)
- see it marked with a proper UniFFI Rust attribute like this `#[uniffi::export]`
### Adding a missing matrix API
1. Unless you want to contribute on the crypto side, you probably need to add some code in the [matrix-sdk-ffi](https://github.com/matrix-org/matrix-rust-sdk/tree/main/bindings/matrix-sdk-ffi) crate. After you find the crate you need to understand which file is best to contain the new Rust definition. When exposing new matrix API often (but not always) you need to touch the file [client.rs](https://github.com/matrix-org/matrix-rust-sdk/blob/main/bindings/matrix-sdk-ffi/src/client.rs)
2. Identify the API to expose in the target Rust crate (typically in [matrix-sdk](https://github.com/matrix-org/matrix-rust-sdk/tree/main/crates/matrix-sdk). If you cant find it, you probably need to touch the actual Rust SDK as well. In this case you typically just need to write some code around [ruma](https://github.com/ruma/ruma) (a Rust SDKs dependency) which already implements most of the matrix protocol
3. After you got (by finding or writing) the required Rust code, you need to expose to UniFFI. To do that just write a small Rust wrapper in the related UniFFI crate (most of the time is **matrix-sdk-ffi**) you found on step 1.
4. When your new (wrapping) Rust definition is ready, remember to expose it to UniFFI.
Its best to do it using UniFFI Rust attributes (e.g. `#[uniffi::export]`). Otherwise add the new definition in the crates `.udl` file. For the **matrix-sdk-ffi** crate the definition file is [api.udl](https://github.com/matrix-org/matrix-rust-sdk/blob/main/bindings/matrix-sdk-ffi/src/api.udl). **Remember**: the language inside a `.udl` file isnt Rust. To learn more about how map Rust into UDL read [here](https://mozilla.github.io/uniffi-rs/udl_file_spec.html)
## FAQ
**Q**: I wrote my Rust code and exposed it to UniFFI. How can I check if the compiler is happy?\
**A**: Run `cargo build` in the crate you touched (e.g. matrix-sdk-ffi). The compiler will complain if the Rust code and/or the `.udl` is wrong.
**Q**: The compiler is happy with my code but the CI is failing on GitHub. How can I fix it?\
**A**: The CI may fail for different reasons, you need to have a look on the failing GitHub workflow. One common reason though is that the linter ([Clippy](https://github.com/rust-lang/rust-clippy)) isnt happy with your code. If this is the case, you can run `cargo clippy` in the crate you touched to see whats wrong and fix it accordingly.
+7 -4
View File
@@ -5,18 +5,21 @@ maintained by the owners of the Matrix Rust SDK project.
* [`apple`] or `matrix-rust-components-swift`, Swift bindings of the
[`matrix-sdk`] crate via [`matrix-sdk-ffi`],
* [`matrix-sdk-crypto-ffi`], bindings of the [`matrix-sdk-crypto`]
* [`matrix-sdk-crypto-ffi`], UniFFI (Kotlin, Swift, Python, Ruby) bindings of the [`matrix-sdk-crypto`]
crate,
* [`matrix-sdk-crypto-js`], JavaScript bindings of the
[`matrix-sdk-crypto`] crate,
* [`matrix-sdk-crypto-nodejs`], Node.js bindings of the
[`matrix-sdk-crypto`] crate,
* [`matrix-sdk-ffi`], bindings of the [`matrix-sdk`] crate,
* [`matrix-sdk-ffi`], UniFFI bindings of the [`matrix-sdk`] crate.
[`apple`]: ./apple
[`matrix-sdk-crypto-ffi`]: ./matrix-sdk-crypto-ffi
[`matrix-sdk-crypto-js`]: ../crates/matrix-sdk-crypto
[`matrix-sdk-crypto-nodejs`]: ../crates/matrix-sdk-crypto
[`matrix-sdk-crypto-js`]: ./matrix-sdk-crypto-js
[`matrix-sdk-crypto-nodejs`]: ./matrix-sdk-crypto-nodejs
[`matrix-sdk-crypto`]: ../crates/matrix-sdk-crypto
[`matrix-sdk-ffi`]: ./matrix-sdk-ffi
[`matrix-sdk`]: ../crates/matrix-sdk
# Contributing
To contribute read this [guide](./CONTRIBUTING.md).
+8
View File
@@ -0,0 +1,8 @@
// swift-tools-version:5.6
// A package manifest for local development. This file will be copied
// into the root of the repo when generating an XCFramework.
import PackageDescription
let package = Package()
+24
View File
@@ -0,0 +1,24 @@
// swift-tools-version:5.6
// A package manifest for local development. This file will be copied
// into the root of the repo when generating an XCFramework.
import PackageDescription
let package = Package(
name: "MatrixRustSDK",
platforms: [
.iOS(.v15),
.macOS(.v12)
],
products: [
.library(name: "MatrixRustSDK",
targets: ["MatrixRustSDK"]),
],
targets: [
.binaryTarget(name: "MatrixSDKFFI", path: "bindings/apple/generated/MatrixSDKFFI.xcframework"),
.target(name: "MatrixRustSDK",
dependencies: [.target(name: "MatrixSDKFFI")],
path: "bindings/apple/generated/swift")
]
)
@@ -0,0 +1,21 @@
# Podspec file for local-development only, which points to local version of generated framework instead of github release
# To use this, the file needs to be copied to the root of `matrix-rust-sdk` in order to have access to the source files.`
Pod::Spec.new do |s|
s.name = "MatrixSDKCrypto"
s.version = "0.0.1"
s.summary = "Uniffi based bindings for the Rust SDK crypto crate."
s.homepage = "https://github.com/matrix-org/matrix-rust-sdk"
s.license = { :type => "Apache License, Version 2.0", :file => "LICENSE" }
s.author = { "matrix.org" => "support@matrix.org" }
s.ios.deployment_target = "11.0"
s.osx.deployment_target = "10.10"
s.swift_versions = ['5.1', '5.2']
s.source = { :git => "Not Published", :tag => "Cocoapods/#{s.name}/#{s.version}" }
s.vendored_frameworks = "generated/MatrixSDKCryptoFFI.xcframework"
s.source_files = "generated/Sources/**/*.{swift}"
s.resources = ["bindings/matrix-sdk-crypto-ffi/src/**/*.rs", "crates/matrix-sdk-crypto/src/**/*.rs"]
end
+3 -1
View File
@@ -1,13 +1,15 @@
Pod::Spec.new do |s|
s.name = "MatrixSDKCrypto"
s.version = "0.1.0"
s.version = "0.0.1" # Version is only incremented manually and locally before pushing to CocoaPods
s.summary = "Uniffi based bindings for the Rust SDK crypto crate."
s.homepage = "https://github.com/matrix-org/matrix-rust-sdk"
s.license = { :type => "Apache License, Version 2.0", :file => "LICENSE" }
s.author = { "matrix.org" => "support@matrix.org" }
s.ios.deployment_target = "11.0"
s.osx.deployment_target = "10.10"
s.swift_versions = ['5.0']
s.source = { :http => "https://github.com/matrix-org/matrix-rust-sdk/releases/download/matrix-sdk-crypto-ffi-#{s.version}/MatrixSDKCryptoFFI.zip" }
+17 -5
View File
@@ -5,17 +5,29 @@ import PackageDescription
let package = Package(
name: "MatrixRustSDK",
platforms: [.iOS(.v15)],
platforms: [
.iOS(.v15),
.macOS(.v12)
],
products: [
.library(name: "MatrixRustSDK",
targets: ["MatrixRustSDK"]),
],
targets: [
.binaryTarget(name: "MatrixSDKFFI", path: "generated/MatrixSDKFFI.xcframework"),
.target(name: "MatrixRustSDK",
dependencies: [.target(name: "MatrixSDKFFI")],
path: "generated/swift"),
path: "generated/swift",
swiftSettings: [
.unsafeFlags(["-I", "./generated/matrix_sdk_ffi"])
]),
.testTarget(name: "MatrixRustSDKTests",
dependencies: ["MatrixRustSDK"]),
dependencies: ["MatrixRustSDK"],
swiftSettings: [
.unsafeFlags(["-I", "./generated/matrix_sdk_ffi"])
],
linkerSettings: [
.linkedLibrary("matrix_sdk_ffi", .when(platforms: [.macOS])),
.linkedLibrary("matrix_sdk_ffiFFI", .when(platforms: [.linux])),
.unsafeFlags(["-L./generated/matrix_sdk_ffi"])
])
]
)
+40 -20
View File
@@ -2,32 +2,37 @@
This project and build script demonstrate how to create an XCFramework that can be imported into an Xcode project and run on Apple platforms. It can compile and bundle an [entire SDK](#Building-the-SDK), or only a smaller [Crypto module](#Building-only-the-Crypto-SDK) that provides end-to-end encryption for clients that already depend on an SDK (e.g. [Matrix iOS SDK](https://github.com/matrix-org/matrix-ios-sdk))
## Prerequisites for building universal frameworks
## Building
* the Rust toolchain
* UniFFI - `cargo install uniffi_bindgen`
* Apple targets (e.g. `rustup target add aarch64-apple-ios`)
* `xcodebuild` command line tool from [Apple](https://developer.apple.com/library/archive/technotes/tn2339/_index.html)
* `lipo` for creating the fat static libs
### Prerequisites for building universal frameworks
## Building the SDK
- the Rust toolchain
- Apple targets (e.g. `rustup target add aarch64-apple-ios aarch64-apple-ios-sim x86_64-apple-ios aarch64-apple-darwin x86_64-apple-darwin`)
- `xcodebuild` command line tool from [Apple](https://developer.apple.com/library/archive/technotes/tn2339/_index.html)
- `lipo` for creating the fat static libs
### Building the SDK
```
sh build_xcframework.sh
cargo xtask swift build-framework
```
The `build_xcframework.sh` script will go through all the steps required to generate a fully usable `.xcframework`:
The `build-framework` task will go through all the steps required to generate a fully usable `.xcframework`:
1. compile `matrix-sdk-ffi` libraries for iOS, the iOS simulator, MacOS, and Mac Catalyst under `/target`. Some targets are not part of the standard library and they will be built using the nightly toolchain.
1. compile `matrix-sdk-ffi` libraries for iOS, the iOS simulator and macOS under `/target`. Some targets are not part of the standard library and they will be built using the nightly toolchain.
2. `lipo` together the libraries for the same platform under `/generated`
3. run `uniffi` and generate the C header, module map and swift files
4. `xcodebuild` an `xcframework` from the fat static libs and the original iOS one, and add the header and module map to it under `generated/MatrixSDKFFI.xcframework`
5. cleanup and delete the generated files except the .xcframework and the swift sources (that aren't part of the framework)
## Building only the Crypto SDK
For development purposes, it will additionally generate a `Package.swift` file in the root of the repo that can be used to add the framework to your project and enable debugging through the use of [rust-xcode-plugin](https://github.com/BrainiumLLC/rust-xcode-plugin) (make sure to run the task with the argument `--profile=reldbg`).
When building the SDK for release you should pass the `--release` argument to the task, which will strip away any symbols and optimise the created binary.
### Building only the Crypto SDK
```
sh build_crypto_xcframework.sh
build_crypto_xcframework.sh
```
The `build_crypto_xcframework.sh` script will go through all the steps required to generate a fully usable `.xcframework`:
@@ -38,16 +43,31 @@ The `build_crypto_xcframework.sh` script will go through all the steps required
4. `xcodebuild` an `xcframework` from the fat static libs and the original iOS one, and add the header and module map to it under `generated/MatrixSDKCryptoFFI.xcframework`
5. cleanup and delete the generated files except the .xcframework and the swift sources (that aren't part of the framework)
## Running the Xcode project
### Building & testing the Swift package
The Xcode project is meant to provide a simple example on how to integrate everything together but also a place to run unit and integration tests from.
The `Package.swift` file in this directory provides a simple example on how to integrate everything together but also a place to run unit and integration tests from.
It's pre-configured to link to the generated .xcframework and .swift files so successfully running the script first is necessary for it to compile.
It makes the compiled code available to swift by importing the C header through its bridging header.
Once all the generated components are available running it should be as easy as choosing a platform and clicking run.
It's pre-configured to link to the generated static lib and .swift files so successfully running `cargo xtask swift build-library` first is necessary for it to compile. Afterwards you can execute the tests with `swift test`. Note that for the moment this only works on macOS but we're planning to add Linux support in the future.
## Distribution
The generated framework and Swift code can be distributed and integrated directly but in order to make things simpler we bundle them together as a Swift package available [TBD](here) in the case of SDK, and as CocoaPods podspec in the case of Crypto SDK.
The generated framework and Swift code can be distributed and integrated directly but in order to make things simpler we bundle them together as a [Swift package](https://github.com/matrix-org/matrix-rust-components-swift/) in the case of SDK, and as a CocoaPods podspec in the case of Crypto SDK.
### Publishing MatrixSDKCrypto
1. Navigate into `bindings/apple` and run [`build_crypto_xcframework.sh`](#building-only-the-crypto-sdk) script which generates a .zip file with the framework in `./generated` folder
Note that whilst you can run this command from any git branch, if you want to make a public release, ensure you are building from latest `main`
2. Tag the commit you just used to build the release and push the tag to GitHub
Use `matrix-sdk-crypto-ffi-<major>.<minor>.<patch>` tag name
3. Create a new [GitHub release](https://github.com/matrix-org/matrix-rust-sdk/releases) using this tag (see [example](https://github.com/matrix-org/matrix-rust-sdk/releases/tag/matrix-sdk-crypto-ffi-0.3.4))
4. Upload the previously generated .zip file to this release
5. Increment the version in [`MatrixSDKCrypto.podspec`](./MatrixSDKCrypto.podspec)
Note that this is not automated and is a local-only change. To determine the most recent published version, run `pod repo update && pod search MatrixSDKCrypto`
or check git tags via `git tag | grep matrix-sdk-crypto-ffi`
6. Push new Podspec version to Cocoapods via `pod trunk push MatrixSDKCrypto.podspec --allow-warnings`
@@ -11,6 +11,17 @@ final class ClientTests: XCTestCase {
XCTFail("The client should build successfully when given a homeserver.")
}
}
func testBuildingWithHomeserverURLAndUserAgent() {
do {
_ = try ClientBuilder()
.homeserverUrl(url: "https://localhost:8008")
.userAgent(userAgent: "golden-eye/007")
.build()
} catch {
XCTFail("The client should build successfully when given a homeserver and user agent.")
}
}
func testBuildingWithUsername() {
do {
+38 -10
View File
@@ -10,7 +10,7 @@ TARGET_DIR="${SRC_ROOT}/target"
GENERATED_DIR="${SRC_ROOT}/generated"
if [ -d "${GENERATED_DIR}" ]; then rm -rf "${GENERATED_DIR}"; fi
mkdir -p ${GENERATED_DIR}
mkdir -p ${GENERATED_DIR}/{macos,simulator}
REL_FLAG="--release"
REL_TYPE_DIR="release"
@@ -19,23 +19,47 @@ TARGET_CRATE=matrix-sdk-crypto-ffi
# Build static libs for all the different architectures
# Required by olm-sys crate
export IOS_SDK_PATH=`xcrun --show-sdk-path --sdk iphoneos`
# iOS
echo -e "Building for iOS [1/5]"
cargo build -p ${TARGET_CRATE} ${REL_FLAG} --target "aarch64-apple-ios"
# MacOS
echo -e "\nBuilding for macOS (Apple Silicon) [2/5]"
cargo build -p ${TARGET_CRATE} ${REL_FLAG} --target "aarch64-apple-darwin"
echo -e "\nBuilding for macOS (Intel) [3/5]"
cargo build -p ${TARGET_CRATE} ${REL_FLAG} --target "x86_64-apple-darwin"
# iOS Simulator
echo -e "\nBuilding for iOS Simulator (Apple Silicon) [4/5]"
cargo build -p ${TARGET_CRATE} ${REL_FLAG} --target "aarch64-apple-ios-sim"
echo -e "\nBuilding for iOS Simulator (Intel) [5/5]"
cargo build -p ${TARGET_CRATE} ${REL_FLAG} --target "x86_64-apple-ios"
echo -e "\nCreating XCFramework"
# Lipo together the libraries for the same platform
# MacOS
lipo -create \
"${TARGET_DIR}/x86_64-apple-darwin/${REL_TYPE_DIR}/libmatrix_sdk_crypto_ffi.a" \
"${TARGET_DIR}/aarch64-apple-darwin/${REL_TYPE_DIR}/libmatrix_sdk_crypto_ffi.a" \
-output "${GENERATED_DIR}/macos/libmatrix_sdk_crypto_ffi.a"
# iOS Simulator
lipo -create \
"${TARGET_DIR}/x86_64-apple-ios/${REL_TYPE_DIR}/libmatrix_crypto_ffi.a" \
"${TARGET_DIR}/aarch64-apple-ios-sim/${REL_TYPE_DIR}/libmatrix_crypto_ffi.a" \
-output "${GENERATED_DIR}/libmatrix_crypto_ffi.a"
"${TARGET_DIR}/x86_64-apple-ios/${REL_TYPE_DIR}/libmatrix_sdk_crypto_ffi.a" \
"${TARGET_DIR}/aarch64-apple-ios-sim/${REL_TYPE_DIR}/libmatrix_sdk_crypto_ffi.a" \
-output "${GENERATED_DIR}/simulator/libmatrix_sdk_crypto_ffi.a"
# Generate uniffi files
uniffi-bindgen generate "${SRC_ROOT}/bindings/${TARGET_CRATE}/src/olm.udl" --language swift --config "${SRC_ROOT}/bindings/${TARGET_CRATE}/uniffi.toml" --out-dir ${GENERATED_DIR}
cargo uniffi-bindgen generate \
--language swift \
--lib-file "${TARGET_DIR}/aarch64-apple-ios-sim/${REL_TYPE_DIR}/libmatrix_sdk_crypto_ffi.a" \
--config "${SRC_ROOT}/bindings/${TARGET_CRATE}/uniffi.toml" \
--out-dir ${GENERATED_DIR} \
"${SRC_ROOT}/bindings/${TARGET_CRATE}/src/olm.udl"
# Move headers to the right place
HEADERS_DIR=${GENERATED_DIR}/headers
@@ -55,19 +79,23 @@ mv ${GENERATED_DIR}/*.swift ${SWIFT_DIR}
if [ -d "${GENERATED_DIR}/MatrixSDKCryptoFFI.xcframework" ]; then rm -rf "${GENERATED_DIR}/MatrixSDKCryptoFFI.xcframework"; fi
xcodebuild -create-xcframework \
-library "${TARGET_DIR}/aarch64-apple-ios/${REL_TYPE_DIR}/libmatrix_crypto_ffi.a" \
-library "${TARGET_DIR}/aarch64-apple-ios/${REL_TYPE_DIR}/libmatrix_sdk_crypto_ffi.a" \
-headers ${HEADERS_DIR} \
-library "${GENERATED_DIR}/libmatrix_crypto_ffi.a" \
-library "${GENERATED_DIR}/macos/libmatrix_sdk_crypto_ffi.a" \
-headers ${HEADERS_DIR} \
-library "${GENERATED_DIR}/simulator/libmatrix_sdk_crypto_ffi.a" \
-headers ${HEADERS_DIR} \
-output "${GENERATED_DIR}/MatrixSDKCryptoFFI.xcframework"
# Cleanup
if [ -f "${TARGET_DIR}/aarch64-apple-ios-sim/${REL_TYPE_DIR}/libmatrix_crypto_ffi.a" ]; then rm -rf "${TARGET_DIR}/aarch64-apple-ios-sim/${REL_TYPE_DIR}/libmatrix_crypto_ffi.a"; fi
if [ -f "${GENERATED_DIR}/libmatrix_crypto_ffi.a" ]; then rm -rf "${GENERATED_DIR}/libmatrix_crypto_ffi.a"; fi
if [ -d "${GENERATED_DIR}/macos" ]; then rm -rf "${GENERATED_DIR}/macos"; fi
if [ -d "${GENERATED_DIR}/simulator" ]; then rm -rf "${GENERATED_DIR}/simulator"; fi
if [ -d ${HEADERS_DIR} ]; then rm -rf ${HEADERS_DIR}; fi
# Zip up framework, sources and LICENSE, ready to be uploaded to GitHub Releases and used by MatrixSDKCrypto.podspec
cp ${SRC_ROOT}/LICENSE $GENERATED_DIR
cd $GENERATED_DIR
zip -r MatrixSDKCryptoFFI.zip MatrixSDKCryptoFFI.xcframework Sources LICENSE
rm LICENSE
echo "XCFramework is ready 🚀"
-90
View File
@@ -1,90 +0,0 @@
#!/usr/bin/env bash
set -eEu
cd "$(dirname "$0")"
# Path to the repo root
SRC_ROOT=../..
TARGET_DIR="${SRC_ROOT}/target"
GENERATED_DIR="${SRC_ROOT}/generated"
mkdir -p ${GENERATED_DIR}
REL_FLAG="--release"
REL_TYPE_DIR="release"
# Build static libs for all the different architectures
# iOS
echo -e "Building for iOS [1/5]"
cargo build -p matrix-sdk-ffi ${REL_FLAG} --target "aarch64-apple-ios"
# MacOS
echo -e "\nBuilding for macOS (Apple Silicon) [2/5]"
cargo build -p matrix-sdk-ffi ${REL_FLAG} --target "aarch64-apple-darwin"
echo -e "\nBuilding for macOS (Intel) [3/5]"
cargo build -p matrix-sdk-ffi ${REL_FLAG} --target "x86_64-apple-darwin"
# iOS Simulator
echo -e "\nBuilding for iOS Simulator (Apple Silicon) [4/5]"
cargo build -p matrix-sdk-ffi ${REL_FLAG} --target "aarch64-apple-ios-sim"
echo -e "\nBuilding for iOS Simulator (Intel) [5/5]"
cargo build -p matrix-sdk-ffi ${REL_FLAG} --target "x86_64-apple-ios"
echo -e "\nCreating XCFramework"
# Lipo together the libraries for the same platform
# MacOS
lipo -create \
"${TARGET_DIR}/x86_64-apple-darwin/${REL_TYPE_DIR}/libmatrix_sdk_ffi.a" \
"${TARGET_DIR}/aarch64-apple-darwin/${REL_TYPE_DIR}/libmatrix_sdk_ffi.a" \
-output "${GENERATED_DIR}/libmatrix_sdk_ffi_macos.a"
# iOS Simulator
lipo -create \
"${TARGET_DIR}/x86_64-apple-ios/${REL_TYPE_DIR}/libmatrix_sdk_ffi.a" \
"${TARGET_DIR}/aarch64-apple-ios-sim/${REL_TYPE_DIR}/libmatrix_sdk_ffi.a" \
-output "${GENERATED_DIR}/libmatrix_sdk_ffi_iossimulator.a"
# Generate uniffi files
# Architecture for the .a file argument doesn't matter, since the API is the same on all
uniffi-bindgen generate \
--language swift \
--lib-file "${TARGET_DIR}/x86_64-apple-darwin/${REL_TYPE_DIR}/libmatrix_sdk_ffi.a" \
--out-dir ${GENERATED_DIR} \
"${SRC_ROOT}/bindings/matrix-sdk-ffi/src/api.udl"
# Move them to the right place
HEADERS_DIR=${GENERATED_DIR}/headers
mkdir -p ${HEADERS_DIR}
mv ${GENERATED_DIR}/*.h ${HEADERS_DIR}
# Rename and move modulemap to the right place
mv ${GENERATED_DIR}/*.modulemap ${HEADERS_DIR}/module.modulemap
SWIFT_DIR="${GENERATED_DIR}/swift"
mkdir -p ${SWIFT_DIR}
mv ${GENERATED_DIR}/*.swift ${SWIFT_DIR}
# Build the xcframework
if [ -d "${GENERATED_DIR}/MatrixSDKFFI.xcframework" ]; then rm -rf "${GENERATED_DIR}/MatrixSDKFFI.xcframework"; fi
xcodebuild -create-xcframework \
-library "${GENERATED_DIR}/libmatrix_sdk_ffi_macos.a" \
-headers ${HEADERS_DIR} \
-library "${GENERATED_DIR}/libmatrix_sdk_ffi_iossimulator.a" \
-headers ${HEADERS_DIR} \
-library "${TARGET_DIR}/aarch64-apple-ios/${REL_TYPE_DIR}/libmatrix_sdk_ffi.a" \
-headers ${HEADERS_DIR} \
-output "${GENERATED_DIR}/MatrixSDKFFI.xcframework"
# Cleanup
if [ -f "${GENERATED_DIR}/libmatrix_sdk_ffi_macos.a" ]; then rm -rf "${GENERATED_DIR}/libmatrix_sdk_ffi_macos.a"; fi
if [ -f "${GENERATED_DIR}/libmatrix_sdk_ffi_iossimulator.a" ]; then rm -rf "${GENERATED_DIR}/libmatrix_sdk_ffi_iossimulator.a"; fi
if [ -d ${HEADERS_DIR} ]; then rm -rf ${HEADERS_DIR}; fi
-90
View File
@@ -1,90 +0,0 @@
#!/usr/bin/env bash
set -eEu
cd "$(dirname "$0")"
IS_CI=false
ACTIVE_ARCH="arm64"
if [ $# -eq 2 ]; then
echo "Running CI build"
IS_CI=true
ARCHS=( $1 )
ACTIVE_ARCH=${ARCHS[0]}
elif [ $# -eq 1 ]; then
echo "Running debug build"
ARCHS=( $1 )
ACTIVE_ARCH=${ARCHS[0]}
else
echo "Running debug build"
fi
echo "Active architecture ${ACTIVE_ARCH}"
# Path to the repo root
SRC_ROOT=../..
TARGET_DIR="${SRC_ROOT}/target"
GENERATED_DIR="${SRC_ROOT}/bindings/apple/generated"
mkdir -p ${GENERATED_DIR}
REL_FLAG=""
REL_TYPE_DIR="debug"
# iOS Simulator arm64
if [ "$ACTIVE_ARCH" = "arm64" ]; then
TARGET="aarch64-apple-ios-sim"
# iOS Simulator intel
else
TARGET="x86_64-apple-ios"
fi
cargo build -p matrix-sdk-ffi ${REL_FLAG} --target "$TARGET"
lipo -create \
"${TARGET_DIR}/$TARGET/${REL_TYPE_DIR}/libmatrix_sdk_ffi.a" \
-output "${GENERATED_DIR}/libmatrix_sdk_ffi_iossimulator.a"
# Generate uniffi files
uniffi-bindgen generate \
--language swift \
--lib-file "${TARGET_DIR}/$TARGET/${REL_TYPE_DIR}/libmatrix_sdk_ffi.a" \
--out-dir ${GENERATED_DIR} \
"${SRC_ROOT}/bindings/matrix-sdk-ffi/src/api.udl"
# Move them to the right place
HEADERS_DIR=${GENERATED_DIR}/headers
mkdir -p ${HEADERS_DIR}
mv ${GENERATED_DIR}/*.h ${HEADERS_DIR}
# Rename and move modulemap to the right place
mv ${GENERATED_DIR}/*.modulemap ${HEADERS_DIR}/module.modulemap
SWIFT_DIR="${GENERATED_DIR}/swift"
mkdir -p ${SWIFT_DIR}
mv ${GENERATED_DIR}/*.swift ${SWIFT_DIR}
# Build the xcframework
if [ -d "${GENERATED_DIR}/MatrixSDKFFI.xcframework" ]; then rm -rf "${GENERATED_DIR}/MatrixSDKFFI.xcframework"; fi
xcodebuild -create-xcframework \
-library "${GENERATED_DIR}/libmatrix_sdk_ffi_iossimulator.a" \
-headers ${HEADERS_DIR} \
-output "${GENERATED_DIR}/MatrixSDKFFI.xcframework"
# Cleanup
if [ -f "${GENERATED_DIR}/libmatrix_sdk_ffi_iossimulator.a" ]; then rm -rf "${GENERATED_DIR}/libmatrix_sdk_ffi_iossimulator.a"; fi
if [ -d ${HEADERS_DIR} ]; then rm -rf ${HEADERS_DIR}; fi
if [ "$IS_CI" = false ] ; then
echo "Preparing matrix-rust-components-swift"
# Debug -> Copy generated files over to ../../../matrix-rust-components-swift
rsync -a --delete "${GENERATED_DIR}/MatrixSDKFFI.xcframework" "${SRC_ROOT}/../matrix-rust-components-swift/"
rsync -a --delete "${GENERATED_DIR}/swift/" "${SRC_ROOT}/../matrix-rust-components-swift/Sources/MatrixRustSDK"
fi
+25 -21
View File
@@ -3,7 +3,7 @@ name = "matrix-sdk-crypto-ffi"
version = "0.1.0"
authors = ["Damir Jelić <poljar@termina.org.uk>"]
edition = "2021"
rust-version = "1.60"
rust-version = { workspace = true }
description = "Uniffi based bindings for the Rust SDK crypto crate"
repository = "https://github.com/matrix-org/matrix-rust-sdk"
license = "Apache-2.0"
@@ -11,25 +11,29 @@ publish = false
[lib]
crate-type = ["cdylib", "staticlib"]
name = "matrix_crypto_ffi"
[features]
default = ["bundled-sqlite"]
bundled-sqlite = ["matrix-sdk-sqlite/bundled"]
[dependencies]
anyhow = "1.0.57"
base64 = "0.13.0"
anyhow = { workspace = true }
base64 = { workspace = true }
futures-util = "0.3.25"
hmac = "0.12.1"
http = "0.2.6"
http = { workspace = true }
pbkdf2 = "0.11.0"
rand = "0.8.5"
ruma = { version = "0.7.0", features = ["client-api-c"] }
serde = "1.0.136"
serde_json = "1.0.79"
ruma = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
sha2 = "0.10.2"
thiserror = "1.0.30"
tracing = "0.1.34"
thiserror = { workspace = true }
tracing-subscriber = { version = "0.3.11", features = ["env-filter"] }
# keep in sync with uniffi dependency in matrix-sdk-ffi, and uniffi_bindgen in ffi CI job
uniffi = { git = "https://github.com/mozilla/uniffi-rs", rev = "091c3561656e72e1a4160412c83b36d98e556d06" }
zeroize = { version = "1.3.0", features = ["zeroize_derive"] }
uniffi = { workspace = true }
vodozemac = { workspace = true }
zeroize = { workspace = true, features = ["zeroize_derive"] }
[dependencies.js_int]
version = "0.2.2"
@@ -42,24 +46,24 @@ version = "0.6.0"
[dependencies.matrix-sdk-crypto]
path = "../../crates/matrix-sdk-crypto"
version = "0.6.0"
features = ["qrcode", "backups_v1"]
default_features = false
features = ["qrcode", "backups_v1", "automatic-room-key-forwarding"]
[dependencies.matrix-sdk-sled]
path = "../../crates/matrix-sdk-sled"
version = "0.2.0"
[dependencies.matrix-sdk-sqlite]
path = "../../crates/matrix-sdk-sqlite"
version = "0.1.0"
default_features = false
features = ["crypto-store"]
[dependencies.tokio]
version = "1.17.0"
version = "1.24.2"
default_features = false
features = ["rt-multi-thread"]
[dependencies.vodozemac]
version = "0.3.0"
[build-dependencies]
uniffi_build = { git = "https://github.com/mozilla/uniffi-rs", rev = "091c3561656e72e1a4160412c83b36d98e556d06", features = ["builtin-bindgen"] }
uniffi = { workspace = true, features = ["build"] }
vergen = { version = "8.0.0", features = ["build", "git", "gitcl"] }
[dev-dependencies]
tempfile = "3.3.0"
assert_matches = { workspace = true }
+3 -1
View File
@@ -5,6 +5,8 @@ README mainly describes how to build and integrate the bindings into a Kotlin
based Android project, but the Android specific bits can be skipped if you are
targeting an x86 Linux project.
To build and distribute bindings for iOS projects, see a [dedicated page](../apple/README.md)
## Prerequisites
### Rust
@@ -71,7 +73,7 @@ $ cp ../../target/aarch64-linux-android/debug/libmatrix_crypto.so \
## Minimum Supported Rust Version (MSRV)
These crates are built with the Rust language version 2021 and require a minimum compiler version of `1.60`.
These crates are built with the Rust language version 2021 and require a minimum compiler version of `1.62`.
## License
+10 -2
View File
@@ -1,3 +1,11 @@
fn main() {
uniffi_build::generate_scaffolding("./src/olm.udl").unwrap();
use std::error::Error;
use vergen::EmitBuilder;
fn main() -> Result<(), Box<dyn Error>> {
uniffi::generate_scaffolding("./src/olm.udl")?;
EmitBuilder::builder().git_sha(true).git_describe(true, false, None).emit()?;
Ok(())
}
@@ -1,8 +1,8 @@
use std::{collections::HashMap, iter, ops::DerefMut};
use std::{collections::HashMap, iter, ops::DerefMut, sync::Arc};
use hmac::Hmac;
use matrix_sdk_crypto::{
backups::OlmPkDecryptionError,
backups::DecryptionError,
store::{CryptoStoreError as InnerStoreError, RecoveryKey},
};
use pbkdf2::pbkdf2;
@@ -12,21 +12,24 @@ use thiserror::Error;
use zeroize::Zeroize;
/// The private part of the backup key, the one used for recovery.
#[derive(uniffi::Object)]
pub struct BackupRecoveryKey {
pub(crate) inner: RecoveryKey,
pub(crate) passphrase_info: Option<PassphraseInfo>,
}
/// Error type for the decryption of backed up room keys.
#[derive(Debug, Error)]
#[derive(Debug, Error, uniffi::Error)]
#[uniffi(flat_error)]
pub enum PkDecryptionError {
/// An internal libolm error happened during decryption.
#[error("Error decryption a PkMessage {0}")]
Olm(#[from] OlmPkDecryptionError),
Olm(#[from] DecryptionError),
}
/// Error type for the decoding and storing of the backup key.
#[derive(Debug, Error)]
#[derive(Debug, Error, uniffi::Error)]
#[uniffi(flat_error)]
pub enum DecodeError {
/// An error happened while decoding the recovery key.
#[error(transparent)]
@@ -39,7 +42,7 @@ pub enum DecodeError {
/// Struct containing info about the way the backup key got derived from a
/// passphrase.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, uniffi::Record)]
pub struct PassphraseInfo {
/// The salt that was used during key derivation.
pub private_key_salt: String,
@@ -48,6 +51,7 @@ pub struct PassphraseInfo {
}
/// The public part of the backup key.
#[derive(uniffi::Record)]
pub struct MegolmV1BackupKey {
/// The actual base64 encoded public key.
pub public_key: String,
@@ -63,29 +67,36 @@ impl BackupRecoveryKey {
const KEY_SIZE: usize = 32;
const SALT_SIZE: usize = 32;
const PBKDF_ROUNDS: i32 = 500_000;
}
#[uniffi::export]
impl BackupRecoveryKey {
/// Create a new random [`BackupRecoveryKey`].
#[allow(clippy::new_without_default)]
pub fn new() -> Self {
Self {
#[uniffi::constructor]
pub fn new() -> Arc<Self> {
Arc::new(Self {
inner: RecoveryKey::new()
.expect("Can't gather enough randomness to create a recovery key"),
passphrase_info: None,
}
})
}
/// Try to create a [`BackupRecoveryKey`] from a base 64 encoded string.
pub fn from_base64(key: String) -> Result<Self, DecodeError> {
Ok(Self { inner: RecoveryKey::from_base64(&key)?, passphrase_info: None })
#[uniffi::constructor]
pub fn from_base64(key: String) -> Result<Arc<Self>, DecodeError> {
Ok(Arc::new(Self { inner: RecoveryKey::from_base64(&key)?, passphrase_info: None }))
}
/// Try to create a [`BackupRecoveryKey`] from a base 58 encoded string.
pub fn from_base58(key: String) -> Result<Self, DecodeError> {
Ok(Self { inner: RecoveryKey::from_base58(&key)?, passphrase_info: None })
#[uniffi::constructor]
pub fn from_base58(key: String) -> Result<Arc<Self>, DecodeError> {
Ok(Arc::new(Self { inner: RecoveryKey::from_base58(&key)?, passphrase_info: None }))
}
/// Create a new [`BackupRecoveryKey`] from the given passphrase.
pub fn new_from_passphrase(passphrase: String) -> Self {
#[uniffi::constructor]
pub fn new_from_passphrase(passphrase: String) -> Arc<Self> {
let mut rng = thread_rng();
let salt: String = iter::repeat(())
.map(|()| rng.sample(Alphanumeric))
@@ -97,7 +108,8 @@ impl BackupRecoveryKey {
}
/// Restore a [`BackupRecoveryKey`] from the given passphrase.
pub fn from_passphrase(passphrase: String, salt: String, rounds: i32) -> Self {
#[uniffi::constructor]
pub fn from_passphrase(passphrase: String, salt: String, rounds: i32) -> Arc<Self> {
let mut key = Box::new([0u8; Self::KEY_SIZE]);
let rounds = rounds as u32;
@@ -107,13 +119,23 @@ impl BackupRecoveryKey {
key.zeroize();
Self {
Arc::new(Self {
inner: recovery_key,
passphrase_info: Some(PassphraseInfo {
private_key_salt: salt,
private_key_iterations: rounds as i32,
}),
}
})
}
/// Convert the recovery key to a base 58 encoded string.
pub fn to_base58(&self) -> String {
self.inner.to_base58()
}
/// Convert the recovery key to a base 64 encoded string.
pub fn to_base64(&self) -> String {
self.inner.to_base64()
}
/// Get the public part of the backup key.
@@ -134,16 +156,6 @@ impl BackupRecoveryKey {
}
}
/// Convert the recovery key to a base 58 encoded string.
pub fn to_base58(&self) -> String {
self.inner.to_base58()
}
/// Convert the recovery key to a base 64 encoded string.
pub fn to_base64(&self) -> String {
self.inner.to_base64()
}
/// Try to decrypt a message that was encrypted using the public part of the
/// backup key.
pub fn decrypt_v1(
@@ -152,6 +164,51 @@ impl BackupRecoveryKey {
mac: String,
ciphertext: String,
) -> Result<String, PkDecryptionError> {
self.inner.decrypt_v1(ephemeral_key, mac, ciphertext).map_err(|e| e.into())
self.inner.decrypt_v1(&ephemeral_key, &mac, &ciphertext).map_err(|e| e.into())
}
}
#[cfg(test)]
mod test {
use ruma::api::client::backup::KeyBackupData;
use serde_json::json;
use super::*;
#[test]
fn test_decrypt_key() {
let recovery_key = BackupRecoveryKey::from_base64(
"Ha9cklU/9NqFo9WKdVfGzmqUL/9wlkdxfEitbSIPVXw".to_owned(),
)
.unwrap();
let data = json!({
"first_message_index": 0,
"forwarded_count": 0,
"is_verified": false,
"session_data": {
"ephemeral": "HlLi76oV6wxHz3PCqE/bxJi6yF1HnYz5Dq3T+d/KpRw",
"ciphertext": "MuM8E3Yc6TSAvhVGb77rQ++jE6p9dRepx63/3YPD2wACKAppkZHeFrnTH6wJ/HSyrmzo\
7HfwqVl6tKNpfooSTHqUf6x1LHz+h4B/Id5ITO1WYt16AaI40LOnZqTkJZCfSPuE2oxa\
lwEHnCS3biWybutcnrBFPR3LMtaeHvvkb+k3ny9l5ZpsU9G7vCm3XoeYkWfLekWXvDhb\
qWrylXD0+CNUuaQJ/S527TzLd4XKctqVjjO/cCH7q+9utt9WJAfK8LGaWT/mZ3AeWjf5\
kiqOpKKf5Cn4n5SSil5p/pvGYmjnURvZSEeQIzHgvunIBEPtzK/MYEPOXe/P5achNGlC\
x+5N19Ftyp9TFaTFlTWCTi0mpD7ePfCNISrwpozAz9HZc0OhA8+1aSc7rhYFIeAYXFU3\
26NuFIFHI5pvpSxjzPQlOA+mavIKmiRAtjlLw11IVKTxgrdT4N8lXeMr4ndCSmvIkAzF\
Mo1uZA4fzjiAdQJE4/2WeXFNNpvdfoYmX8Zl9CAYjpSO5HvpwkAbk4/iLEH3hDfCVUwD\
fMh05PdGLnxeRpiEFWSMSsJNp+OWAA+5JsF41BoRGrxoXXT+VKqlUDONd+O296Psu8Q+\
d8/S618",
"mac": "GtMrurhDTwo"
}
});
let key_backup_data: KeyBackupData = serde_json::from_value(data).unwrap();
let ephemeral = key_backup_data.session_data.ephemeral.encode();
let ciphertext = key_backup_data.session_data.ciphertext.encode();
let mac = key_backup_data.session_data.mac.encode();
let _ = recovery_key
.decrypt_v1(ephemeral, mac, ciphertext)
.expect("The backed up key should be decrypted successfully");
}
}
@@ -3,6 +3,7 @@ use std::collections::HashMap;
use matrix_sdk_crypto::Device as InnerDevice;
/// An E2EE capable Matrix device.
#[derive(uniffi::Record)]
pub struct Device {
/// The device owner.
pub user_id: String,
@@ -24,6 +25,9 @@ pub struct Device {
/// Is our cross signing identity trusted and does the identity trust the
/// device.
pub cross_signing_trusted: bool,
/// The first time this device was seen in local timestamp, seconds since
/// epoch.
pub first_time_seen_ts: u64,
}
impl From<InnerDevice> for Device {
@@ -37,6 +41,7 @@ impl From<InnerDevice> for Device {
is_blocked: d.is_blacklisted(),
locally_trusted: d.is_locally_trusted(),
cross_signing_trusted: d.is_cross_signing_trusted(),
first_time_seen_ts: d.first_time_seen_ts().0.into(),
}
}
}
+70 -11
View File
@@ -4,9 +4,11 @@ use matrix_sdk_crypto::{
store::CryptoStoreError as InnerStoreError, KeyExportError, MegolmError, OlmError,
SecretImportError as RustSecretImportError, SignatureError as InnerSignatureError,
};
use matrix_sdk_sqlite::OpenStoreError;
use ruma::{IdParseError, OwnedUserId};
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, uniffi::Error)]
#[uniffi(flat_error)]
pub enum KeyImportError {
#[error(transparent)]
Export(#[from] KeyExportError),
@@ -16,7 +18,8 @@ pub enum KeyImportError {
Json(#[from] serde_json::Error),
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, uniffi::Error)]
#[uniffi(flat_error)]
pub enum SecretImportError {
#[error(transparent)]
CryptoStore(#[from] InnerStoreError),
@@ -24,7 +27,8 @@ pub enum SecretImportError {
Import(#[from] RustSecretImportError),
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, uniffi::Error)]
#[uniffi(flat_error)]
pub enum SignatureError {
#[error(transparent)]
Signature(#[from] InnerSignatureError),
@@ -38,8 +42,11 @@ pub enum SignatureError {
UnknownUserIdentity(String),
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, thiserror::Error, uniffi::Error)]
#[uniffi(flat_error)]
pub enum CryptoStoreError {
#[error("Failed to open the store")]
OpenStore(#[from] OpenStoreError),
#[error(transparent)]
CryptoStore(#[from] InnerStoreError),
#[error(transparent)]
@@ -52,12 +59,64 @@ pub enum CryptoStoreError {
Identifier(#[from] IdParseError),
}
#[derive(Debug, thiserror::Error)]
#[derive(Debug, uniffi::Error)]
pub enum DecryptionError {
#[error(transparent)]
Serialization(#[from] serde_json::Error),
#[error(transparent)]
Identifier(#[from] IdParseError),
#[error(transparent)]
Megolm(#[from] MegolmError),
Serialization { error: String },
Identifier { error: String },
Megolm { error: String },
MissingRoomKey { error: String, withheld_code: Option<String> },
Store { error: String },
}
impl From<MegolmError> for DecryptionError {
fn from(value: MegolmError) -> Self {
match value {
MegolmError::MissingRoomKey(withheld_code) => Self::MissingRoomKey {
error: "Withheld Inbound group session".to_owned(),
withheld_code: withheld_code.map(|w| w.as_str().to_owned()),
},
_ => Self::Megolm { error: value.to_string() },
}
}
}
impl From<serde_json::Error> for DecryptionError {
fn from(err: serde_json::Error) -> Self {
Self::Serialization { error: err.to_string() }
}
}
impl From<IdParseError> for DecryptionError {
fn from(err: IdParseError) -> Self {
Self::Identifier { error: err.to_string() }
}
}
impl From<InnerStoreError> for DecryptionError {
fn from(err: InnerStoreError) -> Self {
Self::Store { error: err.to_string() }
}
}
#[cfg(test)]
mod tests {
use assert_matches::assert_matches;
use super::*;
#[test]
fn test_withheld_error_mapping() {
use matrix_sdk_crypto::types::events::room_key_withheld::WithheldCode;
let inner_error = MegolmError::MissingRoomKey(Some(WithheldCode::Unverified));
let binding_error: DecryptionError = inner_error.into();
let code = assert_matches!(
binding_error,
DecryptionError::MissingRoomKey { error: _, withheld_code: Some(withheld_code) } => withheld_code
);
assert_eq!("m.unverified", code)
}
}
+552 -104
View File
@@ -4,6 +4,7 @@
//! client or client library in any of the language targets Uniffi supports.
#![warn(missing_docs)]
#![allow(unused_qualifications)]
mod backup_recovery_key;
mod device;
@@ -14,8 +15,9 @@ mod responses;
mod users;
mod verification;
use std::{borrow::Borrow, collections::HashMap, str::FromStr, sync::Arc};
use std::{collections::HashMap, str::FromStr, sync::Arc, time::Duration};
use anyhow::Context;
pub use backup_recovery_key::{
BackupRecoveryKey, DecodeError, MegolmV1BackupKey, PassphraseInfo, PkDecryptionError,
};
@@ -25,22 +27,37 @@ pub use error::{
};
use js_int::UInt;
pub use logger::{set_logger, Logger};
pub use machine::{KeyRequestPair, OlmMachine};
use matrix_sdk_crypto::types::{EventEncryptionAlgorithm, SigningKey};
pub use machine::{KeyRequestPair, OlmMachine, SignatureVerification};
use matrix_sdk_common::deserialized_responses::ShieldState as RustShieldState;
use matrix_sdk_crypto::{
backups::SignatureState,
olm::{IdentityKeys, InboundGroupSession, Session},
store::{Changes, CryptoStore, RoomSettings as RustRoomSettings},
types::{EventEncryptionAlgorithm as RustEventEncryptionAlgorithm, SigningKey},
EncryptionSettings as RustEncryptionSettings, LocalTrust,
};
use matrix_sdk_sqlite::SqliteCryptoStore;
pub use responses::{
BootstrapCrossSigningResult, DeviceLists, KeysImportResult, OutgoingVerificationRequest,
Request, RequestType, SignatureUploadRequest, UploadSigningKeysRequest,
};
use ruma::{DeviceId, DeviceKeyAlgorithm, OwnedUserId, RoomId, SecondsSinceUnixEpoch, UserId};
use ruma::{
events::room::history_visibility::HistoryVisibility as RustHistoryVisibility,
DeviceKeyAlgorithm, MilliSecondsSinceUnixEpoch, OwnedDeviceId, OwnedUserId, RoomId,
SecondsSinceUnixEpoch, UserId,
};
use serde::{Deserialize, Serialize};
use tokio::runtime::Runtime;
pub use users::UserIdentity;
pub use verification::{
CancelInfo, ConfirmVerificationResult, QrCode, RequestVerificationResult, Sas, ScanResult,
StartSasResult, Verification, VerificationRequest,
CancelInfo, ConfirmVerificationResult, QrCode, QrCodeListener, QrCodeState,
RequestVerificationResult, Sas, SasListener, SasState, ScanResult, StartSasResult,
Verification, VerificationRequest, VerificationRequestListener, VerificationRequestState,
};
use vodozemac::{Curve25519PublicKey, Ed25519PublicKey};
/// Struct collecting data that is important to migrate to the rust-sdk
#[derive(Deserialize, Serialize)]
#[derive(Deserialize, Serialize, uniffi::Record)]
pub struct MigrationData {
/// The pickled version of the Olm Account
account: PickledAccount,
@@ -58,13 +75,34 @@ pub struct MigrationData {
cross_signing: CrossSigningKeyExport,
/// The list of users that the Rust SDK should track.
tracked_users: Vec<String>,
/// Map of room settings
room_settings: HashMap<String, RoomSettings>,
}
/// Struct collecting data that is important to migrate sessions to the rust-sdk
#[derive(uniffi::Record)]
pub struct SessionMigrationData {
/// The user id that the data belongs to.
user_id: String,
/// The device id that the data belongs to.
device_id: String,
/// The Curve25519 public key of the Account that owns this data.
curve25519_key: String,
/// The Ed25519 public key of the Account that owns this data.
ed25519_key: String,
/// The list of pickleds Olm Sessions.
sessions: Vec<PickledSession>,
/// The list of pickled Megolm inbound group sessions.
inbound_group_sessions: Vec<PickledInboundGroupSession>,
/// The Olm pickle key that was used to pickle all the Olm objects.
pickle_key: Vec<u8>,
}
/// A pickled version of an `Account`.
///
/// Holds all the information that needs to be stored in a database to restore
/// an account.
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Deserialize, Serialize, uniffi::Record)]
pub struct PickledAccount {
/// The user id of the account owner.
pub user_id: String,
@@ -82,7 +120,7 @@ pub struct PickledAccount {
///
/// Holds all the information that needs to be stored in a database to restore
/// a Session.
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Deserialize, Serialize, uniffi::Record)]
pub struct PickledSession {
/// The pickle string holding the Olm Session.
pub pickle: String,
@@ -100,7 +138,7 @@ pub struct PickledSession {
///
/// Holds all the information that needs to be stored in a database to restore
/// an InboundGroupSession.
#[derive(Debug, Deserialize, Serialize)]
#[derive(Debug, Deserialize, Serialize, uniffi::Record)]
pub struct PickledInboundGroupSession {
/// The pickle string holding the InboundGroupSession.
pub pickle: String,
@@ -121,7 +159,7 @@ pub struct PickledInboundGroupSession {
}
/// Error type for the migration process.
#[derive(thiserror::Error, Debug)]
#[derive(Debug, thiserror::Error, uniffi::Error)]
pub enum MigrationError {
/// Generic catch all error variant.
#[error("error migrating database: {error_message}")]
@@ -137,38 +175,43 @@ impl From<anyhow::Error> for MigrationError {
}
}
/// Migrate a libolm based setup to a vodozemac based setup stored in a Sled
/// Migrate a libolm based setup to a vodozemac based setup stored in a SQLite
/// store.
///
/// # Arguments
///
/// * `data` - The data that should be migrated over to the Sled store.
/// * `data` - The data that should be migrated over to the SQLite store.
///
/// * `path` - The path where the Sled store should be created.
/// * `path` - The path where the SQLite store should be created.
///
/// * `passphrase` - The passphrase that should be used to encrypt the data at
/// rest in the Sled store. **Warning**, if no passphrase is given, the store
/// rest in the SQLite store. **Warning**, if no passphrase is given, the store
/// and all its data will remain unencrypted.
///
/// * `progress_listener` - A callback that can be used to introspect the
/// progress of the migration.
#[uniffi::export]
pub fn migrate(
data: MigrationData,
path: String,
passphrase: Option<String>,
progress_listener: Box<dyn ProgressListener>,
) -> Result<(), MigrationError> {
let runtime = Runtime::new().context("initializing tokio runtime")?;
runtime.block_on(async move {
migrate_data(data, &path, passphrase, progress_listener).await?;
Ok(())
})
}
async fn migrate_data(
mut data: MigrationData,
path: &str,
passphrase: Option<String>,
progress_listener: Box<dyn ProgressListener>,
) -> anyhow::Result<()> {
use matrix_sdk_crypto::{
olm::PrivateCrossSigningIdentity,
store::{Changes as RustChanges, CryptoStore, RecoveryKey},
};
use matrix_sdk_sled::SledCryptoStore;
use tokio::runtime::Runtime;
use vodozemac::{
megolm::InboundGroupSession,
olm::{Account, Session},
Curve25519PublicKey,
};
use matrix_sdk_crypto::{olm::PrivateCrossSigningIdentity, store::RecoveryKey};
use vodozemac::olm::Account;
use zeroize::Zeroize;
// The total steps here include all the sessions/inbound group sessions and
@@ -185,41 +228,196 @@ pub fn migrate(
progress_listener.on_progress(progress as i32, total as i32)
};
let store = SledCryptoStore::open_with_passphrase(path, passphrase.as_deref())?;
let runtime = Runtime::new()?;
let store = SqliteCryptoStore::open(path, passphrase.as_deref()).await?;
processed_steps += 1;
listener(processed_steps, total_steps);
let user_id: Arc<UserId> = {
let user_id: OwnedUserId = parse_user_id(&data.account.user_id)?;
let user_id: &UserId = user_id.borrow();
user_id.into()
};
let device_id: Box<DeviceId> = data.account.device_id.into();
let device_id: Arc<DeviceId> = device_id.into();
let user_id = parse_user_id(&data.account.user_id)?;
let device_id: OwnedDeviceId = data.account.device_id.into();
let account = Account::from_libolm_pickle(&data.account.pickle, &data.pickle_key)?;
let pickle = account.pickle();
let identity_keys = Arc::new(account.identity_keys());
let pickled_account = matrix_sdk_crypto::olm::PickledAccount {
user_id: parse_user_id(&data.account.user_id)?,
device_id: device_id.as_ref().to_owned(),
device_id: device_id.clone(),
pickle,
shared: data.account.shared,
uploaded_signed_key_count: data.account.uploaded_signed_key_count as u64,
creation_local_time: MilliSecondsSinceUnixEpoch(UInt::default()),
};
let account = matrix_sdk_crypto::olm::ReadOnlyAccount::from_pickle(pickled_account)?;
processed_steps += 1;
listener(processed_steps, total_steps);
let (sessions, inbound_group_sessions) = collect_sessions(
processed_steps,
total_steps,
&listener,
&data.pickle_key,
user_id.clone(),
device_id,
identity_keys,
data.sessions,
data.inbound_group_sessions,
)?;
let recovery_key =
data.backup_recovery_key.map(|k| RecoveryKey::from_base58(k.as_str())).transpose()?;
let cross_signing = PrivateCrossSigningIdentity::empty((*user_id).into());
cross_signing
.import_secrets_unchecked(
data.cross_signing.master_key.as_deref(),
data.cross_signing.self_signing_key.as_deref(),
data.cross_signing.user_signing_key.as_deref(),
)
.await?;
data.cross_signing.master_key.zeroize();
data.cross_signing.self_signing_key.zeroize();
data.cross_signing.user_signing_key.zeroize();
processed_steps += 1;
listener(processed_steps, total_steps);
let tracked_users: Vec<_> = data
.tracked_users
.into_iter()
.filter_map(|s| parse_user_id(&s).ok().map(|u| (u, true)))
.collect();
let tracked_users: Vec<_> = tracked_users.iter().map(|(u, d)| (&**u, *d)).collect();
store.save_tracked_users(tracked_users.as_slice()).await?;
processed_steps += 1;
listener(processed_steps, total_steps);
let mut room_settings = HashMap::new();
for (room_id, settings) in data.room_settings {
let room_id = RoomId::parse(room_id)?;
room_settings.insert(room_id, settings.into());
}
let changes = Changes {
account: Some(account),
private_identity: Some(cross_signing),
sessions,
inbound_group_sessions,
recovery_key,
backup_version: data.backup_version,
room_settings,
..Default::default()
};
save_changes(processed_steps, total_steps, &listener, changes, &store).await
}
async fn save_changes(
mut processed_steps: usize,
total_steps: usize,
listener: &dyn Fn(usize, usize),
changes: Changes,
store: &SqliteCryptoStore,
) -> anyhow::Result<()> {
store.save_changes(changes).await?;
processed_steps += 1;
listener(processed_steps, total_steps);
Ok(())
}
/// Migrate sessions and group sessions of a libolm based setup to a vodozemac
/// based setup stored in a SQLite store.
///
/// This method allows you to migrate a subset of the data, it should only be
/// used after the [`migrate()`] method has been already used.
///
/// # Arguments
///
/// * `data` - The data that should be migrated over to the SQLite store.
///
/// * `path` - The path where the SQLite store should be created.
///
/// * `passphrase` - The passphrase that should be used to encrypt the data at
/// rest in the SQLite store. **Warning**, if no passphrase is given, the store
/// and all its data will remain unencrypted.
///
/// * `progress_listener` - A callback that can be used to introspect the
/// progress of the migration.
#[uniffi::export]
pub fn migrate_sessions(
data: SessionMigrationData,
path: String,
passphrase: Option<String>,
progress_listener: Box<dyn ProgressListener>,
) -> Result<(), MigrationError> {
let runtime = Runtime::new().context("initializing tokio runtime")?;
runtime.block_on(migrate_session_data(data, &path, passphrase, progress_listener))?;
Ok(())
}
async fn migrate_session_data(
data: SessionMigrationData,
path: &str,
passphrase: Option<String>,
progress_listener: Box<dyn ProgressListener>,
) -> anyhow::Result<()> {
let store = SqliteCryptoStore::open(path, passphrase.as_deref()).await?;
let listener = |progress: usize, total: usize| {
progress_listener.on_progress(progress as i32, total as i32)
};
let total_steps = 1 + data.sessions.len() + data.inbound_group_sessions.len();
let processed_steps = 0;
let user_id = UserId::parse(data.user_id)?;
let device_id: OwnedDeviceId = data.device_id.into();
let identity_keys = IdentityKeys {
ed25519: Ed25519PublicKey::from_base64(&data.ed25519_key)?,
curve25519: Curve25519PublicKey::from_base64(&data.curve25519_key)?,
}
.into();
let (sessions, inbound_group_sessions) = collect_sessions(
processed_steps,
total_steps,
&listener,
&data.pickle_key,
user_id,
device_id,
identity_keys,
data.sessions,
data.inbound_group_sessions,
)?;
let changes = Changes { sessions, inbound_group_sessions, ..Default::default() };
save_changes(processed_steps, total_steps, &listener, changes, &store).await
}
#[allow(clippy::too_many_arguments)]
fn collect_sessions(
mut processed_steps: usize,
total_steps: usize,
listener: &dyn Fn(usize, usize),
pickle_key: &[u8],
user_id: OwnedUserId,
device_id: OwnedDeviceId,
identity_keys: Arc<IdentityKeys>,
session_pickles: Vec<PickledSession>,
group_session_pickles: Vec<PickledInboundGroupSession>,
) -> anyhow::Result<(Vec<Session>, Vec<InboundGroupSession>)> {
let mut sessions = Vec::new();
for session_pickle in data.sessions {
for session_pickle in session_pickles {
let pickle =
Session::from_libolm_pickle(&session_pickle.pickle, &data.pickle_key)?.pickle();
vodozemac::olm::Session::from_libolm_pickle(&session_pickle.pickle, pickle_key)?
.pickle();
let creation_time = SecondsSinceUnixEpoch(UInt::from_str(&session_pickle.creation_time)?);
let last_use_time = SecondsSinceUnixEpoch(UInt::from_str(&session_pickle.last_use_time)?);
@@ -232,12 +430,8 @@ pub fn migrate(
last_use_time,
};
let session = matrix_sdk_crypto::olm::Session::from_pickle(
user_id.clone(),
device_id.clone(),
identity_keys.clone(),
pickle,
);
let session =
Session::from_pickle(user_id.clone(), device_id.clone(), identity_keys.clone(), pickle);
sessions.push(session);
processed_steps += 1;
@@ -246,9 +440,12 @@ pub fn migrate(
let mut inbound_group_sessions = Vec::new();
for session in data.inbound_group_sessions {
let pickle =
InboundGroupSession::from_libolm_pickle(&session.pickle, &data.pickle_key)?.pickle();
for session in group_session_pickles {
let pickle = vodozemac::megolm::InboundGroupSession::from_libolm_pickle(
&session.pickle,
pickle_key,
)?
.pickle();
let sender_key = Curve25519PublicKey::from_base64(&session.sender_key)?;
@@ -269,7 +466,7 @@ pub fn migrate(
imported: session.imported,
backed_up: session.backed_up,
history_visibility: None,
algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
algorithm: RustEventEncryptionAlgorithm::MegolmV1AesSha2,
};
let session = matrix_sdk_crypto::olm::InboundGroupSession::from_pickle(pickle)?;
@@ -279,51 +476,49 @@ pub fn migrate(
listener(processed_steps, total_steps);
}
let recovery_key =
data.backup_recovery_key.map(|k| RecoveryKey::from_base58(k.as_str())).transpose()?;
Ok((sessions, inbound_group_sessions))
}
let cross_signing = PrivateCrossSigningIdentity::empty((*user_id).into());
runtime.block_on(cross_signing.import_secrets_unchecked(
data.cross_signing.master_key.as_deref(),
data.cross_signing.self_signing_key.as_deref(),
data.cross_signing.user_signing_key.as_deref(),
))?;
/// Migrate room settings, including room algorithm and whether to block
/// untrusted devices from legacy store to Sqlite store.
///
/// Note that this method should only be used if a client has already migrated
/// account data via [migrate](#method.migrate) method, which did not include
/// room settings. For a brand new migration, the [migrate](#method.migrate)
/// method will take care of room settings automatically, if provided.
///
/// # Arguments
///
/// * `room_settings` - Map of room settings
///
/// * `path` - The path where the Sqlite store should be created.
///
/// * `passphrase` - The passphrase that should be used to encrypt the data at
/// rest in the Sqlite store. **Warning**, if no passphrase is given, the store
/// and all its data will remain unencrypted.
#[uniffi::export]
pub fn migrate_room_settings(
room_settings: HashMap<String, RoomSettings>,
path: String,
passphrase: Option<String>,
) -> Result<(), MigrationError> {
let runtime = Runtime::new().context("initializing tokio runtime")?;
runtime.block_on(async move {
let store = SqliteCryptoStore::open(path, passphrase.as_deref())
.await
.context("opening sqlite crypto store")?;
data.cross_signing.master_key.zeroize();
data.cross_signing.self_signing_key.zeroize();
data.cross_signing.user_signing_key.zeroize();
let mut rust_settings = HashMap::new();
for (room_id, settings) in room_settings {
let room_id = RoomId::parse(room_id).context("parsing room ID")?;
rust_settings.insert(room_id, settings.into());
}
processed_steps += 1;
listener(processed_steps, total_steps);
let changes = Changes { room_settings: rust_settings, ..Default::default() };
store.save_changes(changes).await.context("saving changes")?;
let tracked_users: Vec<_> = data
.tracked_users
.into_iter()
.map(|u| Ok(((parse_user_id(&u)?), true)))
.collect::<anyhow::Result<_>>()?;
let tracked_users: Vec<_> = tracked_users.iter().map(|(u, d)| (&**u, *d)).collect();
runtime.block_on(store.save_tracked_users(tracked_users.as_slice()))?;
processed_steps += 1;
listener(processed_steps, total_steps);
let changes = RustChanges {
account: Some(account),
private_identity: Some(cross_signing),
sessions,
inbound_group_sessions,
recovery_key,
backup_version: data.backup_version,
..Default::default()
};
runtime.block_on(store.save_changes(changes))?;
processed_steps += 1;
listener(processed_steps, total_steps);
Ok(())
Ok(())
})
}
/// Callback that will be passed over the FFI to report progress
@@ -344,7 +539,114 @@ impl<T: Fn(i32, i32)> ProgressListener for T {
}
}
/// An encryption algorithm to be used to encrypt messages sent to a room.
#[derive(Debug, Deserialize, Serialize, PartialEq, uniffi::Enum)]
pub enum EventEncryptionAlgorithm {
/// Olm version 1 using Curve25519, AES-256, and SHA-256.
OlmV1Curve25519AesSha2,
/// Megolm version 1 using AES-256 and SHA-256.
MegolmV1AesSha2,
}
impl From<EventEncryptionAlgorithm> for RustEventEncryptionAlgorithm {
fn from(a: EventEncryptionAlgorithm) -> Self {
match a {
EventEncryptionAlgorithm::OlmV1Curve25519AesSha2 => Self::OlmV1Curve25519AesSha2,
EventEncryptionAlgorithm::MegolmV1AesSha2 => Self::MegolmV1AesSha2,
}
}
}
impl TryFrom<RustEventEncryptionAlgorithm> for EventEncryptionAlgorithm {
type Error = serde_json::Error;
fn try_from(value: RustEventEncryptionAlgorithm) -> Result<Self, Self::Error> {
match value {
RustEventEncryptionAlgorithm::OlmV1Curve25519AesSha2 => {
Ok(Self::OlmV1Curve25519AesSha2)
}
RustEventEncryptionAlgorithm::MegolmV1AesSha2 => Ok(Self::MegolmV1AesSha2),
_ => Err(serde::de::Error::custom(format!("Unsupported algorithm {value}"))),
}
}
}
/// Who can see a room's history.
#[derive(uniffi::Enum)]
pub enum HistoryVisibility {
/// Previous events are accessible to newly joined members from the point
/// they were invited onwards.
///
/// Events stop being accessible when the member's state changes to
/// something other than *invite* or *join*.
Invited,
/// Previous events are accessible to newly joined members from the point
/// they joined the room onwards.
/// Events stop being accessible when the member's state changes to
/// something other than *join*.
Joined,
/// Previous events are always accessible to newly joined members.
///
/// All events in the room are accessible, even those sent when the member
/// was not a part of the room.
Shared,
/// All events while this is the `HistoryVisibility` value may be shared by
/// any participating homeserver with anyone, regardless of whether they
/// have ever joined the room.
WorldReadable,
}
impl From<HistoryVisibility> for RustHistoryVisibility {
fn from(h: HistoryVisibility) -> Self {
match h {
HistoryVisibility::Invited => Self::Invited,
HistoryVisibility::Joined => Self::Joined,
HistoryVisibility::Shared => Self::Shared,
HistoryVisibility::WorldReadable => Self::Shared,
}
}
}
/// Settings that should be used when a room key is shared.
///
/// These settings control which algorithm the room key should use, how long a
/// room key should be used and some other important information that determines
/// the lifetime of a room key.
#[derive(uniffi::Record)]
pub struct EncryptionSettings {
/// The encryption algorithm that should be used in the room.
pub algorithm: EventEncryptionAlgorithm,
/// How long can the room key be used before it should be rotated. Time in
/// seconds.
pub rotation_period: u64,
/// How many messages should be sent before the room key should be rotated.
pub rotation_period_msgs: u64,
/// The current history visibility of the room. The visibility will be
/// tracked by the room key and the key will be rotated if the visibility
/// changes.
pub history_visibility: HistoryVisibility,
/// Should untrusted devices receive the room key, or should they be
/// excluded from the conversation.
pub only_allow_trusted_devices: bool,
}
impl From<EncryptionSettings> for RustEncryptionSettings {
fn from(v: EncryptionSettings) -> Self {
RustEncryptionSettings {
algorithm: v.algorithm.into(),
rotation_period: Duration::from_secs(v.rotation_period),
rotation_period_msgs: v.rotation_period_msgs,
history_visibility: v.history_visibility.into(),
only_allow_trusted_devices: v.only_allow_trusted_devices,
}
}
}
/// An event that was successfully decrypted.
#[derive(uniffi::Record)]
pub struct DecryptedEvent {
/// The decrypted version of the event.
pub clear_event: String,
@@ -356,11 +658,53 @@ pub struct DecryptedEvent {
/// key to us. Is empty if the key came directly from the sender of the
/// event.
pub forwarding_curve25519_chain: Vec<String>,
/// The shield state (color and message to display to user) for the event,
/// representing the event's authenticity. Computed from the properties of
/// the sender user identity and their Olm device.
///
/// Note that this is computed at time of decryption, so the value reflects
/// the computed event authenticity at that time. Authenticity-related
/// properties can change later on, such as when a user identity is
/// subsequently verified or a device is deleted.
pub shield_state: ShieldState,
}
/// Take a look at [`matrix_sdk_common::deserialized_responses::ShieldState`]
/// for more info.
#[allow(missing_docs)]
#[derive(uniffi::Enum)]
pub enum ShieldColor {
Red,
Grey,
None,
}
/// Take a look at [`matrix_sdk_common::deserialized_responses::ShieldState`]
/// for more info.
#[derive(uniffi::Record)]
#[allow(missing_docs)]
pub struct ShieldState {
color: ShieldColor,
message: Option<String>,
}
impl From<RustShieldState> for ShieldState {
fn from(value: RustShieldState) -> Self {
match value {
RustShieldState::Red { message } => {
Self { color: ShieldColor::Red, message: Some(message.to_owned()) }
}
RustShieldState::Grey { message } => {
Self { color: ShieldColor::Grey, message: Some(message.to_owned()) }
}
RustShieldState::None => Self { color: ShieldColor::None, message: None },
}
}
}
/// Struct representing the state of our private cross signing keys, it shows
/// which private cross signing keys we have locally stored.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, uniffi::Record)]
pub struct CrossSigningStatus {
/// Do we have the master key.
pub has_master: bool,
@@ -374,7 +718,7 @@ pub struct CrossSigningStatus {
/// A struct containing private cross signing keys that can be backed up or
/// uploaded to the secret store.
#[derive(Deserialize, Serialize)]
#[derive(Deserialize, Serialize, uniffi::Record)]
pub struct CrossSigningKeyExport {
/// The seed of the master key encoded as unpadded base64.
pub master_key: Option<String>,
@@ -385,6 +729,7 @@ pub struct CrossSigningKeyExport {
}
/// Struct holding the number of room keys we have.
#[derive(uniffi::Record)]
pub struct RoomKeyCounts {
/// The total number of room keys.
pub total: i64,
@@ -393,6 +738,7 @@ pub struct RoomKeyCounts {
}
/// Backup keys and information we load from the store.
#[derive(uniffi::Object)]
pub struct BackupKeys {
/// The recovery key as a base64 encoded string.
recovery_key: Arc<BackupRecoveryKey>,
@@ -400,6 +746,7 @@ pub struct BackupKeys {
backup_version: String,
}
#[uniffi::export]
impl BackupKeys {
/// Get the recovery key that we're holding on to.
pub fn recovery_key(&self) -> Arc<BackupRecoveryKey> {
@@ -463,17 +810,73 @@ impl From<matrix_sdk_crypto::CrossSigningStatus> for CrossSigningStatus {
}
}
/// Room encryption settings which are modified by state events or user options
#[derive(Debug, PartialEq, Deserialize, Serialize, uniffi::Record)]
pub struct RoomSettings {
/// The encryption algorithm that should be used in the room.
pub algorithm: EventEncryptionAlgorithm,
/// Should untrusted devices receive the room key, or should they be
/// excluded from the conversation.
pub only_allow_trusted_devices: bool,
}
impl TryFrom<RustRoomSettings> for RoomSettings {
type Error = serde_json::Error;
fn try_from(value: RustRoomSettings) -> Result<Self, Self::Error> {
let algorithm = value.algorithm.try_into()?;
Ok(Self { algorithm, only_allow_trusted_devices: value.only_allow_trusted_devices })
}
}
impl From<RoomSettings> for RustRoomSettings {
fn from(value: RoomSettings) -> Self {
Self {
algorithm: value.algorithm.into(),
only_allow_trusted_devices: value.only_allow_trusted_devices,
}
}
}
fn parse_user_id(user_id: &str) -> Result<OwnedUserId, CryptoStoreError> {
ruma::UserId::parse(user_id).map_err(|e| CryptoStoreError::InvalidUserId(user_id.to_owned(), e))
}
#[allow(warnings)]
mod generated {
use super::*;
include!(concat!(env!("OUT_DIR"), "/olm.uniffi.rs"));
#[uniffi::export]
fn version_info() -> VersionInfo {
VersionInfo {
version: matrix_sdk_crypto::VERSION.to_owned(),
vodozemac_version: matrix_sdk_crypto::vodozemac::VERSION.to_owned(),
git_description: env!("VERGEN_GIT_DESCRIBE").to_owned(),
git_sha: env!("VERGEN_GIT_SHA").to_owned(),
}
}
pub use generated::*;
/// Build-time information about important crates that are used.
#[derive(uniffi::Record)]
pub struct VersionInfo {
/// The version of the matrix-sdk-crypto crate.
pub version: String,
/// The version of the vodozemac crate.
pub vodozemac_version: String,
/// The Git commit hash of the crate's source tree at build time.
pub git_sha: String,
/// The build-time output of the `git describe` command of the source tree
/// of crate.
pub git_description: String,
}
#[uniffi::export]
fn version() -> String {
matrix_sdk_crypto::VERSION.to_owned()
}
#[uniffi::export]
fn vodozemac_version() -> String {
vodozemac::VERSION.to_owned()
}
uniffi::include_scaffolding!("olm");
#[cfg(test)]
mod test {
@@ -482,7 +885,7 @@ mod test {
use tempfile::tempdir;
use super::MigrationData;
use crate::{migrate, OlmMachine};
use crate::{migrate, EventEncryptionAlgorithm, OlmMachine, RoomSettings};
#[test]
fn android_migration() -> Result<()> {
@@ -564,19 +967,38 @@ mod test {
"@ganfra146:matrix.org",
"@this-is-me:matrix.org",
"@Amandine:matrix.org",
"@ganfra:matrix.org"
]
"@ganfra:matrix.org",
"NotAUser%ID"
],
"room_settings": {
"!AZkqtjvtwPAuyNOXEt:matrix.org": {
"algorithm": "OlmV1Curve25519AesSha2",
"only_allow_trusted_devices": true
},
"!CWLUCoEWXSFyTCOtfL:matrix.org": {
"algorithm": "MegolmV1AesSha2",
"only_allow_trusted_devices": false
},
}
});
let migration_data: MigrationData = serde_json::from_value(data)?;
let dir = tempdir()?;
let path =
dir.path().to_str().expect("Creating a string from the tempdir path should not fail");
let path = dir
.path()
.to_str()
.expect("Creating a string from the tempdir path should not fail")
.to_owned();
migrate(migration_data, path, None, Box::new(|_, _| {}))?;
migrate(migration_data, path.clone(), None, Box::new(|_, _| {}))?;
let machine = OlmMachine::new("@ganfra146:matrix.org", "DEWRCMENGS", path, None)?;
let machine = OlmMachine::new(
"@ganfra146:matrix.org".to_owned(),
"DEWRCMENGS".to_owned(),
path,
None,
)?;
assert_eq!(
machine.identity_keys()["ed25519"],
@@ -594,6 +1016,32 @@ mod test {
let backup_keys = machine.get_backup_keys()?;
assert!(backup_keys.is_some());
let settings1 = machine.get_room_settings("!AZkqtjvtwPAuyNOXEt:matrix.org".into())?;
assert_eq!(
Some(RoomSettings {
algorithm: EventEncryptionAlgorithm::OlmV1Curve25519AesSha2,
only_allow_trusted_devices: true
}),
settings1
);
let settings2 = machine.get_room_settings("!CWLUCoEWXSFyTCOtfL:matrix.org".into())?;
assert_eq!(
Some(RoomSettings {
algorithm: EventEncryptionAlgorithm::MegolmV1AesSha2,
only_allow_trusted_devices: false
}),
settings2
);
let settings3 = machine.get_room_settings("!XYZ:matrix.org".into())?;
assert!(settings3.is_none());
assert!(machine.is_user_tracked("@ganfra146:matrix.org".into()).unwrap());
assert!(machine.is_user_tracked("@Amandine:matrix.org".into()).unwrap());
assert!(machine.is_user_tracked("@this-is-me:matrix.org".into()).unwrap());
assert!(machine.is_user_tracked("@ganfra:matrix.org".into()).unwrap());
Ok(())
}
}
+9 -3
View File
@@ -41,16 +41,22 @@ pub struct LoggerWrapper {
}
/// Set the logger that should be used to forward Rust logs over FFI.
#[uniffi::export]
pub fn set_logger(logger: Box<dyn Logger>) {
let logger = LoggerWrapper { inner: Arc::new(Mutex::new(logger)) };
let filter = EnvFilter::from_default_env().add_directive(
"matrix_sdk_crypto=trace".parse().expect("Can't parse logging filter directive"),
);
let filter = EnvFilter::from_default_env()
.add_directive(
"matrix_sdk_crypto=trace".parse().expect("Can't parse logging filter directive"),
)
.add_directive(
"matrix_sdk_sqlite=debug".parse().expect("Can't parse logging filter directive"),
);
let _ = tracing_subscriber::fmt()
.with_writer(logger)
.with_env_filter(filter)
.with_ansi(false)
.without_time()
.try_init();
}
File diff suppressed because it is too large Load Diff
+38 -452
View File
@@ -1,483 +1,69 @@
namespace olm {
void set_logger(Logger logger);
[Throws=MigrationError]
void migrate(
MigrationData data,
[ByRef] string path,
string? passphrase,
ProgressListener progress_listener
);
};
[Error]
interface MigrationError {
Generic(string error_message);
};
namespace matrix_sdk_crypto_ffi {};
callback interface Logger {
void log(string logLine);
void log(string log_line);
};
callback interface ProgressListener {
void on_progress(i32 progress, i32 total);
};
[Error]
enum PkDecryptionError {
"Olm",
};
[Error]
enum KeyImportError {
"Export",
"CryptoStore",
"Json",
};
[Error]
enum SignatureError {
"Signature",
"Identifier",
"CryptoStore",
"UnknownDevice",
"UnknownUserIdentity",
};
[Error]
enum SecretImportError {
"Import",
"CryptoStore",
};
[Error]
enum CryptoStoreError {
"CryptoStore",
"OlmError",
"Serialization",
"Identifier",
"InvalidUserId",
};
[Error]
enum DecryptionError {
"Identifier",
"Serialization",
"Megolm",
};
dictionary DeviceLists {
sequence<string> changed;
sequence<string> left;
};
dictionary KeysImportResult {
i64 imported;
i64 total;
record<DOMString, record<DOMString, sequence<string>>> keys;
};
dictionary DecryptedEvent {
string clear_event;
string sender_curve25519_key;
string? claimed_ed25519_key;
sequence<string> forwarding_curve25519_chain;
};
dictionary Device {
string user_id;
string device_id;
record<DOMString, string> keys;
sequence<string> algorithms;
string? display_name;
boolean is_blocked;
boolean locally_trusted;
boolean cross_signing_trusted;
};
[Enum]
interface UserIdentity {
Own(
string user_id,
boolean trusts_our_own_device,
string master_key,
string self_signing_key,
string user_signing_key
);
Other(
string user_id,
string master_key,
string self_signing_key
);
};
dictionary CrossSigningStatus {
boolean has_master;
boolean has_self_signing;
boolean has_user_signing;
};
dictionary CrossSigningKeyExport {
string? master_key;
string? self_signing_key;
string? user_signing_key;
};
dictionary UploadSigningKeysRequest {
string master_key;
string self_signing_key;
string user_signing_key;
};
dictionary BootstrapCrossSigningResult {
UploadSigningKeysRequest upload_signing_keys_request;
SignatureUploadRequest signature_request;
};
dictionary CancelInfo {
string cancel_code;
string reason;
boolean cancelled_by_us;
};
dictionary StartSasResult {
Sas sas;
OutgoingVerificationRequest request;
[Enum]
interface SasState {
Started();
Accepted();
KeysExchanged(sequence<i32>? emojis, sequence<i32> decimals);
Confirmed();
Done();
Cancelled(CancelInfo cancel_info);
};
dictionary Sas {
string other_user_id;
string other_device_id;
string flow_id;
string? room_id;
boolean we_started;
boolean has_been_accepted;
boolean can_be_presented;
boolean supports_emoji;
boolean have_we_confirmed;
boolean is_done;
boolean is_cancelled;
CancelInfo? cancel_info;
};
dictionary ScanResult {
QrCode qr;
OutgoingVerificationRequest request;
};
dictionary QrCode {
string other_user_id;
string other_device_id;
string flow_id;
string? room_id;
boolean we_started;
boolean other_side_scanned;
boolean has_been_confirmed;
boolean reciprocated;
boolean is_done;
boolean is_cancelled;
CancelInfo? cancel_info;
};
dictionary VerificationRequest {
string other_user_id;
string? other_device_id;
string flow_id;
string? room_id;
boolean we_started;
boolean is_ready;
boolean is_passive;
boolean is_done;
boolean is_cancelled;
CancelInfo? cancel_info;
sequence<string>? their_methods;
sequence<string>? our_methods;
};
dictionary RequestVerificationResult {
VerificationRequest verification;
OutgoingVerificationRequest request;
};
dictionary ConfirmVerificationResult {
sequence<OutgoingVerificationRequest> requests;
SignatureUploadRequest? signature_request;
callback interface SasListener {
void on_change(SasState state);
};
[Enum]
interface Verification {
SasV1(Sas sas);
QrCodeV1(QrCode qrcode);
interface QrCodeState {
Started();
Scanned();
Confirmed();
Reciprocated();
Done();
Cancelled(CancelInfo cancel_info);
};
dictionary KeyRequestPair {
Request? cancellation;
Request key_request;
callback interface QrCodeListener {
void on_change(QrCodeState state);
};
[Enum]
interface OutgoingVerificationRequest {
ToDevice(string request_id, string event_type, string body);
InRoom(string request_id, string room_id, string event_type, string content);
interface VerificationRequestState {
Requested();
Ready(sequence<string> their_methods, sequence<string> our_methods);
Done();
Cancelled(CancelInfo cancel_info);
};
[Enum]
interface Request {
ToDevice(string request_id, string event_type, string body);
KeysUpload(string request_id, string body);
KeysQuery(string request_id, sequence<string> users);
KeysClaim(string request_id, record<DOMString, record<DOMString, string>> one_time_keys);
KeysBackup(string request_id, string version, string rooms);
RoomMessage(string request_id, string room_id, string event_type, string content);
SignatureUpload(string request_id, string body);
callback interface VerificationRequestListener {
void on_change(VerificationRequestState state);
};
dictionary SignatureUploadRequest {
string body;
enum LocalTrust {
"Verified",
"BlackListed",
"Ignored",
"Unset",
};
enum RequestType {
"KeysQuery",
"KeysClaim",
"KeysUpload",
"ToDevice",
"SignatureUpload",
"KeysBackup",
"RoomMessage",
};
interface OlmMachine {
[Throws=CryptoStoreError]
constructor(
[ByRef] string user_id,
[ByRef] string device_id,
[ByRef] string path,
string? passphrase
);
record<DOMString, string> identity_keys();
string user_id();
string device_id();
[Throws=CryptoStoreError]
string receive_sync_changes([ByRef] string events,
DeviceLists device_changes,
record<DOMString, i32> key_counts,
sequence<string>? unused_fallback_keys);
[Throws=CryptoStoreError]
sequence<Request> outgoing_requests();
[Throws=CryptoStoreError]
void mark_request_as_sent(
[ByRef] string request_id,
RequestType request_type,
[ByRef] string response
);
[Throws=DecryptionError]
DecryptedEvent decrypt_room_event([ByRef] string event, [ByRef] string room_id);
[Throws=CryptoStoreError]
string encrypt([ByRef] string room_id, [ByRef] string event_type, [ByRef] string content);
[Throws=CryptoStoreError]
UserIdentity? get_identity([ByRef] string user_id, u32 timeout);
[Throws=SignatureError]
SignatureUploadRequest verify_identity([ByRef] string user_id);
[Throws=CryptoStoreError]
Device? get_device([ByRef] string user_id, [ByRef] string device_id, u32 timeout);
[Throws=CryptoStoreError]
void mark_device_as_trusted([ByRef] string user_id, [ByRef] string device_id);
[Throws=SignatureError]
SignatureUploadRequest verify_device([ByRef] string user_id, [ByRef] string device_id);
[Throws=CryptoStoreError]
sequence<Device> get_user_devices([ByRef] string user_id, u32 timeout);
[Throws=CryptoStoreError]
boolean is_user_tracked([ByRef] string user_id);
void update_tracked_users(sequence<string> users);
[Throws=CryptoStoreError]
Request? get_missing_sessions(sequence<string> users);
[Throws=CryptoStoreError]
sequence<Request> share_room_key([ByRef] string room_id, sequence<string> users);
[Throws=CryptoStoreError]
void receive_unencrypted_verification_event([ByRef] string event, [ByRef] string room_id);
sequence<VerificationRequest> get_verification_requests([ByRef] string user_id);
VerificationRequest? get_verification_request([ByRef] string user_id, [ByRef] string flow_id);
Verification? get_verification([ByRef] string user_id, [ByRef] string flow_id);
[Throws=CryptoStoreError]
VerificationRequest? request_verification(
[ByRef] string user_id,
[ByRef] string room_id,
[ByRef] string event_id,
sequence<string> methods
);
[Throws=CryptoStoreError]
string? verification_request_content(
[ByRef] string user_id,
sequence<string> methods
);
[Throws=CryptoStoreError]
RequestVerificationResult? request_self_verification(sequence<string> methods);
[Throws=CryptoStoreError]
RequestVerificationResult? request_verification_with_device(
[ByRef] string user_id,
[ByRef] string device_id,
sequence<string> methods
);
OutgoingVerificationRequest? accept_verification_request(
[ByRef] string user_id,
[ByRef] string flow_id,
sequence<string> methods
);
[Throws=CryptoStoreError]
ConfirmVerificationResult? confirm_verification([ByRef] string user_id, [ByRef] string flow_id);
OutgoingVerificationRequest? cancel_verification(
[ByRef] string user_id,
[ByRef] string flow_id,
[ByRef] string cancel_code
);
[Throws=CryptoStoreError]
StartSasResult? start_sas_with_device([ByRef] string user_id, [ByRef] string device_id);
[Throws=CryptoStoreError]
StartSasResult? start_sas_verification([ByRef] string user_id, [ByRef] string flow_id);
OutgoingVerificationRequest? accept_sas_verification([ByRef] string user_id, [ByRef] string flow_id);
sequence<i32>? get_emoji_index([ByRef] string user_id, [ByRef] string flow_id);
sequence<i32>? get_decimals([ByRef] string user_id, [ByRef] string flow_id);
[Throws=CryptoStoreError]
QrCode? start_qr_verification([ByRef] string user_id, [ByRef] string flow_id);
ScanResult? scan_qr_code([ByRef] string user_id, [ByRef] string flow_id, [ByRef] string data);
string? generate_qr_code([ByRef] string user_id, [ByRef] string flow_id);
[Throws=DecryptionError]
KeyRequestPair request_room_key([ByRef] string event, [ByRef] string room_id);
[Throws=CryptoStoreError]
string export_room_keys([ByRef] string passphrase, i32 rounds);
[Throws=KeyImportError]
KeysImportResult import_room_keys(
[ByRef] string keys,
[ByRef] string passphrase,
ProgressListener progress_listener
);
[Throws=KeyImportError]
KeysImportResult import_decrypted_room_keys(
[ByRef] string keys,
ProgressListener progress_listener
);
[Throws=CryptoStoreError]
void discard_room_key([ByRef] string room_id);
CrossSigningStatus cross_signing_status();
[Throws=CryptoStoreError]
BootstrapCrossSigningResult bootstrap_cross_signing();
CrossSigningKeyExport? export_cross_signing_keys();
[Throws=SecretImportError]
void import_cross_signing_keys(CrossSigningKeyExport export);
[Throws=CryptoStoreError]
boolean is_identity_verified([ByRef] string user_id);
record<DOMString, record<DOMString, string>> sign([ByRef] string message);
[Throws=DecodeError]
void enable_backup_v1(MegolmV1BackupKey key, string version);
[Throws=CryptoStoreError]
void disable_backup();
[Throws=CryptoStoreError]
Request? backup_room_keys();
[Throws=CryptoStoreError]
void save_recovery_key(BackupRecoveryKey? key, string? version);
[Throws=CryptoStoreError]
RoomKeyCounts room_key_counts();
[Throws=CryptoStoreError]
BackupKeys? get_backup_keys();
boolean backup_enabled();
[Throws=CryptoStoreError]
boolean verify_backup([ByRef] string auth_data);
};
dictionary PassphraseInfo {
string private_key_salt;
i32 private_key_iterations;
};
dictionary MegolmV1BackupKey {
string public_key;
record<DOMString, record<DOMString, string>> signatures;
PassphraseInfo? passphrase_info;
string backup_algorithm;
};
interface BackupKeys {
BackupRecoveryKey recovery_key();
string backup_version();
};
dictionary RoomKeyCounts {
i64 total;
i64 backed_up;
};
[Error]
enum DecodeError {
"Decode",
"CryptoStore",
};
interface BackupRecoveryKey {
constructor();
[Name=from_passphrase]
constructor(string passphrase, string salt, i32 rounds);
[Name=new_from_passphrase]
constructor(string passphrase);
[Name=from_base64, Throws=DecodeError]
constructor(string key);
[Name=from_base58, Throws=DecodeError]
constructor(string key);
string to_base58();
string to_base64();
MegolmV1BackupKey megolm_v1_public_key();
[Throws=PkDecryptionError]
string decrypt_v1(string ephemeral_key, string mac, string ciphertext);
};
dictionary MigrationData {
PickledAccount account;
sequence<PickledSession> sessions;
sequence<PickledInboundGroupSession> inbound_group_sessions;
string? backup_version;
string? backup_recovery_key;
sequence<u8> pickle_key;
CrossSigningKeyExport cross_signing;
sequence<string> tracked_users;
};
dictionary PickledAccount {
string user_id;
string device_id;
string pickle;
boolean shared;
i64 uploaded_signed_key_count;
};
dictionary PickledSession {
string pickle;
string sender_key;
boolean created_using_fallback_key;
string creation_time;
string last_use_time;
};
dictionary PickledInboundGroupSession {
string pickle;
string sender_key;
record<DOMString, string> signing_key;
string room_id;
sequence<string> forwarding_chains;
boolean imported;
boolean backed_up;
enum SignatureState {
"Missing",
"Invalid",
"ValidButNotTrusted",
"ValidAndTrusted",
};
@@ -19,7 +19,7 @@ use ruma::{
},
},
message::send_message_event::v3::Response as RoomMessageResponse,
sync::sync_events::v3::DeviceLists as RumaDeviceLists,
sync::sync_events::DeviceLists as RumaDeviceLists,
to_device::send_event_to_device::v3::Response as ToDeviceResponse,
},
assign,
@@ -28,6 +28,7 @@ use ruma::{
};
use serde_json::json;
#[derive(uniffi::Record)]
pub struct SignatureUploadRequest {
pub body: String,
}
@@ -41,6 +42,7 @@ impl From<RustSignatureUploadRequest> for SignatureUploadRequest {
}
}
#[derive(uniffi::Record)]
pub struct UploadSigningKeysRequest {
pub master_key: String,
pub self_signing_key: String,
@@ -66,6 +68,7 @@ impl From<RustUploadSigningKeysRequest> for UploadSigningKeysRequest {
}
}
#[derive(uniffi::Record)]
pub struct BootstrapCrossSigningResult {
pub upload_signing_keys_request: UploadSigningKeysRequest,
pub signature_request: SignatureUploadRequest,
@@ -82,6 +85,7 @@ impl From<(RustUploadSigningKeysRequest, RustSignatureUploadRequest)>
}
}
#[derive(uniffi::Enum)]
pub enum OutgoingVerificationRequest {
ToDevice { request_id: String, event_type: String, body: String },
InRoom { request_id: String, room_id: String, event_type: String, content: String },
@@ -112,15 +116,15 @@ impl From<ToDeviceRequest> for OutgoingVerificationRequest {
}
}
#[derive(Debug)]
#[derive(Debug, uniffi::Enum)]
pub enum Request {
ToDevice { request_id: String, event_type: String, body: String },
KeysUpload { request_id: String, body: String },
KeysQuery { request_id: String, users: Vec<String> },
KeysClaim { request_id: String, one_time_keys: HashMap<String, HashMap<String, String>> },
KeysBackup { request_id: String, version: String, rooms: String },
RoomMessage { request_id: String, room_id: String, event_type: String, content: String },
SignatureUpload { request_id: String, body: String },
KeysBackup { request_id: String, version: String, rooms: String },
}
impl From<OutgoingRequest> for Request {
@@ -221,6 +225,7 @@ pub(crate) fn response_from_string(body: &str) -> Response<Vec<u8>> {
.expect("Can't create HTTP response")
}
#[derive(uniffi::Enum)]
pub enum RequestType {
KeysQuery,
KeysClaim,
@@ -231,6 +236,7 @@ pub enum RequestType {
RoomMessage,
}
#[derive(uniffi::Record)]
pub struct DeviceLists {
pub changed: Vec<String>,
pub left: Vec<String>,
@@ -253,6 +259,7 @@ impl From<DeviceLists> for RumaDeviceLists {
}
}
#[derive(uniffi::Record)]
pub struct KeysImportResult {
/// The number of room keys that were imported.
pub imported: i64,
@@ -4,6 +4,7 @@ use crate::CryptoStoreError;
/// Enum representing cross signing identities of our own user or some other
/// user.
#[derive(uniffi::Enum)]
pub enum UserIdentity {
/// Our own user identity.
Own {
+724 -153
View File
@@ -1,100 +1,458 @@
use matrix_sdk_crypto::{
CancelInfo as RustCancelInfo, QrVerification as InnerQr, Sas as InnerSas,
VerificationRequest as InnerVerificationRequest,
use std::sync::Arc;
use base64::{
alphabet,
engine::{general_purpose, GeneralPurpose},
Engine,
};
use futures_util::{Stream, StreamExt};
use matrix_sdk_crypto::{
matrix_sdk_qrcode::QrVerificationData, CancelInfo as RustCancelInfo, QrVerification as InnerQr,
QrVerificationState, Sas as InnerSas, SasState as RustSasState,
Verification as InnerVerification, VerificationRequest as InnerVerificationRequest,
VerificationRequestState as RustVerificationRequestState,
};
use ruma::events::key::verification::VerificationMethod;
use tokio::runtime::Handle;
use crate::{OutgoingVerificationRequest, SignatureUploadRequest};
use crate::{CryptoStoreError, OutgoingVerificationRequest, SignatureUploadRequest};
/// Enum representing the different verification flows we support.
pub enum Verification {
/// The `m.sas.v1` verification flow.
SasV1 {
#[allow(missing_docs)]
sas: Sas,
const STANDARD_NO_PAD: GeneralPurpose =
GeneralPurpose::new(&alphabet::STANDARD, general_purpose::NO_PAD);
/// Listener that will be passed over the FFI to report changes to a SAS
/// verification.
pub trait SasListener: Send {
/// The callback that should be called on the Rust side
///
/// # Arguments
///
/// * `state` - The current state of the SAS verification.
fn on_change(&self, state: SasState);
}
/// An Enum describing the state the SAS verification is in.
pub enum SasState {
/// The verification has been started, the protocols that should be used
/// have been proposed and can be accepted.
Started,
/// The verification has been accepted and both sides agreed to a set of
/// protocols that will be used for the verification process.
Accepted,
/// The public keys have been exchanged and the short auth string can be
/// presented to the user.
KeysExchanged {
/// The emojis that represent the short auth string, will be `None` if
/// the emoji SAS method wasn't one of accepted protocols.
emojis: Option<Vec<i32>>,
/// The list of decimals that represent the short auth string.
decimals: Vec<i32>,
},
/// The `m.qr_code.scan.v1`, `m.qr_code.show.v1`, and `m.reciprocate.v1`
/// verification flow.
QrCodeV1 {
#[allow(missing_docs)]
qrcode: QrCode,
/// The verification process has been confirmed from our side, we're waiting
/// for the other side to confirm as well.
Confirmed,
/// The verification process has been successfully concluded.
Done,
/// The verification process has been cancelled.
Cancelled {
/// Information about the reason of the cancellation.
cancel_info: CancelInfo,
},
}
impl From<RustSasState> for SasState {
fn from(s: RustSasState) -> Self {
match s {
RustSasState::Started { .. } => Self::Started,
RustSasState::Accepted { .. } => Self::Accepted,
RustSasState::KeysExchanged { emojis, decimals } => Self::KeysExchanged {
emojis: emojis.map(|e| e.indices.map(|i| i as i32).to_vec()),
decimals: [decimals.0.into(), decimals.1.into(), decimals.2.into()].to_vec(),
},
RustSasState::Confirmed => Self::Confirmed,
RustSasState::Done { .. } => Self::Done,
RustSasState::Cancelled(c) => Self::Cancelled { cancel_info: c.into() },
}
}
}
/// Enum representing the different verification flows we support.
#[derive(uniffi::Object)]
pub struct Verification {
pub(crate) inner: InnerVerification,
pub(crate) runtime: Handle,
}
#[uniffi::export]
impl Verification {
/// Try to represent the `Verification` as an `Sas` verification object,
/// returns `None` if the verification is not a `Sas` verification.
pub fn as_sas(&self) -> Option<Arc<Sas>> {
if let InnerVerification::SasV1(sas) = &self.inner {
Some(Sas { inner: sas.to_owned(), runtime: self.runtime.to_owned() }.into())
} else {
None
}
}
/// Try to represent the `Verification` as an `QrCode` verification object,
/// returns `None` if the verification is not a `QrCode` verification.
pub fn as_qr(&self) -> Option<Arc<QrCode>> {
if let InnerVerification::QrV1(qr) = &self.inner {
Some(QrCode { inner: qr.to_owned(), runtime: self.runtime.to_owned() }.into())
} else {
None
}
}
}
/// The `m.sas.v1` verification flow.
#[derive(uniffi::Object)]
pub struct Sas {
/// The other user that is participating in the verification flow
pub other_user_id: String,
/// The other user's device that is participating in the verification flow
pub other_device_id: String,
/// The unique ID of this verification flow, will be a random string for
/// to-device events or a event ID for in-room events.
pub flow_id: String,
/// The room ID where this verification is happening, will be `None` if the
/// verification is going through to-device messages
pub room_id: Option<String>,
/// Did we initiate the verification flow
pub we_started: bool,
/// Has the non-initiating side accepted the verification flow
pub has_been_accepted: bool,
/// Can the short auth string be presented
pub can_be_presented: bool,
/// Does the flow support the emoji representation of the short auth string
pub supports_emoji: bool,
/// Have we confirmed that the short auth strings match
pub have_we_confirmed: bool,
/// Has the verification completed successfully
pub is_done: bool,
/// Has the flow been cancelled
pub is_cancelled: bool,
/// Information about the cancellation of the flow, will be `None` if the
/// flow hasn't been cancelled
pub cancel_info: Option<CancelInfo>,
pub(crate) inner: InnerSas,
pub(crate) runtime: Handle,
}
#[uniffi::export]
impl Sas {
/// Get the user id of the other side.
pub fn other_user_id(&self) -> String {
self.inner.other_user_id().to_string()
}
/// Get the device ID of the other side.
pub fn other_device_id(&self) -> String {
self.inner.other_device_id().to_string()
}
/// Get the unique ID that identifies this SAS verification flow.
pub fn flow_id(&self) -> String {
self.inner.flow_id().as_str().to_owned()
}
/// Get the room id if the verification is happening inside a room.
pub fn room_id(&self) -> Option<String> {
self.inner.room_id().map(|r| r.to_string())
}
/// Is the SAS flow done.
pub fn is_done(&self) -> bool {
self.inner.is_done()
}
/// Did we initiate the verification flow.
pub fn we_started(&self) -> bool {
self.inner.we_started()
}
/// Accept that we're going forward with the short auth string verification.
pub fn accept(&self) -> Option<OutgoingVerificationRequest> {
self.inner.accept().map(|r| r.into())
}
/// Confirm a verification was successful.
///
/// This method should be called if a short auth string should be confirmed
/// as matching.
pub fn confirm(&self) -> Result<Option<ConfirmVerificationResult>, CryptoStoreError> {
let (requests, signature_request) = self.runtime.block_on(self.inner.confirm())?;
let requests = requests.into_iter().map(|r| r.into()).collect();
Ok(Some(ConfirmVerificationResult {
requests,
signature_request: signature_request.map(|s| s.into()),
}))
}
/// Cancel the SAS verification using the given cancel code.
///
/// # Arguments
///
/// * `cancel_code` - The error code for why the verification was cancelled,
/// manual cancellatio usually happens with `m.user` cancel code. The full
/// list of cancel codes can be found in the [spec]
///
/// [spec]: https://spec.matrix.org/unstable/client-server-api/#mkeyverificationcancel
pub fn cancel(&self, cancel_code: String) -> Option<OutgoingVerificationRequest> {
self.inner.cancel_with_code(cancel_code.into()).map(|r| r.into())
}
/// Get a list of emoji indices of the emoji representation of the short
/// auth string.
///
/// *Note*: A SAS verification needs to be started and in the presentable
/// state for this to return the list of emoji indices, otherwise returns
/// `None`.
pub fn get_emoji_indices(&self) -> Option<Vec<i32>> {
self.inner.emoji_index().map(|v| v.iter().map(|i| (*i).into()).collect())
}
/// Get the decimal representation of the short auth string.
///
/// *Note*: A SAS verification needs to be started and in the presentable
/// state for this to return the list of decimals, otherwise returns
/// `None`.
pub fn get_decimals(&self) -> Option<Vec<i32>> {
self.inner.decimals().map(|v| [v.0.into(), v.1.into(), v.2.into()].to_vec())
}
/// Set a listener for changes in the SAS verification process.
///
/// The given callback will be called whenever the state changes.
///
/// This method can be used to react to changes in the state of the
/// verification process, or rather the method can be used to handle
/// each step of the verification process.
///
/// This method will spawn a tokio task on the Rust side, once we reach the
/// Done or Cancelled state, the task will stop listening for changes.
///
/// # Flowchart
///
/// The flow of the verification process is pictured bellow. Please note
/// that the process can be cancelled at each step of the process.
/// Either side can cancel the process.
///
/// ```text
/// ┌───────┐
/// │Started│
/// └───┬───┘
/// │
/// ┌────⌄───┐
/// │Accepted│
/// └────┬───┘
/// │
/// ┌───────⌄──────┐
/// │Keys Exchanged│
/// └───────┬──────┘
/// │
/// ________⌄________
/// ╲ ┌─────────┐
/// Does the short ╲______│Cancelled│
/// ╲ auth string match no └─────────┘
/// ╲_________________
/// │yes
/// │
/// ┌────⌄────┐
/// │Confirmed│
/// └────┬────┘
/// │
/// ┌───⌄───┐
/// │ Done │
/// └───────┘
/// ```
pub fn set_changes_listener(&self, listener: Box<dyn SasListener>) {
let stream = self.inner.changes();
self.runtime.spawn(Self::changes_listener(stream, listener));
}
/// Get the current state of the SAS verification process.
pub fn state(&self) -> SasState {
self.inner.state().into()
}
}
impl Sas {
async fn changes_listener(
mut stream: impl Stream<Item = RustSasState> + std::marker::Unpin,
listener: Box<dyn SasListener>,
) {
while let Some(state) = stream.next().await {
// If we receive a done or a cancelled state we're at the end of our road, we
// break out of the loop to deallocate the stream and finish the
// task.
let should_break =
matches!(state, RustSasState::Done { .. } | RustSasState::Cancelled { .. });
listener.on_change(state.into());
if should_break {
break;
}
}
}
}
/// Listener that will be passed over the FFI to report changes to a QrCode
/// verification.
pub trait QrCodeListener: Send {
/// The callback that should be called on the Rust side
///
/// # Arguments
///
/// * `state` - The current state of the QrCode verification.
fn on_change(&self, state: QrCodeState);
}
/// An Enum describing the state the QrCode verification is in.
pub enum QrCodeState {
/// The QR verification has been started.
Started,
/// The QR verification has been scanned by the other side.
Scanned,
/// The scanning of the QR code has been confirmed by us.
Confirmed,
/// We have successfully scanned the QR code and are able to send a
/// reciprocation event.
Reciprocated,
/// The verification process has been successfully concluded.
Done,
/// The verification process has been cancelled.
Cancelled {
/// Information about the reason of the cancellation.
cancel_info: CancelInfo,
},
}
impl From<QrVerificationState> for QrCodeState {
fn from(value: QrVerificationState) -> Self {
match value {
QrVerificationState::Started => Self::Started,
QrVerificationState::Scanned => Self::Scanned,
QrVerificationState::Confirmed => Self::Confirmed,
QrVerificationState::Reciprocated => Self::Reciprocated,
QrVerificationState::Done { .. } => Self::Done,
QrVerificationState::Cancelled(c) => Self::Cancelled { cancel_info: c.into() },
}
}
}
/// The `m.qr_code.scan.v1`, `m.qr_code.show.v1`, and `m.reciprocate.v1`
/// verification flow.
#[derive(uniffi::Object)]
pub struct QrCode {
/// The other user that is participating in the verification flow
pub other_user_id: String,
/// The other user's device that is participating in the verification flow
pub other_device_id: String,
/// The unique ID of this verification flow, will be a random string for
/// to-device events or a event ID for in-room events.
pub flow_id: String,
/// The room ID where this verification is happening, will be `None` if the
/// verification is going through to-device messages
pub room_id: Option<String>,
/// Did we initiate the verification flow
pub we_started: bool,
/// Has the QR code been scanned by the other side
pub other_side_scanned: bool,
/// Has the scanning of the QR code been confirmed by us
pub has_been_confirmed: bool,
/// Did we scan the QR code and sent out a reciprocation
pub reciprocated: bool,
/// Has the verification completed successfully
pub is_done: bool,
/// Has the flow been cancelled
pub is_cancelled: bool,
/// Information about the cancellation of the flow, will be `None` if the
/// flow hasn't been cancelled
pub cancel_info: Option<CancelInfo>,
pub(crate) inner: InnerQr,
pub(crate) runtime: Handle,
}
impl From<InnerQr> for QrCode {
fn from(qr: InnerQr) -> Self {
Self {
other_user_id: qr.other_user_id().to_string(),
flow_id: qr.flow_id().as_str().to_owned(),
is_cancelled: qr.is_cancelled(),
is_done: qr.is_done(),
cancel_info: qr.cancel_info().map(|c| c.into()),
reciprocated: qr.reciprocated(),
we_started: qr.we_started(),
other_side_scanned: qr.has_been_scanned(),
has_been_confirmed: qr.has_been_confirmed(),
other_device_id: qr.other_device_id().to_string(),
room_id: qr.room_id().map(|r| r.to_string()),
#[uniffi::export]
impl QrCode {
/// Get the user id of the other side.
pub fn other_user_id(&self) -> String {
self.inner.other_user_id().to_string()
}
/// Get the device ID of the other side.
pub fn other_device_id(&self) -> String {
self.inner.other_device_id().to_string()
}
/// Get the unique ID that identifies this QR code verification flow.
pub fn flow_id(&self) -> String {
self.inner.flow_id().as_str().to_owned()
}
/// Get the room id if the verification is happening inside a room.
pub fn room_id(&self) -> Option<String> {
self.inner.room_id().map(|r| r.to_string())
}
/// Is the QR code verification done.
pub fn is_done(&self) -> bool {
self.inner.is_done()
}
/// Has the verification flow been cancelled.
pub fn is_cancelled(&self) -> bool {
self.inner.is_cancelled()
}
/// Did we initiate the verification flow.
pub fn we_started(&self) -> bool {
self.inner.we_started()
}
/// Get the CancelInfo of this QR code verification object.
///
/// Will be `None` if the flow has not been cancelled.
pub fn cancel_info(&self) -> Option<CancelInfo> {
self.inner.cancel_info().map(|c| c.into())
}
/// Has the QR verification been scanned by the other side.
///
/// When the verification object is in this state it's required that the
/// user confirms that the other side has scanned the QR code.
pub fn has_been_scanned(&self) -> bool {
self.inner.has_been_scanned()
}
/// Have we successfully scanned the QR code and are able to send a
/// reciprocation event.
pub fn reciprocated(&self) -> bool {
self.inner.reciprocated()
}
/// Cancel the QR code verification using the given cancel code.
///
/// # Arguments
///
/// * `cancel_code` - The error code for why the verification was cancelled,
/// manual cancellatio usually happens with `m.user` cancel code. The full
/// list of cancel codes can be found in the [spec]
///
/// [spec]: https://spec.matrix.org/unstable/client-server-api/#mkeyverificationcancel
pub fn cancel(&self, cancel_code: String) -> Option<OutgoingVerificationRequest> {
self.inner.cancel_with_code(cancel_code.into()).map(|r| r.into())
}
/// Confirm a verification was successful.
///
/// This method should be called if we want to confirm that the other side
/// has scanned our QR code.
pub fn confirm(&self) -> Option<ConfirmVerificationResult> {
self.inner.confirm_scanning().map(|r| ConfirmVerificationResult {
requests: vec![r.into()],
signature_request: None,
})
}
/// Generate data that should be encoded as a QR code.
///
/// This method should be called right before a QR code should be displayed,
/// the returned data is base64 encoded (without padding) and needs to be
/// decoded on the other side before it can be put through a QR code
/// generator.
pub fn generate_qr_code(&self) -> Option<String> {
self.inner.to_bytes().map(|data| STANDARD_NO_PAD.encode(data)).ok()
}
/// Set a listener for changes in the QrCode verification process.
///
/// The given callback will be called whenever the state changes.
pub fn set_changes_listener(&self, listener: Box<dyn QrCodeListener>) {
let stream = self.inner.changes();
self.runtime.spawn(Self::changes_listener(stream, listener));
}
/// Get the current state of the QrCode verification process.
pub fn state(&self) -> QrCodeState {
self.inner.state().into()
}
}
impl QrCode {
async fn changes_listener(
mut stream: impl Stream<Item = QrVerificationState> + std::marker::Unpin,
listener: Box<dyn QrCodeListener>,
) {
while let Some(state) = stream.next().await {
// If we receive a done or a cancelled state we're at the end of our road, we
// break out of the loop to deallocate the stream and finish the
// task.
let should_break = matches!(
state,
QrVerificationState::Done { .. } | QrVerificationState::Cancelled { .. }
);
listener.on_change(state.into());
if should_break {
break;
}
}
}
}
@@ -120,52 +478,37 @@ impl From<RustCancelInfo> for CancelInfo {
}
/// A result type for starting SAS verifications.
#[derive(uniffi::Record)]
pub struct StartSasResult {
/// The SAS verification object that got created.
pub sas: Sas,
pub sas: Arc<Sas>,
/// The request that needs to be sent out to notify the other side that a
/// SAS verification should start.
pub request: OutgoingVerificationRequest,
}
/// A result type for scanning QR codes.
#[derive(uniffi::Record)]
pub struct ScanResult {
/// The QR code verification object that got created.
pub qr: QrCode,
pub qr: Arc<QrCode>,
/// The request that needs to be sent out to notify the other side that a
/// QR code verification should start.
pub request: OutgoingVerificationRequest,
}
impl From<InnerSas> for Sas {
fn from(sas: InnerSas) -> Self {
Self {
other_user_id: sas.other_user_id().to_string(),
other_device_id: sas.other_device_id().to_string(),
flow_id: sas.flow_id().as_str().to_owned(),
is_cancelled: sas.is_cancelled(),
is_done: sas.is_done(),
can_be_presented: sas.can_be_presented(),
supports_emoji: sas.supports_emoji(),
have_we_confirmed: sas.have_we_confirmed(),
we_started: sas.we_started(),
room_id: sas.room_id().map(|r| r.to_string()),
has_been_accepted: sas.has_been_accepted(),
cancel_info: sas.cancel_info().map(|c| c.into()),
}
}
}
/// A result type for requesting verifications.
#[derive(uniffi::Record)]
pub struct RequestVerificationResult {
/// The verification request object that got created.
pub verification: VerificationRequest,
pub verification: Arc<VerificationRequest>,
/// The request that needs to be sent out to notify the other side that
/// we're requesting verification to begin.
pub request: OutgoingVerificationRequest,
}
/// A result type for confirming verifications.
#[derive(uniffi::Record)]
pub struct ConfirmVerificationResult {
/// The requests that needs to be sent out to notify the other side that we
/// confirmed the verification.
@@ -175,58 +518,286 @@ pub struct ConfirmVerificationResult {
pub signature_request: Option<SignatureUploadRequest>,
}
/// The verificatoin request object which then can transition into some concrete
/// verification method
pub struct VerificationRequest {
/// The other user that is participating in the verification flow
pub other_user_id: String,
/// The other user's device that is participating in the verification flow
pub other_device_id: Option<String>,
/// The unique ID of this verification flow, will be a random string for
/// to-device events or a event ID for in-room events.
pub flow_id: String,
/// The room ID where this verification is happening, will be `None` if the
/// verification is going through to-device messages
pub room_id: Option<String>,
/// Did we initiate the verification flow
pub we_started: bool,
/// Did both parties aggree to verification
pub is_ready: bool,
/// Did another device respond to the verification request
pub is_passive: bool,
/// Has the verification completed successfully
pub is_done: bool,
/// Has the flow been cancelled
pub is_cancelled: bool,
/// The list of verification methods that the other side advertised as
/// supported
pub their_methods: Option<Vec<String>>,
/// The list of verification methods that we advertised as supported
pub our_methods: Option<Vec<String>>,
/// Information about the cancellation of the flow, will be `None` if the
/// flow hasn't been cancelled
pub cancel_info: Option<CancelInfo>,
/// Listener that will be passed over the FFI to report changes to a
/// verification request.
pub trait VerificationRequestListener: Send {
/// The callback that should be called on the Rust side
///
/// # Arguments
///
/// * `state` - The current state of the verification request.
fn on_change(&self, state: VerificationRequestState);
}
impl From<InnerVerificationRequest> for VerificationRequest {
fn from(v: InnerVerificationRequest) -> Self {
Self {
other_user_id: v.other_user().to_string(),
other_device_id: v.other_device_id().map(|d| d.to_string()),
flow_id: v.flow_id().as_str().to_owned(),
is_cancelled: v.is_cancelled(),
is_done: v.is_done(),
is_ready: v.is_ready(),
room_id: v.room_id().map(|r| r.to_string()),
we_started: v.we_started(),
is_passive: v.is_passive(),
cancel_info: v.cancel_info().map(|c| c.into()),
their_methods: v
.their_supported_methods()
.map(|v| v.into_iter().map(|m| m.to_string()).collect()),
our_methods: v
.our_supported_methods()
.map(|v| v.into_iter().map(|m| m.to_string()).collect()),
/// An Enum describing the state the QrCode verification is in.
pub enum VerificationRequestState {
/// The verification request was sent
Requested,
/// The verification request is ready to start a verification flow.
Ready {
/// The verification methods supported by the other side.
their_methods: Vec<String>,
/// The verification methods supported by the us.
our_methods: Vec<String>,
},
/// The verification flow that was started with this request has finished.
Done,
/// The verification process has been cancelled.
Cancelled {
/// Information about the reason of the cancellation.
cancel_info: CancelInfo,
},
}
/// The verificatoin request object which then can transition into some concrete
/// verification method
#[derive(uniffi::Object)]
pub struct VerificationRequest {
pub(crate) inner: InnerVerificationRequest,
pub(crate) runtime: Handle,
}
#[uniffi::export]
impl VerificationRequest {
/// The id of the other user that is participating in this verification
/// request.
pub fn other_user_id(&self) -> String {
self.inner.other_user().to_string()
}
/// The id of the other device that is participating in this verification.
pub fn other_device_id(&self) -> Option<String> {
self.inner.other_device_id().map(|d| d.to_string())
}
/// Get the unique ID of this verification request
pub fn flow_id(&self) -> String {
self.inner.flow_id().as_str().to_owned()
}
/// Get the room id if the verification is happening inside a room.
pub fn room_id(&self) -> Option<String> {
self.inner.room_id().map(|r| r.to_string())
}
/// Has the verification flow that was started with this request finished.
pub fn is_done(&self) -> bool {
self.inner.is_done()
}
/// Is the verification request ready to start a verification flow.
pub fn is_ready(&self) -> bool {
self.inner.is_ready()
}
/// Did we initiate the verification request
pub fn we_started(&self) -> bool {
self.inner.we_started()
}
/// Has the verification request been answered by another device.
pub fn is_passive(&self) -> bool {
self.inner.is_passive()
}
/// Has the verification flow that been cancelled.
pub fn is_cancelled(&self) -> bool {
self.inner.is_cancelled()
}
/// Get info about the cancellation if the verification request has been
/// cancelled.
pub fn cancel_info(&self) -> Option<CancelInfo> {
self.inner.cancel_info().map(|v| v.into())
}
/// Get the supported verification methods of the other side.
///
/// Will be present only if the other side requested the verification or if
/// we're in the ready state.
pub fn their_supported_methods(&self) -> Option<Vec<String>> {
self.inner.their_supported_methods().map(|m| m.iter().map(|m| m.to_string()).collect())
}
/// Get our own supported verification methods that we advertised.
///
/// Will be present only we requested the verification or if we're in the
/// ready state.
pub fn our_supported_methods(&self) -> Option<Vec<String>> {
self.inner.our_supported_methods().map(|m| m.iter().map(|m| m.to_string()).collect())
}
/// Accept a verification requests that we share with the given user with
/// the given flow id.
///
/// This will move the verification request into the ready state.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to accept the
/// verification requests.
///
/// * `flow_id` - The ID that uniquely identifies the verification flow.
///
/// * `methods` - A list of verification methods that we want to advertise
/// as supported.
pub fn accept(&self, methods: Vec<String>) -> Option<OutgoingVerificationRequest> {
let methods = methods.into_iter().map(VerificationMethod::from).collect();
self.inner.accept_with_methods(methods).map(|r| r.into())
}
/// Cancel a verification for the given user with the given flow id using
/// the given cancel code.
pub fn cancel(&self) -> Option<OutgoingVerificationRequest> {
self.inner.cancel().map(|r| r.into())
}
/// Transition from a verification request into short auth string based
/// verification.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to start the
/// SAS verification.
///
/// * `flow_id` - The ID of the verification request that initiated the
/// verification flow.
pub fn start_sas_verification(&self) -> Result<Option<StartSasResult>, CryptoStoreError> {
Ok(self.runtime.block_on(self.inner.start_sas())?.map(|(sas, r)| StartSasResult {
sas: Arc::new(Sas { inner: sas, runtime: self.runtime.clone() }),
request: r.into(),
}))
}
/// Transition from a verification request into QR code verification.
///
/// This method should be called when one wants to display a QR code so the
/// other side can scan it and move the QR code verification forward.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to start the
/// QR code verification.
///
/// * `flow_id` - The ID of the verification request that initiated the
/// verification flow.
pub fn start_qr_verification(&self) -> Result<Option<Arc<QrCode>>, CryptoStoreError> {
Ok(self
.runtime
.block_on(self.inner.generate_qr_code())?
.map(|qr| QrCode { inner: qr, runtime: self.runtime.clone() }.into()))
}
/// Pass data from a scanned QR code to an active verification request and
/// transition into QR code verification.
///
/// This requires an active `VerificationRequest` to succeed, returns `None`
/// if no `VerificationRequest` is found or if the QR code data is invalid.
///
/// # Arguments
///
/// * `user_id` - The ID of the user for which we would like to start the
/// QR code verification.
///
/// * `flow_id` - The ID of the verification request that initiated the
/// verification flow.
///
/// * `data` - The data that was extracted from the scanned QR code as an
/// base64 encoded string, without padding.
pub fn scan_qr_code(&self, data: String) -> Option<ScanResult> {
let data = STANDARD_NO_PAD.decode(data).ok()?;
let data = QrVerificationData::from_bytes(data).ok()?;
if let Some(qr) = self.runtime.block_on(self.inner.scan_qr_code(data)).ok()? {
let request = qr.reciprocate()?;
Some(ScanResult {
qr: QrCode { inner: qr, runtime: self.runtime.clone() }.into(),
request: request.into(),
})
} else {
None
}
}
/// Set a listener for changes in the verification request
///
/// The given callback will be called whenever the state changes.
pub fn set_changes_listener(&self, listener: Box<dyn VerificationRequestListener>) {
let stream = self.inner.changes();
self.runtime.spawn(Self::changes_listener(self.inner.to_owned(), stream, listener));
}
/// Get the current state of the verification request.
pub fn state(&self) -> VerificationRequestState {
Self::convert_verification_request(&self.inner, self.inner.state())
}
}
impl VerificationRequest {
fn convert_verification_request(
request: &InnerVerificationRequest,
value: RustVerificationRequestState,
) -> VerificationRequestState {
match value {
// The clients do not need to distinguish `Created` and `Requested` state
RustVerificationRequestState::Created { .. } => VerificationRequestState::Requested,
RustVerificationRequestState::Requested { .. } => VerificationRequestState::Requested,
RustVerificationRequestState::Ready {
their_methods,
our_methods,
other_device_id: _,
} => VerificationRequestState::Ready {
their_methods: their_methods.iter().map(|m| m.to_string()).collect(),
our_methods: our_methods.iter().map(|m| m.to_string()).collect(),
},
RustVerificationRequestState::Done => VerificationRequestState::Done,
RustVerificationRequestState::Transitioned { .. } => {
let their_methods = request
.their_supported_methods()
.expect("The transitioned state should know the other side's methods")
.into_iter()
.map(|m| m.to_string())
.collect();
let our_methods = request
.our_supported_methods()
.expect("The transitioned state should know our own supported methods")
.iter()
.map(|m| m.to_string())
.collect();
VerificationRequestState::Ready { their_methods, our_methods }
}
RustVerificationRequestState::Cancelled(c) => {
VerificationRequestState::Cancelled { cancel_info: c.into() }
}
}
}
async fn changes_listener(
request: InnerVerificationRequest,
mut stream: impl Stream<Item = RustVerificationRequestState> + std::marker::Unpin,
listener: Box<dyn VerificationRequestListener>,
) {
while let Some(state) = stream.next().await {
// If we receive a done or a cancelled state we're at the end of our road, we
// break out of the loop to deallocate the stream and finish the
// task.
let should_break = matches!(
state,
RustVerificationRequestState::Done { .. }
| RustVerificationRequestState::Cancelled { .. }
);
let state = Self::convert_verification_request(&request, state);
listener.on_change(state);
if should_break {
break;
}
}
}
}
@@ -1,2 +1,6 @@
[bindings.kotlin]
package_name = "org.matrix.rustcomponents.sdk.crypto"
cdylib_name = "matrix_sdk_crypto_ffi"
[bindings.swift]
module_name = "MatrixSDKCrypto"
@@ -0,0 +1 @@
/pkg
@@ -0,0 +1,9 @@
// prettier configuration: the same as the conventions used throughout Matrix.org
// see: https://github.com/matrix-org/eslint-plugin-matrix-org/blob/main/.prettierrc.js
module.exports = {
printWidth: 120,
tabWidth: 4,
quoteProps: "consistent",
trailingComma: "all",
};
+2
View File
@@ -0,0 +1,2 @@
version-tag-prefix "matrix-sdk-crypto-js-"
version-git-message "matrix-sdk-crypto-js v%s"
@@ -0,0 +1,76 @@
# v0.1.2
## Changes in the Javascript bindings
- Add `Qr.state()` method to inspect the current state of QR code
verifications.
## Changes in the underlying Rust crate
- Fix handling of SAS verification start events once we have shown a QR code.
# v0.1.1
- Add `verify` method to `Device`.
# v0.1.0
## Changes in the Javascript bindings
- In `OlmMachine.getIdentity`, wait a limited time for any in-flight
device-list updates to complete.
- Add `VerificationRequest.timeRemainingMillis()`.
## Changes in the underlying Rust crate
- When rejecting a key-verification request over to-device messages, send the
`m.key.verification.cancel` to the device that made the request, rather
than broadcasting to all devices.
# v0.1.0-alpha.11
## Changes in the Javascript bindings
- Simplify the response type of `Sas.confirm()`.
- Add `VerificationRequest.registerChangesCallback()`,
`Sas.registerChangesCallback()`, and `Qr.registerChangesCallback()`.
- Add `VerificationRequest.phase()` and `VerificationRequest.getVerification()`.
## Changes in the underlying Rust crate
- Add support for the `hkdf-hmac-sha256.v2` SAS message authentication code.
- Ensure that the correct short authentication strings are used when accepting a
SAS verification with the `Sas::accept()` method.
# v0.1.0-alpha.10
- Add `masterKey`, `userSigningKey`, `selfSigningKey` to `UserIdentity` and `OwnUserIdentity`
# v0.1.0-alpha.9
- Extend `OlmDevice.markRequestAsSent` to accept responses to
`SigningKeysUploadRequest`s.
- Add a missing `const` for compatibility with ECMAScript Module compatibility
mode.
- Fix the body of `SignatureUploadRequest`s to match the spec.
- Add a constructor for `SigningKeysUploadRequest`.
# v0.1.0-alpha.8
- `importCrossSigningKeys`: change the parameters to be individual keys
rather than a `CrossSigningKeyExport` object.
- Make `unused_fallback_keys` optional in `Machine.receive_sync_changes`
# v0.1.0-alpha.7
- Add new accessors `Device.algorithms` and `Device.isSignedByOwner`
- In `OlmMachine.getUserDevices`, wait a limited time for any in-flight
device-list updates to complete.
# v0.1.0-alpha.6
- Add new accessor `InboundGroupSession.senderKey`.
- Add a new API, `OlmMachine.registerRoomKeyUpdatedCallback`, which
applications can use to listen for received room keys.
+29 -15
View File
@@ -8,13 +8,21 @@ keywords = ["matrix", "chat", "messaging", "ruma", "nio"]
license = "Apache-2.0"
readme = "README.md"
repository = "https://github.com/matrix-org/matrix-rust-sdk"
rust-version = "1.60"
rust-version = { workspace = true }
version = "0.1.0-alpha.0"
publish = false
[package.metadata.docs.rs]
rustdoc-args = ["--cfg", "docsrs"]
[package.metadata.wasm-pack.profile.profiling]
wasm-opt = false
[package.metadata.wasm-pack.profile.profiling.wasm-bindgen]
debug-js-glue = false
demangle-name-section = true
dwarf-debug-info = true
[package.metadata.wasm-pack.profile.release]
wasm-opt = ['-Oz']
@@ -27,19 +35,25 @@ qrcode = ["matrix-sdk-crypto/qrcode", "dep:matrix-sdk-qrcode"]
tracing = []
[dependencies]
matrix-sdk-common = { version = "0.6.0", path = "../../crates/matrix-sdk-common", features = ["js"] }
matrix-sdk-crypto = { version = "0.6.0", path = "../../crates/matrix-sdk-crypto", features = ["js"] }
matrix-sdk-indexeddb = { version = "0.2.0", path = "../../crates/matrix-sdk-indexeddb", features = ["experimental-nodejs"] }
matrix-sdk-qrcode = { version = "0.4.0", path = "../../crates/matrix-sdk-qrcode", optional = true }
ruma = { version = "0.7.0", features = ["client-api-c", "js", "rand", "unstable-msc2676", "unstable-msc2677"] }
vodozemac = { version = "0.3.0", features = ["js"] }
wasm-bindgen = "0.2.80"
wasm-bindgen-futures = "0.4.30"
js-sys = "0.3.49"
anyhow = { workspace = true }
console_error_panic_hook = "0.1.7"
serde_json = "1.0.79"
http = "0.2.6"
anyhow = "1.0.58"
tracing = { version = "0.1.35", default-features = false, features = ["attributes"] }
futures-util = "0.3.27"
http = { workspace = true }
js-sys = "0.3.49"
matrix-sdk-common = { version = "0.6.0", path = "../../crates/matrix-sdk-common", features = ["js"] }
matrix-sdk-indexeddb = { version = "0.2.0", path = "../../crates/matrix-sdk-indexeddb" }
matrix-sdk-qrcode = { version = "0.4.0", path = "../../crates/matrix-sdk-qrcode", optional = true }
ruma = { workspace = true, features = ["js", "rand"] }
serde_json = { workspace = true }
tracing = { workspace = true }
tracing-subscriber = { version = "0.3.14", default-features = false, features = ["registry", "std"] }
zeroize = "1.3.0"
vodozemac = { workspace = true, features = ["js"] }
wasm-bindgen = "0.2.83"
wasm-bindgen-futures = "0.4.33"
zeroize = { workspace = true }
[dependencies.matrix-sdk-crypto]
path = "../../crates/matrix-sdk-crypto"
version = "0.6.0"
default_features = false
features = ["js", "automatic-room-key-forwarding"]
+7 -9
View File
@@ -16,17 +16,17 @@ Encryption](https://en.wikipedia.org/wiki/End-to-end_encryption)) for
These WebAssembly bindings are written in [Rust]. To build them, you
need to install the Rust compiler, see [the Install Rust
Page](https://www.rust-lang.org/tools/install). Then, the workflow is
pretty classical by using [npm], see [the Downloading and installing
pretty classical by using [yarn](https://yarnpkg.com/), see [the Downloading and installing
Node.js and npm
Page](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm).
Page](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm) and [installing yarn](https://classic.yarnpkg.com/lang/en/docs/install).
Once the Rust compiler, Node.js and npm are installed, you can run the
Once the Rust compiler, Node.js and yarn are installed, you can run the
following commands:
```sh
$ npm install
$ npm run build
$ npm run test
$ yarn install
$ yarn build
$ yarn test
```
A `matrix_sdk_crypto.js`, `matrix_sdk_crypto.d.ts` and a
@@ -44,13 +44,11 @@ To generate the documentation locally, please run the following
command:
```sh
$ npm run doc
$ yarn doc
```
The documentation is generated in the `./docs` directory.
[WebAssembly]: https://webassembly.org/
[`matrix-sdk-crypto`]: https://github.com/matrix-org/matrix-rust-sdk/tree/main/crates/matrix-sdk-crypto
[`matrix-rust-sdk`]: https://github.com/matrix-org/matrix-rust-sdk
@@ -0,0 +1,13 @@
# Steps for releasing `matrix-sdk-crypto-js`
1. Create a new branch, named `release-matrix-sdk-crypto-js-<version>`.
2. Update `CHANGELOG.md`, if necessary.
3. Run `yarn version` to bump the version number and create a tag.
4. Push the branch, but not yet the tag.
5. Create a PR to approve the changes.
6. Once approved:
1. Update the git tag to the new head of the branch, if necessary.
2. Push the git tag; doing so triggers the github actions workflow which
builds and publishes to npm, and creates a draft GH release.
3. Merge the PR.
7. Update the release on github and publish.
-61
View File
@@ -1,61 +0,0 @@
# configuration file for git-cliff (0.1.0)
[changelog]
# changelog header
header = """
# Matrix SDK Crypto JavaScript Changelog\n
All notable changes to this project will be documented in this file.\n
"""
# template for the changelog body
# https://tera.netlify.app/docs/#introduction
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | filter(attribute="scope", value="crypto-js") | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits %}
- {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}\
{% endfor %}
{% endfor %}\n
"""
# remove the leading and trailing whitespace from the template
trim = true
# changelog footer
footer = """
"""
[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out the commits that are not conventional
filter_unconventional = true
# regex for preprocessing the commit messages
commit_preprocessors = [
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/matrix-org/matrix-rust-sdk/issues/${2}))"},
]
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^feat", group = "Features"},
{ message = "^fix", group = "Bug Fixes"},
{ message = "^test", group = "Testing"},
{ message = "^doc", group = "Documentation"},
{ message = "^refactor", group = "Refactoring"},
{ message = "^ci", group = "Continuous Integration"},
{ message = "^chore", group = "Miscellaneous Tasks"},
{ body = ".*security", group = "Security"},
]
# filter out the commits that are not matched by commit parsers
filter_commits = false
# glob pattern for matching git tags
tag_pattern = "v[0-9]*"
# regex for skipping tags
skip_tags = ""
# regex for ignoring tags
ignore_tags = ""
# sort the tags chronologically
date_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "oldest"
+13 -11
View File
@@ -1,6 +1,6 @@
{
"name": "@matrix-org/matrix-sdk-crypto-js",
"version": "0.1.0-alpha.0",
"version": "0.1.2",
"homepage": "https://github.com/matrix-org/matrix-rust-sdk",
"description": "Matrix encryption library, for JavaScript",
"license": "Apache-2.0",
@@ -18,18 +18,21 @@
"ruma",
"nio"
],
"main": "matrix_sdk_crypto.js",
"types": "pkg/matrix_sdk_crypto.d.ts",
"main": "pkg/matrix_sdk_crypto_js.js",
"types": "pkg/matrix_sdk_crypto_js.d.ts",
"files": [
"pkg/matrix_sdk_crypto_bg.wasm",
"pkg/matrix_sdk_crypto.js",
"pkg/matrix_sdk_crypto.d.ts"
"pkg/matrix_sdk_crypto_js_bg.wasm.js",
"pkg/matrix_sdk_crypto_js_bg.wasm.d.ts",
"pkg/matrix_sdk_crypto_js.js",
"pkg/matrix_sdk_crypto_js.d.ts"
],
"devDependencies": {
"cross-env": "^7.0.3",
"fake-indexeddb": "^4.0",
"jest": "^28.1.0",
"prettier": "^2.8.3",
"typedoc": "^0.22.17",
"typescript": "4.7",
"wasm-pack": "^0.10.2",
"yargs-parser": "~21.0.1"
},
@@ -37,12 +40,11 @@
"node": ">= 10"
},
"scripts": {
"build": "cross-env RUSTFLAGS='-C opt-level=z' wasm-pack build --release --target nodejs --scope matrix-org --out-dir ./pkg",
"lint": "prettier --check .",
"build": "WASM_PACK_ARGS=--release ./scripts/build.sh",
"build:dev": "WASM_PACK_ARGS=--dev ./scripts/build.sh",
"test": "jest --verbose",
"doc": "typedoc --tsconfig .",
"prepack": "npm run build && npm run test",
"pack": "wasm-pack pack",
"prepublish": "npm run pack",
"publish": "wasm-pack publish"
"prepack": "npm run build && npm run test"
}
}
+39
View File
@@ -0,0 +1,39 @@
#!/bin/bash
#
# Build the JavaScript modules
#
# This script is really a workaround for https://github.com/rustwasm/wasm-pack/issues/1074.
#
# Currently, the only reliable way to load WebAssembly in all the JS
# environments we want to target (web-via-webpack, web-via-browserify, jest)
# seems to be to pack the WASM into base64, and then unpack it and instantiate
# it at runtime.
#
# Hopefully one day, https://github.com/rustwasm/wasm-pack/issues/1074 will be
# fixed and this will be unnecessary.
set -e
cd $(dirname "$0")/..
RUSTFLAGS='-C opt-level=z' WASM_BINDGEN_WEAKREF=1 wasm-pack build --target nodejs --scope matrix-org --out-dir pkg "${WASM_PACK_ARGS[@]}"
# Convert the Wasm into a JS file that exports the base64'ed Wasm.
{
printf 'module.exports = `'
base64 < pkg/matrix_sdk_crypto_js_bg.wasm
printf '`;'
} > pkg/matrix_sdk_crypto_js_bg.wasm.js
# In the JavaScript:
# 1. Strip out the lines that load the WASM, and our new epilogue.
# 2. Remove the imports of `TextDecoder` and `TextEncoder`. We rely on the global defaults.
{
sed -e '/Text..coder.*= require(.util.)/d' \
-e '/^const path = /,$d' pkg/matrix_sdk_crypto_js.js
cat scripts/epilogue.js
} > pkg/matrix_sdk_crypto_js.js.new
mv pkg/matrix_sdk_crypto_js.js.new pkg/matrix_sdk_crypto_js.js
# also extend the typescript
cat scripts/epilogue.d.ts >> pkg/matrix_sdk_crypto_js.d.ts
+8
View File
@@ -0,0 +1,8 @@
/**
* Load the WebAssembly module in the background, if it has not already been loaded.
*
* Returns a promise which will resolve once the other methods are ready.
*
* @returns {Promise<void>}
*/
export function initAsync(): Promise<void>;
@@ -0,0 +1,88 @@
// Initially, 'wasm' is set to a Proxy object which will synchronously load the WebAssembly module and
// replace 'wasm' with a reference to the exports from the wasm module.
//
// Ideally this will never get used because the application will call initAsync instead.
wasm = new Proxy(
{},
{
get: (target, prop, receiver) => __initSync()[prop],
},
);
let inited = false;
const __initSync = function () {
if (inited) {
return;
}
if (initPromise) {
throw new Error("Asynchronous initialisation already in progress: cannot initialise synchronously");
}
const bytes = unbase64(require("./matrix_sdk_crypto_js_bg.wasm.js"));
const mod = new WebAssembly.Module(bytes);
const instance = new WebAssembly.Instance(mod, imports);
wasm = instance.exports;
wasm.__wbindgen_start();
inited = true;
return wasm;
};
let initPromise = null;
/**
* Load the WebAssembly module in the background, if it has not already been loaded.
*
* Returns a promise which will resolve once the other methods are ready.
*
* @returns {Promise<void>}
*/
module.exports.initAsync = function () {
if (inited) {
return Promise.resolve();
}
if (!initPromise) {
initPromise = Promise.resolve()
.then(() => require("./matrix_sdk_crypto_js_bg.wasm.js"))
.then((b64) => WebAssembly.instantiate(unbase64(b64), imports))
.then((result) => {
wasm = result.instance.exports;
wasm.__wbindgen_start();
inited = true;
});
}
return initPromise;
};
const b64lookup = new Uint8Array([
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 62, 0, 62, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29, 30, 31, 32,
33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
]);
// base64 decoder, based on the code at https://developer.mozilla.org/en-US/docs/Glossary/Base64#solution_2_%E2%80%93_rewriting_atob_and_btoa_using_typedarrays_and_utf-8
function unbase64(sBase64) {
const sB64Enc = sBase64.replace(/[^A-Za-z0-9+/]/g, "");
const nInLen = sB64Enc.length;
const nOutLen = (nInLen * 3 + 1) >> 2;
const taBytes = new Uint8Array(nOutLen);
let nMod3;
let nMod4;
let nUint24 = 0;
let nOutIdx = 0;
for (let nInIdx = 0; nInIdx < nInLen; nInIdx++) {
nMod4 = nInIdx & 3;
nUint24 |= b64lookup[sB64Enc.charCodeAt(nInIdx)] << (6 * (3 - nMod4));
if (nMod4 === 3 || nInLen - nInIdx === 1) {
nMod3 = 0;
while (nMod3 < 3 && nOutIdx < nOutLen) {
taBytes[nOutIdx] = (nUint24 >>> ((16 >>> nMod3) & 24)) & 255;
nMod3++;
nOutIdx++;
}
nUint24 = 0;
}
}
return taBytes;
}
@@ -41,13 +41,10 @@ impl Attachment {
/// destroyed. It is still possible to get a JSON-encoded backup
/// by calling `EncryptedAttachment.mediaEncryptionInfo`.
pub fn decrypt(attachment: &mut EncryptedAttachment) -> Result<Vec<u8>, JsError> {
let media_encryption_info = match attachment.media_encryption_info.take() {
Some(media_encryption_info) => media_encryption_info,
None => {
return Err(JsError::new(
"The media encryption info are absent from the given encrypted attachment",
))
}
let Some(media_encryption_info) = attachment.media_encryption_info.take() else {
return Err(JsError::new(
"The media encryption info are absent from the given encrypted attachment",
));
};
let encrypted_data: &[u8] = attachment.encrypted_data.as_slice();
+43 -1
View File
@@ -4,11 +4,12 @@ use js_sys::{Array, Map, Promise};
use wasm_bindgen::prelude::*;
use crate::{
encryption::EncryptionAlgorithm,
future::future_to_promise,
identifiers::{self, DeviceId, UserId},
impl_from_to_inner,
js::try_array_to_vec,
types, verification, vodozemac,
requests, types, verification, vodozemac,
};
/// A device represents a E2EE capable client of an user.
@@ -23,6 +24,9 @@ impl_from_to_inner!(matrix_sdk_crypto::Device => Device);
#[wasm_bindgen]
impl Device {
/// Request an interactive verification with this device.
///
/// Returns a Promise for a 2-element array `[VerificationRequest,
/// ToDeviceRequest]`.
#[wasm_bindgen(js_name = "requestVerification")]
pub fn request_verification(&self, methods: Option<Array>) -> Result<Promise, JsError> {
let methods =
@@ -63,6 +67,12 @@ impl Device {
self.inner.is_cross_signing_trusted()
}
/// Is this device cross-signed by its owner?
#[wasm_bindgen(js_name = "isCrossSignedByOwner")]
pub fn is_cross_signed_by_owner(&self) -> bool {
self.inner.is_cross_signed_by_owner()
}
/// Set the local trust state of the device to the given state.
///
/// This wont affect any cross signing trust state, this only
@@ -135,6 +145,19 @@ impl Device {
map
}
/// Get the list of algorithms this device supports.
///
/// Returns `Array<EncryptionAlgorithm>`.
#[wasm_bindgen(getter)]
pub fn algorithms(&self) -> Array {
self.inner
.algorithms()
.iter()
.map(|alg| EncryptionAlgorithm::from(alg.clone()))
.map(JsValue::from)
.collect()
}
/// Get a map containing all the device signatures.
#[wasm_bindgen(getter)]
pub fn signatures(&self) -> types::Signatures {
@@ -166,6 +189,25 @@ impl Device {
pub fn is_deleted(&self) -> bool {
self.inner.is_deleted()
}
/// Timestamp representing the first time this device has been seen (in
/// milliseconds).
#[wasm_bindgen(js_name = "firstTimeSeen")]
pub fn first_time_seen(&self) -> u64 {
self.inner.first_time_seen_ts().0.into()
}
/// Mark this device as verified.
/// Works only if the device is owned by the current user.
///
/// Returns a signature upload request that needs to be sent out.
pub fn verify(&self) -> Promise {
let device = self.inner.clone();
future_to_promise(async move {
Ok(requests::SignatureUploadRequest::try_from(&device.verify().await?)?)
})
}
}
/// The local trust state of a device.
+49 -17
View File
@@ -2,6 +2,7 @@
use std::time::Duration;
use matrix_sdk_common::deserialized_responses::ShieldState as RustShieldState;
use wasm_bindgen::prelude::*;
use crate::events;
@@ -85,6 +86,17 @@ pub enum EncryptionAlgorithm {
MegolmV1AesSha2,
}
impl From<EncryptionAlgorithm> for JsValue {
fn from(value: EncryptionAlgorithm) -> Self {
use EncryptionAlgorithm::*;
match value {
OlmV1Curve25519AesSha2 => JsValue::from(0),
MegolmV1AesSha2 => JsValue::from(1),
}
}
}
impl From<EncryptionAlgorithm> for matrix_sdk_crypto::types::EventEncryptionAlgorithm {
fn from(value: EncryptionAlgorithm) -> Self {
use EncryptionAlgorithm::*;
@@ -108,28 +120,48 @@ impl From<matrix_sdk_crypto::types::EventEncryptionAlgorithm> for EncryptionAlgo
}
}
/// The verification state of the device that sent an event to us.
/// Take a look at [`matrix_sdk_common::deserialized_responses::ShieldState`]
/// for more info.
#[wasm_bindgen]
#[derive(Debug)]
pub enum VerificationState {
/// The device is trusted.
Trusted,
/// The device is not trusted.
Untrusted,
/// The device is not known to us.
UnknownDevice,
#[derive(Debug, Clone, Copy)]
pub enum ShieldColor {
/// Important warning
Red,
/// Low warning
Grey,
/// No warning
None,
}
impl From<&matrix_sdk_common::deserialized_responses::VerificationState> for VerificationState {
fn from(value: &matrix_sdk_common::deserialized_responses::VerificationState) -> Self {
use matrix_sdk_common::deserialized_responses::VerificationState::*;
/// Take a look at [`matrix_sdk_common::deserialized_responses::ShieldState`]
/// for more info.
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub struct ShieldState {
/// The shield color
pub color: ShieldColor,
message: Option<String>,
}
#[wasm_bindgen]
impl ShieldState {
/// Error message that can be displayed as a tooltip
#[wasm_bindgen(getter)]
pub fn message(&self) -> Option<String> {
self.message.clone()
}
}
impl From<RustShieldState> for ShieldState {
fn from(value: RustShieldState) -> Self {
match value {
Trusted => Self::Trusted,
Untrusted => Self::Untrusted,
UnknownDevice => Self::UnknownDevice,
RustShieldState::Red { message } => {
Self { color: ShieldColor::Red, message: Some(message.to_owned()) }
}
RustShieldState::Grey { message } => {
Self { color: ShieldColor::Grey, message: Some(message.to_owned()) }
}
RustShieldState::None => Self { color: ShieldColor::None, message: None },
}
}
}
+4 -4
View File
@@ -1,7 +1,7 @@
use std::future::Future;
use js_sys::Promise;
use wasm_bindgen::{JsValue, UnwrapThrowExt};
use wasm_bindgen::{JsError, JsValue, UnwrapThrowExt};
use wasm_bindgen_futures::spawn_local;
pub(crate) fn future_to_promise<F, T>(future: F) -> Promise
@@ -17,9 +17,9 @@ where
spawn_local(async move {
match future.await {
Ok(value) => resolve.call1(&JsValue::UNDEFINED, &value.into()).unwrap_throw(),
Err(value) => {
reject.call1(&JsValue::UNDEFINED, &value.to_string().into()).unwrap_throw()
}
Err(value) => reject
.call1(&JsValue::UNDEFINED, &JsError::new(&value.to_string()).into())
.unwrap_throw(),
};
});
})
@@ -85,6 +85,28 @@ impl OwnUserIdentity {
future_to_promise(async move { Ok(me.trusts_our_own_device().await?) })
}
/// Get the master key of the identity.
#[wasm_bindgen(getter, js_name = "masterKey")]
pub fn master_key(&self) -> Result<String, JsError> {
let master_key = self.inner.master_key().as_ref();
Ok(serde_json::to_string(master_key)?)
}
/// Get the self-signing key of the identity.
#[wasm_bindgen(getter, js_name = "selfSigningKey")]
pub fn self_signing_key(&self) -> Result<String, JsError> {
let self_signing_key = self.inner.self_signing_key().as_ref();
Ok(serde_json::to_string(self_signing_key)?)
}
/// Get the user-signing key of the identity, this is only present for our
/// own user identity..
#[wasm_bindgen(getter, js_name = "userSigningKey")]
pub fn user_signing_key(&self) -> Result<String, JsError> {
let user_signing_key = self.inner.user_signing_key().as_ref();
Ok(serde_json::to_string(user_signing_key)?)
}
}
/// Struct representing a cross signing identity of a user.
@@ -130,7 +152,7 @@ impl UserIdentity {
}
/// Create a `VerificationRequest` object after the verification
/// request content has been sent out. }
/// request content has been sent out.
#[wasm_bindgen(js_name = "requestVerification")]
pub fn request_verification(
&self,
@@ -169,4 +191,18 @@ impl UserIdentity {
Ok(serde_json::to_string(&me.verification_request_content(methods).await)?)
}))
}
/// Get the master key of the identity.
#[wasm_bindgen(getter, js_name = "masterKey")]
pub fn master_key(&self) -> Result<String, JsError> {
let master_key = self.inner.master_key().as_ref();
Ok(serde_json::to_string(master_key)?)
}
/// Get the self-signing key of the identity.
#[wasm_bindgen(getter, js_name = "selfSigningKey")]
pub fn self_signing_key(&self) -> Result<String, JsError> {
let self_signing_key = self.inner.self_signing_key().as_ref();
Ok(serde_json::to_string(self_signing_key)?)
}
}
+24 -1
View File
@@ -15,7 +15,8 @@
#![doc = include_str!("../README.md")]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![warn(missing_docs, missing_debug_implementations)]
#![allow(clippy::drop_non_drop)] // triggered by wasm_bindgen code
// triggered by wasm_bindgen code
#![allow(clippy::drop_non_drop)]
pub mod attachment;
pub mod device;
@@ -37,8 +38,30 @@ pub mod types;
pub mod verification;
pub mod vodozemac;
use js_sys::JsString;
use wasm_bindgen::prelude::*;
/// Object containing the versions of the Rust libraries we are using.
#[wasm_bindgen(getter_with_clone)]
#[derive(Debug)]
pub struct Versions {
/// The version of the vodozemac crate.
#[wasm_bindgen(readonly)]
pub vodozemac: JsString,
/// The version of the matrix-sdk-crypto crate.
#[wasm_bindgen(readonly)]
pub matrix_sdk_crypto: JsString,
}
/// Get the versions of the Rust libraries we are using.
#[wasm_bindgen(js_name = "getVersions")]
pub fn get_versions() -> Versions {
Versions {
vodozemac: matrix_sdk_crypto::vodozemac::VERSION.into(),
matrix_sdk_crypto: matrix_sdk_crypto::VERSION.into(),
}
}
/// Run some stuff when the Wasm module is instantiated.
///
/// Right now, it does the following:
+227 -88
View File
@@ -1,11 +1,14 @@
//! The crypto specific Olm objects.
use std::collections::BTreeMap;
use std::{collections::BTreeMap, ops::Deref, time::Duration};
use futures_util::StreamExt;
use js_sys::{Array, Function, Map, Promise, Set};
use ruma::{serde::Raw, DeviceKeyAlgorithm, OwnedTransactionId, UInt};
use serde_json::{json, Value as JsonValue};
use tracing::warn;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::{spawn_local, JsFuture};
use crate::{
device, encryption,
@@ -13,9 +16,11 @@ use crate::{
identifiers, identities,
js::downcast,
olm, requests,
requests::OutgoingRequest,
requests::{OutgoingRequest, ToDeviceRequest},
responses::{self, response_from_string},
store, sync_events, types, verification, vodozemac,
store,
store::RoomKeyInfo,
sync_events, types, verification, vodozemac,
};
/// State machine implementation of the Olm/Megolm encryption protocol
@@ -28,25 +33,38 @@ pub struct OlmMachine {
#[wasm_bindgen]
impl OlmMachine {
/// Create a new memory based `OlmMachine`.
/// Constructor will always fail. To create a new `OlmMachine`, please use
/// the `initialize` method.
///
/// The created machine will keep the encryption keys only in
/// memory and once the objects is dropped, the keys will be lost.
/// Why this pattern? `initialize` returns a `Promise`. Returning a
// `Promise` from a constructor is not idiomatic in JavaScript.
#[wasm_bindgen(constructor)]
pub fn new() -> Result<OlmMachine, JsError> {
Err(JsError::new("To build an `OlmMachine`, please use the `initialize` method"))
}
/// Create a new `OlmMachine`.
///
/// `user_id` represents the unique ID of the user that owns this
/// machine. `device_id` represents the unique ID of the device
/// The created machine will keep the encryption keys either in a IndexedDB
/// based store, or in a memory store and once the objects is dropped,
/// the keys will be lost.
///
/// # Arguments
///
/// * `user_id` - represents the unique ID of the user that owns this
/// machine.
///
/// * `device_id` - represents the unique ID of the device
/// that owns this machine.
///
/// `store_name` and `store_passphrase` are both optional, but
/// must be both set to have an effect. If they are both set, the
/// state of the machine will persist in a database named
/// `store_name` where its content is encrypted by the passphrase
/// given by `store_passphrase`. If they are not both set, the
/// created machine will keep the encryption keys only in memory,
/// and once the object is dropped, the keys will be lost.
#[wasm_bindgen(constructor)]
#[allow(clippy::new_ret_no_self)]
pub fn new(
/// * `store_name` - The name that should be used to open the IndexedDB
/// based database. If this isn't provided, a memory-only store will be
/// used. *Note* the memory-only store will lose your E2EE keys when the
/// `OlmMachine` gets dropped.
///
/// * `store_passphrase` - The passphrase that should be used to encrypt the
/// IndexedDB based
pub fn initialize(
user_id: &identifiers::UserId,
device_id: &identifiers::DeviceId,
store_name: Option<String>,
@@ -57,15 +75,7 @@ impl OlmMachine {
future_to_promise(async move {
let store = match (store_name, store_passphrase) {
// We need this `#[cfg]` because `IndexeddbCryptoStore`
// implements `CryptoStore` only on `target_arch =
// "wasm32"`. Without that, we could have a compilation
// error when checking the entire workspace. In
// practise, it doesn't impact this crate because it's
// always compiled for `wasm32`.
#[cfg(target_arch = "wasm32")]
(Some(store_name), Some(mut store_passphrase)) => {
use std::sync::Arc;
use zeroize::Zeroize;
let store = Some(
@@ -73,8 +83,7 @@ impl OlmMachine {
&store_name,
&store_passphrase,
)
.await
.map(Arc::new)?,
.await?,
);
store_passphrase.zeroize();
@@ -82,15 +91,29 @@ impl OlmMachine {
store
}
(Some(_), None) => return Err(anyhow::Error::msg("The `store_name` has been set, and so, it expects a `store_passphrase`, which is not set; please provide one")),
(Some(store_name), None) => Some(
matrix_sdk_indexeddb::IndexeddbCryptoStore::open_with_name(&store_name).await?,
),
(None, Some(_)) => return Err(anyhow::Error::msg("The `store_passphrase` has been set, but it has an effect only if `store_name` is set, which is not; please provide one")),
(None, Some(_)) => {
return Err(anyhow::Error::msg(
"The `store_passphrase` has been set, but it has an effect only if \
`store_name` is set, which is not; please provide one",
))
}
_ => None,
(None, None) => None,
};
Ok(OlmMachine {
inner: match store {
// We need this `#[cfg]` because `IndexeddbCryptoStore`
// implements `CryptoStore` only on `target_arch =
// "wasm32"`. Without that, we could have a compilation
// error when checking the entire workspace. In practice,
// it doesn't impact this crate because it's always
// compiled for `wasm32`.
#[cfg(target_arch = "wasm32")]
Some(store) => {
matrix_sdk_crypto::OlmMachine::with_store(
user_id.as_ref(),
@@ -99,7 +122,7 @@ impl OlmMachine {
)
.await?
}
None => {
_ => {
matrix_sdk_crypto::OlmMachine::new(user_id.as_ref(), device_id.as_ref())
.await
}
@@ -134,30 +157,42 @@ impl OlmMachine {
future_to_promise(async move { Ok(me.display_name().await?) })
}
/// Get all the tracked users of our own device.
/// Get the list of users whose devices we are currently tracking.
///
/// A user can be marked for tracking using the
/// [`update_tracked_users`](#method.update_tracked_users) method.
///
/// Returns a `Set<UserId>`.
#[wasm_bindgen(js_name = "trackedUsers")]
pub fn tracked_users(&self) -> Set {
pub fn tracked_users(&self) -> Result<Promise, JsError> {
let set = Set::new(&JsValue::UNDEFINED);
let me = self.inner.clone();
for user in self.inner.tracked_users() {
set.add(&identifiers::UserId::from(user).into());
}
set
Ok(future_to_promise(async move {
for user in me.tracked_users().await? {
set.add(&identifiers::UserId::from(user).into());
}
Ok(set)
}))
}
/// Update the tracked users.
/// Update the list of tracked users.
///
/// `users` is an iterator over user IDs that should be marked for
/// tracking.
/// The OlmMachine maintains a list of users whose devices we are keeping
/// track of: these are known as "tracked users". These must be users
/// that we share a room with, so that the server sends us updates for
/// their device lists.
///
/// This will mark users that weren't seen before for a key query
/// and tracking.
/// # Arguments
///
/// If the user is already known to the Olm machine, it will not
/// be considered for a key query.
/// * `users` - An array of user ids that should be added to the list of
/// tracked users
///
/// Any users that hadn't been seen before will be flagged for a key query
/// immediately, and whenever `receive_sync_changes` receives a
/// "changed" notification for that user in the future.
///
/// Users that were already in the list are unaffected.
#[wasm_bindgen(js_name = "updateTrackedUsers")]
pub fn update_tracked_users(&self, users: &Array) -> Result<Promise, JsError> {
let users = users
@@ -168,7 +203,7 @@ impl OlmMachine {
let me = self.inner.clone();
Ok(future_to_promise(async move {
me.update_tracked_users(users.iter().map(AsRef::as_ref)).await;
me.update_tracked_users(users.iter().map(AsRef::as_ref)).await?;
Ok(JsValue::UNDEFINED)
}))
}
@@ -187,7 +222,7 @@ impl OlmMachine {
to_device_events: &str,
changed_devices: &sync_events::DeviceLists,
one_time_key_counts: &Map,
unused_fallback_keys: &Set,
unused_fallback_keys: Option<Set>,
) -> Result<Promise, JsError> {
let to_device_events = serde_json::from_str(to_device_events)?;
let changed_devices = changed_devices.inner.clone();
@@ -204,13 +239,18 @@ impl OlmMachine {
Some((key, value))
})
.collect();
let unused_fallback_keys: Option<Vec<DeviceKeyAlgorithm>> = Some(
unused_fallback_keys
.values()
.into_iter()
.filter_map(|js_value| Some(DeviceKeyAlgorithm::from(js_value.ok()?.as_string()?)))
.collect(),
);
// Convert the unused_fallback_keys JS Set to a `Vec<DeviceKeyAlgorithm>`
let unused_fallback_keys: Option<Vec<DeviceKeyAlgorithm>> =
unused_fallback_keys.map(|fallback_keys| {
fallback_keys
.values()
.into_iter()
.filter_map(|js_value| {
Some(DeviceKeyAlgorithm::from(js_value.ok()?.as_string()?))
})
.collect()
});
let me = self.inner.clone();
@@ -357,28 +397,38 @@ impl OlmMachine {
/// Export all the private cross signing keys we have.
///
/// The export will contain the seed for the ed25519 keys as a
/// unpadded base64 encoded string.
/// The export will contain the seeds for the ed25519 keys as
/// unpadded base64 encoded strings.
///
/// This method returns None if we dont have any private cross
/// signing keys.
/// Returns `null` if we dont have any private cross signing keys;
/// otherwise returns a `CrossSigningKeyExport`.
#[wasm_bindgen(js_name = "exportCrossSigningKeys")]
pub fn export_cross_signing_keys(&self) -> Promise {
let me = self.inner.clone();
future_to_promise(async move {
Ok(me.export_cross_signing_keys().await.map(store::CrossSigningKeyExport::from))
Ok(me.export_cross_signing_keys().await?.map(store::CrossSigningKeyExport::from))
})
}
/// Import our private cross signing keys.
///
/// The export needs to contain the seed for the ed25519 keys as
/// an unpadded base64 encoded string.
/// The keys should be provided as unpadded-base64-encoded strings.
///
/// Returns a `CrossSigningStatus`.
#[wasm_bindgen(js_name = "importCrossSigningKeys")]
pub fn import_cross_signing_keys(&self, export: store::CrossSigningKeyExport) -> Promise {
pub fn import_cross_signing_keys(
&self,
master_key: Option<String>,
self_signing_key: Option<String>,
user_signing_key: Option<String>,
) -> Promise {
let me = self.inner.clone();
let export = export.inner;
let export = matrix_sdk_crypto::store::CrossSigningKeyExport {
master_key,
self_signing_key,
user_signing_key,
};
future_to_promise(async move {
Ok(me.import_cross_signing_keys(export).await.map(olm::CrossSigningStatus::from)?)
@@ -393,6 +443,8 @@ impl OlmMachine {
/// between all the devices.
///
/// Uploading these keys will require user interactive auth.
///
/// Returns an `Array` of `OutgoingRequest`s
#[wasm_bindgen(js_name = "bootstrapCrossSigning")]
pub fn bootstrap_cross_signing(&self, reset: bool) -> Promise {
let me = self.inner.clone();
@@ -416,13 +468,21 @@ impl OlmMachine {
}
/// Get the cross signing user identity of a user.
///
/// Returns a promise for an `OwnUserIdentity`, a `UserIdentity`, or
/// `undefined`.
#[wasm_bindgen(js_name = "getIdentity")]
pub fn get_identity(&self, user_id: &identifiers::UserId) -> Promise {
let me = self.inner.clone();
let user_id = user_id.inner.clone();
future_to_promise(async move {
Ok(me.get_identity(user_id.as_ref(), None).await?.map(identities::UserIdentities::from))
// wait for up to a second for any in-flight device list requests to complete.
// The reason for this isn't so much to avoid races, but to make testing easier.
Ok(me
.get_identity(user_id.as_ref(), Some(Duration::from_secs(1)))
.await?
.map(identities::UserIdentities::from))
})
}
@@ -452,6 +512,8 @@ impl OlmMachine {
/// `room_id` is the room ID. `users` is an array of `UserId`
/// objects. `encryption_settings` are an `EncryptionSettings`
/// object.
///
/// Returns an array of `ToDeviceRequest`s.
#[wasm_bindgen(js_name = "shareRoomKey")]
pub fn share_room_key(
&self,
@@ -470,20 +532,27 @@ impl OlmMachine {
let me = self.inner.clone();
Ok(future_to_promise(async move {
Ok(serde_json::to_string(
&me.share_room_key(&room_id, users.iter().map(AsRef::as_ref), encryption_settings)
.await?,
)?)
let to_device_requests = me
.share_room_key(&room_id, users.iter().map(AsRef::as_ref), encryption_settings)
.await?;
// convert each request to our own ToDeviceRequest struct, and then wrap it in a
// JsValue.
//
// Then collect the results into a javascript Array, throwing any errors into
// the promise.
Ok(to_device_requests
.into_iter()
.map(|td| ToDeviceRequest::try_from(td.deref()).map(JsValue::from))
.collect::<Result<Array, _>>()?)
}))
}
/// Get the a key claiming request for the user/device pairs that
/// we are missing Olm sessions for.
///
/// Returns `NULL` if no key claiming request needs to be sent
/// out, otherwise it returns an `Array` where the first key is
/// the transaction ID as a string, and the second key is the keys
/// claim request serialized to JSON.
/// Returns `null` if no key claiming request needs to be sent
/// out, otherwise it returns a `KeysClaimRequest` object.
///
/// Sessions need to be established between devices so group
/// sessions for a room can be shared with them.
@@ -538,7 +607,10 @@ impl OlmMachine {
let me = self.inner.clone();
future_to_promise::<_, device::UserDevices>(async move {
Ok(me.get_user_devices(&user_id, None).await.map(Into::into)?)
// wait for up to a second for any in-flight device list requests to complete.
// The reason for this isn't so much to avoid races (some level of raciness is
// inevitable for this method) but to make testing easier.
Ok(me.get_user_devices(&user_id, Some(Duration::from_secs(1))).await.map(Into::into)?)
})
}
@@ -606,24 +678,24 @@ impl OlmMachine {
.collect()
}
/// Receive an unencrypted verification event.
/// Receive a verification event.
///
/// This method can be used to pass verification events that are
/// happening in unencrypted rooms to the `OlmMachine`.
///
/// Note: This does not need to be called for encrypted events
/// since those will get passed to the `OlmMachine` during
/// decryption.
#[wasm_bindgen(js_name = "receiveUnencryptedVerificationEvent")]
pub fn receive_unencrypted_verification_event(&self, event: &str) -> Result<Promise, JsError> {
let event: ruma::events::AnyMessageLikeEvent = serde_json::from_str(event)?;
/// This method can be used to pass verification events that are happening
/// in rooms to the `OlmMachine`. The event should be in the decrypted form.
#[wasm_bindgen(js_name = "receiveVerificationEvent")]
pub fn receive_verification_event(
&self,
event: &str,
room_id: &identifiers::RoomId,
) -> Result<Promise, JsError> {
let room_id = room_id.inner.clone();
let event: ruma::events::AnySyncMessageLikeEvent = serde_json::from_str(event)?;
let event = event.into_full_event(room_id);
let me = self.inner.clone();
Ok(future_to_promise(async move {
Ok(me
.receive_unencrypted_verification_event(&event)
.await
.map(|_| JsValue::UNDEFINED)?)
Ok(me.receive_verification_event(&event).await.map(|_| JsValue::UNDEFINED)?)
}))
}
@@ -728,4 +800,71 @@ impl OlmMachine {
passphrase,
)?)?)
}
/// Register a callback which will be called whenever there is an update to
/// a room key.
///
/// `callback` should be a function that takes a single argument (an array
/// of {@link RoomKeyInfo}) and returns a Promise.
#[wasm_bindgen(js_name = "registerRoomKeyUpdatedCallback")]
pub async fn register_room_key_updated_callback(&self, callback: Function) {
let stream = self.inner.store().room_keys_received_stream();
// fire up a promise chain which will call `cb` on each result from the stream
spawn_local(async move {
// take a reference to `callback` (which we then pass into the closure), to stop
// the callback being moved into the closure (which would mean we could only
// call the closure once)
let callback_ref = &callback;
stream.for_each(move |item| send_room_key_info_to_callback(callback_ref, item)).await;
});
}
/// Shut down the `OlmMachine`.
///
/// The `OlmMachine` cannot be used after this method has been called.
///
/// All associated resources will be closed too, like IndexedDB
/// connections.
pub fn close(self) {}
}
// helper for register_room_key_received_callback: wraps the key info
// into our own RoomKeyInfo struct, and passes it into the javascript
// function
async fn send_room_key_info_to_callback(
callback: &Function,
room_key_info: Vec<matrix_sdk_crypto::store::RoomKeyInfo>,
) {
let rki: Array = room_key_info.into_iter().map(RoomKeyInfo::from).map(JsValue::from).collect();
match promise_result_to_future(callback.call1(&JsValue::NULL, &rki)).await {
Ok(_) => (),
Err(e) => {
warn!("Error calling room-key-received callback: {:?}", e);
}
}
}
/// Given a result from a javascript function which returns a Promise (or throws
/// an exception before returning one), convert the result to a rust Future
/// which completes with the result of the promise
pub(crate) async fn promise_result_to_future(
res: Result<JsValue, JsValue>,
) -> Result<JsValue, JsValue> {
match res {
Ok(retval) => {
if !retval.has_type::<Promise>() {
panic!("not a promise");
}
let prom: Promise = retval.dyn_into().map_err(|v| {
JsError::new(&format!("function returned a non-Promise value {v:?}"))
})?;
JsFuture::from(prom).await
}
Err(e) => {
// the function threw an exception before it returned the promise. We can just
// return the error as an error result.
Err(e)
}
}
}
+8 -1
View File
@@ -2,7 +2,7 @@
use wasm_bindgen::prelude::*;
use crate::{identifiers, impl_from_to_inner};
use crate::{identifiers, impl_from_to_inner, vodozemac::Curve25519PublicKey};
/// Struct representing the state of our private cross signing keys,
/// it shows which private cross signing keys we have locally stored.
@@ -57,6 +57,13 @@ impl InboundGroupSession {
self.inner.room_id().to_owned().into()
}
/// The Curve25519 key of the sender of this session, as a
/// [Curve25519PublicKey].
#[wasm_bindgen(getter, js_name = "senderKey")]
pub fn sender_key(&self) -> Curve25519PublicKey {
self.inner.sender_key().into()
}
/// Returns the unique identifier for this session.
#[wasm_bindgen(getter, js_name = "sessionId")]
pub fn session_id(&self) -> String {
+176 -92
View File
@@ -11,10 +11,13 @@ use matrix_sdk_crypto::{
},
OutgoingRequests,
};
use ruma::api::client::keys::{
claim_keys::v3::Request as OriginalKeysClaimRequest,
upload_keys::v3::Request as OriginalKeysUploadRequest,
upload_signatures::v3::Request as OriginalSignatureUploadRequest,
use ruma::{
api::client::keys::{
claim_keys::v3::Request as OriginalKeysClaimRequest,
upload_keys::v3::Request as OriginalKeysUploadRequest,
upload_signatures::v3::Request as OriginalSignatureUploadRequest,
},
events::EventContent,
};
use wasm_bindgen::prelude::*;
@@ -33,11 +36,10 @@ pub struct KeysUploadRequest {
#[wasm_bindgen(readonly)]
pub id: Option<JsString>,
/// A JSON-encoded object of form:
/// A JSON-encoded string containing the rest of the payload: `device_keys`,
/// `one_time_keys`, `fallback_keys`.
///
/// ```json
/// {"device_keys": …, "one_time_keys": …, "fallback_keys": …}
/// ```
/// It represents the body of the HTTP request.
#[wasm_bindgen(readonly)]
pub body: JsString,
}
@@ -70,11 +72,10 @@ pub struct KeysQueryRequest {
#[wasm_bindgen(readonly)]
pub id: Option<JsString>,
/// A JSON-encoded object of form:
/// A JSON-encoded string containing the rest of the payload: `timeout`,
/// `device_keys`, `token`.
///
/// ```json
/// {"timeout": …, "device_keys": …, "token": …}
/// ```
/// It represents the body of the HTTP request.
#[wasm_bindgen(readonly)]
pub body: JsString,
}
@@ -108,11 +109,10 @@ pub struct KeysClaimRequest {
#[wasm_bindgen(readonly)]
pub id: Option<JsString>,
/// A JSON-encoded object of form:
/// A JSON-encoded string containing the rest of the payload: `timeout`,
/// `one_time_keys`.
///
/// ```json
/// {"timeout": …, "one_time_keys": …}
/// ```
/// It represents the body of the HTTP request.
#[wasm_bindgen(readonly)]
pub body: JsString,
}
@@ -145,11 +145,18 @@ pub struct ToDeviceRequest {
#[wasm_bindgen(readonly)]
pub id: Option<JsString>,
/// A JSON-encoded object of form:
/// A string representing the type of event being sent to each devices.
#[wasm_bindgen(readonly)]
pub event_type: JsString,
/// A string representing a request identifier unique to the access token
/// used to send the request.
#[wasm_bindgen(readonly)]
pub txn_id: JsString,
/// A JSON-encoded string containing the rest of the payload: `messages`.
///
/// ```json
/// {"event_type": …, "txn_id": …, "messages": …}
/// ```
/// It represents the body of the HTTP request.
#[wasm_bindgen(readonly)]
pub body: JsString,
}
@@ -158,8 +165,13 @@ pub struct ToDeviceRequest {
impl ToDeviceRequest {
/// Create a new `ToDeviceRequest`.
#[wasm_bindgen(constructor)]
pub fn new(id: JsString, body: JsString) -> ToDeviceRequest {
Self { id: Some(id), body }
pub fn new(
id: JsString,
event_type: JsString,
txn_id: JsString,
body: JsString,
) -> ToDeviceRequest {
Self { id: Some(id), event_type, txn_id, body }
}
/// Get its request type.
@@ -182,21 +194,19 @@ pub struct SignatureUploadRequest {
#[wasm_bindgen(readonly)]
pub id: Option<JsString>,
/// A JSON-encoded object of form:
/// A JSON-encoded string containing the payload of the request
///
/// ```json
/// {"signed_keys": …, "txn_id": …, "messages": …}
/// ```
#[wasm_bindgen(readonly)]
pub body: JsString,
/// It represents the body of the HTTP request.
#[wasm_bindgen(readonly, js_name = "body")]
pub signed_keys: JsString,
}
#[wasm_bindgen]
impl SignatureUploadRequest {
/// Create a new `SignatureUploadRequest`.
#[wasm_bindgen(constructor)]
pub fn new(id: JsString, body: JsString) -> SignatureUploadRequest {
Self { id: Some(id), body }
pub fn new(id: JsString, signed_keys: JsString) -> SignatureUploadRequest {
Self { id: Some(id), signed_keys }
}
/// Get its request type.
@@ -217,21 +227,39 @@ pub struct RoomMessageRequest {
#[wasm_bindgen(readonly)]
pub id: Option<JsString>,
/// A JSON-encoded object of form:
///
/// ```json
/// {"room_id": …, "txn_id": …, "content": …}
/// ```
/// A string representing the room to send the event to.
#[wasm_bindgen(readonly)]
pub body: JsString,
pub room_id: JsString,
/// A string representing the transaction ID for this event.
///
/// Clients should generate an ID unique across requests with the same
/// access token; it will be used by the server to ensure idempotency of
/// requests.
#[wasm_bindgen(readonly)]
pub txn_id: JsString,
/// A string representing the type of event to be sent.
#[wasm_bindgen(readonly)]
pub event_type: JsString,
/// A JSON-encoded string containing the message's content.
#[wasm_bindgen(readonly, js_name = "body")]
pub content: JsString,
}
#[wasm_bindgen]
impl RoomMessageRequest {
/// Create a new `RoomMessageRequest`.
#[wasm_bindgen(constructor)]
pub fn new(id: JsString, body: JsString) -> RoomMessageRequest {
Self { id: Some(id), body }
pub fn new(
id: JsString,
room_id: JsString,
txn_id: JsString,
event_type: JsString,
content: JsString,
) -> RoomMessageRequest {
Self { id: Some(id), room_id, txn_id, event_type, content }
}
/// Get its request type.
@@ -252,32 +280,9 @@ pub struct KeysBackupRequest {
#[wasm_bindgen(readonly)]
pub id: Option<JsString>,
/// A JSON-encoded object of form:
/// A JSON-encoded string containing the rest of the payload: `rooms`.
///
/// ```json
/// {"rooms": …}
/// ```
#[wasm_bindgen(readonly)]
pub body: JsString,
}
/** Other Requests * */
/// Request that will publish a cross signing identity.
///
/// This uploads the public cross signing key triplet.
#[wasm_bindgen(getter_with_clone)]
#[derive(Debug)]
pub struct SigningKeysUploadRequest {
/// The request ID.
#[wasm_bindgen(readonly)]
pub id: Option<JsString>,
/// A JSON-encoded object of form:
///
/// ```json
/// {"master_key": …, "self_signing_key": …, "user_signing_key": …}
/// ```
/// It represents the body of the HTTP request.
#[wasm_bindgen(readonly)]
pub body: JsString,
}
@@ -297,28 +302,57 @@ impl KeysBackupRequest {
}
}
/** Other Requests * */
/// Request that will publish a cross signing identity.
///
/// This uploads the public cross signing key triplet.
#[wasm_bindgen(getter_with_clone)]
#[derive(Debug)]
pub struct SigningKeysUploadRequest {
/// The request ID.
#[wasm_bindgen(readonly)]
pub id: Option<JsString>,
/// A JSON-encoded string containing the rest of the payload: `master_key`,
/// `self_signing_key`, `user_signing_key`.
///
/// It represents the body of the HTTP request.
#[wasm_bindgen(readonly)]
pub body: JsString,
}
#[wasm_bindgen]
impl SigningKeysUploadRequest {
/// Create a new `SigningKeysUploadRequest`.
#[wasm_bindgen(constructor)]
pub fn new(id: JsString, body: JsString) -> SigningKeysUploadRequest {
Self { id: Some(id), body }
}
/// Get its request type.
#[wasm_bindgen(getter, js_name = "type")]
pub fn request_type(&self) -> RequestType {
RequestType::SigningKeysUpload
}
}
macro_rules! request {
($destination_request:ident from $source_request:ident maps fields $( $field:ident ),+ $(,)? ) => {
impl $destination_request {
pub(crate) fn to_json(request: &$source_request) -> Result<String, serde_json::Error> {
let mut map = serde_json::Map::new();
$(
map.insert(stringify!($field).to_owned(), serde_json::to_value(&request.$field).unwrap());
)+
let object = serde_json::Value::Object(map);
serde_json::to_string(&object)
}
}
(
$destination_request:ident from $source_request:ident
$( extracts $( $field_name:ident : $field_type:tt ),+ $(,)? )?
$( $( and )? groups $( $grouped_field_name:ident ),+ $(,)? )?
) => {
impl TryFrom<&$source_request> for $destination_request {
type Error = serde_json::Error;
fn try_from(request: &$source_request) -> Result<Self, Self::Error> {
Ok($destination_request {
id: None,
body: Self::to_json(request)?.into(),
})
request!(
@__try_from $destination_request from $source_request
(request_id = None, request = request)
$( extracts [ $( $field_name : $field_type, )+ ] )?
$( groups [ $( $grouped_field_name, )+ ] )?
)
}
}
@@ -328,26 +362,73 @@ macro_rules! request {
fn try_from(
(request_id, request): (String, &$source_request),
) -> Result<Self, Self::Error> {
Ok($destination_request {
id: Some(request_id.into()),
body: Self::to_json(request)?.into(),
})
request!(
@__try_from $destination_request from $source_request
(request_id = Some(request_id.into()), request = request)
$( extracts [ $( $field_name : $field_type, )+ ] )?
$( groups [ $( $grouped_field_name, )+ ] )?
)
}
}
};
(
@__try_from $destination_request:ident from $source_request:ident
(request_id = $request_id:expr, request = $request:expr)
$( extracts [ $( $field_name:ident : $field_type:tt ),* $(,)? ] )?
$( groups [ $( $grouped_field_name:ident ),* $(,)? ] )?
) => {
{
Ok($destination_request {
id: $request_id,
$(
$(
$field_name: request!(@__field $field_name : $field_type ; request = $request),
)*
)?
$(
body: {
let mut map = serde_json::Map::new();
$(
map.insert(stringify!($grouped_field_name).to_owned(), serde_json::to_value(&$request.$grouped_field_name).unwrap());
)*
let object = serde_json::Value::Object(map);
serde_json::to_string(&object)?.into()
}
)?
})
}
};
( @__field $field_name:ident : $field_type:ident ; request = $request:expr ) => {
request!(@__field_type as $field_type ; request = $request, field_name = $field_name)
};
( @__field_type as string ; request = $request:expr, field_name = $field_name:ident ) => {
$request.$field_name.to_string().into()
};
( @__field_type as json ; request = $request:expr, field_name = $field_name:ident ) => {
serde_json::to_string(&$request.$field_name)?.into()
};
( @__field_type as event_type ; request = $request:expr, field_name = $field_name:ident ) => {
$request.content.event_type().to_string().into()
};
}
// Outgoing Requests
request!(KeysUploadRequest from OriginalKeysUploadRequest maps fields device_keys, one_time_keys, fallback_keys);
request!(KeysQueryRequest from OriginalKeysQueryRequest maps fields timeout, device_keys, token);
request!(KeysClaimRequest from OriginalKeysClaimRequest maps fields timeout, one_time_keys);
request!(ToDeviceRequest from OriginalToDeviceRequest maps fields event_type, txn_id, messages);
request!(SignatureUploadRequest from OriginalSignatureUploadRequest maps fields signed_keys);
request!(RoomMessageRequest from OriginalRoomMessageRequest maps fields room_id, txn_id, content);
request!(KeysBackupRequest from OriginalKeysBackupRequest maps fields rooms);
request!(KeysUploadRequest from OriginalKeysUploadRequest groups device_keys, one_time_keys, fallback_keys);
request!(KeysQueryRequest from OriginalKeysQueryRequest groups timeout, device_keys, token);
request!(KeysClaimRequest from OriginalKeysClaimRequest groups timeout, one_time_keys);
request!(ToDeviceRequest from OriginalToDeviceRequest extracts event_type: string, txn_id: string and groups messages);
request!(SignatureUploadRequest from OriginalSignatureUploadRequest extracts signed_keys: json);
request!(RoomMessageRequest from OriginalRoomMessageRequest extracts room_id: string, txn_id: string, event_type: event_type, content: json);
request!(KeysBackupRequest from OriginalKeysBackupRequest groups rooms);
// Other Requests
request!(SigningKeysUploadRequest from OriginalUploadSigningKeysRequest maps fields master_key, self_signing_key, user_signing_key);
request!(SigningKeysUploadRequest from OriginalUploadSigningKeysRequest groups master_key, self_signing_key, user_signing_key);
// JavaScript has no complex enums like Rust. To return structs of
// different types, we have no choice that hiding everything behind a
@@ -416,4 +497,7 @@ pub enum RequestType {
/// Represents a `KeysBackupRequest`.
KeysBackup,
/// Represents a `SigningKeysUploadRequest`
SigningKeysUpload,
}
+47 -6
View File
@@ -1,7 +1,5 @@
//! Types related to responses.
use std::borrow::Borrow;
use js_sys::{Array, JsString};
use matrix_sdk_common::deserialized_responses::{AlgorithmInfo, EncryptionInfo};
use matrix_sdk_crypto::IncomingResponse;
@@ -11,6 +9,7 @@ pub(crate) use ruma::api::client::{
claim_keys::v3::Response as KeysClaimResponse, get_keys::v3::Response as KeysQueryResponse,
upload_keys::v3::Response as KeysUploadResponse,
upload_signatures::v3::Response as SignatureUploadResponse,
upload_signing_keys::v3::Response as SigningKeysUploadResponse,
},
message::send_message_event::v3::Response as RoomMessageResponse,
to_device::send_event_to_device::v3::Response as ToDeviceResponse,
@@ -34,6 +33,7 @@ pub(crate) enum OwnedResponse {
SignatureUpload(SignatureUploadResponse),
RoomMessage(RoomMessageResponse),
KeysBackup(KeysBackupResponse),
SigningKeysUpload(SigningKeysUploadResponse),
}
impl From<KeysUploadResponse> for OwnedResponse {
@@ -78,9 +78,25 @@ impl From<KeysBackupResponse> for OwnedResponse {
}
}
impl From<SigningKeysUploadResponse> for OwnedResponse {
fn from(response: SigningKeysUploadResponse) -> OwnedResponse {
Self::SigningKeysUpload(response)
}
}
impl TryFrom<(RequestType, http::Response<Vec<u8>>)> for OwnedResponse {
type Error = JsError;
/// Convert an HTTP response object into the underlying ruma model of the
/// response, and wrap as an OwnedResponse.
///
/// (This is used in
/// `matrix_sdk_crypto_js::OlmMachine::mark_request_as_sent`.)
///
/// # Arguments
///
/// * `request_type` - the type of the request that got this response
/// * `response` - the raw HTTP response
fn try_from(
(request_type, response): (RequestType, http::Response<Vec<u8>>),
) -> Result<Self, Self::Error> {
@@ -112,11 +128,27 @@ impl TryFrom<(RequestType, http::Response<Vec<u8>>)> for OwnedResponse {
RequestType::KeysBackup => {
KeysBackupResponse::try_from_http_response(response).map(Into::into)
}
RequestType::SigningKeysUpload => {
// SigningKeysUploadResponse::try_from_http_response returns a
// FromHttpResponseError<UiaaResponse> instead of a
// ruma_client_api::error::Error, so we have to handle it
// separately. In practice, the application is supposed to
// have dealt with UIA before we get here, so we just map it straight into a
// regular `JsError` anyway.
return SigningKeysUploadResponse::try_from_http_response(response)
.map(Into::into)
.map_err(JsError::from);
}
}
.map_err(JsError::from)
}
}
// Make `OwnedResponse` implement `Into<IncomingResponse>`.
//
// Required so that we can pass `OwnedResponse` into the real
// `matrix_sdk_crypto_js::OlmMachine::mark_request_as_sent`.
impl<'a> From<&'a OwnedResponse> for IncomingResponse<'a> {
fn from(response: &'a OwnedResponse) -> Self {
match response {
@@ -127,6 +159,9 @@ impl<'a> From<&'a OwnedResponse> for IncomingResponse<'a> {
OwnedResponse::SignatureUpload(response) => IncomingResponse::SignatureUpload(response),
OwnedResponse::RoomMessage(response) => IncomingResponse::RoomMessage(response),
OwnedResponse::KeysBackup(response) => IncomingResponse::KeysBackup(response),
OwnedResponse::SigningKeysUpload(response) => {
IncomingResponse::SigningKeysUpload(response)
}
}
}
}
@@ -156,7 +191,7 @@ impl DecryptedRoomEvent {
/// trusted.
#[wasm_bindgen(getter, js_name = "senderDevice")]
pub fn sender_device(&self) -> Option<identifiers::DeviceId> {
Some(identifiers::DeviceId::from(self.encryption_info.as_ref()?.sender_device.clone()))
Some(self.encryption_info.as_ref()?.sender_device.as_ref()?.clone().into())
}
/// The Curve25519 key of the device that created the megolm
@@ -190,9 +225,15 @@ impl DecryptedRoomEvent {
/// note this is the state of the device at the time of
/// decryption. It may change in the future if a device gets
/// verified or deleted.
#[wasm_bindgen(getter, js_name = "verificationState")]
pub fn verification_state(&self) -> Option<encryption::VerificationState> {
Some((self.encryption_info.as_ref()?.verification_state.borrow()).into())
#[wasm_bindgen(js_name = "shieldState")]
pub fn shield_state(&self, strict: bool) -> Option<encryption::ShieldState> {
let state = &self.encryption_info.as_ref()?.verification_state;
if strict {
Some(state.to_shield_state_strict().into())
} else {
Some(state.to_shield_state_lax().into())
}
}
}
+41 -1
View File
@@ -2,7 +2,10 @@
use wasm_bindgen::prelude::*;
use crate::impl_from_to_inner;
use crate::{
encryption::EncryptionAlgorithm, identifiers::RoomId, impl_from_to_inner,
vodozemac::Curve25519PublicKey,
};
/// A struct containing private cross signing keys that can be backed
/// up or uploaded to the secret store.
@@ -34,3 +37,40 @@ impl CrossSigningKeyExport {
self.inner.user_signing_key.clone()
}
}
/// Information on a room key that has been received or imported.
#[wasm_bindgen]
#[derive(Debug)]
pub struct RoomKeyInfo {
pub(crate) inner: matrix_sdk_crypto::store::RoomKeyInfo,
}
impl_from_to_inner!(matrix_sdk_crypto::store::RoomKeyInfo => RoomKeyInfo);
#[wasm_bindgen]
impl RoomKeyInfo {
/// The {@link EncryptionAlgorithm} that this key is used for. Will be one
/// of the `m.megolm.*` algorithms.
#[wasm_bindgen(getter)]
pub fn algorithm(&self) -> EncryptionAlgorithm {
self.inner.algorithm.clone().into()
}
/// The room where the key is used.
#[wasm_bindgen(getter, js_name = "roomId")]
pub fn room_id(&self) -> RoomId {
self.inner.room_id.clone().into()
}
/// The Curve25519 key of the device which initiated the session originally.
#[wasm_bindgen(getter, js_name = "senderKey")]
pub fn sender_key(&self) -> Curve25519PublicKey {
self.inner.sender_key.into()
}
/// The ID of the session that the key is for.
#[wasm_bindgen(getter, js_name = "sessionId")]
pub fn session_id(&self) -> String {
self.inner.session_id.clone()
}
}
@@ -9,7 +9,7 @@ use crate::{identifiers, js::downcast};
#[wasm_bindgen]
#[derive(Debug)]
pub struct DeviceLists {
pub(crate) inner: ruma::api::client::sync::sync_events::v3::DeviceLists,
pub(crate) inner: ruma::api::client::sync::sync_events::DeviceLists,
}
#[wasm_bindgen]
@@ -19,7 +19,7 @@ impl DeviceLists {
/// `changed` and `left` must be an array of `UserId`.
#[wasm_bindgen(constructor)]
pub fn new(changed: Option<Array>, left: Option<Array>) -> Result<DeviceLists, JsError> {
let mut inner = ruma::api::client::sync::sync_events::v3::DeviceLists::default();
let mut inner = ruma::api::client::sync::sync_events::DeviceLists::default();
inner.changed = changed
.unwrap_or_default()
+1 -4
View File
@@ -145,9 +145,6 @@ mod inner {
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console, js_name = "trace")]
fn log_trace(message: String);
#[wasm_bindgen(js_namespace = console, js_name = "debug")]
fn log_debug(message: String);
@@ -213,7 +210,7 @@ mod inner {
let message = format!("{level} {origin}{recorder}");
match *level {
Level::TRACE => log_trace(message),
Level::TRACE => log_debug(message),
Level::DEBUG => log_debug(message),
Level::INFO => log_info(message),
Level::WARN => log_warn(message),
+264 -53
View File
@@ -3,19 +3,24 @@
#[cfg(feature = "qrcode")]
use std::fmt;
use futures_util::StreamExt;
#[cfg(feature = "qrcode")]
use js_sys::Uint8ClampedArray;
use js_sys::{Array, JsString, Promise};
use js_sys::{Array, Function, JsString, Promise};
use matrix_sdk_crypto::{QrVerificationState, VerificationRequestState};
use ruma::events::key::verification::{
cancel::CancelCode as RumaCancelCode, VerificationMethod as RumaVerificationMethod,
};
use tracing::warn;
use wasm_bindgen::prelude::*;
use wasm_bindgen_futures::spawn_local;
use crate::{
future::future_to_promise,
identifiers::{DeviceId, RoomId, UserId},
impl_from_to_inner,
js::try_array_to_vec,
machine::promise_result_to_future,
requests,
};
@@ -66,8 +71,7 @@ impl TryFrom<JsValue> for VerificationMethod {
3 => Self::ReciprocateV1,
_ => {
return Err(JsError::new(&format!(
"Unknown verification method (received `{:?}`)",
value
"Unknown verification method (received `{value:?}`)"
)))
}
})
@@ -100,8 +104,7 @@ impl TryFrom<RumaVerificationMethod> for VerificationMethod {
ReciprocateV1 => Self::ReciprocateV1,
_ => {
return Err(JsError::new(&format!(
"Unknown verification method (received `{:?}`)",
value
"Unknown verification method (received `{value:?}`)"
)))
}
})
@@ -181,32 +184,32 @@ impl Sas {
}
/// Does this verification flow support displaying emoji for the
/// short authentication string.
/// short authentication string?
#[wasm_bindgen(js_name = "supportsEmoji")]
pub fn supports_emoji(&self) -> bool {
self.inner.supports_emoji()
}
/// Did this verification flow start from a verification request.
/// Did this verification flow start from a verification request?
#[wasm_bindgen(js_name = "startedFromRequest")]
pub fn started_from_request(&self) -> bool {
self.inner.started_from_request()
}
/// Is this a verification that is veryfying one of our own
/// devices.
/// Is this a verification that is verifying one of our own
/// devices?
#[wasm_bindgen(js_name = "isSelfVerification")]
pub fn is_self_verification(&self) -> bool {
self.inner.is_self_verification()
}
/// Have we confirmed that the short auth string matches.
/// Have we confirmed that the short auth string matches?
#[wasm_bindgen(js_name = "haveWeConfirmed")]
pub fn have_we_confirmed(&self) -> bool {
self.inner.have_we_confirmed()
}
/// Has the verification been accepted by both parties.
/// Has the verification been accepted by both parties?
#[wasm_bindgen(js_name = "hasBeenAccepted")]
pub fn has_been_accepted(&self) -> bool {
self.inner.has_been_accepted()
@@ -219,7 +222,8 @@ impl Sas {
self.inner.cancel_info().map(Into::into)
}
/// Did we initiate the verification flow.
/// True if we initiated the verification flow (ie, we sent the
/// `m.key.verification.request`).
#[wasm_bindgen(js_name = "weStarted")]
pub fn we_started(&self) -> bool {
self.inner.we_started()
@@ -227,9 +231,9 @@ impl Sas {
/// Accept the SAS verification.
///
/// This does nothing if the verification was already accepted,
/// otherwise it returns an `AcceptEventContent` that needs to be
/// sent out.
/// This does nothing (and returns `undefined`) if the verification was
/// already accepted, otherwise it returns an `OutgoingRequest`
/// that needs to be sent out.
pub fn accept(&self) -> Result<JsValue, JsError> {
self.inner
.accept()
@@ -245,8 +249,9 @@ impl Sas {
/// This confirms that the short auth strings match on both sides.
///
/// Does nothing if were not in a state where we can confirm the
/// short auth string, otherwise returns a `MacEventContent` that
/// needs to be sent to the server.
/// short auth string.
///
/// Returns a `Promise` for an array of `OutgoingRequest`s.
pub fn confirm(&self) -> Promise {
let me = self.inner.clone();
@@ -258,21 +263,21 @@ impl Sas {
.map(JsValue::try_from)
.collect::<Result<Array, _>>()?;
let tuple = Array::new();
tuple.set(0, outgoing_verification_requests.into());
tuple.set(
1,
signature_upload_request
.map(|request| requests::SignatureUploadRequest::try_from(&request))
.transpose()?
.into(),
);
// if a signature upload request was returned, push it onto the end of the array
// of OutgoingRequests we just built.
if let Some(sig_rq) = signature_upload_request {
outgoing_verification_requests
.push(&requests::SignatureUploadRequest::try_from(&sig_rq)?.into());
}
Ok(tuple)
Ok(outgoing_verification_requests)
})
}
/// Cancel the verification.
///
/// Returns either an `OutgoingRequest` which should be sent out, or
/// `undefined` if the verification is already cancelled.
pub fn cancel(&self) -> Result<JsValue, JsError> {
self.inner
.cancel()
@@ -286,6 +291,9 @@ impl Sas {
/// Cancel the verification.
///
/// This cancels the verification with given code.
///
/// Returns either an `OutgoingRequest` which should be sent out, or
/// `undefined` if the verification is already cancelled.
#[wasm_bindgen(js_name = "cancelWithCode")]
pub fn cancel_with_code(&self, code: CancelCode) -> Result<JsValue, JsError> {
self.inner
@@ -297,25 +305,25 @@ impl Sas {
.map_err(Into::into)
}
/// Has the SAS verification flow timed out.
/// Has the SAS verification flow timed out?
#[wasm_bindgen(js_name = "timedOut")]
pub fn timed_out(&self) -> bool {
self.inner.timed_out()
}
/// Are we in a state where we can show the short auth string.
/// Are we in a state where we can show the short auth string?
#[wasm_bindgen(js_name = "canBePresented")]
pub fn can_be_presented(&self) -> bool {
self.inner.can_be_presented()
}
/// Is the SAS flow done.
/// Is the SAS flow done?
#[wasm_bindgen(js_name = "isDone")]
pub fn is_done(&self) -> bool {
self.inner.is_done()
}
/// Is the SAS flow canceled.
/// Is the SAS flow cancelled?
#[wasm_bindgen(js_name = "isCancelled")]
pub fn is_cancelled(&self) -> bool {
self.inner.is_cancelled()
@@ -324,7 +332,7 @@ impl Sas {
/// Get the emoji version of the short auth string.
///
/// Returns `undefined` if we can't yet present the short auth string,
/// otherwise seven tuples containing the emoji and description.
/// otherwise an array of seven `Emoji` objects.
pub fn emoji(&self) -> Option<Array> {
Some(
self.inner
@@ -363,6 +371,21 @@ impl Sas {
Some(out)
}
/// Register a callback which will be called whenever there is an update to
/// the request.
///
/// The `callback` is called with no parameters.
#[wasm_bindgen(js_name = "registerChangesCallback")]
pub fn register_changes_callback(&self, callback: Function) {
let stream = self.inner.changes();
// fire up a promise chain which will call `callback` on each result from the
// stream
spawn_local(async move {
stream.for_each(|_| send_change_info_to_callback(&callback)).await;
});
}
}
/// QR code based verification.
@@ -379,6 +402,13 @@ impl_from_to_inner!(matrix_sdk_crypto::QrVerification => Qr);
#[cfg(feature = "qrcode")]
#[wasm_bindgen]
impl Qr {
/// Get the current state of this request.
///
/// Returns a `QrState`.
pub fn state(&self) -> QrState {
self.inner.state().into()
}
/// Has the QR verification been scanned by the other side.
///
/// When the verification object is in this state its required
@@ -389,7 +419,7 @@ impl Qr {
self.inner.has_been_scanned()
}
/// Has the scanning of the QR code been confirmed by us.
/// Has the scanning of the QR code been confirmed by us?
#[wasm_bindgen(js_name = "hasBeenConfirmed")]
pub fn has_been_confirmed(&self) -> bool {
self.inner.has_been_confirmed()
@@ -414,7 +444,7 @@ impl Qr {
self.inner.other_device_id().to_owned().into()
}
/// Did we initiate the verification request.
/// Did we initiate the verification request?
#[wasm_bindgen(js_name = "weStarted")]
pub fn we_started(&self) -> bool {
self.inner.we_started()
@@ -427,26 +457,26 @@ impl Qr {
self.inner.cancel_info().map(Into::into)
}
/// Has the verification flow completed.
/// Has the verification flow completed?
#[wasm_bindgen(js_name = "isDone")]
pub fn is_done(&self) -> bool {
self.inner.is_done()
}
/// Has the verification flow been cancelled.
/// Has the verification flow been cancelled?
#[wasm_bindgen(js_name = "isCancelled")]
pub fn is_cancelled(&self) -> bool {
self.inner.is_cancelled()
}
/// Is this a verification that is veryfying one of our own devices.
/// Is this a verification that is verifying one of our own devices?
#[wasm_bindgen(js_name = "isSelfVerification")]
pub fn is_self_verification(&self) -> bool {
self.inner.is_self_verification()
}
/// Have we successfully scanned the QR code and are able to send
/// a reciprocation event.
/// a reciprocation event?
pub fn reciprocated(&self) -> bool {
self.inner.reciprocated()
}
@@ -473,6 +503,8 @@ impl Qr {
///
/// The `to_bytes` method can be used to instead output the raw
/// bytes that should be encoded as a QR code.
///
/// Returns a `QrCode`.
#[wasm_bindgen(js_name = "toQrCode")]
pub fn to_qr_code(&self) -> Result<QrCode, JsError> {
Ok(self.inner.to_qr_code().map(Into::into)?)
@@ -484,8 +516,13 @@ impl Qr {
/// The `to_qr_code` method can be used to instead output a QrCode
/// object that can be rendered.
#[wasm_bindgen(js_name = "toBytes")]
pub fn to_bytes(&self) -> Result<Array, JsError> {
Ok(self.inner.to_bytes()?.into_iter().map(JsValue::from).collect())
pub fn to_bytes(&self) -> Result<Uint8ClampedArray, JsError> {
let bytes = self.inner.to_bytes()?;
let output = Uint8ClampedArray::new_with_length(bytes.len() as _);
output.copy_from(&bytes);
Ok(output)
}
/// Notify the other side that we have successfully scanned the QR
@@ -504,6 +541,9 @@ impl Qr {
}
/// Confirm that the other side has scanned our QR code.
///
/// Returns either an `OutgoingRequest` which should be sent out, or
/// `undefined` if the verification is already confirmed.
#[wasm_bindgen(js_name = "confirmScanning")]
pub fn confirm_scanning(&self) -> Result<JsValue, JsError> {
self.inner
@@ -516,6 +556,9 @@ impl Qr {
}
/// Cancel the verification flow.
///
/// Returns either an `OutgoingRequest` which should be sent out, or
/// `undefined` if the verification is already cancelled.
pub fn cancel(&self) -> Result<JsValue, JsError> {
self.inner
.cancel()
@@ -529,6 +572,9 @@ impl Qr {
/// Cancel the verification.
///
/// This cancels the verification with given code.
///
/// Returns either an `OutgoingRequest` which should be sent out, or
/// `undefined` if the verification is already cancelled.
#[wasm_bindgen(js_name = "cancelWithCode")]
pub fn cancel_with_code(&self, code: CancelCode) -> Result<JsValue, JsError> {
self.inner
@@ -539,6 +585,21 @@ impl Qr {
.map(JsValue::from)
.map_err(Into::into)
}
/// Register a callback which will be called whenever there is an update to
/// the request
///
/// The `callback` is called with no parameters.
#[wasm_bindgen(js_name = "registerChangesCallback")]
pub fn register_changes_callback(&self, callback: Function) {
let stream = self.inner.changes();
// fire up a promise chain which will call `callback` on each result from the
// stream
spawn_local(async move {
stream.for_each(|_| send_change_info_to_callback(&callback)).await;
});
}
}
/// Information about the cancellation of a verification request or
@@ -754,10 +815,60 @@ impl QrCodeScan {
/// This method is useful if you would like to do your own custom QR code
/// decoding.
#[wasm_bindgen(js_name = "fromBytes")]
pub fn from_bytes(buffer: Uint8ClampedArray) -> Result<QrCodeScan, JsError> {
pub fn from_bytes(buffer: &Uint8ClampedArray) -> Result<QrCodeScan, JsError> {
let bytes = buffer.to_vec();
Ok(Self { inner: matrix_sdk_qrcode::QrVerificationData::from_bytes(&bytes)? })
Ok(Self { inner: matrix_sdk_qrcode::QrVerificationData::from_bytes(bytes)? })
}
}
/// List of `Qr` states
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub enum QrState {
/// We have received the other device's details (from the
/// `m.key.verification.request` or `m.key.verification.ready`) and
/// established the shared secret, so can
/// display the QR code.
Created = 0,
/// The other side has scanned our QR code and sent an
/// `m.key.verification.start` message with `method: m.reciprocate.v1` with
/// matching shared secret.
Scanned = 1,
/// Our user has confirmed that the other device scanned successfully. We
/// have sent an `m.key.verification.done`.
Confirmed = 2,
/// We have scanned the other side's QR code and are able to send a
/// `m.key.verification.start` message with `method: m.reciprocate.v1`.
///
/// Call `Qr::reciprocate` to build the start message.
///
/// Note that, despite the name of this state, we have not necessarily
/// yet sent the `m.reciprocate.v1` message.
Reciprocated = 3,
/// Verification complete: we have received an `m.key.verification.done`
/// from the other side.
Done = 4,
/// Verification cancelled or failed.
Cancelled = 5,
}
impl From<QrVerificationState> for QrState {
fn from(value: QrVerificationState) -> Self {
use matrix_sdk_crypto::QrVerificationState::*;
match value {
Started => Self::Created,
Scanned => Self::Scanned,
Confirmed => Self::Confirmed,
Reciprocated => Self::Reciprocated,
Done { .. } => Self::Done,
Cancelled(..) => Self::Cancelled,
}
}
}
@@ -834,24 +945,33 @@ impl VerificationRequest {
self.inner.cancel_info().map(Into::into)
}
/// Has the verification request been answered by another device.
/// Has the verification request been answered by another device?
#[wasm_bindgen(js_name = "isPassive")]
pub fn is_passive(&self) -> bool {
self.inner.is_passive()
}
/// Is the verification request ready to start a verification flow.
/// Is the verification request ready to start a verification flow?
#[wasm_bindgen(js_name = "isReady")]
pub fn is_ready(&self) -> bool {
self.inner.is_ready()
}
/// Has the verification flow timed out.
/// Has the verification flow timed out?
#[wasm_bindgen(js_name = "timedOut")]
pub fn timed_out(&self) -> bool {
self.inner.timed_out()
}
/// The number of milliseconds remaining before this verification flow times
/// out.
///
/// Returns zero if the time has already passed.
#[wasm_bindgen(js_name = "timeRemainingMillis")]
pub fn time_remaining_millis(&self) -> f64 {
self.inner.time_remaining().as_millis() as f64
}
/// Get the supported verification methods of the other side.
///
/// Will be present only if the other side requested the
@@ -888,34 +1008,72 @@ impl VerificationRequest {
.transpose()
}
/// Get the unique ID of this verification request
/// Get the unique ID of this verification request.
#[wasm_bindgen(getter, js_name = "flowId")]
pub fn flow_id(&self) -> String {
self.inner.flow_id().as_str().to_owned()
}
/// Is this a verification that is veryfying one of our own
/// devices.
/// Is this a verification that is verifying one of our own
/// devices?
#[wasm_bindgen(js_name = "isSelfVerification")]
pub fn is_self_verification(&self) -> bool {
self.inner.is_self_verification()
}
/// Did we initiate the verification request.
/// Did we initiate the verification request?
#[wasm_bindgen(js_name = "weStarted")]
pub fn we_started(&self) -> bool {
self.inner.we_started()
}
/// Has the verification flow that was started with this request
/// finished.
/// finished?
#[wasm_bindgen(js_name = "isDone")]
pub fn is_done(&self) -> bool {
self.inner.is_done()
}
/// Get the current phase of this request.
///
/// Returns a `VerificationRequestPhase`.
pub fn phase(&self) -> VerificationRequestPhase {
self.inner.state().into()
}
/// If this request has transitioned into a concrete verification
/// flow (and not yet been completed or cancelled), returns a `Verification`
/// object.
///
/// Returns: a `Sas`, a `Qr`, or `undefined`.
#[wasm_bindgen(js_name = "getVerification")]
pub fn get_verification(&self) -> JsValue {
let result: Option<JsValue> =
if let VerificationRequestState::Transitioned { verification } = self.inner.state() {
Verification(verification).try_into().ok()
} else {
None
};
result.into()
}
/// Register a callback which will be called whenever there is an update to
/// the request.
///
/// The `callback` is called with no parameters.
#[wasm_bindgen(js_name = "registerChangesCallback")]
pub fn register_changes_callback(&self, callback: Function) {
let stream = self.inner.changes();
// fire up a promise chain which will call `callback` on each result from the
// stream
spawn_local(async move {
stream.for_each(|_| send_change_info_to_callback(&callback)).await;
});
}
/// Has the verification flow that was started with this request
/// been cancelled.
/// been cancelled?
#[wasm_bindgen(js_name = "isCancelled")]
pub fn is_cancelled(&self) -> bool {
self.inner.is_cancelled()
@@ -981,6 +1139,8 @@ impl VerificationRequest {
}
/// Transition from this verification request into a SAS verification flow.
///
/// Returns `Promise<[Sas, RoomMessageRequest|ToDeviceRequest] | undefined>`
#[wasm_bindgen(js_name = "startSas")]
pub fn start_sas(&self) -> Promise {
let me = self.inner.clone();
@@ -1013,6 +1173,8 @@ impl VerificationRequest {
/// Generate a QR code that can be used by another client to start
/// a QR code based verification.
///
/// Returns a `Qr`.
#[cfg(feature = "qrcode")]
#[wasm_bindgen(js_name = "generateQrCode")]
pub fn generate_qr_code(&self) -> Promise {
@@ -1029,9 +1191,9 @@ impl VerificationRequest {
/// for this verification flow.
#[cfg(feature = "qrcode")]
#[wasm_bindgen(js_name = "scanQrCode")]
pub fn scan_qr_code(&self, data: QrCodeScan) -> Promise {
pub fn scan_qr_code(&self, data: &QrCodeScan) -> Promise {
let me = self.inner.clone();
let qr_verification_data = data.inner;
let qr_verification_data = data.inner.clone();
future_to_promise(
async move { Ok(me.scan_qr_code(qr_verification_data).await?.map(Qr::from)) },
@@ -1067,3 +1229,52 @@ impl TryFrom<OutgoingVerificationRequest> for JsValue {
})
}
}
/// List of VerificationRequestState phases
#[wasm_bindgen]
#[derive(Debug, Clone)]
pub enum VerificationRequestPhase {
/// The verification request has been newly created by us.
Created = 0,
/// The verification request was received from the other party.
Requested = 1,
/// The verification request is ready to start a verification flow.
Ready = 2,
/// The verification request has transitioned into a concrete verification
/// flow. For example it transitioned into the emoji based SAS
/// verification.
Transitioned = 3,
/// The verification flow that was started with this request has finished.
Done = 4,
/// The verification process has been cancelled.
Cancelled = 5,
}
impl From<VerificationRequestState> for VerificationRequestPhase {
fn from(value: VerificationRequestState) -> Self {
use matrix_sdk_crypto::VerificationRequestState::*;
match value {
Created { .. } => Self::Created,
Requested { .. } => Self::Requested,
Transitioned { .. } => Self::Transitioned,
Ready { .. } => Self::Ready,
Done => Self::Done,
Cancelled(_) => Self::Cancelled,
}
}
}
// helper for register_changes_callback: calls the javascript callback
async fn send_change_info_to_callback(callback: &Function) {
match promise_result_to_future(callback.call0(&JsValue::NULL)).await {
Ok(_) => (),
Err(e) => {
warn!("Error calling changes callback: {:?}", e);
}
}
}
@@ -0,0 +1,17 @@
const { UserId, initAsync } = require("../pkg/matrix_sdk_crypto_js");
test("can instantiate rust objects with async initialiser", async () => {
initUserId = () => new UserId("@foo:bar.org");
// stub out the synchronous WebAssembly loader with one that raises an error
jest.spyOn(WebAssembly, "Module").mockImplementation(() => {
throw new Error("synchronous WebAssembly.Module() not allowed");
});
// this should fail
expect(initUserId).toThrow(/synchronous/);
// but once we init with async, it should work
await initAsync();
initUserId();
});
@@ -1,37 +1,41 @@
const { Attachment, EncryptedAttachment } = require('../pkg/matrix_sdk_crypto_js');
const { Attachment, EncryptedAttachment } = require("../pkg/matrix_sdk_crypto_js");
describe(Attachment.name, () => {
const originalData = 'hello';
const originalData = "hello";
const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder();
let encryptedAttachment;
test('can encrypt data', () => {
test("can encrypt data", () => {
encryptedAttachment = Attachment.encrypt(textEncoder.encode(originalData));
const mediaEncryptionInfo = JSON.parse(encryptedAttachment.mediaEncryptionInfo);
expect(mediaEncryptionInfo).toMatchObject({
v: 'v2',
v: "v2",
key: {
kty: expect.any(String),
key_ops: expect.arrayContaining(['encrypt', 'decrypt']),
key_ops: expect.arrayContaining(["encrypt", "decrypt"]),
alg: expect.any(String),
k: expect.any(String),
ext: expect.any(Boolean),
},
iv: expect.stringMatching(/^[A-Za-z0-9\+/]+$/),
hashes: {
sha256: expect.stringMatching(/^[A-Za-z0-9\+/]+$/)
}
sha256: expect.stringMatching(/^[A-Za-z0-9\+/]+$/),
},
});
const encryptedData = encryptedAttachment.encryptedData;
expect(encryptedData.every((i) => { i != 0 })).toStrictEqual(false);
expect(
encryptedData.every((i) => {
i != 0;
}),
).toStrictEqual(false);
});
test('can decrypt data', () => {
test("can decrypt data", () => {
expect(encryptedAttachment.hasMediaEncryptionInfoBeenConsumed).toStrictEqual(false);
const decryptedAttachment = Attachment.decrypt(encryptedAttachment);
@@ -40,34 +44,36 @@ describe(Attachment.name, () => {
expect(encryptedAttachment.hasMediaEncryptionInfoBeenConsumed).toStrictEqual(true);
});
test('can only decrypt once', () => {
test("can only decrypt once", () => {
expect(encryptedAttachment.hasMediaEncryptionInfoBeenConsumed).toStrictEqual(true);
expect(() => { textDecoder.decode(decryptedAttachment) }).toThrow()
expect(() => {
textDecoder.decode(decryptedAttachment);
}).toThrow();
});
});
describe(EncryptedAttachment.name, () => {
const originalData = 'hello';
const originalData = "hello";
const textDecoder = new TextDecoder();
test('can be created manually', () => {
test("can be created manually", () => {
const encryptedAttachment = new EncryptedAttachment(
new Uint8Array([24, 150, 67, 37, 144]),
JSON.stringify({
v: 'v2',
v: "v2",
key: {
kty: 'oct',
key_ops: [ 'encrypt', 'decrypt' ],
alg: 'A256CTR',
k: 'QbNXUjuukFyEJ8cQZjJuzN6mMokg0HJIjx0wVMLf5BM',
ext: true
kty: "oct",
key_ops: ["encrypt", "decrypt"],
alg: "A256CTR",
k: "QbNXUjuukFyEJ8cQZjJuzN6mMokg0HJIjx0wVMLf5BM",
ext: true,
},
iv: 'xk2AcWkomiYAAAAAAAAAAA',
iv: "xk2AcWkomiYAAAAAAAAAAA",
hashes: {
sha256: 'JsRbDXgOja4xvDiF3DwBuLHdxUzIrVYIuj7W/t3aEok'
}
})
sha256: "JsRbDXgOja4xvDiF3DwBuLHdxUzIrVYIuj7W/t3aEok",
},
}),
);
expect(encryptedAttachment.hasMediaEncryptionInfoBeenConsumed).toStrictEqual(false);
File diff suppressed because it is too large Load Diff
@@ -1,14 +1,19 @@
const { EncryptionAlgorithm, EncryptionSettings, HistoryVisibility, VerificationState } = require('../pkg/matrix_sdk_crypto_js');
const {
EncryptionAlgorithm,
EncryptionSettings,
HistoryVisibility,
VerificationState,
} = require("../pkg/matrix_sdk_crypto_js");
describe('EncryptionAlgorithm', () => {
test('has the correct variant values', () => {
describe("EncryptionAlgorithm", () => {
test("has the correct variant values", () => {
expect(EncryptionAlgorithm.OlmV1Curve25519AesSha2).toStrictEqual(0);
expect(EncryptionAlgorithm.MegolmV1AesSha2).toStrictEqual(1);
});
});
describe(EncryptionSettings.name, () => {
test('can be instantiated with default values', () => {
test("can be instantiated with default values", () => {
const es = new EncryptionSettings();
expect(es.algorithm).toStrictEqual(EncryptionAlgorithm.MegolmV1AesSha2);
@@ -17,20 +22,14 @@ describe(EncryptionSettings.name, () => {
expect(es.historyVisibility).toStrictEqual(HistoryVisibility.Shared);
});
test('checks the history visibility values', () => {
test("checks the history visibility values", () => {
const es = new EncryptionSettings();
es.historyVisibility = HistoryVisibility.Invited;
expect(es.historyVisibility).toStrictEqual(HistoryVisibility.Invited);
expect(() => { es.historyVisibility = 42 }).toThrow();
});
});
describe('VerificationState', () => {
test('has the correct variant values', () => {
expect(VerificationState.Trusted).toStrictEqual(0);
expect(VerificationState.Untrusted).toStrictEqual(1);
expect(VerificationState.UnknownDevice).toStrictEqual(2);
expect(() => {
es.historyVisibility = 42;
}).toThrow();
});
});
@@ -1,7 +1,7 @@
const { HistoryVisibility } = require('../pkg/matrix_sdk_crypto_js');
const { HistoryVisibility } = require("../pkg/matrix_sdk_crypto_js");
describe('HistoryVisibility', () => {
test('has the correct variant values', () => {
describe("HistoryVisibility", () => {
test("has the correct variant values", () => {
expect(HistoryVisibility.Invited).toStrictEqual(0);
expect(HistoryVisibility.Joined).toStrictEqual(1);
expect(HistoryVisibility.Shared).toStrictEqual(2);
+29 -17
View File
@@ -1,24 +1,26 @@
const { DeviceLists, RequestType, KeysUploadRequest, KeysQueryRequest } = require('../pkg/matrix_sdk_crypto_js');
const { DeviceLists, RequestType, KeysUploadRequest, KeysQueryRequest } = require("../pkg/matrix_sdk_crypto_js");
function* zip(...arrays) {
const len = Math.min(...arrays.map((array) => array.length));
for (let nth = 0; nth < len; ++nth) {
yield [...arrays.map((array) => array.at(nth))]
yield [...arrays.map((array) => array.at(nth))];
}
}
// Add a machine to another machine, i.e. be sure a machine knows
// another exists.
async function addMachineToMachine(machineToAdd, machine) {
const toDeviceEvents = JSON.stringify({});
const toDeviceEvents = JSON.stringify([]);
const changedDevices = new DeviceLists();
const oneTimeKeyCounts = new Map();
const unusedFallbackKeys = new Set();
const receiveSyncChanges = JSON.parse(await machineToAdd.receiveSyncChanges(toDeviceEvents, changedDevices, oneTimeKeyCounts, unusedFallbackKeys));
const receiveSyncChanges = JSON.parse(
await machineToAdd.receiveSyncChanges(toDeviceEvents, changedDevices, oneTimeKeyCounts, unusedFallbackKeys),
);
expect(receiveSyncChanges).toEqual({});
expect(receiveSyncChanges).toEqual([[], []]);
const outgoingRequests = await machineToAdd.outgoingRequests();
@@ -30,6 +32,7 @@ async function addMachineToMachine(machineToAdd, machine) {
expect(outgoingRequests[0]).toBeInstanceOf(KeysUploadRequest);
expect(outgoingRequests[0].id).toBeDefined();
expect(outgoingRequests[0].type).toStrictEqual(RequestType.KeysUpload);
expect(outgoingRequests[0].body).toBeDefined();
const body = JSON.parse(outgoingRequests[0].body);
expect(body.device_keys).toBeDefined();
@@ -37,22 +40,25 @@ async function addMachineToMachine(machineToAdd, machine) {
// https://spec.matrix.org/v1.2/client-server-api/#post_matrixclientv3keysupload
const hypothetical_response = JSON.stringify({
"one_time_key_counts": {
"curve25519": 10,
"signed_curve25519": 20
}
one_time_key_counts: {
curve25519: 10,
signed_curve25519: 20,
},
});
const marked = await machineToAdd.markRequestAsSent(outgoingRequests[0].id, outgoingRequests[0].type, hypothetical_response);
const marked = await machineToAdd.markRequestAsSent(
outgoingRequests[0].id,
outgoingRequests[0].type,
hypothetical_response,
);
expect(marked).toStrictEqual(true);
keysUploadRequest = body;
keysUploadRequest = outgoingRequests[0];
}
{
expect(outgoingRequests[1]).toBeInstanceOf(KeysQueryRequest);
let [signingKeysUploadRequest, _] = await machineToAdd.bootstrapCrossSigning(true);
signingKeysUploadRequest = JSON.parse(signingKeysUploadRequest.body);
// Let's forge a `KeysQuery`'s response.
let keyQueryResponse = {
@@ -64,12 +70,18 @@ async function addMachineToMachine(machineToAdd, machine) {
const userId = machineToAdd.userId.toString();
const deviceId = machineToAdd.deviceId.toString();
keyQueryResponse.device_keys[userId] = {};
keyQueryResponse.device_keys[userId][deviceId] = keysUploadRequest.device_keys;
keyQueryResponse.master_keys[userId] = signingKeysUploadRequest.master_key;
keyQueryResponse.self_signing_keys[userId] = signingKeysUploadRequest.self_signing_key;
keyQueryResponse.user_signing_keys[userId] = signingKeysUploadRequest.user_signing_key;
keyQueryResponse.device_keys[userId][deviceId] = JSON.parse(keysUploadRequest.body).device_keys;
const marked = await machine.markRequestAsSent(outgoingRequests[1].id, outgoingRequests[1].type, JSON.stringify(keyQueryResponse));
const keys = JSON.parse(signingKeysUploadRequest.body);
keyQueryResponse.master_keys[userId] = keys.master_key;
keyQueryResponse.self_signing_keys[userId] = keys.self_signing_key;
keyQueryResponse.user_signing_keys[userId] = keys.user_signing_key;
const marked = await machine.markRequestAsSent(
outgoingRequests[1].id,
outgoingRequests[1].type,
JSON.stringify(keyQueryResponse),
);
expect(marked).toStrictEqual(true);
}
}
@@ -7,65 +7,75 @@ const {
RoomId,
ServerName,
UserId,
} = require('../pkg/matrix_sdk_crypto_js');
} = require("../pkg/matrix_sdk_crypto_js");
describe(UserId.name, () => {
test('cannot be invalid', () => {
expect(() => { new UserId('@foobar') }).toThrow();
test("cannot be invalid", () => {
expect(() => {
new UserId("@foobar");
}).toThrow();
});
const user = new UserId('@foo:bar.org');
const user = new UserId("@foo:bar.org");
test('localpart is present', () => {
expect(user.localpart).toStrictEqual('foo');
test("localpart is present", () => {
expect(user.localpart).toStrictEqual("foo");
});
test('server name is present', () => {
test("server name is present", () => {
expect(user.serverName).toBeInstanceOf(ServerName);
});
test('user ID is not historical', () => {
test("user ID is not historical", () => {
expect(user.isHistorical()).toStrictEqual(false);
});
test('can read the user ID as a string', () => {
expect(user.toString()).toStrictEqual('@foo:bar.org');
})
test("can read the user ID as a string", () => {
expect(user.toString()).toStrictEqual("@foo:bar.org");
});
});
describe(DeviceId.name, () => {
const device = new DeviceId('foo');
const device = new DeviceId("foo");
test('can read the device ID as a string', () => {
expect(device.toString()).toStrictEqual('foo');
})
test("can read the device ID as a string", () => {
expect(device.toString()).toStrictEqual("foo");
});
});
describe(DeviceKeyId.name, () => {
for (const deviceKey of [
{ name: 'ed25519',
id: 'ed25519:foobar',
algorithmName: DeviceKeyAlgorithmName.Ed25519,
algorithm: 'ed25519',
deviceId: 'foobar' },
{
name: "ed25519",
id: "ed25519:foobar",
algorithmName: DeviceKeyAlgorithmName.Ed25519,
algorithm: "ed25519",
deviceId: "foobar",
},
{ name: 'curve25519',
id: 'curve25519:foobar',
algorithmName: DeviceKeyAlgorithmName.Curve25519,
algorithm: 'curve25519',
deviceId: 'foobar' },
{
name: "curve25519",
id: "curve25519:foobar",
algorithmName: DeviceKeyAlgorithmName.Curve25519,
algorithm: "curve25519",
deviceId: "foobar",
},
{ name: 'signed curve25519',
id: 'signed_curve25519:foobar',
algorithmName: DeviceKeyAlgorithmName.SignedCurve25519,
algorithm: 'signed_curve25519',
deviceId: 'foobar' },
{
name: "signed curve25519",
id: "signed_curve25519:foobar",
algorithmName: DeviceKeyAlgorithmName.SignedCurve25519,
algorithm: "signed_curve25519",
deviceId: "foobar",
},
{ name: 'unknown',
id: 'hello:foobar',
algorithmName: DeviceKeyAlgorithmName.Unknown,
algorithm: 'hello',
deviceId: 'foobar' },
{
name: "unknown",
id: "hello:foobar",
algorithmName: DeviceKeyAlgorithmName.Unknown,
algorithm: "hello",
deviceId: "foobar",
},
]) {
test(`${deviceKey.name} algorithm`, () => {
const dk = new DeviceKeyId(deviceKey.id);
@@ -78,8 +88,8 @@ describe(DeviceKeyId.name, () => {
}
});
describe('DeviceKeyAlgorithmName', () => {
test('has the correct variants', () => {
describe("DeviceKeyAlgorithmName", () => {
test("has the correct variants", () => {
expect(DeviceKeyAlgorithmName.Ed25519).toStrictEqual(0);
expect(DeviceKeyAlgorithmName.Curve25519).toStrictEqual(1);
expect(DeviceKeyAlgorithmName.SignedCurve25519).toStrictEqual(2);
@@ -88,94 +98,100 @@ describe('DeviceKeyAlgorithmName', () => {
});
describe(RoomId.name, () => {
test('cannot be invalid', () => {
expect(() => { new RoomId('!foo') }).toThrow();
test("cannot be invalid", () => {
expect(() => {
new RoomId("!foo");
}).toThrow();
});
const room = new RoomId('!foo:bar.org');
const room = new RoomId("!foo:bar.org");
test('localpart is present', () => {
expect(room.localpart).toStrictEqual('foo');
test("localpart is present", () => {
expect(room.localpart).toStrictEqual("foo");
});
test('server name is present', () => {
test("server name is present", () => {
expect(room.serverName).toBeInstanceOf(ServerName);
});
test('can read the room ID as string', () => {
expect(room.toString()).toStrictEqual('!foo:bar.org');
test("can read the room ID as string", () => {
expect(room.toString()).toStrictEqual("!foo:bar.org");
});
});
describe(ServerName.name, () => {
test('cannot be invalid', () => {
expect(() => { new ServerName('@foobar') }).toThrow()
test("cannot be invalid", () => {
expect(() => {
new ServerName("@foobar");
}).toThrow();
});
test('host is present', () => {
expect(new ServerName('foo.org').host).toStrictEqual('foo.org');
test("host is present", () => {
expect(new ServerName("foo.org").host).toStrictEqual("foo.org");
});
test('port can be optional', () => {
expect(new ServerName('foo.org').port).toStrictEqual(undefined);
expect(new ServerName('foo.org:1234').port).toStrictEqual(1234);
test("port can be optional", () => {
expect(new ServerName("foo.org").port).toStrictEqual(undefined);
expect(new ServerName("foo.org:1234").port).toStrictEqual(1234);
});
test('server is not an IP literal', () => {
expect(new ServerName('foo.org').isIpLiteral()).toStrictEqual(false);
test("server is not an IP literal", () => {
expect(new ServerName("foo.org").isIpLiteral()).toStrictEqual(false);
});
});
describe(EventId.name, () => {
test('cannot be invalid', () => {
expect(() => { new EventId('%foo') }).toThrow();
test("cannot be invalid", () => {
expect(() => {
new EventId("%foo");
}).toThrow();
});
describe('Versions 1 & 2', () => {
const room = new EventId('$h29iv0s8:foo.org');
describe("Versions 1 & 2", () => {
const room = new EventId("$h29iv0s8:foo.org");
test('localpart is present', () => {
expect(room.localpart).toStrictEqual('h29iv0s8');
test("localpart is present", () => {
expect(room.localpart).toStrictEqual("h29iv0s8");
});
test('server name is present', () => {
test("server name is present", () => {
expect(room.serverName).toBeInstanceOf(ServerName);
});
test('can read the room ID as string', () => {
expect(room.toString()).toStrictEqual('$h29iv0s8:foo.org');
test("can read the room ID as string", () => {
expect(room.toString()).toStrictEqual("$h29iv0s8:foo.org");
});
});
describe('Version 3', () => {
const room = new EventId('$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk');
describe("Version 3", () => {
const room = new EventId("$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk");
test('localpart is present', () => {
expect(room.localpart).toStrictEqual('acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk');
test("localpart is present", () => {
expect(room.localpart).toStrictEqual("acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk");
});
test('server name is present', () => {
test("server name is present", () => {
expect(room.serverName).toBeUndefined();
});
test('can read the room ID as string', () => {
expect(room.toString()).toStrictEqual('$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk');
test("can read the room ID as string", () => {
expect(room.toString()).toStrictEqual("$acR1l0raoZnm60CBwAVgqbZqoO/mYU81xysh1u7XcJk");
});
});
describe('Version 4', () => {
const room = new EventId('$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg');
describe("Version 4", () => {
const room = new EventId("$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg");
test('localpart is present', () => {
expect(room.localpart).toStrictEqual('Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg');
test("localpart is present", () => {
expect(room.localpart).toStrictEqual("Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg");
});
test('server name is present', () => {
test("server name is present", () => {
expect(room.serverName).toBeUndefined();
});
test('can read the room ID as string', () => {
expect(room.toString()).toStrictEqual('$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg');
test("can read the room ID as string", () => {
expect(room.toString()).toStrictEqual("$Rqnc-F-dvnEYJTyHq_iKxU2bZ1CI92-kuZq3a5lr5Zg");
});
});
})
});
File diff suppressed because it is too large Load Diff
@@ -1,7 +1,16 @@
const { RequestType, KeysUploadRequest, KeysQueryRequest, KeysClaimRequest, ToDeviceRequest, SignatureUploadRequest, RoomMessageRequest, KeysBackupRequest } = require('../pkg/matrix_sdk_crypto_js');
const {
RequestType,
KeysUploadRequest,
KeysQueryRequest,
KeysClaimRequest,
ToDeviceRequest,
SignatureUploadRequest,
RoomMessageRequest,
KeysBackupRequest,
} = require("../pkg/matrix_sdk_crypto_js");
describe('RequestType', () => {
test('has the correct variant values', () => {
describe("RequestType", () => {
test("has the correct variant values", () => {
expect(RequestType.KeysUpload).toStrictEqual(0);
expect(RequestType.KeysQuery).toStrictEqual(1);
expect(RequestType.KeysClaim).toStrictEqual(2);
@@ -11,25 +20,3 @@ describe('RequestType', () => {
expect(RequestType.KeysBackup).toStrictEqual(6);
});
});
for (const [request, requestType] of [
[KeysUploadRequest, RequestType.KeysUpload],
[KeysQueryRequest, RequestType.KeysQuery],
[KeysClaimRequest, RequestType.KeysClaim],
[ToDeviceRequest, RequestType.ToDevice],
[SignatureUploadRequest, RequestType.SignatureUpload],
[RoomMessageRequest, RequestType.RoomMessage],
[KeysBackupRequest, RequestType.KeysBackup],
]) {
describe(request.name, () => {
test('can be instantiated', () => {
const r = new (request)('foo', '{"bar": "baz"}');
expect(r).toBeInstanceOf(request);
expect(r.id).toStrictEqual('foo');
expect(r.body).toStrictEqual('{"bar": "baz"}');
expect(r.type).toStrictEqual(requestType);
});
})
}
@@ -1,7 +1,7 @@
const { DeviceLists, UserId } = require('../pkg/matrix_sdk_crypto_js');
const { DeviceLists, UserId } = require("../pkg/matrix_sdk_crypto_js");
describe(DeviceLists.name, () => {
test('can be empty', () => {
test("can be empty", () => {
const empty = new DeviceLists();
expect(empty.isEmpty()).toStrictEqual(true);
@@ -9,7 +9,7 @@ describe(DeviceLists.name, () => {
expect(empty.left).toHaveLength(0);
});
test('can be coerced empty', () => {
test("can be coerced empty", () => {
const empty = new DeviceLists([], []);
expect(empty.isEmpty()).toStrictEqual(true);
@@ -17,15 +17,15 @@ describe(DeviceLists.name, () => {
expect(empty.left).toHaveLength(0);
});
test('returns the correct `changed` and `left`', () => {
const list = new DeviceLists([new UserId('@foo:bar.org')], [new UserId('@baz:qux.org')]);
test("returns the correct `changed` and `left`", () => {
const list = new DeviceLists([new UserId("@foo:bar.org")], [new UserId("@baz:qux.org")]);
expect(list.isEmpty()).toStrictEqual(false);
expect(list.changed).toHaveLength(1);
expect(list.changed[0].toString()).toStrictEqual('@foo:bar.org');
expect(list.changed[0].toString()).toStrictEqual("@foo:bar.org");
expect(list.left).toHaveLength(1);
expect(list.left[0].toString()).toStrictEqual('@baz:qux.org');
expect(list.left[0].toString()).toStrictEqual("@baz:qux.org");
});
});
@@ -1,7 +1,7 @@
const { Tracing, LoggerLevel, OlmMachine, UserId, DeviceId } = require('../pkg/matrix_sdk_crypto_js');
const { Tracing, LoggerLevel, OlmMachine, UserId, DeviceId } = require("../pkg/matrix_sdk_crypto_js");
describe('LoggerLevel', () => {
test('has the correct variant values', () => {
describe("LoggerLevel", () => {
test("has the correct variant values", () => {
expect(LoggerLevel.Trace).toStrictEqual(0);
expect(LoggerLevel.Debug).toStrictEqual(1);
expect(LoggerLevel.Info).toStrictEqual(2);
@@ -14,7 +14,7 @@ describe(Tracing.name, () => {
if (Tracing.isAvailable()) {
let tracing = new Tracing(LoggerLevel.Debug);
test('can installed several times', () => {
test("can installed several times", () => {
new Tracing(LoggerLevel.Debug);
new Tracing(LoggerLevel.Warn);
new Tracing(LoggerLevel.Debug);
@@ -23,27 +23,30 @@ describe(Tracing.name, () => {
const originalConsoleDebug = console.debug;
for (const [testName, testPreState, testPostState, expectedGotcha] of [
["can log something", () => {}, () => {}, true],
[
'can log something',
() => {},
() => {},
true,
],
[
'can change the logger level',
() => { tracing.minLevel = LoggerLevel.Warn },
() => { tracing.minLevel = LoggerLevel.Debug },
"can change the logger level",
() => {
tracing.minLevel = LoggerLevel.Warn;
},
() => {
tracing.minLevel = LoggerLevel.Debug;
},
false,
],
[
'can be turned off',
() => { tracing.turnOff() },
"can be turned off",
() => {
tracing.turnOff();
},
() => {},
false,
],
[
'can be turned on',
() => { tracing.turnOn() },
"can be turned on",
() => {
tracing.turnOn();
},
() => {},
true,
],
@@ -51,8 +54,10 @@ describe(Tracing.name, () => {
// This one *must* be the last. We are turning tracing off
// again for the other tests.
[
'can be turned off',
() => { tracing.turnOff() },
"can be turned off",
() => {
tracing.turnOff();
},
() => {},
false,
],
@@ -68,7 +73,7 @@ describe(Tracing.name, () => {
};
// Do something that emits a `DEBUG` log.
await new OlmMachine(new UserId('@alice:example.org'), new DeviceId('foo'));
await OlmMachine.initialize(new UserId("@alice:example.org"), new DeviceId("foo"));
console.debug = originalConsoleDebug;
testPostState();
@@ -77,8 +82,10 @@ describe(Tracing.name, () => {
});
}
} else {
test('cannot be constructed', () => {
expect(() => { new Tracing(LoggerLevel.Error) }).toThrow();
test("cannot be constructed", () => {
expect(() => {
new Tracing(LoggerLevel.Error);
}).toThrow();
});
}
});
+1 -1
View File
@@ -5,6 +5,6 @@
"typedocOptions": {
"entryPoints": ["pkg/matrix_sdk_crypto_js.d.ts"],
"out": "docs",
"readme": "README.md",
"readme": "README.md"
}
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -4,4 +4,4 @@
/index.d.ts
/matrix-sdk-crypto.*.node
/docs/*
*.tgz
*.tgz
@@ -5,4 +5,3 @@ build.rs
*.node
*.tgz
tsconfig.json
cliff.toml
@@ -0,0 +1 @@
/pkg
@@ -0,0 +1,9 @@
// prettier configuration: the same as the conventions used throughout Matrix.org
// see: https://github.com/matrix-org/eslint-plugin-matrix-org/blob/main/.prettierrc.js
module.exports = {
printWidth: 120,
tabWidth: 4,
quoteProps: "consistent",
trailingComma: "all",
};
@@ -2,7 +2,7 @@
## 0.1.0-beta.1 - 2022-07-14
- Fixing broken download link, [#842](https://github.com/matrix-org/matrix-rust-sdk/issues/842)
- Fixing broken download link, [#842](https://github.com/matrix-org/matrix-rust-sdk/issues/842)
## 0.1.0-beta.0 - 2022-07-12
+14 -11
View File
@@ -8,7 +8,7 @@ license = "Apache-2.0"
name = "matrix-sdk-crypto-nodejs"
readme = "README.md"
repository = "https://github.com/matrix-org/matrix-rust-sdk"
rust-version = "1.60"
rust-version = { workspace = true }
version = "0.6.0"
[package.metadata.docs.rs]
@@ -18,25 +18,28 @@ rustdoc-args = ["--cfg", "docsrs"]
crate-type = ["cdylib"]
[features]
default = []
default = ["bundled-sqlite"]
bundled-sqlite = ["matrix-sdk-sqlite/bundled"]
qrcode = ["matrix-sdk-crypto/qrcode"]
tracing = ["dep:tracing-subscriber"]
[dependencies]
matrix-sdk-crypto = { version = "0.6.0", path = "../../crates/matrix-sdk-crypto", features = ["js"] }
matrix-sdk-common = { version = "0.6.0", path = "../../crates/matrix-sdk-common", features = ["js"] }
matrix-sdk-sled = { version = "0.2.0", path = "../../crates/matrix-sdk-sled", default-features = false, features = ["crypto-store"] }
ruma = { version = "0.7.0", features = ["client-api-c", "rand", "unstable-msc2676", "unstable-msc2677"] }
matrix-sdk-sqlite = { version = "0.1.0", path = "../../crates/matrix-sdk-sqlite", features = ["crypto-store"] }
ruma = { workspace = true, features = ["rand"] }
napi = { version = "2.9.1", default-features = false, features = ["napi6", "tokio_rt"] }
napi-derive = "2.9.1"
serde_json = "1.0.79"
http = "0.2.6"
zeroize = "1.3.0"
serde_json = { workspace = true }
http = { workspace = true }
tracing-subscriber = { version = "0.3", default-features = false, features = ["tracing-log", "time", "smallvec", "fmt", "env-filter"], optional = true }
vodozemac = { workspace = true, features = ["js"] }
zeroize = { workspace = true }
[dependencies.vodozemac]
version = "0.3.0"
features = ["js"]
[dependencies.matrix-sdk-crypto]
path = "../../crates/matrix-sdk-crypto"
version = "0.6.0"
default_features = false
features = ["js", "automatic-room-key-forwarding"]
[build-dependencies]
napi-build = "2.0.0"
+27 -15
View File
@@ -12,6 +12,7 @@ Encryption](https://en.wikipedia.org/wiki/End-to-end_encryption)) for
## Usage
Just add the latest release to your `package.json`:
```sh
$ npm install --save @matrix-org/matrix-sdk-crypto-nodejs
```
@@ -95,8 +96,8 @@ according to [the Node.js Releases
Page](https://nodejs.org/en/about/releases/), _and_ which are
compatible with [NAPI v6 (Node.js
API)](https://nodejs.org/api/n-api.html#node-api-version-matrix). It
means that this binding will work with the following versions: 14.0.0,
16.0.0 and 18.0.0.
means that this binding will work with the following versions: 16.0.0,
18.0.0, 19.0.0 and 20.0.0.
Once the Rust compiler, Node.js and npm are installed, you can run the
following commands:
@@ -112,35 +113,34 @@ generated. At the same level of those files, you can edit a file and
try this:
```javascript
const { OlmMachine } = require('./index.js');
const { OlmMachine } = require("./index.js");
// Let's see what we can do.
```
The `OlmMachine` state machine works in a push/pull manner:
* You push state changes and events retrieved from a Matrix homeserver
`/sync` response, into the state machine,
* You pull requests that you will need to send back to the homeserver
out of the state machine.
- You push state changes and events retrieved from a Matrix homeserver
`/sync` response, into the state machine,
- You pull requests that you will need to send back to the homeserver
out of the state machine.
```javascript
const { OlmMachine, UserId, DeviceId, RoomId, DeviceLists } = require('./index.js');
const { OlmMachine, UserId, DeviceId, RoomId, DeviceLists } = require("./index.js");
async function main() {
// Define a user ID.
const alice = new UserId('@alice:example.org');
const alice = new UserId("@alice:example.org");
// Define a device ID.
const device = new DeviceId('DEVICEID');
const device = new DeviceId("DEVICEID");
// Let's create the `OlmMachine` state machine.
const machine = await OlmMachine.initialize(alice, device);
// Let's pretend we have received changes and events from a
// `/sync` endpoint of a Matrix homeserver, …
const toDeviceEvents = "{}"; // JSON-encoded
const toDeviceEvents = "[]"; // JSON-encoded list of events
const changedDevices = new DeviceLists();
const oneTimeKeyCounts = {};
const unusedFallbackKeys = [];
@@ -184,6 +184,20 @@ See
[`tracing-subscriber`](https://tracing.rs/tracing_subscriber/index.html)
to learn more about the `RUST_LOG`/`MATRIX_LOG` environment variable.
#### Using tracing in dependent projects
To enable tracing in client applications that import these bindings, here's how to do it in
a local development environment:
- In this directory, run `npm link` to make your local build of the bindings available to
other Node projects on your system
- In your client app's source directory, run `npm link @matrix-org/matrix-sdk-crypto-nodejs`
to make it use your trace-enabled local build of the bindings
- In your client app's source code, add a call to `initTracing` near startup time
- Run your app with the `MATRIX_LOG` environment variable set to the desired log level
Either `npm link` command may be substituted with `yarn link`.
## Documentation
[The documentation can be found
@@ -198,8 +212,6 @@ $ npm run doc
The documentation is generated in the `./docs` directory.
[Node.js]: https://nodejs.org/
[`matrix-sdk-crypto`]: https://github.com/matrix-org/matrix-rust-sdk/tree/main/crates/matrix-sdk-crypto
[`matrix-rust-sdk`]: https://github.com/matrix-org/matrix-rust-sdk
@@ -1,61 +0,0 @@
# configuration file for git-cliff (0.1.0)
[changelog]
# changelog header
header = """
# Matrix SDK Crypto Node.js Changelog\n
All notable changes to this project will be documented in this file.\n
"""
# template for the changelog body
# https://tera.netlify.app/docs/#introduction
body = """
{% if version %}\
## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }}
{% else %}\
## [unreleased]
{% endif %}\
{% for group, commits in commits | filter(attribute="scope", value="crypto-nodejs") | group_by(attribute="group") %}
### {{ group | upper_first }}
{% for commit in commits %}
- {{ commit.id | truncate(length=7, end="") }}{% if commit.breaking %} [**breaking**] {% endif %}: {{ commit.message | upper_first }}\
{% endfor %}
{% endfor %}\n
"""
# remove the leading and trailing whitespace from the template
trim = true
# changelog footer
footer = """
"""
[git]
# parse the commits based on https://www.conventionalcommits.org
conventional_commits = true
# filter out the commits that are not conventional
filter_unconventional = true
# regex for preprocessing the commit messages
commit_preprocessors = [
{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](https://github.com/matrix-org/matrix-rust-sdk/issues/${2}))"},
]
# regex for parsing and grouping commits
commit_parsers = [
{ message = "^feat", group = "Features"},
{ message = "^fix", group = "Bug Fixes"},
{ message = "^test", group = "Testing"},
{ message = "^doc", group = "Documentation"},
{ message = "^refactor", group = "Refactoring"},
{ message = "^ci", group = "Continuous Integration"},
{ message = "^chore", group = "Miscellaneous Tasks"},
{ body = ".*security", group = "Security"},
]
# filter out the commits that are not matched by commit parsers
filter_commits = true
# glob pattern for matching git tags
tag_pattern = "v[0-9]*"
# regex for skipping tags
skip_tags = "v0.1.0-beta.1"
# regex for ignoring tags
ignore_tags = ""
# sort the tags chronologically
date_order = false
# sort the commits inside sections by oldest/newest order
sort_commits = "oldest"
@@ -1,18 +1,18 @@
const { DownloaderHelper } = require('node-downloader-helper');
const { HttpsProxyAgent } = require("https-proxy-agent");
const { DownloaderHelper } = require("node-downloader-helper");
const { version } = require("./package.json");
const { platform, arch } = process
const { platform, arch } = process;
const DOWNLOADS_BASE_URL = "https://github.com/matrix-org/matrix-rust-sdk/releases/download";
const CURRENT_VERSION = `matrix-sdk-crypto-nodejs-v${version}`;
const byteHelper = function (value) {
if (value === 0) {
return '0 b';
return "0 b";
}
const units = ['b', 'kB', 'MB', 'GB', 'TB'];
const units = ["b", "kB", "MB", "GB", "TB"];
const number = Math.floor(Math.log(value) / Math.log(1024));
return (value / Math.pow(1024, Math.floor(number))).toFixed(1) + ' ' +
units[number];
return (value / Math.pow(1024, Math.floor(number))).toFixed(1) + " " + units[number];
};
function download_lib(libname) {
@@ -24,9 +24,17 @@ function download_lib(libname) {
override: true,
});
dl.on('end', () => console.info('Download Completed'));
dl.on('error', (err) => console.info('Download Failed', err));
dl.on('progress', stats => {
const proxy = process.env.https_proxy ?? process.env.HTTPS_PROXY;
if (proxy) {
const proxyAgent = new HttpsProxyAgent(proxy);
dl.updateOptions({
httpsRequestOptions: { agent: proxyAgent },
});
}
dl.on("end", () => console.info("Download Completed"));
dl.on("error", (err) => console.info("Download Failed", err));
dl.on("progress", (stats) => {
const progress = stats.progress.toFixed(1);
const speed = byteHelper(stats.speed);
const downloaded = byteHelper(stats.downloaded);
@@ -40,74 +48,74 @@ function download_lib(libname) {
console.info(`${speed}/s - ${progress}% [${downloaded}/${total}]`);
}
});
dl.start().catch(err => console.error(err));
dl.start().catch((err) => console.error(err));
}
function isMusl() {
// For Node 10
if (!process.report || typeof process.report.getReport !== 'function') {
try {
return readFileSync('/usr/bin/ldd', 'utf8').includes('musl')
} catch (e) {
return true
// For Node 10
if (!process.report || typeof process.report.getReport !== "function") {
try {
return readFileSync("/usr/bin/ldd", "utf8").includes("musl");
} catch (e) {
return true;
}
} else {
const { glibcVersionRuntime } = process.report.getReport().header;
return !glibcVersionRuntime;
}
} else {
const { glibcVersionRuntime } = process.report.getReport().header
return !glibcVersionRuntime
}
}
switch (platform) {
case 'win32':
switch (arch) {
case 'x64':
download_lib('matrix-sdk-crypto.win32-x64-msvc.node')
break
case 'ia32':
download_lib('matrix-sdk-crypto.win32-ia32-msvc.node')
break
case 'arm64':
download_lib('matrix-sdk-crypto.win32-arm64-msvc.node')
break
default:
throw new Error(`Unsupported architecture on Windows: ${arch}`)
}
break
case 'darwin':
switch (arch) {
case 'x64':
download_lib('matrix-sdk-crypto.darwin-x64.node')
break
case 'arm64':
download_lib('matrix-sdk-crypto.darwin-arm64.node')
break
default:
throw new Error(`Unsupported architecture on macOS: ${arch}`)
}
break
case 'linux':
switch (arch) {
case 'x64':
if (isMusl()) {
download_lib('matrix-sdk-crypto.linux-x64-musl.node')
} else {
download_lib('matrix-sdk-crypto.linux-x64-gnu.node')
case "win32":
switch (arch) {
case "x64":
download_lib("matrix-sdk-crypto.win32-x64-msvc.node");
break;
case "ia32":
download_lib("matrix-sdk-crypto.win32-ia32-msvc.node");
break;
case "arm64":
download_lib("matrix-sdk-crypto.win32-arm64-msvc.node");
break;
default:
throw new Error(`Unsupported architecture on Windows: ${arch}`);
}
break
case 'arm64':
if (isMusl()) {
throw new Error('Linux for arm64 musl isn\'t support at the moment')
} else {
download_lib('matrix-sdk-crypto.linux-arm64-gnu.node')
break;
case "darwin":
switch (arch) {
case "x64":
download_lib("matrix-sdk-crypto.darwin-x64.node");
break;
case "arm64":
download_lib("matrix-sdk-crypto.darwin-arm64.node");
break;
default:
throw new Error(`Unsupported architecture on macOS: ${arch}`);
}
break
case 'arm':
download_lib('matrix-sdk-crypto.linux-arm-gnueabihf.node')
break
default:
throw new Error(`Unsupported architecture on Linux: ${arch}`)
}
break
default:
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
break;
case "linux":
switch (arch) {
case "x64":
if (isMusl()) {
download_lib("matrix-sdk-crypto.linux-x64-musl.node");
} else {
download_lib("matrix-sdk-crypto.linux-x64-gnu.node");
}
break;
case "arm64":
if (isMusl()) {
throw new Error("Linux for arm64 musl isn't support at the moment");
} else {
download_lib("matrix-sdk-crypto.linux-arm64-gnu.node");
}
break;
case "arm":
download_lib("matrix-sdk-crypto.linux-arm-gnueabihf.node");
break;
default:
throw new Error(`Unsupported architecture on Linux: ${arch}`);
}
break;
default:
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`);
}
@@ -15,13 +15,15 @@
"devDependencies": {
"@napi-rs/cli": "^2.9.0",
"jest": "^28.1.0",
"prettier": "^2.8.3",
"typedoc": "^0.22.17",
"yargs-parser": "~21.0.1"
},
"engines": {
"node": ">= 14"
"node": ">= 16"
},
"scripts": {
"lint": "prettier --check .",
"release-build": "napi build --platform --release --strip",
"build": "napi build --platform",
"postinstall": "node download-lib.js",
@@ -29,6 +31,7 @@
"doc": "typedoc --tsconfig ."
},
"dependencies": {
"node-downloader-helper": "^2.1.1"
"https-proxy-agent": "^5.0.1",
"node-downloader-helper": "^2.1.5"
}
}
@@ -50,14 +50,11 @@ impl Attachment {
/// by calling `EncryptedAttachment.mediaEncryptionInfo`.
#[napi]
pub fn decrypt(attachment: &mut EncryptedAttachment) -> napi::Result<Uint8Array> {
let media_encryption_info = match attachment.media_encryption_info.take() {
Some(media_encryption_info) => media_encryption_info,
None => {
return Err(napi::Error::from_reason(
"The media encryption info are absent from the given encrypted attachment"
.to_owned(),
))
}
let Some(media_encryption_info) = attachment.media_encryption_info.take() else {
return Err(napi::Error::from_reason(
"The media encryption info are absent from the given encrypted attachment"
.to_owned(),
));
};
let encrypted_data: &[u8] = attachment.encrypted_data.deref();
@@ -1,6 +1,7 @@
use std::time::Duration;
use napi::bindgen_prelude::{BigInt, ToNapiValue};
use matrix_sdk_common::deserialized_responses::ShieldState as RustShieldState;
use napi::bindgen_prelude::{BigInt, FromNapiValue, ToNapiValue};
use napi_derive::*;
use crate::events;
@@ -107,27 +108,33 @@ impl From<&EncryptionSettings> for matrix_sdk_crypto::olm::EncryptionSettings {
}
}
/// The verification state of the device that sent an event to us.
/// Take a look at [`matrix_sdk_common::deserialized_responses::ShieldState`]
/// for more info.
#[napi]
pub enum VerificationState {
/// The device is trusted.
Trusted,
/// The device is not trusted.
Untrusted,
/// The device is not known to us.
UnknownDevice,
pub enum ShieldColor {
Red,
Grey,
None,
}
impl From<&matrix_sdk_common::deserialized_responses::VerificationState> for VerificationState {
fn from(value: &matrix_sdk_common::deserialized_responses::VerificationState) -> Self {
use matrix_sdk_common::deserialized_responses::VerificationState::*;
/// Take a look at [`matrix_sdk_common::deserialized_responses::ShieldState`]
/// for more info.
#[napi]
pub struct ShieldState {
pub color: ShieldColor,
pub message: Option<&'static str>,
}
impl From<RustShieldState> for ShieldState {
fn from(value: RustShieldState) -> Self {
match value {
Trusted => Self::Trusted,
Untrusted => Self::Untrusted,
UnknownDevice => Self::UnknownDevice,
RustShieldState::Red { message } => {
ShieldState { color: ShieldColor::Red, message: Some(message) }
}
RustShieldState::Grey { message } => {
ShieldState { color: ShieldColor::Grey, message: Some(message) }
}
RustShieldState::None => ShieldState { color: ShieldColor::None, message: None },
}
}
}

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