Fidelis Elevate Network

Automate Detection and Response to Network Threats and data leakage in your organization with Fidelis Elevate Network Integration.

Network Security · Fidelis Elevate Network

Details

IDFidelis Elevate Network
ProviderSkyview Capital
CategoryNetwork Security
From Version5.0.0
Docker Imagedemisto/python3:3.12.13.10116658
Supported ModulesAgentix XSIAM

README

Automate Detection and Response to Network Threats and data leakage in your organization with Fidelis Elevate Network Integration.
This integration was integrated and tested with version 9.2.4 of Fidelis Elevate Network

Configure Fidelis Elevate Network in Cortex

Parameter Description Required
server_url Server URL True
credentials Credentials True
unsecure Trust any certificate (not secure) False
proxy Use system proxy settings False
isFetch Fetch incidents False
incidentType Incident type False
fetch_time First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days, 3 months, 1 year) 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.

fidelis-get-alert


Gets alert details from Fidelis Elevate.

Base Command

fidelis-get-alert

Input
Argument Name Description Required
alert_id Alert ID Required
Context Output
Path Type Description
Fidelis.Alert.ID string Alert ID.
Fidelis.Alert.ThreatScore number Alert threat score.
Fidelis.Alert.Time date Alert time.
Fidelis.Alert.RuleID string Related rule ID.
Fidelis.Alert.RuleName string Related rule name.
Fidelis.Alert.Summary string Alert summary.
Fidelis.Alert.PolicyName string Related policy name.
Fidelis.Alert.Severity string Alert severity.
Fidelis.Alert.Protocol string Protocol involved in the alert.
Fidelis.Alert.Type string Alert type.
Fidelis.Alert.AssignedUser string Assigned user ID.
Command Example

!fidelis-get-alert alert_id=1

Context Example
{
    "Fidelis": {
        "Alert": {
            "AlertUUID": "80d0ccf5-5879-11ea-b430-0eb174ee0947",
            "AssignedUser": 0,
            "ID": 1,
            "PolicyName": "Endpoint Alerts",
            "Protocol": "",
            "RuleID": 227,
            "RuleName": null,
            "Severity": "Medium",
            "Summary": "Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown, Artifact: ",
            "ThreatScore": 100,
            "Time": "2020-02-26 09:21:02",
            "Type": "ENDPOINT"
        }
    }
}
Human Readable Output

Alert 1

Alert UUID Assigned User ID Policy Name Rule ID Severity Summary Threat Score Time Type
80d0ccf5-5879-11ea-b430-0eb174ee0947 0 1 Endpoint Alerts 227 Medium Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown, Artifact: 100 2020-02-26 09:21:02 ENDPOINT

fidelis-delete-alert


Deletes an alert from Fidelis Elevate.

Base Command

fidelis-delete-alert

Input
Argument Name Description Required
alert_id ID of the alert to delete. Required
Context Output

There is no context output for this command.

Command Example

!fidelis-delete-alert alert_id=3

Human Readable Output

Alert (3) deleted successfully!

fidelis-get-malware-data


Retrieves malware data related to a “Malware” type alert.

Base Command

fidelis-get-malware-data

Input
Argument Name Description Required
alert_id Alert ID. Required
Context Output
Path Type Description
Fidelis.Alert.ID string Alert ID.
Fidelis.Alert.Malware.Name string Malware name.
Fidelis.Alert.Malware.Type string Malware type.
Fidelis.Alert.Malware.Behavior string Malware behavior.
Fidelis.Alert.Malware.Platform string Malware platform.
Fidelis.Alert.Malware.DetailName string Malware detail name from Fidelis Elevate.
Fidelis.Alert.Malware.Variant string Malware variant.
Fidelis.Alert.Malware.Description string Malware description from Fidelis Elevate.
Command Example

!fidelis-get-malware-data alert_id=6

Context Example
{
    "Fidelis": {
        "Alert": {
            "ID": "6",
            "Malware": {
                "Behavior": null,
                "Description": null,
                "DetailName": null,
                "Name": "",
                "Platform": null,
                "Type": "",
                "Variant": null
            }
        }
    }
}
Human Readable Output

Alert 6 Malware

Malware Behavior Malware Description Malware Detail Name Malware Name Malware Platform Malware Type Malware Variant
             

fidelis-get-alert-report


Downloads a PDF report for a specified alert.

Base Command

fidelis-get-alert-report

Input
Argument Name Description Required
alert_id Alert ID of the alert for which to download a PDF report. Required
Context Output

There is no context output for this command.

Command Example

!fidelis-get-alert-report alert_id=5

Context Example
{
    "InfoFile": {
        "EntryID": "7382@99f96547-c492-48d1-84bc-070759449a5d",
        "Extension": "pdf",
        "Info": "application/pdf",
        "Name": "Alert_Details_5.pdf",
        "Size": 69507,
        "Type": "PDF document, version 1.4"
    }
}

fidelis-list-alerts


Returns a list of open alerts from Fidelis Elevate.

Base Command

fidelis-list-alerts

Input
Argument Name Description Required
time_frame Filter alerts by time frame, for example, Last 48 Hours. Optional
start_time If the time_frame value is Custom, specify the start time for the time range, for example, 2017-06-01T12:48:16.734. Optional
end_time If the time_frame value is Custom, specify the end time for the time range, for example, 2017-06-01T12:48:16.734. Optional
severity Filter alerts by alert severity. Optional
type Filter alerts by alert type. Optional
threat_score Filter alerts by alert threat score threshold (higher than). Optional
ioc Filter alerts that are related to a specified IOC. Optional
Context Output
Path Type Description
Fidelis.Alert.ID string Alert ID.
Fidelis.Alert.Time date Alert time.
Fidelis.Alert.Summary string Alert summary.
Fidelis.Alert.Severity string Alert severity.
Fidelis.Alert.Type string Alert type.
Command Example

##### Context Example

{
“Fidelis”: {
“Alert”: [
{
“ID”: “6”,
“Severity”: “High”,
“Summary”: “Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown”,
“Time”: “2020-03-19 23:59:59”,
“Type”: “Endpoint”
},
{
“ID”: “5”,
“Severity”: “Medium”,
“Summary”: “Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown, Artifact: “,
“Time”: “2020-03-12 09:21:27”,
“Type”: “Endpoint”
}
]
}
}


##### Human Readable Output

### Found 6 Alerts

|ID|Severity|Summary|Time|Type|
|---|---|---|---|---|
| 6 | High | Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown | 2020-03-19 23:59:59 | Endpoint |
| 5 | Medium | Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown, Artifact:  | 2020-03-12 09:21:27 | Endpoint |
| 4 | Low | Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown, Artifact:  | 2020-03-07 09:21:24 | Endpoint |
| 2 | High | Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown, Artifact:  | 2020-02-27 09:21:03 | Endpoint |
| 3 | High | Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown, Artifact:  | 2020-02-27 09:21:03 | Endpoint |
| 1 | Medium | Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown, Artifact:  | 2020-02-26 09:21:02 | Endpoint |

### fidelis-upload-pcap

***
Uploads a PCAP file to Fidelis Elevate for analysis.

##### Base Command

`fidelis-upload-pcap`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| component_ip | Component IP address. | Required |
| entry_id | War Room entry ID of the PCAP file, for example, "3245@6". | Required |

##### Context Output

There is no context output for this command.

##### Command Example

```!fidelis-upload-pcap component_ip=1.1.1.1 entry_id=7317@99```

##### Human Readable Output

Pcap file uploaded successfully.

### fidelis-list-pcap-components

***
Gets PCAP components.

##### Base Command

`fidelis-list-pcap-components`

##### Input

There are no input arguments for this command.

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Fidelis.Component.Name | string | Component name. |
| Fidelis.Component.IP | string | Component IP address. |

##### Command Example

```!fidelis-list-pcap-components```

##### Context Example

{
“Fidelis”: {
“Component”: {
“IP”: “1.1.1.1”,
“Name”: “Sensor”
}
}
}


##### Human Readable Output

### PCAP Components

|Name|IP|
|---|---|
| Sensor | 1.1.1.1 |

### fidelis-run-pcap

***
Runs PCAP file analysis in Fidelis Elevate.

##### Base Command

`fidelis-run-pcap`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| component_ip | Component IP address. Run the 'fidelis-list-pcap-components' command to get this value. | Required |
| files | CSV list of PCAP file names in Fidelis Elevate. | Required |

##### Context Output

There is no context output for this command.

##### Command Example

```!fidelis-run-pcap component_ip=1.1.1.1 files=file.pcap```

##### Human Readable Output

Pcap file run submitted.

### fidelis-get-alert-by-uuid

***
Returns an alert, by UUID.

##### Base Command

`fidelis-get-alert-by-uuid`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_uuid | The UUID of the alert. | Required |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Fidelis.Alert.ID | Number | Alert ID. |
| Fidelis.Alert.Severity | String | Alert severity. |
| Fidelis.Alert.Summary | String | Alert summary. |
| Fidelis.Alert.Time | Date | Alert time. |
| Fidelis.Alert.Type | String | Alert type. |
| Fidelis.Alert.UUID | String | Alert UUID. |

##### Command Example

```!fidelis-get-alert-by-uuid alert_uuid=80d0ccf5-5879-11ea-b430-0eb174ee0947```

##### Context Example

{
“Fidelis”: {
“Alert”: {
“ID”: “1”,
“Severity”: “Medium”,
“Summary”: “Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown, Artifact: “,
“Time”: “2020-02-26 09:21:02”,
“Type”: “Endpoint”
}
}
}


##### Human Readable Output

