Slack Signature Verification (#2667)
* Slack Verify * Adding await * Update slackVerify.ts Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> Co-authored-by: zomars <zomars@me.com>
This commit is contained in:
parent
02b935bcde
commit
fa1ca5fba0
3 changed files with 40 additions and 1 deletions
|
@ -2,6 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
import { showCreateEventMessage, showTodayMessage } from "../lib";
|
import { showCreateEventMessage, showTodayMessage } from "../lib";
|
||||||
import showLinksMessage from "../lib/showLinksMessage";
|
import showLinksMessage from "../lib/showLinksMessage";
|
||||||
|
import slackVerify from "../lib/slackVerify";
|
||||||
|
|
||||||
export enum SlackAppCommands {
|
export enum SlackAppCommands {
|
||||||
CREATE_EVENT = "create-event",
|
CREATE_EVENT = "create-event",
|
||||||
|
@ -12,7 +13,7 @@ export enum SlackAppCommands {
|
||||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
if (req.method === "POST") {
|
if (req.method === "POST") {
|
||||||
const command = req.body.command.split("/").pop();
|
const command = req.body.command.split("/").pop();
|
||||||
|
await slackVerify(req, res);
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case SlackAppCommands.CREATE_EVENT:
|
case SlackAppCommands.CREATE_EVENT:
|
||||||
return await showCreateEventMessage(req, res);
|
return await showCreateEventMessage(req, res);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { NextApiRequest, NextApiResponse } from "next";
|
import { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
import createEvent from "../lib/actions/createEvent";
|
import createEvent from "../lib/actions/createEvent";
|
||||||
|
import slackVerify from "../lib/slackVerify";
|
||||||
|
|
||||||
enum InteractionEvents {
|
enum InteractionEvents {
|
||||||
CREATE_EVENT = "cal.event.create",
|
CREATE_EVENT = "cal.event.create",
|
||||||
|
@ -8,6 +9,7 @@ enum InteractionEvents {
|
||||||
|
|
||||||
export default async function interactiveHandler(req: NextApiRequest, res: NextApiResponse) {
|
export default async function interactiveHandler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
if (req.method === "POST") {
|
if (req.method === "POST") {
|
||||||
|
await slackVerify(req, res);
|
||||||
const payload = JSON.parse(req.body.payload);
|
const payload = JSON.parse(req.body.payload);
|
||||||
const actions = payload.view.callback_id;
|
const actions = payload.view.callback_id;
|
||||||
|
|
||||||
|
|
36
packages/app-store/slackmessaging/lib/slackVerify.ts
Normal file
36
packages/app-store/slackmessaging/lib/slackVerify.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
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" });
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue