Skip to content

Commit b04baf6

Browse files
fix: Vulnerability in workspace switching and reloading
1 parent bd597e6 commit b04baf6

24 files changed

Lines changed: 142 additions & 108 deletions

File tree

‎ui/src/api/API_README.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,9 @@ System 接口由资源管理服务提供;本地开源后端没有对应扩展
498498

499499
`workspace/knowledge/document.ts` 仅维护文档分页查询,路径为
500500
`/workspace/<workspaceId>/knowledge/<knowledgeId>/document/<currentPage>/<pageSize>`。
501-
分页使用 `ParamsPage` / `ResponsePage<DocumentItem>`,支持 `name`、`create_user` 筛选;
501+
分页使用 `ParamsPage` / `ResponsePage<DocumentItem>`,支持 `name`、`create_user`、`status`、`task_type` 筛选;
502+
文件任务使用 `DOCUMENT_TASK_STATE` 的字符状态及 `DOCUMENT_TASK_TYPE` 的任务位置,
503+
不使用通用 `STATE_TYPES`;选择全部时省略状态与任务类型,非任务专属状态省略任务类型。
502504
文档页传 `resource_type: 'document'`,创建者选项复用 Workspace `common.ts` 的 `getAllUsers`。
503505
类型从 `@/api/types` 导入,命中处理枚举从 `@/api/enums` 导入。API 不接收 loading,不重复包装响应。
504506

‎ui/src/api/enums/document.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
/** 文档命中处理方式。 */
22
export const DOCUMENT_HIT_HANDLING = { OPTIMIZATION: 'optimization', DIRECTLY_RETURN: 'directly_return' } as const
3+
4+
/** 文档任务状态,使用文件状态协议中的字符值。 */
5+
export const DOCUMENT_TASK_STATE = { PENDING: '0', STARTED: '1', SUCCESS: '2', FAILURE: '3' } as const
6+
7+
/** 文档状态字符串中各任务的位置。 */
8+
export const DOCUMENT_TASK_TYPE = { EMBEDDING: 1, GENERATE_PROBLEM: 2, SYNC: 3, TOKENIZE: 4 } as const

