Skip to content

Chore/optimize submit global pwd #6180

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

lwin-kyaw
Copy link
Contributor

@lwin-kyaw lwin-kyaw commented Jul 24, 2025

Explanation

This PR optimizes the password sync operation at unlock.

Previously, we called two methods, submitGlobalPassword and syncLatestGlobalPassword in the controller.

  • The first method calls toprfClient.recoverEncKey to retrieve the latest encKeys to recover the current device's pwEncKey and unlock the SeedlessOnboardingController with the recovered key
  • The later method calls toprfClient.recoverEncKey again to recover the latest key again and do the state sync in the controller.

This PR removes the later method, syncLatestGlobalPassword and do the state sync inside the submitGlobalPassword hence, removing the one extra call to TOPRFEvalRequest

References

Changelog

Checklist

  • I've updated the test suite for new or updated code as appropriate
  • I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate
  • I've communicated my changes to consumers by updating changelogs for packages I've changed, highlighting breaking changes as necessary
  • I've prepared draft pull requests for clients and consumer packages to resolve any breaking changes

@lwin-kyaw
Copy link
Contributor Author

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-tree-controller": "0.6.0-preview-4aa55b88",
  "@metamask-previews/accounts-controller": "32.0.0-preview-4aa55b88",
  "@metamask-previews/address-book-controller": "6.1.1-preview-4aa55b88",
  "@metamask-previews/announcement-controller": "7.0.3-preview-4aa55b88",
  "@metamask-previews/app-metadata-controller": "1.0.0-preview-4aa55b88",
  "@metamask-previews/approval-controller": "7.1.3-preview-4aa55b88",
  "@metamask-previews/assets-controllers": "73.0.0-preview-4aa55b88",
  "@metamask-previews/base-controller": "8.0.1-preview-4aa55b88",
  "@metamask-previews/bridge-controller": "37.0.0-preview-4aa55b88",
  "@metamask-previews/bridge-status-controller": "37.0.0-preview-4aa55b88",
  "@metamask-previews/build-utils": "3.0.3-preview-4aa55b88",
  "@metamask-previews/chain-agnostic-permission": "1.0.0-preview-4aa55b88",
  "@metamask-previews/composable-controller": "11.0.0-preview-4aa55b88",
  "@metamask-previews/controller-utils": "11.11.0-preview-4aa55b88",
  "@metamask-previews/delegation-controller": "0.6.0-preview-4aa55b88",
  "@metamask-previews/earn-controller": "4.0.0-preview-4aa55b88",
  "@metamask-previews/eip1193-permission-middleware": "1.0.0-preview-4aa55b88",
  "@metamask-previews/ens-controller": "17.0.1-preview-4aa55b88",
  "@metamask-previews/error-reporting-service": "2.0.0-preview-4aa55b88",
  "@metamask-previews/eth-json-rpc-provider": "4.1.8-preview-4aa55b88",
  "@metamask-previews/foundryup": "1.0.0-preview-4aa55b88",
  "@metamask-previews/gas-fee-controller": "24.0.0-preview-4aa55b88",
  "@metamask-previews/json-rpc-engine": "10.0.3-preview-4aa55b88",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.7-preview-4aa55b88",
  "@metamask-previews/keyring-controller": "22.1.0-preview-4aa55b88",
  "@metamask-previews/logging-controller": "6.0.4-preview-4aa55b88",
  "@metamask-previews/message-manager": "12.0.2-preview-4aa55b88",
  "@metamask-previews/messenger": "0.0.0-preview-4aa55b88",
  "@metamask-previews/multichain-account-service": "0.2.1-preview-4aa55b88",
  "@metamask-previews/multichain-api-middleware": "1.0.0-preview-4aa55b88",
  "@metamask-previews/multichain-network-controller": "0.11.0-preview-4aa55b88",
  "@metamask-previews/multichain-transactions-controller": "4.0.0-preview-4aa55b88",
  "@metamask-previews/name-controller": "8.0.3-preview-4aa55b88",
  "@metamask-previews/network-controller": "24.0.1-preview-4aa55b88",
  "@metamask-previews/notification-services-controller": "15.0.0-preview-4aa55b88",
  "@metamask-previews/permission-controller": "11.0.6-preview-4aa55b88",
  "@metamask-previews/permission-log-controller": "4.0.0-preview-4aa55b88",
  "@metamask-previews/phishing-controller": "13.1.0-preview-4aa55b88",
  "@metamask-previews/polling-controller": "14.0.0-preview-4aa55b88",
  "@metamask-previews/preferences-controller": "18.4.1-preview-4aa55b88",
  "@metamask-previews/profile-sync-controller": "22.0.0-preview-4aa55b88",
  "@metamask-previews/rate-limit-controller": "6.0.3-preview-4aa55b88",
  "@metamask-previews/remote-feature-flag-controller": "1.6.0-preview-4aa55b88",
  "@metamask-previews/sample-controllers": "1.0.0-preview-4aa55b88",
  "@metamask-previews/seedless-onboarding-controller": "2.4.0-preview-4aa55b88",
  "@metamask-previews/selected-network-controller": "23.0.0-preview-4aa55b88",
  "@metamask-previews/signature-controller": "32.0.0-preview-4aa55b88",
  "@metamask-previews/token-search-discovery-controller": "3.3.0-preview-4aa55b88",
  "@metamask-previews/transaction-controller": "59.0.0-preview-4aa55b88",
  "@metamask-previews/user-operation-controller": "38.0.0-preview-4aa55b88"
}

@lwin-kyaw lwin-kyaw marked this pull request as ready for review July 24, 2025 11:46
@lwin-kyaw lwin-kyaw requested review from a team as code owners July 24, 2025 11:46

// restore the current keyring encryption key with the new global password
await this.storeKeyringEncryptionKey(keyringEncryptionKey);

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Keyring Encryption Key Loading Error

The submitGlobalPassword method unconditionally attempts to load the keyring encryption key via #loadKeyringEncryptionKey. This method throws an error if encryptedKeyringEncryptionKey is not set in the state, which differs from the previous conditional handling and causes failures for users without a stored keyring encryption key.

Locations (1)

Fix in CursorFix in Web

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

encryptedKeyringEncryptionKey is persisted in the controller state and it is required to unlock the Keyring Vault. Expected error will be thrown if it's not present in the state.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's not true. the controller is written in a way that it works also if encryptedKeyringEncryptionKey is not present.

const [vaultKey, keyringEncryptionKey] = await Promise.all([
this.#loadSeedlessEncryptionKey(currentDevicePwEncKey),
this.#loadKeyringEncryptionKey(currentDevicePwEncKey),
]);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Keyring Encryption Key Loading Issue

The submitGlobalPasswordAndSync method unconditionally attempts to load the keyring encryption key via this.#loadKeyringEncryptionKey. This fails if encryptedKeyringEncryptionKey is not set in the state, as this.#loadKeyringEncryptionKey asserts its presence. This breaks backward compatibility, causing the method to fail for users without a stored keyring encryption key, unlike previous implementations (e.g., changePassword or the old submitGlobalPassword) which handled this conditionally or gracefully.

Locations (1)

Fix in CursorFix in Web

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a relevant comment.
note that unlock now fails if the keyring encryption key is not set.

the controller is designed in a way that it works without having a keyring key stored. unlock should work without it.

we should change this function to only attempt loading the keyring encryption key if it is stored.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wait, i'm just realizing that we didn't even update the encrypted encryption key before. why do we do it now?

});

// restore the current keyring encryption key with the new global password
await this.storeKeyringEncryptionKey(keyringEncryptionKey);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Keyring Encryption Key Loading Issue

The submitGlobalPasswordAndSync method unconditionally attempts to load the keyring encryption key via this.#loadKeyringEncryptionKey within a Promise.all. This causes the method to fail with an EncryptedKeyringEncryptionKeyNotSet error if this.state.encryptedKeyringEncryptionKey is not set. This breaks backward compatibility, as previous implementations (e.g., submitGlobalPassword or changePassword) either did not load the key or did so conditionally, allowing the operation to succeed in such scenarios.

Locations (1)

Fix in CursorFix in Web

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only do this if we were able to load the keyring encryption key.

@lwin-kyaw
Copy link
Contributor Author

@metamaskbot publish-preview

Copy link
Contributor

Preview builds have been published. See these instructions for more information about preview builds.

Expand for full list of packages and versions.
{
  "@metamask-previews/account-tree-controller": "0.6.0-preview-a0e6b482",
  "@metamask-previews/accounts-controller": "32.0.0-preview-a0e6b482",
  "@metamask-previews/address-book-controller": "6.1.1-preview-a0e6b482",
  "@metamask-previews/announcement-controller": "7.0.3-preview-a0e6b482",
  "@metamask-previews/app-metadata-controller": "1.0.0-preview-a0e6b482",
  "@metamask-previews/approval-controller": "7.1.3-preview-a0e6b482",
  "@metamask-previews/assets-controllers": "73.0.0-preview-a0e6b482",
  "@metamask-previews/base-controller": "8.0.1-preview-a0e6b482",
  "@metamask-previews/bridge-controller": "37.0.0-preview-a0e6b482",
  "@metamask-previews/bridge-status-controller": "37.0.0-preview-a0e6b482",
  "@metamask-previews/build-utils": "3.0.3-preview-a0e6b482",
  "@metamask-previews/chain-agnostic-permission": "1.0.0-preview-a0e6b482",
  "@metamask-previews/composable-controller": "11.0.0-preview-a0e6b482",
  "@metamask-previews/controller-utils": "11.11.0-preview-a0e6b482",
  "@metamask-previews/delegation-controller": "0.6.0-preview-a0e6b482",
  "@metamask-previews/earn-controller": "4.0.0-preview-a0e6b482",
  "@metamask-previews/eip1193-permission-middleware": "1.0.0-preview-a0e6b482",
  "@metamask-previews/ens-controller": "17.0.1-preview-a0e6b482",
  "@metamask-previews/error-reporting-service": "2.0.0-preview-a0e6b482",
  "@metamask-previews/eth-json-rpc-provider": "4.1.8-preview-a0e6b482",
  "@metamask-previews/foundryup": "1.0.0-preview-a0e6b482",
  "@metamask-previews/gas-fee-controller": "24.0.0-preview-a0e6b482",
  "@metamask-previews/json-rpc-engine": "10.0.3-preview-a0e6b482",
  "@metamask-previews/json-rpc-middleware-stream": "8.0.7-preview-a0e6b482",
  "@metamask-previews/keyring-controller": "22.1.0-preview-a0e6b482",
  "@metamask-previews/logging-controller": "6.0.4-preview-a0e6b482",
  "@metamask-previews/message-manager": "12.0.2-preview-a0e6b482",
  "@metamask-previews/messenger": "0.0.0-preview-a0e6b482",
  "@metamask-previews/multichain-account-service": "0.2.1-preview-a0e6b482",
  "@metamask-previews/multichain-api-middleware": "1.0.0-preview-a0e6b482",
  "@metamask-previews/multichain-network-controller": "0.11.0-preview-a0e6b482",
  "@metamask-previews/multichain-transactions-controller": "4.0.0-preview-a0e6b482",
  "@metamask-previews/name-controller": "8.0.3-preview-a0e6b482",
  "@metamask-previews/network-controller": "24.0.1-preview-a0e6b482",
  "@metamask-previews/notification-services-controller": "15.0.0-preview-a0e6b482",
  "@metamask-previews/permission-controller": "11.0.6-preview-a0e6b482",
  "@metamask-previews/permission-log-controller": "4.0.0-preview-a0e6b482",
  "@metamask-previews/phishing-controller": "13.1.0-preview-a0e6b482",
  "@metamask-previews/polling-controller": "14.0.0-preview-a0e6b482",
  "@metamask-previews/preferences-controller": "18.4.1-preview-a0e6b482",
  "@metamask-previews/profile-sync-controller": "22.0.0-preview-a0e6b482",
  "@metamask-previews/rate-limit-controller": "6.0.3-preview-a0e6b482",
  "@metamask-previews/remote-feature-flag-controller": "1.6.0-preview-a0e6b482",
  "@metamask-previews/sample-controllers": "1.0.0-preview-a0e6b482",
  "@metamask-previews/seedless-onboarding-controller": "2.4.0-preview-a0e6b482",
  "@metamask-previews/selected-network-controller": "23.0.0-preview-a0e6b482",
  "@metamask-previews/signature-controller": "32.0.0-preview-a0e6b482",
  "@metamask-previews/token-search-discovery-controller": "3.3.0-preview-a0e6b482",
  "@metamask-previews/transaction-controller": "59.0.0-preview-a0e6b482",
  "@metamask-previews/user-operation-controller": "38.0.0-preview-a0e6b482"
}

@@ -11,6 +11,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Added an optional parameter, `passwordOutdatedCacheTTL` to the constructor params and exported `SecretMetadata` class from the controller.([#6169](https://github.com/MetaMask/core/pull/6169))

### Changed

- Renamed public method `submitGlobalPassword` to `submitGlobalPasswordAndSync`. ([#6180](https://github.com/MetaMask/core/pull/6180))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Renamed public method `submitGlobalPassword` to `submitGlobalPasswordAndSync`. ([#6180](https://github.com/MetaMask/core/pull/6180))
- **Breaking** Renamed public method `submitGlobalPassword` to `submitGlobalPasswordAndSync`. ([#6180](https://github.com/MetaMask/core/pull/6180))


### Removed

- Removed `syncLatestGlobalPassword` from the Controller. ([#6180](https://github.com/MetaMask/core/pull/6180))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Removed `syncLatestGlobalPassword` from the Controller. ([#6180](https://github.com/MetaMask/core/pull/6180))
- **Breaking** Removed `syncLatestGlobalPassword` from the Controller. ([#6180](https://github.com/MetaMask/core/pull/6180))

const [vaultKey, keyringEncryptionKey] = await Promise.all([
this.#loadSeedlessEncryptionKey(currentDevicePwEncKey),
this.#loadKeyringEncryptionKey(currentDevicePwEncKey),
]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a relevant comment.
note that unlock now fails if the keyring encryption key is not set.

the controller is designed in a way that it works without having a keyring key stored. unlock should work without it.

we should change this function to only attempt loading the keyring encryption key if it is stored.

Comment on lines +757 to +760
const { revokeToken } = await this.#unlockVaultAndGetVaultData(
undefined,
vaultKey,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

note to myself: i should have written unlockVaultAndGetVaultData to accept an args object (args: {password?, encryptionKey?}) instead of (password, encryptionKey). calling it with (undefined, encryptionKey) just looks odd 🙈

});

// restore the current keyring encryption key with the new global password
await this.storeKeyringEncryptionKey(keyringEncryptionKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only do this if we were able to load the keyring encryption key.


// restore the current keyring encryption key with the new global password
await this.storeKeyringEncryptionKey(keyringEncryptionKey);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that's not true. the controller is written in a way that it works also if encryptedKeyringEncryptionKey is not present.

@himanshuchawla009 himanshuchawla009 marked this pull request as draft July 25, 2025 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants