1
0
mirror of https://github.com/element-hq/element-web.git synced 2025-08-09 14:42:51 +03:00

Delegate to new ResetIdentityDialog from SetupEncryptionBody (#29701)

This commit is contained in:
Andy Balaam
2025-04-30 11:08:38 +01:00
committed by GitHub
parent 4f4f391959
commit 23597e959b
16 changed files with 453 additions and 218 deletions

View File

@@ -19,126 +19,162 @@ import {
test.describe("Encryption tab", () => {
test.use({ displayName: "Alice" });
let recoveryKey: GeneratedSecretStorageKey;
let expectedBackupVersion: string;
test.describe("when encryption is set up", () => {
let recoveryKey: GeneratedSecretStorageKey;
let expectedBackupVersion: string;
test.beforeEach(async ({ page, homeserver, credentials }) => {
// The bot bootstraps cross-signing, creates a key backup and sets up a recovery key
const res = await createBot(page, homeserver, credentials);
recoveryKey = res.recoveryKey;
expectedBackupVersion = res.expectedBackupVersion;
});
test.beforeEach(async ({ page, homeserver, credentials }) => {
// The bot bootstraps cross-signing, creates a key backup and sets up a recovery key
const res = await createBot(page, homeserver, credentials);
recoveryKey = res.recoveryKey;
expectedBackupVersion = res.expectedBackupVersion;
});
test(
"should show a 'Verify this device' button if the device is unverified",
{ tag: "@screenshot" },
async ({ page, app, util }) => {
const dialog = await util.openEncryptionTab();
const content = util.getEncryptionTabContent();
test(
"should show a 'Verify this device' button if the device is unverified",
{ tag: "@screenshot" },
async ({ page, app, util }) => {
const dialog = await util.openEncryptionTab();
const content = util.getEncryptionTabContent();
// The user's device is in an unverified state, therefore the only option available to them here is to verify it
const verifyButton = dialog.getByRole("button", { name: "Verify this device" });
await expect(verifyButton).toBeVisible();
await expect(content).toMatchScreenshot("verify-device-encryption-tab.png");
await verifyButton.click();
// The user's device is in an unverified state, therefore the only option available to them here is to verify it
const verifyButton = dialog.getByRole("button", { name: "Verify this device" });
await expect(verifyButton).toBeVisible();
await expect(content).toMatchScreenshot("verify-device-encryption-tab.png");
await verifyButton.click();
await util.verifyDevice(recoveryKey);
await util.verifyDevice(recoveryKey);
await expect(content).toMatchScreenshot("default-tab.png", {
mask: [content.getByTestId("deviceId"), content.getByTestId("sessionKey")],
});
await expect(content).toMatchScreenshot("default-tab.png", {
mask: [content.getByTestId("deviceId"), content.getByTestId("sessionKey")],
});
// Check that our device is now cross-signed
await checkDeviceIsCrossSigned(app);
// Check that our device is now cross-signed
await checkDeviceIsCrossSigned(app);
// Check that the current device is connected to key backup
// The backup decryption key should be in cache also, as we got it directly from the 4S
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
},
);
// Check that the current device is connected to key backup
// The backup decryption key should be in cache also, as we got it directly from the 4S
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
},
);
// Test what happens if the cross-signing secrets are in secret storage but are not cached in the local DB.
//
// This can happen if we verified another device and secret-gossiping failed, or the other device itself lacked the secrets.
// We simulate this case by deleting the cached secrets in the indexedDB.
test(
"should prompt to enter the recovery key when the secrets are not cached locally",
{ tag: "@screenshot" },
async ({ page, app, util }) => {
// Test what happens if the cross-signing secrets are in secret storage but are not cached in the local DB.
//
// This can happen if we verified another device and secret-gossiping failed, or the other device itself lacked the secrets.
// We simulate this case by deleting the cached secrets in the indexedDB.
test(
"should prompt to enter the recovery key when the secrets are not cached locally",
{ tag: "@screenshot" },
async ({ page, app, util }) => {
await verifySession(app, recoveryKey.encodedPrivateKey);
// We need to delete the cached secrets
await deleteCachedSecrets(page);
await util.openEncryptionTab();
// We ask the user to enter the recovery key
const dialog = util.getEncryptionTabContent();
const enterKeyButton = dialog.getByRole("button", { name: "Enter recovery key" });
await expect(enterKeyButton).toBeVisible();
await expect(dialog).toMatchScreenshot("out-of-sync-recovery.png");
await enterKeyButton.click();
// Fill the recovery key
await util.enterRecoveryKey(recoveryKey);
await expect(dialog).toMatchScreenshot("default-tab.png", {
mask: [dialog.getByTestId("deviceId"), dialog.getByTestId("sessionKey")],
});
// Check that our device is now cross-signed
await checkDeviceIsCrossSigned(app);
// Check that the current device is connected to key backup
// The backup decryption key should be in cache also, as we got it directly from the 4S
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
},
);
test("should display the reset identity panel when the user clicks on 'Forgot recovery key?'", async ({
page,
app,
util,
}) => {
await verifySession(app, recoveryKey.encodedPrivateKey);
// We need to delete the cached secrets
await deleteCachedSecrets(page);
// The "Key storage is out sync" section is displayed and the user click on the "Forgot recovery key?" button
await util.openEncryptionTab();
// We ask the user to enter the recovery key
const dialog = util.getEncryptionTabContent();
const enterKeyButton = dialog.getByRole("button", { name: "Enter recovery key" });
await expect(enterKeyButton).toBeVisible();
await expect(dialog).toMatchScreenshot("out-of-sync-recovery.png");
await enterKeyButton.click();
await dialog.getByRole("button", { name: "Forgot recovery key?" }).click();
// Fill the recovery key
await util.enterRecoveryKey(recoveryKey);
await expect(dialog).toMatchScreenshot("default-tab.png", {
mask: [dialog.getByTestId("deviceId"), dialog.getByTestId("sessionKey")],
});
// The user is prompted to reset their identity
await expect(
dialog.getByText("Forgot your recovery key? Youll need to reset your identity."),
).toBeVisible();
});
// Check that our device is now cross-signed
await checkDeviceIsCrossSigned(app);
test("should warn before turning off key storage", { tag: "@screenshot" }, async ({ page, app, util }) => {
await verifySession(app, recoveryKey.encodedPrivateKey);
await util.openEncryptionTab();
// Check that the current device is connected to key backup
// The backup decryption key should be in cache also, as we got it directly from the 4S
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
},
);
await page.getByRole("checkbox", { name: "Allow key storage" }).click();
test("should display the reset identity panel when the user clicks on 'Forgot recovery key?'", async ({
page,
app,
util,
}) => {
await verifySession(app, recoveryKey.encodedPrivateKey);
// We need to delete the cached secrets
await deleteCachedSecrets(page);
await expect(
page.getByRole("heading", { name: "Are you sure you want to turn off key storage and delete it?" }),
).toBeVisible();
// The "Key storage is out sync" section is displayed and the user click on the "Forgot recovery key?" button
await util.openEncryptionTab();
const dialog = util.getEncryptionTabContent();
await dialog.getByRole("button", { name: "Forgot recovery key?" }).click();
await expect(util.getEncryptionTabContent()).toMatchScreenshot("delete-key-storage-confirm.png");
// The user is prompted to reset their identity
await expect(dialog.getByText("Forgot your recovery key? Youll need to reset your identity.")).toBeVisible();
const deleteRequestPromises = [
page.waitForRequest((req) => req.url().endsWith("/account_data/m.cross_signing.master")),
page.waitForRequest((req) => req.url().endsWith("/account_data/m.cross_signing.self_signing")),
page.waitForRequest((req) => req.url().endsWith("/account_data/m.cross_signing.user_signing")),
page.waitForRequest((req) => req.url().endsWith("/account_data/m.megolm_backup.v1")),
page.waitForRequest((req) => req.url().endsWith("/account_data/m.secret_storage.default_key")),
page.waitForRequest((req) => req.url().includes("/account_data/m.secret_storage.key.")),
];
await page.getByRole("button", { name: "Delete key storage" }).click();
await expect(page.getByRole("checkbox", { name: "Allow key storage" })).not.toBeChecked();
for (const prom of deleteRequestPromises) {
const request = await prom;
expect(request.method()).toBe("PUT");
expect(request.postData()).toBe(JSON.stringify({}));
}
});
});
test("should warn before turning off key storage", { tag: "@screenshot" }, async ({ page, app, util }) => {
await verifySession(app, recoveryKey.encodedPrivateKey);
await util.openEncryptionTab();
test.describe("when encryption is not set up", () => {
test("'Verify this device' allows us to become verified", async ({
page,
user,
credentials,
app,
}, workerInfo) => {
const settings = await app.settings.openUserSettings("Encryption");
await page.getByRole("checkbox", { name: "Allow key storage" }).click();
// Initially, our device is not verified
await expect(settings.getByRole("heading", { name: "Device not verified" })).toBeVisible();
await expect(
page.getByRole("heading", { name: "Are you sure you want to turn off key storage and delete it?" }),
).toBeVisible();
// We will reset our identity
await settings.getByRole("button", { name: "Verify this device" }).click();
await page.getByRole("button", { name: "Proceed with reset" }).click();
await expect(util.getEncryptionTabContent()).toMatchScreenshot("delete-key-storage-confirm.png");
// First try cancelling and restarting
await page.getByRole("button", { name: "Cancel" }).click();
await page.getByRole("button", { name: "Proceed with reset" }).click();
const deleteRequestPromises = [
page.waitForRequest((req) => req.url().endsWith("/account_data/m.cross_signing.master")),
page.waitForRequest((req) => req.url().endsWith("/account_data/m.cross_signing.self_signing")),
page.waitForRequest((req) => req.url().endsWith("/account_data/m.cross_signing.user_signing")),
page.waitForRequest((req) => req.url().endsWith("/account_data/m.megolm_backup.v1")),
page.waitForRequest((req) => req.url().endsWith("/account_data/m.secret_storage.default_key")),
page.waitForRequest((req) => req.url().includes("/account_data/m.secret_storage.key.")),
];
// Then click outside the dialog and restart
await page.locator("li").filter({ hasText: "Encryption" }).click({ force: true });
await page.getByRole("button", { name: "Proceed with reset" }).click();
await page.getByRole("button", { name: "Delete key storage" }).click();
// Finally we actually continue
await page.getByRole("button", { name: "Continue" }).click();
await expect(page.getByRole("checkbox", { name: "Allow key storage" })).not.toBeChecked();
for (const prom of deleteRequestPromises) {
const request = await prom;
expect(request.method()).toBe("PUT");
expect(request.postData()).toBe(JSON.stringify({}));
}
// Now we are verified, so we see the Key storage toggle
await expect(settings.getByRole("heading", { name: "Key storage" })).toBeVisible();
});
});
});