67 lines
2.2 KiB
TypeScript
67 lines
2.2 KiB
TypeScript
import { VercelRequest, VercelResponse } from "@vercel/node";
|
|
import { createVerify } from "crypto";
|
|
|
|
export default function handler(req: VercelRequest, res: VercelResponse) {
|
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
|
|
if (req.method !== "POST") {
|
|
return res.status(405).json({ error: "Method not allowed" });
|
|
}
|
|
|
|
try {
|
|
const signature = req.headers["x-signature-ed25519"] as string;
|
|
const timestamp = req.headers["x-signature-timestamp"] as string;
|
|
const publicKey = process.env.DISCORD_PUBLIC_KEY;
|
|
|
|
if (!signature || !timestamp || !publicKey) {
|
|
console.error("[Discord] Missing signature, timestamp, or public key");
|
|
return res.status(401).json({ error: "Unauthorized" });
|
|
}
|
|
|
|
// Reconstruct raw body exactly as Discord sent it
|
|
let rawBody: string;
|
|
if (typeof req.body === "string") {
|
|
rawBody = req.body;
|
|
} else {
|
|
rawBody = JSON.stringify(req.body);
|
|
}
|
|
|
|
// Create message for signature verification
|
|
const message = `${timestamp}${rawBody}`;
|
|
|
|
// Verify Discord's signature
|
|
try {
|
|
const signatureBuffer = Buffer.from(signature, "hex");
|
|
const verifier = createVerify("ed25519");
|
|
verifier.update(message);
|
|
const isValid = verifier.verify(publicKey, signatureBuffer);
|
|
|
|
if (!isValid) {
|
|
console.error("[Discord] Signature verification failed");
|
|
return res.status(401).json({ error: "Invalid signature" });
|
|
}
|
|
} catch (err: any) {
|
|
console.error("[Discord] Signature verification error:", err.message);
|
|
return res.status(401).json({ error: "Signature error" });
|
|
}
|
|
|
|
// Parse interaction
|
|
const interaction = JSON.parse(rawBody);
|
|
|
|
// Respond to PING with type 1
|
|
if (interaction.type === 1) {
|
|
console.log("[Discord] ✓ PING verified");
|
|
return res.status(200).json({ type: 1 });
|
|
}
|
|
|
|
// Handle other interaction types
|
|
console.log("[Discord] Interaction type:", interaction.type);
|
|
return res.status(200).json({
|
|
type: 4,
|
|
data: { content: "Pong!" },
|
|
});
|
|
} catch (err: any) {
|
|
console.error("[Discord] Error:", err?.message);
|
|
return res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
}
|