-
Notifications
You must be signed in to change notification settings - Fork 216
SELF-1231: feat- add restore account #1445
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
dd65ac1
415659e
26502cd
8aad749
6d8a6f0
b8ceda4
efb6f26
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,6 +4,7 @@ | |
|
|
||
| import React, { useCallback, useState } from 'react'; | ||
| import { Separator, View, XStack, YStack } from 'tamagui'; | ||
| import type { StaticScreenProps } from '@react-navigation/native'; | ||
| import { useNavigation } from '@react-navigation/native'; | ||
| import type { NativeStackNavigationProp } from '@react-navigation/native-stack'; | ||
|
|
||
|
|
@@ -36,12 +37,20 @@ import { getPrivateKeyFromMnemonic, useAuth } from '@/providers/authProvider'; | |
| import { | ||
| loadPassportData, | ||
| reStorePassportDataWithRightCSCA, | ||
| restoreSecretForAllDocuments, | ||
| } from '@/providers/passportDataProvider'; | ||
| import { STORAGE_NAME, useBackupMnemonic } from '@/services/cloud-backup'; | ||
| import { useSettingStore } from '@/stores/settingStore'; | ||
| import type { Mnemonic } from '@/types/mnemonic'; | ||
|
|
||
| const AccountRecoveryChoiceScreen: React.FC = () => { | ||
| type AccountRecoveryChoiceScreenProps = StaticScreenProps<{ | ||
| restoreAllDocuments?: boolean; | ||
| }>; | ||
|
|
||
| const AccountRecoveryChoiceScreen: React.FC< | ||
| AccountRecoveryChoiceScreenProps | ||
| > = ({ route }) => { | ||
| const restoreAllDocuments = route.params?.restoreAllDocuments ?? false; | ||
| const selfClient = useSelfClient(); | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const { useProtocolStore } = selfClient; | ||
| const { trackEvent } = useSelfClient(); | ||
|
|
@@ -63,13 +72,29 @@ const AccountRecoveryChoiceScreen: React.FC = () => { | |
| // ); | ||
|
|
||
| const onRestoreFromCloudNext = useHapticNavigation('AccountVerifiedSuccess'); | ||
| const onEnterRecoveryPress = useHapticNavigation('RecoverWithPhrase'); | ||
| const onEnterRecoveryPress = useHapticNavigation('RecoverWithPhrase', { | ||
| params: { | ||
| restoreAllDocuments: restoreAllDocuments, | ||
| }, | ||
| }); | ||
|
|
||
| // DISABLED FOR NOW: Turnkey functionality | ||
| // useEffect(() => { | ||
| // refreshWallets(); | ||
| // }, [refreshWallets]); | ||
|
|
||
| const handleRestoreFailed = useCallback( | ||
| (reason: string, hasCSCA: boolean) => { | ||
| console.warn('Failed to restore account'); | ||
| trackEvent(BackupEvents.CLOUD_RESTORE_FAILED_PASSPORT_NOT_REGISTERED, { | ||
| reason: reason, | ||
| hasCSCA: hasCSCA, | ||
| }); | ||
| navigation.navigate({ name: 'Home', params: {} }); | ||
| }, | ||
| [trackEvent, navigation], | ||
| ); | ||
|
Comment on lines
+86
to
+96
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: find . -type f -name "AccountRecoveryChoiceScreen.tsx" | head -5Repository: selfxyz/self Length of output: 122 🏁 Script executed: cat -n app/src/screens/account/recovery/AccountRecoveryChoiceScreen.tsxRepository: selfxyz/self Length of output: 14363 🏁 Script executed: cd app && yarn types 2>&1 | grep -A 5 "AccountRecoveryChoiceScreen"Repository: selfxyz/self Length of output: 38 🏁 Script executed: cd app && yarn types 2>&1 | head -100Repository: selfxyz/self Length of output: 525 🏁 Script executed: cd app && npx tsc --noEmit 2>&1 | grep -A 3 "AccountRecoveryChoiceScreen"Repository: selfxyz/self Length of output: 38 Move Line 95 references Move 🧰 Tools🪛 GitHub Actions: Mobile CI[error] 95-95: TypeScript error: Cannot find name 'setRestoring'. Ensure 'setRestoring' is defined (e.g., from useState) or fix its usage. |
||
|
|
||
| const restoreAccountFlow = useCallback( | ||
| async ( | ||
| mnemonic: Mnemonic, | ||
|
|
@@ -100,54 +125,61 @@ const AccountRecoveryChoiceScreen: React.FC = () => { | |
| return false; | ||
| } | ||
|
|
||
| const passportDataParsed = JSON.parse(passportData); | ||
|
|
||
| const { isRegistered, csca } = | ||
| await isUserRegisteredWithAlternativeCSCA( | ||
| passportDataParsed, | ||
| if (restoreAllDocuments) { | ||
| const successDocuments = await restoreSecretForAllDocuments( | ||
| selfClient, | ||
| secret as string, | ||
| { | ||
| getCommitmentTree(docCategory) { | ||
| return useProtocolStore.getState()[docCategory].commitment_tree; | ||
| }, | ||
| getAltCSCA(docCategory) { | ||
| if (docCategory === 'aadhaar') { | ||
| const publicKeys = | ||
| useProtocolStore.getState().aadhaar.public_keys; | ||
| // Convert string[] to Record<string, string> format expected by AlternativeCSCA | ||
| return publicKeys | ||
| ? Object.fromEntries(publicKeys.map(key => [key, key])) | ||
| : {}; | ||
| } | ||
| ); | ||
| if (successDocuments.length === 0) { | ||
| handleRestoreFailed('all_documents_not_registered', false); | ||
| setRestoring(false); | ||
| return false; | ||
| } | ||
| } else { | ||
| const passportDataParsed = JSON.parse(passportData); | ||
|
|
||
| return useProtocolStore.getState()[docCategory] | ||
| .alternative_csca; | ||
| const { isRegistered, csca } = | ||
| await isUserRegisteredWithAlternativeCSCA( | ||
| passportDataParsed, | ||
| secret as string, | ||
| { | ||
| getCommitmentTree(docCategory) { | ||
| return useProtocolStore.getState()[docCategory] | ||
| .commitment_tree; | ||
| }, | ||
| getAltCSCA(docCategory) { | ||
| if (docCategory === 'aadhaar') { | ||
| const publicKeys = | ||
| useProtocolStore.getState().aadhaar.public_keys; | ||
| // Convert string[] to Record<string, string> format expected by AlternativeCSCA | ||
| return publicKeys | ||
| ? Object.fromEntries(publicKeys.map(key => [key, key])) | ||
| : {}; | ||
| } | ||
|
|
||
| return useProtocolStore.getState()[docCategory] | ||
| .alternative_csca; | ||
| }, | ||
| }, | ||
| }, | ||
| ); | ||
| if (!isRegistered) { | ||
| console.warn( | ||
| 'Secret provided did not match a registered ID. Please try again.', | ||
| ); | ||
| trackEvent( | ||
| BackupEvents.CLOUD_RESTORE_FAILED_PASSPORT_NOT_REGISTERED, | ||
| { | ||
| reason: 'document_not_registered', | ||
| hasCSCA: !!csca, | ||
| }, | ||
| ); | ||
| if (!isRegistered) { | ||
| console.warn( | ||
| 'Secret provided did not match a registered ID. Please try again.', | ||
| ); | ||
| handleRestoreFailed('document_not_registered', !!csca); | ||
| setRestoring(false); | ||
| return false; | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (isCloudRestore && !cloudBackupEnabled) { | ||
| toggleCloudBackupEnabled(); | ||
| } | ||
| await reStorePassportDataWithRightCSCA( | ||
|
Comment on lines
+128
to
+176
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cloud backup toggle is skipped for “restore all documents” cloud restores In if (restoreAllDocuments) {
const successDocuments = await restoreSecretForAllDocuments(...);
if (successDocuments.length === 0) {
handleRestoreFailed(...);
setRestoring(false);
return false;
}
} else {
// ...
if (isCloudRestore && !cloudBackupEnabled) {
toggleCloudBackupEnabled();
}
await reStorePassportDataWithRightCSCA(...);
await markCurrentDocumentAsRegistered(selfClient);
}When You can restore the original “enable backup whenever a cloud restore succeeds” behavior (for both single-doc and all-doc flows) by moving the toggle to after the branch, just before logging success: - if (isCloudRestore && !cloudBackupEnabled) {
- toggleCloudBackupEnabled();
- }
- await reStorePassportDataWithRightCSCA(
+ await reStorePassportDataWithRightCSCA(
passportDataParsed,
csca as string,
);
await markCurrentDocumentAsRegistered(selfClient);
}
-
- trackEvent(BackupEvents.CLOUD_RESTORE_SUCCESS);
+ if (isCloudRestore && !cloudBackupEnabled) {
+ toggleCloudBackupEnabled();
+ }
+
+ trackEvent(BackupEvents.CLOUD_RESTORE_SUCCESS);This keeps the early-return failure paths unchanged while ensuring any successful cloud-based restore (single doc or all docs) leaves the account with cloud backup correctly enabled. Also applies to: 183-187, 198-209 🤖 Prompt for AI Agents |
||
| passportDataParsed, | ||
| csca as string, | ||
| ); | ||
| navigation.navigate({ name: 'Home', params: {} }); | ||
| setRestoring(false); | ||
| return false; | ||
| await markCurrentDocumentAsRegistered(selfClient); | ||
| } | ||
| if (isCloudRestore && !cloudBackupEnabled) { | ||
| toggleCloudBackupEnabled(); | ||
| } | ||
| await reStorePassportDataWithRightCSCA( | ||
| passportDataParsed, | ||
| csca as string, | ||
| ); | ||
| await markCurrentDocumentAsRegistered(selfClient); | ||
|
|
||
| trackEvent(BackupEvents.CLOUD_RESTORE_SUCCESS); | ||
| trackEvent(BackupEvents.ACCOUNT_RECOVERY_COMPLETED); | ||
| onRestoreFromCloudNext(); | ||
|
|
@@ -164,14 +196,16 @@ const AccountRecoveryChoiceScreen: React.FC = () => { | |
| } | ||
| }, | ||
| [ | ||
| trackEvent, | ||
| restoreAccountFromMnemonic, | ||
| cloudBackupEnabled, | ||
| restoreAllDocuments, | ||
| trackEvent, | ||
| onRestoreFromCloudNext, | ||
| navigation, | ||
| toggleCloudBackupEnabled, | ||
| useProtocolStore, | ||
| selfClient, | ||
| handleRestoreFailed, | ||
| cloudBackupEnabled, | ||
| useProtocolStore, | ||
| toggleCloudBackupEnabled, | ||
| ], | ||
| ); | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid hard‑coding
'prod'when fetching Aadhaar protocol data in bulk restoreIn
restoreSecretForAllDocuments, Aadhaar keys are loaded with a hard‑coded production environment:This couples bulk restore to prod only and will likely break or silently mis‑verify documents in staging/dev (or any non‑prod environment), since the commitment tree and public keys won’t match the environment the app/selfClient is actually using.
Consider deriving the environment from existing configuration (e.g., a field on
selfClient, a global env setting, or whatever your other protocol-store fetches already use) and passing that through instead of a literal:This keeps restore behavior aligned with the currently active network and avoids hard‑to‑debug environment mismatches.
Also applies to: 892-947
🤖 Prompt for AI Agents
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The screen where we hardcoded will be accessible only in the ‘prod’ environment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@seshanthS, thanks for clarifying! If the restore feature is prod-only by design, then hard-coding
'prod'is reasonable.To make that constraint more explicit for future maintainers, you could consider adding a comment above the fetch call:
Or if you want to be extra defensive, add a runtime check that throws early if someone tries to use this in non-prod. But if the UI already enforces the prod-only access, the current approach is fine.
🧠 Learnings used