added encryption
This commit is contained in:
@@ -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>
|
||||
))
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user