auto-sync: 2026-05-29 21:11:09

This commit is contained in:
cfdaily
2026-05-29 21:11:09 +08:00
parent 3f9b6975a5
commit ab9accca99
+79 -14
View File
@@ -182,22 +182,83 @@ async def get_mail(mail_id: str):
@router.post("")
async def send_mail(body: Dict[str, Any]):
"""发送 Mail(创建 Task"""
"""发送 Mail(创建 Task
API 层防御(A1-A10):
A1: from 必填
A9: from 必须是有效 Agent
A5: in_reply_to 存在性校验
A6/A7: 自动纠正 to
A2: to 必填(非回复)
A3: from != to 防自环
A4: to 必须是有效 Agent
A8: 回复权限校验(严格 1 对 1)
A10: 正文非空
"""
bb = _bb()
valid_agents = _get_valid_agents()
auto_corrected = None
# --- A1: from 必填 ---
from_agent = body.get("from", "").strip()
if not from_agent:
raise HTTPException(400, "`from` 必填")
# --- A9: from 必须是有效 Agent ---
if from_agent not in valid_agents:
raise HTTPException(400, f"`from` 不是有效的 Agent: {from_agent}")
# --- A5/A6/A7/A8: in_reply_to 处理 ---
in_reply_to = body.get("in_reply_to")
original = None
if in_reply_to:
original = bb.get_task(in_reply_to)
# A5: 原邮件必须存在
if not original:
raise HTTPException(400, f"回复的邮件不存在: {in_reply_to}")
orig_from = original.assigned_by or ""
orig_to = original.assignee or ""
# A8: 只有原邮件的双方能回复(严格 1 对 1)
if from_agent not in (orig_from, orig_to):
raise HTTPException(400, f"只有邮件的发送者或接收者可以回复")
# A6/A7: 自动纠正 to → 原邮件发件者
to_agent = body.get("to", "").strip()
corrected_to = orig_from # 回复方向固定: reply → original sender
if to_agent and to_agent != corrected_to:
auto_corrected = {"field": "to", "original": to_agent, "corrected": corrected_to}
to_agent = corrected_to
else:
# --- A2: to 必填(非回复场景) ---
to_agent = body.get("to", "").strip()
if not to_agent:
raise HTTPException(400, "`to` 必填")
# --- A3: from != to 防自环 ---
if from_agent == to_agent:
raise HTTPException(400, "不能给自己发邮件")
# --- A4: to 必须是有效 Agent ---
if to_agent not in valid_agents:
raise HTTPException(400, f"`to` 不是有效的 Agent: {to_agent}")
# --- A10: 正文非空 ---
text = body.get("text", body.get("description", "")) or ""
if not text.strip():
raise HTTPException(400, "邮件正文不能为空")
mail_id = body.get("id", f"mail-{int(datetime.now().timestamp() * 1000)}")
# 自动处理 conversation_id:有 in_reply_to 时继承原邮件的 conversation_id
conversation_id = body.get("conversation_id")
in_reply_to = body.get("in_reply_to")
if not conversation_id and in_reply_to:
original = bb.get_task(in_reply_to)
if original:
try:
orig_meta = json.loads(original.must_haves) if original.must_haves else {}
conversation_id = orig_meta.get("conversation_id")
except Exception:
pass
if not conversation_id and original:
try:
orig_meta = json.loads(original.must_haves) if original.must_haves else {}
conversation_id = orig_meta.get("conversation_id")
except Exception:
pass
if not conversation_id:
conversation_id = f"conv-{int(datetime.now().timestamp() * 1000)}"
@@ -220,15 +281,19 @@ async def send_mail(body: Dict[str, Any]):
task = Task(
id=mail_id,
title=body.get("title", ""),
description=body.get("text", body.get("description", "")),
assignee=body.get("to"),
assigned_by=body.get("from", "user"),
description=text,
assignee=to_agent,
assigned_by=from_agent,
must_haves=json.dumps(meta),
task_type="mail",
status="pending",
)
bb.create_task(task)
return {"ok": True, "mail_id": task.id}
result = {"ok": True, "mail_id": task.id}
if auto_corrected:
result["auto_corrected"] = auto_corrected
return result
@router.patch("/{mail_id}")