internet_ip plugin

This commit is contained in:
Jokob-sk
2023-09-19 07:48:53 +10:00
parent 1395dd9fb5
commit add9800f42
14 changed files with 758 additions and 329 deletions

View File

@@ -98,8 +98,7 @@ def main ():
conf.loop_start_time = timeNowTZ()
# TODO fix these
loop_start_time = conf.loop_start_time # TODO fix
last_update_vendors = conf.last_update_vendors
loop_start_time = conf.loop_start_time # TODO fix
last_version_check = conf.last_version_check
# check if new version is available / only check once an hour

View File

@@ -6,7 +6,6 @@
# These are global variables, not config items and should not exist !
mySettings = []
mySettingsSQLsafe = []
debug_force_notification = False
cycle = 1
userSubnets = []
mySchedules = [] # bad solution for global - TO-DO
@@ -23,7 +22,6 @@ time_started = ''
startTime = ''
last_internet_IP_scan = ''
last_scan_run = ''
last_update_vendors = ''
last_version_check = ''
arpscan_devices = []
@@ -31,75 +29,83 @@ arpscan_devices = []
mqtt_connected_to_broker = False
mqtt_sensors = []
client = None # mqtt client
# for notifications
# ACTUAL CONFIGRATION ITEMS set to defaults
# -------------------------------------------
# General
SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth1', '192.168.1.0/24 --interface=eth0']
LOG_LEVEL = 'verbose'
TIMEZONE = 'Europe/Berlin'
PIALERT_WEB_PROTECTION = False
PIALERT_WEB_PASSWORD = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'
INCLUDED_SECTIONS = ['internet', 'new_devices', 'down_devices', 'events']
DAYS_TO_KEEP_EVENTS = 90
REPORT_DASHBOARD_URL = 'http://pi.alert/'
DIG_GET_IP_ARG = '-4 myip.opendns.com @resolver1.opendns.com'
UI_LANG = 'English'
UI_PRESENCE = ['online', 'offline', 'archived']
# -------------------------------------------
SCAN_SUBNETS = ['192.168.1.0/24 --interface=eth1', '192.168.1.0/24 --interface=eth0']
LOG_LEVEL = 'verbose'
TIMEZONE = 'Europe/Berlin'
DIG_GET_IP_ARG = '-4 myip.opendns.com @resolver1.opendns.com'
UI_LANG = 'English'
UI_PRESENCE = ['online', 'offline', 'archived']
PIALERT_WEB_PROTECTION = False
PIALERT_WEB_PASSWORD = '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'
INCLUDED_SECTIONS = ['internet', 'new_devices', 'down_devices', 'events']
DAYS_TO_KEEP_EVENTS = 90
REPORT_DASHBOARD_URL = 'http://pi.alert/'
# -------------------------------------------
# Notification gateways
# -------------------------------------------
# Email
REPORT_MAIL = False
SMTP_SERVER = ''
SMTP_PORT = 587
REPORT_TO = 'user@gmail.com'
REPORT_FROM = 'Pi.Alert <user@gmail.com>'
SMTP_SKIP_LOGIN = False
SMTP_USER = ''
SMTP_PASS = ''
SMTP_SKIP_TLS = False
SMTP_FORCE_SSL = False
REPORT_MAIL = False
SMTP_SERVER = ''
SMTP_PORT = 587
REPORT_TO = 'user@gmail.com'
REPORT_FROM = 'Pi.Alert <user@gmail.com>'
SMTP_SKIP_LOGIN = False
SMTP_USER = ''
SMTP_PASS = ''
SMTP_SKIP_TLS = False
SMTP_FORCE_SSL = False
# Webhooks
REPORT_WEBHOOK = False
WEBHOOK_URL = ''
REPORT_WEBHOOK = False
WEBHOOK_URL = ''
WEBHOOK_PAYLOAD = 'json'
WEBHOOK_REQUEST_METHOD = 'GET'
# Apprise
REPORT_APPRISE = False
APPRISE_HOST = ''
APPRISE_URL = ''
REPORT_APPRISE = False
APPRISE_HOST = ''
APPRISE_URL = ''
APPRISE_PAYLOAD = 'html'
# NTFY
REPORT_NTFY = False
NTFY_HOST ='https://ntfy.sh'
NTFY_TOPIC =''
NTFY_USER = ''
NTFY_PASSWORD = ''
REPORT_NTFY = False
NTFY_HOST = 'https://ntfy.sh'
NTFY_TOPIC = ''
NTFY_USER = ''
NTFY_PASSWORD = ''
# PUSHSAFER
REPORT_PUSHSAFER = False
PUSHSAFER_TOKEN = 'ApiKey'
REPORT_PUSHSAFER = False
PUSHSAFER_TOKEN = 'ApiKey'
# MQTT
REPORT_MQTT = False
MQTT_BROKER = ''
MQTT_PORT = 1883
MQTT_USER = ''
MQTT_PASSWORD = ''
MQTT_QOS = 0
MQTT_DELAY_SEC = 2
REPORT_MQTT = False
MQTT_BROKER = ''
MQTT_PORT = 1883
MQTT_USER = ''
MQTT_PASSWORD = ''
MQTT_QOS = 0
MQTT_DELAY_SEC = 2
# DynDNS
DDNS_ACTIVE = False
DDNS_DOMAIN = 'your_domain.freeddns.org'
DDNS_USER = 'dynu_user'
DDNS_PASSWORD = 'A0000000B0000000C0000000D0000000'
DDNS_UPDATE_URL = 'https://api.dynu.com/nic/update?'
# -------------------------------------------
# Misc
# -------------------------------------------
# API
API_CUSTOM_SQL = 'SELECT * FROM Devices WHERE dev_PresentLastScan = 0'
API_CUSTOM_SQL = 'SELECT * FROM Devices WHERE dev_PresentLastScan = 0'
# DynDNS
DDNS_ACTIVE = False
DDNS_DOMAIN = 'your_domain.freeddns.org'
DDNS_USER = 'dynu_user'
DDNS_PASSWORD = 'A0000000B0000000C0000000D0000000'
DDNS_UPDATE_URL = 'https://api.dynu.com/nic/update?'

View File

@@ -4,10 +4,9 @@
# PATHS
#===============================================================================
pialertPath = '/home/pi/pialert'
#pialertPath ='/home/roland/repos/Pi.Alert'
confPath = "/config/pialert.conf"
dbPath = '/db/pialert.db'
confPath = "/config/pialert.conf"
dbPath = '/db/pialert.db'
pluginsPath = pialertPath + '/front/plugins'
@@ -15,8 +14,8 @@ logPath = pialertPath + '/front/log'
apiPath = pialertPath + '/front/api/'
fullConfPath = pialertPath + confPath
fullDbPath = pialertPath + dbPath
vendorsPath6 = '/usr/share/arp-scan/ieee-oui.txt'
vendorsPath9 = '/usr/share/arp-scan/ieee-iab.txt'
vendorsPath6 = '/usr/share/arp-scan/ieee-oui.txt'
vendorsPath9 = '/usr/share/arp-scan/ieee-iab.txt'

View File

@@ -3,8 +3,7 @@ import subprocess
import conf
import re
from helper import timeNowTZ, get_setting, get_setting_value,resolve_device_name_dig, resolve_device_name_pholus
from scanners.internet import check_IP_format, get_internet_IP
from helper import timeNowTZ, get_setting, get_setting_value,resolve_device_name_dig, resolve_device_name_pholus, check_IP_format, get_internet_IP
from logger import mylog, print_log
from const import vendorsPath6, vendorsPath9
@@ -13,13 +12,9 @@ from const import vendorsPath6, vendorsPath9
def save_scanned_devices (db):
sql = db.sql #TO-DO
cycle = 1 # always 1, only one cycle supported
# handled by the ARPSCAN plugin
# handled by the Pi-hole plugin
# Check Internet connectivity
internet_IP = get_internet_IP( conf.DIG_GET_IP_ARG )
internet_IP = get_internet_IP()
# TESTING - Force IP
# internet_IP = ""
if internet_IP != "" :

