From d1b1f078aa702f48e82c2aac958dd658ea1c4fe0 Mon Sep 17 00:00:00 2001 From: Jokob-sk Date: Sun, 2 Jul 2023 08:45:57 +1000 Subject: [PATCH] webhook #271 work --- front/php/templates/language/en_us.php | 2 +- front/php/templates/language/es_es.php | 2 +- pialert/helper.py | 21 +++--- pialert/logger.py | 3 + pialert/publishers/webhook.py | 98 ++++++++++++++------------ 5 files changed, 67 insertions(+), 59 deletions(-) diff --git a/front/php/templates/language/en_us.php b/front/php/templates/language/en_us.php index c22d4208..fd930796 100755 --- a/front/php/templates/language/en_us.php +++ b/front/php/templates/language/en_us.php @@ -576,7 +576,7 @@ The arp-scan time itself depends on the number of IP addresses to check so set t 'WEBHOOK_URL_name' => 'Target URL', 'WEBHOOK_URL_description' => 'Target URL starting with http:// or https://.', 'WEBHOOK_PAYLOAD_name' => 'Payload type', -'WEBHOOK_PAYLOAD_description' => 'The Webhook payload data format for the body > attachments > text attribute in the payload json. See an example of the payload here. (e.g.: for discord use html)', +'WEBHOOK_PAYLOAD_description' => 'The Webhook payload data format for the body > attachments > text attribute in the payload json. See an example of the payload here. (e.g.: for discord use text)', 'WEBHOOK_REQUEST_METHOD_name' => 'Request method', 'WEBHOOK_REQUEST_METHOD_description' => 'The HTTP request method to be used for the webhook call.', diff --git a/front/php/templates/language/es_es.php b/front/php/templates/language/es_es.php index de2cd40b..478b1d3c 100755 --- a/front/php/templates/language/es_es.php +++ b/front/php/templates/language/es_es.php @@ -571,7 +571,7 @@ $lang['es_es'] = array( 'WEBHOOK_URL_name' => 'URL de destino', 'WEBHOOK_URL_description' => 'URL de destino comienza con http:// o https://.', 'WEBHOOK_PAYLOAD_name' => 'Tipo de carga', -'WEBHOOK_PAYLOAD_description' => 'El formato de datos de carga de Webhook para el atributo body > attachments > text en el json de carga. Vea un ejemplo de la carga aquí. (por ejemplo: para discord use html)', +'WEBHOOK_PAYLOAD_description' => 'El formato de datos de carga de Webhook para el atributo body > attachments > text en el json de carga. Vea un ejemplo de la carga aquí. (por ejemplo: para discord use text)', 'WEBHOOK_REQUEST_METHOD_name' => 'Método de solicitud', 'WEBHOOK_REQUEST_METHOD_description' => 'El método de solicitud HTTP que se utilizará para la llamada de webhook.', 'Webhooks_settings_group' => ' Webhooks', diff --git a/pialert/helper.py b/pialert/helper.py index 05d710c0..a25796a9 100755 --- a/pialert/helper.py +++ b/pialert/helper.py @@ -312,17 +312,18 @@ def write_file(pPath, pText): for item in pText: write_file(pPath, item) - # Write the text using the correct Python version - if sys.version_info < (3, 0): - file = io.open(pPath, mode='w', encoding='utf-8') - file.write(pText.decode('unicode_escape')) - file.close() else: - file = open(pPath, 'w', encoding='utf-8') - if pText is None: - pText = "" - file.write(pText) - file.close() + # Write the text using the correct Python version + if sys.version_info < (3, 0): + file = io.open(pPath, mode='w', encoding='utf-8') + file.write(pText.decode('unicode_escape')) + file.close() + else: + file = open(pPath, 'w', encoding='utf-8') + if pText is None: + pText = "" + file.write(pText) + file.close() #------------------------------------------------------------------------------- class noti_struc: diff --git a/pialert/logger.py b/pialert/logger.py index 3ae32dc2..a2d61bb5 100755 --- a/pialert/logger.py +++ b/pialert/logger.py @@ -71,6 +71,9 @@ def print_log (pText): #------------------------------------------------------------------------------- +# textchars = bytearray({7,8,9,10,12,13,27} | set(range(0x20, 0x100)) - {0x7f}) +# is_binary_string = lambda bytes: bool(bytes.translate(None, textchars)) + def append_file_binary (pPath, input): file = open (pPath, 'ab') file.write (input) diff --git a/pialert/publishers/webhook.py b/pialert/publishers/webhook.py index 56f80283..653d9b6d 100755 --- a/pialert/publishers/webhook.py +++ b/pialert/publishers/webhook.py @@ -18,13 +18,47 @@ def check_config(): def send (msg: noti_struc): + # limit = 1024 * 1024 # 1MB limit (1024 bytes * 1024 bytes = 1MB) + limit = 1024 * 1 # 1MB limit (1024 bytes * 1024 bytes = 1MB) + # use data type based on specified payload type if conf.WEBHOOK_PAYLOAD == 'json': - payloadData = msg.json - if conf.WEBHOOK_PAYLOAD == 'html': - payloadData = msg.html - if conf.WEBHOOK_PAYLOAD == 'text': - payloadData = to_text(msg.json) # TO DO can we just send msg.text? + # In this code, the truncate_json function is used to recursively traverse the JSON object + # and remove nodes that exceed the size limit. It checks the size of each node's JSON representation + # using json.dumps and includes only the nodes that are within the limit. + json_data = msg.json + json_str = json.dumps(json_data) + + if len(json_str) <= limit: + payloadData = json_data + else: + def truncate_json(obj): + if isinstance(obj, dict): + return { + key: truncate_json(value) + for key, value in obj.items() + if len(json.dumps(value)) <= limit + } + elif isinstance(obj, list): + return [ + truncate_json(item) + for item in obj + if len(json.dumps(item)) <= limit + ] + else: + return obj + + payloadData = truncate_json(json_data) + if conf.WEBHOOK_PAYLOAD == 'html': + if len(msg.html) > limit: + payloadData = msg.html[:limit] + "

