2
0

fix: Allow webhook with basic auth

This commit is contained in:
Baptiste Arnaud
2022-02-15 12:36:08 +01:00
parent b95d907e8f
commit 93e8f90ac3
9 changed files with 38 additions and 37 deletions

View File

@@ -14,7 +14,6 @@ import {
IntegrationStepType, IntegrationStepType,
LogicStepType, LogicStepType,
Step, Step,
StepIndices,
StepOptions, StepOptions,
TextBubbleStep, TextBubbleStep,
Webhook, Webhook,
@@ -44,7 +43,6 @@ type Props = {
onExpandClick: () => void onExpandClick: () => void
onStepChange: (updates: Partial<Step>) => void onStepChange: (updates: Partial<Step>) => void
onTestRequestClick: () => void onTestRequestClick: () => void
indices: StepIndices
} }
export const SettingsPopoverContent = ({ onExpandClick, ...props }: Props) => { export const SettingsPopoverContent = ({ onExpandClick, ...props }: Props) => {
@@ -87,13 +85,11 @@ export const StepSettings = ({
step, step,
onStepChange, onStepChange,
onTestRequestClick, onTestRequestClick,
indices,
}: { }: {
step: Step step: Step
webhook?: Webhook webhook?: Webhook
onStepChange: (step: Partial<Step>) => void onStepChange: (step: Partial<Step>) => void
onTestRequestClick: () => void onTestRequestClick: () => void
indices: StepIndices
}) => { }) => {
const handleOptionsChange = (options: StepOptions) => { const handleOptionsChange = (options: StepOptions) => {
onStepChange({ options } as Partial<Step>) onStepChange({ options } as Partial<Step>)
@@ -210,7 +206,6 @@ export const StepSettings = ({
onOptionsChange={handleOptionsChange} onOptionsChange={handleOptionsChange}
onWebhookChange={handleWebhookChange} onWebhookChange={handleWebhookChange}
onTestRequestClick={onTestRequestClick} onTestRequestClick={onTestRequestClick}
indices={indices}
/> />
) )
} }

View File

@@ -20,7 +20,6 @@ import {
Webhook, Webhook,
ResponseVariableMapping, ResponseVariableMapping,
WebhookStep, WebhookStep,
StepIndices,
} from 'models' } from 'models'
import { DropdownList } from 'components/shared/DropdownList' import { DropdownList } from 'components/shared/DropdownList'
import { TableList, TableListItemProps } from 'components/shared/TableList' import { TableList, TableListItemProps } from 'components/shared/TableList'
@@ -39,15 +38,13 @@ type Props = {
onOptionsChange: (options: WebhookOptions) => void onOptionsChange: (options: WebhookOptions) => void
onWebhookChange: (updates: Partial<Webhook>) => void onWebhookChange: (updates: Partial<Webhook>) => void
onTestRequestClick: () => void onTestRequestClick: () => void
indices: StepIndices
} }
export const WebhookSettings = ({ export const WebhookSettings = ({
step: { webhook, options }, step: { webhook, options, blockId, id: stepId },
onOptionsChange, onOptionsChange,
onWebhookChange, onWebhookChange,
onTestRequestClick, onTestRequestClick,
indices,
}: Props) => { }: Props) => {
const { typebot, save } = useTypebot() const { typebot, save } = useTypebot()
const [isTestResponseLoading, setIsTestResponseLoading] = useState(false) const [isTestResponseLoading, setIsTestResponseLoading] = useState(false)
@@ -85,12 +82,11 @@ export const WebhookSettings = ({
await save() await save()
const { data, error } = await executeWebhook( const { data, error } = await executeWebhook(
typebot.id, typebot.id,
webhook.id,
convertVariableForTestToVariables( convertVariableForTestToVariables(
options.variablesForTest, options.variablesForTest,
typebot.variables typebot.variables
), ),
indices { blockId, stepId }
) )
if (error) return toast({ title: error.name, description: error.message }) if (error) return toast({ title: error.name, description: error.message })
setTestResponse(JSON.stringify(data, undefined, 2)) setTestResponse(JSON.stringify(data, undefined, 2))

View File

@@ -216,7 +216,6 @@ export const StepNode = ({
onExpandClick={handleExpandClick} onExpandClick={handleExpandClick}
onStepChange={handleStepChange} onStepChange={handleStepChange}
onTestRequestClick={updateOptions} onTestRequestClick={updateOptions}
indices={indices}
/> />
)} )}
{isMediaBubbleStep(localStep) && ( {isMediaBubbleStep(localStep) && (
@@ -230,7 +229,6 @@ export const StepNode = ({
step={localStep} step={localStep}
onStepChange={handleStepChange} onStepChange={handleStepChange}
onTestRequestClick={updateOptions} onTestRequestClick={updateOptions}
indices={indices}
/> />
</SettingsModal> </SettingsModal>
</Popover> </Popover>

View File

@@ -3,7 +3,7 @@ import { WritableDraft } from 'immer/dist/types/types-external'
import { generate } from 'short-uuid' import { generate } from 'short-uuid'
import { SetTypebot } from '../TypebotContext' import { SetTypebot } from '../TypebotContext'
import { produce } from 'immer' import { produce } from 'immer'
import { byId, isDefined, isNotDefined } from 'utils' import { byId, isDefined } from 'utils'
export type EdgesActions = { export type EdgesActions = {
createEdge: (edge: Omit<Edge, 'id'>) => void createEdge: (edge: Omit<Edge, 'id'>) => void

View File

@@ -2,7 +2,7 @@ import { sendRequest } from 'utils'
import { stringify } from 'qs' import { stringify } from 'qs'
import useSWR from 'swr' import useSWR from 'swr'
import { fetcher } from './utils' import { fetcher } from './utils'
import { StepIndices, Variable, VariableForTest, WebhookResponse } from 'models' import { Variable, VariableForTest, WebhookResponse } from 'models'
export const getGoogleSheetsConsentScreenUrl = ( export const getGoogleSheetsConsentScreenUrl = (
redirectUrl: string, redirectUrl: string,
@@ -68,12 +68,11 @@ export const useSheets = ({
export const executeWebhook = ( export const executeWebhook = (
typebotId: string, typebotId: string,
webhookId: string,
variables: Variable[], variables: Variable[],
{ blockIndex, stepIndex }: StepIndices { blockId, stepId }: { blockId: string; stepId: string }
) => ) =>
sendRequest<WebhookResponse>({ sendRequest<WebhookResponse>({
url: `/api/typebots/${typebotId}/blocks/${blockIndex}/steps/${stepIndex}/executeWebhook`, url: `${process.env.NEXT_PUBLIC_VIEWER_HOST}/api/typebots/${typebotId}/blocks/${blockId}/steps/${stepId}/executeWebhook`,
method: 'POST', method: 'POST',
body: { body: {
variables, variables,

View File

@@ -3,23 +3,26 @@ import { KeyValue, Typebot, Variable, Webhook, WebhookResponse } from 'models'
import { parseVariables } from 'bot-engine' import { parseVariables } from 'bot-engine'
import { NextApiRequest, NextApiResponse } from 'next' import { NextApiRequest, NextApiResponse } from 'next'
import got, { Method, Headers, HTTPError } from 'got' import got, { Method, Headers, HTTPError } from 'got'
import { methodNotAllowed } from 'utils' import { byId, initMiddleware, methodNotAllowed } from 'utils'
import { stringify } from 'qs' import { stringify } from 'qs'
import { withSentry } from '@sentry/nextjs' import { withSentry } from '@sentry/nextjs'
import Cors from 'cors'
const cors = initMiddleware(Cors())
const handler = async (req: NextApiRequest, res: NextApiResponse) => { const handler = async (req: NextApiRequest, res: NextApiResponse) => {
await cors(req, res)
if (req.method === 'POST') { if (req.method === 'POST') {
const typebotId = req.query.typebotId.toString() const typebotId = req.query.typebotId.toString()
const blockIndex = Number(req.query.blockIndex) const blockId = req.query.blockId.toString()
const stepIndex = Number(req.query.stepIndex) const stepId = req.query.stepId.toString()
const variables = JSON.parse(req.body).variables as Variable[] const variables = JSON.parse(req.body).variables as Variable[]
const typebot = await prisma.typebot.findUnique({ const typebot = await prisma.typebot.findUnique({
where: { id: typebotId }, where: { id: typebotId },
}) })
const step = (typebot as unknown as Typebot).blocks[blockIndex].steps[ const step = (typebot as unknown as Typebot).blocks
stepIndex .find(byId(blockId))
] ?.steps.find(byId(stepId))
if (!('webhook' in step)) if (!step || !('webhook' in step))
return res return res
.status(404) .status(404)
.send({ statusCode: 404, data: { message: `Couldn't find webhook` } }) .send({ statusCode: 404, data: { message: `Couldn't find webhook` } })
@@ -38,6 +41,19 @@ const executeWebhook = async (
statusCode: 400, statusCode: 400,
data: { message: `Webhook doesn't have url or method` }, data: { message: `Webhook doesn't have url or method` },
} }
const basicAuth: { username?: string; password?: string } = {}
const basicAuthHeaderIdx = webhook.headers.findIndex(
(h) =>
h.key?.toLowerCase() === 'authorization' &&
h.value?.toLowerCase().includes('basic')
)
if (basicAuthHeaderIdx !== -1) {
const [username, password] =
webhook.headers[basicAuthHeaderIdx].value?.slice(6).split(':') ?? []
basicAuth.username = username
basicAuth.password = password
webhook.headers.splice(basicAuthHeaderIdx, 1)
}
const headers = convertKeyValueTableToObject(webhook.headers, variables) as const headers = convertKeyValueTableToObject(webhook.headers, variables) as
| Headers | Headers
| undefined | undefined
@@ -51,6 +67,7 @@ const executeWebhook = async (
{ {
method: webhook.method as Method, method: webhook.method as Method,
headers, headers,
...basicAuth,
json: json:
contentType !== 'x-www-form-urlencoded' && webhook.body contentType !== 'x-www-form-urlencoded' && webhook.body
? JSON.parse(parseVariables(variables)(webhook.body)) ? JSON.parse(parseVariables(variables)(webhook.body))

View File

@@ -19,7 +19,6 @@ import { parseRetryStep, stepCanBeRetried } from 'services/inputs'
type ChatBlockProps = { type ChatBlockProps = {
steps: PublicStep[] steps: PublicStep[]
startStepIndex: number startStepIndex: number
blockIndex: number
onScroll: () => void onScroll: () => void
onBlockEnd: (edgeId?: string) => void onBlockEnd: (edgeId?: string) => void
} }
@@ -27,7 +26,6 @@ type ChatBlockProps = {
export const ChatBlock = ({ export const ChatBlock = ({
steps, steps,
startStepIndex, startStepIndex,
blockIndex,
onScroll, onScroll,
onBlockEnd, onBlockEnd,
}: ChatBlockProps) => { }: ChatBlockProps) => {
@@ -35,8 +33,6 @@ export const ChatBlock = ({
useTypebot() useTypebot()
const [displayedSteps, setDisplayedSteps] = useState<PublicStep[]>([]) const [displayedSteps, setDisplayedSteps] = useState<PublicStep[]>([])
const currentStepIndex = displayedSteps.length - 1
useEffect(() => { useEffect(() => {
const nextStep = steps[startStepIndex] const nextStep = steps[startStepIndex]
if (nextStep) setDisplayedSteps([...displayedSteps, nextStep]) if (nextStep) setDisplayedSteps([...displayedSteps, nextStep])
@@ -65,8 +61,9 @@ export const ChatBlock = ({
step: currentStep, step: currentStep,
context: { context: {
apiHost, apiHost,
typebotId: typebot.id, typebotId: typebot.typebotId,
indices: { blockIndex, stepIndex: currentStepIndex }, blockId: currentStep.blockId,
stepId: currentStep.id,
variables: typebot.variables, variables: typebot.variables,
isPreview, isPreview,
updateVariableValue, updateVariableValue,

View File

@@ -82,7 +82,6 @@ export const ConversationContainer = ({
key={displayedBlock.block.id + idx} key={displayedBlock.block.id + idx}
steps={displayedBlock.block.steps} steps={displayedBlock.block.steps}
startStepIndex={displayedBlock.startStepIndex} startStepIndex={displayedBlock.startStepIndex}
blockIndex={idx}
onScroll={autoScrollToBottom} onScroll={autoScrollToBottom}
onBlockEnd={displayNextBlock} onBlockEnd={displayNextBlock}
/> />

View File

@@ -20,11 +20,11 @@ import { parseVariables, parseVariablesInObject } from './variable'
const safeEval = eval const safeEval = eval
type Indices = { blockIndex: number; stepIndex: number }
type IntegrationContext = { type IntegrationContext = {
apiHost: string apiHost: string
typebotId: string typebotId: string
indices: Indices blockId: string
stepId: string
isPreview: boolean isPreview: boolean
variables: Variable[] variables: Variable[]
updateVariableValue: (variableId: string, value: string) => void updateVariableValue: (variableId: string, value: string) => void
@@ -153,7 +153,8 @@ const parseCellValues = (
const executeWebhook = async ( const executeWebhook = async (
step: WebhookStep, step: WebhookStep,
{ {
indices, blockId,
stepId,
variables, variables,
updateVariableValue, updateVariableValue,
typebotId, typebotId,
@@ -161,9 +162,8 @@ const executeWebhook = async (
}: IntegrationContext }: IntegrationContext
) => { ) => {
if (!step.webhook) return step.outgoingEdgeId if (!step.webhook) return step.outgoingEdgeId
const { blockIndex, stepIndex } = indices
const { data, error } = await sendRequest({ const { data, error } = await sendRequest({
url: `${apiHost}/api/typebots/${typebotId}/blocks/${blockIndex}/steps/${stepIndex}/executeWebhook`, url: `${apiHost}/api/typebots/${typebotId}/blocks/${blockId}/steps/${stepId}/executeWebhook`,
method: 'POST', method: 'POST',
body: { body: {
variables, variables,