View File

@@ -18,10 +18,10 @@ import conf
from const import *
from logger import mylog, logResult
#-------------------------------------------------------------------------------
# DateTime
#-------------------------------------------------------------------------------
# Get the current time in the current TimeZone
def timeNowTZ():
if isinstance(conf.TIMEZONE, str):
tz = pytz.timezone(conf.TIMEZONE)
@@ -34,6 +34,8 @@ def timeNow():
return datetime.datetime.now().replace(microsecond=0)
#-------------------------------------------------------------------------------
# App state
#-------------------------------------------------------------------------------
# A class to manage the application state and to provide a frontend accessible API point
class app_state_class:
@@ -79,20 +81,14 @@ class app_state_class:
return result
#-------------------------------------------------------------------------------
# Checks if the object has a __dict__ attribute. If it does, it assumes that it's an instance of a class and serializes its attributes dynamically.
class AppStateEncoder(json.JSONEncoder):
def default(self, obj):
if hasattr(obj, '__dict__'):
# If the object has a '__dict__', assume it's an instance of a class
return obj.__dict__
return super().default(obj)
#-------------------------------------------------------------------------------
# method to update the state
def updateState(newState, settingsSaved = None, settingsImported = None, showSpinner = False):
state = app_state_class(newState, settingsSaved, settingsImported, showSpinner)
#-------------------------------------------------------------------------------
def updateSubnets(scan_subnets):
subnets = []
@@ -109,6 +105,8 @@ def updateSubnets(scan_subnets):
#-------------------------------------------------------------------------------
# File system permission handling
#-------------------------------------------------------------------------------
# check RW access of DB and config file
def checkPermissionsOK():
@@ -175,7 +173,7 @@ def initialiseFile(pathToCheck, defaultFile):
mylog('none', ["[Setup] Error copying ("+defaultFile+"). Make sure the app has Read & Write access to " + pathToCheck])
mylog('none', [e.output])
#-------------------------------------------------------------------------------
def filePermissions():
# check and initialize pialert.conf
(confR_access, dbR_access) = checkPermissionsOK() # Initial check
@@ -192,162 +190,8 @@ def filePermissions():
#-------------------------------------------------------------------------------
def bytes_to_string(value):
# if value is of type bytes, convert to string
if isinstance(value, bytes):
value = value.decode('utf-8')
return value
# File manipulation methods
#-------------------------------------------------------------------------------
def if_byte_then_to_str(input):
if isinstance(input, bytes):
input = input.decode('utf-8')
input = bytes_to_string(re.sub('[^a-zA-Z0-9-_\s]', '', str(input)))
return input
#-------------------------------------------------------------------------------
def collect_lang_strings(db, json, pref, stringSqlParams):
for prop in json["localized"]:
for language_string in json[prop]:
stringSqlParams.append((str(language_string["language_code"]), str(pref + "_" + prop), str(language_string["string"]), ""))
return stringSqlParams
#-------------------------------------------------------------------------------
# Creates a JSON object from a DB row
def row_to_json(names, row):
rowEntry = {}
index = 0
for name in names:
rowEntry[name]= if_byte_then_to_str(row[name])
index += 1
return rowEntry
#-------------------------------------------------------------------------------
def checkIPV4(ip):
""" 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:
return False
#-------------------------------------------------------------------------------
def isNewVersion(newVersion: bool):
mylog('debug', [f"[Version check] New version available? {newVersion}"])
if newVersion == False:
f = open(pialertPath + '/front/buildtimestamp.txt', 'r')
buildTimestamp = int(f.read().strip())
f.close()
data = ""
try:
url = requests.get("https://api.github.com/repos/jokob-sk/Pi.Alert/releases")
text = url.text
data = json.loads(text)
except requests.exceptions.ConnectionError as e:
mylog('minimal', [" Couldn't check for new release."])
data = ""
# make sure we received a valid response and not an API rate limit exceeded message
if data != "" and len(data) > 0 and isinstance(data, list) and "published_at" in data[0]:
dateTimeStr = data[0]["published_at"]
realeaseTimestamp = int(datetime.datetime.strptime(dateTimeStr, '%Y-%m-%dT%H:%M:%SZ').strftime('%s'))
if realeaseTimestamp > buildTimestamp + 600:
mylog('none', ["[Version check] New version of the container available!"])
newVersion = True
return newVersion
#-------------------------------------------------------------------------------
def hide_email(email):
m = email.split('@')
if len(m) == 2:
return f'{m[0][0]}{"*"*(len(m[0])-2)}{m[0][-1] if len(m[0]) > 1 else ""}@{m[1]}'
return email
#-------------------------------------------------------------------------------
def removeDuplicateNewLines(text):
if "\n\n\n" in text:
return removeDuplicateNewLines(text.replace("\n\n\n", "\n\n"))
else:
return text
#-------------------------------------------------------------------------------
def add_json_list (row, list):
new_row = []
for column in row :
column = bytes_to_string(column)
new_row.append(column)
list.append(new_row)
return list
#-------------------------------------------------------------------------------
def sanitize_string(input):
if isinstance(input, bytes):
input = input.decode('utf-8')
value = bytes_to_string(re.sub('[^a-zA-Z0-9-_\s]', '', str(input)))
return value
#-------------------------------------------------------------------------------
def generate_mac_links (html, deviceUrl):
p = re.compile(r'(?:[0-9a-fA-F]:?){12}')
MACs = re.findall(p, html)
for mac in MACs:
html = html.replace('<td>' + mac + '</td>','<td><a href="' + deviceUrl + mac + '">' + mac + '</a></td>')
return html
#-------------------------------------------------------------------------------
def initOrSetParam(db, parID, parValue):
sql = db.sql
sql.execute ("INSERT INTO Parameters(par_ID, par_Value) VALUES('"+str(parID)+"', '"+str(parValue)+"') ON CONFLICT(par_ID) DO UPDATE SET par_Value='"+str(parValue)+"' where par_ID='"+str(parID)+"'")
db.commitDB()
#-------------------------------------------------------------------------------
class json_struc:
def __init__(self, jsn, columnNames):
self.json = jsn
self.columnNames = columnNames
#-------------------------------------------------------------------------------
def get_file_content(path):
@@ -382,16 +226,8 @@ def write_file(pPath, pText):
file.close()
#-------------------------------------------------------------------------------
class noti_struc:
def __init__(self, json, text, html):
self.json = json
self.text = text
self.html = html
# Setting methods
#-------------------------------------------------------------------------------
def isJsonObject(value):
return isinstance(value, dict)
#-------------------------------------------------------------------------------
# Return whole setting touple
def get_setting(key):
@@ -423,6 +259,100 @@ def get_setting_value(key):
return ''
#-------------------------------------------------------------------------------
# IP validation methods
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
def checkIPV4(ip):
""" 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:
return False
#-------------------------------------------------------------------------------
def check_IP_format (pIP):
# Check IP format
IPv4SEG = r'(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])'
IPv4ADDR = r'(?:(?:' + IPv4SEG + r'\.){3,3}' + IPv4SEG + r')'
IP = re.search(IPv4ADDR, pIP)
# Return error if not IP
if IP is None :
return ""
# Return IP
return IP.group(0)
#-------------------------------------------------------------------------------
def get_internet_IP ():
# BUGFIX #46 - curl http://ipv4.icanhazip.com repeatedly is very slow
# Using 'dig'
dig_args = ['dig', '+short'] + conf.DIG_GET_IP_ARG.strip().split()
try:
cmd_output = subprocess.check_output (dig_args, universal_newlines=True)
except subprocess.CalledProcessError as e:
mylog('none', [e.output])
cmd_output = '' # no internet
# Check result is an IP
IP = check_IP_format (cmd_output)
# Handle invalid response
if IP == '':
IP = '0.0.0.0'
return IP
#-------------------------------------------------------------------------------
def resolve_device_name_dig (pMAC, pIP):
newName = ""
try :
dig_args = ['dig', '+short', '-x', pIP]
# Execute command
try:
# try runnning a subprocess
newName = subprocess.check_output (dig_args, universal_newlines=True)
except subprocess.CalledProcessError as e:
# An error occured, handle it
mylog('none', ['[device_name_dig] ', e.output])
# newName = "Error - check logs"
return -1
# Check returns
newName = newName.strip()
if len(newName) == 0 :
return -1
# Cleanup
newName = cleanResult(newName)
if newName == "" or len(newName) == 0:
return -1
# Return newName
return newName
# not Found
except subprocess.CalledProcessError :
return -1
#-------------------------------------------------------------------------------
# DNS record (Pholus/Name resolution) cleanup methods
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
# Disclaimer - I'm interfacing with a script I didn't write (pholus3.py) so it's possible I'm missing types of answers
# it's also possible the pholus3.py script can be adjusted to provide a better output to interface with it
@@ -498,43 +428,7 @@ def resolve_device_name_pholus (pMAC, pIP, allRes):
return -1
#-------------------------------------------------------------------------------
def resolve_device_name_dig (pMAC, pIP):
newName = ""
try :
dig_args = ['dig', '+short', '-x', pIP]
# Execute command
try:
# try runnning a subprocess
newName = subprocess.check_output (dig_args, universal_newlines=True)
except subprocess.CalledProcessError as e:
# An error occured, handle it
mylog('none', ['[device_name_dig] ', e.output])
# newName = "Error - check logs"
return -1
# Check returns
newName = newName.strip()
if len(newName) == 0 :
return -1
# Cleanup
newName = cleanResult(newName)
if newName == "" or len(newName) == 0:
return -1
# Return newName
return newName
# not Found
except subprocess.CalledProcessError :
return -1
#-------------------------------------------------------------------------------
def cleanResult(str):
@@ -552,4 +446,178 @@ def cleanResult(str):
if str.endswith('.'):
str = str[:-1]
return str
return str
#-------------------------------------------------------------------------------
# String manipulation methods
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
def bytes_to_string(value):
# if value is of type bytes, convert to string
if isinstance(value, bytes):
value = value.decode('utf-8')
return value
#-------------------------------------------------------------------------------
def if_byte_then_to_str(input):
if isinstance(input, bytes):
input = input.decode('utf-8')
input = bytes_to_string(re.sub('[^a-zA-Z0-9-_\s]', '', str(input)))
return input
#-------------------------------------------------------------------------------
def hide_email(email):
m = email.split('@')
if len(m) == 2:
return f'{m[0][0]}{"*"*(len(m[0])-2)}{m[0][-1] if len(m[0]) > 1 else ""}@{m[1]}'
return email
#-------------------------------------------------------------------------------
def removeDuplicateNewLines(text):
if "\n\n\n" in text:
return removeDuplicateNewLines(text.replace("\n\n\n", "\n\n"))
else:
return text
#-------------------------------------------------------------------------------
def sanitize_string(input):
if isinstance(input, bytes):
input = input.decode('utf-8')
value = bytes_to_string(re.sub('[^a-zA-Z0-9-_\s]', '', str(input)))
return value
#-------------------------------------------------------------------------------
def generate_mac_links (html, deviceUrl):
p = re.compile(r'(?:[0-9a-fA-F]:?){12}')
MACs = re.findall(p, html)
for mac in MACs:
html = html.replace('<td>' + mac + '</td>','<td><a href="' + deviceUrl + mac + '">' + mac + '</a></td>')
return html
#-------------------------------------------------------------------------------
# JSON methods
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
def isJsonObject(value):
return isinstance(value, dict)
#-------------------------------------------------------------------------------
def add_json_list (row, list):
new_row = []
for column in row :
column = bytes_to_string(column)
new_row.append(column)
list.append(new_row)
return list
#-------------------------------------------------------------------------------
# Checks if the object has a __dict__ attribute. If it does, it assumes that it's an instance of a class and serializes its attributes dynamically.
class AppStateEncoder(json.JSONEncoder):
def default(self, obj):
if hasattr(obj, '__dict__'):
# If the object has a '__dict__', assume it's an instance of a class
return obj.__dict__
return super().default(obj)
#-------------------------------------------------------------------------------
# Creates a JSON object from a DB row
def row_to_json(names, row):
rowEntry = {}
index = 0
for name in names:
rowEntry[name]= if_byte_then_to_str(row[name])
index += 1
return rowEntry
#-------------------------------------------------------------------------------
# Get language strings from plugin JSON
def collect_lang_strings(json, pref, stringSqlParams):
for prop in json["localized"]:
for language_string in json[prop]:
stringSqlParams.append((str(language_string["language_code"]), str(pref + "_" + prop), str(language_string["string"]), ""))
return stringSqlParams
#-------------------------------------------------------------------------------
# Misc
#-------------------------------------------------------------------------------
#-------------------------------------------------------------------------------
def isNewVersion(newVersion: bool):
mylog('debug', [f"[Version check] New version available? {newVersion}"])
if newVersion == False:
f = open(pialertPath + '/front/buildtimestamp.txt', 'r')
buildTimestamp = int(f.read().strip())
f.close()
data = ""
try:
url = requests.get("https://api.github.com/repos/jokob-sk/Pi.Alert/releases")
text = url.text
data = json.loads(text)
except requests.exceptions.ConnectionError as e:
mylog('minimal', [" Couldn't check for new release."])
data = ""
# make sure we received a valid response and not an API rate limit exceeded message
if data != "" and len(data) > 0 and isinstance(data, list) and "published_at" in data[0]:
dateTimeStr = data[0]["published_at"]
realeaseTimestamp = int(datetime.datetime.strptime(dateTimeStr, '%Y-%m-%dT%H:%M:%SZ').strftime('%s'))
if realeaseTimestamp > buildTimestamp + 600:
mylog('none', ["[Version check] New version of the container available!"])
newVersion = True
return newVersion
#-------------------------------------------------------------------------------
def initOrSetParam(db, parID, parValue):
sql = db.sql
sql.execute ("INSERT INTO Parameters(par_ID, par_Value) VALUES('"+str(parID)+"', '"+str(parValue)+"') ON CONFLICT(par_ID) DO UPDATE SET par_Value='"+str(parValue)+"' where par_ID='"+str(parID)+"'")
db.commitDB()
#-------------------------------------------------------------------------------
class json_struc:
def __init__(self, jsn, columnNames):
self.json = jsn
self.columnNames = columnNames
#-------------------------------------------------------------------------------
class noti_struc:
def __init__(self, json, text, html):
self.json = json
self.text = text
self.html = html

