diff --git a/packages/server/src/Interface.ts b/packages/server/src/Interface.ts index 57dacd73ea2..abb458d24e7 100644 --- a/packages/server/src/Interface.ts +++ b/packages/server/src/Interface.ts @@ -69,7 +69,7 @@ export interface IChatFlow { apiConfig?: string category?: string type?: ChatflowType - workspaceId?: string + workspaceId: string } export interface IChatMessage { @@ -114,7 +114,7 @@ export interface ITool { func?: string updatedDate: Date createdDate: Date - workspaceId?: string + workspaceId: string } export interface IAssistant { @@ -124,7 +124,7 @@ export interface IAssistant { iconSrc?: string updatedDate: Date createdDate: Date - workspaceId?: string + workspaceId: string } export interface ICredential { @@ -134,7 +134,7 @@ export interface ICredential { encryptedData: string updatedDate: Date createdDate: Date - workspaceId?: string + workspaceId: string } export interface IVariable { @@ -144,7 +144,7 @@ export interface IVariable { type: string updatedDate: Date createdDate: Date - workspaceId?: string + workspaceId: string } export interface ILead { @@ -176,7 +176,7 @@ export interface IExecution { createdDate: Date updatedDate: Date stoppedDate: Date - workspaceId?: string + workspaceId: string } export interface IComponentNodes { @@ -332,7 +332,7 @@ export interface ICredentialReqBody { name: string credentialName: string plainDataObj: ICredentialDataDecrypted - workspaceId?: string + workspaceId: string } // Decrypted credential object sent back to client @@ -351,7 +351,7 @@ export interface IApiKey { apiKey: string apiSecret: string updatedDate: Date - workspaceId?: string + workspaceId: string } export interface ICustomTemplate { @@ -365,7 +365,7 @@ export interface ICustomTemplate { badge?: string framework?: string usecases?: string - workspaceId?: string + workspaceId: string } export interface IFlowConfig { diff --git a/packages/server/src/controllers/apikey/index.ts b/packages/server/src/controllers/apikey/index.ts index 340ff27b251..677d689311c 100644 --- a/packages/server/src/controllers/apikey/index.ts +++ b/packages/server/src/controllers/apikey/index.ts @@ -9,6 +9,9 @@ const getAllApiKeys = async (req: Request, res: Response, next: NextFunction) => try { const autoCreateNewKey = true const { page, limit } = getPageAndLimitParams(req) + if (!req.user?.activeWorkspaceId) { + throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Workspace ID is required`) + } const apiResponse = await apikeyService.getAllApiKeys(req.user?.activeWorkspaceId, autoCreateNewKey, page, limit) return res.json(apiResponse) } catch (error) { @@ -21,6 +24,9 @@ const createApiKey = async (req: Request, res: Response, next: NextFunction) => if (typeof req.body === 'undefined' || !req.body.keyName) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.createApiKey - keyName not provided!`) } + if (!req.user?.activeWorkspaceId) { + throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Workspace ID is required`) + } const apiResponse = await apikeyService.createApiKey(req.body.keyName, req.user?.activeWorkspaceId) return res.json(apiResponse) } catch (error) { @@ -37,6 +43,9 @@ const updateApiKey = async (req: Request, res: Response, next: NextFunction) => if (typeof req.body === 'undefined' || !req.body.keyName) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.updateApiKey - keyName not provided!`) } + if (!req.user?.activeWorkspaceId) { + throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Workspace ID is required`) + } const apiResponse = await apikeyService.updateApiKey(req.params.id, req.body.keyName, req.user?.activeWorkspaceId) return res.json(apiResponse) } catch (error) { @@ -50,6 +59,9 @@ const importKeys = async (req: Request, res: Response, next: NextFunction) => { if (typeof req.body === 'undefined' || !req.body.jsonFile) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.importKeys - body not provided!`) } + if (!req.user?.activeWorkspaceId) { + throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Workspace ID is required`) + } req.body.workspaceId = req.user?.activeWorkspaceId const apiResponse = await apikeyService.importKeys(req.body) return res.json(apiResponse) @@ -64,6 +76,9 @@ const deleteApiKey = async (req: Request, res: Response, next: NextFunction) => if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: apikeyController.deleteApiKey - id not provided!`) } + if (!req.user?.activeWorkspaceId) { + throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Workspace ID is required`) + } const apiResponse = await apikeyService.deleteApiKey(req.params.id, req.user?.activeWorkspaceId) return res.json(apiResponse) } catch (error) { diff --git a/packages/server/src/controllers/assistants/index.ts b/packages/server/src/controllers/assistants/index.ts index 324907d0b2c..e4159bf3fa8 100644 --- a/packages/server/src/controllers/assistants/index.ts +++ b/packages/server/src/controllers/assistants/index.ts @@ -52,7 +52,14 @@ const deleteAssistant = async (req: Request, res: Response, next: NextFunction) `Error: assistantsController.deleteAssistant - id not provided!` ) } - const apiResponse = await assistantsService.deleteAssistant(req.params.id, req.query.isDeleteBoth) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: assistantsController.deleteAssistant - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await assistantsService.deleteAssistant(req.params.id, req.query.isDeleteBoth, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -62,7 +69,14 @@ const deleteAssistant = async (req: Request, res: Response, next: NextFunction) const getAllAssistants = async (req: Request, res: Response, next: NextFunction) => { try { const type = req.query.type as AssistantType - const apiResponse = await assistantsService.getAllAssistants(type, req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: assistantsController.getAllAssistants - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await assistantsService.getAllAssistants(workspaceId, type) return res.json(apiResponse) } catch (error) { next(error) @@ -77,7 +91,14 @@ const getAssistantById = async (req: Request, res: Response, next: NextFunction) `Error: assistantsController.getAssistantById - id not provided!` ) } - const apiResponse = await assistantsService.getAssistantById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: assistantsController.getAssistantById - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await assistantsService.getAssistantById(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -98,7 +119,14 @@ const updateAssistant = async (req: Request, res: Response, next: NextFunction) `Error: assistantsController.updateAssistant - body not provided!` ) } - const apiResponse = await assistantsService.updateAssistant(req.params.id, req.body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: assistantsController.updateAssistant - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await assistantsService.updateAssistant(req.params.id, req.body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -116,7 +144,14 @@ const getChatModels = async (req: Request, res: Response, next: NextFunction) => const getDocumentStores = async (req: Request, res: Response, next: NextFunction) => { try { - const apiResponse = await assistantsService.getDocumentStores(req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: assistantsController.getDocumentStores - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await assistantsService.getDocumentStores(workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/chat-messages/index.ts b/packages/server/src/controllers/chat-messages/index.ts index b000c9ea3fb..d1d7cccbab7 100644 --- a/packages/server/src/controllers/chat-messages/index.ts +++ b/packages/server/src/controllers/chat-messages/index.ts @@ -166,7 +166,7 @@ const removeAllChatMessages = async (req: Request, res: Response, next: NextFunc ) } const chatflowid = req.params.id - const chatflow = await chatflowsService.getChatflowById(req.params.id) + const chatflow = await chatflowsService.getChatflowById(req.params.id, workspaceId) if (!chatflow) { return res.status(404).send(`Chatflow ${req.params.id} not found`) } diff --git a/packages/server/src/controllers/chatflows/index.ts b/packages/server/src/controllers/chatflows/index.ts index f8a10c33f21..6b1a554caa9 100644 --- a/packages/server/src/controllers/chatflows/index.ts +++ b/packages/server/src/controllers/chatflows/index.ts @@ -110,7 +110,14 @@ const getChatflowById = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: chatflowsController.getChatflowById - id not provided!`) } - const apiResponse = await chatflowsService.getChatflowById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: chatflowsController.getChatflowById - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await chatflowsService.getChatflowById(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -165,7 +172,14 @@ const updateChatflow = async (req: Request, res: Response, next: NextFunction) = if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: chatflowsController.updateChatflow - id not provided!`) } - const chatflow = await chatflowsService.getChatflowById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: chatflowsController.saveChatflow - workspace ${workspaceId} not found!` + ) + } + const chatflow = await chatflowsService.getChatflowById(req.params.id, workspaceId) if (!chatflow) { return res.status(404).send(`Chatflow ${req.params.id} not found`) } @@ -176,13 +190,6 @@ const updateChatflow = async (req: Request, res: Response, next: NextFunction) = `Error: chatflowsController.saveChatflow - organization ${orgId} not found!` ) } - const workspaceId = req.user?.activeWorkspaceId - if (!workspaceId) { - throw new InternalFlowiseError( - StatusCodes.NOT_FOUND, - `Error: chatflowsController.saveChatflow - workspace ${workspaceId} not found!` - ) - } const subscriptionId = req.user?.activeOrganizationSubscriptionId || '' const body = req.body const updateChatFlow = new ChatFlow() diff --git a/packages/server/src/controllers/credentials/index.ts b/packages/server/src/controllers/credentials/index.ts index 78cb4348c5e..6c6dea22a34 100644 --- a/packages/server/src/controllers/credentials/index.ts +++ b/packages/server/src/controllers/credentials/index.ts @@ -28,7 +28,14 @@ const deleteCredentials = async (req: Request, res: Response, next: NextFunction `Error: credentialsController.deleteCredentials - id not provided!` ) } - const apiResponse = await credentialsService.deleteCredentials(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: credentialsController.deleteCredentials - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await credentialsService.deleteCredentials(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -37,7 +44,14 @@ const deleteCredentials = async (req: Request, res: Response, next: NextFunction const getAllCredentials = async (req: Request, res: Response, next: NextFunction) => { try { - const apiResponse = await credentialsService.getAllCredentials(req.query.credentialName, req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: credentialsController.getAllCredentials - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await credentialsService.getAllCredentials(req.query.credentialName, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -52,7 +66,14 @@ const getCredentialById = async (req: Request, res: Response, next: NextFunction `Error: credentialsController.getCredentialById - id not provided!` ) } - const apiResponse = await credentialsService.getCredentialById(req.params.id, req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: credentialsController.getCredentialById - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await credentialsService.getCredentialById(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -73,7 +94,14 @@ const updateCredential = async (req: Request, res: Response, next: NextFunction) `Error: credentialsController.updateCredential - body not provided!` ) } - const apiResponse = await credentialsService.updateCredential(req.params.id, req.body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: credentialsController.updateCredential - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await credentialsService.updateCredential(req.params.id, req.body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/dataset/index.ts b/packages/server/src/controllers/dataset/index.ts index d6c7531181f..0479a20de0d 100644 --- a/packages/server/src/controllers/dataset/index.ts +++ b/packages/server/src/controllers/dataset/index.ts @@ -7,7 +7,14 @@ import { getPageAndLimitParams } from '../../utils/pagination' const getAllDatasets = async (req: Request, res: Response, next: NextFunction) => { try { const { page, limit } = getPageAndLimitParams(req) - const apiResponse = await datasetService.getAllDatasets(req.user?.activeWorkspaceId, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.getAllDatasets - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.getAllDatasets(workspaceId, page, limit) return res.json(apiResponse) } catch (error) { next(error) @@ -20,7 +27,14 @@ const getDataset = async (req: Request, res: Response, next: NextFunction) => { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.getDataset - id not provided!`) } const { page, limit } = getPageAndLimitParams(req) - const apiResponse = await datasetService.getDataset(req.params.id, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.getDataset - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.getDataset(req.params.id, workspaceId, page, limit) return res.json(apiResponse) } catch (error) { next(error) @@ -33,7 +47,14 @@ const createDataset = async (req: Request, res: Response, next: NextFunction) => throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.createDataset - body not provided!`) } const body = req.body - body.workspaceId = req.user?.activeWorkspaceId + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.createDataset - workspace ${workspaceId} not found!` + ) + } + body.workspaceId = workspaceId const apiResponse = await datasetService.createDataset(body) return res.json(apiResponse) } catch (error) { @@ -49,7 +70,14 @@ const updateDataset = async (req: Request, res: Response, next: NextFunction) => if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.updateDataset - id not provided!`) } - const apiResponse = await datasetService.updateDataset(req.params.id, req.body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.updateDataset - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.updateDataset(req.params.id, req.body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -61,7 +89,14 @@ const deleteDataset = async (req: Request, res: Response, next: NextFunction) => if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.deleteDataset - id not provided!`) } - const apiResponse = await datasetService.deleteDataset(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.deleteDataset - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.deleteDataset(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -76,6 +111,14 @@ const addDatasetRow = async (req: Request, res: Response, next: NextFunction) => if (!req.body.datasetId) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.addDatasetRow - datasetId not provided!`) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.addDatasetRow - workspace ${workspaceId} not found!` + ) + } + req.body.workspaceId = workspaceId const apiResponse = await datasetService.addDatasetRow(req.body) return res.json(apiResponse) } catch (error) { @@ -91,6 +134,14 @@ const updateDatasetRow = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.updateDatasetRow - id not provided!`) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.updateDatasetRow - workspace ${workspaceId} not found!` + ) + } + req.body.workspaceId = workspaceId const apiResponse = await datasetService.updateDatasetRow(req.params.id, req.body) return res.json(apiResponse) } catch (error) { @@ -103,7 +154,14 @@ const deleteDatasetRow = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.deleteDatasetRow - id not provided!`) } - const apiResponse = await datasetService.deleteDatasetRow(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.deleteDatasetRow - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.deleteDatasetRow(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -113,7 +171,14 @@ const deleteDatasetRow = async (req: Request, res: Response, next: NextFunction) const patchDeleteRows = async (req: Request, res: Response, next: NextFunction) => { try { const ids = req.body.ids ?? [] - const apiResponse = await datasetService.patchDeleteRows(ids) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.patchDeleteRows - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.patchDeleteRows(ids, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -125,8 +190,14 @@ const reorderDatasetRow = async (req: Request, res: Response, next: NextFunction if (!req.body) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: datasetService.reorderDatasetRow - body not provided!`) } - - const apiResponse = await datasetService.reorderDatasetRow(req.body.datasetId, req.body.rows) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: datasetController.reorderDatasetRow - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await datasetService.reorderDatasetRow(req.body.datasetId, req.body.rows, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/documentstore/index.ts b/packages/server/src/controllers/documentstore/index.ts index 9d19373b436..1ac4f439575 100644 --- a/packages/server/src/controllers/documentstore/index.ts +++ b/packages/server/src/controllers/documentstore/index.ts @@ -27,7 +27,12 @@ const createDocumentStore = async (req: Request, res: Response, next: NextFuncti const body = req.body body.workspaceId = req.user?.activeWorkspaceId - + if (!body.workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.createDocumentStore - workspaceId not provided!` + ) + } const docStore = DocumentStoreDTO.toEntity(body) const apiResponse = await documentStoreService.createDocumentStore(docStore, orgId) return res.json(apiResponse) @@ -40,7 +45,14 @@ const getAllDocumentStores = async (req: Request, res: Response, next: NextFunct try { const { page, limit } = getPageAndLimitParams(req) - const apiResponse: any = await documentStoreService.getAllDocumentStores(req.user?.activeWorkspaceId, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.getAllDocumentStores - workspaceId not provided!` + ) + } + const apiResponse: any = await documentStoreService.getAllDocumentStores(workspaceId, page, limit) if (apiResponse?.total >= 0) { return res.json({ total: apiResponse.total, @@ -102,9 +114,16 @@ const getDocumentStoreById = async (req: Request, res: Response, next: NextFunct `Error: documentStoreController.getDocumentStoreById - id not provided!` ) } - const apiResponse = await documentStoreService.getDocumentStoreById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.getDocumentStoreById - workspaceId not provided!` + ) + } + const apiResponse = await documentStoreService.getDocumentStoreById(req.params.id, workspaceId) if (apiResponse && apiResponse.whereUsed) { - apiResponse.whereUsed = JSON.stringify(await documentStoreService.getUsedChatflowNames(apiResponse)) + apiResponse.whereUsed = JSON.stringify(await documentStoreService.getUsedChatflowNames(apiResponse, workspaceId)) } return res.json(DocumentStoreDTO.fromEntity(apiResponse)) } catch (error) { @@ -126,12 +145,20 @@ const getDocumentStoreFileChunks = async (req: Request, res: Response, next: Nex `Error: documentStoreController.getDocumentStoreFileChunks - fileId not provided!` ) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.getDocumentStoreFileChunks - workspaceId not provided!` + ) + } const appDataSource = getRunningExpressApp().AppDataSource const page = req.params.pageNo ? parseInt(req.params.pageNo) : 1 const apiResponse = await documentStoreService.getDocumentStoreFileChunks( appDataSource, req.params.storeId, req.params.fileId, + workspaceId, page ) return res.json(apiResponse) @@ -160,10 +187,18 @@ const deleteDocumentStoreFileChunk = async (req: Request, res: Response, next: N `Error: documentStoreController.deleteDocumentStoreFileChunk - chunkId not provided!` ) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.deleteDocumentStoreFileChunk - workspaceId not provided!` + ) + } const apiResponse = await documentStoreService.deleteDocumentStoreFileChunk( req.params.storeId, req.params.loaderId, - req.params.chunkId + req.params.chunkId, + workspaceId ) return res.json(apiResponse) } catch (error) { @@ -198,12 +233,20 @@ const editDocumentStoreFileChunk = async (req: Request, res: Response, next: Nex `Error: documentStoreController.editDocumentStoreFileChunk - body not provided!` ) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.editDocumentStoreFileChunk - workspaceId not provided!` + ) + } const apiResponse = await documentStoreService.editDocumentStoreFileChunk( req.params.storeId, req.params.loaderId, req.params.chunkId, body.pageContent, - body.metadata + body.metadata, + workspaceId ) return res.json(apiResponse) } catch (error) { @@ -221,7 +264,14 @@ const saveProcessingLoader = async (req: Request, res: Response, next: NextFunct ) } const body = req.body - const apiResponse = await documentStoreService.saveProcessingLoader(appServer.AppDataSource, body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.saveProcessingLoader - workspaceId not provided!` + ) + } + const apiResponse = await documentStoreService.saveProcessingLoader(appServer.AppDataSource, body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -289,7 +339,14 @@ const updateDocumentStore = async (req: Request, res: Response, next: NextFuncti `Error: documentStoreController.updateDocumentStore - body not provided!` ) } - const store = await documentStoreService.getDocumentStoreById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.updateDocumentStore - workspaceId not provided!` + ) + } + const store = await documentStoreService.getDocumentStoreById(req.params.id, workspaceId) if (!store) { throw new InternalFlowiseError( StatusCodes.NOT_FOUND, @@ -449,7 +506,14 @@ const deleteVectorStoreFromStore = async (req: Request, res: Response, next: Nex `Error: documentStoreController.deleteVectorStoreFromStore - storeId not provided!` ) } - const apiResponse = await documentStoreService.deleteVectorStoreFromStore(req.params.storeId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.deleteVectorStoreFromStore - workspaceId not provided!` + ) + } + const apiResponse = await documentStoreService.deleteVectorStoreFromStore(req.params.storeId, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -463,7 +527,14 @@ const saveVectorStoreConfig = async (req: Request, res: Response, next: NextFunc } const body = req.body const appDataSource = getRunningExpressApp().AppDataSource - const apiResponse = await documentStoreService.saveVectorStoreConfig(appDataSource, body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.saveVectorStoreConfig - workspaceId not provided!` + ) + } + const apiResponse = await documentStoreService.saveVectorStoreConfig(appDataSource, body, true, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -476,7 +547,14 @@ const updateVectorStoreConfigOnly = async (req: Request, res: Response, next: Ne throw new Error('Error: documentStoreController.updateVectorStoreConfigOnly - body not provided!') } const body = req.body - const apiResponse = await documentStoreService.updateVectorStoreConfigOnly(body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.PRECONDITION_FAILED, + `Error: documentStoreController.updateVectorStoreConfigOnly - workspaceId not provided!` + ) + } + const apiResponse = await documentStoreService.updateVectorStoreConfigOnly(body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/evaluations/index.ts b/packages/server/src/controllers/evaluations/index.ts index 4cde7615804..b38213aa0b7 100644 --- a/packages/server/src/controllers/evaluations/index.ts +++ b/packages/server/src/controllers/evaluations/index.ts @@ -31,7 +31,7 @@ const createEvaluation = async (req: Request, res: Response, next: NextFunction) const httpProtocol = req.get('x-forwarded-proto') || req.get('X-Forwarded-Proto') || req.protocol const baseURL = `${httpProtocol}://${req.get('host')}` - const apiResponse = await evaluationsService.createEvaluation(body, baseURL, orgId) + const apiResponse = await evaluationsService.createEvaluation(body, baseURL, orgId, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -47,9 +47,16 @@ const runAgain = async (req: Request, res: Response, next: NextFunction) => { if (!orgId) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Error: evaluationsService.runAgain - organization ${orgId} not found!`) } + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.runAgain - workspace ${workspaceId} not found!` + ) + } const httpProtocol = req.get('x-forwarded-proto') || req.get('X-Forwarded-Proto') || req.protocol const baseURL = `${httpProtocol}://${req.get('host')}` - const apiResponse = await evaluationsService.runAgain(req.params.id, baseURL, orgId) + const apiResponse = await evaluationsService.runAgain(req.params.id, baseURL, orgId, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -61,7 +68,14 @@ const getEvaluation = async (req: Request, res: Response, next: NextFunction) => if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluationsService.getEvaluation - id not provided!`) } - const apiResponse = await evaluationsService.getEvaluation(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.getEvaluation - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.getEvaluation(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -73,7 +87,14 @@ const deleteEvaluation = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluationsService.deleteEvaluation - id not provided!`) } - const apiResponse = await evaluationsService.deleteEvaluation(req.params.id, req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.deleteEvaluation - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.deleteEvaluation(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -83,7 +104,14 @@ const deleteEvaluation = async (req: Request, res: Response, next: NextFunction) const getAllEvaluations = async (req: Request, res: Response, next: NextFunction) => { try { const { page, limit } = getPageAndLimitParams(req) - const apiResponse = await evaluationsService.getAllEvaluations(req.user?.activeWorkspaceId, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.getAllEvaluations - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.getAllEvaluations(workspaceId, page, limit) return res.json(apiResponse) } catch (error) { next(error) @@ -95,7 +123,14 @@ const isOutdated = async (req: Request, res: Response, next: NextFunction) => { if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluationsService.isOutdated - id not provided!`) } - const apiResponse = await evaluationsService.isOutdated(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.isOutdated - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.isOutdated(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -107,7 +142,14 @@ const getVersions = async (req: Request, res: Response, next: NextFunction) => { if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluationsService.getVersions - id not provided!`) } - const apiResponse = await evaluationsService.getVersions(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.getVersions - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.getVersions(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -118,7 +160,14 @@ const patchDeleteEvaluations = async (req: Request, res: Response, next: NextFun try { const ids = req.body.ids ?? [] const isDeleteAllVersion = req.body.isDeleteAllVersion ?? false - const apiResponse = await evaluationsService.patchDeleteEvaluations(ids, isDeleteAllVersion, req.user?.activeWorkspaceId) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluationsService.patchDeleteEvaluations - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluationsService.patchDeleteEvaluations(ids, workspaceId, isDeleteAllVersion) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/evaluators/index.ts b/packages/server/src/controllers/evaluators/index.ts index 1f151c37c73..5f864a85c5e 100644 --- a/packages/server/src/controllers/evaluators/index.ts +++ b/packages/server/src/controllers/evaluators/index.ts @@ -7,7 +7,14 @@ import { getPageAndLimitParams } from '../../utils/pagination' const getAllEvaluators = async (req: Request, res: Response, next: NextFunction) => { try { const { page, limit } = getPageAndLimitParams(req) - const apiResponse = await evaluatorService.getAllEvaluators(req.user?.activeWorkspaceId, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluatorService.getAllEvaluators - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluatorService.getAllEvaluators(workspaceId, page, limit) return res.json(apiResponse) } catch (error) { next(error) @@ -19,7 +26,14 @@ const getEvaluator = async (req: Request, res: Response, next: NextFunction) => if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluatorService.getEvaluator - id not provided!`) } - const apiResponse = await evaluatorService.getEvaluator(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluatorService.getEvaluator - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluatorService.getEvaluator(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -48,7 +62,14 @@ const updateEvaluator = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluatorService.updateEvaluator - id not provided!`) } - const apiResponse = await evaluatorService.updateEvaluator(req.params.id, req.body) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluatorService.updateEvaluator - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluatorService.updateEvaluator(req.params.id, req.body, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -60,7 +81,14 @@ const deleteEvaluator = async (req: Request, res: Response, next: NextFunction) if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: evaluatorService.deleteEvaluator - id not provided!`) } - const apiResponse = await evaluatorService.deleteEvaluator(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: evaluatorService.deleteEvaluator - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await evaluatorService.deleteEvaluator(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/export-import/index.ts b/packages/server/src/controllers/export-import/index.ts index b066df0c8a8..ae2a869283a 100644 --- a/packages/server/src/controllers/export-import/index.ts +++ b/packages/server/src/controllers/export-import/index.ts @@ -5,10 +5,14 @@ import exportImportService from '../../services/export-import' const exportData = async (req: Request, res: Response, next: NextFunction) => { try { - const apiResponse = await exportImportService.exportData( - exportImportService.convertExportInput(req.body), - req.user?.activeWorkspaceId - ) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: exportImportController.exportData - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await exportImportService.exportData(exportImportService.convertExportInput(req.body), workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/flow-configs/index.ts b/packages/server/src/controllers/flow-configs/index.ts index c0926266085..ba5fadeee38 100644 --- a/packages/server/src/controllers/flow-configs/index.ts +++ b/packages/server/src/controllers/flow-configs/index.ts @@ -11,7 +11,14 @@ const getSingleFlowConfig = async (req: Request, res: Response, next: NextFuncti `Error: flowConfigsController.getSingleFlowConfig - id not provided!` ) } - const apiResponse = await flowConfigsService.getSingleFlowConfig(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: flowConfigsController.getSingleFlowConfig - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await flowConfigsService.getSingleFlowConfig(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/controllers/marketplaces/index.ts b/packages/server/src/controllers/marketplaces/index.ts index 5d19d40e6cd..1984f3ad938 100644 --- a/packages/server/src/controllers/marketplaces/index.ts +++ b/packages/server/src/controllers/marketplaces/index.ts @@ -47,6 +47,12 @@ const saveCustomTemplate = async (req: Request, res: Response, next: NextFunctio } const body = req.body body.workspaceId = req.user?.activeWorkspaceId + if (!body.workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: marketplacesController.saveCustomTemplate - workspace ${body.workspaceId} not found!` + ) + } const apiResponse = await marketplacesService.saveCustomTemplate(body) return res.json(apiResponse) } catch (error) { diff --git a/packages/server/src/controllers/predictions/index.ts b/packages/server/src/controllers/predictions/index.ts index b7f79b642c8..d467f3157e4 100644 --- a/packages/server/src/controllers/predictions/index.ts +++ b/packages/server/src/controllers/predictions/index.ts @@ -25,7 +25,9 @@ const createPrediction = async (req: Request, res: Response, next: NextFunction) `Error: predictionsController.createPrediction - body not provided!` ) } - const chatflow = await chatflowsService.getChatflowById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + + const chatflow = await chatflowsService.getChatflowById(req.params.id, workspaceId) if (!chatflow) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Chatflow ${req.params.id} not found`) } diff --git a/packages/server/src/controllers/variables/index.ts b/packages/server/src/controllers/variables/index.ts index 42b58603ecc..3f8455410bf 100644 --- a/packages/server/src/controllers/variables/index.ts +++ b/packages/server/src/controllers/variables/index.ts @@ -37,7 +37,14 @@ const deleteVariable = async (req: Request, res: Response, next: NextFunction) = if (typeof req.params === 'undefined' || !req.params.id) { throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, 'Error: variablesController.deleteVariable - id not provided!') } - const apiResponse = await variablesService.deleteVariable(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: variablesController.deleteVariable - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await variablesService.deleteVariable(req.params.id, workspaceId) return res.json(apiResponse) } catch (error) { next(error) @@ -47,7 +54,14 @@ const deleteVariable = async (req: Request, res: Response, next: NextFunction) = const getAllVariables = async (req: Request, res: Response, next: NextFunction) => { try { const { page, limit } = getPageAndLimitParams(req) - const apiResponse = await variablesService.getAllVariables(req.user?.activeWorkspaceId, page, limit) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: variablesController.getAllVariables - workspace ${workspaceId} not found!` + ) + } + const apiResponse = await variablesService.getAllVariables(workspaceId, page, limit) return res.json(apiResponse) } catch (error) { next(error) @@ -65,7 +79,14 @@ const updateVariable = async (req: Request, res: Response, next: NextFunction) = 'Error: variablesController.updateVariable - body not provided!' ) } - const variable = await variablesService.getVariableById(req.params.id) + const workspaceId = req.user?.activeWorkspaceId + if (!workspaceId) { + throw new InternalFlowiseError( + StatusCodes.NOT_FOUND, + `Error: variablesController.updateVariable - workspace ${workspaceId} not found!` + ) + } + const variable = await variablesService.getVariableById(req.params.id, workspaceId) if (!variable) { return res.status(404).send(`Variable ${req.params.id} not found in the database`) } diff --git a/packages/server/src/database/entities/ApiKey.ts b/packages/server/src/database/entities/ApiKey.ts index e7c1d84e55d..4778962a14f 100644 --- a/packages/server/src/database/entities/ApiKey.ts +++ b/packages/server/src/database/entities/ApiKey.ts @@ -19,6 +19,6 @@ export class ApiKey implements IApiKey { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Assistant.ts b/packages/server/src/database/entities/Assistant.ts index 28843213928..1d9eabbe8f1 100644 --- a/packages/server/src/database/entities/Assistant.ts +++ b/packages/server/src/database/entities/Assistant.ts @@ -27,6 +27,6 @@ export class Assistant implements IAssistant { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/ChatFlow.ts b/packages/server/src/database/entities/ChatFlow.ts index 7d047ba4a9a..159cc425cf2 100644 --- a/packages/server/src/database/entities/ChatFlow.ts +++ b/packages/server/src/database/entities/ChatFlow.ts @@ -58,6 +58,6 @@ export class ChatFlow implements IChatFlow { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Credential.ts b/packages/server/src/database/entities/Credential.ts index 2c43158c487..5cff59f49ea 100644 --- a/packages/server/src/database/entities/Credential.ts +++ b/packages/server/src/database/entities/Credential.ts @@ -24,6 +24,6 @@ export class Credential implements ICredential { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/CustomTemplate.ts b/packages/server/src/database/entities/CustomTemplate.ts index e45719e69d4..ed99cebd3c6 100644 --- a/packages/server/src/database/entities/CustomTemplate.ts +++ b/packages/server/src/database/entities/CustomTemplate.ts @@ -27,7 +27,7 @@ export class CustomTemplate implements ICustomTemplate { @Column({ nullable: true, type: 'text' }) type?: string - @Column({ nullable: true, type: 'text' }) + @Column({ nullable: false, type: 'text' }) workspaceId: string @Column({ type: 'timestamp' }) diff --git a/packages/server/src/database/entities/Dataset.ts b/packages/server/src/database/entities/Dataset.ts index 8dd604d3d01..8acd5f2bb15 100644 --- a/packages/server/src/database/entities/Dataset.ts +++ b/packages/server/src/database/entities/Dataset.ts @@ -19,6 +19,6 @@ export class Dataset implements IDataset { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/DocumentStore.ts b/packages/server/src/database/entities/DocumentStore.ts index 01babca474b..9a94fde52fa 100644 --- a/packages/server/src/database/entities/DocumentStore.ts +++ b/packages/server/src/database/entities/DocumentStore.ts @@ -38,6 +38,6 @@ export class DocumentStore implements IDocumentStore { @Column({ nullable: true, type: 'text' }) recordManagerConfig: string | null - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Evaluation.ts b/packages/server/src/database/entities/Evaluation.ts index 85128ae0173..4f23a05e3c7 100644 --- a/packages/server/src/database/entities/Evaluation.ts +++ b/packages/server/src/database/entities/Evaluation.ts @@ -36,6 +36,6 @@ export class Evaluation implements IEvaluation { @UpdateDateColumn() runDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Evaluator.ts b/packages/server/src/database/entities/Evaluator.ts index 8e7f6f9b962..a14e0c9059a 100644 --- a/packages/server/src/database/entities/Evaluator.ts +++ b/packages/server/src/database/entities/Evaluator.ts @@ -23,6 +23,6 @@ export class Evaluator implements IEvaluator { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Execution.ts b/packages/server/src/database/entities/Execution.ts index 87885cf8a3f..eac53f6392a 100644 --- a/packages/server/src/database/entities/Execution.ts +++ b/packages/server/src/database/entities/Execution.ts @@ -42,6 +42,6 @@ export class Execution implements IExecution { @JoinColumn({ name: 'agentflowId' }) agentflow: ChatFlow - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Tool.ts b/packages/server/src/database/entities/Tool.ts index 3a0dcbc898a..2e35b64a685 100644 --- a/packages/server/src/database/entities/Tool.ts +++ b/packages/server/src/database/entities/Tool.ts @@ -33,6 +33,6 @@ export class Tool implements ITool { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/database/entities/Variable.ts b/packages/server/src/database/entities/Variable.ts index 6a8006dd67e..33105c0f6ed 100644 --- a/packages/server/src/database/entities/Variable.ts +++ b/packages/server/src/database/entities/Variable.ts @@ -24,6 +24,6 @@ export class Variable implements IVariable { @UpdateDateColumn() updatedDate: Date - @Column({ nullable: true, type: 'text' }) - workspaceId?: string + @Column({ nullable: false, type: 'text' }) + workspaceId: string } diff --git a/packages/server/src/enterprise/Interface.Enterprise.ts b/packages/server/src/enterprise/Interface.Enterprise.ts index d7ddfc393d6..5dd4384e043 100644 --- a/packages/server/src/enterprise/Interface.Enterprise.ts +++ b/packages/server/src/enterprise/Interface.Enterprise.ts @@ -17,7 +17,6 @@ export class IUser { role: string lastLogin: Date activeWorkspaceId: string - isApiKeyValidated?: boolean loginMode?: string activeOrganizationId?: string } @@ -73,7 +72,6 @@ export type LoggedInUser = { activeWorkspaceId: string activeWorkspace: string assignedWorkspaces: IAssignedWorkspace[] - isApiKeyValidated: boolean permissions?: string[] features?: Record ssoRefreshToken?: string diff --git a/packages/server/src/enterprise/controllers/workspace.controller.ts b/packages/server/src/enterprise/controllers/workspace.controller.ts index d20edcf9449..dc29f97a654 100644 --- a/packages/server/src/enterprise/controllers/workspace.controller.ts +++ b/packages/server/src/enterprise/controllers/workspace.controller.ts @@ -129,7 +129,6 @@ export class WorkspaceController { activeWorkspaceId: workspace.id, activeWorkspace: workspace.name, assignedWorkspaces, - isApiKeyValidated: true, isSSO: req.user.ssoProvider ? true : false, permissions: [...JSON.parse(role.permissions)], features, diff --git a/packages/server/src/enterprise/middleware/passport/index.ts b/packages/server/src/enterprise/middleware/passport/index.ts index 5cbf0b16bc0..083c93e178c 100644 --- a/packages/server/src/enterprise/middleware/passport/index.ts +++ b/packages/server/src/enterprise/middleware/passport/index.ts @@ -165,7 +165,6 @@ export const initializeJwtCookieMiddleware = async (app: express.Application, id activeWorkspaceId: workspaceUser.workspaceId, activeWorkspace: workspaceUser.workspace.name, assignedWorkspaces, - isApiKeyValidated: true, permissions: [...JSON.parse(role.permissions)], features } diff --git a/packages/server/src/enterprise/rbac/PermissionCheck.ts b/packages/server/src/enterprise/rbac/PermissionCheck.ts index 583d4ad604c..d0856c4bc9e 100644 --- a/packages/server/src/enterprise/rbac/PermissionCheck.ts +++ b/packages/server/src/enterprise/rbac/PermissionCheck.ts @@ -7,7 +7,7 @@ export const checkPermission = (permission: string) => { const user = req.user // if the user is not logged in, return forbidden if (user) { - if (user.isApiKeyValidated || user.isOrganizationAdmin) { + if (user.isOrganizationAdmin) { return next() } const permissions = user.permissions @@ -26,7 +26,7 @@ export const checkAnyPermission = (permissionsString: string) => { const user = req.user // if the user is not logged in, return forbidden if (user) { - if (user.isApiKeyValidated || user.isOrganizationAdmin) { + if (user.isOrganizationAdmin) { return next() } const permissions = user.permissions diff --git a/packages/server/src/enterprise/sso/SSOBase.ts b/packages/server/src/enterprise/sso/SSOBase.ts index f990de5a85f..e216c6977ee 100644 --- a/packages/server/src/enterprise/sso/SSOBase.ts +++ b/packages/server/src/enterprise/sso/SSOBase.ts @@ -132,7 +132,6 @@ abstract class SSOBase { activeWorkspaceId: workspaceUser.workspaceId, activeWorkspace: workspaceUser.workspace.name, assignedWorkspaces, - isApiKeyValidated: true, ssoToken: accessToken as string, ssoRefreshToken: refreshToken, ssoProvider: ssoProviderName, diff --git a/packages/server/src/enterprise/utils/ControllerServiceUtils.ts b/packages/server/src/enterprise/utils/ControllerServiceUtils.ts index 245f1e4711e..1d0983c6761 100644 --- a/packages/server/src/enterprise/utils/ControllerServiceUtils.ts +++ b/packages/server/src/enterprise/utils/ControllerServiceUtils.ts @@ -1,11 +1,19 @@ import { Equal } from 'typeorm' import { Request } from 'express' +import { InternalFlowiseError } from '../../errors/internalFlowiseError' +import { StatusCodes } from 'http-status-codes' export const getWorkspaceSearchOptions = (workspaceId?: string) => { - return workspaceId ? { workspaceId: Equal(workspaceId) } : {} + if (!workspaceId) { + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, `Workspace ID is required`) + } + return { workspaceId: Equal(workspaceId) } } export const getWorkspaceSearchOptionsFromReq = (req: Request) => { const workspaceId = req.user?.activeWorkspaceId - return workspaceId ? { workspaceId: Equal(workspaceId) } : {} + if (!workspaceId) { + throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, `Workspace ID is required`) + } + return { workspaceId: Equal(workspaceId) } } diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts index 40666c5c5fa..b2213e92ef2 100644 --- a/packages/server/src/index.ts +++ b/packages/server/src/index.ts @@ -203,28 +203,37 @@ export class App { const URL_CASE_SENSITIVE_REGEX: RegExp = /\/api\/v1\// await initializeJwtCookieMiddleware(this.app, this.identityManager) - + logger.info(`Inside config:`) this.app.use(async (req, res, next) => { // Step 1: Check if the req path contains /api/v1 regardless of case if (URL_CASE_INSENSITIVE_REGEX.test(req.path)) { + logger.info(`Inside config2:`) // Step 2: Check if the req path is casesensitive if (URL_CASE_SENSITIVE_REGEX.test(req.path)) { + logger.info(`Inside config3:`) // Step 3: Check if the req path is in the whitelist const isWhitelisted = whitelistURLs.some((url) => req.path.startsWith(url)) if (isWhitelisted) { + logger.info(`Inside config4:`) next() } else if (req.headers['x-request-from'] === 'internal') { + logger.info(`Inside config5:`) verifyToken(req, res, next) } else { + logger.info(`Inside config6:`) // Only check license validity for non-open-source platforms if (this.identityManager.getPlatformType() !== Platform.OPEN_SOURCE) { + logger.info(`Inside config7:`) if (!this.identityManager.isLicenseValid()) { + logger.info(`Inside config8:`) return res.status(401).json({ error: 'Unauthorized Access' }) } } const { isValid, workspaceId: apiKeyWorkSpaceId } = await validateAPIKey(req) + logger.info(`Inside config9:`) if (!isValid) { + logger.info(`Inside config10:`) return res.status(401).json({ error: 'Unauthorized Access' }) } @@ -232,7 +241,9 @@ export class App { const workspace = await this.AppDataSource.getRepository(Workspace).findOne({ where: { id: apiKeyWorkSpaceId } }) + logger.info(`Inside config11:`) if (!workspace) { + logger.info(`Inside config12:`) return res.status(401).json({ error: 'Unauthorized Access' }) } @@ -240,7 +251,9 @@ export class App { const ownerRole = await this.AppDataSource.getRepository(Role).findOne({ where: { name: GeneralRole.OWNER, organizationId: IsNull() } }) + logger.info(`Inside config13:`) if (!ownerRole) { + logger.info(`Inside config14:`) return res.status(401).json({ error: 'Unauthorized Access' }) } @@ -249,14 +262,17 @@ export class App { const org = await this.AppDataSource.getRepository(Organization).findOne({ where: { id: activeOrganizationId } }) + logger.info(`Inside config15:`) if (!org) { + logger.info(`Inside config16:`) return res.status(401).json({ error: 'Unauthorized Access' }) } const subscriptionId = org.subscriptionId as string const customerId = org.customerId as string const features = await this.identityManager.getFeaturesByPlan(subscriptionId) + logger.info(`Inside config17:`) const productId = await this.identityManager.getProductIdFromSubscription(subscriptionId) - + logger.info(`Inside config18:`) // @ts-ignore req.user = { permissions: [...JSON.parse(ownerRole.permissions)], @@ -267,8 +283,7 @@ export class App { activeOrganizationProductId: productId, isOrganizationAdmin: true, activeWorkspaceId: apiKeyWorkSpaceId!, - activeWorkspace: workspace.name, - isApiKeyValidated: true + activeWorkspace: workspace.name } next() } diff --git a/packages/server/src/routes/chatflows/index.ts b/packages/server/src/routes/chatflows/index.ts index 774f0928dcb..a043d8dacfa 100644 --- a/packages/server/src/routes/chatflows/index.ts +++ b/packages/server/src/routes/chatflows/index.ts @@ -18,6 +18,6 @@ router.put(['/', '/:id'], checkAnyPermission('chatflows:create,chatflows:update' router.delete(['/', '/:id'], checkPermission('chatflows:delete'), chatflowsController.deleteChatflow) // CHECK FOR CHANGE -router.get('/has-changed/:id/:lastUpdatedDateTime', chatflowsController.checkIfChatflowHasChanged) +router.get('/has-changed/:id/:lastUpdatedDateTime', checkPermission('chatflows:update'), chatflowsController.checkIfChatflowHasChanged) export default router diff --git a/packages/server/src/services/apikey/index.ts b/packages/server/src/services/apikey/index.ts index a8b6036333a..5e009c92774 100644 --- a/packages/server/src/services/apikey/index.ts +++ b/packages/server/src/services/apikey/index.ts @@ -9,14 +9,14 @@ import { Not, IsNull } from 'typeorm' import { getWorkspaceSearchOptions } from '../../enterprise/utils/ControllerServiceUtils' import { v4 as uuidv4 } from 'uuid' -const getAllApiKeysFromDB = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllApiKeysFromDB = async (workspaceId: string, page: number = -1, limit: number = -1) => { const appServer = getRunningExpressApp() const queryBuilder = appServer.AppDataSource.getRepository(ApiKey).createQueryBuilder('api_key').orderBy('api_key.updatedDate', 'DESC') if (page > 0 && limit > 0) { queryBuilder.skip((page - 1) * limit) queryBuilder.take(limit) } - if (workspaceId) queryBuilder.andWhere('api_key.workspaceId = :workspaceId', { workspaceId }) + queryBuilder.andWhere('api_key.workspaceId = :workspaceId', { workspaceId }) const [data, total] = await queryBuilder.getManyAndCount() const keysWithChatflows = await addChatflowsCount(data) @@ -27,7 +27,7 @@ const getAllApiKeysFromDB = async (workspaceId?: string, page: number = -1, limi } } -const getAllApiKeys = async (workspaceId?: string, autoCreateNewKey?: boolean, page: number = -1, limit: number = -1) => { +const getAllApiKeys = async (workspaceId: string, autoCreateNewKey?: boolean, page: number = -1, limit: number = -1) => { try { let keys = await getAllApiKeysFromDB(workspaceId, page, limit) const isEmpty = keys?.total === 0 || (Array.isArray(keys) && keys?.length === 0) @@ -71,7 +71,7 @@ const getApiKeyById = async (apiKeyId: string) => { } } -const createApiKey = async (keyName: string, workspaceId?: string) => { +const createApiKey = async (keyName: string, workspaceId: string) => { try { const apiKey = generateAPIKey() const apiSecret = generateSecretHash(apiKey) @@ -91,11 +91,12 @@ const createApiKey = async (keyName: string, workspaceId?: string) => { } // Update api key -const updateApiKey = async (id: string, keyName: string, workspaceId?: string) => { +const updateApiKey = async (id: string, keyName: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const currentKey = await appServer.AppDataSource.getRepository(ApiKey).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!currentKey) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `ApiKey ${currentKey} not found`) @@ -108,7 +109,7 @@ const updateApiKey = async (id: string, keyName: string, workspaceId?: string) = } } -const deleteApiKey = async (id: string, workspaceId?: string) => { +const deleteApiKey = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const dbResponse = await appServer.AppDataSource.getRepository(ApiKey).delete({ id, workspaceId }) diff --git a/packages/server/src/services/assistants/index.ts b/packages/server/src/services/assistants/index.ts index 72dfc4a008a..0151124b9ca 100644 --- a/packages/server/src/services/assistants/index.ts +++ b/packages/server/src/services/assistants/index.ts @@ -160,11 +160,12 @@ const createAssistant = async (requestBody: any, orgId: string): Promise => { +const deleteAssistant = async (assistantId: string, isDeleteBoth: any, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const assistant = await appServer.AppDataSource.getRepository(Assistant).findOneBy({ - id: assistantId + id: assistantId, + workspaceId: workspaceId }) if (!assistant) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Assistant ${assistantId} not found`) @@ -225,7 +226,7 @@ async function getAssistantsCountByOrganization(type: AssistantType, organizatio } } -const getAllAssistants = async (type?: AssistantType, workspaceId?: string): Promise => { +const getAllAssistants = async (workspaceId: string, type?: AssistantType): Promise => { try { const appServer = getRunningExpressApp() if (type) { @@ -245,7 +246,7 @@ const getAllAssistants = async (type?: AssistantType, workspaceId?: string): Pro } } -const getAllAssistantsCount = async (type?: AssistantType, workspaceId?: string): Promise => { +const getAllAssistantsCount = async (workspaceId: string, type?: AssistantType): Promise => { try { const appServer = getRunningExpressApp() if (type) { @@ -265,11 +266,12 @@ const getAllAssistantsCount = async (type?: AssistantType, workspaceId?: string) } } -const getAssistantById = async (assistantId: string): Promise => { +const getAssistantById = async (assistantId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const dbResponse = await appServer.AppDataSource.getRepository(Assistant).findOneBy({ - id: assistantId + id: assistantId, + workspaceId: workspaceId }) if (!dbResponse) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Assistant ${assistantId} not found`) @@ -283,11 +285,12 @@ const getAssistantById = async (assistantId: string): Promise => { } } -const updateAssistant = async (assistantId: string, requestBody: any): Promise => { +const updateAssistant = async (assistantId: string, requestBody: any, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const assistant = await appServer.AppDataSource.getRepository(Assistant).findOneBy({ - id: assistantId + id: assistantId, + workspaceId: workspaceId }) if (!assistant) { @@ -461,7 +464,7 @@ const getChatModels = async (): Promise => { } } -const getDocumentStores = async (activeWorkspaceId?: string): Promise => { +const getDocumentStores = async (activeWorkspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const stores = await appServer.AppDataSource.getRepository(DocumentStore).findBy(getWorkspaceSearchOptions(activeWorkspaceId)) diff --git a/packages/server/src/services/chatflows/index.ts b/packages/server/src/services/chatflows/index.ts index 0b2e651f35f..59e9ab4f032 100644 --- a/packages/server/src/services/chatflows/index.ts +++ b/packages/server/src/services/chatflows/index.ts @@ -238,11 +238,14 @@ const getChatflowByApiKey = async (apiKeyId: string, keyonly?: unknown): Promise } } -const getChatflowById = async (chatflowId: string): Promise => { +const getChatflowById = async (chatflowId: string, workspaceId?: string): Promise => { try { const appServer = getRunningExpressApp() - const dbResponse = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ - id: chatflowId + const dbResponse = await appServer.AppDataSource.getRepository(ChatFlow).findOne({ + where: { + id: chatflowId, + ...(workspaceId ? { workspaceId } : {}) + } }) if (!dbResponse) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Chatflow ${chatflowId} not found in the database!`) diff --git a/packages/server/src/services/credentials/index.ts b/packages/server/src/services/credentials/index.ts index 89219cabe26..e07c32da3af 100644 --- a/packages/server/src/services/credentials/index.ts +++ b/packages/server/src/services/credentials/index.ts @@ -31,10 +31,10 @@ const createCredential = async (requestBody: any) => { } // Delete all credentials from chatflowid -const deleteCredentials = async (credentialId: string): Promise => { +const deleteCredentials = async (credentialId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() - const dbResponse = await appServer.AppDataSource.getRepository(Credential).delete({ id: credentialId }) + const dbResponse = await appServer.AppDataSource.getRepository(Credential).delete({ id: credentialId, workspaceId: workspaceId }) if (!dbResponse) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Credential ${credentialId} not found`) } @@ -47,7 +47,7 @@ const deleteCredentials = async (credentialId: string): Promise => { } } -const getAllCredentials = async (paramCredentialName: any, workspaceId?: string) => { +const getAllCredentials = async (paramCredentialName: any, workspaceId: string) => { try { const appServer = getRunningExpressApp() let dbResponse = [] @@ -124,7 +124,7 @@ const getAllCredentials = async (paramCredentialName: any, workspaceId?: string) } } -const getCredentialById = async (credentialId: string, workspaceId?: string): Promise => { +const getCredentialById = async (credentialId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const credential = await appServer.AppDataSource.getRepository(Credential).findOneBy({ @@ -165,11 +165,12 @@ const getCredentialById = async (credentialId: string, workspaceId?: string): Pr } } -const updateCredential = async (credentialId: string, requestBody: any): Promise => { +const updateCredential = async (credentialId: string, requestBody: any, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() const credential = await appServer.AppDataSource.getRepository(Credential).findOneBy({ - id: credentialId + id: credentialId, + workspaceId: workspaceId }) if (!credential) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Credential ${credentialId} not found`) @@ -177,6 +178,7 @@ const updateCredential = async (credentialId: string, requestBody: any): Promise const decryptedCredentialData = await decryptCredentialData(credential.encryptedData) requestBody.plainDataObj = { ...decryptedCredentialData, ...requestBody.plainDataObj } const updateCredential = await transformToCredentialEntity(requestBody) + updateCredential.workspaceId = workspaceId await appServer.AppDataSource.getRepository(Credential).merge(credential, updateCredential) const dbResponse = await appServer.AppDataSource.getRepository(Credential).save(credential) return dbResponse diff --git a/packages/server/src/services/dataset/index.ts b/packages/server/src/services/dataset/index.ts index 351919e6b23..4042e420f40 100644 --- a/packages/server/src/services/dataset/index.ts +++ b/packages/server/src/services/dataset/index.ts @@ -9,7 +9,7 @@ import { In } from 'typeorm' import csv from 'csv-parser' -const getAllDatasets = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllDatasets = async (workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() const queryBuilder = appServer.AppDataSource.getRepository(Dataset).createQueryBuilder('ds').orderBy('ds.updatedDate', 'DESC') @@ -43,11 +43,12 @@ const getAllDatasets = async (workspaceId?: string, page: number = -1, limit: nu } } -const getDataset = async (id: string, page: number = -1, limit: number = -1) => { +const getDataset = async (id: string, workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() const dataset = await appServer.AppDataSource.getRepository(Dataset).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) const queryBuilder = appServer.AppDataSource.getRepository(DatasetRow).createQueryBuilder('dsr').orderBy('dsr.sequenceNo', 'ASC') queryBuilder.andWhere('dsr.datasetId = :datasetId', { datasetId: id }) @@ -88,7 +89,7 @@ const getDataset = async (id: string, page: number = -1, limit: number = -1) => } } -const reorderDatasetRow = async (datasetId: string, rows: any[]) => { +const reorderDatasetRow = async (datasetId: string, rows: any[], workspaceId: string) => { try { const appServer = getRunningExpressApp() await appServer.AppDataSource.transaction(async (entityManager) => { @@ -102,7 +103,7 @@ const reorderDatasetRow = async (datasetId: string, rows: any[]) => { item.sequenceNo = row.sequenceNo await entityManager.getRepository(DatasetRow).save(item) } - await changeUpdateOnDataset(datasetId, entityManager) + await changeUpdateOnDataset(datasetId, workspaceId, entityManager) }) return { message: 'Dataset row reordered successfully' } } catch (error) { @@ -211,11 +212,12 @@ const createDataset = async (body: any) => { } // Update dataset -const updateDataset = async (id: string, body: any) => { +const updateDataset = async (id: string, body: any, workspaceId: string) => { try { const appServer = getRunningExpressApp() const dataset = await appServer.AppDataSource.getRepository(Dataset).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!dataset) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Dataset ${id} not found`) @@ -230,10 +232,10 @@ const updateDataset = async (id: string, body: any) => { } // Delete dataset via id -const deleteDataset = async (id: string) => { +const deleteDataset = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() - const result = await appServer.AppDataSource.getRepository(Dataset).delete({ id: id }) + const result = await appServer.AppDataSource.getRepository(Dataset).delete({ id: id, workspaceId: workspaceId }) // delete all rows for this dataset await appServer.AppDataSource.getRepository(DatasetRow).delete({ datasetId: id }) @@ -250,7 +252,7 @@ const addDatasetRow = async (body: any) => { const appServer = getRunningExpressApp() if (body.csvFile) { await _csvToDatasetRows(body.datasetId, body.csvFile, body.firstRowHeaders) - await changeUpdateOnDataset(body.datasetId) + await changeUpdateOnDataset(body.datasetId, body.workspaceId) return { message: 'Dataset rows added successfully' } } else { // get the max value first @@ -272,7 +274,7 @@ const addDatasetRow = async (body: any) => { newDs.sequenceNo = sequenceNo === 0 ? sequenceNo : sequenceNo + 1 const row = appServer.AppDataSource.getRepository(DatasetRow).create(newDs) const result = await appServer.AppDataSource.getRepository(DatasetRow).save(row) - await changeUpdateOnDataset(body.datasetId) + await changeUpdateOnDataset(body.datasetId, body.workspaceId) return result } } catch (error) { @@ -283,10 +285,11 @@ const addDatasetRow = async (body: any) => { } } -const changeUpdateOnDataset = async (id: string, entityManager?: any) => { +const changeUpdateOnDataset = async (id: string, workspaceId: string, entityManager?: any) => { const appServer = getRunningExpressApp() const dataset = await appServer.AppDataSource.getRepository(Dataset).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!dataset) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Dataset ${id} not found`) @@ -311,7 +314,7 @@ const updateDatasetRow = async (id: string, body: any) => { Object.assign(updateItem, body) appServer.AppDataSource.getRepository(DatasetRow).merge(item, updateItem) const result = await appServer.AppDataSource.getRepository(DatasetRow).save(item) - await changeUpdateOnDataset(body.datasetId) + await changeUpdateOnDataset(body.datasetId, body.workspaceId) return result } catch (error) { throw new InternalFlowiseError( @@ -322,7 +325,7 @@ const updateDatasetRow = async (id: string, body: any) => { } // Delete dataset row via id -const deleteDatasetRow = async (id: string) => { +const deleteDatasetRow = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() return await appServer.AppDataSource.transaction(async (entityManager) => { @@ -332,7 +335,7 @@ const deleteDatasetRow = async (id: string) => { if (!item) throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Dataset Row ${id} not found`) const result = await entityManager.getRepository(DatasetRow).delete({ id: id }) - await changeUpdateOnDataset(item.datasetId, entityManager) + await changeUpdateOnDataset(item.datasetId, workspaceId, entityManager) return result }) } catch (error) { @@ -344,7 +347,7 @@ const deleteDatasetRow = async (id: string) => { } // Delete dataset rows via ids -const patchDeleteRows = async (ids: string[] = []) => { +const patchDeleteRows = async (ids: string[] = [], workspaceId: string) => { try { const appServer = getRunningExpressApp() const datasetItemsToBeDeleted = await appServer.AppDataSource.getRepository(DatasetRow).find({ @@ -356,7 +359,7 @@ const patchDeleteRows = async (ids: string[] = []) => { const datasetIds = [...new Set(datasetItemsToBeDeleted.map((item) => item.datasetId))] for (const datasetId of datasetIds) { - await changeUpdateOnDataset(datasetId) + await changeUpdateOnDataset(datasetId, workspaceId) } return dbResponse } catch (error) { diff --git a/packages/server/src/services/documentstore/index.ts b/packages/server/src/services/documentstore/index.ts index 05520523de4..0ee1cad2015 100644 --- a/packages/server/src/services/documentstore/index.ts +++ b/packages/server/src/services/documentstore/index.ts @@ -77,7 +77,7 @@ const createDocumentStore = async (newDocumentStore: DocumentStore, orgId: strin } } -const getAllDocumentStores = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllDocumentStores = async (workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() const queryBuilder = appServer.AppDataSource.getRepository(DocumentStore) @@ -88,7 +88,7 @@ const getAllDocumentStores = async (workspaceId?: string, page: number = -1, lim queryBuilder.skip((page - 1) * limit) queryBuilder.take(limit) } - if (workspaceId) queryBuilder.andWhere('doc_store.workspaceId = :workspaceId', { workspaceId }) + queryBuilder.andWhere('doc_store.workspaceId = :workspaceId', { workspaceId }) const [data, total] = await queryBuilder.getManyAndCount() @@ -172,11 +172,12 @@ const deleteLoaderFromDocumentStore = async ( } } -const getDocumentStoreById = async (storeId: string) => { +const getDocumentStoreById = async (storeId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError( @@ -193,7 +194,7 @@ const getDocumentStoreById = async (storeId: string) => { } } -const getUsedChatflowNames = async (entity: DocumentStore) => { +const getUsedChatflowNames = async (entity: DocumentStore, workspaceId: string) => { try { const appServer = getRunningExpressApp() if (entity.whereUsed) { @@ -201,7 +202,7 @@ const getUsedChatflowNames = async (entity: DocumentStore) => { const updatedWhereUsed: IDocumentStoreWhereUsed[] = [] for (let i = 0; i < whereUsed.length; i++) { const associatedChatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOne({ - where: { id: whereUsed[i] }, + where: { id: whereUsed[i], workspaceId: workspaceId }, select: ['id', 'name'] }) if (associatedChatflow) { @@ -223,10 +224,17 @@ const getUsedChatflowNames = async (entity: DocumentStore) => { } // Get chunks for a specific loader or store -const getDocumentStoreFileChunks = async (appDataSource: DataSource, storeId: string, docId: string, pageNo: number = 1) => { +const getDocumentStoreFileChunks = async ( + appDataSource: DataSource, + storeId: string, + docId: string, + workspaceId: string, + pageNo: number = 1 +) => { try { const entity = await appDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError( @@ -307,24 +315,20 @@ const deleteDocumentStore = async (storeId: string, orgId: string, workspaceId: try { const appServer = getRunningExpressApp() - // delete all the chunks associated with the store - await appServer.AppDataSource.getRepository(DocumentStoreFileChunk).delete({ - storeId: storeId - }) - // now delete the files associated with the store const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${storeId} not found`) } - if (workspaceId) { - if (entity?.workspaceId !== workspaceId) { - throw new Error('Unauthorized access') - } - } + // delete all the chunks associated with the store + await appServer.AppDataSource.getRepository(DocumentStoreFileChunk).delete({ + storeId: storeId + }) + // now delete the files associated with the store try { const { totalSize } = await removeFilesFromStorage(orgId, DOCUMENT_STORE_BASE_FOLDER, entity.id) await updateStorageUsage(orgId, workspaceId, totalSize, usageCacheManager) @@ -351,11 +355,12 @@ const deleteDocumentStore = async (storeId: string, orgId: string, workspaceId: } } -const deleteDocumentStoreFileChunk = async (storeId: string, docId: string, chunkId: string) => { +const deleteDocumentStoreFileChunk = async (storeId: string, docId: string, chunkId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${storeId} not found`) @@ -377,7 +382,7 @@ const deleteDocumentStoreFileChunk = async (storeId: string, docId: string, chun found.totalChars -= tbdChunk.pageContent.length entity.loaders = JSON.stringify(loaders) await appServer.AppDataSource.getRepository(DocumentStore).save(entity) - return getDocumentStoreFileChunks(appServer.AppDataSource, storeId, docId) + return getDocumentStoreFileChunks(appServer.AppDataSource, storeId, docId, workspaceId) } catch (error) { throw new InternalFlowiseError( StatusCodes.INTERNAL_SERVER_ERROR, @@ -386,13 +391,14 @@ const deleteDocumentStoreFileChunk = async (storeId: string, docId: string, chun } } -const deleteVectorStoreFromStore = async (storeId: string) => { +const deleteVectorStoreFromStore = async (storeId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const componentNodes = appServer.nodesPool.componentNodes const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${storeId} not found`) @@ -465,11 +471,19 @@ const deleteVectorStoreFromStore = async (storeId: string) => { } } -const editDocumentStoreFileChunk = async (storeId: string, docId: string, chunkId: string, content: string, metadata: ICommonObject) => { +const editDocumentStoreFileChunk = async ( + storeId: string, + docId: string, + chunkId: string, + content: string, + metadata: ICommonObject, + workspaceId: string +) => { try { const appServer = getRunningExpressApp() const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: storeId + id: storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${storeId} not found`) @@ -493,7 +507,7 @@ const editDocumentStoreFileChunk = async (storeId: string, docId: string, chunkI await appServer.AppDataSource.getRepository(DocumentStoreFileChunk).save(editChunk) entity.loaders = JSON.stringify(loaders) await appServer.AppDataSource.getRepository(DocumentStore).save(entity) - return getDocumentStoreFileChunks(appServer.AppDataSource, storeId, docId) + return getDocumentStoreFileChunks(appServer.AppDataSource, storeId, docId, workspaceId) } catch (error) { throw new InternalFlowiseError( StatusCodes.INTERNAL_SERVER_ERROR, @@ -718,10 +732,15 @@ export const previewChunks = async ({ appDataSource, componentNodes, data, orgId } } -const saveProcessingLoader = async (appDataSource: DataSource, data: IDocumentStoreLoaderForPreview): Promise => { +const saveProcessingLoader = async ( + appDataSource: DataSource, + data: IDocumentStoreLoaderForPreview, + workspaceId: string +): Promise => { try { const entity = await appDataSource.getRepository(DocumentStore).findOneBy({ - id: data.storeId + id: data.storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError( @@ -809,7 +828,8 @@ export const processLoader = async ({ usageCacheManager }: IExecuteProcessLoader) => { const entity = await appDataSource.getRepository(DocumentStore).findOneBy({ - id: data.storeId + id: data.storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError( @@ -817,11 +837,6 @@ export const processLoader = async ({ `Error: documentStoreServices.processLoader - Document store ${data.storeId} not found` ) } - if (workspaceId) { - if (entity?.workspaceId !== workspaceId) { - throw new Error('Unauthorized access') - } - } await _saveChunksToStorage( appDataSource, componentNodes, @@ -833,7 +848,7 @@ export const processLoader = async ({ subscriptionId, usageCacheManager ) - return getDocumentStoreFileChunks(appDataSource, data.storeId as string, docLoaderId) + return getDocumentStoreFileChunks(appDataSource, data.storeId as string, docLoaderId, workspaceId) } const processLoaderMiddleware = async ( @@ -1114,11 +1129,12 @@ const updateDocumentStoreUsage = async (chatId: string, storeId: string | undefi } } -const updateVectorStoreConfigOnly = async (data: ICommonObject) => { +const updateVectorStoreConfigOnly = async (data: ICommonObject, workspaceId: string) => { try { const appServer = getRunningExpressApp() const entity = await appServer.AppDataSource.getRepository(DocumentStore).findOneBy({ - id: data.storeId + id: data.storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${data.storeId} not found`) @@ -1141,10 +1157,11 @@ const updateVectorStoreConfigOnly = async (data: ICommonObject) => { ) } } -const saveVectorStoreConfig = async (appDataSource: DataSource, data: ICommonObject, isStrictSave = true) => { +const saveVectorStoreConfig = async (appDataSource: DataSource, data: ICommonObject, isStrictSave = true, workspaceId: string) => { try { const entity = await appDataSource.getRepository(DocumentStore).findOneBy({ - id: data.storeId + id: data.storeId, + workspaceId: workspaceId }) if (!entity) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Document store ${data.storeId} not found`) @@ -1210,14 +1227,23 @@ export const insertIntoVectorStore = async ({ telemetry, data, isStrictSave, - orgId + orgId, + workspaceId }: IExecuteVectorStoreInsert) => { try { - const entity = await saveVectorStoreConfig(appDataSource, data, isStrictSave) + const entity = await saveVectorStoreConfig(appDataSource, data, isStrictSave, workspaceId) entity.status = DocumentStoreStatus.UPSERTING await appDataSource.getRepository(DocumentStore).save(entity) - const indexResult = await _insertIntoVectorStoreWorkerThread(appDataSource, componentNodes, telemetry, data, isStrictSave, orgId) + const indexResult = await _insertIntoVectorStoreWorkerThread( + appDataSource, + componentNodes, + telemetry, + data, + isStrictSave, + orgId, + workspaceId + ) return indexResult } catch (error) { throw new InternalFlowiseError( @@ -1283,10 +1309,11 @@ const _insertIntoVectorStoreWorkerThread = async ( telemetry: Telemetry, data: ICommonObject, isStrictSave = true, - orgId: string + orgId: string, + workspaceId: string ) => { try { - const entity = await saveVectorStoreConfig(appDataSource, data, isStrictSave) + const entity = await saveVectorStoreConfig(appDataSource, data, isStrictSave, workspaceId) let upsertHistory: Record = {} const chatflowid = data.storeId // fake chatflowid because this is not tied to any chatflow @@ -1858,7 +1885,7 @@ const upsertDocStore = async ( } try { - const newLoader = await saveProcessingLoader(appDataSource, processData) + const newLoader = await saveProcessingLoader(appDataSource, processData, workspaceId) const result = await processLoader({ appDataSource, componentNodes, diff --git a/packages/server/src/services/domainValidation/index.ts b/packages/server/src/services/domainValidation/index.ts new file mode 100644 index 00000000000..08f1870ffde --- /dev/null +++ b/packages/server/src/services/domainValidation/index.ts @@ -0,0 +1,102 @@ +import chatflowsService from '../chatflows' +import logger from '../../utils/logger' + +export class DomainValidationService { + /** + * Validates if the origin is allowed for a specific chatflow + * @param chatflowId - The chatflow ID to validate against + * @param origin - The origin URL to validate + * @param workspaceId - Optional workspace ID for enterprise features + * @returns Promise - True if domain is allowed, false otherwise + */ + static async validateChatflowDomain(chatflowId: string, origin: string, workspaceId?: string): Promise { + try { + const chatflow = await chatflowsService.getChatflowById(chatflowId, workspaceId) + + if (!chatflow?.chatbotConfig) { + logger.info(`No chatbotConfig found for chatflow ${chatflowId}, allowing domain`) + return true + } + + const config = JSON.parse(chatflow.chatbotConfig) + + // If no allowed origins configured or first entry is empty, allow all + if (!config.allowedOrigins?.length || config.allowedOrigins[0] === '') { + logger.info(`No domain restrictions configured for chatflow ${chatflowId}`) + return true + } + + const originHost = new URL(origin).host + const isAllowed = config.allowedOrigins.some((domain: string) => { + try { + const allowedOrigin = new URL(domain).host + return originHost === allowedOrigin + } catch (error) { + logger.warn(`Invalid domain format in allowedOrigins: ${domain}`) + return false + } + }) + + logger.info(`Domain validation for ${origin} against chatflow ${chatflowId}: ${isAllowed}`) + return isAllowed + + } catch (error) { + logger.error(`Error validating domain for chatflow ${chatflowId}:`, error) + return false + } + } + + /** + * Extracts chatflow ID from prediction URL + * @param url - The request URL + * @returns string | null - The chatflow ID or null if not found + */ + static extractChatflowId(url: string): string | null { + try { + const urlParts = url.split('/') + const predictionIndex = urlParts.indexOf('prediction') + + if (predictionIndex !== -1 && urlParts.length > predictionIndex + 1) { + const chatflowId = urlParts[predictionIndex + 1] + // Remove query parameters if present + return chatflowId.split('?')[0] + } + + return null + } catch (error) { + logger.error('Error extracting chatflow ID from URL:', error) + return null + } + } + + /** + * Validates if a request is a prediction request + * @param url - The request URL + * @returns boolean - True if it's a prediction request + */ + static isPredictionRequest(url: string): boolean { + return url.includes('/prediction/') + } + + /** + * Get the custom error message for unauthorized origin + * @param chatflowId - The chatflow ID + * @param workspaceId - Optional workspace ID + * @returns Promise - Custom error message or default + */ + static async getUnauthorizedOriginError(chatflowId: string, workspaceId?: string): Promise { + try { + const chatflow = await chatflowsService.getChatflowById(chatflowId, workspaceId) + + if (chatflow?.chatbotConfig) { + const config = JSON.parse(chatflow.chatbotConfig) + return config.allowedOriginsError || 'This site is not allowed to access this chatbot' + } + + return 'This site is not allowed to access this chatbot' + } catch (error) { + logger.error(`Error getting unauthorized origin error for chatflow ${chatflowId}:`, error) + return 'This site is not allowed to access this chatbot' + } + } +} \ No newline at end of file diff --git a/packages/server/src/services/evaluations/EvaluatorRunner.ts b/packages/server/src/services/evaluations/EvaluatorRunner.ts index 4b2d7d81da1..3f2a42081d7 100644 --- a/packages/server/src/services/evaluations/EvaluatorRunner.ts +++ b/packages/server/src/services/evaluations/EvaluatorRunner.ts @@ -14,7 +14,8 @@ export const runAdditionalEvaluators = async ( metricsArray: ICommonObject[], actualOutputArray: string[], errorArray: string[], - selectedEvaluators: string[] + selectedEvaluators: string[], + workspaceId: string ) => { const evaluationResults: any[] = [] const evaluatorDict: any = {} @@ -27,7 +28,7 @@ export const runAdditionalEvaluators = async ( const evaluatorId = selectedEvaluators[i] let evaluator = evaluatorDict[evaluatorId] if (!evaluator) { - evaluator = await evaluatorsService.getEvaluator(evaluatorId) + evaluator = await evaluatorsService.getEvaluator(evaluatorId, workspaceId) evaluatorDict[evaluatorId] = evaluator } diff --git a/packages/server/src/services/evaluations/index.ts b/packages/server/src/services/evaluations/index.ts index 9195ac26f7c..fe0aae71b73 100644 --- a/packages/server/src/services/evaluations/index.ts +++ b/packages/server/src/services/evaluations/index.ts @@ -21,11 +21,12 @@ import evaluatorsService from '../evaluator' import { LLMEvaluationRunner } from './LLMEvaluationRunner' import { Assistant } from '../../database/entities/Assistant' -const runAgain = async (id: string, baseURL: string, orgId: string) => { +const runAgain = async (id: string, baseURL: string, orgId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluation = await appServer.AppDataSource.getRepository(Evaluation).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluation) throw new Error(`Evaluation ${id} not found`) const additionalConfig = evaluation.additionalConfig ? JSON.parse(evaluation.additionalConfig) : {} @@ -55,13 +56,13 @@ const runAgain = async (id: string, baseURL: string, orgId: string) => { } } data.version = true - return await createEvaluation(data, baseURL, orgId) + return await createEvaluation(data, baseURL, orgId, workspaceId) } catch (error) { throw new InternalFlowiseError(StatusCodes.INTERNAL_SERVER_ERROR, `Error: EvalsService.runAgain - ${getErrorMessage(error)}`) } } -const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: string) => { +const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const newEval = new Evaluation() @@ -97,7 +98,8 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str ) const dataset = await appServer.AppDataSource.getRepository(Dataset).findOneBy({ - id: body.datasetId + id: body.datasetId, + workspaceId: workspaceId }) if (!dataset) throw new Error(`Dataset ${body.datasetId} not found`) @@ -124,7 +126,8 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str for (let i = 0; i < chatflowIds.length; i++) { const chatflowId = chatflowIds[i] const cFlow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ - id: chatflowId + id: chatflowId, + workspaceId: workspaceId }) if (cFlow && cFlow.apikeyid) { const apikeyObj = await appServer.AppDataSource.getRepository(ApiKey).findOneBy({ @@ -243,7 +246,8 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str metricsArray, actualOutputArray, errorArray, - body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [] + body.selectedSimpleEvaluators.length > 0 ? JSON.parse(body.selectedSimpleEvaluators) : [], + workspaceId ) newRun.evaluators = JSON.stringify(results) @@ -257,7 +261,7 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str const llmEvaluatorMap: { evaluatorId: string; evaluator: any }[] = [] for (let i = 0; i < resultRow.LLMEvaluators.length; i++) { const evaluatorId = resultRow.LLMEvaluators[i] - const evaluator = await evaluatorsService.getEvaluator(evaluatorId) + const evaluator = await evaluatorsService.getEvaluator(evaluatorId, workspaceId) llmEvaluatorMap.push({ evaluatorId: evaluatorId, evaluator: evaluator @@ -338,7 +342,7 @@ const createEvaluation = async (body: ICommonObject, baseURL: string, orgId: str } } -const getAllEvaluations = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllEvaluations = async (workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() @@ -421,7 +425,7 @@ const getAllEvaluations = async (workspaceId?: string, page: number = -1, limit: } // Delete evaluation and all rows via id -const deleteEvaluation = async (id: string, activeWorkspaceId?: string) => { +const deleteEvaluation = async (id: string, activeWorkspaceId: string) => { try { const appServer = getRunningExpressApp() await appServer.AppDataSource.getRepository(Evaluation).delete({ id: id }) @@ -437,11 +441,12 @@ const deleteEvaluation = async (id: string, activeWorkspaceId?: string) => { } // check for outdated evaluations -const isOutdated = async (id: string) => { +const isOutdated = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluation = await appServer.AppDataSource.getRepository(Evaluation).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluation) throw new Error(`Evaluation ${id} not found`) const evaluationRunDate = evaluation.runDate.getTime() @@ -456,7 +461,8 @@ const isOutdated = async (id: string) => { // check if the evaluation is outdated by extracting the runTime and then check with the dataset last updated time as well // as the chatflows last updated time. If the evaluation is outdated, then return true else return false const dataset = await appServer.AppDataSource.getRepository(Dataset).findOneBy({ - id: evaluation.datasetId + id: evaluation.datasetId, + workspaceId: workspaceId }) if (dataset) { const datasetLastUpdated = dataset.updatedDate.getTime() @@ -483,7 +489,8 @@ const isOutdated = async (id: string) => { } } const chatflow = await appServer.AppDataSource.getRepository(ChatFlow).findOneBy({ - id: chatflowIds[i] + id: chatflowIds[i], + workspaceId: workspaceId }) if (!chatflow) { returnObj.errors.push({ @@ -511,7 +518,8 @@ const isOutdated = async (id: string) => { continue } const assistant = await appServer.AppDataSource.getRepository(Assistant).findOneBy({ - id: chatflowIds[i] + id: chatflowIds[i], + workspaceId: workspaceId }) if (!assistant) { returnObj.errors.push({ @@ -540,11 +548,12 @@ const isOutdated = async (id: string) => { } } -const getEvaluation = async (id: string) => { +const getEvaluation = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluation = await appServer.AppDataSource.getRepository(Evaluation).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluation) throw new Error(`Evaluation ${id} not found`) const versionCount = await appServer.AppDataSource.getRepository(Evaluation).countBy({ @@ -553,7 +562,7 @@ const getEvaluation = async (id: string) => { const items = await appServer.AppDataSource.getRepository(EvaluationRun).find({ where: { evaluationId: id } }) - const versions = (await getVersions(id)).versions + const versions = (await getVersions(id, workspaceId)).versions const versionNo = versions.findIndex((version) => version.id === id) + 1 return { ...evaluation, @@ -566,11 +575,12 @@ const getEvaluation = async (id: string) => { } } -const getVersions = async (id: string) => { +const getVersions = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluation = await appServer.AppDataSource.getRepository(Evaluation).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluation) throw new Error(`Evaluation ${id} not found`) const versions = await appServer.AppDataSource.getRepository(Evaluation).find({ @@ -597,12 +607,13 @@ const getVersions = async (id: string) => { } } -const patchDeleteEvaluations = async (ids: string[] = [], isDeleteAllVersion?: boolean, activeWorkspaceId?: string) => { +const patchDeleteEvaluations = async (ids: string[] = [], activeWorkspaceId: string, isDeleteAllVersion?: boolean) => { try { const appServer = getRunningExpressApp() const evalsToBeDeleted = await appServer.AppDataSource.getRepository(Evaluation).find({ where: { - id: In(ids) + id: In(ids), + workspaceId: activeWorkspaceId } }) await appServer.AppDataSource.getRepository(Evaluation).delete(ids) diff --git a/packages/server/src/services/evaluator/index.ts b/packages/server/src/services/evaluator/index.ts index 3cfbcc6f399..bd3d7e23a30 100644 --- a/packages/server/src/services/evaluator/index.ts +++ b/packages/server/src/services/evaluator/index.ts @@ -5,11 +5,11 @@ import { getErrorMessage } from '../../errors/utils' import { Evaluator } from '../../database/entities/Evaluator' import { EvaluatorDTO } from '../../Interface.Evaluation' -const getAllEvaluators = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllEvaluators = async (workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() const queryBuilder = appServer.AppDataSource.getRepository(Evaluator).createQueryBuilder('ev').orderBy('ev.updatedDate', 'DESC') - if (workspaceId) queryBuilder.andWhere('ev.workspaceId = :workspaceId', { workspaceId }) + queryBuilder.andWhere('ev.workspaceId = :workspaceId', { workspaceId }) if (page > 0 && limit > 0) { queryBuilder.skip((page - 1) * limit) queryBuilder.take(limit) @@ -31,11 +31,12 @@ const getAllEvaluators = async (workspaceId?: string, page: number = -1, limit: } } -const getEvaluator = async (id: string) => { +const getEvaluator = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluator = await appServer.AppDataSource.getRepository(Evaluator).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluator) throw new Error(`Evaluator ${id} not found`) return EvaluatorDTO.fromEntity(evaluator) @@ -65,11 +66,12 @@ const createEvaluator = async (body: any) => { } // Update Evaluator -const updateEvaluator = async (id: string, body: any) => { +const updateEvaluator = async (id: string, body: any, workspaceId: string) => { try { const appServer = getRunningExpressApp() const evaluator = await appServer.AppDataSource.getRepository(Evaluator).findOneBy({ - id: id + id: id, + workspaceId: workspaceId }) if (!evaluator) throw new Error(`Evaluator ${id} not found`) @@ -88,10 +90,10 @@ const updateEvaluator = async (id: string, body: any) => { } // Delete Evaluator via id -const deleteEvaluator = async (id: string) => { +const deleteEvaluator = async (id: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() - return await appServer.AppDataSource.getRepository(Evaluator).delete({ id: id }) + return await appServer.AppDataSource.getRepository(Evaluator).delete({ id: id, workspaceId: workspaceId }) } catch (error) { throw new InternalFlowiseError( StatusCodes.INTERNAL_SERVER_ERROR, diff --git a/packages/server/src/services/export-import/index.ts b/packages/server/src/services/export-import/index.ts index 8873f9824da..7e2d8f461d7 100644 --- a/packages/server/src/services/export-import/index.ts +++ b/packages/server/src/services/export-import/index.ts @@ -90,7 +90,7 @@ const convertExportInput = (body: any): ExportInput => { } const FileDefaultName = 'ExportData.json' -const exportData = async (exportInput: ExportInput, activeWorkspaceId?: string): Promise<{ FileDefaultName: string } & ExportData> => { +const exportData = async (exportInput: ExportInput, activeWorkspaceId: string): Promise<{ FileDefaultName: string } & ExportData> => { try { let AgentFlow: ChatFlow[] | { data: ChatFlow[]; total: number } = exportInput.agentflow === true ? await chatflowService.getAllChatflows('MULTIAGENT', activeWorkspaceId) : [] @@ -101,17 +101,17 @@ const exportData = async (exportInput: ExportInput, activeWorkspaceId?: string): AgentFlowV2 = 'data' in AgentFlowV2 ? AgentFlowV2.data : AgentFlowV2 let AssistantCustom: Assistant[] = - exportInput.assistantCustom === true ? await assistantService.getAllAssistants('CUSTOM', activeWorkspaceId) : [] + exportInput.assistantCustom === true ? await assistantService.getAllAssistants(activeWorkspaceId, 'CUSTOM') : [] let AssistantFlow: ChatFlow[] | { data: ChatFlow[]; total: number } = exportInput.assistantCustom === true ? await chatflowService.getAllChatflows('ASSISTANT', activeWorkspaceId) : [] AssistantFlow = 'data' in AssistantFlow ? AssistantFlow.data : AssistantFlow let AssistantOpenAI: Assistant[] = - exportInput.assistantOpenAI === true ? await assistantService.getAllAssistants('OPENAI', activeWorkspaceId) : [] + exportInput.assistantOpenAI === true ? await assistantService.getAllAssistants(activeWorkspaceId, 'OPENAI') : [] let AssistantAzure: Assistant[] = - exportInput.assistantAzure === true ? await assistantService.getAllAssistants('AZURE', activeWorkspaceId) : [] + exportInput.assistantAzure === true ? await assistantService.getAllAssistants(activeWorkspaceId, 'AZURE') : [] let ChatFlow: ChatFlow[] | { data: ChatFlow[]; total: number } = exportInput.chatflow === true ? await chatflowService.getAllChatflows('CHATFLOW', activeWorkspaceId) : [] diff --git a/packages/server/src/services/flow-configs/index.ts b/packages/server/src/services/flow-configs/index.ts index 8ce05499f2c..7755e86f39e 100644 --- a/packages/server/src/services/flow-configs/index.ts +++ b/packages/server/src/services/flow-configs/index.ts @@ -6,10 +6,10 @@ import chatflowsService from '../chatflows' import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { getErrorMessage } from '../../errors/utils' -const getSingleFlowConfig = async (chatflowId: string): Promise => { +const getSingleFlowConfig = async (chatflowId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() - const chatflow = await chatflowsService.getChatflowById(chatflowId) + const chatflow = await chatflowsService.getChatflowById(chatflowId, workspaceId) if (!chatflow) { throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Chatflow ${chatflowId} not found in the database!`) } diff --git a/packages/server/src/services/marketplaces/index.ts b/packages/server/src/services/marketplaces/index.ts index 6f7f9c6b654..c7a3b26a18c 100644 --- a/packages/server/src/services/marketplaces/index.ts +++ b/packages/server/src/services/marketplaces/index.ts @@ -211,7 +211,7 @@ const saveCustomTemplate = async (body: any): Promise => { Object.assign(customTemplate, body) if (body.chatflowId) { - const chatflow = await chatflowsService.getChatflowById(body.chatflowId) + const chatflow = await chatflowsService.getChatflowById(body.chatflowId, body.workspaceId) const flowData = JSON.parse(chatflow.flowData) const { framework, exportJson } = _generateExportFlowData(flowData) flowDataStr = JSON.stringify(exportJson) diff --git a/packages/server/src/services/variables/index.ts b/packages/server/src/services/variables/index.ts index fb1f10a48ae..5b427e95488 100644 --- a/packages/server/src/services/variables/index.ts +++ b/packages/server/src/services/variables/index.ts @@ -32,10 +32,10 @@ const createVariable = async (newVariable: Variable, orgId: string) => { } } -const deleteVariable = async (variableId: string): Promise => { +const deleteVariable = async (variableId: string, workspaceId: string): Promise => { try { const appServer = getRunningExpressApp() - const dbResponse = await appServer.AppDataSource.getRepository(Variable).delete({ id: variableId }) + const dbResponse = await appServer.AppDataSource.getRepository(Variable).delete({ id: variableId, workspaceId: workspaceId }) return dbResponse } catch (error) { throw new InternalFlowiseError( @@ -45,7 +45,7 @@ const deleteVariable = async (variableId: string): Promise => { } } -const getAllVariables = async (workspaceId?: string, page: number = -1, limit: number = -1) => { +const getAllVariables = async (workspaceId: string, page: number = -1, limit: number = -1) => { try { const appServer = getRunningExpressApp() const queryBuilder = appServer.AppDataSource.getRepository(Variable) @@ -77,11 +77,12 @@ const getAllVariables = async (workspaceId?: string, page: number = -1, limit: n } } -const getVariableById = async (variableId: string) => { +const getVariableById = async (variableId: string, workspaceId: string) => { try { const appServer = getRunningExpressApp() const dbResponse = await appServer.AppDataSource.getRepository(Variable).findOneBy({ - id: variableId + id: variableId, + workspaceId: workspaceId }) if (appServer.identityManager.getPlatformType() === Platform.CLOUD && dbResponse?.type === 'runtime') { diff --git a/packages/server/src/utils/XSS.ts b/packages/server/src/utils/XSS.ts index 96bbab573cd..d7a0fd97a51 100644 --- a/packages/server/src/utils/XSS.ts +++ b/packages/server/src/utils/XSS.ts @@ -1,5 +1,7 @@ import { Request, Response, NextFunction } from 'express' import sanitizeHtml from 'sanitize-html' +import logger from './logger' +import { DomainValidationService } from '../services/domainValidation' export function sanitizeMiddleware(req: Request, res: Response, next: NextFunction): void { // decoding is necessary as the url is encoded by the browser @@ -25,17 +27,50 @@ export function getAllowedCorsOrigins(): string { } export function getCorsOptions(): any { - const corsOptions = { - origin: function (origin: string | undefined, callback: (err: Error | null, allow?: boolean) => void) { - const allowedOrigins = getAllowedCorsOrigins() - if (!origin || allowedOrigins == '*' || allowedOrigins.indexOf(origin) !== -1) { - callback(null, true) - } else { - callback(null, false) + return function (req: any, callback: (err: Error | null, options?: any) => void) { + const corsOptions = { + origin: async function (origin: string | undefined, originCallback: (err: Error | null, allow?: boolean) => void) { + const allowedOrigins = getAllowedCorsOrigins() + const isPredictionRequest = DomainValidationService.isPredictionRequest(req.url) + + logger.info('allowedOrigins: ' + allowedOrigins) + logger.info('origin: ' + origin) + logger.info('req.url: ' + req.url) + logger.info('req.method: ' + req.method) + logger.info('isPredictionRequest: ' + isPredictionRequest) + logger.info('req.headers: ' + JSON.stringify(req.headers)) + logger.info('req.query: ' + JSON.stringify(req.query)) + logger.info('req.body: ' + JSON.stringify(req.body)) + + // First check global CORS origins + if (!origin || allowedOrigins == '*' || allowedOrigins.indexOf(origin) !== -1) { + + // Additional prediction-specific validation + if (isPredictionRequest) { + const chatflowId = DomainValidationService.extractChatflowId(req.url) + if (chatflowId && origin) { + const isAllowed = await DomainValidationService.validateChatflowDomain( + chatflowId, + origin, + req.user?.activeWorkspaceId + ) + logger.info(`Prediction domain validation result: ${isAllowed}`) + originCallback(null, isAllowed) + } else { + logger.info('No chatflow ID found in prediction URL or no origin header, allowing request') + originCallback(null, true) + } + } else { + originCallback(null, true) + } + } else { + logger.info('Global CORS validation failed') + originCallback(null, false) + } } } + callback(null, corsOptions) } - return corsOptions } export function getAllowedIframeOrigins(): string { diff --git a/packages/server/src/utils/index.ts b/packages/server/src/utils/index.ts index 9451a49b688..c15949386ee 100644 --- a/packages/server/src/utils/index.ts +++ b/packages/server/src/utils/index.ts @@ -833,7 +833,8 @@ export const getGlobalVariable = async ( value: overrideConfig.vars[propertyName], id: '', updatedDate: new Date(), - createdDate: new Date() + createdDate: new Date(), + workspaceId: '' }) } }