SOCRadarRapidReputation

Enrich indicators (IP, Domain, URL, Hash) by obtaining reputation information via SOCRadar Rapid Reputation API.

Data Enrichment & Threat Intelligence · SOCRadar

Details

IDSOCRadarRapidReputation
ProviderSOCRadar
CategoryData Enrichment & Threat Intelligence
From Version6.10.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

SOCRadar Rapid Reputation

Enrich indicators (IP, Domain, URL, Hash) by obtaining reputation information via SOCRadar’s Rapid Reputation API.

This integration was integrated and tested with the latest version of SOCRadar Rapid Reputation API.

Configure SOCRadarRapidReputation on Cortex XSOAR

  1. Navigate to Settings > Integrations > Servers & Services.
  2. Search for SOCRadarRapidReputation.
  3. Click Add instance to create and configure a new integration instance.

    Parameter Description Required
    API Key The API Key to use for connection to SOCRadar Rapid Reputation API. True
    Trust any certificate (not secure) Trust any certificate (not secure). False
    Use system proxy settings Whether to use XSOAR’s system proxy settings to connect to the API. False
    Source Reliability Reliability of the source providing the intelligence data. False
  4. Click Test to validate API key and connection to SOCRadar Rapid Reputation API.

Commands

You can execute these commands from the Cortex XSOAR CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.

How to obtain SOCRadar API key?

SOCRadar Rapid Reputation is an Advanced Intelligence API optimized for high-volume and fast reputation queries.

  • Licensing Model: The features of this module are licensed separately from the standard SOCRadar platform package. To use the integration, your API key must be activated with “Rapid Reputation” privileges.
  • Standalone Purchase: This service can be added to your existing SOCRadar subscription, or it can be purchased as a standalone key completely independent of a platform membership.
  • Purchase & Activation: For API authorization, pricing information, or to purchase a new key, please contact our support team at support@socradar.io.


socradar-bulk-check

🎯 NEW FEATURE - Bulk check reputation for mixed list of indicators with automatic entity type detection.

This powerful command allows you to check reputation for a mixed list of IPs, domains, URLs, and hashes in a single command. The integration automatically detects the type of each indicator and processes it accordingly.

Base Command

socradar-bulk-check

Input

Argument Name Description Required
indicators Mixed list of indicators to check (IPs, domains, URLs, hashes). Automatically detects entity types. Supports comma-separated values. Required

Context Output

Path Type Description
SOCRadarRapidReputation.BulkCheck.Entity String The queried entity value.
SOCRadarRapidReputation.BulkCheck.EntityType String Detected type of the entity.
SOCRadarRapidReputation.BulkCheck.DetectedType String Auto-detected entity type.
SOCRadarRapidReputation.BulkCheck.Score Number Reputation score of the entity.
SOCRadarRapidReputation.BulkCheck.IsWhitelisted Boolean Whether the entity is whitelisted.
SOCRadarRapidReputation.BulkCheck.FindingSources Unknown List of threat sources that detected this entity.
SOCRadarRapidReputation.BulkCheckSummary.total Number Total number of indicators checked.
SOCRadarRapidReputation.BulkCheckSummary.processed Number Number of successfully processed indicators.
SOCRadarRapidReputation.BulkCheckSummary.failed Number Number of failed indicators.
SOCRadarRapidReputation.BulkCheckSummary.by_type Unknown Breakdown by entity type (ip, hostname, url, hash).
SOCRadarRapidReputation.BulkCheckSummary.by_score Unknown Breakdown by score classification (malicious, suspicious, good, unknown, whitelisted).

Command Example

!socradar-bulk-check indicators="1.1.1.1,malicious.example.com"

Use Cases for Bulk Check

  1. Incident Response: Quickly check all IOCs extracted from a security incident

    !socradar-bulk-check indicators="192.168.1.100,malware.example.com,3b7b359ea17ac76341957573e332a2d6bcac363401ac71c8df94dac93df6d792"
    
  2. Threat Intel Feed Processing: Validate a list of indicators from threat intelligence feeds

    !socradar-bulk-check indicators="${File.Name}"
    
  3. Automated Playbooks: Use in playbooks to process multiple indicators in one step

    !socradar-bulk-check indicators="${inputs.indicators}"
    
  4. Daily Security Monitoring: Check a list of suspicious entities identified during monitoring

    !socradar-bulk-check indicators="suspicious_ip1,suspicious_domain1,suspicious_url1"
    

Output Features

The bulk check command provides:

  1. Summary Statistics:
    • Total indicators processed
    • Success/failure counts
    • Breakdown by entity type (IPs, domains, URLs, hashes)
    • Breakdown by threat level (malicious, suspicious, good, unknown, whitelisted)
  2. Individual Results:
    • Each indicator gets its own detailed result card
    • Includes reputation score, whitelisting status, and threat sources
    • Clear classification (Malicious/Suspicious/Good/Unknown)
  3. Automatic Type Detection:
    • IPs: Automatically detected (IPv4 and IPv6)
    • Domains: Detected based on domain validation
    • URLs: Detected by http:// or https:// prefix
    • Hashes: Detected (MD5, SHA1, SHA256)
  4. Error Handling:
    • Invalid indicators are reported with clear error messages
    • Processing continues even if some indicators fail
    • Failed indicators don’t stop the entire batch

Human Readable Output Example

📊 Bulk Check Summary
┌─────────────────────────┬───────┐
│ Metric                  │ Count │
├─────────────────────────┼───────┤
│ Total Indicators        │ 10    │
│ Successfully Processed  │ 9     │
│ Failed                  │ 1     │
│ IPs                     │ 3     │
│ Domains                 │ 4     │
│ URLs                    │ 2     │
│ Hashes                  │ 1     │
│ Malicious               │ 2     │
│ Suspicious              │ 3     │
│ Good                    │ 3     │
│ Unknown                 │ 1     │
│ Whitelisted             │ 0     │
└─────────────────────────┴───────┘