View File

@@ -78,6 +78,7 @@ def importConfigs (db):
# remove all plugin langauge strings
sql.execute("DELETE FROM Plugins_Language_Strings;")
db.commitDB()
mylog('debug', ['[Import Config] importing config file'])
conf.mySettings = [] # reset settings
@@ -169,8 +170,6 @@ def importConfigs (db):
conf.time_started = datetime.datetime.now(conf.tz)
conf.cycle = ""
conf.plugins_once_run = False
#cron_instance = Cron()
# timestamps of last execution times
conf.startTime = conf.time_started
@@ -178,8 +177,7 @@ def importConfigs (db):
# set these times to the past to force the first run
conf.last_internet_IP_scan = now_minus_24h
conf.last_scan_run = now_minus_24h
conf.last_update_vendors = conf.time_started - datetime.timedelta(days = 6) # update vendors 24h after first run and then once a week
conf.last_scan_run = now_minus_24h
conf.last_version_check = now_minus_24h
# TODO cleanup later ----------------------------------------------------------------------------------
@@ -211,7 +209,7 @@ def importConfigs (db):
stringSqlParams = []
# collect plugin level language strings
stringSqlParams = collect_lang_strings(db, plugin, pref, stringSqlParams)
stringSqlParams = collect_lang_strings(plugin, pref, stringSqlParams)
for set in plugin["settings"]:
setFunction = set["function"]
@@ -242,12 +240,12 @@ def importConfigs (db):
# Collect settings related language strings
# Creates an entry with key, for example ARPSCAN_CMD_name
stringSqlParams = collect_lang_strings(db, set, pref + "_" + set["function"], stringSqlParams)
stringSqlParams = collect_lang_strings(set, pref + "_" + set["function"], stringSqlParams)
# Collect column related language strings
for clmn in plugin.get('database_column_definitions', []):
# Creates an entry with key, for example ARPSCAN_Object_PrimaryID_name
stringSqlParams = collect_lang_strings(db, clmn, pref + "_" + clmn.get("column", ""), stringSqlParams)
stringSqlParams = collect_lang_strings(clmn, pref + "_" + clmn.get("column", ""), stringSqlParams)
# bulk-import language strings
sql.executemany ("""INSERT INTO Plugins_Language_Strings ("Language_Code", "String_Key", "String_Value", "Extra") VALUES (?, ?, ?, ?)""", stringSqlParams )

