文件
shanghaipeiwan/server/tests/upload.spec.ts
xcbyy 25d8474877 security: 新增全局限流 + 5xx 错误脱敏 + 兜底错误处理
- 内存级限流器(令牌桶):/api 全局 600/分;写接口单独限流(发帖10、评论20、组局申请20、举报5、上传30、下单20、支付30、充值/提现10、浏览1次/3秒);超限 429+Retry-After
- 5xx 统一脱敏:内部错误仅记服务端日志,对外返回“服务器内部错误”,不再回传 SQL/堆栈/内部原因
- 新增兜底错误处理中间件,避免 Express 默认 HTML 堆栈外泄
- 更新 upload 断言;新增回归护栏 ratelimit-5xx.spec.ts(90 套件/648 用例全绿);冒烟 7/7
- 文档补充限流与错误脱敏说明
2026-10-19 13:50:51 +08:00

34 行
1.5 KiB
TypeScript

import * as fs from 'fs';
import * as path from 'path';
describe('FileUpload Service (TDD 文件上传与静态对象存储服务门禁)', () => {
const rootDir = path.resolve(__dirname, '../..');
const serverIndexPath = path.join(rootDir, 'server/src/index.ts');
const uploadsDirPath = path.join(rootDir, 'server/public/uploads');
it('静态文件上传持久化目录 public/uploads 必须存在', () => {
expect(fs.existsSync(uploadsDirPath)).toBe(true);
});
it('server/src/index.ts 必须挂载 /uploads 静态托管路由与 /api/upload 接口', () => {
const content = fs.readFileSync(serverIndexPath, 'utf-8');
expect(content).toContain("app.use('/uploads', express.static(uploadDir));");
expect(content).toContain("app.post('/api/upload', rateLimit({ name: 'upload'");
expect(content).toContain('handleFileUpload);');
});
it('文件上传配置必须限制 10MB 与合法图片格式过滤', () => {
const content = fs.readFileSync(serverIndexPath, 'utf-8');
expect(content).toContain('10 * 1024 * 1024');
expect(content).toContain('image/jpeg');
expect(content).toContain('image/png');
expect(content).toContain('image/webp');
});
it('文件上传逻辑代码中必须严格遵循零 Emoji 门禁规范', () => {
const content = fs.readFileSync(serverIndexPath, 'utf-8');
const emojiRegex = /[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u;
expect(emojiRegex.test(content)).toBe(false);
});
});