Skip to content

Commit

Permalink
Add new verification section to user profile (#29200)
Browse files Browse the repository at this point in the history
* Create new verification section

* Remove old code and use new VerificationSection

* Add styling and translation

* Fix tests

* Remove dead code

* Fix broken test

* Remove imports

* Remove console.log

* Update snapshots

* Fix broken tests

* Fix lint

* Make badge expand with content

* Remove unused code
  • Loading branch information
MidhunSureshR authored Feb 10, 2025
1 parent bb8b4d7 commit 52b42c0
Show file tree
Hide file tree
Showing 14 changed files with 489 additions and 1,095 deletions.
25 changes: 0 additions & 25 deletions playwright/e2e/crypto/dehydration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,13 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Com
Please see LICENSE files in the repository root for full details.
*/

import { type Locator, type Page } from "@playwright/test";

import { test, expect } from "../../element-web-test";
import { viewRoomSummaryByName } from "../right-panel/utils";
import { isDendrite } from "../../plugins/homeserver/dendrite";
import { completeCreateSecretStorageDialog, createBot, logIntoElement } from "./utils.ts";
import { type Client } from "../../pages/client.ts";

const ROOM_NAME = "Test room";
const NAME = "Alice";

function getMemberTileByName(page: Page, name: string): Locator {
return page.locator(`.mx_MemberTileView, [title="${name}"]`);
}

test.use({
displayName: NAME,
synapseConfig: {
Expand Down Expand Up @@ -70,23 +62,6 @@ test.describe("Dehydration", () => {
// device.
const sessionsTab = await app.settings.openUserSettings("Sessions");
await expect(sessionsTab.getByText("Dehydrated device")).not.toBeVisible();

await app.settings.closeDialog();

// now check that the user info right-panel shows the dehydrated device
// as a feature rather than as a normal device
await app.client.createRoom({ name: ROOM_NAME });

await viewRoomSummaryByName(page, app, ROOM_NAME);

await page.locator(".mx_RightPanel").getByRole("menuitem", { name: "People" }).click();
await expect(page.locator(".mx_MemberListView")).toBeVisible();

await getMemberTileByName(page, NAME).click();
await page.locator(".mx_UserInfo_devices .mx_UserInfo_expand").click();

await expect(page.locator(".mx_UserInfo_devices").getByText("Offline device enabled")).toBeVisible();
await expect(page.locator(".mx_UserInfo_devices").getByText("Dehydrated device")).not.toBeVisible();
});

test("Reset recovery key during login re-creates dehydrated device", async ({
Expand Down
28 changes: 4 additions & 24 deletions playwright/e2e/crypto/event-shields.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
logIntoElement,
logOutOfElement,
verify,
waitForDevices,
} from "./utils";
import { bootstrapCrossSigningForClient } from "../../pages/client.ts";
import { type ElementAppPage } from "../../pages/ElementAppPage.ts";
Expand Down Expand Up @@ -144,25 +145,8 @@ test.describe("Cryptography", function () {
// bob deletes his second device
await bobSecondDevice.evaluate((cli) => cli.logout(true));

// wait for the logout to propagate. Workaround for https://github.com/vector-im/element-web/issues/26263 by repeatedly closing and reopening Bob's user info.
async function awaitOneDevice(iterations = 1) {
const rightPanel = page.locator(".mx_RightPanel");
await rightPanel.getByTestId("base-card-back-button").click();
await rightPanel.getByText("Bob").click();
const sessionCountText = await rightPanel
.locator(".mx_UserInfo_devices")
.getByText(" session", { exact: false })
.textContent();
// cf https://github.com/vector-im/element-web/issues/26279: Element-R uses the wrong text here
if (sessionCountText != "1 session" && sessionCountText != "1 verified session") {
if (iterations >= 10) {
throw new Error(`Bob still has ${sessionCountText} after 10 iterations`);
}
await awaitOneDevice(iterations + 1);
}
}

await awaitOneDevice();
// wait for the logout to propagate.
await waitForDevices(app, bob.credentials.userId, 1);

// close and reopen the room, to get the shield to update.
await app.viewRoomByName("Bob");
Expand Down Expand Up @@ -285,11 +269,7 @@ test.describe("Cryptography", function () {
// Workaround for https://github.com/element-hq/element-web/issues/28640:
// make sure that Alice has seen Bob's identity before she goes offline. We do this by opening
// his user info.
await app.toggleRoomInfoPanel();
const rightPanel = page.locator(".mx_RightPanel");
await rightPanel.getByRole("menuitem", { name: "People" }).click();
await rightPanel.getByRole("button", { name: bob.credentials!.userId }).click();
await expect(rightPanel.locator(".mx_UserInfo_devices")).toContainText("1 session");
await waitForDevices(app, bob.credentials.userId, 1);

// Our app is blocked from syncing while Bob sends his messages.
await app.client.network.goOffline();
Expand Down
27 changes: 11 additions & 16 deletions playwright/e2e/crypto/user-verification.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ Please see LICENSE files in the repository root for full details.

import { type Preset, type Visibility } from "matrix-js-sdk/src/matrix";

import type { Page } from "@playwright/test";
import { test, expect } from "../../element-web-test";
import { doTwoWaySasVerification, awaitVerifier } from "./utils";
import { doTwoWaySasVerification, awaitVerifier, waitForDevices } from "./utils";
import { type Client } from "../../pages/client";

test.describe("User verification", () => {
Expand All @@ -33,13 +32,17 @@ test.describe("User verification", () => {
});

test("can receive a verification request when there is no existing DM", async ({
app,
page,
bot: bob,
user: aliceCredentials,
toasts,
room: { roomId: dmRoomId },
}) => {
await waitForDeviceKeys(page);
await waitForDevices(app, bob.credentials.userId, 1);
await expect(page.getByRole("button", { name: "Avatar" })).toBeVisible();
const avatar = page.getByRole("button", { name: "Avatar" });
await avatar.click();

// once Alice has joined, Bob starts the verification
const bobVerificationRequest = await bob.evaluateHandle(
Expand Down Expand Up @@ -84,13 +87,17 @@ test.describe("User verification", () => {
});

test("can abort emoji verification when emoji mismatch", async ({
app,
page,
bot: bob,
user: aliceCredentials,
toasts,
room: { roomId: dmRoomId },
}) => {
await waitForDeviceKeys(page);
await waitForDevices(app, bob.credentials.userId, 1);
await expect(page.getByRole("button", { name: "Avatar" })).toBeVisible();
const avatar = page.getByRole("button", { name: "Avatar" });
await avatar.click();

// once Alice has joined, Bob starts the verification
const bobVerificationRequest = await bob.evaluateHandle(
Expand Down Expand Up @@ -154,15 +161,3 @@ async function createDMRoom(client: Client, userId: string): Promise<string> {
],
});
}

/**
* Wait until we get the other user's device keys.
* In newer rust-crypto versions, the verification request will be ignored if we
* don't have the sender's device keys.
*/
async function waitForDeviceKeys(page: Page): Promise<void> {
await expect(page.getByRole("button", { name: "Avatar" })).toBeVisible();
const avatar = await page.getByRole("button", { name: "Avatar" });
await avatar.click();
await expect(page.getByText("1 session")).toBeVisible();
}
28 changes: 28 additions & 0 deletions playwright/e2e/crypto/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,3 +502,31 @@ export async function deleteCachedSecrets(page: Page) {
});
await page.reload();
}

/**
* Wait until the given user has a given number of devices.
* This function will check the device keys ten times and if
* the expected number of devices were not found by then, an
* error is thrown.
*/
export async function waitForDevices(
app: ElementAppPage,
userId: string,
expectedNumberOfDevices: number,
): Promise<void> {
const result = await app.client.evaluate(
async (cli, { userId, expectedNumberOfDevices }) => {
for (let i = 0; i < 10; ++i) {
const userDeviceMap = await cli.getCrypto()?.getUserDeviceInfo([userId], true);
const deviceMap = userDeviceMap?.get(userId);
if (deviceMap.size === expectedNumberOfDevices) return true;
await new Promise((r) => setTimeout(r, 500));
}
return false;
},
{ userId, expectedNumberOfDevices },
);
if (!result) {
throw new Error(`User ${userId} did not have ${expectedNumberOfDevices} devices within ten iterations!`);
}
}
1 change: 0 additions & 1 deletion playwright/e2e/user-view/user-view.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ test.describe("UserView", () => {

const rightPanel = page.locator("#mx_RightPanel");
await expect(rightPanel.getByRole("heading", { name: bot.credentials.displayName, exact: true })).toBeVisible();
await expect(rightPanel.getByText("1 session")).toBeVisible();
await expect(rightPanel).toMatchScreenshot("user-info.png", {
mask: [page.locator(".mx_UserInfo_profile_mxid")],
css: `
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
65 changes: 22 additions & 43 deletions res/css/views/right_panel/_UserInfo.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ Please see LICENSE files in the repository root for full details.
padding: var(--cpd-space-2x) 0 var(--cpd-space-4x);
margin: 0 var(--cpd-space-4x);

.mx_UserInfo_container_verifyButton {
margin-top: $spacing-8;
}

& + .mx_UserInfo_container {
border-top: 1px solid $separator;
}
Expand Down Expand Up @@ -180,6 +176,28 @@ Please see LICENSE files in the repository root for full details.
opacity: 1;
}

.mx_UserInfo_verification {
margin-top: var(--cpd-space-4x);
height: 36px;

.mx_UserInfo_verified_badge {
min-width: 68px;
height: 20px;

.mx_UserInfo_verified_icon {
flex-shrink: 0;
}

.mx_UserInfo_verified_label {
margin: 0;
}
}

.mx_UserInfo_verification_unavailable {
color: var(--cpd-color-text-secondary);
}
}

.mx_UserInfo_memberDetails {
.mx_UserInfo_profileField {
display: flex;
Expand Down Expand Up @@ -226,45 +244,6 @@ Please see LICENSE files in the repository root for full details.
flex: 1 1 0;
}

.mx_UserInfo_devices {
.mx_UserInfo_device {
display: flex;
margin: $spacing-8 0;

&.mx_UserInfo_device_verified {
.mx_UserInfo_device_trusted {
color: $accent;
}
}
&.mx_UserInfo_device_unverified {
.mx_UserInfo_device_trusted {
color: $alert;
}
}

.mx_UserInfo_device_name {
flex: 1;
margin: 0 5px;
word-break: break-word;
}
}

/* both for icon in expand button and device item */
.mx_E2EIcon {
/* don't squeeze */
flex: 0 0 auto;
margin: 0;
width: 12px;
height: 12px;
}

.mx_UserInfo_expand {
column-gap: 5px; /* cf: mx_UserInfo_device_name */
margin-bottom: 11px;
align-items: initial; /* Cancel the default property */
}
}

&.mx_UserInfo_smallAvatar {
.mx_UserInfo_avatar {
.mx_UserInfo_avatar_transition {
Expand Down
Loading

0 comments on commit 52b42c0

Please sign in to comment.