1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-12-16 09:42:23 +03:00

Experimental support for sharing encrypted history on invite (#4920)

* tests: Cross-signing keys support in `E2EKeyReceiver`

Have `E2EKeyReceiver` collect uploaded cross-signing keys, so that they can be
returned by `E2EKeyResponder`.

* tests: Signature upload support in `E2EKeyReceiver`

Have `E2EKeyReceiver` collect uploaded device signatures, so that they can be
returned by `E2EKeyResponder`.

* tests: Implement `E2EOTKClaimResponder` class

A new test helper, which intercepts `/keys/claim`, allowing clients under test
to claim OTKs uploaded by other devices.

* Expose experimental settings for encrypted history sharing

Add options to `MatrixClient.invite` and `MatrixClient.joinRoom` to share and
accept encrypted history on invite, per MSC4268.

* Clarify pre-join-membership logic

* Improve tests

* Update spec/integ/crypto/cross-signing.spec.ts

Co-authored-by: Hubert Chathi <hubertc@matrix.org>

---------

Co-authored-by: Hubert Chathi <hubertc@matrix.org>
This commit is contained in:
Richard van der Hoff
2025-07-29 16:42:35 +01:00
committed by GitHub
parent 56b24c0bdc
commit c4e1e0723e
13 changed files with 694 additions and 89 deletions

View File

@@ -223,9 +223,9 @@ import { RUST_SDK_STORE_PREFIX } from "./rust-crypto/constants.ts";
import {
type CrossSigningKeyInfo,
type CryptoApi,
type CryptoCallbacks,
CryptoEvent,
type CryptoEventHandlerMap,
type CryptoCallbacks,
} from "./crypto-api/index.ts";
import {
type SecretStorageKeyDescription,
@@ -2371,7 +2371,17 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
*/
public async joinRoom(roomIdOrAlias: string, opts: IJoinRoomOpts = {}): Promise<Room> {
const room = this.getRoom(roomIdOrAlias);
if (room?.hasMembershipState(this.credentials.userId!, KnownMembership.Join)) return room;
const roomMember = room?.getMember(this.getSafeUserId());
const preJoinMembership = roomMember?.membership;
// If we were invited to the room, the ID of the user that sent the invite. Otherwise, `null`.
const inviter =
preJoinMembership == KnownMembership.Invite ? (roomMember?.events.member?.getSender() ?? null) : null;
this.logger.debug(
`joinRoom[${roomIdOrAlias}]: preJoinMembership=${preJoinMembership}, inviter=${inviter}, opts=${JSON.stringify(opts)}`,
);
if (preJoinMembership == KnownMembership.Join) return room!;
let signPromise: Promise<IThirdPartySigned | void> = Promise.resolve();
@@ -2398,6 +2408,10 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
const res = await this.http.authedRequest<{ room_id: string }>(Method.Post, path, queryParams, data);
const roomId = res.room_id;
if (opts.acceptSharedHistory && inviter && this.cryptoBackend) {
await this.cryptoBackend.maybeAcceptKeyBundle(roomId, inviter);
}
// In case we were originally given an alias, check the room cache again
// with the resolved ID - this method is supposed to no-op if we already
// were in the room, after all.
@@ -3764,11 +3778,16 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
*
* @returns An empty object.
*/
public invite(roomId: string, userId: string, opts: InviteOpts | string = {}): Promise<EmptyObject> {
public async invite(roomId: string, userId: string, opts: InviteOpts | string = {}): Promise<EmptyObject> {
if (typeof opts != "object") {
opts = { reason: opts };
}
return this.membershipChange(roomId, userId, KnownMembership.Invite, opts.reason);
if (opts.shareEncryptedHistory) {
await this.cryptoBackend?.shareRoomHistoryWithUser(roomId, userId);
}
return await this.membershipChange(roomId, userId, KnownMembership.Invite, opts.reason);
}
/**