1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-11-26 17:03:12 +03:00

Element-R: Stub out isCrossSigningReady and isSecretStorageReady (#3354)

* Stub implementation of `isCrossSigningReady`

* Stub implementation of `isSecretStorageReady`

* add tests to meet quality gate

* factor out common

* Remove accidentally-added file
This commit is contained in:
Richard van der Hoff
2023-05-12 13:21:52 +01:00
committed by GitHub
parent 40f2579158
commit 63abd00ca7
5 changed files with 122 additions and 37 deletions

View File

@@ -70,6 +70,7 @@ import { SyncState } from "../../src/sync";
import * as featureUtils from "../../src/feature"; import * as featureUtils from "../../src/feature";
import { StubStore } from "../../src/store/stub"; import { StubStore } from "../../src/store/stub";
import { SecretStorageKeyDescriptionAesV1, ServerSideSecretStorageImpl } from "../../src/secret-storage"; import { SecretStorageKeyDescriptionAesV1, ServerSideSecretStorageImpl } from "../../src/secret-storage";
import { CryptoBackend } from "../../src/common-crypto/CryptoBackend";
jest.useFakeTimers(); jest.useFakeTimers();
@@ -2750,6 +2751,47 @@ describe("MatrixClient", function () {
}); });
}); });
// these wrappers are deprecated, but we need coverage of them to pass the quality gate
describe("Crypto wrappers", () => {
describe("exception if no crypto", () => {
it("isCrossSigningReady", () => {
expect(() => client.isCrossSigningReady()).toThrow("End-to-end encryption disabled");
});
it("isSecretStorageReady", () => {
expect(() => client.isSecretStorageReady()).toThrow("End-to-end encryption disabled");
});
});
describe("defer to crypto backend", () => {
let mockCryptoBackend: Mocked<CryptoBackend>;
beforeEach(() => {
mockCryptoBackend = {
isCrossSigningReady: jest.fn(),
isSecretStorageReady: jest.fn(),
stop: jest.fn().mockResolvedValue(undefined),
} as unknown as Mocked<CryptoBackend>;
client["cryptoBackend"] = mockCryptoBackend;
});
it("isCrossSigningReady", async () => {
const testResult = "test";
mockCryptoBackend.isCrossSigningReady.mockResolvedValue(testResult as unknown as boolean);
expect(await client.isCrossSigningReady()).toBe(testResult);
expect(mockCryptoBackend.isCrossSigningReady).toHaveBeenCalledTimes(1);
});
it("isSecretStorageReady", async () => {
client["cryptoBackend"] = mockCryptoBackend;
const testResult = "test";
mockCryptoBackend.isSecretStorageReady.mockResolvedValue(testResult as unknown as boolean);
expect(await client.isSecretStorageReady()).toBe(testResult);
expect(mockCryptoBackend.isSecretStorageReady).toHaveBeenCalledTimes(1);
});
});
});
describe("paginateEventTimeline()", () => { describe("paginateEventTimeline()", () => {
describe("notifications timeline", () => { describe("notifications timeline", () => {
const unsafeNotification = { const unsafeNotification = {

View File

@@ -22,7 +22,7 @@ import { Mocked } from "jest-mock";
import { RustCrypto } from "../../../src/rust-crypto/rust-crypto"; import { RustCrypto } from "../../../src/rust-crypto/rust-crypto";
import { initRustCrypto } from "../../../src/rust-crypto"; import { initRustCrypto } from "../../../src/rust-crypto";
import { IToDeviceEvent, MatrixClient, MatrixHttpApi } from "../../../src"; import { IHttpOpts, IToDeviceEvent, MatrixClient, MatrixHttpApi } from "../../../src";
import { mkEvent } from "../../test-utils/test-utils"; import { mkEvent } from "../../test-utils/test-utils";
import { CryptoBackend } from "../../../src/common-crypto/CryptoBackend"; import { CryptoBackend } from "../../../src/common-crypto/CryptoBackend";
import { IEventDecryptionResult } from "../../../src/@types/crypto"; import { IEventDecryptionResult } from "../../../src/@types/crypto";
@@ -36,21 +36,15 @@ afterEach(() => {
indexedDB = new IDBFactory(); indexedDB = new IDBFactory();
}); });
describe("RustCrypto", () => {
const TEST_USER = "@alice:example.com"; const TEST_USER = "@alice:example.com";
const TEST_DEVICE_ID = "TEST_DEVICE"; const TEST_DEVICE_ID = "TEST_DEVICE";
describe("RustCrypto", () => {
describe(".exportRoomKeys", () => { describe(".exportRoomKeys", () => {
let rustCrypto: RustCrypto; let rustCrypto: RustCrypto;
beforeEach(async () => { beforeEach(async () => {
const mockHttpApi = {} as MatrixClient["http"]; rustCrypto = await makeTestRustCrypto();
rustCrypto = (await initRustCrypto(
mockHttpApi,
TEST_USER,
TEST_DEVICE_ID,
{} as ServerSideSecretStorage,
)) as RustCrypto;
}); });
it("should return a list", async () => { it("should return a list", async () => {
@@ -63,13 +57,7 @@ describe("RustCrypto", () => {
let rustCrypto: RustCrypto; let rustCrypto: RustCrypto;
beforeEach(async () => { beforeEach(async () => {
const mockHttpApi = {} as MatrixClient["http"]; rustCrypto = await makeTestRustCrypto();
rustCrypto = (await initRustCrypto(
mockHttpApi,
TEST_USER,
TEST_DEVICE_ID,
{} as ServerSideSecretStorage,
)) as RustCrypto;
}); });
it("should pass through unencrypted to-device messages", async () => { it("should pass through unencrypted to-device messages", async () => {
@@ -105,6 +93,16 @@ describe("RustCrypto", () => {
}); });
}); });
it("isCrossSigningReady", async () => {
const rustCrypto = await makeTestRustCrypto();
await expect(rustCrypto.isCrossSigningReady()).resolves.toBe(false);
});
it("isSecretStorageReady", async () => {
const rustCrypto = await makeTestRustCrypto();
await expect(rustCrypto.isSecretStorageReady()).resolves.toBe(false);
});
describe("outgoing requests", () => { describe("outgoing requests", () => {
/** the RustCrypto implementation under test */ /** the RustCrypto implementation under test */
let rustCrypto: RustCrypto; let rustCrypto: RustCrypto;
@@ -223,13 +221,7 @@ describe("RustCrypto", () => {
let rustCrypto: RustCrypto; let rustCrypto: RustCrypto;
beforeEach(async () => { beforeEach(async () => {
const mockHttpApi = {} as MatrixClient["http"]; rustCrypto = await makeTestRustCrypto();
rustCrypto = (await initRustCrypto(
mockHttpApi,
TEST_USER,
TEST_DEVICE_ID,
{} as ServerSideSecretStorage,
)) as RustCrypto;
}); });
it("should handle unencrypted events", () => { it("should handle unencrypted events", () => {
@@ -257,12 +249,7 @@ describe("RustCrypto", () => {
let rustCrypto: RustCrypto; let rustCrypto: RustCrypto;
beforeEach(async () => { beforeEach(async () => {
rustCrypto = await initRustCrypto( rustCrypto = await makeTestRustCrypto();
{} as MatrixClient["http"],
TEST_USER,
TEST_DEVICE_ID,
{} as ServerSideSecretStorage,
);
}); });
it("should be true by default", () => { it("should be true by default", () => {
@@ -315,3 +302,16 @@ describe("RustCrypto", () => {
}); });
}); });
}); });
/** build a basic RustCrypto instance for testing
*
* just provides default arguments for initRustCrypto()
*/
async function makeTestRustCrypto(
http: MatrixHttpApi<IHttpOpts & { onlyData: true }> = {} as MatrixClient["http"],
userId: string = TEST_USER,
deviceId: string = TEST_DEVICE_ID,
secretStorage: ServerSideSecretStorage = {} as ServerSideSecretStorage,
): Promise<RustCrypto> {
return await initRustCrypto(http, userId, deviceId, secretStorage);
}

View File

@@ -2731,12 +2731,13 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
* bootstrapCrossSigning() completes successfully, this function should * bootstrapCrossSigning() completes successfully, this function should
* return true. * return true.
* @returns True if cross-signing is ready to be used on this device * @returns True if cross-signing is ready to be used on this device
* @deprecated Prefer {@link CryptoApi.isCrossSigningReady | `CryptoApi.isCrossSigningReady`}:
*/ */
public isCrossSigningReady(): Promise<boolean> { public isCrossSigningReady(): Promise<boolean> {
if (!this.crypto) { if (!this.cryptoBackend) {
throw new Error("End-to-end encryption disabled"); throw new Error("End-to-end encryption disabled");
} }
return this.crypto.isCrossSigningReady(); return this.cryptoBackend.isCrossSigningReady();
} }
/** /**
@@ -2843,15 +2844,14 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
* bootstrapSecretStorage() completes successfully, this function should * bootstrapSecretStorage() completes successfully, this function should
* return true. * return true.
* *
* The Secure Secret Storage API is currently UNSTABLE and may change without notice.
*
* @returns True if secret storage is ready to be used on this device * @returns True if secret storage is ready to be used on this device
* @deprecated Prefer {@link CryptoApi.isSecretStorageReady | `CryptoApi.isSecretStorageReady`}:
*/ */
public isSecretStorageReady(): Promise<boolean> { public isSecretStorageReady(): Promise<boolean> {
if (!this.crypto) { if (!this.cryptoBackend) {
throw new Error("End-to-end encryption disabled"); throw new Error("End-to-end encryption disabled");
} }
return this.crypto.isSecretStorageReady(); return this.cryptoBackend.isSecretStorageReady();
} }
/** /**

View File

@@ -122,6 +122,35 @@ export interface CryptoApi {
* @returns Verification status of the device, or `null` if the device is not known * @returns Verification status of the device, or `null` if the device is not known
*/ */
getDeviceVerificationStatus(userId: string, deviceId: string): Promise<DeviceVerificationStatus | null>; getDeviceVerificationStatus(userId: string, deviceId: string): Promise<DeviceVerificationStatus | null>;
/**
* Checks whether cross signing:
* - is enabled on this account and trusted by this device
* - has private keys either cached locally or stored in secret storage
*
* If this function returns false, bootstrapCrossSigning() can be used
* to fix things such that it returns true. That is to say, after
* bootstrapCrossSigning() completes successfully, this function should
* return true.
*
* @returns True if cross-signing is ready to be used on this device
*/
isCrossSigningReady(): Promise<boolean>;
/**
* Checks whether secret storage:
* - is enabled on this account
* - is storing cross-signing private keys
* - is storing session backup key (if enabled)
*
* If this function returns false, bootstrapSecretStorage() can be used
* to fix things such that it returns true. That is to say, after
* bootstrapSecretStorage() completes successfully, this function should
* return true.
*
* @returns True if secret storage is ready to be used on this device
*/
isSecretStorageReady(): Promise<boolean>;
} }
/** /**

View File

@@ -317,6 +317,20 @@ export class RustCrypto implements CryptoBackend {
}); });
} }
/**
* Implementation of {@link CryptoApi#isCrossSigningReady}
*/
public async isCrossSigningReady(): Promise<boolean> {
return false;
}
/**
* Implementation of {@link CryptoApi#isSecretStorageReady}
*/
public async isSecretStorageReady(): Promise<boolean> {
return false;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// SyncCryptoCallbacks implementation // SyncCryptoCallbacks implementation