Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

e2e test: Check key backup with js-sdk api instead of relying of Security & Privacy tab #29066

Merged
merged 2 commits into from
Jan 24, 2025
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
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);
Copy link
Member Author

Choose a reason for hiding this comment

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

This is still not working

Copy link
Member

Choose a reason for hiding this comment

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

just this test isn't working?

Copy link
Member Author

@florianduros florianduros Jan 22, 2025

Choose a reason for hiding this comment

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

The others are working if we check that the key backup is in cache but this one is failing (so I kept the false attribute)

// 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
61 changes: 43 additions & 18 deletions playwright/e2e/crypto/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,14 @@ 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 -` ElementAppPage` wrapper for the playwright `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.
* @param checkBackupPrivateKeyInCache - whether to check that the backup decryption key is cached locally
*/
export async function checkDeviceIsConnectedKeyBackup(
page: Page,
app: ElementAppPage,
expectedBackupVersion: string,
checkBackupKeyInCache: boolean,
checkBackupPrivateKeyInCache: boolean,
): Promise<void> {
// Sanity check the given backup version: if it's null, something went wrong earlier in the test.
if (!expectedBackupVersion) {
Expand All @@ -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);
}
}

/**
Expand Down
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);
},
);
});
Loading