From e4a64a11bd33b8fe4edd7bf2d1c1a6273eecd7de Mon Sep 17 00:00:00 2001 From: Jokob-sk Date: Sun, 8 Oct 2023 16:54:13 +1100 Subject: [PATCH] =?UTF-8?q?Notification=20rework=20-=20SMTP=20v0.1=20-=20W?= =?UTF-8?q?IP=F0=9F=91=B7=E2=80=8D=E2=99=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- front/plugins/_publisher_apprise/README.md | 8 + front/plugins/_publisher_apprise/apprise.py | 9 +- front/plugins/_publisher_email/README.md | 8 + front/plugins/_publisher_email/config.json | 424 ++++++++++++++++++++ front/plugins/_publisher_email/email.py | 160 ++++++++ front/plugins/internet_speedtest/script.py | 1 - 6 files changed, 605 insertions(+), 5 deletions(-) create mode 100755 front/plugins/_publisher_apprise/README.md create mode 100755 front/plugins/_publisher_email/README.md create mode 100755 front/plugins/_publisher_email/config.json create mode 100755 front/plugins/_publisher_email/email.py diff --git a/front/plugins/_publisher_apprise/README.md b/front/plugins/_publisher_apprise/README.md new file mode 100755 index 00000000..e32cc3f2 --- /dev/null +++ b/front/plugins/_publisher_apprise/README.md @@ -0,0 +1,8 @@ +## Overview + +[Apprise](front/plugins/arp_scan/README.md) is a notification gateway/publisher that allows you to push notifications to 80+ different services. + +### Usage + +- Go to settings and fill in relevant details. + diff --git a/front/plugins/_publisher_apprise/apprise.py b/front/plugins/_publisher_apprise/apprise.py index 27b23fc8..08f7ebd9 100755 --- a/front/plugins/_publisher_apprise/apprise.py +++ b/front/plugins/_publisher_apprise/apprise.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# Based on the work of https://github.com/leiweibau/Pi.Alert import json import subprocess @@ -23,13 +22,15 @@ from database import DB CUR_PATH = str(pathlib.Path(__file__).parent.resolve()) RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log') +pluginName = 'APPRISE' + def main(): - mylog('verbose', ['[APPRISE](publisher) In script']) + mylog('verbose', [f'[{pluginName}](publisher) In script']) # Check if basic config settings supplied if check_config() == False: - mylog('none', ['[Check Config] Error: Apprise service not set up correctly. Check your pialert.conf APPRISE_* variables.']) + mylog('none', [f'[{pluginName}] Error: Publisher notification gateway not set up correctly. Check your pialert.conf {pluginName}_* variables.']) return # Create a database connection @@ -53,7 +54,7 @@ def main(): # Log result plugin_objects.add_object( - primaryId = 'APPRISE', + primaryId = pluginName, secondaryId = timeNowTZ(), watched1 = notification["GUID"], watched2 = result, diff --git a/front/plugins/_publisher_email/README.md b/front/plugins/_publisher_email/README.md new file mode 100755 index 00000000..e32cc3f2 --- /dev/null +++ b/front/plugins/_publisher_email/README.md @@ -0,0 +1,8 @@ +## Overview + +[Apprise](front/plugins/arp_scan/README.md) is a notification gateway/publisher that allows you to push notifications to 80+ different services. + +### Usage + +- Go to settings and fill in relevant details. + diff --git a/front/plugins/_publisher_email/config.json b/front/plugins/_publisher_email/config.json new file mode 100755 index 00000000..d073f963 --- /dev/null +++ b/front/plugins/_publisher_email/config.json @@ -0,0 +1,424 @@ +{ + "code_name": "_publisher_apprise", + "unique_prefix": "SMTP", + "enabled": true, + "data_source": "script", + "show_ui": true, + "localized": ["display_name", "description", "icon"], + "display_name" : [ + { + "language_code": "en_us", + "string" : "Apprise publisher" + }, + { + "language_code": "es_es", + "string" : "Habilitar Apprise" + } + ], + "icon":[{ + "language_code": "en_us", + "string" : "" + }], + "description": [ + { + "language_code": "en_us", + "string" : "A plugin to publish a notification via the Apprise gateway." + } + ], + "params" : [], + "database_column_definitions": + [ + { + "column": "Index", + "css_classes": "col-sm-2", + "show": false, + "type": "label", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "N/A" + }, + { + "language_code": "es_es", + "string" : "N/A" + }] + }, + { + "column": "Plugin", + "css_classes": "col-sm-2", + "show": false, + "type": "label", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "N/A" + }, + { + "language_code": "es_es", + "string" : "N/A" + }] + }, + { + "column": "Object_PrimaryID", + "css_classes": "col-sm-2", + "show": false, + "type": "url", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "N/A" + }] + }, + { + "column": "Object_SecondaryID", + "css_classes": "col-sm-2", + "show": false, + "type": "label", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "N/A" + }, + { + "language_code": "es_es", + "string" : "N/A" + }] + }, + { + "column": "DateTimeCreated", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "Sent when" + }] + }, + { + "column": "DateTimeChanged", + "css_classes": "col-sm-2", + "show": false, + "type": "label", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "Changed" + }, + { + "language_code": "es_es", + "string" : "Cambiado" + }] + }, + { + "column": "Watched_Value1", + "css_classes": "col-sm-2", + "show": true, + "type": "label", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "Notification GUID" + }] + }, + { + "column": "Watched_Value2", + "css_classes": "col-sm-8", + "show": true, + "type": "textarea_readonly", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "Result" + }] + }, + { + "column": "Watched_Value3", + "css_classes": "col-sm-2", + "show": false, + "type": "label", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "N/A" + }, + { + "language_code": "es_es", + "string" : "N/A" + }] + }, + { + "column": "Watched_Value4", + "css_classes": "col-sm-2", + "show": false, + "type": "label", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "N/A" + }, + { + "language_code": "es_es", + "string" : "N/A" + }] + }, + { + "column": "UserData", + "css_classes": "col-sm-2", + "show": false, + "type": "textbox_save", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "Comments" + }, + { + "language_code": "es_es", + "string" : "Comentarios" + }] + }, + { + "column": "Status", + "css_classes": "col-sm-1", + "show": false, + "type": "replace", + "default_value":"", + "options": [ + { + "equals": "watched-not-changed", + "replacement": "
" + }, + { + "equals": "watched-changed", + "replacement": "
" + }, + { + "equals": "new", + "replacement": "
" + }, + { + "equals": "missing-in-last-scan", + "replacement": "
" + } + ], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "Status" + }, + { + "language_code": "es_es", + "string" : "Estado" + }] + }, + { + "column": "Extra", + "css_classes": "col-sm-3", + "show": false, + "type": "label", + "default_value":"", + "options": [], + "localized": ["name"], + "name":[{ + "language_code": "en_us", + "string" : "Extra" + }, + { + "language_code": "es_es", + "string" : "Extra" + }] + } + ], + "settings":[ + { + "function": "RUN", + "events": ["test"], + "type": "text.select", + "default_value":"disabled", + "options": ["disabled", "on_notification" ], + "localized": ["name", "description"], + "name" :[{ + "language_code": "en_us", + "string" : "When to run" + }, + { + "language_code": "es_es", + "string" : "Cuando ejecuta" + }], + "description": [ + { + "language_code": "en_us", + "string" : "Enable sending notifications via Apprise." + }, + { + "language_code": "es_es", + "string" : "Habilitar el envío de notificaciones a través de Apprise." + } + ] + }, + { + "function": "CMD", + "type": "readonly", + "default_value":"python3 /home/pi/pialert/front/plugins/_publisher_email/email.py", + "options": [], + "localized": ["name", "description"], + "name" : [{ + "language_code": "en_us", + "string" : "Command" + }, + { + "language_code": "es_es", + "string" : "Comando" + }], + "description": [{ + "language_code": "en_us", + "string" : "Command to run" + }, + { + "language_code": "es_es", + "string" : "Comando a ejecutar" + }] + }, + { + "function": "RUN_TIMEOUT", + "type": "integer", + "default_value": 10, + "options": [], + "localized": ["name", "description"], + "name" : [{ + "language_code": "en_us", + "string" : "Run timeout" + }, + { + "language_code": "es_es", + "string" : "Tiempo de espera de ejecución" + }, + { + "language_code": "de_de", + "string" : "Wartezeit" + }], + "description": [{ + "language_code": "en_us", + "string" : "Maximum time in seconds to wait for the script to finish. If this time is exceeded the script is aborted." + }, + { + "language_code": "es_es", + "string" : "Tiempo máximo en segundos para esperar a que finalice el script. Si se supera este tiempo, el script se cancela." + }] + }, + { + "function": "HOST", + "type": "text", + "default_value": "", + "options": [], + "localized": ["name", "description"], + "name" : [{ + "language_code": "en_us", + "string" : "Apprise host URL" + }, + { + "language_code": "es_es", + "string" : "URL del host de Apprise" + }], + "description": [{ + "language_code": "en_us", + "string" : "Apprise host URL starting with http:// or https://. (do not forget to include /notify at the end)" + }, + { + "language_code": "es_es", + "string" : "URL del host de Apprise que comienza con http:// o https://. (no olvide incluir /notify al final)" + }] + }, + { + "function": "URL", + "type": "text", + "default_value": "", + "options": [], + "localized": ["name", "description"], + "name" : [{ + "language_code": "en_us", + "string" : "Apprise notification URL" + }, + { + "language_code": "es_es", + "string" : "URL de notificación de Apprise" + }], + "description": [{ + "language_code": "en_us", + "string" : "Apprise notification target URL. For example for Telegram it would be tgram://{bot_token}/{chat_id}." + }, + { + "language_code": "es_es", + "string" : "Informar de la URL de destino de la notificación. Por ejemplo, para Telegram sería tgram://{bot_token}/{chat_id}." + }] + }, + { + "function": "PAYLOAD", + "type": "text.select", + "default_value": "html", + "options": ["html", "text"], + "localized": ["name", "description"], + "name" : [{ + "language_code": "en_us", + "string" : "Payload type" + }, + { + "language_code": "es_es", + "string" : "Tipo de carga" + }], + "description": [{ + "language_code": "en_us", + "string" : "Select the payoad type sent to Apprise. For example html works well with emails, text with chat apps, such as Telegram." + }, + { + "language_code": "es_es", + "string" : "Seleccione el tipo de carga útil enviada a Apprise. Por ejemplo, html funciona bien con correos electrónicos, text con aplicaciones de chat, como Telegram." + }] + }, + { + "function": "SIZE", + "type": "integer", + "default_value": 1024, + "options": [], + "localized": ["name", "description"], + "name" : [{ + "language_code": "en_us", + "string" : "Max payload size" + }, + { + "language_code": "es_es", + "string" : "Tamaño máximo de carga útil" + }], + "description": [{ + "language_code": "en_us", + "string" : "The maximum size of the apprise payload as number of characters in the passed string. If above limit, it will be truncated and a (text was truncated) message is appended." + }, + { + "language_code": "es_es", + "string" : "El tamaño máximo de la carga útil de información como número de caracteres en la cadena pasada. Si supera el límite, se truncará y se agregará un mensaje (text was truncated)." + }] + } + ] +} diff --git a/front/plugins/_publisher_email/email.py b/front/plugins/_publisher_email/email.py new file mode 100755 index 00000000..25f1d638 --- /dev/null +++ b/front/plugins/_publisher_email/email.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +import json +import subprocess +import argparse +import os +import pathlib +import sys +from datetime import datetime +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +import smtplib +import socket + +# Replace these paths with the actual paths to your Pi.Alert directories +sys.path.extend(["/home/pi/pialert/front/plugins", "/home/pi/pialert/pialert"]) + +# PiAlert modules +import conf +from plugin_helper import Plugin_Objects +from logger import mylog, append_line_to_file, print_log +from helper import timeNowTZ, noti_obj, get_setting_value, hide_email +from notification import Notification_obj +from database import DB + + +CUR_PATH = str(pathlib.Path(__file__).parent.resolve()) +RESULT_FILE = os.path.join(CUR_PATH, 'last_result.log') + +pluginName = 'SMTP' + +def main(): + + mylog('verbose', [f'[{pluginName}](publisher) In script']) + + # Check if basic config settings supplied + if check_config() == False: + mylog('none', [f'[{pluginName}] Error: Publisher notification gateway not set up correctly. Check your pialert.conf {pluginName}_* variables.']) + return + + # Create a database connection + db = DB() # instance of class DB + db.open() + + # Initialize the Plugin obj output file + plugin_objects = Plugin_Objects(RESULT_FILE) + + # Create a Notification_obj instance + notifications = Notification_obj(db) + + # Retrieve new notifications + new_notifications = notifications.getNew() + + # Process the new notifications + for notification in new_notifications: + + # Send notification + result = send(notification["HTML"], notification["Text"]) + + # Log result + plugin_objects.add_object( + primaryId = pluginName, + secondaryId = timeNowTZ(), + watched1 = notification["GUID"], + watched2 = result, + watched3 = 'null', + watched4 = 'null', + extra = 'null', + foreignKey = 'null' + ) + + plugin_objects.write_result_file() + +#------------------------------------------------------------------------------- +def check_config (): + if get_setting_value('SMTP_SERVER') == '' or get_setting_value('REPORT_FROM') == '' or get_setting_value('REPORT_TO') == '': + mylog('none', ['[Email Check Config] Error: Email service not set up correctly. Check your pialert.conf SMTP_*, REPORT_FROM and REPORT_TO variables.']) + return False + else: + return True + +#------------------------------------------------------------------------------- +def send(pHTML, pText): + + mylog('debug', [f'[{pluginName}] REPORT_TO: {hide_email(str(get_setting_value('REPORT_TO')))} SMTP_USER: {hide_email(str(get_setting_value('SMTP_USER')))}']) + + # Compose email + msg = MIMEMultipart('alternative') + msg['Subject'] = 'Pi.Alert Report' + msg['From'] = get_setting_value('REPORT_FROM') + msg['To'] = get_setting_value('REPORT_TO') + msg.attach (MIMEText (pText, 'plain')) + msg.attach (MIMEText (pHTML, 'html')) + + failedAt = '' + + failedAt = print_log ('SMTP try') + + try: + # Send mail + failedAt = print_log('Trying to open connection to ' + str(get_setting_value('SMTP_SERVER')) + ':' + str(get_setting_value('SMTP_PORT'))) + + # Set a timeout for the SMTP connection (in seconds) + smtp_timeout = 30 + + if get_setting_value('SMTP_FORCE_SSL'): + failedAt = print_log('SMTP_FORCE_SSL == True so using .SMTP_SSL()') + if get_setting_value('SMTP_PORT') == 0: + failedAt = print_log('SMTP_PORT == 0 so sending .SMTP_SSL(SMTP_SERVER)') + smtp_connection = smtplib.SMTP_SSL(get_setting_value('SMTP_SERVER')) + else: + failedAt = print_log('SMTP_PORT == 0 so sending .SMTP_SSL(SMTP_SERVER, SMTP_PORT)') + smtp_connection = smtplib.SMTP_SSL(get_setting_value('SMTP_SERVER'), get_setting_value('SMTP_PORT'), timeout=smtp_timeout) + + else: + failedAt = print_log('SMTP_FORCE_SSL == False so using .SMTP()') + if get_setting_value('SMTP_PORT') == 0: + failedAt = print_log('SMTP_PORT == 0 so sending .SMTP(SMTP_SERVER)') + smtp_connection = smtplib.SMTP (get_setting_value('SMTP_SERVER')) + else: + failedAt = print_log('SMTP_PORT == 0 so sending .SMTP(SMTP_SERVER, SMTP_PORT)') + smtp_connection = smtplib.SMTP (get_setting_value('SMTP_SERVER'), get_setting_value('SMTP_PORT')) + + failedAt = print_log('Setting SMTP debug level') + + # Log level set to debug of the communication between SMTP server and client + if get_setting_value('LOG_LEVEL') == 'debug': + smtp_connection.set_debuglevel(1) + + failedAt = print_log( 'Sending .ehlo()') + smtp_connection.ehlo() + + if not get_setting_value('SMTP_SKIP_TLS'): + failedAt = print_log('SMTP_SKIP_TLS == False so sending .starttls()') + smtp_connection.starttls() + failedAt = print_log('SMTP_SKIP_TLS == False so sending .ehlo()') + smtp_connection.ehlo() + if not get_setting_value('SMTP_SKIP_LOGIN'): + failedAt = print_log('SMTP_SKIP_LOGIN') == False so sending .login()') + smtp_connection.login (get_setting_value('SMTP_USER'), get_setting_value('SMTP_PASS')) + + failedAt = print_log('Sending .sendmail()') + smtp_connection.sendmail (get_setting_value('REPORT_FROM'), get_setting_value('REPORT_TO'), msg.as_string()) + smtp_connection.quit() + except smtplib.SMTPAuthenticationError as e: + mylog('none', [' ERROR: Failed at - ', failedAt]) + mylog('none', [' ERROR: Couldn\'t connect to the SMTP server (SMTPAuthenticationError), skipping Email (enable LOG_LEVEL=debug for more logging)']) + mylog('none', [' ERROR: ', str(e)]) + except smtplib.SMTPServerDisconnected as e: + mylog('none', [' ERROR: Failed at - ', failedAt]) + mylog('none', [' ERROR: Couldn\'t connect to the SMTP server (SMTPServerDisconnected), skipping Email (enable LOG_LEVEL=debug for more logging)']) + mylog('none', [' ERROR: ', str(e)]) + except socket.gaierror as e: + mylog('none', [' ERROR: Failed at - ', failedAt]) + mylog('none', [' ERROR: Could not resolve hostname (socket.gaierror), skipping Email (enable LOG_LEVEL=debug for more logging)']) + mylog('none', [' ERROR: ', str(e)]) + + mylog('debug', [f'[{pluginName}] Last executed - {str(failedAt)}']) + +if __name__ == '__main__': + sys.exit(main()) diff --git a/front/plugins/internet_speedtest/script.py b/front/plugins/internet_speedtest/script.py index 10b65cc0..8acadaba 100755 --- a/front/plugins/internet_speedtest/script.py +++ b/front/plugins/internet_speedtest/script.py @@ -1,5 +1,4 @@ #!/usr/bin/env python -# Based on the work of https://github.com/leiweibau/Pi.Alert import argparse import os