Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ Cargo.lock

# Node/Front-end temp (if any)
node_modules/
.vite/
*.cache/
*.tsbuildinfo
dist/
Expand Down
33 changes: 33 additions & 0 deletions app/main_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ def _get_app_root():
from fastapi import FastAPI, Request # noqa
from fastapi.responses import JSONResponse # noqa
from fastapi.staticfiles import StaticFiles # noqa
from fastapi.middleware.cors import CORSMiddleware # noqa
from main_logic import core as core, cross_server as cross_server # noqa
from main_logic.agent_event_bus import MainServerAgentBridge, notify_analyze_ack, set_main_bridge # noqa
from fastapi.templating import Jinja2Templates # noqa
Expand Down Expand Up @@ -1365,6 +1366,15 @@ async def remove_one_catgirl(name: str):
# --- FastAPI App Setup ---
app = FastAPI()

# 允许 battle-arena 前端及其他跨域来源访问头像同步端点
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)

_main_runtime_limited_mode_enabled = False
_main_runtime_limited_mode_reason = ""
_MAIN_LIMITED_MODE_ALLOWED_EXACT_PATHS = {
Expand Down Expand Up @@ -1594,6 +1604,29 @@ async def beacon_shutdown():
logger.error(f"Beacon处理错误: {e}")
return {"success": False, "error": str(e)}

# ── Battle-Arena 跨域头像同步端点 ────────────────────────────────
_battle_arena_avatars: dict = {} # side -> {dataUrl, name}


@app.post('/battle-arena/avatar')
async def set_battle_avatar(payload: dict):
"""由 app-chat-avatar.js 在捕获头像后调用,存储 dataUrl 和角色名供 battle-arena 获取。"""
side = str(payload.get('side', 'left'))
data_url = str(payload.get('dataUrl', ''))
name = str(payload.get('name', ''))
if data_url:
_battle_arena_avatars[side] = {'dataUrl': data_url, 'name': name}
return {"ok": True}


@app.get('/battle-arena/avatar/{side}')
async def get_battle_avatar(side: str):
"""battle-arena 前端轮询此端点获取最新头像 dataUrl 和角色名。"""
from fastapi.responses import JSONResponse
entry = _battle_arena_avatars.get(side, {})
return JSONResponse({'dataUrl': entry.get('dataUrl', ''), 'name': entry.get('name', '')})
Comment on lines +1662 to +1678
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

头像同步端点缺少输入边界,容易被超大 dataUrl 或任意 side 撑爆内存喵。

Line [1601-1606] 直接把外部 side/dataUrl/name 入内存,没有 side 白名单、格式校验和长度上限喵。建议最少限制 side(left/right)并限制 dataUrl 前缀与长度(超限返回 4xx)喵。

💡 建议修复(示例)
 _battle_arena_avatars: dict = {}  # side -> {dataUrl, name}
+_BATTLE_AVATAR_SIDES = {"left", "right"}
+_BATTLE_AVATAR_MAX_DATA_URL_LEN = 2_000_000

 `@app.post`('/battle-arena/avatar')
 async def set_battle_avatar(payload: dict):
@@
-    side = str(payload.get('side', 'left'))
+    side = str(payload.get('side', 'left')).strip()
     data_url = str(payload.get('dataUrl', ''))
     name = str(payload.get('name', ''))
-    if data_url:
+    if side not in _BATTLE_AVATAR_SIDES:
+        return JSONResponse(status_code=400, content={"ok": False, "error": "invalid side"})
+    if data_url and (not data_url.startswith("data:image/") or len(data_url) > _BATTLE_AVATAR_MAX_DATA_URL_LEN):
+        return JSONResponse(status_code=413, content={"ok": False, "error": "avatar too large or invalid"})
+    if data_url:
         _battle_arena_avatars[side] = {'dataUrl': data_url, 'name': name}
     return {"ok": True}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/main_server.py` around lines 1598 - 1614, The set_battle_avatar and
get_battle_avatar endpoints currently accept untrusted side/dataUrl/name into
_battle_arena_avatars; add input validation and bounds: enforce side whitelist
(only "left" or "right") in both set_battle_avatar and get_battle_avatar,
validate dataUrl starts with an allowed prefix like "data:image/" and cap its
length (e.g. max bytes/chars) and similarly cap name length; if validation fails
return a 4xx response (e.g. 400) instead of storing; ensure you reference and
update _battle_arena_avatars only after passing these checks so oversized or
invalid payloads cannot exhaust memory.



# 挂载全部路由
app.include_router(config_router)
app.include_router(proactive_router)
Expand Down
12 changes: 12 additions & 0 deletions battle-arena/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>猫娘大乱斗 · Nekoverse</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.jsx"></script>
</body>
</html>
Loading
Loading