@metamask/eth-ledger-bridge-keyring
Version:
A MetaMask compatible keyring, for ledger hardware wallets
183 lines • 10.6 kB
JavaScript
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var _LedgerIframeBridge_instances, _LedgerIframeBridge_opts, _LedgerIframeBridge_messageResponseHandles, _LedgerIframeBridge_deviceActionMessage, _LedgerIframeBridge_setupIframe, _LedgerIframeBridge_getOrigin, _LedgerIframeBridge_eventListener, _LedgerIframeBridge_sendMessage, _LedgerIframeBridge_validateConfiguration;
import { createDeferredPromise } from "@metamask/utils";
const LEDGER_IFRAME_ID = 'LEDGER-IFRAME';
const IFRAME_MESSAGE_TIMEOUT = 8000;
export var IFrameMessageAction;
(function (IFrameMessageAction) {
IFrameMessageAction["LedgerIsIframeReady"] = "ledger-is-iframe-ready";
IFrameMessageAction["LedgerConnectionChange"] = "ledger-connection-change";
IFrameMessageAction["LedgerUnlock"] = "ledger-unlock";
IFrameMessageAction["LedgerMakeApp"] = "ledger-make-app";
IFrameMessageAction["LedgerUpdateTransport"] = "ledger-update-transport";
IFrameMessageAction["LedgerSignTransaction"] = "ledger-sign-transaction";
IFrameMessageAction["LedgerSignPersonalMessage"] = "ledger-sign-personal-message";
IFrameMessageAction["LedgerSignTypedData"] = "ledger-sign-typed-data";
IFrameMessageAction["LedgerGetAppNameAndVersion"] = "ledger-get-app-name-and-version";
IFrameMessageAction["LedgerGetAppConfiguration"] = "ledger-get-app-configuration";
})(IFrameMessageAction || (IFrameMessageAction = {}));
export class LedgerIframeBridge {
constructor(opts = {
bridgeUrl: 'https://metamask.github.io/eth-ledger-bridge-keyring',
}) {
_LedgerIframeBridge_instances.add(this);
this.iframeLoaded = false;
_LedgerIframeBridge_opts.set(this, void 0);
this.isDeviceConnected = false;
this.currentMessageId = 0;
_LedgerIframeBridge_messageResponseHandles.set(this, new Map());
__classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_validateConfiguration).call(this, opts);
__classPrivateFieldSet(this, _LedgerIframeBridge_opts, {
bridgeUrl: opts?.bridgeUrl,
}, "f");
}
async init() {
await __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_setupIframe).call(this, __classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f").bridgeUrl);
this.eventListener = __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_eventListener).bind(this, __classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f").bridgeUrl);
window.addEventListener('message', this.eventListener);
}
async destroy() {
if (this.eventListener) {
window.removeEventListener('message', this.eventListener);
}
}
async getOptions() {
return __classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f");
}
async setOptions(opts) {
__classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_validateConfiguration).call(this, opts);
if (__classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f")?.bridgeUrl !== opts.bridgeUrl) {
__classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f").bridgeUrl = opts.bridgeUrl;
await this.destroy();
await this.init();
}
}
async attemptMakeApp() {
const response = await __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_sendMessage).call(this, {
action: IFrameMessageAction.LedgerMakeApp,
}, { timeout: IFRAME_MESSAGE_TIMEOUT });
if ('success' in response && response.success) {
return true;
}
else if ('error' in response) {
// Assuming this is using an `Error` type:
throw response.error;
}
else {
throw new Error('Unknown error occurred');
}
}
async updateTransportMethod(transportType) {
if (!this.iframeLoaded) {
throw new Error('The iframe is not loaded yet');
}
const response = await __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_sendMessage).call(this, {
action: IFrameMessageAction.LedgerUpdateTransport,
params: { transportType },
}, { timeout: IFRAME_MESSAGE_TIMEOUT });
if ('success' in response && response.success) {
return true;
}
throw new Error('Ledger transport could not be updated');
}
async getPublicKey(params) {
return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerUnlock, params);
}
async deviceSignTransaction(params) {
return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerSignTransaction, params);
}
async deviceSignMessage(params) {
return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerSignPersonalMessage, params);
}
async deviceSignTypedData(params) {
return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerSignTypedData, params);
}
async deviceSignDelegationAuthorization(_params) {
throw new Error('Ledger: signDelegationAuthorization is not supported via iframe bridge');
}
async getAppNameAndVersion() {
return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerGetAppNameAndVersion, {});
}
async getAppConfiguration() {
return __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_deviceActionMessage).call(this, IFrameMessageAction.LedgerGetAppConfiguration, {});
}
}
_LedgerIframeBridge_opts = new WeakMap(), _LedgerIframeBridge_messageResponseHandles = new WeakMap(), _LedgerIframeBridge_instances = new WeakSet(), _LedgerIframeBridge_deviceActionMessage = async function _LedgerIframeBridge_deviceActionMessage(...[action, params]) {
const response = await __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_sendMessage).call(this, { action, params });
if ('payload' in response && response.payload) {
if ('success' in response && response.success) {
return response.payload;
}
if ('error' in response.payload) {
throw response.payload.error;
}
}
throw new Error('Unknown error occurred');
}, _LedgerIframeBridge_setupIframe = async function _LedgerIframeBridge_setupIframe(bridgeUrl) {
return new Promise((resolve) => {
this.iframe = document.createElement('iframe');
this.iframe.src = bridgeUrl;
this.iframe.allow = `hid 'src'`;
this.iframe.onload = async () => {
this.iframeLoaded = true;
resolve();
};
document.head.appendChild(this.iframe);
});
}, _LedgerIframeBridge_getOrigin = function _LedgerIframeBridge_getOrigin(bridgeUrl) {
const tmp = bridgeUrl.split('/');
tmp.splice(-1, 1);
return tmp.join('/');
}, _LedgerIframeBridge_eventListener = function _LedgerIframeBridge_eventListener(bridgeUrl, eventMessage) {
const { origin, data } = eventMessage;
if (origin !== __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_getOrigin).call(this, bridgeUrl)) {
return;
}
if (data) {
const messageResponseHandle = __classPrivateFieldGet(this, _LedgerIframeBridge_messageResponseHandles, "f").get(data.messageId);
if (messageResponseHandle) {
messageResponseHandle.resolve(data);
__classPrivateFieldGet(this, _LedgerIframeBridge_messageResponseHandles, "f").delete(data.messageId);
}
else if (data.action === IFrameMessageAction.LedgerConnectionChange) {
this.isDeviceConnected = data.payload.connected;
}
}
}, _LedgerIframeBridge_sendMessage = async function _LedgerIframeBridge_sendMessage(message, { timeout } = {}) {
this.currentMessageId += 1;
const postMsg = {
...message,
messageId: this.currentMessageId,
target: LEDGER_IFRAME_ID,
};
const messageResponseHandle = createDeferredPromise();
__classPrivateFieldGet(this, _LedgerIframeBridge_messageResponseHandles, "f").set(this.currentMessageId, messageResponseHandle);
if (!this.iframeLoaded || !this.iframe?.contentWindow) {
throw new Error('The iframe is not loaded yet');
}
if (timeout) {
setTimeout(() => {
if (__classPrivateFieldGet(this, _LedgerIframeBridge_messageResponseHandles, "f").has(postMsg.messageId)) {
__classPrivateFieldGet(this, _LedgerIframeBridge_messageResponseHandles, "f").delete(postMsg.messageId);
messageResponseHandle.reject(new Error('Ledger iframe message timeout'));
}
}, timeout);
}
this.iframe.contentWindow.postMessage(postMsg, '*');
return messageResponseHandle.promise;
}, _LedgerIframeBridge_validateConfiguration = function _LedgerIframeBridge_validateConfiguration(opts) {
if (typeof opts.bridgeUrl !== 'string' || opts.bridgeUrl.length === 0) {
throw new Error('bridgeURL is not a valid URL');
}
};
//# sourceMappingURL=ledger-iframe-bridge.mjs.map