Skip to content

Error: DomException IdbKeyRangeMakeError (0): Creating key range failed #4675

Closed
@bigg-S

Description

@bigg-S

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;
    }
  }

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions