Skip to content

Commit

Permalink
Teste le format d'IP pour la page qui liste les membres utilisant la …
Browse files Browse the repository at this point in the history
…même IP (#6553)

Si on passe comme paramètre une adresse IP invalide, l'appel à
get_geo_location_from_ip() va lever une exception ValueError, qui est
désormais rattrapée.
  • Loading branch information
philippemilink authored Nov 1, 2023
1 parent 630f5e3 commit bfd9099
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 5 deletions.
9 changes: 8 additions & 1 deletion zds/member/tests/views/tests_moderation.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ def test_filter_member_ip(self):


class IpListingsTests(TestCase):
"""Test the member_from_ip function : listing users from a same IPV4/IPV6 address or same IPV6 network."""
"""Test the member_from_ip view: listing users from a same IPv4/IPv6 address or same IPv6 network."""

def setUp(self) -> None:
self.staff = StaffProfileFactory().user
Expand Down Expand Up @@ -600,6 +600,13 @@ def test_different_ipv6_network(self) -> None:
self.assertNotContains(response, self.user_ipv6_same_ip_2.user.username)
self.assertNotContains(response, self.user_ipv6_same_network.user.username)

def test_ip_page_invalid_ip(self) -> None:
self.client.force_login(self.staff)
for ip in ["foo", "340.340.340.340", "2402:4899:1c8a:d75a:"]:
with self.subTest(ip):
response = self.client.get(reverse(member_from_ip, args=[ip]))
self.assertEqual(response.status_code, 404)

def test_access_rights_to_ip_page_as_regular_user(self) -> None:
self.client.force_login(self.regular_user.user)
response = self.client.get(reverse(member_from_ip, args=["0.0.0.0"]))
Expand Down
19 changes: 15 additions & 4 deletions zds/member/views/moderation.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required, permission_required
from django.core.exceptions import PermissionDenied
from django.core.exceptions import PermissionDenied, ValidationError
from django.core.validators import validate_ipv46_address
from django.db import transaction
from django.http import Http404, HttpResponseBadRequest
from django.shortcuts import redirect, render, get_object_or_404
Expand All @@ -29,7 +30,17 @@
@login_required
@permission_required("member.change_profile", raise_exception=True)
def member_from_ip(request, ip_address):
"""List users connected from a particular IP, and an IPV6 subnetwork."""
"""List users connected from a particular IP, and an IPv6 subnetwork."""

# If we don't check if the ip_address has a valid format, two things can
# happen:
# - the list of members with this IP will be empty (that's fine)
# - the call to get_geo_location_from_ip() will raise a ValueError, which
# in production will turn into an error 500 (which is not fine)
try:
validate_ipv46_address(ip_address)
except ValidationError:
raise Http404(_("Mauvais format d'adresse IP"))

members = Profile.objects.filter(last_ip_address=ip_address).order_by("-last_visit")
context_data = {
Expand All @@ -38,9 +49,9 @@ def member_from_ip(request, ip_address):
"ip_location": get_geo_location_from_ip(ip_address),
}

if ":" in ip_address: # Check if it's an IPV6
if ":" in ip_address: # Check if it's an IPv6
network_ip = ipaddress.ip_network(ip_address + "/64", strict=False).network_address # Get the network / block
# Remove the additional ":" at the end of the network adresse, so we can filter the IP adresses on this network
# Remove the additional ":" at the end of the network address, so we can filter the IP adresses on this network
network_ip = str(network_ip)[:-1]
network_members = Profile.objects.filter(last_ip_address__startswith=network_ip).order_by("-last_visit")
context_data["network_members"] = network_members
Expand Down

0 comments on commit bfd9099

Please sign in to comment.