Skip to content

Commit 815c36e

Browse files
authored
Support for migration from from libolm (#3978)
* Use a `StoreHandle` to init OlmMachine This will be faster if we need to prepare the store. * Include "needsBackup" flag in inbound group session batches * On startup, import data from libolm cryptostore * ISessionExtended -> SessionExtended
1 parent d355073 commit 815c36e

File tree

15 files changed

+72481
-51
lines changed

15 files changed

+72481
-51
lines changed

.prettierignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ out
2525
# This file is owned, parsed, and generated by allchange, which doesn't comply with prettier
2626
/CHANGELOG.md
2727

28-
# This file is also autogenerated
28+
# These files are also autogenerated
2929
/spec/test-utils/test-data/index.ts
30+
/spec/test-utils/test_indexeddb_cryptostore_dump/dump.json

spec/integ/crypto/rust-crypto.spec.ts

+46-1
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@ limitations under the License.
1616

1717
import "fake-indexeddb/auto";
1818
import { IDBFactory } from "fake-indexeddb";
19+
import fetchMock from "fetch-mock-jest";
1920

20-
import { createClient } from "../../../src";
21+
import { createClient, IndexedDBCryptoStore } from "../../../src";
22+
import { populateStore } from "../../test-utils/test_indexeddb_cryptostore_dump";
23+
24+
jest.setTimeout(15000);
2125

2226
afterEach(() => {
2327
// reset fake-indexeddb after each test, to make sure we don't leak connections
@@ -88,6 +92,47 @@ describe("MatrixClient.initRustCrypto", () => {
8892
await matrixClient.initRustCrypto();
8993
await matrixClient.initRustCrypto();
9094
});
95+
96+
it("should migrate from libolm", async () => {
97+
fetchMock.get("path:/_matrix/client/v3/room_keys/version", {
98+
auth_data: {
99+
public_key: "q+HZiJdHl2Yopv9GGvv7EYSzDMrAiRknK4glSdoaomI",
100+
signatures: {
101+
"@vdhtest200713:matrix.org": {
102+
"ed25519:gh9fGr39eNZUdWynEMJ/q/WZq/Pk/foFxHXFBFm18ZI":
103+
"reDp6Mu+j+tfUL3/T6f5OBT3N825Lzpc43vvG+RvjX6V+KxXzodBQArgCoeEHLtL9OgSBmNrhTkSOX87MWCKAw",
104+
"ed25519:KMFSTJSMLB":
105+
"F8tyV5W6wNi0GXTdSg+gxSCULQi0EYxdAAqfkyNq58KzssZMw5i+PRA0aI2b+D7NH/aZaJrtiYNHJ0gWLSQvAw",
106+
},
107+
},
108+
},
109+
version: "7",
110+
algorithm: "m.megolm_backup.v1.curve25519-aes-sha2",
111+
etag: "1",
112+
count: 79,
113+
});
114+
115+
const testStoreName = "test-store";
116+
await populateStore(testStoreName);
117+
const cryptoStore = new IndexedDBCryptoStore(indexedDB, testStoreName);
118+
119+
const matrixClient = createClient({
120+
baseUrl: "http://test.server",
121+
userId: "@vdhtest200713:matrix.org",
122+
deviceId: "KMFSTJSMLB",
123+
cryptoStore,
124+
pickleKey: "+1k2Ppd7HIisUY824v7JtV3/oEE4yX0TqtmNPyhaD7o",
125+
});
126+
127+
await matrixClient.initRustCrypto();
128+
129+
// Do some basic checks on the imported data
130+
const deviceKeys = await matrixClient.getCrypto()!.getOwnDeviceKeys();
131+
expect(deviceKeys.curve25519).toEqual("LKv0bKbc0EC4h0jknbemv3QalEkeYvuNeUXVRgVVTTU");
132+
expect(deviceKeys.ed25519).toEqual("qK70DEqIXq7T+UU3v/al47Ab4JkMEBLpNrTBMbS5rrw");
133+
134+
expect(await matrixClient.getCrypto()!.getActiveSessionBackupVersion()).toEqual("7");
135+
});
91136
});
92137

93138
describe("MatrixClient.clearStores", () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
## Dump of libolm indexeddb cryptostore
2+
3+
This directory contains a dump of a real indexeddb store from a session using
4+
libolm crypto.
5+
6+
The corresponding pickle key is `+1k2Ppd7HIisUY824v7JtV3/oEE4yX0TqtmNPyhaD7o`.
7+
8+
It was created by pasting the following into the browser console:
9+
10+
```javascript
11+
async function exportIndexedDb(name) {
12+
const db = await new Promise((resolve, reject) => {
13+
const dbReq = indexedDB.open(name);
14+
dbReq.onerror = reject;
15+
dbReq.onsuccess = () => resolve(dbReq.result);
16+
});
17+
18+
const storeNames = db.objectStoreNames;
19+
const exports = {};
20+
for (const store of storeNames) {
21+
exports[store] = [];
22+
const txn = db.transaction(store, "readonly");
23+
const objectStore = txn.objectStore(store);
24+
await new Promise((resolve, reject) => {
25+
const cursorReq = objectStore.openCursor();
26+
cursorReq.onerror = reject;
27+
cursorReq.onsuccess = (event) => {
28+
const cursor = event.target.result;
29+
if (cursor) {
30+
const entry = { value: cursor.value };
31+
if (!objectStore.keyPath) {
32+
entry.key = cursor.key;
33+
}
34+
exports[store].push(entry);
35+
cursor.continue();
36+
} else {
37+
resolve();
38+
}
39+
};
40+
});
41+
}
42+
return exports;
43+
}
44+
45+
window.saveAs(
46+
new Blob([JSON.stringify(await exportIndexedDb("matrix-js-sdk:crypto"), null, 2)], {
47+
type: "application/json;charset=utf-8",
48+
}),
49+
"dump.json",
50+
);
51+
```
52+
53+
The pickle key is extracted via `mxMatrixClientPeg.get().crypto.olmDevice.pickleKey`.

0 commit comments

Comments
 (0)