‎ui/src/components/global/mk-form-list/index.vue‎

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -71,24 +71,26 @@ function removeRow(index: number) {
7171

7272
<template>
7373
<div ref="rowsRef" class="w-full">
74-
<div v-for="(item, index) in formRows" :key="getRowKey(item, index)" class="mk-form-list__row flex w-full gap-2">
75-
<!-- 拖拽排序 -->
76-
<el-button
77-
v-if="sortable"
78-
link
79-
class="mk-form-list__handle shrink-0 text-N600 -mr-2 h-8!"
80-
:class="{ 'mt-8': firstRowHasLabel && index === 0 }"
81-
:disabled="sortDisabled"
82-
>
83-
<MkIcon name="icon_drag_outlined" />
84-
</el-button>
85-
<slot :index="index" :item="item" />
86-
<el-form-item class="shrink-0" :class="firstRowHasLabel ? (index === 0 ? 'mt-8' : 'mt-0.5') : 'mt-1'">
87-
<el-button :disabled="formRows.length <= minRows" text @click="removeRow(index)">
88-
<MkIcon name="icon_delete-trash_outlined" class="text-N600" />
74+
<template v-for="(item, index) in formRows" :key="getRowKey(item, index)">
75+
<div class="mk-form-list__row flex w-full gap-2">
76+
<!-- 拖拽排序 -->
77+
<el-button
78+
v-if="sortable"
79+
link
80+
class="mk-form-list__handle shrink-0 text-N600 -mr-2 h-8!"
81+
:class="{ 'mt-8': firstRowHasLabel && index === 0 }"
82+
:disabled="sortDisabled"
83+
>
84+
<MkIcon name="icon_drag_outlined" />
8985
</el-button>
90-
</el-form-item>
91-
</div>
86+
<slot :index="index" :item="item" />
87+
<el-form-item class="shrink-0" :class="firstRowHasLabel ? (index === 0 ? 'mt-8' : 'mt-0.5') : 'mt-1'">
88+
<el-button :disabled="formRows.length <= minRows" text @click="removeRow(index)">
89+
<MkIcon name="icon_delete-trash_outlined" class="text-N600" />
90+
</el-button>
91+
</el-form-item>
92+
</div>
93+
</template>
9294
</div>
9395

9496
<el-button v-if="showAddButton" class="-mt-1" link type="primary" @click="addRow">

‎ui/src/components/mk-dynamics-form/FormItem.vue‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ defineExpose({ validate })
180180
<template>
181181
<el-form-item
182182
v-loading="loading"
183-
:key="formField.field"
184183
:style="formItemStyle"
185184
:prop="formField.field"
186185
:rules="validationRules"

‎ui/src/constants/CONSTANT_README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ API 枚举值。例如角色类型和登录方式以 `src/api/enums` 为唯一
2222

2323
知识库类型的接口值保持为 `KNOWLEDGE_TYPE` 中的数字。`constants/knowledge.ts` 提供
2424
`KNOWLEDGE_TYPE_MAP`,将数字转换为 `BASE`、`WEB`、`LARK`、`WORKFLOW` 字符串,
25-
供前端判断;`KNOWLEDGE_TYPE_LABELS` 按这些字符串提供展示文案。提交接口时仍使用数字枚举值。
25+
供前端判断及知识库详情路由 `type` 参数使用,地址不传数字;`KNOWLEDGE_TYPE_LABELS` 按这些字符串提供展示文案。提交接口时仍使用数字枚举值。
2626
字符串标识统一由 `KNOWLEDGE_TYPE_KEY` 维护,映射、文案和业务判断均引用该常量,避免重复写裸字符串。
2727

2828
```ts

‎ui/src/layout/header-workspace-dropdown/index.vue‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,19 @@ watch(
2727
function handleWorkspaceSelect(workspace: WorkspaceItem) {
2828
const workspaceId = workspace.id ?? 'default'
2929
if (workspaceId === route.params.workspaceId || !route.name) return
30-
void router.push({ name: route.name, params: { ...route.params, workspaceId }, query: route.query, hash: route.hash })
30+
// 详情中的资源属于原工作空间,切换后回到对应列表。
31+
let listRouteName: string | undefined
32+
if (route.meta.resourceDetailRoot) {
33+
if (route.params.applicationId) listRouteName = 'workspace-application-list'
34+
else if (route.params.knowledgeId) listRouteName = 'workspace-knowledge-list'
35+
}
36+
const targetRoute = router.resolve(
37+
listRouteName
38+
? { name: listRouteName, params: { workspaceId } }
39+
: { name: route.name, params: { ...route.params, workspaceId }, query: route.query, hash: route.hash },
40+
)
41+
// 切换工作空间时整页加载,重新初始化用户权限和页面状态。
42+
window.location.assign(targetRoute.href)
3143
}
3244
</script>
3345

‎ui/src/router/ROUTE_README.md‎

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,14 @@ Workspace 使用 `AppLayout`,左侧导航根据 `scope: 'workspace'` 对应路
4545

4646
Workspace 根地址为 `/admin/workspace/:workspaceId`。`workspaceId` 只以当前路由参数为准。应用根
4747
地址、登录成功和从 System 返回 Workspace 时统一进入 `/admin/workspace/default`。父路由的
48-
`scope` 会合并到匹配的子路由 `meta` 中。
48+
`scope` 会合并到匹配的子路由 `meta` 中。
49+
50+
顶部工作空间切换统一由 `layout/header-workspace-dropdown/index.vue` 处理:选择不同工作空间时,
51+
通过 `router.resolve()` 生成目标地址,再调用 `window.location.assign()` 整页加载,重新初始化
52+
用户资料、权限和页面状态。智能体详情及其子页切换后进入目标工作空间的智能体列表;普通或共享
53+
知识库详情及其子页切换后进入目标工作空间的知识库列表,不携带原详情的资源参数、query 或 hash。
54+
其他页面保留当前路由名称、其他参数、query 和 hash;选择当前工作空间不刷新。
55+
不要改为仅 `router.push()` 或依赖组件 `key` 重建来替代整页加载。
4956

5057
触发器列表地址为 `/admin/workspace/:workspaceId/trigger`,渲染 `views/trigger/index.vue`。
5158

@@ -211,11 +218,11 @@ Workspace 页面:
211218
212219
/admin/workspace/:workspaceId/knowledge
213220
/admin/workspace/:workspaceId/knowledge/:knowledgeId/workflow
214-
/admin/workspace/:workspaceId/knowledge/:knowledgeId
215-
/admin/workspace/:workspaceId/knowledge/:knowledgeId/document
216-
/admin/workspace/:workspaceId/knowledge/:knowledgeId/setting
217-
/admin/workspace/:workspaceId/knowledge/:knowledgeId/workflow-entry
218-
/admin/workspace/:workspaceId/knowledge/:knowledgeId/document/:documentId
221+
/admin/workspace/:workspaceId/knowledge/:knowledgeId/:type
222+
/admin/workspace/:workspaceId/knowledge/:knowledgeId/:type/document
223+
/admin/workspace/:workspaceId/knowledge/:knowledgeId/:type/setting
224+
/admin/workspace/:workspaceId/knowledge/:knowledgeId/:type/workflow-entry
225+
/admin/workspace/:workspaceId/knowledge/:knowledgeId/:type/document/:documentId
219226
```
220227

221228
智能体详情路由的 `type` 来自当前 `ApplicationDetail.type`;卡片概览和简易智能体设置等详情入口
@@ -327,6 +334,9 @@ System 共享资源页面:
327334
- 每次新增、删除、移动或修改路由时,必须同步更新本文件。
328335

329336
工作空间知识库卡片进入 `workspace-knowledge-detail`,默认重定向到“文档”子路由。
337+
普通与共享知识库详情的 `type` 通过 `KNOWLEDGE_TYPE_MAP[knowledge.type]` 转换为
338+
`BASE`、`WEB`、`LARK`、`WORKFLOW`,地址不使用接口数字枚举;卡片、设置、创建成功跳转及工作流返回详情
339+
必须与 `knowledgeId` 一并传入。独立知识库工作流地址保持不变。
330340
详情容器复用 `ResourceDetailLayout`,菜单依次为“资料库(文档、图片、标签管理)”、
331341
“工作流”、“检索优化(召回测试、问题、自定义分词)”、“授权与集成(对话用户、外部检索服务)”、
332342
“设置”。资料库分组使用空 path,保留原 `/document` 地址;图片和标签分别使用 `/image`、`/tag`。
@@ -375,7 +385,7 @@ Workspace 父路由为 `workspace-application-detail-layout`;System 详情实
375385
### Workspace 共享知识库详情
376386

377387
共享知识库卡片进入 `workspace-shared-knowledge-detail`,地址为
378-
`/admin/workspace/:workspaceId/shared/knowledge/:knowledgeId`,默认重定向到
388+
`/admin/workspace/:workspaceId/shared/knowledge/:knowledgeId/:type`,默认重定向到
379389
`workspace-shared-knowledge-document-list`(`document`)。详情父路由配置
380390
`resourceScope: 'workspace-shared'` 和 `activeMenu: 'workspace-knowledge'`,复用知识库详情容器和文档页,侧栏仍高亮 Workspace 知识库。
381391
共享详情目前仅注册“资料库 → 文档”,后续页面需接入对应共享接口后再注册,不跳转普通设置或工作流。

‎ui/src/router/admin/workspace/modules/knowledge-shared.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { RouteRecordRaw } from 'vue-router'
33
/** 工作空间知识库模块下的共享详情路由。 */
44
export const sharedKnowledgeRoutes: RouteRecordRaw[] = [
55
{
6-
path: 'shared/knowledge/:knowledgeId',
6+
path: 'shared/knowledge/:knowledgeId/:type',
77
name: 'workspace-shared-knowledge-detail',
88
component: () => import('@/views/knowledge-detail/index.vue'),
99
redirect: { name: 'workspace-shared-knowledge-document-list' },

‎ui/src/router/admin/workspace/modules/knowledge.ts‎

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const knowledgeRoutes: RouteRecordRaw[] = [
1414
meta: { title: '知识库列表', hidden: true },
1515
},
1616
{
17-
path: ':knowledgeId',
17+
path: ':knowledgeId/:type',
1818
name: 'workspace-knowledge-detail',
1919
component: () => import('@/views/knowledge-detail/index.vue'),
2020
redirect: { name: 'workspace-knowledge-document-list' },
@@ -104,12 +104,6 @@ export const knowledgeRoutes: RouteRecordRaw[] = [
104104
component: () => import('@/views/knowledge-detail/setting/index.vue'),
105105
meta: { title: '设置', icon: 'icon_setting', activeIcon: 'icon_setting_filled', order: 50 },
106106
},
107-
// {
108-
// path: 'document/:documentId',
109-
// name: 'workspace-knowledge-document-detail',
110-
// component: () => import('@/views/knowledge-detail/DocumentDetailView.vue'),
111-
// meta: { title: '文档详情', hidden: true, detailActiveMenu: 'workspace-knowledge-document-list' },
112-
// },
113107
],
114108
},
115109
],

‎ui/src/views/VIEW_README.md‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ src/views/knowledge/
201201
`KnowledgeCard` 只负责展示、选择状态和 `action-dropdown` 插槽;页面传入完整 Knowledge API,
202202
组合单项转移、删除 Action,并管理批量选择、全选、批量转移与批量删除。共享知识库不展示这些操作。
203203
`SettingKnowledgeAction` 暂不增加权限判断,点击后携带当前
204-
`workspaceId` 和知识库 ID 跳转 `workspace-knowledge-setting`;阻止事件冒泡,避免同时触发卡片详情跳转。
204+
`workspaceId`、知识库 ID 和 `KNOWLEDGE_TYPE_MAP[knowledge.type]` 跳转 `workspace-knowledge-setting`;阻止事件冒泡,避免同时触发卡片详情跳转。
205205
“设置”之后依次组合 `KeywordIndexKnowledgeAction` 和 `McpConfigKnowledgeAction`,接收完整
206206
Knowledge API 并复用页面操作 loading。分词索引不增加确认弹窗,调用成功后只提示“操作成功”;
207207
MCP 配置沿用工具的只读文本与悬浮复制交互,专属弹窗按需挂载、关闭后卸载。
@@ -228,7 +228,7 @@ MCP 配置沿用工具的只读文本与悬浮复制交互,专属弹窗按需
228228
模型加载后仅在未选择时默认选中首个可用模型;重置表单时恢复该默认值,无可用模型时保持为空。
229229
刷新选项不覆盖用户选择或设置页回填的模型。
230230
创建前校验表单,提交期间禁止重复提交和关闭;成功后刷新用户基础资料并通知列表刷新,
231-
普通类型进入文档列表,工作流进入画布。每次打开及关闭动画结束后清理表单,工作流模板使用
231+
普通类型将接口返回的 `knowledge.type` 通过 `KNOWLEDGE_TYPE_MAP` 转为字符串后进入文档列表,工作流进入画布。每次打开及关闭动画结束后清理表单,工作流模板使用
232232
`cloneDeep` 隔离;创建流程使用 Workspace API,不通过路由字符串推测 System 范围。
233233
飞书创建沿用扩展接口 `/lark/save`,部署环境需要提供该接口。
234234
“导入创建”沿用智能体和工具的菜单文件选择交互,调用 `postKnowledgeImport` 上传文件及当前
@@ -670,8 +670,13 @@ Workspace API 内部通过 `getWorkspaceId()` 读取当前路由工作空间。
670670
搜索只提供名称 `name` 和创建者 `create_user`;创建者通过 Workspace `CommonApi.getAllUsers`
671671
加载,支持按 `nick_name` 远程搜索。列表使用 `documentData`、`paginationConfig`、`documentQuery`,
672672
查询方法为 `loadDocuments`,搜索处理为 `handleSearchChange`,搜索变化后回到第一页。
673-
切换工作空间、知识库或资源范围时重置筛选与页码;无轮询、排序入口、选择列和文档操作。
674-
文档分页接口维护在 `workspace/knowledge/document.ts`,页面管理 loading,状态仅作展示。
673+
文档页通过 `onMounted` 加载文档列表,创建者选项在展开下拉或输入关键词时通过 `remoteMethod`
674+
按需加载,不在进入页面时预加载;其他列表页的同类创建者筛选遵循相同方式。不额外监听路由重置状态。切换工作空间
675+
整页加载并返回知识库列表;当前知识库与共享资源入口均从其他页面进入,挂载时初始化筛选和分页。
676+
无轮询、排序入口、选择列和文档操作。
677+
文档分页接口维护在 `workspace/knowledge/document.ts`,页面管理 loading。文件状态表头使用
678+
`MkDropdown` 单选筛选全部、成功、失败、索引中、分词索引中、排队中和生成中;查询组合
679+
`status` 与可选的 `task_type`,切换选项清除旧任务类型并回到第一页,保留名称和创建者条件。
675680

676681
文档详情路由暂未启用,System 知识库详情路由暂未注册。
677682

@@ -746,7 +751,7 @@ application、tool、knowledge 的 WorkflowView 统一使用一个 `loading` 控
746751

747752
### 知识库工作流导航与导出
748753

749-
`workflow/knowledge/navigation.ts` 统一返回入口:Workspace 返回当前知识库详情,System 资源管理和共享资源返回各自知识库列表。
754+
`workflow/knowledge/navigation.ts` 统一返回入口:Workspace 将详情中的 `type` 通过 `KNOWLEDGE_TYPE_MAP` 转为字符串后返回当前知识库详情,详情尚未加载时使用 `WORKFLOW`;System 资源管理和共享资源返回各自知识库列表。
750755
历史模式下返回只退出预览;普通编辑态返回保留未保存确认。更多菜单的导出工作流先保存未提交改动,
751756
再调用专用 `.kbwf` 导出接口;保存失败不导出。知识库原有文件上传、数据源表单与任务轮询调试流程保持独立。
752757

@@ -769,7 +774,7 @@ application、tool、knowledge 的 WorkflowView 统一使用一个 `loading` 控
769774
`HomeView` 向 `HomeResourceOverview` 传入完整首页 API 对象,组件通过 `typeof HomepageApi`
770775
约束 `api` Prop 并调用 `props.api`。资源概况、使用统计和排行均由 `HomeView` 显式传入
771776
`workspaceId`,排行榜继续向详情抽屉传递;调用首页接口时逐次传入此 ID,不在 API 内读取路由。
772-
统计组件按 `workspaceId` 设置 key,切换工作空间时重载数据并清理旧筛选与排行榜详情。
777+
顶部切换工作空间时统一整页加载,重载统计数据并清理旧筛选与排行榜详情,统计组件无需额外设置工作空间 key。
773778

774779
快捷创建通过插槽复用智能体、知识库、工具和模型的现有入口,目标文件夹为当前工作空间根目录;
775780
保留创建流程中的用户资料刷新及详情/工作流导航,停留首页的成功操作刷新资源概况与智能体选项。

0 commit comments

Comments
 (0)