Skip to content
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

Electron Ledger + Trezor Support #1836

Merged
merged 48 commits into from
Jun 15, 2018
Merged

Electron Ledger + Trezor Support #1836

merged 48 commits into from
Jun 15, 2018

Conversation

wbobeirne
Copy link
Contributor

@wbobeirne wbobeirne commented May 23, 2018

Closes #1621, closes #1616.

Description

This PR is the first of a few to add hardware wallet support to Electron with a new library dubbed Enclave (props to @HenryNguyen5 for the name.) You can read more about its specific approach here: https://github.com/MyCryptoHQ/MyCrypto/blob/enclave-willo-protocol/shared/enclave/README.md. While it's being developed, I'd like to keep it in the MyCrypto repo. But once we're in a steady place with it, I think it could easily be its own module.

Likewise, I think it's still a little rough around the edges. There's maybe too much boilerplate both on the server and client side and the types could probably be better, I'm definitely expecting some feedback and changes on the pr. There's also huge amount of repeated code between common/libs/wallets and enclave/server/wallets. We could potentially expand Enclave to handle web wallets as well, and just have a single API for interacting with wallets, regardless of platform.

I also adjusted the Ledger unlock screen with persistent information (screenshot below.)

Changes

  • Made Enclave lib with Ledger support, Trezor & KeepKey stubs
  • Changed Ledger libs over to their @ledgerhq/* packages
  • Changed our Ledger and Trezor libraries to defer to EnclaveAPI in Electron
  • Change Ledger tip to display persistently and have messaging about browser support and which Ledger app to open

Steps to Test

  1. Unlock ledger on web
  2. Display address on device with ledger on the web
  3. Send a transaction with ledger on web
  4. Sign a message with ledger on the web
  5. Do all of the above in Electron

Screenshots

screen shot 2018-05-23 at 5 12 40 pm

try {
// TODO: Validate params based on provided method
const params = JSON.parse(data.bytes.toString());
return params as EnclaveMethodParams;

Choose a reason for hiding this comment

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

Should turn this into a validation function that performs the job of a user defined type guard instead of casting it

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure what that would look like, can you describe it a bit more?

const params = JSON.parse(data.bytes.toString());
return params as EnclaveMethodParams;
} catch (err) {
throw new Error(`Invalid JSON blob provided for '${method}'`);

Choose a reason for hiding this comment

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

Should we include the actual error in here too?

@@ -0,0 +1,21 @@
import { WalletLib } from 'shared/enclave/types';

const KeepKey: WalletLib = {

Choose a reason for hiding this comment

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

Instead of the repetition of implementing a wallet lib here, we should make a base class that has all of the methods throw the unimplemented error

Choose a reason for hiding this comment

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

Also we could have a util function that can be used to wrap each method in a try/catch with a supplied error message if it matches some conditional, otherwise throws the original error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I initially decided against classes in favor of singletons since there aren't multiple instances of any of these, they're moreso handlers than instances. However I could still make them classes and just export an instance of them, so I guess that makes more sense.

The util function makes sense though, I'll try to work that out.

import { WalletLib } from 'shared/enclave/types';
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
import LedgerEth from '@ledgerhq/hw-app-eth';
let transport: any;

Choose a reason for hiding this comment

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

Prefer to have this typed

} catch (err) {
if (err && err.message && err.message.includes('cannot open device with path')) {
throw new Error(
'Your Ledger is currently in use with another application. Please wait, or close other wallet applications before trying again.'

Choose a reason for hiding this comment

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

Should have this i18n'd i think since its a user error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Absolutely, though I have no way of getting at redux state in here. Probably what I should do is replace all of these human readable errors with ERROR_CODES to be translate'd on the frontend.

Choose a reason for hiding this comment

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

That sounds like a good idea

chainCode: res.chainCode as string
};
} catch (err) {
throw new Error('Failed to connect to Ledger');

Choose a reason for hiding this comment

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

I feel like we should include the err message here for diagnostics

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No way to do that & do i18n at the same time, so I'm going to settle for a console.error. In general we'll probably need to come up with a way to get console logs from users if they experience issues electron-side.

const showErr = error ? 'is-showing' : '';

if (!dPath) {
return <UnsupportedNetwork walletType={translateRaw('x_Ledger')} />;
}

if (window.location.protocol !== 'https:') {
if (!process.env.BUILD_ELECTRON && window.location.protocol !== 'https:') {

Choose a reason for hiding this comment

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

We use this env variable everywhere in the codebase, perhaps use another level of indirection by hiding it behind a function like isElectron so we can change it if need be in the future? We could do this for any other environment variables too.

@HenryNguyen5
Copy link

I think that the easiest way to remedy the code duplication is to have each duplicated method its own function, then use that function where it used to be duplicated.

@dternyak dternyak changed the title Electron Ledger Support Electron Ledger + Trezor Support Jun 15, 2018
@dternyak dternyak merged commit cb92f59 into develop Jun 15, 2018
dternyak pushed a commit that referenced this pull request Jun 18, 2018
* Add a new route for AddressBook

* Further templating of the AddressBook view

* Add initial functionality to handle a table of existing address labels

* Make the linter happy

* Adjust paths

* Factor out TableRow and add common functionality

* Add initial Redux boilerplate for addressBook | fix minor linting issues

* Swap out terminology and types

* Connect up to Redux

* Connect data for AddressBookTable to Redux

* Use temporary fields for addition

* Remove alignment and index column

* Stopping point

* Adjust the sizing of rows to be consistent

* Initial implementation of a dropdown for the address field

* Minor styling to dropdown

* Stopping point

* Apply a focus concept onto the factory

* Add keyboard controls for the address field dropdown

* Adjust label of address field when it matches an addressBook entry

* Properly handle attempting to blur a non-existent component

* Minor styling changes on dropdown box

* Standardize address casing, add accessibility to dropdown

* Create an addressLabel component

* Pass refs correctly and fix some typings

* Exact version

* Add module name mapping for shared/keycodes

* addressBook reducer tests

* Add functionality to DeterministicModal

* Minor changes / Add test for addressBook selectors

* Move out AddressBookTable to a component

* Typing, translation and restructuring

* More typing and translation fixes

* More linting fixes

* More type changes

* Variable name for dropdown background

* Fix TS type errors, lint errors, remove unused props

* Used a different selector and removed method: AddressBookTable

* Linter was mad

* Linter mad again :(

* Add a translation and adjust styling of AddressBookTable

* Move the onBlur to a class method

* Prevent the default behavior of up/down/enter for dropdown

* Let's do it this way instead

* Adjust the styling on DeterministicWalletModal labels

* Change `AddressBookTable` into a pseudo-table using section and div

* Use readable keys vs. keycodes

* Put the dropdown in InputFactory and position it correctly

* Sanitation of label adding and changing

* Prevent duplicate labels in AddressBook and Row

* Add a box shadow and use `invalid` class insted of custom

* Use emphasis vs strong for address in dropdown

* Display the label undernearth the input vs. changing it

* Isolate AccountAddress into its own component

* Introduce interactivity to AccountAddress

* Fully incorporate with Redux

* Validation for AccountAddress

* Add validation notifications for address field on AddressBookTable

* Minor formatting

* Adjust wrappage for optimal flexboxxing

* Make AddressBookTable responsive

* Show an invalid input in "real time" instead of only on submit

* Real time input validation for AddressBookTableRow

* Responsive-ize the To address dropdown

* Hide identicons instead at small enough screen sizes

* Fix repsonsiveness of dropdown further

* Fix responsiveness of table rows and inputs

* Truncate account info and switch identicons to the right for consistency

* Use classnames instead of targetting element directly for DWM

* Display a notice if the entered query doesnt match a label and isnt an addr

* Don't show an error on the To address if its a label entry

* Display an error under AddressBookTableRow in real time

* Display errors in real time for AddressBookTable temp inputs

* Add realtime validation to AccountAddress

* Ensure toChecksumAddress is used when entering labels to address manager

* Show errors even after blurring.

* Create a ducks/ implementation for addressBook

* Duck-ize notifications

* Duck-ize customTokens

* Duck-ize deterministicWallets

* Only show errors on address/label entry if they have been blurred

* On certain inputs, show an invalid input immediately

* spec files in same directory

* Rename top-level redux directory

* Duck-ize gas

* Add displayed errors for labels with 0x and labels containing ens

* Move ENS checking validation out

* Add a saga for addLabelForAddress

* Completely revamp the redux side of Address Manager and test it all

* Adjust components to use new redux addressBook

* Incorporate new redux into AddressBookTableRow and clean up for linter

* Make linter and tests happy

* Another reduxy overhaul

* Still fixing it

* More redux updates

* Finalize redux stuff.

* Incorporate new reduxy way into AddressBookTable & Row

* Incorporate redux changes into Account Address

* Small tests fix

* Add and fix some selector tests

* Addressing Will's comments

* Shortened visibility class for line length reasons.

* Incorporate ducks pattern on updates addressBook

* Fix typeerror

* Migrate messages to ducks

* For Henry

* Duckify onboardStatus

* Duckify paritySigner

* Duckify rates

* Duckify transactions

* Duckerize wallet

* Reduckerate config

* Adjust exports and tests of every duck so far

* Duckify ENS

* Duckerificate schedule

* Duckificate swap

* Actually use the new sagas;  fix a circular dependency problem.

* Duckify transaction (phew)

* Add basics to redux/ directory

* Remove non-ducked redux stuff

* First sweep of redux/ directory

* Combine redundant imports

* Fix more linting stuff.

* A few more type fixes

* Welp... now I know not to use index.

* Sweep components/

* Sweep through containers/

* Im really starting to get frustrated

* The dawn of a new age.

* Linter fixes.

* De-flatten config/ reducers

* Do my thang on config selectors

* Adjust all references to config

* Split up ens reducers

* Wrap up de-nesting ENS

* Big boy refactor

* Split transaction into its reducers

* Fix reducers in transaction/

* Stopping point

* Adjust references to transaction from components

* Fix references to selectors

* Nest broadcast actions

* Nest field actions

* Nest meta actions

* Nest network actions

* Nest sign actions

* Nest broadcast types

* Nested fields types

* Nest meta types

* Nested network types

* Nested sign types

* Implement transaction saga changes

* Huh? No prepush problems?

* Update snappshot

* Reintroduce deleted tests

* A few missing tests found

* Found three missing transaction tests

* Found more tests

* Found the rest of the tests, woohoo.

* Renamed TypeKeys in TRANSACTION

* Specify TRANSACTION_BROADCAST

* Pretty up these imports

* Specify TRANSACTION_FIELDS

* Specify TRANSACTION_META

* Specify TRANSACTION_NETWORK

* Specify TRANSACTION_SIGN

* Adjust imports and add translations

* Update config snapshot

* Post-merge

* Temporary fix for DW/Config sagas so Daniel can continue smoke testing

* Remove first circulat dependency

* Fix more circular dependencies

* Properly structure config indices

* Further restructure config

* Prepare for idea

* Target directly from within features/

* Remove that circular dependency -- woohoo

* Remove the circular dependency from Web3Wallet, temporarily comment some tests pending assistance

* Un-comment the component-in-redux phenomenon

* Move onLoad to the store file

* Adjust addressBook imports/exports

* Adjusted imports/exports for customTokens

* Adjust imports/exports of deterministicWallets

* Adjust imports/exports of ens

* Restructure imports/exports of gas

* Restructure imports/exports for message

* Adjust imports/exports of notifications

* Restructure onboardStatus imports/exports

* Restructure paritySigner imports/exports

* Restructure rates imports/exports

* Restructure schedule imports/exports

* Fix broadcastweb3handler test

* Restructure swap imports/exports/

* Restructure transactionS imports/exports

* Restructured wallet imports and exports

* Hoist all necessary selectors aside from config/**/* and transaction/**/*

