diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index ab405e35..d18111e3 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -1319,7 +1319,28 @@ export class App { upload.array('files'), (req: Request, res: Response, next: NextFunction) => getRateLimiter(req, res, next), async (req: Request, res: Response) => { - await this.buildChatflow(req, res, socketIO) + const chatflow = await this.AppDataSource.getRepository(ChatFlow).findOneBy({ + id: req.params.id + }) + if (!chatflow) return res.status(404).send(`Chatflow ${req.params.id} not found`) + let isDomainAllowed = true + logger.info(`[server]: Request originated from ${req.headers.origin}`) + if (chatflow.chatbotConfig) { + const parsedConfig = JSON.parse(chatflow.chatbotConfig) + // check whether the first one is not empty. if it is empty that means the user set a value and then removed it. + const isValidAllowedOrigins = parsedConfig.allowedOrigins[0] !== '' + if (parsedConfig.allowedOrigins && parsedConfig.allowedOrigins.length > 0 && isValidAllowedOrigins) { + const originHeader = req.headers.origin as string + const origin = new URL(originHeader).host + isDomainAllowed = parsedConfig.allowedOrigins.includes(origin) + } + } + + if (isDomainAllowed) { + await this.buildChatflow(req, res, socketIO) + } else { + return res.status(401).send(`This site is not allowed to access this chatbot`) + } } ) diff --git a/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.js b/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.js new file mode 100644 index 00000000..f389aebc --- /dev/null +++ b/packages/ui/src/ui-component/dialog/AllowedDomainsDialog.js @@ -0,0 +1,176 @@ +import { useDispatch } from 'react-redux' +import { useState, useEffect } from 'react' +import PropTypes from 'prop-types' +import { enqueueSnackbar as enqueueSnackbarAction, closeSnackbar as closeSnackbarAction, SET_CHATFLOW } from 'store/actions' + +// material-ui +import { Button, IconButton, OutlinedInput, Box, List, InputAdornment } from '@mui/material' +import { IconX, IconTrash, IconPlus } from '@tabler/icons' + +// Project import +import { StyledButton } from 'ui-component/button/StyledButton' + +// store +import useNotifier from 'utils/useNotifier' + +// API +import chatflowsApi from 'api/chatflows' + +const AllowedDomains = ({ dialogProps }) => { + const dispatch = useDispatch() + + useNotifier() + + const enqueueSnackbar = (...args) => dispatch(enqueueSnackbarAction(...args)) + const closeSnackbar = (...args) => dispatch(closeSnackbarAction(...args)) + + const [inputFields, setInputFields] = useState(['']) + + const [chatbotConfig, setChatbotConfig] = useState({}) + + const addInputField = () => { + setInputFields([...inputFields, '']) + } + const removeInputFields = (index) => { + const rows = [...inputFields] + rows.splice(index, 1) + setInputFields(rows) + } + + const handleChange = (index, evnt) => { + const { value } = evnt.target + const list = [...inputFields] + list[index] = value + setInputFields(list) + } + + const onSave = async () => { + try { + let value = { + allowedOrigins: [...inputFields] + } + chatbotConfig.allowedOrigins = value.allowedOrigins + const saveResp = await chatflowsApi.updateChatflow(dialogProps.chatflow.id, { + chatbotConfig: JSON.stringify(chatbotConfig) + }) + if (saveResp.data) { + enqueueSnackbar({ + message: 'Allowed Origins Saved', + options: { + key: new Date().getTime() + Math.random(), + variant: 'success', + action: (key) => ( + + ) + } + }) + dispatch({ type: SET_CHATFLOW, chatflow: saveResp.data }) + } + } catch (error) { + const errorData = error.response.data || `${error.response.status}: ${error.response.statusText}` + enqueueSnackbar({ + message: `Failed to save Allowed Origins: ${errorData}`, + options: { + key: new Date().getTime() + Math.random(), + variant: 'error', + persist: true, + action: (key) => ( + + ) + } + }) + } + } + + useEffect(() => { + if (dialogProps.chatflow && dialogProps.chatflow.chatbotConfig) { + try { + let chatbotConfig = JSON.parse(dialogProps.chatflow.chatbotConfig) + setChatbotConfig(chatbotConfig || {}) + if (chatbotConfig.allowedOrigins) { + let inputFields = [...chatbotConfig.allowedOrigins] + setInputFields(inputFields) + } else { + setInputFields(['']) + } + } catch (e) { + setInputFields(['']) + } + } + + return () => {} + }, [dialogProps]) + + return ( + <> +
+ + Your chatbot will only work when used from the following domains. When adding domains, exclude the{' '} +
http://
or
https://
part. +
+
+ :not(style)': { m: 1 }, pt: 2 }}> + + {inputFields.map((origin, index) => { + return ( +
+ + handleChange(index, e)} + size='small' + value={origin} + name='origin' + endAdornment={ + + {inputFields.length > 1 && ( + removeInputFields(index)} + edge='end' + > + + + )} + + } + /> + + + {index === inputFields.length - 1 && ( + + + + )} + +
+ ) + })} +
+
+ + Save + + + ) +} + +AllowedDomains.propTypes = { + dialogProps: PropTypes.object +} + +export default AllowedDomains diff --git a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js index 5f5b78a7..bc2f6451 100644 --- a/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js +++ b/packages/ui/src/ui-component/dialog/ChatflowConfigurationDialog.js @@ -4,6 +4,7 @@ import { createPortal } from 'react-dom' import { Box, Dialog, DialogContent, DialogTitle, Tabs, Tab } from '@mui/material' import SpeechToText from './SpeechToTextDialog' import Configuration from 'views/chatflows/Configuration' +import AllowedDomains from './AllowedDomainsDialog' const CHATFLOW_CONFIGURATION_TABS = [ { @@ -32,6 +33,7 @@ function TabPanel(props) { hidden={value !== index} id={`chatflow-config-tabpanel-${index}`} aria-labelledby={`chatflow-config-tab-${index}`} + style={{ paddingTop: '1rem' }} {...other} > {value === index && {children}} @@ -84,6 +86,7 @@ const ChatflowConfigurationDialog = ({ show, dialogProps, onCancel }) => { {item.id === 'rateLimiting' && } {item.id === 'speechToText' ? : null} + {item.id === 'allowedDomains' ? : null} ))} diff --git a/packages/ui/src/views/chatflows/Configuration.js b/packages/ui/src/views/chatflows/Configuration.js index d569020b..cc6c2da5 100644 --- a/packages/ui/src/views/chatflows/Configuration.js +++ b/packages/ui/src/views/chatflows/Configuration.js @@ -131,7 +131,7 @@ const Configuration = () => { return ( <> {/*Rate Limit*/} - + Rate Limit{' '}