-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
284 additions
and
36 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
__version__ = "0.0.3" | ||
__version__ = "0.0.4" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import json | ||
import re | ||
|
||
from django.conf import settings | ||
from django.http import HttpResponse | ||
from django.http import HttpResponseForbidden | ||
from django.shortcuts import redirect | ||
from django.shortcuts import render | ||
|
||
|
||
def detect_vpn(get_response, request): | ||
response_attributes = ("content", "charset", "status", "reason") | ||
|
||
def erase_response_attributes(): | ||
for attr in response_attributes: | ||
request.session.pop(attr) | ||
|
||
if any([ | ||
# The session key is checked to avoid | ||
# redirect loops in development mode. | ||
not request.session.has_key("tz"), | ||
# Checks if FORBID_VPN is False or not set. | ||
not getattr(settings, "FORBID_VPN", False), | ||
# Checks if the request is an AJAX request. | ||
not re.search( | ||
r"\w+\/(?:html|xhtml\+xml|xml)", | ||
request.META.get("HTTP_ACCEPT"), | ||
), | ||
]): | ||
return get_response(request) | ||
|
||
if all(map(request.session.has_key, ("tz", *response_attributes))): | ||
# Handles if the user's timezone differs from the | ||
# one determined by GeoIP API. If so, VPN is used. | ||
if request.POST.get("timezone", "N/A") != request.session.get("tz"): | ||
erase_response_attributes() | ||
if hasattr(settings, "FORBIDDEN_URL"): | ||
return redirect(settings.FORBIDDEN_URL) | ||
return HttpResponseForbidden() | ||
|
||
# Restores the response from the session. | ||
response = HttpResponse(**{attr: request.session.get(attr) for attr in response_attributes}) | ||
if hasattr(response, "headers"): | ||
response.headers = json.loads(request.session.get("headers")) | ||
erase_response_attributes() | ||
return response | ||
|
||
# Gets the response and saves attributes in the session to restore it later. | ||
response = get_response(request) | ||
if hasattr(response, "headers"): | ||
# In older versions of Django, HttpResponse does not have headers attribute. | ||
request.session["headers"] = json.dumps(dict(response.headers)) | ||
request.session["content"] = response.content.decode(response.charset) | ||
request.session["charset"] = response.charset | ||
request.session["status"] = response.status_code | ||
request.session["reason"] = response.reason_phrase | ||
|
||
return render(request, "timezone.html", status=302) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<head> | ||
<link rel="icon" href="data:image/x-icon;base64,AAABAAEAAQEAAAEAIAAwAAAAF | ||
gAAACgAAAABAAAAAgAAAAEAIAAAAAAABAAAAMMOAADDDgAAAAAAAAAAAAD/////AAAAAA=="> | ||
</head> | ||
<form id="detector" method="post"> | ||
{% csrf_token %} | ||
</form> | ||
<script type="text/javascript"> | ||
(() => { | ||
const form = document.getElementById("detector"); | ||
const input = document.createElement("input"); | ||
input.setAttribute("type", "hidden"); | ||
input.setAttribute("name", "timezone"); | ||
input.setAttribute("value", Intl.DateTimeFormat().resolvedOptions().timeZone); | ||
form.action = window.location.href; | ||
form.appendChild(input); | ||
form.submit(); | ||
})(); | ||
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,82 +1,100 @@ | ||
from django.test import RequestFactory | ||
from django.test import override_settings | ||
|
||
from django_forbid.access import grants_access | ||
|
||
factory = RequestFactory() | ||
request = factory.get("/") | ||
request.session = {} | ||
|
||
LOCALHOST = "localhost" | ||
IP_LOCAL1 = "0.0.0.0" | ||
IP_LOCAL2 = "127.0.0.1" | ||
IP_LONDON = "212.102.63.59" | ||
|
||
|
||
def test_access_without_configuration(): | ||
"""If no configuration is provided, access is granted everywhere.""" | ||
assert grants_access("doesnt-matter") | ||
assert grants_access(request, LOCALHOST) | ||
|
||
|
||
@override_settings(FORBID_VPN=True) | ||
def test_access_forbid_vpn(): | ||
"""If VPN detection is enabled, access is granted everywhere.""" | ||
assert grants_access(request, LOCALHOST) | ||
|
||
|
||
@override_settings(WHITELIST_COUNTRIES=["US"], DEBUG=True) | ||
def test_access_from_localhost_development_mode(): | ||
"""In development mode, access is granted from localhost.""" | ||
assert grants_access("127.0.0.1") | ||
assert grants_access("localhost") | ||
assert grants_access(request, IP_LOCAL1) | ||
assert grants_access(request, IP_LOCAL2) | ||
assert grants_access(request, LOCALHOST) | ||
|
||
|
||
@override_settings(WHITELIST_COUNTRIES=["US"]) | ||
def test_access_from_localhost_production_mode(): | ||
"""In production mode, access is not granted from localhost.""" | ||
assert not grants_access("127.0.0.1") | ||
assert not grants_access("localhost") | ||
assert not grants_access(request, IP_LOCAL1) | ||
assert not grants_access(request, IP_LOCAL2) | ||
assert not grants_access(request, LOCALHOST) | ||
|
||
|
||
@override_settings(WHITELIST_COUNTRIES=["GB"]) | ||
def test_access_from_gb_when_gb_in_countries_whitelist(): | ||
"""Access is granted from GB when GB is in the counties' whitelist.""" | ||
assert grants_access("212.102.63.59") | ||
assert grants_access(request, IP_LONDON) | ||
|
||
|
||
@override_settings(WHITELIST_COUNTRIES=["US"]) | ||
def test_access_from_gb_when_gb_not_in_countries_whitelist(): | ||
"""Access is not granted from GB when GB is not in the counties' whitelist.""" | ||
assert not grants_access("212.102.63.59") | ||
assert not grants_access(request, IP_LONDON) | ||
|
||
|
||
@override_settings(WHITELIST_TERRITORIES=["EU"]) | ||
def test_access_from_gb_when_eu_in_continent_whitelist(): | ||
"""Access is granted from GB when EU is in the continents' whitelist.""" | ||
assert grants_access("212.102.63.59") | ||
assert grants_access(request, IP_LONDON) | ||
|
||
|
||
@override_settings(WHITELIST_TERRITORIES=["US"]) | ||
def test_access_from_gb_when_gb_not_in_continent_whitelist(): | ||
"""Access is not granted from GB when EU is not in the continents' whitelist.""" | ||
assert not grants_access("212.102.63.59") | ||
assert not grants_access(request, IP_LONDON) | ||
|
||
|
||
@override_settings(FORBIDDEN_COUNTRIES=["GB"]) | ||
def test_access_from_gb_when_gb_in_forbidden_countries(): | ||
"""Access is not granted from GB when GB is in the forbidden list.""" | ||
assert not grants_access("212.102.63.59") | ||
assert not grants_access(request, IP_LONDON) | ||
|
||
|
||
@override_settings(FORBIDDEN_COUNTRIES=["RU"]) | ||
def test_access_from_gb_when_gb_not_in_forbidden_countries(): | ||
"""Access is granted from GB when GB is not in the forbidden list.""" | ||
assert grants_access("212.102.63.59") | ||
assert grants_access(request, IP_LONDON) | ||
|
||
|
||
@override_settings(FORBIDDEN_TERRITORIES=["EU"]) | ||
def test_access_from_gb_when_eu_in_forbidden_territories(): | ||
"""Access is not granted from GB when EU is in the forbidden list.""" | ||
assert not grants_access("212.102.63.59") | ||
assert not grants_access(request, IP_LONDON) | ||
|
||
|
||
@override_settings(FORBIDDEN_TERRITORIES=["AS"]) | ||
def test_access_from_gb_when_eu_not_in_forbidden_territories(): | ||
"""Access is granted from GB when EU is not in the forbidden list.""" | ||
assert grants_access("212.102.63.59") | ||
assert grants_access(request, IP_LONDON) | ||
|
||
|
||
@override_settings(WHITELIST_TERRITORIES=["EU"], FORBIDDEN_COUNTRIES=["GB"]) | ||
def test_mix_config_access_from_gb_when_eu_in_whitelist_but_gb_is_forbidden(): | ||
"""Access is not granted from GB when EU is in the whitelist but GB is forbidden.""" | ||
assert not grants_access("212.102.63.59") | ||
assert not grants_access(request, IP_LONDON) | ||
|
||
|
||
@override_settings(WHITELIST_COUNTRIES=["GB"], FORBIDDEN_COUNTRIES=["GB"]) | ||
def test_mix_config_access_from_gb_when_gb_in_both_lists(): | ||
"""Access is not granted from GB when GB is in both lists.""" | ||
assert not grants_access("212.102.63.59") | ||
assert not grants_access(request, IP_LONDON) |
Oops, something went wrong.