@metamask/eth-ledger-bridge-keyring
Version:
A MetaMask compatible keyring, for ledger hardware wallets
1 lines • 18.5 kB
Source Map (JSON)
{"version":3,"file":"ledger-iframe-bridge.cjs","sourceRoot":"","sources":["../src/ledger-iframe-bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import { createDeferredPromise, DeferredPromise } from '@metamask/utils';\n\nimport {\n AppConfigurationResponse,\n GetAppNameAndVersionResponse,\n GetPublicKeyParams,\n GetPublicKeyResponse,\n LedgerBridge,\n LedgerSignDelegationAuthorizationParams,\n LedgerSignDelegationAuthorizationResponse,\n LedgerSignMessageParams,\n LedgerSignMessageResponse,\n LedgerSignTransactionParams,\n LedgerSignTransactionResponse,\n LedgerSignTypedDataParams,\n LedgerSignTypedDataResponse,\n} from './ledger-bridge';\n\nconst LEDGER_IFRAME_ID = 'LEDGER-IFRAME';\n\nconst IFRAME_MESSAGE_TIMEOUT = 8000;\n\nexport enum IFrameMessageAction {\n LedgerIsIframeReady = 'ledger-is-iframe-ready',\n LedgerConnectionChange = 'ledger-connection-change',\n LedgerUnlock = 'ledger-unlock',\n LedgerMakeApp = 'ledger-make-app',\n LedgerUpdateTransport = 'ledger-update-transport',\n LedgerSignTransaction = 'ledger-sign-transaction',\n LedgerSignPersonalMessage = 'ledger-sign-personal-message',\n LedgerSignTypedData = 'ledger-sign-typed-data',\n LedgerGetAppNameAndVersion = 'ledger-get-app-name-and-version',\n LedgerGetAppConfiguration = 'ledger-get-app-configuration',\n}\n\ntype IFrameMessageResponseStub<\n SuccessResult extends Record<string, unknown>,\n FailureResult = Error,\n> = {\n messageId: number;\n} & (\n | { success: true; payload: SuccessResult }\n | { success: false; payload: { error: FailureResult } }\n);\n\ntype LedgerConnectionChangeActionResponse = {\n messageId: number;\n action: IFrameMessageAction.LedgerConnectionChange;\n payload: { connected: boolean };\n};\n\ntype LedgerMakeAppActionResponse = {\n messageId: number;\n action: IFrameMessageAction.LedgerMakeApp;\n} & ({ success: true } | { success: false; error?: unknown });\n\ntype LedgerUpdateTransportActionResponse = {\n messageId: number;\n action: IFrameMessageAction.LedgerUpdateTransport;\n success: boolean;\n};\n\ntype LedgerUnlockActionResponse = {\n action: IFrameMessageAction.LedgerUnlock;\n} & IFrameMessageResponseStub<GetPublicKeyResponse>;\n\ntype LedgerSignTransactionActionResponse = {\n action: IFrameMessageAction.LedgerSignTransaction;\n} & IFrameMessageResponseStub<LedgerSignTransactionResponse>;\n\ntype LedgerSignPersonalMessageActionResponse = {\n action: IFrameMessageAction.LedgerSignPersonalMessage;\n} & IFrameMessageResponseStub<LedgerSignMessageResponse>;\n\ntype LedgerSignTypedDataActionResponse = {\n action: IFrameMessageAction.LedgerSignTypedData;\n} & IFrameMessageResponseStub<LedgerSignTypedDataResponse>;\n\ntype LedgerGetAppNameAndVersionActionResponse = {\n action: IFrameMessageAction.LedgerGetAppNameAndVersion;\n} & IFrameMessageResponseStub<GetAppNameAndVersionResponse>;\n\ntype LedgerGetAppConfigurationActionResponse = {\n action: IFrameMessageAction.LedgerGetAppConfiguration;\n} & IFrameMessageResponseStub<AppConfigurationResponse>;\n\nexport type IFrameMessageResponse =\n | LedgerConnectionChangeActionResponse\n | LedgerMakeAppActionResponse\n | LedgerUpdateTransportActionResponse\n | LedgerUnlockActionResponse\n | LedgerSignTransactionActionResponse\n | LedgerSignPersonalMessageActionResponse\n | LedgerSignTypedDataActionResponse\n | LedgerGetAppNameAndVersionActionResponse\n | LedgerGetAppConfigurationActionResponse;\n\ntype IFrameMessage<TAction extends IFrameMessageAction> = {\n action: TAction;\n params?: Readonly<Record<string, unknown>>;\n};\n\ntype IFramePostMessage<TAction extends IFrameMessageAction> =\n IFrameMessage<TAction> & {\n messageId: number;\n target: typeof LEDGER_IFRAME_ID;\n };\n\nexport type LedgerIframeBridgeOptions = {\n bridgeUrl: string;\n};\n\nexport class LedgerIframeBridge implements LedgerBridge<LedgerIframeBridgeOptions> {\n iframe?: HTMLIFrameElement;\n\n iframeLoaded = false;\n\n readonly #opts: LedgerIframeBridgeOptions;\n\n eventListener?: (eventMessage: {\n origin: string;\n data: IFrameMessageResponse;\n }) => void;\n\n isDeviceConnected = false;\n\n currentMessageId = 0;\n\n readonly #messageResponseHandles: Map<\n number,\n DeferredPromise<IFrameMessageResponse>\n > = new Map();\n\n constructor(\n opts: LedgerIframeBridgeOptions = {\n bridgeUrl: 'https://metamask.github.io/eth-ledger-bridge-keyring',\n },\n ) {\n this.#validateConfiguration(opts);\n this.#opts = {\n bridgeUrl: opts?.bridgeUrl,\n };\n }\n\n async init(): Promise<void> {\n await this.#setupIframe(this.#opts.bridgeUrl);\n\n this.eventListener = this.#eventListener.bind(this, this.#opts.bridgeUrl);\n\n window.addEventListener('message', this.eventListener);\n }\n\n async destroy(): Promise<void> {\n if (this.eventListener) {\n window.removeEventListener('message', this.eventListener);\n }\n }\n\n async getOptions(): Promise<LedgerIframeBridgeOptions> {\n return this.#opts;\n }\n\n async setOptions(opts: LedgerIframeBridgeOptions): Promise<void> {\n this.#validateConfiguration(opts);\n if (this.#opts?.bridgeUrl !== opts.bridgeUrl) {\n this.#opts.bridgeUrl = opts.bridgeUrl;\n await this.destroy();\n await this.init();\n }\n }\n\n async attemptMakeApp(): Promise<boolean> {\n const response = await this.#sendMessage(\n {\n action: IFrameMessageAction.LedgerMakeApp,\n },\n { timeout: IFRAME_MESSAGE_TIMEOUT },\n );\n\n if ('success' in response && response.success) {\n return true;\n } else if ('error' in response) {\n // Assuming this is using an `Error` type:\n throw response.error;\n } else {\n throw new Error('Unknown error occurred');\n }\n }\n\n async updateTransportMethod(transportType: string): Promise<boolean> {\n if (!this.iframeLoaded) {\n throw new Error('The iframe is not loaded yet');\n }\n\n const response = await this.#sendMessage(\n {\n action: IFrameMessageAction.LedgerUpdateTransport,\n params: { transportType },\n },\n { timeout: IFRAME_MESSAGE_TIMEOUT },\n );\n\n if ('success' in response && response.success) {\n return true;\n }\n\n throw new Error('Ledger transport could not be updated');\n }\n\n async getPublicKey(\n params: GetPublicKeyParams,\n ): Promise<GetPublicKeyResponse> {\n return this.#deviceActionMessage(IFrameMessageAction.LedgerUnlock, params);\n }\n\n async deviceSignTransaction(\n params: LedgerSignTransactionParams,\n ): Promise<LedgerSignTransactionResponse> {\n return this.#deviceActionMessage(\n IFrameMessageAction.LedgerSignTransaction,\n params,\n );\n }\n\n async deviceSignMessage(\n params: LedgerSignMessageParams,\n ): Promise<LedgerSignMessageResponse> {\n return this.#deviceActionMessage(\n IFrameMessageAction.LedgerSignPersonalMessage,\n params,\n );\n }\n\n async deviceSignTypedData(\n params: LedgerSignTypedDataParams,\n ): Promise<LedgerSignTypedDataResponse> {\n return this.#deviceActionMessage(\n IFrameMessageAction.LedgerSignTypedData,\n params,\n );\n }\n\n async deviceSignDelegationAuthorization(\n _params: LedgerSignDelegationAuthorizationParams,\n ): Promise<LedgerSignDelegationAuthorizationResponse> {\n throw new Error(\n 'Ledger: signDelegationAuthorization is not supported via iframe bridge',\n );\n }\n\n async getAppNameAndVersion(): Promise<GetAppNameAndVersionResponse> {\n return this.#deviceActionMessage(\n IFrameMessageAction.LedgerGetAppNameAndVersion,\n {},\n );\n }\n\n async getAppConfiguration(): Promise<AppConfigurationResponse> {\n return this.#deviceActionMessage(\n IFrameMessageAction.LedgerGetAppConfiguration,\n {},\n );\n }\n\n async #deviceActionMessage(\n action: IFrameMessageAction.LedgerUnlock,\n params: GetPublicKeyParams,\n ): Promise<GetPublicKeyResponse>;\n\n async #deviceActionMessage(\n action: IFrameMessageAction.LedgerSignTransaction,\n params: LedgerSignTransactionParams,\n ): Promise<LedgerSignTransactionResponse>;\n\n async #deviceActionMessage(\n action: IFrameMessageAction.LedgerSignPersonalMessage,\n params: LedgerSignMessageParams,\n ): Promise<LedgerSignMessageResponse>;\n\n async #deviceActionMessage(\n action: IFrameMessageAction.LedgerSignTypedData,\n params: LedgerSignTypedDataParams,\n ): Promise<LedgerSignTypedDataResponse>;\n\n async #deviceActionMessage(\n action: IFrameMessageAction.LedgerGetAppNameAndVersion,\n params: Record<string, never>,\n ): Promise<GetAppNameAndVersionResponse>;\n\n async #deviceActionMessage(\n action: IFrameMessageAction.LedgerGetAppConfiguration,\n params: Record<string, never>,\n ): Promise<AppConfigurationResponse>;\n\n async #deviceActionMessage(\n ...[action, params]:\n | [IFrameMessageAction.LedgerUnlock, GetPublicKeyParams]\n | [IFrameMessageAction.LedgerSignTransaction, LedgerSignTransactionParams]\n | [IFrameMessageAction.LedgerSignPersonalMessage, LedgerSignMessageParams]\n | [IFrameMessageAction.LedgerSignTypedData, LedgerSignTypedDataParams]\n | [IFrameMessageAction.LedgerGetAppNameAndVersion, Record<string, never>]\n | [IFrameMessageAction.LedgerGetAppConfiguration, Record<string, never>]\n ): Promise<\n | GetPublicKeyResponse\n | LedgerSignTransactionResponse\n | LedgerSignMessageResponse\n | LedgerSignTypedDataResponse\n | GetAppNameAndVersionResponse\n | AppConfigurationResponse\n > {\n const response = await this.#sendMessage({ action, params });\n\n if ('payload' in response && response.payload) {\n if ('success' in response && response.success) {\n return response.payload;\n }\n if ('error' in response.payload) {\n throw response.payload.error;\n }\n }\n\n throw new Error('Unknown error occurred');\n }\n\n async #setupIframe(bridgeUrl: string): Promise<void> {\n return new Promise((resolve) => {\n this.iframe = document.createElement('iframe');\n this.iframe.src = bridgeUrl;\n this.iframe.allow = `hid 'src'`;\n this.iframe.onload = async (): Promise<void> => {\n this.iframeLoaded = true;\n resolve();\n };\n document.head.appendChild(this.iframe);\n });\n }\n\n #getOrigin(bridgeUrl: string): string {\n const tmp = bridgeUrl.split('/');\n tmp.splice(-1, 1);\n return tmp.join('/');\n }\n\n #eventListener(\n bridgeUrl: string,\n eventMessage: {\n origin: string;\n data: IFrameMessageResponse;\n },\n ): void {\n const { origin, data } = eventMessage;\n\n if (origin !== this.#getOrigin(bridgeUrl)) {\n return;\n }\n\n if (data) {\n const messageResponseHandle = this.#messageResponseHandles.get(\n data.messageId,\n );\n if (messageResponseHandle) {\n messageResponseHandle.resolve(data);\n this.#messageResponseHandles.delete(data.messageId);\n } else if (data.action === IFrameMessageAction.LedgerConnectionChange) {\n this.isDeviceConnected = data.payload.connected;\n }\n }\n }\n\n async #sendMessage<TAction extends IFrameMessageAction>(\n message: IFrameMessage<TAction>,\n { timeout }: { timeout?: number } = {},\n ): Promise<IFrameMessageResponse> {\n this.currentMessageId += 1;\n\n const postMsg: IFramePostMessage<TAction> = {\n ...message,\n messageId: this.currentMessageId,\n target: LEDGER_IFRAME_ID,\n };\n\n const messageResponseHandle =\n createDeferredPromise<IFrameMessageResponse>();\n\n this.#messageResponseHandles.set(\n this.currentMessageId,\n messageResponseHandle,\n );\n\n if (!this.iframeLoaded || !this.iframe?.contentWindow) {\n throw new Error('The iframe is not loaded yet');\n }\n\n if (timeout) {\n setTimeout(() => {\n if (this.#messageResponseHandles.has(postMsg.messageId)) {\n this.#messageResponseHandles.delete(postMsg.messageId);\n messageResponseHandle.reject(\n new Error('Ledger iframe message timeout'),\n );\n }\n }, timeout);\n }\n\n this.iframe.contentWindow.postMessage(postMsg, '*');\n\n return messageResponseHandle.promise;\n }\n\n #validateConfiguration(opts: LedgerIframeBridgeOptions): void {\n if (typeof opts.bridgeUrl !== 'string' || opts.bridgeUrl.length === 0) {\n throw new Error('bridgeURL is not a valid URL');\n }\n }\n}\n"]}