mirror of https://github.com/vector-im/riot-web
Ensure we do not fire the verification mismatch modal multiple times (#12526)
* Ensure we do not fire the verification mismatch modal multiple times Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> * Add rust crypto test for mismatch emoji cancellation Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --------- Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>pull/28217/head
parent
113c365563
commit
24df2e8cb7
|
@ -240,24 +240,26 @@ test.describe("User verification", () => {
|
||||||
test.use({
|
test.use({
|
||||||
displayName: "Alice",
|
displayName: "Alice",
|
||||||
botCreateOpts: { displayName: "Bob", autoAcceptInvites: true, userIdPrefix: "bob_" },
|
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 ({
|
test("can receive a verification request when there is no existing DM", async ({
|
||||||
page,
|
page,
|
||||||
app,
|
|
||||||
bot: bob,
|
bot: bob,
|
||||||
user: aliceCredentials,
|
user: aliceCredentials,
|
||||||
toasts,
|
toasts,
|
||||||
|
room: { roomId: dmRoomId },
|
||||||
}) => {
|
}) => {
|
||||||
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();
|
|
||||||
|
|
||||||
// once Alice has joined, Bob starts the verification
|
// once Alice has joined, Bob starts the verification
|
||||||
const bobVerificationRequest = await bob.evaluateHandle(
|
const bobVerificationRequest = await bob.evaluateHandle(
|
||||||
async (client, { dmRoomId, aliceCredentials }) => {
|
async (client, { dmRoomId, aliceCredentials }) => {
|
||||||
|
@ -294,6 +296,51 @@ test.describe("User verification", () => {
|
||||||
await expect(page.getByText("You've successfully verified Bob!")).toBeVisible();
|
await expect(page.getByText("You've successfully verified Bob!")).toBeVisible();
|
||||||
await page.getByRole("button", { name: "Got it" }).click();
|
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 },
|
||||||
|
cryptoBackend,
|
||||||
|
}) => {
|
||||||
|
test.skip(cryptoBackend === "legacy", "Not implemented for legacy crypto");
|
||||||
|
|
||||||
|
// 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 Session" }).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();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
/** Extract the qrcode out of an on-screen html element */
|
/** Extract the qrcode out of an on-screen html element */
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { VerificationPhase, VerificationRequest, VerificationRequestEvent } from "matrix-js-sdk/src/crypto-api";
|
import { VerificationPhase, VerificationRequest, VerificationRequestEvent } from "matrix-js-sdk/src/crypto-api";
|
||||||
import { RoomMember, User } from "matrix-js-sdk/src/matrix";
|
import { RoomMember, User } from "matrix-js-sdk/src/matrix";
|
||||||
|
|
||||||
|
@ -69,13 +69,17 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
|
||||||
awaitPromise();
|
awaitPromise();
|
||||||
}
|
}
|
||||||
}, [verificationRequestPromise]);
|
}, [verificationRequestPromise]);
|
||||||
|
// Use a ref to track whether we are already showing the mismatch modal as state may not update fast enough
|
||||||
|
// if two change events are fired in quick succession like can happen with rust crypto.
|
||||||
|
const isShowingMismatchModal = useRef(false);
|
||||||
const changeHandler = useCallback(() => {
|
const changeHandler = useCallback(() => {
|
||||||
// handle transitions -> cancelled for mismatches which fire a modal instead of showing a card
|
// handle transitions -> cancelled for mismatches which fire a modal instead of showing a card
|
||||||
if (
|
if (
|
||||||
request &&
|
!isShowingMismatchModal.current &&
|
||||||
request.phase === VerificationPhase.Cancelled &&
|
request?.phase === VerificationPhase.Cancelled &&
|
||||||
MISMATCHES.includes(request.cancellationCode ?? "")
|
MISMATCHES.includes(request.cancellationCode ?? "")
|
||||||
) {
|
) {
|
||||||
|
isShowingMismatchModal.current = true;
|
||||||
Modal.createDialog(ErrorDialog, {
|
Modal.createDialog(ErrorDialog, {
|
||||||
headerImage: require("../../../../res/img/e2e/warning-deprecated.svg").default,
|
headerImage: require("../../../../res/img/e2e/warning-deprecated.svg").default,
|
||||||
title: _t("encryption|messages_not_secure|title"),
|
title: _t("encryption|messages_not_secure|title"),
|
||||||
|
|
Loading…
Reference in New Issue