diff --git a/apps/easypid/src/app/+native-intent.tsx b/apps/easypid/src/app/+native-intent.tsx index 22df945f..b63e3f22 100644 --- a/apps/easypid/src/app/+native-intent.tsx +++ b/apps/easypid/src/app/+native-intent.tsx @@ -1,5 +1,6 @@ import 'fast-text-encoding' +import { TypedArrayEncoder } from '@credo-ts/core' import { appScheme } from '@easypid/constants' import { parseInvitationUrl } from '@package/agent' import { deeplinkSchemes } from '@package/app' @@ -57,14 +58,18 @@ export async function redirectSystemPath({ path, initial }: { path: string; init } if (redirectPath) { + // Always make the user authenticate first when opening with a deeplink + const encodedRedirect = TypedArrayEncoder.toBase64URL(TypedArrayEncoder.fromString(redirectPath)) + const newPath = `/authenticate?redirectAfterUnlock=${encodedRedirect}` + // NOTE: it somehow doesn't handle the intent if the app is already open // so we replace the router to the path. I think it can break easily though if e.g. // the wallet is locked in the background. Not sure how to proceed, this is best effort fix if (!initial) { - router.replace(redirectPath) + router.replace(newPath) return null } - return redirectPath + return newPath } void Haptics.notificationAsync(Haptics.NotificationFeedbackType.Error) diff --git a/apps/easypid/src/app/authenticate.tsx b/apps/easypid/src/app/authenticate.tsx index f9f64d6f..e366abe4 100644 --- a/apps/easypid/src/app/authenticate.tsx +++ b/apps/easypid/src/app/authenticate.tsx @@ -27,6 +27,14 @@ export default function Authenticate() { const isLoading = secureUnlock.state === 'acquired-wallet-key' || (secureUnlock.state === 'locked' && secureUnlock.isUnlocking) + // If there is a redirectAfterUnlock param, we require the user to authenticate again + // biome-ignore lint/correctness/useExhaustiveDependencies: only check on component mount + useEffect(() => { + if (secureUnlock.state === 'unlocked' && redirectAfterUnlock) { + secureUnlock.lock() + } + }, []) + // After resetting the wallet, we want to avoid prompting for face id immediately // So we add an artificial delay useEffect(() => { diff --git a/apps/easypid/src/features/menu/FunkeMenuScreen.tsx b/apps/easypid/src/features/menu/FunkeMenuScreen.tsx index 76e2516f..f3d95f9b 100644 --- a/apps/easypid/src/features/menu/FunkeMenuScreen.tsx +++ b/apps/easypid/src/features/menu/FunkeMenuScreen.tsx @@ -1,5 +1,6 @@ import type React from 'react' +import { useSecureUnlock } from '@easypid/agent' import { useFeatureFlag } from '@easypid/hooks/useFeatureFlag' import { useWalletReset } from '@easypid/hooks/useWalletReset' import { useCredentialByCategory } from '@package/agent/src/hooks/useCredentialByCategory' @@ -62,13 +63,19 @@ export function FunkeMenuScreen() { const { handleScroll, isScrolledByOffset, scrollEventThrottle } = useScrollViewPosition() const onResetWallet = useWalletReset() const { withHaptics } = useHaptics() - + const secureUnlock = useSecureUnlock() const { credential, isLoading } = useCredentialByCategory('DE-PID') const hasEidCardFeatureFlag = useFeatureFlag('EID_CARD') const handleFeedback = withHaptics(() => Linking.openURL('mailto:ana@animo.id?subject=Feedback on the Wallet')) const handlePush = (path: string) => withHaptics(() => router.push(path)) + const handleLock = () => { + if (secureUnlock.state === 'unlocked') { + secureUnlock.lock() + } + } + return ( @@ -117,6 +124,7 @@ export function FunkeMenuScreen() { icon={} label="About this wallet" /> + } label="Lock app" /> { + if (router.canGoBack()) { + router.back() + } else { + router.replace('/') + } + } + return ( - router.back())} scaleOnPress> + Back ) diff --git a/packages/app/src/provider/BackgroundLockProvider.tsx b/packages/app/src/provider/BackgroundLockProvider.tsx index 9553a83d..3527b0f7 100644 --- a/packages/app/src/provider/BackgroundLockProvider.tsx +++ b/packages/app/src/provider/BackgroundLockProvider.tsx @@ -1,6 +1,6 @@ import type { PropsWithChildren } from 'react' -import { useSecureUnlock } from '@package/secure-store/secure-wallet-key/SecureUnlockProvider' +import { useSecureUnlock } from '@easypid/agent' import { useRouter } from 'expo-router' import { useEffect, useRef } from 'react' import { AppState, type AppStateStatus } from 'react-native'