# -*- coding: utf-8 -*- """响应卫生中间件测试:音频直链保护、安全头、Server 指纹。""" import pytest from fastapi import FastAPI from fastapi.responses import JSONResponse from fastapi.testclient import TestClient from core import security from web.middleware import ResponseHygieneMiddleware @pytest.fixture() def client(): security.init_secret_key('test-secret-key') app = FastAPI() app.add_middleware(ResponseHygieneMiddleware) @app.get('/audio') async def audio(): return JSONResponse({ 'data': [{'url': 'http://m801.music.126.net/obj/song.mp3', 'id': 1}], 'nested': {'audioUrl': 'http://m701.music.126.net/x.flac'}, 'other': 'https://example.com/not-audio.mp3', }) @app.get('/plain') async def plain(): return JSONResponse({'url': 'http://m801.music.126.net/obj/song.mp3'}) return TestClient(app) def test_audio_url_replaced_with_signed_proxy(client): r = client.get('/audio') body = r.json() assert body['data'][0]['url'].startswith('/audio_stream?token=') assert body['nested']['audioUrl'].startswith('/audio_stream?token=') # 非网易音频域名不被替换 assert body['other'] == 'https://example.com/not-audio.mp3' # token 应可被 core.security 校验回原 URL(同一密钥) token = body['data'][0]['url'].split('token=', 1)[1] assert security.verify_audio_token(token) == 'http://m801.music.126.net/obj/song.mp3' def test_security_headers_present(client): r = client.get('/plain') assert r.headers['x-content-type-options'] == 'nosniff' assert r.headers['x-frame-options'] == 'DENY' assert r.headers['referrer-policy'] == 'same-origin' assert 'content-security-policy' in r.headers assert r.headers['server'] == 'NeteaseUrl' def test_non_json_body_untouched(client): """非 JSON 响应不应被中间件改写/缓冲。""" security.init_secret_key('k') app = FastAPI() app.add_middleware(ResponseHygieneMiddleware) @app.get('/text') async def text(): from fastapi.responses import PlainTextResponse return PlainTextResponse('http://m801.music.126.net/x.mp3') c = TestClient(app) r = c.get('/text') assert r.text == 'http://m801.music.126.net/x.mp3'