From e7886ba7637309c3006a417d9211185558f63805 Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 18:48:11 +0400 Subject: [PATCH 01/13] GH-27: Include the `skills` and `templates` in the build --- setup.cfg | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/setup.cfg b/setup.cfg index 8ff549f..38f6d88 100644 --- a/setup.cfg +++ b/setup.cfg @@ -50,6 +50,7 @@ classifiers = [options] packages = django_forbid + django_forbid.skills install_requires = Django>=2.1 geoip2 @@ -59,3 +60,6 @@ python_requires = >=3.6 package_dir = =src zip_safe = no + +[options.package_data] +django_forbid = templates/* From eb2760c68daafe229a34e502dde268d46def827c Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 18:49:54 +0400 Subject: [PATCH 02/13] GH-27: Change local build strategy for tests --- .github/workflows/tests.yml | 3 ++- tox.ini | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c4352a2..ca6b44b 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -51,7 +51,8 @@ jobs: - name: Install dependencies run: | pip install --upgrade pip - python -m pip install -e . + python setup.py sdist bdist_wheel + pip install dist/django_forbid-*.whl pip install tox tox-gh-actions - name: Run tests using tox run: tox -e ${{ matrix.env }} \ No newline at end of file diff --git a/tox.ini b/tox.ini index 9e52bed..84a0d23 100644 --- a/tox.ini +++ b/tox.ini @@ -15,5 +15,6 @@ deps = django21: django==2.1 -r{toxinidir}/tests/requirements.txt commands = - pip install -e . + python setup.py sdist bdist_wheel + pip install dist/django_forbid-*.whl pytest \ No newline at end of file From 387f861622c08ae5534d23e28ce39a7a37439f2a Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 18:50:56 +0400 Subject: [PATCH 03/13] Ignore `build` and `dist` directories --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index f3c3919..40e7d85 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,16 @@ +# caches .idea .tox .pytest_cache *.egg-info __pycache__ +# docs docs/node_modules docs/package-lock.json docs/.vitepress/cache docs/.vitepress/dist + +# build +build +dist From 50ef4f710eade29b589395eb0b5adb2d7e0987ef Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 18:53:07 +0400 Subject: [PATCH 04/13] Upgrade the version to `0.1.1` --- src/django_forbid/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/django_forbid/__init__.py b/src/django_forbid/__init__.py index 3dc1f76..485f44a 100644 --- a/src/django_forbid/__init__.py +++ b/src/django_forbid/__init__.py @@ -1 +1 @@ -__version__ = "0.1.0" +__version__ = "0.1.1" From 7114e398530bb7d67967b7a0bc71f02b68b95883 Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 19:10:51 +0400 Subject: [PATCH 05/13] Fix the deprecation warning --- setup.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 38f6d88..becbb48 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,7 +26,7 @@ keywords = detection django-forbid license = MIT -license_file = LICENSE +license_files = LICENSE platforms = unix, linux, osx, win32 classifiers = Operating System :: OS Independent From 7883b265d83a32dac96492fe1e10e15bf94fe8ee Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 19:16:18 +0400 Subject: [PATCH 06/13] Deploy docs only when PR is merged with master --- .github/workflows/docs.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index bfb8063..3a9b717 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,8 +3,6 @@ name: docs on: push: branches: [ master ] - pull_request: - branches: [ master ] jobs: deploy: From 52e50281dbc262656bc7b14204b325f37bb29dd5 Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 19:46:10 +0400 Subject: [PATCH 07/13] Include `templates` in the packages --- setup.cfg | 4 +--- src/django_forbid/templates/__init__.py | 0 2 files changed, 1 insertion(+), 3 deletions(-) create mode 100644 src/django_forbid/templates/__init__.py diff --git a/setup.cfg b/setup.cfg index becbb48..95c702c 100644 --- a/setup.cfg +++ b/setup.cfg @@ -51,6 +51,7 @@ classifiers = packages = django_forbid django_forbid.skills + django_forbid.templates install_requires = Django>=2.1 geoip2 @@ -60,6 +61,3 @@ python_requires = >=3.6 package_dir = =src zip_safe = no - -[options.package_data] -django_forbid = templates/* diff --git a/src/django_forbid/templates/__init__.py b/src/django_forbid/templates/__init__.py new file mode 100644 index 0000000..e69de29 From 39892bf9be82bc8ada79d0af9452e4a8ff227faf Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 20:49:51 +0400 Subject: [PATCH 08/13] Change the building tool --- .github/workflows/tests.yml | 3 +-- build.sh | 8 ++++++++ tox.ini | 3 +-- 3 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 build.sh diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index ca6b44b..5e4aedc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -51,8 +51,7 @@ jobs: - name: Install dependencies run: | pip install --upgrade pip - python setup.py sdist bdist_wheel - pip install dist/django_forbid-*.whl + sh build.sh pip install tox tox-gh-actions - name: Run tests using tox run: tox -e ${{ matrix.env }} \ No newline at end of file diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..b7ad47e --- /dev/null +++ b/build.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +# last version of `build` supporting Python 3.6 +pip install build==0.9.0 + +# build the wheel and install it +WHEEL_NAME=$(python -m build | grep -Po "django_forbid-.*\.whl" | tail -n 1) +pip install dist/$WHEEL_NAME \ No newline at end of file diff --git a/tox.ini b/tox.ini index 84a0d23..eec138a 100644 --- a/tox.ini +++ b/tox.ini @@ -15,6 +15,5 @@ deps = django21: django==2.1 -r{toxinidir}/tests/requirements.txt commands = - python setup.py sdist bdist_wheel - pip install dist/django_forbid-*.whl + sh build.sh pytest \ No newline at end of file From 49b2f7c47ebcdfb0c3972893933700567f209013 Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 20:56:31 +0400 Subject: [PATCH 09/13] Add `sh` in externals allowlist --- tox.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/tox.ini b/tox.ini index eec138a..38ef4eb 100644 --- a/tox.ini +++ b/tox.ini @@ -14,6 +14,7 @@ deps = django32: django<3.3 django21: django==2.1 -r{toxinidir}/tests/requirements.txt +allowlist_externals = sh commands = sh build.sh pytest \ No newline at end of file From afa281bfd500d4c0d62b3a15dbab04ceb9bea2c9 Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 21:19:32 +0400 Subject: [PATCH 10/13] GH-27: Fix the `VERIFIED_TZ` session management --- src/django_forbid/skills/forbid_network.py | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/django_forbid/skills/forbid_network.py b/src/django_forbid/skills/forbid_network.py index e32c900..0f98b38 100644 --- a/src/django_forbid/skills/forbid_network.py +++ b/src/django_forbid/skills/forbid_network.py @@ -22,7 +22,17 @@ def erase_response_attributes(): for attr in response_attributes: request.session.pop(attr) + def forbidden_page(): + # Redirects to the FORBIDDEN_NET URL if set. + if Settings.has("OPTIONS.URL.FORBIDDEN_NET"): + return redirect(Settings.get("OPTIONS.URL.FORBIDDEN_NET")) + return HttpResponseForbidden() + + geoip2_tz = request.session.get("GEOIP2_TZ") + verified_tz = request.session.get("VERIFIED_TZ", "") + if any([ + verified_tz == geoip2_tz, # Checks if VPN is False or not set. not Settings.get("OPTIONS.VPN", False), # Checks if the request is an AJAX request. @@ -33,19 +43,19 @@ def erase_response_attributes(): ]): return self.get_response(request) + # Checks if GEOIP2_TZ and VERIFIED_TZ don't exist. + if all([verified_tz, geoip2_tz != "N/A"]): + return forbidden_page() + if all(map(request.session.has_key, ("GEOIP2_TZ", *response_attributes))): # Handles if the user's timezone differs from the # one determined by GeoIP API. If so, VPN is used. - verified_tz = request.session.get("VERIFIED_TZ") - geoip2_tz = request.session.get("GEOIP2_TZ") client_tz = request.POST.get("CLIENT_TZ", verified_tz) if geoip2_tz != "N/A" and client_tz != geoip2_tz: + request.session["VERIFIED_TZ"] = "" erase_response_attributes() - # Redirects to the FORBIDDEN_NET URL if set. - if Settings.has("OPTIONS.URL.FORBIDDEN_NET"): - return redirect(Settings.get("OPTIONS.URL.FORBIDDEN_NET")) - return HttpResponseForbidden() + return forbidden_page() # Restores the response from the session. response = HttpResponse(**{ From 733a69e025236ec6a39822a24677b90f689021f6 Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 21:19:56 +0400 Subject: [PATCH 11/13] GH-27: Fix the skills execution order --- src/django_forbid/middleware.py | 4 ++-- tests/test_network_middleware.py | 25 ++++++++++++------------- tests/test_primary_middleware.py | 25 +++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 15 deletions(-) diff --git a/src/django_forbid/middleware.py b/src/django_forbid/middleware.py index 9cc319c..d874000 100644 --- a/src/django_forbid/middleware.py +++ b/src/django_forbid/middleware.py @@ -3,9 +3,9 @@ from .skills.forbid_network import ForbidNetworkMiddleware __skills__ = ( - ForbidDeviceMiddleware, - ForbidLocationMiddleware, ForbidNetworkMiddleware, + ForbidLocationMiddleware, + ForbidDeviceMiddleware, ) diff --git a/tests/test_network_middleware.py b/tests/test_network_middleware.py index e859825..e2557ac 100644 --- a/tests/test_network_middleware.py +++ b/tests/test_network_middleware.py @@ -12,19 +12,16 @@ def skips(get_response, ip_address, ajax=False): return response.status_code == 200 -def forbids(get_response, ip_address): - detector = Detector(get_response) +def forbids_shared_session(detector, ip_address): response = detector.request_resource(ip_address) - assert response.status_code == 302 - response = detector.request_access() + if response.status_code == 302: + response = detector.request_access(ip_address) return response.status_code == 403 -def forbids_shared_session(detector, ip_address): - response = detector.request_resource(ip_address) - assert response.status_code == 302 - response = detector.request_access() - return response.status_code == 403 +def forbids(get_response, ip_address): + detector = Detector(get_response) + return forbids_shared_session(detector, ip_address) class Detector: @@ -36,13 +33,15 @@ def request_resource(self, ip_address=""): """Sends a request to the server to access a resource""" request = self.request.get() request.META["HTTP_X_FORWARDED_FOR"] = ip_address - get_response = ForbidLocationMiddleware(self.get_response) - return ForbidNetworkMiddleware(get_response)(request) + get_response = ForbidNetworkMiddleware(self.get_response) + return ForbidLocationMiddleware(get_response)(request) - def request_access(self): + def request_access(self, ip_address=""): """Simulates the request sent by the user browser to the server""" request = self.request.post({"CLIENT_TZ": "Europe/London"}) - return ForbidNetworkMiddleware(self.get_response)(request) + request.META["HTTP_X_FORWARDED_FOR"] = ip_address + get_response = ForbidNetworkMiddleware(self.get_response) + return ForbidLocationMiddleware(get_response)(request) def test_should_allow_all_when_no_config_provided(get_response): diff --git a/tests/test_primary_middleware.py b/tests/test_primary_middleware.py index 697401c..360e724 100644 --- a/tests/test_primary_middleware.py +++ b/tests/test_primary_middleware.py @@ -11,8 +11,10 @@ def forbids(get_response, request): response = ForbidMiddleware(get_response)(request) + client_ip = request.META["HTTP_X_FORWARDED_FOR"] if response.status_code == 302: request = wsgi.post({"CLIENT_TZ": "Europe/London"}) + request.META["HTTP_X_FORWARDED_FOR"] = client_ip response = ForbidMiddleware(get_response)(request) return response.status_code == 403 @@ -49,9 +51,32 @@ def test_should_forbid_users_when_country_in_territories_blacklist(get_response) @override_settings(DJANGO_FORBID={"COUNTRIES": ["GB"], "OPTIONS": {"VPN": True}}) def test_should_allow_users_when_country_in_countries_whitelist(get_response): + """Should allow access to users from countries in whitelist.""" for ip_address in IP.all: request.META["HTTP_X_FORWARDED_FOR"] = ip_address if ip_address == IP.ip_london: assert not forbids(get_response, request) continue assert forbids(get_response, request) + + +@override_settings(DJANGO_FORBID={"OPTIONS": {"VPN": True}}) +def test_should_allow_users_only_from_great_britain_with_shared_session(get_response): + """It should give access to the user from Great Britain when session is shared""" + # Get access from London + request.META["HTTP_X_FORWARDED_FOR"] = IP.ip_london + assert not forbids(get_response, request) + # Turn on VPN temporary + request.META["HTTP_X_FORWARDED_FOR"] = IP.ip_zurich + assert forbids(get_response, request) + request.META["HTTP_X_FORWARDED_FOR"] = IP.ip_cobain + assert forbids(get_response, request) + # Turn off VPN - back to London + request.META["HTTP_X_FORWARDED_FOR"] = IP.ip_london + assert not forbids(get_response, request) + # Turn on VPN temporary + request.META["HTTP_X_FORWARDED_FOR"] = IP.ip_cobain + assert forbids(get_response, request) + # Turn off VPN - back to London + request.META["HTTP_X_FORWARDED_FOR"] = IP.ip_london + assert not forbids(get_response, request) From 08c15c8f631f5216f24ac581be5e7c06b8cfb4a7 Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 21:22:15 +0400 Subject: [PATCH 12/13] GH-27: Include `templates` in a proper way --- MANIFEST.in | 1 + setup.cfg | 1 - src/django_forbid/templates/__init__.py | 0 3 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 MANIFEST.in delete mode 100644 src/django_forbid/templates/__init__.py diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..518140c --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include src/django_forbid/templates/*.html \ No newline at end of file diff --git a/setup.cfg b/setup.cfg index 95c702c..e9723da 100644 --- a/setup.cfg +++ b/setup.cfg @@ -51,7 +51,6 @@ classifiers = packages = django_forbid django_forbid.skills - django_forbid.templates install_requires = Django>=2.1 geoip2 diff --git a/src/django_forbid/templates/__init__.py b/src/django_forbid/templates/__init__.py deleted file mode 100644 index e69de29..0000000 From 3a62b51340dfcc5e98a80b5fa08c5e69a322fdbd Mon Sep 17 00:00:00 2001 From: Artyom Vancyan Date: Mon, 29 May 2023 21:33:06 +0400 Subject: [PATCH 13/13] Upgrade the version to `0.1.2` --- src/django_forbid/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/django_forbid/__init__.py b/src/django_forbid/__init__.py index 485f44a..b3f4756 100644 --- a/src/django_forbid/__init__.py +++ b/src/django_forbid/__init__.py @@ -1 +1 @@ -__version__ = "0.1.1" +__version__ = "0.1.2"