[Followed by detailed results for each indicator]

Commands Overview

ip

Checks reputation of provided IP entities using SOCRadar Rapid Reputation API.

Base Command

ip

Input

Argument Name Description Required
ip IP entities to check reputation. (IPv4 or IPv6). Supports comma-separated values. Required

Context Output

Path Type Description
SOCRadarRapidReputation.IP.Entity String The queried IP address.
SOCRadarRapidReputation.IP.EntityType String Type of the entity (ip).
SOCRadarRapidReputation.IP.Score Number Reputation score of the IP address.
SOCRadarRapidReputation.IP.IsWhitelisted Boolean Whether the IP is whitelisted.
SOCRadarRapidReputation.IP.FindingSources Unknown List of threat sources that detected this IP.
SOCRadarRapidReputation.IP.FindingSources.SourceName String Name of the threat intelligence source.
SOCRadarRapidReputation.IP.FindingSources.MainCategory String Primary threat category.
SOCRadarRapidReputation.IP.FindingSources.MaintainerName String Organization maintaining the threat list.
SOCRadarRapidReputation.IP.FindingSources.FirstSeenDate Date First time the IP was seen on this source.
SOCRadarRapidReputation.IP.FindingSources.LastSeenDate Date Last time the IP was seen on this source.
SOCRadarRapidReputation.IP.FindingSources.SeenCount Number Number of times the IP was observed on this source.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Score Number The actual score.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
IP.Address String IP address

Command Example

!ip ip="1.1.1.1"

Human Readable Output

Example output showing reputation score, whitelisting status, and threat sources that have detected the IP.


domain

Checks reputation of provided domain entities using SOCRadar Rapid Reputation API.

Base Command

domain

Input

Argument Name Description Required
domain Domain entities to check reputation. Supports comma-separated values. Required

Context Output

Path Type Description
SOCRadarRapidReputation.Domain.Entity String The queried domain.
SOCRadarRapidReputation.Domain.EntityType String Type of the entity (hostname).
SOCRadarRapidReputation.Domain.Score Number Reputation score of the domain.
SOCRadarRapidReputation.Domain.IsWhitelisted Boolean Whether the domain is whitelisted.
SOCRadarRapidReputation.Domain.FindingSources Unknown List of threat sources that detected this domain.
SOCRadarRapidReputation.Domain.FindingSources.SourceName String Name of the threat intelligence source.
SOCRadarRapidReputation.Domain.FindingSources.MainCategory String Primary threat category.
SOCRadarRapidReputation.Domain.FindingSources.MaintainerName String Organization maintaining the threat list.
SOCRadarRapidReputation.Domain.FindingSources.FirstSeenDate Date First time the domain was seen on this source.
SOCRadarRapidReputation.Domain.FindingSources.LastSeenDate Date Last time the domain was seen on this source.
SOCRadarRapidReputation.Domain.FindingSources.SeenCount Number Number of times the domain was observed on this source.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Score Number The actual score.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
Domain.Name String Domain name

Command Example

!domain domain="example.com"

url

Checks reputation of provided URL entities using SOCRadar Rapid Reputation API.

Base Command

url

Input

Argument Name Description Required
url URL entities to check reputation. Supports comma-separated values. Required

Context Output

Path Type Description
SOCRadarRapidReputation.URL.Entity String The queried URL.
SOCRadarRapidReputation.URL.EntityType String Type of the entity (url).
SOCRadarRapidReputation.URL.Score Number Reputation score of the URL.
SOCRadarRapidReputation.URL.IsWhitelisted Boolean Whether the URL is whitelisted.
SOCRadarRapidReputation.URL.FindingSources Unknown List of threat sources that detected this URL.
SOCRadarRapidReputation.URL.FindingSources.SourceName String Name of the threat intelligence source.
SOCRadarRapidReputation.URL.FindingSources.MainCategory String Primary threat category.
SOCRadarRapidReputation.URL.FindingSources.MaintainerName String Organization maintaining the threat list.
SOCRadarRapidReputation.URL.FindingSources.FirstSeenDate Date First time the URL was seen on this source.
SOCRadarRapidReputation.URL.FindingSources.LastSeenDate Date Last time the URL was seen on this source.
SOCRadarRapidReputation.URL.FindingSources.SeenCount Number Number of times the URL was observed on this source.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Score Number The actual score.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
URL.Data String URL

Command Example

!url url="https://malicious.example.com/file.exe"

file

Checks reputation of provided file hash entities using SOCRadar Rapid Reputation API.

Base Command

file

Input

Argument Name Description Required
file File hash entities to check reputation. (MD5, SHA1, or SHA256). Supports comma-separated values. Required

Context Output

Path Type Description
SOCRadarRapidReputation.File.Entity String The queried file hash.
SOCRadarRapidReputation.File.EntityType String Type of the entity (hash).
SOCRadarRapidReputation.File.Score Number Reputation score of the hash.
SOCRadarRapidReputation.File.IsWhitelisted Boolean Whether the hash is whitelisted.
SOCRadarRapidReputation.File.FindingSources Unknown List of threat sources that detected this hash.
SOCRadarRapidReputation.File.FindingSources.SourceName String Name of the threat intelligence source.
SOCRadarRapidReputation.File.FindingSources.MainCategory String Primary threat category.
SOCRadarRapidReputation.File.FindingSources.MaintainerName String Organization maintaining the threat list.
SOCRadarRapidReputation.File.FindingSources.FirstSeenDate Date First time the hash was seen on this source.
SOCRadarRapidReputation.File.FindingSources.LastSeenDate Date Last time the hash was seen on this source.
SOCRadarRapidReputation.File.FindingSources.SeenCount Number Number of times the hash was observed on this source.
DBotScore.Indicator String The indicator that was tested.
DBotScore.Score Number The actual score.
DBotScore.Type String The indicator type.
DBotScore.Vendor String The vendor used to calculate the score.
DBotScore.Reliability String Reliability of the source providing the intelligence data.
File.MD5 String MD5 hash of the file
File.SHA1 String SHA1 hash of the file
File.SHA256 String SHA256 hash of the file

