Files
MC_Report/README.md
canglan 356d7ab5ab chore: remove plugin from repo, add plugin guide, docs + AGPLv3 license
- mc-report-plugin removed from git tracking (kept locally), gitignored;
  plugin code no longer distributed (old x-external-key auth, outdated)
- docs/PLUGIN-GUIDE.md: Java plugin integration guide using new
  ID+Secret -> SESSION auth (session mgmt, submit ticket, track, bans)
- README: updated external API table (SESSION), dynamic sources,
  removed obsolete plugin commands/tech row, new dir structure, doc links
- INSTALL: drop restart requirement, add upgrade-migration/log/sources
  sections, license section
- LICENSE: GNU AGPL v3 full text
- verified: 24 checks (git tracking, docs consistency, license integrity)
2026-08-19 20:23:04 +08:00

202 lines
9.1 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# MC Report System
游戏玩家投诉/建议/申诉系统。Web 端 + Paper 插件双端提交MySQL 存储JWT 鉴权,三级角色。
## 功能模块
| 模块 | 说明 |
|------|------|
| **举报** | 指定目标玩家或事项举报,可上传截图/视频≤50MB支持投诉管理员仅服主可见 |
| **建议** | 提交改进建议,仅服主处理 |
| **申诉** | 封禁申诉 + 结果申诉(对处理结果不满可提交一次,关联原工单) |
| **审批流** | 待处理→接单→处理中→待补充→已解决/已驳回→关闭7天自动关闭 |
| **接单制** | 管理员一人一单,可转单(带原因),处理备注(玩家不可见) |
| **投票** | 分组/子服管理,定时/不定时投票,盲投制,管理员 1.5 票权 |
| **更新内容** | Issues 风格,分状态(待定/计划中/已完成),讨论区,按时间/热度排序,分组筛选 |
| **通知** | SMTP 邮件 + WebhookDiscord/企微/QQ/飞书SSRF 防护),邮件模板自定义 |
| **日志** | 邮件日志 + 系统日志Webhook 失败/服务器错误),后台可视化排查 |
| **导出** | CSVUTF-8 BOM导出工单/被举报人统计/操作日志(仅服主) |
| **外部 API** | ID+Secret → SESSION 鉴权;工单提交/追踪、封禁拉取/新增、按子服过滤(机器人/插件对接) |
| **找回密码** | 邮箱验证1小时有效重置链接 |
| **多来源身份** | 来源动态管理(后台增删),一个账号可绑定多个来源身份,无默认来源 |
| **安装向导** | Web 页面配置 MySQL 连接 + 创建服主账号(完成后无需重启) |
## API 文档
- **完整接口文档**:[docs/API.md](docs/API.md)(认证/工单/封禁/用户/设置/通知/投票/更新/导出/外部 API)
- **第三方外部 API(机器人/插件)**:[docs/EXTERNAL-API.md](docs/EXTERNAL-API.md)(ID+Secret 换取 SESSION、提交工单、进度追踪、封禁拉取、按子服拉数据)
- **MC 插件对接示例**:[docs/PLUGIN-GUIDE.md](docs/PLUGIN-GUIDE.md)(Java 实现:换取 SESSION、提交举报、同步封禁)
## 快速开始
```bash
npm install
node backend/server.js
# → 打开 http://localhost:3100/#/install
```
两步安装:填 MySQL 连接信息 → 建服主账号 → 重启生效。
## 默认端口
`3100`,可通过 `PORT=8080` 环境变量修改。
## 技术栈
| 层 | 技术 |
|----|------|
| 后端 | Node.js + Express + mysql2 |
| 前端 | Vanilla JS SPAHash路由+ Inter 字体 |
| 数据库 | MySQL ≥ 5.7 / MariaDB ≥ 10.2 |
| 认证 | Web: JWT256 位随机密钥72h 有效期);外部 API: ID+Secret → SESSION24h单会话 |
| 安全 | Helmet 7 + Rate Limit分路由限速+ XSS 过滤 + CSP + SSRF 防护 |
| 验证码 | SVG 混淆图片svg-captcha4 位字符 + 噪点 + 颜色变形) |
| 文件上传 | Multer + MIME + 魔数字节校验UUID 命名web 外存储 |
| 许可证 | AGPLv3 |
## 角色权限矩阵
| 操作 | 玩家 | 管理员 | 服主 |
|------|:--:|:--:|:--:|
| 提交工单 | ✅ | ✅ | ✅ |
| 查看工单 | 仅自己 | 待处理 + 自己接的 | 全部 |
| 查看详情 | 仅自己 | 待处理 + 自己接的 | 全部 |
| 接单认领 | — | 举报/申诉 | 全部 |
| 更新处理备注 | — | 自己接的 | 全部 |
| 变更状态 | — | 自己接的 | 全部 |
| 转单 | — | 自己接的 | 全部 |
| 回复工单 | 自己的 | ✅ | ✅ |
| 用户管理 | — | ✅ | ✅ |
| 邮件模板 | — | ✅ | ✅ |
| 通知配置 | — | ✅ | ✅ |
| 系统设置 | — | ✅ | ✅ |
| 导出数据 | — | — | ✅ |
| 投票/更新管理 | — | — | ✅ |
| 工单追加(未接单) | 自己的 | — | — |
## 审批流状态
```
待处理(pending) ──接单──→ 处理中(processing) ──→ 已解决(resolved)
│ │ ├── 已驳回(rejected)
│ 待补充(awaiting_info) └── 7天自动关闭(closed)
│ │
└── 结果申诉 ──→ 申诉中(appealing) ──服主处理──→ 原工单关闭
```
- `closed` 为终态,仅服主可操作
- 结果申诉仅一次,关联原工单,仅服主可见
## 注册来源与多身份
来源在后台「来源管理」页**动态维护**(可增删/停用/排序,不设默认)。初始预置:
| 来源 | 标识 | 说明 |
|------|------|------|
| 网易端 | `netease` | 网易端身份 |
| 皮肤站 | `skin` | 皮肤站身份 |
**多身份绑定**:一个账号可绑定多个来源身份(控制台「我的身份」或 `POST /api/auth/identities` 管理)。提交工单时可选择使用哪个身份;`user_identities` 表由启动时自动迁移回填,`users` 表主身份字段保持不变(完全兼容旧数据)。
## 工单提交流程
1. 填写标题 + 游戏名(登录后自动填充)
2. 举报:选目标玩家 + 原因(内置选项或自定义)+ 可投诉管理员
3. 建议:填写建议内容
4. 申诉:填写封禁申诉理由
5. 上传附件(可选,图片/视频 ≤50MB,最多5个)
6. 提交 → 生成 tracking_token(Cookie 留存)
## 外部 API
| 端点 | 用途 | 认证 |
|------|------|------|
| `POST /api/external/auth/session` | ID+Secret 换取 SESSION | x-api-client-id + x-api-secret |
| `POST /api/external/auth/register` | 插件注册 | Bearer SESSION |
| `POST /api/external/tickets` | 提交工单(带 server 可选) | Bearer SESSION |
| `GET /api/external/tickets/track` | 按追踪码查进度 | Bearer SESSION |
| `GET /api/external/all-tickets` | 工单列表(可按子服过滤) | Bearer SESSION |
| `GET/POST /api/external/bans` | 拉取/新增封禁 | Bearer SESSION |
| `GET /api/external/reported-players` | 被举报统计 | Bearer SESSION |
| `GET /api/external/servers` | 服务器列表(含别名) | Bearer SESSION |
| `GET /api/external/stats` | 统计 | Bearer SESSION |
完整说明见 [docs/EXTERNAL-API.md](docs/EXTERNAL-API.md);MC 插件对接示例见 [docs/PLUGIN-GUIDE.md](docs/PLUGIN-GUIDE.md)。
## 部署
```bash
# 环境变量
PORT=3100 CORS_ORIGIN=https://your-domain.com node backend/server.js
# PM2 持久化
pm2 start backend/server.js --name mc-report
# Nginx 反代(还需 include nginx.inc
proxy_pass http://127.0.0.1:3100;
```
完整部署步骤见 [INSTALL.md](INSTALL.md)。
## MC 插件对接
仓库不内置插件代码,按 [docs/PLUGIN-GUIDE.md](docs/PLUGIN-GUIDE.md) 用 Java 自行实现即可:
- `POST /api/external/auth/session`:ID+Secret 换取 SESSION(自动续期)
- `POST /api/external/tickets`:游戏内提交举报/建议/申诉(带子服)
- `GET /api/external/tickets/track`:玩家查询处理进度(tracking_token)
- `GET/POST /api/external/bans`:同步本服封禁
## 目录结构
```text
├── backend/
│ ├── server.js # Express 入口(动态加载业务路由)
│ ├── db.js # MySQL 连接池 + 建表 + 幂等迁移
│ ├── logger.js # 邮件/系统日志(写库, 失败不影响主流程)
│ ├── mailer.js # SMTP 邮件(自动记录日志)
│ ├── webhook.js # Webhook 推送(SSRF 防护 + 10s 超时)
│ ├── middleware/
│ │ ├── auth.js # JWT(Web 鉴权)
│ │ ├── security.js # 限速 + XSS + API Key 校验
│ │ └── upload.js # 文件上传(魔数校验)
│ └── routes/
│ ├── auth.js # 注册/登录/验证/找回密码/多身份
│ ├── tickets.js # 工单核心(状态流转)
│ ├── install.js # 安装向导
│ ├── external.js # 外部 API(SESSION 鉴权)
│ ├── sources.js # 动态来源管理
│ ├── users.js # 用户管理
│ ├── logs.js # 日志查询
│ ├── settings.js # 站点设置 + UUID 查询
│ ├── export.js # CSV 导出
│ ├── polls.js # 投票 + 服务器分组
│ ├── features.js # 更新内容
│ ├── notifications.js # 通知配置
│ ├── captcha.js # SVG 验证码
│ └── uploads.js # 附件下载
├── public/ # 前端 SPA
├── docs/ # 文档(API / 外部API / 插件指南)
├── nginx.inc # Nginx 额外配置
├── data/ # config.json + uploads/ (git 忽略)
├── README.md
├── INSTALL.md
├── LICENSE # AGPLv3
└── package.json
```
## 安全
| 措施 | 实现 |
|------|------|
| JWT 秘钥 | 256 位随机,惰性缓存,无硬编码 fallback |
| API Key | 48 位随机,常量时间比对防时序攻击 |
| 限速 | 登录 8/min、注册 3/min、工单 10/min、全局 300/min |
| XSS | `sanitizeBody` 递归过滤 + `U.esc` 前端转义 |
| CSP | Helmet + `script-src-attr 'unsafe-inline'` |
| SQL 注入 | 全参数化查询 |
| 文件上传 | 扩展名 + MIME + 魔数(仅读 256B+ UUID 命名 |
| Webhook SSRF | DNS 解析后过滤内网 IP |
| 用户名枚举 | 注册/登录统一错误信息 |
| CORS | 环境变量控制 + localhost 自动放行 |