From 0db7521bee6c1204e91b8095cb49f75f39e15b7c Mon Sep 17 00:00:00 2001 From: Data-Monkey Date: Wed, 24 May 2023 22:34:09 +1000 Subject: [PATCH] change to import conf --- db/pialert.db | Bin 245760 -> 262144 bytes pialert/conf.py | 13 ++- pialert/database.py | 2 +- pialert/device.py | 44 ++++---- pialert/files.py | 13 ++- pialert/helper.py | 85 +++++----------- pialert/initialise.py | 225 ++++++++++++++++++----------------------- pialert/internet.py | 18 ++-- pialert/mqtt.py | 12 +-- pialert/networkscan.py | 45 ++++----- pialert/nmapscan.py | 6 +- pialert/pialert.py | 67 ++++++------ pialert/pihole.py | 2 + pialert/plugin.py | 16 +-- pialert/reporting.py | 159 +++++++++++++++-------------- pialert/scheduler.py | 41 ++++++++ 16 files changed, 375 insertions(+), 373 deletions(-) create mode 100644 pialert/scheduler.py diff --git a/db/pialert.db b/db/pialert.db index 623697800f95c196d98f45a2a461bd137bf22354..2e998bb24810d810e43ce4dc1c1ba7efcbb8a2cf 100755 GIT binary patch delta 2309 zcmZ`(32YSC8J>Cn?C$LD%#JyH;Ty1x4aR%hJAki1NdOZYNQenw8!$&8#wj-8Ft-17 z04Ju##(^IwASf7zI}XK@ibg?csv29(P+>N`Z${O1KRq(2m6AiKgi(`kJ#)pLlH9&;ArCiL%m{e!lTgwGbr}PKa9pa zP|RD0O&^EPuKHm0P$sLrSFewh)84q@ZmT-B{aLH>;`MOs`ng zv}{HFn!yHHiAhk6OCq=uagOno@r7~QxM6&1T;i?I8ST;3L+N@UjAJ;&(jt(~7sgPYDP9=XJQM0=2YUD+z9gzKVYpFW`+VKp+Q!Ap z>z2Hvpl*FR0c?z+M&C?=9ENU6FM?)sTDw=NID80R!GH5u|z zN&kobE4^2{r(JY6xXWCr&d;2k&T?m#TB(kA{Mm8Nk!HVV-)671kFb4eL)#qXzG5j| zP|0=ulf5s0Bp($9!WcB^N-xt!8etfoJm;^BUO1ezG;&?l!LkKq`y zorcF5X4A~mFp^;wy>J>XGR&mOXGG|u>A5p7k>M!nKLb?|#E~@13t<&Ac+V%=*VF4h zNVMi}0$GN!m`*2rqHCIU#Rt_q@Knwg-X8-QI5lj++4jAxic*+F5; z2&*ax4rYpc5~W&6|5krb->pm9755f*l`HJBJ6oJnovDtyj$b?0I?8P`Y#ETqK4-sR z8S*`;ORDX`Y{e4Yv#eHv72MuRy0cphQU%5Aft?JWq@#NvPsf>@;-pb}U43=a z8XDNc9hx2l&8c8HS2$(s6pGmg@$|=bD7RMcg`e_HGswLUav4sy!u#NR{$d)14v6HQ zpaln@oZ;hi;(&;Ds`dK=;FTc@e?)Ldte8S$4?&pWWLk6xHZy#TK0gHc49l#9pZ)O3 zlv3odpj~1uJq#7RcQIK<1nnZac0|ygM2&rd_QZ#2xAy&)_Jjwtuk}N`^<^J?CYK8@ zM@icy&sERso(fN_{#WfSZI3ox%W%Kqu5rt*Ph9A#cK*(J*qN=~S1Z&k$4W=3ZK6$6 zt|?QM4E7Q0liTIl(pQotQE3U3K_;%Hqgw^BCi-A26f$fidk54oTtmw`grpx^)B$OH z243Jy3({zR2e)x!3wU4#Hdwb_hH|cMHTgOrQ^k5QO?*OAw?U$q&_+H?&(jy3!irUt zxDE1ET*=owwzZThyCCjAdAzX=_V6ap(TpxJ_A6*@7re=EIpuE`&&#N4JM=>iE~T1o z5m+5{cEbjSOUT|MF0jRv-viwY7tw_tNM~3}H+x_X!x{?j5O_6J?|=mi7t&ihAVy_^B`!a9cYskv7yeU|!qVFtr_^tWCZ#jwhXdlm9Hxo2qdPGQqrTDcP<44e8=-(j?UdLIe`iq}c{cF~qKZ|#iT7qvpz0QWg+!Uv z*#b>6jEc&%3i>AvBL5qaDrA2d-w`%(9$i0!Up0v%q$i0_MN`O04r3_?Q_O`1|;c z_%8F6^C|Kk;!WeZ$rHkMgLN6pGuBLIpzga&%+1L~+nZ)EK4xTYWGI+EcNSv0&STVP+ cur_IP """, - (cycle,)) + (conf.cycle,)) mylog('verbose', [' IP Changes.........: ' + str ( sql.fetchone()[0]) ]) @@ -176,7 +176,7 @@ def create_new_devices (db): WHERE cur_ScanCycle = ? AND NOT EXISTS (SELECT 1 FROM Devices WHERE dev_MAC = cur_MAC) """, - (startTime, cycle) ) + (startTime, conf.cycle) ) print_log ('New devices - Insert Connection into session table') sql.execute ("""INSERT INTO Sessions (ses_MAC, ses_IP, ses_EventTypeConnection, ses_DateTimeConnection, @@ -186,7 +186,7 @@ def create_new_devices (db): WHERE cur_ScanCycle = ? AND NOT EXISTS (SELECT 1 FROM Sessions WHERE ses_MAC = cur_MAC) """, - (startTime, cycle) ) + (startTime, conf.cycle) ) # arpscan - Create new devices print_log ('New devices - 2 Create devices') @@ -200,7 +200,7 @@ def create_new_devices (db): WHERE cur_ScanCycle = ? AND NOT EXISTS (SELECT 1 FROM Devices WHERE dev_MAC = cur_MAC) """, - (startTime, startTime, cycle) ) + (startTime, startTime, conf.cycle) ) # Pi-hole - Insert events for new devices # NOT STRICYLY NECESARY (Devices can be created through Current_Scan) @@ -277,7 +277,7 @@ def create_new_devices (db): # WHERE dev_MAC = DHCP_MAC) """, # (startTime, startTime) ) print_log ('New Devices end') - db.commit() + db.commitDB() #------------------------------------------------------------------------------- @@ -293,7 +293,7 @@ def update_devices_data_from_scan (db): AND EXISTS (SELECT 1 FROM CurrentScan WHERE dev_MAC = cur_MAC AND dev_ScanCycle = cur_ScanCycle) """, - (startTime, cycle)) + (startTime, conf.cycle)) # Clean no active devices print_log ('Update devices - 2 Clean no active devices') @@ -302,7 +302,7 @@ def update_devices_data_from_scan (db): AND NOT EXISTS (SELECT 1 FROM CurrentScan WHERE dev_MAC = cur_MAC AND dev_ScanCycle = cur_ScanCycle) """, - (cycle,)) + (conf.cycle,)) # Update IP & Vendor print_log ('Update devices - 3 LastIP & Vendor') @@ -317,7 +317,7 @@ def update_devices_data_from_scan (db): AND EXISTS (SELECT 1 FROM CurrentScan WHERE dev_MAC = cur_MAC AND dev_ScanCycle = cur_ScanCycle) """, - (cycle,)) + (conf.cycle,)) # Pi-hole Network - Update (unknown) Name print_log ('Update devices - 4 Unknown Name') @@ -379,11 +379,11 @@ def update_devices_names (db): db.commitDB() # perform Pholus scan if (unknown) devices found - if PHOLUS_ACTIVE and (len(unknownDevices) > 0 or PHOLUS_FORCE): - performPholusScan(db, PHOLUS_TIMEOUT, userSubnets) + if conf.PHOLUS_ACTIVE and (len(unknownDevices) > 0 or conf.PHOLUS_FORCE): + performPholusScan(db, conf.PHOLUS_TIMEOUT, conf.userSubnets) # skip checks if no unknown devices - if len(unknownDevices) == 0 and PHOLUS_FORCE == False: + if len(unknownDevices) == 0 and conf.PHOLUS_FORCE == False: return # Devices without name diff --git a/pialert/files.py b/pialert/files.py index e283c59c..55d33faa 100644 --- a/pialert/files.py +++ b/pialert/files.py @@ -23,4 +23,15 @@ def get_file_content(path): content = f.read() f.close() - return content \ No newline at end of file + return content + +#------------------------------------------------------------------------------- +def read_config_file(filename): + """ + retuns dict on the config file key:value pairs + """ + # load the variables from pialert.conf + code = compile(filename.read_text(), filename.name, "exec") + confDict = {} # config dictionary + exec(code, {"__builtins__": {}}, confDict) + return confDict \ No newline at end of file diff --git a/pialert/helper.py b/pialert/helper.py index 18886cd6..d3c54015 100644 --- a/pialert/helper.py +++ b/pialert/helper.py @@ -12,11 +12,8 @@ import time from pathlib import Path import requests - - - +import conf from const import * -from conf import tz from logger import mylog, logResult, print_log # from api import update_api # to avoid circular reference @@ -25,9 +22,15 @@ from logger import mylog, logResult, print_log #------------------------------------------------------------------------------- def timeNow(): return datetime.datetime.now().replace(microsecond=0) +#------------------------------------------------------------------------------- +def timeNowTZ(): + return datetime.datetime.now(conf.tz).replace(microsecond=0) #------------------------------------------------------------------------------- -def updateState(db, newState): +def updateState(db, newState): + + # ?? Why is the state written to the DB? + #sql = db.sql mylog('debug', ' [updateState] changing state to: "' + newState +'"') @@ -35,18 +38,20 @@ def updateState(db, newState): db.commitDB() #------------------------------------------------------------------------------- -def updateSubnets(SCAN_SUBNETS): +def updateSubnets(scan_subnets): # remove old list - userSubnets = [] + subnets = [] # multiple interfaces - if type(SCAN_SUBNETS) is list: - for interface in SCAN_SUBNETS : - userSubnets.append(interface) + if type(scan_subnets) is list: + for interface in scan_subnets : + subnets.append(interface) # one interface only else: - userSubnets.append(SCAN_SUBNETS) + subnets.append(scan_subnets) + + return subnets @@ -129,43 +134,6 @@ def filePermissions(): # last attempt fixPermissions() -#------------------------------------------------------------------------------- -class schedule_class: - def __init__(self, service, scheduleObject, last_next_schedule, was_last_schedule_used, last_run = 0): - self.service = service - self.scheduleObject = scheduleObject - self.last_next_schedule = last_next_schedule - self.last_run = last_run - self.was_last_schedule_used = was_last_schedule_used - def runScheduleCheck(self): - - result = False - - # Initialize the last run time if never run before - if self.last_run == 0: - self.last_run = (datetime.datetime.now(tz) - timedelta(days=365)).replace(microsecond=0) - - # get the current time with the currently specified timezone - nowTime = datetime.datetime.now(tz).replace(microsecond=0) - - # Run the schedule if the current time is past the schedule time we saved last time and - # (maybe the following check is unnecessary:) - # if the last run is past the last time we run a scheduled Pholus scan - if nowTime > self.last_next_schedule and self.last_run < self.last_next_schedule: - print_log(f'Scheduler run for {self.service}: YES') - self.was_last_schedule_used = True - result = True - else: - print_log(f'Scheduler run for {self.service}: NO') - - if self.was_last_schedule_used: - self.was_last_schedule_used = False - self.last_next_schedule = self.scheduleObject.next() - - return result - - - #------------------------------------------------------------------------------- @@ -220,15 +188,11 @@ def import_language_string(db, code, key, value, extra = ""): #------------------------------------------------------------------------------- -# Make a regular expression -# for validating an Ip-address -ipRegex = "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$" - -# Define a function to -# validate an Ip address def checkIPV4(ip): - # pass the regular expression - # and the string in search() method + """ Define a function to validate an Ip address + """ + ipRegex = "^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$" + if(re.search(ipRegex, ip)): return True else: @@ -236,10 +200,9 @@ def checkIPV4(ip): #------------------------------------------------------------------------------- -def isNewVersion(db): - global newVersionAvailable +def isNewVersion(newVersion: bool): - if newVersionAvailable == False: + if newVersion == False: f = open(pialertPath + '/front/buildtimestamp.txt', 'r') buildTimestamp = int(f.read().strip()) @@ -264,10 +227,10 @@ def isNewVersion(db): if realeaseTimestamp > buildTimestamp + 600: mylog('none', [" New version of the container available!"]) - newVersionAvailable = True + newVersion = True # updateState(db, 'Back_New_Version_Available', str(newVersionAvailable)) ## TO DO add this back in but avoid circular ref with database - return newVersionAvailable + return newVersion #------------------------------------------------------------------------------- def hide_email(email): diff --git a/pialert/initialise.py b/pialert/initialise.py index 6202fed1..f8d91813 100644 --- a/pialert/initialise.py +++ b/pialert/initialise.py @@ -6,10 +6,12 @@ from cron_converter import Cron from pathlib import Path import datetime -from conf import * +import conf from const import * -from helper import collect_lang_strings, schedule_class, timeNow, updateSubnets, initOrSetParam +from helper import collect_lang_strings, timeNow, updateSubnets, initOrSetParam from logger import mylog +from files import read_config_file +from scheduler import schedule_class from plugin import get_plugins_configs, print_plugin_info #=============================================================================== @@ -21,18 +23,18 @@ from plugin import get_plugins_configs, print_plugin_info #------------------------------------------------------------------------------- # Import user values # Check config dictionary -def ccd(key, default, config, name, inputtype, options, group, events=[], desc = "", regex = ""): +def ccd(key, default, config_dir, name, inputtype, options, group, events=[], desc = "", regex = ""): result = default # use existing value if already supplied, otherwise default value is used - if key in config: - result = config[key] + if key in config_dir: + result = config_dir[key] if inputtype == 'text': result = result.replace('\'', "{s-quote}") - mySettingsSQLsafe.append((key, name, desc, inputtype, options, regex, str(result), group, str(events))) - mySettings.append((key, name, desc, inputtype, options, regex, result, group, str(events))) + conf.mySettingsSQLsafe.append((key, name, desc, inputtype, options, regex, str(result), group, str(events))) + conf.mySettings.append((key, name, desc, inputtype, options, regex, result, group, str(events))) return result #------------------------------------------------------------------------------- @@ -41,33 +43,7 @@ def importConfigs (db): sql = db.sql - # Specify globals so they can be overwritten with the new config - global lastTimeImported, mySettings, mySettingsSQLsafe, plugins, plugins_once_run lastTimeImported = 0 - # General - global ENABLE_ARPSCAN, SCAN_SUBNETS, LOG_LEVEL, TIMEZONE, ENABLE_PLUGINS, PIALERT_WEB_PROTECTION, PIALERT_WEB_PASSWORD, INCLUDED_SECTIONS, SCAN_CYCLE_MINUTES, DAYS_TO_KEEP_EVENTS, REPORT_DASHBOARD_URL, DIG_GET_IP_ARG, UI_LANG - # Email - global REPORT_MAIL, SMTP_SERVER, SMTP_PORT, REPORT_TO, REPORT_FROM, SMTP_SKIP_LOGIN, SMTP_USER, SMTP_PASS, SMTP_SKIP_TLS, SMTP_FORCE_SSL - # Webhooks - global REPORT_WEBHOOK, WEBHOOK_URL, WEBHOOK_PAYLOAD, WEBHOOK_REQUEST_METHOD - # Apprise - global REPORT_APPRISE, APPRISE_HOST, APPRISE_URL, APPRISE_PAYLOAD - # NTFY - global REPORT_NTFY, NTFY_HOST, NTFY_TOPIC, NTFY_USER, NTFY_PASSWORD - # PUSHSAFER - global REPORT_PUSHSAFER, PUSHSAFER_TOKEN - # MQTT - global REPORT_MQTT, MQTT_BROKER, MQTT_PORT, MQTT_USER, MQTT_PASSWORD, MQTT_QOS, MQTT_DELAY_SEC - # DynDNS - global DDNS_ACTIVE, DDNS_DOMAIN, DDNS_USER, DDNS_PASSWORD, DDNS_UPDATE_URL - # PiHole - global PIHOLE_ACTIVE, DHCP_ACTIVE - # Pholus - global PHOLUS_ACTIVE, PHOLUS_TIMEOUT, PHOLUS_FORCE, PHOLUS_DAYS_DATA, PHOLUS_RUN, PHOLUS_RUN_SCHD, PHOLUS_RUN_TIMEOUT - # Nmap - global NMAP_ACTIVE, NMAP_TIMEOUT, NMAP_RUN, NMAP_RUN_SCHD, NMAP_ARGS - # API - global API_CUSTOM_SQL # get config file config_file = Path(fullConfPath) @@ -76,136 +52,133 @@ def importConfigs (db): if (os.path.getmtime(config_file) < lastTimeImported) : return - mySettings = [] # reset settings - mySettingsSQLsafe = [] # same as above but safe to be passed into a SQL query - - # load the variables from pialert.conf - code = compile(config_file.read_text(), config_file.name, "exec") - c_d = {} # config dictionary - exec(code, {"__builtins__": {}}, c_d) + conf.mySettings = [] # reset settings + conf.mySettingsSQLsafe = [] # same as above but safe to be passed into a SQL query + + c_d = read_config_file(config_file) # Import setting if found in the dictionary # General - ENABLE_ARPSCAN = ccd('ENABLE_ARPSCAN', True , c_d, 'Enable arpscan', 'boolean', '', 'General', ['run']) - SCAN_SUBNETS = ccd('SCAN_SUBNETS', ['192.168.1.0/24 --interface=eth1', '192.168.1.0/24 --interface=eth0'] , c_d, 'Subnets to scan', 'subnets', '', 'General') - LOG_LEVEL = ccd('LOG_LEVEL', 'verbose' , c_d, 'Log verboseness', 'selecttext', "['none', 'minimal', 'verbose', 'debug']", 'General') - TIMEZONE = ccd('TIMEZONE', 'Europe/Berlin' , c_d, 'Time zone', 'text', '', 'General') - ENABLE_PLUGINS = ccd('ENABLE_PLUGINS', True , c_d, 'Enable plugins', 'boolean', '', 'General') - PIALERT_WEB_PROTECTION = ccd('PIALERT_WEB_PROTECTION', False , c_d, 'Enable logon', 'boolean', '', 'General') - PIALERT_WEB_PASSWORD = ccd('PIALERT_WEB_PASSWORD', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92' , c_d, 'Logon password', 'readonly', '', 'General') - INCLUDED_SECTIONS = ccd('INCLUDED_SECTIONS', ['internet', 'new_devices', 'down_devices', 'events', 'ports'] , c_d, 'Notify on', 'multiselect', "['internet', 'new_devices', 'down_devices', 'events', 'ports', 'plugins']", 'General') - SCAN_CYCLE_MINUTES = ccd('SCAN_CYCLE_MINUTES', 5 , c_d, 'Scan cycle delay (m)', 'integer', '', 'General') - DAYS_TO_KEEP_EVENTS = ccd('DAYS_TO_KEEP_EVENTS', 90 , c_d, 'Delete events days', 'integer', '', 'General') - REPORT_DASHBOARD_URL = ccd('REPORT_DASHBOARD_URL', 'http://pi.alert/' , c_d, 'PiAlert URL', 'text', '', 'General') - DIG_GET_IP_ARG = ccd('DIG_GET_IP_ARG', '-4 myip.opendns.com @resolver1.opendns.com' , c_d, 'DIG arguments', 'text', '', 'General') - UI_LANG = ccd('UI_LANG', 'English' , c_d, 'Language Interface', 'selecttext', "['English', 'German', 'Spanish']", 'General') - UI_PRESENCE = ccd('UI_PRESENCE', ['online', 'offline', 'archived'] , c_d, 'Include in presence', 'multiselect', "['online', 'offline', 'archived']", 'General') + conf.ENABLE_ARPSCAN = ccd('ENABLE_ARPSCAN', True , c_d, 'Enable arpscan', 'boolean', '', 'General', ['run']) + conf.SCAN_SUBNETS = ccd('SCAN_SUBNETS', ['192.168.1.0/24 --interface=eth1', '192.168.1.0/24 --interface=eth0'] , c_d, 'Subnets to scan', 'subnets', '', 'General') + conf.LOG_LEVEL = ccd('LOG_LEVEL', 'verbose' , c_d, 'Log verboseness', 'selecttext', "['none', 'minimal', 'verbose', 'debug']", 'General') + conf.TIMEZONE = ccd('TIMEZONE', 'Europe/Berlin' , c_d, 'Time zone', 'text', '', 'General') + conf.ENABLE_PLUGINS = ccd('ENABLE_PLUGINS', True , c_d, 'Enable plugins', 'boolean', '', 'General') + conf.PIALERT_WEB_PROTECTION = ccd('PIALERT_WEB_PROTECTION', False , c_d, 'Enable logon', 'boolean', '', 'General') + conf.PIALERT_WEB_PASSWORD = ccd('PIALERT_WEB_PASSWORD', '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92' , c_d, 'Logon password', 'readonly', '', 'General') + conf.INCLUDED_SECTIONS = ccd('INCLUDED_SECTIONS', ['internet', 'new_devices', 'down_devices', 'events', 'ports'] , c_d, 'Notify on', 'multiselect', "['internet', 'new_devices', 'down_devices', 'events', 'ports', 'plugins']", 'General') + conf.SCAN_CYCLE_MINUTES = ccd('SCAN_CYCLE_MINUTES', 5 , c_d, 'Scan cycle delay (m)', 'integer', '', 'General') + conf.DAYS_TO_KEEP_EVENTS = ccd('DAYS_TO_KEEP_EVENTS', 90 , c_d, 'Delete events days', 'integer', '', 'General') + conf.REPORT_DASHBOARD_URL = ccd('REPORT_DASHBOARD_URL', 'http://pi.alert/' , c_d, 'PiAlert URL', 'text', '', 'General') + conf.DIG_GET_IP_ARG = ccd('DIG_GET_IP_ARG', '-4 myip.opendns.com @resolver1.opendns.com' , c_d, 'DIG arguments', 'text', '', 'General') + conf.UI_LANG = ccd('UI_LANG', 'English' , c_d, 'Language Interface', 'selecttext', "['English', 'German', 'Spanish']", 'General') + conf.UI_PRESENCE = ccd('UI_PRESENCE', ['online', 'offline', 'archived'] , c_d, 'Include in presence', 'multiselect', "['online', 'offline', 'archived']", 'General') # Email - REPORT_MAIL = ccd('REPORT_MAIL', False , c_d, 'Enable email', 'boolean', '', 'Email', ['test']) - SMTP_SERVER = ccd('SMTP_SERVER', '' , c_d,'SMTP server URL', 'text', '', 'Email') - SMTP_PORT = ccd('SMTP_PORT', 587 , c_d, 'SMTP port', 'integer', '', 'Email') - REPORT_TO = ccd('REPORT_TO', 'user@gmail.com' , c_d, 'Email to', 'text', '', 'Email') - REPORT_FROM = ccd('REPORT_FROM', 'Pi.Alert ' , c_d, 'Email Subject', 'text', '', 'Email') - SMTP_SKIP_LOGIN = ccd('SMTP_SKIP_LOGIN', False , c_d, 'SMTP skip login', 'boolean', '', 'Email') - SMTP_USER = ccd('SMTP_USER', '' , c_d, 'SMTP user', 'text', '', 'Email') - SMTP_PASS = ccd('SMTP_PASS', '' , c_d, 'SMTP password', 'password', '', 'Email') - SMTP_SKIP_TLS = ccd('SMTP_SKIP_TLS', False , c_d, 'SMTP skip TLS', 'boolean', '', 'Email') - SMTP_FORCE_SSL = ccd('SMTP_FORCE_SSL', False , c_d, 'Force SSL', 'boolean', '', 'Email') + conf.REPORT_MAIL = ccd('REPORT_MAIL', False , c_d, 'Enable email', 'boolean', '', 'Email', ['test']) + conf.SMTP_SERVER = ccd('SMTP_SERVER', '' , c_d,'SMTP server URL', 'text', '', 'Email') + conf.SMTP_PORT = ccd('SMTP_PORT', 587 , c_d, 'SMTP port', 'integer', '', 'Email') + conf.REPORT_TO = ccd('REPORT_TO', 'user@gmail.com' , c_d, 'Email to', 'text', '', 'Email') + conf.REPORT_FROM = ccd('REPORT_FROM', 'Pi.Alert ' , c_d, 'Email Subject', 'text', '', 'Email') + conf.SMTP_SKIP_LOGIN = ccd('SMTP_SKIP_LOGIN', False , c_d, 'SMTP skip login', 'boolean', '', 'Email') + conf.SMTP_USER = ccd('SMTP_USER', '' , c_d, 'SMTP user', 'text', '', 'Email') + conf.SMTP_PASS = ccd('SMTP_PASS', '' , c_d, 'SMTP password', 'password', '', 'Email') + conf.SMTP_SKIP_TLS = ccd('SMTP_SKIP_TLS', False , c_d, 'SMTP skip TLS', 'boolean', '', 'Email') + conf.SMTP_FORCE_SSL = ccd('SMTP_FORCE_SSL', False , c_d, 'Force SSL', 'boolean', '', 'Email') # Webhooks - REPORT_WEBHOOK = ccd('REPORT_WEBHOOK', False , c_d, 'Enable Webhooks', 'boolean', '', 'Webhooks', ['test']) - WEBHOOK_URL = ccd('WEBHOOK_URL', '' , c_d, 'Target URL', 'text', '', 'Webhooks') - WEBHOOK_PAYLOAD = ccd('WEBHOOK_PAYLOAD', 'json' , c_d, 'Payload type', 'selecttext', "['json', 'html', 'text']", 'Webhooks') - WEBHOOK_REQUEST_METHOD = ccd('WEBHOOK_REQUEST_METHOD', 'GET' , c_d, 'Req type', 'selecttext', "['GET', 'POST', 'PUT']", 'Webhooks') + conf.REPORT_WEBHOOK = ccd('REPORT_WEBHOOK', False , c_d, 'Enable Webhooks', 'boolean', '', 'Webhooks', ['test']) + conf.WEBHOOK_URL = ccd('WEBHOOK_URL', '' , c_d, 'Target URL', 'text', '', 'Webhooks') + conf.WEBHOOK_PAYLOAD = ccd('WEBHOOK_PAYLOAD', 'json' , c_d, 'Payload type', 'selecttext', "['json', 'html', 'text']", 'Webhooks') + conf.WEBHOOK_REQUEST_METHOD = ccd('WEBHOOK_REQUEST_METHOD', 'GET' , c_d, 'Req type', 'selecttext', "['GET', 'POST', 'PUT']", 'Webhooks') # Apprise - REPORT_APPRISE = ccd('REPORT_APPRISE', False , c_d, 'Enable Apprise', 'boolean', '', 'Apprise', ['test']) - APPRISE_HOST = ccd('APPRISE_HOST', '' , c_d, 'Apprise host URL', 'text', '', 'Apprise') - APPRISE_URL = ccd('APPRISE_URL', '' , c_d, 'Apprise notification URL', 'text', '', 'Apprise') - APPRISE_PAYLOAD = ccd('APPRISE_PAYLOAD', 'html' , c_d, 'Payload type', 'selecttext', "['html', 'text']", 'Apprise') + conf.REPORT_APPRISE = ccd('REPORT_APPRISE', False , c_d, 'Enable Apprise', 'boolean', '', 'Apprise', ['test']) + conf.APPRISE_HOST = ccd('APPRISE_HOST', '' , c_d, 'Apprise host URL', 'text', '', 'Apprise') + conf.APPRISE_URL = ccd('APPRISE_URL', '' , c_d, 'Apprise notification URL', 'text', '', 'Apprise') + conf.APPRISE_PAYLOAD = ccd('APPRISE_PAYLOAD', 'html' , c_d, 'Payload type', 'selecttext', "['html', 'text']", 'Apprise') # NTFY - REPORT_NTFY = ccd('REPORT_NTFY', False , c_d, 'Enable NTFY', 'boolean', '', 'NTFY', ['test']) - NTFY_HOST = ccd('NTFY_HOST', 'https://ntfy.sh' , c_d, 'NTFY host URL', 'text', '', 'NTFY') - NTFY_TOPIC = ccd('NTFY_TOPIC', '' , c_d, 'NTFY topic', 'text', '', 'NTFY') - NTFY_USER = ccd('NTFY_USER', '' , c_d, 'NTFY user', 'text', '', 'NTFY') - NTFY_PASSWORD = ccd('NTFY_PASSWORD', '' , c_d, 'NTFY password', 'password', '', 'NTFY') + conf.REPORT_NTFY = ccd('REPORT_NTFY', False , c_d, 'Enable NTFY', 'boolean', '', 'NTFY', ['test']) + conf.NTFY_HOST = ccd('NTFY_HOST', 'https://ntfy.sh' , c_d, 'NTFY host URL', 'text', '', 'NTFY') + conf.NTFY_TOPIC = ccd('NTFY_TOPIC', '' , c_d, 'NTFY topic', 'text', '', 'NTFY') + conf.NTFY_USER = ccd('NTFY_USER', '' , c_d, 'NTFY user', 'text', '', 'NTFY') + conf.NTFY_PASSWORD = ccd('NTFY_PASSWORD', '' , c_d, 'NTFY password', 'password', '', 'NTFY') # PUSHSAFER - REPORT_PUSHSAFER = ccd('REPORT_PUSHSAFER', False , c_d, 'Enable PUSHSAFER', 'boolean', '', 'PUSHSAFER', ['test']) - PUSHSAFER_TOKEN = ccd('PUSHSAFER_TOKEN', 'ApiKey' , c_d, 'PUSHSAFER token', 'text', '', 'PUSHSAFER') + conf.REPORT_PUSHSAFER = ccd('REPORT_PUSHSAFER', False , c_d, 'Enable PUSHSAFER', 'boolean', '', 'PUSHSAFER', ['test']) + conf.PUSHSAFER_TOKEN = ccd('PUSHSAFER_TOKEN', 'ApiKey' , c_d, 'PUSHSAFER token', 'text', '', 'PUSHSAFER') # MQTT - REPORT_MQTT = ccd('REPORT_MQTT', False , c_d, 'Enable MQTT', 'boolean', '', 'MQTT') - MQTT_BROKER = ccd('MQTT_BROKER', '' , c_d, 'MQTT broker', 'text', '', 'MQTT') - MQTT_PORT = ccd('MQTT_PORT', 1883 , c_d, 'MQTT broker port', 'integer', '', 'MQTT') - MQTT_USER = ccd('MQTT_USER', '' , c_d, 'MQTT user', 'text', '', 'MQTT') - MQTT_PASSWORD = ccd('MQTT_PASSWORD', '' , c_d, 'MQTT password', 'password', '', 'MQTT') - MQTT_QOS = ccd('MQTT_QOS', 0 , c_d, 'MQTT Quality of Service', 'selectinteger', "['0', '1', '2']", 'MQTT') - MQTT_DELAY_SEC = ccd('MQTT_DELAY_SEC', 2 , c_d, 'MQTT delay', 'selectinteger', "['2', '3', '4', '5']", 'MQTT') + conf.REPORT_MQTT = ccd('REPORT_MQTT', False , c_d, 'Enable MQTT', 'boolean', '', 'MQTT') + conf.MQTT_BROKER = ccd('MQTT_BROKER', '' , c_d, 'MQTT broker', 'text', '', 'MQTT') + conf.MQTT_PORT = ccd('MQTT_PORT', 1883 , c_d, 'MQTT broker port', 'integer', '', 'MQTT') + conf.MQTT_USER = ccd('MQTT_USER', '' , c_d, 'MQTT user', 'text', '', 'MQTT') + conf.MQTT_PASSWORD = ccd('MQTT_PASSWORD', '' , c_d, 'MQTT password', 'password', '', 'MQTT') + conf.MQTT_QOS = ccd('MQTT_QOS', 0 , c_d, 'MQTT Quality of Service', 'selectinteger', "['0', '1', '2']", 'MQTT') + conf.MQTT_DELAY_SEC = ccd('MQTT_DELAY_SEC', 2 , c_d, 'MQTT delay', 'selectinteger', "['2', '3', '4', '5']", 'MQTT') # DynDNS - DDNS_ACTIVE = ccd('DDNS_ACTIVE', False , c_d, 'Enable DynDNS', 'boolean', '', 'DynDNS') - DDNS_DOMAIN = ccd('DDNS_DOMAIN', 'your_domain.freeddns.org' , c_d, 'DynDNS domain URL', 'text', '', 'DynDNS') - DDNS_USER = ccd('DDNS_USER', 'dynu_user' , c_d, 'DynDNS user', 'text', '', 'DynDNS') - DDNS_PASSWORD = ccd('DDNS_PASSWORD', 'A0000000B0000000C0000000D0000000' , c_d, 'DynDNS password', 'password', '', 'DynDNS') - DDNS_UPDATE_URL = ccd('DDNS_UPDATE_URL', 'https://api.dynu.com/nic/update?' , c_d, 'DynDNS update URL', 'text', '', 'DynDNS') + conf.DDNS_ACTIVE = ccd('DDNS_ACTIVE', False , c_d, 'Enable DynDNS', 'boolean', '', 'DynDNS') + conf.DDNS_DOMAIN = ccd('DDNS_DOMAIN', 'your_domain.freeddns.org' , c_d, 'DynDNS domain URL', 'text', '', 'DynDNS') + conf.DDNS_USER = ccd('DDNS_USER', 'dynu_user' , c_d, 'DynDNS user', 'text', '', 'DynDNS') + conf.DDNS_PASSWORD = ccd('DDNS_PASSWORD', 'A0000000B0000000C0000000D0000000' , c_d, 'DynDNS password', 'password', '', 'DynDNS') + conf.DDNS_UPDATE_URL = ccd('DDNS_UPDATE_URL', 'https://api.dynu.com/nic/update?' , c_d, 'DynDNS update URL', 'text', '', 'DynDNS') # PiHole - PIHOLE_ACTIVE = ccd('PIHOLE_ACTIVE', False, c_d, 'Enable PiHole mapping', 'boolean', '', 'PiHole') - DHCP_ACTIVE = ccd('DHCP_ACTIVE', False , c_d, 'Enable PiHole DHCP', 'boolean', '', 'PiHole') + conf.PIHOLE_ACTIVE = ccd('PIHOLE_ACTIVE', False, c_d, 'Enable PiHole mapping', 'boolean', '', 'PiHole') + conf.DHCP_ACTIVE = ccd('DHCP_ACTIVE', False , c_d, 'Enable PiHole DHCP', 'boolean', '', 'PiHole') # PHOLUS - PHOLUS_ACTIVE = ccd('PHOLUS_ACTIVE', False , c_d, 'Enable Pholus scans', 'boolean', '', 'Pholus') - PHOLUS_TIMEOUT = ccd('PHOLUS_TIMEOUT', 20 , c_d, 'Pholus timeout', 'integer', '', 'Pholus') - PHOLUS_FORCE = ccd('PHOLUS_FORCE', False , c_d, 'Pholus force check', 'boolean', '', 'Pholus') - PHOLUS_RUN = ccd('PHOLUS_RUN', 'once' , c_d, 'Pholus enable schedule', 'selecttext', "['none', 'once', 'schedule']", 'Pholus') - PHOLUS_RUN_TIMEOUT = ccd('PHOLUS_RUN_TIMEOUT', 600 , c_d, 'Pholus timeout schedule', 'integer', '', 'Pholus') - PHOLUS_RUN_SCHD = ccd('PHOLUS_RUN_SCHD', '0 4 * * *' , c_d, 'Pholus schedule', 'text', '', 'Pholus') - PHOLUS_DAYS_DATA = ccd('PHOLUS_DAYS_DATA', 0 , c_d, 'Pholus keep days', 'integer', '', 'Pholus') + conf.PHOLUS_ACTIVE = ccd('PHOLUS_ACTIVE', False , c_d, 'Enable Pholus scans', 'boolean', '', 'Pholus') + conf.PHOLUS_TIMEOUT = ccd('PHOLUS_TIMEOUT', 20 , c_d, 'Pholus timeout', 'integer', '', 'Pholus') + conf.PHOLUS_FORCE = ccd('PHOLUS_FORCE', False , c_d, 'Pholus force check', 'boolean', '', 'Pholus') + conf.PHOLUS_RUN = ccd('PHOLUS_RUN', 'once' , c_d, 'Pholus enable schedule', 'selecttext', "['none', 'once', 'schedule']", 'Pholus') + conf.PHOLUS_RUN_TIMEOUT = ccd('PHOLUS_RUN_TIMEOUT', 600 , c_d, 'Pholus timeout schedule', 'integer', '', 'Pholus') + conf.PHOLUS_RUN_SCHD = ccd('PHOLUS_RUN_SCHD', '0 4 * * *' , c_d, 'Pholus schedule', 'text', '', 'Pholus') + conf.PHOLUS_DAYS_DATA = ccd('PHOLUS_DAYS_DATA', 0 , c_d, 'Pholus keep days', 'integer', '', 'Pholus') # Nmap - NMAP_ACTIVE = ccd('NMAP_ACTIVE', True , c_d, 'Enable Nmap scans', 'boolean', '', 'Nmap') - NMAP_TIMEOUT = ccd('NMAP_TIMEOUT', 150 , c_d, 'Nmap timeout', 'integer', '', 'Nmap') - NMAP_RUN = ccd('NMAP_RUN', 'none' , c_d, 'Nmap enable schedule', 'selecttext', "['none', 'once', 'schedule']", 'Nmap') - NMAP_RUN_SCHD = ccd('NMAP_RUN_SCHD', '0 2 * * *' , c_d, 'Nmap schedule', 'text', '', 'Nmap') - NMAP_ARGS = ccd('NMAP_ARGS', '-p -10000' , c_d, 'Nmap custom arguments', 'text', '', 'Nmap') + conf.NMAP_ACTIVE = ccd('NMAP_ACTIVE', True , c_d, 'Enable Nmap scans', 'boolean', '', 'Nmap') + conf.NMAP_TIMEOUT = ccd('NMAP_TIMEOUT', 150 , c_d, 'Nmap timeout', 'integer', '', 'Nmap') + conf.NMAP_RUN = ccd('NMAP_RUN', 'none' , c_d, 'Nmap enable schedule', 'selecttext', "['none', 'once', 'schedule']", 'Nmap') + conf.NMAP_RUN_SCHD = ccd('NMAP_RUN_SCHD', '0 2 * * *' , c_d, 'Nmap schedule', 'text', '', 'Nmap') + conf.NMAP_ARGS = ccd('NMAP_ARGS', '-p -10000' , c_d, 'Nmap custom arguments', 'text', '', 'Nmap') # API - API_CUSTOM_SQL = ccd('API_CUSTOM_SQL', 'SELECT * FROM Devices WHERE dev_PresentLastScan = 0' , c_d, 'Custom endpoint', 'text', '', 'API') + conf.API_CUSTOM_SQL = ccd('API_CUSTOM_SQL', 'SELECT * FROM Devices WHERE dev_PresentLastScan = 0' , c_d, 'Custom endpoint', 'text', '', 'API') # Prepare scheduler - global tz, mySchedules, plugins + #global tz, mySchedules, plugins # Init timezone in case it changed - tz = timezone(TIMEZONE) - + conf.tz = timezone(conf.TIMEZONE) + # global mySchedules # reset schedules - mySchedules = [] + conf.mySchedules = [] # init pholus schedule - pholusSchedule = Cron(PHOLUS_RUN_SCHD).schedule(start_date=datetime.datetime.now(tz)) - mySchedules.append(schedule_class("pholus", pholusSchedule, pholusSchedule.next(), False)) + pholusSchedule = Cron(conf.PHOLUS_RUN_SCHD).schedule(start_date=datetime.datetime.now(conf.tz)) + + conf.mySchedules.append(schedule_class("pholus", pholusSchedule, pholusSchedule.next(), False)) + mylog('debug', "schedules (appended) : " + str(conf.mySchedules)) # init nmap schedule - nmapSchedule = Cron(NMAP_RUN_SCHD).schedule(start_date=datetime.datetime.now(tz)) - mySchedules.append(schedule_class("nmap", nmapSchedule, nmapSchedule.next(), False)) + nmapSchedule = Cron(conf.NMAP_RUN_SCHD).schedule(start_date=datetime.datetime.now(conf.tz)) + conf.mySchedules.append(schedule_class("nmap", nmapSchedule, nmapSchedule.next(), False)) # Format and prepare the list of subnets - userSubnets = updateSubnets(SCAN_SUBNETS) - - + conf.userSubnets = updateSubnets(conf.SCAN_SUBNETS) # Plugins START # ----------------- - if ENABLE_PLUGINS: - plugins = get_plugins_configs() + if conf.ENABLE_PLUGINS: + conf.plugins = get_plugins_configs() - mylog('none', ['[', timeNow(), '] Plugins: Number of dynamically loaded plugins: ', len(plugins)]) + mylog('none', ['[', timeNow(), '] Plugins: Number of dynamically loaded plugins: ', len(conf.plugins)]) # handle plugins - for plugin in plugins: + for plugin in conf.plugins: print_plugin_info(plugin, ['display_name','description']) pref = plugin["unique_prefix"] @@ -227,13 +200,13 @@ def importConfigs (db): # Setup schedules if setFunction == 'RUN_SCHD': - newSchedule = Cron(v).schedule(start_date=datetime.datetime.now(tz)) - mySchedules.append(schedule_class(pref, newSchedule, newSchedule.next(), False)) + newSchedule = Cron(v).schedule(start_date=datetime.datetime.now(conf.tz)) + conf.mySchedules.append(schedule_class(pref, newSchedule, newSchedule.next(), False)) # Collect settings related language strings collect_lang_strings(db, set, pref + "_" + set["function"]) - plugins_once_run = False + conf.plugins_once_run = False # ----------------- # Plugins END @@ -244,10 +217,10 @@ def importConfigs (db): # Insert settings into the DB sql.execute ("DELETE FROM Settings") sql.executemany ("""INSERT INTO Settings ("Code_Name", "Display_Name", "Description", "Type", "Options", - "RegEx", "Value", "Group", "Events" ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", mySettingsSQLsafe) + "RegEx", "Value", "Group", "Events" ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)""", conf.mySettingsSQLsafe) # Used to determine the next import - lastTimeImported = time.time() + conf.lastTimeImported = time.time() # Is used to display a message in the UI when old (outdated) settings are loaded initOrSetParam(db, "Back_Settings_Imported",(round(time.time() * 1000),) ) diff --git a/pialert/internet.py b/pialert/internet.py index 3b13db4f..cd68f881 100644 --- a/pialert/internet.py +++ b/pialert/internet.py @@ -5,10 +5,10 @@ import re # pialert modules +import conf from helper import timeNow, updateState from logger import append_line_to_file, mylog from const import logPath -from conf import DDNS_ACTIVE, DDNS_DOMAIN, DDNS_UPDATE_URL, DDNS_PASSWORD, DDNS_USER @@ -19,7 +19,7 @@ from conf import DDNS_ACTIVE, DDNS_DOMAIN, DDNS_UPDATE_URL, DDNS_PASSWORD, DDNS_ #=============================================================================== # INTERNET IP CHANGE #=============================================================================== -def check_internet_IP (db, DIG_GET_IP_ARG): +def check_internet_IP ( db ): # Header updateState(db,"Scan: Internet IP") @@ -27,7 +27,7 @@ def check_internet_IP (db, DIG_GET_IP_ARG): # Get Internet IP mylog('verbose', [' Retrieving Internet IP:']) - internet_IP = get_internet_IP(DIG_GET_IP_ARG) + internet_IP = get_internet_IP(conf.DIG_GET_IP_ARG) # TESTING - Force IP # internet_IP = "1.2.3.4" @@ -52,7 +52,7 @@ def check_internet_IP (db, DIG_GET_IP_ARG): mylog('verbose', [' No changes to perform']) # Get Dynamic DNS IP - if DDNS_ACTIVE : + if conf.DDNS_ACTIVE : mylog('verbose', [' Retrieving Dynamic DNS IP']) dns_IP = get_dynamic_DNS_IP() @@ -157,7 +157,7 @@ def get_dynamic_DNS_IP (): # dig_args = ['dig', '+short', DDNS_DOMAIN, '@resolver1.opendns.com'] # Using default DNS server - dig_args = ['dig', '+short', DDNS_DOMAIN] + dig_args = ['dig', '+short', conf.DDNS_DOMAIN] try: # try runnning a subprocess @@ -182,10 +182,10 @@ def set_dynamic_DNS_IP (): # try runnning a subprocess # Update Dynamic IP curl_output = subprocess.check_output (['curl', '-s', - DDNS_UPDATE_URL + - 'username=' + DDNS_USER + - '&password=' + DDNS_PASSWORD + - '&hostname=' + DDNS_DOMAIN], + conf.DDNS_UPDATE_URL + + 'username=' + conf.DDNS_USER + + '&password=' + conf.DDNS_PASSWORD + + '&hostname=' + conf.DDNS_DOMAIN], universal_newlines=True) except subprocess.CalledProcessError as e: # An error occured, handle it diff --git a/pialert/mqtt.py b/pialert/mqtt.py index 0d47e142..8843b1d5 100644 --- a/pialert/mqtt.py +++ b/pialert/mqtt.py @@ -3,8 +3,8 @@ import time import re from paho.mqtt import client as mqtt_client +import conf from logger import mylog -from conf import MQTT_BROKER, MQTT_DELAY_SEC, MQTT_PASSWORD, MQTT_PORT, MQTT_QOS, MQTT_USER from database import get_all_devices, get_device_stats from helper import bytes_to_string, sanitize_string @@ -35,7 +35,7 @@ def publish_mqtt(client, topic, message): result = client.publish( topic=topic, payload=message, - qos=MQTT_QOS, + qos=conf.MQTT_QOS, retain=True, ) @@ -106,7 +106,7 @@ def publish_sensor(client, sensorConf): # add the sensor to the global list to keep track of succesfully added sensors if publish_mqtt(client, topic, message): # hack - delay adding to the queue in case the process is - time.sleep(MQTT_DELAY_SEC) # restarted and previous publish processes aborted + time.sleep(conf.MQTT_DELAY_SEC) # restarted and previous publish processes aborted # (it takes ~2s to update a sensor config on the broker) mqtt_sensors.append(sensorConf) @@ -131,10 +131,10 @@ def mqtt_create_client(): client = mqtt_client.Client('PiAlert') # Set Connecting Client ID - client.username_pw_set(MQTT_USER, MQTT_PASSWORD) + client.username_pw_set(conf.MQTT_USER, conf.MQTT_PASSWORD) client.on_connect = on_connect client.on_disconnect = on_disconnect - client.connect(MQTT_BROKER, MQTT_PORT) + client.connect(conf.MQTT_BROKER, conf.MQTT_PORT) client.loop_start() return client @@ -177,7 +177,7 @@ def mqtt_start(): # Get all devices devices = get_all_devices() - sec_delay = len(devices) * int(MQTT_DELAY_SEC)*5 + sec_delay = len(devices) * int(conf.MQTT_DELAY_SEC)*5 mylog('info', [" Estimated delay: ", (sec_delay), 's ', '(', round(sec_delay/60,1) , 'min)' ]) diff --git a/pialert/networkscan.py b/pialert/networkscan.py index 63a81481..3471bdb4 100644 --- a/pialert/networkscan.py +++ b/pialert/networkscan.py @@ -1,7 +1,6 @@ - -from conf import DHCP_ACTIVE, PIHOLE_ACTIVE, cycle, ENABLE_ARPSCAN +import conf from arpscan import execute_arpscan from database import insertOnlineHistory from device import create_new_devices, print_scan_stats, save_scanned_devices, update_devices_data_from_scan, update_devices_names @@ -27,10 +26,10 @@ def scan_network (db): mylog('verbose', ['[', timeNow(), '] Scan Devices:' ]) # Query ScanCycle properties - scanCycle_data = query_ScanCycle_Data (True) + scanCycle_data = query_ScanCycle_Data (db, True) if scanCycle_data is None: mylog('none', ['\n*************** ERROR ***************']) - mylog('none', ['ScanCycle %s not found' % cycle ]) + mylog('none', ['ScanCycle %s not found' % conf.cycle ]) mylog('none', [' Exiting...\n']) return False @@ -41,45 +40,45 @@ def scan_network (db): # arp-scan command arpscan_devices = [] - if ENABLE_ARPSCAN: + if conf.ENABLE_ARPSCAN: mylog('verbose', [' arp-scan start']) - arpscan_devices = execute_arpscan () + arpscan_devices = execute_arpscan (conf.userSubnets) print_log ('arp-scan ends') # Pi-hole method - if PIHOLE_ACTIVE : + if conf.PIHOLE_ACTIVE : mylog('verbose', [' Pi-hole start']) copy_pihole_network(db) db.commitDB() # DHCP Leases method - if DHCP_ACTIVE : + if conf.DHCP_ACTIVE : mylog('verbose', [' DHCP Leases start']) read_DHCP_leases (db) db.commitDB() # Load current scan data mylog('verbose', [' Processing scan results']) - save_scanned_devices (arpscan_devices, cycle_interval) + save_scanned_devices (db, arpscan_devices, cycle_interval) # Print stats - print_log ('Print Stats') - print_scan_stats() - print_log ('Stats end') + mylog ('none', 'Print Stats') + print_scan_stats(db) + mylog ('none', 'Stats end') # Create Events mylog('verbose', [' Updating DB Info']) mylog('verbose', [' Sessions Events (connect / discconnect)']) - insert_events() + insert_events(db) # Create New Devices # after create events -> avoid 'connection' event mylog('verbose', [' Creating new devices']) - create_new_devices () + create_new_devices (db) # Update devices info mylog('verbose', [' Updating Devices Info']) - update_devices_data_from_scan () + update_devices_data_from_scan (db) # Resolve devices names print_log (' Resolve devices names') @@ -99,7 +98,7 @@ def scan_network (db): # Sessions snapshot mylog('verbose', [' Inserting scan results into Online_History']) - insertOnlineHistory(db,cycle) + insertOnlineHistory(db,conf.cycle) # Skip repeated notifications mylog('verbose', [' Skipping repeated notifications']) @@ -150,7 +149,7 @@ def void_ghost_disconnections (db): AND eve_DateTime >= DATETIME (?, '-' || cic_EveryXmin ||' minutes') ) """, - (startTime, cycle, startTime) ) + (startTime, conf.cycle, startTime) ) # Void connect paired events print_log ('Void - 2 Paired events') @@ -168,7 +167,7 @@ def void_ghost_disconnections (db): AND eve_DateTime >= DATETIME (?, '-' || cic_EveryXmin ||' minutes') ) """, - (cycle, startTime) ) + (conf.cycle, startTime) ) # Void disconnect ghost events print_log ('Void - 3 Disconnect ghost events') @@ -187,7 +186,7 @@ def void_ghost_disconnections (db): AND eve_DateTime >= DATETIME (?, '-' || cic_EveryXmin ||' minutes') ) """, - (cycle, startTime) ) + (conf.cycle, startTime) ) print_log ('Void end') db.commitDB() @@ -267,7 +266,7 @@ def insert_events (db): AND NOT EXISTS (SELECT 1 FROM CurrentScan WHERE dev_MAC = cur_MAC AND dev_ScanCycle = cur_ScanCycle) """, - (startTime, cycle) ) + (startTime, conf.cycle) ) # Check new connections print_log ('Events 2 - New Connections') @@ -279,7 +278,7 @@ def insert_events (db): WHERE dev_MAC = cur_MAC AND dev_ScanCycle = cur_ScanCycle AND dev_PresentLastScan = 0 AND dev_ScanCycle = ? """, - (startTime, cycle) ) + (startTime, conf.cycle) ) # Check disconnections print_log ('Events 3 - Disconnections') @@ -295,7 +294,7 @@ def insert_events (db): AND NOT EXISTS (SELECT 1 FROM CurrentScan WHERE dev_MAC = cur_MAC AND dev_ScanCycle = cur_ScanCycle) """, - (startTime, cycle) ) + (startTime, conf.cycle) ) # Check IP Changed print_log ('Events 4 - IP Changes') @@ -308,7 +307,7 @@ def insert_events (db): WHERE dev_MAC = cur_MAC AND dev_ScanCycle = cur_ScanCycle AND dev_ScanCycle = ? AND dev_LastIP <> cur_IP """, - (startTime, cycle) ) + (startTime, conf.cycle) ) print_log ('Events end') diff --git a/pialert/nmapscan.py b/pialert/nmapscan.py index e5f0e1d2..38a55105 100644 --- a/pialert/nmapscan.py +++ b/pialert/nmapscan.py @@ -1,8 +1,8 @@ import subprocess +import conf from const import logPath -from conf import NMAP_ARGS, NMAP_TIMEOUT from database import sql_nmap_scan_all from helper import json_struc, timeNow, updateState from logger import append_line_to_file, mylog @@ -33,7 +33,7 @@ def performNmapScan(db, devicesToScan): if len(devicesToScan) > 0: - timeoutSec = NMAP_TIMEOUT + timeoutSec = conf.NMAP_TIMEOUT devTotal = len(devicesToScan) @@ -48,7 +48,7 @@ def performNmapScan(db, devicesToScan): # Execute command output = "" # prepare arguments from user supplied ones - nmapArgs = ['nmap'] + NMAP_ARGS.split() + [device["dev_LastIP"]] + nmapArgs = ['nmap'] + conf.NMAP_ARGS.split() + [device["dev_LastIP"]] progress = ' (' + str(devIndex+1) + '/' + str(devTotal) + ')' diff --git a/pialert/pialert.py b/pialert/pialert.py index ae75f53a..141801dd 100755 --- a/pialert/pialert.py +++ b/pialert/pialert.py @@ -42,10 +42,10 @@ import multiprocessing # pialert modules +import conf from const import * -from conf import * from logger import mylog -from helper import filePermissions, timeNow, updateState +from helper import filePermissions, isNewVersion, timeNow, updateState from api import update_api from files import get_file_content from networkscan import scan_network @@ -62,10 +62,6 @@ from internet import check_internet_IP # Global variables - - - -userSubnets = [] changedPorts_json_struc = None time_started = datetime.datetime.now() cron_instance = Cron() @@ -83,7 +79,7 @@ sql_connection = None #=============================================================================== cycle = "" check_report = [1, "internet_IP", "update_vendors_silent"] -plugins_once_run = False +conf.plugins_once_run = False # timestamps of last execution times startTime = time_started @@ -103,9 +99,7 @@ def main (): global time_started, cycle, last_network_scan, last_internet_IP_scan, last_run, last_cleanup, last_update_vendors # second set of global variables global startTime, log_timestamp, plugins_once_run - - # To-Do all these DB Globals need to be removed - global db, sql, sql_connection + # check file permissions and fix if required filePermissions() @@ -116,7 +110,7 @@ def main (): db.openDB() # To-Do replace the following to lines with the db class - sql_connection = db.sql_connection + # sql_connection = db.sql_connection sql = db.sql # Upgrade DB if needed @@ -134,10 +128,15 @@ def main (): mylog('debug', ['[', timeNow(), '] [MAIN] Stating loop']) # re-load user configuration and plugins + mylog('debug', "tz before config : " + str(conf.tz)) importConfigs(db) - + mylog('debug', "tz after config : " + str(conf.tz)) + + # check if new version is available + conf.newVersionAvailable = isNewVersion(False) + # Handle plugins executed ONCE - if ENABLE_PLUGINS and plugins_once_run == False: + if conf.ENABLE_PLUGINS and conf.plugins_once_run == False: run_plugin_scripts(db, 'once') plugins_once_run = True @@ -161,7 +160,7 @@ def main (): startTime = startTime.replace (microsecond=0) # Check if any plugins need to run on schedule - if ENABLE_PLUGINS: + if conf.ENABLE_PLUGINS: run_plugin_scripts(db,'schedule') # determine run/scan type based on passed time @@ -171,7 +170,7 @@ def main (): if last_internet_IP_scan + datetime.timedelta(minutes=3) < time_started: cycle = 'internet_IP' last_internet_IP_scan = time_started - check_internet_IP(db,DIG_GET_IP_ARG) + check_internet_IP(db) # Update vendors once a week if last_update_vendors + datetime.timedelta(days = 7) < time_started: @@ -181,43 +180,48 @@ def main (): update_devices_MAC_vendors() # Execute scheduled or one-off Pholus scan if enabled and run conditions fulfilled - if PHOLUS_RUN == "schedule" or PHOLUS_RUN == "once": + if conf.PHOLUS_RUN == "schedule" or conf.PHOLUS_RUN == "once": - pholusSchedule = [sch for sch in mySchedules if sch.service == "pholus"][0] + mylog('debug', "PHOLUS_RUN_SCHD: " + conf.PHOLUS_RUN_SCHD) + mylog('debug', "schedules : " + str(conf.mySchedules)) + + pholusSchedule = [sch for sch in conf.mySchedules if sch.service == "pholus"][0] run = False # run once after application starts - if PHOLUS_RUN == "once" and pholusSchedule.last_run == 0: + + + if conf.PHOLUS_RUN == "once" and pholusSchedule.last_run == 0: run = True # run if overdue scheduled time - if PHOLUS_RUN == "schedule": + if conf.PHOLUS_RUN == "schedule": run = pholusSchedule.runScheduleCheck() if run: - pholusSchedule.last_run = datetime.datetime.now(tz).replace(microsecond=0) - performPholusScan(db, PHOLUS_RUN_TIMEOUT, userSubnets) + pholusSchedule.last_run = datetime.datetime.now(conf.tz).replace(microsecond=0) + performPholusScan(db, conf.PHOLUS_RUN_TIMEOUT, conf.userSubnets) # Execute scheduled or one-off Nmap scan if enabled and run conditions fulfilled - if NMAP_RUN == "schedule" or NMAP_RUN == "once": + if conf.NMAP_RUN == "schedule" or conf.NMAP_RUN == "once": - nmapSchedule = [sch for sch in mySchedules if sch.service == "nmap"][0] + nmapSchedule = [sch for sch in conf.mySchedules if sch.service == "nmap"][0] run = False # run once after application starts - if NMAP_RUN == "once" and nmapSchedule.last_run == 0: + if conf.NMAP_RUN == "once" and conf.nmapSchedule.last_run == 0: run = True # run if overdue scheduled time - if NMAP_RUN == "schedule": + if conf.NMAP_RUN == "schedule": run = nmapSchedule.runScheduleCheck() if run: - nmapSchedule.last_run = datetime.datetime.now(tz).replace(microsecond=0) + conf.nmapSchedule.last_run = datetime.datetime.now(conf.tz).replace(microsecond=0) performNmapScan(db, get_all_devices(db)) # Perform a network scan via arp-scan or pihole - if last_network_scan + datetime.timedelta(minutes=SCAN_CYCLE_MINUTES) < time_started: + if last_network_scan + datetime.timedelta(minutes=conf.SCAN_CYCLE_MINUTES) < time_started: last_network_scan = time_started cycle = 1 # network scan mylog('verbose', ['[', timeNow(), '] cycle:',cycle]) @@ -248,7 +252,7 @@ def main (): # DEBUG end ++++++++++++++++++++++++++++++++++++++++++++++++++++++ # Run splugin scripts which are set to run every timne after a scan finished - if ENABLE_PLUGINS: + if conf.ENABLE_PLUGINS: run_plugin_scripts(db,'always_after_scan') @@ -262,11 +266,11 @@ def main (): # new devices were found if len(newDevices) > 0: # run all plugins registered to be run when new devices are found - if ENABLE_PLUGINS: + if conf.ENABLE_PLUGINS: run_plugin_scripts(db, 'on_new_device') # Scan newly found devices with Nmap if enabled - if NMAP_ACTIVE and len(newDevices) > 0: + if conf.NMAP_ACTIVE and len(newDevices) > 0: performNmapScan( db, newDevices) # send all configured notifications @@ -277,7 +281,7 @@ def main (): last_cleanup = time_started cycle = 'cleanup' mylog('verbose', ['[', timeNow(), '] cycle:',cycle]) - db.cleanup_database(startTime, DAYS_TO_KEEP_EVENTS, PHOLUS_DAYS_DATA) + db.cleanup_database(startTime, conf.DAYS_TO_KEEP_EVENTS, conf.PHOLUS_DAYS_DATA) # Commit SQL db.commitDB() @@ -314,6 +318,7 @@ def main (): #------------------------------------------------------------------------------- def check_and_run_event(db): + sql = db.sql # TO-DO sql.execute(""" select * from Parameters where par_ID = "Front_Event" """) rows = sql.fetchall() diff --git a/pialert/pihole.py b/pialert/pihole.py index d13a1c04..b85efd28 100644 --- a/pialert/pihole.py +++ b/pialert/pihole.py @@ -1,3 +1,5 @@ +""" module to import db and leases from PiHole """ + from const import piholeDB, piholeDhcpleases #------------------------------------------------------------------------------- diff --git a/pialert/plugin.py b/pialert/plugin.py index f2ce9569..a9c685ee 100644 --- a/pialert/plugin.py +++ b/pialert/plugin.py @@ -5,11 +5,11 @@ import datetime from collections import namedtuple # pialert modules +import conf from const import pluginsPath, logPath -from conf import mySettings, plugins from files import get_file_content, write_file from logger import mylog -from helper import updateState +from helper import timeNowTZ, updateState @@ -23,14 +23,14 @@ def timeNow(): #------------------------------------------------------------------------------- def run_plugin_scripts(db, runType): - global plugins, tz, mySchedules + # global plugins, tz, mySchedules # Header updateState(db,"Run: Plugins") mylog('debug', [' [Plugins] Check if any plugins need to be executed on run type: ', runType]) - for plugin in plugins: + for plugin in conf.plugins: shouldRun = False @@ -43,13 +43,13 @@ def run_plugin_scripts(db, runType): prefix = plugin["unique_prefix"] # check scheduels if any contains a unique plugin prefix matching the current plugin - for schd in mySchedules: + for schd in conf.mySchedules: if schd.service == prefix: # Check if schedule overdue shouldRun = schd.runScheduleCheck() if shouldRun: # note the last time the scheduled plugin run was executed - schd.last_run = datetime.datetime.now(tz).replace(microsecond=0) + schd.last_run = timeNowTZ() if shouldRun: @@ -107,14 +107,14 @@ def get_plugin_setting(plugin, function_key): def get_setting(key): result = None # index order: key, name, desc, inputtype, options, regex, result, group, events - for set in mySettings: + for set in conf.mySettings: if set[0] == key: result = set if result is None: mylog('info', [' Error - setting_missing - Setting not found for key: ', key]) mylog('info', [' Error - logging the settings into file: ', logPath + '/setting_missing.json']) - write_file (logPath + '/setting_missing.json', json.dumps({ 'data' : mySettings})) + write_file (logPath + '/setting_missing.json', json.dumps({ 'data' : conf.mySettings})) return result diff --git a/pialert/reporting.py b/pialert/reporting.py index 0100fc62..3df6fa18 100644 --- a/pialert/reporting.py +++ b/pialert/reporting.py @@ -10,9 +10,9 @@ import subprocess import requests from json2table import convert +# pialert modules +import conf from const import pialertPath, logPath -# from pialert.api import update_api -from conf import * from database import get_table_as_json from files import write_file from helper import generate_mac_links, isNewVersion, removeDuplicateNewLines, timeNow, hide_email, json_struc, updateState @@ -39,7 +39,7 @@ class noti_struc: #------------------------------------------------------------------------------- -def construct_notifications(sqlQuery, tableTitle, skipText = False, suppliedJsonStruct = None): +def construct_notifications(db, sqlQuery, tableTitle, skipText = False, suppliedJsonStruct = None): if suppliedJsonStruct is None and sqlQuery == "": return noti_struc("", "", "") @@ -52,7 +52,7 @@ def construct_notifications(sqlQuery, tableTitle, skipText = False, suppliedJson text_line = '{}\t{}\n' if suppliedJsonStruct is None: - json_struc = get_table_as_json(sqlQuery) + json_struc = get_table_as_json(db, sqlQuery) else: json_struc = suppliedJsonStruct @@ -92,7 +92,7 @@ def send_notifications (db): sql = db.sql #TO-DO global mail_text, mail_html, json_final, changedPorts_json_struc, partial_html, partial_txt, partial_json - deviceUrl = REPORT_DASHBOARD_URL + '/deviceDetails.php?mac=' + deviceUrl = conf.REPORT_DASHBOARD_URL + '/deviceDetails.php?mac=' plugins_report = False # Reporting section @@ -125,7 +125,7 @@ def send_notifications (db): # Open html Template template_file = open(pialertPath + '/back/report_template.html', 'r') - if isNewVersion(db): + if conf.newVersionAvailable : template_file = open(pialertPath + '/back/report_template_new_version.html', 'r') mail_html = template_file.read() @@ -139,13 +139,13 @@ def send_notifications (db): mail_text = mail_text.replace ('', socket.gethostname() ) mail_html = mail_html.replace ('', socket.gethostname() ) - if 'internet' in INCLUDED_SECTIONS: + if 'internet' in conf.INCLUDED_SECTIONS: # Compose Internet Section sqlQuery = """SELECT eve_MAC as MAC, eve_IP as IP, eve_DateTime as Datetime, eve_EventType as "Event Type", eve_AdditionalInfo as "More info" FROM Events WHERE eve_PendingAlertEmail = 1 AND eve_MAC = 'Internet' ORDER BY eve_DateTime""" - notiStruc = construct_notifications(sqlQuery, "Internet IP change") + notiStruc = construct_notifications(db, sqlQuery, "Internet IP change") # collect "internet" (IP changes) for the webhook json json_internet = notiStruc.json["data"] @@ -153,14 +153,14 @@ def send_notifications (db): mail_text = mail_text.replace ('', notiStruc.text + '\n') mail_html = mail_html.replace ('', notiStruc.html) - if 'new_devices' in INCLUDED_SECTIONS: + if 'new_devices' in conf.INCLUDED_SECTIONS: # Compose New Devices Section sqlQuery = """SELECT eve_MAC as MAC, eve_DateTime as Datetime, dev_LastIP as IP, eve_EventType as "Event Type", dev_Name as "Device name", dev_Comments as Comments FROM Events_Devices WHERE eve_PendingAlertEmail = 1 AND eve_EventType = 'New Device' ORDER BY eve_DateTime""" - notiStruc = construct_notifications(sqlQuery, "New devices") + notiStruc = construct_notifications(db, sqlQuery, "New devices") # collect "new_devices" for the webhook json json_new_devices = notiStruc.json["data"] @@ -168,14 +168,14 @@ def send_notifications (db): mail_text = mail_text.replace ('', notiStruc.text + '\n') mail_html = mail_html.replace ('', notiStruc.html) - if 'down_devices' in INCLUDED_SECTIONS: + if 'down_devices' in conf.INCLUDED_SECTIONS: # Compose Devices Down Section sqlQuery = """SELECT eve_MAC as MAC, eve_DateTime as Datetime, dev_LastIP as IP, eve_EventType as "Event Type", dev_Name as "Device name", dev_Comments as Comments FROM Events_Devices WHERE eve_PendingAlertEmail = 1 AND eve_EventType = 'Device Down' ORDER BY eve_DateTime""" - notiStruc = construct_notifications(sqlQuery, "Down devices") + notiStruc = construct_notifications(db, sqlQuery, "Down devices") # collect "new_devices" for the webhook json json_down_devices = notiStruc.json["data"] @@ -183,7 +183,7 @@ def send_notifications (db): mail_text = mail_text.replace ('', notiStruc.text + '\n') mail_html = mail_html.replace ('', notiStruc.html) - if 'events' in INCLUDED_SECTIONS: + if 'events' in conf.INCLUDED_SECTIONS: # Compose Events Section sqlQuery = """SELECT eve_MAC as MAC, eve_DateTime as Datetime, dev_LastIP as IP, eve_EventType as "Event Type", dev_Name as "Device name", dev_Comments as Comments FROM Events_Devices WHERE eve_PendingAlertEmail = 1 @@ -191,7 +191,7 @@ def send_notifications (db): 'IP Changed') ORDER BY eve_DateTime""" - notiStruc = construct_notifications(sqlQuery, "Events") + notiStruc = construct_notifications(db, sqlQuery, "Events") # collect "events" for the webhook json json_events = notiStruc.json["data"] @@ -199,12 +199,12 @@ def send_notifications (db): mail_text = mail_text.replace ('', notiStruc.text + '\n') mail_html = mail_html.replace ('', notiStruc.html) - if 'ports' in INCLUDED_SECTIONS: + if 'ports' in conf.INCLUDED_SECTIONS: # collect "ports" for the webhook json if changedPorts_json_struc is not None: json_ports = changedPorts_json_struc.json["data"] - notiStruc = construct_notifications("", "Ports", True, changedPorts_json_struc) + notiStruc = construct_notifications(db, "", "Ports", True, changedPorts_json_struc) mail_html = mail_html.replace ('', notiStruc.html) @@ -214,11 +214,11 @@ def send_notifications (db): mail_text = mail_text.replace ('', portsTxt ) - if 'plugins' in INCLUDED_SECTIONS and ENABLE_PLUGINS: + if 'plugins' in conf.INCLUDED_SECTIONS and conf.ENABLE_PLUGINS: # Compose Plugins Section sqlQuery = """SELECT Plugin, Object_PrimaryId, Object_SecondaryId, DateTimeChanged, Watched_Value1, Watched_Value2, Watched_Value3, Watched_Value4, Status from Plugins_Events""" - notiStruc = construct_notifications(sqlQuery, "Plugins") + notiStruc = construct_notifications(db, sqlQuery, "Plugins") # collect "plugins" for the webhook json json_plugins = notiStruc.json["data"] @@ -250,44 +250,44 @@ def send_notifications (db): write_file (logPath + '/report_output.html', mail_html) # Send Mail - if json_internet != [] or json_new_devices != [] or json_down_devices != [] or json_events != [] or json_ports != [] or debug_force_notification or plugins_report: + if json_internet != [] or json_new_devices != [] or json_down_devices != [] or json_events != [] or json_ports != [] or conf.debug_force_notification or plugins_report: # update_api(True) # TO-DO mylog('none', [' Changes detected, sending reports']) - if REPORT_MAIL and check_config('email'): + if conf.REPORT_MAIL and check_config('email'): updateState(db,"Send: Email") mylog('info', [' Sending report by Email']) send_email (mail_text, mail_html) else : mylog('verbose', [' Skip email']) - if REPORT_APPRISE and check_config('apprise'): + if conf.REPORT_APPRISE and check_config('apprise'): updateState(db,"Send: Apprise") mylog('info', [' Sending report by Apprise']) send_apprise (mail_html, mail_text) else : mylog('verbose', [' Skip Apprise']) - if REPORT_WEBHOOK and check_config('webhook'): + if conf.REPORT_WEBHOOK and check_config('webhook'): updateState(db,"Send: Webhook") mylog('info', [' Sending report by Webhook']) send_webhook (json_final, mail_text) else : mylog('verbose', [' Skip webhook']) - if REPORT_NTFY and check_config('ntfy'): + if conf.REPORT_NTFY and check_config('ntfy'): updateState(db,"Send: NTFY") mylog('info', [' Sending report by NTFY']) send_ntfy (mail_text) else : mylog('verbose', [' Skip NTFY']) - if REPORT_PUSHSAFER and check_config('pushsafer'): + if conf.REPORT_PUSHSAFER and check_config('pushsafer'): updateState(db,"Send: PUSHSAFER") mylog('info', [' Sending report by PUSHSAFER']) send_pushsafer (mail_text) else : mylog('verbose', [' Skip PUSHSAFER']) # Update MQTT entities - if REPORT_MQTT and check_config('mqtt'): + if conf.REPORT_MQTT and check_config('mqtt'): updateState(db,"Send: MQTT") mylog('info', [' Establishing MQTT thread']) mqtt_start() @@ -320,42 +320,42 @@ def send_notifications (db): def check_config(service): if service == 'email': - if SMTP_SERVER == '' or REPORT_FROM == '' or REPORT_TO == '': + if conf.SMTP_SERVER == '' or conf.REPORT_FROM == '' or conf.REPORT_TO == '': mylog('none', [' Error: Email service not set up correctly. Check your pialert.conf SMTP_*, REPORT_FROM and REPORT_TO variables.']) return False else: return True if service == 'apprise': - if APPRISE_URL == '' or APPRISE_HOST == '': + if conf.APPRISE_URL == '' or conf.APPRISE_HOST == '': mylog('none', [' Error: Apprise service not set up correctly. Check your pialert.conf APPRISE_* variables.']) return False else: return True if service == 'webhook': - if WEBHOOK_URL == '': + if conf.WEBHOOK_URL == '': mylog('none', [' Error: Webhook service not set up correctly. Check your pialert.conf WEBHOOK_* variables.']) return False else: return True if service == 'ntfy': - if NTFY_HOST == '' or NTFY_TOPIC == '': + if conf.NTFY_HOST == '' or conf.NTFY_TOPIC == '': mylog('none', [' Error: NTFY service not set up correctly. Check your pialert.conf NTFY_* variables.']) return False else: return True if service == 'pushsafer': - if PUSHSAFER_TOKEN == 'ApiKey': + if conf.PUSHSAFER_TOKEN == 'ApiKey': mylog('none', [' Error: Pushsafer service not set up correctly. Check your pialert.conf PUSHSAFER_TOKEN variable.']) return False else: return True if service == 'mqtt': - if MQTT_BROKER == '' or MQTT_PORT == '' or MQTT_USER == '' or MQTT_PASSWORD == '': + if conf.MQTT_BROKER == '' or conf.MQTT_PORT == '' or conf.MQTT_USER == '' or conf.MQTT_PASSWORD == '': mylog('none', [' Error: MQTT service not set up correctly. Check your pialert.conf MQTT_* variables.']) return False else: @@ -371,19 +371,18 @@ def format_table (html, thValue, props, newThValue = ''): #------------------------------------------------------------------------------- def format_report_section (pActive, pSection, pTable, pText, pHTML): - global mail_text - global mail_html + # Replace section text if pActive : - mail_text = mail_text.replace ('<'+ pTable +'>', pText) - mail_html = mail_html.replace ('<'+ pTable +'>', pHTML) + conf.mail_text = conf.mail_text.replace ('<'+ pTable +'>', pText) + conf.mail_html = conf.mail_html.replace ('<'+ pTable +'>', pHTML) - mail_text = remove_tag (mail_text, pSection) - mail_html = remove_tag (mail_html, pSection) + conf.mail_text = remove_tag (conf.mail_text, pSection) + conf.mail_html = remove_tag (conf.mail_html, pSection) else: - mail_text = remove_section (mail_text, pSection) - mail_html = remove_section (mail_html, pSection) + conf.mail_text = remove_section (conf.mail_text, pSection) + conf.mail_html = remove_section (conf.mail_html, pSection) #------------------------------------------------------------------------------- def remove_section (pText, pSection): @@ -409,14 +408,14 @@ def remove_tag (pText, pTag): def send_email (pText, pHTML): # Print more info for debugging if LOG_LEVEL == 'debug' - if LOG_LEVEL == 'debug': - print_log ('REPORT_TO: ' + hide_email(str(REPORT_TO)) + ' SMTP_USER: ' + hide_email(str(SMTP_USER))) + if conf.LOG_LEVEL == 'debug': + print_log ('REPORT_TO: ' + hide_email(str(conf.REPORT_TO)) + ' SMTP_USER: ' + hide_email(str(conf.SMTP_USER))) # Compose email msg = MIMEMultipart('alternative') msg['Subject'] = 'Pi.Alert Report' - msg['From'] = REPORT_FROM - msg['To'] = REPORT_TO + msg['From'] = conf.REPORT_FROM + msg['To'] = conf.REPORT_TO msg.attach (MIMEText (pText, 'plain')) msg.attach (MIMEText (pHTML, 'html')) @@ -426,46 +425,46 @@ def send_email (pText, pHTML): try: # Send mail - failedAt = print_log('Trying to open connection to ' + str(SMTP_SERVER) + ':' + str(SMTP_PORT)) + failedAt = print_log('Trying to open connection to ' + str(conf.SMTP_SERVER) + ':' + str(conf.SMTP_PORT)) - if SMTP_FORCE_SSL: + if conf.SMTP_FORCE_SSL: failedAt = print_log('SMTP_FORCE_SSL == True so using .SMTP_SSL()') - if SMTP_PORT == 0: + if conf.SMTP_PORT == 0: failedAt = print_log('SMTP_PORT == 0 so sending .SMTP_SSL(SMTP_SERVER)') - smtp_connection = smtplib.SMTP_SSL(SMTP_SERVER) + smtp_connection = smtplib.SMTP_SSL(conf.SMTP_SERVER) else: failedAt = print_log('SMTP_PORT == 0 so sending .SMTP_SSL(SMTP_SERVER, SMTP_PORT)') - smtp_connection = smtplib.SMTP_SSL(SMTP_SERVER, SMTP_PORT) + smtp_connection = smtplib.SMTP_SSL(conf.SMTP_SERVER, conf.SMTP_PORT) else: failedAt = print_log('SMTP_FORCE_SSL == False so using .SMTP()') - if SMTP_PORT == 0: + if conf.SMTP_PORT == 0: failedAt = print_log('SMTP_PORT == 0 so sending .SMTP(SMTP_SERVER)') - smtp_connection = smtplib.SMTP (SMTP_SERVER) + smtp_connection = smtplib.SMTP (conf.SMTP_SERVER) else: failedAt = print_log('SMTP_PORT == 0 so sending .SMTP(SMTP_SERVER, SMTP_PORT)') - smtp_connection = smtplib.SMTP (SMTP_SERVER, SMTP_PORT) + smtp_connection = smtplib.SMTP (conf.SMTP_SERVER, conf.SMTP_PORT) failedAt = print_log('Setting SMTP debug level') # Log level set to debug of the communication between SMTP server and client - if LOG_LEVEL == 'debug': + if conf.LOG_LEVEL == 'debug': smtp_connection.set_debuglevel(1) failedAt = print_log( 'Sending .ehlo()') smtp_connection.ehlo() - if not SMTP_SKIP_TLS: + if not conf.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 SMTP_SKIP_LOGIN: + if not conf.SMTP_SKIP_LOGIN: failedAt = print_log('SMTP_SKIP_LOGIN == False so sending .login()') - smtp_connection.login (SMTP_USER, SMTP_PASS) + smtp_connection.login (conf.SMTP_USER, conf.SMTP_PASS) failedAt = print_log('Sending .sendmail()') - smtp_connection.sendmail (REPORT_FROM, REPORT_TO, msg.as_string()) + smtp_connection.sendmail (conf.REPORT_FROM, conf.REPORT_TO, msg.as_string()) smtp_connection.quit() except smtplib.SMTPAuthenticationError as e: mylog('none', [' ERROR: Failed at - ', failedAt]) @@ -480,20 +479,20 @@ def send_email (pText, pHTML): def send_ntfy (_Text): headers = { "Title": "Pi.Alert Notification", - "Actions": "view, Open Dashboard, "+ REPORT_DASHBOARD_URL, + "Actions": "view, Open Dashboard, "+ conf.REPORT_DASHBOARD_URL, "Priority": "urgent", "Tags": "warning" } # if username and password are set generate hash and update header - if NTFY_USER != "" and NTFY_PASSWORD != "": + if conf.NTFY_USER != "" and conf.NTFY_PASSWORD != "": # Generate hash for basic auth - usernamepassword = "{}:{}".format(NTFY_USER,NTFY_PASSWORD) - basichash = b64encode(bytes(NTFY_USER + ':' + NTFY_PASSWORD, "utf-8")).decode("ascii") + usernamepassword = "{}:{}".format(conf.NTFY_USER,conf.NTFY_PASSWORD) + basichash = b64encode(bytes(conf.NTFY_USER + ':' + conf.NTFY_PASSWORD, "utf-8")).decode("ascii") # add authorization header with hash headers["Authorization"] = "Basic {}".format(basichash) - requests.post("{}/{}".format( NTFY_HOST, NTFY_TOPIC), + requests.post("{}/{}".format( conf.NTFY_HOST, conf.NTFY_TOPIC), data=_Text, headers=headers) @@ -507,9 +506,9 @@ def send_pushsafer (_Text): "i" : 148, "c" : '#ef7f7f', "d" : 'a', - "u" : REPORT_DASHBOARD_URL, + "u" : conf.REPORT_DASHBOARD_URL, "ut" : 'Open Pi.Alert', - "k" : PUSHSAFER_TOKEN, + "k" : conf.PUSHSAFER_TOKEN, } requests.post(url, data=post_fields) @@ -517,20 +516,20 @@ def send_pushsafer (_Text): def send_webhook (_json, _html): # use data type based on specified payload type - if WEBHOOK_PAYLOAD == 'json': + if conf.WEBHOOK_PAYLOAD == 'json': payloadData = _json - if WEBHOOK_PAYLOAD == 'html': + if conf.WEBHOOK_PAYLOAD == 'html': payloadData = _html - if WEBHOOK_PAYLOAD == 'text': + if conf.WEBHOOK_PAYLOAD == 'text': payloadData = to_text(_json) # Define slack-compatible payload - _json_payload = { "text": payloadData } if WEBHOOK_PAYLOAD == 'text' else { + _json_payload = { "text": payloadData } if conf.WEBHOOK_PAYLOAD == 'text' else { "username": "Pi.Alert", "text": "There are new notifications", "attachments": [{ "title": "Pi.Alert Notifications", - "title_link": REPORT_DASHBOARD_URL, + "title_link": conf.REPORT_DASHBOARD_URL, "text": payloadData }] } @@ -539,12 +538,12 @@ def send_webhook (_json, _html): 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 - if(WEBHOOK_URL.startswith('https://discord.com/api/webhooks/') and not WEBHOOK_URL.endswith("/slack")): - _WEBHOOK_URL = f"{WEBHOOK_URL}/slack" + 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] else: - _WEBHOOK_URL = WEBHOOK_URL - curlParams = ["curl","-i","-X", WEBHOOK_REQUEST_METHOD ,"-H", "Content-Type:application/json" ,"-d", json.dumps(_json_payload), _WEBHOOK_URL] + _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: @@ -565,19 +564,19 @@ def send_apprise (html, text): #Define Apprise compatible payload (https://github.com/caronc/apprise-api#stateless-solution) payload = html - if APPRISE_PAYLOAD == 'text': + if conf.APPRISE_PAYLOAD == 'text': payload = text _json_payload={ - "urls": APPRISE_URL, + "urls": conf.APPRISE_URL, "title": "Pi.Alert Notifications", - "format": APPRISE_PAYLOAD, + "format": conf.APPRISE_PAYLOAD, "body": payload } try: # try runnning a subprocess - p = subprocess.Popen(["curl","-i","-X", "POST" ,"-H", "Content-Type:application/json" ,"-d", json.dumps(_json_payload), APPRISE_HOST], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + p = subprocess.Popen(["curl","-i","-X", "POST" ,"-H", "Content-Type:application/json" ,"-d", json.dumps(_json_payload), conf.APPRISE_HOST], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) stdout, stderr = p.communicate() # write stdout and stderr into .log files for debugging if needed logResult (stdout, stderr) # TO-DO should be changed to mylog @@ -588,19 +587,19 @@ def send_apprise (html, text): def to_text(_json): payloadData = "" - if len(_json['internet']) > 0 and 'internet' in INCLUDED_SECTIONS: + 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 INCLUDED_SECTIONS: + 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 INCLUDED_SECTIONS: + 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']: @@ -608,7 +607,7 @@ def to_text(_json): event[4] = event[11] payloadData += event[1] + ' - ' + event[4] + '\n' - if len(_json['events']) > 0 and 'events' in INCLUDED_SECTIONS: + if len(_json['events']) > 0 and 'events' in conf.INCLUDED_SECTIONS: payloadData += "EVENTS:\n" for event in _json['events']: if event[8] != "Internet": diff --git a/pialert/scheduler.py b/pialert/scheduler.py new file mode 100644 index 00000000..b0cbc2ca --- /dev/null +++ b/pialert/scheduler.py @@ -0,0 +1,41 @@ +""" class to manage schedules """ +import datetime + +from logger import print_log +import conf + +#------------------------------------------------------------------------------- +class schedule_class: + def __init__(self, service, scheduleObject, last_next_schedule, was_last_schedule_used, last_run = 0): + self.service = service + self.scheduleObject = scheduleObject + self.last_next_schedule = last_next_schedule + self.last_run = last_run + self.was_last_schedule_used = was_last_schedule_used + + def runScheduleCheck(self): + + result = False + + # Initialize the last run time if never run before + if self.last_run == 0: + self.last_run = (datetime.datetime.now(conf.tz) - datetime.timedelta(days=365)).replace(microsecond=0) + + # get the current time with the currently specified timezone + nowTime = datetime.datetime.now(conf.tz).replace(microsecond=0) + + # Run the schedule if the current time is past the schedule time we saved last time and + # (maybe the following check is unnecessary:) + # if the last run is past the last time we run a scheduled Pholus scan + if nowTime > self.last_next_schedule and self.last_run < self.last_next_schedule: + print_log(f'Scheduler run for {self.service}: YES') + self.was_last_schedule_used = True + result = True + else: + print_log(f'Scheduler run for {self.service}: NO') + + if self.was_last_schedule_used: + self.was_last_schedule_used = False + self.last_next_schedule = self.scheduleObject.next() + + return result