Skip to content
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
859f6f0
Send a message when disconncting
darkwing Dec 3, 2021
2b2a162
Temporarily remove cleanup calls from attemptMakeApp
darkwing Jan 20, 2022
6a5b97f
Switch to using a buffer
darkwing Jan 21, 2022
2c8b235
Check for device unlocked
darkwing Jan 21, 2022
4fa846e
Add address check to ensure device is unlocked
darkwing Jan 21, 2022
f8c0eed
Cleanup
darkwing Feb 8, 2022
3c4f0e2
Immediately check for collection
darkwing Feb 9, 2022
d5fb774
Restore cleanups from attemptMakeApp, move clearInterval out of cleanup
darkwing Feb 10, 2022
f9834d9
Don't trigger initial poll
darkwing Feb 11, 2022
01c1f4c
Again remove cleanup from makeAttemptApp
darkwing Feb 11, 2022
cbd0077
Remove debug
darkwing Mar 1, 2022
356e5d4
Remove code comment
darkwing Mar 2, 2022
e411cd6
Send an immediate connection event upon connection
darkwing Mar 3, 2022
be6c19d
Restore dynamic script injection
darkwing Mar 3, 2022
c1f58cc
Experiment with removing polling and checking upon transport creation
darkwing Mar 3, 2022
33a7d0d
Restore the cleanups to attemptMakeApp
darkwing Mar 3, 2022
742de94
Remove dynamic script injection
darkwing Mar 7, 2022
d0648c3
Temporarily hide transport check
darkwing Mar 29, 2022
bfe5188
Try connecting with getAddress attempt
darkwing Mar 29, 2022
25b09cb
Remove entire block
darkwing Mar 29, 2022
47bdc6f
Restore functionality
darkwing Mar 29, 2022
af2d214
Await cleanups
darkwing Mar 29, 2022
52662e0
Remove cleanup from unlock
darkwing Mar 29, 2022
e2c37ef
Remove app check
darkwing Mar 29, 2022
e378116
Remove if, throw
darkwing Mar 29, 2022
343cb0d
Don't send connection replies
darkwing Mar 29, 2022
376c15e
Restore connection messages
darkwing May 9, 2022
9e79046
Address feedback
darkwing May 12, 2022
ce80fc5
Try avoiding cleanup
darkwing May 12, 2022
d5ec804
Restore cleanup
darkwing May 12, 2022
b56410b
Restore prior nits
darkwing May 12, 2022
58ddedf
Skip the connectivity check for U2f/Firefox
darkwing May 13, 2022
62bae55
Reimplement polling for connected status
darkwing May 18, 2022
917aa33
Ensure interval is cleared when transport is cleared up
darkwing Jun 9, 2022
94dce64
Add start and stop methods for polling
darkwing Jun 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 60 additions & 7 deletions bundle.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
(function (Buffer){
'use strict';

Object.defineProperty(exports, "__esModule", {
Expand Down Expand Up @@ -141,8 +142,16 @@ var LedgerBridge = function () {
}, {
key: 'makeApp',
value: async function makeApp() {
var _this3 = this;

var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

// It's possible that a connection to the device could already exist
// at the time a user tries to sign; in that case, simply bail!
if (this.transport) {
return Promise.resolve(true);
}

try {
if (this.transportType === 'ledgerLive') {
var reestablish = false;
Expand Down Expand Up @@ -170,6 +179,36 @@ var LedgerBridge = function () {
this.transport = await _hwTransportU2f2.default.create();
this.app = new _hwAppEth2.default(this.transport);
}

// Ensure the correct (Ethereum) app is open; if not, immediately kill
// the connection as the wrong app is open and switching apps will call
// a disconnect from within the Ledger API
try {
var sampleSendResult = await this.transport.send(0xb0, 0x01, 0x00, 0x00);
var bufferResult = Buffer.from(sampleSendResult).toString();
// Ensures the correct app is open
if (bufferResult.includes('Ethereum')) {
// Ensure the device is unlocked by requesting an account
// An error of `6b0c` will throw if locked
var _ref = await this.app.getAddress('44\'/60\'/0\'/0', false, true),
address = _ref.address;

if (address) {
this.sendConnectionMessage(true);

this.transport.on('disconnect', function (event) {
_this3.onDisconnect();
});
} else {
this.onDisconnect();
}
}
} catch (e) {
console.log('LEDGER:::Transport check error', e);
this.sendConnectionMessage(false);
this.onDisconnect();
throw e;
}
} catch (e) {
console.log('LEDGER:::CREATE APP ERROR', e);
throw e;
Expand Down Expand Up @@ -224,7 +263,7 @@ var LedgerBridge = function () {
});
} finally {
if (this.transportType !== 'ledgerLive') {
this.cleanUp();
// await this.cleanUp()
}
}
}
Expand All @@ -250,7 +289,7 @@ var LedgerBridge = function () {
});
} finally {
if (this.transportType !== 'ledgerLive') {
this.cleanUp();
await this.cleanUp();
}
}
}
Expand All @@ -277,7 +316,7 @@ var LedgerBridge = function () {
});
} finally {
if (this.transportType !== 'ledgerLive') {
this.cleanUp();
await this.cleanUp();
}
}
}
Expand All @@ -303,9 +342,24 @@ var LedgerBridge = function () {
messageId: messageId
});
} finally {
this.cleanUp();
await this.cleanUp();
}
}
}, {
key: 'onDisconnect',
value: function onDisconnect() {
this.cleanUp();
this.sendConnectionMessage(false);
}
}, {
key: 'sendConnectionMessage',
value: function sendConnectionMessage(connected) {
this.sendMessageToExtension({
action: 'ledger-connection-change',
success: true,
payload: { connected: connected }
});
}
}, {
key: 'ledgerErrToMessage',
value: function ledgerErrToMessage(err) {
Expand Down Expand Up @@ -358,6 +412,7 @@ var LedgerBridge = function () {

exports.default = LedgerBridge;

}).call(this,require("buffer").Buffer)
},{"@ledgerhq/hw-app-eth":125,"@ledgerhq/hw-transport-http/lib/WebSocketTransport":161,"@ledgerhq/hw-transport-u2f":165,"@ledgerhq/hw-transport-webhid":166,"buffer":226}],2:[function(require,module,exports){
'use strict';

Expand All @@ -367,9 +422,7 @@ var _ledgerBridge2 = _interopRequireDefault(_ledgerBridge);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

(async function () {
var bridge = new _ledgerBridge2.default();
})();
new _ledgerBridge2.default();
console.log('MetaMask < = > Ledger Bridge initialized from ' + window.location + '!');

},{"./ledger-bridge":1}],3:[function(require,module,exports){
Expand Down
69 changes: 59 additions & 10 deletions ledger-bridge.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,15 @@ export default class LedgerBridge {

async attemptMakeApp (replyAction, messageId) {
try {
await this.makeApp({ openOnly: true });
await this.cleanUp();
await this.makeApp({ openOnly: true })
await this.cleanUp()
this.sendMessageToExtension({
action: replyAction,
success: true,
messageId,
})
} catch (error) {
await this.cleanUp();
await this.cleanUp()
this.sendMessageToExtension({
action: replyAction,
success: false,
Expand All @@ -99,15 +99,21 @@ export default class LedgerBridge {
}

async makeApp (config = {}) {
// It's possible that a connection to the device could already exist
// at the time a user tries to sign; in that case, simply bail!
if(this.transport) {
return Promise.resolve(true);
}

try {
if (this.transportType === 'ledgerLive') {
let reestablish = false;
let reestablish = false
try {
await WebSocketTransport.check(BRIDGE_URL)
} catch (_err) {
window.open('ledgerlive://bridge?appName=Ethereum')
await this.checkTransportLoop()
reestablish = true;
reestablish = true
}
if (!this.app || reestablish) {
this.transport = await WebSocketTransport.open(BRIDGE_URL)
Expand All @@ -118,7 +124,7 @@ export default class LedgerBridge {
const nameOfDeviceType = device && device.constructor.name
const deviceIsOpen = device && device.opened
if (this.app && nameOfDeviceType === 'HIDDevice' && deviceIsOpen) {
return;
return
}
this.transport = config.openOnly
? await TransportWebHID.openConnected()
Expand All @@ -128,6 +134,36 @@ export default class LedgerBridge {
this.transport = await TransportU2F.create()
this.app = new LedgerEth(this.transport)
}

// Ensure the correct (Ethereum) app is open; if not, immediately kill
// the connection as the wrong app is open and switching apps will call
// a disconnect from within the Ledger API
try {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This block needs to be skipped for Firefox because the U2F library throws on the await this.transport.send(0xb0, 0x01, 0x00, 0x00) line.

const sampleSendResult = await this.transport.send(0xb0, 0x01, 0x00, 0x00)
const bufferResult = Buffer.from(sampleSendResult).toString()
// Ensures the correct app is open
if(bufferResult.includes('Ethereum')) {
// Ensure the device is unlocked by requesting an account
// An error of `6b0c` will throw if locked
const { address } = await this.app.getAddress(`44'/60'/0'/0`, false, true)
if (address) {
this.sendConnectionMessage(true)

this.transport.on('disconnect', (event) => {
this.onDisconnect()
})
}
else {
this.onDisconnect()
}
}
}
catch(e) {
console.log('LEDGER:::Transport check error', e)
this.sendConnectionMessage(false)
Copy link

@digiwand digiwand May 12, 2022

Choose a reason for hiding this comment

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

this.onDisconnect() below also appears to call this.sendConnectionMessage(false). Maybe we don't need this line? Same comment applies to similar logic added in bundle.js

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch!

this.onDisconnect()
throw e
}
} catch (e) {
console.log('LEDGER:::CREATE APP ERROR', e)
throw e
Expand Down Expand Up @@ -179,7 +215,7 @@ export default class LedgerBridge {
})
} finally {
if (this.transportType !== 'ledgerLive') {
this.cleanUp()
// await this.cleanUp()
}
}
}
Expand All @@ -206,7 +242,7 @@ export default class LedgerBridge {

} finally {
if (this.transportType !== 'ledgerLive') {
this.cleanUp()
await this.cleanUp()
}
}
}
Expand All @@ -233,7 +269,7 @@ export default class LedgerBridge {

} finally {
if (this.transportType !== 'ledgerLive') {
this.cleanUp()
await this.cleanUp()
}
}
}
Expand All @@ -259,10 +295,23 @@ export default class LedgerBridge {
})

} finally {
this.cleanUp()
await this.cleanUp()
}
}

onDisconnect() {
this.cleanUp()
this.sendConnectionMessage(false)
}

sendConnectionMessage(connected) {
this.sendMessageToExtension({
action: 'ledger-connection-change',
success: true,
payload: { connected }
})
}

ledgerErrToMessage (err) {
const isU2FError = (err) => !!err && !!(err).metaData
const isStringError = (err) => typeof err === 'string'
Expand Down
4 changes: 1 addition & 3 deletions main.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
'use strict'
import LedgerBridge from './ledger-bridge'

(async () => {
const bridge = new LedgerBridge()
})()
new LedgerBridge()
console.log(`MetaMask < = > Ledger Bridge initialized from ${window.location}!`)