Skip to content

Commit 4c3ee0b

Browse files
Added remote port (#671)
1 parent 22dcbc4 commit 4c3ee0b

File tree

7 files changed

+56
-3
lines changed

7 files changed

+56
-3
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,4 @@ venv.bak/
8080

8181
### JetBrains
8282
.idea/
83+
.vscode/

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
## Next Release
44

5+
#### Improvements
6+
- feat: Added `LogEntry.remote_port` field. ([#671](https://github.com/jazzband/django-auditlog/pull/671))
7+
58
#### Fixes
69

710
- Fixed a problem when setting `Value(None)` in `JSONField` ([#646](https://github.com/jazzband/django-auditlog/pull/646))

auditlog/context.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@
1313

1414

1515
@contextlib.contextmanager
16-
def set_actor(actor, remote_addr=None):
16+
def set_actor(actor, remote_addr=None, remote_port=None):
1717
"""Connect a signal receiver with current user attached."""
1818
# Initialize thread local storage
1919
context_data = {
2020
"signal_duid": ("set_actor", time.time()),
2121
"remote_addr": remote_addr,
22+
"remote_port": remote_port,
2223
}
2324
auditlog_value.set(context_data)
2425

@@ -63,6 +64,7 @@ def _set_actor(user, sender, instance, signal_duid, **kwargs):
6364
instance.actor = user
6465

6566
instance.remote_addr = auditlog["remote_addr"]
67+
instance.remote_port = auditlog["remote_port"]
6668

6769

6870
@contextlib.contextmanager

auditlog/middleware.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Optional
2+
13
from django.conf import settings
24
from django.contrib.auth import get_user_model
35

@@ -36,6 +38,17 @@ def _get_remote_addr(request):
3638

3739
return remote_addr
3840

41+
@staticmethod
42+
def _get_remote_port(request) -> Optional[int]:
43+
remote_port = request.headers.get("X-Forwarded-Port", "")
44+
45+
try:
46+
remote_port = int(remote_port)
47+
except ValueError:
48+
remote_port = None
49+
50+
return remote_port
51+
3952
@staticmethod
4053
def _get_actor(request):
4154
user = getattr(request, "user", None)
@@ -45,9 +58,10 @@ def _get_actor(request):
4558

4659
def __call__(self, request):
4760
remote_addr = self._get_remote_addr(request)
61+
remote_port = self._get_remote_port(request)
4862
user = self._get_actor(request)
4963

5064
set_cid(request)
5165

52-
with set_actor(actor=user, remote_addr=remote_addr):
66+
with set_actor(actor=user, remote_addr=remote_addr, remote_port=remote_port):
5367
return self.get_response(request)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
from django.db import migrations, models
2+
3+
4+
class Migration(migrations.Migration):
5+
dependencies = [
6+
("auditlog", "0015_alter_logentry_changes"),
7+
]
8+
9+
operations = [
10+
migrations.AddField(
11+
model_name="logentry",
12+
name="remote_port",
13+
field=models.PositiveIntegerField(
14+
blank=True, null=True, verbose_name="remote port"
15+
),
16+
),
17+
]

auditlog/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,9 @@ class Action:
373373
remote_addr = models.GenericIPAddressField(
374374
blank=True, null=True, verbose_name=_("remote address")
375375
)
376+
remote_port = models.PositiveIntegerField(
377+
blank=True, null=True, verbose_name=_("remote port")
378+
)
376379
timestamp = models.DateTimeField(
377380
default=django_timezone.now,
378381
db_index=True,

auditlog_tests/tests.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,13 @@ def test_get_remote_addr(self):
585585
self.middleware._get_remote_addr(request), expected_remote_addr
586586
)
587587

588+
def test_get_remote_port(self):
589+
headers = {
590+
"HTTP_X_FORWARDED_PORT": "12345",
591+
}
592+
request = self.factory.get("/", **headers)
593+
self.assertEqual(self.middleware._get_remote_port(request), 12345)
594+
588595
def test_cid(self):
589596
header = str(settings.AUDITLOG_CID_HEADER).lstrip("HTTP_").replace("_", "-")
590597
header_meta = "HTTP_" + header.upper().replace("-", "_")
@@ -622,9 +629,10 @@ def test_set_actor_anonymous_request(self):
622629
The remote address will be set even when there is no actor
623630
"""
624631
remote_addr = "123.213.145.99"
632+
remote_port = 12345
625633
actor = None
626634

627-
with set_actor(actor=actor, remote_addr=remote_addr):
635+
with set_actor(actor=actor, remote_addr=remote_addr, remote_port=remote_port):
628636
obj = SimpleModel.objects.create(text="I am not difficult.")
629637

630638
history = obj.history.get()
@@ -633,6 +641,11 @@ def test_set_actor_anonymous_request(self):
633641
remote_addr,
634642
msg=f"Remote address is {remote_addr}",
635643
)
644+
self.assertEqual(
645+
history.remote_port,
646+
remote_port,
647+
msg=f"Remote port is {remote_port}",
648+
)
636649
self.assertIsNone(history.actor, msg="Actor is `None` for anonymous user")
637650

638651
def test_get_actor(self):

0 commit comments

Comments
 (0)