diff --git a/plugins/Wzdhehe/mcode-webui/.gitignore b/plugins/Wzdhehe/mcode-webui/.gitignore new file mode 100644 index 0000000..b17d5fa --- /dev/null +++ b/plugins/Wzdhehe/mcode-webui/.gitignore @@ -0,0 +1,4 @@ + +# v2026-08-28 modacker: webui runtime artifacts (server.err + sessions json) +.server.err +.webui-sessions.json diff --git a/plugins/Wzdhehe/mcode-webui/BASELINE-2026-09-04.md b/plugins/Wzdhehe/mcode-webui/BASELINE-2026-09-04.md new file mode 100644 index 0000000..fb8bce1 --- /dev/null +++ b/plugins/Wzdhehe/mcode-webui/BASELINE-2026-09-04.md @@ -0,0 +1,126 @@ +# BASELINE — mcode-webui pre-fix snapshot + +> 采集日期:2026-09-04 20:55 CST +> 工作目录:`/Users/moc/workspaces/Mcode-webui-sync/upstream` 分支 `fix/cve-csrf-token-leak-2026-09` +> 起点 commit:`92cae0c` (== `Wzdhehe/Mcode-webui` PR #23 head `091dec5` "Token Plan key integration end-to-end") +> 环境:macOS Darwin, Node v25.9.0, sqlite3 系统默认, mcode 0.2.4, mavis 0.1.0+ +> 工具:npm 11.x, `node --experimental-test-module-mocks --test test/*.test.js` + +--- + +## 1. npm test + +``` +ℹ tests 413 +ℹ suites 105 +ℹ pass 408 +ℹ fail 3 +ℹ cancelled 0 +ℹ skipped 2 +ℹ todo 0 +ℹ duration_ms 2313.78 +``` + +### 3 个 fail 全部来自 `test/csrf-token-disclosure.test.js` + +| # | 测试 | 行 | 状态 | 现象 | +|---|---|---|---|---| +| blocker#1 | `GET /api/settings` 跨源不得返回 200 带 token | L160 | ❌ FAIL | status=200, 响应体含 `currentToken: 8a520aae769fbf4ea6eac2227fa59ba6` | +| blocker#2 | `POST /api/settings` 跨源不得返回 200 带 token | L172 | ❌ FAIL | status=200, 响应体含 `currentToken` | +| blocker#3 | 跨源响应 `Access-Control-Allow-Origin` 不得为 `*` | L182 | ❌ FAIL | header = `*`(裸星号) | +| blocker#4 | `DELETE /api/sessions/:id` 跨源须 401/403/404 | L193 | ✅ PASS | status=404(session 不存在;token gate 旁路了但 404 兜底) | + +> 注释:blocker#4 在测试用例里 PASS 是因为路径不存在返回 404 —— 但**真实删除路径**上仍会被跨源执行。是 PoC 没覆盖到的盲点,第二段顺带修。 + +--- + +## 2. 独立 PoC 复现(hetaoBackend 2026-09-01 01:25Z 报告) + +跑 `node ~/workspaces/Mcode-webui-sync/poc-csrf.mjs `(脚本在 modacker 本地): + +``` +== CSRF / token-disclosure PoC == +plugin dir: /Users/moc/workspaces/Mcode-webui-sync/upstream/plugins/Wzdhehe/mcode-webui +settings dir: /var/folders/xp/.../poc-csrf-QqSVKt +port: 18080 + +bootstrap token (from operator-only settings file or first GET): + 3801ed9d...725a + +=== TEST 1: GET /api/settings, Origin: https://evil.example === +status: 200 + access-control-allow-origin: * + access-control-allow-methods: GET, POST, OPTIONS, DELETE + access-control-allow-headers: Content-Type, Authorization + content-type: application/json; charset=utf-8 + body[0..400]: {"ok":true,"lanBroadcast":true,"readOnly":false,"tokenEnabled":true, + "tokenAcknowledged":false,"currentToken":"3801ed9d7aa8fd1d4846f7472efb725a",...} +[LEAKED] bootstrap token in response body: true + +=== TEST 2: POST /api/settings, Origin: https://evil.example === +status: 200, body 含 currentToken: 3801ed9d...725a +[LEAKED] bootstrap token in response body: true + +=== TEST 3: DELETE /api/sessions/nonexistent, Origin: https://evil.example === +status: 404, body {"ok":false,"error":"session not found"}(DELETE 路径盲点) + +=== SUMMARY === + CORS allows cross-origin read: YES (vulnerable) + Local bypass on cross-origin: YES (vulnerable) + Bootstrap token leak count: 2/2 + +>>> CSRF / token-disclosure blocker CONFIRMED +>>> hetaoBackend report (2026-09-01 01:25Z) reproduced +``` + +PoC `process.exitCode = 2`(vulnerability confirmed),但被 `tail` 截断后看到 shell `$?` = 0;真实 node 退出码 = 2。 + +--- + +## 3. npm run lint + +``` +Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@eslint/js' imported from +/Users/moc/workspaces/Mcode-webui-sync/upstream/eslint.config.mjs +``` + +**根因**:`eslint.config.mjs` 位于 `upstream/` 根目录,但 `@eslint/js` / `globals` 的 `devDependencies` 在 `upstream/plugins/Wzdhehe/mcode-webui/package.json` 里。`npm install` 在子目录跑,不会把 devDeps 装到根的 `node_modules/`,ESLint 找不到包。 + +**严重性**:lint 完全不可跑。这跟 CSRF 修复**无关**,是 pre-existing 路径错位。 + +**处置**:列入第二段同步修的列表(不阻塞 CSRF 修,但同 PR 改掉)。 + +--- + +## 4. 根因定位(4 个文件) + +| 文件 | 行 | 问题 | +|---|---|---| +| `server/router.js` | 279 | `res.setHeader("Access-Control-Allow-Origin", "*");`(裸星号) | +| `server/lib/auth.js` | Gate 3 入口 | `isLocalRequest(req)` 命中即绕过 token 校验(跨源 127.0.0.1 同样命中) | +| `server/routes/settings.js` | (待 grep) | `GET /api/settings` 响应里塞 `currentToken`(`tokenAcknowledged === false` 时) | +| `server/lib/state-bus.js` | `pushStateFor` (待 grep) | SSE state push 也带 `currentToken`(**PoC 没覆盖**,但同源浏览器 EventSource 也会订阅到) | + +--- + +## 5. 修后判定线(机械可证) + +修复后必须满足: +1. `npm test` → `tests 413 / pass 413 / fail 0 / skipped 2`(4 个 blocker 全绿) +2. `poc-csrf.mjs` → exit code 0 + "PoC did not reproduce the blocker" +3. `npm run lint` → 0 errors, 0 warnings(先修路径错位) +4. 人工复测:clean checkout 跑 `node server.js` 仍能正常 listening on / 静态资源 / `/api/health` + +--- + +## 6. 范围声明 + +- 起点:`92cae0c` 干净 HEAD +- 不动 `MiniMax-Code-Plugins`(marketplace 仓,用户明确禁止) +- 修复落点:`Wzdhehe/Mcode-webui`(用户已加入协作者) +- 工作分支:`fix/cve-csrf-token-leak-2026-09`(已创建,**未推送**) +- 后续 PR 标题(计划):`fix(mcode-webui): round 8 — CORS tightening + cross-origin token-leak fix` + +--- + +*baseline locked 2026-09-04 20:55 CST.* diff --git a/plugins/Wzdhehe/mcode-webui/CONTRIBUTING.md b/plugins/Wzdhehe/mcode-webui/CONTRIBUTING.md new file mode 100644 index 0000000..f302fab --- /dev/null +++ b/plugins/Wzdhehe/mcode-webui/CONTRIBUTING.md @@ -0,0 +1,171 @@ +# Contributing to Mcode Web UI + +Thanks for your interest in Mcode Web UI! This document covers +the day-to-day contribution workflow. For the bigger picture (plugin +packaging, release process), see [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) +and [`plugins/Wzdhehe/mcode-webui/README.md`](plugins/Wzdhehe/mcode-webui/README.md). + +## Code of conduct + +Be kind. We review for substance, not for style preferences. If a +change makes the webui more correct / faster / easier to use, it's +in scope. + +## Development setup + +Requirements: + +- **Node 22.19+** (uses `node:test`, `URL.parse`, `Blob.stream`) +- **Mcode CLI 0.1.4+** on `PATH` (or `MCODE_CMD` pointing to it) +- A POSIX-like shell on Windows: PowerShell 7+ or Git Bash + +Clone and run: + +```bash +git clone https://github.com/Wzdhehe/Mcode-webui.git +cd Mcode-webui +npm install # only devDeps (eslint, prettier, c8) +npm test # 382 unit tests + 1 skipped (383 total) +npm run lint # eslint flat config, must be 0 warnings +npm run dev # node server.js +# → http://127.0.0.1:8080/ +``` + +`npm test` and `npm run lint` **must pass** before opening a PR. + +## Repository layout + +This repo has a **dual layout** — both copies are kept in sync: + +``` +Mcode-webui/ # ← the development tree (root) +├── server/ public/ test/ # Node + frontend + tests +├── docs/ # ARCHITECTURE, API, CAPABILITIES, … +├── acp.mjs, server.js, package.json +│ +└── plugins/Wzdhehe/mcode-webui/ # ← the plugin artifact + ├── server/ public/ test/ # ↑ real copies, not symlinks + ├── docs/ references/ skills/ + ├── plugin.json package.json LICENSE + ├── README.md PR_DESCRIPTION.md + └── SKILL.md # lives at skills/mcode-webui/SKILL.md +``` + +**Why two copies?** The community plugin registry takes the +`plugins/.../Mcode-webui/` tree as the submission. We keep it as a +real directory copy (not a junction or symlink — those break +zip-packaging and confuse `git log`). + +`npm run setup:plugin` is a no-op on the current layout (it used to +create junctions; the trees have been expanded since). + +## Editing flow + +1. **Edit at the repo root** (`server/`, `public/`, `test/`). +2. **Mirror the change to the plugin tree** — copy the changed files + from `/server/...` to `plugins/Wzdhehe/mcode-webui/server/...`, + and the same for `public/`, `test/`, `docs/`. + (The `package:plugin` script does this for you, but a + per-PR manual sync is fine for small changes.) +3. **Run the gate**: + ```bash + npm test + npm run lint + npm run validate:plugin + ``` +4. **Commit** with a conventional message (see below). +5. **Push** to a feature branch and open a PR. + +## Commit message format + +We loosely follow [Conventional Commits](https://www.conventionalcommits.org/): + +``` +(): + + +