Skip to content
This repository was archived by the owner on Sep 11, 2024. It is now read-only.

Commit 24df2e8

Browse files
authored
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>
1 parent 113c365 commit 24df2e8

File tree

2 files changed

+64
-13
lines changed

2 files changed

+64
-13
lines changed

playwright/e2e/crypto/verification.spec.ts

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -240,24 +240,26 @@ test.describe("User verification", () => {
240240
test.use({
241241
displayName: "Alice",
242242
botCreateOpts: { displayName: "Bob", autoAcceptInvites: true, userIdPrefix: "bob_" },
243+
room: async ({ page, app, bot: bob, user: aliceCredentials }, use) => {
244+
await app.client.bootstrapCrossSigning(aliceCredentials);
245+
246+
// the other user creates a DM
247+
const dmRoomId = await createDMRoom(bob, aliceCredentials.userId);
248+
249+
// accept the DM
250+
await app.viewRoomByName("Bob");
251+
await page.getByRole("button", { name: "Start chatting" }).click();
252+
await use({ roomId: dmRoomId });
253+
},
243254
});
244255

245256
test("can receive a verification request when there is no existing DM", async ({
246257
page,
247-
app,
248258
bot: bob,
249259
user: aliceCredentials,
250260
toasts,
261+
room: { roomId: dmRoomId },
251262
}) => {
252-
await app.client.bootstrapCrossSigning(aliceCredentials);
253-
254-
// the other user creates a DM
255-
const dmRoomId = await createDMRoom(bob, aliceCredentials.userId);
256-
257-
// accept the DM
258-
await app.viewRoomByName("Bob");
259-
await page.getByRole("button", { name: "Start chatting" }).click();
260-
261263
// once Alice has joined, Bob starts the verification
262264
const bobVerificationRequest = await bob.evaluateHandle(
263265
async (client, { dmRoomId, aliceCredentials }) => {
@@ -294,6 +296,51 @@ test.describe("User verification", () => {
294296
await expect(page.getByText("You've successfully verified Bob!")).toBeVisible();
295297
await page.getByRole("button", { name: "Got it" }).click();
296298
});
299+
300+
test("can abort emoji verification when emoji mismatch", async ({
301+
page,
302+
bot: bob,
303+
user: aliceCredentials,
304+
toasts,
305+
room: { roomId: dmRoomId },
306+
cryptoBackend,
307+
}) => {
308+
test.skip(cryptoBackend === "legacy", "Not implemented for legacy crypto");
309+
310+
// once Alice has joined, Bob starts the verification
311+
const bobVerificationRequest = await bob.evaluateHandle(
312+
async (client, { dmRoomId, aliceCredentials }) => {
313+
const room = client.getRoom(dmRoomId);
314+
while (room.getMember(aliceCredentials.userId)?.membership !== "join") {
315+
await new Promise((resolve) => {
316+
room.once(window.matrixcs.RoomStateEvent.Members, resolve);
317+
});
318+
}
319+
320+
return client.getCrypto().requestVerificationDM(aliceCredentials.userId, dmRoomId);
321+
},
322+
{ dmRoomId, aliceCredentials },
323+
);
324+
325+
// Accept verification via toast
326+
const toast = await toasts.getToast("Verification requested");
327+
await toast.getByRole("button", { name: "Verify Session" }).click();
328+
329+
// request verification by emoji
330+
await page.locator("#mx_RightPanel").getByRole("button", { name: "Verify by emoji" }).click();
331+
332+
/* on the bot side, wait for the verifier to exist ... */
333+
const botVerifier = await awaitVerifier(bobVerificationRequest);
334+
// ... confirm ...
335+
botVerifier.evaluate((verifier) => verifier.verify()).catch(() => {});
336+
// ... and abort the verification
337+
await page.getByRole("button", { name: "They don't match" }).click();
338+
339+
const dialog = page.locator(".mx_Dialog");
340+
await expect(dialog.getByText("Your messages are not secure")).toBeVisible();
341+
await dialog.getByRole("button", { name: "OK" }).click();
342+
await expect(dialog).not.toBeVisible();
343+
});
297344
});
298345

299346
/** Extract the qrcode out of an on-screen html element */

src/components/views/right_panel/EncryptionPanel.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17-
import React, { useCallback, useEffect, useState } from "react";
17+
import React, { useCallback, useEffect, useRef, useState } from "react";
1818
import { VerificationPhase, VerificationRequest, VerificationRequestEvent } from "matrix-js-sdk/src/crypto-api";
1919
import { RoomMember, User } from "matrix-js-sdk/src/matrix";
2020

@@ -69,13 +69,17 @@ const EncryptionPanel: React.FC<IProps> = (props: IProps) => {
6969
awaitPromise();
7070
}
7171
}, [verificationRequestPromise]);
72+
// Use a ref to track whether we are already showing the mismatch modal as state may not update fast enough
73+
// if two change events are fired in quick succession like can happen with rust crypto.
74+
const isShowingMismatchModal = useRef(false);
7275
const changeHandler = useCallback(() => {
7376
// handle transitions -> cancelled for mismatches which fire a modal instead of showing a card
7477
if (
75-
request &&
76-
request.phase === VerificationPhase.Cancelled &&
78+
!isShowingMismatchModal.current &&
79+
request?.phase === VerificationPhase.Cancelled &&
7780
MISMATCHES.includes(request.cancellationCode ?? "")
7881
) {
82+
isShowingMismatchModal.current = true;
7983
Modal.createDialog(ErrorDialog, {
8084
headerImage: require("../../../../res/img/e2e/warning-deprecated.svg").default,
8185
title: _t("encryption|messages_not_secure|title"),

0 commit comments

Comments
 (0)