diff --git a/client-app/app/(app)/chats/[id].tsx b/client-app/app/(app)/chats/[id].tsx index c8fec3b..518cd48 100644 --- a/client-app/app/(app)/chats/[id].tsx +++ b/client-app/app/(app)/chats/[id].tsx @@ -26,7 +26,7 @@ import { encryptMessage } from '@/lib/crypto'; import { sendEnvelope } from '@/lib/api'; import { getWSClient } from '@/lib/ws'; import { appendMessage, loadMessages } from '@/lib/storage'; -import { randomId } from '@/lib/utils'; +import { randomId, safeBack } from '@/lib/utils'; import type { Message } from '@/lib/types'; import { Avatar } from '@/components/Avatar'; @@ -404,7 +404,7 @@ export default function ChatScreen() { ) : (
router.back()} />} + left={ safeBack()} />} title={ - router.back()} hitSlop={8}> + safeBack()} hitSlop={8}> diff --git a/client-app/app/(app)/feed/[id].tsx b/client-app/app/(app)/feed/[id].tsx index 46fb1af..3ab9f59 100644 --- a/client-app/app/(app)/feed/[id].tsx +++ b/client-app/app/(app)/feed/[id].tsx @@ -31,6 +31,7 @@ import { fetchPost, fetchStats, bumpView, formatCount, formatFee, type FeedPostItem, type PostStats, } from '@/lib/feed'; +import { safeBack } from '@/lib/utils'; export default function PostDetailScreen() { const insets = useSafeAreaInsets(); @@ -71,14 +72,14 @@ export default function PostDetailScreen() { const onDeleted = useCallback(() => { // Go back to feed — the post is gone. - router.back(); + safeBack(); }, []); return (
router.back()} />} + left={ safeBack()} />} title="Post" /> diff --git a/client-app/app/(app)/feed/tag/[tag].tsx b/client-app/app/(app)/feed/tag/[tag].tsx index fb8b42a..8e9bc6b 100644 --- a/client-app/app/(app)/feed/tag/[tag].tsx +++ b/client-app/app/(app)/feed/tag/[tag].tsx @@ -17,6 +17,7 @@ import { IconButton } from '@/components/IconButton'; import { PostCard, PostSeparator } from '@/components/feed/PostCard'; import { useStore } from '@/lib/store'; import { fetchHashtag, fetchStats, type FeedPostItem } from '@/lib/feed'; +import { safeBack } from '@/lib/utils'; export default function HashtagScreen() { const insets = useSafeAreaInsets(); @@ -80,7 +81,7 @@ export default function HashtagScreen() {
router.back()} />} + left={ safeBack()} />} title={`#${tag}`} /> diff --git a/client-app/app/(app)/new-contact.tsx b/client-app/app/(app)/new-contact.tsx index ca73657..d2b88f4 100644 --- a/client-app/app/(app)/new-contact.tsx +++ b/client-app/app/(app)/new-contact.tsx @@ -18,7 +18,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { useStore } from '@/lib/store'; import { getIdentity, buildContactRequestTx, submitTx, resolveUsername, humanizeTxError } from '@/lib/api'; import { shortAddr } from '@/lib/crypto'; -import { formatAmount } from '@/lib/utils'; +import { formatAmount, safeBack } from '@/lib/utils'; import { Avatar } from '@/components/Avatar'; import { Header } from '@/components/Header'; @@ -64,9 +64,20 @@ export default function NewContactScreen() { if (!addr) { setError(`@${name} is not registered on this chain`); return; } address = addr; } + // Block self-lookup — can't message yourself, and the on-chain + // CONTACT_REQUEST tx would go through but serve no purpose. + if (keyFile && address.toLowerCase() === keyFile.pub_key.toLowerCase()) { + setError("That's you. You can't send a contact request to yourself."); + return; + } const identity = await getIdentity(address); + const resolvedAddr = identity?.pub_key ?? address; + if (keyFile && resolvedAddr.toLowerCase() === keyFile.pub_key.toLowerCase()) { + setError("That's you. You can't send a contact request to yourself."); + return; + } setResolved({ - address: identity?.pub_key ?? address, + address: resolvedAddr, nickname: identity?.nickname || undefined, x25519: identity?.x25519_pub || undefined, }); @@ -79,6 +90,10 @@ export default function NewContactScreen() { async function sendRequest() { if (!resolved || !keyFile) return; + if (resolved.address.toLowerCase() === keyFile.pub_key.toLowerCase()) { + Alert.alert('Can\'t message yourself', "This is your own address."); + return; + } if (balance < fee + 1000) { Alert.alert('Insufficient balance', `Need ${formatAmount(fee + 1000)} (request fee + network).`); return; @@ -96,7 +111,7 @@ export default function NewContactScreen() { Alert.alert( 'Request sent', `A contact request has been sent to ${resolved.nickname ? '@' + resolved.nickname : shortAddr(resolved.address)}.`, - [{ text: 'OK', onPress: () => router.back() }], + [{ text: 'OK', onPress: () => safeBack() }], ); } catch (e: any) { setError(humanizeTxError(e)); @@ -114,7 +129,7 @@ export default function NewContactScreen() {
router.back()} />} + left={ safeBack()} />} /> router.back()} />} + left={ safeBack()} />} /> diff --git a/client-app/app/(app)/settings.tsx b/client-app/app/(app)/settings.tsx index 854fb2d..8414a9c 100644 --- a/client-app/app/(app)/settings.tsx +++ b/client-app/app/(app)/settings.tsx @@ -32,7 +32,7 @@ import { humanizeTxError, } from '@/lib/api'; import { shortAddr } from '@/lib/crypto'; -import { formatAmount } from '@/lib/utils'; +import { formatAmount, safeBack } from '@/lib/utils'; import { Avatar } from '@/components/Avatar'; import { Header } from '@/components/Header'; @@ -335,7 +335,7 @@ export default function SettingsScreen() {
router.back()} />} + left={ safeBack()} />} />
router.back()} />} + left={ safeBack('/')} />} /> diff --git a/client-app/app/(auth)/import.tsx b/client-app/app/(auth)/import.tsx index b2208eb..3456b69 100644 --- a/client-app/app/(auth)/import.tsx +++ b/client-app/app/(auth)/import.tsx @@ -15,6 +15,7 @@ import * as DocumentPicker from 'expo-document-picker'; import * as Clipboard from 'expo-clipboard'; import { saveKeyFile } from '@/lib/storage'; import { useStore } from '@/lib/store'; +import { safeBack } from '@/lib/utils'; import type { KeyFile } from '@/lib/types'; import { Header } from '@/components/Header'; @@ -96,7 +97,7 @@ export default function ImportKeyScreen() {
router.back()} />} + left={ safeBack('/')} />} />