Closed
Description
Issue: IdbKeyRangeMakeError when using fake-indexeddb with initRustCrypto
Description
I'm encountering an error when trying to initialize the crypto backend using initRustCrypto
while using an in-memory IndexedDB from the fake-indexeddb
package. The error occurs specifically when calling this.client.initRustCrypto()
.
Error Message
[0] Checking key backup status...
[0] FetchHttpApi: --> GET https://matrix.beeper.com/_matrix/client/v3/room_keys/version
[0] /node_modules/@matrix-org/matrix-sdk-crypto-wasm/pkg/index.js:10194
[0] const ret = new Error(getStringFromWasm0(arg0, arg1));
[0] ^
[0]
[0] Error: DomException IdbKeyRangeMakeError (0): Creating key range failed
[0] at module.exports.__wbindgen_error_new (/node_modules/@matrix-org/matrix-sdk-crypto-wasm/pkg/index.js:10194:17)
[0] at matrix_sdk_crypto_wasm.wasm.<T as futures_util::fns::FnOnce1<A>>::call_once::h05d72edafa394dd0 (wasm://wasm/matrix_sdk_crypto_wasm.wasm-01906b8e:wasm-function[6552]:0x3af412)
[0] at matrix_sdk_crypto_wasm.wasm.<futures_util::fns::MapErrFn<F> as futures_util::fns::FnOnce1<core::result::Result<T,E>>>::call_once::h0b79ccf2b4c2a322 (wasm://wasm/matrix_sdk_crypto_wasm.wasm-01906b8e:wasm-function[8123]:0x3d9f51)
[0] at matrix_sdk_crypto_wasm.wasm.matrix_sdk_crypto_wasm::future::future_to_promise_with_custom_error::{{closure}}::{{closure}}::h4c8a1194d1f31297 (wasm://wasm/matrix_sdk_crypto_wasm.wasm-01906b8e:wasm-function[1580]:0x270040)
[0] at matrix_sdk_crypto_wasm.wasm.wasm_bindgen_futures::queue::Queue::new::{{closure}}::h84ce96b9c85cc796 (wasm://wasm/matrix_sdk_crypto_wasm.wasm-01906b8e:wasm-function[1468]:0x2380a2)
[0] at matrix_sdk_crypto_wasm.wasm.wasm_bindgen::convert::closures::invoke1_mut::h8343de5045287dec (wasm://wasm/matrix_sdk_crypto_wasm.wasm-01906b8e:wasm-function[9368]:0x3ed3c2)
[0] at __wbg_adapter_65 (/node_modules/@matrix-org/matrix-sdk-crypto-wasm/pkg/index.js:261:10)
[0] at real (node_modules/@matrix-org/matrix-sdk-crypto-wasm/pkg/index.js:203:20)
[0] at node:internal/process/task_queues:151:7
[0] at AsyncResource.runInAsyncScope (node:async_hooks:211:14)
I don't know why I am running into this error and how I can correct it. Any help is much appreciated.
Here is the relevant part of my code:
async initialize(): Promise<{token: string}> {
if(this.client !== null) {
return {token: this.accessToken};
}
if (this.isInitializing) {
console.log('Matrix client initialization in progress.');
return {token: this.accessToken};
}
if (this.isInitialized) {
console.log('Matrix client already initialized.');
return {token: this.accessToken};
}
this.isInitializing = true;
try {
const dbName = `matrix-js-sdk:${this.authConfig.username}`;
this.client = MatrixSDK.createClient({
baseUrl: this.authConfig.domain,
userId: `@${this.authConfig.username}:${this.authConfig.domain}`,
deviceId: this.generateDeviceId(),
cryptoStore: new MatrixSDK.IndexedDBCryptoStore(indexedDB, dbName)
});
if(!this.client.isLoggedIn()) {
await this.login();
}
await this.setupCrypto();
await this.setupEventListeners();
if(!this.client.clientRunning) {
await this.client.startClient({initialSyncLimit: 500, lazyLoadMembers: true})
await this.initialFetch();
}
const syncToken = await this.client.store.getSavedSyncToken();
await updateSyncToken(syncToken ?? "");
this.isInitialized = true;
console.log('Matrix client fully initialized.');
return {token: this.accessToken};
} catch (error: any) {
console.error('Failed to initialize Matrix client:', error);
this.client = null;
throw error;
} finally {
this.isInitializing = false;
}
}
private async setupCrypto(): Promise<void> {
if (!this.client) {
throw new Error('Client not created');
}
for (const dbType of ["indexeddb", "memory"]) {
try {
const promise = this.client.store.startup();
console.log("MatrixClientPeg: waiting for MatrixClient store to initialise");
await promise;
break;
} catch (err) {
if (dbType === "indexeddb") {
console.error("Error starting matrixclient store - falling back to memory store", err);
this.client.store = new MatrixSDK.MemoryStore({
localStorage: localStorage,
});
} else {
console.error("Failed to start memory store!", err);
throw err;
}
}
}
this.client.store.on?.("closed", this.onUnexpectedStoreClose);
this.cryptoManager = new CryptoManager(this.client);
const cryptoStatus = await this.cryptoManager.isCryptoReady();
// initialize crypto if not fully ready
if (!cryptoStatus.crossSigningReady || !cryptoStatus.secretStorageReady) {
try {
await this.cryptoManager.initializeCrypto({
password: this.authConfig.password,
setupCrossSigning: true,
setupSecretStorage: true,
authConfig: this.authConfig
});
} catch (error) {
console.error('Failed to initialize crypto:', error);
throw error;
}
}
// ensure key backup is set up
const cryptoApi = this.client.getCrypto();
if (cryptoApi) {
const keyBackupInfo = await cryptoApi.checkKeyBackupAndEnable();
if (!keyBackupInfo) {
await cryptoApi.resetKeyBackup();
}
// event listener for key backup status (optional)
this.client.on(MatrixSDK.Crypto.CryptoEvent.KeyBackupStatus, async (status) => {
try {
await setKeyBackupStatus(status);
} catch (error) {
console.error('Failed to update key backup status:', error);
}
});
}
}
\async initializeCrypto(opts?: {
password?: string;
setupCrossSigning?: boolean;
setupSecretStorage?: boolean;
authConfig?: UserPayload;
}): Promise<CryptoSetupStatus> {
if (!this.client) {
throw new Error("createClient must be called first");
}
this.client.getUserId()?.replace(/^(.+?):https:\/\/matrix\.(.+)$/, '$1:$2') || '';
await this.client.initRustCrypto();
const crypto = this.client.getCrypto();
if (!crypto) {
throw new Error('Crypto not initialized');
}
try {
// bootstrap cross-signing if requested
if (opts?.setupCrossSigning) {
await crypto.bootstrapCrossSigning({
authUploadDeviceSigningKeys: async (makeRequest) => {
const { username, password } = opts.authConfig as UserPayload;
const authData: AuthDict = {
type: AuthType.Password,
identifier: { type: "m.id.user", username },
password,
session: "",
};
return makeRequest(authData).then(() => {});
},
});
}
// bootstrap secret storage if requested
if (opts?.setupSecretStorage) {
await crypto.bootstrapSecretStorage({
// create new secret storage key (if needed)
setupNewSecretStorage: true,
...(opts.password ? {
createSecretStorageKey: async () => {
return crypto.createRecoveryKeyFromPassphrase(opts.password);
}
} : {})
});
}
// verify the current device
await this.verifyCurrentDevice();
// return current crypto status
return this.isCryptoReady();
} catch (error) {
console.error('Crypto initialization error:', error);
throw error;
}
}