Files
2026-09-12 18:24:41 +08:00

88 lines
3.3 KiB
Python

"""上传安全: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'<svg/>')))
body = json.loads(result.body)
assert body['ok'] is False
def test_save_upload_rejects_svg_even_if_config_allows():
# 兜底硬拒绝:即使配置或其他入口放行 .svg,落盘前一律拒绝
content = b'<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>'
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']