feat(stream): require auth on GET /stream/{id} via token query param
Docker Build & Publish / build (push) Has been cancelled
Docker Build & Publish / push (push) Has been cancelled
Docker Build & Publish / Prune old image versions (push) Has been cancelled

The audio stream endpoint was unauthenticated. Add a get_streaming_user
dependency that accepts the access token either as a ?token= query param
(the browser <audio> element can't send an Authorization header) or a
bearer header for native clients. Update streaming tests accordingly and
add a test asserting unauthenticated requests are rejected with 401.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Senko-san
2026-06-08 17:11:43 +03:00
parent 5c5df5d3cc
commit 4ade6939b6
3 changed files with 34 additions and 4 deletions
+12 -3
View File
@@ -143,7 +143,8 @@ async def test_stream_full(api: AsyncClient) -> None:
assert up.status_code == 200
track_id = up.json()["track_id"]
resp = await api.get(f"/api/v1/stream/{track_id}")
# Browser <audio> can't send headers — auth rides on the ?token= query param.
resp = await api.get(f"/api/v1/stream/{track_id}?token={token}")
assert resp.status_code == 200
assert resp.content == audio
assert resp.headers["content-type"].startswith("audio/mpeg")
@@ -164,7 +165,7 @@ async def test_stream_range(api: AsyncClient) -> None:
resp = await api.get(
f"/api/v1/stream/{track_id}",
headers={"Range": "bytes=0-9"},
headers={"Range": "bytes=0-9", "Authorization": f"Bearer {token}"},
)
assert resp.status_code == 206
assert resp.content == b"0123456789"
@@ -173,10 +174,18 @@ async def test_stream_range(api: AsyncClient) -> None:
async def test_stream_not_found(api: AsyncClient) -> None:
resp = await api.get("/api/v1/stream/00000000-0000-0000-0000-000000000000")
token = await _login(api)
resp = await api.get(
f"/api/v1/stream/00000000-0000-0000-0000-000000000000?token={token}"
)
assert resp.status_code == 404
async def test_stream_requires_auth(api: AsyncClient) -> None:
resp = await api.get("/api/v1/stream/00000000-0000-0000-0000-000000000000")
assert resp.status_code == 401
async def test_upload_requires_auth(api: AsyncClient) -> None:
resp = await api.post(
"/api/v1/upload",