From 850c1a5b3ae1dbba9c3d8e4c74ee8832ec8a080c Mon Sep 17 00:00:00 2001 From: Florian Duros Date: Fri, 24 Jan 2025 13:34:22 +0100 Subject: [PATCH] e2e test: Check key backup with js-sdk api instead of relying of `Security & Privacy` tab (#29066) * test(e2e): `checkDeviceIsConnectedKeyBackup` is checking the key backup with the matrix client and the crypto api instead of relying of the `Security & Privacy` tab. * test(e2e): renaming and improve documentation --- .../e2e/crypto/device-verification.spec.ts | 12 ++-- playwright/e2e/crypto/utils.ts | 61 +++++++++++++------ .../encryption-user-tab/recovery.spec.ts | 9 +-- 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/playwright/e2e/crypto/device-verification.spec.ts b/playwright/e2e/crypto/device-verification.spec.ts index 4091b1e6761..ffa269a0c51 100644 --- a/playwright/e2e/crypto/device-verification.spec.ts +++ b/playwright/e2e/crypto/device-verification.spec.ts @@ -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 }) => { @@ -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 }) => { @@ -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 }) => { @@ -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 }) => { diff --git a/playwright/e2e/crypto/utils.ts b/playwright/e2e/crypto/utils.ts index 7474c5a4354..441f44eba8a 100644 --- a/playwright/e2e/crypto/utils.ts +++ b/playwright/e2e/crypto/utils.ts @@ -139,14 +139,14 @@ export async function checkDeviceIsCrossSigned(app: ElementAppPage): Promise { // Sanity check the given backup version: if it's null, something went wrong earlier in the test. if (!expectedBackupVersion) { @@ -155,23 +155,48 @@ 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(); - - // expand the advanced section to see the active version in the reports - await page.locator(".mx_SecureBackupPanel_advanced").locator("..").click(); + const backupData = await app.client.evaluate(async (client: MatrixClient) => { + const crypto = client.getCrypto(); + if (!crypto) return; + + const backupInfo = await crypto.getKeyBackupInfo(); + const backupKeyIn4S = Boolean(await client.isKeyBackupKeyStored()); + const backupPrivateKeyFromCache = await crypto.getSessionBackupPrivateKey(); + const hasBackupPrivateKeyFromCache = Boolean(backupPrivateKeyFromCache); + const backupPrivateKeyWellFormed = backupPrivateKeyFromCache instanceof Uint8Array; + const activeBackupVersion = await crypto.getActiveSessionBackupVersion(); + + return { + backupInfo, + hasBackupPrivateKeyFromCache, + backupPrivateKeyWellFormed, + backupKeyIn4S, + activeBackupVersion, + }; + }); - if (checkBackupKeyInCache) { - const cacheDecryptionKeyStatusElement = page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(2) td"); - await expect(cacheDecryptionKeyStatusElement).toHaveText("cached locally, well formed"); + if (!backupData) { + throw new Error("Crypto 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)", - ); - - await expect(page.locator(".mx_SecureBackupPanel_statusList tr:nth-child(6) td")).toHaveText(expectedBackupVersion); + const { backupInfo, backupKeyIn4S, hasBackupPrivateKeyFromCache, backupPrivateKeyWellFormed, 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(backupKeyIn4S).toBe(true); + + if (checkBackupPrivateKeyInCache) { + // The backup key is available locally + expect(hasBackupPrivateKeyFromCache).toBe(true); + // The backup key is well-formed + expect(backupPrivateKeyWellFormed).toBe(true); + } } /** diff --git a/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts b/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts index 82839258a2d..316f305c974 100644 --- a/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts +++ b/playwright/e2e/settings/encryption-user-tab/recovery.spec.ts @@ -51,8 +51,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( @@ -119,9 +118,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. @@ -153,8 +151,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); }, ); });