added encryption

This commit is contained in:
2026-03-09 10:54:07 +05:30
parent 6e184dc590
commit 6720e28d08
27 changed files with 2093 additions and 709 deletions

View File

@@ -1,14 +1,21 @@
import { useState, useEffect } from 'react'
import { useAuth } from '../contexts/AuthContext'
import { getUserEntries, type JournalEntry } from '../lib/api'
import { formatIST, formatISTDateOnly, getISTDateComponents } from '../lib/timezone'
import { decryptEntry } from '../lib/crypto'
import { formatIST, getISTDateComponents } from '../lib/timezone'
import BottomNav from '../components/BottomNav'
interface DecryptedEntry extends JournalEntry {
decryptedTitle?: string
decryptedContent?: string
decryptError?: string
}
export default function HistoryPage() {
const { user, userId, loading } = useAuth()
const { user, userId, secretKey, loading } = useAuth()
const [currentMonth, setCurrentMonth] = useState(new Date())
const [selectedDate, setSelectedDate] = useState(new Date())
const [entries, setEntries] = useState<JournalEntry[]>([])
const [entries, setEntries] = useState<DecryptedEntry[]>([])
const [loadingEntries, setLoadingEntries] = useState(false)
// Fetch entries on mount and when userId changes
@@ -20,7 +27,57 @@ export default function HistoryPage() {
try {
const token = await user.getIdToken()
const response = await getUserEntries(userId, token, 100, 0)
setEntries(response.entries)
// Decrypt entries if they are encrypted
const decryptedEntries: DecryptedEntry[] = await Promise.all(
response.entries.map(async (entry) => {
if (entry.encryption?.encrypted && entry.encryption?.ciphertext && entry.encryption?.nonce) {
// Entry is encrypted, try to decrypt
if (!secretKey) {
return {
...entry,
decryptError: 'Encryption key not available',
decryptedTitle: '[Encrypted]',
}
}
try {
const decrypted = await decryptEntry(
entry.encryption.ciphertext,
entry.encryption.nonce,
secretKey
)
// Split decrypted content: first line is title, rest is content
const lines = decrypted.split('\n\n')
const decryptedTitle = lines[0]
const decryptedContent = lines.slice(1).join('\n\n')
return {
...entry,
decryptedTitle,
decryptedContent,
}
} catch (error) {
console.error(`Failed to decrypt entry ${entry.id}:`, error)
return {
...entry,
decryptError: 'Failed to decrypt entry',
decryptedTitle: '[Decryption Failed]',
}
}
} else {
// Entry is not encrypted, use plaintext
return {
...entry,
decryptedTitle: entry.title || '[Untitled]',
decryptedContent: entry.content || '',
}
}
})
)
setEntries(decryptedEntries)
} catch (error) {
console.error('Error fetching entries:', error)
} finally {
@@ -29,7 +86,7 @@ export default function HistoryPage() {
}
fetchEntries()
}, [user, userId])
}, [user, userId, secretKey])
const getDaysInMonth = (date: Date) => {
const year = date.getFullYear()
@@ -208,7 +265,7 @@ export default function HistoryPage() {
<span className="entry-date">{formatDate(entry.createdAt)}</span>
<span className="entry-time">{formatTime(entry.createdAt)}</span>
</div>
<h4 className="entry-title">{entry.title}</h4>
<h4 className="entry-title">{entry.decryptedTitle || entry.title || '[Untitled]'}</h4>
</button>
))
)}