Check in progress

This commit is contained in:
Will O'Beirne 2018-04-27 16:49:17 -04:00
parent ac8777bab5
commit 50a960f62f
No known key found for this signature in database
GPG Key ID: 44C190DB5DEAF9F6
15 changed files with 134 additions and 37 deletions

View File

@ -8,7 +8,7 @@ import { render } from 'react-dom';
import Root from './Root'; import Root from './Root';
import { configuredStore } from './store'; import { configuredStore } from './store';
import consoleAdvertisement from './utils/consoleAdvertisement'; import consoleAdvertisement from './utils/consoleAdvertisement';
import { registerClient } from 'shared/enclave/client'; import EnclaveAPI, { registerClient } from 'shared/enclave/client';
const appEl = document.getElementById('app'); const appEl = document.getElementById('app');
@ -28,4 +28,5 @@ if (process.env.NODE_ENV === 'production') {
if (process.env.BUILD_ELECTRON) { if (process.env.BUILD_ELECTRON) {
registerClient(); registerClient();
(window as any).EnclaveAPI = EnclaveAPI;
} }

View File

@ -4,6 +4,7 @@ import path from 'path';
import MENU from './menu'; import MENU from './menu';
import updater from './updater'; import updater from './updater';
import { APP_TITLE } from '../constants'; import { APP_TITLE } from '../constants';
import ledger from 'shared/enclave/server/wallets/ledger';
const isDevelopment = process.env.NODE_ENV !== 'production'; const isDevelopment = process.env.NODE_ENV !== 'production';
// Cached reference, preventing recreations // Cached reference, preventing recreations

View File

@ -10,6 +10,8 @@
"npm": ">= 5.0.0" "npm": ">= 5.0.0"
}, },
"dependencies": { "dependencies": {
"@ledgerhq/hw-app-eth": "4.7.3",
"@ledgerhq/hw-transport-node-hid": "4.7.6",
"@parity/qr-signer": "0.1.1", "@parity/qr-signer": "0.1.1",
"babel-polyfill": "6.26.0", "babel-polyfill": "6.26.0",
"bip39": "2.5.0", "bip39": "2.5.0",
@ -18,8 +20,7 @@
"classnames": "2.2.5", "classnames": "2.2.5",
"electron-updater": "2.21.4", "electron-updater": "2.21.4",
"ethereum-blockies-base64": "1.0.1", "ethereum-blockies-base64": "1.0.1",
"ethereumjs-abi": "ethereumjs-abi": "git://github.com/ethereumjs/ethereumjs-abi.git#09c3c48fd3bed143df7fa8f36f6f164205e23796",
"git://github.com/ethereumjs/ethereumjs-abi.git#09c3c48fd3bed143df7fa8f36f6f164205e23796",
"ethereumjs-tx": "1.3.4", "ethereumjs-tx": "1.3.4",
"ethereumjs-util": "5.1.5", "ethereumjs-util": "5.1.5",
"ethereumjs-wallet": "0.6.0", "ethereumjs-wallet": "0.6.0",
@ -92,6 +93,7 @@
"css-loader": "0.28.11", "css-loader": "0.28.11",
"electron": "1.8.4", "electron": "1.8.4",
"electron-builder": "20.8.1", "electron-builder": "20.8.1",
"electron-rebuild": "1.7.3",
"empty": "0.10.1", "empty": "0.10.1",
"enzyme": "3.3.0", "enzyme": "3.3.0",
"enzyme-adapter-react-16": "1.1.1", "enzyme-adapter-react-16": "1.1.1",
@ -109,6 +111,7 @@
"lint-staged": "7.0.4", "lint-staged": "7.0.4",
"mini-css-extract-plugin": "0.4.0", "mini-css-extract-plugin": "0.4.0",
"minimist": "1.2.0", "minimist": "1.2.0",
"node-hid": "0.7.2",
"node-sass": "4.8.3", "node-sass": "4.8.3",
"nodemon": "1.17.3", "nodemon": "1.17.3",
"null-loader": "0.1.1", "null-loader": "0.1.1",
@ -153,19 +156,13 @@
"prebuild": "check-node-version --package", "prebuild": "check-node-version --package",
"build:downloadable": "webpack --mode=production --config webpack_config/webpack.html.js", "build:downloadable": "webpack --mode=production --config webpack_config/webpack.html.js",
"prebuild:downloadable": "check-node-version --package", "prebuild:downloadable": "check-node-version --package",
"build:electron": "build:electron": "webpack --config webpack_config/webpack.electron-prod.js && node webpack_config/buildElectron.js",
"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:osx": "build:electron:windows": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=windows node webpack_config/buildElectron.js",
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=osx 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: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", "prebuild:electron": "check-node-version --package",
"jenkins:build:linux": "jenkins:build:linux": "webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_LINUX node webpack_config/buildElectron.js",
"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:mac":
"webpack --config webpack_config/webpack.electron-prod.js && ELECTRON_OS=JENKINS_MAC node webpack_config/buildElectron.js",
"jenkins:upload": "node jenkins/upload", "jenkins:upload": "node jenkins/upload",
"test:coverage": "jest --config=jest_config/jest.config.json --coverage", "test:coverage": "jest --config=jest_config/jest.config.json --coverage",
"test": "jest --config=jest_config/jest.config.json", "test": "jest --config=jest_config/jest.config.json",
@ -178,18 +175,16 @@
"predev": "check-node-version --package", "predev": "check-node-version --package",
"dev:https": "HTTPS=true node webpack_config/devServer.js", "dev:https": "HTTPS=true node webpack_config/devServer.js",
"predev:https": "check-node-version --package", "predev:https": "check-node-version --package",
"dev:electron": "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'",
"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/**/*", "tslint": "tslint --project . --exclude common/vendor/**/*",
"tscheck": "tsc --noEmit", "tscheck": "tsc --noEmit",
"start": "npm run dev", "start": "npm run dev",
"precommit": "lint-staged", "precommit": "lint-staged",
"formatAll": "formatAll": "find ./common/ -name '*.ts*' | xargs prettier --write --config ./.prettierrc --config-precedence file-override",
"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\"",
"prettier:diff":
"prettier --write --config ./.prettierrc --list-different \"common/**/*.ts\" \"common/**/*.tsx\"",
"prepush": "npm run tslint && npm run tscheck", "prepush": "npm run tslint && npm run tscheck",
"update:tokens": "ts-node scripts/update-tokens" "update:tokens": "ts-node scripts/update-tokens",
"postinstall": "electron-rebuild --force"
}, },
"lint-staged": { "lint-staged": {
"*.{ts,tsx}": [ "*.{ts,tsx}": [

View File

@ -3,6 +3,8 @@ import {
EnclaveEvents, EnclaveEvents,
GetAddressesParams, GetAddressesParams,
GetAddressesResponse, GetAddressesResponse,
GetChainCodeParams,
GetChainCodeResponse,
SignTransactionParams, SignTransactionParams,
SignTransactionResponse SignTransactionResponse
} from 'shared/enclave/types'; } from 'shared/enclave/types';
@ -16,6 +18,10 @@ const api = {
return makeRequestExpectingResponse<GetAddressesResponse>(EnclaveEvents.GET_ADDRESSES, params); return makeRequestExpectingResponse<GetAddressesResponse>(EnclaveEvents.GET_ADDRESSES, params);
}, },
getChainCode(params: GetChainCodeParams) {
return makeRequestExpectingResponse<GetChainCodeResponse>(EnclaveEvents.GET_CHAIN_CODE, params);
},
signTransaction(params: SignTransactionParams) { signTransaction(params: SignTransactionParams) {
return makeRequestExpectingResponse<SignTransactionResponse>( return makeRequestExpectingResponse<SignTransactionResponse>(
EnclaveEvents.SIGN_TRANSACTION, EnclaveEvents.SIGN_TRANSACTION,

View File

@ -0,0 +1,7 @@
import { getWalletLib } from 'shared/enclave/server/wallets';
import { GetChainCodeParams, GetChainCodeResponse } from 'shared/enclave/types';
export default async function(params: GetChainCodeParams): Promise<GetChainCodeResponse> {
const wallet = getWalletLib(params.walletType);
return wallet.getChainCode(params.dpath);
}

View File

@ -1,9 +1,13 @@
import getAddresses from './getAddresses'; import getAddresses from './getAddresses';
import getChainCode from './getChainCode';
import signTransaction from './signTransaction'; import signTransaction from './signTransaction';
import { EnclaveEvents, EventParams, EventResponse } from 'shared/enclave/types'; import { EnclaveEvents, EventParams, EventResponse } from 'shared/enclave/types';
const handlers: { [key in EnclaveEvents]: (params: EventParams) => EventResponse } = { const handlers: {
[key in EnclaveEvents]: (params: EventParams) => EventResponse | Promise<EventResponse>
} = {
[EnclaveEvents.GET_ADDRESSES]: getAddresses, [EnclaveEvents.GET_ADDRESSES]: getAddresses,
[EnclaveEvents.GET_CHAIN_CODE]: getChainCode,
[EnclaveEvents.SIGN_TRANSACTION]: signTransaction [EnclaveEvents.SIGN_TRANSACTION]: signTransaction
}; };

View File

@ -2,13 +2,14 @@ import handlers from './handlers';
import { isValidEventType } from 'shared/enclave/utils'; import { isValidEventType } from 'shared/enclave/utils';
import { RpcRequest, RpcEventSuccess, RpcEventFailure, EventResponse } from 'shared/enclave/types'; import { RpcRequest, RpcEventSuccess, RpcEventFailure, EventResponse } from 'shared/enclave/types';
function processRequest(req: RpcRequest) { async function processRequest(req: RpcRequest) {
try { try {
const data = handlers[req.type](req.params); const data = await handlers[req.type](req.params);
if (data) { if (data) {
respondWithPayload(req, data); respondWithPayload(req, data);
} }
} catch (err) { } catch (err) {
console.error('Request', req.type, 'failed with error:', err);
respondWithError(req, err.toString()); respondWithError(req, err.toString());
} }
} }

View File

@ -0,0 +1,14 @@
import Ledger from './ledger';
import Trezor from './trezor';
import KeepKey from './keepkey';
import { WalletTypes, WalletLib } from 'shared/enclave/types';
export const wallets: { [key in WalletTypes]: WalletLib } = {
[WalletTypes.LEDGER]: Ledger,
[WalletTypes.TREZOR]: Trezor,
[WalletTypes.KEEPKEY]: KeepKey
};
export function getWalletLib(type: WalletTypes): WalletLib {
return wallets[type];
}

View File

@ -0,0 +1,9 @@
import { WalletLib } from 'shared/enclave/types';
const KeepKey: WalletLib = {
async getChainCode() {
throw new Error('Not yet supported');
}
};
export default KeepKey;

View File

@ -0,0 +1,27 @@
import { WalletLib } from 'shared/enclave/types';
import TransportNodeHid from '@ledgerhq/hw-transport-node-hid';
import LedgerEth from '@ledgerhq/hw-app-eth';
async function getEthApp() {
const transport = await TransportNodeHid.create();
return new LedgerEth(transport);
}
const Ledger: WalletLib = {
async getChainCode(dpath: string) {
const app = await getEthApp();
try {
const res = await app.getAddress(dpath);
console.log(res);
return {
publicKey: res.publicKey,
chainCode: res.chainCode
};
} catch (err) {
console.log('wtf', err);
throw new Error('test');
}
}
};
export default Ledger;

View File

@ -0,0 +1,9 @@
import { WalletLib } from 'shared/enclave/types';
const Trezor: WalletLib = {
async getChainCode() {
throw new Error('Not yet supported');
}
};
export default Trezor;

View File

@ -1,18 +1,36 @@
// All enclave event types // Enclave enums
export enum EnclaveEvents { export enum EnclaveEvents {
GET_ADDRESSES = 'get-addresses', GET_ADDRESSES = 'get-addresses',
GET_CHAIN_CODE = 'get-chain-code',
SIGN_TRANSACTION = 'sign-transaction' SIGN_TRANSACTION = 'sign-transaction'
} }
export enum WalletTypes {
LEDGER = 'ledger',
TREZOR = 'trezor',
KEEPKEY = 'keepkey'
}
// Get Addresses Request // Get Addresses Request
export interface GetAddressesParams { export interface GetAddressesParams {
walletType: string; walletType: WalletTypes;
} }
export interface GetAddressesResponse { export interface GetAddressesResponse {
addresses: string[]; addresses: string[];
} }
// Get chain code request
export interface GetChainCodeParams {
walletType: WalletTypes;
dpath: string;
}
export interface GetChainCodeResponse {
publicKey: string;
chainCode: string;
}
// Sign Transaction Request // Sign Transaction Request
export interface SignTransactionParams { export interface SignTransactionParams {
path: string; path: string;
@ -26,8 +44,8 @@ export interface SignTransactionResponse {
} }
// All Requests & Responses // All Requests & Responses
export type EventParams = GetAddressesParams | SignTransactionParams; export type EventParams = GetAddressesParams | GetChainCodeParams | SignTransactionParams;
export type EventResponse = GetAddressesResponse | SignTransactionResponse; export type EventResponse = GetAddressesResponse | GetChainCodeResponse | SignTransactionResponse;
// RPC requests, responses & failures // RPC requests, responses & failures
export interface RpcRequest { export interface RpcRequest {
@ -53,10 +71,7 @@ export interface RpcEventFailure {
export type RpcEvent<T = any> = RpcEventFailure | RpcEventSuccess<T>; export type RpcEvent<T = any> = RpcEventFailure | RpcEventSuccess<T>;
// No clue // Wallet lib
export interface RpcEventServer<T = any> { export interface WalletLib {
payload: T; getChainCode(dpath: string): Promise<GetChainCodeResponse>;
id: number;
} }
export type RpcEventHandler<A = any, R = any> = (event: EnclaveEvents, args: A) => R;
export type MatchingIdHandler<A = any> = (event: string, args: A) => void;

View File

@ -18,7 +18,8 @@
"noEmitOnError": false, "noEmitOnError": false,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"noImplicitAny": true "noImplicitAny": true,
"noImplicitUseStrict": true
}, },
"include": [ "include": [
"./scripts", "./scripts",

View File

@ -29,10 +29,15 @@ const electronConfig = {
'process.env.NODE_ENV': JSON.stringify('development') 'process.env.NODE_ENV': JSON.stringify('development')
}), }),
], ],
externals: {
'node-hid': 'commonjs node-hid',
'@ledger/hw-transport-hid': 'commonjs @ledger/hw-transport-hid'
},
node: { node: {
__dirname: false, __dirname: false,
__filename: false __filename: false
} },
devtool: 'eval'
}; };
module.exports = electronConfig; module.exports = electronConfig;

View File

@ -23,4 +23,6 @@ electronConfig.plugins = [
new DelayPlugin(500) new DelayPlugin(500)
]; ];
electronConfig.devtool = undefined;
module.exports = [electronConfig, jsConfig]; module.exports = [electronConfig, jsConfig];