From e90cde75fd20901ff3f320ac03c6db49586ca8f0 Mon Sep 17 00:00:00 2001 From: William O'Beirne Date: Mon, 25 Jun 2018 15:27:27 -0400 Subject: [PATCH] Allow PIN Entry for TREZOR One in App (#1971) * Create popup window for TREZOR pin. * Address PR feedback. Move pin template into its own file loaded via raw-loader. * Fix PIN not unlocking * Dont minify electron main code --- common/typescript/custom.d.ts | 5 + common/typescript/trezor-js.d.ts | 2 +- package.json | 35 ++-- shared/enclave/server/views/pin.html | 226 ++++++++++++++++++++++++ shared/enclave/server/views/pin.ts | 40 +++++ shared/enclave/server/wallets/trezor.ts | 14 +- webpack_config/webpack.electron-dev.js | 9 +- webpack_config/webpack.electron-prod.js | 5 + yarn.lock | 60 ++++--- 9 files changed, 342 insertions(+), 54 deletions(-) create mode 100644 shared/enclave/server/views/pin.html create mode 100644 shared/enclave/server/views/pin.ts diff --git a/common/typescript/custom.d.ts b/common/typescript/custom.d.ts index 73b08ad3..897914a0 100644 --- a/common/typescript/custom.d.ts +++ b/common/typescript/custom.d.ts @@ -12,3 +12,8 @@ declare module '*.png' { const content: any; export default content; } + +declare module '*.html' { + const content: string; + export default content; +} diff --git a/common/typescript/trezor-js.d.ts b/common/typescript/trezor-js.d.ts index 3bf73f35..5906a1f8 100644 --- a/common/typescript/trezor-js.d.ts +++ b/common/typescript/trezor-js.d.ts @@ -2,7 +2,7 @@ // Types are only based off of what's mentioned in the API // https://github.com/trezor/trezor.js/blob/master/API.md -declare module 'mycrypto-trezor.js' { +declare module 'trezor.js' { import { EventEmitter } from 'events'; import { Transport, TrezorDeviceInfoWithSession as DeviceDescriptor } from 'trezor-link'; diff --git a/package.json b/package.json index 3055ee2f..d721909a 100644 --- a/package.json +++ b/package.json @@ -22,8 +22,7 @@ "classnames": "2.2.5", "electron-updater": "2.21.10", "ethereum-blockies-base64": "1.0.1", - "ethereumjs-abi": - "git://github.com/ethereumjs/ethereumjs-abi.git#09c3c48fd3bed143df7fa8f36f6f164205e23796", + "ethereumjs-abi": "git://github.com/ethereumjs/ethereumjs-abi.git#09c3c48fd3bed143df7fa8f36f6f164205e23796", "ethereumjs-tx": "1.3.4", "ethereumjs-util": "5.1.5", "ethereumjs-wallet": "0.6.0", @@ -37,7 +36,6 @@ "moment-timezone": "0.5.14", "mycrypto-eth-exists": "1.0.0", "mycrypto-shepherd": "1.4.0", - "mycrypto-trezor.js": "6.17.5", "normalizr": "3.2.4", "qrcode": "1.2.0", "qrcode.react": "0.8.0", @@ -60,6 +58,7 @@ "rskjs-util": "1.0.3", "scryptsy": "2.0.0", "semver": "5.5.0", + "trezor.js": "6.17.5", "uuid": "3.2.1", "wallet-address-validator": "0.1.6", "whatwg-fetch": "2.0.3", @@ -120,12 +119,13 @@ "lint-staged": "7.0.4", "mini-css-extract-plugin": "0.4.0", "minimist": "1.2.0", - "node-hid": "0.7.2", "mycrypto-nano-result": "0.0.1", + "node-hid": "0.7.2", "node-sass": "4.8.3", "nodemon": "1.17.3", "null-loader": "0.1.1", "prettier": "1.11.1", + "raw-loader": "0.5.1", "react-hot-loader": "4.0.0", "react-test-renderer": "16.3.2", "redux-devtools-extension": "2.13.2", @@ -167,19 +167,13 @@ "prebuild": "check-node-version --package", "build:downloadable": "webpack --mode=production --config webpack_config/webpack.html.js", "prebuild:downloadable": "check-node-version --package", - "build:electron": - "webpack --config webpack_config/webpack.electron-prod.js && node webpack_config/buildElectron.js", - "build:electron:osx": - "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=osx node webpack_config/buildElectron.js", - "build:electron:windows": - "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=windows node webpack_config/buildElectron.js", - "build:electron:linux": - "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=linux node webpack_config/buildElectron.js", + "build:electron": "webpack --config webpack_config/webpack.electron-prod.js && node webpack_config/buildElectron.js", + "build:electron:osx": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=osx node webpack_config/buildElectron.js", + "build:electron:windows": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=windows node webpack_config/buildElectron.js", + "build:electron:linux": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=linux node webpack_config/buildElectron.js", "prebuild:electron": "check-node-version --package", - "jenkins:build:linux": - "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_LINUX node webpack_config/buildElectron.js", - "jenkins:build:mac": - "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_MAC node webpack_config/buildElectron.js", + "jenkins:build:linux": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_LINUX node webpack_config/buildElectron.js", + "jenkins:build:mac": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_MAC node webpack_config/buildElectron.js", "jenkins:upload": "node jenkins/upload", "test:coverage": "jest --config=jest_config/jest.config.json --coverage", "test": "jest --config=jest_config/jest.config.json", @@ -192,16 +186,13 @@ "predev": "check-node-version --package", "dev:https": "HTTPS=true node webpack_config/devServer.js", "predev:https": "check-node-version --package", - "dev:electron": - "concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true node webpack_config/devServer.js' 'webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'", + "dev:electron": "concurrently --kill-others --names 'webpack,electron' 'BUILD_ELECTRON=true node webpack_config/devServer.js' 'webpack --config webpack_config/webpack.electron-dev.js && electron dist/electron-js/main.js'", "tslint": "tslint --project . --exclude common/vendor/**/*", "tscheck": "tsc --noEmit", "start": "npm run dev", "precommit": "lint-staged", - "formatAll": - "find ./common/ -name '*.ts*' | xargs prettier --write --config ./.prettierrc --config-precedence file-override", - "prettier:diff": - "prettier --write --config ./.prettierrc --list-different \"common/**/*.ts\" \"common/**/*.tsx\"", + "formatAll": "find ./common/ -name '*.ts*' | xargs prettier --write --config ./.prettierrc --config-precedence file-override", + "prettier:diff": "prettier --write --config ./.prettierrc --list-different \"common/**/*.ts\" \"common/**/*.tsx\"", "prepush": "npm run tslint && npm run tscheck", "update:tokens": "ts-node scripts/update-tokens", "postinstall": "electron-rebuild --force" diff --git a/shared/enclave/server/views/pin.html b/shared/enclave/server/views/pin.html new file mode 100644 index 00000000..291937b4 --- /dev/null +++ b/shared/enclave/server/views/pin.html @@ -0,0 +1,226 @@ + + + TREZOR - Enter PIN + + + +

