- 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)
202 lines
9.1 KiB
Markdown
202 lines
9.1 KiB
Markdown
# MC Report System
|
||
|
||
游戏玩家投诉/建议/申诉系统。Web 端 + Paper 插件双端提交,MySQL 存储,JWT 鉴权,三级角色。
|
||
|
||
## 功能模块
|
||
|
||
| 模块 | 说明 |
|
||
|------|------|
|
||
| **举报** | 指定目标玩家或事项举报,可上传截图/视频(≤50MB),支持投诉管理员(仅服主可见) |
|
||
| **建议** | 提交改进建议,仅服主处理 |
|
||
| **申诉** | 封禁申诉 + 结果申诉(对处理结果不满可提交一次,关联原工单) |
|
||
| **审批流** | 待处理→接单→处理中→待补充→已解决/已驳回→关闭(7天自动关闭) |
|
||
| **接单制** | 管理员一人一单,可转单(带原因),处理备注(玩家不可见) |
|
||
| **投票** | 分组/子服管理,定时/不定时投票,盲投制,管理员 1.5 票权 |
|
||
| **更新内容** | Issues 风格,分状态(待定/计划中/已完成),讨论区,按时间/热度排序,分组筛选 |
|
||
| **通知** | SMTP 邮件 + Webhook(Discord/企微/QQ/飞书,SSRF 防护),邮件模板自定义 |
|
||
| **日志** | 邮件日志 + 系统日志(Webhook 失败/服务器错误),后台可视化排查 |
|
||
| **导出** | CSV(UTF-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 SPA(Hash路由)+ Inter 字体 |
|
||
| 数据库 | MySQL ≥ 5.7 / MariaDB ≥ 10.2 |
|
||
| 认证 | Web: JWT(256 位随机密钥,72h 有效期);外部 API: ID+Secret → SESSION(24h,单会话) |
|
||
| 安全 | Helmet 7 + Rate Limit(分路由限速)+ XSS 过滤 + CSP + SSRF 防护 |
|
||
| 验证码 | SVG 混淆图片(svg-captcha,4 位字符 + 噪点 + 颜色变形) |
|
||
| 文件上传 | 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 自动放行 |
|