Skip to content

Commit 19b4a3a

Browse files
authored
Merge pull request #433 from intelowlproject/develop
1.4.0
2 parents d800fa8 + 84ba5d9 commit 19b4a3a

38 files changed

+1338
-654
lines changed

README.md

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
[![Twitter Follow](https://img.shields.io/twitter/follow/intel_owl?style=social)](https://twitter.com/intel_owl)
77
[![Linkedin](https://img.shields.io/badge/LinkedIn-0077B5?style=flat&logo=linkedin&logoColor=white)](https://www.linkedin.com/company/intelowl/)
88

9-
[![CodeFactor](https://www.codefactor.io/repository/github/intelowlproject/greedybear/badge)](https://www.codefactor.io/repository/github/intelowlproject/greedybear)
109
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
1110
[![Imports: isort](https://img.shields.io/badge/%20imports-isort-%231674b1?style=flat&labelColor=ef8336)](https://pycqa.github.io/isort/)
1211
[![CodeQL](https://github.com/intelowlproject/GreedyBear/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/intelowlproject/GreedyBear/actions/workflows/codeql-analysis.yml)

api/serializers.py

+65-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import logging
22
import re
3+
from functools import cache
34

5+
from django.core.exceptions import FieldDoesNotExist
46
from greedybear.consts import REGEX_DOMAIN, REGEX_IP
57
from greedybear.models import IOC, GeneralHoneypot
68
from rest_framework import serializers
@@ -47,37 +49,85 @@ def validate(self, data):
4749
return data
4850

4951

50-
def feed_type_validation(feed_type):
51-
feed_choices = ["log4j", "cowrie", "all"]
52-
generalHoneypots = GeneralHoneypot.objects.all().filter(active=True)
53-
feed_choices.extend([hp.name.lower() for hp in generalHoneypots]) # FEEDS
52+
def feed_type_validation(feed_type: str, valid_feed_types: frozenset) -> str:
53+
"""Validates that a given feed type exists in the set of valid feed types.
5454
55-
if feed_type not in feed_choices:
56-
logger.info(f"Feed type {feed_type} not in feed_choices {feed_choices}")
57-
raise serializers.ValidationError("Invalid feed_type")
55+
Args:
56+
feed_type (str): The feed type to validate
57+
valid_feed_types (frozenset): Set of allowed feed type values
58+
59+
Returns:
60+
str: The validated feed type string, unchanged
61+
62+
Raises:
63+
serializers.ValidationError: If feed_type is not found in valid_feed_types
64+
"""
65+
if feed_type not in valid_feed_types:
66+
logger.info(f"Feed type {feed_type} not in feed_choices {valid_feed_types}")
67+
raise serializers.ValidationError(f"Invalid feed_type: {feed_type}")
5868
return feed_type
5969

6070

61-
class FeedsSerializer(serializers.Serializer):
71+
@cache
72+
def ordering_validation(ordering: str) -> str:
73+
"""Validates that given ordering corresponds to a field in the IOC model.
74+
75+
Args:
76+
ordering (str): The ordering to validate
77+
78+
Returns:
79+
str: The validated ordering string, unchanged
80+
81+
Raises:
82+
serializers.ValidationError: If ordering does not correspond to a field in the IOC model
83+
"""
84+
if not ordering:
85+
raise serializers.ValidationError("Invalid ordering: <empty string>")
86+
# remove minus sign if present
87+
field_name = ordering[1:] if ordering.startswith("-") else ordering
88+
try:
89+
IOC._meta.get_field(field_name)
90+
except FieldDoesNotExist as exc:
91+
raise serializers.ValidationError(f"Invalid ordering: {ordering}") from exc
92+
return ordering
93+
94+
95+
class FeedsRequestSerializer(serializers.Serializer):
6296
feed_type = serializers.CharField(max_length=120)
6397
attack_type = serializers.ChoiceField(choices=["scanner", "payload_request", "all"])
64-
age = serializers.ChoiceField(choices=["persistent", "recent"])
65-
format = serializers.ChoiceField(choices=["csv", "json", "txt"], default="json")
98+
max_age = serializers.IntegerField(min_value=1)
99+
min_days_seen = serializers.IntegerField(min_value=1)
100+
include_reputation = serializers.ListField(child=serializers.CharField(max_length=120))
101+
exclude_reputation = serializers.ListField(child=serializers.CharField(max_length=120))
102+
feed_size = serializers.IntegerField(min_value=1)
103+
ordering = serializers.CharField(max_length=120)
104+
verbose = serializers.ChoiceField(choices=["true", "false"])
105+
paginate = serializers.ChoiceField(choices=["true", "false"])
106+
format = serializers.ChoiceField(choices=["csv", "json", "txt"])
66107

67108
def validate_feed_type(self, feed_type):
68-
logger.debug(f"FeedsSerializer - Validation feed_type: '{feed_type}'")
69-
return feed_type_validation(feed_type)
109+
logger.debug(f"FeedsRequestSerializer - validation feed_type: '{feed_type}'")
110+
return feed_type_validation(feed_type, self.context["valid_feed_types"])
111+
112+
def validate_ordering(self, ordering):
113+
logger.debug(f"FeedsRequestSerializer - validation ordering: '{ordering}'")
114+
return ordering_validation(ordering)
70115

71116

72117
class FeedsResponseSerializer(serializers.Serializer):
73118
feed_type = serializers.CharField(max_length=120)
74-
value = serializers.CharField(max_length=120)
119+
value = serializers.CharField(max_length=256)
75120
scanner = serializers.BooleanField()
76121
payload_request = serializers.BooleanField()
77122
first_seen = serializers.DateField(format="%Y-%m-%d")
78123
last_seen = serializers.DateField(format="%Y-%m-%d")
79-
times_seen = serializers.IntegerField()
124+
attack_count = serializers.IntegerField(min_value=1)
125+
interaction_count = serializers.IntegerField(min_value=1)
126+
ip_reputation = serializers.CharField(allow_blank=True, max_length=32)
127+
asn = serializers.IntegerField(allow_null=True, min_value=1)
128+
destination_port_count = serializers.IntegerField(min_value=0)
129+
login_attempts = serializers.IntegerField(min_value=0)
80130

81131
def validate_feed_type(self, feed_type):
82132
logger.debug(f"FeedsResponseSerializer - validation feed_type: '{feed_type}'")
83-
return feed_type_validation(feed_type)
133+
return feed_type_validation(feed_type, self.context["valid_feed_types"])

api/urls.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file is a part of GreedyBear https://github.com/honeynet/GreedyBear
22
# See the file 'LICENSE' for copying permission.
3-
from api.views import StatisticsViewSet, enrichment_view, feeds, feeds_pagination, general_honeypot_list
3+
from api.views import StatisticsViewSet, enrichment_view, feeds, feeds_advanced, feeds_pagination, general_honeypot_list
44
from django.urls import include, path
55
from rest_framework import routers
66

@@ -11,6 +11,7 @@
1111
# These come after /api/..
1212
urlpatterns = [
1313
path("feeds/", feeds_pagination),
14+
path("feeds/advanced/", feeds_advanced),
1415
path("feeds/<str:feed_type>/<str:attack_type>/<str:age>.<str:format_>", feeds),
1516
path("enrichment", enrichment_view),
1617
path("general_honeypot", general_honeypot_list),

0 commit comments

Comments
 (0)