Commit Graph

4 Commits

Author SHA1 Message Date
matevip
e6c35ecfc7 fix(channel): sanitize conversationId as a filesystem path segment — fixes wecom/dingtalk/feishu attachment upload on Windows (#507) 2026-07-10 16:54:05 +08:00
倪程伟
fcb488c567
feat(workspace): chat-uploads 上传目录工作空间/Agent 感知化 (#422)
* feat(workspace): chat-uploads 上传目录工作空间/Agent 感知化 (#421)

把硬编码的 data/chat-uploads/{conversationId}/ 改为按工作空间/Agent 解析,
解析优先级:Agent workspaceBasePath → Workspace basePath → 可配置默认目录
(新配置 mateclaw.chat.upload.base-dir,默认 data/chat-uploads,保持现网零行为变化)。

- 新增 ChatUploadLocationResolver 中央解析器:写路径返回唯一根,读/清理
  路径返回候选根列表(工作空间根 + 默认根)做双重查找,保证迁移前旧附件
  仍可解析/清理;conversationId→ConversationEntity 查询带 5min 缓存。
- 新增 ChatUploadProperties + ChatUploadAutoConfiguration(启动建目录)。
- 复用 AgentGraphBuilder.resolveAgentBasePath(提升为 public)的优先级与
  安全规则(相对路径在 workspace 根下解析,绝对路径逃逸被拒)。
- 所有写入/读取点改为走 resolver;读取点走双重查找。
- 解决 Spring 循环依赖(resolver → agentService → ... → conversationService
  → resolver):resolver 的 AgentService 注入加 @Lazy。

向后兼容:默认目录不变;双重查找覆盖历史消息里的相对路径;
服务端点 URL 契约不变,前端无需改动。

测试:新增 ChatUploadLocationResolverTest(8 用例);修复受影响的现有测试构造。

* refactor(workspace): address review findings on chat-uploads resolver (#421)

应用 code review 的 4 项修复:

1. (correctness) ChatUploadLocationResolver 缓存新增 ConversationDeletedEvent
   监听器,删除会话时立即失效 conversationId→ConversationEntity 映射。
   否则备份恢复后用相同 id 重建会话,会继承最长 5 分钟的过期 workspace/agent
   映射,导致 cleanAttachmentFiles 走错(过期的)上传目录。复用既有
   @EventListener-on-bean 模式(与 AsyncTaskService / WorkspaceLookupCache 一致)。

2. 收紧 resolveWorkspaceScopedRoot 里 3 个过宽的 catch(Exception) →
   MateClawException + warn,让真正的 bug(NPE / DataAccessException)暴露
   而非被静默降级为 debug 日志。

3. 更新 ChatController.upload 过期注释:会话尚未创建时附件暂存默认目录,
   会话创建后读取走双重查找仍能命中。

4. 移除不可达分支(agentWorkspaceId != workspaceId)—— 会话的 agent 必然
   归属会话的 workspace(创建时强约束),直接用会话 workspace 即可,
   少一次冗余 DB 查询与一层推测性逻辑。

测试:ChatUploadLocationResolverTest (8) + ConversationServiceCleanAttachmentFilesTest (2) 全绿。
2026-06-26 14:20:54 +08:00
倪程伟
bdda9c7357 perf(webchat): scope session listing to the visitor; cap upload disk use
Two webchat hardening fixes:

- Session listing no longer pulls every system-owned conversation into
  memory. listSessions/pageSessions went through listConversations(owner)
  whose `username IN (owner, system)` loaded all IM/cron rows just to show
  one visitor's handful of threads. New listWebchatConversations(username)
  queries only the visitor's own rows; the channel prefix is matched
  in-memory with a literal startsWith (so a '_'/'%' in the api key's first
  8 chars can't act as a LIKE wildcard).
- Upload now enforces a per-conversation quota (file count + total bytes,
  both configurable) so a visitor can't fill the disk with many
  individually-under-cap files. Pairs with the existing staging TTL sweep.
2026-06-17 23:21:08 +08:00
倪程伟
594880bd64 feat(webchat): support inbound file upload and outbound download
WebChat had no file support: the /stream body carried only text, and
agent-produced files had no visitor-reachable download path (the JWT
/chat/files endpoint is unreachable for API-key visitors).

Add webchat-authenticated file transfer, reusing MessageContentPart +
the existing upload dir + agent multimodal injection:

- WebChatFileService: validate (size cap, extension whitelist, filename
  sanitize), store under the conversation's upload dir, stage by opaque
  fileId, traversal-safe resolve. Untrusted-uploader hardening lives here.
- POST /upload (multipart) and GET /files, both authed by API key +
  visitor token with a server-derived conversationId (never client paths).
  Downloads send non-images as attachment + X-Content-Type-Options:nosniff.
- /stream gains attachmentIds; the server resolves each id from the
  staging registry (client metadata is never trusted), builds parts, and
  persists them on the user message so the agent's multimodal/file tools
  pick them up from history — same path as the JWT web chat.
- Strip server-side file paths from the visitor-facing message view
  (listMessageViewsExternal + includePath flag) so the filesystem layout
  is not disclosed.

Refs matevip/mateclaw#342
2026-06-17 23:21:08 +08:00