import { verifyKey } from "discord-interactions";
import { createServer, type IncomingMessage, type ServerResponse } from "node:http";
import type { CommandConfig } from "../adapters/discord/config.ts";
import { handleInteraction, type CreateAddressFn, type DiscordInteraction } from "../adapters/discord/interactions.ts";
import type { SqlExecutor } from "../core/storage.ts";
// Serves Discord's /interactions webhook. Identical regardless of receiver
// (SMTP, mail.tm), since it only ever talks to the command layer, never to
// however mail happens to arrive.
export function startHttpServer(
httpPort: number,
discordPublicKey: string,
db: SqlExecutor,
createAddressFn: CreateAddressFn,
commandConfig: CommandConfig
) {
const server = createServer((req: IncomingMessage, res: ServerResponse) => {
if (req.method !== "POST" || req.url !== "/interactions") {
res.writeHead(404).end("not found");
return;
}
const chunks: Buffer[] = [];
req.on("data", (chunk: Buffer) => chunks.push(chunk));
req.on("end", () => {
void (async () => {
const rawBody = Buffer.concat(chunks);
const signature = req.headers["x-signature-ed25519"];
const timestamp = req.headers["x-signature-timestamp"];
if (typeof signature !== "string" || typeof timestamp !== "string") {
res.writeHead(401).end("missing signature headers");
return;
}
const isValid = await verifyKey(rawBody, signature, timestamp, discordPublicKey);
if (!isValid) {
res.writeHead(401).end("invalid request signature");
return;
}