// 已读取AGENTS.md import * as fs from 'fs'; import * as path from 'path'; /** * 第六批回归闸门:评价下架鉴权 / 大神资料越权 / 剩余写接口身份绑定 */ describe('第六批安全加固闸门 (评价下架鉴权 / 大神资料越权 / 身份绑定)', () => { const rootDir = path.resolve(__dirname, '../../'); const serverRepoPath = path.join(rootDir, 'server/src/db/repository.ts'); const serverIndexPath = path.join(rootDir, 'server/src/index.ts'); const apiPath = path.join(rootDir, 'pwuniapp/common/api.js'); const indexCode = fs.readFileSync(serverIndexPath, 'utf-8'); const repoCode = fs.readFileSync(serverRepoPath, 'utf-8'); const apiCode = fs.readFileSync(apiPath, 'utf-8'); describe('1. 评价违规下架仅管理员可执行', () => { it('DELETE /api/reviews/:id 必须挂载 requireAdmin', () => { expect(indexCode).toContain("app.delete('/api/reviews/:id', requireAdmin"); }); }); describe('2. 大神资料/接单状态越权修改', () => { it('仓储层必须提供 getCompanionOwnership 解析归属', () => { expect(repoCode).toContain('async getCompanionOwnership('); const start = repoCode.indexOf('async getCompanionOwnership('); const block = repoCode.slice(start, start + 600); expect(block).toContain('ownerUserId'); expect(block).toContain('comp.user_id'); }); it('服务端必须提供 assertCompanionActor 且生产环境要求已绑定 user_id', () => { const start = indexCode.indexOf('function assertCompanionActor('); expect(start).toBeGreaterThan(-1); const block = indexCode.slice(start, start + 1000); expect(block).toContain('isVerifiedAdminRequest(req)'); expect(block).toContain('IS_PRODUCTION'); expect(block).toContain('ownerUserId'); expect(block).toContain('无权'); }); it('两个大神资料更新路由都必须先做归属校验', () => { for (const marker of ["app.put('/api/companions/:id',", "app.put('/api/companions/:id/profile',"]) { const start = indexCode.indexOf(marker); expect(start).toBeGreaterThan(-1); const block = indexCode.slice(start, start + 600); expect(block).toContain('repo.getCompanionOwnership(companionId)'); expect(block).toContain("assertCompanionActor(req, own, '修改大神资料')"); } }); }); describe('3. 剩余写接口身份以服务端会话为准', () => { it('点赞/评论/举报/收藏/分销/入驻均必须经 resolveSecureUserId 绑定身份', () => { const expected = [ "'点赞动态'", "'发表评论'", "'提交举报'", "'收藏大神'", "'取消收藏'", "'绑定邀请码'", "'申请大神入驻'", ]; for (const tag of expected) { expect(indexCode).toContain(`resolveSecureUserId(req,`); expect(indexCode).toContain(tag); } // 旧的可伪造缺省默认值必须被移除 expect(indexCode).not.toContain('addFavorite(Number(userId || 1001)'); expect(indexCode).not.toContain('bindInviteCode(Number(userId || 1001)'); }); }); describe('4. 小程序端写接口携带真实身份', () => { it('评论/举报/入驻/大神资料/上车处置均注入当前用户身份', () => { expect(apiCode).toContain('userId: normalizeUserId(commentData.userId)'); expect(apiCode).toContain('reporterId: normalizeUserId(payload.reporterId || payload.userId)'); expect(apiCode).toContain('userId: normalizeUserId(data && data.userId)'); expect(apiCode).toContain('userId: normalizeUserId(profileData.userId)'); expect(apiCode).toContain('{ status, userId: normalizeUserId() }'); }); }); });