2961ca67d14a1ca8244510d70220959efcf6b9ef
MC Report System
游戏玩家投诉/建议/申诉系统。Web 端 + Paper 插件双端提交,MySQL 存储,JWT 鉴权,三级角色。
功能模块
| 模块 | 说明 |
|---|---|
| 举报 | 指定目标玩家或事项举报,可上传截图/视频(≤50MB),支持投诉管理员(仅服主可见) |
| 建议 | 提交改进建议,仅服主处理 |
| 申诉 | 封禁申诉 + 结果申诉(对处理结果不满可提交一次,关联原工单) |
| 审批流 | 待处理→接单→处理中→待补充→已解决/已驳回→关闭(7天自动关闭) |
| 接单制 | 管理员一人一单,可转单(带原因),处理备注(玩家不可见) |
| 投票 | 分组/子服管理,定时/不定时投票,盲投制,管理员 1.5 票权 |
| 更新内容 | Issues 风格,分状态(待定/计划中/已完成),讨论区,按时间/热度排序,分组筛选 |
| 通知 | SMTP 邮件 + Discord Webhook(SSRF 防护),邮件模板自定义(编辑变量) |
| 导出 | CSV(UTF-8 BOM),导出工单/被举报人统计/操作日志(仅服主) |
| 插件 | Paper 1.20+,统一 /report 命令,游戏内注册/登录/举报/追踪 |
| 找回密码 | 邮箱验证,1小时有效重置链接 |
| 安装向导 | Web 页面配置 MySQL 连接 + 创建服主账号 |
快速开始
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 |
| 认证 | JWT(256 位随机密钥,72h 有效期) |
| 安全 | Helmet 7 + Rate Limit(分路由限速)+ XSS 过滤 + CSP + API Key 常量时间比对 + SSRF 防护 |
| 验证码 | SVG 混淆图片(svg-captcha,4 位字符 + 噪点 + 颜色变形) |
| 文件上传 | Multer + MIME + 魔数字节校验,UUID 命名,web 外存储 |
| 插件 | Paper API 1.20.4 + java.net.HttpURLConnection |
角色权限矩阵
| 操作 | 玩家 | 管理员 | 服主 |
|---|---|---|---|
| 提交工单 | ✅ | ✅ | ✅ |
| 查看工单 | 仅自己 | 待处理 + 自己接的 | 全部 |
| 查看详情 | 仅自己 | 待处理 + 自己接的 | 全部 |
| 接单认领 | — | 举报/申诉 | 全部 |
| 更新处理备注 | — | 自己接的 | 全部 |
| 变更状态 | — | 自己接的 | 全部 |
| 转单 | — | 自己接的 | 全部 |
| 回复工单 | 自己的 | ✅ | ✅ |
| 用户管理 | — | ✅ | ✅ |
| 邮件模板 | — | ✅ | ✅ |
| 通知配置 | — | ✅ | ✅ |
| 系统设置 | — | ✅ | ✅ |
| 导出数据 | — | — | ✅ |
| 投票/更新管理 | — | — | ✅ |
| 工单追加(未接单) | 自己的 | — | — |
审批流状态
待处理(pending) ──接单──→ 处理中(processing) ──→ 已解决(resolved)
│ │ ├── 已驳回(rejected)
│ 待补充(awaiting_info) └── 7天自动关闭(closed)
│ │
└── 结果申诉 ──→ 申诉中(appealing) ──服主处理──→ 原工单关闭
closed为终态,仅服主可操作- 结果申诉仅一次,关联原工单,仅服主可见
注册来源
| 来源 | 标识 | UID 含义 |
|---|---|---|
| 网易端 | netease |
网易 UID |
| 皮肤站 | skin |
皮肤站 UID / Minecraft UUID |
插件注册默认 skin。
工单提交流程
- 填写标题 + 游戏名 + UID(登录后自动填充)
- 举报:选目标玩家 + 原因(内置选项或自定义)+ 可投诉管理员
- 建议:填写建议内容
- 申诉:填写封禁申诉理由
- 上传附件(可选,图片/视频 ≤50MB,最多5个)
- 提交 → 生成 tracking_token(Cookie 留存)
外部 API
| 端点 | 用途 | 认证 |
|---|---|---|
POST /api/external/auth/register |
插件注册 | x-external-key |
POST /api/external/auth/login |
插件登录 | x-external-key |
GET /api/external/my-tickets |
我的工单(JWT) | x-external-key + Bearer |
GET /api/external/my-tickets/:id |
工单详情(JWT) | x-external-key + Bearer |
POST /api/external/tickets |
提交工单 | x-external-key |
GET /api/external/all-tickets |
全部工单 | x-external-key |
GET /api/external/reported-players |
被举报统计 | x-external-key |
GET /api/external/stats |
统计 | x-external-key |
部署
# 环境变量
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;
插件命令
/report reg <密码> <邮箱> [用户名] 注册(默认用户=游戏名)
/report login <密码> [用户名] 登录
/report report [玩家] <原因> 举报
/report suggest <内容> 建议
/report track [id] 追踪工单
配置 plugins/MCReport/config.yml 填写 api_url 和 external_key。
目录结构
├── backend/
│ ├── server.js # Express 入口
│ ├── db.js # MySQL 连接池 + 建表 + 迁移
│ ├── mailer.js # SMTP 邮件(缓存 transporter)
│ ├── webhook.js # Discord Webhook(SSRF 防护 + 10s 超时)
│ ├── middleware/
│ │ ├── auth.js # JWT(惰性缓存 secret)
│ │ ├── security.js # 限速 + XSS 递归 + API Key 常量时间比对
│ │ └── upload.js # 文件上传(仅读 256B 头验证魔数)
│ └── routes/
│ ├── auth.js # 注册/登录/验证/找回密码
│ ├── tickets.js # 工单核心(自动关闭 + 状态流转)
│ ├── install.js # 安装向导(含 api_key 生成)
│ ├── external.js # 外部 API(插件 + Java 服务器)
│ ├── users.js # 用户管理(含 source 字段)
│ ├── settings.js # 站点设置 + 邮件模板编辑
│ ├── export.js # CSV 导出(服主专享)
│ ├── polls.js # 投票(分组/子服/定时)
│ ├── features.js # 更新内容(Issues 风格 + 讨论)
│ ├── notifications.js # Webhook 配置
│ ├── captcha.js # SVG 验证码
│ └── uploads.js # 附件下载(鉴权)
├── public/ # 前端 SPA (16 页面)
├── mc-report-plugin/ # Paper 1.20+ 插件 (Maven)
├── nginx.inc # Nginx 额外配置
├── data/ # config.json + uploads/
├── README.md
└── 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 自动放行 |
Description
Languages
JavaScript
94.9%
CSS
4.6%
HTML
0.5%