(text was truncated)

" + else: + payloadData = msg.html + if conf.WEBHOOK_PAYLOAD == 'text': + if len(msg.text) > limit: + payloadData = msg.text[:limit] + " (text was truncated)" + else: + payloadData = msg.text # Define slack-compatible payload _json_payload = { "text": payloadData } if conf.WEBHOOK_PAYLOAD == 'text' else { @@ -41,6 +75,7 @@ def send (msg: noti_struc): write_file (logPath + '/webhook_payload.json', json.dumps(_json_payload)) # Using the Slack-Compatible Webhook endpoint for Discord so that the same payload can be used for both + # Consider: curl has the ability to load in data to POST from a file + piping if(conf.WEBHOOK_URL.startswith('https://discord.com/api/webhooks/') and not conf.WEBHOOK_URL.endswith("/slack")): _WEBHOOK_URL = f"{conf.WEBHOOK_URL}/slack" curlParams = ["curl","-i","-H", "Content-Type:application/json" ,"-d", json.dumps(_json_payload), _WEBHOOK_URL] @@ -48,51 +83,20 @@ def send (msg: noti_struc): _WEBHOOK_URL = conf.WEBHOOK_URL curlParams = ["curl","-i","-X", conf.WEBHOOK_REQUEST_METHOD ,"-H", "Content-Type:application/json" ,"-d", json.dumps(_json_payload), _WEBHOOK_URL] - # execute CURL call try: - # try runnning a subprocess + # Execute CURL call mylog('debug', ['[send_webhook] curlParams: ', curlParams]) - p = subprocess.Popen(curlParams, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + result = subprocess.run(curlParams, capture_output=True, text=True) - stdout, stderr = p.communicate() + stdout = result.stdout + stderr = result.stderr + + # Write stdout and stderr into .log files for debugging if needed + mylog('debug', ['[send_webhook] stdout: ', stdout]) + mylog('debug', ['[send_webhook] stderr: ', stderr]) + # logResult(stdout, stderr) # TO-DO should be changed to mylog - # write stdout and stderr into .log files for debugging if needed - logResult (stdout, stderr) # TO-DO should be changed to mylog except subprocess.CalledProcessError as e: - # An error occured, handle it - mylog('none', ['[send_webhook] Error', e.output]) + # An error occurred, handle it + mylog('none', ['[send_webhook] Error: ', e.output]) - - - - -#------------------------------------------------------------------------------- -def to_text(_json): - payloadData = "" - if len(_json['internet']) > 0 and 'internet' in conf.INCLUDED_SECTIONS: - payloadData += "INTERNET\n" - for event in _json['internet']: - payloadData += event[3] + ' on ' + event[2] + '. ' + event[4] + '. New address:' + event[1] + '\n' - - if len(_json['new_devices']) > 0 and 'new_devices' in conf.INCLUDED_SECTIONS: - payloadData += "NEW DEVICES:\n" - for event in _json['new_devices']: - if event[4] is None: - event[4] = event[11] - payloadData += event[1] + ' - ' + event[4] + '\n' - - if len(_json['down_devices']) > 0 and 'down_devices' in conf.INCLUDED_SECTIONS: - write_file (logPath + '/down_devices_example.log', _json['down_devices']) - payloadData += 'DOWN DEVICES:\n' - for event in _json['down_devices']: - if event[4] is None: - event[4] = event[11] - payloadData += event[1] + ' - ' + event[4] + '\n' - - if len(_json['events']) > 0 and 'events' in conf.INCLUDED_SECTIONS: - payloadData += "EVENTS:\n" - for event in _json['events']: - if event[8] != "Internet": - payloadData += event[8] + " on " + event[1] + " " + event[3] + " at " + event[2] + "\n" - - return payloadData \ No newline at end of file