mirror of https://github.com/vector-im/riot-web
146 lines
5.8 KiB
TypeScript
146 lines
5.8 KiB
TypeScript
|
/*
|
||
|
Copyright 2023 The Matrix.org Foundation C.I.C.
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
Unless required by applicable law or agreed to in writing, software
|
||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
See the License for the specific language governing permissions and
|
||
|
limitations under the License.
|
||
|
*/
|
||
|
|
||
|
import { type Preset, type Visibility } from "matrix-js-sdk/src/matrix";
|
||
|
|
||
|
import { test, expect } from "../../element-web-test";
|
||
|
import { doTwoWaySasVerification, awaitVerifier } from "./utils";
|
||
|
import { Client } from "../../pages/client";
|
||
|
|
||
|
test.describe("User verification", () => {
|
||
|
// note that there are other tests that check user verification works in `crypto.spec.ts`.
|
||
|
|
||
|
test.use({
|
||
|
displayName: "Alice",
|
||
|
botCreateOpts: { displayName: "Bob", autoAcceptInvites: true, userIdPrefix: "bob_" },
|
||
|
room: async ({ page, app, bot: bob, user: aliceCredentials }, use) => {
|
||
|
await app.client.bootstrapCrossSigning(aliceCredentials);
|
||
|
|
||
|
// the other user creates a DM
|
||
|
const dmRoomId = await createDMRoom(bob, aliceCredentials.userId);
|
||
|
|
||
|
// accept the DM
|
||
|
await app.viewRoomByName("Bob");
|
||
|
await page.getByRole("button", { name: "Start chatting" }).click();
|
||
|
await use({ roomId: dmRoomId });
|
||
|
},
|
||
|
});
|
||
|
|
||
|
test("can receive a verification request when there is no existing DM", async ({
|
||
|
page,
|
||
|
bot: bob,
|
||
|
user: aliceCredentials,
|
||
|
toasts,
|
||
|
room: { roomId: dmRoomId },
|
||
|
}) => {
|
||
|
// once Alice has joined, Bob starts the verification
|
||
|
const bobVerificationRequest = await bob.evaluateHandle(
|
||
|
async (client, { dmRoomId, aliceCredentials }) => {
|
||
|
const room = client.getRoom(dmRoomId);
|
||
|
while (room.getMember(aliceCredentials.userId)?.membership !== "join") {
|
||
|
await new Promise((resolve) => {
|
||
|
room.once(window.matrixcs.RoomStateEvent.Members, resolve);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return client.getCrypto().requestVerificationDM(aliceCredentials.userId, dmRoomId);
|
||
|
},
|
||
|
{ dmRoomId, aliceCredentials },
|
||
|
);
|
||
|
|
||
|
// there should also be a toast
|
||
|
const toast = await toasts.getToast("Verification requested");
|
||
|
// it should contain the details of the requesting user
|
||
|
await expect(toast.getByText(`Bob (${bob.credentials.userId})`)).toBeVisible();
|
||
|
// Accept
|
||
|
await toast.getByRole("button", { name: "Verify User" }).click();
|
||
|
|
||
|
// request verification by emoji
|
||
|
await page.locator("#mx_RightPanel").getByRole("button", { name: "Verify by emoji" }).click();
|
||
|
|
||
|
/* on the bot side, wait for the verifier to exist ... */
|
||
|
const botVerifier = await awaitVerifier(bobVerificationRequest);
|
||
|
// ... confirm ...
|
||
|
botVerifier.evaluate((verifier) => verifier.verify());
|
||
|
// ... and then check the emoji match
|
||
|
await doTwoWaySasVerification(page, botVerifier);
|
||
|
|
||
|
await page.getByRole("button", { name: "They match" }).click();
|
||
|
await expect(page.getByText("You've successfully verified Bob!")).toBeVisible();
|
||
|
await page.getByRole("button", { name: "Got it" }).click();
|
||
|
});
|
||
|
|
||
|
test("can abort emoji verification when emoji mismatch", async ({
|
||
|
page,
|
||
|
bot: bob,
|
||
|
user: aliceCredentials,
|
||
|
toasts,
|
||
|
room: { roomId: dmRoomId },
|
||
|
}) => {
|
||
|
// once Alice has joined, Bob starts the verification
|
||
|
const bobVerificationRequest = await bob.evaluateHandle(
|
||
|
async (client, { dmRoomId, aliceCredentials }) => {
|
||
|
const room = client.getRoom(dmRoomId);
|
||
|
while (room.getMember(aliceCredentials.userId)?.membership !== "join") {
|
||
|
await new Promise((resolve) => {
|
||
|
room.once(window.matrixcs.RoomStateEvent.Members, resolve);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
return client.getCrypto().requestVerificationDM(aliceCredentials.userId, dmRoomId);
|
||
|
},
|
||
|
{ dmRoomId, aliceCredentials },
|
||
|
);
|
||
|
|
||
|
// Accept verification via toast
|
||
|
const toast = await toasts.getToast("Verification requested");
|
||
|
await toast.getByRole("button", { name: "Verify User" }).click();
|
||
|
|
||
|
// request verification by emoji
|
||
|
await page.locator("#mx_RightPanel").getByRole("button", { name: "Verify by emoji" }).click();
|
||
|
|
||
|
/* on the bot side, wait for the verifier to exist ... */
|
||
|
const botVerifier = await awaitVerifier(bobVerificationRequest);
|
||
|
// ... confirm ...
|
||
|
botVerifier.evaluate((verifier) => verifier.verify()).catch(() => {});
|
||
|
// ... and abort the verification
|
||
|
await page.getByRole("button", { name: "They don't match" }).click();
|
||
|
|
||
|
const dialog = page.locator(".mx_Dialog");
|
||
|
await expect(dialog.getByText("Your messages are not secure")).toBeVisible();
|
||
|
await dialog.getByRole("button", { name: "OK" }).click();
|
||
|
await expect(dialog).not.toBeVisible();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
async function createDMRoom(client: Client, userId: string): Promise<string> {
|
||
|
return client.createRoom({
|
||
|
preset: "trusted_private_chat" as Preset,
|
||
|
visibility: "private" as Visibility,
|
||
|
invite: [userId],
|
||
|
is_direct: true,
|
||
|
initial_state: [
|
||
|
{
|
||
|
type: "m.room.encryption",
|
||
|
state_key: "",
|
||
|
content: {
|
||
|
algorithm: "m.megolm.v1.aes-sha2",
|
||
|
},
|
||
|
},
|
||
|
],
|
||
|
});
|
||
|
}
|