From 46c1f8b2b761e33d69e0998866a2cc071545d6ca Mon Sep 17 00:00:00 2001 From: Szymon Lesisz Date: Mon, 28 May 2018 19:42:03 +0200 Subject: [PATCH] remove device instances with different "passphrase_protection" settings while DEVICE.CONNECT event --- src/js/actions/WalletActions.js | 32 +++++++++++++++++++++- src/js/actions/constants/wallet.js | 4 ++- src/js/reducers/AccountsReducer.js | 12 +++++++++ src/js/reducers/DevicesReducer.js | 41 +++++++++++++++++------------ src/js/reducers/DiscoveryReducer.js | 11 ++++++++ src/js/reducers/TokensReducer.js | 14 +++++++++- src/js/services/WalletService.js | 5 ++++ 7 files changed, 99 insertions(+), 20 deletions(-) diff --git a/src/js/actions/WalletActions.js b/src/js/actions/WalletActions.js index b670e52e..067e6bd4 100644 --- a/src/js/actions/WalletActions.js +++ b/src/js/actions/WalletActions.js @@ -3,8 +3,10 @@ import { LOCATION_CHANGE } from 'react-router-redux'; import * as WALLET from './constants/wallet'; +import * as CONNECT from './constants/TrezorConnect'; import * as stateUtils from '../reducers/utils'; +import type { Device } from 'trezor-connect'; import type { Account, @@ -12,7 +14,6 @@ import type Discovery, Token, Web3Instance, - TrezorDevice, RouterLocationState, ThunkAction, @@ -41,6 +42,9 @@ export type WalletAction = { } | { type: typeof WALLET.UPDATE_SELECTED_DEVICE, device: TrezorDevice +} | { + type: typeof WALLET.CLEAR_UNAVAILABLE_DEVICE_DATA, + devices: Array } export const init = (): ThunkAction => { @@ -70,6 +74,32 @@ export const toggleDeviceDropdown = (opened: boolean): WalletAction => { } } +// This method will be called after each DEVICE.CONNECT action +// if connected device has different "passphrase_protection" settings than saved instances +// all saved instances will be removed immediately inside DevicesReducer +// This method will clear leftovers associated with removed instances from reducers. +// (DiscoveryReducer, AccountReducer, TokensReducer) +export const clearUnavailableDevicesData = (prevState: State, device: Device): ThunkAction => { + return (dispatch: Dispatch, getState: GetState): void => { + + if (!device.features) return; + + const affectedDevices = prevState.devices.filter(d => + d.features + && d.features.device_id === device.features.device_id + && d.features.passphrase_protection !== device.features.passphrase_protection + ); + + if (affectedDevices.length > 0) { + dispatch({ + type: WALLET.CLEAR_UNAVAILABLE_DEVICE_DATA, + devices: affectedDevices, + }) + } + } +} + + export const updateSelectedValues = (prevState: State, action: Action): AsyncAction => { return async (dispatch: Dispatch, getState: GetState): Promise => { diff --git a/src/js/actions/constants/wallet.js b/src/js/actions/constants/wallet.js index e525151d..c19c73ba 100644 --- a/src/js/actions/constants/wallet.js +++ b/src/js/actions/constants/wallet.js @@ -7,4 +7,6 @@ export const SET_INITIAL_URL: 'wallet__set_initial_url' = 'wallet__set_initial_u export const ONLINE_STATUS: 'wallet__online_status' = 'wallet__online_status'; export const SET_SELECTED_DEVICE: 'wallet__set_selected_device' = 'wallet__set_selected_device'; -export const UPDATE_SELECTED_DEVICE: 'wallet__update_selected_device' = 'wallet__update_selected_device'; \ No newline at end of file +export const UPDATE_SELECTED_DEVICE: 'wallet__update_selected_device' = 'wallet__update_selected_device'; + +export const CLEAR_UNAVAILABLE_DEVICE_DATA: 'wallet__clear_unavailable_device_data' = 'wallet__clear_unavailable_device_data'; \ No newline at end of file diff --git a/src/js/reducers/AccountsReducer.js b/src/js/reducers/AccountsReducer.js index 4f255ee5..0e8b5d1a 100644 --- a/src/js/reducers/AccountsReducer.js +++ b/src/js/reducers/AccountsReducer.js @@ -2,6 +2,7 @@ 'use strict'; import * as CONNECT from '../actions/constants/TrezorConnect'; +import * as WALLET from '../actions/constants/wallet'; import * as ACCOUNT from '../actions/constants/account'; import type { Action, TrezorDevice } from '~/flowtype'; @@ -71,6 +72,14 @@ const removeAccounts = (state: State, device: TrezorDevice): State => { return state.filter(account => account.deviceState !== device.state); } +const clear = (state: State, devices: Array): State => { + let newState: State = [ ...state ]; + devices.forEach(d => { + newState = removeAccounts(newState, d); + }); + return newState; +} + const setBalance = (state: State, action: AccountSetBalanceAction): State => { const index: number = state.findIndex(account => account.address === action.address && account.network === action.network && account.deviceState === action.deviceState); const newState: State = [ ...state ]; @@ -98,6 +107,9 @@ export default (state: State = initialState, action: Action): State => { case CONNECT.FORGET_SINGLE : return removeAccounts(state, action.device); + case WALLET.CLEAR_UNAVAILABLE_DEVICE_DATA : + return clear(state, action.devices); + //case CONNECT.FORGET_SINGLE : // return forgetAccounts(state, action); diff --git a/src/js/reducers/DevicesReducer.js b/src/js/reducers/DevicesReducer.js index 87b2cdf6..7fd73295 100644 --- a/src/js/reducers/DevicesReducer.js +++ b/src/js/reducers/DevicesReducer.js @@ -89,28 +89,35 @@ const addDevice = (state: State, device: Device): State => { if (affectedDevices.length > 0 ) { // check if freshly added device has different "passphrase_protection" settings - let hasDifferentPassphraseSettings: boolean = false; - let hasInstancesWithPassphraseSettings: boolean = false; - const changedDevices: Array = affectedDevices.map(d => { - if (d.features && d.features.passphrase_protection === device.features.passphrase_protection) { - hasInstancesWithPassphraseSettings = true; - return mergeDevices(d, { ...device, connected: true, available: true } ); - } else { - hasDifferentPassphraseSettings = true; - d.connected = true; - d.available = false; - return d; - } - }); + // let hasDifferentPassphraseSettings: boolean = false; + // let hasInstancesWithPassphraseSettings: boolean = false; + // const changedDevices: Array = affectedDevices.map(d => { + // if (d.features && d.features.passphrase_protection === device.features.passphrase_protection) { + // hasInstancesWithPassphraseSettings = true; + // return mergeDevices(d, { ...device, connected: true, available: true } ); + // } else { + // hasDifferentPassphraseSettings = true; + // d.connected = true; + // d.available = false; + // return d; + // } + // }); // edge case: freshly connected device has different "passphrase_protection" than saved instances // need to automatically create another instance with default instance name - if (hasDifferentPassphraseSettings && !hasInstancesWithPassphraseSettings) { - const instance = getNewInstance(affectedDevices, device); + // if (hasDifferentPassphraseSettings && !hasInstancesWithPassphraseSettings) { + // const instance = getNewInstance(affectedDevices, device); + + // newDevice.instance = instance; + // newDevice.instanceLabel = `${device.label} (${instance})`; - newDevice.instance = instance; - newDevice.instanceLabel = `${device.label} (${instance})`; + // changedDevices.push(newDevice); + // } + const changedDevices: Array = affectedDevices.filter(d => d.features && d.features.passphrase_protection === device.features.passphrase_protection).map(d => { + return mergeDevices(d, { ...device, connected: true, available: true } ); + }); + if (changedDevices.length !== affectedDevices.length) { changedDevices.push(newDevice); } diff --git a/src/js/reducers/DiscoveryReducer.js b/src/js/reducers/DiscoveryReducer.js index 8fb0dd72..b22b41f3 100644 --- a/src/js/reducers/DiscoveryReducer.js +++ b/src/js/reducers/DiscoveryReducer.js @@ -6,6 +6,7 @@ import HDKey from 'hdkey'; import * as DISCOVERY from '../actions/constants/discovery'; import * as ACCOUNT from '../actions/constants/account'; import * as CONNECT from '../actions/constants/TrezorConnect'; +import * as WALLET from '../actions/constants/wallet'; import type { Action, TrezorDevice } from '~/flowtype'; import type { @@ -87,6 +88,14 @@ const forgetDiscovery = (state: State, device: TrezorDevice): State => { return state.filter(d => d.deviceState !== device.state); } +const clear = (state: State, devices: Array): State => { + let newState: State = [ ...state ]; + devices.forEach(d => { + newState = forgetDiscovery(newState, d); + }); + return newState; +} + const stop = (state: State, action: DiscoveryStopAction): State => { const newState: State = [ ...state ]; return newState.map( (d: Discovery) => { @@ -184,6 +193,8 @@ export default function discovery(state: State = initialState, action: Action): case CONNECT.FORGET : case CONNECT.FORGET_SINGLE : return forgetDiscovery(state, action.device); + case WALLET.CLEAR_UNAVAILABLE_DEVICE_DATA : + return clear(state, action.devices); default: return state; diff --git a/src/js/reducers/TokensReducer.js b/src/js/reducers/TokensReducer.js index 66c5e073..5e3c9e7a 100644 --- a/src/js/reducers/TokensReducer.js +++ b/src/js/reducers/TokensReducer.js @@ -2,6 +2,7 @@ 'use strict'; import * as CONNECT from '../actions/constants/TrezorConnect'; +import * as WALLET from '../actions/constants/wallet'; import * as TOKEN from '../actions/constants/token'; import type { Action, TrezorDevice } from '~/flowtype'; @@ -43,7 +44,7 @@ export const findAccountTokens = (state: Array, account: Account): Array< // } const create = (state: State, token: Token): State => { - const newState: Array = [ ...state ]; + const newState: State = [ ...state ]; newState.push(token); return newState; } @@ -52,6 +53,14 @@ const forget = (state: State, device: TrezorDevice): State => { return state.filter(t => t.deviceState !== device.state); } +const clear = (state: State, devices: Array): State => { + let newState: State = [ ...state ]; + devices.forEach(d => { + newState = forget(newState, d); + }); + return newState; +} + const remove = (state: State, token: Token): State => { return state.filter(t => { return !(t.ethAddress === token.ethAddress && t.address === token.address && t.deviceState === token.deviceState); @@ -76,6 +85,9 @@ export default (state: State = initialState, action: Action): State => { case CONNECT.FORGET_SINGLE : return forget(state, action.device); + case WALLET.CLEAR_UNAVAILABLE_DEVICE_DATA : + return clear(state, action.devices); + default: return state; } diff --git a/src/js/services/WalletService.js b/src/js/services/WalletService.js index 233c06eb..79e8bd02 100644 --- a/src/js/services/WalletService.js +++ b/src/js/services/WalletService.js @@ -1,6 +1,7 @@ /* @flow */ 'use strict'; +import { DEVICE } from 'trezor-connect'; import { LOCATION_CHANGE } from 'react-router-redux'; import * as WALLET from '../actions/constants/wallet'; import * as SEND from '../actions/constants/wallet'; @@ -42,6 +43,10 @@ const WalletService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa // pass action next(action); + if (action.type === DEVICE.CONNECT) { + api.dispatch( WalletActions.clearUnavailableDevicesData(prevState, action.device) ); + } + // update common values in WallerReducer api.dispatch( WalletActions.updateSelectedValues(prevState, action) );