Fix crypto migration for megolm sessions with no sender key (#4024)
Fixes https://github.com/element-hq/element-web/issues/26894 Requires https://github.com/matrix-org/matrix-rust-sdk-crypto-wasm/pull/89 (or rather, an update to a version of matrix-rust-sdk-crypto-wasm) which includes it).
This commit is contained in:
committed by
GitHub
parent
ab217bdc35
commit
19494e093b
@@ -167,6 +167,21 @@ describe("initRustCrypto", () => {
|
||||
});
|
||||
|
||||
describe("libolm migration", () => {
|
||||
let mockStore: RustSdkCryptoJs.StoreHandle;
|
||||
|
||||
beforeEach(() => {
|
||||
// Stub out a bunch of stuff in the Rust library
|
||||
mockStore = { free: jest.fn() } as unknown as StoreHandle;
|
||||
jest.spyOn(StoreHandle, "open").mockResolvedValue(mockStore);
|
||||
|
||||
jest.spyOn(Migration, "migrateBaseData").mockResolvedValue(undefined);
|
||||
jest.spyOn(Migration, "migrateOlmSessions").mockResolvedValue(undefined);
|
||||
jest.spyOn(Migration, "migrateMegolmSessions").mockResolvedValue(undefined);
|
||||
|
||||
const testOlmMachine = makeTestOlmMachine();
|
||||
jest.spyOn(OlmMachine, "initFromStore").mockResolvedValue(testOlmMachine);
|
||||
});
|
||||
|
||||
it("migrates data from a legacy crypto store", async () => {
|
||||
const PICKLE_KEY = "pickle1234";
|
||||
const legacyStore = new MemoryCryptoStore();
|
||||
@@ -186,17 +201,6 @@ describe("initRustCrypto", () => {
|
||||
createMegolmSessions(legacyStore, nDevices, nSessionsPerDevice);
|
||||
await legacyStore.markSessionsNeedingBackup([{ senderKey: pad43("device5"), sessionId: "session5" }]);
|
||||
|
||||
// Stub out a bunch of stuff in the Rust library
|
||||
const mockStore = { free: jest.fn() } as unknown as StoreHandle;
|
||||
jest.spyOn(StoreHandle, "open").mockResolvedValue(mockStore);
|
||||
|
||||
jest.spyOn(Migration, "migrateBaseData").mockResolvedValue(undefined);
|
||||
jest.spyOn(Migration, "migrateOlmSessions").mockResolvedValue(undefined);
|
||||
jest.spyOn(Migration, "migrateMegolmSessions").mockResolvedValue(undefined);
|
||||
|
||||
const testOlmMachine = makeTestOlmMachine();
|
||||
jest.spyOn(OlmMachine, "initFromStore").mockResolvedValue(testOlmMachine);
|
||||
|
||||
fetchMock.get("path:/_matrix/client/v3/room_keys/version", { version: "45" });
|
||||
|
||||
function legacyMigrationProgressListener(progress: number, total: number): void {
|
||||
@@ -275,12 +279,59 @@ describe("initRustCrypto", () => {
|
||||
expect(session.senderKey).toEqual(pad43(`device${i}`));
|
||||
expect(session.pickle).toEqual("sessionPickle");
|
||||
expect(session.roomId!.toString()).toEqual("!room:id");
|
||||
expect(session.senderSigningKey).toEqual("sender_signing_key");
|
||||
|
||||
// only one of the sessions needs backing up
|
||||
expect(session.backedUp).toEqual(i !== 5 || j !== 5);
|
||||
}
|
||||
}
|
||||
}, 10000);
|
||||
|
||||
it("handles megolm sessions with no `keysClaimed`", async () => {
|
||||
const legacyStore = new MemoryCryptoStore();
|
||||
legacyStore.storeAccount({}, "not a real account");
|
||||
|
||||
legacyStore.storeEndToEndInboundGroupSession(
|
||||
pad43(`device1`),
|
||||
`session1`,
|
||||
{
|
||||
forwardingCurve25519KeyChain: [],
|
||||
room_id: "!room:id",
|
||||
session: "sessionPickle",
|
||||
},
|
||||
undefined,
|
||||
);
|
||||
|
||||
const PICKLE_KEY = "pickle1234";
|
||||
await initRustCrypto({
|
||||
logger,
|
||||
http: makeMatrixHttpApi(),
|
||||
userId: TEST_USER,
|
||||
deviceId: TEST_DEVICE_ID,
|
||||
secretStorage: {} as ServerSideSecretStorage,
|
||||
cryptoCallbacks: {} as CryptoCallbacks,
|
||||
storePrefix: "storePrefix",
|
||||
storePassphrase: "storePassphrase",
|
||||
legacyCryptoStore: legacyStore,
|
||||
legacyPickleKey: PICKLE_KEY,
|
||||
});
|
||||
|
||||
expect(Migration.migrateMegolmSessions).toHaveBeenCalledTimes(1);
|
||||
expect(Migration.migrateMegolmSessions).toHaveBeenCalledWith(
|
||||
expect.any(Array),
|
||||
new Uint8Array(Buffer.from(PICKLE_KEY)),
|
||||
mockStore,
|
||||
);
|
||||
const megolmSessions: PickledInboundGroupSession[] = mocked(Migration.migrateMegolmSessions).mock
|
||||
.calls[0][0];
|
||||
expect(megolmSessions.length).toEqual(1);
|
||||
const session = megolmSessions[0];
|
||||
expect(session.senderKey).toEqual(pad43(`device1`));
|
||||
expect(session.pickle).toEqual("sessionPickle");
|
||||
expect(session.roomId!.toString()).toEqual("!room:id");
|
||||
expect(session.senderSigningKey).toBe(undefined);
|
||||
}, 10000);
|
||||
|
||||
async function encryptAndStoreSecretKey(type: string, key: Uint8Array, pickleKey: string, store: CryptoStore) {
|
||||
const encryptedKey = await encryptAES(encodeBase64(key), Buffer.from(pickleKey), type);
|
||||
store.storeSecretStorePrivateKey(undefined, type as keyof SecretStorePrivateKeys, encryptedKey);
|
||||
|
||||
@@ -64,7 +64,7 @@ export interface InboundGroupSessionData {
|
||||
room_id: string; // eslint-disable-line camelcase
|
||||
/** pickled Olm.InboundGroupSession */
|
||||
session: string;
|
||||
keysClaimed: Record<string, string>;
|
||||
keysClaimed?: Record<string, string>;
|
||||
/** Devices involved in forwarding this session to us (normally empty). */
|
||||
forwardingCurve25519KeyChain: string[];
|
||||
/** whether this session is untrusted. */
|
||||
|
||||
@@ -232,11 +232,13 @@ async function migrateMegolmSessions(
|
||||
logger.debug(`Migrating batch of ${batch.length} megolm sessions`);
|
||||
const migrationData: RustSdkCryptoJs.PickledInboundGroupSession[] = [];
|
||||
for (const session of batch) {
|
||||
const sessionData = session.sessionData!;
|
||||
|
||||
const pickledSession = new RustSdkCryptoJs.PickledInboundGroupSession();
|
||||
pickledSession.pickle = session.sessionData!.session;
|
||||
pickledSession.roomId = new RustSdkCryptoJs.RoomId(session.sessionData!.room_id);
|
||||
pickledSession.pickle = sessionData.session;
|
||||
pickledSession.roomId = new RustSdkCryptoJs.RoomId(sessionData.room_id);
|
||||
pickledSession.senderKey = session.senderKey;
|
||||
pickledSession.senderSigningKey = session.sessionData!.keysClaimed["ed25519"];
|
||||
pickledSession.senderSigningKey = sessionData.keysClaimed?.["ed25519"];
|
||||
pickledSession.backedUp = !session.needsBackup;
|
||||
|
||||
// Not sure if we can reliably distinguish imported vs not-imported sessions in the libolm database.
|
||||
|
||||
Reference in New Issue
Block a user