From 6a2e76857bb70b898ec985367bf49c64829a4b28 Mon Sep 17 00:00:00 2001 From: m5r Date: Mon, 30 Aug 2021 19:24:05 +0800 Subject: [PATCH] clean setTwilioWebhooks and twilio webhook verification --- app/api/ddd.ts | 12 +++++++--- app/messages/api/webhook/incoming-message.ts | 4 ++-- .../api/queue/set-twilio-webhooks.ts | 24 ++++++------------- app/phone-calls/api/webhook/call.ts | 6 ++--- integrations/twilio.ts | 19 ++++++++++++++- 5 files changed, 39 insertions(+), 26 deletions(-) diff --git a/app/api/ddd.ts b/app/api/ddd.ts index f6bdc7e..3378b02 100644 --- a/app/api/ddd.ts +++ b/app/api/ddd.ts @@ -2,6 +2,7 @@ import { BlitzApiRequest, BlitzApiResponse } from "blitz"; import db from "db"; import twilio from "twilio"; +import setTwilioWebhooks from "../onboarding/api/queue/set-twilio-webhooks"; export default async function ddd(req: BlitzApiRequest, res: BlitzApiResponse) { /*await Promise.all([ @@ -49,7 +50,12 @@ export default async function ddd(req: BlitzApiRequest, res: BlitzApiResponse) { console.log("messagesReceived", messagesReceived.sort((a, b) => a.dateCreated.getTime() - b.dateCreated.getTime())); // console.log("messagesReceived", messagesReceived);*/ - setTimeout(() => { - res.status(200).end(); - }, 1000 * 60 * 5); + /*setTwilioWebhooks.enqueue({ + phoneNumberId: "PNb77c9690c394368bdbaf20ea6fe5e9fc", + organizationId: "95267d60-3d35-4c36-9905-8543ecb4f174", + });*/ + + // setTimeout(() => { + res.status(200).end(); + // }, 1000 * 60 * 5); } diff --git a/app/messages/api/webhook/incoming-message.ts b/app/messages/api/webhook/incoming-message.ts index b07923d..2118a30 100644 --- a/app/messages/api/webhook/incoming-message.ts +++ b/app/messages/api/webhook/incoming-message.ts @@ -5,6 +5,7 @@ import twilio from "twilio"; import appLogger from "../../../../integrations/logger"; import db from "../../../../db"; import insertIncomingMessageQueue from "../queue/insert-incoming-message"; +import { smsUrl } from "../../../../integrations/twilio"; type ApiError = { statusCode: number; @@ -53,13 +54,12 @@ export default async function incomingMessageHandler(req: BlitzApiRequest, res: return; } - const url = `https://${serverRuntimeConfig.app.baseUrl}/api/webhook/incoming-message`; const phoneNumber = phoneNumbers.find((phoneNumber) => { // if multiple organizations have the same number // find the organization currently using that phone number // maybe we shouldn't let multiple organizations use the same phone number const authToken = phoneNumber.organization.twilioAuthToken ?? ""; - return twilio.validateRequest(authToken, twilioSignature, url, req.body); + return twilio.validateRequest(authToken, twilioSignature, smsUrl, req.body); }); if (!phoneNumber) { const statusCode = 400; diff --git a/app/onboarding/api/queue/set-twilio-webhooks.ts b/app/onboarding/api/queue/set-twilio-webhooks.ts index 294f453..7012f93 100644 --- a/app/onboarding/api/queue/set-twilio-webhooks.ts +++ b/app/onboarding/api/queue/set-twilio-webhooks.ts @@ -4,7 +4,7 @@ import type twilio from "twilio"; import type { ApplicationInstance } from "twilio/lib/rest/api/v2010/account/application"; import db from "../../../../db"; -import getTwilioClient from "../../../../integrations/twilio"; +import getTwilioClient, { getTwiMLName, smsUrl, voiceUrl } from "../../../../integrations/twilio"; type Payload = { organizationId: string; @@ -45,7 +45,7 @@ async function getTwimlApplication( ): Promise { try { if (organizationTwimlAppSid) { - return updateTwimlApplication(twilioClient, organizationTwimlAppSid); + return await updateTwimlApplication(twilioClient, organizationTwimlAppSid); } } catch { // twiml app with sid `organizationTwimlAppSid` probably doesn't exist anymore @@ -59,33 +59,23 @@ async function getTwimlApplication( return twilioClient.applications.create({ friendlyName: getTwiMLName(), - smsUrl: `https://${serverRuntimeConfig.app.baseUrl}/api/webhook/incoming-message`, + smsUrl, smsMethod: "POST", - voiceUrl: `https://${serverRuntimeConfig.app.baseUrl}/api/webhook/call`, + voiceUrl, voiceMethod: "POST", }); } async function updateTwimlApplication(twilioClient: twilio.Twilio, twimlAppSid: string) { await twilioClient.applications.get(twimlAppSid).update({ - smsUrl: `https://${serverRuntimeConfig.app.baseUrl}/api/webhook/incoming-message`, + friendlyName: getTwiMLName(), + smsUrl, smsMethod: "POST", - voiceUrl: `https://${serverRuntimeConfig.app.baseUrl}/api/webhook/call`, + voiceUrl, voiceMethod: "POST", }); return twilioClient.applications.get(twimlAppSid).fetch(); } -function getTwiMLName() { - switch (serverRuntimeConfig.app.baseUrl) { - case "local.shellphone.app": - return "Shellphone LOCAL"; - case "dev.shellphone.app": - return "Shellphone DEV"; - case "www.shellphone.app": - return "Shellphone"; - } -} - export default setTwilioWebhooks; diff --git a/app/phone-calls/api/webhook/call.ts b/app/phone-calls/api/webhook/call.ts index e9d055d..ce43297 100644 --- a/app/phone-calls/api/webhook/call.ts +++ b/app/phone-calls/api/webhook/call.ts @@ -5,6 +5,7 @@ import type { CallInstance } from "twilio/lib/rest/api/v2010/account/call"; import db, { CallStatus, Direction } from "../../../../db"; import appLogger from "../../../../integrations/logger"; +import { voiceUrl } from "../../../../integrations/twilio"; const { serverRuntimeConfig } = getConfig(); const logger = appLogger.child({ route: "/api/webhook/call" }); @@ -17,7 +18,6 @@ type ApiError = { export default async function incomingCallHandler(req: BlitzApiRequest, res: BlitzApiResponse) { console.log("req.body", req.body); - const url = `https://${serverRuntimeConfig.app.baseUrl}/api/webhook/call`; const twilioSignature = req.headers["X-Twilio-Signature"] || req.headers["x-twilio-signature"]; if (!twilioSignature || Array.isArray(twilioSignature)) { const statusCode = 400; @@ -42,7 +42,7 @@ export default async function incomingCallHandler(req: BlitzApiRequest, res: Bli if ( !phoneNumber || !phoneNumber.organization.twilioAuthToken || - !twilio.validateRequest(phoneNumber.organization.twilioAuthToken, twilioSignature, url, req.body) + !twilio.validateRequest(phoneNumber.organization.twilioAuthToken, twilioSignature, voiceUrl, req.body) ) { const statusCode = 400; const apiError: ApiError = { @@ -93,7 +93,7 @@ export default async function incomingCallHandler(req: BlitzApiRequest, res: Bli // find the organization currently using that phone number // maybe we shouldn't let multiple organizations use the same phone number const authToken = phoneNumber.organization.twilioAuthToken ?? ""; - return twilio.validateRequest(authToken, twilioSignature, url, req.body); + return twilio.validateRequest(authToken, twilioSignature, voiceUrl, req.body); }); if (!phoneNumber) { const statusCode = 400; diff --git a/integrations/twilio.ts b/integrations/twilio.ts index 86f5440..c1663a1 100644 --- a/integrations/twilio.ts +++ b/integrations/twilio.ts @@ -1,4 +1,4 @@ -import { NotFoundError } from "blitz"; +import { getConfig, NotFoundError } from "blitz"; import twilio from "twilio"; import type { Organization } from "db"; @@ -19,3 +19,20 @@ export default function getTwilioClient(organization: MinimalOrganization | null accountSid: organization.twilioAccountSid, }); } + +const { serverRuntimeConfig } = getConfig(); + +export const smsUrl = `https://${serverRuntimeConfig.app.baseUrl}/api/webhook/incoming-message`; + +export const voiceUrl = `https://${serverRuntimeConfig.app.baseUrl}/api/webhook/call`; + +export function getTwiMLName() { + switch (serverRuntimeConfig.app.baseUrl) { + case "local.shellphone.app": + return "Shellphone LOCAL"; + case "dev.shellphone.app": + return "Shellphone DEV"; + case "www.shellphone.app": + return "Shellphone"; + } +}