From 1a75d5d869c743d20a38225f04d6832a80195b1f Mon Sep 17 00:00:00 2001 From: Richard van der Hoff <1389908+richvdh@users.noreply.github.com> Date: Fri, 7 Jul 2023 17:56:53 +0100 Subject: [PATCH] Cypress: Use Rust crypto for the bot user in verification tests (#11173) * Cypress: `crypto.verification.request` -> `crypto.verificationRequestReceived` matrix-org/matrix-js-sdk#3514 deprecated crypto.verification.request. * Cypress: `beginKeyVerification` -> `startVerification` matrix-org/matrix-js-sdk#3528 deprecated beginKeyVerification * simplify `setupBotClient` no functional change here, just combining the various `cy.wrap()`ed things into a single async func * Cypress: Use Rust crypto for the bot user in verification tests We can already start using the Rust crypto implementation for the "bot" user in the verification tests! --- cypress/e2e/crypto/crypto.spec.ts | 4 +- cypress/e2e/crypto/utils.ts | 12 +-- cypress/e2e/crypto/verification.spec.ts | 6 +- cypress/support/bot.ts | 118 +++++++++++++----------- 4 files changed, 75 insertions(+), 65 deletions(-) diff --git a/cypress/e2e/crypto/crypto.spec.ts b/cypress/e2e/crypto/crypto.spec.ts index 0d323dbcec..718ef1f3e6 100644 --- a/cypress/e2e/crypto/crypto.spec.ts +++ b/cypress/e2e/crypto/crypto.spec.ts @@ -116,9 +116,9 @@ const verify = function (this: CryptoTestContext) { // this requires creating a DM, so can take a while. Give it a longer timeout. cy.findByRole("button", { name: "Verify by emoji", timeout: 30000 }).click(); - cy.wrap(bobsVerificationRequestPromise).then((request: VerificationRequest) => { + cy.wrap(bobsVerificationRequestPromise).then(async (request: VerificationRequest) => { // the bot user races with the Element user to hit the "verify by emoji" button - const verifier = request.beginKeyVerification("m.sas.v1"); + const verifier = await request.startVerification("m.sas.v1"); doTwoWaySasVerification(verifier); }); cy.findByRole("button", { name: "They match" }).click(); diff --git a/cypress/e2e/crypto/utils.ts b/cypress/e2e/crypto/utils.ts index 3d63fcb124..5de56cde9d 100644 --- a/cypress/e2e/crypto/utils.ts +++ b/cypress/e2e/crypto/utils.ts @@ -28,13 +28,11 @@ export type EmojiMapping = [emoji: string, name: string]; export function waitForVerificationRequest(cli: MatrixClient): Promise { return new Promise((resolve) => { const onVerificationRequestEvent = async (request: VerificationRequest) => { - // @ts-ignore CryptoEvent is not exported to window.matrixcs; using the string value here - cli.off("crypto.verification.request", onVerificationRequestEvent); await request.accept(); resolve(request); }; - // @ts-ignore - cli.on("crypto.verification.request", onVerificationRequestEvent); + // @ts-ignore CryptoEvent is not exported to window.matrixcs; using the string value here + cli.once("crypto.verificationRequestReceived", onVerificationRequestEvent); }); } @@ -59,7 +57,6 @@ export function handleSasVerification(verifier: Verifier): Promise { cy.get(".mx_VerificationShowSas_emojiSas_block").then((emojiBlocks) => { emojis.forEach((emoji: EmojiMapping, index: number) => { - expect(emojiBlocks[index].textContent.toLowerCase()).to.eq(emoji[0] + emoji[1]); + // VerificationShowSas munges the case of the emoji descriptions returned by the js-sdk before + // displaying them. Once we drop support for legacy crypto, that code can go away, and so can the + // case-munging here. + expect(emojiBlocks[index].textContent.toLowerCase()).to.eq(emoji[0] + emoji[1].toLowerCase()); }); }); }); diff --git a/cypress/e2e/crypto/verification.spec.ts b/cypress/e2e/crypto/verification.spec.ts index 31d3c83212..b6ec5f0fbb 100644 --- a/cypress/e2e/crypto/verification.spec.ts +++ b/cypress/e2e/crypto/verification.spec.ts @@ -36,7 +36,7 @@ describe("Device verification", () => { cy.window({ log: false }).should("have.property", "matrixcs"); // Create a new device for alice - cy.getBot(homeserver, { bootstrapCrossSigning: true }).then((bot) => { + cy.getBot(homeserver, { rustCrypto: true, bootstrapCrossSigning: true }).then((bot) => { aliceBotClient = bot; }); }); @@ -71,9 +71,9 @@ describe("Device verification", () => { // Handle emoji SAS verification cy.get(".mx_InfoDialog").within(() => { - cy.get("@verificationRequest").then((request: VerificationRequest) => { + cy.get("@verificationRequest").then(async (request: VerificationRequest) => { // the bot chooses to do an emoji verification - const verifier = request.beginKeyVerification("m.sas.v1"); + const verifier = await request.startVerification("m.sas.v1"); // Handle emoji request and check that emojis are matching doTwoWaySasVerification(verifier); diff --git a/cypress/support/bot.ts b/cypress/support/bot.ts index 6d16a110a4..5806bab7ef 100644 --- a/cypress/support/bot.ts +++ b/cypress/support/bot.ts @@ -43,6 +43,10 @@ interface CreateBotOpts { * Whether or not to generate cross-signing keys */ bootstrapCrossSigning?: boolean; + /** + * Whether to use the rust crypto impl. Defaults to false (for now!) + */ + rustCrypto?: boolean; } const defaultCreateBotOptions = { @@ -125,66 +129,72 @@ function setupBotClient( opts: CreateBotOpts, ): Chainable { opts = Object.assign({}, defaultCreateBotOptions, opts); - return cy.window({ log: false }).then((win) => { - const keys = {}; + return cy.window({ log: false }).then( + // extra timeout, as this sometimes takes a while + { timeout: 30_000 }, + async (win): Promise => { + const keys = {}; - const getCrossSigningKey = (type: string) => { - return keys[type]; - }; + const getCrossSigningKey = (type: string) => { + return keys[type]; + }; - const saveCrossSigningKeys = (k: Record) => { - Object.assign(keys, k); - }; + const saveCrossSigningKeys = (k: Record) => { + Object.assign(keys, k); + }; - const cli = new win.matrixcs.MatrixClient({ - baseUrl: homeserver.baseUrl, - userId: credentials.userId, - deviceId: credentials.deviceId, - accessToken: credentials.accessToken, - store: new win.matrixcs.MemoryStore(), - scheduler: new win.matrixcs.MatrixScheduler(), - cryptoStore: new win.matrixcs.MemoryCryptoStore(), - cryptoCallbacks: { getCrossSigningKey, saveCrossSigningKeys }, - }); - - if (opts.autoAcceptInvites) { - cli.on(win.matrixcs.RoomMemberEvent.Membership, (event, member) => { - if (member.membership === "invite" && member.userId === cli.getUserId()) { - cli.joinRoom(member.roomId); - } + const cli = new win.matrixcs.MatrixClient({ + baseUrl: homeserver.baseUrl, + userId: credentials.userId, + deviceId: credentials.deviceId, + accessToken: credentials.accessToken, + store: new win.matrixcs.MemoryStore(), + scheduler: new win.matrixcs.MatrixScheduler(), + cryptoStore: new win.matrixcs.MemoryCryptoStore(), + cryptoCallbacks: { getCrossSigningKey, saveCrossSigningKeys }, }); - } - if (!opts.startClient) { - return cy.wrap(cli); - } - - return cy.wrap( - cli - .initCrypto() - .then(() => cli.setGlobalErrorOnUnknownDevices(false)) - .then(() => cli.startClient()) - .then(async () => { - if (opts.bootstrapCrossSigning) { - await cli.bootstrapCrossSigning({ - authUploadDeviceSigningKeys: async (func) => { - await func({ - type: "m.login.password", - identifier: { - type: "m.id.user", - user: credentials.userId, - }, - password: credentials.password, - }); - }, - }); + if (opts.autoAcceptInvites) { + cli.on(win.matrixcs.RoomMemberEvent.Membership, (event, member) => { + if (member.membership === "invite" && member.userId === cli.getUserId()) { + cli.joinRoom(member.roomId); } - }) - .then(() => cli), - // extra timeout, as this sometimes takes a while - { timeout: 30_000 }, - ); - }); + }); + } + + if (!opts.startClient) { + return cli; + } + + if (opts.rustCrypto) { + await cli.initRustCrypto({ useIndexedDB: false }); + } else { + await cli.initCrypto(); + } + cli.setGlobalErrorOnUnknownDevices(false); + await cli.startClient(); + + if (opts.bootstrapCrossSigning) { + // XXX: workaround https://github.com/matrix-org/matrix-rust-sdk/issues/2193 + // wait for out device list to be available, as a proxy for the device keys having been uploaded. + await cli.getCrypto()!.getUserDeviceInfo([credentials.userId]); + + await cli.getCrypto()!.bootstrapCrossSigning({ + authUploadDeviceSigningKeys: async (func) => { + await func({ + type: "m.login.password", + identifier: { + type: "m.id.user", + user: credentials.userId, + }, + password: credentials.password, + }); + }, + }); + } + return cli; + }, + ); } Cypress.Commands.add("getBot", (homeserver: HomeserverInstance, opts: CreateBotOpts): Chainable => {