1
0
mirror of https://github.com/trezor/trezor-wallet synced 2024-11-15 12:59:09 +00:00
trezor-wallet/src/actions/TrezorConnectActions.js

327 lines
10 KiB
JavaScript
Raw Normal View History

2017-12-13 11:01:37 +00:00
/* @flow */
2018-07-30 10:52:13 +00:00
import TrezorConnect, {
2018-09-21 12:01:41 +00:00
DEVICE, DEVICE_EVENT, UI_EVENT, TRANSPORT_EVENT, BLOCKCHAIN_EVENT,
2018-07-30 10:52:13 +00:00
} from 'trezor-connect';
import { CONTEXT_NONE } from 'actions/constants/modal';
2018-08-14 13:18:16 +00:00
import * as CONNECT from 'actions/constants/TrezorConnect';
import * as NOTIFICATION from 'actions/constants/notification';
2018-08-20 11:01:43 +00:00
import { getDuplicateInstanceNumber } from 'reducers/utils';
import * as RouterActions from 'actions/RouterActions';
import * as deviceUtils from 'utils/device';
2018-10-11 16:04:25 +00:00
import * as buildUtils from 'utils/build';
2018-02-20 09:30:36 +00:00
2018-04-16 21:19:50 +00:00
import type {
DeviceMessage,
DeviceMessageType,
2018-04-16 21:19:50 +00:00
UiMessage,
UiMessageType,
2018-04-16 21:19:50 +00:00
TransportMessage,
TransportMessageType,
BlockchainEvent,
2018-04-16 21:19:50 +00:00
} from 'trezor-connect';
2018-07-30 10:52:13 +00:00
import type {
2018-04-16 21:19:50 +00:00
Dispatch,
GetState,
Action,
2018-05-02 09:01:08 +00:00
ThunkAction,
2018-04-16 21:19:50 +00:00
AsyncAction,
Device,
2018-04-16 21:19:50 +00:00
TrezorDevice,
2018-08-14 12:56:47 +00:00
} from 'flowtype';
2018-04-16 21:19:50 +00:00
export type TrezorConnectAction = {
type: typeof CONNECT.INITIALIZATION_ERROR,
2018-04-23 10:20:15 +00:00
error: string
2018-04-16 21:19:50 +00:00
} | {
2018-10-15 13:44:10 +00:00
type: typeof CONNECT.NETWORK_CHANGED,
2018-04-16 21:19:50 +00:00
payload: {
network: string
}
} | {
type: typeof CONNECT.AUTH_DEVICE,
2018-05-19 16:26:39 +00:00
device: TrezorDevice,
state: string
2018-04-16 21:19:50 +00:00
} | {
type: typeof CONNECT.DUPLICATE,
2018-04-23 10:20:15 +00:00
device: TrezorDevice
2018-04-16 21:19:50 +00:00
} | {
type: typeof CONNECT.REMEMBER_REQUEST,
2018-04-23 10:20:15 +00:00
device: TrezorDevice,
instances: Array<TrezorDevice>
2018-04-16 21:19:50 +00:00
} | {
type: typeof CONNECT.DISCONNECT_REQUEST,
2018-04-23 10:20:15 +00:00
device: TrezorDevice
2018-04-16 21:19:50 +00:00
} | {
type: typeof CONNECT.FORGET_REQUEST,
2018-04-23 10:20:15 +00:00
device: TrezorDevice
2018-04-16 21:19:50 +00:00
} | {
type: typeof CONNECT.FORGET,
2018-04-23 10:20:15 +00:00
device: TrezorDevice
2018-04-16 21:19:50 +00:00
} | {
type: typeof CONNECT.FORGET_SINGLE | typeof CONNECT.FORGET_SILENT,
2018-04-23 10:20:15 +00:00
device: TrezorDevice
2018-04-16 21:19:50 +00:00
} | {
type: typeof CONNECT.REMEMBER,
2018-04-23 10:20:15 +00:00
device: TrezorDevice
2018-04-16 21:19:50 +00:00
} | {
type: typeof CONNECT.TRY_TO_DUPLICATE,
2018-04-23 10:20:15 +00:00
device: TrezorDevice
2018-04-16 21:19:50 +00:00
} | {
type: typeof CONNECT.DEVICE_FROM_STORAGE,
2018-04-23 10:20:15 +00:00
payload: Array<TrezorDevice>
2018-05-23 09:46:57 +00:00
} | {
type: typeof CONNECT.START_ACQUIRING | typeof CONNECT.STOP_ACQUIRING,
} | {
type: typeof CONNECT.REQUEST_WALLET_TYPE,
device: TrezorDevice
} | {
type: typeof CONNECT.RECEIVE_WALLET_TYPE | typeof CONNECT.UPDATE_WALLET_TYPE,
device: TrezorDevice,
hidden: boolean,
2018-04-16 21:19:50 +00:00
};
declare var LOCAL: ?string;
2018-07-30 10:52:13 +00:00
export const init = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
// set listeners
TrezorConnect.on(DEVICE_EVENT, (event: DeviceMessage): void => {
// post event to reducers
2018-09-21 12:01:41 +00:00
const type: DeviceMessageType = event.type; // eslint-disable-line prefer-destructuring
2018-07-30 10:52:13 +00:00
dispatch({
type,
device: event.payload,
2018-02-20 09:30:36 +00:00
});
2018-07-30 10:52:13 +00:00
});
2018-02-20 09:30:36 +00:00
2018-07-30 10:52:13 +00:00
TrezorConnect.on(UI_EVENT, (event: UiMessage): void => {
// post event to reducers
2018-09-21 12:01:41 +00:00
const type: UiMessageType = event.type; // eslint-disable-line prefer-destructuring
2018-07-30 10:52:13 +00:00
dispatch({
type,
payload: event.payload,
});
2018-07-30 10:52:13 +00:00
});
2018-07-30 10:52:13 +00:00
TrezorConnect.on(TRANSPORT_EVENT, (event: TransportMessage): void => {
// post event to reducers
2018-09-21 12:01:41 +00:00
const type: TransportMessageType = event.type; // eslint-disable-line prefer-destructuring
2018-07-30 10:52:13 +00:00
dispatch({
type,
payload: event.payload,
});
2018-07-30 10:52:13 +00:00
});
2018-02-20 09:30:36 +00:00
// post event to reducers
TrezorConnect.on(BLOCKCHAIN_EVENT, (event: BlockchainEvent): void => {
dispatch(event);
});
2018-10-11 16:04:25 +00:00
if (buildUtils.isDev()) {
window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://sisyfos.trezor.io/connect/'; // eslint-disable-line no-underscore-dangle
// window.__TREZOR_CONNECT_SRC = typeof LOCAL === 'string' ? LOCAL : 'https://connect.trezor.io/5/'; // eslint-disable-line no-underscore-dangle
window.TrezorConnect = TrezorConnect;
}
2018-08-08 11:21:28 +00:00
2018-07-30 10:52:13 +00:00
try {
await TrezorConnect.init({
transportReconnect: true,
debug: false,
2018-07-30 10:52:13 +00:00
popup: false,
webusb: true,
pendingTransportEvent: (getState().devices.length < 1),
});
} catch (error) {
dispatch({
type: CONNECT.INITIALIZATION_ERROR,
error,
});
2017-12-13 11:01:37 +00:00
}
2018-07-30 10:52:13 +00:00
};
2017-12-13 11:01:37 +00:00
2018-09-06 15:04:28 +00:00
// called after backend was initialized
// set listeners for connect/disconnect
2018-09-21 12:01:41 +00:00
export const postInit = (): ThunkAction => (dispatch: Dispatch): void => {
2018-09-06 15:04:28 +00:00
const handleDeviceConnect = (device: Device) => {
2018-09-21 12:01:41 +00:00
dispatch(RouterActions.selectDevice(device));
2018-09-06 15:04:28 +00:00
};
TrezorConnect.off(DEVICE.CONNECT, handleDeviceConnect);
TrezorConnect.off(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
TrezorConnect.on(DEVICE.CONNECT, handleDeviceConnect);
TrezorConnect.on(DEVICE.CONNECT_UNACQUIRED, handleDeviceConnect);
// try to redirect to initial url
2018-09-21 12:01:41 +00:00
if (!dispatch(RouterActions.setInitialUrl())) {
// if initial redirection fails try to switch to first available device
2018-09-21 12:01:41 +00:00
dispatch(RouterActions.selectFirstAvailableDevice());
2018-09-06 15:04:28 +00:00
}
};
export const requestWalletType = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const selected = getState().wallet.selectedDevice;
if (!selected) return;
const isDeviceReady = selected.connected && selected.features && !selected.state && selected.mode === 'normal' && selected.firmware !== 'required';
if (!isDeviceReady) return;
if (selected.features && selected.features.passphrase_protection) {
dispatch({
type: CONNECT.REQUEST_WALLET_TYPE,
device: selected,
});
} else {
dispatch({
type: CONNECT.RECEIVE_WALLET_TYPE,
device: selected,
hidden: false,
state: selected.state,
});
}
};
export const authorizeDevice = (): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
2018-07-30 10:52:13 +00:00
const selected = getState().wallet.selectedDevice;
if (!selected) return;
const isDeviceReady = selected.connected && selected.features && !selected.state && selected.mode === 'normal' && selected.firmware !== 'required';
if (!isDeviceReady) return;
const response = await TrezorConnect.getDeviceState({
device: {
path: selected.path,
instance: selected.instance,
state: selected.state,
},
useEmptyPassphrase: selected.useEmptyPassphrase,
});
2018-02-20 09:30:36 +00:00
if (response && response.success) {
dispatch({
type: CONNECT.AUTH_DEVICE,
device: selected,
state: response.payload.state,
});
} else {
dispatch({
type: NOTIFICATION.ADD,
payload: {
devicePath: selected.path,
type: 'error',
title: 'Authentication error',
message: response.payload.error,
cancelable: false,
actions: [
{
label: 'Try again',
callback: () => {
dispatch({
type: NOTIFICATION.CLOSE,
payload: { devicePath: selected.path },
});
dispatch(authorizeDevice());
2018-07-30 10:52:13 +00:00
},
},
],
},
});
2018-02-20 09:30:36 +00:00
}
2018-07-30 10:52:13 +00:00
};
2018-02-20 09:30:36 +00:00
2018-07-30 10:52:13 +00:00
export const deviceDisconnect = (device: Device): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
if (device.features) {
const instances = getState().devices.filter(d => d.features && device.features && d.state && !d.remember && d.features.device_id === device.features.device_id);
2018-07-30 10:52:13 +00:00
if (instances.length > 0) {
2018-10-11 11:07:29 +00:00
const isSelected = deviceUtils.isSelectedDevice(getState().wallet.selectedDevice, device);
if (!isSelected && getState().modal.context !== CONTEXT_NONE) {
dispatch({
type: CONNECT.FORGET_SILENT,
device: instances[0],
});
} else {
dispatch({
type: CONNECT.REMEMBER_REQUEST,
device: instances[0],
instances,
});
}
} else {
dispatch(RouterActions.selectFirstAvailableDevice());
2018-03-08 16:10:53 +00:00
}
} else {
dispatch(RouterActions.selectFirstAvailableDevice());
2018-02-20 09:30:36 +00:00
}
2018-07-30 10:52:13 +00:00
};
2018-02-20 09:30:36 +00:00
2018-04-16 21:19:50 +00:00
export function reload(): AsyncAction {
2018-09-21 12:01:41 +00:00
return async (): Promise<void> => {
2018-07-30 10:52:13 +00:00
};
}
2018-02-20 09:30:36 +00:00
2018-04-16 21:19:50 +00:00
export function acquire(): AsyncAction {
return async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const selected: ?TrezorDevice = getState().wallet.selectedDevice;
2018-04-16 21:19:50 +00:00
if (!selected) return;
2018-02-20 09:30:36 +00:00
2018-05-23 09:46:57 +00:00
dispatch({
type: CONNECT.START_ACQUIRING,
2018-07-30 10:52:13 +00:00
});
2018-05-23 09:46:57 +00:00
// this is the only place where useEmptyPassphrase should be used every time
// the goal here is to acquire device and get his features
// authentication (passphrase) is not needed here yet
2018-07-30 10:52:13 +00:00
const response = await TrezorConnect.getFeatures({
2018-02-20 09:30:36 +00:00
device: {
path: selected.path,
},
useEmptyPassphrase: true,
2018-02-20 09:30:36 +00:00
});
2018-05-16 16:55:12 +00:00
if (!response.success) {
2018-02-20 09:30:36 +00:00
dispatch({
type: NOTIFICATION.ADD,
payload: {
type: 'error',
title: 'Acquire device error',
message: response.payload.error,
2018-02-20 09:30:36 +00:00
cancelable: true,
2018-05-23 09:46:57 +00:00
// actions: [
// {
// label: 'Try again',
// callback: () => {
// dispatch(acquire())
// }
// }
// ]
2018-07-30 10:52:13 +00:00
},
});
2018-02-20 09:30:36 +00:00
}
2018-05-23 09:46:57 +00:00
dispatch({
type: CONNECT.STOP_ACQUIRING,
2018-07-30 10:52:13 +00:00
});
};
2018-02-20 09:30:36 +00:00
}
// called from Aside - device menu (forget single instance)
2018-07-30 10:52:13 +00:00
export const forget = (device: TrezorDevice): Action => ({
type: CONNECT.FORGET_REQUEST,
device,
});
export const duplicateDeviceOld = (device: TrezorDevice): AsyncAction => async (dispatch: Dispatch, getState: GetState): Promise<void> => {
const instance: number = getDuplicateInstanceNumber(getState().devices, device);
const extended: Object = { instance };
2018-07-30 10:52:13 +00:00
dispatch({
type: CONNECT.DUPLICATE,
2018-08-20 11:01:43 +00:00
device: { ...device, ...extended },
2018-07-30 10:52:13 +00:00
});
};
export const duplicateDevice = (device: TrezorDevice): AsyncAction => async (dispatch: Dispatch): Promise<void> => {
dispatch({
type: CONNECT.REQUEST_WALLET_TYPE,
device,
});
};