SELF-1190: patch turnkey to prevent keychain deletes (#1388)

* 2.9 release

* 2.9 release

* Remove debug console logs from generateTEEInputsRegister function in registerInputs.ts

* parse only the passport data during the dsc step

* Add ReferralScreen and integrate referral functionality
- Introduced ReferralScreen for sharing referral links via messages, WhatsApp, and clipboard.
- Updated navigation to include ReferralScreen in the home stack.
- Added new icons for sharing and messaging.
- Enhanced points utility functions to check user identity document registration and points disclosure status.
- Minor adjustments to existing components for better integration with the new referral feature.

* fix types

* fix font

* fix vertical spacing

* save current abstraction

* clean up linking

* clean up spurious ai slop comments

* add dinot bold font

* minify animations

* update fonts and add placeholder animation

* fix pipelines

* fix order

* Update dependencies and enhance Points component functionality
- Added `@react-native-masked-view/masked-view` and `react-native-linear-gradient` to dependencies for improved UI components.
- Refactored `PointHistoryList` to accept `ListHeaderComponent` and `onRefreshRef` props for better integration with parent components.
- Enhanced `Points` component to manage notification and backup point events, including user feedback through modals.
- Updated navigation to use `PointsNavBar` for a more cohesive user experience.
- Introduced new utility functions for managing incoming points and point event records.

* update lock

* update lock and project settings

* fix line height for android

* save wip referral message fix and deeplink setup

* Fix whatsapp link (#1352)

* add 2 new lines

* use path based param instead of query string

* use staging url for now

* SELF-1089: Fix black screen on Points (#1351)

* Fix black screen on Points

* Fix: black screen on Referral Page

* fix: prevent BlurView from displaying when IdDetailsScreen loses focus

* Fix Android message share (#1355)

* Referral flow (#1354)

* SELF-1139: update getUserAddress() (#1353)

* update getUserAddress()

* rename getUserAddress to getPointsAddress

* [SELF-1098, SELF-1099] polish gratification screen post referrer update history (#1356)

* fix: mark document as registered after restoring secret (#1350)

* update lock

* create useRegisterReferral hook and test

* add referral message test

* save wip register referral flow request

* use register referral from the home screen

* fix typing and sort screens

* fix linting issues

* register poitns and update tests

* use package

* fix tests

* simplify HomeScreen with hooks

* fix tests

* address tests

* abstract points logic, fix types and linting

* add test referral flow hook

* coderabbit feedback: fix refereral logic issues, remove sensitive logs

* move test referral flow button to dev settings screen

* close modal after referring and viewing gratification screen

* fix tests, remove alert, format

---------

Co-authored-by: Seshanth.S <35675963+seshanthS@users.noreply.github.com>

* add gratification bg; use safe bottom padding hook on home screen

* prep 2.7.4 as 2.9.0

* manually bump version for custom deploy

* match version code

* fix types

* formatting

* fix tests

* SELF-1144 - use real points on home screen and improve points screen (#1361)

* fix whitespace

* move effects for fetching points and incoming points to hooks, add items to deps array so that they refresh when we expect points to change.

* cleanup

* Add events for new Points Flow (#1362)

* remove deeplinkCallback from pointsSelfApp. (#1365)

* fix pipelines

* SELF-978: wire cloudbackup with points (#1360)

* wire cloudbackup with points

* wire cloudbackup with points

* Remove redundant setSelfPoints()

* add signature and simplify POST api requests (#1367)

* add signature and simplify POST api requests

* better gitleaks ignore

* update toml

* have gitguardian ignore gitleaks

* add buffer lib

* update api with 202 success code

* update scope and contract-address (#1366)

* fix navigation test

* SELF-915: Setup and add turnkey utils (#1314)

* Setup and add turnkey utils

* update CloudBackupScreen

* fix: turnkey

* add yarn.lock

* lint

* add podfile.lock

* fix deeplink

* fix tests: mock turnkey

* yarn nice

* update .gitleaksignore

* patch react-native-svg

* fix patch-package

* fix lineHeight

* points.tsx: fix lineHeight

* fix: recover with turnkey disabled state

* fix turnkey flow

* fix: address generation

* minify animations (#1368)

* fix pipelines

* fix false positives

* fix gitguardian

---------

Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz>

* enable turnkey only on success

* use prod url

* fix tests and update mocks

* update version and fastlane readme

* pointsSelfApp: update scope

* bump android version to 117

* incremenet timestamp

* abstract points css, hide explore button for now, add points guardrail

* better logic

* simplify point event list data acquisition (#1375)

* simplify point event list data acquisition

* explain

* Remove BlurView in Points.tsx

* Move Points and IncomingPoints to the Point Events Store (#1363)


* add polling for event processing.
atomically update store state

* handle failed states and use real backend api


* improve concurrency reliability of pointevents

* move points to the store


* refresh all points on pull

* add points tracking events

* fix imports

* fix headers

* fix import

* fix misspelling

* enable apps link

* remove __DEV__ logging

* remove additional referall dev mode features

* Add turnkey env

* don't allow users to refer themselves

* prettier

* trim both addresses

* fix close webview button

* fix tests and format

* lint and format

* Update point rewards in NavBar component: change earned points from 20 to 44 and from 100 to 32.

* Refactor point rewards in NavBar component: replace hardcoded values with constants for backup and notification points, and update subscription state variable names for clarity.

* Update POINT_VALUES in types.ts: adjust point rewards for disclosure, notification, and backup events to 8, 44, and 32 respectively.

* App/fix backup points (#1381)

* Enhance backup completion tracking in Points component: Introduce a ref to manage backup check flag, ensuring points are recorded only when explicitly set, preventing false triggers from other navigation flows.

* Update API endpoint in getTotalPoints function: change URL from /distribution to /points for accurate points retrieval.

* formatting

* update points url

* Clear referrer on modal dismiss in useEarnPointsFlow hook to prevent retry loop

* use points private key to sign api requests

* formatting

* save working version of referral confirmation

* fix circular dependency

* don't fetch private key if unable to fetch points key

* add url

* add debug info

* Refactor optimistic points calculation in usePointEventStore: update return value to only include incomingPoints.amount, marking the optimistic approach for future improvement.

* save clean up

* clean useReferralConfirmation logic

* fix tests

* tests pass

* standardize android compile sdk version

* fix package version

* don't log errors

* Update app/src/hooks/useReferralConfirmation.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* better test

* add turnkey entitlements

* fix linting

* remove entitlements

* prettier and fix lint

* update gradle version

* update lock file

* fix tests

* fix build failure

* bump android version to 118

* update date

* bump version for next build

* address failing pipelines due to cache issues

* Hide turnkey button (#1387)

* prep for 2.9.0 release

* patch turnkey to prevent keychain deletes

* add yarn.lock

* update yarn.lock

* enable buttons

* remove console logging from patch

* fix test

* skip tests

* fix test

* allow users to advance if they backup via turnkey

* Recognize Turnkey backups in onboarding (#1394)

* rename var

* update var name

* remove transform

* simplify tests to avoid oom issues

* fix check

* fix tests

---------

Co-authored-by: turnoffthiscomputer <colin.remi07@gmail.com>
Co-authored-by: Justin Hernandez <justin.hernandez@self.xyz>
Co-authored-by: Leszek Stachowski <leszek.stachowski@self.xyz>
Co-authored-by: Aaron DeRuvo <aaron.deruvo@clabs.co>
Co-authored-by: turnoffthiscomputer <98749896+remicolin@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Seshanth.S
2025-11-12 05:51:10 +05:30
committed by GitHub
parent c4dbb902a3
commit ad726a7286
11 changed files with 194 additions and 127 deletions

View File

@@ -94,7 +94,7 @@ const Points: React.FC = () => {
// Detect when returning from backup screen and record points if backup was completed
useFocusEffect(
React.useCallback(() => {
const { cloudBackupEnabled, backedUpWithTurnKey } =
const { cloudBackupEnabled, turnkeyBackupEnabled } =
useSettingStore.getState();
const currentHasCompletedBackup =
useSettingStore.getState().hasCompletedBackupForPoints;
@@ -103,7 +103,7 @@ const Points: React.FC = () => {
// This prevents false triggers when returning from other flows (like notification permissions)
if (
shouldCheckBackupRef.current &&
(cloudBackupEnabled || backedUpWithTurnKey) &&
(cloudBackupEnabled || turnkeyBackupEnabled) &&
!currentHasCompletedBackup
) {
const recordPoints = async () => {
@@ -265,11 +265,11 @@ const Points: React.FC = () => {
}
selfClient.trackEvent(PointEvents.EARN_BACKUP);
const { cloudBackupEnabled, backedUpWithTurnKey } =
const { cloudBackupEnabled, turnkeyBackupEnabled } =
useSettingStore.getState();
// If either backup method is already enabled, just record points
if (cloudBackupEnabled || backedUpWithTurnKey) {
if (cloudBackupEnabled || turnkeyBackupEnabled) {
setIsBackingUp(true);
try {
// this will add event to store and the new event will then trigger useIncomingPoints hook to refetch incoming points

View File

@@ -52,8 +52,8 @@ const AccountRecoveryChoiceScreen: React.FC = () => {
const { download } = useBackupMnemonic();
const navigation =
useNavigation<NativeStackNavigationProp<RootStackParamList>>();
const setBackedUpWithTurnKey = useSettingStore(
state => state.setBackedUpWithTurnKey,
const setTurnkeyBackupEnabled = useSettingStore(
state => state.setTurnkeyBackupEnabled,
);
const onRestoreFromCloudNext = useHapticNavigation('AccountVerifiedSuccess');
@@ -152,7 +152,7 @@ const AccountRecoveryChoiceScreen: React.FC = () => {
};
const success = await restoreAccountFlow(mnemonic);
if (success) {
setBackedUpWithTurnKey(true);
setTurnkeyBackupEnabled(true);
}
} catch (error) {
console.error('Turnkey restore error:', error);
@@ -160,7 +160,7 @@ const AccountRecoveryChoiceScreen: React.FC = () => {
} finally {
setRestoring(false);
}
}, [getMnemonic, restoreAccountFlow, setBackedUpWithTurnKey, trackEvent]);
}, [getMnemonic, restoreAccountFlow, setTurnkeyBackupEnabled, trackEvent]);
const onRestoreFromCloudPress = useCallback(async () => {
setRestoring(true);
@@ -205,7 +205,7 @@ const AccountRecoveryChoiceScreen: React.FC = () => {
</Description>
<YStack gap="$2.5" width="100%" paddingTop="$6">
{/* <PrimaryButton
<PrimaryButton
trackEvent={BackupEvents.CLOUD_BACKUP_STARTED}
onPress={onRestoreFromTurnkeyPress}
testID="button-from-turnkey"
@@ -218,7 +218,7 @@ const AccountRecoveryChoiceScreen: React.FC = () => {
>
{restoring ? 'Restoring' : 'Restore'} from Turnkey
{restoring ? '' : ''}
</PrimaryButton> */}
</PrimaryButton>
<PrimaryButton
trackEvent={BackupEvents.CLOUD_BACKUP_STARTED}
onPress={onRestoreFromCloudPress}

View File

@@ -50,7 +50,7 @@ const CloudBackupScreen: React.FC<CloudBackupScreenProps> = ({
cloudBackupEnabled,
toggleCloudBackupEnabled,
biometricsAvailable,
backedUpWithTurnKey,
turnkeyBackupEnabled,
} = useSettingStore();
const { upload, disableBackup } = useBackupMnemonic();
const navigation =
@@ -157,7 +157,7 @@ const CloudBackupScreen: React.FC<CloudBackupScreenProps> = ({
buttonTap();
setSelectedMethod('turnkey');
if (backedUpWithTurnKey) {
if (turnkeyBackupEnabled) {
return;
}
@@ -200,7 +200,7 @@ const CloudBackupScreen: React.FC<CloudBackupScreenProps> = ({
setTurnkeyPending(false);
}
}, [
backedUpWithTurnKey,
turnkeyBackupEnabled,
backupAccount,
getOrCreateMnemonic,
showAlreadySignedInModal,
@@ -259,7 +259,7 @@ const CloudBackupScreen: React.FC<CloudBackupScreenProps> = ({
</Pressable>
)}
{/* {backedUpWithTurnKey ? (
{turnkeyBackupEnabled ? (
<SecondaryButton
disabled
trackEvent={BackupEvents.CLOUD_BACKUP_DISABLE_STARTED}
@@ -281,10 +281,11 @@ const CloudBackupScreen: React.FC<CloudBackupScreenProps> = ({
{turnkeyPending ? '…' : ''}
</Text>
</Pressable>
)} */}
)}
<BottomButton
cloudBackupEnabled={cloudBackupEnabled}
turnkeyBackupEnabled={turnkeyBackupEnabled}
nextScreen={params?.nextScreen}
/>
</View>
@@ -303,9 +304,11 @@ const CloudBackupScreen: React.FC<CloudBackupScreenProps> = ({
function BottomButton({
cloudBackupEnabled,
turnkeyBackupEnabled,
nextScreen,
}: {
cloudBackupEnabled: boolean;
turnkeyBackupEnabled: boolean;
nextScreen?: NextScreen;
}) {
const { trackEvent } = useSelfClient();
@@ -318,7 +321,9 @@ function BottomButton({
navigation.goBack();
};
if (nextScreen && cloudBackupEnabled) {
const hasBackup = cloudBackupEnabled || turnkeyBackupEnabled;
if (nextScreen && hasBackup) {
return (
<PrimaryButton
onPress={() => {
@@ -330,7 +335,7 @@ function BottomButton({
Continue
</PrimaryButton>
);
} else if (nextScreen && !cloudBackupEnabled) {
} else if (nextScreen && !hasBackup) {
return (
<SecondaryButton
onPress={() => {
@@ -342,7 +347,7 @@ function BottomButton({
Back up manually
</SecondaryButton>
);
} else if (cloudBackupEnabled) {
} else if (hasBackup) {
return (
<PrimaryButton
onPress={goBack}

View File

@@ -23,7 +23,7 @@ import { black, slate400, white } from '@/utils/colors';
const SaveRecoveryPhraseScreen: React.FC = () => {
const [userHasSeenMnemonic, setUserHasSeenMnemonic] = useState(false);
const { mnemonic, loadMnemonic } = useMnemonic();
const { cloudBackupEnabled } = useSettingStore();
const { cloudBackupEnabled, turnkeyBackupEnabled } = useSettingStore();
const onRevealWords = useCallback(async () => {
await loadMnemonic();
@@ -60,13 +60,14 @@ const SaveRecoveryPhraseScreen: React.FC = () => {
>
<Mnemonic words={mnemonic} onRevealWords={onRevealWords} />
<Caption style={{ color: slate400 }}>
You can reveal your recovery phrase in settings.
You can reveal your recovery phrase or manage your backups in
settings.
</Caption>
<PrimaryButton onPress={onCloudBackupPress}>
Manage {STORAGE_NAME} backups
Manage {STORAGE_NAME} or Turnkey backups
</PrimaryButton>
<SecondaryButton onPress={onSkipPress}>
{userHasSeenMnemonic || cloudBackupEnabled
{userHasSeenMnemonic || cloudBackupEnabled || turnkeyBackupEnabled
? 'Continue'
: 'Skip making a backup'}
</SecondaryButton>

View File

@@ -24,8 +24,8 @@ interface PersistedSettingsState {
setKeychainMigrationCompleted: () => void;
fcmToken: string | null;
setFcmToken: (token: string | null) => void;
backedUpWithTurnKey: boolean;
setBackedUpWithTurnKey: (backedUpWithTurnKey: boolean) => void;
turnkeyBackupEnabled: boolean;
setTurnkeyBackupEnabled: (turnkeyBackupEnabled: boolean) => void;
subscribedTopics: string[];
setSubscribedTopics: (topics: string[]) => void;
addSubscribedTopic: (topic: string) => void;
@@ -103,9 +103,9 @@ export const useSettingStore = create<SettingsState>()(
subscribedTopics: state.subscribedTopics.filter(t => t !== topic),
})),
backedUpWithTurnKey: false,
setBackedUpWithTurnKey: (backedUpWithTurnKey: boolean) =>
set({ backedUpWithTurnKey }),
turnkeyBackupEnabled: false,
setTurnkeyBackupEnabled: (turnkeyBackupEnabled: boolean) =>
set({ turnkeyBackupEnabled }),
hasCompletedBackupForPoints: false,
setBackupForPointsCompleted: () =>
set({ hasCompletedBackupForPoints: true }),

View File

@@ -19,11 +19,11 @@ export function useTurnkeyUtils() {
logout,
} = turnkey;
const setBackedUpWithTurnKey = useSettingStore(
state => state.setBackedUpWithTurnKey,
const setTurnkeyBackupEnabled = useSettingStore(
state => state.setTurnkeyBackupEnabled,
);
const backedUpWithTurnKey = useSettingStore(
state => state.backedUpWithTurnKey,
const turnkeyBackupEnabled = useSettingStore(
state => state.turnkeyBackupEnabled,
);
const [turnkeyWallets, setTurnkeyWallets] = useState<Array<TurnkeyWallet>>(
[],
@@ -60,8 +60,8 @@ export function useTurnkeyUtils() {
await authenticateIfNeeded(authenticate);
const fetchedWallets = await fetchWallets();
if (fetchedWallets.length > 0) {
if (!backedUpWithTurnKey) {
setBackedUpWithTurnKey(true);
if (!turnkeyBackupEnabled) {
setTurnkeyBackupEnabled(true);
}
return { message: 'Wallet restored successfully' };
}
@@ -95,8 +95,8 @@ export function useTurnkeyUtils() {
if (normalizedExisting === normalizedProvided) {
// Same wallet, already backed up
if (!backedUpWithTurnKey) {
setBackedUpWithTurnKey(true);
if (!turnkeyBackupEnabled) {
setTurnkeyBackupEnabled(true);
}
throw new Error('already_backed_up');
} else {
@@ -109,7 +109,7 @@ export function useTurnkeyUtils() {
mnemonic,
walletName: `Self-${new Date().toISOString()}`,
});
setBackedUpWithTurnKey(true);
setTurnkeyBackupEnabled(true);
await refreshWallets();
},
@@ -137,8 +137,8 @@ export function useTurnkeyUtils() {
authState,
authenticateIfNeeded,
fetchWallets,
backedUpWithTurnKey,
setBackedUpWithTurnKey,
turnkeyBackupEnabled,
setTurnkeyBackupEnabled,
importWallet,
exportWallet,
],