1+ import { stripProtectedFields } from '../../utils/stripProtectedFields'
12import { extractResponseContent , ICommonObject } from 'flowise-components'
23import { StatusCodes } from 'http-status-codes'
34import { cloneDeep , isEqual , uniqWith } from 'lodash'
@@ -20,7 +21,7 @@ import { ASSISTANT_PROMPT_GENERATOR } from '../../utils/prompt'
2021import { checkUsageLimit } from '../../utils/quotaUsage'
2122import nodesService from '../nodes'
2223
23- const createAssistant = async ( requestBody : any , orgId : string ) : Promise < Assistant > => {
24+ const createAssistant = async ( requestBody : any , orgId : string , workspaceId : string ) : Promise < Assistant > => {
2425 try {
2526 const appServer = getRunningExpressApp ( )
2627 if ( ! requestBody . details ) {
@@ -29,8 +30,11 @@ const createAssistant = async (requestBody: any, orgId: string): Promise<Assista
2930 const assistantDetails = JSON . parse ( requestBody . details )
3031
3132 if ( requestBody . type === 'CUSTOM' ) {
33+ // For CUSTOM assistants the credential field is a client-generated UUID used as an
34+ // internal identifier, not a reference to the Credential entity, so no lookup is needed.
3235 const newAssistant = new Assistant ( )
33- Object . assign ( newAssistant , requestBody )
36+ Object . assign ( newAssistant , stripProtectedFields ( requestBody ) )
37+ newAssistant . workspaceId = workspaceId
3438
3539 const assistant = appServer . AppDataSource . getRepository ( Assistant ) . create ( newAssistant )
3640 const dbResponse = await appServer . AppDataSource . getRepository ( Assistant ) . save ( assistant )
@@ -51,7 +55,8 @@ const createAssistant = async (requestBody: any, orgId: string): Promise<Assista
5155
5256 try {
5357 const credential = await appServer . AppDataSource . getRepository ( Credential ) . findOneBy ( {
54- id : requestBody . credential
58+ id : requestBody . credential ,
59+ workspaceId : workspaceId
5560 } )
5661
5762 if ( ! credential ) {
@@ -297,12 +302,24 @@ const updateAssistant = async (assistantId: string, requestBody: any, workspaceI
297302 throw new InternalFlowiseError ( StatusCodes . NOT_FOUND , `Assistant ${ assistantId } not found` )
298303 }
299304
305+ if ( requestBody . details !== undefined ) {
306+ if ( ! requestBody . details ) {
307+ throw new InternalFlowiseError ( StatusCodes . PRECONDITION_FAILED , `Details cannot be empty` )
308+ }
309+ let parsedDetails : any
310+ try {
311+ parsedDetails = JSON . parse ( requestBody . details )
312+ } catch ( e ) {
313+ throw new InternalFlowiseError ( StatusCodes . PRECONDITION_FAILED , `Details must be valid JSON` )
314+ }
315+ if ( assistant . type === 'CUSTOM' && ! parsedDetails ?. name ) {
316+ throw new InternalFlowiseError ( StatusCodes . PRECONDITION_FAILED , `Details must include a name field` )
317+ }
318+ }
319+
300320 if ( assistant . type === 'CUSTOM' ) {
301- const body = requestBody
302- const updateAssistant = new Assistant ( )
303- Object . assign ( updateAssistant , body )
321+ Object . assign ( assistant , stripProtectedFields ( requestBody ) )
304322
305- appServer . AppDataSource . getRepository ( Assistant ) . merge ( assistant , updateAssistant )
306323 const dbResponse = await appServer . AppDataSource . getRepository ( Assistant ) . save ( assistant )
307324 return dbResponse
308325 }
@@ -312,7 +329,8 @@ const updateAssistant = async (assistantId: string, requestBody: any, workspaceI
312329 const body = requestBody
313330 const assistantDetails = JSON . parse ( body . details )
314331 const credential = await appServer . AppDataSource . getRepository ( Credential ) . findOneBy ( {
315- id : body . credential
332+ id : body . credential ,
333+ workspaceId : workspaceId
316334 } )
317335
318336 if ( ! credential ) {
@@ -376,11 +394,12 @@ const updateAssistant = async (assistantId: string, requestBody: any, workspaceI
376394 }
377395 if ( savedToolResources ) newAssistantDetails . tool_resources = savedToolResources
378396
379- const updateAssistant = new Assistant ( )
380- body . details = JSON . stringify ( newAssistantDetails )
381- Object . assign ( updateAssistant , body )
397+ // Explicit allowlist — mutate only allowed fields on the fetched entity (same
398+ // reasoning as the CUSTOM path above: avoid merge() with an intermediate entity).
399+ assistant . details = JSON . stringify ( newAssistantDetails )
400+ if ( body . credential !== undefined ) assistant . credential = body . credential
401+ if ( body . iconSrc !== undefined ) assistant . iconSrc = body . iconSrc
382402
383- appServer . AppDataSource . getRepository ( Assistant ) . merge ( assistant , updateAssistant )
384403 const dbResponse = await appServer . AppDataSource . getRepository ( Assistant ) . save ( assistant )
385404 return dbResponse
386405 } catch ( error ) {
0 commit comments