import { DEVICE_NAME } from '@/constants/config';
import { 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';
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' },
});
};
export const handleSignalInfoFragment = async () => {
const html = (await hasValidAccount())
? `
Unlink and remove device
- Open Signal app → Settings → Linked Devices
- Find "${DEVICE_NAME}" and tap it
- Tap "Unlink Device"
`
: ``;
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 = `
${endpoints
.map(
(e) => `
-
${e.appName}
`,
)
.join('')}
`;
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 = `
`;
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: () => new Response(Bun.file('public/admin.html')),
},
'/admin.css': {
GET: () => new Response(Bun.file('public/admin.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),
},
};