You've already forked matrix-js-sdk
mirror of
https://github.com/matrix-org/matrix-js-sdk.git
synced 2025-08-09 10:22:46 +03:00
Fix rust migration when ssss secret not encrypted (#4168)
This commit is contained in:
@@ -304,6 +304,56 @@ describe("initRustCrypto", () => {
|
||||
}
|
||||
}, 10000);
|
||||
|
||||
it("migrates data from a legacy crypto store when secret are not encrypted", async () => {
|
||||
const PICKLE_KEY = "pickle1234";
|
||||
const legacyStore = new MemoryCryptoStore();
|
||||
|
||||
// It's possible for old sessions to directly store the secrets as raw UInt8Array,
|
||||
// so we need to support that in the migration code.
|
||||
// See https://github.com/matrix-org/matrix-js-sdk/commit/c81f11df0afd4d0da3b088892745ae2f8ba1c4a7
|
||||
async function storeSecretKeyInClear(type: string, key: Uint8Array, store: CryptoStore) {
|
||||
// @ts-ignore The API to store raw UInt8Array does not exist anymore, so we need that for this test.
|
||||
store.privateKeys[type as keyof SecretStorePrivateKeys] = key;
|
||||
}
|
||||
|
||||
// Populate the legacy store with some test data
|
||||
const storeSecretKey = (type: string, key: string) =>
|
||||
storeSecretKeyInClear(type, new TextEncoder().encode(key), legacyStore);
|
||||
|
||||
await legacyStore.storeAccount({}, "not a real account");
|
||||
await storeSecretKey("master", "master key");
|
||||
await storeSecretKey("self_signing", "ssk");
|
||||
await storeSecretKey("user_signing", "usk");
|
||||
|
||||
fetchMock.get("path:/_matrix/client/v3/room_keys/version", 404);
|
||||
|
||||
function legacyMigrationProgressListener(progress: number, total: number): void {
|
||||
logger.log(`migrated ${progress} of ${total}`);
|
||||
}
|
||||
|
||||
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,
|
||||
legacyMigrationProgressListener,
|
||||
});
|
||||
|
||||
const data = mocked(Migration.migrateBaseData).mock.calls[0][0];
|
||||
expect(data.pickledAccount).toEqual("not a real account");
|
||||
expect(data.userId!.toString()).toEqual(TEST_USER);
|
||||
expect(data.deviceId!.toString()).toEqual(TEST_DEVICE_ID);
|
||||
expect(atob(data.privateCrossSigningMasterKey!)).toEqual("master key");
|
||||
expect(atob(data.privateCrossSigningUserSigningKey!)).toEqual("usk");
|
||||
expect(atob(data.privateCrossSigningSelfSigningKey!)).toEqual("ssk");
|
||||
});
|
||||
|
||||
it("handles megolm sessions with no `keysClaimed`", async () => {
|
||||
const legacyStore = new MemoryCryptoStore();
|
||||
legacyStore.storeAccount({}, "not a real account");
|
||||
|
@@ -27,6 +27,7 @@ import { CrossSigningKeyInfo, Curve25519AuthData } from "../crypto-api";
|
||||
import { RustCrypto } from "./rust-crypto";
|
||||
import { KeyBackupInfo } from "../crypto-api/keybackup";
|
||||
import { sleep } from "../utils";
|
||||
import { encodeBase64 } from "../base64";
|
||||
|
||||
/**
|
||||
* Determine if any data needs migrating from the legacy store, and do so.
|
||||
@@ -400,19 +401,20 @@ async function getAndDecryptCachedSecretKey(
|
||||
legacyPickleKey: Uint8Array,
|
||||
name: string,
|
||||
): Promise<string | undefined> {
|
||||
let encodedKey: IEncryptedPayload | null = null;
|
||||
|
||||
await legacyStore.doTxn("readonly", "account", (txn) => {
|
||||
legacyStore.getSecretStorePrivateKey(
|
||||
txn,
|
||||
(k) => {
|
||||
encodedKey = k as IEncryptedPayload | null;
|
||||
},
|
||||
name as keyof SecretStorePrivateKeys,
|
||||
);
|
||||
const key = await new Promise<any>((resolve) => {
|
||||
legacyStore.doTxn("readonly", [IndexedDBCryptoStore.STORE_ACCOUNT], (txn) => {
|
||||
legacyStore.getSecretStorePrivateKey(txn, resolve, name as keyof SecretStorePrivateKeys);
|
||||
});
|
||||
});
|
||||
|
||||
return encodedKey === null ? undefined : await decryptAES(encodedKey, legacyPickleKey, name);
|
||||
if (key && key.ciphertext && key.iv && key.mac) {
|
||||
return await decryptAES(key as IEncryptedPayload, legacyPickleKey, name);
|
||||
} else if (key instanceof Uint8Array) {
|
||||
// This is a legacy backward compatibility case where the key was stored in clear.
|
||||
return encodeBase64(key);
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user