Skip to content

Commit

Permalink
test(e2e): checkDeviceIsConnectedKeyBackup is checking the key back…
Browse files Browse the repository at this point in the history
…up with the matrix client and the crypto api instead of relying of the `Security & Privacy` tab.
  • Loading branch information
florianduros committed Jan 22, 2025
1 parent 84c6146 commit 44c6d1d
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 27 deletions.
12 changes: 5 additions & 7 deletions playwright/e2e/crypto/device-verification.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {

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

test("Verify device with QR code during login", async ({ page, app, credentials, homeserver }) => {
Expand Down Expand Up @@ -112,9 +112,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
await checkDeviceIsCrossSigned(app);

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

test("Verify device with Security Phrase during login", async ({ page, app, credentials, homeserver }) => {
Expand All @@ -135,7 +133,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {

// 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(page, expectedBackupVersion, true);
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
});

test("Verify device with Security Key during login", async ({ page, app, credentials, homeserver }) => {
Expand All @@ -158,7 +156,7 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {

// 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(page, expectedBackupVersion, true);
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
});

test("Handle incoming verification request with SAS", async ({ page, credentials, homeserver, toasts }) => {
Expand Down
46 changes: 32 additions & 14 deletions playwright/e2e/crypto/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,12 @@ export async function checkDeviceIsCrossSigned(app: ElementAppPage): Promise<voi
* Check that the current device is connected to the expected key backup.
* Also checks that the decryption key is known and cached locally.
*
* @param page - the page to check
* @param app - app page
* @param expectedBackupVersion - the version of the backup we expect to be connected to.
* @param checkBackupKeyInCache - whether to check that the backup key is cached locally.
*/
export async function checkDeviceIsConnectedKeyBackup(
page: Page,
app: ElementAppPage,
expectedBackupVersion: string,
checkBackupKeyInCache: boolean,
): Promise<void> {
Expand All @@ -155,23 +155,41 @@ export async function checkDeviceIsConnectedKeyBackup(
);
}

await page.getByRole("button", { name: "User menu" }).click();
await page.locator(".mx_UserMenu_contextMenu").getByRole("menuitem", { name: "Security & Privacy" }).click();
await expect(page.locator(".mx_Dialog").getByRole("button", { name: "Restore from Backup" })).toBeVisible();
const backupData = await app.client.evaluate(async (client: MatrixClient) => {
const crypto = client.getCrypto();
if (!crypto) return;

// expand the advanced section to see the active version in the reports
await page.locator(".mx_SecureBackupPanel_advanced").locator("..").click();
const backupInfo = await crypto.getKeyBackupInfo();
const backupKeyStored = Boolean(await client.isKeyBackupKeyStored());
const backupKeyFromCache = await crypto.getSessionBackupPrivateKey();
const backupKeyCached = Boolean(backupKeyFromCache);
const backupKeyWellFormed = backupKeyFromCache instanceof Uint8Array;
const activeBackupVersion = await crypto.getActiveSessionBackupVersion();

if (checkBackupKeyInCache) {
const cacheDecryptionKeyStatusElement = page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(2) td");
await expect(cacheDecryptionKeyStatusElement).toHaveText("cached locally, well formed");
return { backupInfo, backupKeyStored, backupKeyCached, backupKeyWellFormed, activeBackupVersion };
});

if (!backupData) {
throw new Error("Crypo module is not available");
}

await expect(page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(5) td")).toHaveText(
expectedBackupVersion + " (Algorithm: m.megolm_backup.v1.curve25519-aes-sha2)",
);
const { backupInfo, backupKeyStored, backupKeyCached, backupKeyWellFormed, activeBackupVersion } = backupData;

// We have a key backup
expect(backupInfo).toBeDefined();
// The key backup version is as expected
expect(backupInfo.version).toBe(expectedBackupVersion);
// The active backup version is as expected
expect(activeBackupVersion).toBe(expectedBackupVersion);
// The backup key is stored in 4S
expect(backupKeyStored).toBe(true);

await expect(page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(6) td")).toHaveText(expectedBackupVersion);
if (checkBackupKeyInCache) {
// The backup key is available locally
expect(backupKeyCached).toBe(true);
// The backup key is well-formed
expect(backupKeyWellFormed).toBe(true);
}
}

/**
Expand Down
9 changes: 3 additions & 6 deletions playwright/e2e/settings/encryption-user-tab/recovery.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,7 @@ test.describe("Recovery section in Encryption tab", () => {

// 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 app.closeDialog();
await checkDeviceIsConnectedKeyBackup(page, expectedBackupVersion, true);
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
});

test(
Expand Down Expand Up @@ -115,9 +114,8 @@ test.describe("Recovery section in Encryption tab", () => {
// The recovery key is now set up and the user can change it
await expect(dialog.getByRole("button", { name: "Change recovery key" })).toBeVisible();

await app.closeDialog();
// Check that the current device is connected to key backup and the backup version is the expected one
await checkDeviceIsConnectedKeyBackup(page, "1", true);
await checkDeviceIsConnectedKeyBackup(app, "1", true);
});

// Test what happens if the cross-signing secrets are in secret storage but are not cached in the local DB.
Expand Down Expand Up @@ -149,8 +147,7 @@ test.describe("Recovery section in Encryption tab", () => {

// 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 app.closeDialog();
await checkDeviceIsConnectedKeyBackup(page, expectedBackupVersion, true);
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
},
);
});

0 comments on commit 44c6d1d

Please sign in to comment.