### Found 1 Alerts

|ID|Severity|Summary|Time|Type|
|---|---|---|---|---|
| 1 | Medium | Endpoint alert on fidelis-endpoint.c.dmst-integrations.internal: , Intel Source: Unknown, Artifact:  | 2020-02-26 09:21:02 | Endpoint |

### fidelis-list-metadata

***
Returns a metadata list.

##### Base Command

`fidelis-list-metadata`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| time_frame | Filter alerts by time frame, for example, Last 48 Hours. | Optional |
| start_time | If the time_frame value is Custom, specify the start time for the time range, for example, 2017-06-01T12:48:16.734. | Optional |
| end_time | If the time_frame value is Custom, specify the end time for the time range, for example,2017-06-01T12:48:16.734. | Optional |
| client_ip | Filter alerts by client IP. | Optional |
| server_ip | Filter alerts by server IP address. | Optional |
| request_direction | Direction of the request. Can be "s2c" (server to client) or "c2s" (client to server). | Optional |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Fidelis.Metadata.MalwareName | String | Malware name. |
| Fidelis.Metadata.ServerPort | Number | Server port number. |
| Fidelis.Metadata.SHA256 | String | SHA256 hash of the file. |
| Fidelis.Metadata.FileName | String | File name. |
| Fidelis.Metadata.PcapFilename | String | PCAP file name. |
| Fidelis.Metadata.SessionDuration | String | The event session duration. |
| Fidelis.Metadata.ServerIP | String | The server IP address. |
| Fidelis.Metadata.ClientCountry | String | The client country. |
| Fidelis.Metadata.ClientPort | Number | The client port number. |
| Fidelis.Metadata.SessionStart | Date | The date/time that the session started. |
| Fidelis.Metadata.MalwareType | String | The malware type. |
| Fidelis.Metadata.URL | String | Request URL. |
| Fidelis.Metadata.RequestDirection | String | Request direction (s2c or c2s).  |
| Fidelis.Metadata.MalwareSeverity | String | The severity of the malware. |
| Fidelis.Metadata.ClientIP | String | The client IP address. |
| Fidelis.Metadata.ServerCountry | String | The country of the server. |
| Fidelis.Metadata.PcapTimestamp | Date | PCAP timestamp. |
| Fidelis.Metadata.SensorUUID | String | Sensor UUID. |
| Fidelis.Metadata.Timestamp | Date | Timestamp of the event. |
| Fidelis.Metadata.FileType | String | File type. |
| Fidelis.Metadata.Protocol | String | Event protocol. |
| Fidelis.Metadata.UserAgent | String | User agent of the request. |
| Fidelis.Metadata.Type | String | Type of the event. |
| Fidelis.Metadata.FileSize | Number | The size of the file. |
| Fidelis.Metadata.MD5 | String | MD5 hash of the file. |

##### Command Example

```!fidelis-list-metadata```

##### Context Example

{
“Fidelis”: {
“Metadata”: null
}
}


##### Human Readable Output

### Found 0 Metadata

**No entries.**

### fidelis-list-alerts-by-ip

***
Returns a list of alerts, by source IP address or destination IP address.

##### Base Command

`fidelis-list-alerts-by-ip`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| time_frame | Today,Yesterday,Last 7 Days,Last Hour,Last 24 Hours,Last 48 Hours,Last 30 Days,Custom | Optional |
| start_time | If the time_frame value is Custom, specify the start time for the time range, for example, 2017-06-01T12:48:16.734. | Optional |
| end_time | If the time_frame value is Custom, specify the start time for the time range, for example, 2017-06-01T12:48:16.734. | Optional |
| src_ip | Filter alerts by the source IP. | Optional |
| dest_ip | Filter alerts by the destination IP address. | Optional |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Fidelis.Alert.SourceIP | String | The alert source IP address.  |
| Fidelis.Alert.UserRating | String | User rating. |
| Fidelis.Alert.DestinationCountry | String | Destination country of the alert. |
| Fidelis.Alert.AssetID | Number | The ID of the asset. |
| Fidelis.Alert.Time | Date | Date/time that the alert started. |
| Fidelis.Alert.HostIP | String | The host IP address of the alert. |
| Fidelis.Alert.DistributedAlertID | String | Alert distributed ID. |
| Fidelis.Alert.DestinationIP | String | Alert destination IP address. |
| Fidelis.Alert.AlertUUID | String | The alert UUID. |
| Fidelis.Alert.Type | String | The alert type. |
| Fidelis.Alert.ID | Number | Alert ID. |
| Fidelis.Alert.SourceCountry | String | Alert source country |

##### Command Example

```!fidelis-list-alerts-by-ip```

##### Context Example

{
“Fidelis”: {
“Alert”: [
{
“AlertUUID”: “151fa61c-6b08-11ea-85b0-0eb174ee0947”,
“AssetID”: “2”,
“DestinationCountry”: “”,
“DestinationIP”: “::”,
“DistributedAlertID”: “Console-6”,
“HostIP”: “2.2.2.2”,
“ID”: “6”,
“SourceCountry”: “”,
“SourceIP”: “::”,
“Time”: “2020-03-19 23:59:59”,
“Type”: “Endpoint”,
“UserRating”: “No Rating”
},
{
“AlertUUID”: “1dee426f-6443-11ea-83d9-0eb174ee0947”,
“AssetID”: “2”,
“DestinationCountry”: “”,
“DestinationIP”: “::”,
“DistributedAlertID”: “Console-5”,
“HostIP”: “2.2.2.2”,
“ID”: “5”,
“SourceCountry”: “”,
“SourceIP”: “::”,
“Time”: “2020-03-12 09:21:27”,
“Type”: “Endpoint”,
“UserRating”: “No Rating”
}
]
}
}


##### Human Readable Output

### Found 6 Alerts

|Time|AlertUUID|ID|DistributedAlertID|UserRating|HostIP|AssetID|Type|DestinationCountry|SourceCountry|DestinationIP|SourceIP|
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2020-03-19 23:59:59 | 151fa61c-6b08-11ea-85b0-0eb174ee0947 | 6 | Console-6 | No Rating | 2.2.2.2| 2 | Endpoint |  |  | :: | :: |
| 2020-03-12 09:21:27 | 1dee426f-6443-11ea-83d9-0eb174ee0947 | 5 | Console-5 | No Rating | 2.2.2.2 | 2 | Endpoint |  |  | :: | :: |
| 2020-03-07 09:21:24 | 244267da-6055-11ea-b430-0eb174ee0947 | 4 | Console-4 | No Rating | 2.2.2.2 | 2 | Endpoint |  |  | :: | :: |
| 2020-02-27 09:21:03 | a2d7fa21-5942-11ea-b430-0eb174ee0947 | 2 | Console-2 | No Rating | 2.2.2.2 | 2 | Endpoint |  |  | :: | :: |
| 2020-02-27 09:21:03 | a2d8eec9-5942-11ea-b430-0eb174ee0947 | 3 | Console-3 | False Positive | 2.2.2.2 | 2 | Endpoint |  |  | :: | :: |
| 2020-02-26 09:21:02 | 80d0ccf5-5879-11ea-b430-0eb174ee0947 | 1 | Console-1 | Actionable | 2.2.2.2 | 2 | Endpoint |  |  | :: | :: |

### fidelis-download-malware-file

***
Downloads a malware file from a specified alert.

##### Base Command

`fidelis-download-malware-file`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_id | ID of the alert from which to download the file. | Required |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| File.Size | Number | The size of the file. |
| File.Extension | String | The file extension.  |
| File.Info | String | Information about the file. |
| File.Name | String | The name of the file. |
| File.SHA1 | String | SHA1 hash of the file. |
| File.Type | String | The file type. |
| File.SHA256 | String | SHA256 hash of the file. |
| File.SSDeep | String | SSDeep hash of the file. |
| File.EntryID | String | File entry ID. |
| File.MD5 | String | MD5 hash of the file. |

##### Command Example

```!fidelis-download-malware-file alert_id=9```

##### Context Example

{
“File”: {
“EntryID”: “7640@99f96547-c492-48d1-84bc-070759449a5d”,
“Extension”: “zip”,
“Info”: “application/zip”,
“MD5”: “d41d8cd98f00b204e9800998ecf8427e”,
“Name”: “:HTTP(file.pcap).zip”,
“SHA1”: “52483514f07eb14570142f6927b77deb7b4da99f”,
“SHA256”: “42a5e275559a1651b3df8e15d3f5912499f0f2d3d1523959c56fc5aea6371e59”,
“SHA512”: “3fbdc4195b66297eaa4168ad6ded010c47eaea57496b6cc1ccfa34c9579d21562451d1269c7412e31e926cbb7c50ffc160a6493f4a8df0235ecd3ea2c9bfddb5”,
“SSDeep”: “3::”,
“Size”: 0,
“Type”: “empty”
}
}


##### Human Readable Output

No File Found

### fidelis-download-pcap-file

***
Downloads the PCAP file from a specified alert.

##### Base Command

`fidelis-download-pcap-file`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_id | The ID of the alert from which to download the file. | Required |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| File.EntryID | String | The entry ID of the file. |
| File.Info | String | File information. |
| File.Name | String | Name of the file. |
| File.Size | Number | File size |
| File.Type | String | File type. |
| File.SHA1 | String | SHA1 hash of the file. |
| File.SHA256 | String | SHA256 hash of the file. |
| File.SSDeep | String | SSDeep hash of the file. |
| File.MD5 | String | MD5 hash of the file. |

##### Command Example

