Dismiss "Key storage out of sync" toast when secrets received (#29348)

* DeviceListener: improve logging

use a LogSpan to tie together logs from the same run, and add some more logs
for various cases

* Regression playwright test

* Remove unused mocking of `getCrossSigningId`

DeviceListener no longer reads this thing

* Clean up unit tests

Remove redundant describe block

* Remove the "out of sync" toast when we are no longer out of sync

Receiving the crypto secrets via secret sharing should make the toast go away.
This commit is contained in:
Richard van der Hoff
2025-02-25 12:13:42 +00:00
committed by GitHub
parent 43efd911c7
commit 3cc1ccd029
3 changed files with 158 additions and 29 deletions

View File

@@ -7,7 +7,14 @@ Please see LICENSE files in the repository root for full details.
*/
import { type Mocked, mocked } from "jest-mock";
import { MatrixEvent, type Room, type MatrixClient, Device, ClientStoppedError } from "matrix-js-sdk/src/matrix";
import {
MatrixEvent,
type Room,
type MatrixClient,
Device,
ClientStoppedError,
ClientEvent,
} from "matrix-js-sdk/src/matrix";
import {
CryptoEvent,
type CrossSigningStatus,
@@ -81,7 +88,6 @@ describe("DeviceListener", () => {
getDeviceVerificationStatus: jest.fn().mockResolvedValue({
crossSigningVerified: false,
}),
getCrossSigningKeyId: jest.fn(),
getUserDeviceInfo: jest.fn().mockResolvedValue(new Map()),
isCrossSigningReady: jest.fn().mockResolvedValue(true),
isSecretStorageReady: jest.fn().mockResolvedValue(true),
@@ -328,26 +334,21 @@ describe("DeviceListener", () => {
expect(SetupEncryptionToast.showToast).not.toHaveBeenCalled();
});
describe("when user does not have a cross signing id on this device", () => {
beforeEach(() => {
mockCrypto!.getCrossSigningKeyId.mockResolvedValue(null);
});
it("shows verify session toast when account has cross signing", async () => {
mockCrypto!.isCrossSigningReady.mockResolvedValue(true);
await createAndStart();
it("shows verify session toast when account has cross signing", async () => {
mockCrypto!.isCrossSigningReady.mockResolvedValue(true);
await createAndStart();
expect(mockCrypto!.getUserDeviceInfo).toHaveBeenCalled();
expect(SetupEncryptionToast.showToast).toHaveBeenCalledWith(
SetupEncryptionToast.Kind.VERIFY_THIS_SESSION,
);
});
expect(mockCrypto!.getUserDeviceInfo).toHaveBeenCalled();
expect(SetupEncryptionToast.showToast).toHaveBeenCalledWith(
SetupEncryptionToast.Kind.VERIFY_THIS_SESSION,
);
});
describe("when user does have a cross signing id on this device", () => {
describe("when current device is verified", () => {
beforeEach(() => {
mockCrypto!.isCrossSigningReady.mockResolvedValue(true);
mockCrypto!.getCrossSigningKeyId.mockResolvedValue("abc");
// current device is verified
mockCrypto!.getDeviceVerificationStatus.mockResolvedValue(
new DeviceVerificationStatus({
trustCrossSignedDevices: true,
@@ -356,6 +357,60 @@ describe("DeviceListener", () => {
);
});
it("shows an out-of-sync toast when one of the secrets is missing", async () => {
mockCrypto!.getCrossSigningStatus.mockResolvedValue({
publicKeysOnDevice: true,
privateKeysInSecretStorage: true,
privateKeysCachedLocally: {
masterKey: false,
selfSigningKey: true,
userSigningKey: true,
},
});
await createAndStart();
expect(SetupEncryptionToast.showToast).toHaveBeenCalledWith(
SetupEncryptionToast.Kind.KEY_STORAGE_OUT_OF_SYNC,
);
});
it("hides the out-of-sync toast when one of the secrets is missing", async () => {
mockCrypto!.isSecretStorageReady.mockResolvedValue(true);
// First show the toast
mockCrypto!.getCrossSigningStatus.mockResolvedValue({
publicKeysOnDevice: true,
privateKeysInSecretStorage: true,
privateKeysCachedLocally: {
masterKey: false,
selfSigningKey: true,
userSigningKey: true,
},
});
await createAndStart();
expect(SetupEncryptionToast.showToast).toHaveBeenCalledWith(
SetupEncryptionToast.Kind.KEY_STORAGE_OUT_OF_SYNC,
);
// Then, when we receive the secret, it should be hidden.
mockCrypto!.getCrossSigningStatus.mockResolvedValue({
publicKeysOnDevice: true,
privateKeysInSecretStorage: true,
privateKeysCachedLocally: {
masterKey: true,
selfSigningKey: true,
userSigningKey: true,
},
});
mockClient.emit(ClientEvent.ToDeviceEvent, new MatrixEvent({ type: "m.secret.send" }));
await flushPromises();
expect(SetupEncryptionToast.hideToast).toHaveBeenCalled();
});
it("shows set up recovery toast when user has a key backup available", async () => {
// non falsy response
mockCrypto.getKeyBackupInfo.mockResolvedValue({} as unknown as KeyBackupInfo);