|
|
@@ -0,0 +1,50 @@
|
|
|
+"""Admin JWT attachment file proxy."""
|
|
|
+import pytest
|
|
|
+
|
|
|
+from app.core import storage
|
|
|
+from app.core.config import get_settings
|
|
|
+
|
|
|
+PNG = b"\x89PNG\r\n\x1a\n" + b"\x00" * 8
|
|
|
+
|
|
|
+
|
|
|
+@pytest.fixture
|
|
|
+def local_storage_env(tmp_path, monkeypatch):
|
|
|
+ monkeypatch.setenv("STORAGE_TYPE", "local")
|
|
|
+ monkeypatch.setenv("LOCAL_STORAGE_DIR", str(tmp_path))
|
|
|
+ get_settings.cache_clear()
|
|
|
+ yield tmp_path
|
|
|
+ get_settings.cache_clear()
|
|
|
+
|
|
|
+
|
|
|
+def _token(client):
|
|
|
+ r = client.post("/api/web/auth/login", json={"username": "admin", "password": "Admin@123"})
|
|
|
+ return r.json()["data"]["token"]
|
|
|
+
|
|
|
+
|
|
|
+def test_attachment_proxy_requires_auth(client, local_storage_env):
|
|
|
+ r = client.get("/api/web/admin/attachment/file", params={"url": "/uploads/feedback/x.png"})
|
|
|
+ assert r.status_code == 401
|
|
|
+
|
|
|
+
|
|
|
+def test_attachment_proxy_streams_file(client, local_storage_env):
|
|
|
+ stored = storage.upload_file(PNG, "a.png", "feedback")
|
|
|
+ token = _token(client)
|
|
|
+ r = client.get(
|
|
|
+ "/api/web/admin/attachment/file",
|
|
|
+ params={"url": stored["url"]},
|
|
|
+ headers={"Authorization": f"Bearer {token}"},
|
|
|
+ )
|
|
|
+ assert r.status_code == 200
|
|
|
+ assert r.headers.get("x-content-type-options", "").lower() == "nosniff"
|
|
|
+ assert "image" in (r.headers.get("content-type") or "")
|
|
|
+ assert r.content.startswith(b"\x89PNG")
|
|
|
+
|
|
|
+
|
|
|
+def test_attachment_proxy_rejects_foreign_url(client, local_storage_env):
|
|
|
+ token = _token(client)
|
|
|
+ r = client.get(
|
|
|
+ "/api/web/admin/attachment/file",
|
|
|
+ params={"url": "https://evil.example/a.png"},
|
|
|
+ headers={"Authorization": f"Bearer {token}"},
|
|
|
+ )
|
|
|
+ assert r.status_code == 400
|