View File

@@ -283,7 +283,7 @@ 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 conf.debug_force_notification or plugins_report:
if json_internet != [] or json_new_devices != [] or json_down_devices != [] or json_events != [] or json_ports != [] or plugins_report:
mylog('none', ['[Notification] Changes detected, sending reports'])

View File

@@ -6,15 +6,11 @@ import re
# pialert modules
import conf
from helper import timeNowTZ, updateState
from helper import timeNowTZ, updateState, check_IP_format, get_internet_IP
from logger import append_line_to_file, mylog
from const import logPath
# need to find a better way to deal with settings !
#global DDNS_ACTIVE, DDNS_DOMAIN, DDNS_UPDATE_URL, DDNS_USER, DDNS_PASSWORD
#===============================================================================
# INTERNET IP CHANGE
#===============================================================================
@@ -26,7 +22,7 @@ def check_internet_IP ( db ):
# Get Internet IP
mylog('verbose', ['[Internet IP] - Retrieving Internet IP'])
internet_IP = get_internet_IP(conf.DIG_GET_IP_ARG)
internet_IP = get_internet_IP()
# TESTING - Force IP
# internet_IP = "1.2.3.4"
@@ -72,25 +68,6 @@ def check_internet_IP ( db ):
#-------------------------------------------------------------------------------
def get_internet_IP (DIG_GET_IP_ARG):
# BUGFIX #46 - curl http://ipv4.icanhazip.com repeatedly is very slow
# Using 'dig'
dig_args = ['dig', '+short'] + DIG_GET_IP_ARG.strip().split()
try:
cmd_output = subprocess.check_output (dig_args, universal_newlines=True)
except subprocess.CalledProcessError as e:
mylog('none', [e.output])
cmd_output = '' # no internet
# Check result is an IP
IP = check_IP_format (cmd_output)
# Handle invalid response
if IP == '':
IP = '0.0.0.0'
return IP
#-------------------------------------------------------------------------------
def get_previous_internet_IP (db):
@@ -134,21 +111,6 @@ def save_new_internet_IP (db, pNewIP):
# commit changes
db.commitDB()
#-------------------------------------------------------------------------------
def check_IP_format (pIP):
# Check IP format
IPv4SEG = r'(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])'
IPv4ADDR = r'(?:(?:' + IPv4SEG + r'\.){3,3}' + IPv4SEG + r')'
IP = re.search(IPv4ADDR, pIP)
# Return error if not IP
if IP is None :
return ""
# Return IP
return IP.group(0)
#-------------------------------------------------------------------------------
def get_dynamic_DNS_IP ():