import React, { useEffect, useState } from 'react'; import { useLocalSearchParams } from 'expo-router'; import { YStack, XStack, Text, Input, Button, ScrollView } from 'tamagui'; import { chacha20Encrypt,chacha20Decrypt } from '../../components/crypto'; const ChatApp = () => { const {friendUsername } = useLocalSearchParams(); // Friend's username passed via params const [messages, setMessages] = useState([]); const [inputText, setInputText] = useState(''); const [loading, setLoading] = useState(true); const [friendPubKey, setFriendPubKey] = useState(null); // Friend's public key // Fetch friend's public key const fetchPublicKey = async () => { try { const authToken = localStorage.getItem('jwtToken'); if (!authToken) { console.error('User is not authenticated'); return; } const response = await fetch(`http://localhost:4000/user/pubkey?username=${friendUsername}`, { headers: { Authorization: `Bearer ${authToken}`, }, }); if (!response.ok) throw new Error('Failed to fetch public key'); const { pubKey } = await response.json(); setFriendPubKey(pubKey); } catch (err) { console.error('Error fetching public key:', err); } }; // Fetch messages // Fetch messages const fetchMessages = async () => { try { const authToken = localStorage.getItem('jwtToken'); if (!authToken) { console.error('User is not authenticated'); return; } const response = await fetch(`http://localhost:4000/messages/?receiverUsername=${friendUsername}`, { headers: { Authorization: `Bearer ${authToken}`, }, }); if (!response.ok) throw new Error('Failed to fetch messages'); // Fetch encrypted messages as JSON const encryptedMessages = await response.json(); console.log('Encrypted Messages:', encryptedMessages); // Debug: log encrypted messages // Decrypt each message and store the decrypted result const decryptedMessages = await Promise.all( encryptedMessages.map(async (msg) => { const decryptedMessage = await chacha20Decrypt(msg); return { ...msg, content: decryptedMessage }; // Attach decrypted message to original message }) ); console.log('Decrypted Messages:', decryptedMessages); // Debug: log decrypted messages // Update the state with the decrypted messages setMessages(decryptedMessages); } catch (err) { console.error('Error fetching messages:', err); setMessages(["Error fetching messages"]); // Provide a default error message } finally { setLoading(false); } }; // Fetch initial data useEffect(() => { fetchPublicKey(); fetchMessages(); // Poll for new messages every 5 seconds const intervalId = setInterval(fetchMessages, 1000); return () => clearInterval(intervalId); // Cleanup on component unmount }, [friendUsername]); // Send message const sendMessage = async () => { if (!inputText.trim() || !friendPubKey) return; try { const authToken = localStorage.getItem('jwtToken'); if (!authToken) { console.error('User is not authenticated'); return; } // Prepare the JSON object for encryption const messageData = JSON.stringify({ message: inputText, receiver: friendUsername, pubkey: friendPubKey, }); // Encrypt the message using chacha20Encrypt const encryptedPayload = chacha20Encrypt(messageData); console.log("payload", JSON.parse(encryptedPayload)) const decrypted = chacha20Decrypt(encryptedPayload) console.log("decrypted:", decrypted) // Send the encrypted message to the server const response = await fetch('http://localhost:4000/messages', { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${authToken}`, }, body: encryptedPayload, // Send the encrypted payload }); if (!response.ok) throw new Error('Failed to send message'); const newMessage = await response.json(); setMessages((prevMessages) => [...prevMessages, newMessage]); setInputText(''); } catch (err) { console.error('Error sending message:', err); } }; return ( {/* Chat Header */} Chat with {friendUsername} {/* Messages List */} {loading ? ( Loading... ) : ( messages.map((msg) => ( )) )} {/* Input Field and Send Button */} ); }; const MessageBubble = ({ text, sender }) => { const isUser = sender === 'user'; return ( {text} ); }; export default ChatApp;