From 06708efb8d75103abe672949ca547b5a8175395f Mon Sep 17 00:00:00 2001 From: Sarthak5598 Date: Sat, 10 Aug 2024 01:38:08 +0530 Subject: [PATCH 1/6] add ability to block ip addresses that are submitting spam #1938 --- blt/middleware/count_ip_requests.py | 24 ++++++++++ blt/middleware/ip_restrict.py | 70 ++++++++++++++++++++++++++++ blt/settings.py | 4 +- website/admin.py | 54 ++++++++++++++++++++- website/migrations/0125_blockedip.py | 44 +++++++++++++++++ website/models.py | 12 +++++ 6 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 blt/middleware/count_ip_requests.py create mode 100644 blt/middleware/ip_restrict.py create mode 100644 website/migrations/0125_blockedip.py diff --git a/blt/middleware/count_ip_requests.py b/blt/middleware/count_ip_requests.py new file mode 100644 index 000000000..93b6fde92 --- /dev/null +++ b/blt/middleware/count_ip_requests.py @@ -0,0 +1,24 @@ +from django.utils.deprecation import MiddlewareMixin +from user_agents import parse + +from website.models import IP + + +class MonitorIPMiddleware(MiddlewareMixin): + def process_request(self, request): + x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") + if x_forwarded_for: + ip = x_forwarded_for.split(",")[0].strip() + else: + ip = request.META.get("REMOTE_ADDR") + + user_agent = request.META.get("HTTP_USER_AGENT", "") + parsed_agent = parse(user_agent) + + if ip: + ip_record = IP.objects.filter(address=ip).first() + + if ip_record: + ip_record.user_agent_string = parsed_agent + ip_record.count += 1 + ip_record.save() diff --git a/blt/middleware/ip_restrict.py b/blt/middleware/ip_restrict.py new file mode 100644 index 000000000..4eb6e629b --- /dev/null +++ b/blt/middleware/ip_restrict.py @@ -0,0 +1,70 @@ +import ipaddress + +from django.core.cache import cache +from django.http import HttpResponseForbidden +from user_agents import parse + +from website.models import BlockedIP + + +class IPRestrictMiddleware: + """ + Middleware to restrict access based on client IP addresses. + """ + + def __init__(self, get_response): + self.get_response = get_response + + def blocked_ips(self): + blocked_ips = cache.get("blocked_ips") + if blocked_ips is None: + blocked_addresses = BlockedIP.objects.values_list("address", flat=True) + blocked_ips = set(blocked_addresses) + cache.set("blocked_ips", blocked_ips, timeout=86400) + return blocked_ips + + def blocked_ip_ranges(self): + blocked_ip_ranges = cache.get("blocked_ip_ranges") + if blocked_ip_ranges is None: + blocked_ip_start = BlockedIP.objects.values_list("address_range_start", flat=True) + blocked_ip_end = BlockedIP.objects.values_list("address_range_end", flat=True) + blocked_ip_ranges = list(zip(blocked_ip_start, blocked_ip_end)) + cache.set("blocked_ip_ranges", blocked_ip_ranges, timeout=86400) + return blocked_ip_ranges + + def ip_in_range(self, ip, ip_ranges): + ip_int = int(ipaddress.IPv4Address(ip)) + for start, end in ip_ranges: + start_int = int(ipaddress.IPv4Address(start)) + end_int = int(ipaddress.IPv4Address(end)) + if start_int <= ip_int <= end_int: + return True + return False + + def blocked_agents(self): + blocked_agents = cache.get("blocked_agents") + if blocked_agents is None: + blocked_user_agents = BlockedIP.objects.values_list("user_agent_string", flat=True) + blocked_agents = set(blocked_user_agents) + cache.set("blocked_agents", blocked_agents, timeout=86400) + return blocked_agents + + def __call__(self, request): + ip = request.META.get("REMOTE_ADDR") + user_agent = request.META.get("HTTP_USER_AGENT", "") + parsed_agent = parse(user_agent) + + if ip: + if ip in self.blocked_ips(): + return HttpResponseForbidden( + "Your IP address is restricted from accessing this site." + ) + blocked_ip_ranges = self.blocked_ip_ranges() + if self.ip_in_range(ip, blocked_ip_ranges): + return HttpResponseForbidden( + "Your IP address is restricted from accessing this site." + ) + if parsed_agent and parsed_agent in self.blocked_agents(): + return HttpResponseForbidden("Your IP address is restricted from accessing this site.") + + return self.get_response(request) diff --git a/blt/settings.py b/blt/settings.py index 3a5917db7..d5d208b00 100644 --- a/blt/settings.py +++ b/blt/settings.py @@ -118,6 +118,8 @@ "django.middleware.security.SecurityMiddleware", "whitenoise.middleware.WhiteNoiseMiddleware", "tz_detect.middleware.TimezoneMiddleware", + "blt.middleware.ip_restrict.IPRestrictMiddleware", + "blt.middleware.count_ip_requests.MonitorIPMiddleware", ) TESTING = len(sys.argv) > 1 and sys.argv[1] == "test" @@ -360,7 +362,7 @@ }, }, } - +DEFAULT_FILE_STORAGE = "django.core.files.storage.FileSystemStorage" USERS_AVATAR_PATH = "avatars" AVATAR_PATH = os.path.join(MEDIA_ROOT, USERS_AVATAR_PATH) diff --git a/website/admin.py b/website/admin.py index cd737bd4b..7baa633e1 100644 --- a/website/admin.py +++ b/website/admin.py @@ -7,6 +7,7 @@ from website.models import ( IP, Bid, + BlockedIP, ChatBotLog, Company, CompanyAdmin, @@ -276,9 +277,49 @@ def issue_description(self, obj): return obj.issue.description +def block_ip(modeladmin, request, queryset): + for ip in queryset: + BlockedIP.objects.create(address=ip.address, count=ip.count) + modeladmin.message_user(request, "Selected IPs have been blocked successfully.") + + +block_ip.short_description = "Block selected IPs" + + +def unblock_ip(modeladmin, request, queryset): + for ip in queryset: + BlockedIP.objects.filter(ip=ip.address).delete() + modeladmin.message_user(request, "Selected IPs have ben unblocked successfully") + + +unblock_ip.short_description = "Unblock selected IPs" + + +def block_user_agent(modeladmin, request, queryset): + for ip in queryset: + BlockedIP.objects.create(user_agent_string=ip.user_agent_string) + + modeladmin.message_user(request, "Selected UserAgent have been blocked successfully.") + + +block_user_agent.short_description = "Block selected UserAgent" + + +def unblock_user_agent(modeladmin, request, queryset): + for ip in queryset: + BlockedIP.objects.filter(user_agent_string=ip.user_agent_string).delete() + + modeladmin.message_user(request, "Selected UserAgent have been unblocked successfully.") + + +unblock_user_agent.short_description = "Unblock selected UserAgent" + + class IPAdmin(admin.ModelAdmin): list_display = ("id", "address", "user", "issuenumber", "created", "agent", "path") + actions = [block_ip, unblock_ip, block_user_agent, unblock_user_agent] + class MonitorAdmin(admin.ModelAdmin): list_display = ( @@ -305,6 +346,17 @@ class SuggestionVotesAdmin(admin.ModelAdmin): list_display = ("user", "suggestion", "up_vote", "down_vote") +class BlockedIPAdmin(admin.ModelAdmin): + list_display = ( + "address", + "reason_for_block", + "address_range_start", + "address_range_end", + "user_agent_string", + "count", + ) + + class ProjectAdmin(admin.ModelAdmin): list_display = ( "id", @@ -315,7 +367,6 @@ class ProjectAdmin(admin.ModelAdmin): "created", "modified", ) - search_fields = ["name", "description", "slug"] @@ -338,6 +389,7 @@ class ProjectAdmin(admin.ModelAdmin): admin.site.register(IssueScreenshot, IssueScreenshotAdmin) admin.site.register(HuntPrize) admin.site.register(ChatBotLog, ChatBotLogAdmin) +admin.site.register(BlockedIP, BlockedIPAdmin) admin.site.register(Suggestion, SuggestionAdmin) admin.site.register(SuggestionVotes, SuggestionVotesAdmin) diff --git a/website/migrations/0125_blockedip.py b/website/migrations/0125_blockedip.py new file mode 100644 index 000000000..fe06eb98c --- /dev/null +++ b/website/migrations/0125_blockedip.py @@ -0,0 +1,44 @@ +# Generated by Django 5.1 on 2024-08-09 19:59 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("website", "0124_company_tags_domain_tags_project_tags_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="BlockedIP", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("address", models.GenericIPAddressField(blank=True, null=True)), + ( + "reason_for_block", + models.TextField(blank=True, max_length=255, null=True), + ), + ( + "address_range_start", + models.GenericIPAddressField(blank=True, null=True), + ), + ( + "address_range_end", + models.GenericIPAddressField(blank=True, null=True), + ), + ( + "user_agent_string", + models.CharField(blank=True, default="", max_length=255, null=True), + ), + ("count", models.IntegerField(default=1)), + ], + ), + ] diff --git a/website/models.py b/website/models.py index 20b998ba5..6eb207505 100644 --- a/website/models.py +++ b/website/models.py @@ -786,3 +786,15 @@ class BaconToken(models.Model): def __str__(self): return f"{self.user.username} - {self.amount} BACON" + + +class BlockedIP(models.Model): + address = models.GenericIPAddressField(null=True, blank=True) + reason_for_block = models.TextField(blank=True, null=True, max_length=255) + address_range_start = models.GenericIPAddressField(null=True, blank=True) + address_range_end = models.GenericIPAddressField(null=True, blank=True) + user_agent_string = models.CharField(max_length=255, default="", null=True, blank=True) + count = models.IntegerField(default=1) + + def __str__(self): + return f"user agent : {self.user_agent_string} | IP : {self.address}" From 411b65dde9e4cdd9105868def708eb48671be151 Mon Sep 17 00:00:00 2001 From: Sarthak5598 Date: Sat, 10 Aug 2024 01:51:05 +0530 Subject: [PATCH 2/6] migration --- ...merge_0125_activitylog_timelog_0125_blockedip.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py diff --git a/website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py b/website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py new file mode 100644 index 000000000..f9cae7599 --- /dev/null +++ b/website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py @@ -0,0 +1,13 @@ +# Generated by Django 5.1 on 2024-08-09 20:18 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("website", "0125_activitylog_timelog"), + ("website", "0125_blockedip"), + ] + + operations = [] From a9225a5390bf24c53f9d55efb5f53badc42a0bca Mon Sep 17 00:00:00 2001 From: Sarthak5598 Date: Mon, 12 Aug 2024 23:00:03 +0530 Subject: [PATCH 3/6] added changes! --- blt/middleware/count_ip_requests.py | 24 ---- blt/middleware/ip_restrict.py | 132 +++++++++++++----- blt/settings.py | 1 - website/admin.py | 33 +++-- ...0125_activitylog_timelog_0125_blockedip.py | 1 - .../0127_blocked_delete_blockedip.py | 41 ++++++ website/models.py | 24 +++- 7 files changed, 183 insertions(+), 73 deletions(-) delete mode 100644 blt/middleware/count_ip_requests.py create mode 100644 website/migrations/0127_blocked_delete_blockedip.py diff --git a/blt/middleware/count_ip_requests.py b/blt/middleware/count_ip_requests.py deleted file mode 100644 index 93b6fde92..000000000 --- a/blt/middleware/count_ip_requests.py +++ /dev/null @@ -1,24 +0,0 @@ -from django.utils.deprecation import MiddlewareMixin -from user_agents import parse - -from website.models import IP - - -class MonitorIPMiddleware(MiddlewareMixin): - def process_request(self, request): - x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") - if x_forwarded_for: - ip = x_forwarded_for.split(",")[0].strip() - else: - ip = request.META.get("REMOTE_ADDR") - - user_agent = request.META.get("HTTP_USER_AGENT", "") - parsed_agent = parse(user_agent) - - if ip: - ip_record = IP.objects.filter(address=ip).first() - - if ip_record: - ip_record.user_agent_string = parsed_agent - ip_record.count += 1 - ip_record.save() diff --git a/blt/middleware/ip_restrict.py b/blt/middleware/ip_restrict.py index 4eb6e629b..356ffa6c2 100644 --- a/blt/middleware/ip_restrict.py +++ b/blt/middleware/ip_restrict.py @@ -4,67 +4,131 @@ from django.http import HttpResponseForbidden from user_agents import parse -from website.models import BlockedIP +from website.models import IP, Blocked class IPRestrictMiddleware: """ - Middleware to restrict access based on client IP addresses. + Middleware to restrict access based on client IP addresses and user agents. """ def __init__(self, get_response): self.get_response = get_response def blocked_ips(self): + """ + Retrieve blocked IP addresses from cache or database. + """ blocked_ips = cache.get("blocked_ips") if blocked_ips is None: - blocked_addresses = BlockedIP.objects.values_list("address", flat=True) - blocked_ips = set(blocked_addresses) + blocked_addresses = Blocked.objects.values_list("address", flat=True) + blocked_ips = set(filter(None, blocked_addresses)) cache.set("blocked_ips", blocked_ips, timeout=86400) return blocked_ips - def blocked_ip_ranges(self): - blocked_ip_ranges = cache.get("blocked_ip_ranges") - if blocked_ip_ranges is None: - blocked_ip_start = BlockedIP.objects.values_list("address_range_start", flat=True) - blocked_ip_end = BlockedIP.objects.values_list("address_range_end", flat=True) - blocked_ip_ranges = list(zip(blocked_ip_start, blocked_ip_end)) - cache.set("blocked_ip_ranges", blocked_ip_ranges, timeout=86400) - return blocked_ip_ranges - - def ip_in_range(self, ip, ip_ranges): - ip_int = int(ipaddress.IPv4Address(ip)) - for start, end in ip_ranges: - start_int = int(ipaddress.IPv4Address(start)) - end_int = int(ipaddress.IPv4Address(end)) - if start_int <= ip_int <= end_int: - return True - return False + def ip_in_ips(self, ip, blocked_ips): + if blocked_ips is None: + return False + return ip in blocked_ips + + def blocked_ip_network(self): + """ + Retrieve blocked IP networks from cache or database. + """ + blocked_ip_network = cache.get("blocked_ip_network") + if blocked_ip_network is None: + blocked_network = Blocked.objects.values_list("ip_network", flat=True) + blocked_ip_network = [ + ipaddress.ip_network(range_str, strict=False) + for range_str in filter(None, blocked_network) + ] + cache.set("blocked_ip_network", blocked_ip_network, timeout=86400) + return blocked_ip_network or [] + + def ip_in_range(self, ip, blocked_ip_network): + """ + Check if the IP address is within any of the blocked IP networks. + """ + if not blocked_ip_network: + return False + ip_obj = ipaddress.ip_address(ip) + return any(ip_obj in ip_range for ip_range in blocked_ip_network if ip_range) def blocked_agents(self): + """ + Retrieve blocked user agents from cache or database. + """ blocked_agents = cache.get("blocked_agents") - if blocked_agents is None: - blocked_user_agents = BlockedIP.objects.values_list("user_agent_string", flat=True) - blocked_agents = set(blocked_user_agents) - cache.set("blocked_agents", blocked_agents, timeout=86400) + if blocked_agents is None or blocked_agents == []: + blocked_user_agents = Blocked.objects.values_list("user_agent_string", flat=True) + if blocked_user_agents: + blocked_agents = set(blocked_user_agents) + cache.set("blocked_agents", blocked_agents, timeout=86400) + return blocked_agents + else: + return None return blocked_agents + def is_user_agent_blocked(self, user_agent, blocked_agents): + """ + Check if the user agent is in the list of blocked user agents. + """ + user_agent_str = str(user_agent).strip() + + if not blocked_agents: + return False + blocked_agents = [str(agent).strip() for agent in blocked_agents if str(agent).strip()] + + for blocked_agent in blocked_agents: + blocked_agent_str = str(blocked_agent).strip() + if blocked_agent_str.lower() in user_agent_str.lower(): + return True + + return False + + def delete_all_info(self): + Blocked.objects.all().delete() + cache.delete("blocked_ips") + cache.delete("blocked_ip_network") + cache.delete("blocked_agents") + def __call__(self, request): + """ + Process the request and restrict access based on IP address and user agent. + """ ip = request.META.get("REMOTE_ADDR") - user_agent = request.META.get("HTTP_USER_AGENT", "") - parsed_agent = parse(user_agent) + agent = request.META.get("HTTP_USER_AGENT", "") + user_agent = parse(agent) + # If you want to clear everything use this + # self.delete_all_info() - if ip: - if ip in self.blocked_ips(): + if ( + self.ip_in_ips(ip, self.blocked_ips()) + or self.ip_in_range(ip, self.blocked_ip_network()) + or self.is_user_agent_blocked(user_agent, self.blocked_agents()) + ): + if self.ip_in_ips(ip, self.blocked_ips()) or self.ip_in_range( + ip, self.blocked_ip_network() + ): return HttpResponseForbidden( "Your IP address is restricted from accessing this site." ) - blocked_ip_ranges = self.blocked_ip_ranges() - if self.ip_in_range(ip, blocked_ip_ranges): + if self.is_user_agent_blocked(user_agent, self.blocked_agents()): return HttpResponseForbidden( - "Your IP address is restricted from accessing this site." + "Your user agent is restricted from accessing this site." ) - if parsed_agent and parsed_agent in self.blocked_agents(): - return HttpResponseForbidden("Your IP address is restricted from accessing this site.") + + x_forwarded_for = request.META.get("HTTP_X_FORWARDED_FOR") + if x_forwarded_for: + ip = x_forwarded_for.split(",")[0].strip() + else: + ip = request.META.get("REMOTE_ADDR") + + if ip: + ip_record = IP.objects.filter(address=ip).first() + if ip_record: + ip_record.agent = parse(agent) + ip_record.count += 1 + ip_record.save() return self.get_response(request) diff --git a/blt/settings.py b/blt/settings.py index d5d208b00..fb8a382cc 100644 --- a/blt/settings.py +++ b/blt/settings.py @@ -119,7 +119,6 @@ "whitenoise.middleware.WhiteNoiseMiddleware", "tz_detect.middleware.TimezoneMiddleware", "blt.middleware.ip_restrict.IPRestrictMiddleware", - "blt.middleware.count_ip_requests.MonitorIPMiddleware", ) TESTING = len(sys.argv) > 1 and sys.argv[1] == "test" diff --git a/website/admin.py b/website/admin.py index 7baa633e1..20d2b8b28 100644 --- a/website/admin.py +++ b/website/admin.py @@ -1,13 +1,14 @@ from django.contrib import admin from django.contrib.auth.models import User from django.template.defaultfilters import truncatechars +from django.utils import timezone from import_export import resources from import_export.admin import ImportExportModelAdmin from website.models import ( IP, Bid, - BlockedIP, + Blocked, ChatBotLog, Company, CompanyAdmin, @@ -279,7 +280,8 @@ def issue_description(self, obj): def block_ip(modeladmin, request, queryset): for ip in queryset: - BlockedIP.objects.create(address=ip.address, count=ip.count) + Blocked.objects.create(address=ip.address, count=ip.count, created=timezone.now()) + modeladmin.message_user(request, "Selected IPs have been blocked successfully.") @@ -288,7 +290,7 @@ def block_ip(modeladmin, request, queryset): def unblock_ip(modeladmin, request, queryset): for ip in queryset: - BlockedIP.objects.filter(ip=ip.address).delete() + Blocked.objects.filter(ip=ip.address).delete() modeladmin.message_user(request, "Selected IPs have ben unblocked successfully") @@ -297,7 +299,7 @@ def unblock_ip(modeladmin, request, queryset): def block_user_agent(modeladmin, request, queryset): for ip in queryset: - BlockedIP.objects.create(user_agent_string=ip.user_agent_string) + Blocked.objects.create(user_agent_string=ip.agent, count=ip.count, created=timezone.now()) modeladmin.message_user(request, "Selected UserAgent have been blocked successfully.") @@ -307,7 +309,7 @@ def block_user_agent(modeladmin, request, queryset): def unblock_user_agent(modeladmin, request, queryset): for ip in queryset: - BlockedIP.objects.filter(user_agent_string=ip.user_agent_string).delete() + Blocked.objects.filter(user_agent_string=ip.agent).delete() modeladmin.message_user(request, "Selected UserAgent have been unblocked successfully.") @@ -316,7 +318,18 @@ def unblock_user_agent(modeladmin, request, queryset): class IPAdmin(admin.ModelAdmin): - list_display = ("id", "address", "user", "issuenumber", "created", "agent", "path") + list_display = ( + "id", + "address", + "user", + "issuenumber", + "count", + "created", + "agent", + "path", + "method", + "referer", + ) actions = [block_ip, unblock_ip, block_user_agent, unblock_user_agent] @@ -346,14 +359,14 @@ class SuggestionVotesAdmin(admin.ModelAdmin): list_display = ("user", "suggestion", "up_vote", "down_vote") -class BlockedIPAdmin(admin.ModelAdmin): +class BlockedAdmin(admin.ModelAdmin): list_display = ( "address", "reason_for_block", - "address_range_start", - "address_range_end", + "ip_network", "user_agent_string", "count", + "created", ) @@ -389,7 +402,7 @@ class ProjectAdmin(admin.ModelAdmin): admin.site.register(IssueScreenshot, IssueScreenshotAdmin) admin.site.register(HuntPrize) admin.site.register(ChatBotLog, ChatBotLogAdmin) -admin.site.register(BlockedIP, BlockedIPAdmin) +admin.site.register(Blocked, BlockedAdmin) admin.site.register(Suggestion, SuggestionAdmin) admin.site.register(SuggestionVotes, SuggestionVotesAdmin) diff --git a/website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py b/website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py index f9cae7599..8578cfec1 100644 --- a/website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py +++ b/website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("website", "0125_activitylog_timelog"), ("website", "0125_blockedip"), diff --git a/website/migrations/0127_blocked_delete_blockedip.py b/website/migrations/0127_blocked_delete_blockedip.py new file mode 100644 index 000000000..8a30c5b5f --- /dev/null +++ b/website/migrations/0127_blocked_delete_blockedip.py @@ -0,0 +1,41 @@ +# Generated by Django 5.1 on 2024-08-11 07:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("website", "0126_merge_0125_activitylog_timelog_0125_blockedip"), + ] + + operations = [ + migrations.CreateModel( + name="Blocked", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("address", models.GenericIPAddressField(blank=True, null=True)), + ( + "reason_for_block", + models.TextField(blank=True, max_length=255, null=True), + ), + ("ip_network", models.GenericIPAddressField(blank=True, null=True)), + ( + "user_agent_string", + models.CharField(blank=True, default="", max_length=255, null=True), + ), + ("count", models.IntegerField(default=1)), + ("created", models.DateField(blank=True, null=True)), + ], + ), + migrations.DeleteModel( + name="BlockedIP", + ), + ] diff --git a/website/models.py b/website/models.py index 0c617df08..6300dc147 100644 --- a/website/models.py +++ b/website/models.py @@ -10,6 +10,7 @@ from colorthief import ColorThief from django.conf import settings from django.contrib.auth.models import User +from django.core.cache import cache from django.core.exceptions import MultipleObjectsReturned, ValidationError from django.core.files.base import ContentFile from django.core.files.storage import default_storage @@ -788,18 +789,35 @@ def __str__(self): return f"{self.user.username} - {self.amount} BACON" -class BlockedIP(models.Model): +class Blocked(models.Model): address = models.GenericIPAddressField(null=True, blank=True) reason_for_block = models.TextField(blank=True, null=True, max_length=255) - address_range_start = models.GenericIPAddressField(null=True, blank=True) - address_range_end = models.GenericIPAddressField(null=True, blank=True) + ip_network = models.GenericIPAddressField(null=True, blank=True) user_agent_string = models.CharField(max_length=255, default="", null=True, blank=True) count = models.IntegerField(default=1) + created = models.DateField(null=True, blank=True) def __str__(self): return f"user agent : {self.user_agent_string} | IP : {self.address}" +@receiver(post_save, sender=Blocked) +@receiver(post_delete, sender=Blocked) +def clear_blocked_cache(sender, instance=None, **kwargs): + """ + Clears the cache when a Blocked instance is created, updated, or deleted. + """ + cache.delete("blocked_ips") + cache.delete("blocked_ip_network") + cache.delete("blocked_agents") + blocked_ips = Blocked.objects.values_list("address", flat=True) + blocked_ip_network = Blocked.objects.values_list("ip_network", flat=True) + blocked_agents = Blocked.objects.values_list("user_agent_string", flat=True) + cache.set("blocked_ips", blocked_ips, timeout=86400) + cache.set("blocked_ip_network", blocked_ip_network, timeout=86400) + cache.set("blocked_agents", blocked_agents, timeout=86400) + + class TimeLog(models.Model): user = models.ForeignKey( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="timelogs" From 6c96a976d7adc915de286a3b608a6925531576c7 Mon Sep 17 00:00:00 2001 From: Sarthak5598 Date: Mon, 12 Aug 2024 23:23:14 +0530 Subject: [PATCH 4/6] migration issue --- website/migrations/0129_merge_20240812_2313.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 website/migrations/0129_merge_20240812_2313.py diff --git a/website/migrations/0129_merge_20240812_2313.py b/website/migrations/0129_merge_20240812_2313.py new file mode 100644 index 000000000..66fed41a9 --- /dev/null +++ b/website/migrations/0129_merge_20240812_2313.py @@ -0,0 +1,12 @@ +# Generated by Django 5.1 on 2024-08-12 17:43 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("website", "0127_blocked_delete_blockedip"), + ("website", "0128_userprofile_discounted_hourly_rate_and_more"), + ] + + operations = [] From e80954f913256fd5cfc1810719556ecdb5c9fd39 Mon Sep 17 00:00:00 2001 From: Sarthak5598 Date: Tue, 13 Aug 2024 14:31:07 +0530 Subject: [PATCH 5/6] resolved migration --- website/migrations/0125_blockedip.py | 44 ------------------- ...0125_activitylog_timelog_0125_blockedip.py | 12 ----- ...ed_delete_blockedip.py => 0129_blocked.py} | 7 +-- .../migrations/0129_merge_20240812_2313.py | 12 ----- 4 files changed, 2 insertions(+), 73 deletions(-) delete mode 100644 website/migrations/0125_blockedip.py delete mode 100644 website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py rename website/migrations/{0127_blocked_delete_blockedip.py => 0129_blocked.py} (85%) delete mode 100644 website/migrations/0129_merge_20240812_2313.py diff --git a/website/migrations/0125_blockedip.py b/website/migrations/0125_blockedip.py deleted file mode 100644 index fe06eb98c..000000000 --- a/website/migrations/0125_blockedip.py +++ /dev/null @@ -1,44 +0,0 @@ -# Generated by Django 5.1 on 2024-08-09 19:59 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - dependencies = [ - ("website", "0124_company_tags_domain_tags_project_tags_and_more"), - ] - - operations = [ - migrations.CreateModel( - name="BlockedIP", - fields=[ - ( - "id", - models.AutoField( - auto_created=True, - primary_key=True, - serialize=False, - verbose_name="ID", - ), - ), - ("address", models.GenericIPAddressField(blank=True, null=True)), - ( - "reason_for_block", - models.TextField(blank=True, max_length=255, null=True), - ), - ( - "address_range_start", - models.GenericIPAddressField(blank=True, null=True), - ), - ( - "address_range_end", - models.GenericIPAddressField(blank=True, null=True), - ), - ( - "user_agent_string", - models.CharField(blank=True, default="", max_length=255, null=True), - ), - ("count", models.IntegerField(default=1)), - ], - ), - ] diff --git a/website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py b/website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py deleted file mode 100644 index 8578cfec1..000000000 --- a/website/migrations/0126_merge_0125_activitylog_timelog_0125_blockedip.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 5.1 on 2024-08-09 20:18 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("website", "0125_activitylog_timelog"), - ("website", "0125_blockedip"), - ] - - operations = [] diff --git a/website/migrations/0127_blocked_delete_blockedip.py b/website/migrations/0129_blocked.py similarity index 85% rename from website/migrations/0127_blocked_delete_blockedip.py rename to website/migrations/0129_blocked.py index 8a30c5b5f..1bcf36a7c 100644 --- a/website/migrations/0127_blocked_delete_blockedip.py +++ b/website/migrations/0129_blocked.py @@ -1,11 +1,11 @@ -# Generated by Django 5.1 on 2024-08-11 07:03 +# Generated by Django 5.1 on 2024-08-13 08:55 from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ("website", "0126_merge_0125_activitylog_timelog_0125_blockedip"), + ("website", "0128_userprofile_discounted_hourly_rate_and_more"), ] operations = [ @@ -35,7 +35,4 @@ class Migration(migrations.Migration): ("created", models.DateField(blank=True, null=True)), ], ), - migrations.DeleteModel( - name="BlockedIP", - ), ] diff --git a/website/migrations/0129_merge_20240812_2313.py b/website/migrations/0129_merge_20240812_2313.py deleted file mode 100644 index 66fed41a9..000000000 --- a/website/migrations/0129_merge_20240812_2313.py +++ /dev/null @@ -1,12 +0,0 @@ -# Generated by Django 5.1 on 2024-08-12 17:43 - -from django.db import migrations - - -class Migration(migrations.Migration): - dependencies = [ - ("website", "0127_blocked_delete_blockedip"), - ("website", "0128_userprofile_discounted_hourly_rate_and_more"), - ] - - operations = [] From eedf816dbc246ac465b96d590b2aabb9d31a312b Mon Sep 17 00:00:00 2001 From: Sarthak5598 Date: Tue, 13 Aug 2024 20:20:19 +0530 Subject: [PATCH 6/6] added get_or_create --- blt/middleware/ip_restrict.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/blt/middleware/ip_restrict.py b/blt/middleware/ip_restrict.py index 356ffa6c2..c256d3557 100644 --- a/blt/middleware/ip_restrict.py +++ b/blt/middleware/ip_restrict.py @@ -125,10 +125,13 @@ def __call__(self, request): ip = request.META.get("REMOTE_ADDR") if ip: - ip_record = IP.objects.filter(address=ip).first() - if ip_record: + ip_record, created = IP.objects.get_or_create( + address=ip, defaults={"agent": parse(agent), "count": 1, "path": request.path} + ) + if not created: ip_record.agent = parse(agent) ip_record.count += 1 + ip_record.path = request.path ip_record.save() return self.get_response(request)