diff --git a/spec/integ/crypto.spec.ts b/spec/integ/crypto.spec.ts index 83e49cca7..6f13448d0 100644 --- a/spec/integ/crypto.spec.ts +++ b/spec/integ/crypto.spec.ts @@ -536,6 +536,10 @@ describe.each(Object.entries(CRYPTO_BACKENDS))("crypto (%s)", (backend: string, fetchMock.mockReset(); }); + it("MatrixClient.getCrypto returns a CryptoApi", () => { + expect(aliceClient.getCrypto()).toHaveProperty("globalBlacklistUnverifiedDevices"); + }); + it("Alice receives a megolm message", async () => { expectAliceKeyQuery({ device_keys: { "@alice:localhost": {} }, failures: {} }); await startClientAndAwaitFirstSync(); diff --git a/src/client.ts b/src/client.ts index 8f861892a..43e659433 100644 --- a/src/client.ts +++ b/src/client.ts @@ -206,6 +206,7 @@ import { LocalNotificationSettings } from "./@types/local_notifications"; import { buildFeatureSupportMap, Feature, ServerSupport } from "./feature"; import { CryptoBackend } from "./common-crypto/CryptoBackend"; import { RUST_SDK_STORE_PREFIX } from "./rust-crypto/constants"; +import { CryptoApi } from "./crypto-api"; export type Store = IStore; @@ -1166,7 +1167,15 @@ export class MatrixClient extends TypedEventEmitter } = {}; public identityServer?: IIdentityServerProvider; public http: MatrixHttpApi; // XXX: Intended private, used in code. - public crypto?: Crypto; // libolm crypto implementation. XXX: Intended private, used in code. Being replaced by cryptoBackend + + /** + * The libolm crypto implementation, if it is in use. + * + * @deprecated This should not be used. Instead, use the methods exposed directly on this class or + * (where they are available) via {@link getCrypto}. + */ + public crypto?: Crypto; // XXX: Intended private, used in code. Being replaced by cryptoBackend + private cryptoBackend?: CryptoBackend; // one of crypto or rustCrypto public cryptoCallbacks: ICryptoCallbacks; // XXX: Intended private, used in code. public callEventHandler?: CallEventHandler; // XXX: Intended private, used in code. @@ -2200,9 +2209,20 @@ export class MatrixClient extends TypedEventEmitter { if (!this.cryptoBackend) { @@ -3088,8 +3136,13 @@ export class MatrixClient extends TypedEventEmitter { if (!this.cryptoBackend) { diff --git a/src/common-crypto/CryptoBackend.ts b/src/common-crypto/CryptoBackend.ts index d8e61a8b4..0433e649b 100644 --- a/src/common-crypto/CryptoBackend.ts +++ b/src/common-crypto/CryptoBackend.ts @@ -14,31 +14,26 @@ See the License for the specific language governing permissions and limitations under the License. */ -import type { IEventDecryptionResult, IMegolmSessionData } from "../@types/crypto"; import type { IToDeviceEvent } from "../sync-accumulator"; -import type { DeviceTrustLevel, UserTrustLevel } from "../crypto/CrossSigning"; import { MatrixEvent } from "../models/event"; import { Room } from "../models/room"; +import { CryptoApi } from "../crypto-api"; +import { DeviceTrustLevel, UserTrustLevel } from "../crypto/CrossSigning"; import { IEncryptedEventInfo } from "../crypto/api"; +import { IEventDecryptionResult } from "../@types/crypto"; /** * Common interface for the crypto implementations */ -export interface CryptoBackend extends SyncCryptoCallbacks { - /** - * Global override for whether the client should ever send encrypted - * messages to unverified devices. This provides the default for rooms which - * do not specify a value. - * - * If true, all unverified devices will be blacklisted by default - */ - globalBlacklistUnverifiedDevices: boolean; - +export interface CryptoBackend extends SyncCryptoCallbacks, CryptoApi { /** * Whether sendMessage in a room with unknown and unverified devices * should throw an error and not send the message. This has 'Global' for * symmetry with setGlobalBlacklistUnverifiedDevices but there is currently * no room-level equivalent for this setting. + * + * @remarks this is here, rather than in `CryptoApi`, because I don't think we're + * going to support it in the rust crypto implementation. */ globalErrorOnUnknownDevices: boolean; @@ -47,16 +42,6 @@ export interface CryptoBackend extends SyncCryptoCallbacks { */ stop(): void; - /** - * Checks if the user has previously published cross-signing keys - * - * This means downloading the devicelist for the user and checking if the list includes - * the cross-signing pseudo-device. - - * @returns true if the user has previously published cross-signing keys - */ - userHasCrossSigningKeys(): Promise; - /** * Get the verification level for a given user * @@ -76,14 +61,6 @@ export interface CryptoBackend extends SyncCryptoCallbacks { */ checkDeviceTrust(userId: string, deviceId: string): DeviceTrustLevel; - /** - * Perform any background tasks that can be done before a message is ready to - * send, in order to speed up sending of the message. - * - * @param room - the room the event is in - */ - prepareToEncrypt(room: Room): void; - /** * Encrypt an event according to the configuration of the room. * @@ -110,16 +87,6 @@ export interface CryptoBackend extends SyncCryptoCallbacks { * @param event - event to be checked */ getEventEncryptionInfo(event: MatrixEvent): IEncryptedEventInfo; - - /** - * Get a list containing all of the room keys - * - * This should be encrypted before returning it to the user. - * - * @returns a promise which resolves to a list of - * session export objects - */ - exportRoomKeys(): Promise; } /** The methods which crypto implementations should expose to the Sync api */ diff --git a/src/crypto-api.ts b/src/crypto-api.ts new file mode 100644 index 000000000..8c29c2ca5 --- /dev/null +++ b/src/crypto-api.ts @@ -0,0 +1,62 @@ +/* +Copyright 2023 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 { IMegolmSessionData } from "./@types/crypto"; +import { Room } from "./models/room"; + +/** + * Public interface to the cryptography parts of the js-sdk + * + * @remarks Currently, this is a work-in-progress. In time, more methods will be added here. + */ +export interface CryptoApi { + /** + * Global override for whether the client should ever send encrypted + * messages to unverified devices. This provides the default for rooms which + * do not specify a value. + * + * If true, all unverified devices will be blacklisted by default + */ + globalBlacklistUnverifiedDevices: boolean; + + /** + * Checks if the user has previously published cross-signing keys + * + * This means downloading the devicelist for the user and checking if the list includes + * the cross-signing pseudo-device. + * + * @returns true if the user has previously published cross-signing keys + */ + userHasCrossSigningKeys(): Promise; + + /** + * Perform any background tasks that can be done before a message is ready to + * send, in order to speed up sending of the message. + * + * @param room - the room the event is in + */ + prepareToEncrypt(room: Room): void; + + /** + * Get a list containing all of the room keys + * + * This should be encrypted before returning it to the user. + * + * @returns a promise which resolves to a list of + * session export objects + */ + exportRoomKeys(): Promise; +} diff --git a/src/matrix.ts b/src/matrix.ts index 11367880d..a6fa12e6a 100644 --- a/src/matrix.ts +++ b/src/matrix.ts @@ -60,6 +60,7 @@ export { createNewMatrixCall } from "./webrtc/call"; export type { MatrixCall } from "./webrtc/call"; export { GroupCallEvent, GroupCallIntent, GroupCallState, GroupCallType } from "./webrtc/groupCall"; export type { GroupCall } from "./webrtc/groupCall"; +export type { CryptoApi } from "./crypto-api"; let cryptoStoreFactory = (): CryptoStore => new MemoryCryptoStore(); diff --git a/src/rust-crypto/index.ts b/src/rust-crypto/index.ts index 7faeff158..e2c541f5c 100644 --- a/src/rust-crypto/index.ts +++ b/src/rust-crypto/index.ts @@ -30,7 +30,7 @@ export async function initRustCrypto( await RustSdkCryptoJs.initAsync(); // enable tracing in the rust-sdk - new RustSdkCryptoJs.Tracing(RustSdkCryptoJs.LoggerLevel.Debug).turnOn(); + new RustSdkCryptoJs.Tracing(RustSdkCryptoJs.LoggerLevel.Trace).turnOn(); const u = new RustSdkCryptoJs.UserId(userId); const d = new RustSdkCryptoJs.DeviceId(deviceId); diff --git a/src/rust-crypto/rust-crypto.ts b/src/rust-crypto/rust-crypto.ts index 8b62e9e6c..5d8e405f3 100644 --- a/src/rust-crypto/rust-crypto.ts +++ b/src/rust-crypto/rust-crypto.ts @@ -34,7 +34,6 @@ import { KeyClaimManager } from "./KeyClaimManager"; * An implementation of {@link CryptoBackend} using the Rust matrix-sdk-crypto. */ export class RustCrypto implements CryptoBackend { - public globalBlacklistUnverifiedDevices = false; public globalErrorOnUnknownDevices = false; /** whether {@link stop} has been called */ @@ -81,14 +80,6 @@ export class RustCrypto implements CryptoBackend { this.olmMachine.close(); } - public prepareToEncrypt(room: Room): void { - const encryptor = this.roomEncryptors[room.roomId]; - - if (encryptor) { - encryptor.ensureEncryptionSession(); - } - } - public async encryptEvent(event: MatrixEvent, _room: Room): Promise { const roomId = event.getRoomId()!; const encryptor = this.roomEncryptors[roomId]; @@ -147,16 +138,6 @@ export class RustCrypto implements CryptoBackend { return ret as IEncryptedEventInfo; } - public async userHasCrossSigningKeys(): Promise { - // TODO - return false; - } - - public async exportRoomKeys(): Promise { - // TODO - return []; - } - public checkUserTrust(userId: string): UserTrustLevel { // TODO return new UserTrustLevel(false, false, false); @@ -167,6 +148,32 @@ export class RustCrypto implements CryptoBackend { return new DeviceTrustLevel(false, false, false, false); } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + // + // CryptoApi implementation + // + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + public globalBlacklistUnverifiedDevices = false; + + public async userHasCrossSigningKeys(): Promise { + // TODO + return false; + } + + public prepareToEncrypt(room: Room): void { + const encryptor = this.roomEncryptors[room.roomId]; + + if (encryptor) { + encryptor.ensureEncryptionSession(); + } + } + + public async exportRoomKeys(): Promise { + // TODO + return []; + } + /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // SyncCryptoCallbacks implementation