Skip to content

Commit

Permalink
Detect and react to transport and connection events
Browse files Browse the repository at this point in the history
  • Loading branch information
matheusd committed Oct 10, 2018
1 parent 96e724f commit 314b2f9
Show file tree
Hide file tree
Showing 11 changed files with 2,087 additions and 1,001 deletions.
2 changes: 2 additions & 0 deletions app/actions/ClientActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { getTransactions as walletGetTransactions } from "wallet/service";
import { TransactionDetails } from "middleware/walletrpc/api_pb";
import { clipboard } from "electron";
import { getStartupStats } from "./StatisticsActions";
import * as trezorActions from "./TrezorActions";

export const goToTransactionHistory = () => (dispatch) => {
dispatch(pushHistory("/transactions/history"));
Expand Down Expand Up @@ -55,6 +56,7 @@ const startWalletServicesTrigger = () => (dispatch, getState) => new Promise((re
await dispatch(getVotingServiceAttempt());
await dispatch(getAgendaServiceAttempt());
await dispatch(getStakepoolStats());
await dispatch(trezorActions.loadDeviceList());

var goHomeCb = () => {
dispatch(pushHistory("/home"));
Expand Down
91 changes: 91 additions & 0 deletions app/actions/TrezorActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import * as trezorjs from "trezor.js";
import trezorTransports from "trezor-link";
import * as wallet from "wallet";
import { EXTERNALREQUEST_TREZOR_BRIDGE } from "main_dev/externalRequests";

export const TRZ_LOADDEVICELIST_ATTEMPT = "TRZ_LOADDEVICELIST_ATTEMPT";
export const TRZ_LOADDEVICELIST_FAILED = "TRZ_LOADDEVICELIST_FAILED";
export const TRZ_LOADDEVICELIST_SUCCESS = "TRZ_LOADDEVICELIST_SUCCESS";
export const TRZ_DEVICELISTTRANSPORT_LOST = "TRZ_DEVICELISTTRANSPORT_LOST";
export const TRZ_SELECTEDDEVICE_CHANGED = "TRZ_SELECTEDDEVICE_CHANGED";

export const loadDeviceList = () => (dispatch, getState) => {
return new Promise((resolve, reject) => {
if (!getState().trezor.enabled) return;
wallet.allowExternalRequest(EXTERNALREQUEST_TREZOR_BRIDGE);

dispatch({ type: TRZ_LOADDEVICELIST_ATTEMPT });
const debug = getState().trezor.debug;

// TODO: decide whether we want to provide our own config blob.
const configUrl = "https://wallet.trezor.io/data/config_signed.bin?"
+ Date.now();

const opts = { debug, debugInfo: debug, configUrl,
transport: new trezorTransports.BridgeV2() };
const devList = new trezorjs.DeviceList(opts);
let resolvedTransport = false;

devList.on("transport", t => {
console.log("transport", t);
if (resolvedTransport) return;
resolvedTransport = true; // resolved with success
dispatch({ deviceList: devList, type: TRZ_LOADDEVICELIST_SUCCESS });
resolve(t);
});

devList.on("error", err => {
console.log("error", err);
if (!resolvedTransport && err.message.includes("ECONNREFUSED")) {
resolvedTransport = true; // resolved with failure
dispatch({ error: err.message, type: TRZ_LOADDEVICELIST_FAILED });
reject(err);
} else if (err.message.includes("socket hang up")) {
// this might happen any time throughout the app lifetime if the bridge
// service is shutdown for any reason
dispatch({ error: err.message, type: TRZ_DEVICELISTTRANSPORT_LOST });
}
});

devList.on("connect", device => {
console.log("connect", Object.keys(devList.devices), device);
const currentDevice = getState().trezor.device;
if (!currentDevice) {
// first device connected. Use it.
dispatch({ device, type: TRZ_SELECTEDDEVICE_CHANGED });
}
});

devList.on("disconnect", device => {
console.log("disconnect", Object.keys(devList.devices), device);
const currentDevice = getState().trezor.device;
if (currentDevice && device.originalDescriptor.path === currentDevice.originalDescriptor.path ) {
const devicePaths = Object.keys(devList.devices);

// we were using the device that was just disconnected. Pick a new
// device to use.
if (devicePaths.length === 0) {
// no more devices left to use
dispatch({ device: null, type: TRZ_SELECTEDDEVICE_CHANGED });
} else {
dispatch({ device: devList.devices[devicePaths[0]], type: TRZ_SELECTEDDEVICE_CHANGED });
}
}
});

devList.on("connectUnacquired", device => {
console.log("connect unacquired", device);
});

devList.on("disconnectUnacquired", device => {
console.log("disconnect unacquired", device);
});

});
};

export const selectDevice = (path) => async (dispatch, getState) => {
const devList = getState().trezor.deviceList;
if (!devList.devices[path]) return;
dispatch({ device: devList.devices[path], type: TRZ_SELECTEDDEVICE_CHANGED });
};
3 changes: 3 additions & 0 deletions app/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ export function initWalletCfg(testnet, walletPath) {
if (!config.has("iswatchonly")) {
config.set("iswatchonly", false);
}
if (!config.has("trezor")) {
config.set("trezor", false);
}
stakePoolInfo(function(foundStakePoolConfigs) {
if (foundStakePoolConfigs !== null) {
updateStakePoolConfig(config, foundStakePoolConfigs);
Expand Down
7 changes: 7 additions & 0 deletions app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,13 @@ var initialState = {
proposals: {}, // map from proposal token (id) to proposal details
lastVettedFetchTime: new Date(0), // time when vetted proposals were requested
},
trezor: {
enabled: true,
debug: true,
deviceList: null,
transportError: false,
device: null,
},
locales: locales
};

Expand Down
8 changes: 7 additions & 1 deletion app/main.development.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { createLogger, lastLogLine, GetDcrdLogs, GetDcrwalletLogs } from "./main
import { OPTIONS, USAGE_MESSAGE, VERSION_MESSAGE, BOTH_CONNECTION_ERR_MESSAGE } from "./main_dev/constants";
import { getWalletsDirectoryPath, getWalletsDirectoryPathNetwork, appDataDirectory } from "./main_dev/paths";
import { getGlobalCfgPath, checkAndInitWalletCfg } from "./main_dev/paths";
import { installSessionHandlers, reloadAllowedExternalRequests, allowStakepoolRequests } from "./main_dev/externalRequests";
import { installSessionHandlers, reloadAllowedExternalRequests, allowStakepoolRequests, allowExternalRequest } from "./main_dev/externalRequests";
import { setupProxy } from "./main_dev/proxy";
import { cleanShutdown, GetDcrdPID, GetDcrwPID } from "./main_dev/launch";
import { getAvailableWallets, startDaemon, createWallet, removeWallet, stopDaemon, stopWallet, startWallet, checkDaemon, deleteDaemon, setWatchingOnlyWallet, getWatchingOnlyWallet } from "./main_dev/ipc";
Expand Down Expand Up @@ -109,11 +109,17 @@ ipcMain.on("reload-allowed-external-request", (event) => {
reloadAllowedExternalRequests();
event.returnValue = true;
});

ipcMain.on("allow-stakepool-host", (event, host) => {
allowStakepoolRequests(host);
event.returnValue = true;
});

ipcMain.on("allow-external-request", (event, requestType) => {
allowExternalRequest(requestType);
event.returnValue = true;
});

ipcMain.on("setup-proxy", () => {
setupProxy(logger);
});
Expand Down
17 changes: 17 additions & 0 deletions app/main_dev/externalRequests.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const EXTERNALREQUEST_NETWORK_STATUS = "EXTERNALREQUEST_NETWORK_STATUS";
export const EXTERNALREQUEST_STAKEPOOL_LISTING = "EXTERNALREQUEST_STAKEPOOL_LISTING";
export const EXTERNALREQUEST_UPDATE_CHECK = "EXTERNALREQUEST_UPDATE_CHECK";
export const EXTERNALREQUEST_POLITEIA = "EXTERNALREQUEST_POLITEIA";
export const EXTERNALREQUEST_TREZOR_BRIDGE = "EXTERNALREQUEST_TREZOR_BRIDGE";

// These are the requests allowed when the standard privacy mode is selected.
export const STANDARD_EXTERNAL_REQUESTS = [
Expand Down Expand Up @@ -62,6 +63,11 @@ export const installSessionHandlers = (mainLogger) => {
callback({ cancel: true, requestHeaders: details.requestHeaders });
} else {
logger.log("verbose", details.method + " " + details.url);
if (allowedExternalRequests[EXTERNALREQUEST_TREZOR_BRIDGE] && /^http:\/\/127.0.0.1:21325\//.test(details.url)) {
// trezor bridge requires this as an origin to prevent unwanted access.
details.requestHeaders["Origin"] = "https://dummy-origin-to-fool-trezor-bridge.trezor.io";
}

callback({ cancel: false, requestHeaders: details.requestHeaders });
}
});
Expand Down Expand Up @@ -89,6 +95,17 @@ export const allowExternalRequest = (externalReqType) => {
case EXTERNALREQUEST_POLITEIA:
addAllowedURL(POLITEIA_URL_TESTNET);
addAllowedURL(POLITEIA_URL_MAINNET);
break;
case EXTERNALREQUEST_TREZOR_BRIDGE:
addAllowedURL(/^http:\/\/127.0.0.1:21324\//);
addAllowedURL(/^http:\/\/127.0.0.1:21325\//);

// TODO: decide whether we want to provide our own signed config
addAllowedURL(/^https:\/\/wallet.trezor.io\/data\/config_signed.bin\?[\d]+$/);

// TODO: decide if we wanna block this
addAllowedURL(/^https:\/\/wallet.trezor.io\/data\/bridge\/latest.txt\?[\d]+$/);

break;
default:
logger.log("error", "Unknown external request type: " + externalReqType);
Expand Down
2 changes: 2 additions & 0 deletions app/reducers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import sidebar from "./sidebar";
import snackbar from "./snackbar";
import statistics from "./statistics";
import governance from "./governance";
import trezor from "./trezor";

const rootReducer = combineReducers({
grpc,
Expand All @@ -30,6 +31,7 @@ const rootReducer = combineReducers({
snackbar,
statistics,
governance,
trezor,
});

export default rootReducer;
37 changes: 37 additions & 0 deletions app/reducers/trezor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
TRZ_LOADDEVICELIST_ATTEMPT, TRZ_LOADDEVICELIST_FAILED, TRZ_LOADDEVICELIST_SUCCESS,
TRZ_DEVICELISTTRANSPORT_LOST,
TRZ_SELECTEDDEVICE_CHANGED,
} from "actions/TrezorActions";

export default function trezor(state = {}, action) {
switch (action.type) {
case TRZ_LOADDEVICELIST_ATTEMPT:
return { ...state,
deviceList: null,
transportError: false,
device: null,
};
case TRZ_LOADDEVICELIST_SUCCESS:
return { ...state,
deviceList: action.deviceList,
transportError: false,
};
case TRZ_LOADDEVICELIST_FAILED:
return { ...state,
transportError: action.error,
};
case TRZ_DEVICELISTTRANSPORT_LOST:
return { ...state,
deviceList: null,
transportError: action.error,
device: null,
};
case TRZ_SELECTEDDEVICE_CHANGED:
return { ...state,
device: action.device,
};
default:
return state;
}
}
4 changes: 4 additions & 0 deletions app/wallet/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ export const reloadAllowedExternalRequests = log(() => Promise
.resolve(ipcRenderer.sendSync("reload-allowed-external-request"))
, "Reload allowed external request");

export const allowExternalRequest = log(requestType => Promise
.resolve(ipcRenderer.sendSync("allow-external-request", requestType))
, "Allow External Request");

export const allowStakePoolHost = log(host => Promise
.resolve(ipcRenderer.sendSync("allow-stakepool-host", host))
, "Allow StakePool Host");
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@
"source-map-support": "^0.5.9",
"string-argv": "0.1.1",
"stylelint": "^9.6.0",
"trezor.js": "^6.17.6",
"winston": "^2.3.1"
},
"devEngines": {
Expand Down
Loading

0 comments on commit 314b2f9

Please sign in to comment.