```!fidelis-download-pcap-file alert_id=5```

##### Context Example

{
“File”: {
“EntryID”: “7378@99f96547-c492-48d1-84bc-070759449a5d”,
“Extension”: “pcap”,
“Info”: “application/vnd.tcpdump.pcap”,
“MD5”: “e8a496ed6be700ed61b8b758df3248ef”,
“Name”: “Alert ID_5.pcap”,
“SHA1”: “86a3069583b027eac8cc519c09cff1f7e18ab9c5”,
“SHA256”: “c7911278b27d93e1a5c6998eaca0c75348284caaba9d58ba9951be7d325279a6”,
“SHA512”: “3fbdc4195b66297eaa4168ad6ded010c47eaea57496b6cc1ccfa34c9579d21562451d1269c7412e31e926cbb7c50ffc160a6493f4a8df0235ecd3ea2c9bfddb5”,
“SSDeep”: “48:uuHYx6sS1bioEX7gyLatSqAc8kHRgd5peJB80t9qeM:uuHYx6sS1bUJBqus8v9”,
“Size”: 2036,
“Type”: “HTML document text, ASCII text, with very long lines, with no line terminators”
}
}


##### Human Readable Output

### fidelis-get-alert-session-data

***
Return the session information related to an alert.

##### Base Command

`fidelis-get-alert-session-data`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_id | Alert ID | Required |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Fidelis.Alert.ID | Number | Alert ID. |
| Fidelis.Alert.SessionData.RecordingState | String | The alert's recording state. |
| Fidelis.Alert.SessionData.ClientPackets | String | The client packets. |
| Fidelis.Alert.SessionData.ServerSize | String | The server size. |
| Fidelis.Alert.SessionData.ServerPort | Number | The server port. |
| Fidelis.Alert.SessionData.ServerDataComplete | Boolean | Is the server data complete. |
| Fidelis.Alert.SessionData.ServerPackets | String | The server packets. |
| Fidelis.Alert.SessionData.EndTime | String | The end time. |
| Fidelis.Alert.SessionData.ServerIp | String | The server IP. |
| Fidelis.Alert.SessionData.ClientSize | String | The client size. |
| Fidelis.Alert.SessionData.ClientPort | Number | The client port. |
| Fidelis.Alert.SessionData.ServerData | String | The server data. |
| Fidelis.Alert.SessionData.BinaryServerData | Unknown | The binary server data. |
| Fidelis.Alert.SessionData.ClientDataComplete | Boolean | Is the client data complete. |
| Fidelis.Alert.SessionData.ServerDataSize | Number | The server data size. |
| Fidelis.Alert.SessionData.RecordedObject | Boolean | The recorded object. |
| Fidelis.Alert.SessionData.StartTime | String | The start time. |
| Fidelis.Alert.SessionData.ClientDomainName | String | The client domain name. |
| Fidelis.Alert.SessionData.TcpState | String | The TCP state. |
| Fidelis.Alert.SessionData.ShowingDataSize | Number | Showing the data size. |
| Fidelis.Alert.SessionData.ClientIp | String | The client IP. |
| Fidelis.Alert.SessionData.Duration | Number | The session data duration. |
| Fidelis.Alert.SessionData.ClientData | String | The client data. |
| Fidelis.Alert.SessionData.BinaryClientData | Unknown | The binary client data. |
| Fidelis.Alert.SessionData.ClientDataSize | Number | The client data size. |
| Fidelis.Alert.SessionData.NoForensics | Boolean | Are there no forensics. |
| Fidelis.Alert.SessionData.Exist | Boolean | Does the sesison data exist. |
| Fidelis.Alert.SessionData.TimeZone | String | The time zone. |
| Fidelis.Alert.SessionData.Highlights | Unknown | Highlights in the session data. |
| Fidelis.Alert.SessionData.ServerDomainName | String | The server domain name. |

##### Command Example

```!fidelis-get-alert-session-data alert_id=9```

##### Context Example

{
“Fidelis”: {
“Alert”: {
“ID”: “9”,
“SessionData”: {
“BinaryClientData”: {file binary data},
“BinaryServerData”: null,
“ClientData”: {file client data},
“ClientDataComplete”: true,
“ClientDataSize”: 2990,
“ClientDomainName”: null,
“ClientDomaniName”: “”,
“ClientIp”: “0.0.0.0”,
“ClientPackets”: null,
“ClientPort”: 0,
“ClientSize”: null,
“Duration”: 0,
“EndTime”: “2020-03-30 09:07:33”,
“Exist”: true,
“Highlights”: [],
“NoForensics”: false,
“RecordedObject”: true,
“RecordingState”: null,
“ServerData”: null,
“ServerDataComplete”: true,
“ServerDataSize”: null,
“ServerDomainName”: null,
“ServerDomaniName”: “”,
“ServerIp”: “0.0.0.0”,
“ServerPackets”: null,
“ServerPort”: 0,
“ServerSize”: null,
“ShowingDataSize”: 4,
“StartTime”: “2020-03-30 09:07:33”,
“TcpState”: null,
“TimeZone”: “UTC”
}
}
}
}


##### Human Readable Output

### Alert 9

|Binary Client Data|Client Data|Client Data Complete|Client Data Size|Client Ip|Client Port|Duration|End Time|Exist|No Forensics|Recorded Object|Server Data Complete|Server Ip|Server Port|Showing Data Size|Start Time|Time Zone|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {file binary data} | {file client data} | true | 2990 | 0.0.0.0 | 0 | 0 | 2020-03-30 09:07:33 | true | false | true | true | 0.0.0.0 | 0 | 4 | 2020-03-30 09:07:33 | UTC |

### fidelis-get-alert-execution-forensics

***
Get the exectution forensics for an alert.

##### Base Command

`fidelis-get-alert-execution-forensics`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_id | Alert ID | Required |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Fidelis.Alert.ID | Number | The alert ID. |
| Fidelis.Alert.ExecutionForensics.EFEnabled | Boolean | Is the alert execution forensics enabled. |
| Fidelis.Alert.ExecutionForensics.Size | Number | The execution forensics size. |
| Fidelis.Alert.ExecutionForensics.SubmitTime | Number | The submission time. |
| Fidelis.Alert.ExecutionForensics.SandBoxOn | Boolean | Is the sandbox on. |
| Fidelis.Alert.ExecutionForensics.TgReport | Boolean | The TG report. |
| Fidelis.Alert.ExecutionForensics.FileName | String | The file name. |
| Fidelis.Alert.ExecutionForensics.DnsFeed | Boolean | Is there a DNS feed. |
| Fidelis.Alert.ExecutionForensics.RecordingComplete | Boolean | Is the recording complete. |
| Fidelis.Alert.ExecutionForensics.PcapUrl | String | The PCAP URL. |
| Fidelis.Alert.ExecutionForensics.AlertFlagsXeNonsubmit | Boolean | The alert flag xe-nonsubmit. |
| Fidelis.Alert.ExecutionForensics.Bit9Server | String | The bit 9 server. |
| Fidelis.Alert.ExecutionForensics.DecodingPath | String | The execution forensics decoding path. |
| Fidelis.Alert.ExecutionForensics.FileCheckAlert | Boolean | The file check alert. |
| Fidelis.Alert.ExecutionForensics.Status | String | The execution forensics status. |
| Fidelis.Alert.ExecutionForensics.Submitable | Boolean | Is the execution forensics submitable. |
| Fidelis.Alert.ExecutionForensics.Score | Number | The execution forensics score. |
| Fidelis.Alert.ExecutionForensics.SubmitId | String | The execution forensics submit ID. |
| Fidelis.Alert.ExecutionForensics.VideoUrl | String | The video URL. |
| Fidelis.Alert.ExecutionForensics.StatusMessage | String | The execution forensics status message. |
| Fidelis.Alert.ExecutionForensics.FileType | String | The file type. |
| Fidelis.Alert.ExecutionForensics.AlertId | Number | The alert ID. |
| Fidelis.Alert.ExecutionForensics.Type | String | The type. |
| Fidelis.Alert.ExecutionForensics.ReportUrl | String | The report URL. |
| Fidelis.Alert.ExecutionForensics.JsSubmitable | Boolean | Is the execution forensics JS submitable. |
| Fidelis.Alert.ExecutionForensics.Uuid | String | The UUID. |
| Fidelis.Alert.ExecutionForensics.JsonReport | Unknown | The JSON report. |
| Fidelis.Alert.ExecutionForensics.FileSize | Number | The file size. |
| Fidelis.Alert.ExecutionForensics.Md5 | String | The file's MD5 hash. |
| Fidelis.Alert.ExecutionForensics.ThreatGridOn | Boolean | Is the threat grid on. |

##### Command Example

```!fidelis-get-alert-execution-forensics alert_id=9```

##### Context Example

{
“Fidelis”: {
“Alert”: {
“ExecutionForensics”: {
“AlertFlagsXeNonsubmit”: false,
“AlertId”: 9,
“Bit9Server”: null,
“DecodingPath”: null,
“DnsFeed”: false,
“EFEnabled”: true,
“FileCheckAlert”: true,
“FileName”: null,
“FileSize”: 2990,
“FileType”: “”,
“JsSubmitable”: true,
“JsonReport”: null,
“Md5”: null,
“PcapUrl”: “”,
“RecordingComplete”: true,
“ReportUrl”: “”,
“SandBoxOn”: true,
“Score”: null,
“Size”: 0,
“Status”: “Submitted”,
“StatusMessage”: null,
“SubmitId”: “0”,
“SubmitTime”: 1585559253000,
“Submitable”: true,
“TgReport”: false,
“ThreatGridOn”: false,
“Type”: “alert”,
“Uuid”: null,
“VideoUrl”: “”
},
“ID”: “9”
}
}
}


