Skip to content

API Documentation

enrichment

Handle enrichment requests for a specific observable (domain or IP address).

Parameters:

Name Type Description Default
request

The incoming request object containing query parameters.

required

Returns:

Name Type Description
Response

A JSON response indicating whether the observable was found,

and if so, the corresponding IOC.

Source code in docs/Submodules/GreedyBear/api/views.py
@api_view([GET])
@authentication_classes([CookieTokenAuthentication])
@permission_classes([IsAuthenticated])
def enrichment_view(request):
    """
    Handle enrichment requests for a specific observable (domain or IP address).

    Args:
        request: The incoming request object containing query parameters.

    Returns:
        Response: A JSON response indicating whether the observable was found,
        and if so, the corresponding IOC.
    """
    observable_name = request.query_params.get("query")
    logger.info(f"Enrichment view requested for: {str(observable_name)}")
    serializer = EnrichmentSerializer(data=request.query_params, context={"request": request})
    serializer.is_valid(raise_exception=True)

    source_ip = str(request.META["REMOTE_ADDR"])
    request_source = Statistics(source=source_ip, view=viewType.ENRICHMENT_VIEW.value)
    request_source.save()

    return Response(serializer.data, status=status.HTTP_200_OK)

feeds

Handle requests for IOC feeds with specific parameters and format the response accordingly.

Parameters:

Name Type Description Default
request

The incoming request object.

required
feed_type str

Type of feed (e.g., log4j, cowrie, etc.).

required
attack_type str

Type of attack (e.g., all, specific attack types).

required
age str

Age of the data to filter (e.g., recent, persistent).

required
format_ str

Desired format of the response (e.g., json, csv, txt).

required

Returns:

Name Type Description
Response

The HTTP response with formatted IOC data.

Source code in docs/Submodules/GreedyBear/api/views.py
@api_view([GET])
def feeds(request, feed_type, attack_type, age, format_):
    """
    Handle requests for IOC feeds with specific parameters and format the response accordingly.

    Args:
        request: The incoming request object.
        feed_type (str): Type of feed (e.g., log4j, cowrie, etc.).
        attack_type (str): Type of attack (e.g., all, specific attack types).
        age (str): Age of the data to filter (e.g., recent, persistent).
        format_ (str): Desired format of the response (e.g., json, csv, txt).

    Returns:
        Response: The HTTP response with formatted IOC data.
    """
    logger.info(f"request /api/feeds with params: feed type: {feed_type}, " f"attack_type: {attack_type}, Age: {age}, format: {format_}")

    iocs_queryset = get_queryset(request, feed_type, attack_type, age, format_)
    return feeds_response(request, iocs_queryset, feed_type, format_)

feeds_pagination

Handle requests for paginated IOC feeds based on query parameters.

Parameters:

Name Type Description Default
request

The incoming request object.

required

Returns:

Name Type Description
Response

The paginated HTTP response with IOC data.

Source code in docs/Submodules/GreedyBear/api/views.py
@api_view([GET])
def feeds_pagination(request):
    """
    Handle requests for paginated IOC feeds based on query parameters.

    Args:
        request: The incoming request object.

    Returns:
        Response: The paginated HTTP response with IOC data.
    """
    params = request.query_params
    logger.info(f"request /api/feeds with params: {params}")

    paginator = CustomPageNumberPagination()
    iocs_queryset = get_queryset(
        request,
        params["feed_type"],
        params["attack_type"],
        params["age"],
        "json",
    )
    iocs = paginator.paginate_queryset(iocs_queryset, request)
    resp_data = feeds_response(request, iocs, params["feed_type"], "json", dict_only=True)
    return paginator.get_paginated_response(resp_data)

Statistics

Bases: ViewSet

A viewset for viewing and editing statistics related to feeds and enrichment data.

Provides actions to retrieve statistics about the sources and downloads of feeds, as well as statistics on enrichment data.

