You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-09 10:22:46 +03:00
crypto: configure key sharing strategy based on DeviceIsolationMode (#4425)
* crypto: configure key sharing strategy based on deviceIsolationMode fix eslint import error cryptoMode was renamed to deviceIsolationMode post rebase fix: Device Isolation mode name changes * Fix outdated docs referring to old cryptomode * code review: better comment for globalBlacklistUnverifiedDevices option * RoomEncryptor: Use appropriate default for getBlacklistUnverifiedDevices * do not provide a default value for DeviceIsolationMode for encryption * Update src/rust-crypto/RoomEncryptor.ts --------- Co-authored-by: Richard van der Hoff <1389908+richvdh@users.noreply.github.com>
This commit is contained in:
@@ -611,14 +611,13 @@ export enum DecryptionFailureCode {
|
||||
|
||||
/**
|
||||
* The sender device is not cross-signed. This will only be used if the
|
||||
* crypto mode is set to `CryptoMode.Invisible` or `CryptoMode.Transition`.
|
||||
* device isolation mode is set to `OnlySignedDevicesIsolationMode`.
|
||||
*/
|
||||
UNSIGNED_SENDER_DEVICE = "UNSIGNED_SENDER_DEVICE",
|
||||
|
||||
/**
|
||||
* We weren't able to link the message back to any known device. This will
|
||||
* only be used if the crypto mode is set to `CryptoMode.Invisible` or
|
||||
* `CryptoMode.Transition`.
|
||||
* only be used if the device isolation mode is set to `OnlySignedDevicesIsolationMode`.
|
||||
*/
|
||||
UNKNOWN_SENDER_DEVICE = "UNKNOWN_SENDER_DEVICE",
|
||||
|
||||
|
@@ -36,6 +36,7 @@ import { HistoryVisibility } from "../@types/partials.ts";
|
||||
import { OutgoingRequestsManager } from "./OutgoingRequestsManager.ts";
|
||||
import { logDuration } from "../utils.ts";
|
||||
import { KnownMembership } from "../@types/membership.ts";
|
||||
import { DeviceIsolationMode, DeviceIsolationModeKind } from "../crypto-api/index.ts";
|
||||
|
||||
/**
|
||||
* RoomEncryptor: responsible for encrypting messages to a given room
|
||||
@@ -119,10 +120,15 @@ export class RoomEncryptor {
|
||||
*
|
||||
* This ensures that we have a megolm session ready to use and that we have shared its key with all the devices
|
||||
* in the room.
|
||||
*
|
||||
* @param globalBlacklistUnverifiedDevices - When `true`, it will not send encrypted messages to unverified devices
|
||||
* @param globalBlacklistUnverifiedDevices - When `true`, and `deviceIsolationMode` is `AllDevicesIsolationMode`,
|
||||
* will not send encrypted messages to unverified devices.
|
||||
* Ignored when `deviceIsolationMode` is `OnlySignedDevicesIsolationMode`.
|
||||
* @param deviceIsolationMode - The device isolation mode. See {@link DeviceIsolationMode}.
|
||||
*/
|
||||
public async prepareForEncryption(globalBlacklistUnverifiedDevices: boolean): Promise<void> {
|
||||
public async prepareForEncryption(
|
||||
globalBlacklistUnverifiedDevices: boolean,
|
||||
deviceIsolationMode: DeviceIsolationMode,
|
||||
): Promise<void> {
|
||||
// We consider a prepareForEncryption as an encryption promise as it will potentially share keys
|
||||
// even if it doesn't send an event.
|
||||
// Usually this is called when the user starts typing, so we want to make sure we have keys ready when the
|
||||
@@ -130,7 +136,7 @@ export class RoomEncryptor {
|
||||
// If `encryptEvent` is invoked before `prepareForEncryption` has completed, the `encryptEvent` call will wait for
|
||||
// `prepareForEncryption` to complete before executing.
|
||||
// The part where `encryptEvent` shares the room key will then usually be a no-op as it was already performed by `prepareForEncryption`.
|
||||
await this.encryptEvent(null, globalBlacklistUnverifiedDevices);
|
||||
await this.encryptEvent(null, globalBlacklistUnverifiedDevices, deviceIsolationMode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,9 +146,16 @@ export class RoomEncryptor {
|
||||
* then, if an event is provided, encrypt it using the session.
|
||||
*
|
||||
* @param event - Event to be encrypted, or null if only preparing for encryption (in which case we will pre-share the room key).
|
||||
* @param globalBlacklistUnverifiedDevices - When `true`, it will not send encrypted messages to unverified devices
|
||||
* @param globalBlacklistUnverifiedDevices - When `true`, and `deviceIsolationMode` is `AllDevicesIsolationMode`,
|
||||
* will not send encrypted messages to unverified devices.
|
||||
* Ignored when `deviceIsolationMode` is `OnlySignedDevicesIsolationMode`.
|
||||
* @param deviceIsolationMode - The device isolation mode. See {@link DeviceIsolationMode}.
|
||||
*/
|
||||
public encryptEvent(event: MatrixEvent | null, globalBlacklistUnverifiedDevices: boolean): Promise<void> {
|
||||
public encryptEvent(
|
||||
event: MatrixEvent | null,
|
||||
globalBlacklistUnverifiedDevices: boolean,
|
||||
deviceIsolationMode: DeviceIsolationMode,
|
||||
): Promise<void> {
|
||||
const logger = new LogSpan(this.prefixedLogger, event ? (event.getTxnId() ?? "") : "prepareForEncryption");
|
||||
// Ensure order of encryption to avoid message ordering issues, as the scheduler only ensures
|
||||
// events order after they have been encrypted.
|
||||
@@ -153,7 +166,7 @@ export class RoomEncryptor {
|
||||
})
|
||||
.then(async () => {
|
||||
await logDuration(logger, "ensureEncryptionSession", async () => {
|
||||
await this.ensureEncryptionSession(logger, globalBlacklistUnverifiedDevices);
|
||||
await this.ensureEncryptionSession(logger, globalBlacklistUnverifiedDevices, deviceIsolationMode);
|
||||
});
|
||||
if (event) {
|
||||
await logDuration(logger, "encryptEventInner", async () => {
|
||||
@@ -173,9 +186,16 @@ export class RoomEncryptor {
|
||||
* in the room.
|
||||
*
|
||||
* @param logger - a place to write diagnostics to
|
||||
* @param globalBlacklistUnverifiedDevices - When `true`, it will not send encrypted messages to unverified devices
|
||||
* @param globalBlacklistUnverifiedDevices - When `true`, and `deviceIsolationMode` is `AllDevicesIsolationMode`,
|
||||
* will not send encrypted messages to unverified devices.
|
||||
* Ignored when `deviceIsolationMode` is `OnlySignedDevicesIsolationMode`.
|
||||
* @param deviceIsolationMode - The device isolation mode. See {@link DeviceIsolationMode}.
|
||||
*/
|
||||
private async ensureEncryptionSession(logger: LogSpan, globalBlacklistUnverifiedDevices: boolean): Promise<void> {
|
||||
private async ensureEncryptionSession(
|
||||
logger: LogSpan,
|
||||
globalBlacklistUnverifiedDevices: boolean,
|
||||
deviceIsolationMode: DeviceIsolationMode,
|
||||
): Promise<void> {
|
||||
if (this.encryptionSettings.algorithm !== "m.megolm.v1.aes-sha2") {
|
||||
throw new Error(
|
||||
`Cannot encrypt in ${this.room.roomId} for unsupported algorithm '${this.encryptionSettings.algorithm}'`,
|
||||
@@ -251,12 +271,22 @@ export class RoomEncryptor {
|
||||
rustEncryptionSettings.rotationPeriodMessages = BigInt(this.encryptionSettings.rotation_period_msgs);
|
||||
}
|
||||
|
||||
// When this.room.getBlacklistUnverifiedDevices() === null, the global settings should be used
|
||||
// See Room#getBlacklistUnverifiedDevices
|
||||
if (this.room.getBlacklistUnverifiedDevices() ?? globalBlacklistUnverifiedDevices) {
|
||||
rustEncryptionSettings.sharingStrategy = CollectStrategy.deviceBasedStrategy(true, false);
|
||||
} else {
|
||||
rustEncryptionSettings.sharingStrategy = CollectStrategy.deviceBasedStrategy(false, false);
|
||||
switch (deviceIsolationMode.kind) {
|
||||
case DeviceIsolationModeKind.AllDevicesIsolationMode:
|
||||
{
|
||||
// When this.room.getBlacklistUnverifiedDevices() === null, the global settings should be used
|
||||
// See Room#getBlacklistUnverifiedDevices
|
||||
const onlyAllowTrustedDevices =
|
||||
this.room.getBlacklistUnverifiedDevices() ?? globalBlacklistUnverifiedDevices;
|
||||
rustEncryptionSettings.sharingStrategy = CollectStrategy.deviceBasedStrategy(
|
||||
onlyAllowTrustedDevices,
|
||||
deviceIsolationMode.errorOnVerifiedUserProblems,
|
||||
);
|
||||
}
|
||||
break;
|
||||
case DeviceIsolationModeKind.OnlySignedDevicesIsolationMode:
|
||||
rustEncryptionSettings.sharingStrategy = CollectStrategy.identityBasedStrategy();
|
||||
break;
|
||||
}
|
||||
|
||||
await logDuration(this.prefixedLogger, "shareRoomKey", async () => {
|
||||
|
@@ -248,7 +248,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
|
||||
throw new Error(`Cannot encrypt event in unconfigured room ${roomId}`);
|
||||
}
|
||||
|
||||
await encryptor.encryptEvent(event, this.globalBlacklistUnverifiedDevices);
|
||||
await encryptor.encryptEvent(event, this.globalBlacklistUnverifiedDevices, this.deviceIsolationMode);
|
||||
}
|
||||
|
||||
public async decryptEvent(event: MatrixEvent): Promise<IEventDecryptionResult> {
|
||||
@@ -400,7 +400,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, RustCryptoEv
|
||||
const encryptor = this.roomEncryptors[room.roomId];
|
||||
|
||||
if (encryptor) {
|
||||
encryptor.prepareForEncryption(this.globalBlacklistUnverifiedDevices);
|
||||
encryptor.prepareForEncryption(this.globalBlacklistUnverifiedDevices, this.deviceIsolationMode);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user