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

Start adding Cypress tests for crypto #8577

Merged
merged 14 commits into from
May 30, 2022
7 changes: 7 additions & 0 deletions cypress/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand All @@ -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;
};
}
}
Expand Down
82 changes: 82 additions & 0 deletions cypress/integration/7-crypto/crypto.spec.ts
Original file line number Diff line number Diff line change
@@ -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.
*/

/// <reference types="cypress" />

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<SynapseInstance>('@synapse').then(synapse => cy.stopSynapse(synapse));
});

it("should receive and decrypt encrypted messages", () => {
cy.get<SynapseInstance>('@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<MatrixClient>('@bot'),
cy.get<string>('@roomId'),
cy.window(),
]).then(([bot, roomId, win]) => {
cy.inviteUser(roomId, bot.getUserId());
cy.visit("/#/room/" + roomId);
cy.wrap(
new Promise<void>(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");
});
});
14 changes: 11 additions & 3 deletions cypress/support/bot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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) => {
Expand All @@ -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),
);
});
});
});
58 changes: 58 additions & 0 deletions cypress/support/storage.ts
Original file line number Diff line number Diff line change
@@ -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<string, string> = {};
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;
}
}