Command Example

!file file="3b7b359ea17ac76341957573e332a2d6bcac363401ac71c8df94dac93df6d792"

socradar-reputation

Checks reputation of any entity type using SOCRadar Rapid Reputation API. This is a generic command that can handle any supported entity type.

Base Command

socradar-reputation

Input

Argument Name Description Required
entity_value Entity value to check (IP, domain, URL, or hash). Required
entity_type Type of entity to check. Possible values are: ip, hostname, url, hash. Required

Context Output

Path Type Description
SOCRadarRapidReputation.Reputation.Entity String The queried entity value.
SOCRadarRapidReputation.Reputation.EntityType String Type of the entity.
SOCRadarRapidReputation.Reputation.Score Number Reputation score of the entity.
SOCRadarRapidReputation.Reputation.IsWhitelisted Boolean Whether the entity is whitelisted.
SOCRadarRapidReputation.Reputation.FindingSources Unknown List of threat sources that detected this entity.
SOCRadarRapidReputation.Reputation.FindingSources.SourceName String Name of the threat intelligence source.
SOCRadarRapidReputation.Reputation.FindingSources.MainCategory String Primary threat category.
SOCRadarRapidReputation.Reputation.FindingSources.MaintainerName String Organization maintaining the threat list.
SOCRadarRapidReputation.Reputation.FindingSources.FirstSeenDate Date First time the entity was seen on this source.
SOCRadarRapidReputation.Reputation.FindingSources.LastSeenDate Date Last time the entity was seen on this source.
SOCRadarRapidReputation.Reputation.FindingSources.SeenCount Number Number of times the entity was observed on this source.

Command Example

!socradar-reputation entity_value="37.46.210.230" entity_type="ip"
!socradar-reputation entity_value="malicious.example.com" entity_type="hostname"
!socradar-reputation entity_value="3b7b359ea17ac76341957573e332a2d6bcac363401ac71c8df94dac93df6d792" entity_type="hash"

DBot Score Interpretation

The integration converts SOCRadar reputation scores to DBot scores as follows:

SOCRadar Score DBot Score Classification
> 80 3 Malicious
40 - 80 2 Suspicious
0 - 40 1 Good
None/0 0 Unknown

Whitelisted entities are always assigned a DBot score of 1 (Good), regardless of their reputation score.


Additional Information

Threat Intelligence Sources

The Rapid Reputation API aggregates data from multiple threat intelligence sources, including:

  • CTU AIPP Blacklist
  • Abuse.ch URLhaus
  • Malware feeds
  • Botnet C&C lists
  • And many more

Each finding source provides detailed information about when and how many times the entity was observed.

Use Cases

  1. Incident Response: Quickly check if an IP, domain, or URL involved in an incident is known to be malicious
  2. Threat Hunting: Proactively search for indicators of compromise in your environment
  3. Automated Playbooks: Integrate reputation checks into your security automation workflows
  4. Alert Enrichment: Enhance security alerts with threat intelligence context

Best Practices

  • Use the generic socradar-reputation command when you need flexibility in entity type
  • Use specific commands (ip, domain, url, file) when you know the entity type for better context integration
  • Monitor the FindingSources field to understand which threat intelligence feeds detected the entity
  • Pay attention to the FirstSeenDate and LastSeenDate to understand the timeline of malicious activity

Configuration parameters

  • apikey — (required)
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • integrationReliability — Source Reliability
  • feedExpirationPolicy
  • feedExpirationInterval

Commands (6)

  • domain

    Checks reputation of provided domain entities using SOCRadar Rapid Reputation API.

  • file

    Checks reputation of provided file hash entities using SOCRadar Rapid Reputation API.

  • ip

    Checks reputation of provided IP entities using SOCRadar Rapid Reputation API.

  • socradar-bulk-check

    Bulk check reputation for mixed list of indicators. Automatically detects and processes IPs, domains, URLs, and hashes. Maximum 100 indicators per batch. Rate limit - 1 req/sec (100 indicators = ~100 seconds).

  • socradar-reputation

    Checks reputation of any entity type using SOCRadar Rapid Reputation API.

  • url

    Checks reputation of provided URL entities using SOCRadar Rapid Reputation API.

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401
from CommonServerUserPython import *  # noqa

import urllib3
import traceback
from typing import Any
import re
from json.decoder import JSONDecodeError

# Disable insecure warnings
urllib3.disable_warnings()  # pylint: disable=no-member


""" CONSTANTS """

SOCRADAR_API_ENDPOINT = "https://platform.socradar.com/api"
MESSAGES: dict[str, str] = {
    "BAD_REQUEST_ERROR": "An error occurred while fetching the data.",
    "AUTHORIZATION_ERROR": "Authorization Error: make sure API Key is correctly set.",
    "RATE_LIMIT_EXCEED_ERROR": "Rate limit has been exceeded. Please make sure your API key's rate limit is adequate.",
}
INTEGRATION_NAME = "SOCRadar Rapid Reputation"
MAX_BULK_CHECK_INDICATORS = 100  # Maximum indicators per bulk check to avoid XSOAR limits

""" CLIENT CLASS """


