Skip to content

Commit

Permalink
Refactor to instead create a new storage per device, rather than dele…
Browse files Browse the repository at this point in the history
…ting old storage.
  • Loading branch information
Half-Shot committed Dec 20, 2023
1 parent 959e603 commit 3d82d83
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 18 deletions.
16 changes: 2 additions & 14 deletions src/e2ee/CryptoClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import {
Attachment,
EncryptedAttachment,
} from "@matrix-org/matrix-sdk-crypto-nodejs";
import { rm } from "fs/promises";
import * as path from 'path';

import { MatrixClient } from "../MatrixClient";
import { LogService } from "../logging/LogService";
Expand Down Expand Up @@ -80,17 +78,7 @@ export class CryptoClient {
throw new Error("Encryption not possible: server not revealing device ID");
}

if (storedDeviceId && storedDeviceId !== deviceId) {
LogService.warn("CryptoClient", `Device ID for ${userId} has changed from ${storedDeviceId} to ${deviceId}`);
// Clear storage for old device.
try {
await rm(path.join(this.storage.storagePath, "matrix-sdk-crypto.sqlite3"));
} catch (ex) {
if (ex.code !== 'ENOENT') {
throw ex;
}
}
}
const storagePath = await this.storage.getMachineStoragePath(deviceId);

if (storedDeviceId !== deviceId) {
this.client.cryptoStore.setDeviceId(deviceId);
Expand All @@ -102,7 +90,7 @@ export class CryptoClient {
const machine = await OlmMachine.initialize(
new UserId(userId),
new DeviceId(this.deviceId),
this.storage.storagePath, "",
storagePath, "",
this.storage.storageType,
);
this.engine = new RustEngine(machine, this.client);
Expand Down
4 changes: 2 additions & 2 deletions src/storage/IAppserviceStorageProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export interface IAppserviceStorageProvider {
export interface IAppserviceCryptoStorageProvider {
/**
* Gets a storage provider to use for the given user ID.
* @param {string} userId The user ID.
* @returns {ICryptoStorageProvider} The storage provider.
* @param userId The user ID.
* @returns The storage provider.
*/
storageForUser(userId: string): ICryptoStorageProvider;
}
30 changes: 28 additions & 2 deletions src/storage/RustSdkCryptoStorageProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import * as lowdb from "lowdb";
import * as FileSync from "lowdb/adapters/FileSync";
import * as mkdirp from "mkdirp";
import * as path from "path";
import { stat, rename, mkdir } from "fs/promises";
import { PathLike } from "fs";
import * as sha512 from "hash.js/lib/hash/sha/512";
import * as sha256 from "hash.js/lib/hash/sha/256";
import { StoreType as RustSdkCryptoStoreType } from "@matrix-org/matrix-sdk-crypto-nodejs";
Expand All @@ -12,6 +14,10 @@ import { ICryptoRoomInformation } from "../e2ee/ICryptoRoomInformation";

export { RustSdkCryptoStoreType };

async function doesFileExist(path: PathLike) {
return stat(path).then(() => true).catch(() => false);
}

/**
* A crypto storage provider for the file-based rust-sdk store.
* @category Storage providers
Expand Down Expand Up @@ -40,6 +46,26 @@ export class RustSdkCryptoStorageProvider implements ICryptoStorageProvider {
});
}

public async getMachineStoragePath(deviceId: string): Promise<string> {
const newPath = path.join(this.storagePath, sha256().update(deviceId).digest('hex'));
if (await doesFileExist(newPath)) {
// Already exists, short circuit.
return newPath;
} // else: If the path does NOT exist we might need to perform a migration.

const legacyFilePath = path.join(this.storagePath, 'matrix-sdk-crypto.sqlite3');
// XXX: Slightly gross cross-dependency file name expectations.
if (await doesFileExist(legacyFilePath) === false) {
// No machine files at all, we can skip.
return newPath;
}

// We need to move the file.
await mkdir(newPath);
await rename(legacyFilePath, path.join(newPath, 'matrix-sdk-crypto.sqlite3'));
return newPath;
}

public async getDeviceId(): Promise<string> {
return this.db.get('deviceId').value();
}
Expand Down Expand Up @@ -75,7 +101,7 @@ export class RustSdkAppserviceCryptoStorageProvider extends RustSdkCryptoStorage

public storageForUser(userId: string): ICryptoStorageProvider {
// sha256 because sha512 is a bit big for some operating systems
const key = sha256().update(userId).digest('hex');
return new RustSdkCryptoStorageProvider(path.join(this.baseStoragePath, key), this.storageType);
const storagePath = path.join(this.baseStoragePath, sha256().update(userId).digest('hex'));
return new RustSdkCryptoStorageProvider(storagePath, this.storageType);
}
}

0 comments on commit 3d82d83

Please sign in to comment.