You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-06-13 00:41:55 +03:00
Element R: emit events when devices have changed (#4019)
* emit events when Rust crypto wasm tells us devices have changed * lint * add missing stub function * apply workaround for queueMicrotask
This commit is contained in:
@ -94,6 +94,7 @@ describe("initRustCrypto", () => {
|
|||||||
getSecretsFromInbox: jest.fn().mockResolvedValue([]),
|
getSecretsFromInbox: jest.fn().mockResolvedValue([]),
|
||||||
deleteSecretsFromInbox: jest.fn(),
|
deleteSecretsFromInbox: jest.fn(),
|
||||||
registerReceiveSecretCallback: jest.fn(),
|
registerReceiveSecretCallback: jest.fn(),
|
||||||
|
registerDevicesUpdatedCallback: jest.fn(),
|
||||||
outgoingRequests: jest.fn(),
|
outgoingRequests: jest.fn(),
|
||||||
isBackupEnabled: jest.fn().mockResolvedValue(false),
|
isBackupEnabled: jest.fn().mockResolvedValue(false),
|
||||||
verifyBackup: jest.fn().mockResolvedValue({ trusted: jest.fn().mockReturnValue(false) }),
|
verifyBackup: jest.fn().mockResolvedValue({ trusted: jest.fn().mockReturnValue(false) }),
|
||||||
@ -1132,6 +1133,33 @@ describe("RustCrypto", () => {
|
|||||||
rustCrypto.stop();
|
rustCrypto.stop();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should emit events on device changes", async () => {
|
||||||
|
jest.useFakeTimers({ doNotFake: ["queueMicrotask"] });
|
||||||
|
|
||||||
|
fetchMock.post("path:/_matrix/client/v3/keys/upload", { one_time_key_counts: {} });
|
||||||
|
fetchMock.post("path:/_matrix/client/v3/keys/query", {
|
||||||
|
device_keys: {
|
||||||
|
[testData.TEST_USER_ID]: {
|
||||||
|
[testData.TEST_DEVICE_ID]: testData.SIGNED_TEST_DEVICE_DATA,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const rustCrypto = await makeTestRustCrypto(makeMatrixHttpApi(), testData.TEST_USER_ID);
|
||||||
|
const willUpdateCallback = jest.fn();
|
||||||
|
rustCrypto.on(CryptoEvent.WillUpdateDevices, willUpdateCallback);
|
||||||
|
const devicesUpdatedCallback = jest.fn();
|
||||||
|
rustCrypto.on(CryptoEvent.DevicesUpdated, devicesUpdatedCallback);
|
||||||
|
|
||||||
|
rustCrypto.onSyncCompleted({});
|
||||||
|
|
||||||
|
// wait for the devices to be updated
|
||||||
|
await rustCrypto.getUserDeviceInfo([testData.TEST_USER_ID]);
|
||||||
|
expect(willUpdateCallback).toHaveBeenCalledWith([testData.TEST_USER_ID], false);
|
||||||
|
expect(devicesUpdatedCallback).toHaveBeenCalledWith([testData.TEST_USER_ID], false);
|
||||||
|
rustCrypto.stop();
|
||||||
|
});
|
||||||
|
|
||||||
describe("requestDeviceVerification", () => {
|
describe("requestDeviceVerification", () => {
|
||||||
it("throws an error if the device is unknown", async () => {
|
it("throws an error if the device is unknown", async () => {
|
||||||
const rustCrypto = await makeTestRustCrypto();
|
const rustCrypto = await makeTestRustCrypto();
|
||||||
|
@ -2360,6 +2360,9 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
CryptoEvent.KeyBackupSessionsRemaining,
|
CryptoEvent.KeyBackupSessionsRemaining,
|
||||||
CryptoEvent.KeyBackupFailed,
|
CryptoEvent.KeyBackupFailed,
|
||||||
CryptoEvent.KeyBackupDecryptionKeyCached,
|
CryptoEvent.KeyBackupDecryptionKeyCached,
|
||||||
|
CryptoEvent.KeysChanged,
|
||||||
|
CryptoEvent.DevicesUpdated,
|
||||||
|
CryptoEvent.WillUpdateDevices,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,6 +158,7 @@ async function initOlmMachine(
|
|||||||
await olmMachine.registerUserIdentityUpdatedCallback((userId: RustSdkCryptoJs.UserId) =>
|
await olmMachine.registerUserIdentityUpdatedCallback((userId: RustSdkCryptoJs.UserId) =>
|
||||||
rustCrypto.onUserIdentityUpdated(userId),
|
rustCrypto.onUserIdentityUpdated(userId),
|
||||||
);
|
);
|
||||||
|
await olmMachine.registerDevicesUpdatedCallback((userIds: string[]) => rustCrypto.onDevicesUpdated(userIds));
|
||||||
|
|
||||||
// Check if there are any key backup secrets pending processing. There may be multiple secrets to process if several devices have gossiped them.
|
// Check if there are any key backup secrets pending processing. There may be multiple secrets to process if several devices have gossiped them.
|
||||||
// The `registerReceiveSecretCallback` function will only be triggered for new secrets. If the client is restarted before processing them, the secrets will need to be manually handled.
|
// The `registerReceiveSecretCallback` function will only be triggered for new secrets. If the client is restarted before processing them, the secrets will need to be manually handled.
|
||||||
|
@ -1441,7 +1441,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
|
|||||||
* Callback for `OlmMachine.registerUserIdentityUpdatedCallback`
|
* Callback for `OlmMachine.registerUserIdentityUpdatedCallback`
|
||||||
*
|
*
|
||||||
* Called by the rust-sdk whenever there is an update to any user's cross-signing status. We re-check their trust
|
* Called by the rust-sdk whenever there is an update to any user's cross-signing status. We re-check their trust
|
||||||
* status and emit a `UserTrustStatusChanged` event.
|
* status and emit a `UserTrustStatusChanged` event, as well as a `KeysChanged` if it is our own identity that changed.
|
||||||
*
|
*
|
||||||
* @param userId - the user with the updated identity
|
* @param userId - the user with the updated identity
|
||||||
*/
|
*/
|
||||||
@ -1452,10 +1452,26 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
|
|||||||
// If our own user identity has changed, we may now trust the key backup where we did not before.
|
// If our own user identity has changed, we may now trust the key backup where we did not before.
|
||||||
// So, re-check the key backup status and enable it if available.
|
// So, re-check the key backup status and enable it if available.
|
||||||
if (userId.toString() === this.userId) {
|
if (userId.toString() === this.userId) {
|
||||||
|
this.emit(CryptoEvent.KeysChanged, {});
|
||||||
await this.checkKeyBackupAndEnable();
|
await this.checkKeyBackupAndEnable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback for `OlmMachine.registerDevicesUpdatedCallback`
|
||||||
|
*
|
||||||
|
* Called when users' devices have updated. Emits `WillUpdateDevices` and `DevicesUpdated`. In the JavaScript
|
||||||
|
* crypto backend, these events are called at separate times, with `WillUpdateDevices` being emitted just before
|
||||||
|
* the devices are saved, and `DevicesUpdated` being emitted just after. But the OlmMachine only gives us
|
||||||
|
* one event, so we emit both events here.
|
||||||
|
*
|
||||||
|
* @param userIds - an array of user IDs of users whose devices have updated.
|
||||||
|
*/
|
||||||
|
public async onDevicesUpdated(userIds: string[]): Promise<void> {
|
||||||
|
this.emit(CryptoEvent.WillUpdateDevices, userIds, false);
|
||||||
|
this.emit(CryptoEvent.DevicesUpdated, userIds, false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles secret received from the rust secret inbox.
|
* Handles secret received from the rust secret inbox.
|
||||||
*
|
*
|
||||||
@ -1828,6 +1844,9 @@ function rustEncryptionInfoToJsEncryptionInfo(
|
|||||||
type RustCryptoEvents =
|
type RustCryptoEvents =
|
||||||
| CryptoEvent.VerificationRequestReceived
|
| CryptoEvent.VerificationRequestReceived
|
||||||
| CryptoEvent.UserTrustStatusChanged
|
| CryptoEvent.UserTrustStatusChanged
|
||||||
|
| CryptoEvent.KeysChanged
|
||||||
|
| CryptoEvent.WillUpdateDevices
|
||||||
|
| CryptoEvent.DevicesUpdated
|
||||||
| RustBackupCryptoEvents;
|
| RustBackupCryptoEvents;
|
||||||
|
|
||||||
type RustCryptoEventMap = {
|
type RustCryptoEventMap = {
|
||||||
@ -1842,4 +1861,31 @@ type RustCryptoEventMap = {
|
|||||||
[CryptoEvent.UserTrustStatusChanged]: (userId: string, userTrustLevel: UserVerificationStatus) => void;
|
[CryptoEvent.UserTrustStatusChanged]: (userId: string, userTrustLevel: UserVerificationStatus) => void;
|
||||||
|
|
||||||
[CryptoEvent.KeyBackupDecryptionKeyCached]: (version: string) => void;
|
[CryptoEvent.KeyBackupDecryptionKeyCached]: (version: string) => void;
|
||||||
|
/**
|
||||||
|
* Fires when the user's cross-signing keys have changed or cross-signing
|
||||||
|
* has been enabled/disabled. The client can use getStoredCrossSigningForUser
|
||||||
|
* with the user ID of the logged in user to check if cross-signing is
|
||||||
|
* enabled on the account. If enabled, it can test whether the current key
|
||||||
|
* is trusted using with checkUserTrust with the user ID of the logged
|
||||||
|
* in user. The checkOwnCrossSigningTrust function may be used to reconcile
|
||||||
|
* the trust in the account key.
|
||||||
|
*
|
||||||
|
* The cross-signing API is currently UNSTABLE and may change without notice.
|
||||||
|
* @experimental
|
||||||
|
*/
|
||||||
|
[CryptoEvent.KeysChanged]: (data: {}) => void;
|
||||||
|
/**
|
||||||
|
* Fires whenever the stored devices for a user will be updated
|
||||||
|
* @param users - A list of user IDs that will be updated
|
||||||
|
* @param initialFetch - If true, the store is empty (apart
|
||||||
|
* from our own device) and is being seeded.
|
||||||
|
*/
|
||||||
|
[CryptoEvent.WillUpdateDevices]: (users: string[], initialFetch: boolean) => void;
|
||||||
|
/**
|
||||||
|
* Fires whenever the stored devices for a user have changed
|
||||||
|
* @param users - A list of user IDs that were updated
|
||||||
|
* @param initialFetch - If true, the store was empty (apart
|
||||||
|
* from our own device) and has been seeded.
|
||||||
|
*/
|
||||||
|
[CryptoEvent.DevicesUpdated]: (users: string[], initialFetch: boolean) => void;
|
||||||
} & RustBackupCryptoEventMap;
|
} & RustBackupCryptoEventMap;
|
||||||
|
Reference in New Issue
Block a user