import { DEVICE_NAME } from '@/constants/config'; import { PUBLIC_DIR, SIGNAL_CLI_DATA } from '@/constants/paths'; import { isImapConnected } from '@/modules/protonmail'; import { checkSignalCli, finishLink, generateLinkQR, hasLinkUri, hasValidAccount, initSignal, restartDaemon, unlinkDevice, } from '@/modules/signal'; import { getAllMappings, remove } from '@/modules/store'; import { withAuth } from '@/utils/auth'; import { maybeCompress } from '@/utils/compress'; export const handleHealthFragment = async () => { const signalOk = await checkSignalCli(); const linked = signalOk && (await hasValidAccount()); const imap = isImapConnected(); const html = `
Signal: ${signalOk ? 'Connected' : 'Disconnected'}
Account: ${linked ? 'Linked' : 'Unlinked'}
Proton Mail: ${imap ? 'Connected' : 'Disconnected'}
`; return new Response(html, { headers: { 'content-type': 'text/html', 'HX-Trigger': linked ? 'accountLinked' : '', }, }); }; export const handleSignalInfoFragment = async () => { const html = (await hasValidAccount()) ? `` : ``; return new Response(html, { headers: { 'content-type': 'text/html' }, }); }; export const handleEndpointsFragment = async () => { const endpoints = getAllMappings(); if (endpoints.length === 0) { return new Response('

No endpoints registered

', { headers: { 'content-type': 'text/html' }, }); } const html = ` `; return new Response(html, { headers: { 'content-type': 'text/html' }, }); }; export const handleQRSection = async () => { const html = `

Scan this QR code with your Signal app:

Settings → Linked Devices → Link New Device

Generating QR code...
`; return new Response(html, { headers: { 'content-type': 'text/html' }, }); }; export const handleQRImage = async () => { if (!(await hasValidAccount()) && (await Bun.file(SIGNAL_CLI_DATA).exists())) { await unlinkDevice(); await restartDaemon(); } const qrDataUrl = await generateLinkQR(); const html = `QR Code`; return new Response(html, { headers: { 'content-type': 'text/html' }, }); }; export const handleLinkStatusCheck = async () => { let linked = await hasValidAccount(); if (!linked && hasLinkUri()) { try { await finishLink(); const result = await initSignal(); linked = result.linked; } catch (error) { console.error('Failed to finish link:', error); } } if (linked) { return new Response('', { headers: { 'content-type': 'text/html', 'HX-Refresh': 'true', }, }); } return new Response('', { headers: { 'content-type': 'text/html' }, }); }; export const handleDeleteEndpoint = async (req: Request) => { const url = new URL(req.url); const endpoint = decodeURIComponent(url.pathname.split('/').pop() || ''); if (!endpoint) { return new Response('Invalid endpoint', { status: 400 }); } remove(endpoint); return handleEndpointsFragment(); }; export const adminRoutes = { '/': { GET: withAuth(async (req: Request) => maybeCompress(req, await Bun.file(`${PUBLIC_DIR}/admin.html`).text()), ), }, '/admin.css': { GET: withAuth(async (req: Request) => maybeCompress(req, await Bun.file(`${PUBLIC_DIR}/admin.css`).text(), 'text/css'), ), }, '/health/fragment': { GET: withAuth(handleHealthFragment), }, '/signal-info/fragment': { GET: withAuth(handleSignalInfoFragment), }, '/endpoints/fragment': { GET: withAuth(handleEndpointsFragment), }, '/link/qr-section': { GET: withAuth(handleQRSection), }, '/link/qr-image': { GET: withAuth(handleQRImage), }, '/link/status-check': { GET: withAuth(handleLinkStatusCheck), }, '/endpoint/delete/:endpoint': { DELETE: withAuth(handleDeleteEndpoint), }, };