1
0
mirror of https://github.com/trezor/trezor-wallet synced 2025-05-08 09:58:47 +00:00

Merge pull request #500 from trezor/fix/setInitialUrl-race-condition

fix: setInitialUrl - race condition
This commit is contained in:
Vladimir Volek 2019-04-15 15:13:28 +02:00 committed by GitHub
commit bcd618aa0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 47 additions and 40 deletions

View File

@ -429,30 +429,36 @@ export const setInitialUrl = (): PayloadAction<boolean> => (
dispatch: Dispatch, dispatch: Dispatch,
getState: GetState getState: GetState
): boolean => { ): boolean => {
const { initialPathname } = getState().wallet; // DEVICE.CONNECT race condition, "selectDevice" method was called but currently selectedDevice is in getState (auth) process
if (typeof initialPathname === 'string' && !dispatch(isLandingPageUrl(initialPathname, true))) { // if so, consume this action (return true) to break "selectDevice" process
const valid = dispatch( const { selectedDevice } = getState().wallet;
getValidUrl({ if (selectedDevice && selectedDevice.type === 'acquired' && !selectedDevice.state) return true;
type: LOCATION_CHANGE,
payload: {
location: {
pathname: initialPathname,
hash: '',
search: '',
state: {},
},
},
})
);
if (valid === initialPathname) { const { initialPathname } = getState().wallet;
// reset initial url if (typeof initialPathname !== 'string') return false;
dispatch({
type: SET_INITIAL_URL, const valid = dispatch(
}); getValidUrl({
dispatch(goto(valid)); type: LOCATION_CHANGE,
return true; 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

@ -169,15 +169,11 @@ export const observe = (prevState: State, action: Action): PayloadAction<boolean
const state: State = getState(); const state: State = getState();
const locationChanged = reducerUtils.observeChanges(
prevState.router.location,
state.router.location
);
const device = reducerUtils.getSelectedDevice(state); const device = reducerUtils.getSelectedDevice(state);
const selectedDeviceChanged = reducerUtils.observeChanges(state.wallet.selectedDevice, device); const selectedDeviceChanged = reducerUtils.observeChanges(state.wallet.selectedDevice, device);
// handle devices state change (from trezor-connect events or location change) // handle devices state change (from trezor-connect events or location change)
if (locationChanged || selectedDeviceChanged) { if (selectedDeviceChanged) {
if (device && deviceUtils.isSelectedDevice(state.wallet.selectedDevice, device)) { if (device && deviceUtils.isSelectedDevice(state.wallet.selectedDevice, device)) {
dispatch({ dispatch({
type: WALLET.UPDATE_SELECTED_DEVICE, type: WALLET.UPDATE_SELECTED_DEVICE,

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,
state: {},
});
}
// pass action and break process // pass action and break process
return next(action); return next(action);
} }
@ -42,10 +47,8 @@ const WalletService: Middleware = (api: MiddlewareAPI) => (next: MiddlewareDispa
next(action); next(action);
switch (action.type) { switch (action.type) {
case WALLET.SET_INITIAL_URL: case WALLET.SET_FIRST_LOCATION_CHANGE:
if (action.pathname) { api.dispatch(LocalStorageActions.loadData());
api.dispatch(LocalStorageActions.loadData());
}
break; break;
case WALLET.SET_SELECTED_DEVICE: case WALLET.SET_SELECTED_DEVICE:
// try to authorize device // try to authorize device
@ -63,6 +66,9 @@ 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;
// check for "selectedDevice" change before any action
const selectedDeviceDidChange = await api.dispatch(WalletActions.observe(prevState, action));
// 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,9 +102,8 @@ 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 "selectedDevice" didn't change observe common values in SelectedAccountReducer
if (!(await api.dispatch(WalletActions.observe(prevState, action)))) { if (!selectedDeviceDidChange) {
// if "selectedDevice" didn't change observe common values in SelectedAccountReducer
if (!(await api.dispatch(SelectedAccountActions.observe(prevState, action)))) { if (!(await api.dispatch(SelectedAccountActions.observe(prevState, action)))) {
// if "selectedAccount" didn't change observe send form props changes // if "selectedAccount" didn't change observe send form props changes
api.dispatch(SendFormActions.observe(prevState, action)); api.dispatch(SendFormActions.observe(prevState, action));