Skip to content

Commit

Permalink
feat(suite-native): handle pin by state, not button requests (#12889)
Browse files Browse the repository at this point in the history
* feat(suite-native): handle pin by state, not button requests

* refactor(suite-native): simplify conditions in slice
  • Loading branch information
juriczech authored Jul 1, 2024
1 parent fa514a6 commit 47b69ae
Show file tree
Hide file tree
Showing 22 changed files with 111 additions and 70 deletions.
14 changes: 0 additions & 14 deletions suite-common/wallet-core/src/device/deviceReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -655,20 +655,6 @@ export const selectDeviceButtonRequestsCodes = (state: DeviceRootState) => {

export const selectDeviceMode = (state: DeviceRootState) => state.device.selectedDevice?.mode;

export const selectDeviceRequestedPin = (state: DeviceRootState) => {
const buttonRequestsCodes = selectDeviceButtonRequestsCodes(state);
const isDeviceProtectedByPin = selectIsDeviceProtectedByPin(state);

if (!isDeviceProtectedByPin) return false;

const pinEntryButtonRequestCodes: ButtonRequest['code'][] = [
'PinMatrixRequestType_Current', // T1 with PIN matrix in app
'ButtonRequest_PinEntry', // T2 with PIN entry on device
];

return pinEntryButtonRequestCodes.includes(buttonRequestsCodes.at(-1));
};

export const selectIsUnacquiredDevice = (state: DeviceRootState) => {
const deviceType = selectDeviceType(state);

Expand Down
17 changes: 17 additions & 0 deletions suite-native/device-authorization/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"name": "@suite-native/device-authorization",
"version": "1.0.0",
"private": true,
"license": "See LICENSE.md in repo root",
"sideEffects": false,
"main": "src/index",
"scripts": {
"lint:js": "yarn g:eslint '**/*.{ts,tsx,js}'",
"depcheck": "yarn g:depcheck",
"type-check": "yarn g:tsc --build"
},
"dependencies": {
"@reduxjs/toolkit": "1.9.5",
"@trezor/connect": "workspace:*"
}
}
44 changes: 44 additions & 0 deletions suite-native/device-authorization/src/deviceAuthorizationSlice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { createSlice } from '@reduxjs/toolkit';

import { UI } from '@trezor/connect';

import { isPinButtonRequestCode } from './utils';

type DeviceAuthorizationState = {
hasDeviceRequestedPin: boolean;
};

type DeviceAuthorizationRootState = {
deviceAuthorization: DeviceAuthorizationState;
};

const deviceAuthorizationInitialState: DeviceAuthorizationState = {
hasDeviceRequestedPin: false,
};

export const deviceAuthorizationSlice = createSlice({
name: 'deviceAuthorization',
initialState: deviceAuthorizationInitialState,
reducers: {},
extraReducers: builder => {
builder
.addCase(UI.REQUEST_PIN, state => {
state.hasDeviceRequestedPin = true;
})
.addCase(UI.REQUEST_BUTTON, (state, action) => {
if (isPinButtonRequestCode(action)) {
state.hasDeviceRequestedPin = true;
} else {
state.hasDeviceRequestedPin = false;
}
})
.addCase(UI.CLOSE_UI_WINDOW, state => {
state.hasDeviceRequestedPin = false;
});
},
});

export const selectDeviceRequestedPin = (state: DeviceAuthorizationRootState) =>
state.deviceAuthorization.hasDeviceRequestedPin;

export const deviceAuthorizationReducer = deviceAuthorizationSlice.reducer;
2 changes: 2 additions & 0 deletions suite-native/device-authorization/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './deviceAuthorizationSlice';
export * from './utils';
5 changes: 5 additions & 0 deletions suite-native/device-authorization/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { AnyAction } from '@reduxjs/toolkit';

export const isPinButtonRequestCode = (action: AnyAction) =>
action.payload.code === 'ButtonRequest_PinEntry' || // T2 with PIN entry on device
action.payload.code === 'PinMatrixRequestType_Current'; // T1 with PIN matrix in app
7 changes: 7 additions & 0 deletions suite-native/device-authorization/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": { "outDir": "libDev" },
"references": [
{ "path": "../../packages/connect" }
]
}
1 change: 1 addition & 0 deletions suite-native/device/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"@suite-native/analytics": "workspace:*",
"@suite-native/atoms": "workspace:*",
"@suite-native/biometrics": "workspace:*",
"@suite-native/device-authorization": "workspace:*",
"@suite-native/device-mutex": "workspace:*",
"@suite-native/feature-flags": "workspace:*",
"@suite-native/intl": "workspace:*",
Expand Down
2 changes: 1 addition & 1 deletion suite-native/device/src/hooks/useHandleDeviceConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ import {
} from '@suite-native/navigation';
import {
selectIsPortfolioTrackerDevice,
selectDeviceRequestedPin,
selectIsDeviceConnected,
selectIsDeviceConnectedAndAuthorized,
selectIsNoPhysicalDeviceConnected,
selectIsDeviceUsingPassphrase,
authorizeDeviceThunk,
} from '@suite-common/wallet-core';
import { selectDeviceRequestedPin } from '@suite-native/device-authorization';
import { selectIsOnboardingFinished } from '@suite-native/settings';
import { requestPrioritizedDeviceAccess } from '@suite-native/device-mutex';
import { useIsBiometricsOverlayVisible } from '@suite-native/biometrics';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const prepareButtonRequestMiddleware = createMiddlewareWithExtraDeps(

if (action.type === UI.REQUEST_BUTTON) {
const { device: _, ...request } = action.payload;

dispatch(
deviceActions.addButtonRequest({
device: selectDevice(getState()),
Expand Down
1 change: 1 addition & 0 deletions suite-native/device/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
{ "path": "../analytics" },
{ "path": "../atoms" },
{ "path": "../biometrics" },
{ "path": "../device-authorization" },
{ "path": "../device-mutex" },
{ "path": "../feature-flags" },
{ "path": "../intl" },
Expand Down
1 change: 1 addition & 0 deletions suite-native/module-connect-device/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@suite-native/alerts": "workspace:*",
"@suite-native/atoms": "workspace:*",
"@suite-native/device": "workspace:*",
"@suite-native/device-authorization": "workspace:*",
"@suite-native/device-mutex": "workspace:*",
"@suite-native/forms": "workspace:*",
"@suite-native/intl": "workspace:*",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { BackHandler } from 'react-native';
import { useCallback, useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useSelector } from 'react-redux';

import { useNavigation } from '@react-navigation/native';

import TrezorConnect, { DeviceModelInternal } from '@trezor/connect';
import TrezorConnect from '@trezor/connect';
import {
ConnectDeviceStackParamList,
ConnectDeviceStackRoutes,
Expand All @@ -14,12 +14,7 @@ import {
import { Box, IconButton, ScreenHeaderWrapper } from '@suite-native/atoms';
import { useAlert } from '@suite-native/alerts';
import { Translation } from '@suite-native/intl';
import {
selectDevice,
selectDeviceModel,
removeButtonRequests,
selectIsDeviceDiscoveryActive,
} from '@suite-common/wallet-core';
import { selectIsDeviceDiscoveryActive } from '@suite-common/wallet-core';

import { ConnectingTrezorHelp } from './ConnectingTrezorHelp';

Expand All @@ -37,11 +32,8 @@ export const ConnectDeviceScreenHeader = ({
shouldDisplayCancelButton = true,
}: ConnectDeviceScreenHeaderProps) => {
const navigation = useNavigation<NavigationProp>();
const dispatch = useDispatch();
const { showAlert, hideAlert } = useAlert();

const device = useSelector(selectDevice);
const deviceModel = useSelector(selectDeviceModel);
const isDiscoveryActive = useSelector(selectIsDeviceDiscoveryActive);

const handleCancel = useCallback(() => {
Expand All @@ -61,21 +53,11 @@ export const ConnectDeviceScreenHeader = ({
});
} else {
TrezorConnect.cancel('pin-cancelled');

dispatch(
removeButtonRequests({
device,
buttonRequestCode:
deviceModel === DeviceModelInternal.T1B1
? 'PinMatrixRequestType_Current'
: 'ButtonRequest_PinEntry',
}),
);
if (navigation.canGoBack()) {
navigation.goBack();
}
}
}, [device, deviceModel, dispatch, isDiscoveryActive, navigation, showAlert, hideAlert]);
}, [hideAlert, isDiscoveryActive, navigation, showAlert]);

// Handle hardware back button press same as cancel button
useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useSelector } from 'react-redux';
import { BottomSheet, IconButton, Text, VStack } from '@suite-native/atoms';
import { Translation } from '@suite-native/intl';
import { Link } from '@suite-native/link';
import { selectDeviceRequestedPin } from '@suite-common/wallet-core';
import { selectDeviceRequestedPin } from '@suite-native/device-authorization';

import { PIN_HELP_URL } from '../constants/pinFormConstants';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,7 @@ import {
RootStackParamList,
StackToStackCompositeNavigationProps,
} from '@suite-native/navigation';
import {
selectDevice,
selectDeviceAuthFailed,
removeButtonRequests,
authorizeDeviceThunk,
} from '@suite-common/wallet-core';
import { selectDeviceAuthFailed, authorizeDeviceThunk } from '@suite-common/wallet-core';
import { useAlert } from '@suite-native/alerts';
import { useOpenLink } from '@suite-native/link';
import { requestPrioritizedDeviceAccess } from '@suite-native/device-mutex';
Expand Down Expand Up @@ -59,21 +54,14 @@ export const PinFormControlButtons = () => {
const navigation = useNavigation<NavigationProp>();
const { showAlert } = useAlert();
const { handleSubmit, getValues, watch, setValue, reset } = useFormContext();
const device = useSelector(selectDevice);
const hasDeviceAuthFailed = useSelector(selectDeviceAuthFailed);

const handleSuccess = useCallback(() => {
if (navigation.canGoBack()) {
navigation.goBack();
}
reset();
dispatch(
removeButtonRequests({
device,
buttonRequestCode: 'PinMatrixRequestType_Current',
}),
);
}, [device, dispatch, navigation, reset]);
}, [navigation, reset]);

const handleDeviceChange = useCallback(() => {
if (hasDeviceAuthFailed) {
Expand Down
20 changes: 3 additions & 17 deletions suite-native/module-connect-device/src/components/PinOnDevice.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import { useDispatch, useSelector } from 'react-redux';
import { useSelector } from 'react-redux';
import { Dimensions } from 'react-native';
import { useCallback, useEffect } from 'react';

import { useNavigation } from '@react-navigation/native';

import { Image, Box, Text } from '@suite-native/atoms';
import { DeviceModelInternal } from '@trezor/connect';
import {
removeButtonRequests,
selectDevice,
selectDeviceRequestedPin,
} from '@suite-common/wallet-core';
import { selectDeviceRequestedPin } from '@suite-native/device-authorization';
import { Translation } from '@suite-native/intl';
import { prepareNativeStyle, useNativeStyles } from '@trezor/styles';
import TrezorConnect, { UI_REQUEST } from '@trezor/connect';

const SCREEN_HEIGHT = Dimensions.get('screen').height;

Expand Down Expand Up @@ -43,19 +38,16 @@ type PinOnDeviceProps = {
};

export const PinOnDevice = ({ deviceModel }: PinOnDeviceProps) => {
const dispatch = useDispatch();
const navigation = useNavigation();

const device = useSelector(selectDevice);
const hasDeviceRequestedPin = useSelector(selectDeviceRequestedPin);
const { applyStyle } = useNativeStyles();

const handleSuccess = useCallback(() => {
if (navigation.canGoBack()) {
navigation.goBack();
}
dispatch(removeButtonRequests({ device, buttonRequestCode: 'ButtonRequest_PinEntry' }));
}, [navigation, dispatch, device]);
}, [navigation]);

useEffect(() => {
// hasDeviceRequestedPin is false when the user unlocks the device again
Expand All @@ -66,12 +58,6 @@ export const PinOnDevice = ({ deviceModel }: PinOnDeviceProps) => {
}
}, [hasDeviceRequestedPin, handleSuccess]);

useEffect(() => {
TrezorConnect.on(UI_REQUEST.CLOSE_UI_WINDOW, handleSuccess);

return () => TrezorConnect.off(UI_REQUEST.CLOSE_UI_WINDOW, handleSuccess);
}, [handleSuccess]);

return (
<Box style={applyStyle(wrapperStyle)}>
<Text variant="titleMedium" textAlign="center">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
ConnectDeviceStackRoutes,
stackNavigationOptionsConfig,
} from '@suite-native/navigation';
import { selectDeviceRequestedPin } from '@suite-common/wallet-core';
import { selectDeviceRequestedPin } from '@suite-native/device-authorization';
import { useDetectDeviceError, useReportDeviceConnectToAnalytics } from '@suite-native/device';

import { ConnectAndUnlockDeviceScreen } from '../screens/ConnectAndUnlockDeviceScreen';
Expand Down
1 change: 1 addition & 0 deletions suite-native/module-connect-device/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
{ "path": "../alerts" },
{ "path": "../atoms" },
{ "path": "../device" },
{ "path": "../device-authorization" },
{ "path": "../device-mutex" },
{ "path": "../forms" },
{ "path": "../intl" },
Expand Down
1 change: 1 addition & 0 deletions suite-native/state/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@suite-native/blockchain": "workspace:*",
"@suite-native/config": "workspace:*",
"@suite-native/device": "workspace:*",
"@suite-native/device-authorization": "workspace:*",
"@suite-native/discovery": "workspace:*",
"@suite-native/feature-flags": "workspace:*",
"@suite-native/graph": "workspace:*",
Expand Down
2 changes: 2 additions & 0 deletions suite-native/state/src/reducers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { combineReducers } from '@reduxjs/toolkit';

import { deviceAuthorizationReducer } from '@suite-native/device-authorization';
import {
feesReducer,
prepareAccountsReducer,
Expand Down Expand Up @@ -139,6 +140,7 @@ export const prepareRootReducers = async () => {
featureFlags: featureFlagsPersistedReducer,
graph: graphReducer,
device: devicePersistedReducer,
deviceAuthorization: deviceAuthorizationReducer,
logs: logsSlice.reducer,
notifications: notificationsReducer,
discoveryConfig: discoveryConfigPersistedReducer,
Expand Down
1 change: 1 addition & 0 deletions suite-native/state/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
{ "path": "../blockchain" },
{ "path": "../config" },
{ "path": "../device" },
{ "path": "../device-authorization" },
{ "path": "../discovery" },
{ "path": "../feature-flags" },
{ "path": "../graph" },
Expand Down
3 changes: 3 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@
{ "path": "suite-native/blockchain" },
{ "path": "suite-native/config" },
{ "path": "suite-native/device" },
{
"path": "suite-native/device-authorization"
},
{ "path": "suite-native/device-manager" },
{ "path": "suite-native/device-mutex" },
{ "path": "suite-native/discovery" },
Expand Down
Loading

0 comments on commit 47b69ae

Please sign in to comment.