Proofpoint Threat Response

Use the Proofpoint Threat Response integration to orchestrate and automate incident response.

Network Security · Proofpoint Threat Response

Details

IDProofpoint Threat Response
ProviderThoma Bravo
CategoryNetwork Security
From Version5.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM EDR Cortex Cloud Cloud Runtime Security

README

Use the Proofpoint Threat Response integration to orchestrate and automate incident response.

Configure Proofpoint Threat Response in Cortex

Parameter Description Required
Server URL (e.g. https://192.168.0.1)   True
API Key   True
Trust any certificate (not secure)   False
Use system proxy settings   False
Fetch incidents   False
Incident type   False
First fetch timestamp (“number” “time unit”, e.g., 12 hours, 7 days) The time range for the initial data fetch. If timeout errors occur, consider changing this value. False
Fetch limit - maximum number of incidents per fetch   False
Fetch delta - The delta time in each batch. e.g. 1 hour, 3 minutes. The time range between create_after and created_before that is sent to the API when fetching older incidents. If timeout errors occur, consider changing this value. False
Fetch incidents with specific event sources. Can be a list of comma separated values.   False
Fetch incidents with specific ‘Abuse Disposition’ values. Can be a list of comma separated values.   False
Fetch incident with specific states.   False
POST URL of the JSON alert source. You can find this value by navigating to Sources -> JSON event source -> POST URL. False

Commands

You can execute these commands from the 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.

proofpoint-tr-get-list


Gets items for the specified list.

Base Command

proofpoint-tr-get-list

Input

Argument Name Description Required
list-id The ID of the list. Required

Context Output

There is no context output for this command.

proofpoint-tr-add-to-list


Adds a member to the specified list.

Base Command

proofpoint-tr-add-to-list

Input

Argument Name Description Required
list-id The list to add a member to. Required
indicator A comma-separated list of indicator values. Can be IP addresses, URLs, domains, or file hashes.
For example: “192.168.1.1,192.168.1.2”.
Required
comment A comment about the member. Optional
expiration The expiration of the member. Optional

Context Output

There is no context output for this command.

proofpoint-tr-block-ip


Adds the supplied IP addresses to the specified IP block list.

Base Command

proofpoint-tr-block-ip

Input

Argument Name Description Required
ip A comma-separated list of IP addresses to block list. Required
expiration The date and time the supplied IP addresses should be removed from the block list, in the format YYYY-MM-DDTHH:MM:SSZ.
For example: 2020-02-02T19:00:00Z.
Optional
blacklist_ip The ID of the IP block list. Required

Context Output

There is no context output for this command.

proofpoint-tr-block-domain


Adds the supplied domains to the specified block list.

Base Command

proofpoint-tr-block-domain

Input

Argument Name Description Required
domain A comma-separated list of domains to add to the block list. Required
expiration The date and time the supplied IP addresses should be removed from the block list, in the format YYYY-MM-DDTHH:MM:SSZ.
For example: 2020-02-02T19:00:00Z.
Optional
blacklist_domain The ID of the domain block list. Required

Context Output

There is no context output for this command.

proofpoint-tr-search-indicator


Returns indicators from the specified list, according to the defined filter.

Base Command

proofpoint-tr-search-indicator

Input

Argument Name Description Required
list-id The ID of the list in which to search. Required
filter The filter for the indicator search.
For example, “1.1” will return [1.1.1.1, 22.22.1.1, 1.1.22.22].
Required

Context Output

There is no context output for this command.

proofpoint-tr-delete-indicator


Deletes an indicator from the specified list.

Base Command

proofpoint-tr-delete-indicator

Input

Argument Name Description Required
list-id ID of the list from which to delete indicators. Required
indicator The indicator value to delete from the list. Can be an IP address, URL, domain, or file hash.
For example: “demisto.com”.
Required

Context Output

There is no context output for this command.

proofpoint-tr-block-url


Adds the supplied URLs to the specified URL block list.

Base Command

proofpoint-tr-block-url

Input

Argument Name Description Required
url A comma-separated list of URLs to add to the URL block list. Required
expiration The date and time the supplied URLs should be removed from the block list, in the format YYYY-MM-DDTHH:MM:SSZ.
For example: 2020-02-02T19:00:00Z.
Optional
blacklist_url The ID of the URL block list. Required

Context Output

There is no context output for this command.

proofpoint-tr-block-hash


Adds the supplied file hashes to the specified file hash block list.

Base Command

proofpoint-tr-block-hash

Input

Argument Name Description Required
hash A comma-separated list of file hashes to add to the file hash block list. Required
expiration The date and time the supplied file hashes should be removed from the block list, in the format YYYY-MM-DDTHH:MM:SSZ.
For example: 2020-02-02T19:00:00Z.
Optional
blacklist_hash The ID of the hash block list. Required

Context Output

There is no context output for this command.

proofpoint-tr-list-incidents


Retrieves all incident metadata from Threat Response by specifying filter criteria such as the state of the incident or time of closure.

Base Command

proofpoint-tr-list-incidents

Input

Argument Name Description Required
state State of the incidents to retrieve. Possible values are: new, open, assigned, closed, ignored. Optional
created_after Retrieve incidents that were created after this date, in ISO 8601 format (UTC).
Example: 2020-02-22 or 2020-02-22T00:00:00Z. Possible values are: .
Optional
created_before Retrieve incidents that were created before this date, in ISO 8601 format (UTC).
Example: 2020-02-22 or 2020-02-22T00:00:00Z.
Optional
closed_after Retrieve incidents that were closed after this date, in ISO 8601 format (UTC).
Example: 2020-02-22 or 2020-02-22T00:00:00Z.
Optional
closed_before Retrieve incidents that were closed before this date, in ISO 8601 format (UTC).
Example: 2020-02-22 or 2020-02-22T00:00:00Z.
Optional
expand_events If false, will return an array of event IDs instead of full event objects. This will significantly speed up the response time of the API for incidents with large numbers of alerts. Optional
limit The maximum number of incidents to return. The default value is 50. Required

Context Output

Path Type Description
ProofPointTRAP.Incident.id Number The incident ID.
ProofPointTRAP.Incident.summary String The summary of the incident.
ProofPointTRAP.Incident.score Number The score of the incident from Proofpoint.
ProofPointTRAP.Incident.state String The state of the incident. Can be - Open, Closed, New, Assigned, Ignored.
ProofPointTRAP.Incident.created_at Date The date the incident was created.
ProofPointTRAP.Incident.updated_at Date The date the incident was last updated.
ProofPointTRAP.Incident.event_count Number The number of events attached to the incident.
ProofPointTRAP.Incident.false_positive_count Number The number of false positive events in the incident.
ProofPointTRAP.Incident.event_sources String The sources of the events.
ProofPointTRAP.Incident.assignee String The user assigned to the incident.
ProofPointTRAP.Incident.team String The team assigned to the incident.
ProofPointTRAP.Incident.hosts.attacker String The host attacker.
ProofPointTRAP.Incident.hosts.forensics String The host forensics.
ProofPointTRAP.Incident.incident_field_values.Severity String The severity of the incident.
ProofPointTRAP.Incident.incident_field_values.Abuse_disposition String The abuse disposition of the incident.
ProofPointTRAP.Incident.incident_field_values.Attack_vector String The attack vector of the incident.
ProofPointTRAP.Incident.incident_field_values.Classification String The classification of the incident.
ProofPointTRAP.Incident.events.id Number The event ID.
ProofPointTRAP.Incident.events.category String The event category.
ProofPointTRAP.Incident.events.alertType String The alert type of the event.
ProofPointTRAP.Incident.events.severity String The severity of the event.
ProofPointTRAP.Incident.events.source String The source of the event.
ProofPointTRAP.Incident.events.state String The state of the event.
ProofPointTRAP.Incident.events.attackDirection String The attack direction of the event.
ProofPointTRAP.Incident.events.received Date The time the incident was received.
ProofPointTRAP.Incident.events.emails.sender String The sender of the email.
ProofPointTRAP.Incident.events.emails.recipient String The recipient of the email.
ProofPointTRAP.Incident.events.emails.message_Id String The message ID of the email.
ProofPointTRAP.Incident.events.emails.message_delivery_time Number The delivery time of the message.
ProofPointTRAP.Incident.events.attackers.location String The location of the attacker.
ProofPointTRAP.Incident.events.falsePositive Boolean Whether this incident is a false positive.
ProofPointTRAP.Incident.events.threatname String The threat name.
ProofPointTRAP.Incident.events.description String The description of the event.
ProofPointTRAP.Incident.events.malwareName String The malware name.
ProofPointTRAP.Incident.quarantine_results.alertSource String The alert source.
ProofPointTRAP.Incident.quarantine_results.startTime Date The start time of the result.
ProofPointTRAP.Incident.quarantine_results.endTime Date The end time of the result.
ProofPointTRAP.Incident.quarantine_results.status String The status of the result.
ProofPointTRAP.Incident.quarantine_results.recipientType String The recipient type.
ProofPointTRAP.Incident.quarantine_results.recipient String The recipient email address.
ProofPointTRAP.Incident.quarantine_results.messageId String The message ID.
ProofPointTRAP.Incident.quarantine_results.isRead Boolean Whether the message has been read.
ProofPointTRAP.Incident.quarantine_results.wasUndone String Whether the message was undone.
ProofPointTRAP.Incident.quarantine_results.details String The details about the result.
ProofPointTRAP.Incident.successful_quarantines Number The number of successful quarantines.
ProofPointTRAP.Incident.failed_quarantines Number The number of failed quarantines.
ProofPointTRAP.Incident.pending_quarantines Number The number of pending quarantines.
ProofPointTRAP.Incident.events.emails.body String The body of the email.
ProofPointTRAP.Incident.events.emails.body_type String The format of the body.
ProofPointTRAP.Incident.events.emails.headers Unknown The email headers.
ProofPointTRAP.Incident.events.emails.urls Unknown The list of URLs from the email.
ProofPoint.Incident.event_ids Unknown The list of IDs attached to the incident.

proofpoint-tr-get-incident


Retrieves incident metadata from Threat Response.

Base Command

proofpoint-tr-get-incident

Input

Argument Name Description Required
incident_id The ID value of the incident to retrieve (e.g. for incident INC-4000, the input for this argument should be 4000). Required
expand_events If false, will return an array of event IDs instead of full event objects. This will significantly speed up the response time of the API for incidents with large numbers of alerts. Optional

Context Output

Path Type Description
ProofPointTRAP.Incident.id Number The incident ID.
ProofPointTRAP.Incident.summary String The summary of the incident.
ProofPointTRAP.Incident.score Number The score of the incident from Proofpoint.
ProofPointTRAP.Incident.state String The state of the incident. Can be - Open, Closed, New, Assigned, Ignored.
ProofPointTRAP.Incident.created_at Date The date the incident was created.
ProofPointTRAP.Incident.updated_at Date The date the incident was last updated.
ProofPointTRAP.Incident.event_count Number The number of events attached to the incident.
ProofPointTRAP.Incident.false_positive_count Number The number of false positive events in the incident.
ProofPointTRAP.Incident.event_sources String The sources of the events.
ProofPointTRAP.Incident.assignee String The user assigned to the incident.
ProofPointTRAP.Incident.team String The team assigned to the incident.
ProofPointTRAP.Incident.hosts.attacker String The host attacker.
ProofPointTRAP.Incident.hosts.forensics String The host forensics.
ProofPointTRAP.Incident.incident_field_values.Severity String The severity of the incident.
ProofPointTRAP.Incident.incident_field_values.Abuse_disposition String The abuse disposition of the incident.
ProofPointTRAP.Incident.incident_field_values.Attack_vector String The attack vector of the incident.
ProofPointTRAP.Incident.incident_field_values.Classification String The classification of the incident.
ProofPointTRAP.Incident.events.id Number The event ID.
ProofPointTRAP.Incident.events.category String The event category.
ProofPointTRAP.Incident.events.alertType String The alert type of the event.
ProofPointTRAP.Incident.events.severity String The severity of the event.
ProofPointTRAP.Incident.events.source String The source of the event.
ProofPointTRAP.Incident.events.state String The state of the event.
ProofPointTRAP.Incident.events.attackDirection String The attack direction of the event
ProofPointTRAP.Incident.events.received Date The date the incident was received.
ProofPointTRAP.Incident.events.emails.sender String The sender of the email.
ProofPointTRAP.Incident.events.emails.recipient String The recipient of the email.
ProofPointTRAP.Incident.events.emails.message_Id String The message ID of the email.
ProofPointTRAP.Incident.events.emails.message_delivery_time Number The time the message was delivered.
ProofPointTRAP.Incident.events.attackers.location String The location of the attacker.
ProofPointTRAP.Incident.events.falsePositive Boolean Whether this incident is a false positive.
ProofPointTRAP.Incident.events.threatname String The threat name.
ProofPointTRAP.Incident.events.description String The description of the event.
ProofPointTRAP.Incident.events.malwareName String The malware name.
ProofPointTRAP.Incident.quarantine_results.alertSource String The alert source.
ProofPointTRAP.Incident.quarantine_results.startTime Date The start time of the result.
ProofPointTRAP.Incident.quarantine_results.endTime Date The end time of the result.
ProofPointTRAP.Incident.quarantine_results.status String The status of the result.
ProofPointTRAP.Incident.quarantine_results.recipientType String The recipient type.
ProofPointTRAP.Incident.quarantine_results.recipient String The recipient email address.
ProofPointTRAP.Incident.quarantine_results.messageId String The message ID.
ProofPointTRAP.Incident.quarantine_results.isRead Boolean Whether the message has been read.
ProofPointTRAP.Incident.quarantine_results.wasUndone String Whether the message was undone.
ProofPointTRAP.Incident.quarantine_results.details String The details about the result.
ProofPointTRAP.Incident.successful_quarantines Number The number of successful quarantines.
ProofPointTRAP.Incident.failed_quarantines Number The number of failed quarantines.
ProofPointTRAP.Incident.pending_quarantines Number The number of pending quarantines.
ProofPointTRAP.Incident.events.emails.body String The body of the email.
ProofPointTRAP.Incident.events.emails.body_type String The format of the body.
ProofPointTRAP.Incident.events.emails.headers Unknown The email headers.
ProofPointTRAP.Incident.events.emails.urls Unknown The list of URLs from the email.
ProofPoint.Incident.event_ids Unknown The list of IDs attached to the incident.

proofpoint-tr-update-incident-comment


Adds comments to an existing Threat Response incident, by incident ID.

Base Command

proofpoint-tr-update-incident-comment

Input

Argument Name Description Required
incident_id The ID value of the incident to add the comment to (e.g. for incident INC-4000, the input for this argument should be 4000). Required
details The details of the comments. Required
comments The summary of the comments. Required

Context Output

Path Type Description
ProofPointTRAP.IncidentComment.id Number The ID of the comment.
ProofPointTRAP.IncidentComment.incident_id Number The ID of the incident.
ProofPointTRAP.IncidentComment.response_id Number The ID of the response.
ProofPointTRAP.IncidentComment.user_id String The ID of the user.
ProofPointTRAP.IncidentComment.history_type String The history type.
ProofPointTRAP.IncidentComment.state_from String The state from of the incident.
ProofPointTRAP.IncidentComment.state_to String The state to of the incident.
ProofPointTRAP.IncidentComment.summary String The summary of the comments.
ProofPointTRAP.IncidentComment.detail String The details of the comment.
ProofPointTRAP.IncidentComment.created_at Date The date the incident was created.
ProofPointTRAP.IncidentComment.updated_at Date The date the incident was last updated.

proofpoint-tr-add-user-to-incident


Assigns a user to an incident as a target or attacker.

Base Command

proofpoint-tr-add-user-to-incident

Input

Argument Name Description Required
incident_id The ID value of the incident to add the user to (e.g. for incident INC-4000, the input for this argument should be 4000). Required
targets The list of targets to add to the incident. Required
attackers The list of attackers to add to the incident. Required

Context Output

There is no context output for this command.

proofpoint-tr-ingest-alert


Ingest an alert into Threat Response.

Base Command

proofpoint-tr-ingest-alert

Input

Argument Name Description Required
post_url_id The POST URL of the JSON alert source. You can find it by navigating to Sources -> JSON event source -> POST URL. Optional
json_version The Threat Response JSON version.
Possible values are: 2.0, 1.0. Default is 2.0.
Required
attacker An attacker object in JSON format : “{“attacker” : {…}}”. The attacker object must contain one of [“ip_address”, mac_address”, “host_name”, “url”, “user”] keys. You can also add the “port” key to the object. For more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. Optional
classification The alert classification shown as “Alert Type” in the TRAP UI.
Possible values are: malware, policy-violation, vulnerability, network, spam, phish, command-and-control, data-match, authentication, system-behavior, impostor, reported-abuse, unknown.
Optional
cnc_hosts The Command and Control host information in JSON format : “{“cnc_hosts”: [{“host” : “-“, “port”: “-“}, …]}”.
Note: Every item of the “cnc_hosts” list is in JSON format. For more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”.
Optional
detector The threat detection tool such as Firewall and IPS/IDS systems (in the format: “{“detector” : {…}}”), which generated the original alert. To see all relevant JSON fields and for more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. Optional
email The email metadata related to the alert, in JSON format: “{“email”: {…}}”. To see all relevant JSON fields and for more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. Optional
forensics_hosts The forensics host information in JSON format : “{“forensics_hosts”: [{“host” : “-“, “port”: “-“}…]}”.
Note: Every item of the “forensics_hosts” list is in JSON format. For more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”.
Optional
link_attribute The attribute to link alerts to.
Possible values are: target_ip_address, target_hostname, target_machine_name, target_user, target_mac_address, attacker_ip_address, attacker_hostname, attacker_machine_name, attacker_user, attacker_mac_address, email_recipient, email_sender, email_subject, message_id, threat_filename, threat_filehash.
Optional
severity The severity of the alert.
Possible values are: info, minor, moderate, major, critical, Informational, Low, Medium, High, Critical.
Optional
summary The alert summary. This argument will populate the Alert Details field. Optional
target The target host information in JSON format : “{“target”: {…}}”. To see all relevant JSON fields and for more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. Optional
threat_info The threat information in JSON format: “{“threat_info”: {…}}”. To see all relevant JSON fields and for more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. Optional
custom_fields A JSON object for collecting custom name-value pairs as part of the JSON alert sent to Threat Response, in the format: “{“custom_fields”: {..}}”. Although there is no limit to the number of custom fields, Proofpoint recommends keeping it to 10 or fewer fields. To see all relevant JSON fields and for more information, see Proofpoint TRAP documentation under “JSON Alert Source 2.0”. Optional

Context Output

There is no context output for this command.

proofpoint-tr-close-incident


Close an incident

Base Command

proofpoint-tr-close-incident

Input

Argument Name Description Required
incident_id The ID value of the incident to close. Required
details The details for the closure notes. Required
summary The summary for the closure notes. Required

Context Output

There is no context output for this command.

proofpoint-tr-verify-quarantine


Verify if an email has been quarantined.

Base Command

proofpoint-tr-verify-quarantine

Input

Argument Name Description Required
message_id The ID value of an email. True
time The creation time of the incident in the format YYYY-MM-DDTHH:MM:SSZ. For example: 2020-02-02T19:00:00Z. True
recipient The email recipient. True
limit_quarantine_occurred_time Whether or not to limit the results to include only quarantines that occurred within a limited time after alert creation. Automated quarantine actions for example typically occur within 120 seconds of alert firing. Manual actions executed by human may take longer. Default is True. False
quarantine_limit Only used if ‘limit_quarantine_occurred_time’ argument is set to true. Sets a limit on the quarantines retrieved to include only those where the time difference between alert time and quarantined time is less than the number of seconds specified. The time is in seconds. Default is 120. False
fetch_delta The time frame (in hours) used to identify the size of batches when retrieving the messages. e.g., 12. Default is 6. False
check_exact_reception_time If true, the command checks for quarantined emails with the exact reception time of the email. If false, the verification of the quarantined email only uses the message ID and the recipient email. Default is true. False

Context Output

Path Type Description
ProofPointTRAP.Quarantine String The result of the quarantine.

Command Example

!proofpoint-tr-verify-quarantine messageid=<message_id_example> time="2022-06-02T17:22:45Z" recipient=example@example.com

Context Example

{
    "ProofPointTRAP": {
        "Quarantine": [
            {
                "alert": {
                    "id": 1030,
                    "time": "2022-06-02T17:33:18Z"
                },
                "incident": {
                    "id": 265,
                    "time": "2022-06-02T17:33:18Z"
                },
                "quarantine": {
                    "alertSource": "Admin Portal",
                    "details": "Success",
                    "endTime": "2022-06-02T17:33:37.926Z",
                    "isRead": "false",
                    "messageId": "message_id_example",
                    "recipient": "example@example.com",
                    "recipientType": "Original Recipient",
                    "startTime": "2022-06-02T17:33:20.352Z",
                    "status": "successful",
                    "wasUndone": "false"
                }
            },
            {
                "alert": {
                    "id": 1030,
                    "time": "2022-06-02T17:33:18Z"
                },
                "incident": {
                    "id": 265,
                    "time": "2022-06-02T17:33:18Z"
                },
                "quarantine": {
                    "alertSource": "Admin Portal",
                    "details": "Success",
                    "endTime": "2022-06-02T17:33:37.321Z",
                    "isRead": "false",
                    "messageId": "message_id_example",
                    "recipient": "example@example.com",
                    "recipientType": "Original Recipient",
                    "startTime": "2022-06-02T17:33:20.283Z",
                    "status": "successful",
                    "wasUndone": "false"
                }
            }
        ]
    }
}

Configuration parameters

  • url — Server URL (e.g. https://192.168.0.1) (required)
  • credentials
  • apikey — API Key
  • insecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • incidentFetchInterval — Incidents Fetch Interval
  • first_fetch — First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days)
  • fetch_limit — Fetch limit - maximum number of incidents per fetch
  • fetch_delta — Fetch delta - The delta time in each batch. e.g. 1 hour, 3 minutes.
  • states — Fetch incident with specific states.
  • event_sources — Fetch incidents with specific event sources. Can be a list of comma separated values.
  • abuse_disposition — Fetch incidents with specific 'Abuse Disposition' values. Can be a list of comma separated values.
  • post_url_id — POST URL of the JSON alert source.

Commands (15)

  • proofpoint-tr-add-to-list

    Adds a member to the specified list.

  • proofpoint-tr-add-user-to-incident

    Assigns a user to an incident as a target or attacker.

  • proofpoint-tr-block-domain

    Adds the supplied domains to the specified block list.

  • proofpoint-tr-block-hash

    Adds the supplied file hashes to the specified file hash block list.

  • proofpoint-tr-block-ip

    Adds the supplied IP addresses to the specified IP block list.

  • proofpoint-tr-block-url

    Adds the supplied URLs to the specified URL block list.

  • proofpoint-tr-close-incident

    Close a specified incident.

  • proofpoint-tr-delete-indicator

    Deletes an indicator from the specified list.

  • proofpoint-tr-get-incident

    Retrieves incident metadata from Threat Response.

  • proofpoint-tr-get-list

    Gets items for the specified list.

  • proofpoint-tr-ingest-alert

    Ingest an alert into Threat Response.

  • proofpoint-tr-list-incidents

    Retrieves all incident metadata from Threat Response by specifying filter criteria such as the state of the incident or time of closure.

  • proofpoint-tr-search-indicator

    Returns indicators from the specified list, according to the defined filter.

  • proofpoint-tr-update-incident-comment

    Adds comments to an existing Threat Response incident, by incident ID.

  • proofpoint-tr-verify-quarantine

    Verify if an email has been quarantined.

import copy

import pytest
from CommonServerPython import *
from ProofpointThreatResponse import (
    close_incident_command,
    create_incident_field_context,
    filter_incidents,
    get_emails_context,
    get_incident_command,
    get_incidents_batch_by_time_request,
    get_new_incidents,
    get_time_delta,
    list_incidents_command,
    pass_abuse_disposition_filter,
    pass_sources_list_filter,
    prepare_ingest_alert_request_body,
    search_indicator_command,
    search_quarantine,
)

MOCK_INCIDENT_1 = {
    "id": 1,
    "type": "Malware",
    "summary": "Unsolicited Bulk Email",
    "description": "EvilScheme test message",
    "score": 4200,
    "state": "Open",
    "created_at": "2018-05-26T21:07:17Z",
    "event_count": 3,
    "event_sources": ["Proofpoint TAP"],
    "users": [""],
    "assignee": "Unassigned",
    "team": "Unassigned",
    "hosts": {
        "attacker": [""],
        "forensics": [
            "",
        ],
    },
    "incident_field_values": [
        {"name": "Attack Vector", "value": "Email"},
        {"name": "Classification", "value": "Spam"},
        {"name": "Severity", "value": "Critical"},
        {"name": "Abuse Disposition", "value": "Unknown"},
    ],
    "events": [
        {
            "id": 3,
            "category": "malware",
            "severity": "Info",
            "source": "Proofpoint TAP",
            "threatname": "",
            "state": "Linked",
            "description": "",
            "attackDirection": "inbound",
            "received": "2018-05-26T21:07:17Z",
            "malwareName": "",
            "emails": [
                {
                    "sender": {"email": "test"},
                    "recipient": {"email": "test"},
                    "subject": "test",
                    "messageId": "test",
                    "messageDeliveryTime": {
                        "chronology": {"zone": {"id": "UTC"}},
                        "millis": 1544640072000,
                    },
                    "abuseCopy": "false",
                    "body": "test",
                    "bodyType": "test",
                    "headers": "test",
                    "urls": "test",
                }
            ],
        }
    ],
    "quarantine_results": [],
    "successful_quarantines": 0,
    "failed_quarantines": 0,
    "pending_quarantines": 0,
}
MOCK_INCIDENT_2 = copy.deepcopy(MOCK_INCIDENT_1)
MOCK_INCIDENT_2["events"][0]["emails"][0]["messageDeliveryTime"] = "messageDeliveryTime"

INCIDENT_FIELD_CONTEXT = {
    "Attack_Vector": "Email",
    "Classification": "Spam",
    "Severity": "Critical",
    "Abuse_Disposition": "Unknown",
}

INCIDENT_FIELD_INPUT = [(MOCK_INCIDENT_1, INCIDENT_FIELD_CONTEXT)]


def get_fetch_data():
    with open("./test_data/raw_response.json") as f:
        file = json.loads(f.read())
        return file.get("result")


FETCH_RESPONSE = get_fetch_data()


@pytest.mark.parametrize("incident, answer", INCIDENT_FIELD_INPUT)
def test_get_incident_field_context(incident, answer):
    incident_field_values = create_incident_field_context(incident)
    assert incident_field_values == answer


EMAIL_RESULT = [
    {
        "sender": "test",
        "recipient": "test",
        "subject": "test",
        "message_id": "test",
        "message_delivery_time": 1544640072000,
        "body": "test",
        "body_type": "test",
        "headers": "test",
        "urls": "test",
    }
]

EMAILS_CONTEXT_INPUT = [(MOCK_INCIDENT_1["events"][0], EMAIL_RESULT)]


@pytest.mark.parametrize("event, answer", EMAILS_CONTEXT_INPUT)
def test_get_emails_context(event, answer):
    emails_context = get_emails_context(event)
    assert emails_context == answer


SOURCE_LIST_INPUT = [
    (["Proofpoint TAP"], True),
    ([], True),
    (["No such source"], False),
    (["No such source", "Proofpoint TAP"], True),
]


@pytest.mark.parametrize("sources_list, expected_answer", SOURCE_LIST_INPUT)
def test_pass_sources_list_filter(sources_list, expected_answer):
    result = pass_sources_list_filter(MOCK_INCIDENT_1, sources_list)
    assert result == expected_answer


ABUSE_DISPOSITION_INPUT = [(["Unknown"], True), ([], True), (["No such value"], False), (["No such value", "Unknown"], True)]


@pytest.mark.parametrize("abuse_dispotion_values, expected_answer", ABUSE_DISPOSITION_INPUT)
def test_pass_abuse_disposition_filter(abuse_dispotion_values, expected_answer):
    result = pass_abuse_disposition_filter(MOCK_INCIDENT_1, abuse_dispotion_values)
    assert result == expected_answer


DEMISTO_PARAMS = [
    ({"event_sources": "No such source, Proofpoint TAP", "abuse_disposition": "No such value, Unknown"}, [MOCK_INCIDENT_1]),
    ({"event_sources": "", "abuse_disposition": ""}, [MOCK_INCIDENT_1]),
    ({"event_sources": "No such source", "abuse_disposition": "No such value, Unknown"}, []),
    ({"event_sources": "No such source, Proofpoint TAP", "abuse_disposition": "No such value"}, []),
    ({"event_sources": "No such source", "abuse_disposition": "No such value"}, []),
]


@pytest.mark.parametrize("demisto_params, expected_answer", DEMISTO_PARAMS)
def test_filter_incidents(mocker, demisto_params, expected_answer):
    mocker.patch.object(demisto, "params", return_value=demisto_params)
    filtered_incidents = filter_incidents([MOCK_INCIDENT_1])
    assert filtered_incidents == expected_answer


INGEST_ALERT_ARGS = {
    "attacker": '{"attacker":{"key":"value"}}',
    "cnc_host": '{"cnc_host":{"key":"value"}}',
    "detector": '{"detector":{"key":"value"}}',
    "email": '{"email":{"key":"value"}}',
    "forensics_hosts": '{"forensics_hosts":{"key":"value"}}',
    "target": '{"target":{"key":"value"}}',
    "threat_info": '{"threat_info":{"key":"value"}}',
    "custom_fields": '{"custom_fields":{"key":"value"}}',
    "post_url_id": "value",
    "json_version": "value",
    "summary": "value",
}

EXPECTED_RESULT = {
    "attacker": {"key": "value"},
    "cnc_host": {"key": "value"},
    "detector": {"key": "value"},
    "email": {"key": "value"},
    "forensics_hosts": {"key": "value"},
    "target": {"key": "value"},
    "threat_info": {"key": "value"},
    "custom_fields": {"key": "value"},
    "post_url_id": "value",
    "json_version": "value",
    "summary": "value",
}


def test_prepare_ingest_alert_request_body():
    prepared_body = prepare_ingest_alert_request_body(INGEST_ALERT_ARGS)
    assert prepared_body == EXPECTED_RESULT


def test_fetch_incidents_limit_exceed(mocker):
    """
    Given
    - a dict of params given to the function which is gathered originally from demisto.params()
       The dict includes the relevant params for the fetch e.g. fetch_delta, fetch_limit, created_after, state.
    - response of the api
    When
    - a single iteration of the fetch is activated with a fetch limit set to 5
    Then
    - validate that the number or incidents that is returned is equal to the limit when the api returned more.
    """
    params = {"fetch_delta": "6 hours", "fetch_limit": " 5", "created_after": "2021-03-30T11:44:24Z", "state": "closed"}
    mocker.patch("ProofpointThreatResponse.get_incidents_request", return_value=FETCH_RESPONSE)
    incidents_list = get_incidents_batch_by_time_request(params)
    assert len(incidents_list) == 5


def test_fetch_incidents_with_same_created_time(mocker):
    """
    Given
    - a dict of params given to the function which is gathered originally from demisto.params()
       The dict includes the relevant params for the fetch e.g. fetch_delta, fetch_limit, created_after, state and
        last_fetched_id.
    - response of the api
    When
    - when a fetch occurs and the last fetched incident has exactly the same time of the next incident.
    Then
    - validate that only one of the incidents appear as to the fetch limit.
    - validate that the next incident whose time is exactly the same is brought in the next fetch loop.
    ( e.g. 3057 and 3058)
    """
    expected_ids_to_fetch_first = [3055, 3056, 3057]
    expected_ids_to_fetch_second = [3058, 3059, 3060]

    params = {"fetch_delta": "2 hours", "fetch_limit": "3", "created_after": "2021-03-30T10:44:24Z", "state": "closed"}

    mocker.patch("ProofpointThreatResponse.get_incidents_request", return_value=FETCH_RESPONSE)
    new_fetched_first = get_incidents_batch_by_time_request(params)
    for incident in new_fetched_first:
        assert incident.get("id") in expected_ids_to_fetch_first

    params = {
        "fetch_delta": "2 hour",
        "fetch_limit": "3",
        "created_after": "2021-03-30T11:21:24Z",
        "last_fetched_id": "3057",
        "state": "closed",
    }
    new_fetched_second = get_incidents_batch_by_time_request(params)
    for incident in new_fetched_second:
        assert incident.get("id") in expected_ids_to_fetch_second


def test_get_new_incidents(mocker):
    """
    Given
    - a dict of request_params to the api.
    - The last fetched incident id.
    When
    - Get new incidents is called during the fetch process.
    Then
    - validate that the number of expected incidents return.
    - validate that all of the returned incident have a bigger id then the last fetched incident.
    """
    last_incident_fetched = 3057
    request_params = {
        "state": "closed",
        "created_after": "2021-03-30T10:21:24Z",
        "created_before": "2021-03-31T11:21:24Z",
    }
    mocker.patch("ProofpointThreatResponse.get_incidents_request", return_value=FETCH_RESPONSE)
    new_incidnets = get_new_incidents(request_params, last_incident_fetched)
    assert len(new_incidnets) == 14
    for incident in new_incidnets:
        assert incident.get("id") > 3057


def test_get_time_delta():
    """
    Given
    - input to the get_time_delta function which is valid and invalid
    When
    - run the get_time_delta function.
    Then
    - validate that on invalid input such as days or no units relevant errors are raised.
    - validate that on valid inputs the return value is as expected.
    """
    time_delta = get_time_delta("1 minute")
    assert str(time_delta) == "0:01:00"
    time_delta = get_time_delta("2 hours")
    assert str(time_delta) == "2:00:00"
    try:
        get_time_delta("2")
    except Exception as ex:
        assert "The fetch_delta is invalid. Please make sure to insert both the number and the unit of the fetch delta." in str(
            ex
        )
    try:
        get_time_delta("2 days")
    except Exception as ex:
        assert 'The unit of fetch_delta is invalid. Possible values are "minutes" or "hours' in str(ex)


def test_get_incident_command(mocker, requests_mock):
    """
    Given:
    - Incident ID 3064 to retrieve

    When:
    - Running get-incident command

    Then:
    - Ensure expected fields ('attachments', 'sender_vap', 'recipient_vap') are populated to the context data
    """
    base_url = "https://server_url/"
    requests_mock.get(f"{base_url}api/incidents/3064.json", json=FETCH_RESPONSE[0])
    mocker.patch.object(demisto, "results")
    mocker.patch("ProofpointThreatResponse.BASE_URL", base_url)
    mocker.patch.object(demisto, "args", return_value={"incident_id": "3064"})
    get_incident_command()
    results = demisto.results.call_args[0][0]
    emails = results["EntryContext"]["ProofPointTRAP.Incident(val.id === obj.id)"][0]["events"][0]["emails"][0].keys()
    assert {"attachments", "sender_vap", "recipient_vap"}.issubset(set(emails))


def test_get_incident_command_expand_events_false(mocker, requests_mock):
    """
    Given:
    - Incident ID 3064 to retrieve
    - The expand_events argument set to false

    When:
    - Running get-incident command

    Then:
    - Ensure events field is not returned
    - Ensure event_ids field is populated as expected
    """
    base_url = "https://server_url/"
    with open("./test_data/incident_expand_events_false.json") as f:
        incident = json.loads(f.read())
    requests_mock.get(f"{base_url}api/incidents/3064.json?expand_events=false", json=incident)
    mocker.patch.object(demisto, "results")
    mocker.patch("ProofpointThreatResponse.BASE_URL", base_url)
    mocker.patch.object(
        demisto,
        "args",
        return_value={
            "incident_id": "3064",
            "expand_events": "false",
        },
    )
    get_incident_command()
    results = demisto.results.call_args[0][0]
    incident_result = results["EntryContext"]["ProofPointTRAP.Incident(val.id === obj.id)"][0]
    assert not incident_result["events"]
    assert incident_result["event_ids"]


def test_close_incident_command(mocker, requests_mock):
    """
    Given:
    - Incident ID 3064 to close

    When:
    - Running close-incident command

    Then:
    - Ensure output is success message
    """
    base_url = "https://server_url/"
    requests_mock.post(f"{base_url}api/incidents/3064/close.json")
    mocker.patch.object(demisto, "results")
    mocker.patch("ProofpointThreatResponse.BASE_URL", base_url)
    mocker.patch.object(demisto, "args", return_value={"incident_id": "3064", "summary": "summary", "details": "details"})
    close_incident_command()
    results = demisto.results.call_args[0][0]
    assert "success" in results["HumanReadable"]


def test_search_quarantine_command(mocker, requests_mock):
    """
    Given:
    - Message ID, Recipient and Delivery Time (Email recived time)

    When:
    - Running search-quarantine command

    Then:
    - Ensure output is success message (at least one success).
    """
    base_url = "https://server_url/"
    with open("./test_data/incidents.json") as f:
        incident = json.loads(f.read())
    requests_mock.get(f"{base_url}api/incidents", json=incident)
    mocker.patch("ProofpointThreatResponse.BASE_URL", base_url)
    mocker.patch.object(
        demisto,
        "args",
        return_value={
            "message_id": "<XYZ_EAbcd-@test.test.com>",
            "recipient": "sabrina.test@test.com",
            "time": "2021-03-30T11:17:39Z",
        },
    )
    res = search_quarantine()
    quarantines_res = [x.get("quarantine").get("status") for x in res.outputs]
    assert "successful" in quarantines_res


def test_search_quarantine_command_with_str_messageDeliveryTime(mocker, requests_mock):
    """
    Given:
    - Message ID, Recipient and Delivery Time (Email recived time)

    When:
    - Running search-quarantine command

    Then:
    - Ensure output is success message (at least one success).
    """
    base_url = "https://server_url/"
    with open("./test_data/incident_str_messageDeliveryTime.json") as f:
        incident = json.loads(f.read())
    requests_mock.get(f"{base_url}api/incidents", json=incident)
    mocker.patch("ProofpointThreatResponse.BASE_URL", base_url)
    mocker.patch("ProofpointThreatResponse.get_incidents_batch_by_time_request", return_value=incident)

    mocker.patch.object(
        demisto,
        "args",
        return_value={"message_id": "<ABCD1234@cpus>", "recipient": "sabrina.test@test.com", "time": "2021-03-30T11:17:39Z"},
    )
    res = search_quarantine()

    assert (
        res.outputs_prefix == "<ABCD1234@cpus> Message ID found in TRAP alerts, "
        "but not in the quarantine list meaning that email has not be quarantined."
    )


def test_list_incidents_command(mocker, requests_mock):
    """
    Given:
    - 2 Incidents in the list, with different 'messageDeliveryTime' fields

    When:
    - Running list-incidents command

    Then:
    - Ensure output generated successfully without errors.
    """
    base_url = "https://server_url/"
    requests_mock.get(f"{base_url}api/incidents", json=[MOCK_INCIDENT_1, MOCK_INCIDENT_2])
    mocker.patch("ProofpointThreatResponse.BASE_URL", base_url)
    mocker.patch.object(demisto, "args", return_value={"limit": 2})
    results = mocker.patch.object(demisto, "results")
    list_incidents_command()
    incidents = results.call_args[0][0]["Contents"]
    assert len(incidents) == 2


@pytest.mark.parametrize(
    "list_id_to_search, filter_to_apply,  indicators_to_return, expected_result",
    [
        ("1", "1.1.1.1", [{"host": {"host": "1.1.1.1"}}, {"host": {"host": "2.2.2.2"}}], [{"host": {"host": "1.1.1.1"}}]),
        (
            "1",
            "",
            [{"host": {"host": "1.1.1.1"}}, {"host": {"host": "2.2.2.2"}}],
            [{"host": {"host": "1.1.1.1"}}, {"host": {"host": "2.2.2.2"}}],
        ),
        ("1", "", [{}], []),
    ],
)
def test_search_indicator_command(
    mocker, requests_mock, list_id_to_search, filter_to_apply, indicators_to_return, expected_result
):
    """
    Given:
        - Case A: List id = 1, and filter is 1.1.1.1
        - Case B: List id = 1, no filter is given.
        - Case C: List id = 1, no filter is given.

    When:
        - Case A: 2 indicators [1.1.1.1, 2.2.2.2] are returned from API.
        - Case B: 2 indicators [1.1.1.1, 2.2.2.2] are returned from API.
        - Case C: No indicators are returned from API.

    Then:
        - Case A: Ensure the list is filtered and only the 1.1.1.1 indicator is returned.
        - Case B: Ensure the list is not filtered and both 1.1.1.1 and 2.2.2.2 are returned.
        - Case C: Ensure the logic is working, and an empty list is returnd
    """
    base_url = "https://server_url/"
    requests_mock.get(f"{base_url}api/lists/{list_id_to_search}/members.json", json=indicators_to_return)
    mocker.patch("ProofpointThreatResponse.BASE_URL", base_url)
    mocker.patch.object(demisto, "args", return_value={"list-id": list_id_to_search, "filter": filter_to_apply})
    results = mocker.patch.object(demisto, "results")
    search_indicator_command()
    indicators = results.call_args[0][0]["indicators"]
    assert indicators == expected_result


def test_search_quarantine_command_mismatch_time(mocker, requests_mock):
    """
    Given:
    - Message ID, Recipient and Delivery Time (Email recived time)

    When:
    - Running search-quarantine command

    Then:
    - test fails on time mismatch
    """
    base_url = "https://server_url/"
    with open("./test_data/incident_str_messageDeliveryTime.json") as f:
        incident = json.loads(f.read())
    requests_mock.get(f"{base_url}api/incidents", json=incident)
    mocker.patch("ProofpointThreatResponse.BASE_URL", base_url)
    mocker.patch("ProofpointThreatResponse.get_incidents_batch_by_time_request", return_value=incident)

    mocker.patch.object(
        demisto,
        "args",
        return_value={"message_id": "<ABCD1234@cpus>", "recipient": "sabrina.test@test.com", "time": "2021-04-30T11:17:39Z"},
    )
    res = search_quarantine()

    assert res.readable_output == (
        "<ABCD1234@cpus> Message ID found in TRAP alerts, but timestamp between email delivery time "
        "and time given as argument doesn't match"
    )


def test_search_quarantine_command_with_incident_far_from_alert_time_fail(mocker, requests_mock):
    """
    Given:
    - Message ID, Recipient and Delivery Time (Email recived time)

    When:
    - Running search-quarantine command

    Then:
    - test fails on time mismatch
    """
    base_url = "https://server_url/"
    with open("./test_data/incident_email_manually_quarantined.json") as f:
        incident = json.loads(f.read())
    requests_mock.get(f"{base_url}api/incidents", json=incident)
    mocker.patch("ProofpointThreatResponse.BASE_URL", base_url)
    mocker.patch("ProofpointThreatResponse.get_incidents_batch_by_time_request", return_value=incident)

    mocker.patch.object(
        demisto,
        "args",
        return_value={"message_id": "<ABCD1234@cpus>", "recipient": "sabrina.test@test.com", "time": "2021-04-30T11:17:39Z"},
    )
    res = search_quarantine()

    assert res.readable_output == (
        "<ABCD1234@cpus> Message ID matches to 1 emails quarantined, but time between alert received "
        "and the quarantine starting exceeded the quarantine_limit provided"
    )


def test_search_quarantine_command_with_incident_far_from_alert_time_succeed(mocker, requests_mock):
    """
    Given:
    - Message ID, Recipient and Delivery Time (Email recived time)

    When:
    - Running search-quarantine command

    Then:
    - test succeed
    """
    base_url = "https://server_url/"
    with open("./test_data/incident_email_manually_quarantined.json") as f:
        incident = json.loads(f.read())
    requests_mock.get(f"{base_url}api/incidents", json=incident)
    mocker.patch("ProofpointThreatResponse.BASE_URL", base_url)
    mocker.patch("ProofpointThreatResponse.get_incidents_batch_by_time_request", return_value=incident)

    mocker.patch.object(
        demisto,
        "args",
        return_value={
            "message_id": "<ABCD1234@cpus>",
            "recipient": "sabrina.test@test.com",
            "time": "2021-04-30T11:17:39Z",
            "quarantine_limit": "2665996",
        },
    )
    res = search_quarantine()

    assert res.readable_output == (
        "### Quarantine Result\n|alert|incident|quarantine|\n|---|---|---|\n| id: 9225<br>time: "
        "2021-03-30T11:44:24Z | id: 3065<br>time: 2021-03-30T11:44:24Z | messageId: <ABCD1234@cpu"
        "s><br>recipient: sabrina.test@test.com<br>startTime: 2021-04-30T08:17:39Z |\n"
    )