Skip to content

Commit

Permalink
Don't run migration for Rust crypto if the legacy store is empty
Browse files Browse the repository at this point in the history
  • Loading branch information
andybalaam committed May 24, 2024
1 parent b19817b commit a9e3f28
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 0 deletions.
31 changes: 31 additions & 0 deletions spec/integ/crypto/rust-crypto.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { populateStore } from "../../test-utils/test_indexeddb_cryptostore_dump"
import { MSK_NOT_CACHED_DATASET } from "../../test-utils/test_indexeddb_cryptostore_dump/no_cached_msk_dump";
import { IDENTITY_NOT_TRUSTED_DATASET } from "../../test-utils/test_indexeddb_cryptostore_dump/unverified";
import { FULL_ACCOUNT_DATASET } from "../../test-utils/test_indexeddb_cryptostore_dump/full_account";
import { EMPTY_ACCOUNT_DATASET } from "../../test-utils/test_indexeddb_cryptostore_dump/empty_account";

jest.setTimeout(15000);

Expand Down Expand Up @@ -304,6 +305,36 @@ describe("MatrixClient.initRustCrypto", () => {
});
});

it("should not migrate if account data is missing", async () => {
// See https://github.com/element-hq/element-web/issues/27447

// Given we have an almost-empty legacy account in the database
fetchMock.get("path:/_matrix/client/v3/room_keys/version", EMPTY_ACCOUNT_DATASET.backupResponse);

fetchMock.post("path:/_matrix/client/v3/keys/query", EMPTY_ACCOUNT_DATASET.keyQueryResponse);

const testStoreName = "test-store";
await populateStore(testStoreName, EMPTY_ACCOUNT_DATASET.dumpPath);
const cryptoStore = new IndexedDBCryptoStore(indexedDB, testStoreName);

const matrixClient = createClient({
baseUrl: "http://test.server",
userId: EMPTY_ACCOUNT_DATASET.userId,
deviceId: EMPTY_ACCOUNT_DATASET.deviceId,
cryptoStore,
pickleKey: EMPTY_ACCOUNT_DATASET.pickleKey,
});

// When we start Rust crypto, potentially triggering an upgrade
const progressListener = jest.fn();
matrixClient.addListener(CryptoEvent.LegacyCryptoStoreMigrationProgress, progressListener);

await matrixClient.initRustCrypto();

// Then no error occurs, and no upgrade happens
expect(progressListener.mock.calls.length).toBe(0);
}, 60000);

describe("Legacy trust migration", () => {
async function populateAndStartLegacyCryptoStore(dumpPath: string): Promise<IndexedDBCryptoStore> {
const testStoreName = "test-store";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
## Dump of an empty libolm indexeddb cryptostore to test skipping migration

A dump of an account which is almost completely empty, and totally unsuitable
for use as a real account.

This dump was manually created by copying and editing full_account.

Created to test
["Unable to restore session" error due due to half-initialised legacy indexeddb crypto store #27447](https://github.com/element-hq/element-web/issues/27447).
We should not launch the Rust migration code when we find a DB in this state.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"account": [],
"device_data": [],
"inbound_group_sessions": [],
"inbound_group_sessions_withheld": [],
"notified_error_devices": [],
"outgoingRoomKeyRequests": [],
"parked_shared_history": [],
"rooms": [],
"session_problems": [],
"sessions": [],
"sessions_needing_backup": [],
"shared_history_inbound_group_sessions": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { DumpDataSetInfo } from "../index";

/**
* A key query response containing the current keys of the tested user.
* To be used during tests with fetchmock.
*/
const KEYS_QUERY_RESPONSE: any = {
device_keys: {},
master_keys: {},
self_signing_keys: {},
user_signing_keys: {},
};

/**
* A `/room_keys/version` response containing the current server-side backup info.
* To be used during tests with fetchmock.
*/
const BACKUP_RESPONSE: any = {};

/**
* A dataset containing the information for the tested user.
* To be used during tests.
*/
export const EMPTY_ACCOUNT_DATASET: DumpDataSetInfo = {
userId: "@emptyuser:example.com",
deviceId: "EMPTYDEVIC",
pickleKey: "+/bcdefghijklmnopqrstu1/zyxvutsrqponmlkjih2",
backupResponse: BACKUP_RESPONSE,
keyQueryResponse: KEYS_QUERY_RESPONSE,
dumpPath: "spec/test-utils/test_indexeddb_cryptostore_dump/empty_account/dump.json",
};
13 changes: 13 additions & 0 deletions src/rust-crypto/libolm_migration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,19 @@ export async function migrateFromLegacyCrypto(args: {
}

await legacyStore.startup();

let account;
await legacyStore.doTxn("readonly", [IndexedDBCryptoStore.STORE_ACCOUNT], (txn) => {
legacyStore.getAccount(txn, (acct) => {
account = acct;
});
});
if (!account) {
// This store is not properly set up. Nothing to migrate.
logger.warn("Legacy crypto store is not set up (no account found). Not migrating.");
return;
}

let migrationState = await legacyStore.getMigrationState();

if (migrationState >= MigrationState.MEGOLM_SESSIONS_MIGRATED) {
Expand Down

0 comments on commit a9e3f28

Please sign in to comment.