The Rust SDK removed the low-level SecretStoreWrapper.putSecret/getSecret
API between 26.03.x and 26.04.x — it was an escape hatch we were using
to pin arbitrary bytes into a Matrix 4S slot. The SDK maintainers never
contracted that primitive; locking it down lets their recovery code
evolve without worrying about third-party storage.
This commit replaces that dependency with a self-contained design we
own end-to-end, so future SDK moves no longer break our backup flow.
### Design
- Slot: `com.sulkta.wallet.seed.v1` in Matrix account data.
Our namespace, not a Matrix-spec 4S slot — we are NOT impersonating
Matrix secret storage, we are holding our own opaque blob.
- Envelope (JSON): version tag, algorithm tag, random 12-byte IV, GCM
output (ciphertext || tag), AAD = slot name. AES-256-GCM via stock
javax.crypto. AAD binds a blob to its slot so a blob can't be lifted
from one namespace and successfully opened in another.
- Key: derived from the user's existing Matrix recovery key via
HKDF-SHA256 with info label "sulkta.wallet.seed.v1". The info label
guarantees we never produce the same key bytes Matrix uses for its
own crypto — same secret, different domain.
- I/O: client.setAccountData(key, json) + client.accountData(key)
via the SDK; the homeserver only ever sees the opaque encrypted blob.
### Files
- api/walletsecretstorage/WalletSecretStorage.kt — new interface
- impl/walletsecretstorage/WalletSecretEnvelope.kt — AES-GCM envelope
(with unit tests: round-trip, wrong key, tampered ct, tampered iv,
wrong AAD, wrong version, malformed JSON)
- impl/walletsecretstorage/RecoveryKeyDerivation.kt — base58 decode
+ parity check + HKDF-SHA256 (with unit tests: determinism,
whitespace tolerance, distinct info labels → distinct keys)
- impl/walletsecretstorage/MatrixAccountDataWalletSecretStorage.kt —
WalletSecretStorage impl wrapping Client account data
- test/walletsecretstorage/FakeWalletSecretStorage.kt — in-memory fake
- api/MatrixClient.kt: old .secretStorage → .walletSecretStorage
- features/wallet/.../WalletBackupServiceImpl.kt — rewired to use the
new interface; hasBackupWithoutKey now goes through the same path
instead of manually poking the raw Matrix HTTP API.
- DELETED: api/secretstorage/SecretStorage.kt, SecretStore.kt, impl/
secretstorage/RustSecretStorage.kt — the old SDK-dependent path.
### Backward compat note
Users who backed up a wallet seed on the OLD SDK have a blob in Matrix's
4S at `com.sulkta.cardano.wallet_seed`. This branch cannot read those.
Since the prior integration was only tested internally, acceptable
today — anyone with an old backup re-enters their mnemonic.
* Take into account homeserver capabilities: add `HomeserverCapabilitiesProvider` to check if the HS allows changing the user's display name or avatar. Also, modify the edit user profile screen to reflect these values.
* Add `/myavatar` command. Filter both `/nick` and `/myavatar` commands based on the homeserver capabilities.
* Update screenshots
* Assume the use can change their display name and avatar url if the capabilities check fails: if they try to change those, the HS will return an error anyway.
* Disable also `/myroomname` and `/myroomavatar` based on the HS capabilities.
---------
Co-authored-by: ElementBot <android@element.io>
Add threads list screen for rooms:
- Add `ThreadsListService` to subscribe to thread changes in the room.
- Create `ThreadsListView` and its associated node a presenters (the UI may change).
- Add a menu icon in the room screen to open it.
This is still pending info about unread threads, so several UI components related to it will be hidden.
* Add feature flag and use it to hide the access to this new screen
---------
Co-authored-by: ElementBot <android@element.io>
* feat: Add confirmation modal when inviting unknown users
* tests: Add preview tests for invite confirmation modal
* tests: Add unit tests for invite confirmation modal
* feat: Switch confirmation sheet contents based on identity state
* tests: Add history sharing unit tests for `DefaultStartDMActionTest`
* tests: Update snapshots for `CreateDmConfirmationBottomSheet`
* chore: Fix tiny nits
* fix: Remove default param on `ConfirmingStartDmWithMatrixUser`
* refactor: Use new AsyncAction over boolean flag
* fix: Add sleeps to tests
* refactor: Remove `PromptOrInvite` and switch on async action
* fix: Remove redundant `assertThat`
* feat: Alllow invite confirmation modal to be dismissed
* tests: Update snapshots for InvitePeopleView
* fix: Adjust `CreateDmConfirmationBottomSheet` to conform to design
* feat: Use localazy translations and plurals
* fix: When users are unselected, unselect them in search results too
* tests: Use aMatrixUserList to provide multiple users
* Update screenshots
* fix: Add missing parameter in UserProfilePresenterTest
---------
Co-authored-by: Andy Balaam <andy.balaam@matrix.org>
Co-authored-by: ElementBot <android@element.io>
* Fix `isInAirGappedEnvironment` check for older APIs: use `networkCapabilities.hasCapability` instead of `networkCapabilities.capabilities.contains`, which only works on Android 12 and newer versions
* Check for air-gapped env in the FOSS app too: this unifies the notification behaviour on EXA and Element Pro