DeviceListener: Remove usage of deprecated keybackup API (#11614)

Primarily this means calling `CryptoApi.getActiveSessionBackupVersion` instead
of `MatrixClisnt.getKeyBackupEnabled`
This commit is contained in:
Richard van der Hoff 2023-09-20 13:34:18 +02:00 committed by GitHub
parent 8ac25758b3
commit 51ec7f04b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 35 deletions

View file

@ -25,7 +25,7 @@ import {
} from "matrix-js-sdk/src/matrix"; } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
import { CryptoEvent } from "matrix-js-sdk/src/crypto"; import { CryptoEvent } from "matrix-js-sdk/src/crypto";
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup"; import { KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
import dis from "./dispatcher/dispatcher"; import dis from "./dispatcher/dispatcher";
import { import {
@ -62,10 +62,10 @@ export default class DeviceListener {
private dismissed = new Set<string>(); private dismissed = new Set<string>();
// has the user dismissed any of the various nag toasts to setup encryption on this device? // has the user dismissed any of the various nag toasts to setup encryption on this device?
private dismissedThisDeviceToast = false; private dismissedThisDeviceToast = false;
// cache of the key backup info /** Cache of the info about the current key backup on the server. */
private keyBackupInfo: IKeyBackupInfo | null = null; private keyBackupInfo: KeyBackupInfo | null = null;
/** When `keyBackupInfo` was last updated */
private keyBackupFetchedAt: number | null = null; private keyBackupFetchedAt: number | null = null;
private keyBackupStatusChecked = false;
// We keep a list of our own device IDs so we can batch ones that were already // We keep a list of our own device IDs so we can batch ones that were already
// there the last time the app launched into a single toast, but display new // there the last time the app launched into a single toast, but display new
// ones in their own toasts. // ones in their own toasts.
@ -243,9 +243,14 @@ export default class DeviceListener {
this.updateClientInformation(); this.updateClientInformation();
}; };
// The server doesn't tell us when key backup is set up, so we poll /**
// & cache the result * Fetch the key backup information from the server.
private async getKeyBackupInfo(): Promise<IKeyBackupInfo | null> { *
* The result is cached for `KEY_BACKUP_POLL_INTERVAL` ms to avoid repeated API calls.
*
* @returns The key backup info from the server, or `null` if there is no key backup.
*/
private async getKeyBackupInfo(): Promise<KeyBackupInfo | null> {
if (!this.client) return null; if (!this.client) return null;
const now = new Date().getTime(); const now = new Date().getTime();
if ( if (
@ -402,18 +407,23 @@ export default class DeviceListener {
this.displayingToastsForDeviceIds = newUnverifiedDeviceIds; this.displayingToastsForDeviceIds = newUnverifiedDeviceIds;
} }
/**
* Check if key backup is enabled, and if not, raise an `Action.ReportKeyBackupNotEnabled` event (which will
* trigger an auto-rageshake).
*/
private checkKeyBackupStatus = async (): Promise<void> => { private checkKeyBackupStatus = async (): Promise<void> => {
if (this.keyBackupStatusChecked || !this.client) { if (this.keyBackupStatusChecked || !this.client) {
return; return;
} }
// returns null when key backup status hasn't finished being checked const activeKeyBackupVersion = await this.client.getCrypto()?.getActiveSessionBackupVersion();
const isKeyBackupEnabled = this.client.getKeyBackupEnabled(); // if key backup is enabled, no need to check this ever again (XXX: why only when it is enabled?)
this.keyBackupStatusChecked = isKeyBackupEnabled !== null; this.keyBackupStatusChecked = !!activeKeyBackupVersion;
if (isKeyBackupEnabled === false) { if (!activeKeyBackupVersion) {
dis.dispatch({ action: Action.ReportKeyBackupNotEnabled }); dis.dispatch({ action: Action.ReportKeyBackupNotEnabled });
} }
}; };
private keyBackupStatusChecked = false;
private onRecordClientInformationSettingChange: CallbackFn = ( private onRecordClientInformationSettingChange: CallbackFn = (
_originalSettingName, _originalSettingName,

View file

@ -92,6 +92,7 @@ describe("DeviceListener", () => {
isCrossSigningReady: jest.fn().mockResolvedValue(true), isCrossSigningReady: jest.fn().mockResolvedValue(true),
isSecretStorageReady: jest.fn().mockResolvedValue(true), isSecretStorageReady: jest.fn().mockResolvedValue(true),
userHasCrossSigningKeys: jest.fn(), userHasCrossSigningKeys: jest.fn(),
getActiveSessionBackupVersion: jest.fn(),
} as unknown as Mocked<CryptoApi>; } as unknown as Mocked<CryptoApi>;
mockClient = getMockClientWithEventEmitter({ mockClient = getMockClientWithEventEmitter({
isGuest: jest.fn(), isGuest: jest.fn(),
@ -101,7 +102,6 @@ describe("DeviceListener", () => {
getRooms: jest.fn().mockReturnValue([]), getRooms: jest.fn().mockReturnValue([]),
isVersionSupported: jest.fn().mockResolvedValue(true), isVersionSupported: jest.fn().mockResolvedValue(true),
isInitialSyncComplete: jest.fn().mockReturnValue(true), isInitialSyncComplete: jest.fn().mockReturnValue(true),
getKeyBackupEnabled: jest.fn(),
waitForClientWellKnown: jest.fn(), waitForClientWellKnown: jest.fn(),
isRoomEncrypted: jest.fn(), isRoomEncrypted: jest.fn(),
getClientWellKnown: jest.fn(), getClientWellKnown: jest.fn(),
@ -337,7 +337,7 @@ describe("DeviceListener", () => {
mockCrypto!.userHasCrossSigningKeys.mockResolvedValue(true); mockCrypto!.userHasCrossSigningKeys.mockResolvedValue(true);
await createAndStart(); await createAndStart();
expect(mockClient!.getKeyBackupEnabled).toHaveBeenCalled(); expect(mockCrypto!.getActiveSessionBackupVersion).toHaveBeenCalled();
}); });
}); });
@ -362,8 +362,7 @@ describe("DeviceListener", () => {
it("checks keybackup status when cross signing and secret storage are ready", async () => { it("checks keybackup status when cross signing and secret storage are ready", async () => {
// default mocks set cross signing and secret storage to ready // default mocks set cross signing and secret storage to ready
await createAndStart(); await createAndStart();
expect(mockClient!.getKeyBackupEnabled).toHaveBeenCalled(); expect(mockCrypto.getActiveSessionBackupVersion).toHaveBeenCalled();
expect(mockDispatcher.dispatch).not.toHaveBeenCalled();
}); });
it("checks keybackup status when setup encryption toast has been dismissed", async () => { it("checks keybackup status when setup encryption toast has been dismissed", async () => {
@ -373,40 +372,25 @@ describe("DeviceListener", () => {
instance.dismissEncryptionSetup(); instance.dismissEncryptionSetup();
await flushPromises(); await flushPromises();
expect(mockClient!.getKeyBackupEnabled).toHaveBeenCalled(); expect(mockCrypto.getActiveSessionBackupVersion).toHaveBeenCalled();
});
it("does not dispatch keybackup event when key backup check is not finished", async () => {
// returns null when key backup status hasn't finished being checked
mockClient!.getKeyBackupEnabled.mockReturnValue(null);
await createAndStart();
expect(mockDispatcher.dispatch).not.toHaveBeenCalled();
}); });
it("dispatches keybackup event when key backup is not enabled", async () => { it("dispatches keybackup event when key backup is not enabled", async () => {
mockClient!.getKeyBackupEnabled.mockReturnValue(false); mockCrypto.getActiveSessionBackupVersion.mockResolvedValue(null);
await createAndStart(); await createAndStart();
expect(mockDispatcher.dispatch).toHaveBeenCalledWith({ action: Action.ReportKeyBackupNotEnabled }); expect(mockDispatcher.dispatch).toHaveBeenCalledWith({ action: Action.ReportKeyBackupNotEnabled });
}); });
it("does not check key backup status again after check is complete", async () => { it("does not check key backup status again after check is complete", async () => {
mockClient!.getKeyBackupEnabled.mockReturnValue(null); mockCrypto.getActiveSessionBackupVersion.mockResolvedValue("1");
const instance = await createAndStart(); const instance = await createAndStart();
expect(mockClient!.getKeyBackupEnabled).toHaveBeenCalled(); expect(mockCrypto.getActiveSessionBackupVersion).toHaveBeenCalled();
// keyback check now complete
mockClient!.getKeyBackupEnabled.mockReturnValue(true);
// trigger a recheck // trigger a recheck
instance.dismissEncryptionSetup(); instance.dismissEncryptionSetup();
await flushPromises(); await flushPromises();
expect(mockClient!.getKeyBackupEnabled).toHaveBeenCalledTimes(2);
// trigger another recheck
instance.dismissEncryptionSetup();
await flushPromises();
// not called again, check was complete last time // not called again, check was complete last time
expect(mockClient!.getKeyBackupEnabled).toHaveBeenCalledTimes(2); expect(mockCrypto.getActiveSessionBackupVersion).toHaveBeenCalledTimes(1);
}); });
}); });