Skip to content

Commit bb773ff

Browse files
authored
Fix Flowise 722 node load method workspace (#6593)
fix(flowise-722):add node load method workspace scope
1 parent 096d2d4 commit bb773ff

4 files changed

Lines changed: 57 additions & 10 deletions

File tree

packages/server/src/controllers/nodes/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,8 @@ const getSingleNodeAsyncOptions = async (req: Request, res: Response, next: Next
7777
}
7878
const body = req.body
7979
body.searchOptions = getWorkspaceSearchOptionsFromReq(req)
80-
const apiResponse = await nodesService.getSingleNodeAsyncOptions(req.params.name, body)
80+
const workspaceId = req.user?.activeWorkspaceId
81+
const apiResponse = await nodesService.getSingleNodeAsyncOptions(req.params.name, body, workspaceId)
8182
return res.json(apiResponse)
8283
} catch (error) {
8384
next(error)
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
11
import express from 'express'
22
import nodesRouter from '../../controllers/nodes'
3+
import { checkAnyPermission } from '../../enterprise/rbac/PermissionCheck'
4+
35
const router = express.Router()
46

5-
router.post(['/', '/:name'], nodesRouter.getSingleNodeAsyncOptions)
7+
router.post(
8+
['/', '/:name'],
9+
checkAnyPermission(
10+
'chatflows:view,chatflows:create,chatflows:update,chatflows:delete,agentflows:view,agentflows:create,agentflows:update,agentflows:delete,documentStores:view,documentStores:create,documentStores:update,documentStores:add-loader'
11+
),
12+
nodesRouter.getSingleNodeAsyncOptions
13+
)
614

715
export default router

packages/server/src/services/credentials/index.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,35 @@ const updateCredential = async (credentialId: string, requestBody: any, workspac
192192
}
193193
}
194194

195+
/**
196+
* Confirms a credential exists and belongs to (or is shared with) the given workspace.
197+
* Does NOT decrypt or return credential material — only used for authorization checks.
198+
* Throws 400 when workspaceId is missing (prevents unscoped lookup), 404 when the
199+
* credential does not belong to the workspace or is not shared with it.
200+
*/
201+
const assertCredentialInWorkspace = async (credentialId: string, workspaceId: string | undefined): Promise<void> => {
202+
if (!workspaceId) {
203+
throw new InternalFlowiseError(StatusCodes.BAD_REQUEST, `Workspace ID is required`)
204+
}
205+
const appServer = getRunningExpressApp()
206+
const owned = await appServer.AppDataSource.getRepository(Credential).findOneBy({
207+
id: credentialId,
208+
workspaceId: workspaceId
209+
})
210+
if (owned) return
211+
212+
const shared = await appServer.AppDataSource.getRepository(WorkspaceShared).count({
213+
where: {
214+
workspaceId: workspaceId,
215+
sharedItemId: credentialId,
216+
itemType: 'credential'
217+
}
218+
})
219+
if (shared > 0) return
220+
221+
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Credential ${credentialId} not found`)
222+
}
223+
195224
const revealCredentialById = async (credentialId: string, workspaceId: string): Promise<any> => {
196225
try {
197226
const appServer = getRunningExpressApp()
@@ -227,5 +256,6 @@ export default {
227256
getAllCredentials,
228257
getCredentialById,
229258
revealCredentialById,
230-
updateCredential
259+
updateCredential,
260+
assertCredentialInWorkspace
231261
}

packages/server/src/services/nodes/index.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1-
import { cloneDeep, omit } from 'lodash'
2-
import { StatusCodes } from 'http-status-codes'
3-
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
4-
import { INodeData, MODE } from '../../Interface'
51
import { ClientType, INodeOptionsValue } from 'flowise-components'
6-
import { databaseEntities } from '../../utils'
7-
import logger from '../../utils/logger'
2+
import { StatusCodes } from 'http-status-codes'
3+
import { cloneDeep, omit } from 'lodash'
84
import { InternalFlowiseError } from '../../errors/internalFlowiseError'
95
import { getErrorMessage } from '../../errors/utils'
6+
import { INodeData, MODE } from '../../Interface'
7+
import { databaseEntities } from '../../utils'
108
import { OMIT_QUEUE_JOB_DATA } from '../../utils/constants'
119
import { executeCustomNodeFunction } from '../../utils/executeCustomNodeFunction'
10+
import { getRunningExpressApp } from '../../utils/getRunningExpressApp'
11+
import logger from '../../utils/logger'
12+
import credentialsService from '../credentials'
1213
import { filterNodeByClient } from './filterNodeByClient'
1314

1415
export { filterNodeByClient }
@@ -91,11 +92,15 @@ const getSingleNodeIcon = async (nodeName: string) => {
9192
}
9293
}
9394

94-
const getSingleNodeAsyncOptions = async (nodeName: string, requestBody: any): Promise<any> => {
95+
const getSingleNodeAsyncOptions = async (nodeName: string, requestBody: any, workspaceId?: string): Promise<any> => {
9596
try {
9697
const appServer = getRunningExpressApp()
9798
const nodeData: INodeData = requestBody
9899
if (Object.prototype.hasOwnProperty.call(appServer.nodesPool.componentNodes, nodeName)) {
100+
if (nodeData.credential) {
101+
await credentialsService.assertCredentialInWorkspace(nodeData.credential, workspaceId)
102+
}
103+
99104
try {
100105
const nodeInstance = appServer.nodesPool.componentNodes[nodeName]
101106
const methodName = nodeData.loadMethod || ''
@@ -118,6 +123,9 @@ const getSingleNodeAsyncOptions = async (nodeName: string, requestBody: any): Pr
118123
throw new InternalFlowiseError(StatusCodes.NOT_FOUND, `Node ${nodeName} not found`)
119124
}
120125
} catch (error) {
126+
if (error instanceof InternalFlowiseError) {
127+
throw error
128+
}
121129
throw new InternalFlowiseError(
122130
StatusCodes.INTERNAL_SERVER_ERROR,
123131
`Error: nodesService.getSingleNodeAsyncOptions - ${getErrorMessage(error)}`

0 commit comments

Comments
 (0)