* Hoist all top-level selectors from transaction

* [Fix] Estimate Gas on Value Field Change (#1942) @ skubakdj

* Implement right-click context menu (#1780) @ bryanwb

* No Private Keys Online (#1466) @ wbobeirne

* Fix Stuck Node on Metamask Logout (#1951) @ wbobeirne

* [Fix] Make ENS Value Consistent (#1956) @ skubakdj

* Auto token add (#1808) @ HenryNguyen5

* Electron Ledger + Trezor Support (#1836) @ wbobeirne

* Fix Context Menu Popup Parameters (#1957)

* Add RSK network w/ network agnostic refactors (#1939) @ wbobeirne

* Change displayed notification back in helpers.tsx

* Remove newline on shell files

* Re-add newlines

* Remove newling on .travis.yml

* Prettier two files

* Re-add index.scss import in OnboardModal

* Restructure transaction subdirectories

* Everything in transaction/ except for sagas

* Restructure transaction imports/exports

* Nest broadcast sagas

* Nest fields

* Nest meta

* Nest network

* Nest sign

* Use generic names for reduxy stuff in the same directory to save space

* Do everything every in the whole wide world
@dternyak dternyak deleted the enclave-willo-protocol branch June 19, 2018 18:32
@dternyak dternyak restored the enclave-willo-protocol branch June 19, 2018 18:32
@dternyak dternyak deleted the enclave-willo-protocol branch June 27, 2018 05:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: ready for review Open PR's that are ready for technical review. Replaced with "changes needed" or "ready to merge".
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Enable Ledger & Trezor on Desktop Current Ledger dependency unmaintained
4 participants