#---------------------------------------------------------------------------------# # NetAlertX # # Open Source Network Guard / WIFI & LAN intrusion detector # # # # reporting.py - NetAlertX Back module. Template to email reporting in HTML format # #---------------------------------------------------------------------------------# # Puche 2021 pi.alert.application@gmail.com GNU GPLv3 # # jokob-sk 2022 jokob.sk@gmail.com GNU GPLv3 # # leiweibau 2022 https://github.com/leiweibau GNU GPLv3 # # cvc90 2023 https://github.com/cvc90 GNU GPLv3 # #---------------------------------------------------------------------------------# import datetime import json import conf from const import applicationPath, logPath, apiPath, confFileName from helper import timeNowTZ, get_file_content, write_file, get_timezone_offset, get_setting_value from logger import logResult, mylog, print_log #=============================================================================== # REPORTING #=============================================================================== #------------------------------------------------------------------------------- def get_notifications (db): sql = db.sql #TO-DO # Reporting section mylog('verbose', ['[Notification] Check if something to report']) # prepare variables for JSON construction json_new_devices = [] json_new_devices_meta = {} json_down_devices = [] json_down_devices_meta = {} json_down_reconnected = [] json_down_reconnected_meta = {} json_events = [] json_events_meta = {} json_plugins = [] json_plugins_meta = {} # Disable reporting on events for devices where reporting is disabled based on the MAC address sql.execute ("""UPDATE Events SET eve_PendingAlertEmail = 0 WHERE eve_PendingAlertEmail = 1 AND eve_EventType not in ('Device Down', 'Down Reconnected', 'New Device' ) AND eve_MAC IN ( SELECT devMac FROM Devices WHERE devAlertEvents = 0 )""") sql.execute ("""UPDATE Events SET eve_PendingAlertEmail = 0 WHERE eve_PendingAlertEmail = 1 AND eve_EventType in ('Device Down', 'Down Reconnected') AND eve_MAC IN ( SELECT devMac FROM Devices WHERE devAlertDown = 0 )""") sections = get_setting_value('NTFPRCS_INCLUDED_SECTIONS') mylog('verbose', ['[Notification] Included sections: ', sections ]) if 'new_devices' in sections: # Compose New Devices Section (no empty lines in SQL queries!) sqlQuery = f"""SELECT eve_MAC as MAC, eve_DateTime as Datetime, devLastIP as IP, eve_EventType as "Event Type", devName as "Device name", devComments as Comments FROM Events_Devices WHERE eve_PendingAlertEmail = 1 AND eve_EventType = 'New Device' {get_setting_value('NTFPRCS_new_dev_condition').replace('{s-quote}',"'")} ORDER BY eve_DateTime""" mylog('debug', ['[Notification] new_devices SQL query: ', sqlQuery ]) # Get the events as JSON json_obj = db.get_table_as_json(sqlQuery) json_new_devices_meta = { "title": "🆕 New devices", "columnNames": json_obj.columnNames } json_new_devices = json_obj.json["data"] if 'down_devices' in sections: # Compose Devices Down Section # - select only Down Alerts with pending email of devices that didn't reconnect within the specified time window sqlQuery = f""" SELECT devName, eve_MAC, devVendor, eve_IP, eve_DateTime, eve_EventType FROM Events_Devices AS down_events WHERE eve_PendingAlertEmail = 1 AND down_events.eve_EventType = 'Device Down' AND eve_DateTime < datetime('now', '-{get_setting_value('NTFPRCS_alert_down_time')} minutes', '{get_timezone_offset()}') AND NOT EXISTS ( SELECT 1 FROM Events AS connected_events WHERE connected_events.eve_MAC = down_events.eve_MAC AND connected_events.eve_EventType = 'Connected' AND connected_events.eve_DateTime > down_events.eve_DateTime ) ORDER BY down_events.eve_DateTime; """ # Get the events as JSON json_obj = db.get_table_as_json(sqlQuery) json_down_devices_meta = { "title": "🔴 Down devices", "columnNames": json_obj.columnNames } json_down_devices = json_obj.json["data"] mylog('debug', ['[Notification] json_down_devices: ', json.dumps(json_down_devices) ]) if 'down_reconnected' in sections: # Compose Reconnected Down Section # - select only Devices, that were previously down and now are Connected sqlQuery = f""" SELECT devName, eve_MAC, devVendor, eve_IP, eve_DateTime, eve_EventType FROM Events_Devices AS reconnected_devices WHERE reconnected_devices.eve_EventType = 'Down Reconnected' AND reconnected_devices.eve_PendingAlertEmail = 1 ORDER BY reconnected_devices.eve_DateTime; """ # Get the events as JSON json_obj = db.get_table_as_json(sqlQuery) json_down_reconnected_meta = { "title": "🔁 Reconnected down devices", "columnNames": json_obj.columnNames } json_down_reconnected = json_obj.json["data"] mylog('debug', ['[Notification] json_down_reconnected: ', json.dumps(json_down_reconnected) ]) if 'events' in sections: # Compose Events Section (no empty lines in SQL queries!) sqlQuery = f"""SELECT eve_MAC as MAC, eve_DateTime as Datetime, devLastIP as IP, eve_EventType as "Event Type", devName as "Device name", devComments as Comments FROM Events_Devices WHERE eve_PendingAlertEmail = 1 AND eve_EventType IN ('Connected', 'Down Reconnected', 'Disconnected','IP Changed') {get_setting_value('NTFPRCS_event_condition').replace('{s-quote}',"'")} ORDER BY eve_DateTime""" mylog('debug', ['[Notification] events SQL query: ', sqlQuery ]) # Get the events as JSON json_obj = db.get_table_as_json(sqlQuery) json_events_meta = { "title": "⚡ Events", "columnNames": json_obj.columnNames } json_events = json_obj.json["data"] if 'plugins' in sections: # Compose Plugins Section sqlQuery = """SELECT Plugin, Object_PrimaryId, Object_SecondaryId, DateTimeChanged, Watched_Value1, Watched_Value2, Watched_Value3, Watched_Value4, Status from Plugins_Events""" # Get the events as JSON json_obj = db.get_table_as_json(sqlQuery) json_plugins_meta = { "title": "🔌 Plugins", "columnNames": json_obj.columnNames } json_plugins = json_obj.json["data"] final_json = { "new_devices": json_new_devices, "new_devices_meta": json_new_devices_meta, "down_devices": json_down_devices, "down_devices_meta": json_down_devices_meta, "down_reconnected": json_down_reconnected, "down_reconnected_meta": json_down_reconnected_meta, "events": json_events, "events_meta": json_events_meta, "plugins": json_plugins, "plugins_meta": json_plugins_meta, } return final_json #------------------------------------------------------------------------------- def skip_repeated_notifications (db): # Skip repeated notifications # due strfime : Overflow --> use "strftime / 60" mylog('verbose','[Skip Repeated Notifications] Skip Repeated') db.sql.execute ("""UPDATE Events SET eve_PendingAlertEmail = 0 WHERE eve_PendingAlertEmail = 1 AND eve_MAC IN ( SELECT devMac FROM Devices WHERE devLastNotification IS NOT NULL AND devLastNotification <>"" AND (strftime("%s", devLastNotification)/60 + devSkipRepeated * 60) > (strftime('%s','now','localtime')/60 ) ) """ ) db.commitDB()