Source code in docs/Submodules/GreedyBear/api/views.py
class StatisticsViewSet(viewsets.ViewSet):
    """
    A viewset for viewing and editing statistics related to feeds and enrichment data.

    Provides actions to retrieve statistics about the sources and downloads of feeds,
    as well as statistics on enrichment data.
    """

    @action(detail=True, methods=["GET"])
    def feeds(self, request, pk=None):
        """
        Retrieve feed statistics, including the number of sources and downloads.

        Args:
            request: The incoming request object.
            pk (str): The type of statistics to retrieve (e.g., "sources", "downloads").

        Returns:
            Response: A JSON response containing the requested statistics.
        """
        if pk == "sources":
            annotations = {
                "Sources": Count(
                    "source",
                    distinct=True,
                    filter=Q(view=viewType.FEEDS_VIEW.value),
                )
            }
        elif pk == "downloads":
            annotations = {"Downloads": Count("source", filter=Q(view=viewType.FEEDS_VIEW.value))}
        else:
            logger.error("this is impossible. check the code")
            return HttpResponseServerError()
        return self.__aggregation_response_static_statistics(annotations)

    @action(detail=True, methods=["get"])
    def enrichment(self, request, pk=None):
        """
        Retrieve enrichment statistics, including the number of sources and requests.

        Args:
            request: The incoming request object.
            pk (str): The type of statistics to retrieve (e.g., "sources", "requests").

        Returns:
            Response: A JSON response containing the requested statistics.
        """
        if pk == "sources":
            annotations = {
                "Sources": Count(
                    "source",
                    distinct=True,
                    filter=Q(view=viewType.ENRICHMENT_VIEW.value),
                )
            }
        elif pk == "requests":
            annotations = {"Requests": Count("source", filter=Q(view=viewType.ENRICHMENT_VIEW.value))}
        else:
            logger.error("this is impossible. check the code")
            return HttpResponseServerError()
        return self.__aggregation_response_static_statistics(annotations)

    @action(detail=False, methods=["get"])
    def feeds_types(self, request):
        """
        Retrieve statistics for different types of feeds, including Log4j, Cowrie,
        and general honeypots.

        Args:
            request: The incoming request object.

        Returns:
            Response: A JSON response containing the feed type statistics.
        """
        # FEEDS
        annotations = {
            "Log4j": Count("name", distinct=True, filter=Q(log4j=True)),
            "Cowrie": Count("name", distinct=True, filter=Q(cowrie=True)),
        }
        # feed_type for each general honeypot in the list
        generalHoneypots = GeneralHoneypot.objects.all().filter(active=True)
        for hp in generalHoneypots:
            annotations[hp.name] = Count("name", Q(general_honeypot__name__iexact=hp.name.lower()))
        return self.__aggregation_response_static_ioc(annotations)

    def __aggregation_response_static_statistics(self, annotations: dict) -> Response:
        """
        Helper method to generate statistics response based on annotations.

        Args:
            annotations (dict): Dictionary containing the annotations for the query.

        Returns:
            Response: A JSON response containing the aggregated statistics.
        """
        delta, basis = self.__parse_range(self.request)
        qs = Statistics.objects.filter(request_date__gte=delta).annotate(date=Trunc("request_date", basis)).values("date").annotate(**annotations)
        return Response(qs)

    def __aggregation_response_static_ioc(self, annotations: dict) -> Response:
        """
        Helper method to generate IOC response based on annotations.

        Args:
            annotations (dict): Dictionary containing the annotations for the query.

        Returns:
            Response: A JSON response containing the aggregated IOC data.
        """
        delta, basis = self.__parse_range(self.request)

        qs = (
            IOC.objects.filter(last_seen__gte=delta)
            .exclude(general_honeypot__active=False)
            .annotate(date=Trunc("last_seen", basis))
            .values("date")
            .annotate(**annotations)
        )
        return Response(qs)

    @staticmethod
    def __parse_range(request):
        """
        Parse the range parameter from the request query string to determine the time range for the query.

        Args:
            request: The incoming request object.

        Returns:
            tuple: A tuple containing the delta time and basis for the query range.
        """
        try:
            range_str = request.GET["range"]
        except KeyError:
            # default
            range_str = "7d"

        return parse_humanized_range(range_str)

__aggregation_response_static_ioc(annotations)

Helper method to generate IOC response based on annotations.

Parameters:

Name Type Description Default
annotations dict

Dictionary containing the annotations for the query.

required

Returns:

Name Type Description
Response Response

A JSON response containing the aggregated IOC data.

Source code in docs/Submodules/GreedyBear/api/views.py
def __aggregation_response_static_ioc(self, annotations: dict) -> Response:
    """
    Helper method to generate IOC response based on annotations.

    Args:
        annotations (dict): Dictionary containing the annotations for the query.

    Returns:
        Response: A JSON response containing the aggregated IOC data.
    """
    delta, basis = self.__parse_range(self.request)

    qs = (
        IOC.objects.filter(last_seen__gte=delta)
        .exclude(general_honeypot__active=False)
        .annotate(date=Trunc("last_seen", basis))
        .values("date")
        .annotate(**annotations)
    )
    return Response(qs)

__aggregation_response_static_statistics(annotations)

Helper method to generate statistics response based on annotations.

Parameters:

Name Type Description Default
annotations dict

Dictionary containing the annotations for the query.

required

Returns:

Name Type Description
Response Response

A JSON response containing the aggregated statistics.

Source code in docs/Submodules/GreedyBear/api/views.py
def __aggregation_response_static_statistics(self, annotations: dict) -> Response:
    """
    Helper method to generate statistics response based on annotations.

    Args:
        annotations (dict): Dictionary containing the annotations for the query.

    Returns:
        Response: A JSON response containing the aggregated statistics.
    """
    delta, basis = self.__parse_range(self.request)
    qs = Statistics.objects.filter(request_date__gte=delta).annotate(date=Trunc("request_date", basis)).values("date").annotate(**annotations)
    return Response(qs)

__parse_range(request) staticmethod

Parse the range parameter from the request query string to determine the time range for the query.

Parameters:

Name Type Description Default
request

The incoming request object.

required

Returns:

Name Type Description
tuple

