Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Pack][IdentityRecordedFuture][v2.0.3] #36305

Open
wants to merge 3 commits into
base: contrib/recordedfuture-dev_identityrecordedfuture_pack_update_2024_09
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import base64
import json
import platform
from typing import Any, Dict, Optional
from typing import Any, Dict, List, Optional

import requests

Expand All @@ -17,7 +17,11 @@
# pylint:disable=no-member
requests.packages.urllib3.disable_warnings() # type: ignore

__version__ = "2.0.0"
__version__ = "2.0.3"

TIMEOUT_60 = 60
TIMEOUT_90 = 90
TIMEOUT_120 = 120


class Client(BaseClient):
Expand All @@ -26,7 +30,7 @@ def whoami(self) -> Dict[str, Any]:
return self._http_request(
method="get",
url_suffix="info/whoami",
timeout=60,
timeout=TIMEOUT_60,
)

def _call(self, url_suffix: str, **kwargs):
Expand All @@ -49,11 +53,13 @@ def _call(self, url_suffix: str, **kwargs):
v = kwargs.pop(k)
json_data[k] = v

method = kwargs.get("method", "post")

request_kwargs = {
"method": "post",
"method": method,
"url_suffix": url_suffix,
"json_data": json_data,
"timeout": 90,
"timeout": TIMEOUT_90,
"retries": 3,
"status_list_to_retry": STATUS_TO_RETRY,
}
Expand Down Expand Up @@ -112,7 +118,7 @@ def fetch_incidents(self) -> Dict[str, Any]:
"""Fetch incidents."""
return self._call(
url_suffix="/playbook_alert/fetch",
timeout=120,
timeout=TIMEOUT_120,
)

def search_playbook_alerts(self) -> Dict[str, Any]:
Expand Down Expand Up @@ -196,7 +202,7 @@ def fetch_incidents(self) -> None:
if _key == "demisto_last_run":
demisto.setLastRun(_val)
if _key == "incidents":
_transform_incidents_attachments(_val)
self._transform_incidents_attachments(_val)
demisto.incidents(_val)

def playbook_alert_search_command(self) -> Optional[List[CommandResults]]:
Expand All @@ -211,28 +217,33 @@ def playbook_alert_update_command(self) -> Optional[List[CommandResults]]:
response = self.client.update_playbook_alerts()
return self._process_result_actions(response=response)

@staticmethod
def _transform_incidents_attachments(incidents: list) -> None:
for incident in incidents:
attachments = []
incident_json = json.loads(incident.get("rawJSON", "{}"))
if incident_json.get("panel_evidence_summary", {}).get("screenshots"):
for screenshot_data in incident_json["panel_evidence_summary"][
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code will throw here an exception if incident_json["panel_evidence_summary"]["screenshots"] does not exist. Is that ok for you?

"screenshots"
]:
file_name = (
f"{screenshot_data.get('image_id', '').replace('img:', '')}.png"
)
file_data = screenshot_data.get("base64", "")
file = fileResult(file_name, base64.b64decode(file_data))
attachment = {
"description": screenshot_data.get("description"),
"name": file.get("File"),
"path": file.get("FileID"),
"showMediaFile": True,
}
attachments.append(attachment)
incident["attachment"] = attachments


def _transform_incidents_attachments(incidents: list) -> None:
for incident in incidents:
attachments = []
incident_json = json.loads(incident.get("rawJSON", "{}"))
if incident_json.get("panel_evidence_summary", {}).get("screenshots"):
for screenshot_data in incident_json["panel_evidence_summary"][
"screenshots"
]:
file_name = (
f'{screenshot_data.get("image_id", "").replace("img:", "")}.png'
)
file_data = screenshot_data.get("base64", "")
file = fileResult(file_name, base64.b64decode(file_data))
attachment = {
"description": screenshot_data.get("description"),
"name": file.get("File"),
"path": file.get("FileID"),
"showMediaFile": True,
}
attachments.append(attachment)
incident["attachment"] = attachments
# === === === === === === === === === === === === === === ===
# === === === === === === === MAIN === === === === === === ==
# === === === === === === === === === === === === === === ===


def get_client() -> Client:
Expand All @@ -248,7 +259,6 @@ def get_client() -> Client:
if not api_token:
return_error(message="Please provide a valid API token")

# If user has not set password properties we will get empty string but client require empty list
headers = {
"X-RFToken": api_token,
"X-RF-User-Agent": (
Expand Down Expand Up @@ -276,9 +286,9 @@ def main() -> None:

if command == "test-module":
# This is the call made when pressing the integration Test button.
# Returning 'ok' indicates that the integration works like it suppose to and
# Returning "ok" indicates that the integration works like it suppose to and
# connection to the service is successful.
# Returning 'ok' will make the test result be green.
# Returning "ok" will make the test result be green.
# Any other response will make the test result be red.

try:
Expand Down Expand Up @@ -313,18 +323,22 @@ def main() -> None:
elif command == "fetch-incidents":
actions.fetch_incidents()

elif command == "recordedfuture-identity-playbook-alerts-search":
return_results(actions.playbook_alert_search_command())

elif command == "recordedfuture-identity-playbook-alerts-details":
return_results(actions.playbook_alert_details_command())

elif command == "recordedfuture-identity-playbook-alerts-update":
return_results(actions.playbook_alert_update_command())

elif command == "recordedfuture-identity-playbook-alerts-search":
return_results(actions.playbook_alert_search_command())
else:
return_error(message=f"Unknown command: {command}")

except Exception as e:
return_error(
message=f"Failed to execute {demisto.command()} command. Error: {str(e)}"
message=f"Failed to execute {demisto.command()} command. Error: {str(e)}",
error=e,
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ script:
script: '-'
type: python
subtype: python3
dockerimage: demisto/python3:3.10.14.99474
dockerimage: demisto/python3:3.11.10.111039
commands:
- name: recordedfuture-identity-search
description: Search for identities in Recorded Future Identity Dataset.
Expand Down Expand Up @@ -758,6 +758,13 @@ script:
- account_disabled_or_terminated
- account_remediated
- other
- name: reopen
description: 'Re-open on Significant Changes? The alert can remain resolved, or automatically re-open in significant new assessments. Default behaviour: reopen on significant updates.'
required: false
auto: PREDEFINED
predefined:
- never
- significant_updates
outputs:
- contextPath: IdentityRecordedFuture.PlaybookAlerts.playbook_alert_id
description: Unique id of the playbook alert in Recorded Future.
Expand Down
Loading
Loading