37 lines
1.3 KiB
TypeScript
37 lines
1.3 KiB
TypeScript
|
import { createHmac } from "crypto";
|
||
|
import dayjs from "dayjs";
|
||
|
import { NextApiRequest, NextApiResponse } from "next";
|
||
|
import { stringify } from "querystring";
|
||
|
|
||
|
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug";
|
||
|
|
||
|
let signingSecret = "";
|
||
|
|
||
|
export default async function slackVerify(req: NextApiRequest, res: NextApiResponse) {
|
||
|
const body = req.body;
|
||
|
const timeStamp = req.headers["x-slack-request-timestamp"] as string; // Always returns a string and not a string[]
|
||
|
const slackSignature = req.headers["x-slack-signature"] as string;
|
||
|
const currentTime = dayjs().unix();
|
||
|
let { signing_secret } = await getAppKeysFromSlug("slack");
|
||
|
if (typeof signing_secret === "string") signingSecret = signing_secret;
|
||
|
|
||
|
if (!timeStamp) {
|
||
|
return res.status(400).json({ message: "Missing X-Slack-Request-Timestamp header" });
|
||
|
}
|
||
|
|
||
|
if (!signingSecret) {
|
||
|
return res.status(400).json({ message: "Missing Slack's signing_secret" });
|
||
|
}
|
||
|
|
||
|
if (Math.abs(currentTime - parseInt(timeStamp)) > 60 * 5) {
|
||
|
return res.status(400).json({ message: "Request is too old" });
|
||
|
}
|
||
|
|
||
|
const signature_base = `v0:${timeStamp}:${stringify(body)}`;
|
||
|
const signed_sig = "v0=" + createHmac("sha256", signingSecret).update(signature_base).digest("hex");
|
||
|
|
||
|
if (signed_sig !== slackSignature) {
|
||
|
return res.status(400).json({ message: "Invalid signature" });
|
||
|
}
|
||
|
}
|