You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2026-01-03 23:22:30 +03:00
Use client logger in more places (crypto code) (#4900)
* Use client logger for `RustBackupManager` * use client logger in `CrossSigningIdentity` * use client logger in `OutgoingRequestProcessor` * RoomEncryptor: use correct logger for logDuration use the logger for this specific event, rather than the more general one for the room * Use client logger in `RoomEncryptor`
This commit is contained in:
committed by
GitHub
parent
70257e0ab4
commit
6e9740d787
@@ -20,6 +20,7 @@ import * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
import { CrossSigningIdentity } from "../../../src/rust-crypto/CrossSigningIdentity";
|
||||
import { type OutgoingRequestProcessor } from "../../../src/rust-crypto/OutgoingRequestProcessor";
|
||||
import { type ServerSideSecretStorage } from "../../../src/secret-storage";
|
||||
import { logger } from "../../../src/logger.ts";
|
||||
|
||||
describe("CrossSigningIdentity", () => {
|
||||
describe("bootstrapCrossSigning", () => {
|
||||
@@ -55,7 +56,7 @@ describe("CrossSigningIdentity", () => {
|
||||
store: jest.fn(),
|
||||
} as unknown as Mocked<ServerSideSecretStorage>;
|
||||
|
||||
crossSigning = new CrossSigningIdentity(olmMachine, outgoingRequestProcessor, secretStorage);
|
||||
crossSigning = new CrossSigningIdentity(logger, olmMachine, outgoingRequestProcessor, secretStorage);
|
||||
});
|
||||
|
||||
it("should do nothing if keys are present on-device and in secret storage", async () => {
|
||||
|
||||
@@ -53,7 +53,7 @@ describe("KeyClaimManager", () => {
|
||||
markRequestAsSent: jest.fn(),
|
||||
} as unknown as Mocked<RustSdkCryptoJs.OlmMachine>;
|
||||
|
||||
const outgoingRequestProcessor = new OutgoingRequestProcessor(olmMachine, httpApi);
|
||||
const outgoingRequestProcessor = new OutgoingRequestProcessor(logger, olmMachine, httpApi);
|
||||
|
||||
keyClaimManager = new KeyClaimManager(olmMachine, outgoingRequestProcessor);
|
||||
});
|
||||
|
||||
@@ -40,6 +40,7 @@ import {
|
||||
type UIAuthCallback,
|
||||
} from "../../../src";
|
||||
import { OutgoingRequestProcessor } from "../../../src/rust-crypto/OutgoingRequestProcessor";
|
||||
import { logger } from "../../../src/logger.ts";
|
||||
|
||||
describe("OutgoingRequestProcessor", () => {
|
||||
/** the OutgoingRequestProcessor implementation under test */
|
||||
@@ -76,7 +77,7 @@ describe("OutgoingRequestProcessor", () => {
|
||||
markRequestAsSent: jest.fn(),
|
||||
} as unknown as Mocked<RustSdkCryptoJs.OlmMachine>;
|
||||
|
||||
processor = new OutgoingRequestProcessor(olmMachine, httpApi);
|
||||
processor = new OutgoingRequestProcessor(logger, olmMachine, httpApi);
|
||||
});
|
||||
|
||||
/* simple requests that map directly to the request body */
|
||||
@@ -293,7 +294,7 @@ describe("OutgoingRequestProcessor", () => {
|
||||
return await authRequestResultResolvers.promise;
|
||||
},
|
||||
} as unknown as Mocked<MatrixHttpApi<IHttpOpts & { onlyData: true }>>;
|
||||
processor = new OutgoingRequestProcessor(olmMachine, mockHttpApi);
|
||||
processor = new OutgoingRequestProcessor(logger, olmMachine, mockHttpApi);
|
||||
});
|
||||
|
||||
// build a request
|
||||
@@ -325,7 +326,7 @@ describe("OutgoingRequestProcessor", () => {
|
||||
onlyData: true,
|
||||
});
|
||||
|
||||
processor = new OutgoingRequestProcessor(olmMachine, httpApi);
|
||||
processor = new OutgoingRequestProcessor(logger, olmMachine, httpApi);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
AllDevicesIsolationMode,
|
||||
OnlySignedDevicesIsolationMode,
|
||||
} from "../../../src/crypto-api";
|
||||
import { logger } from "../../../src/logger.ts";
|
||||
|
||||
describe("RoomEncryptor", () => {
|
||||
describe("History Visibility", () => {
|
||||
@@ -108,6 +109,7 @@ describe("RoomEncryptor", () => {
|
||||
} as unknown as Mocked<Room>;
|
||||
|
||||
roomEncryptor = new RoomEncryptor(
|
||||
logger,
|
||||
mockOlmMachine,
|
||||
mockKeyClaimManager,
|
||||
mockOutgoingRequestManager,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { type OutgoingRequestProcessor } from "../../../src/rust-crypto/Outgoing
|
||||
import * as testData from "../../test-utils/test-data";
|
||||
import * as TestData from "../../test-utils/test-data";
|
||||
import { RustBackupManager, type KeyBackup } from "../../../src/rust-crypto/backup";
|
||||
import { logger } from "../../../src/logger.ts";
|
||||
|
||||
describe("Upload keys to backup", () => {
|
||||
/** The backup manager under test */
|
||||
@@ -63,7 +64,7 @@ describe("Upload keys to backup", () => {
|
||||
makeOutgoingRequest: jest.fn(),
|
||||
} as unknown as Mocked<OutgoingRequestProcessor>;
|
||||
|
||||
rustBackupManager = new RustBackupManager(mockOlmMachine, httpAPi, outgoingRequestProcessor);
|
||||
rustBackupManager = new RustBackupManager(logger, mockOlmMachine, httpAPi, outgoingRequestProcessor);
|
||||
|
||||
fetchMock.get("path:/_matrix/client/v3/room_keys/version", testData.SIGNED_BACKUP_DATA);
|
||||
});
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
|
||||
import type * as RustSdkCryptoJs from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
import { type BootstrapCrossSigningOpts } from "../crypto-api/index.ts";
|
||||
import { logger } from "../logger.ts";
|
||||
import { type Logger } from "../logger.ts";
|
||||
import { type OutgoingRequestProcessor } from "./OutgoingRequestProcessor.ts";
|
||||
import { type UIAuthCallback } from "../interactive-auth.ts";
|
||||
import { type ServerSideSecretStorage } from "../secret-storage.ts";
|
||||
@@ -33,6 +33,7 @@ import { type ServerSideSecretStorage } from "../secret-storage.ts";
|
||||
*/
|
||||
export class CrossSigningIdentity {
|
||||
public constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly olmMachine: OlmMachine,
|
||||
private readonly outgoingRequestProcessor: OutgoingRequestProcessor,
|
||||
private readonly secretStorage: ServerSideSecretStorage,
|
||||
@@ -61,7 +62,7 @@ export class CrossSigningIdentity {
|
||||
olmDeviceStatus.hasMaster && olmDeviceStatus.hasUserSigning && olmDeviceStatus.hasSelfSigning;
|
||||
|
||||
// Log all relevant state for easier parsing of debug logs.
|
||||
logger.log("bootstrapCrossSigning: starting", {
|
||||
this.logger.debug("bootstrapCrossSigning: starting", {
|
||||
setupNewCrossSigning: opts.setupNewCrossSigning,
|
||||
olmDeviceHasMaster: olmDeviceStatus.hasMaster,
|
||||
olmDeviceHasUserSigning: olmDeviceStatus.hasUserSigning,
|
||||
@@ -71,23 +72,23 @@ export class CrossSigningIdentity {
|
||||
|
||||
if (olmDeviceHasKeys) {
|
||||
if (!(await this.secretStorage.hasKey())) {
|
||||
logger.warn(
|
||||
this.logger.warn(
|
||||
"bootstrapCrossSigning: Olm device has private keys, but secret storage is not yet set up; doing nothing for now.",
|
||||
);
|
||||
// the keys should get uploaded to 4S once that is set up.
|
||||
} else if (!privateKeysInSecretStorage) {
|
||||
// the device has the keys but they are not in 4S, so update it
|
||||
logger.log("bootstrapCrossSigning: Olm device has private keys: exporting to secret storage");
|
||||
this.logger.debug("bootstrapCrossSigning: Olm device has private keys: exporting to secret storage");
|
||||
await this.exportCrossSigningKeysToStorage();
|
||||
} else {
|
||||
logger.log(
|
||||
this.logger.debug(
|
||||
"bootstrapCrossSigning: Olm device has private keys and they are saved in secret storage; doing nothing",
|
||||
);
|
||||
}
|
||||
} /* (!olmDeviceHasKeys) */ else {
|
||||
if (privateKeysInSecretStorage) {
|
||||
// they are in 4S, so import from there
|
||||
logger.log(
|
||||
this.logger.debug(
|
||||
"bootstrapCrossSigning: Cross-signing private keys not found locally, but they are available " +
|
||||
"in secret storage, reading storage and caching locally",
|
||||
);
|
||||
@@ -116,7 +117,7 @@ export class CrossSigningIdentity {
|
||||
device.free();
|
||||
}
|
||||
} else {
|
||||
logger.log(
|
||||
this.logger.debug(
|
||||
"bootstrapCrossSigning: Cross-signing private keys not found locally or in secret storage, creating new keys",
|
||||
);
|
||||
await this.resetCrossSigning(opts.authUploadDeviceSigningKeys);
|
||||
@@ -125,7 +126,7 @@ export class CrossSigningIdentity {
|
||||
|
||||
// TODO: we might previously have bootstrapped cross-signing but not completed uploading the keys to the
|
||||
// server -- in which case we should call OlmDevice.bootstrap_cross_signing. How do we know?
|
||||
logger.log("bootstrapCrossSigning: complete");
|
||||
this.logger.debug("bootstrapCrossSigning: complete");
|
||||
}
|
||||
|
||||
/** Reset our cross-signing keys
|
||||
@@ -142,7 +143,7 @@ export class CrossSigningIdentity {
|
||||
|
||||
// If 4S is configured we need to update it.
|
||||
if (!(await this.secretStorage.hasKey())) {
|
||||
logger.warn(
|
||||
this.logger.warn(
|
||||
"resetCrossSigning: Secret storage is not yet set up; not exporting keys to secret storage yet.",
|
||||
);
|
||||
// the keys should get uploaded to 4S once that is set up.
|
||||
@@ -150,11 +151,11 @@ export class CrossSigningIdentity {
|
||||
// Update 4S before uploading cross-signing keys, to stay consistent with legacy that asks
|
||||
// 4S passphrase before asking for account password.
|
||||
// Ultimately should be made atomic and resistant to forgotten password/passphrase.
|
||||
logger.log("resetCrossSigning: exporting private keys to secret storage");
|
||||
this.logger.debug("resetCrossSigning: exporting private keys to secret storage");
|
||||
await this.exportCrossSigningKeysToStorage();
|
||||
}
|
||||
|
||||
logger.log("resetCrossSigning: publishing public keys to server");
|
||||
this.logger.debug("resetCrossSigning: publishing public keys to server");
|
||||
for (const req of [
|
||||
outgoingRequests.uploadKeysRequest,
|
||||
outgoingRequests.uploadSigningKeysRequest,
|
||||
@@ -178,17 +179,17 @@ export class CrossSigningIdentity {
|
||||
if (exported?.masterKey) {
|
||||
await this.secretStorage.store("m.cross_signing.master", exported.masterKey);
|
||||
} else {
|
||||
logger.error(`Cannot export MSK to secret storage, private key unknown`);
|
||||
this.logger.error(`Cannot export MSK to secret storage, private key unknown`);
|
||||
}
|
||||
if (exported?.self_signing_key) {
|
||||
await this.secretStorage.store("m.cross_signing.self_signing", exported.self_signing_key);
|
||||
} else {
|
||||
logger.error(`Cannot export SSK to secret storage, private key unknown`);
|
||||
this.logger.error(`Cannot export SSK to secret storage, private key unknown`);
|
||||
}
|
||||
if (exported?.userSigningKey) {
|
||||
await this.secretStorage.store("m.cross_signing.user_signing", exported.userSigningKey);
|
||||
} else {
|
||||
logger.error(`Cannot export USK to secret storage, private key unknown`);
|
||||
this.logger.error(`Cannot export USK to secret storage, private key unknown`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
UploadSigningKeysRequest,
|
||||
} from "@matrix-org/matrix-sdk-crypto-wasm";
|
||||
|
||||
import { logger } from "../logger.ts";
|
||||
import { type Logger } from "../logger.ts";
|
||||
import { calculateRetryBackoff, type IHttpOpts, type MatrixHttpApi, Method } from "../http-api/index.ts";
|
||||
import { logDuration, type QueryDict, sleep } from "../utils.ts";
|
||||
import { type AuthDict, type UIAuthCallback } from "../interactive-auth.ts";
|
||||
@@ -49,6 +49,7 @@ import { UnstablePrefix as DehydrationUnstablePrefix } from "./DehydratedDeviceM
|
||||
*/
|
||||
export class OutgoingRequestProcessor {
|
||||
public constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly olmMachine: OlmMachine,
|
||||
private readonly http: MatrixHttpApi<IHttpOpts & { onlyData: true }>,
|
||||
) {}
|
||||
@@ -100,13 +101,13 @@ export class OutgoingRequestProcessor {
|
||||
// PutDehydratedDeviceRequest does not implement OutgoingRequest and does not need to be marked as sent.
|
||||
return;
|
||||
} else {
|
||||
logger.warn("Unsupported outgoing message", Object.getPrototypeOf(msg));
|
||||
this.logger.warn("Unsupported outgoing message", Object.getPrototypeOf(msg));
|
||||
resp = "";
|
||||
}
|
||||
|
||||
if (msg.id) {
|
||||
try {
|
||||
await logDuration(logger, `Mark Request as sent ${msg.type}`, async () => {
|
||||
await logDuration(this.logger, `Mark Request as sent ${msg.type}`, async () => {
|
||||
await this.olmMachine.markRequestAsSent(msg.id!, msg.type, resp);
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -116,13 +117,13 @@ export class OutgoingRequestProcessor {
|
||||
e instanceof Error &&
|
||||
(e.message === "Attempt to use a moved value" || e.message === "null pointer passed to rust")
|
||||
) {
|
||||
logger.log(`Ignoring error '${e.message}': client is likely shutting down`);
|
||||
this.logger.debug(`Ignoring error '${e.message}': client is likely shutting down`);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logger.trace(`Outgoing request type:${msg.type} does not have an ID`);
|
||||
this.logger.trace(`Outgoing request type:${msg.type} does not have an ID`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +144,7 @@ export class OutgoingRequestProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(
|
||||
this.logger.info(
|
||||
`Sending batch of to-device messages. type=${request.event_type} txnid=${request.txn_id}`,
|
||||
messageList,
|
||||
);
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
import { EventType } from "../@types/event.ts";
|
||||
import { type IContent, type MatrixEvent } from "../models/event.ts";
|
||||
import { type Room } from "../models/room.ts";
|
||||
import { type Logger, logger, LogSpan } from "../logger.ts";
|
||||
import { type Logger, LogSpan } from "../logger.ts";
|
||||
import { type KeyClaimManager } from "./KeyClaimManager.ts";
|
||||
import { type RoomMember } from "../models/room-member.ts";
|
||||
import { HistoryVisibility } from "../@types/partials.ts";
|
||||
@@ -44,8 +44,6 @@ import { type DeviceIsolationMode, DeviceIsolationModeKind } from "../crypto-api
|
||||
* @internal
|
||||
*/
|
||||
export class RoomEncryptor {
|
||||
private readonly prefixedLogger: Logger;
|
||||
|
||||
/** whether the room members have been loaded and tracked for the first time */
|
||||
private lazyLoadedMembersResolved = false;
|
||||
|
||||
@@ -57,6 +55,7 @@ export class RoomEncryptor {
|
||||
private currentEncryptionPromise: Promise<void> = Promise.resolve();
|
||||
|
||||
/**
|
||||
* @param prefixedLogger - A logger to use for log messages.
|
||||
* @param olmMachine - The rust-sdk's OlmMachine
|
||||
* @param keyClaimManager - Our KeyClaimManager, which manages the queue of one-time-key claim requests
|
||||
* @param outgoingRequestManager - The OutgoingRequestManager, which manages the queue of outgoing requests.
|
||||
@@ -64,14 +63,13 @@ export class RoomEncryptor {
|
||||
* @param encryptionSettings - body of the m.room.encryption event currently in force in this room
|
||||
*/
|
||||
public constructor(
|
||||
private readonly prefixedLogger: Logger,
|
||||
private readonly olmMachine: OlmMachine,
|
||||
private readonly keyClaimManager: KeyClaimManager,
|
||||
private readonly outgoingRequestManager: OutgoingRequestsManager,
|
||||
private readonly room: Room,
|
||||
private encryptionSettings: IContent,
|
||||
) {
|
||||
this.prefixedLogger = logger.getChild(`[${room.roomId} encryption]`);
|
||||
|
||||
// start tracking devices for any users already known to be in this room.
|
||||
// Do not load members here, would defeat lazy loading.
|
||||
const members = room.getJoinedMembers();
|
||||
@@ -212,7 +210,7 @@ export class RoomEncryptor {
|
||||
// This could end up being racy (if two calls to ensureEncryptionSession happen at the same time), but that's
|
||||
// not a particular problem, since `OlmMachine.updateTrackedUsers` just adds any users that weren't already tracked.
|
||||
if (!this.lazyLoadedMembersResolved) {
|
||||
await logDuration(this.prefixedLogger, "loadMembersIfNeeded: updateTrackedUsers", async () => {
|
||||
await logDuration(logger, "loadMembersIfNeeded: updateTrackedUsers", async () => {
|
||||
await this.olmMachine.updateTrackedUsers(members.map((u) => new RustSdkCryptoJs.UserId(u.userId)));
|
||||
});
|
||||
logger.debug(`Updated tracked users`);
|
||||
@@ -229,7 +227,7 @@ export class RoomEncryptor {
|
||||
// XXX future improvement process only KeysQueryRequests for the users that have never been queried.
|
||||
logger.debug(`Processing outgoing requests`);
|
||||
|
||||
await logDuration(this.prefixedLogger, "doProcessOutgoingRequests", async () => {
|
||||
await logDuration(logger, "doProcessOutgoingRequests", async () => {
|
||||
await this.outgoingRequestManager.doProcessOutgoingRequests();
|
||||
});
|
||||
} else {
|
||||
@@ -250,7 +248,7 @@ export class RoomEncryptor {
|
||||
|
||||
const userList = members.map((u) => new UserId(u.userId));
|
||||
|
||||
await logDuration(this.prefixedLogger, "ensureSessionsForUsers", async () => {
|
||||
await logDuration(logger, "ensureSessionsForUsers", async () => {
|
||||
await this.keyClaimManager.ensureSessionsForUsers(logger, userList);
|
||||
});
|
||||
|
||||
@@ -289,7 +287,7 @@ export class RoomEncryptor {
|
||||
break;
|
||||
}
|
||||
|
||||
await logDuration(this.prefixedLogger, "shareRoomKey", async () => {
|
||||
await logDuration(logger, "shareRoomKey", async () => {
|
||||
const shareMessages: ToDeviceRequest[] = await this.olmMachine.shareRoomKey(
|
||||
new RoomId(this.room.roomId),
|
||||
// safe to pass without cloning, as it's not reused here (before or after)
|
||||
|
||||
@@ -28,7 +28,7 @@ import {
|
||||
type KeyBackupRestoreResult,
|
||||
type KeyBackupRoomSessions,
|
||||
} from "../crypto-api/keybackup.ts";
|
||||
import { logger } from "../logger.ts";
|
||||
import { type Logger } from "../logger.ts";
|
||||
import { ClientPrefix, type IHttpOpts, MatrixError, type MatrixHttpApi, Method } from "../http-api/index.ts";
|
||||
import { TypedEventEmitter } from "../models/typed-event-emitter.ts";
|
||||
import { encodeUri, logDuration } from "../utils.ts";
|
||||
@@ -81,6 +81,7 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
private backupKeysLoopRunning = false;
|
||||
|
||||
public constructor(
|
||||
private readonly logger: Logger,
|
||||
private readonly olmMachine: OlmMachine,
|
||||
private readonly http: MatrixHttpApi<IHttpOpts & { onlyData: true }>,
|
||||
private readonly outgoingRequestProcessor: OutgoingRequestProcessor,
|
||||
@@ -131,7 +132,7 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
const backupKeys: RustSdkCryptoJs.BackupKeys = await this.olmMachine.getBackupKeys();
|
||||
const decryptionKey = backupKeys?.decryptionKey;
|
||||
const backupMatchesSavedPrivateKey =
|
||||
!!decryptionKey && backupInfoMatchesBackupDecryptionKey(info, decryptionKey);
|
||||
!!decryptionKey && this.backupInfoMatchesBackupDecryptionKey(info, decryptionKey);
|
||||
return {
|
||||
matchesDecryptionKey: backupMatchesSavedPrivateKey,
|
||||
trusted: signatureVerification.trusted(),
|
||||
@@ -171,14 +172,14 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
try {
|
||||
latestBackupInfo = await this.requestKeyBackupVersion();
|
||||
} catch (e) {
|
||||
logger.warn("handleBackupSecretReceived: Error checking for latest key backup", e);
|
||||
this.logger.warn("handleBackupSecretReceived: Error checking for latest key backup", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!latestBackupInfo?.version) {
|
||||
// There is no server-side key backup.
|
||||
// This decryption key is useless to us.
|
||||
logger.warn(
|
||||
this.logger.warn(
|
||||
"handleBackupSecretReceived: Received a backup decryption key, but there is no trusted server-side key backup",
|
||||
);
|
||||
return false;
|
||||
@@ -186,21 +187,21 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
|
||||
try {
|
||||
const backupDecryptionKey = RustSdkCryptoJs.BackupDecryptionKey.fromBase64(secret);
|
||||
const privateKeyMatches = backupInfoMatchesBackupDecryptionKey(latestBackupInfo, backupDecryptionKey);
|
||||
const privateKeyMatches = this.backupInfoMatchesBackupDecryptionKey(latestBackupInfo, backupDecryptionKey);
|
||||
if (!privateKeyMatches) {
|
||||
logger.warn(
|
||||
this.logger.warn(
|
||||
`handleBackupSecretReceived: Private decryption key does not match the public key of the current remote backup.`,
|
||||
);
|
||||
// just ignore the secret
|
||||
return false;
|
||||
}
|
||||
logger.info(
|
||||
this.logger.info(
|
||||
`handleBackupSecretReceived: A valid backup decryption key has been received and stored in cache.`,
|
||||
);
|
||||
await this.saveBackupDecryptionKey(backupDecryptionKey, latestBackupInfo.version);
|
||||
return true;
|
||||
} catch (e) {
|
||||
logger.warn("handleBackupSecretReceived: Invalid backup decryption key", e);
|
||||
this.logger.warn("handleBackupSecretReceived: Invalid backup decryption key", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -282,19 +283,19 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
|
||||
/** Helper for `checkKeyBackup` */
|
||||
private async doCheckKeyBackup(): Promise<KeyBackupCheck | null> {
|
||||
logger.log("Checking key backup status...");
|
||||
this.logger.debug("Checking key backup status...");
|
||||
let backupInfo: KeyBackupInfo | null | undefined;
|
||||
try {
|
||||
backupInfo = await this.requestKeyBackupVersion();
|
||||
} catch (e) {
|
||||
logger.warn("Error checking for active key backup", e);
|
||||
this.logger.warn("Error checking for active key backup", e);
|
||||
this.serverBackupInfo = undefined;
|
||||
return null;
|
||||
}
|
||||
this.checkedForBackup = true;
|
||||
|
||||
if (backupInfo && !backupInfo.version) {
|
||||
logger.warn("active backup lacks a useful 'version'; ignoring it");
|
||||
this.logger.warn("active backup lacks a useful 'version'; ignoring it");
|
||||
backupInfo = undefined;
|
||||
}
|
||||
this.serverBackupInfo = backupInfo;
|
||||
@@ -303,10 +304,10 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
|
||||
if (!backupInfo) {
|
||||
if (activeVersion !== null) {
|
||||
logger.log("No key backup present on server: disabling key backup");
|
||||
this.logger.debug("No key backup present on server: disabling key backup");
|
||||
await this.disableKeyBackup();
|
||||
} else {
|
||||
logger.log("No key backup present on server: not enabling key backup");
|
||||
this.logger.debug("No key backup present on server: not enabling key backup");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -317,23 +318,25 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
// (b) the public key matches the private decryption key that we have received from 4S.
|
||||
if (!trustInfo.matchesDecryptionKey && !trustInfo.trusted) {
|
||||
if (activeVersion !== null) {
|
||||
logger.log("Key backup present on server but not trusted: disabling key backup");
|
||||
this.logger.debug("Key backup present on server but not trusted: disabling key backup");
|
||||
await this.disableKeyBackup();
|
||||
} else {
|
||||
logger.log("Key backup present on server but not trusted: not enabling key backup");
|
||||
this.logger.debug("Key backup present on server but not trusted: not enabling key backup");
|
||||
}
|
||||
} else {
|
||||
if (activeVersion === null) {
|
||||
logger.log(`Found usable key backup v${backupInfo.version}: enabling key backups`);
|
||||
this.logger.debug(`Found usable key backup v${backupInfo.version}: enabling key backups`);
|
||||
await this.enableKeyBackup(backupInfo);
|
||||
} else if (activeVersion !== backupInfo.version) {
|
||||
logger.log(`On backup version ${activeVersion} but found version ${backupInfo.version}: switching.`);
|
||||
this.logger.debug(
|
||||
`On backup version ${activeVersion} but found version ${backupInfo.version}: switching.`,
|
||||
);
|
||||
// This will remove any pending backup request, remove the backup key and reset the backup state of each room key we have.
|
||||
await this.disableKeyBackup();
|
||||
// Enabling will now trigger re-upload of all the keys
|
||||
await this.enableKeyBackup(backupInfo);
|
||||
} else {
|
||||
logger.log(`Backup version ${backupInfo.version} still current`);
|
||||
this.logger.debug(`Backup version ${backupInfo.version} still current`);
|
||||
}
|
||||
}
|
||||
return { backupInfo, trustInfo };
|
||||
@@ -374,12 +377,12 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
|
||||
private async backupKeysLoop(maxDelay = 10000): Promise<void> {
|
||||
if (this.backupKeysLoopRunning) {
|
||||
logger.log(`Backup loop already running`);
|
||||
this.logger.debug(`Backup loop already running`);
|
||||
return;
|
||||
}
|
||||
this.backupKeysLoopRunning = true;
|
||||
|
||||
logger.log(`Backup: Starting keys upload loop for backup version:${this.activeBackupVersion}.`);
|
||||
this.logger.debug(`Backup: Starting keys upload loop for backup version:${this.activeBackupVersion}.`);
|
||||
|
||||
// wait between 0 and `maxDelay` seconds, to avoid backup
|
||||
// requests from different clients hitting the server all at
|
||||
@@ -401,18 +404,18 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
let request: RustSdkCryptoJs.KeysBackupRequest | undefined = undefined;
|
||||
try {
|
||||
request = await logDuration(
|
||||
logger,
|
||||
this.logger,
|
||||
"BackupRoomKeys: Get keys to backup from rust crypto-sdk",
|
||||
async () => {
|
||||
return await this.olmMachine.backupRoomKeys();
|
||||
},
|
||||
);
|
||||
} catch (err) {
|
||||
logger.error("Backup: Failed to get keys to backup from rust crypto-sdk", err);
|
||||
this.logger.error("Backup: Failed to get keys to backup from rust crypto-sdk", err);
|
||||
}
|
||||
|
||||
if (!request || this.stopped || !this.activeBackupVersion) {
|
||||
logger.log(`Backup: Ending loop for version ${this.activeBackupVersion}.`);
|
||||
this.logger.debug(`Backup: Ending loop for version ${this.activeBackupVersion}.`);
|
||||
if (!request) {
|
||||
// nothing more to upload
|
||||
this.emit(CryptoEvent.KeyBackupSessionsRemaining, 0);
|
||||
@@ -439,7 +442,7 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
const keyCount = await this.olmMachine.roomKeyCounts();
|
||||
remainingToUploadCount = keyCount.total - keyCount.backedUp;
|
||||
} catch (err) {
|
||||
logger.error("Backup: Failed to get key counts from rust crypto-sdk", err);
|
||||
this.logger.error("Backup: Failed to get key counts from rust crypto-sdk", err);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,15 +458,15 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
}
|
||||
} catch (err) {
|
||||
numFailures++;
|
||||
logger.error("Backup: Error processing backup request for rust crypto-sdk", err);
|
||||
this.logger.error("Backup: Error processing backup request for rust crypto-sdk", err);
|
||||
if (err instanceof MatrixError) {
|
||||
const errCode = err.data.errcode;
|
||||
if (errCode == "M_NOT_FOUND" || errCode == "M_WRONG_ROOM_KEYS_VERSION") {
|
||||
logger.log(`Backup: Failed to upload keys to current vesion: ${errCode}.`);
|
||||
this.logger.debug(`Backup: Failed to upload keys to current vesion: ${errCode}.`);
|
||||
try {
|
||||
await this.disableKeyBackup();
|
||||
} catch (error) {
|
||||
logger.error("Backup: An error occurred while disabling key backup:", error);
|
||||
this.logger.error("Backup: An error occurred while disabling key backup:", error);
|
||||
}
|
||||
this.emit(CryptoEvent.KeyBackupFailed, err.data.errcode!);
|
||||
// There was an active backup and we are out of sync with the server
|
||||
@@ -480,7 +483,7 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
continue;
|
||||
}
|
||||
} catch (error) {
|
||||
logger.warn(
|
||||
this.logger.warn(
|
||||
"Backup: An error occurred while retrieving a rate-limit retry delay",
|
||||
error,
|
||||
);
|
||||
@@ -590,7 +593,7 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
* @param version - The backup version to delete.
|
||||
*/
|
||||
public async deleteKeyBackupVersion(version: string): Promise<void> {
|
||||
logger.debug(`deleteKeyBackupVersion v:${version}`);
|
||||
this.logger.debug(`deleteKeyBackupVersion v:${version}`);
|
||||
const path = encodeUri("/room_keys/version/$version", { $version: version });
|
||||
await this.http.authedRequest<void>(Method.Delete, path, undefined, undefined, {
|
||||
prefix: ClientPrefix.V3,
|
||||
@@ -607,7 +610,7 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
* @param decryptionKey - The private key to use for decryption.
|
||||
*/
|
||||
public createBackupDecryptor(decryptionKey: RustSdkCryptoJs.BackupDecryptionKey): BackupDecryptor {
|
||||
return new RustBackupDecryptor(decryptionKey);
|
||||
return new RustBackupDecryptor(this.logger, decryptionKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -707,7 +710,7 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
totalFailures += currentChunk.length;
|
||||
// We failed to import some keys, but we should still try to import the rest?
|
||||
// Log the error and continue
|
||||
logger.error("Error importing keys from backup", e);
|
||||
this.logger.error("Error importing keys from backup", e);
|
||||
}
|
||||
|
||||
opts?.progressCallback?.({
|
||||
@@ -755,27 +758,28 @@ export class RustBackupManager extends TypedEventEmitter<RustBackupCryptoEvents,
|
||||
|
||||
return { total: totalKeyCount, imported: totalImported };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided backup info matches the given private key.
|
||||
*
|
||||
* @param info - The backup info to check.
|
||||
* @param backupDecryptionKey - The `BackupDecryptionKey` private key to check against.
|
||||
* @returns `true` if the private key can decrypt the backup, `false` otherwise.
|
||||
*/
|
||||
function backupInfoMatchesBackupDecryptionKey(
|
||||
info: KeyBackupInfo,
|
||||
backupDecryptionKey: RustSdkCryptoJs.BackupDecryptionKey,
|
||||
): boolean {
|
||||
if (info.algorithm !== "m.megolm_backup.v1.curve25519-aes-sha2") {
|
||||
logger.warn("backupMatchesPrivateKey: Unsupported backup algorithm", info.algorithm);
|
||||
return false;
|
||||
/**
|
||||
* Checks if the provided backup info matches the given private key.
|
||||
*
|
||||
* @param info - The backup info to check.
|
||||
* @param backupDecryptionKey - The `BackupDecryptionKey` private key to check against.
|
||||
* @returns `true` if the private key can decrypt the backup, `false` otherwise.
|
||||
*/
|
||||
private backupInfoMatchesBackupDecryptionKey(
|
||||
info: KeyBackupInfo,
|
||||
backupDecryptionKey: RustSdkCryptoJs.BackupDecryptionKey,
|
||||
): boolean {
|
||||
if (info.algorithm !== "m.megolm_backup.v1.curve25519-aes-sha2") {
|
||||
this.logger.warn("backupMatchesPrivateKey: Unsupported backup algorithm", info.algorithm);
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
(info.auth_data as Curve25519AuthData)?.public_key === backupDecryptionKey.megolmV1PublicKey.publicKeyBase64
|
||||
);
|
||||
}
|
||||
|
||||
return (info.auth_data as Curve25519AuthData)?.public_key === backupDecryptionKey.megolmV1PublicKey.publicKeyBase64;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of {@link BackupDecryptor} for the rust crypto backend.
|
||||
*/
|
||||
@@ -783,7 +787,10 @@ export class RustBackupDecryptor implements BackupDecryptor {
|
||||
private decryptionKey: RustSdkCryptoJs.BackupDecryptionKey;
|
||||
public sourceTrusted: boolean;
|
||||
|
||||
public constructor(decryptionKey: RustSdkCryptoJs.BackupDecryptionKey) {
|
||||
public constructor(
|
||||
private readonly logger: Logger,
|
||||
decryptionKey: RustSdkCryptoJs.BackupDecryptionKey,
|
||||
) {
|
||||
this.decryptionKey = decryptionKey;
|
||||
this.sourceTrusted = false;
|
||||
}
|
||||
@@ -807,7 +814,7 @@ export class RustBackupDecryptor implements BackupDecryptor {
|
||||
decrypted.session_id = sessionId;
|
||||
keys.push(decrypted);
|
||||
} catch (e) {
|
||||
logger.log("Failed to decrypt megolm session from backup", e, sessionData);
|
||||
this.logger.debug("Failed to decrypt megolm session from backup", e, sessionData);
|
||||
}
|
||||
}
|
||||
return keys;
|
||||
|
||||
@@ -163,7 +163,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
private readonly cryptoCallbacks: CryptoCallbacks,
|
||||
) {
|
||||
super();
|
||||
this.outgoingRequestProcessor = new OutgoingRequestProcessor(olmMachine, http);
|
||||
this.outgoingRequestProcessor = new OutgoingRequestProcessor(logger, olmMachine, http);
|
||||
this.outgoingRequestsManager = new OutgoingRequestsManager(
|
||||
this.logger,
|
||||
olmMachine,
|
||||
@@ -172,7 +172,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
|
||||
this.keyClaimManager = new KeyClaimManager(olmMachine, this.outgoingRequestProcessor);
|
||||
|
||||
this.backupManager = new RustBackupManager(olmMachine, http, this.outgoingRequestProcessor);
|
||||
this.backupManager = new RustBackupManager(logger, olmMachine, http, this.outgoingRequestProcessor);
|
||||
this.perSessionBackupDownloader = new PerSessionKeyBackupDownloader(
|
||||
this.logger,
|
||||
this.olmMachine,
|
||||
@@ -206,7 +206,12 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
CryptoEvent.DehydratedDeviceRotationError,
|
||||
]);
|
||||
|
||||
this.crossSigningIdentity = new CrossSigningIdentity(olmMachine, this.outgoingRequestProcessor, secretStorage);
|
||||
this.crossSigningIdentity = new CrossSigningIdentity(
|
||||
logger,
|
||||
olmMachine,
|
||||
this.outgoingRequestProcessor,
|
||||
secretStorage,
|
||||
);
|
||||
|
||||
// Check and start in background the key backup connection
|
||||
this.checkKeyBackupAndEnable();
|
||||
@@ -1625,6 +1630,7 @@ export class RustCrypto extends TypedEventEmitter<RustCryptoEvents, CryptoEventH
|
||||
existingEncryptor.onCryptoEvent(config);
|
||||
} else {
|
||||
this.roomEncryptors[room.roomId] = new RoomEncryptor(
|
||||
this.logger.getChild(`[${room.roomId} encryption]`),
|
||||
this.olmMachine,
|
||||
this.keyClaimManager,
|
||||
this.outgoingRequestsManager,
|
||||
|
||||
Reference in New Issue
Block a user