1
0
mirror of https://github.com/trezor/trezor-wallet synced 2025-03-28 14:05:44 +00:00

fix: setInitialUrl - race condition

- Do not set initialUrl if it is landingPage
- Block "RouterAction.selectDevice" if currently selected device is in auth process
- Move WalletActions.observe() before DiscoveryActions.restore() in "WalletSerivce"
This commit is contained in:
Szymon Lesisz 2019-04-12 16:22:57 +02:00
parent 241e59dc98
commit 585c79a738
2 changed files with 68 additions and 50 deletions

View File

@ -430,29 +430,42 @@ export const setInitialUrl = (): PayloadAction<boolean> => (
getState: GetState getState: GetState
): boolean => { ): boolean => {
const { initialPathname } = getState().wallet; const { initialPathname } = getState().wallet;
if (typeof initialPathname === 'string' && !dispatch(isLandingPageUrl(initialPathname, true))) { if (typeof initialPathname !== 'string') return false;
const valid = dispatch(
getValidUrl({
type: LOCATION_CHANGE,
payload: {
location: {
pathname: initialPathname,
hash: '',
search: '',
state: {},
},
},
})
);
if (valid === initialPathname) { // DEVICE.CONNECT race condition, "selectDevice" method was called but currently selectedDevice is in getState (auth) process
// reset initial url // if so, consume this action (return true) to break "selectDevice" process
dispatch({ // "setInitialUrl" will be called again after AUTH_DEVICE action
type: SET_INITIAL_URL, const { selectedDevice } = getState().wallet;
}); if (
dispatch(goto(valid)); selectedDevice &&
return true; selectedDevice.type === 'acquired' &&
} !selectedDevice.features.passphrase_protection &&
!selectedDevice.state
)
return true;
const valid = dispatch(
getValidUrl({
type: LOCATION_CHANGE,
payload: {
location: {
pathname: initialPathname,
hash: '',
search: '',
state: {},
},
},
})
);
if (valid === initialPathname) {
// reset initial url
dispatch({
type: SET_INITIAL_URL,
});
dispatch(goto(valid));
return true;
} }
return false; return false;
}; };

View File

@ -29,11 +29,16 @@ const WalletService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa
api.dispatch(WalletActions.init()); api.dispatch(WalletActions.init());
// set initial url // set initial url
// TODO: validate if initial url is potentially correct // TODO: validate if initial url is potentially correct
api.dispatch({ // exclude landing page url
type: WALLET.SET_INITIAL_URL, const { pathname } = action.payload.location;
pathname: action.payload.location.pathname, const isValidPath = !api.dispatch(RouterActions.isLandingPageUrl(pathname, true));
state: {}, if (isValidPath) {
}); api.dispatch({
type: WALLET.SET_INITIAL_URL,
pathname: action.payload.location.pathname,
state: {},
});
}
// pass action and break process // pass action and break process
return next(action); return next(action);
} }
@ -63,6 +68,29 @@ const WalletService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa
// update common values ONLY if application is ready // update common values ONLY if application is ready
if (!api.getState().wallet.ready) return action; if (!api.getState().wallet.ready) return action;
// observe common values in WallerReducer
if (!(await api.dispatch(WalletActions.observe(prevState, action)))) {
// if "selectedDevice" didn't change observe common values in SelectedAccountReducer
if (!(await api.dispatch(SelectedAccountActions.observe(prevState, action)))) {
// if "selectedAccount" didn't change observe send form props changes
api.dispatch(SendFormActions.observe(prevState, action));
}
} else {
// no changes in common values
if (action.type === CONNECT.RECEIVE_WALLET_TYPE) {
if (action.device.state) {
// redirect to root view (Dashboard) if device was authenticated before
api.dispatch(RouterActions.selectFirstAvailableDevice(true));
}
api.dispatch(TrezorConnectActions.authorizeDevice());
}
if (action.type === CONNECT.AUTH_DEVICE) {
// selected device did changed
// try to restore discovery after device authentication
api.dispatch(DiscoveryActions.restore());
}
}
// double verification needed // double verification needed
// Corner case: LOCATION_CHANGE was called but pathname didn't changed (redirection from RouterService) // Corner case: LOCATION_CHANGE was called but pathname didn't changed (redirection from RouterService)
const prevLocation = prevState.router.location; const prevLocation = prevState.router.location;
@ -96,29 +124,6 @@ const WalletService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa
api.dispatch(NotificationActions.clear(prevLocation.state, currentLocation.state)); api.dispatch(NotificationActions.clear(prevLocation.state, currentLocation.state));
} }
// observe common values in WallerReducer
if (!(await api.dispatch(WalletActions.observe(prevState, action)))) {
// if "selectedDevice" didn't change observe common values in SelectedAccountReducer
if (!(await api.dispatch(SelectedAccountActions.observe(prevState, action)))) {
// if "selectedAccount" didn't change observe send form props changes
api.dispatch(SendFormActions.observe(prevState, action));
}
} else {
// no changes in common values
if (action.type === CONNECT.RECEIVE_WALLET_TYPE) {
if (action.device.state) {
// redirect to root view (Dashboard) if device was authenticated before
api.dispatch(RouterActions.selectFirstAvailableDevice(true));
}
api.dispatch(TrezorConnectActions.authorizeDevice());
}
if (action.type === CONNECT.AUTH_DEVICE) {
// selected device did changed
// try to restore discovery after device authentication
api.dispatch(DiscoveryActions.restore());
}
}
// even if "selectedDevice" didn't change because it was updated on DEVICE.CHANGED before DEVICE.CONNECT action // even if "selectedDevice" didn't change because it was updated on DEVICE.CHANGED before DEVICE.CONNECT action
// try to restore discovery // try to restore discovery
if (action.type === DEVICE.CONNECT) { if (action.type === DEVICE.CONNECT) {