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;