##### Human Readable Output

### Alert 9

|Alert Flags Xe Nonsubmit|Alert Id|Dns Feed|EF Enabled|File Check Alert|File Size|Js Submitable|Recording Complete|Sand Box On|Size|Status|Submit Id|Submit Time|Submitable|Tg Report|Threat Grid On|Type|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| false | 9 | false | true | true | 2990 | true | true | true | 0 | Submitted | 0 | 1585559253000 | true | false | false | alert |

### fidelis-get-alert-forensic-text

***
Get the text of the forensic data.

##### Base Command

`fidelis-get-alert-forensic-text`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_id | The alert ID. | Required |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Fidelis.Alert.ID | Number | The alert ID. |
| Fidelis.Alert.ForensicText | String | The alert's forensic text. |

##### Command Example

```!fidelis-get-alert-forensic-text alert_id=9```

##### Context Example

{
“Fidelis”: {
“Alert”: {
“ForensicText”: {file forensic text},
“ID”: “9”
}
}
}


##### Human Readable Output

Alert 9
Forensic Text: {file forensic text}

### fidelis-get-alert-decoding-path

***
Get the alert's decoding path.

##### Base Command

`fidelis-get-alert-decoding-path`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_id | Alert ID | Required |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Fidelis.Alert.ID | Number | The alert ID. |
| Fidelis.Alert.DecodingPath.ClickableDpaths | Unknown | The clickable decoding paths |
| Fidelis.Alert.DecodingPath.CommandpostIp | String | The command post IP. |
| Fidelis.Alert.DecodingPath.DecodingPaths | Unknown | The decoding path info. |
| Fidelis.Alert.DecodingPath.OriginalAttributes | String | The original attribute. |
| Fidelis.Alert.DecodingPath.OriginalDPath | String | The original path. |
| Fidelis.Alert.DecodingPath.AttributeMap | Unknown | The attribute map. |
| Fidelis.Alert.DecodingPath.AttributeMapHighLights | Unknown | The attribute map highlights. |

##### Command Example

```!fidelis-get-alert-decoding-path alert_id=9```

##### Context Example

{
“Fidelis”: {
“Alert”: {
“DecodingPath”: {
“AttributeMap”: {
“HTTP”: [
{
“endIndex”: 29,
“highLights”: [],
“link”: false,
“name”: “Filename”,
“partialAttr”: “HTTP\fFilename\tfile.pcap\n”,
“startIndex”: 0,
“value”: “file.pcap”,
“valueFirst255”: “file.pcap”
}
]
},
“AttributeMapHighLights”: [],
“ClickableDpaths”: [
“HTTP(file.pcap)”
],
“CommandpostIp”: null,
“DecodingPaths”: [
{
“clickable”: true,
“highLights”: [],
“linkPath”: “:HTTP(file.pcap)”,
“path”: “HTTP(file.pcap)”
}
],
“OriginalAttributes”: “HTTP\fFilename\tfile.pcap\n”,
“OriginalDPath”: “:HTTP(file.pcap)”
},
“ID”: “9”
}
}
}


##### Human Readable Output

### Alert 9

|Attribute Map|Clickable Dpaths|Decoding Paths|Original Attributes|Original D Path|
|---|---|---|---|---|
| HTTP: {u'endIndex': 29, u'name': u'Filename', u'valueFirst255': u'file.pcap', u'highLights': [], u'value': u'file.pcap', u'startIndex': 0, u'link': False, u'partialAttr': u'HTTP\x0cFilename\tfile.pcap\n'} | HTTP(file.pcap) | {u'clickable': True, u'highLights': [], u'linkPath': u':HTTP(file.pcap)', u'path': u'HTTP(file.pcap)'} | HTTPFilename file.pcap<br/> | :HTTP(file.pcap) |

### fidelis-update-alert-status

***
Update alert status

##### Base Command

`fidelis-update-alert-status`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_id | Alert ID | Required |
| status | The new alert status. | Required |

##### Context Output

There is no context output for this command.

##### Command Example

```!fidelis-update-alert-status alert_id=1 status=Actionable```

##### Human Readable Output

Alert 1 has been updated to Actionable status

### fidelis-alert-execution-forensics-submission

***
Submit an excutable file to the fidelis sandbox.

##### Base Command

`fidelis-alert-execution-forensics-submission`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_id | The alert ID. | Required |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Fidelis.Alert.ExecutionForensics.EFEnabled | Number | Is the alert execution forensics enabled. |
| Fidelis.Alert.ExecutionForensics.Size | Number | The execution forensics size. |
| Fidelis.Alert.ExecutionForensics.SubmitTime | Number | The submission time. |
| Fidelis.Alert.ExecutionForensics.SandBoxOn | Boolean | Is the sandbox on. |
| Fidelis.Alert.ExecutionForensics.TgReport | Boolean | The TG report. |
| Fidelis.Alert.ExecutionForensics.FileName | String | The file name. |
| Fidelis.Alert.ExecutionForensics.DnsFeed | Boolean | Is there a DNS feed. |
| Fidelis.Alert.ExecutionForensics.RecordingComplete | Boolean | Is the recording complete. |
| Fidelis.Alert.ExecutionForensics.PcapUrl | String | The PCAP URL. |
| Fidelis.Alert.ExecutionForensics.AlertFlagsXeNonsubmit | Boolean | The alert flag xe-nonsubmit. |
| Fidelis.Alert.ExecutionForensics.Bit9Server | String | The bit 9 server. |
| Fidelis.Alert.ExecutionForensics.DecodingPath | String | The execution forensics decoding path. |
| Fidelis.Alert.ExecutionForensics.FileCheckAlert | Boolean | The file check alert. |
| Fidelis.Alert.ExecutionForensics.Status | String | The execution forensics status. |
| Fidelis.Alert.ExecutionForensics.Submitable | Boolean | Is the execution forensics submitable. |
| Fidelis.Alert.ExecutionForensics.Score | Number | The execution forensics score. |
| Fidelis.Alert.ExecutionForensics.SubmitId | String | The execution forensics submit ID. |
| Fidelis.Alert.ExecutionForensics.VideoUrl | String | The video URL. |
| Fidelis.Alert.ExecutionForensics.StatusMessage | String | The execution forensics status message. |
| Fidelis.Alert.ExecutionForensics.FileType | String | The file type. |
| Fidelis.Alert.ExecutionForensics.AlertId | Number | The alert ID. |
| Fidelis.Alert.ExecutionForensics.Type | String | The type. |
| Fidelis.Alert.ExecutionForensics.ReportUrl | String | The report URL. |
| Fidelis.Alert.ExecutionForensics.JsSubmitable | Boolean | Is the execution forensics JS submitable. |
| Fidelis.Alert.ExecutionForensics.Uuid | String | The UUID. |
| Fidelis.Alert.ExecutionForensics.JsonReport | Unknown | The JSON report. |
| Fidelis.Alert.ExecutionForensics.FileSize | Unknown | The file size. |
| Fidelis.Alert.ExecutionForensics.Md5 | String | The file's MD5 hash. |
| Fidelis.Alert.ExecutionForensics.ThreatGridOn | Unknown | Is the threat grid on. |
| Fidelis.Alert.ID | Number | The alert ID. |

##### Command Example

```!fidelis-alert-execution-forensics-submission alert_id=9```

##### Context Example

{
“Fidelis”: {
“Alert”: {
“ExecutionForensics”: {
“AlertFlagsXeNonsubmit”: false,
“AlertId”: 9,
“Bit9Server”: null,
“DecodingPath”: null,
“DnsFeed”: false,
“EFEnabled”: true,
“FileCheckAlert”: true,
“FileName”: null,
“FileSize”: 2990,
“FileType”: “”,
“JsSubmitable”: true,
“JsonReport”: null,
“Md5”: null,
“PcapUrl”: “”,
“RecordingComplete”: true,
“ReportUrl”: “”,
“SandBoxOn”: true,
“Score”: null,
“Size”: 0,
“Status”: “Submitted”,
“StatusMessage”: null,
“SubmitId”: “0”,
“SubmitTime”: 1585559253000,
“Submitable”: true,
“TgReport”: false,
“ThreatGridOn”: false,
“Type”: “alert”,
“Uuid”: null,
“VideoUrl”: “”
},
“ID”: “9”
}
}
}


##### Human Readable Output

### Alert 9

|Alert Flags Xe Nonsubmit|Alert Id|Dns Feed|EF Enabled|File Check Alert|File Size|Js Submitable|Recording Complete|Sand Box On|Size|Status|Submit Id|Submit Time|Submitable|Tg Report|Threat Grid On|Type|
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| false | 9 | false | true | true | 2990 | true | true | true | 0 | Submitted | 0 | 1585559253000 | true | false | false | alert |

### fidelis-add-alert-comment

***
Adds a comment to an alert.

##### Base Command

`fidelis-add-alert-comment`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| alert_id | Alert ID | Required |
| comment | comment | Required |

##### Context Output

There is no context output for this command.

##### Command Example

```!fidelis-add-alert-comment alert_id=1 comment="my new comment"```

##### Human Readable Output

Added this comment: my new comment
 To alert ID: 1

### fidelis-assign-user-to-alert

***
Assign a user to an alert.

##### Base Command

`fidelis-assign-user-to-alert`

##### Input

| **Argument Name** | **Description** | **Required** |
| --- | --- | --- |
| conclusion_id | The alert conclusion ID. | Required |
| comment | Add a comment to the alert | Optional |
| assign_user | The user to assign. | Required |

##### Context Output

| **Path** | **Type** | **Description** |
| --- | --- | --- |
| Fidelis.Alert.AssignedUser | String | Assigned user ID. |
| Fidelis.Alert.ConclusionID | Number | The alert conclusion ID. |

##### Command Example

```!fidelis-assign-user-to-alert assign_user=cloud-user conclusion_id=2```

##### Context Example

{
“Fidelis”: {
“Alert”: {
“AssignedUser”: “cloud-user”,
“ConclusionID”: “2”
}
}
}
```

Human Readable Output

Assigned User: cloud-user to alert with conclusion ID 2

fidelis-close-alert


Closes a fidelis alert and can assign a user.

Base Command

fidelis-close-alert

Input
Argument Name Description Required
conclusion_id The conclusion ID. Required
resolution The alert resolution. Required
comment Add a comment to the alert. Optional
Context Output
Path Type Description
Fidelis.Alert.ConclusionID Number The conclusion ID.
Command Example

!fidelis-close-alert conclusion_id=2 resolution="False Positive"

Human Readable Output

Closed alert conclusion ID 2

fidelis-manage-alert-label


Adds a label to an alert.

Base Command

fidelis-manage-alert-label

Input
Argument Name Description Required
alert_id Alert ID. Required
label The label to add. Required
action What action should be taken. Required
Context Output

There is no context output for this command.

Command Example

!fidelis-manage-alert-label action=Add alert_id=3 label="example-label"

Human Readable Output

Assigned label: example-label to alert 3

Configuration parameters

  • server_url — Server URL (required)
  • credentials — Credentials (required)
  • unsecure — Trust any certificate (not secure)
  • proxy — Use system proxy settings
  • isFetch — Fetch incidents
  • incidentType — Incident type
  • incidentFetchInterval — Incidents Fetch Interval
  • fetch_time — First fetch timestamp (<number> <time unit>, e.g., 12 hours, 7 days, 3 months, 1 year)

Commands (25)

  • fidelis-add-alert-comment

    Adds a comment to an alert.

  • fidelis-alert-execution-forensics-submission

    Submit an excutable file to the fidelis sandbox.

  • fidelis-assign-user-to-alert

    Assign a user to an alert.

  • fidelis-close-alert

    Closes a fidelis alert and can assign a user.

  • fidelis-delete-alert

    Deletes an alert from Fidelis Elevate.

  • fidelis-download-malware-file

    Downloads a malware file from a specified alert.

  • fidelis-download-pcap-file

    Downloads the PCAP file from a specified alert.

  • fidelis-get-alert

    Gets alert details from Fidelis Elevate.

  • fidelis-get-alert-by-uuid

    Returns an alert, by UUID.

  • fidelis-get-alert-decoding-path

    Get the alert's decoding path.

  • fidelis-get-alert-execution-forensics

    Get the exectution forensics for an alert.

  • fidelis-get-alert-forensic-text

    Get the text of the forensic data.

  • fidelis-get-alert-pcap Deprecated

    Retrieves the alert PCAP from Fidelis Elevate.

  • fidelis-get-alert-report

    Downloads a PDF report for a specified alert.

  • fidelis-get-alert-session-data

    Return the session information related to an alert.

  • fidelis-get-malware-data

    Retrieves malware data related to a "Malware" type alert.

  • fidelis-list-alerts

    Returns a list of open alerts from Fidelis Elevate.

  • fidelis-list-alerts-by-ip

    Returns a list of alerts, by source IP address or destination IP address.

  • fidelis-list-metadata

    Returns a metadata list.

  • fidelis-list-pcap-components

    Gets PCAP components.

  • fidelis-manage-alert-label

    Adds a label to an alert.

  • fidelis-run-pcap

    Runs PCAP file analysis in Fidelis Elevate.

  • fidelis-sandbox-upload Deprecated

    Uploads a file or a URL for sandbox analysis in Fidelis Elevate.

  • fidelis-update-alert-status

    Update alert status

  • fidelis-upload-pcap

    Uploads a PCAP file to Fidelis Elevate for analysis.

import re
from urllib.parse import unquote

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

from CommonServerUserPython import *

""" IMPORTS """
import json
import random
import shutil

import requests

# disable insecure warnings
urllib3.disable_warnings()

""" GLOBALS / PARAMS """
IS_FETCH = demisto.params().get("isFetch")
SERVER_URL = demisto.params().get("server_url", "")
CREDENTIALS = demisto.params().get("credentials")
INSECURE = demisto.params().get("unsecure")
PROXY = demisto.params().get("proxy")
FETCH_TIME = demisto.params().get("fetch_time", "3 days")
SESSION_ID = None
ALERT_UUID_REGEX = re.compile("[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}")

""" HELPER FUNCTIONS """


def capitalize_first_letter(raw_dict):
    parsed_dict = {}
    for key in list(raw_dict.keys()):
        cap_key = key[0].capitalize() + key[1:]
        parsed_dict[cap_key] = raw_dict[key]

    return parsed_dict


def http_request(method, url_suffix, params=None, data=None, files=None, is_json=True):
    # A wrapper for requests lib to send our requests and handle requests and responses better
    headers = {}  # type: Dict[str, str]
    if SESSION_ID is not None:
        headers["x-uid"] = SESSION_ID
    if files is None:
        headers["Content-Type"] = "application/json"

    res = requests.request(
        method,
        SERVER_URL + url_suffix,
        data=None if data is None else json.dumps(data),
        headers=headers,
        params=params,
        files=files,
        verify=not INSECURE,
    )

    # Handle error responses gracefully
    if res.status_code not in {200, 201}:
        if res.status_code == 500:
            try:
                error = res.json().get("detailMessage", res.content)

            except:  # noqa
                error = res.content

            raise Exception(f"Error in API call to Fidelis Integration {res.status_code} - {error}")
        else:
            raise Exception(f"Error in API call to Fidelis Integration {res.status_code} - {res.reason}")

    if is_json:
        try:
            return res.json()

        except ValueError:
            return_error(f"failed to parse json object from response: {res.content!s}")

    else:
        return res.content


@logger
def login():
    global SESSION_ID

    data = {"user": CREDENTIALS.get("identifier"), "password": CREDENTIALS.get("password")}

    if SESSION_ID is None:
        url = "/j/rest/v1/access/login/json/"
        try:
            res = http_request("POST", url, data=data)
            if res.get("error") is not None:
                raise requests.HTTPError(f'Failed to login: {res.get("error")}')
            SESSION_ID = res.get("uid")
        except requests.exceptions.RequestException as e:  # noqa
            return_error("Demisto has encounter a connection error, please check the server_url and credentials parameters")


def logout():
    global SESSION_ID
    if SESSION_ID is not None:
        try:
            url = f"/j/rest/v1/access/logout/{SESSION_ID}/"
            http_request("GET", url)
            SESSION_ID = None

        except:  # noqa
            pass


def generate_pagination():
    return {
        "getLast": False,
        "page": 1,
        "referenceTime": "",
        "size": 200,
        "supportPaging": True,
    }


def get_ioc_filter(ioc):
    if re.match(ipv4Regex, ioc):
        return {"simple": {"column": "ANY_IP", "operator": "=", "value": ioc}}
    elif md5Regex.match(ioc):
        return {"simple": {"column": "MD5", "operator": "=", "value": ioc}}
    elif sha256Regex.match(ioc):
        return {"simple": {"column": "SHA256", "operator": "=", "value": ioc}}
    elif sha1Regex.match(ioc):
        return {"simple": {"column": "SHA1_HASH", "operator": "=", "value": ioc}}
    elif ALERT_UUID_REGEX.match(ioc):
        return {"simple": {"column": "UUID", "operator": "=", "value": ioc}}
    else:
        return {"simple": {"column": "ANY_STRING", "operator": "=~", "value": ioc}}


def to_fidelis_time_format(t):
    if isinstance(t, STRING_TYPES):
        try:
            t = datetime.strptime(str(t), "%Y-%m-%dT%H:%M:%SZ")
        except ValueError:
            t = datetime.strptime(t, "%Y-%m-%dT%H:%M:%S")

    return datetime.strftime(t, "%Y-%m-%d %H:%M:%S")


def generate_time_settings(time_frame=None, start_time=None, end_time=None):
    # default value
    settings = {
        "from": "",
        "to": "",
        "key": "all",
        "value": "",
    }

    if time_frame is None:
        return settings
    elif time_frame in ["Today", "Yesterday"]:
        settings["key"] = time_frame.lower()
    elif "Last" in time_frame:
        settings["key"] = "last"
        if time_frame == "Last 7 Days":
            settings["value"] = "7:00:00:00"
        elif time_frame == "Last 30 Days":
            settings["value"] = "30:00:00:00"
        elif time_frame == "Last Hour":
            settings["value"] = "1:00:00"
        elif time_frame == "Last 24 Hours":
            settings["value"] = "24:00:00"
        elif time_frame == "Last 48 Hours":
            settings["value"] = "48:00:00"
        else:
            raise ValueError(f"Could not parse time frame: {time_frame}")

    elif time_frame == "Custom":
        settings["key"] = "custom"
        if start_time is None and end_time is None:
            raise ValueError("invalid custom time frame: need to specify one of start_time, end_time")
        if start_time is not None:
            settings["from"] = to_fidelis_time_format(start_time)
        if end_time is not None:
            settings["to"] = to_fidelis_time_format(end_time)

    return settings


""" COMMANDS + REQUESTS FUNCTIONS """


def update_alertstatus_command():
    status_to_explicit_score = {"False Positive": 1, "Not Interesting": 2, "Interesting": 3, "Actionable": 4}
    args = demisto.args()
    alert_id = args["alert_id"]
    status = args["status"]

    data = {"alertIds": [alert_id], "explicitScore": status_to_explicit_score[status]}

    raw_res = update_alertstatus(data)
    return_outputs(f"Alert {alert_id} has been updated to {status.capitalize()} status", {}, raw_res)


@logger
def update_alertstatus(data):
    url = "/j/rest/v1/alert/feedback/"

    return http_request("PUT", url, data=data)


def get_alert_dpath_command():
    args = demisto.args()
    alert_id = args["alert_id"]

    result = get_alert_dpath(alert_id)
    context_result = capitalize_first_letter(result)

    output = {"ID": alert_id, "DecodingPath": context_result}

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": result,
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown(f"Alert {alert_id}", context_result, headerTransform=pascalToSpace, removeNull=True),
            "EntryContext": {
                "Fidelis.Alert(val.ID && val.ID == obj.ID)": output,
            },
        }
    )


@logger
def get_alert_dpath(alert_id):
    result = http_request("GET", f"/j/rest/v1/alert/dpath/{alert_id}/")

    return result


def alert_ef_submission_command():
    args = demisto.args()

    alert_id = args["alert_id"]

    result = alert_ef_submission(alert_id)
    context_result = capitalize_first_letter(result)

    output = {"ID": alert_id, "ExecutionForensics": context_result}

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": result,
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown(f"Alert {alert_id}", context_result, headerTransform=pascalToSpace, removeNull=True),
            "EntryContext": {
                "Fidelis.Alert(val.ID && val.ID == obj.ID)": output,
            },
        }
    )


@logger
def alert_ef_submission(alert_id):
    result = http_request("GET", f"/j/rest/v1/alert/efsubmit/{alert_id}/")

    return result


def add_alert_comment_command():
    args = demisto.args()
    alert_id = args["alert_id"]
    comment = args["comment"]

    data = {"type": "byAlertID", "alertIds": [alert_id], "comment": comment}

    add_alert_comment(alert_id, data)
    return_outputs(f"Added this comment: {comment}\n To alert ID: {alert_id}", {}, {})


@logger
def add_alert_comment(alert_id, data):
    url = "/j/rest/v1/alert/mgmt/"
    http_request("PUT", url, data=data)


def manage_alert_label_command():
    args = demisto.args()
    alert_id = args["alert_id"]
    label = args["label"]
    action = args["action"]

    label_action = {"Add": "LABEL_ADD", "Remove": "LABEL_REMOVE"}

    data = {
        "type": "byAlertID",
        "alertIds": [alert_id],
        "labels": [label],
        "labelAction": label_action[action],
    }

    bad_res = manage_alert_label(data)
    if bad_res and action == "Add":
        return_error(f"Was not able to add the label {label} to alert {alert_id}")

    elif bad_res and action == "Remove":
        return_error(f"Was not able to remove the label {label} to alert {alert_id}")

    else:
        return_outputs(f"Assigned label: {label} to alert {alert_id}", {}, {})


@logger
def manage_alert_label(data):
    url = "/j/rest/v1/alert/mgmt/"
    res = http_request("PUT", url, data=data)
    if res.get("Console") == "OK":
        return 0

    else:
        return 1


def manage_alert_assignuser_command():
    args = demisto.args()
    conclusion_id = args["conclusion_id"]
    assign_user = args["assign_user"]
    comment = args.get("comment")

    data = {
        "alertIds": [f"Console-{conclusion_id}"],
        "assignToUser": assign_user,
        "searchParams": None,
        "byId": True,
        "purgeEvents": False,
        "resolution": None,
        "comment": comment,
        "labels": None,
        "rating": None,
        "status": "OPEN",
        "action": "ASSIGN",
    }

    raw_response = manage_alert_assignuser(data)
    entry_context = {"AssignedUser": assign_user, "ConclusionID": conclusion_id}

    return_outputs(
        f"Assigned User: {assign_user} to alert with conclusion ID {conclusion_id}",
        {"Fidelis.Alert(val.ConclusionID && val.ConclusionID == obj.ConclusionID)": entry_context},
        raw_response,
    )


def manage_alert_assignuser(data):
    url = "/j/rest/v2/alert/mgmt/"
    raw_res = http_request("POST", url, data=data)
    return raw_res


def manage_alert_closealert_command():
    args = demisto.args()
    conclusion_id = args["conclusion_id"]
    comment = args.get("comment")
    resolution = args["resolution"]

    data = {
        "alertIds": [f"Console-{conclusion_id}"],
        # This field is not used by Fidelis when closing alerts / So setting it doesn't matter
        "searchParams": None,
        "byId": True,
        "purgeEvents": False,
        "resolution": resolution,
        "comment": comment,
        "labels": None,
        "rating": None,
        "status": "CLOSED",
        "action": "STATUS",
    }

    raw_response = manage_alert_closealert(data)

    return_outputs(f"Closed alert conclusion ID {conclusion_id}", {}, raw_response)


@logger
def manage_alert_closealert(data):
    url = "/j/rest/v2/alert/mgmt/"
    raw_res = http_request("POST", url, data=data)
    return raw_res


def get_alert_sessiondata_command():
    args = demisto.args()
    alert_id = args["alert_id"]

    result = get_alert_sessiondata(alert_id)
    context_result = capitalize_first_letter(result)

    # The API has typos built in "serverDomaniName" - should be ServerDomainName,
    # clientDomaniName - should be ClientDomainName,
    if context_result.get("ServerDomaniName"):
        context_result["ServerDomainName"] = context_result["ServerDomaniName"]
        del context_result["ServerDomaniName"]

    else:
        context_result["ServerDomainName"] = None

    if context_result.get("ClientDomaniClient"):
        context_result["ClientDomainName"] = context_result.get("ClientDomaniClient")
        del context_result["ClientDomaniClient"]

    else:
        context_result["ClientDomainName"] = None

    output = {"ID": alert_id, "SessionData": context_result}

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": result,
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown(f"Alert {alert_id}", context_result, headerTransform=pascalToSpace, removeNull=True),
            "EntryContext": {
                "Fidelis.Alert(val.ID && val.ID == obj.ID)": output,
            },
        }
    )


@logger
def get_alert_sessiondata(alert_id):
    result = http_request("GET", f"/j/rest/v2/event/sessiondata/{alert_id}/")

    return result


def get_alert_ef_command():
    args = demisto.args()
    alert_id = args["alert_id"]

    result = get_alert_ef(alert_id)
    context_result = capitalize_first_letter(result)
    output = {"ID": alert_id, "ExecutionForensics": context_result}

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": result,
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown(f"Alert {alert_id}", context_result, headerTransform=pascalToSpace, removeNull=True),
            "EntryContext": {
                "Fidelis.Alert(val.ID && val.ID == obj.ID)": output,
            },
        }
    )


@logger
def get_alert_ef(alert_id):
    result = http_request("GET", f"/j/rest/v1/alert/ef/{alert_id}/")

    return result


def get_alert_forensictext_command():
    args = demisto.args()
    alert_id = args["alert_id"]

    result = get_alert_forensictext(alert_id)
    output = {"ID": alert_id, "ForensicText": result}

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["text"],
            "Contents": str(result),
            "EntryContext": {
                "Fidelis.Alert(val.ID && val.ID == obj.ID)": output,
            },
            "HumanReadable": f"Alert {alert_id}\nForensic Text: {result}",
        }
    )


@logger
def get_alert_forensictext(alert_id):
    headers = {}  # type: Dict[str, str]
    if SESSION_ID is not None:
        headers["x-uid"] = SESSION_ID
    headers["Content-Type"] = "application/json"

    res = requests.request(
        method="GET",
        url=SERVER_URL + f"/j/rest/v1/alert/file/forensic/text/{alert_id}/",
        data=None,
        headers=headers,
        params=None,
        files=None,
        verify=not INSECURE,
    )

    return res.text


def get_alert_command():
    args = demisto.args()
    alert_id = args["alert_id"]

    alert = get_alert(alert_id)

    output = {
        "ID": alert["alertId"],
        "ThreatScore": alert["fidelisScore"],
        "Time": alert["time"],
        "RuleID": alert["ruleId"],
        "RuleName": alert["rule"],
        "Summary": alert["summary"],
        "PolicyName": alert["policy"],
        "Severity": alert["severity"],
        "Protocol": alert["protocol"],
        "Type": alert["alertType"],
        "AlertUUID": alert["alertUUID"],
        "AssignedUser": alert["ticket"]["assignedUserId"] if alert["ticket"] is not None else None,
    }

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": alert,
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown(f"Alert {alert_id}", output, headerTransform=pascalToSpace, removeNull=True),
            "EntryContext": {
                "Fidelis.Alert(val.ID && val.ID == obj.ID)": output,
            },
        }
    )


@logger
def get_alert(alert_id):
    return http_request("GET", f"/j/rest/v1/alert/info/{alert_id}/")


def delete_alert_command():
    args = demisto.args()
    alert_id = args["alert_id"].split(",")

    delete_alert(alert_id)

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": "\n".join(f"Alert ({_id}) deleted successfully!" for _id in alert_id),
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": "\n".join(f"Alert ({_id}) deleted successfully!" for _id in alert_id),
        }
    )


@logger
def delete_alert(alert_id):
    data = {
        "type": "byAlertID",
        "alertIds": alert_id,
    }
    result = http_request("POST", "/j/rest/v1/alert/delete/", data=data)

    return result


def get_malware_data_command():
    args = demisto.args()
    alert_id = args["alert_id"]

    result = get_malware_data(alert_id)

    output = {
        "ID": alert_id,
        "Malware": {
            "Name": result["malwareName"],
            "Behavior": result["malwareBehavior"],
            "Description": result["malwareDescription"],
            "DetailName": result["malwareDetailName"],
            "Platform": result["malwarePlatform"],
            "Type": result["malwareType"],
            "Variant": result["malwareVariant"],
        },
    }

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": result,
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown(f"Alert {alert_id} Malware:", result, headerTransform=pascalToSpace),
            "EntryContext": {
                "Fidelis.Alert(val.ID && val.ID == obj.ID)": output,
            },
        }
    )


@logger
def get_malware_data(alert_id):
    result = http_request("GET", f"/j/rest/v1/alert/malware/{alert_id}/")

    return result


def get_alert_pcap_command():
    args = demisto.args()
    alert_id = args["alert_id"]

    results = get_alert_pcap(alert_id)

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": results,
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown("<INSERT TITLE HERE>", results),
        }
    )


@logger
def get_alert_pcap(alert_id):
    # result = http_request('GET', '/j/rest/v1/alert/pcap/{}/'.format(alert_id), is_json=False)
    # return result
    raise NotImplementedError


def get_alert_report_command():
    args = demisto.args()
    alert_id = int(args["alert_id"])

    pdf_content = get_alert_report(alert_id)

    demisto.results(fileResult(f"Alert_Details_{alert_id}.pdf", pdf_content, file_type=entryTypes["entryInfoFile"]))


@logger
def get_alert_report(alert_id):
    result = http_request("GET", "/j/rest/v1/alert/export/alertdetails/pdf", params={"alertIds": alert_id}, is_json=False)

    return result


def sandbox_upload_command():
    args = demisto.args()
    upload_item = args["upload_item"]

    results = sandbox_upload(upload_item)

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": results,
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown("<INSERT TITLE HERE>", results),
            # 'EntryContext': create_context([indicator]),
        }
    )


@logger
def sandbox_upload(upload_item):
    raise NotImplementedError("The command is not implemented and could only be done manually through Fidelis.")


def list_alerts_command():
    args = demisto.args()
    time_frame = args.get("time_frame")
    start_time = args.get("start_time")
    end_time = args.get("end_time")
    severity = args.get("severity")
    _type = args.get("type")
    threat_score = args.get("threat_score")
    ioc = args.get("ioc")

    results = list_alerts(
        time_frame=time_frame,
        start_time=start_time,
        end_time=end_time,
        severity=severity,
        _type=_type,
        threat_score=threat_score,
        ioc=ioc,
    )
    output = [
        {
            "ID": alert["ALERT_ID"],
            "Time": alert["ALERT_TIME"],
            "Summary": alert["SUMMARY"],
            "Severity": alert["SEVERITY"],
            "Type": alert["ALERT_TYPE"],
        }
        for alert in results
    ]

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": results,
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown(f"Found {len(output)} Alerts:", output),
            "EntryContext": {
                "Fidelis.Alert(val.ID && val.ID == obj.ID)": output,
            },
        }
    )


@logger
def list_alerts(
    time_frame=None,
    start_time=None,
    end_time=None,
    severity=None,
    _type=None,
    threat_score=None,
    ioc=None,
    additional_columns=None,
):
    columns = additional_columns if additional_columns is not None else []

    filters = [{"simple": {"column": "ACTION", "operator": "=", "value": "alert"}}]
    if severity is not None:
        filters.append({"simple": {"column": "SEVERITY", "operator": "IN", "value": severity}})
    if _type is not None:
        filters.append({"simple": {"column": "ALERT_TYPE", "operator": "IN", "value": _type}})
    if threat_score is not None:
        filters.append({"simple": {"column": "FIDELIS_SCORE", "operator": ">", "value": threat_score}})
    if ioc is not None:
        filters.append(get_ioc_filter(ioc))

    data = {
        "columns": columns
        + [
            "ALERT_ID",
            "ALERT_TIME",
            "SUMMARY",
            "SEVERITY",
            "ALERT_TYPE",
        ],
        "filter": {
            "composite": {
                "logic": "and",
                "filters": filters,
            }
        },
        "order": [{"column": "ALERT_TIME", "direction": "DESC"}],
        "pagination": generate_pagination(),
        "timeSettings": generate_time_settings(time_frame, start_time, end_time),
    }
    res = http_request("POST", "/j/rest/v1/alert/search/", data=data)

    return res["aaData"]


def list_alerts_by_ip_request(time_frame=None, start_time=None, end_time=None, src_ip=None, dest_ip=None):
    filters = []
    if src_ip is not None:
        filters.append({"simple": {"column": "SRC_IP", "operator": "IN", "value": src_ip}})
    if dest_ip is not None:
        filters.append({"simple": {"column": "DEST_IP", "operator": "IN", "value": dest_ip}})

    data = {
        "commandPosts": [],
        "filter": {"composite": {"logic": "or", "filters": filters}},
        "order": [{"column": "ALERT_TIME", "direction": "DESC"}],
        "pagination": {"page": 1, "size": 100},
        "columns": [
            "ALERT_TIME",
            "UUID",
            "ALERT_ID",
            "DISTRIBUTED_ALERT_ID",
            "USER_RATING",
            "HOST_IP",
            "ASSET_ID",
            "ALERT_TYPE",
            "DEST_COUNTRY_NAME",
            "SRC_COUNTRY_NAME",
            "DEST_IP",
            "SRC_IP",
        ],
        "timeSettings": generate_time_settings(time_frame, start_time, end_time),
    }

    res = http_request("POST", "/j/rest/v1/alert/search/", data=data)
    return res["aaData"]


def list_alerts_by_ip():
    """
    List alerts by the source IP or destination IP
    """
    args = demisto.args()
    time_frame = args.get("time_frame")
    start_time = args.get("start_time")
    end_time = args.get("end_time")
    src_ip = args.get("src_ip")
    dest_ip = args.get("dest_ip")
    headers = [
        "Time",
        "AlertUUID",
        "ID",
        "DistributedAlertID",
        "UserRating",
        "HostIP",
        "AssetID",
        "Type",
        "DestinationCountry",
        "SourceCountry",
        "DestinationIP",
        "SourceIP",
    ]
    results = list_alerts_by_ip_request(
        time_frame=time_frame, start_time=start_time, end_time=end_time, src_ip=src_ip, dest_ip=dest_ip
    )
    output = [
        {
            "ID": alert.get("ALERT_ID"),
            "Time": alert.get("ALERT_TIME"),
            "AlertUUID": alert.get("UUID"),
            "DistributedAlertID": alert.get("DISTRIBUTED_ALERT_ID"),
            "Type": alert.get("ALERT_TYPE"),
            "UserRating": alert.get("USER_RATING"),
            "HostIP": alert.get("HOST_IP"),
            "AssetID": alert.get("ASSET_ID"),
            "DestinationCountry": alert.get("DEST_COUNTRY_NAME"),
            "SourceCountry": alert.get("SRC_COUNTRY_NAME"),
            "DestinationIP": alert.get("DEST_IP"),
            "SourceIP": alert.get("SRC_IP"),
        }
        for alert in results
    ]

    context = {"Fidelis.Alert(val.ID && val.ID == obj.ID)": output}

    return_outputs(tableToMarkdown(f"Found {len(output)} Alerts:", output, headers), context, results)


def get_alert_by_uuid():
    alert_uuid = demisto.args().get("alert_uuid")

    results = list_alerts(ioc=alert_uuid)

    output = [
        {
            "ID": alert["ALERT_ID"],
            "Time": alert["ALERT_TIME"],
            "Summary": alert["SUMMARY"],
            "Severity": alert["SEVERITY"],
            "Type": alert["ALERT_TYPE"],
        }
        for alert in results
    ]

    context = {"Fidelis.Alert(val.ID && val.ID == obj.ID)": output}

    return_outputs(tableToMarkdown(f"Found {len(output)} Alerts:", output), context, results)


def upload_pcap_command():
    args = demisto.args()
    component_ip = args["component_ip"]
    entry_id = args["entry_id"]

    upload_pcap(component_ip, entry_id)

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["text"],
            "Contents": "Pcap file uploaded successfully.",
        }
    )


@logger
def upload_pcap(component_ip, entry_id):
    file_info = demisto.getFilePath(entry_id)
    shutil.copy(file_info["path"], file_info["name"])

    try:
        with open(file_info["name"], "rb") as f:
            http_request("POST", f"/j/rest/policy/pcap/upload/{component_ip}/", files={"uploadFile": f}, is_json=False)
    finally:
        shutil.rmtree(file_info["name"], ignore_errors=True)


def run_pcap_command():
    args = demisto.args()
    component_ip = args["component_ip"]
    file_names = args["files"].split(",")

    run_pcap(component_ip, file_names)

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["text"],
            "Contents": "Pcap file run submitted.",
        }
    )


@logger
def run_pcap(component_ip, file_names):
    data = {"component": component_ip, "files": file_names}
    http_request("POST", "/j/rest/policy/pcap/run/", data=data)  # noqa


def list_pcap_components_command():
    results = list_pcap_components()
    output = [
        {
            "IP": r["ip"],
            "Name": r["name"],
        }
        for r in results
    ]

    demisto.results(
        {
            "Type": entryTypes["note"],
            "ContentsFormat": formats["json"],
            "Contents": results,
            "ReadableContentsFormat": formats["markdown"],
            "HumanReadable": tableToMarkdown("PCAP Components", output, headers=["Name", "IP"]),
            "EntryContext": {"Fidelis.Component(val.Name && val.Name == obj.Name)": output},
        }
    )


@logger
def list_pcap_components():
    res = http_request("GET", "/j/rest/policy/pcap/components/")

    return res


def list_metadata_request(
    time_frame=None, start_time=None, end_time=None, client_ip=None, server_ip=None, request_direction=None
):
    filters = []
    if client_ip is not None:
        filters.append({"simple": {"column": "ClientIP", "operator": "=", "value": client_ip}})
    if server_ip is not None:
        filters.append({"simple": {"column": "ServerIP", "operator": "=", "value": server_ip}})
    if request_direction is not None:
        filters.append({"simple": {"column": "Direction", "operator": "=", "value": request_direction}})
    search_id = str([random.randint(1, 9) for _ in range(8)])

    data = {
        "collectors": [],
        "action": "new",
        "allCollectors": True,
        "timeSettings": generate_time_settings(time_frame, start_time, end_time),
        "displaySettings": {
            "pageSize": 1000,
            "currentPage": 1,
            "pageNavigation": "",
            "sorting": {"column": "Timestamp", "sortingOrder": "D"},
        },
        "dataSettings": {"composite": {"logic": "and", "filters": filters}},
        "searchId": search_id,
    }
    res = http_request("POST", "/j/rest/metadata/search/", data=data)

    return res.get("aaData")


def list_metadata():
    args = demisto.args()
    time_frame = args.get("time_frame")
    start_time = args.get("start_time")
    end_time = args.get("end_time")
    client_ip = args.get("client_ip")
    server_ip = args.get("server_ip")
    request_direction = args.get("request_direction")

    data = []
    event_context = []

    results = list_metadata_request(
        time_frame=time_frame,
        start_time=start_time,
        end_time=end_time,
        client_ip=client_ip,
        server_ip=server_ip,
        request_direction=request_direction,
    )
    for event in results:
        data.append(
            {
                "Timestamp": event.get("Timestamp"),
                "ServerIP": event.get("ServerIP"),
                "ServerPort": event.get("ServerPort"),
                "ClientIP": event.get("ClientIP"),
                "ClientPort": event.get("ClientPort"),
            }
        )

        event_context.append(
            {
                "Timestamp": event.get("Timestamp"),
                "ServerIP": event.get("ServerIP"),
                "ServerPort": event.get("ServerPort"),
                "ServerCountry": event.get("ServerCountry"),
                "ClientIP": event.get("ClientIP"),
                "ClientPort": event.get("ClientPort"),
                "ClientCountry": event.get("ClientCountry"),
                "Type": event.get("Type"),
                "SensorUUID": event.get("SensorUUID"),
                "SessionStart": event.get("SessionStart"),
                "SessionDuration": event.get("SessionDuration"),
                "Protocol": event.get("Protocol"),
                "URL": event.get("URL"),
                "RequestDirection": event.get("RequestDirection"),
                "UserAgent": event.get("UserAgent"),
                "FileName": event.get("FileName"),
                "FileType": event.get("FileType"),
                "FileSize": event.get("FileSize"),
                "MD5": event.get("MD5"),
                "SHA256": event.get("SHA256"),
                "MalwareName": event.get("MalwareName"),
                "MalwareType": event.get("MalwareType"),
                "MalwareSeverity": event.get("MalwareSeverity"),
                "PcapFilename": event.get("PcapFilename"),
                "PcapTimestamp": event.get("PcapTimestamp"),
            }
        )
    context = {"Fidelis.Metadata(val.ID && val.ID == obj.ID)": event_context}

    return_outputs(tableToMarkdown(f"Found {len(data)} Metadata:", data), context, results)


def request_dpath(alert_id):
    res = http_request("GET", f"/j/rest/v1/alert/dpath/{alert_id}/")
    if res.get("decodingPaths"):
        dpath = res.get("decodingPaths")[0]
        link_path = dpath.get("linkPath")
    else:
        raise Exception("Could not find the file path.")

    return link_path


def download_malware_file_request(alert_id):
    dpath = request_dpath(alert_id)
    query_params = {"uid": SESSION_ID, "alert_id": alert_id, "type": "1", "params": dpath}
    res = http_request("GET", "/query/tcpses_getfile.cgi", params=query_params, is_json=False)

    return res


def download_malware_file():
    """
    Download specific malware from the alert
    """
    alert_id = demisto.args().get("alert_id")
    file_name = request_dpath(alert_id)

    if not file_name:
        return_outputs("No File Found", {}, {})

    else:
        decoded_file_name = unquote(file_name)
        results = download_malware_file_request(alert_id)

        demisto.results(fileResult(decoded_file_name + ".zip", results, file_type=entryTypes["file"]))


def download_pcap_request(alert_id):
    query_params = {
        "uid": SESSION_ID,
        "alert_id": alert_id,
        "commandpost": "127.0.0.1",
    }

    results = http_request("GET", "/e.cgi", params=query_params, is_json=False)

    return results


def download_pcap_file():
    """
    Download PCAP from an alert
    """
    alert_id = demisto.args().get("alert_id")

    results = download_pcap_request(alert_id)
    demisto.results(fileResult("Alert ID_" + alert_id + ".pcap", results, file_type=entryTypes["file"]))


def test_integration():
    # the login is executed in the switch panel code
    if IS_FETCH:
        # just check the correctness of the parameter
        parse_date_range(FETCH_TIME)
    list_pcap_components()
    demisto.results("ok")


def fetch_incidents():
    last_run = demisto.getLastRun()
    # Get the last fetch time, if exists
    last_fetch = last_run.get("time")

    # Handle first time fetch, fetch incidents retroactively
    if last_fetch is None:
        last_fetch, _ = parse_date_range(FETCH_TIME, date_format="%Y-%m-%dT%H:%M:%S")

    latest = datetime.strptime(last_fetch, "%Y-%m-%dT%H:%M:%S")

    demisto.debug(f"getting alarms since {last_fetch}")
    incidents = []
    items = list_alerts(time_frame="Custom", start_time=last_fetch)
    demisto.debug(f"got {len(items)} new alarms")
    for item in items:
        incident_date = datetime.strptime(item["ALERT_TIME"], "%Y-%m-%d %H:%M:%S")
        incident = {
            "Type": "Fidelis",
            "name": f'{item["ALERT_ID"].encode("utf-8")} {item["SUMMARY"].encode("utf-8")}',
            "occurred": incident_date.strftime("%Y-%m-%dT%H:%M:%SZ"),
            "rawJSON": json.dumps(item),
        }
        latest = max(latest, incident_date)
        incidents.append(incident)

    if latest != last_fetch:
        last_fetch = (latest + timedelta(seconds=1)).strftime("%Y-%m-%dT%H:%M:%S")
        demisto.setLastRun({"time": last_fetch})

    demisto.incidents(incidents)


""" COMMANDS MANAGER / SWITCH PANEL """


def main():
    try:
        handle_proxy()
        command = demisto.command()
        demisto.debug(f"Command being called is {command}")
        login()
        if command == "test-module":
            test_integration()
        elif command == "fetch-incidents":
            fetch_incidents()

        elif command == "fidelis-get-alert":
            get_alert_command()

        elif command == "fidelis-delete-alert":
            delete_alert_command()

        elif command == "fidelis-get-malware-data":
            get_malware_data_command()

        elif command == "fidelis-get-alert-pcap":
            get_alert_pcap_command()

        elif command == "fidelis-get-alert-report":
            get_alert_report_command()

        elif command == "fidelis-sandbox-upload":
            sandbox_upload_command()

        elif command == "fidelis-list-alerts":
            list_alerts_command()

        elif command == "fidelis-upload-pcap":
            upload_pcap_command()

        elif command == "fidelis-run-pcap":
            run_pcap_command()

        elif command == "fidelis-list-pcap-components":
            list_pcap_components_command()

        elif command == "fidelis-get-alert-by-uuid":
            get_alert_by_uuid()

        elif command == "fidelis-list-metadata":
            list_metadata()

        elif command == "fidelis-list-alerts-by-ip":
            list_alerts_by_ip()

        elif command == "fidelis-download-malware-file":
            download_malware_file()

        elif command == "fidelis-download-pcap-file":
            download_pcap_file()

        elif command == "fidelis-get-alert-session-data":
            get_alert_sessiondata_command()

        elif command == "fidelis-get-alert-execution-forensics":
            get_alert_ef_command()

        elif command == "fidelis-get-alert-forensic-text":
            get_alert_forensictext_command()

        elif command == "fidelis-get-alert-decoding-path":
            get_alert_dpath_command()

        elif command == "fidelis-update-alert-status":
            update_alertstatus_command()

        elif command == "fidelis-alert-execution-forensics-submission":
            alert_ef_submission_command()

        elif command == "fidelis-add-alert-comment":
            add_alert_comment_command()

        elif command == "fidelis-assign-user-to-alert":
            manage_alert_assignuser_command()

        elif command == "fidelis-close-alert":
            manage_alert_closealert_command()

        elif command == "fidelis-manage-alert-label":
            manage_alert_label_command()

    except Exception as e:
        return_error(f"error has occurred: {e!s}")

    finally:
        logout()


# python2 uses __builtin__ python3 uses builtins
if __name__ == "__builtin__" or __name__ == "builtins":
    main()