Skip to content

Commit

Permalink
feat(suite): exonerate persisted failed FW by automatic hash check
Browse files Browse the repository at this point in the history
  • Loading branch information
Lemonexe committed Dec 6, 2024
1 parent 9140df2 commit e8fbc88
Show file tree
Hide file tree
Showing 4 changed files with 21 additions and 2 deletions.
2 changes: 2 additions & 0 deletions packages/suite/src/middlewares/wallet/storageMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,8 @@ const storageMiddleware = (api: MiddlewareAPI<Dispatch, AppState>) => {
case FORM_DRAFT.REMOVE_DRAFT:
storageActions.removeFormDraft(action.key);
break;

case deviceActions.connectDevice.type: // so that firmwareReducer.addCase for the same action is persisted
case firmwareActions.clearInvalidHash.type:
case firmwareActions.setHashInvalid.type:
api.dispatch(storageActions.saveFirmware());
Expand Down
13 changes: 13 additions & 0 deletions suite-common/firmware/src/firmwareReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
} from '@trezor/connect';
import { createReducerWithExtraDeps } from '@suite-common/redux-utils';
import { deviceActions } from '@suite-common/wallet-core';
import { isDeviceKnown } from '@suite-common/suite-utils';

import { firmwareActions } from './firmwareActions';

Expand Down Expand Up @@ -86,6 +87,18 @@ export const prepareFirmwareReducer = createReducerWithExtraDeps(initialState, (
state.cachedDevice = payload;
})
.addCase(deviceActions.addButtonRequest, extra.reducers.addButtonRequestFirmware)
.addCase(deviceActions.connectDevice, (state, { payload: { device } }) => {
if (!isDeviceKnown(device)) return;

// use the automatic hash check to clear device if it hasn't passed hash check done after firmware update
// otherwise it'd be stuck in "error" state until next firmware update
// in `storageMiddleware` this is persisted into storage (on the same action type)
if (device.authenticityChecks?.firmwareHash?.success) {
state.firmwareHashInvalid = state.firmwareHashInvalid.filter(
deviceId => deviceId !== device.id,
);
}
})
.addMatcher(
action => action.type === extra.actionTypes.storageLoad,
extra.reducers.storageLoadFirmware,
Expand Down
2 changes: 1 addition & 1 deletion suite-common/firmware/src/firmwareThunks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ export const firmwareUpdate = createThunk<
// hash check was performed, and it does not match, so consider firmware counterfeit
dispatch(handleFwHashMismatch(device));
} else if (check === 'other-error') {
// device failed to respond to the hash check, consider the firmware counterfeit
// device failed to respond, so display a warning in the modal
dispatch(
handleFwHashError({
errorMessage: firmwareUpdateResponse.payload.checkError,
Expand Down
6 changes: 5 additions & 1 deletion suite-common/suite-utils/src/device.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Device, UnavailableCapability, DeviceModelInternal } from '@trezor/connect';
import { Device, UnavailableCapability, DeviceModelInternal, KnownDevice } from '@trezor/connect';
import { TrezorDevice, AcquiredDevice } from '@suite-common/suite-types';
import * as URLS from '@trezor/urls';

Expand Down Expand Up @@ -119,6 +119,10 @@ export const isDeviceAccessible = (device?: TrezorDevice) => {
return device.mode === 'normal' && device.firmware !== 'required';
};

// useful for working with `Device` type straight from connect, which is missing `ExtendedDevice` properties (required on `TrezorDevice`)
export const isDeviceKnown = (device?: Device): device is KnownDevice =>
device?.type === 'acquired';

export const isDeviceAcquired = (device?: TrezorDevice): device is AcquiredDevice =>
!!device?.features;

Expand Down

0 comments on commit e8fbc88

Please sign in to comment.