A tuple containing the delta time and basis for the query range.

Source code in docs/Submodules/GreedyBear/api/views.py
@staticmethod
def __parse_range(request):
    """
    Parse the range parameter from the request query string to determine the time range for the query.

    Args:
        request: The incoming request object.

    Returns:
        tuple: A tuple containing the delta time and basis for the query range.
    """
    try:
        range_str = request.GET["range"]
    except KeyError:
        # default
        range_str = "7d"

    return parse_humanized_range(range_str)

enrichment(request, pk=None)

Retrieve enrichment statistics, including the number of sources and requests.

Parameters:

Name Type Description Default
request

The incoming request object.

required
pk str

The type of statistics to retrieve (e.g., "sources", "requests").

None

Returns:

Name Type Description
Response

A JSON response containing the requested statistics.

Source code in docs/Submodules/GreedyBear/api/views.py
@action(detail=True, methods=["get"])
def enrichment(self, request, pk=None):
    """
    Retrieve enrichment statistics, including the number of sources and requests.

    Args:
        request: The incoming request object.
        pk (str): The type of statistics to retrieve (e.g., "sources", "requests").

    Returns:
        Response: A JSON response containing the requested statistics.
    """
    if pk == "sources":
        annotations = {
            "Sources": Count(
                "source",
                distinct=True,
                filter=Q(view=viewType.ENRICHMENT_VIEW.value),
            )
        }
    elif pk == "requests":
        annotations = {"Requests": Count("source", filter=Q(view=viewType.ENRICHMENT_VIEW.value))}
    else:
        logger.error("this is impossible. check the code")
        return HttpResponseServerError()
    return self.__aggregation_response_static_statistics(annotations)

feeds(request, pk=None)

Retrieve feed statistics, including the number of sources and downloads.

Parameters:

Name Type Description Default
request

The incoming request object.

required
pk str

The type of statistics to retrieve (e.g., "sources", "downloads").

None

Returns:

Name Type Description
Response

A JSON response containing the requested statistics.

Source code in docs/Submodules/GreedyBear/api/views.py
@action(detail=True, methods=["GET"])
def feeds(self, request, pk=None):
    """
    Retrieve feed statistics, including the number of sources and downloads.

    Args:
        request: The incoming request object.
        pk (str): The type of statistics to retrieve (e.g., "sources", "downloads").

    Returns:
        Response: A JSON response containing the requested statistics.
    """
    if pk == "sources":
        annotations = {
            "Sources": Count(
                "source",
                distinct=True,
                filter=Q(view=viewType.FEEDS_VIEW.value),
            )
        }
    elif pk == "downloads":
        annotations = {"Downloads": Count("source", filter=Q(view=viewType.FEEDS_VIEW.value))}
    else:
        logger.error("this is impossible. check the code")
        return HttpResponseServerError()
    return self.__aggregation_response_static_statistics(annotations)

feeds_types(request)

Retrieve statistics for different types of feeds, including Log4j, Cowrie, and general honeypots.

Parameters:

Name Type Description Default
request

The incoming request object.

required

Returns:

Name Type Description
Response

A JSON response containing the feed type statistics.

Source code in docs/Submodules/GreedyBear/api/views.py
@action(detail=False, methods=["get"])
def feeds_types(self, request):
    """
    Retrieve statistics for different types of feeds, including Log4j, Cowrie,
    and general honeypots.

    Args:
        request: The incoming request object.

    Returns:
        Response: A JSON response containing the feed type statistics.
    """
    # FEEDS
    annotations = {
        "Log4j": Count("name", distinct=True, filter=Q(log4j=True)),
        "Cowrie": Count("name", distinct=True, filter=Q(cowrie=True)),
    }
    # feed_type for each general honeypot in the list
    generalHoneypots = GeneralHoneypot.objects.all().filter(active=True)
    for hp in generalHoneypots:
        annotations[hp.name] = Count("name", Q(general_honeypot__name__iexact=hp.name.lower()))
    return self.__aggregation_response_static_ioc(annotations)

general_honeypot_list

Retrieve a list of all general honeypots, optionally filtering by active status.

Parameters:

Name Type Description Default
request

The incoming request object containing query parameters.

required

Returns:

Name Type Description
Response

A JSON response containing the list of general honeypots.

Source code in docs/Submodules/GreedyBear/api/views.py
@api_view([GET])
def general_honeypot_list(request):
    """
    Retrieve a list of all general honeypots, optionally filtering by active status.

    Args:
        request: The incoming request object containing query parameters.

    Returns:
        Response: A JSON response containing the list of general honeypots.
    """

    logger.info(f"Requested general honeypots list from {request.user}.")
    active = request.query_params.get("onlyActive")
    honeypots = []
    generalHoneypots = GeneralHoneypot.objects.all()
    if active == "true":
        generalHoneypots = generalHoneypots.filter(active=True)
        logger.info("Requested only active general honeypots")
    honeypots.extend([hp.name for hp in generalHoneypots])

    logger.info(f"General honeypots: {honeypots}")
    return Response(honeypots)