Fix e2e icons in CompleteSecurity & SetupEncryptionBody (#31521)
* Fix e2e icons in CompleteSecurity & SetupEncryptionBody Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Prevent screenshot clash between tests Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
committed by
GitHub
parent
362e34513d
commit
7b024f956d
@@ -130,53 +130,68 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
|
|||||||
await page.unrouteAll({ behavior: "ignoreErrors" });
|
await page.unrouteAll({ behavior: "ignoreErrors" });
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Verify device with QR code during login", async ({ page, app, credentials, homeserver }) => {
|
test(
|
||||||
// A mode 0x02 verification: "self-verifying in which the current device does not yet trust the master key"
|
"Verify device with QR code during login",
|
||||||
await logIntoElement(page, credentials);
|
{ tag: "@screenshot" },
|
||||||
|
async ({ page, app, credentials, homeserver }) => {
|
||||||
|
// A mode 0x02 verification: "self-verifying in which the current device does not yet trust the master key"
|
||||||
|
await logIntoElement(page, credentials);
|
||||||
|
|
||||||
// Launch the verification request between alice and the bot
|
// Launch the verification request between alice and the bot
|
||||||
const verificationRequest = await initiateAliceVerificationRequest(page);
|
const verificationRequest = await initiateAliceVerificationRequest(page);
|
||||||
|
|
||||||
const infoDialog = page.locator(".mx_InfoDialog");
|
const infoDialog = page.locator(".mx_InfoDialog");
|
||||||
// feed the QR code into the verification request.
|
// feed the QR code into the verification request.
|
||||||
const qrData = await readQrCode(infoDialog);
|
const qrData = await readQrCode(infoDialog);
|
||||||
const verifier = await verificationRequest.evaluateHandle(
|
await expect(page.locator(".mx_Dialog")).toMatchScreenshot("qr-code.png", {
|
||||||
(request, qrData) => request.scanQRCode(new Uint8ClampedArray(qrData)),
|
mask: [infoDialog.locator("img")],
|
||||||
[...qrData],
|
});
|
||||||
);
|
const verifier = await verificationRequest.evaluateHandle(
|
||||||
|
(request, qrData) => request.scanQRCode(new Uint8ClampedArray(qrData)),
|
||||||
|
[...qrData],
|
||||||
|
);
|
||||||
|
|
||||||
// Confirm that the bot user scanned successfully
|
// Confirm that the bot user scanned successfully
|
||||||
await expect(infoDialog.getByText("Confirm that you see a green shield on your other device")).toBeVisible();
|
await expect(
|
||||||
await infoDialog.getByRole("button", { name: "Yes, I see a green shield" }).click();
|
infoDialog.getByText("Confirm that you see a green shield on your other device"),
|
||||||
await infoDialog.getByRole("button", { name: "Got it" }).click();
|
).toBeVisible();
|
||||||
|
await expect(page.locator(".mx_Dialog")).toMatchScreenshot("confirm-green-shield.png");
|
||||||
|
await infoDialog.getByRole("button", { name: "Yes, I see a green shield" }).click();
|
||||||
|
await expect(page.locator(".mx_Dialog")).toMatchScreenshot("got-it.png");
|
||||||
|
await infoDialog.getByRole("button", { name: "Got it" }).click();
|
||||||
|
|
||||||
// wait for the bot to see we have finished
|
// wait for the bot to see we have finished
|
||||||
await verifier.evaluate((verifier) => verifier.verify());
|
await verifier.evaluate((verifier) => verifier.verify());
|
||||||
|
|
||||||
// the bot uploads the signatures asynchronously, so wait for that to happen
|
// the bot uploads the signatures asynchronously, so wait for that to happen
|
||||||
await page.waitForTimeout(1000);
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
// our device should trust the bot device
|
// our device should trust the bot device
|
||||||
await app.client.evaluate(async (cli, aliceBotCredentials) => {
|
await app.client.evaluate(async (cli, aliceBotCredentials) => {
|
||||||
const deviceStatus = await cli
|
const deviceStatus = await cli
|
||||||
.getCrypto()!
|
.getCrypto()!
|
||||||
.getDeviceVerificationStatus(aliceBotCredentials.userId, aliceBotCredentials.deviceId);
|
.getDeviceVerificationStatus(aliceBotCredentials.userId, aliceBotCredentials.deviceId);
|
||||||
if (!deviceStatus.isVerified()) {
|
if (!deviceStatus.isVerified()) {
|
||||||
throw new Error("Bot device was not verified after QR code verification");
|
throw new Error("Bot device was not verified after QR code verification");
|
||||||
}
|
}
|
||||||
}, aliceBotClient.credentials);
|
}, aliceBotClient.credentials);
|
||||||
|
|
||||||
// Check that our device is now cross-signed
|
// Check that our device is now cross-signed
|
||||||
await checkDeviceIsCrossSigned(app);
|
await checkDeviceIsCrossSigned(app);
|
||||||
|
|
||||||
// Check that the current device is connected to key backup
|
// Check that the current device is connected to key backup
|
||||||
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
|
await checkDeviceIsConnectedKeyBackup(app, expectedBackupVersion, true);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
test("Verify device with Security Phrase during login", async ({ page, app, credentials, homeserver }) => {
|
test(
|
||||||
await logIntoElement(page, credentials);
|
"Verify device with Security Phrase during login",
|
||||||
await enterRecoveryKeyAndCheckVerified(page, app, "new passphrase");
|
{ tag: "@screenshot" },
|
||||||
});
|
async ({ page, app, credentials, homeserver }) => {
|
||||||
|
await logIntoElement(page, credentials);
|
||||||
|
await enterRecoveryKeyAndCheckVerified(page, app, "new passphrase", true);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
test("Verify device with Recovery Key during login", async ({ page, app, credentials, homeserver }) => {
|
test("Verify device with Recovery Key during login", async ({ page, app, credentials, homeserver }) => {
|
||||||
const recoveryKey = (await aliceBotClient.getRecoveryKey()).encodedPrivateKey;
|
const recoveryKey = (await aliceBotClient.getRecoveryKey()).encodedPrivateKey;
|
||||||
@@ -226,7 +241,12 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/** Helper for the three tests above which verify by recovery key */
|
/** Helper for the three tests above which verify by recovery key */
|
||||||
async function enterRecoveryKeyAndCheckVerified(page: Page, app: ElementAppPage, recoveryKey: string) {
|
async function enterRecoveryKeyAndCheckVerified(
|
||||||
|
page: Page,
|
||||||
|
app: ElementAppPage,
|
||||||
|
recoveryKey: string,
|
||||||
|
screenshot = false,
|
||||||
|
) {
|
||||||
await page.getByRole("button", { name: "Use recovery key" }).click();
|
await page.getByRole("button", { name: "Use recovery key" }).click();
|
||||||
|
|
||||||
// Enter the recovery key
|
// Enter the recovery key
|
||||||
@@ -234,8 +254,12 @@ test.describe("Device verification", { tag: "@no-webkit" }, () => {
|
|||||||
// We use `pressSequentially` here to make sure that the FocusLock isn't causing us any problems
|
// We use `pressSequentially` here to make sure that the FocusLock isn't causing us any problems
|
||||||
// (cf https://github.com/element-hq/element-web/issues/30089)
|
// (cf https://github.com/element-hq/element-web/issues/30089)
|
||||||
await dialog.getByTitle("Recovery key").pressSequentially(recoveryKey);
|
await dialog.getByTitle("Recovery key").pressSequentially(recoveryKey);
|
||||||
|
if (screenshot) {
|
||||||
|
await expect(page.locator(".mx_Dialog").filter({ hasText: "Enter your recovery key" })).toMatchScreenshot(
|
||||||
|
"recovery-key.png",
|
||||||
|
);
|
||||||
|
}
|
||||||
await dialog.getByRole("button", { name: "Continue", disabled: false }).click();
|
await dialog.getByRole("button", { name: "Continue", disabled: false }).click();
|
||||||
|
|
||||||
await page.getByRole("button", { name: "Done" }).click();
|
await page.getByRole("button", { name: "Done" }).click();
|
||||||
|
|
||||||
// Check that our device is now cross-signed
|
// Check that our device is now cross-signed
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 17 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
@@ -15,14 +15,14 @@ Please see LICENSE files in the repository root for full details.
|
|||||||
width: 24px;
|
width: 24px;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
position: relative;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_CompleteSecurity_heroIcon {
|
.mx_CompleteSecurity_heroIcon {
|
||||||
width: 128px;
|
width: 128px;
|
||||||
height: 128px;
|
height: 128px;
|
||||||
position: relative;
|
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_CompleteSecurity_skip {
|
.mx_CompleteSecurity_skip {
|
||||||
|
|||||||
@@ -10,12 +10,14 @@ import React from "react";
|
|||||||
import { Glass } from "@vector-im/compound-web";
|
import { Glass } from "@vector-im/compound-web";
|
||||||
|
|
||||||
import { _t } from "../../../languageHandler";
|
import { _t } from "../../../languageHandler";
|
||||||
import { SetupEncryptionStore, Phase } from "../../../stores/SetupEncryptionStore";
|
import { Phase, SetupEncryptionStore } from "../../../stores/SetupEncryptionStore";
|
||||||
import SetupEncryptionBody from "./SetupEncryptionBody";
|
import SetupEncryptionBody from "./SetupEncryptionBody";
|
||||||
import AccessibleButton from "../../views/elements/AccessibleButton";
|
import AccessibleButton from "../../views/elements/AccessibleButton";
|
||||||
import CompleteSecurityBody from "../../views/auth/CompleteSecurityBody";
|
import CompleteSecurityBody from "../../views/auth/CompleteSecurityBody";
|
||||||
import AuthPage from "../../views/auth/AuthPage";
|
import AuthPage from "../../views/auth/AuthPage";
|
||||||
import SdkConfig from "../../../SdkConfig";
|
import SdkConfig from "../../../SdkConfig";
|
||||||
|
import E2EIcon from "../../views/rooms/E2EIcon.tsx";
|
||||||
|
import { E2EStatus } from "../../../utils/ShieldUtils.ts";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: () => void;
|
onFinished: () => void;
|
||||||
@@ -67,13 +69,13 @@ export default class CompleteSecurity extends React.Component<IProps, IState> {
|
|||||||
} else if (phase === Phase.Intro) {
|
} else if (phase === Phase.Intro) {
|
||||||
// We don't specify an icon nor title since `SetupEncryptionBody` provides its own
|
// We don't specify an icon nor title since `SetupEncryptionBody` provides its own
|
||||||
} else if (phase === Phase.Done) {
|
} else if (phase === Phase.Done) {
|
||||||
icon = <span className="mx_CompleteSecurity_headerIcon mx_E2EIcon_verified" />;
|
icon = <E2EIcon className="mx_CompleteSecurity_headerIcon" status={E2EStatus.Verified} hideTooltip />;
|
||||||
title = _t("encryption|verification|after_new_login|device_verified");
|
title = _t("encryption|verification|after_new_login|device_verified");
|
||||||
} else if (phase === Phase.ConfirmSkip) {
|
} else if (phase === Phase.ConfirmSkip) {
|
||||||
icon = <span className="mx_CompleteSecurity_headerIcon mx_E2EIcon_warning" />;
|
icon = <E2EIcon className="mx_CompleteSecurity_headerIcon" status={E2EStatus.Warning} hideTooltip />;
|
||||||
title = _t("common|are_you_sure");
|
title = _t("common|are_you_sure");
|
||||||
} else if (phase === Phase.Busy) {
|
} else if (phase === Phase.Busy) {
|
||||||
icon = <span className="mx_CompleteSecurity_headerIcon mx_E2EIcon_warning" />;
|
icon = <E2EIcon className="mx_CompleteSecurity_headerIcon" status={E2EStatus.Warning} hideTooltip />;
|
||||||
title = _t("encryption|verification|after_new_login|verify_this_device");
|
title = _t("encryption|verification|after_new_login|verify_this_device");
|
||||||
} else if (phase === Phase.Finished) {
|
} else if (phase === Phase.Finished) {
|
||||||
// SetupEncryptionBody will take care of calling onFinished, we don't need to do anything
|
// SetupEncryptionBody will take care of calling onFinished, we don't need to do anything
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import { EncryptionCardButtons } from "../../views/settings/encryption/Encryptio
|
|||||||
import { EncryptionCardEmphasisedContent } from "../../views/settings/encryption/EncryptionCardEmphasisedContent";
|
import { EncryptionCardEmphasisedContent } from "../../views/settings/encryption/EncryptionCardEmphasisedContent";
|
||||||
import ExternalLink from "../../views/elements/ExternalLink";
|
import ExternalLink from "../../views/elements/ExternalLink";
|
||||||
import dispatcher from "../../../dispatcher/dispatcher";
|
import dispatcher from "../../../dispatcher/dispatcher";
|
||||||
|
import E2EIcon from "../../views/rooms/E2EIcon.tsx";
|
||||||
|
import { E2EStatus } from "../../../utils/ShieldUtils.ts";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
onFinished: () => void;
|
onFinished: () => void;
|
||||||
@@ -228,7 +230,7 @@ export default class SetupEncryptionBody extends React.Component<IProps, IState>
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="mx_CompleteSecurity_heroIcon mx_E2EIcon_verified" />
|
<E2EIcon className="mx_CompleteSecurity_heroIcon" status={E2EStatus.Verified} hideTooltip />
|
||||||
{message}
|
{message}
|
||||||
<div className="mx_CompleteSecurity_actionRow">
|
<div className="mx_CompleteSecurity_actionRow">
|
||||||
<AccessibleButton kind="primary" onClick={this.onDoneClick}>
|
<AccessibleButton kind="primary" onClick={this.onDoneClick}>
|
||||||
|
|||||||
Reference in New Issue
Block a user