Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 6107069

Browse files
authored
Revert "Set up key backup using non-deprecated APIs (#12005)" (#12102)
1 parent def4b72 commit 6107069

File tree

11 files changed

+79
-211
lines changed

11 files changed

+79
-211
lines changed

playwright/e2e/crypto/backups.spec.ts

-57
This file was deleted.

playwright/e2e/crypto/utils.ts

+25-2
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,35 @@ export async function checkDeviceIsCrossSigned(app: ElementAppPage): Promise<voi
103103
}
104104

105105
/**
106-
* Check that the current device is connected to the key backup.
106+
* Check that the current device is connected to the expected key backup.
107+
* Also checks that the decryption key is known and cached locally.
108+
*
109+
* @param page - the page to check
110+
* @param expectedBackupVersion - the version of the backup we expect to be connected to.
111+
* @param checkBackupKeyInCache - whether to check that the backup key is cached locally.
107112
*/
108-
export async function checkDeviceIsConnectedKeyBackup(page: Page) {
113+
export async function checkDeviceIsConnectedKeyBackup(
114+
page: Page,
115+
expectedBackupVersion: string,
116+
checkBackupKeyInCache: boolean,
117+
): Promise<void> {
109118
await page.getByRole("button", { name: "User menu" }).click();
110119
await page.locator(".mx_UserMenu_contextMenu").getByRole("menuitem", { name: "Security & Privacy" }).click();
111120
await expect(page.locator(".mx_Dialog").getByRole("button", { name: "Restore from Backup" })).toBeVisible();
121+
122+
// expand the advanced section to see the active version in the reports
123+
await page.locator(".mx_SecureBackupPanel_advanced").locator("..").click();
124+
125+
if (checkBackupKeyInCache) {
126+
const cacheDecryptionKeyStatusElement = page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(2) td");
127+
await expect(cacheDecryptionKeyStatusElement).toHaveText("cached locally, well formed");
128+
}
129+
130+
await expect(page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(5) td")).toHaveText(
131+
expectedBackupVersion + " (Algorithm: m.megolm_backup.v1.curve25519-aes-sha2)",
132+
);
133+
134+
await expect(page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(6) td")).toHaveText(expectedBackupVersion);
112135
}
113136

114137
/**

playwright/e2e/crypto/verification.spec.ts

+18-5
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ import { Bot } from "../../pages/bot";
3333
test.describe("Device verification", () => {
3434
let aliceBotClient: Bot;
3535

36+
/** The backup version that was set up by the bot client. */
37+
let expectedBackupVersion: string;
38+
3639
test.beforeEach(async ({ page, homeserver, credentials }) => {
3740
// Visit the login page of the app, to load the matrix sdk
3841
await page.goto("/#/login");
@@ -49,9 +52,13 @@ test.describe("Device verification", () => {
4952
bootstrapSecretStorage: true,
5053
});
5154
aliceBotClient.setCredentials(credentials);
52-
await aliceBotClient.prepareClient();
55+
const mxClientHandle = await aliceBotClient.prepareClient();
5356

5457
await page.waitForTimeout(20000);
58+
59+
expectedBackupVersion = await mxClientHandle.evaluate(async (mxClient) => {
60+
return await mxClient.getCrypto()!.getActiveSessionBackupVersion();
61+
});
5562
});
5663

5764
// Click the "Verify with another device" button, and have the bot client auto-accept it.
@@ -87,7 +94,9 @@ test.describe("Device verification", () => {
8794
await checkDeviceIsCrossSigned(app);
8895

8996
// Check that the current device is connected to key backup
90-
await checkDeviceIsConnectedKeyBackup(page);
97+
// For now we don't check that the backup key is in cache because it's a bit flaky,
98+
// as we need to wait for the secret gossiping to happen and the settings dialog doesn't refresh automatically.
99+
await checkDeviceIsConnectedKeyBackup(page, expectedBackupVersion, false);
91100
});
92101

93102
test("Verify device with QR code during login", async ({ page, app, credentials, homeserver }) => {
@@ -130,7 +139,9 @@ test.describe("Device verification", () => {
130139
await checkDeviceIsCrossSigned(app);
131140

132141
// Check that the current device is connected to key backup
133-
await checkDeviceIsConnectedKeyBackup(page);
142+
// For now we don't check that the backup key is in cache because it's a bit flaky,
143+
// as we need to wait for the secret gossiping to happen and the settings dialog doesn't refresh automatically.
144+
await checkDeviceIsConnectedKeyBackup(page, expectedBackupVersion, false);
134145
});
135146

136147
test("Verify device with Security Phrase during login", async ({ page, app, credentials, homeserver }) => {
@@ -150,7 +161,8 @@ test.describe("Device verification", () => {
150161
await checkDeviceIsCrossSigned(app);
151162

152163
// Check that the current device is connected to key backup
153-
await checkDeviceIsConnectedKeyBackup(page);
164+
// The backup decryption key should be in cache also, as we got it directly from the 4S
165+
await checkDeviceIsConnectedKeyBackup(page, expectedBackupVersion, true);
154166
});
155167

156168
test("Verify device with Security Key during login", async ({ page, app, credentials, homeserver }) => {
@@ -172,7 +184,8 @@ test.describe("Device verification", () => {
172184
await checkDeviceIsCrossSigned(app);
173185

174186
// Check that the current device is connected to key backup
175-
await checkDeviceIsConnectedKeyBackup(page);
187+
// The backup decryption key should be in cache also, as we got it directly from the 4S
188+
await checkDeviceIsConnectedKeyBackup(page, expectedBackupVersion, true);
176189
});
177190

178191
test("Handle incoming verification request with SAS", async ({ page, credentials, homeserver, toasts }) => {

playwright/element-web-test.ts

-4
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,3 @@ export const expect = baseExpect.extend({
293293
return { pass: true, message: () => "", name: "toMatchScreenshot" };
294294
},
295295
});
296-
297-
test.use({
298-
permissions: ["clipboard-read"],
299-
});

playwright/pages/ElementAppPage.ts

-13
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,6 @@ export class ElementAppPage {
5151
return this.settings.closeDialog();
5252
}
5353

54-
public async getClipboard(): Promise<string> {
55-
return await this.page.evaluate(() => navigator.clipboard.readText());
56-
}
57-
58-
/**
59-
* Find an open dialog by its title
60-
*/
61-
public async getDialogByTitle(title: string, timeout = 5000): Promise<Locator> {
62-
const dialog = this.page.locator(".mx_Dialog");
63-
await dialog.getByRole("heading", { name: title }).waitFor({ timeout });
64-
return dialog;
65-
}
66-
6754
/**
6855
* Opens the given room by name. The room must be visible in the
6956
* room list, but the room list may be folded horizontally, and the

src/SecurityManager.ts

+5-20
Original file line numberDiff line numberDiff line change
@@ -341,22 +341,13 @@ export async function withSecretStorageKeyCache<T>(func: () => Promise<T>): Prom
341341
* @param {Function} [func] An operation to perform once secret storage has been
342342
* bootstrapped. Optional.
343343
* @param {bool} [forceReset] Reset secret storage even if it's already set up
344-
* @param {bool} [setupNewKeyBackup] Reset secret storage even if it's already set up
345344
*/
346-
export async function accessSecretStorage(
347-
func = async (): Promise<void> => {},
348-
forceReset = false,
349-
setupNewKeyBackup = true,
350-
): Promise<void> {
351-
await withSecretStorageKeyCache(() => doAccessSecretStorage(func, forceReset, setupNewKeyBackup));
345+
export async function accessSecretStorage(func = async (): Promise<void> => {}, forceReset = false): Promise<void> {
346+
await withSecretStorageKeyCache(() => doAccessSecretStorage(func, forceReset));
352347
}
353348

354349
/** Helper for {@link #accessSecretStorage} */
355-
async function doAccessSecretStorage(
356-
func: () => Promise<void>,
357-
forceReset: boolean,
358-
setupNewKeyBackup: boolean,
359-
): Promise<void> {
350+
export async function doAccessSecretStorage(func = async (): Promise<void> => {}, forceReset = false): Promise<void> {
360351
try {
361352
const cli = MatrixClientPeg.safeGet();
362353
if (!(await cli.hasSecretStorageKey()) || forceReset) {
@@ -387,12 +378,7 @@ async function doAccessSecretStorage(
387378
throw new Error("Secret storage creation canceled");
388379
}
389380
} else {
390-
const crypto = cli.getCrypto();
391-
if (!crypto) {
392-
throw new Error("End-to-end encryption is disabled - unable to access secret storage.");
393-
}
394-
395-
await crypto.bootstrapCrossSigning({
381+
await cli.bootstrapCrossSigning({
396382
authUploadDeviceSigningKeys: async (makeRequest): Promise<void> => {
397383
const { finished } = Modal.createDialog(InteractiveAuthDialog, {
398384
title: _t("encryption|bootstrap_title"),
@@ -405,9 +391,8 @@ async function doAccessSecretStorage(
405391
}
406392
},
407393
});
408-
await crypto.bootstrapSecretStorage({
394+
await cli.bootstrapSecretStorage({
409395
getKeyBackupPassphrase: promptForBackupPassphrase,
410-
setupNewKeyBackup,
411396
});
412397

413398
const keyId = Object.keys(secretStorageKeys)[0];

src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx

+20-17
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717

1818
import React from "react";
1919
import { logger } from "matrix-js-sdk/src/logger";
20+
import { IKeyBackupInfo } from "matrix-js-sdk/src/crypto/keybackup";
2021

2122
import { MatrixClientPeg } from "../../../../MatrixClientPeg";
2223
import { _t } from "../../../../languageHandler";
@@ -74,25 +75,24 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
7475
this.setState({
7576
error: undefined,
7677
});
78+
let info: IKeyBackupInfo | undefined;
7779
const cli = MatrixClientPeg.safeGet();
7880
try {
79-
// We don't want accessSecretStorage to create a backup for us - we
80-
// will create one ourselves in the closure we pass in by calling
81-
// resetKeyBackup.
82-
const setupNewKeyBackup = false;
83-
const forceReset = false;
84-
85-
await accessSecretStorage(
86-
async (): Promise<void> => {
87-
const crypto = cli.getCrypto();
88-
if (!crypto) {
89-
throw new Error("End-to-end encryption is disabled - unable to create backup.");
90-
}
91-
await crypto.resetKeyBackup();
92-
},
93-
forceReset,
94-
setupNewKeyBackup,
95-
);
81+
await accessSecretStorage(async (): Promise<void> => {
82+
// `accessSecretStorage` will have bootstrapped secret storage if necessary, so we can now
83+
// set up key backup.
84+
//
85+
// XXX: `bootstrapSecretStorage` also sets up key backup as a side effect, so there is a 90% chance
86+
// this is actually redundant.
87+
//
88+
// The only time it would *not* be redundant would be if, for some reason, we had working 4S but no
89+
// working key backup. (For example, if the user clicked "Delete Backup".)
90+
info = await cli.prepareKeyBackupVersion(null /* random key */, {
91+
secureSecretStorage: true,
92+
});
93+
info = await cli.createKeyBackupVersion(info);
94+
});
95+
await cli.scheduleAllGroupSessionsForBackup();
9696
this.setState({
9797
phase: Phase.Done,
9898
});
@@ -102,6 +102,9 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
102102
// delete the version, disable backup, or do nothing? If we just
103103
// disable without deleting, we'll enable on next app reload since
104104
// it is trusted.
105+
if (info?.version) {
106+
cli.deleteKeyBackupVersion(info.version);
107+
}
105108
this.setState({
106109
error: true,
107110
});

test/SecurityManager-test.ts

-62
This file was deleted.

0 commit comments

Comments
 (0)