mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-02-20 00:33:07 +01:00
feat: disable standard recovery for T1B1 with 12 or 18 words
This commit is contained in:
32
packages/suite/src/utils/suite/recovery.ts
Normal file
32
packages/suite/src/utils/suite/recovery.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { DeviceModelInternal } from '@trezor/device-utils';
|
||||
|
||||
import { RecoveryType, WordCount } from 'src/types/recovery';
|
||||
|
||||
const WORD_COUNT_12 = 12 as const;
|
||||
const WORD_COUNT_18 = 18 as const;
|
||||
|
||||
/**
|
||||
* Determines if a specific recovery type should be disabled for a given device and word count.
|
||||
*
|
||||
* For Trezor Model One (T1B1):
|
||||
* - Standard recovery is disabled for 12 and 18-word seeds (lower security)
|
||||
* - Standard recovery is enabled for 24-word seeds (sufficient entropy)
|
||||
* - Advanced recovery is always available for all word counts
|
||||
*/
|
||||
export const isStandardRecoveryDisabled = (
|
||||
deviceModelInternal: DeviceModelInternal,
|
||||
wordCount: WordCount,
|
||||
recoveryType: RecoveryType,
|
||||
): boolean => {
|
||||
// Advanced recovery is never disabled
|
||||
if (recoveryType === 'advanced') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only disable Standard recovery for T1B1 with 12 or 18-word seeds
|
||||
return (
|
||||
recoveryType === 'standard' &&
|
||||
deviceModelInternal === DeviceModelInternal.T1B1 &&
|
||||
(wordCount === WORD_COUNT_12 || wordCount === WORD_COUNT_18)
|
||||
);
|
||||
};
|
||||
@@ -7,6 +7,7 @@ import { goToNextStep, updateAnalytics } from 'src/actions/onboarding/onboarding
|
||||
import { OnboardingCard } from 'src/components/onboarding/OnboardingCard/OnboardingCard';
|
||||
import { SelectRecoveryType, SelectRecoveryWord, SelectWordCount } from 'src/components/recovery';
|
||||
import { useDispatch, useRecovery, useSelector } from 'src/hooks/suite';
|
||||
import { isStandardRecoveryDisabled } from 'src/utils/suite/recovery';
|
||||
|
||||
import RecoveryStepBox from './RecoveryStepBox';
|
||||
|
||||
@@ -46,7 +47,21 @@ export const RecoveryStep = () => {
|
||||
<SelectWordCount
|
||||
onSelect={number => {
|
||||
setWordsCount(number);
|
||||
setStatus('select-recovery-type');
|
||||
// For T1B1 with 12 or 18 words, skip recovery type selection and use Advanced recovery
|
||||
// For 24 words, show the recovery type selection
|
||||
const shouldSkipSelection = isStandardRecoveryDisabled(
|
||||
deviceModelInternal,
|
||||
number,
|
||||
'standard',
|
||||
);
|
||||
|
||||
if (shouldSkipSelection) {
|
||||
setAdvancedRecovery(true);
|
||||
dispatch(updateAnalytics({ recoveryType: 'advanced' }));
|
||||
recoverDevice();
|
||||
} else {
|
||||
setStatus('select-recovery-type');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</RecoveryStepBox>
|
||||
|
||||
@@ -22,6 +22,7 @@ import { Loading, PinMatrix, WordInputAdvanced } from 'src/components/suite';
|
||||
import { useDevice, useDispatch, useSelector } from 'src/hooks/suite';
|
||||
import type { RecoveryType, WordCount } from 'src/types/recovery';
|
||||
import type { ForegroundAppProps } from 'src/types/suite';
|
||||
import { isStandardRecoveryDisabled } from 'src/utils/suite/recovery';
|
||||
|
||||
import { EnterOnDeviceStep } from './steps/EnterOnDeviceStep';
|
||||
import { InitialStep } from './steps/InitialStep';
|
||||
@@ -193,7 +194,21 @@ export const Recovery = ({ onCancel }: ForegroundAppProps) => {
|
||||
if (!wordCount) return;
|
||||
|
||||
dispatch(setWordsCount(wordCount));
|
||||
dispatch(setStatus('select-recovery-type'));
|
||||
|
||||
// For T1B1 with 12 or 18 words, skip recovery type selection and use Advanced recovery
|
||||
// For 24 words, show the recovery type selection
|
||||
const shouldSkipSelection = isStandardRecoveryDisabled(
|
||||
deviceModelInternal,
|
||||
wordCount,
|
||||
'standard',
|
||||
);
|
||||
|
||||
if (shouldSkipSelection) {
|
||||
dispatch(setAdvancedRecovery(true));
|
||||
dispatch(checkSeed());
|
||||
} else {
|
||||
dispatch(setStatus('select-recovery-type'));
|
||||
}
|
||||
}}
|
||||
data-testid="@recovery/continue-button"
|
||||
>
|
||||
|
||||
@@ -48,10 +48,11 @@ test.describe('Onboarding - recover wallet T1B1', { tag: ['@firmware-ready', '@T
|
||||
await device.powerOn();
|
||||
});
|
||||
|
||||
await test.step('Retry recovery with basic type', async () => {
|
||||
await test.step('Retry recovery with 12 words (automatically uses advanced recovery)', async () => {
|
||||
await onboardingPage.retryRecoveryButton.click({ timeout: 15_000 });
|
||||
// For T1B1 with 12 words, Standard recovery is disabled, so it automatically uses Advanced recovery
|
||||
await recoveryModal.selectWordCount(12);
|
||||
await recoveryModal.selectRecoveryButton('standard').click();
|
||||
// No recovery type selection needed - it goes directly to advanced recovery
|
||||
// Emulator isn't sometimes ready to accept confirm right away. Retry approach doesn't work.
|
||||
await page.waitForTimeout(500);
|
||||
});
|
||||
@@ -61,8 +62,8 @@ test.describe('Onboarding - recover wallet T1B1', { tag: ['@firmware-ready', '@T
|
||||
await device.pressYes();
|
||||
});
|
||||
|
||||
await test.step('Ensure input field for basic recovery is visible', async () => {
|
||||
await expect(page.getByTestId('@word-input-select/input')).toBeVisible();
|
||||
await test.step('Ensure input field for advanced recovery is visible', async () => {
|
||||
await expect(recoveryModal.wordInputAtIndex(1)).toBeVisible();
|
||||
});
|
||||
|
||||
// Note: Completion of reading device data requires support in trezor-user-env
|
||||
|
||||
Reference in New Issue
Block a user