From 8b0074f82013c131edc61368e0828893debae043 Mon Sep 17 00:00:00 2001 From: Russell Osborne Date: Wed, 25 Oct 2023 10:49:43 -0400 Subject: [PATCH] Changes to use python-ipware As django-ipware is being deprecated in favor of python-ipware, and the fact they share the same import namespace any project python-ipware Signed-off-by: Russell Osborne --- django_structlog/middlewares/request.py | 22 ++++++++++++++++++-- pyproject.toml | 2 +- requirements/local-base.txt | 2 +- test_app/tests/middlewares/test_request.py | 24 ++++++++++++++++++++++ 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/django_structlog/middlewares/request.py b/django_structlog/middlewares/request.py index 538ea209..eaae7e18 100644 --- a/django_structlog/middlewares/request.py +++ b/django_structlog/middlewares/request.py @@ -19,6 +19,25 @@ def get_request_header(request, header_key, meta_key): return request.META.get(meta_key) +def get_client_ip(request): + from ipware import IpWare + + # Instantiate IpWare with default values + ipw = IpWare() + + # Get the request headers for Django 4.0 + if hasattr(request, "headers"): + meta = request.headers + + # Get the request headers for Django < 4 + else: + meta = request.META + + # Get the client IP + ip, _ = ipw.get_client_ip(meta) + + # Cast IP to string + return str(ip), _ class BaseRequestMiddleWare: def __init__(self, get_response): @@ -57,9 +76,8 @@ def handle_response(self, request, response): ) structlog.contextvars.clear_contextvars() - def prepare(self, request): - from ipware import get_client_ip + def prepare(self, request): request_id = get_request_header( request, "x-request-id", "HTTP_X_REQUEST_ID" ) or str(uuid.uuid4()) diff --git a/pyproject.toml b/pyproject.toml index 0a44f895..d6251a78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,7 +16,7 @@ build-backend = "setuptools.build_meta" "django>=3.2", "structlog>=21.4.0", "asgiref>=3.6.0", - "django-ipware", + "python-ipware", ] classifiers = [ "Development Status :: 5 - Production/Stable", diff --git a/requirements/local-base.txt b/requirements/local-base.txt index 165a5ab6..907b40c7 100644 --- a/requirements/local-base.txt +++ b/requirements/local-base.txt @@ -17,7 +17,7 @@ coreapi==2.3.3 # https://github.com/core-api/python-client structlog==23.2.0 colorama==0.4.6 -django-ipware==5.0.1 +python-ipware==1.0.5 # https://github.com/un33k/python-ipware Werkzeug==3.0.0 # https://github.com/pallets/werkzeug ipdb==0.13.13 # https://github.com/gotcha/ipdb diff --git a/test_app/tests/middlewares/test_request.py b/test_app/tests/middlewares/test_request.py index a76b6256..d62f9e03 100644 --- a/test_app/tests/middlewares/test_request.py +++ b/test_app/tests/middlewares/test_request.py @@ -742,6 +742,30 @@ def get_response(_response): self.assertNotIn("user_id", record.msg) self.assertEqual(x_correlation_id, record.msg["correlation_id"]) + def test_should_log_remote_ip(self): + mock_response = Mock() + mock_response.status_code = 200 + x_forwarded_for = "123.123.123.1" + + def get_response(_response): + with self.assertLogs(__name__, logging.INFO) as log_results: + self.logger.info("hello") + self.log_results = log_results + return mock_response + + request = RequestFactory(HTTP_X_FORWARDED_FOR=x_forwarded_for).get("/foo") + + middleware = middlewares.RequestMiddleware(get_response) + middleware(request) + + self.assertEqual(1, len(self.log_results.records)) + record = self.log_results.records[0] + + self.assertEqual("INFO", record.levelname) + self.assertIn("request_id", record.msg) + self.assertNotIn("user_id", record.msg) + self.assertEqual(x_forwarded_for, record.msg["ip"]) + class TestRequestMiddlewareRouter(TestCase): async def test_async(self):