Fix enabling key backup not working if there is an untrusted key backup (#30707)
* Fix enabling key backup not working if there is an untrusted key backup on the server. * lint * Add test for trust situations. * remove conditional * Update src/components/viewmodels/settings/encryption/KeyStoragePanelViewModel.ts Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> * Update src/components/viewmodels/settings/encryption/KeyStoragePanelViewModel.ts Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> --------- Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
@@ -79,12 +79,30 @@ export function useKeyStoragePanelViewModel(): KeyStoragePanelState {
|
||||
return;
|
||||
}
|
||||
if (enable) {
|
||||
// If there is no existing key backup on the server, create one.
|
||||
// `resetKeyBackup` will delete any existing backup, so we only do this if there is no existing backup.
|
||||
const currentKeyBackup = await crypto.checkKeyBackupAndEnable();
|
||||
const childLogger = logger.getChild("[enable key storage]");
|
||||
childLogger.info("User requested enabling key storage");
|
||||
let currentKeyBackup = await crypto.checkKeyBackupAndEnable();
|
||||
if (currentKeyBackup) {
|
||||
logger.info(
|
||||
`Existing key backup is present. version: ${currentKeyBackup.backupInfo.version}`,
|
||||
currentKeyBackup.trustInfo,
|
||||
);
|
||||
// Check if the current key backup can be used. Either of these properties causes the key backup to be used.
|
||||
if (currentKeyBackup.trustInfo.trusted || currentKeyBackup.trustInfo.matchesDecryptionKey) {
|
||||
logger.info("Existing key backup can be used");
|
||||
} else {
|
||||
logger.warn("Existing key backup cannot be used, creating new backup");
|
||||
// There aren't any *usable* backups, so we need to create a new one.
|
||||
currentKeyBackup = null;
|
||||
}
|
||||
} else {
|
||||
logger.info("No existing key backup versions are present, creating new backup");
|
||||
}
|
||||
|
||||
// If there is no usable key backup on the server, create one.
|
||||
// `resetKeyBackup` will delete any existing backup, so we only do this if there is no usable backup.
|
||||
if (currentKeyBackup === null) {
|
||||
await crypto.resetKeyBackup();
|
||||
|
||||
// resetKeyBackup fires this off in the background without waiting, so we need to do it
|
||||
// explicitly and wait for it, otherwise it won't be enabled yet when we check again.
|
||||
await crypto.checkKeyBackupAndEnable();
|
||||
@@ -93,6 +111,7 @@ export function useKeyStoragePanelViewModel(): KeyStoragePanelState {
|
||||
// Set the flag so that EX no longer thinks the user wants backup disabled
|
||||
await matrixClient.setAccountData(BACKUP_DISABLED_ACCOUNT_DATA_KEY, { disabled: false });
|
||||
} else {
|
||||
logger.info("User requested disabling key backup");
|
||||
// This method will delete the key backup as well as server side recovery keys and other
|
||||
// server-side crypto data.
|
||||
await crypto.disableKeyStorage();
|
||||
|
||||
@@ -10,7 +10,7 @@ import { act } from "react";
|
||||
import { mocked } from "jest-mock";
|
||||
|
||||
import type { MatrixClient } from "matrix-js-sdk/src/matrix";
|
||||
import type { KeyBackupCheck, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
|
||||
import type { BackupTrustInfo, KeyBackupCheck, KeyBackupInfo } from "matrix-js-sdk/src/crypto-api";
|
||||
import { useKeyStoragePanelViewModel } from "../../../../../../src/components/viewmodels/settings/encryption/KeyStoragePanelViewModel";
|
||||
import { createTestClient, withClientContextRenderOptions } from "../../../../../test-utils";
|
||||
|
||||
@@ -49,8 +49,21 @@ describe("KeyStoragePanelViewModel", () => {
|
||||
expect(mocked(matrixClient.getCrypto()!.resetKeyBackup)).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should not call resetKeyBackup if there is a backup currently", async () => {
|
||||
mocked(matrixClient.getCrypto()!.checkKeyBackupAndEnable).mockResolvedValue({} as KeyBackupCheck);
|
||||
it.each<BackupTrustInfo>([
|
||||
{ trusted: true, matchesDecryptionKey: false },
|
||||
{ trusted: false, matchesDecryptionKey: true },
|
||||
{ trusted: true, matchesDecryptionKey: true },
|
||||
])("should not call resetKeyBackup if there is a backup currently and it is trusted", async (trustInfo) => {
|
||||
mocked(matrixClient.getCrypto()!.checkKeyBackupAndEnable).mockResolvedValue({
|
||||
backupInfo: {
|
||||
version: "1",
|
||||
algorithm: "foobar",
|
||||
auth_data: {
|
||||
public_key: "foobar",
|
||||
},
|
||||
},
|
||||
trustInfo,
|
||||
});
|
||||
|
||||
const { result } = renderHook(
|
||||
() => useKeyStoragePanelViewModel(),
|
||||
@@ -61,6 +74,30 @@ describe("KeyStoragePanelViewModel", () => {
|
||||
expect(mocked(matrixClient.getCrypto()!.resetKeyBackup)).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should call resetKeyBackup if there is a backup currently but it is not trusted", async () => {
|
||||
mocked(matrixClient.getCrypto()!.checkKeyBackupAndEnable).mockResolvedValue({
|
||||
backupInfo: {
|
||||
version: "1",
|
||||
algorithm: "foobar",
|
||||
auth_data: {
|
||||
public_key: "foobar",
|
||||
},
|
||||
},
|
||||
trustInfo: {
|
||||
trusted: false,
|
||||
matchesDecryptionKey: false,
|
||||
},
|
||||
});
|
||||
|
||||
const { result } = renderHook(
|
||||
() => useKeyStoragePanelViewModel(),
|
||||
withClientContextRenderOptions(matrixClient),
|
||||
);
|
||||
|
||||
await result.current.setEnabled(true);
|
||||
expect(mocked(matrixClient.getCrypto()!.resetKeyBackup)).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should set account data flag when enabling", async () => {
|
||||
mocked(matrixClient.getCrypto()!.checkKeyBackupAndEnable).mockResolvedValue(null);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user