class Client(BaseClient):
    """
    Client class to interact with the SOCRadar Rapid Reputation API
    """

    def __init__(self, base_url, api_key, verify, proxy):
        super().__init__(base_url, verify=verify, proxy=proxy)
        self.api_key = api_key

    def get_entity_reputation(self, entity_value: str, entity_type: str):
        """Get entity reputation from SOCRadar Rapid Reputation API

        Args:
            entity_value: The value of the entity (IP, domain, URL, or hash)
            entity_type: The type of entity (ip, hostname, url, hash)

        Returns:
            API response with reputation data
        """
        suffix = "/threatfeed/rapid/reputation"
        api_params = {"entity_value": entity_value, "entity_type": entity_type}
        headers = {"Api-Key": self.api_key}

        response = self._http_request(
            method="GET",
            url_suffix=suffix,
            params=api_params,
            headers=headers,
            timeout=60,
            error_handler=self.handle_error_response,
            resp_type="json",
            retries=3,
            status_list_to_retry=[429],
            backoff_factor=1,
        )
        return response

    def check_auth(self):
        """Check API authentication by making a test request"""
        try:
            demisto.debug("Testing API authentication...")
            response = self.get_entity_reputation("8.8.8.8", "ip")
            demisto.debug(f"Auth test response: {response}")
            return response
        except Exception as e:
            demisto.error(f"Authentication test failed: {str(e)}")
            raise DemistoException(f"Authentication failed: {str(e)}")

    @staticmethod
    def handle_error_response(response) -> None:
        """Handles API response to display descriptive error messages based on status code"""
        error_reason = ""
        try:
            json_resp = response.json()
            error_reason = json_resp.get("exception") or json_resp.get("message")
        except JSONDecodeError:
            pass

        status_code_messages = {
            400: f"{MESSAGES['BAD_REQUEST_ERROR']} Reason: {error_reason}",
            401: MESSAGES["AUTHORIZATION_ERROR"],
            404: f"{MESSAGES['BAD_REQUEST_ERROR']} Reason: {error_reason}",
            429: MESSAGES["RATE_LIMIT_EXCEED_ERROR"],
        }

        if response.status_code in status_code_messages:
            demisto.debug(f"Response Code: {response.status_code}, Reason: {status_code_messages[response.status_code]}")
            raise DemistoException(status_code_messages[response.status_code])
        else:
            try:
                response.raise_for_status()
            except Exception as e:
                raise DemistoException(f"Error in API call [{response.status_code}] - {response.text}\n{e}")


""" HELPER FUNCTIONS """


def calculate_dbot_score(score: float) -> int:
    """Transforms reputation score from SOCRadar API to DBot Score.

    SOCRadar score ranges:
        0       → Unknown    (0)
        1–49    → Suspicious (2)
        50–100  → Malicious  (3)

    Returns:
        DBot score (0=Unknown, 2=Suspicious, 3=Malicious)
    """
    if score is None or score == 0:
        return 0  # Unknown
    elif score > 49:
        return 3  # Malicious
    else:
        return 2  # Suspicious


