feat: 用户信息完善 + 一起记功能

- users 表添加 nickname、avatar_url 字段
- 用户信息 API(GET/PUT /me)+ 头像上传(multer)
- 头像通过 API 路由获取(公开,不经过 auth)
- 登录接口返回用户昵称和头像
- 用户信息 Store + 个人资料编辑页面
- 我的页面和首页显示真实用户信息
- 群组表(groups、group_members)+ transactions 添加 group_id
- 群组 API(创建/加入/退出/解散)
- 交易和统计 API 支持 group_id 视图切换
- 群组客户端 Store + 身份切换
- 群组管理页面
- App 初始化群组 Store
- UPLOAD_DIR 配置化
- Node.js 备份替代 mysqldump
- 统一前端 BASE_URL(config.ts)
- uploads 加入 .gitignore
- 修复 trust proxy 警告
This commit is contained in:
2026-06-03 17:04:22 +08:00
parent 9162b2c87c
commit 21f4d81959
45 changed files with 3145 additions and 348 deletions

View File

@@ -1,5 +1,5 @@
import { Request, Response, NextFunction } from 'express'
import { createHmac } from 'crypto'
import { createHmac, timingSafeEqual } from 'crypto'
export interface AuthRequest extends Request {
userId?: number
@@ -48,10 +48,12 @@ export function authMiddleware(req: AuthRequest, res: Response, next: NextFuncti
return res.status(401).json({ code: 40100, message: 'token无效' })
}
// Verify HMAC signature (full length)
// Verify HMAC signature (constant-time comparison)
const payload = `${userId}:${timestamp}`
const expectedSig = createHmac('sha256', TOKEN_SECRET).update(payload).digest('hex')
if (signature !== expectedSig) {
const sigBuf = Buffer.from(signature, 'hex')
const expectedBuf = Buffer.from(expectedSig, 'hex')
if (sigBuf.length !== expectedBuf.length || !timingSafeEqual(sigBuf, expectedBuf)) {
return res.status(401).json({ code: 40100, message: 'token无效' })
}