diff --git a/spec/unit/crypto/cross-signing.spec.ts b/spec/unit/crypto/cross-signing.spec.ts index fe5b37eb206..99ad5d0dafe 100644 --- a/spec/unit/crypto/cross-signing.spec.ts +++ b/spec/unit/crypto/cross-signing.spec.ts @@ -23,7 +23,7 @@ import HttpBackend from "matrix-mock-request"; import * as olmlib from "../../../src/crypto/olmlib"; import { MatrixError } from '../../../src/http-api'; import { logger } from '../../../src/logger'; -import { ICrossSigningKey, ICreateClientOpts, ISignedKey } from '../../../src/client'; +import { ICrossSigningKey, ICreateClientOpts, ISignedKey, MatrixClient } from '../../../src/client'; import { CryptoEvent, IBootstrapCrossSigningOpts } from '../../../src/crypto'; import { IDevice } from '../../../src/crypto/deviceinfo'; import { TestClient } from '../../TestClient'; @@ -1137,3 +1137,67 @@ describe("Cross Signing", function() { alice.stopClient(); }); }); + +describe("userHasCrossSigningKeys", function() { + if (!global.Olm) { + return; + } + + beforeAll(() => { + return global.Olm.init(); + }); + + let aliceClient: MatrixClient; + let httpBackend: HttpBackend; + beforeEach(async () => { + const testClient = await makeTestClient({ userId: "@alice:example.com", deviceId: "Osborne2" }); + aliceClient = testClient.client; + httpBackend = testClient.httpBackend; + }); + + afterEach(() => { + aliceClient.stopClient(); + }); + + it("should download devices and return true if one is a cross-signing key", async () => { + httpBackend + .when("POST", "/keys/query") + .respond(200, { + "master_keys": { + "@alice:example.com": { + user_id: "@alice:example.com", + usage: ["master"], + keys: { + "ed25519:nqOvzeuGWT/sRx3h7+MHoInYj3Uk2LD/unI9kDYcHwk": + "nqOvzeuGWT/sRx3h7+MHoInYj3Uk2LD/unI9kDYcHwk", + }, + }, + }, + }); + + let result: boolean; + await Promise.all([ + httpBackend.flush("/keys/query"), + aliceClient.userHasCrossSigningKeys().then((res) => {result = res;}), + ]); + expect(result!).toBeTruthy(); + }); + + it("should download devices and return false if there is no cross-signing key", async () => { + httpBackend + .when("POST", "/keys/query") + .respond(200, {}); + + let result: boolean; + await Promise.all([ + httpBackend.flush("/keys/query"), + aliceClient.userHasCrossSigningKeys().then((res) => {result = res;}), + ]); + expect(result!).toBeFalsy(); + }); + + it("throws an error if crypto is disabled", () => { + aliceClient.crypto = undefined; + expect(() => aliceClient.userHasCrossSigningKeys()).toThrowError("encryption disabled"); + }); +}); diff --git a/src/client.ts b/src/client.ts index fba259a5671..ce44d32fd66 100644 --- a/src/client.ts +++ b/src/client.ts @@ -2473,6 +2473,19 @@ export class MatrixClient extends TypedEventEmitter { + if (!this.crypto) { + throw new Error("End-to-end encryption disabled"); + } + return this.crypto.userHasCrossSigningKeys(); + } + /** * Checks whether cross signing: * - is enabled on this account and trusted by this device diff --git a/src/crypto/index.ts b/src/crypto/index.ts index 65b43a635a0..9191522da25 100644 --- a/src/crypto/index.ts +++ b/src/crypto/index.ts @@ -718,6 +718,19 @@ export class Crypto extends TypedEventEmitter { + await this.downloadKeys([this.userId]); + return this.deviceList.getStoredCrossSigningForUser(this.userId) !== null; + } + /** * Checks whether cross signing: * - is enabled on this account and trusted by this device