diff --git a/apps/docs/openapi/builder.json b/apps/docs/openapi/builder.json index d3f8a3d914..462f6f8c18 100644 --- a/apps/docs/openapi/builder.json +++ b/apps/docs/openapi/builder.json @@ -19078,6 +19078,144 @@ "action" ] }, + { + "type": "object", + "properties": { + "baseUrl": { + "type": "string" + }, + "apiVersion": { + "type": "string" + }, + "credentialsId": { + "type": "string" + }, + "action": { + "type": "string", + "enum": [ + "Generate variables" + ] + }, + "model": { + "type": "string" + }, + "prompt": { + "type": "string" + }, + "variablesToExtract": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "enum" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + } + ] + } + } + }, + "required": [ + "action" + ] + }, { "type": "object", "properties": { @@ -19680,6 +19818,138 @@ "required": [ "action" ] + }, + { + "type": "object", + "properties": { + "credentialsId": { + "type": "string" + }, + "action": { + "type": "string", + "enum": [ + "Generate variables" + ] + }, + "model": { + "type": "string" + }, + "prompt": { + "type": "string" + }, + "variablesToExtract": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "enum" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + } + ] + } + } + }, + "required": [ + "action" + ] } ] } @@ -19908,6 +20178,146 @@ "required": [ "action" ] + }, + { + "type": "object", + "properties": { + "credentialsId": { + "type": "string" + }, + "action": { + "type": "string", + "enum": [ + "Generate variables" + ] + }, + "model": { + "type": "string", + "enum": [ + "claude-3-opus-20240229", + "claude-3-sonnet-20240229", + "claude-3-haiku-20240307", + "claude-2.1", + "claude-2.0", + "claude-instant-1.2" + ] + }, + "prompt": { + "type": "string" + }, + "variablesToExtract": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "enum" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + } + ] + } + } + }, + "required": [ + "action" + ] } ] } diff --git a/apps/docs/openapi/viewer.json b/apps/docs/openapi/viewer.json index 2fe6749413..314256ac89 100644 --- a/apps/docs/openapi/viewer.json +++ b/apps/docs/openapi/viewer.json @@ -10059,6 +10059,144 @@ "action" ] }, + { + "type": "object", + "properties": { + "baseUrl": { + "type": "string" + }, + "apiVersion": { + "type": "string" + }, + "credentialsId": { + "type": "string" + }, + "action": { + "type": "string", + "enum": [ + "Generate variables" + ] + }, + "model": { + "type": "string" + }, + "prompt": { + "type": "string" + }, + "variablesToExtract": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "enum" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + } + ] + } + } + }, + "required": [ + "action" + ] + }, { "type": "object", "properties": { @@ -10661,6 +10799,138 @@ "required": [ "action" ] + }, + { + "type": "object", + "properties": { + "credentialsId": { + "type": "string" + }, + "action": { + "type": "string", + "enum": [ + "Generate variables" + ] + }, + "model": { + "type": "string" + }, + "prompt": { + "type": "string" + }, + "variablesToExtract": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "enum" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + } + ] + } + } + }, + "required": [ + "action" + ] } ] } @@ -10889,6 +11159,146 @@ "required": [ "action" ] + }, + { + "type": "object", + "properties": { + "credentialsId": { + "type": "string" + }, + "action": { + "type": "string", + "enum": [ + "Generate variables" + ] + }, + "model": { + "type": "string", + "enum": [ + "claude-3-opus-20240229", + "claude-3-sonnet-20240229", + "claude-3-haiku-20240307", + "claude-2.1", + "claude-2.0", + "claude-instant-1.2" + ] + }, + "prompt": { + "type": "string" + }, + "variablesToExtract": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": {} + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "enum" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "variableId": { + "type": "string" + }, + "description": { + "type": "string" + }, + "isRequired": { + "type": "boolean" + } + }, + "required": [ + "type" + ] + } + ] + } + } + }, + "required": [ + "action" + ] } ] } diff --git a/apps/viewer/src/helpers/server/context.ts b/apps/viewer/src/helpers/server/context.ts index 866431f63d..1e2cdaab8c 100644 --- a/apps/viewer/src/helpers/server/context.ts +++ b/apps/viewer/src/helpers/server/context.ts @@ -11,7 +11,10 @@ export async function createContext(opts: trpcNext.CreateNextContextOptions) { return { user, - origin: opts.req.headers.origin, + origin: + (opts.req.headers['x-typebot-iframe-referrer-origin'] as + | string + | undefined) ?? opts.req.headers.origin, res: opts.res, } } diff --git a/packages/embeds/js/package.json b/packages/embeds/js/package.json index cfed7deb0e..e7468c3fac 100644 --- a/packages/embeds/js/package.json +++ b/packages/embeds/js/package.json @@ -1,6 +1,6 @@ { "name": "@typebot.io/js", - "version": "0.2.87", + "version": "0.2.88", "description": "Javascript library to display typebots on your website", "type": "module", "main": "dist/index.js", @@ -48,4 +48,4 @@ "tailwindcss": "3.3.3", "typescript": "5.4.5" } -} \ No newline at end of file +} diff --git a/packages/embeds/js/src/components/Bot.tsx b/packages/embeds/js/src/components/Bot.tsx index dca0e93b09..15e414629b 100644 --- a/packages/embeds/js/src/components/Bot.tsx +++ b/packages/embeds/js/src/components/Bot.tsx @@ -29,6 +29,7 @@ import { defaultFontType, defaultProgressBarPosition, } from '@typebot.io/schemas/features/typebot/theme/constants' +import { CorsError } from '@/utils/CorsError' export type BotProps = { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -106,6 +107,10 @@ export const Bot = (props: BotProps & { class?: string }) => { ) } + if (error instanceof CorsError) { + return setError(new Error(error.message)) + } + if (!data) { if (error) { console.error(error) diff --git a/packages/embeds/js/src/queries/startChatQuery.ts b/packages/embeds/js/src/queries/startChatQuery.ts index 682ec7e00a..96a7a3ffe4 100644 --- a/packages/embeds/js/src/queries/startChatQuery.ts +++ b/packages/embeds/js/src/queries/startChatQuery.ts @@ -11,6 +11,7 @@ import { StartPreviewChatInput, } from '@typebot.io/schemas' import ky from 'ky' +import { CorsError } from '@/utils/CorsError' type Props = { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -102,27 +103,40 @@ export async function startChatQuery({ } try { - const data = await ky - .post( - `${ - isNotEmpty(apiHost) ? apiHost : guessApiHost() - }/api/v1/typebots/${typebotId}/startChat`, - { - json: { - isStreamEnabled: true, - prefilledVariables, - resultId, - isOnlyRegistering: false, - } satisfies Omit< - StartChatInput, - 'publicId' | 'textBubbleContentFormat' - >, - timeout: false, - } - ) - .json() + const iframeReferrerOrigin = + parent !== window ? new URL(document.referrer).origin : undefined + const response = await ky.post( + `${ + isNotEmpty(apiHost) ? apiHost : guessApiHost() + }/api/v1/typebots/${typebotId}/startChat`, + { + headers: { + 'x-typebot-iframe-referrer-origin': iframeReferrerOrigin, + }, + json: { + isStreamEnabled: true, + prefilledVariables, + resultId, + isOnlyRegistering: false, + } satisfies Omit< + StartChatInput, + 'publicId' | 'textBubbleContentFormat' + >, + timeout: false, + } + ) - return { data } + const corsAllowOrigin = response.headers.get('access-control-allow-origin') + + if ( + iframeReferrerOrigin && + corsAllowOrigin && + corsAllowOrigin !== '*' && + !iframeReferrerOrigin.includes(corsAllowOrigin) + ) + throw new CorsError(corsAllowOrigin) + + return { data: await response.json() } } catch (error) { return { error } } diff --git a/packages/embeds/js/src/utils/CorsError.ts b/packages/embeds/js/src/utils/CorsError.ts new file mode 100644 index 0000000000..5ce6ff2011 --- /dev/null +++ b/packages/embeds/js/src/utils/CorsError.ts @@ -0,0 +1,5 @@ +export class CorsError extends Error { + constructor(origin: string) { + super('This bot can only be executed on ' + origin) + } +} diff --git a/packages/embeds/nextjs/package.json b/packages/embeds/nextjs/package.json index 32dd8b7196..935d2f802f 100644 --- a/packages/embeds/nextjs/package.json +++ b/packages/embeds/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@typebot.io/nextjs", - "version": "0.2.87", + "version": "0.2.88", "description": "Convenient library to display typebots on your Next.js website", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -42,4 +42,4 @@ "next": "12.x || 13.x || 14.x", "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } -} \ No newline at end of file +} diff --git a/packages/embeds/react/package.json b/packages/embeds/react/package.json index 947b518b56..f2d3e9f4dd 100644 --- a/packages/embeds/react/package.json +++ b/packages/embeds/react/package.json @@ -1,6 +1,6 @@ { "name": "@typebot.io/react", - "version": "0.2.87", + "version": "0.2.88", "description": "Convenient library to display typebots on your React app", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -45,4 +45,4 @@ "peerDependencies": { "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } -} \ No newline at end of file +}