From 2f528ceced74afaa95fc7a282965e7788796448b Mon Sep 17 00:00:00 2001 From: yau-wd Date: Sat, 30 May 2026 08:05:24 +0800 Subject: [PATCH] Fix FLOWISE-597 (#6445) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(flowise-597): chatflow deletion permissions handling * fix(package.json): ERR_PNPM_MISSING_TARBALL_INTEGRITY  Cannot install package "xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz": its lockfile entry has no "integrity" field, so pnpm cannot verify the downloaded tarball. --- package.json | 2 +- .../server/src/controllers/chatflows/index.ts | 23 +++++- packages/server/src/routes/chatflows/index.ts | 2 +- .../server/src/services/chatflows/index.ts | 19 +++-- pnpm-lock.yaml | 75 +++++++++++++++++-- 5 files changed, 102 insertions(+), 19 deletions(-) diff --git a/package.json b/package.json index 6d0b8b68b..d8a43876d 100644 --- a/package.json +++ b/package.json @@ -90,7 +90,7 @@ "unset-value": "2.0.1", "webpack-dev-middleware": "7.4.2", "ws": "8.18.3", - "xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz", + "xlsx": "0.18.5", "uuid": "^10.0.0", "request>uuid": "^3.4.0" } diff --git a/packages/server/src/controllers/chatflows/index.ts b/packages/server/src/controllers/chatflows/index.ts index dcc0c152d..af3f76d84 100644 --- a/packages/server/src/controllers/chatflows/index.ts +++ b/packages/server/src/controllers/chatflows/index.ts @@ -1,20 +1,20 @@ import { NextFunction, Request, Response } from 'express' import { StatusCodes } from 'http-status-codes' import { QueryRunner } from 'typeorm' -import { ChatFlow } from '../../database/entities/ChatFlow' +import { ChatFlow, EnumChatflowType } from '../../database/entities/ChatFlow' import { WorkspaceUserErrorMessage, WorkspaceUserService } from '../../enterprise/services/workspace-user.service' import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { ChatflowType } from '../../Interface' +import { ScheduleBeat } from '../../schedule/ScheduleBeat' import apiKeyService from '../../services/apikey' import chatflowsService from '../../services/chatflows' +import scheduleService from '../../services/schedule' import { GeneralErrorMessage } from '../../utils/constants' import { getRunningExpressApp } from '../../utils/getRunningExpressApp' import { getPageAndLimitParams } from '../../utils/pagination' import { checkUsageLimit } from '../../utils/quotaUsage' import { RateLimiterManager } from '../../utils/rateLimit' import { sanitizeFlowDataForPublicEndpoint } from '../../utils/sanitizeFlowData' -import scheduleService from '../../services/schedule' -import { ScheduleBeat } from '../../schedule/ScheduleBeat' import { stripProtectedFields } from '../../utils/stripProtectedFields' const checkIfChatflowIsValidForStreaming = async (req: Request, res: Response, next: NextFunction) => { @@ -66,7 +66,22 @@ const deleteChatflow = async (req: Request, res: Response, next: NextFunction) = `Error: chatflowsController.deleteChatflow - workspace ${workspaceId} not found!` ) } - const apiResponse = await chatflowsService.deleteChatflow(req.params.id, orgId, workspaceId) + const userPermittedTypes: EnumChatflowType[] = [] + const permissions = req.user!.permissions + if (req.user?.isOrganizationAdmin) { + userPermittedTypes.push(EnumChatflowType.CHATFLOW) + userPermittedTypes.push(EnumChatflowType.AGENTFLOW) + userPermittedTypes.push(EnumChatflowType.MULTIAGENT) + userPermittedTypes.push(EnumChatflowType.ASSISTANT) + } else { + if (permissions.includes(`chatflows:delete`)) userPermittedTypes.push(EnumChatflowType.CHATFLOW) + if (permissions.includes(`agentflows:delete`)) userPermittedTypes.push(EnumChatflowType.AGENTFLOW) + if (permissions.includes(`agentflows:delete`)) userPermittedTypes.push(EnumChatflowType.MULTIAGENT) + if (permissions.includes(`assistants:delete`)) userPermittedTypes.push(EnumChatflowType.ASSISTANT) + if (userPermittedTypes.length === 0) + throw new InternalFlowiseError(StatusCodes.FORBIDDEN, `You do not have permission to delete any chatflow types`) + } + const apiResponse = await chatflowsService.deleteChatflow(req.params.id, orgId, workspaceId, userPermittedTypes) return res.json(apiResponse) } catch (error) { next(error) diff --git a/packages/server/src/routes/chatflows/index.ts b/packages/server/src/routes/chatflows/index.ts index 8e963b041..2dfdfaab6 100644 --- a/packages/server/src/routes/chatflows/index.ts +++ b/packages/server/src/routes/chatflows/index.ts @@ -31,7 +31,7 @@ router.put( ) // DELETE -router.delete(['/', '/:id'], checkAnyPermission('chatflows:delete,agentflows:delete'), chatflowsController.deleteChatflow) +router.delete(['/', '/:id'], checkAnyPermission('chatflows:delete,agentflows:delete,assistants:delete'), chatflowsController.deleteChatflow) // WEBHOOK SECRET router.post('/:id/webhook-secret', checkAnyPermission('chatflows:update,agentflows:update'), chatflowsController.setWebhookSecret) diff --git a/packages/server/src/services/chatflows/index.ts b/packages/server/src/services/chatflows/index.ts index e301ac4ec..140cc9d31 100644 --- a/packages/server/src/services/chatflows/index.ts +++ b/packages/server/src/services/chatflows/index.ts @@ -9,12 +9,15 @@ import { UsageCacheManager } from '../../UsageCacheManager' import { ChatFlow, EnumChatflowType } from '../../database/entities/ChatFlow' import { ChatMessage } from '../../database/entities/ChatMessage' import { ChatMessageFeedback } from '../../database/entities/ChatMessageFeedback' +import { ScheduleTriggerType } from '../../database/entities/ScheduleRecord' import { UpsertHistory } from '../../database/entities/UpsertHistory' import { Workspace } from '../../enterprise/database/entities/workspace.entity' import { getWorkspaceSearchOptions } from '../../enterprise/utils/ControllerServiceUtils' import { InternalFlowiseError } from '../../errors/internalFlowiseError' import { getErrorMessage } from '../../errors/utils' +import { ScheduleBeat } from '../../schedule/ScheduleBeat' import documentStoreService from '../../services/documentstore' +import scheduleService from '../../services/schedule' import { constructGraphs, decryptCredentialData, @@ -24,16 +27,13 @@ import { getTelemetryFlowObj, isFlowValidForStream } from '../../utils' -import { sanitizeAllowedUploadMimeTypesFromConfig } from '../../utils/fileValidation' import { containsBase64File, updateFlowDataWithFilePaths } from '../../utils/fileRepository' -import { sanitizeFlowDataForPublicEndpoint } from '../../utils/sanitizeFlowData' +import { sanitizeAllowedUploadMimeTypesFromConfig } from '../../utils/fileValidation' import { getRunningExpressApp } from '../../utils/getRunningExpressApp' import { utilGetUploadsConfig } from '../../utils/getUploadsConfig' import logger from '../../utils/logger' import { updateStorageUsage } from '../../utils/quotaUsage' -import { ScheduleTriggerType } from '../../database/entities/ScheduleRecord' -import scheduleService from '../../services/schedule' -import { ScheduleBeat } from '../../schedule/ScheduleBeat' +import { sanitizeFlowDataForPublicEndpoint } from '../../utils/sanitizeFlowData' export const enum ChatflowErrorMessage { INVALID_CHATFLOW_TYPE = 'Invalid Chatflow Type', @@ -119,11 +119,18 @@ const checkIfChatflowIsValidForUploads = async (chatflowId: string): Promise => { +const deleteChatflow = async ( + chatflowId: string, + orgId: string, + workspaceId: string, + userPermittedTypes: EnumChatflowType[] +): Promise => { try { const appServer = getRunningExpressApp() const chatflow = await getChatflowById(chatflowId, workspaceId) + if (!userPermittedTypes.includes(chatflow.type as EnumChatflowType)) + throw new InternalFlowiseError(StatusCodes.FORBIDDEN, `You do not have permission to delete this chatflow type`) const dbResponse = await appServer.AppDataSource.getRepository(ChatFlow).delete({ id: chatflowId }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 812b8856a..5cb60a266 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,7 +32,7 @@ overrides: unset-value: 2.0.1 webpack-dev-middleware: 7.4.2 ws: 8.18.3 - xlsx: https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz + xlsx: 0.18.5 request>uuid: ^3.4.0 importers: @@ -747,8 +747,8 @@ importers: specifier: 8.18.3 version: 8.18.3(bufferutil@4.0.8)(utf-8-validate@6.0.4) xlsx: - specifier: https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz - version: https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz + specifier: 0.18.5 + version: 0.18.5 zod: specifier: ^3.25.76 || ^4 version: 4.3.6 @@ -9844,6 +9844,10 @@ packages: resolution: {integrity: sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==} engines: {node: '>=8.9'} + adler-32@1.3.1: + resolution: {integrity: sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==} + engines: {node: '>=0.8'} + adm-zip@0.5.16: resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} engines: {node: '>=12.0'} @@ -10717,6 +10721,10 @@ packages: ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + cfb@1.2.2: + resolution: {integrity: sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==} + engines: {node: '>=0.8'} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -10995,6 +11003,10 @@ packages: codemirror@6.0.1: resolution: {integrity: sha512-J8j+nZ+CdWmIeFIGXEFbFPtpiYacFMDR8GlHK3IyHQJMCaVRfGx9NT+Hxivv1ckLWPvNdZqndbr/7lVhrf/Svg==} + codepage@1.15.0: + resolution: {integrity: sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==} + engines: {node: '>=0.8'} + codsen-utils@1.6.4: resolution: {integrity: sha512-PDyvQ5f2PValmqZZIJATimcokDt4JjIev8cKbZgEOoZm+U1IJDYuLeTcxZPQdep99R/X0RIlQ6ReQgPOVnPbNw==} engines: {node: '>=14.18.0'} @@ -11309,6 +11321,11 @@ packages: resolution: {integrity: sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==} engines: {node: '>=10.0.0'} + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + create-jest@29.7.0: resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -13032,6 +13049,10 @@ packages: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} + frac@1.1.2: + resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} + engines: {node: '>=0.8'} + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -19035,6 +19056,10 @@ packages: resolution: {integrity: sha512-dANP1AyJTI503H0/kXwRza+7QxDB3BqeFvEKTF4MI9lQcBe8JbRUQTKVIGzGABJCwBovEYavZ2Qsdm/s8XKz8A==} hasBin: true + ssf@0.11.2: + resolution: {integrity: sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==} + engines: {node: '>=0.8'} + ssh2@1.16.0: resolution: {integrity: sha512-r1X4KsBGedJqo7h8F5c4Ybpcr5RjyP+aWIG007uBPRjmdQWfEiVLzSK71Zji1B9sKxwaCvD8y8cwSkYrlLiRRg==} engines: {node: '>=10.16.0'} @@ -20713,10 +20738,18 @@ packages: resolution: {integrity: sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w==} engines: {node: '>= 12.0.0'} + wmf@1.0.2: + resolution: {integrity: sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==} + engines: {node: '>=0.8'} + word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + word@0.3.0: + resolution: {integrity: sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==} + engines: {node: '>=0.8'} + wordwrap@1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} @@ -20869,9 +20902,8 @@ packages: resolution: {integrity: sha512-HY4G725+IDQr16N8XOjAms5qJGArdJaWIuC7Q7A8UXIwj2mifqnPXephazyL7sIkQPvmEoPX3E0v2yFv6hQUNg==} engines: {node: '>=4'} - xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz: - resolution: {tarball: https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz} - version: 0.20.3 + xlsx@0.18.5: + resolution: {integrity: sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==} engines: {node: '>=0.8'} hasBin: true @@ -32956,6 +32988,8 @@ snapshots: loader-utils: 2.0.4 regex-parser: 2.3.0 + adler-32@1.3.1: {} + adm-zip@0.5.16: {} agent-base@6.0.2: @@ -34028,6 +34062,11 @@ snapshots: ccount@2.0.1: {} + cfb@1.2.2: + dependencies: + adler-32: 1.3.1 + crc-32: 1.2.2 + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -34337,6 +34376,8 @@ snapshots: transitivePeerDependencies: - '@lezer/common' + codepage@1.15.0: {} + codsen-utils@1.6.4: dependencies: rfdc: 1.3.1 @@ -34687,6 +34728,8 @@ snapshots: nan: 2.22.2 optional: true + crc-32@1.2.2: {} + create-jest@29.7.0(@types/node@22.16.3)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@swc/core@1.4.6)(@types/node@22.16.3)(typescript@5.5.2)): dependencies: '@jest/types': 29.6.3 @@ -37044,6 +37087,8 @@ snapshots: forwarded@0.2.0: {} + frac@1.1.2: {} + fraction.js@4.3.7: {} fragment-cache@0.2.1: @@ -44992,6 +45037,10 @@ snapshots: srt-parser-2@1.2.3: {} + ssf@0.11.2: + dependencies: + frac: 1.1.2 + ssh2@1.16.0: dependencies: asn1: 0.2.6 @@ -46989,8 +47038,12 @@ snapshots: triple-beam: 1.4.1 winston-transport: 4.7.0 + wmf@1.0.2: {} + word-wrap@1.2.5: {} + word@0.3.0: {} + wordwrap@1.0.0: {} workbox-background-sync@6.6.0: @@ -47278,7 +47331,15 @@ snapshots: execa: 0.2.2 titleize: 1.0.1 - xlsx@https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz: {} + xlsx@0.18.5: + dependencies: + adler-32: 1.3.1 + cfb: 1.2.2 + codepage: 1.15.0 + crc-32: 1.2.2 + ssf: 0.11.2 + wmf: 1.0.2 + word: 0.3.0 xml-name-validator@3.0.0: {}