class Validator:
    @staticmethod
    def validate_domain(domain_to_validate):
        if not isinstance(domain_to_validate, str) or len(domain_to_validate) > 255:
            return False
        if domain_to_validate.endswith("."):
            domain_to_validate = domain_to_validate[:-1]
        domain_regex = re.compile(r"(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)
        return all(domain_regex.match(x) for x in domain_to_validate.split("."))

    @staticmethod
    def validate_ipv4(ip_to_validate):
        return is_ip_valid(ip_to_validate)

    @staticmethod
    def validate_ipv6(ip_to_validate):
        return is_ipv6_valid(ip_to_validate)

    @staticmethod
    def validate_hash(hash_to_validate):
        return get_hash_type(hash_to_validate) != "Unknown"

    @staticmethod
    def validate_url(url_to_validate):
        """Validate URL format"""
        url_regex = re.compile(
            r"^https?://"  # http:// or https://
            r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|"  # domain
            r"localhost|"  # localhost
            r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"  # or IP
            r"(?::\d+)?"  # optional port
            r"(?:/?|[/?]\S+)$",
            re.IGNORECASE,
        )
        return url_regex.match(url_to_validate) is not None

    @staticmethod
    def raise_if_ip_not_valid(ip: str):
        """Raises an error if ip is not valid"""
        if not Validator.validate_ipv4(ip) and not Validator.validate_ipv6(ip):
            raise ValueError(f'IP "{ip}" is not a type of IPv4 or IPv6')

    @staticmethod
    def raise_if_domain_not_valid(domain: str):
        """Raises an error if domain is not valid"""
        if not Validator.validate_domain(domain):
            raise ValueError(f'Domain "{domain}" is not a valid domain address')

    @staticmethod
    def raise_if_hash_not_valid(file_hash: str):
        """Raises an error if file_hash is not valid"""
        if not Validator.validate_hash(file_hash):
            raise ValueError(f'Hash "{file_hash}" is not a valid hash')

    @staticmethod
    def raise_if_url_not_valid(url: str):
        """Raises an error if URL is not valid"""
        if not Validator.validate_url(url):
            raise ValueError(f'URL "{url}" is not a valid URL')


def build_entry_context(raw_response: dict, entity_value: str, entity_type: str) -> dict:
    """Build context entry from API response"""
    data = raw_response.get("data", {})

    # Get and round score to 2 decimal places
    score = data.get("score")
    if score is not None:
        score = round(float(score), 2)

    context_entry = {
        "Entity": entity_value,
        "EntityType": entity_type,
        "Score": score,
        "IsWhitelisted": data.get("is_whitelisted", False),
        "FindingSources": [],
    }

    # Process finding sources
    finding_sources = data.get("finding_sources", [])
    for source in finding_sources:
        source_entry = {
            "SourceName": source.get("source_name"),
            "MainCategory": source.get("main_category"),
            "MaintainerName": source.get("maintainer_name"),
            "FirstSeenDate": source.get("first_seen_date"),
            "LastSeenDate": source.get("last_seen_date"),
            "SeenCount": source.get("seen_count"),
        }
        context_entry["FindingSources"].append(source_entry)

    return context_entry


def detect_entity_type(entity: str) -> str:
    """Automatically detect the type of an entity"""
    entity = entity.strip()

    # Check if it's a URL (starts with http:// or https://)
    if entity.startswith(("http://", "https://")):
        return "url"

    # Check if it's an IP address
    if Validator.validate_ipv4(entity) or Validator.validate_ipv6(entity):
        return "ip"

    # Check if it's a hash
    if Validator.validate_hash(entity):
        return "hash"

    # Check if it's a domain
    if Validator.validate_domain(entity):
        return "hostname"

    # If nothing matches, raise an error
    raise ValueError(f"Unable to determine entity type for: {entity}")


def process_entity_by_type(client: Client, entity: str, entity_type: str) -> dict:
    """Process a single entity based on its type"""
    raw_response = client.get_entity_reputation(entity, entity_type)

    if raw_response.get("is_success"):
        data = raw_response.get("data", {})

        if data.get("is_whitelisted"):
            score = 1
        elif (api_score := data.get("score")) is not None:
            score = calculate_dbot_score(api_score)
        else:
            score = 0

        context_entry = build_entry_context(raw_response, entity, entity_type)
        context_entry["DetectedType"] = entity_type

        return {
            "entity": entity,
            "entity_type": entity_type,
            "success": True,
            "context": context_entry,
            "raw_response": raw_response,
            "dbot_score": score,
        }
    else:
        return {
            "entity": entity,
            "entity_type": entity_type,
            "success": False,
            "error": raw_response.get("message", "Unknown error"),
            "raw_response": raw_response,
        }


""" COMMAND FUNCTIONS """


def test_module(client: Client) -> str:
    """Tests API connectivity and authentication"""
    try:
        demisto.debug("Starting test_module...")
        response = client.check_auth()
        demisto.debug(f"Test response received: {response}")

        if response and response.get("is_success"):
            demisto.debug("Test successful")
            return "ok"
        else:
            error_msg = response.get("message", "Unknown error") if response else "No response from API"
            demisto.error(f"Test failed: {error_msg}")
            raise DemistoException(f"API test failed: {error_msg}")
    except DemistoException:
        raise
    except Exception as e:
        demisto.error(f"Test module exception: {str(e)}")
        error_details = f"Connection failed: {str(e)}\n\n"
        error_details += "Please check:\n"
        error_details += "1. API Key is correct\n"
        error_details += "2. Network connectivity to platform.socradar.com\n"
        error_details += "3. Firewall allows HTTPS outbound connections"
        raise DemistoException(error_details)


def ip_command(client: Client, args: dict[str, Any], reliability: str = None) -> list[CommandResults]:
    """Returns SOCRadar reputation details for the given IP entity."""
    ips = args.get("ip", "")
    ip_list: list = argToList(ips)

    command_results_list: list[CommandResults] = []

    for ip_to_score in ip_list:
        try:
            Validator.raise_if_ip_not_valid(ip_to_score)

            raw_response = client.get_entity_reputation(ip_to_score, "ip")

            if raw_response.get("is_success"):
                data = raw_response.get("data", {})

                if data.get("is_whitelisted"):
                    score = 1
                elif (api_score := data.get("score")) is not None:
                    score = calculate_dbot_score(api_score)
                else:
                    score = 0

                title = f"SOCRadar Rapid Reputation - Analysis results for IP: {ip_to_score}"

                context_entry = build_entry_context(raw_response, ip_to_score, "ip")
                human_readable = tableToMarkdown(title, context_entry)

                dbot_score = Common.DBotScore(
                    indicator=ip_to_score,
                    indicator_type=DBotScoreType.IP,
                    integration_name=INTEGRATION_NAME,
                    score=score,
                    reliability=reliability,
                )

                ip_object = Common.IP(ip=ip_to_score, dbot_score=dbot_score)

                command_results_list.append(
                    CommandResults(
                        outputs_prefix="SOCRadarRapidReputation.IP",
                        outputs_key_field="Entity",
                        readable_output=human_readable,
                        raw_response=raw_response,
                        outputs=context_entry,
                        indicator=ip_object,
                    )
                )
            else:
                message = f"Error at scoring IP {ip_to_score}: {raw_response.get('message', 'Unknown error')}"
                command_results_list.append(CommandResults(readable_output=message))
        except ValueError as e:
            command_results_list.append(CommandResults(readable_output=str(e)))
        except Exception as e:
            command_results_list.append(CommandResults(readable_output=f"Error processing IP {ip_to_score}: {str(e)}"))

    if not command_results_list:
        command_results_list = [
            CommandResults(readable_output="SOCRadar Rapid Reputation could not find any results for the given IP(s).")
        ]

    return command_results_list


def domain_command(client: Client, args: dict[str, Any], reliability: str = None) -> list[CommandResults]:
    """Returns SOCRadar reputation details for the given domain entity."""
    domains = args.get("domain", "")
    domain_list: list = argToList(domains)

    command_results_list: list[CommandResults] = []

    for domain_to_score in domain_list:
        try:
            Validator.raise_if_domain_not_valid(domain_to_score)

            raw_response = client.get_entity_reputation(domain_to_score, "hostname")

            if raw_response.get("is_success"):
                data = raw_response.get("data", {})

                if data.get("is_whitelisted"):
                    score = 1
                elif (api_score := data.get("score")) is not None:
                    score = calculate_dbot_score(api_score)
                else:
                    score = 0

                title = f"SOCRadar Rapid Reputation - Analysis results for Domain: {domain_to_score}"

                context_entry = build_entry_context(raw_response, domain_to_score, "hostname")
                human_readable = tableToMarkdown(title, context_entry)

                dbot_score = Common.DBotScore(
                    indicator=domain_to_score,
                    indicator_type=DBotScoreType.DOMAIN,
                    integration_name=INTEGRATION_NAME,
                    score=score,
                    reliability=reliability,
                )

                domain_object = Common.Domain(domain=domain_to_score, dbot_score=dbot_score)

                command_results_list.append(
                    CommandResults(
                        outputs_prefix="SOCRadarRapidReputation.Domain",
                        outputs_key_field="Entity",
                        readable_output=human_readable,
                        raw_response=raw_response,
                        outputs=context_entry,
                        indicator=domain_object,
                    )
                )
            else:
                message = f"Error at scoring domain {domain_to_score}: {raw_response.get('message', 'Unknown error')}"
                command_results_list.append(CommandResults(readable_output=message))
        except ValueError as e:
            command_results_list.append(CommandResults(readable_output=str(e)))
        except Exception as e:
            command_results_list.append(CommandResults(readable_output=f"Error processing domain {domain_to_score}: {str(e)}"))

    if not command_results_list:
        command_results_list = [
            CommandResults(readable_output="SOCRadar Rapid Reputation could not find any results for the given domain(s).")
        ]

    return command_results_list


def url_command(client: Client, args: dict[str, Any], reliability: str = None) -> list[CommandResults]:
    """Returns SOCRadar reputation details for the given URL entity."""
    urls = args.get("url", "")
    url_list: list = argToList(urls)

    command_results_list: list[CommandResults] = []

    for url_to_score in url_list:
        try:
            Validator.raise_if_url_not_valid(url_to_score)

            raw_response = client.get_entity_reputation(url_to_score, "url")

            if raw_response.get("is_success"):
                data = raw_response.get("data", {})

                if data.get("is_whitelisted"):
                    score = 1
                elif (api_score := data.get("score")) is not None:
                    score = calculate_dbot_score(api_score)
                else:
                    score = 0

                title = f"SOCRadar Rapid Reputation - Analysis results for URL: {url_to_score}"

                context_entry = build_entry_context(raw_response, url_to_score, "url")
                human_readable = tableToMarkdown(title, context_entry)

                dbot_score = Common.DBotScore(
                    indicator=url_to_score,
                    indicator_type=DBotScoreType.URL,
                    integration_name=INTEGRATION_NAME,
                    score=score,
                    reliability=reliability,
                )

                url_object = Common.URL(url=url_to_score, dbot_score=dbot_score)

                command_results_list.append(
                    CommandResults(
                        outputs_prefix="SOCRadarRapidReputation.URL",
                        outputs_key_field="Entity",
                        readable_output=human_readable,
                        raw_response=raw_response,
                        outputs=context_entry,
                        indicator=url_object,
                    )
                )
            else:
                message = f"Error at scoring URL {url_to_score}: {raw_response.get('message', 'Unknown error')}"
                command_results_list.append(CommandResults(readable_output=message))
        except ValueError as e:
            command_results_list.append(CommandResults(readable_output=str(e)))
        except Exception as e:
            command_results_list.append(CommandResults(readable_output=f"Error processing URL {url_to_score}: {str(e)}"))

    if not command_results_list:
        command_results_list = [
            CommandResults(readable_output="SOCRadar Rapid Reputation could not find any results for the given URL(s).")
        ]

    return command_results_list


def file_command(client: Client, args: dict[str, Any], reliability: str = None) -> list[CommandResults]:
    """Returns SOCRadar reputation details for the given file hash entity."""
    file_hashes = args.get("file", "")
    file_hash_list: list = argToList(file_hashes)

    command_results_list: list[CommandResults] = []

    for hash_to_score in file_hash_list:
        try:
            Validator.raise_if_hash_not_valid(hash_to_score)
            hash_type = get_hash_type(hash_to_score)

            raw_response = client.get_entity_reputation(hash_to_score, "hash")

            if raw_response.get("is_success"):
                data = raw_response.get("data", {})

                if data.get("is_whitelisted"):
                    score = 1
                elif (api_score := data.get("score")) is not None:
                    score = calculate_dbot_score(api_score)
                else:
                    score = 0

                title = f"SOCRadar Rapid Reputation - Analysis results for Hash: {hash_to_score}"

                context_entry = build_entry_context(raw_response, hash_to_score, "hash")
                human_readable = tableToMarkdown(title, context_entry)

                dbot_score = Common.DBotScore(
                    indicator=hash_to_score,
                    indicator_type=DBotScoreType.FILE,
                    integration_name=INTEGRATION_NAME,
                    score=score,
                    reliability=reliability,
                )

                file_object = Common.File(dbot_score=dbot_score)

                # Set hash based on type
                if hash_type == "sha256":
                    file_object.sha256 = hash_to_score
                elif hash_type == "sha1":
                    file_object.sha1 = hash_to_score
                elif hash_type == "md5":
                    file_object.md5 = hash_to_score

                command_results_list.append(
                    CommandResults(
                        outputs_prefix="SOCRadarRapidReputation.File",
                        outputs_key_field="Entity",
                        readable_output=human_readable,
                        raw_response=raw_response,
                        outputs=context_entry,
                        indicator=file_object,
                    )
                )
            else:
                message = f"Error at scoring file hash {hash_to_score}: {raw_response.get('message', 'Unknown error')}"
                command_results_list.append(CommandResults(readable_output=message))
        except ValueError as e:
            command_results_list.append(CommandResults(readable_output=str(e)))
        except Exception as e:
            command_results_list.append(CommandResults(readable_output=f"Error processing hash {hash_to_score}: {str(e)}"))

    if not command_results_list:
        command_results_list = [
            CommandResults(readable_output="SOCRadar Rapid Reputation could not find any results for the given file hash(es).")
        ]

    return command_results_list


def socradar_bulk_check_command(client: Client, args: dict[str, Any]) -> list[CommandResults]:
    """Check reputation for a mixed list of indicators with automatic type detection."""
    indicators = args.get("indicators", "")
    indicator_list: list = argToList(indicators)

    if not indicator_list:
        return [CommandResults(readable_output="No indicators provided.")]

    # Check maximum limit to avoid XSOAR argument/output size limits
    if len(indicator_list) > MAX_BULK_CHECK_INDICATORS:
        error_msg = (
            f"⚠️ **Too Many Indicators!**\n\n"
            f"**Maximum allowed:** {MAX_BULK_CHECK_INDICATORS} indicators\n"
            f"**You provided:** {len(indicator_list)} indicators\n\n"
            f"**Why this limit?**\n"
            f"- XSOAR has command argument size limits (~10KB)\n"
            f"- War Room output size limits (~500KB)\n"
            f"- Context data size limits (~1MB)\n"
            f"- Rate limit: 1 req/sec = {MAX_BULK_CHECK_INDICATORS} sec (~{MAX_BULK_CHECK_INDICATORS / 60:.1f} min)\n\n"
            f"**Solution:** Split into batches of {MAX_BULK_CHECK_INDICATORS} or less\n\n"
            f"**Example:**\n"
            f"```\n"
            f'Batch 1: !socradar-bulk-check indicators="[first {MAX_BULK_CHECK_INDICATORS} indicators]"\n'
            f'Batch 2: !socradar-bulk-check indicators="[next {MAX_BULK_CHECK_INDICATORS} indicators]"\n'
            f"```\n\n"
            f"**Recommended:** Use 10-20 indicators per batch for best performance."
        )
        return [CommandResults(readable_output=error_msg)]

    command_results_list: list[CommandResults] = []

    # Warning for large batches (over 50 indicators)
    if len(indicator_list) > 50:
        warning_msg = (
            f"⚠️ **Large Batch Detected**\n\n"
            f"Indicators: {len(indicator_list)}\n"
            f"Estimated time: ~{len(indicator_list)} seconds ({len(indicator_list) / 60:.1f} minutes)\n"
            f"Rate limit: 1 request/second\n\n"
            f"💡 **Tip:** For faster results, use smaller batches (10-20 indicators)."
        )
        command_results_list.append(CommandResults(readable_output=warning_msg))

    summary_data: dict[str, Any] = {
        "total": len(indicator_list),
        "processed": 0,
        "failed": 0,
        "failed_details": [],
        "by_type": {"ip": 0, "hostname": 0, "url": 0, "hash": 0},
        "by_score_range": {"0-25": 0, "26-50": 0, "51-75": 0, "76-100": 0, "whitelisted": 0},
    }

    for indicator in indicator_list:
        try:
            # Detect entity type
            entity_type = detect_entity_type(indicator)
            summary_data["by_type"][entity_type] += 1

            # Process the entity
            result = process_entity_by_type(client, indicator, entity_type)

            if result["success"]:
                summary_data["processed"] += 1
                context = result["context"]
                score = context.get("Score", 0) or 0

                # Score range classification
                if context.get("IsWhitelisted"):
                    summary_data["by_score_range"]["whitelisted"] += 1
                    score_range = "Whitelisted"
                elif score >= 76:
                    summary_data["by_score_range"]["76-100"] += 1
                    score_range = "76-100"
                elif score >= 51:
                    summary_data["by_score_range"]["51-75"] += 1
                    score_range = "51-75"
                elif score >= 26:
                    summary_data["by_score_range"]["26-50"] += 1
                    score_range = "26-50"
                else:
                    summary_data["by_score_range"]["0-25"] += 1
                    score_range = "0-25"

                title = f"SOCRadar - {entity_type.upper()}: {indicator}"
                summary_dict = {
                    "Entity": indicator,
                    "Type": entity_type,
                    "Score": score,
                    "ScoreRange": score_range,
                    "IsWhitelisted": context.get("IsWhitelisted", False),
                    "Sources": len(context.get("FindingSources", [])),
                }

                human_readable = tableToMarkdown(title, summary_dict)

                command_results_list.append(
                    CommandResults(
                        outputs_prefix="SOCRadarRapidReputation.BulkCheck",
                        outputs_key_field="Entity",
                        readable_output=human_readable,
                        raw_response=result["raw_response"],
                        outputs=context,
                    )
                )
            else:
                summary_data["failed"] += 1
                error_reason = result.get("error", "Unknown error")
                summary_data["failed_details"].append({"Entity": indicator, "Reason": error_reason})
                error_msg = f"❌ Failed: {indicator} - {error_reason}"
                command_results_list.append(CommandResults(readable_output=error_msg))

        except Exception as e:
            summary_data["failed"] += 1
            error_reason = str(e)
            summary_data["failed_details"].append({"Entity": indicator, "Reason": error_reason})
            error_msg = f"❌ Error: {indicator} - {error_reason}"
            command_results_list.append(CommandResults(readable_output=error_msg))

    # Build summary with score ranges
    summary_table_data = [
        {"Metric": "Total Indicators", "Count": summary_data["total"]},
        {"Metric": "Successfully Processed", "Count": summary_data["processed"]},
        {"Metric": "Failed", "Count": summary_data["failed"]},
        {"Metric": "" * 20, "Count": "" * 5},
        {"Metric": "Score 76-100", "Count": summary_data["by_score_range"]["76-100"]},
        {"Metric": "Score 51-75", "Count": summary_data["by_score_range"]["51-75"]},
        {"Metric": "Score 26-50", "Count": summary_data["by_score_range"]["26-50"]},
        {"Metric": "Score 0-25", "Count": summary_data["by_score_range"]["0-25"]},
        {"Metric": "Whitelisted", "Count": summary_data["by_score_range"]["whitelisted"]},
    ]

    summary_table = tableToMarkdown("📊 Bulk Check Summary", summary_table_data)

    # Add failed details if any
    if summary_data["failed_details"]:
        failed_table = tableToMarkdown("❌ Failed Indicators", summary_data["failed_details"], headers=["Entity", "Reason"])
        summary_table += "\n\n" + failed_table

    command_results_list.insert(
        0,
        CommandResults(
            outputs_prefix="SOCRadarRapidReputation.BulkCheckSummary", readable_output=summary_table, outputs=summary_data
        ),
    )

    return command_results_list


def socradar_reputation_command(client: Client, args: dict[str, Any], reliability: str = None) -> list[CommandResults]:
    """Generic reputation check for any entity type."""
    entity_value = args.get("entity_value")
    entity_type = args.get("entity_type")

    if not entity_value or not entity_type:
        return [CommandResults(readable_output="Both entity_value and entity_type are required.")]

    command_results_list: list[CommandResults] = []

    try:
        raw_response = client.get_entity_reputation(entity_value, entity_type)

        if raw_response.get("is_success"):
            data = raw_response.get("data", {})

            if data.get("is_whitelisted"):
                score = 1
            elif (api_score := data.get("score")) is not None:
                score = calculate_dbot_score(api_score)
            else:
                score = 0

            title = f"SOCRadar Rapid Reputation - Analysis for {entity_type.upper()}: {entity_value}"

            context_entry = build_entry_context(raw_response, entity_value, entity_type)
            human_readable = tableToMarkdown(title, context_entry)

            # Determine DBot type based on entity_type
            if entity_type == "ip":
                dbot_type = DBotScoreType.IP
            elif entity_type == "hostname":
                dbot_type = DBotScoreType.DOMAIN
            elif entity_type == "url":
                dbot_type = DBotScoreType.URL
            elif entity_type == "hash":
                dbot_type = DBotScoreType.FILE
            else:
                dbot_type = DBotScoreType.IP  # default

            dbot_score = Common.DBotScore(
                indicator=entity_value,
                indicator_type=dbot_type,
                integration_name=INTEGRATION_NAME,
                score=score,
                reliability=reliability,
            )

            # Initialize indicator_object with Union type
            indicator_object: Common.IP | Common.Domain | Common.URL | Common.File | None = None

            # Create appropriate indicator object based on entity type
            if entity_type == "ip":
                indicator_object = Common.IP(ip=entity_value, dbot_score=dbot_score)
            elif entity_type == "hostname":
                indicator_object = Common.Domain(domain=entity_value, dbot_score=dbot_score)
            elif entity_type == "url":
                indicator_object = Common.URL(url=entity_value, dbot_score=dbot_score)
            elif entity_type == "hash":
                indicator_object = Common.File(dbot_score=dbot_score)
                hash_type = get_hash_type(entity_value)
                if hash_type == "sha256":
                    indicator_object.sha256 = entity_value
                elif hash_type == "sha1":
                    indicator_object.sha1 = entity_value
                elif hash_type == "md5":
                    indicator_object.md5 = entity_value
            else:
                indicator_object = None

            command_results_list.append(
                CommandResults(
                    outputs_prefix="SOCRadarRapidReputation.Reputation",
                    outputs_key_field="Entity",
                    readable_output=human_readable,
                    raw_response=raw_response,
                    outputs=context_entry,
                    indicator=indicator_object,
                )
            )
        else:
            message = f"Error checking {entity_type} {entity_value}: {raw_response.get('message', 'Unknown error')}"
            command_results_list.append(CommandResults(readable_output=message))
    except Exception as e:
        command_results_list.append(CommandResults(readable_output=f"Error: {str(e)}"))

    return command_results_list


""" MAIN FUNCTION """


def main() -> None:
    """main function, parses params and runs command functions"""

    params = demisto.params()
    api_key = params.get("apikey", {}).get("password")
    base_url = SOCRADAR_API_ENDPOINT
    verify_certificate = not params.get("insecure", False)
    proxy = params.get("proxy", False)
    reliability = params.get("integrationReliability")

    demisto.debug(f"Command being called is {demisto.command()}")
    try:
        client = Client(base_url=base_url, api_key=api_key, verify=verify_certificate, proxy=proxy)
        command = demisto.command()

        if command == "test-module":
            demisto.debug("Executing test-module command")
            result = test_module(client)
            demisto.debug(f"Test module result: {result}")
            return_results(result)
        elif command == "ip":
            demisto.debug("Executing ip command")
            return_results(ip_command(client, demisto.args(), reliability))
        elif command == "domain":
            demisto.debug("Executing domain command")
            return_results(domain_command(client, demisto.args(), reliability))
        elif command == "url":
            demisto.debug("Executing url command")
            return_results(url_command(client, demisto.args(), reliability))
        elif command == "file":
            demisto.debug("Executing file command")
            return_results(file_command(client, demisto.args(), reliability))
        elif command == "socradar-reputation":
            demisto.debug("Executing socradar-reputation command")
            return_results(socradar_reputation_command(client, demisto.args(), reliability))
        elif command == "socradar-bulk-check":
            demisto.debug("Executing socradar-bulk-check command")
            return_results(socradar_bulk_check_command(client, demisto.args()))
        else:
            demisto.debug(f"Unknown command: {command}")
            return_error(f"Command {command} is not supported")

    except Exception as e:
        demisto.error(traceback.format_exc())
        return_error(f"Failed to execute {demisto.command()} command.\nError:\n{str(e)}")


""" ENTRY POINT """


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()