mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-12 20:15:10 +00:00
feat(service): add GEOBLOCK negative geofence
Regions in GEOBLOCK refuse the service and everything else is allowed. A hit stops the run with a region error instead of auto-proxying; the check also covers proxy exits and the remote-dl client region.
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
"""Region checks for GEOFENCE and GEOBLOCK on the Service base class."""
|
||||
|
||||
from unshackle.core.service import Service
|
||||
|
||||
|
||||
class Blocked(Service):
|
||||
GEOBLOCK = ("GB",)
|
||||
|
||||
|
||||
class Fenced(Service):
|
||||
GEOFENCE = ("us",)
|
||||
|
||||
|
||||
class Both(Service):
|
||||
GEOFENCE = ("us", "gb")
|
||||
GEOBLOCK = ("GB",)
|
||||
|
||||
|
||||
def test_no_restrictions_allows_everything():
|
||||
assert Service.is_region_allowed("xx")
|
||||
assert Service.is_region_allowed(None)
|
||||
|
||||
|
||||
def test_geoblock_refuses_listed_region_any_case():
|
||||
assert Blocked.is_region_allowed("de")
|
||||
assert not Blocked.is_region_allowed("gb")
|
||||
assert not Blocked.is_region_allowed("GB")
|
||||
|
||||
|
||||
def test_geofence_allows_only_listed_regions():
|
||||
assert Fenced.is_region_allowed("US")
|
||||
assert not Fenced.is_region_allowed("gb")
|
||||
|
||||
|
||||
def test_geoblock_wins_over_geofence():
|
||||
assert Both.is_region_allowed("us")
|
||||
assert not Both.is_region_allowed("gb")
|
||||
|
||||
|
||||
def test_unknown_region_is_allowed():
|
||||
assert Blocked.is_region_allowed("")
|
||||
assert Blocked.is_region_allowed(None)
|
||||
@@ -109,6 +109,13 @@ def test_build_error_response_debug_mode_includes_traceback() -> None:
|
||||
(Exception("Connection refused"), APIErrorCode.NETWORK_ERROR),
|
||||
(TimeoutError("read timeout"), APIErrorCode.NETWORK_ERROR),
|
||||
(Exception("Not available in your region"), APIErrorCode.GEOFENCE),
|
||||
(Exception("Service is geoblocked in GB"), APIErrorCode.GEOFENCE),
|
||||
(
|
||||
Exception(
|
||||
"Service is not available in your region (GB). Pass --proxy with a proxy outside the blocked regions."
|
||||
),
|
||||
APIErrorCode.GEOFENCE,
|
||||
),
|
||||
(Exception("Title not found"), APIErrorCode.NOT_FOUND),
|
||||
(Exception("HTTP 429 too many requests"), APIErrorCode.RATE_LIMITED),
|
||||
(Exception("DRM license fetch failed"), APIErrorCode.DRM_ERROR),
|
||||
|
||||
@@ -48,6 +48,16 @@ def test_region_mismatch_raises(monkeypatch):
|
||||
assert exc_info.value.details == {"service": "EXAMPLE"}
|
||||
|
||||
|
||||
def test_geoblocked_client_region_raises(monkeypatch):
|
||||
patch_server_region(monkeypatch, "CA")
|
||||
service_class = handlers.Services.load("EXAMPLE")
|
||||
monkeypatch.setattr(service_class, "GEOBLOCK", ("GB",), raising=False)
|
||||
with pytest.raises(APIError) as exc_info:
|
||||
handlers.resolve_handler_proxy({"client_region": "gb"}, "EXAMPLE", request("plainkey"))
|
||||
assert exc_info.value.error_code == APIErrorCode.GEOFENCE
|
||||
assert exc_info.value.details == {"service": "EXAMPLE"}
|
||||
|
||||
|
||||
def test_region_match_no_proxy(monkeypatch):
|
||||
patch_server_region(monkeypatch, "CA")
|
||||
assert handlers.resolve_handler_proxy({"client_region": "ca"}, "EXAMPLE", request("plainkey")) == (None, [])
|
||||
|
||||
Reference in New Issue
Block a user