Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really feels like this ought to be exposed more explicitly by checkKeyBackupAndEnable (a result field, maybe?) rather than something you have to reverse-engineer, but I'll not insist on that change.

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();
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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(),
Expand All @@ -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);

Expand Down
Loading