"""上传安全:SVG/WebP 整体禁止上传(存储型 XSS 面 / 无可靠魔数)。""" import asyncio import json from modules.upload import service as upload_service from modules.upload.service import _save_upload, upload_file class _FakeUpload: """模拟异步分块读取的 UploadFile。""" def __init__(self, filename, data=b''): self.filename = filename self._data = data async def read(self, size=65536): data = self._data self._data = b'' return data def test_upload_file_rejects_svg(monkeypatch): # SVG 被 BANNED_UPLOAD_EXTS 硬拒绝(即使配置放行) monkeypatch.setattr(upload_service, 'UPLOAD_ALLOWED_EXTS', '.svg') result = asyncio.run(upload_file(_FakeUpload('logo.svg', b''))) body = json.loads(result.body) assert body['ok'] is False def test_save_upload_rejects_svg_even_if_config_allows(): # 兜底硬拒绝:即使配置或其他入口放行 .svg,落盘前一律拒绝 content = b'' result = _save_upload(content, 'a.svg', '.svg') body = json.loads(result.body) assert body['ok'] is False assert 'SVG' in body['msg'] def test_upload_file_rejects_webp(monkeypatch): # WebP 被 BANNED_UPLOAD_EXTS 硬拒绝(即使配置放行) monkeypatch.setattr(upload_service, 'UPLOAD_ALLOWED_EXTS', '.webp') result = asyncio.run(upload_file(_FakeUpload('a.webp', b'RIFF' + b'\x00' * 32))) body = json.loads(result.body) assert body['ok'] is False def test_save_upload_rejects_webp_even_if_config_allows(): # 兜底硬拒绝:webp 魔数仅 RIFF 前缀(WAV/AVI 可冒充),落盘前一律拒绝 result = _save_upload(b'RIFF' + b'\x00' * 32, 'a.webp', '.webp') body = json.loads(result.body) assert body['ok'] is False assert 'WebP' in body['msg'] def test_upload_file_uses_builtin_set_when_unconfigured(monkeypatch): # 方案A:未配置时回落内置智能集合,白名单校验放行内置格式 from core import R called = {} def fake_save(content, original_name, ext): called['ext'] = ext return R.ok(msg="ok", data={}) monkeypatch.setattr(upload_service, 'UPLOAD_ALLOWED_EXTS', '') monkeypatch.setattr(upload_service, '_save_upload', fake_save) result = asyncio.run(upload_file(_FakeUpload('a.jpg', b'\xff\xd8\xff'))) body = json.loads(result.body) assert body['ok'] is True assert called['ext'] == '.jpg' def test_upload_file_fail_closed_when_config_outside_builtin(monkeypatch): # 配置的扩展名全不在内置集合内 → 有效白名单为空 → 拒绝一切上传 monkeypatch.setattr(upload_service, 'UPLOAD_ALLOWED_EXTS', '.svg,.webp,.exe') result = asyncio.run(upload_file(_FakeUpload('a.jpg', b'\xff\xd8\xff'))) body = json.loads(result.body) assert body['ok'] is False assert '允许上传范围' in body['msg'] def test_upload_file_rejects_ext_outside_effective_set(monkeypatch): # 配置收缩白名单后,内置集合中但不在配置内的扩展名被拒绝 monkeypatch.setattr(upload_service, 'UPLOAD_ALLOWED_EXTS', '.jpg,.png') result = asyncio.run(upload_file(_FakeUpload('a.txt', b'hello'))) body = json.loads(result.body) assert body['ok'] is False assert '文件格式' in body['msg']