Enter your PIN

+

Look at your device for the number positions

+ +
+ + + + + + + + + + + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + diff --git a/shared/enclave/server/views/pin.ts b/shared/enclave/server/views/pin.ts new file mode 100644 index 00000000..fc54d842 --- /dev/null +++ b/shared/enclave/server/views/pin.ts @@ -0,0 +1,40 @@ +import { BrowserWindow, ipcMain, IpcMessageEvent } from 'electron'; +import template from './pin.html'; + +const EVENT = 'enclave:pin'; + +export function showPinPrompt(): Promise { + return new Promise((resolve, reject) => { + const scriptNonce = Math.floor(Math.random() * 1000000000000); + const html = template + .replace(/\$scriptNonce/g, scriptNonce.toString()) + .replace(/\$EVENT/g, EVENT); + + let hasResolved = false; + + const window = new BrowserWindow({ + width: 320, + height: 380, + frame: false, + backgroundColor: '#21252B', + darkTheme: true + }); + + window.on('closed', () => { + if (hasResolved) { + return; + } + reject(new Error('ENCLAVE_TREZOR_CANCELED')); + }); + + ipcMain.once(EVENT, (_: IpcMessageEvent, pin: string) => { + resolve(pin); + hasResolved = true; + window.close(); + }); + + window.loadURL(`data:text/html;charset=UTF-8,${encodeURIComponent(html)}`); + window.show(); + window.focus(); + }); +} diff --git a/shared/enclave/server/wallets/trezor.ts b/shared/enclave/server/wallets/trezor.ts index 61996e61..02f8684b 100644 --- a/shared/enclave/server/wallets/trezor.ts +++ b/shared/enclave/server/wallets/trezor.ts @@ -1,12 +1,12 @@ import BN from 'bn.js'; -import { DeviceList, Session } from 'mycrypto-trezor.js'; +import { DeviceList, Session } from 'trezor.js'; import mapValues from 'lodash/mapValues'; import { addHexPrefix } from 'ethereumjs-util'; import EthTx from 'ethereumjs-tx'; - import { WalletLib } from 'shared/enclave/types'; import { padLeftEven } from 'libs/values'; import { stripHexPrefixAndLower } from 'libs/formatters'; +import { showPinPrompt } from '../views/pin'; const deviceList = new DeviceList({ debug: false }); @@ -25,6 +25,16 @@ async function getSession() { currentSession = null; } }); + device.on('pin', (_, cb: (err?: Error, pin?: string) => void) => { + showPinPrompt() + .then(pin => { + cb(undefined, pin); + }) + .catch(err => { + console.error('PIN entry failed', err); + cb(err); + }); + }); currentSession = session; return currentSession; diff --git a/webpack_config/webpack.electron-dev.js b/webpack_config/webpack.electron-dev.js index b9d1dabe..5e798caa 100644 --- a/webpack_config/webpack.electron-dev.js +++ b/webpack_config/webpack.electron-dev.js @@ -12,7 +12,14 @@ const electronConfig = { preload: path.join(config.path.electron, 'preload/index.ts') }, module: { - rules: [config.typescriptRule] + rules: [ + config.typescriptRule, + // HTML as string + { + test: /\.html$/, + use: 'raw-loader', + } + ] }, resolve: { extensions: ['.ts', '.js', '.json'], diff --git a/webpack_config/webpack.electron-prod.js b/webpack_config/webpack.electron-prod.js index 9bd8fc85..2e61ba00 100644 --- a/webpack_config/webpack.electron-prod.js +++ b/webpack_config/webpack.electron-prod.js @@ -23,6 +23,11 @@ electronConfig.plugins = [ new DelayPlugin(500) ]; +// Many native node modules don't like being uglified since they often aren't +// for most use cases, and this way logging is a lot easier too. electronConfig.devtool = undefined; +electronConfig.optimization = { + minimize: false +}; module.exports = [electronConfig, jsConfig]; diff --git a/yarn.lock b/yarn.lock index 9e2dcfe1..885a11d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7635,34 +7635,6 @@ mycrypto-shepherd@1.4.0: remote-redux-devtools "^0.5.12" url-search-params "^0.10.0" -mycrypto-trezor-link@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/mycrypto-trezor-link/-/mycrypto-trezor-link-1.5.1.tgz#1d0b13bd854022dcd9960062d04f8d9e7b4c67c0" - dependencies: - bigi "^1.4.1" - bitcoinjs-lib-zcash "^3.0.0" - ecurve "^1.0.3" - json-stable-stringify "^1.0.1" - node-fetch "^1.6.0" - object.values "^1.0.3" - protobufjs-old-fixed-webpack "3.8.5" - semver-compare "^1.0.0" - whatwg-fetch "0.11.0" - -mycrypto-trezor.js@6.17.5: - version "6.17.5" - resolved "https://registry.yarnpkg.com/mycrypto-trezor.js/-/mycrypto-trezor.js-6.17.5.tgz#f92cf11e614aa813814f8e444f459f02bf7ce906" - dependencies: - bchaddrjs "^0.2.1" - bitcoinjs-lib-zcash "^3.3.2" - ecurve "^1.0.2" - mycrypto-trezor-link "1.5.1" - node-fetch "^1.6.0" - randombytes "^2.0.1" - semver-compare "1.0.0" - unorm "^1.3.3" - whatwg-fetch "0.11.0" - nan@^2.0.5, nan@^2.0.8, nan@^2.10.0, nan@^2.2.1, nan@^2.3.0, nan@^2.6.2: version "2.10.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" @@ -9207,6 +9179,10 @@ raw-body@2.3.2: iconv-lite "0.4.19" unpipe "1.0.0" +raw-loader@0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" + rc-align@2.x: version "2.3.6" resolved "https://registry.yarnpkg.com/rc-align/-/rc-align-2.3.6.tgz#35046d2ac25771b1e5cbd600eae8f862c450f9e6" @@ -11299,6 +11275,34 @@ tree-kill@^1.1.0: version "1.2.0" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.0.tgz#5846786237b4239014f05db156b643212d4c6f36" +trezor-link@1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/trezor-link/-/trezor-link-1.5.2.tgz#a87defc5ea4d0e882c5a8623b554673d62cdabbb" + dependencies: + bigi "^1.4.1" + bitcoinjs-lib-zcash "^3.0.0" + ecurve "^1.0.3" + json-stable-stringify "^1.0.1" + node-fetch "^1.6.0" + object.values "^1.0.3" + protobufjs-old-fixed-webpack "3.8.5" + semver-compare "^1.0.0" + whatwg-fetch "0.11.0" + +trezor.js@6.17.5: + version "6.17.5" + resolved "https://registry.yarnpkg.com/trezor.js/-/trezor.js-6.17.5.tgz#cc080fce430c0ad921474ef210da2eceab8ec1f1" + dependencies: + bchaddrjs "^0.2.1" + bitcoinjs-lib-zcash "^3.3.2" + ecurve "^1.0.2" + node-fetch "^1.6.0" + randombytes "^2.0.1" + semver-compare "1.0.0" + trezor-link "1.5.2" + unorm "^1.3.3" + whatwg-fetch "0.11.0" + trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"