diff --git a/support/routes/v2/isobot/index.ts b/support/routes/v2/isobot/index.ts index 204e8b9c5..63aba993b 100644 --- a/support/routes/v2/isobot/index.ts +++ b/support/routes/v2/isobot/index.ts @@ -1,13 +1,11 @@ import { App, ExpressReceiver } from "@slack/bolt" -import { RequestHandler } from "express" import { Whitelist } from "@database/models" import config from "@root/config/config" import logger from "@root/logger/logger" import WhitelistService from "@root/services/identity/WhitelistService" -import type { DnsCheckerResponse } from "@root/types/dnsChecker" -import BotService, { SlackPayload } from "./ops/botService" +import BotService from "./ops/botService" const botService = new BotService( new WhitelistService({ repository: Whitelist }) @@ -23,55 +21,8 @@ const bot = new App({ receiver: botReceiver, }) -const handleWhitelistEmails: RequestHandler< - {}, - { message: string }, - SlackPayload, - {}, - {} -> = async (req, res) => { - const slackTimestamp = req.headers["x-slack-request-timestamp"] as string - const slackSig = req.headers["x-slack-signature"] as string - - if (!slackTimestamp || !slackSig) - return res.send({ message: "Missing header/signature" }) - - const isVerifiedMessage = botService.verifySignature( - slackSig, - slackTimestamp, - req.body - ) - if (!isVerifiedMessage) return res.send({ message: "Invalid signature" }) - - try { - await botService.whitelistEmails(req.body) - return res.send({ message: "Emails whitelisted successfully" }) - } catch (e) { - logger.error({ error: e }) - return res.send({ message: "Failed to whitelist emails" }) - } -} - -const handleDnsChecker: RequestHandler< - never, - DnsCheckerResponse | { message: string }, - SlackPayload, - unknown, - never -> = async (req, res) => { - const validatedDomain = botService.getValidatedDomain(req.body) - if (!validatedDomain) - return res.status(200).send({ - message: `Sorry, \`${req.body.text}\` is not a valid domain name. Please try again with a valid one instead.`, - }) - - return botService - .dnsChecker(req.body) - .map((response) => res.status(200).send(response)) -} - // TODO: add in validation for user once downstream is merged -bot.command("/siteup", async ({ payload, respond, ack }) => { +bot.command("/whitelist", async ({ payload, respond, ack }) => { await ack() try { @@ -83,5 +34,14 @@ bot.command("/siteup", async ({ payload, respond, ack }) => { } }) -// bot.command("/siteup", handleDnsChecker) -// bot.command("/whitelist-emails", handleWhitelistEmails) +bot.command("/siteup", async ({ payload, respond, ack }) => { + await ack() + + const validatedDomain = botService.getValidatedDomain(payload.text) + if (!validatedDomain) + return respond( + `Sorry, \`${payload.text}\` is not a valid domain name. Please try again with a valid one instead.` + ) + + return botService.dnsChecker(payload).map((response) => respond(response)) +}) diff --git a/support/routes/v2/isobot/ops/botService.ts b/support/routes/v2/isobot/ops/botService.ts index 8195b498e..54b626406 100644 --- a/support/routes/v2/isobot/ops/botService.ts +++ b/support/routes/v2/isobot/ops/botService.ts @@ -1,5 +1,6 @@ import dns from "node:dns/promises" +import { SlashCommand } from "@slack/bolt" import { ResultAsync, okAsync } from "neverthrow" import { @@ -12,10 +13,6 @@ import logger from "@root/logger/logger" import WhitelistService from "@root/services/identity/WhitelistService" import { DnsCheckerResponse } from "@root/types/dnsChecker" -// Slack only gives us 3 seconds to respond, but usually DNS resolution is fast, -// so we will give it 2 seconds before we give up -const DNS_TIMEOUT = 2000 - class BotService { whitelistService: WhitelistService @@ -24,21 +21,13 @@ class BotService { } private checkCname(domain: string) { - return ResultAsync.fromPromise( - Promise.race([ - dns.resolveCname(domain), - new Promise((_, reject) => - setTimeout(() => reject(null), DNS_TIMEOUT) - ), - ]), - () => { - logger.info({ - message: "Error resolving CNAME", - meta: { domain, method: "checkCname" }, - }) - return new Error() - } - ) + return ResultAsync.fromPromise(dns.resolveCname(domain), () => { + logger.info({ + message: "Error resolving CNAME", + meta: { domain, method: "checkCname" }, + }) + return new Error() + }) .andThen((cname) => { if (!cname || cname.length === 0) { return okAsync(null) @@ -50,21 +39,13 @@ class BotService { } private checkA(domain: string) { - return ResultAsync.fromPromise( - Promise.race([ - dns.resolve4(domain), - new Promise((_, reject) => - setTimeout(() => reject(null), DNS_TIMEOUT) - ), - ]), - () => { - logger.info({ - message: "Error resolving A record", - meta: { domain, method: "checkA" }, - }) - return new Error() - } - ) + return ResultAsync.fromPromise(dns.resolve4(domain), () => { + logger.info({ + message: "Error resolving A record", + meta: { domain, method: "checkA" }, + }) + return new Error() + }) .andThen((a) => { if (!a || a.length === 0) { return okAsync(null) @@ -119,8 +100,7 @@ class BotService { await this.whitelistService.addWhitelist(emails) } - getValidatedDomain(payload: SlackPayload) { - const { text: domain } = payload + getValidatedDomain(domain: string) { const DOMAIN_NAME_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9](?:\.[a-zA-Z]{2,})+$/ if (!DOMAIN_NAME_REGEX.test(domain)) { @@ -296,7 +276,7 @@ class BotService { return this.getSlackMessage(response) } - dnsChecker(payload: SlackPayload) { + dnsChecker(payload: SlashCommand) { // Step 1: Get the domain name provided by the user const { user_name: user, channel_name: channel, text: domain } = payload logger.info({