-
-
Notifications
You must be signed in to change notification settings - Fork 277
feat(keyring-controller): add keyring.fingerprint support
#8341
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -309,6 +309,11 @@ export type KeyringMetadata = { | |
| * Keyring name | ||
| */ | ||
| name: string; | ||
| /** | ||
| * Keyring fingerprint, computed by the builder's `getFingerprint` function. | ||
| * Absent if the builder does not provide `getFingerprint`. | ||
| */ | ||
| fingerprint?: string; | ||
| }; | ||
|
|
||
| /** | ||
|
|
@@ -513,6 +518,9 @@ export type KeyringSelector = | |
| } | ||
| | { | ||
| id: string; | ||
| } | ||
| | { | ||
| fingerprint: string; | ||
| }; | ||
|
|
||
| /** | ||
|
|
@@ -521,6 +529,14 @@ export type KeyringSelector = | |
| export type KeyringBuilder = { | ||
| (): Keyring; | ||
| type: string; | ||
| /** | ||
| * Compute a deterministic fingerprint for a keyring instance. | ||
| * Called after the keyring is fully initialized (post `deserialize` and `init`). | ||
| * | ||
| * @param keyring - The initialized keyring instance. | ||
| * @returns An opaque string that uniquely identifies this keyring. | ||
| */ | ||
| getFingerprint?: (keyring: Keyring) => string; | ||
| }; | ||
|
|
||
| /** | ||
|
|
@@ -1778,6 +1794,10 @@ export class KeyringController< | |
| } | ||
| } else if ('id' in selector) { | ||
| keyring = this.#getKeyringById(selector.id) as SelectedKeyring; | ||
| } else if ('fingerprint' in selector) { | ||
| keyring = this.#getKeyringByFingerprint( | ||
| selector.fingerprint, | ||
| ) as SelectedKeyring; | ||
| } | ||
|
|
||
| if (!keyring) { | ||
|
|
@@ -1924,6 +1944,36 @@ export class KeyringController< | |
| ?.keyring; | ||
| } | ||
|
|
||
| #getKeyringByFingerprint(fingerprint: string): EthKeyring | undefined { | ||
| return this.#keyrings.find( | ||
| ({ metadata }) => metadata.fingerprint === fingerprint, | ||
| )?.keyring; | ||
| } | ||
|
|
||
| /** | ||
| * Safely compute the fingerprint for a keyring using the given builder. | ||
| * Returns `undefined` if the builder has no `getFingerprint`, or if | ||
| * `getFingerprint` throws — in which case the error is logged. | ||
| * | ||
| * @param builder - The keyring builder, or undefined if none is registered. | ||
| * @param keyring - The initialized keyring instance. | ||
| * @returns The fingerprint string, or `undefined`. | ||
| */ | ||
| #getSafeFingerprint( | ||
| builder: KeyringBuilder | undefined, | ||
| keyring: EthKeyring, | ||
| ): string | undefined { | ||
| if (!builder?.getFingerprint) { | ||
| return undefined; | ||
| } | ||
| try { | ||
| return builder.getFingerprint(keyring); | ||
| } catch (error) { | ||
| console.error('Unable to compute fingerprint (skipping):', error); | ||
| return undefined; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Get the keyring by id or return the first keyring if the id is not found. | ||
| * | ||
|
|
@@ -1962,9 +2012,7 @@ export class KeyringController< | |
| * @param type - The type of keyring to get the builder for. | ||
| * @returns The keyring builder, or undefined if none exists. | ||
| */ | ||
| #getKeyringBuilderForType( | ||
| type: string, | ||
| ): { (): EthKeyring; type: string } | undefined { | ||
| #getKeyringBuilderForType(type: string): KeyringBuilder | undefined { | ||
| return this.#keyringBuilders.find( | ||
| (keyringBuilder) => keyringBuilder.type === type, | ||
| ); | ||
|
|
@@ -2451,8 +2499,13 @@ export class KeyringController< | |
| */ | ||
| async #newKeyring(type: string, data?: unknown): Promise<EthKeyring> { | ||
| const keyring = await this.#createKeyring(type, data); | ||
|
|
||
| this.#keyrings.push({ keyring, metadata: getDefaultKeyringMetadata() }); | ||
| const metadata = getDefaultKeyringMetadata(); | ||
| const builder = this.#getKeyringBuilderForType(type); | ||
| const fingerprint = this.#getSafeFingerprint(builder, keyring); | ||
| if (fingerprint !== undefined) { | ||
| metadata.fingerprint = fingerprint; | ||
| } | ||
| this.#keyrings.push({ keyring, metadata }); | ||
|
|
||
| return keyring; | ||
| } | ||
|
|
@@ -2555,6 +2608,14 @@ export class KeyringController< | |
| newMetadata = true; | ||
| metadata = getDefaultKeyringMetadata(); | ||
| } | ||
| // We recompute the fingerprint for the keyring. This way, if an existing | ||
| // keyring now supports fingerprinting, we can still get the fingerprint | ||
| // for keyrings that were created before fingerprinting was supported. | ||
| const builder = this.#getKeyringBuilderForType(type); | ||
| const fingerprint = this.#getSafeFingerprint(builder, keyring); | ||
| if (fingerprint !== undefined) { | ||
| metadata = { ...metadata, fingerprint }; | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Stale fingerprint not cleared during keyring restoreLow Severity In |
||
| // The keyring is added to the keyrings array only if it's successfully restored | ||
| // and the metadata is successfully added to the controller | ||
| this.#keyrings.push({ | ||
|
|
||


Uh oh!
There was an error while loading. Please reload this page.