Skip to content

Commit

Permalink
DeleteReportedEmail (script) - Improve Error Handling (#26363)
Browse files Browse the repository at this point in the history
* Raise an error if `reportedemailmessageid` is missing

* Raise an error if `reportedemailto` is missing

* Bump version

* Add exception error messages to assertion

* Bump pack from version Phishing to 3.5.17.

* Improve docs and errors

* Update Packs/Phishing/Scripts/DeleteReportedEmail/README.md

Co-authored-by: Ido van Dijk <43602124+idovandijk@users.noreply.github.com>

* Bump Docker version

* Fix unit-tests

* Apply suggestions from code review

Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com>

---------

Co-authored-by: Content Bot <bot@demisto.com>
Co-authored-by: Ido van Dijk <43602124+idovandijk@users.noreply.github.com>
Co-authored-by: ShirleyDenkberg <62508050+ShirleyDenkberg@users.noreply.github.com>
  • Loading branch information
4 people committed May 18, 2023
1 parent 0a6ff0c commit a098619
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 18 deletions.
9 changes: 6 additions & 3 deletions Packs/Phishing/Playbooks/Phishing_-_Generic_v3_6_5_README.md
@@ -1,8 +1,11 @@
This playbook investigates and remediates a potential phishing incident. It engages with the user who triggered the incident while investigating the incident itself.
A playbook for investigating and remediating potential phishing incidents.
The playbook engages with the user who triggered the incident while investigating the incident itself.

Note:
## Notes
- For the playbook to run properly, emails forwarded to the listener mailbox must be forwarded as an attachment \(with an `EML` file\).
- The playbook may not work properly when used as a sub-playbook inside another playbook.
- Do not re-run this playbook inside a phishing incident, as it can produce an unexpected result. Create a new incident instead.
- Final remediation tasks are manual by default. can be managed by "SearchAndDelete" and "BlockIndicators" inputs.
- Do not rerun this playbook inside a phishing incident since it can produce an unexpected result. Create a new incident instead if needed.

## Dependencies

Expand Down
7 changes: 7 additions & 0 deletions Packs/Phishing/ReleaseNotes/3_5_17.md
@@ -0,0 +1,7 @@

#### Scripts

##### DeleteReportedEmail

- Fixed an issue where if context data about the original email is missing, the script would fail with a vague error instead of a proper error message.
- Updated the Docker image to: *demisto/python3:3.10.11.58677*.
32 changes: 23 additions & 9 deletions Packs/Phishing/Scripts/DeleteReportedEmail/DeleteReportedEmail.py
Expand Up @@ -5,16 +5,15 @@
import time
from urllib.parse import quote, unquote

seconds = time.time()

DOCS_TROUBLESHOOTING_URL = 'https://xsoar.pan.dev/docs/reference/scripts/delete-reported-email#troubleshooting'
EMAIL_INTEGRATIONS = ['Gmail', 'EWSO365', 'EWS v2', 'Agari Phishing Defense', 'MicrosoftGraphMail',
'SecurityAndCompliance', 'SecurityAndComplianceV2']
seconds = time.time()


class MissingEmailException(Exception):
def __init__(self):
super().__init__('Email was not found in the mailbox. It is possible that the email was already '
'deleted manually.')
super().__init__('Email not found in mailbox. It may have been manually deleted.')


class DeletionFailed(Exception):
Expand Down Expand Up @@ -274,23 +273,38 @@ def delete_email(search_args: dict, search_function: str,
def get_search_args(args: dict):
"""
Get the parsed arguments needed for the search operation
Args:
args: this script's arguments.
Returns: parsed arguments needed for the search operation
"""
incident_info = demisto.incident()
custom_fields = incident_info.get('CustomFields', {})
message_id = custom_fields.get('reportedemailmessageid')
user_id = custom_fields.get('reportedemailto')
email_subject = custom_fields.get('reportedemailsubject')
from_user_id = custom_fields.get('reportedemailfrom')
email_origin = custom_fields.get('reportedemailorigin')
delete_type = args.get('delete_type', custom_fields.get('emaildeletetype', 'soft'))
delete_from_brand = delete_from_brand_handler(incident_info, args)

missing_field_error_message = "'{field_name}' field could not be found.\n" \
f"See {DOCS_TROUBLESHOOTING_URL} for possible solutions."

if not email_origin or email_origin.lower() == 'none':
raise ValueError(missing_field_error_message.format(field_name='Reported Email Origin'))

if not message_id:
raise ValueError(missing_field_error_message.format(field_name='Reported Email Message ID'))

if not user_id:
raise ValueError(missing_field_error_message.format(field_name='Reported Email To'))

search_args = {
'delete-type': delete_type,
'using-brand': delete_from_brand,
'email_subject': custom_fields.get('reportedemailsubject'),
'email_subject': email_subject,
'message-id': message_id,
}
additional_args = {
Expand All @@ -299,8 +313,8 @@ def get_search_args(args: dict):
'EWS v2': {'target-mailbox': user_id},
'MicrosoftGraphMail': {'user_id': user_id, 'odata': f'"$filter=internetMessageId eq '
f'\'{quote(unquote(message_id))}\'"'},
'SecurityAndCompliance': {'to_user_id': user_id, 'from_user_id': custom_fields.get('reportedemailfrom')},
'SecurityAndComplianceV2': {'to_user_id': user_id, 'from_user_id': custom_fields.get('reportedemailfrom')}
'SecurityAndCompliance': {'to_user_id': user_id, 'from_user_id': from_user_id},
'SecurityAndComplianceV2': {'to_user_id': user_id, 'from_user_id': from_user_id}
}

search_args.update(additional_args.get(delete_from_brand, {}))
Expand Down Expand Up @@ -339,8 +353,8 @@ def main():
search_args = get_search_args(args)
result, deletion_failure_reason, scheduled_command = '', '', None
delete_from_brand = search_args['using-brand']
try:

try:
if delete_from_brand in ['SecurityAndCompliance', 'SecurityAndComplianceV2']:
security_and_compliance_args = {k.replace('-', '_'): v for k, v in search_args.items()}
result, scheduled_command = security_and_compliance_delete_mail(args, **security_and_compliance_args)
Expand Down
Expand Up @@ -67,7 +67,7 @@ tags:
timeout: '0'
type: python
subtype: python3
dockerimage: demisto/python3:3.10.11.54132
dockerimage: demisto/python3:3.10.11.58677
fromversion: '6.1.0'
tests:
- No tests (auto formatted)
@@ -1,3 +1,5 @@
from copy import deepcopy

import CommonServerPython
from DeleteReportedEmail import *
import DeleteReportedEmail
Expand Down Expand Up @@ -50,7 +52,7 @@
'user-id': 'user_id'
}

MISSING_EMAIL_ERROR_MSG = 'Email was not found in the mailbox. It is possible that the email was already deleted manually.'
MISSING_EMAIL_ERROR_MSG = 'Email not found in mailbox. It may have been manually deleted.'

WAS_EMAIL_DELETED_EXPECTED_RESULTS = [([], ('Skipped', MISSING_EMAIL_ERROR_MSG)),
([{'message_id': 'message-id', 'result': 'Success'}], ('Success', ''))]
Expand All @@ -67,7 +69,6 @@ def test_get_deletion_args(integration_name):
Then:
return the suitable deletion args
"""

with open(os.path.join(TEST_DATA, f'{integration_name}{SEARCH_RESPONSE_SUFFIX}'), 'r') as file:
search_results = json.load(file)
assert EXPECTED_DELETION_ARGS_RESULTS[integration_name] == ARGS_FUNC[integration_name](search_results, SEARCH_ARGS)
Expand Down Expand Up @@ -243,10 +244,10 @@ def test_search_args(mocker, brand):
Return the suitable search args
"""
import DeleteReportedEmail
INCIDENT_INFO = {
'CustomFields':
{
'reportedemailorigin': 'Attached',
'reportedemailmessageid': 'reportedemailmessageid',
'reportedemailto': 'reportedemailto',
'emaildeletetype': 'emaildeletetype',
Expand All @@ -261,6 +262,30 @@ def test_search_args(mocker, brand):
current_search_args.update(ADDED_SEARCH_ARGS.get(brand, {}))
assert get_search_args({}) == current_search_args

# Test 'email_origin' is 'none' exception
incident_info_copy = deepcopy(INCIDENT_INFO)
mocker.patch.object(demisto, 'incident', return_value=incident_info_copy)
incident_info_copy['CustomFields']["reportedemailorigin"] = "None"
with pytest.raises(ValueError) as e:
get_search_args({})
assert "'Reported Email Origin' field could not be found" in str(e.value)

# Test missing message id exception
incident_info_copy = deepcopy(INCIDENT_INFO)
mocker.patch.object(demisto, 'incident', return_value=incident_info_copy)
incident_info_copy['CustomFields'].pop("reportedemailmessageid")
with pytest.raises(ValueError) as e:
get_search_args({})
assert "'Reported Email Message ID' field could not be found" in str(e.value)

# Test missing user id exception
incident_info_copy = deepcopy(INCIDENT_INFO)
mocker.patch.object(demisto, 'incident', return_value=incident_info_copy)
incident_info_copy['CustomFields'].pop("reportedemailto")
with pytest.raises(ValueError) as e:
get_search_args({})
assert "'Reported Email To' field could not be found" in str(e.value)


def test_schedule_next_command(mocker):
"""
Expand Down
14 changes: 13 additions & 1 deletion Packs/Phishing/Scripts/DeleteReportedEmail/README.md
@@ -1,4 +1,7 @@
Use this script to delete a reported phishing email from the mailbox it was reported to.
A script for deleting reported phishing emails from the mailbox in which they were reported.

## Note
The script was specifically developed for use by the `Delete Reported Email` layout on the `Phishing - Generic v3` playbook, and should not be used elsewhere.

## Script Data
---
Expand Down Expand Up @@ -31,3 +34,12 @@ Use this script to delete a reported phishing email from the mailbox it was repo
| DeleteReportedEmail.using_brand | The email service that was used to delete the email. | String |
| DeleteReportedEmail.email_subject | The subject of the deleted email. | String |
| DeleteReportedEmail.message_id | The message ID of the deleted email. | String |

## Troubleshooting
---
* If the `Reported Email Origin` field is missing or has a value of `None`, the script will not be able to locate the email and fail.
This can happen if the email forwarded to the listener mailbox was not forwarded as an attachment (with an `EML` file) as it should.
* If either the `Reported Email Message ID` or `Reported Email To` fields are missing, the cause is likely to be one of the following:
* An `EML` file was not attached to the email.
* The playbook is being used as a sub-playbook, causing the `EML` file to exist only in the parent playbook.
* The `Process Email - Generic v2` sub-playbook failed, or the `ParseEmailFilesV2` step within it specifically failed.
2 changes: 1 addition & 1 deletion Packs/Phishing/pack_metadata.json
Expand Up @@ -2,7 +2,7 @@
"name": "Phishing",
"description": "Phishing emails still hooking your end users? This Content Pack can drastically reduce the time your security team spends on phishing alerts.",
"support": "xsoar",
"currentVersion": "3.5.16",
"currentVersion": "3.5.17",
"serverMinVersion": "6.0.0",
"videos": [
"https://www.youtube.com/watch?v=SY-3L348PoY"
Expand Down

0 comments on commit a098619

Please sign in to comment.