You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-11-26 17:03:12 +03:00
Element-R: use the pickleKey to encrypt the crypto store (#3732)
* Element-R: use the pickleKey to encrypt the crypto store `pickleKey` is a passphrase set by the application for this express purpose. * update tests * fix tests, again
This commit is contained in:
committed by
GitHub
parent
a3e273d6f1
commit
425cf6b91e
@@ -41,7 +41,7 @@ describe("MatrixClient.initRustCrypto", () => {
|
|||||||
await expect(() => unknownDeviceClient.initRustCrypto()).rejects.toThrow("unknown deviceId");
|
await expect(() => unknownDeviceClient.initRustCrypto()).rejects.toThrow("unknown deviceId");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should create the indexed dbs", async () => {
|
it("should create the indexed db", async () => {
|
||||||
const matrixClient = createClient({
|
const matrixClient = createClient({
|
||||||
baseUrl: "http://test.server",
|
baseUrl: "http://test.server",
|
||||||
userId: "@alice:localhost",
|
userId: "@alice:localhost",
|
||||||
@@ -53,7 +53,25 @@ describe("MatrixClient.initRustCrypto", () => {
|
|||||||
|
|
||||||
await matrixClient.initRustCrypto();
|
await matrixClient.initRustCrypto();
|
||||||
|
|
||||||
// should have two dbs now
|
// should have an indexed db now
|
||||||
|
const databaseNames = (await indexedDB.databases()).map((db) => db.name);
|
||||||
|
expect(databaseNames).toEqual(expect.arrayContaining(["matrix-js-sdk::matrix-sdk-crypto"]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should create the meta db if given a pickleKey", async () => {
|
||||||
|
const matrixClient = createClient({
|
||||||
|
baseUrl: "http://test.server",
|
||||||
|
userId: "@alice:localhost",
|
||||||
|
deviceId: "aliceDevice",
|
||||||
|
pickleKey: "testKey",
|
||||||
|
});
|
||||||
|
|
||||||
|
// No databases.
|
||||||
|
expect(await indexedDB.databases()).toHaveLength(0);
|
||||||
|
|
||||||
|
await matrixClient.initRustCrypto();
|
||||||
|
|
||||||
|
// should have two indexed dbs now
|
||||||
const databaseNames = (await indexedDB.databases()).map((db) => db.name);
|
const databaseNames = (await indexedDB.databases()).map((db) => db.name);
|
||||||
expect(databaseNames).toEqual(
|
expect(databaseNames).toEqual(
|
||||||
expect.arrayContaining(["matrix-js-sdk::matrix-sdk-crypto", "matrix-js-sdk::matrix-sdk-crypto-meta"]),
|
expect.arrayContaining(["matrix-js-sdk::matrix-sdk-crypto", "matrix-js-sdk::matrix-sdk-crypto-meta"]),
|
||||||
@@ -78,6 +96,7 @@ describe("MatrixClient.clearStores", () => {
|
|||||||
baseUrl: "http://test.server",
|
baseUrl: "http://test.server",
|
||||||
userId: "@alice:localhost",
|
userId: "@alice:localhost",
|
||||||
deviceId: "aliceDevice",
|
deviceId: "aliceDevice",
|
||||||
|
pickleKey: "testKey",
|
||||||
});
|
});
|
||||||
|
|
||||||
await matrixClient.initRustCrypto();
|
await matrixClient.initRustCrypto();
|
||||||
|
|||||||
@@ -54,6 +54,56 @@ const TEST_DEVICE_ID = "TEST_DEVICE";
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
fetchMock.reset();
|
fetchMock.reset();
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("initRustCrypto", () => {
|
||||||
|
function makeTestOlmMachine(): Mocked<OlmMachine> {
|
||||||
|
return {
|
||||||
|
registerRoomKeyUpdatedCallback: jest.fn(),
|
||||||
|
registerUserIdentityUpdatedCallback: jest.fn(),
|
||||||
|
outgoingRequests: jest.fn(),
|
||||||
|
} as unknown as Mocked<OlmMachine>;
|
||||||
|
}
|
||||||
|
|
||||||
|
it("passes through the store params", async () => {
|
||||||
|
const testOlmMachine = makeTestOlmMachine();
|
||||||
|
jest.spyOn(OlmMachine, "initialize").mockResolvedValue(testOlmMachine);
|
||||||
|
|
||||||
|
await initRustCrypto(
|
||||||
|
{} as MatrixClient["http"],
|
||||||
|
TEST_USER,
|
||||||
|
TEST_DEVICE_ID,
|
||||||
|
{} as ServerSideSecretStorage,
|
||||||
|
{} as CryptoCallbacks,
|
||||||
|
"storePrefix",
|
||||||
|
"storePassphrase",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(OlmMachine.initialize).toHaveBeenCalledWith(
|
||||||
|
expect.anything(),
|
||||||
|
expect.anything(),
|
||||||
|
"storePrefix",
|
||||||
|
"storePassphrase",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("suppresses the storePassphrase if storePrefix is unset", async () => {
|
||||||
|
const testOlmMachine = makeTestOlmMachine();
|
||||||
|
jest.spyOn(OlmMachine, "initialize").mockResolvedValue(testOlmMachine);
|
||||||
|
|
||||||
|
await initRustCrypto(
|
||||||
|
{} as MatrixClient["http"],
|
||||||
|
TEST_USER,
|
||||||
|
TEST_DEVICE_ID,
|
||||||
|
{} as ServerSideSecretStorage,
|
||||||
|
{} as CryptoCallbacks,
|
||||||
|
null,
|
||||||
|
"storePassphrase",
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(OlmMachine.initialize).toHaveBeenCalledWith(expect.anything(), expect.anything(), undefined, undefined);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("RustCrypto", () => {
|
describe("RustCrypto", () => {
|
||||||
@@ -398,10 +448,6 @@ describe("RustCrypto", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
jest.restoreAllMocks();
|
|
||||||
});
|
|
||||||
|
|
||||||
async function makeEncryptedEvent(): Promise<MatrixEvent> {
|
async function makeEncryptedEvent(): Promise<MatrixEvent> {
|
||||||
const encryptedEvent = mkEvent({
|
const encryptedEvent = mkEvent({
|
||||||
event: true,
|
event: true,
|
||||||
@@ -812,5 +858,5 @@ async function makeTestRustCrypto(
|
|||||||
secretStorage: ServerSideSecretStorage = {} as ServerSideSecretStorage,
|
secretStorage: ServerSideSecretStorage = {} as ServerSideSecretStorage,
|
||||||
cryptoCallbacks: CryptoCallbacks = {} as CryptoCallbacks,
|
cryptoCallbacks: CryptoCallbacks = {} as CryptoCallbacks,
|
||||||
): Promise<RustCrypto> {
|
): Promise<RustCrypto> {
|
||||||
return await initRustCrypto(http, userId, deviceId, secretStorage, cryptoCallbacks, null);
|
return await initRustCrypto(http, userId, deviceId, secretStorage, cryptoCallbacks, null, undefined);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -343,7 +343,14 @@ export interface ICreateClientOpts {
|
|||||||
deviceToImport?: IExportedDevice;
|
deviceToImport?: IExportedDevice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Key used to pickle olm objects or other sensitive data.
|
* Encryption key used for encrypting sensitive data (such as e2ee keys) in storage.
|
||||||
|
*
|
||||||
|
* This must be set to the same value every time the client is initialised for the same device.
|
||||||
|
*
|
||||||
|
* If unset, either a hardcoded key or no encryption at all is used, depending on the Crypto implementation.
|
||||||
|
*
|
||||||
|
* No particular requirement is placed on the key data (it is fed into an HKDF to generate the actual encryption
|
||||||
|
* keys).
|
||||||
*/
|
*/
|
||||||
pickleKey?: string;
|
pickleKey?: string;
|
||||||
|
|
||||||
@@ -1193,7 +1200,18 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
public store: Store;
|
public store: Store;
|
||||||
public deviceId: string | null;
|
public deviceId: string | null;
|
||||||
public credentials: { userId: string | null };
|
public credentials: { userId: string | null };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encryption key used for encrypting sensitive data (such as e2ee keys) in storage.
|
||||||
|
*
|
||||||
|
* As supplied in the constructor via {@link IMatrixClientCreateOpts#pickleKey}.
|
||||||
|
*
|
||||||
|
* If unset, either a hardcoded key or no encryption at all is used, depending on the Crypto implementation.
|
||||||
|
*
|
||||||
|
* @deprecated this should be a private property.
|
||||||
|
*/
|
||||||
public pickleKey?: string;
|
public pickleKey?: string;
|
||||||
|
|
||||||
public scheduler?: MatrixScheduler;
|
public scheduler?: MatrixScheduler;
|
||||||
public clientRunning = false;
|
public clientRunning = false;
|
||||||
public timelineSupport = false;
|
public timelineSupport = false;
|
||||||
@@ -2279,6 +2297,7 @@ export class MatrixClient extends TypedEventEmitter<EmittedEvents, ClientEventHa
|
|||||||
this.secretStorage,
|
this.secretStorage,
|
||||||
this.cryptoCallbacks,
|
this.cryptoCallbacks,
|
||||||
useIndexedDB ? RUST_SDK_STORE_PREFIX : null,
|
useIndexedDB ? RUST_SDK_STORE_PREFIX : null,
|
||||||
|
this.pickleKey,
|
||||||
);
|
);
|
||||||
rustCrypto.setSupportedVerificationMethods(this.verificationMethods);
|
rustCrypto.setSupportedVerificationMethods(this.verificationMethods);
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,10 @@ import { ICryptoCallbacks } from "../crypto";
|
|||||||
* @param secretStorage - Interface to server-side secret storage.
|
* @param secretStorage - Interface to server-side secret storage.
|
||||||
* @param cryptoCallbacks - Crypto callbacks provided by the application
|
* @param cryptoCallbacks - Crypto callbacks provided by the application
|
||||||
* @param storePrefix - the prefix to use on the indexeddbs created by rust-crypto.
|
* @param storePrefix - the prefix to use on the indexeddbs created by rust-crypto.
|
||||||
* If unset, a memory store will be used.
|
* If `null`, a memory store will be used.
|
||||||
|
* @param storePassphrase - a passphrase to use to encrypt the indexeddbs created by rust-crypto.
|
||||||
|
* Ignored if `storePrefix` is null. If this is `undefined` (and `storePrefix` is not null), the indexeddbs
|
||||||
|
* will be unencrypted.
|
||||||
*
|
*
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
@@ -43,6 +46,7 @@ export async function initRustCrypto(
|
|||||||
secretStorage: ServerSideSecretStorage,
|
secretStorage: ServerSideSecretStorage,
|
||||||
cryptoCallbacks: ICryptoCallbacks,
|
cryptoCallbacks: ICryptoCallbacks,
|
||||||
storePrefix: string | null,
|
storePrefix: string | null,
|
||||||
|
storePassphrase: string | undefined,
|
||||||
): Promise<RustCrypto> {
|
): Promise<RustCrypto> {
|
||||||
// initialise the rust matrix-sdk-crypto-wasm, if it hasn't already been done
|
// initialise the rust matrix-sdk-crypto-wasm, if it hasn't already been done
|
||||||
await RustSdkCryptoJs.initAsync();
|
await RustSdkCryptoJs.initAsync();
|
||||||
@@ -59,7 +63,7 @@ export async function initRustCrypto(
|
|||||||
u,
|
u,
|
||||||
d,
|
d,
|
||||||
storePrefix ?? undefined,
|
storePrefix ?? undefined,
|
||||||
(storePrefix && "test pass") ?? undefined,
|
(storePrefix && storePassphrase) ?? undefined,
|
||||||
);
|
);
|
||||||
const rustCrypto = new RustCrypto(olmMachine, http, userId, deviceId, secretStorage, cryptoCallbacks);
|
const rustCrypto = new RustCrypto(olmMachine, http, userId, deviceId, secretStorage, cryptoCallbacks);
|
||||||
await olmMachine.registerRoomKeyUpdatedCallback((sessions: RustSdkCryptoJs.RoomKeyInfo[]) =>
|
await olmMachine.registerRoomKeyUpdatedCallback((sessions: RustSdkCryptoJs.RoomKeyInfo[]) =>
|
||||||
|
|||||||
Reference in New Issue
Block a user