diff --git a/cypress/global.d.ts b/cypress/global.d.ts
index efbb255b08..a3e91a2b44 100644
--- a/cypress/global.d.ts
+++ b/cypress/global.d.ts
@@ -16,7 +16,9 @@ limitations under the License.
import "matrix-js-sdk/src/@types/global";
import type { MatrixClient, ClientEvent } from "matrix-js-sdk/src/client";
+import type { MatrixScheduler, MemoryCryptoStore, MemoryStore, RoomStateEvent } from "matrix-js-sdk/src/matrix";
import type { RoomMemberEvent } from "matrix-js-sdk/src/models/room-member";
+import type { WebStorageSessionStore } from "matrix-js-sdk/src/store/session/webstorage";
import type { MatrixDispatcher } from "../src/dispatcher/dispatcher";
import type PerformanceMonitor from "../src/performance";
@@ -35,6 +37,11 @@ declare global {
MatrixClient: typeof MatrixClient;
ClientEvent: typeof ClientEvent;
RoomMemberEvent: typeof RoomMemberEvent;
+ RoomStateEvent: typeof RoomStateEvent;
+ MatrixScheduler: typeof MatrixScheduler;
+ MemoryStore: typeof MemoryStore;
+ MemoryCryptoStore: typeof MemoryCryptoStore;
+ WebStorageSessionStore: typeof WebStorageSessionStore;
};
}
}
diff --git a/cypress/integration/7-crypto/crypto.spec.ts b/cypress/integration/7-crypto/crypto.spec.ts
new file mode 100644
index 0000000000..2446e3bd2b
--- /dev/null
+++ b/cypress/integration/7-crypto/crypto.spec.ts
@@ -0,0 +1,82 @@
+/*
+Copyright 2022 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 { MatrixClient } from "matrix-js-sdk/src/matrix";
+import { SynapseInstance } from "../../plugins/synapsedocker";
+
+function waitForEncryption(cli: MatrixClient, roomId: string, win: Cypress.AUTWindow, resolve: () => void) {
+ cli.crypto.cryptoStore.getEndToEndRooms(null, (result) => {
+ if (result[roomId]) {
+ resolve();
+ } else {
+ cli.once(win.matrixcs.RoomStateEvent.Update, () => waitForEncryption(cli, roomId, win, resolve));
+ }
+ });
+}
+
+describe("Cryptography", () => {
+ beforeEach(() => {
+ cy.startSynapse("default").as('synapse').then(
+ synapse => cy.initTestUser(synapse, "Alice"),
+ );
+ });
+
+ afterEach(() => {
+ cy.get('@synapse').then(synapse => cy.stopSynapse(synapse));
+ });
+
+ it("should receive and decrypt encrypted messages", () => {
+ cy.get('@synapse').then(synapse => cy.getBot(synapse, "Beatrice").as('bot'));
+
+ cy.createRoom({
+ initial_state: [
+ {
+ type: "m.room.encryption",
+ state_key: '',
+ content: {
+ algorithm: "m.megolm.v1.aes-sha2",
+ },
+ },
+ ],
+ }).as('roomId');
+
+ cy.all([
+ cy.get('@bot'),
+ cy.get('@roomId'),
+ cy.window(),
+ ]).then(([bot, roomId, win]) => {
+ cy.inviteUser(roomId, bot.getUserId());
+ cy.visit("/#/room/" + roomId);
+ cy.wrap(
+ new Promise(resolve =>
+ waitForEncryption(bot, roomId, win, resolve),
+ ).then(() => bot.sendMessage(roomId, {
+ body: "Top secret message",
+ msgtype: "m.text",
+ })),
+ );
+ });
+
+ cy.get(".mx_RoomView_body .mx_cryptoEvent").should("contain", "Encryption enabled");
+
+ cy.get(".mx_EventTile_body")
+ .contains("Top secret message")
+ .closest(".mx_EventTile_line")
+ .should("not.have.descendants", ".mx_EventTile_e2eIcon_warning");
+ });
+});
diff --git a/cypress/support/bot.ts b/cypress/support/bot.ts
index a2488c0081..e3bdf49d31 100644
--- a/cypress/support/bot.ts
+++ b/cypress/support/bot.ts
@@ -20,6 +20,7 @@ import request from "browser-request";
import type { MatrixClient } from "matrix-js-sdk/src/client";
import { SynapseInstance } from "../plugins/synapsedocker";
+import { MockStorage } from "./storage";
import Chainable = Cypress.Chainable;
declare global {
@@ -47,6 +48,10 @@ Cypress.Commands.add("getBot", (synapse: SynapseInstance, displayName?: string):
deviceId: credentials.deviceId,
accessToken: credentials.accessToken,
request,
+ store: new win.matrixcs.MemoryStore(),
+ scheduler: new win.matrixcs.MatrixScheduler(),
+ cryptoStore: new win.matrixcs.MemoryCryptoStore(),
+ sessionStore: new win.matrixcs.WebStorageSessionStore(new MockStorage()),
});
cli.on(win.matrixcs.RoomMemberEvent.Membership, (event, member) => {
@@ -55,9 +60,12 @@ Cypress.Commands.add("getBot", (synapse: SynapseInstance, displayName?: string):
}
});
- cli.startClient();
-
- return cli;
+ return cy.wrap(
+ cli.initCrypto()
+ .then(() => cli.setGlobalErrorOnUnknownDevices(false))
+ .then(() => cli.startClient())
+ .then(() => cli),
+ );
});
});
});
diff --git a/cypress/support/storage.ts b/cypress/support/storage.ts
new file mode 100644
index 0000000000..d93e118835
--- /dev/null
+++ b/cypress/support/storage.ts
@@ -0,0 +1,58 @@
+/*
+Copyright 2022 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.
+*/
+
+export class MockStorage implements Storage {
+ private data: Record = {};
+ private keys: string[] = [];
+ public length = 0;
+
+ constructor() {}
+
+ public setItem(k: string, v: string) {
+ this.data[k] = v;
+ this.recalc();
+ }
+
+ public getItem(k: string): string | null {
+ return this.data[k] || null;
+ }
+
+ public removeItem(k: string) {
+ delete this.data[k];
+ this.recalc();
+ }
+
+ public clear() {
+ this.data = {};
+ this.recalc();
+ }
+
+ public key(index: number): string {
+ return this.keys[index];
+ }
+
+ private recalc() {
+ const keys = [];
+ for (const k in this.data) {
+ if (!this.data.hasOwnProperty(k)) {
+ continue;
+ }
+ keys.push(k);
+ }
+ this.keys = keys;
+ this.length = keys.length;
+ }
+}