@metamask/eth-ledger-bridge-keyring
Advanced tools
Comparing version 2.0.1 to 3.0.0
@@ -9,2 +9,16 @@ # Changelog | ||
## [3.0.0] | ||
### Added | ||
- Add `getOptions` and `setOptions` methods to `LedgerBridge` interface ([#210](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/210)) | ||
### Changed | ||
- **BREAKING**: `LedgerIframeBridge` class constructor now takes an options object with `bridgeUrl` ([#210](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/210)) | ||
- **BREAKING**: `LedgerBridge` `init` function now takes no parameters ([#210](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/210)) | ||
- **BREAKING**: `LedgerBridgeKeyringOptions` no longer contain `bridgeUrl` ([#210](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/210)) | ||
- **BREAKING**: `LedgerBridge` interface is now parameterized over its option type ([#210](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/210)) | ||
- Minor performance enhancement ([#211](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/211)) | ||
### Fixed | ||
- **BREAKING**: `IFrameMessageResponse` now has more restrictive typings (#207) ([#207](https://github.com/MetaMask/eth-ledger-bridge-keyring/pull/207)) | ||
## [2.0.1] | ||
@@ -89,3 +103,4 @@ ### Fixed | ||
[Unreleased]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v2.0.1...HEAD | ||
[Unreleased]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v3.0.0...HEAD | ||
[3.0.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v2.0.1...v3.0.0 | ||
[2.0.1]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v2.0.0...v2.0.1 | ||
@@ -92,0 +107,0 @@ [2.0.0]: https://github.com/MetaMask/eth-ledger-bridge-keyring/compare/v1.0.1...v2.0.0 |
@@ -24,6 +24,17 @@ import type LedgerHwAppEth from '@ledgerhq/hw-app-eth'; | ||
export declare type LedgerSignTypedDataResponse = Awaited<ReturnType<LedgerHwAppEth['signEIP712HashedMessage']>>; | ||
export interface LedgerBridge { | ||
export declare type LedgerBridgeOptions = Record<string, unknown>; | ||
export declare type LedgerBridge<T extends LedgerBridgeOptions> = { | ||
isDeviceConnected: boolean; | ||
init(bridgeUrl: string): Promise<void>; | ||
init(): Promise<void>; | ||
destroy(): Promise<void>; | ||
/** | ||
* Method to get the current configuration of the ledger bridge keyring. | ||
*/ | ||
getOptions(): Promise<T>; | ||
/** | ||
* Method to set the current configuration of the ledger bridge keyring. | ||
* | ||
* @param opts - An object contains configuration of the bridge. | ||
*/ | ||
setOptions(opts: T): Promise<void>; | ||
attemptMakeApp(): Promise<boolean>; | ||
@@ -35,2 +46,2 @@ updateTransportMethod(transportType: string): Promise<boolean>; | ||
deviceSignTypedData(params: LedgerSignTypedDataParams): Promise<LedgerSignTypedDataResponse>; | ||
} | ||
}; |
@@ -11,6 +11,15 @@ import { GetPublicKeyParams, GetPublicKeyResponse, LedgerBridge, LedgerSignMessageParams, LedgerSignMessageResponse, LedgerSignTransactionParams, LedgerSignTransactionResponse, LedgerSignTypedDataParams, LedgerSignTypedDataResponse } from './ledger-bridge'; | ||
} | ||
declare type IFrameMessageResponse<TAction extends IFrameMessageAction> = { | ||
action: TAction; | ||
declare type IFrameMessageResponseStub<SuccessResult extends Record<string, unknown>, FailureResult = Error> = { | ||
messageId: number; | ||
} & ({ | ||
success: true; | ||
payload: SuccessResult; | ||
} | { | ||
success: false; | ||
payload: { | ||
error: FailureResult; | ||
}; | ||
}); | ||
declare type LedgerConnectionChangeActionResponse = { | ||
messageId: number; | ||
action: IFrameMessageAction.LedgerConnectionChange; | ||
@@ -20,3 +29,5 @@ payload: { | ||
}; | ||
} | ({ | ||
}; | ||
declare type LedgerMakeAppActionResponse = { | ||
messageId: number; | ||
action: IFrameMessageAction.LedgerMakeApp; | ||
@@ -28,37 +39,25 @@ } & ({ | ||
error?: unknown; | ||
})) | { | ||
}); | ||
declare type LedgerUpdateTransportActionResponse = { | ||
messageId: number; | ||
action: IFrameMessageAction.LedgerUpdateTransport; | ||
success: boolean; | ||
} | ({ | ||
}; | ||
declare type LedgerUnlockActionResponse = { | ||
action: IFrameMessageAction.LedgerUnlock; | ||
} & ({ | ||
success: true; | ||
payload: GetPublicKeyResponse; | ||
} | { | ||
success: false; | ||
payload: { | ||
error: Error; | ||
}; | ||
})) | ({ | ||
} & IFrameMessageResponseStub<GetPublicKeyResponse>; | ||
declare type LedgerSignTransactionActionResponse = { | ||
action: IFrameMessageAction.LedgerSignTransaction; | ||
} & ({ | ||
success: true; | ||
payload: LedgerSignTransactionResponse; | ||
} | { | ||
success: false; | ||
payload: { | ||
error: Error; | ||
}; | ||
})) | ({ | ||
action: IFrameMessageAction.LedgerSignPersonalMessage | IFrameMessageAction.LedgerSignTypedData; | ||
} & ({ | ||
success: true; | ||
payload: LedgerSignMessageResponse | LedgerSignTypedDataResponse; | ||
} | { | ||
success: false; | ||
payload: { | ||
error: Error; | ||
}; | ||
}))); | ||
export declare class LedgerIframeBridge implements LedgerBridge { | ||
} & IFrameMessageResponseStub<LedgerSignTransactionResponse>; | ||
declare type LedgerSignPersonalMessageActionResponse = { | ||
action: IFrameMessageAction.LedgerSignPersonalMessage; | ||
} & IFrameMessageResponseStub<LedgerSignMessageResponse>; | ||
declare type LedgerSignTypedDataActionResponse = { | ||
action: IFrameMessageAction.LedgerSignTypedData; | ||
} & IFrameMessageResponseStub<LedgerSignTypedDataResponse>; | ||
export declare type IFrameMessageResponse = LedgerConnectionChangeActionResponse | LedgerMakeAppActionResponse | LedgerUpdateTransportActionResponse | LedgerUnlockActionResponse | LedgerSignTransactionActionResponse | LedgerSignPersonalMessageActionResponse | LedgerSignTypedDataActionResponse; | ||
export declare type LedgerIframeBridgeOptions = { | ||
bridgeUrl: string; | ||
}; | ||
export declare class LedgerIframeBridge implements LedgerBridge<LedgerIframeBridgeOptions> { | ||
#private; | ||
@@ -69,7 +68,7 @@ iframe?: HTMLIFrameElement; | ||
origin: string; | ||
data: IFrameMessageResponse<IFrameMessageAction>; | ||
data: IFrameMessageResponse; | ||
}) => void; | ||
isDeviceConnected: boolean; | ||
currentMessageId: number; | ||
messageCallbacks: Record<number, (response: IFrameMessageResponse<IFrameMessageAction>) => void>; | ||
messageCallbacks: Record<number, (response: IFrameMessageResponse) => void>; | ||
delayedPromise?: { | ||
@@ -80,4 +79,7 @@ resolve: (value: boolean) => void; | ||
}; | ||
init(bridgeUrl: string): Promise<void>; | ||
constructor(opts?: LedgerIframeBridgeOptions); | ||
init(): Promise<void>; | ||
destroy(): Promise<void>; | ||
getOptions(): Promise<LedgerIframeBridgeOptions>; | ||
setOptions(opts: LedgerIframeBridgeOptions): Promise<void>; | ||
attemptMakeApp(): Promise<boolean>; | ||
@@ -84,0 +86,0 @@ updateTransportMethod(transportType: string): Promise<boolean>; |
@@ -7,3 +7,9 @@ "use strict"; | ||
}; | ||
var _LedgerIframeBridge_instances, _LedgerIframeBridge_deviceActionMessage, _LedgerIframeBridge_setupIframe, _LedgerIframeBridge_getOrigin, _LedgerIframeBridge_eventListener, _LedgerIframeBridge_sendMessage; | ||
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_deviceActionMessage, _LedgerIframeBridge_setupIframe, _LedgerIframeBridge_getOrigin, _LedgerIframeBridge_eventListener, _LedgerIframeBridge_sendMessage, _LedgerIframeBridge_validateConfiguration; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -23,12 +29,19 @@ exports.LedgerIframeBridge = exports.IFrameMessageAction = void 0; | ||
class LedgerIframeBridge { | ||
constructor() { | ||
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; | ||
this.messageCallbacks = {}; | ||
__classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_validateConfiguration).call(this, opts); | ||
__classPrivateFieldSet(this, _LedgerIframeBridge_opts, { | ||
bridgeUrl: opts === null || opts === void 0 ? void 0 : opts.bridgeUrl, | ||
}, "f"); | ||
} | ||
async init(bridgeUrl) { | ||
__classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_setupIframe).call(this, bridgeUrl); | ||
this.eventListener = __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_eventListener).bind(this, bridgeUrl); | ||
async init() { | ||
__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); | ||
@@ -41,2 +54,14 @@ } | ||
} | ||
async getOptions() { | ||
return __classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f"); | ||
} | ||
async setOptions(opts) { | ||
var _a; | ||
__classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_validateConfiguration).call(this, opts); | ||
if (((_a = __classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f")) === null || _a === void 0 ? void 0 : _a.bridgeUrl) !== opts.bridgeUrl) { | ||
__classPrivateFieldGet(this, _LedgerIframeBridge_opts, "f").bridgeUrl = opts.bridgeUrl; | ||
await this.destroy(); | ||
await this.init(); | ||
} | ||
} | ||
async attemptMakeApp() { | ||
@@ -47,8 +72,11 @@ return new Promise((resolve, reject) => { | ||
}, (response) => { | ||
if (response.success) { | ||
if ('success' in response && response.success) { | ||
resolve(true); | ||
} | ||
else { | ||
else if ('error' in response) { | ||
reject(response.error); | ||
} | ||
else { | ||
reject(new Error('Unknown error occurred')); | ||
} | ||
}); | ||
@@ -72,4 +100,4 @@ }); | ||
params: { transportType }, | ||
}, ({ success }) => { | ||
if (success) { | ||
}, (response) => { | ||
if ('success' in response && response.success) { | ||
return resolve(true); | ||
@@ -95,3 +123,3 @@ } | ||
exports.LedgerIframeBridge = LedgerIframeBridge; | ||
_LedgerIframeBridge_instances = new WeakSet(), _LedgerIframeBridge_deviceActionMessage = async function _LedgerIframeBridge_deviceActionMessage(...[action, params]) { | ||
_LedgerIframeBridge_opts = new WeakMap(), _LedgerIframeBridge_instances = new WeakSet(), _LedgerIframeBridge_deviceActionMessage = async function _LedgerIframeBridge_deviceActionMessage(...[action, params]) { | ||
return new Promise((resolve, reject) => { | ||
@@ -101,7 +129,12 @@ __classPrivateFieldGet(this, _LedgerIframeBridge_instances, "m", _LedgerIframeBridge_sendMessage).call(this, { | ||
params, | ||
}, ({ success, payload }) => { | ||
if (success) { | ||
return resolve(payload); | ||
}, (response) => { | ||
if ('payload' in response && response.payload) { | ||
if ('success' in response && response.success) { | ||
return resolve(response.payload); | ||
} | ||
if ('error' in response.payload) { | ||
return reject(response.payload.error); | ||
} | ||
} | ||
return reject(payload.error); | ||
return reject(new Error('Unknown error occurred')); | ||
}); | ||
@@ -156,3 +189,7 @@ }); | ||
this.iframe.contentWindow.postMessage(postMsg, '*'); | ||
}, _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.js.map |
@@ -7,3 +7,3 @@ /// <reference types="node" /> | ||
import HDKey from 'hdkey'; | ||
import { LedgerBridge } from './ledger-bridge'; | ||
import { LedgerBridge, LedgerBridgeOptions } from './ledger-bridge'; | ||
declare enum NetworkApiUrls { | ||
@@ -25,3 +25,2 @@ Ropsten = "http://api-ropsten.etherscan.io", | ||
accountIndexes: Readonly<Record<string, number>>; | ||
bridgeUrl: string; | ||
implementFullBIP44: boolean; | ||
@@ -43,6 +42,5 @@ }; | ||
implementFullBIP44: boolean; | ||
bridgeUrl: string; | ||
bridge: LedgerBridge; | ||
bridge: LedgerBridge<LedgerBridgeOptions>; | ||
constructor({ bridge }: { | ||
bridge: LedgerBridge; | ||
bridge: LedgerBridge<LedgerBridgeOptions>; | ||
}); | ||
@@ -55,3 +53,2 @@ init(): Promise<void>; | ||
accountDetails: Record<string, AccountDetails>; | ||
bridgeUrl: string; | ||
implementFullBIP44: boolean; | ||
@@ -58,0 +55,0 @@ }>; |
@@ -48,3 +48,2 @@ "use strict"; | ||
const keyringType = 'Ledger Hardware'; | ||
const BRIDGE_URL = 'https://metamask.github.io/eth-ledger-bridge-keyring'; | ||
const MAX_INDEX = 1000; | ||
@@ -89,3 +88,2 @@ var NetworkApiUrls; | ||
this.implementFullBIP44 = false; | ||
this.bridgeUrl = BRIDGE_URL; | ||
if (!bridge) { | ||
@@ -97,3 +95,3 @@ throw new Error('Bridge is a required dependency for the keyring'); | ||
async init() { | ||
return this.bridge.init(this.bridgeUrl); | ||
return this.bridge.init(); | ||
} | ||
@@ -108,3 +106,2 @@ async destroy() { | ||
accountDetails: this.accountDetails, | ||
bridgeUrl: this.bridgeUrl, | ||
implementFullBIP44: false, | ||
@@ -114,13 +111,13 @@ }; | ||
async deserialize(opts = {}) { | ||
var _a, _b, _c, _d, _e; | ||
var _a, _b, _c, _d; | ||
this.hdPath = (_a = opts.hdPath) !== null && _a !== void 0 ? _a : hdPathString; | ||
this.bridgeUrl = (_b = opts.bridgeUrl) !== null && _b !== void 0 ? _b : BRIDGE_URL; | ||
this.accounts = (_c = opts.accounts) !== null && _c !== void 0 ? _c : []; | ||
this.accountDetails = (_d = opts.accountDetails) !== null && _d !== void 0 ? _d : {}; | ||
this.accounts = (_b = opts.accounts) !== null && _b !== void 0 ? _b : []; | ||
this.accountDetails = (_c = opts.accountDetails) !== null && _c !== void 0 ? _c : {}; | ||
if (!opts.accountDetails) { | ||
__classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_migrateAccountDetails).call(this, opts); | ||
} | ||
this.implementFullBIP44 = (_e = opts.implementFullBIP44) !== null && _e !== void 0 ? _e : false; | ||
this.implementFullBIP44 = (_d = opts.implementFullBIP44) !== null && _d !== void 0 ? _d : false; | ||
const keys = new Set(Object.keys(this.accountDetails)); | ||
// Remove accounts that don't have corresponding account details | ||
this.accounts = this.accounts.filter((account) => Object.keys(this.accountDetails).includes(ethUtil.toChecksumAddress(account))); | ||
this.accounts = this.accounts.filter((account) => keys.has(ethUtil.toChecksumAddress(account))); | ||
return Promise.resolve(); | ||
@@ -211,6 +208,7 @@ } | ||
removeAccount(address) { | ||
if (!this.accounts.map((a) => a.toLowerCase()).includes(address.toLowerCase())) { | ||
const filteredAccounts = this.accounts.filter((a) => a.toLowerCase() !== address.toLowerCase()); | ||
if (filteredAccounts.length === this.accounts.length) { | ||
throw new Error(`Address ${address} not found in this keyring`); | ||
} | ||
this.accounts = this.accounts.filter((a) => a.toLowerCase() !== address.toLowerCase()); | ||
this.accounts = filteredAccounts; | ||
delete this.accountDetails[ethUtil.toChecksumAddress(address)]; | ||
@@ -395,12 +393,14 @@ } | ||
} | ||
const keys = new Set(Object.keys(this.accountDetails)); | ||
// try to migrate non-LedgerLive accounts too | ||
if (!__classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_isLedgerLiveHdPath).call(this)) { | ||
this.accounts | ||
.filter((account) => !Object.keys(this.accountDetails).includes(ethUtil.toChecksumAddress(account))) | ||
.forEach((account) => { | ||
this.accounts.forEach((account) => { | ||
try { | ||
this.accountDetails[ethUtil.toChecksumAddress(account)] = { | ||
bip44: false, | ||
hdPath: __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_pathFromAddress).call(this, account), | ||
}; | ||
const key = ethUtil.toChecksumAddress(account); | ||
if (!keys.has(key)) { | ||
this.accountDetails[key] = { | ||
bip44: false, | ||
hdPath: __classPrivateFieldGet(this, _LedgerKeyring_instances, "m", _LedgerKeyring_pathFromAddress).call(this, account), | ||
}; | ||
} | ||
} | ||
@@ -407,0 +407,0 @@ catch (error) { |
{ | ||
"name": "@metamask/eth-ledger-bridge-keyring", | ||
"version": "2.0.1", | ||
"version": "3.0.0", | ||
"description": "A MetaMask compatible keyring, for ledger hardware wallets", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
114865
954