一个给熟人群使用的音游好友码网站,使用 Node.js 部署。支持注册登录、游戏与服务器筛选、好友码管理、个人昵称和复制统计。
站长有独立后台,可以为群友重置随机临时密码,查看、复制和更换群验证码,并查看验证码的历史有效时间段。
本仓库只提供程序和配置模板,不包含实际账号、密码、群验证码或群友数据。
| 功能 | 说明 |
|---|---|
| 好友码收集 | 按游戏、区域服务器和平台整理,支持搜索、复制、备注和个人主页 |
| 群内账号 | 群验证码注册、服务端会话、密码哈希和按记录归属校验权限 |
| 唯一站长后台 | 查看成员、重置随机临时密码、管理群验证码及历史有效时间段 |
| 平滑增量更新 | 只更新变化的卡片和字段;新增、删除与排序有过渡,悬停复制时暂缓上移 |
| 金龙与本地字体 | Canvas 分部件龙头动画、站长专属金龙边框、本地 Orbitron 数字字体 |
| 轻量部署 | 运行时零第三方 npm 依赖,本地 JSON 原子写入、加密备份与恢复 |
适合熟人群、小规模社区和自托管使用,不依赖 QQ 官方登录,也不是大型公共账号平台。
- Node.js 22 或更高版本。
- 持久化磁盘。程序采用本地 JSON 存储,适合规模不大的熟人群。
- 只运行一个服务进程,不支持 PM2 cluster、多副本或多个进程共享数据目录。
- 密码哈希使用 scrypt,单次计算约需要 128 MiB 工作内存,服务器建议至少预留 512 MiB 可用内存。
运行时不依赖第三方 npm 包;开发依赖仅用于浏览器测试。
npm ci
npm start也可以直接运行:
node server.js如果没有站长账号,程序会在终端引导设置:
- 站长 QQ。
- 站长密码及确认密码,输入不回显。
- 初始群验证码,留空自动生成随机验证码。
新密码与手动设置的验证码长度为 8–128 位。初始化完成后,站长 QQ 会写入本地 .env,密码只保存为哈希,验证码保存到私有配置文件中。
默认访问地址是 http://127.0.0.1:3000/。站长登录首页后,点击右上角「管理后台」,也可以访问 /admin/。
初始群验证码可以在后台查看。再次启动不会覆盖已有站长账号或重置密码。
Docker、服务管理器等没有交互终端的环境,需要在首次启动时设置:
OWNER_QQ:部署者自己的站长 QQ。OWNER_PASSWORD:首次创建站长使用的强密码。REGISTER_CODE:可选的初始群验证码;不提供则自动生成。
请通过部署平台的私有环境变量或 Secret 注入,不要将实际值写入源码、镜像或命令示例。创建完成后移除 OWNER_PASSWORD;后续启动不会用它覆盖已有密码。
持久化 .env 与数据目录,或在部署环境持续设置相同的 OWNER_QQ。不要在每次容器重建时使用一个空的数据目录。
可以复制 .env.example 为 .env 后填写私有配置,也可以让首次启动引导创建 .env。系统环境变量优先于 .env。
| 变量 | 说明 |
|---|---|
OWNER_QQ |
唯一站长账号。没有添加管理员或角色分配入口 |
OWNER_PASSWORD |
仅在没有站长账号时,用于非交互初始化;不写入 .env |
REGISTER_CODE |
仅作为首次初始化的验证码种子。已有验证码历史后,改这个变量不会覆盖历史;请在后台更换 |
HOST |
监听地址,默认 127.0.0.1。容器中通常需要 0.0.0.0 |
PORT |
监听端口,默认 3000 |
DATA_DIR |
私有数据目录,默认项目根目录;相对路径以项目根目录为基准 |
BASE_PATH |
部署子路径,例如 /friendcode;根路径部署留空 |
PUBLIC_ORIGIN |
对外访问的来源,如 https://friends.example.com,不要带路径或尾斜杠 |
COOKIE_SECURE |
HTTPS 生产环境设为 true;本机 HTTP 开发使用 false |
TRUST_PROXY |
仅在可信反向代理覆盖客户端 IP 请求头时设为 true |
设置 NODE_ENV=production 或 HTTPS 的 PUBLIC_ORIGIN 时,未显式设置的 COOKIE_SECURE 默认启用。模板为本机开发配置;部署到 HTTPS 时不要继续沿用 false。
- 使用 QQ、密码和当前群验证码注册。
- 登录后才能获取群友列表及好友码,未登录接口不会返回这些数据。
- 只能编辑和删除自己的好友码;删除时需要再次输入当前密码。
- 可以修改自己的昵称与密码。修改密码后,其他设备的会话失效。
- 忘记密码时,私聊站长核对身份后重置。
QQ 号是登录标识,并不是 QQ 官方授权登录。程序不会验证填写的 QQ 是否属于注册者,群验证码也不能替代身份核对;请只向群友分享验证码。
列表每 30 秒自动从后端同步一次,切回网页时也会补充同步。没有变化时不重建卡片;新增、删除、排序移动与字段变化分别平滑过渡,头像和金龙动画不会因轮询重新加载。个人主页里的未保存昵称草稿、筛选条件与阅读位置会尽量保留。复制次数会立即更新;若鼠标仍停留在因此需要上移的卡片内,会等鼠标离开整张卡片后再执行排序过渡,避免按钮在鼠标下移动。正常情况下播放完整过渡;仅在系统开启减少动态效果时简化动画。
只有私有 OWNER_QQ 指定的账号能访问后台接口。修改浏览器缓存或账号文件里的 role 字段,不会让普通成员获得后台权限。
后台支持:
- 搜索成员 QQ 或昵称,查看其好友码数量。
- 为普通成员重置随机临时密码。
- 查看当前群验证码并复制。
- 更换验证码,可手动输入,也可生成随机码。
- 查看全部已记录验证码的启用、停用时间。
- 查看最近的账号操作日志,日志不记录密码。
- 先通过私聊核对本人身份。
- 点击对应成员的「重置密码」,确认后生成随机临时密码。
- 临时密码只在这次弹窗中显示,通过私聊发给本人,不要发到群里。
- 对方用临时密码登录后,必须先设置自己的新密码,才能继续使用网站。
重置不会改动昵称和好友码。旧密码与该成员的所有会话立即失效。弹窗关闭后不能再次查看临时密码;如果没有保存,可以重新重置。
站长账号不能在后台重置自身密码,正常情况下使用首页的「修改密码」。
每次更换会关闭上一条验证码的有效时间段,并开启新验证码的时间段,旧验证码立即不能用于注册,已注册成员不受影响。
为避免旧码重新流入群外,不能重复使用历史验证码。历史起点是首次初始化或从旧版升级的时间,不代表旧版验证码真实的最初使用时间。
先停止服务,再在服务器执行:
npm run owner:reset命令只恢复私有配置指定的站长账号,输出一个随机临时密码。重新启动服务,用临时密码登录并修改。不要把命令输出提交到仓库或发到群里。
升级前停止旧服务,并备份私有 .env、账号文件、好友码文件和 .private-backups/。
- 保留原来的
user.json和data.json,放在选定的DATA_DIR中。 - 在私有
.env中设置原站长的OWNER_QQ和原群验证码。若未设置站长且旧账号中只有一个role: "admin",启动时会识别该账号并写入私有配置。 - 首次启动前会创建加密备份,然后将明文密码转换为 scrypt 哈希。原密码仍可登录,昵称、角色及其他账号字段保持不变。
- 已有好友码记录、复制次数、ID 与时间不会因密码迁移而重写。
- 旧版短密码暂时仍可登录;新注册、改密和重置后的改密需要至少 8 位。
- 旧版浏览器缓存会被清除,所有人需要重新登录。
- 前端文件已移入
public/。反向代理应将请求交给 Node,不要继续静态托管旧项目目录。
也可以先停止服务,单独检查并执行密码迁移:
npm run migrate不要把空示例数据覆盖到已有数据上。若账号、好友码或验证码文件损坏,程序会停止启动,不会用空数据静默替换。
- 准备持久化、仅服务用户可读写的数据目录。
- 首次交互运行一次,或使用私有环境变量完成初始化。
- 配置 HTTPS,填写
PUBLIC_ORIGIN,设置COOKIE_SECURE=true。 - 使用 systemd、Docker 或 PM2 单实例 fork 模式托管进程。
- 反向代理将页面和
/api/一并转发给 Node。
示例配置见 deploy/nginx.conf.example。示例不包含实际域名、证书或私有账号。
子路径部署时设置 BASE_PATH,并让代理保留完整请求路径。不要给代理的 proxy_pass 添加会剥离该子路径的 URI 部分。
不要将项目根目录、数据目录、.env 或备份目录配置为 Nginx 静态根目录。Node 只提供 public/ 中允许类型的静态资源。
会话保存在内存中,服务重启后需要重新登录,这是当前轻量方案的预期行为。
先停止服务再执行:
npm run backup备份在数据目录下的 .private-backups/ 中,使用 AES-256-GCM 加密。backup.key 是解密密钥;请将它和备份文件分开保管,并复制到服务器以外的安全位置。密钥丢失后无法恢复备份。两者仍放在同一服务器上不能防御整台服务器被攻破。
密码迁移、改密、重置密码、编辑/删除好友码、更换验证码和恢复前也会生成安全备份。备份不会自动清理,请定期检查占用并自行制定保留周期。
恢复会覆盖当前数据;请先核对文件名,停止服务,再执行:
npm run restore -- <backup-file.enc.json> --confirm只传 .private-backups/ 中的文件名,不传路径。恢复前会额外保存当前文件的加密副本,恢复旧版账号时也会先哈希明文密码。
如果恢复过程被中断,服务会拒绝启动;重新执行同一个恢复命令完成操作。恢复不修改 .env,需自行确认 OWNER_QQ 与备份中的目标站长一致。
- 数字与展示标题保留 Orbitron,字体随项目本地托管,不依赖外部字体服务。字体授权文件为
public/fonts/OFL-Orbitron.txt。 - 站长龙头采用 Canvas 分部件绘制,嘴、眼睛、耳朵、胡须与鬃毛独立运动,不依赖图片或视频素材。
- 动画尊重系统的减少动态效果设置,页面在后台或龙卡片不在视口时停止连续绘制。
- 主页面每轮同步只发一个请求,同时校验登录状态与数据版本。数据没有变化时,只返回小型状态信息,不重复传输整份成员与好友码列表。
- 静态 HTML、CSS、JavaScript 和字体使用有容量上限的内存缓存;文本资源预生成 Brotli/Gzip,浏览器可用 ETag 重新校验。修改文件后会自动失效,不使用会阻碍更新的长期强缓存。
- 账号、群友数据和包含会话信息的响应仍是
no-store,不会因为性能优化而被公共缓存保存。 - 搜索文本、排序和统计按数据版本复用。输入事件按帧合并,并避免在中文输入法组合过程中反复过滤。
- 金龙保持原有画面和 30 FPS 上限;复用几何缓存,暂停弹窗背后的金龙与频谱背景,关闭弹窗后从当前状态恢复。当前可见弹窗里的金龙正常播放。
- 列表过渡继续保留;鼠标悬停时先更新复制次数,离开卡片后再移动位置。
安装浏览器测试环境后,可以用虚构的 60 条数据运行本地性能检查:
npm run benchmark该命令使用临时数据目录,比较旧式双请求与版本同步的请求数、响应大小,并输出静态资源压缩量和固定画面的绘制校验值。耗时受机器和浏览器影响,不是服务器的生产性能承诺。
npm run check
npm test后端测试使用临时虚构账号和临时数据目录,不读取或修改部署数据。
运行浏览器测试:
npx playwright install chromium
npm run test:e2e浏览器测试覆盖成员添加/编辑/删除、站长后台、随机重置密码、强制改密、验证码更换与历史时间段,以及手机布局。测试截图只包含虚构数据。
deploy/github-actions.example.yml 提供 Node.js 22/24 检查、后端测试和浏览器测试配置。
需要启用 GitHub Actions 时,将它复制到 .github/workflows/checks.yml 并提交。通过 Git 凭据上传该路径需要 workflow 权限,也可以由仓库维护者在 GitHub 网页中添加;仅保留在 deploy/ 下不会自动运行。
.gitignore已排除.env、实际数据、备份、日志和测试产物。- 如果使用自定义
DATA_DIR,不要把它放在public/或未忽略的仓库子目录中。 - 提交前检查暂存区,不要强制添加私有文件。
- 忽略规则不清理 Git 历史;如果以前提交过密码或验证码,先更换泄露内容,再清理历史。
- 不要上传真实成员截图或包含真实注册信息的测试产物。
授权方式见 LICENSE。安全说明见 SECURITY.md。