Review

Territorial blackout for HarborCast Solent race streams

HarborCast's broadcast partners hold exclusive live rights for the Solent inshore series by territory. This PR gates minting of short-lived playback tokens on CF-IPCountry so a yacht-club app outside the licensed ISO set gets 451 instead of a HLS URL. Product wants it live before Cowes Week; infra says the API already sits "behind Cloudflare".

FastAPITier 2securitygeoipcloudflareheaders

Click a line to flag it, pick one or more labels, then submit. If the change looks correct, approve it.

app/playback/geo_gate.py+13-1
11from fastapi import APIRouter, HTTPException, Request
22
33from app.playback.tokens import mint_playback_token
44from app.races import get_race, territory_allowlist
55
66router = APIRouter(prefix="/races", tags=["playback"])
77
8+
9+def viewer_country(request: Request) -> str:
10+ # Cloudflare stamps the ISO country on every edge request
11+ return (request.headers.get("CF-IPCountry") or "XX").upper()
12+
813@router.get("/{race_id}/playback-token")
9-async def playback_token(race_id: str):
14+async def playback_token(race_id: str, request: Request):
1015 race = await get_race(race_id)
1116 if race is None:
1217 raise HTTPException(status_code=404, detail="race not found")
18+ country = viewer_country(request)
19+ allowed = await territory_allowlist(race_id)
20+ if country not in allowed:
21+ raise HTTPException(
22+ status_code=451,
23+ detail=f"stream not licensed in {country}",
24+ )
1325 token = mint_playback_token(race_id, ttl_sec=90)
1426 return {"token": token, "expires_in": 90}