Plugins 0.1 - ONCE execution support

This commit is contained in:
Jokob-sk
2023-02-06 21:47:58 +11:00
parent 5ed142a6b8
commit 887c2d0f42
7 changed files with 528 additions and 240 deletions

View File

@@ -50,15 +50,18 @@ sql_devices_stats = "SELECT Online_Devices as online, Down_Devices as down, All
sql_nmap_scan_all = "SELECT * FROM Nmap_Scan" sql_nmap_scan_all = "SELECT * FROM Nmap_Scan"
sql_pholus_scan_all = "SELECT * FROM Pholus_Scan" sql_pholus_scan_all = "SELECT * FROM Pholus_Scan"
sql_events_pending_alert = "SELECT * FROM Events where eve_PendingAlertEmail is not 0" sql_events_pending_alert = "SELECT * FROM Events where eve_PendingAlertEmail is not 0"
sql_settings = "SELECT * FROM Settings"
#=============================================================================== #===============================================================================
# PATHS # PATHS
#=============================================================================== #===============================================================================
pialertPath = '/home/pi/pialert' pialertPath = '/home/pi/pialert'
logPath = pialertPath + '/front/log'
confPath = "/config/pialert.conf" confPath = "/config/pialert.conf"
dbPath = '/db/pialert.db' dbPath = '/db/pialert.db'
pluginsPath = pialertPath + '/front/plugins'
pluginsPath = pialertPath + '/front/plugins'
logPath = pialertPath + '/front/log'
fullConfPath = pialertPath + confPath fullConfPath = pialertPath + confPath
fullDbPath = pialertPath + dbPath fullDbPath = pialertPath + dbPath
@@ -151,7 +154,7 @@ def checkPermissionsOK():
file_print('------------------------------------------------') file_print('------------------------------------------------')
return dbR_access and dbW_access and confR_access and confW_access return dbR_access and dbW_access and confR_access and confW_access
#-------------------------------------------------------------------------------
def fixPermissions(): def fixPermissions():
# Try fixing access rights if needed # Try fixing access rights if needed
chmodCommands = [] chmodCommands = []
@@ -173,6 +176,7 @@ def fixPermissions():
checkPermissionsOK() # Initial check checkPermissionsOK() # Initial check
#-------------------------------------------------------------------------------
def initialiseFile(pathToCheck, defaultFile): def initialiseFile(pathToCheck, defaultFile):
# if file not readable (missing?) try to copy over the backed-up (default) one # if file not readable (missing?) try to copy over the backed-up (default) one
if str(os.access(pathToCheck, os.R_OK)) == "False": if str(os.access(pathToCheck, os.R_OK)) == "False":
@@ -255,6 +259,7 @@ def commitDB ():
def ccd(key, default, config, name, inputtype, options, group, events=[], desc = "", regex = ""): def ccd(key, default, config, name, inputtype, options, group, events=[], desc = "", regex = ""):
result = default result = default
# use existing value if already supplied, otehrwise default value is used
if key in config: if key in config:
result = config[key] result = config[key]
@@ -266,10 +271,10 @@ def ccd(key, default, config, name, inputtype, options, group, events=[], desc =
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def importConfig (): def importConfigs ():
# Specify globals so they can be overwritten with the new config # Specify globals so they can be overwritten with the new config
global lastTimeImported, mySettings global lastTimeImported, mySettings, plugins
# General # General
global ENABLE_ARPSCAN, SCAN_SUBNETS, PRINT_LOG, TIMEZONE, PIALERT_WEB_PROTECTION, PIALERT_WEB_PASSWORD, INCLUDED_SECTIONS, SCAN_CYCLE_MINUTES, DAYS_TO_KEEP_EVENTS, REPORT_DASHBOARD_URL, DIG_GET_IP_ARG, UI_LANG global ENABLE_ARPSCAN, SCAN_SUBNETS, PRINT_LOG, TIMEZONE, 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 # Email
@@ -293,7 +298,7 @@ def importConfig ():
# Nmap # Nmap
global NMAP_ACTIVE, NMAP_TIMEOUT, NMAP_RUN, NMAP_RUN_SCHD, NMAP_ARGS global NMAP_ACTIVE, NMAP_TIMEOUT, NMAP_RUN, NMAP_RUN_SCHD, NMAP_ARGS
# API # API
global ENABLE_API, API_RUN, API_RUN_SCHD, API_RUN_INTERVAL, API_CUSTOM_SQL global API_RUN, API_RUN_SCHD, API_RUN_INTERVAL, API_CUSTOM_SQL
mySettings = [] # reset settings mySettings = [] # reset settings
# get config file # get config file
@@ -395,30 +400,13 @@ def importConfig ():
NMAP_ARGS = ccd('NMAP_ARGS', '-p -10000' , c_d, 'Nmap custom arguments', 'text', '', 'Nmap') NMAP_ARGS = ccd('NMAP_ARGS', '-p -10000' , c_d, 'Nmap custom arguments', 'text', '', 'Nmap')
# API # API
ENABLE_API = ccd('ENABLE_API', True , c_d, 'Enable API', 'boolean', '', 'API')
API_RUN = ccd('API_RUN', 'schedule' , c_d, 'API execution', 'selecttext', "['none', 'interval', 'schedule']", 'API') API_RUN = ccd('API_RUN', 'schedule' , c_d, 'API execution', 'selecttext', "['none', 'interval', 'schedule']", 'API')
API_RUN_SCHD = ccd('API_RUN_SCHD', '*/3 * * * *' , c_d, 'API schedule', 'text', '', 'API') API_RUN_SCHD = ccd('API_RUN_SCHD', '*/3 * * * *' , c_d, 'API schedule', 'text', '', 'API')
API_RUN_INTERVAL = ccd('API_RUN_INTERVAL', 10 , c_d, 'API update interval', 'integer', '', 'API') API_RUN_INTERVAL = ccd('API_RUN_INTERVAL', 10 , c_d, 'API update interval', 'integer', '', 'API')
API_CUSTOM_SQL = ccd('API_CUSTOM_SQL', 'SELECT * FROM Devices WHERE dev_PresentLastScan = 0' , c_d, 'Custom endpoint', 'text', '', 'API') API_CUSTOM_SQL = ccd('API_CUSTOM_SQL', 'SELECT * FROM Devices WHERE dev_PresentLastScan = 0' , c_d, 'Custom endpoint', 'text', '', 'API')
#Plugins # Prepare scheduler
plugins = get_plugins_configs() global tz, mySchedules, plugins
file_print('[', timeNow(), '] Plugins: Number of dynamically loaded plugins: ', len(plugins) )
for plugin in plugins:
file_print(' ---------------------------------------------')
file_print(' Name : ', plugin.display_name )
file_print(' Description: ', plugin.description.en_us )
prefix = plugin.settings_short_prefix
for set in plugin.settings:
codeName = prefix + "_" + set.type
ccd(codeName, set.default_value , c_d, set.name.en_us, get_setting_type(set), str(set.options), prefix)
# Update scheduler
global tz, mySchedules
# Init timezone in case it changed # Init timezone in case it changed
tz = timezone(TIMEZONE) tz = timezone(TIMEZONE)
@@ -428,19 +416,56 @@ def importConfig ():
# init pholus schedule # init pholus schedule
pholusSchedule = Cron(PHOLUS_RUN_SCHD).schedule(start_date=datetime.datetime.now(tz)) pholusSchedule = Cron(PHOLUS_RUN_SCHD).schedule(start_date=datetime.datetime.now(tz))
mySchedules.append(serviceSchedule("pholus", pholusSchedule, pholusSchedule.next(), False)) mySchedules.append(schedule_class("pholus", pholusSchedule, pholusSchedule.next(), False))
# init nmap schedule # init nmap schedule
nmapSchedule = Cron(NMAP_RUN_SCHD).schedule(start_date=datetime.datetime.now(tz)) nmapSchedule = Cron(NMAP_RUN_SCHD).schedule(start_date=datetime.datetime.now(tz))
mySchedules.append(serviceSchedule("nmap", nmapSchedule, nmapSchedule.next(), False)) mySchedules.append(schedule_class("nmap", nmapSchedule, nmapSchedule.next(), False))
# init API schedule # init API schedule
apiSchedule = Cron(API_RUN_SCHD).schedule(start_date=datetime.datetime.now(tz)) apiSchedule = Cron(API_RUN_SCHD).schedule(start_date=datetime.datetime.now(tz))
mySchedules.append(serviceSchedule("api", apiSchedule, apiSchedule.next(), False)) mySchedules.append(schedule_class("api", apiSchedule, apiSchedule.next(), False))
# Format and prepare the list of subnets # Format and prepare the list of subnets
updateSubnets() updateSubnets()
# Plugins START
# -----------------
plugins = get_plugins_configs()
file_print('[', timeNow(), '] Plugins: Number of dynamically loaded plugins: ', len(plugins.dict) )
# handle plugins
for plugin in plugins.list:
print_plugin_info(plugin, ['display_name','description'])
pref = plugin["settings_short_prefix"]
# collect plugin level language strings
collect_lang_strings(plugin, pref)
for set in plugin["settings"]:
setType = set["type"]
# Setting code name / key
key = pref + "_" + setType
v = ccd(key, set["default_value"], c_d, set["name"][0]["string"], get_form_control(set), str(set["options"]), pref)
# Save the user defined value into the object
set["value"] = v
# Setup schedules
if setType == 'RUN_SCHD':
newSchedule = Cron(v).schedule(start_date=datetime.datetime.now(tz))
mySchedules.append(schedule_class(pref, newSchedule, newSchedule.next(), False))
# Collect settings related language strings
collect_lang_strings(set, pref + "_" + set["type"])
# -----------------
# Plugins END
# Insert settings into the DB # Insert settings into the DB
sql.execute ("DELETE FROM Settings") sql.execute ("DELETE FROM Settings")
sql.executemany ("""INSERT INTO Settings ("Code_Name", "Display_Name", "Description", "Type", "Options", sql.executemany ("""INSERT INTO Settings ("Code_Name", "Display_Name", "Description", "Type", "Options",
@@ -454,6 +479,9 @@ def importConfig ():
commitDB() commitDB()
# update only the settings datasource
update_api(False, ["settings"])
file_print('[', timeNow(), '] Config: Imported new config') file_print('[', timeNow(), '] Config: Imported new config')
#=============================================================================== #===============================================================================
@@ -461,6 +489,7 @@ def importConfig ():
#=============================================================================== #===============================================================================
cycle = "" cycle = ""
check_report = [1, "internet_IP", "update_vendors_silent"] check_report = [1, "internet_IP", "update_vendors_silent"]
plugins_once_run = False
# timestamps of last execution times # timestamps of last execution times
startTime = time_started startTime = time_started
@@ -480,7 +509,7 @@ def main ():
# Initialize global variables # Initialize global variables
global time_started, cycle, last_network_scan, last_internet_IP_scan, last_run, last_cleanup, last_update_vendors, last_API_update global time_started, cycle, last_network_scan, last_internet_IP_scan, last_run, last_cleanup, last_update_vendors, last_API_update
# second set of global variables # second set of global variables
global startTime, log_timestamp, sql_connection, sql global startTime, log_timestamp, sql_connection, sql, plugins_once_run
# DB # DB
sql_connection = None sql_connection = None
@@ -498,8 +527,13 @@ def main ():
# update time started # update time started
time_started = datetime.datetime.now() time_started = datetime.datetime.now()
# re-load user configuration # re-load user configuration and plugins
importConfig() importConfigs()
# Handle plugins executed ONCE
if plugins_once_run == False:
run_plugin_script('once')
plugins_once_run = True
# check if there is a front end initiated event which needs to be executed # check if there is a front end initiated event which needs to be executed
check_and_run_event() check_and_run_event()
@@ -819,8 +853,8 @@ def cleanup_database ():
file_print('[', startTime, '] Upkeep Database:' ) file_print('[', startTime, '] Upkeep Database:' )
# Cleanup Online History # Cleanup Online History
file_print(' Online_History: Delete all older than 1 day') file_print(' Online_History: Delete all older than 3 days')
sql.execute ("DELETE FROM Online_History WHERE Scan_Date <= date('now', '-1 day')") sql.execute ("DELETE FROM Online_History WHERE Scan_Date <= date('now', '-3 day')")
file_print(' Optimize Database') file_print(' Optimize Database')
# Cleanup Events # Cleanup Events
@@ -3075,7 +3109,7 @@ def upgradeDB ():
Extra TEXT NOT NULL, Extra TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT) PRIMARY KEY("Index" AUTOINCREMENT)
); """ ); """
# sql.execute(sql_Plugins_State) sql.execute(sql_Plugins_State)
# Plugin execution results # Plugin execution results
sql_Plugin_Events = """ CREATE TABLE IF NOT EXISTS Plugins_Events( sql_Plugin_Events = """ CREATE TABLE IF NOT EXISTS Plugins_Events(
@@ -3091,7 +3125,26 @@ def upgradeDB ():
Processed TEXT NOT NULL, Processed TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT) PRIMARY KEY("Index" AUTOINCREMENT)
); """ ); """
# sql.execute(sql_Plugin_Events) sql.execute(sql_Plugin_Events)
# Dynamically generated language strings
# indicates, if Language_Strings table is available
languageStringsMissing = sql.execute("""
SELECT name FROM sqlite_master WHERE type='table'
AND name='Language_Strings';
""").fetchone() == None
if languageStringsMissing == False:
sql.execute("DROP TABLE Language_Strings;")
sql.execute(""" CREATE TABLE IF NOT EXISTS Language_Strings(
"Index" INTEGER,
Language_Code TEXT NOT NULL,
String_Key TEXT NOT NULL,
String_Value TEXT NOT NULL,
Extra TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT)
); """)
commitDB () commitDB ()
@@ -3136,11 +3189,7 @@ def to_binary_sensor(input):
#=============================================================================== #===============================================================================
# API # API
#=============================================================================== #===============================================================================
def update_api(isNotification = False): def update_api(isNotification = False, updateOnlyDataSources = []):
# Proceed only if enabled in settings
if ENABLE_API == False:
return
file_print(' [API] Updating files in /front/api') file_print(' [API] Updating files in /front/api')
folder = pialertPath + '/front/api/' folder = pialertPath + '/front/api/'
@@ -3157,15 +3206,18 @@ def update_api(isNotification = False):
["nmap_scan", sql_nmap_scan_all], ["nmap_scan", sql_nmap_scan_all],
["pholus_scan", sql_pholus_scan_all], ["pholus_scan", sql_pholus_scan_all],
["events_pending_alert", sql_events_pending_alert], ["events_pending_alert", sql_events_pending_alert],
["settings", sql_settings],
["custom_endpoint", API_CUSTOM_SQL] ["custom_endpoint", API_CUSTOM_SQL]
] ]
# Save selected database tables # Save selected database tables
for dsSQL in dataSourcesSQLs: for dsSQL in dataSourcesSQLs:
json_string = get_table_as_json(dsSQL[1]).json if updateOnlyDataSources == [] or dsSQL[0] in updateOnlyDataSources:
write_file(folder + 'table_' + dsSQL[0] + '.json' , json.dumps(json_string)) json_string = get_table_as_json(dsSQL[1]).json
write_file(folder + 'table_' + dsSQL[0] + '.json' , json.dumps(json_string))
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def get_table_as_json(sqlQuery): def get_table_as_json(sqlQuery):
@@ -3482,25 +3534,49 @@ def isNewVersion():
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def get_plugins_configs(): def get_plugins_configs():
plugins = [] pluginsDict = []
pluginsList = []
for root, dirs, files in os.walk(pluginsPath): for root, dirs, files in os.walk(pluginsPath):
for d in dirs: # Loop over directories, not files for d in dirs: # Loop over directories, not files
pluginsDict.append(json.loads(get_file_content(pluginsPath + "/" + d + '/config.json'), object_hook=custom_plugin_decoder))
pluginsList.append(json.loads(get_file_content(pluginsPath + "/" + d + '/config.json')))
# filelist.append(os.path.join(root, d)) return plugins_class(pluginsDict, pluginsList)
plugins.append(json.loads(get_file_content(pluginsPath + "/" + d + '/config.json'), object_hook=custom_plugin_decoder))
return plugins
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def get_setting_type(setting): class plugins_class:
if setting.type in ['RUN']: def __init__(self, dict, list):
self.dict = dict
self.list = list
#-------------------------------------------------------------------------------
def collect_lang_strings(json, pref):
for prop in json["localized"]:
for language_string in json[prop]:
import_language_string(language_string["language_code"], pref + "_" + prop, language_string["string"])
#-------------------------------------------------------------------------------
def import_language_string(code, key, value, extra = ""):
sql.execute ("""INSERT INTO Language_Strings ("Language_Code", "String_Key", "String_Value", "Extra") VALUES (?, ?, ?, ?)""", (str(code), str(key), str(value), str(extra)))
commitDB ()
#-------------------------------------------------------------------------------
def get_form_control(setting):
type = setting["type"]
if type in ['RUN']:
return 'selecttext' return 'selecttext'
if setting.type in ['ENABLE', 'FORCE_REPORT']: if type in ['ENABLE', 'FORCE_REPORT']:
return 'boolean' return 'boolean'
if setting.type in ['TIMEOUT', 'RUN_TIMEOUT']: if type in ['TIMEOUT', 'RUN_TIMEOUT']:
return 'integer' return 'integer'
if setting.type in ['NOTIFY_ON']: if type in ['WATCH', 'LIST']:
return 'multiselect' return 'multiselect'
return 'text' return 'text'
@@ -3509,10 +3585,59 @@ def get_setting_type(setting):
def custom_plugin_decoder(pluginDict): def custom_plugin_decoder(pluginDict):
return namedtuple('X', pluginDict.keys())(*pluginDict.values()) return namedtuple('X', pluginDict.keys())(*pluginDict.values())
#-------------------------------------------------------------------------------
def run_plugin_script(runType):
global plugins
for plugin in plugins.list:
set = get_plugin_setting(plugin, "RUN")
if set['value'] == runType:
file_print(' [Plugin] Run')
print_plugin_info(plugin, ['display_name'])
file_print(' [Plugin] CMD', get_plugin_setting(plugin, "CMD")["value"])
#-------------------------------------------------------------------------------
def get_plugin_setting(plugin, key):
for set in plugin['settings']:
if set["type"] == key:
return set
#-------------------------------------------------------------------------------
def get_plugin_string(props, el):
result = ''
if el in props['localized']:
for str in props[el]:
if str['language_code'] == 'en_us':
result = str['string']
if result == '':
result = 'en_us string missing'
else:
result = props[el]
return result
#-------------------------------------------------------------------------------
def print_plugin_info(plugin, elements = ['display_name']):
file_print(' ---------------------------------------------')
for el in elements:
res = get_plugin_string(plugin, el)
file_print(' ', el ,': ', res)
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
# Cron-like Scheduling # Cron-like Scheduling
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
class serviceSchedule: class schedule_class:
def __init__(self, service, scheduleObject, last_next_schedule, was_last_schedule_used, last_run = 0): def __init__(self, service, scheduleObject, last_next_schedule, was_last_schedule_used, last_run = 0):
self.service = service self.service = service
self.scheduleObject = scheduleObject self.scheduleObject = scheduleObject

View File

@@ -29,6 +29,7 @@ You can access the following files:
| `table_nmap_scan.json` | The current state of the discovered ports by the regular NMAP scans. | | `table_nmap_scan.json` | The current state of the discovered ports by the regular NMAP scans. |
| `table_pholus_scan.json` | The latest state of the [pholus](https://github.com/jokob-sk/Pi.Alert/tree/main/pholus) (A multicast DNS and DNS Service Discovery Security Assessment Tool) scan results. | | `table_pholus_scan.json` | The latest state of the [pholus](https://github.com/jokob-sk/Pi.Alert/tree/main/pholus) (A multicast DNS and DNS Service Discovery Security Assessment Tool) scan results. |
| `table_events_pending_alert.json` | The list of the unprocessed (pending) notification events. | | `table_events_pending_alert.json` | The list of the unprocessed (pending) notification events. |
| `table_settings.json` | The content of the settings table. |
| `table_custom_endpoint.json` | A custom endpoint generated by the SQL query specified by the `API_CUSTOM_SQL` setting. | | `table_custom_endpoint.json` | A custom endpoint generated by the SQL query specified by the `API_CUSTOM_SQL` setting. |
Current/latest state of the aforementioned files depends on your settings. Current/latest state of the aforementioned files depends on your settings.

View File

@@ -482,7 +482,8 @@ $lang['en_us'] = array(
//General //General
'General_settings_group' => '<i class="fa fa-gears"></i> General', 'General_display_name' => 'General',
'General_icon' => '<i class="fa fa-gears"></i>',
'ENABLE_ARPSCAN_name' => 'Enable ARP scan', 'ENABLE_ARPSCAN_name' => 'Enable ARP scan',
'ENABLE_ARPSCAN_description' => 'Arp-scan is a command-line tool that uses the ARP protocol to discover and fingerprint IP hosts on the local network. An alternative to ARP scan is to enable the <a onclick="toggleAllSettings()" href="#PIHOLE_ACTIVE"><code>PIHOLE_ACTIVE</code>PiHole integration settings</a>.', 'ENABLE_ARPSCAN_description' => 'Arp-scan is a command-line tool that uses the ARP protocol to discover and fingerprint IP hosts on the local network. An alternative to ARP scan is to enable the <a onclick="toggleAllSettings()" href="#PIHOLE_ACTIVE"><code>PIHOLE_ACTIVE</code>PiHole integration settings</a>.',
'SCAN_SUBNETS_name' => 'Subnets to scan', 'SCAN_SUBNETS_name' => 'Subnets to scan',
@@ -519,7 +520,8 @@ the arp-scan will take hours to complete instead of seconds.
'UI_LANG_description' => 'Select the preferred UI language.', 'UI_LANG_description' => 'Select the preferred UI language.',
//Email //Email
'Email_settings_group' => '<i class="fa fa-at"></i> Email', 'Email_display_name' => 'Email',
'Email_icon' => '<i class="fa fa-at"></i>',
'REPORT_MAIL_name' => 'Enable email', 'REPORT_MAIL_name' => 'Enable email',
'REPORT_MAIL_description' => 'If enabled an email is sent out with a list of changes you\'ve subscribed to. Please also fill out all remaining settings related to the SMTP setup below.', 'REPORT_MAIL_description' => 'If enabled an email is sent out with a list of changes you\'ve subscribed to. Please also fill out all remaining settings related to the SMTP setup below.',
'SMTP_SERVER_name' => 'SMTP server URL', 'SMTP_SERVER_name' => 'SMTP server URL',
@@ -542,7 +544,8 @@ the arp-scan will take hours to complete instead of seconds.
'REPORT_FROM_description' => 'Notification email subject line.', 'REPORT_FROM_description' => 'Notification email subject line.',
//Webhooks //Webhooks
'Webhooks_settings_group' => '<i class="fa fa-circle-nodes"></i> Webhooks', 'Webhooks_display_name' => 'Webhooks',
'Webhooks_icon' => '<i class="fa fa-circle-nodes"></i>',
'REPORT_WEBHOOK_name' => 'Enable Webhooks', 'REPORT_WEBHOOK_name' => 'Enable Webhooks',
'REPORT_WEBHOOK_description' => 'Enable webhooks for notifications. Webhooks help you to connect to a lot of 3rd party tools, such as IFTTT, Zapier or <a href="https://n8n.io/" target="_blank">n8n</a> to name a few. Check out this simple <a href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md" target="_blank">n8n guide here</a> to get started. If enabled, configure related settings below.', 'REPORT_WEBHOOK_description' => 'Enable webhooks for notifications. Webhooks help you to connect to a lot of 3rd party tools, such as IFTTT, Zapier or <a href="https://n8n.io/" target="_blank">n8n</a> to name a few. Check out this simple <a href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/WEBHOOK_N8N.md" target="_blank">n8n guide here</a> to get started. If enabled, configure related settings below.',
'WEBHOOK_URL_name' => 'Target URL', 'WEBHOOK_URL_name' => 'Target URL',
@@ -553,7 +556,8 @@ the arp-scan will take hours to complete instead of seconds.
'WEBHOOK_REQUEST_METHOD_description' => 'The HTTP request method to be used for the webhook call.', 'WEBHOOK_REQUEST_METHOD_description' => 'The HTTP request method to be used for the webhook call.',
// Apprise // Apprise
'Apprise_settings_group' => '<i class="fa fa-bullhorn"></i> Apprise', 'Apprise_display_name' => 'Apprise',
'Apprise_icon' => '<i class="fa fa-bullhorn"></i>',
'REPORT_APPRISE_name' => 'Enable Apprise', 'REPORT_APPRISE_name' => 'Enable Apprise',
'REPORT_APPRISE_description' => 'Enable sending notifications via <a target="_blank" href="https://hub.docker.com/r/caronc/apprise">Apprise</a>.', 'REPORT_APPRISE_description' => 'Enable sending notifications via <a target="_blank" href="https://hub.docker.com/r/caronc/apprise">Apprise</a>.',
'APPRISE_HOST_name' => 'Apprise host URL', 'APPRISE_HOST_name' => 'Apprise host URL',
@@ -562,7 +566,8 @@ the arp-scan will take hours to complete instead of seconds.
'APPRISE_URL_description' => 'Apprise notification target URL. For example for Telegram it would be <code>tgram://{bot_token}/{chat_id}</code>.', 'APPRISE_URL_description' => 'Apprise notification target URL. For example for Telegram it would be <code>tgram://{bot_token}/{chat_id}</code>.',
// NTFY // NTFY
'NTFY_settings_group' => '<i class="fa fa-terminal"></i> NTFY', 'NTFY_display_name' => 'NTFY',
'NTFY_icon' => '<i class="fa fa-terminal"></i>',
'REPORT_NTFY_name' => 'Enable NTFY', 'REPORT_NTFY_name' => 'Enable NTFY',
'REPORT_NTFY_description' => 'Enable sending notifications via <a target="_blank" href="https://ntfy.sh/">NTFY</a>.', 'REPORT_NTFY_description' => 'Enable sending notifications via <a target="_blank" href="https://ntfy.sh/">NTFY</a>.',
'NTFY_HOST_name' => 'NTFY host URL', 'NTFY_HOST_name' => 'NTFY host URL',
@@ -575,7 +580,8 @@ the arp-scan will take hours to complete instead of seconds.
'NTFY_PASSWORD_description' => 'Enter password if you need (host) an instance with enabled authetication.', 'NTFY_PASSWORD_description' => 'Enter password if you need (host) an instance with enabled authetication.',
// Pushsafer // Pushsafer
'PUSHSAFER_settings_group' => '<i class="fa fa-bell"></i> Pushsafer', 'PUSHSAFER_display_name' => 'Pushsafer',
'PUSHSAFER_icon' => '<i class="fa fa-bell"></i>',
'REPORT_PUSHSAFER_name' => 'Enable Pushsafer', 'REPORT_PUSHSAFER_name' => 'Enable Pushsafer',
'REPORT_PUSHSAFER_description' => 'Enable sending notifications via <a target="_blank" href="https://www.pushsafer.com/">Pushsafer</a>.', 'REPORT_PUSHSAFER_description' => 'Enable sending notifications via <a target="_blank" href="https://www.pushsafer.com/">Pushsafer</a>.',
'PUSHSAFER_TOKEN_name' => 'Pushsafer token', 'PUSHSAFER_TOKEN_name' => 'Pushsafer token',
@@ -585,7 +591,8 @@ the arp-scan will take hours to complete instead of seconds.
// MQTT // MQTT
'MQTT_settings_group' => '<i class="fa fa-square-rss"></i> MQTT', 'MQTT_display_name' => 'MQTT',
'MQTT_icon' => '<i class="fa fa-square-rss"></i>',
'REPORT_MQTT_name' => 'Enable MQTT', 'REPORT_MQTT_name' => 'Enable MQTT',
'REPORT_MQTT_description' => 'Enable sending notifications via <a target="_blank" href="https://www.home-assistant.io/integrations/mqtt/">MQTT</a> to your Home Assistance instance.', 'REPORT_MQTT_description' => 'Enable sending notifications via <a target="_blank" href="https://www.home-assistant.io/integrations/mqtt/">MQTT</a> to your Home Assistance instance.',
'MQTT_BROKER_name' => 'MQTT broker URL', 'MQTT_BROKER_name' => 'MQTT broker URL',
@@ -602,7 +609,8 @@ the arp-scan will take hours to complete instead of seconds.
'MQTT_DELAY_SEC_description' => 'A little hack - delay adding to the queue in case the process is restarted and previous publish processes aborted (it takes ~<code>2</code>s to update a sensor config on the broker). Tested with <code>2</code>-<code>3</code> seconds of delay. This delay is only applied when devices are created (during the first notification loop). It doesn\'t affect subsequent scans or notifications.', 'MQTT_DELAY_SEC_description' => 'A little hack - delay adding to the queue in case the process is restarted and previous publish processes aborted (it takes ~<code>2</code>s to update a sensor config on the broker). Tested with <code>2</code>-<code>3</code> seconds of delay. This delay is only applied when devices are created (during the first notification loop). It doesn\'t affect subsequent scans or notifications.',
//DynDNS //DynDNS
'DynDNS_settings_group' => '<i class="fa fa-globe"></i> DynDNS', 'DynDNS_display_name' => 'DynDNS',
'DynDNS_icon' => '<i class="fa fa-globe"></i>',
'DDNS_ACTIVE_name' => 'Enable DynDNS', 'DDNS_ACTIVE_name' => 'Enable DynDNS',
'DDNS_ACTIVE_description' => '', 'DDNS_ACTIVE_description' => '',
'DDNS_DOMAIN_name' => 'DynDNS domain URL', 'DDNS_DOMAIN_name' => 'DynDNS domain URL',
@@ -615,14 +623,16 @@ the arp-scan will take hours to complete instead of seconds.
'DDNS_UPDATE_URL_description' => 'Update URL starting with <code>http://</code> or <code>https://</code>.', 'DDNS_UPDATE_URL_description' => 'Update URL starting with <code>http://</code> or <code>https://</code>.',
// PiHole // PiHole
'PiHole_settings_group' => '<i class="fa fa-seedling"></i> PiHole', 'PiHole_display_name' => 'PiHole',
'PiHole_icon' => '<i class="fa fa-seedling"></i>',
'PIHOLE_ACTIVE_name' => 'Enable PiHole mapping', 'PIHOLE_ACTIVE_name' => 'Enable PiHole mapping',
'PIHOLE_ACTIVE_description' => 'You need to map<code>:/etc/pihole/pihole-FTL.db</code> in the <code>docker-compose.yml</code> file if you enable this setting.', 'PIHOLE_ACTIVE_description' => 'You need to map<code>:/etc/pihole/pihole-FTL.db</code> in the <code>docker-compose.yml</code> file if you enable this setting.',
'DHCP_ACTIVE_name' => 'Enable PiHole DHCP', 'DHCP_ACTIVE_name' => 'Enable PiHole DHCP',
'DHCP_ACTIVE_description' => 'You need to map <code>:/etc/pihole/dhcp.leases</code> in the <code>docker-compose.yml</code> file if you enable this setting.', 'DHCP_ACTIVE_description' => 'You need to map <code>:/etc/pihole/dhcp.leases</code> in the <code>docker-compose.yml</code> file if you enable this setting.',
// Pholus // Pholus
'Pholus_settings_group' => '<i class="fa fa-search"></i> Pholus', 'Pholus_display_name' => 'Pholus',
'Pholus_icon' => '<i class="fa fa-search"></i>',
'PHOLUS_ACTIVE_name' => 'Cycle run', 'PHOLUS_ACTIVE_name' => 'Cycle run',
'PHOLUS_ACTIVE_description' => '<a href="https://github.com/jokob-sk/Pi.Alert/tree/main/pholus" target="_blank" >Pholus</a> is a sniffing tool to discover additional information about the devices on the network, including the device name. If enabled this will execute the scan before every network scan cycle until there are no <code>(unknown)</code> or <code>(name not found)</code> devices. Please be aware it can spam the network with unnecessary traffic. Depends on the <a onclick="toggleAllSettings()" href="#SCAN_SUBNETS"><code>SCAN_SUBNETS</code> setting</a>. For a scheduled or one-off scan, check the <a href="#PHOLUS_RUN"><code>PHOLUS_RUN</code> setting</a>.', 'PHOLUS_ACTIVE_description' => '<a href="https://github.com/jokob-sk/Pi.Alert/tree/main/pholus" target="_blank" >Pholus</a> is a sniffing tool to discover additional information about the devices on the network, including the device name. If enabled this will execute the scan before every network scan cycle until there are no <code>(unknown)</code> or <code>(name not found)</code> devices. Please be aware it can spam the network with unnecessary traffic. Depends on the <a onclick="toggleAllSettings()" href="#SCAN_SUBNETS"><code>SCAN_SUBNETS</code> setting</a>. For a scheduled or one-off scan, check the <a href="#PHOLUS_RUN"><code>PHOLUS_RUN</code> setting</a>.',
'PHOLUS_TIMEOUT_name' => 'Cycle run timeout', 'PHOLUS_TIMEOUT_name' => 'Cycle run timeout',
@@ -640,7 +650,8 @@ the arp-scan will take hours to complete instead of seconds.
'PHOLUS_DAYS_DATA_description' => 'How many days of Pholus scan entries should be kept (globally, not device specific!). The <a href="/maintenance.php#tab_Logging">pialert_pholus.log</a> file is not touched. Enter <code>0</code> to disable.', 'PHOLUS_DAYS_DATA_description' => 'How many days of Pholus scan entries should be kept (globally, not device specific!). The <a href="/maintenance.php#tab_Logging">pialert_pholus.log</a> file is not touched. Enter <code>0</code> to disable.',
// Nmap // Nmap
'Nmap_settings_group' => '<i class="fa fa-ethernet"></i> Nmap', 'Nmap_display_name' => 'Nmap',
'Nmap_icon' => '<i class="fa fa-ethernet"></i>',
'NMAP_ACTIVE_name' => 'Cycle run', 'NMAP_ACTIVE_name' => 'Cycle run',
'NMAP_ACTIVE_description' => 'If enabled this will execute a scan on a newly found device. For a scheduled or one-off scan, check the <a href="#NMAP_RUN"><code>NMAP_RUN</code> setting</a>.', 'NMAP_ACTIVE_description' => 'If enabled this will execute a scan on a newly found device. For a scheduled or one-off scan, check the <a href="#NMAP_RUN"><code>NMAP_RUN</code> setting</a>.',
'NMAP_TIMEOUT_name' => 'Run timeout', 'NMAP_TIMEOUT_name' => 'Run timeout',
@@ -653,7 +664,8 @@ the arp-scan will take hours to complete instead of seconds.
'NMAP_ARGS_description' => 'Arguments used to run the Nmap scan. Be careful to specify <a href="https://linux.die.net/man/1/nmap" target="_blank">the arguments</a> correctly. For example <code>-p -10000</code> scans ports from 1 to 10000.', 'NMAP_ARGS_description' => 'Arguments used to run the Nmap scan. Be careful to specify <a href="https://linux.die.net/man/1/nmap" target="_blank">the arguments</a> correctly. For example <code>-p -10000</code> scans ports from 1 to 10000.',
// API // API
'API_settings_group' => '<i class="fa fa-arrow-down-up-across-line"></i> API', 'API_display_name' => 'API',
'API_icon' => '<i class="fa fa-arrow-down-up-across-line"></i>',
'ENABLE_API_name' => 'Enable API', 'ENABLE_API_name' => 'Enable API',
'ENABLE_API_description' => 'If enabled the app will start publishing and updating <a href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md" target="_blank">simple API endpoints</a> under the <code>/home/pi/pialert/front/api/</code> folder and thus on the <code>pialert_url/api/File_name</code> url.', 'ENABLE_API_description' => 'If enabled the app will start publishing and updating <a href="https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md" target="_blank">simple API endpoints</a> under the <code>/home/pi/pialert/front/api/</code> folder and thus on the <code>pialert_url/api/File_name</code> url.',
'API_RUN_name' => 'Scheduling updates', 'API_RUN_name' => 'Scheduling updates',

View File

@@ -5,6 +5,7 @@
// ################################### // ###################################
$defaultLang = "en_us"; $defaultLang = "en_us";
$allLanguages = ["en_us","es_es","de_de"];
global $db; global $db;
@@ -17,6 +18,20 @@ switch($result){
if (isset($pia_lang_selected) == FALSE or (strlen($pia_lang_selected) == 0)) {$pia_lang_selected = $defaultLang;} if (isset($pia_lang_selected) == FALSE or (strlen($pia_lang_selected) == 0)) {$pia_lang_selected = $defaultLang;}
//Language_Strings ("Language_Code", "String_Key", "String_Value", "Extra")
$result = $db->query("SELECT * FROM Language_Strings");
// array
$strings = array();
while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
// Push row data
$strings[] = array( 'Language_Code' => $row['Language_Code'],
'String_Key' => $row['String_Key'],
'String_Value' => $row['String_Value'],
'Extra' => $row['Extra']
);
}
require dirname(__FILE__).'/../skinUI.php'; require dirname(__FILE__).'/../skinUI.php';
require dirname(__FILE__).'/en_us.php'; require dirname(__FILE__).'/en_us.php';
require dirname(__FILE__).'/de_de.php'; require dirname(__FILE__).'/de_de.php';
@@ -24,7 +39,13 @@ require dirname(__FILE__).'/es_es.php';
function lang($key) function lang($key)
{ {
global $pia_lang_selected, $lang, $defaultLang; global $pia_lang_selected, $lang, $defaultLang, $strings;
// get strings from the DB and append them to the ones from the files
foreach ($strings as $string)
{
$lang[$string["Language_Code"]][$string["String_Key"]] = $string["String_Value"];
}
// check if key exists in selected language // check if key exists in selected language
if(array_key_exists($key, $lang[$pia_lang_selected]) == FALSE) if(array_key_exists($key, $lang[$pia_lang_selected]) == FALSE)

View File

@@ -12,7 +12,7 @@ If you wish to develop a plugin, please check the existing plugin structure.
| `script.py` | yes | The Python script itself | | `script.py` | yes | The Python script itself |
| `last_result.log` | yes | The file used to interface between PiAlert and the plugin (script). | | `last_result.log` | yes | The file used to interface between PiAlert and the plugin (script). |
| `script.log` | no | Logging output (recommended) | | `script.log` | no | Logging output (recommended) |
| `README.md` | no | Amy setup considerations or overview | | `README.md` | no | Any setup considerations or overview (recommended) |
More on specific files below. More on specific files below.
@@ -21,7 +21,7 @@ More on specific files below.
Used to interface between PiAlert and the plugin (script). After every scan it should contain only the results from the latest scan/execution. Used to interface between PiAlert and the plugin (script). After every scan it should contain only the results from the latest scan/execution.
- The format is a `csv`-like file with the pipe `|` separator. 8 (eight) values need to be supplied, so every line needs to contain 7 pipe separators. Empty values arerepresented by `null` - The format is a `csv`-like file with the pipe `|` separator. 8 (eight) values need to be supplied, so every line needs to contain 7 pipe separators. Empty values are represented by `null`
- Don't render "headers" for these "columns" - Don't render "headers" for these "columns"
- Every scan result / event entry needs to be on a new line - Every scan result / event entry needs to be on a new line
- You can find which "columns" need to be present in the script results and if the value is required below. - You can find which "columns" need to be present in the script results and if the value is required below.
@@ -66,14 +66,37 @@ https://www.google.com|null|2023-01-02 15:56:30|200|0.7898|
### config.json ### config.json
#### Supported settings types ##### Setting object struncture
- `RUN` ```json
- `RUN_SCHD` {
- `API_SQL` "type": "RUN",
- `TIMEOUT` "default_value":"disabled",
- `NOTIFY_ON` "options": ["disabled", "once", "schedule", "always_after_scan", "on_new_device"],
- `ARGS` "localized": ["name", "description"],
"name" :[{
"language_code":"en_us",
"string" : "Run condition"
},
{
"language_code":"de_de",
"string" : "Ausführungsbedingung"
}],
"description": [{
"language_code":"en_us",
"string" : "Enable a regular scan of your services. If you select <code>schedule</code> the scheduling settings from below are applied. If you select <code>once</code> the scan is run only once on start of the application (container) for the time specified in <a href=\"#WEBMON_TIMEOUT\"><code>WEBMON_TIMEOUT</code> setting</a>."
}]
}
```
###### Supported settings types
- `RUN` - (required) Specifies when the service is executed
- Supported Options: "disabled", "once", "schedule" (if included then a `RUN_SCHD` setting needs to be specified), "always_after_scan", "on_new_device"
- `RUN_SCHD` - (required if you include the `RUN`) Cron-like scheduling used if the `RUN` setting set to `schedule`
- `CMD` - (required) What command should be executed.
- `API_SQL` - (optional) Generates a `table_` + code_name + `.json` file as per (API docs)[https://github.com/jokob-sk/Pi.Alert/blob/main/docs/API.md].
- `TIMEOUT` - (optional) Max execution time of the script. If not specified a default value of 10 seconds is used to prevent hanging.
- `WATCH` - (optional) Which database columns are watched for changes. If not specified no notifications are sent.
#### Example #### Example
@@ -82,102 +105,157 @@ https://www.google.com|null|2023-01-02 15:56:30|200|0.7898|
{ {
"code_name": "website_monitor", "code_name": "website_monitor",
"settings_short_prefix": "WEBMON", "settings_short_prefix": "WEBMON",
"display_name" : "Website monitor", "localized": ["display_name", "description", "icon"],
"font_awesome_icon_classses": "fa-solid fa-globe", "display_name" : [{
"description": { "language_code":"en_us",
"en_us" : "This plugin is to monitor status changes of different services or websites." "string" : "Website monitor"
}, }],
"icon":[{
"language_code":"en_us",
"string" : "<i class=\"fa-solid fa-globe\"></i>"
}],
"argument" : "urls",
"description": [{
"language_code":"en_us",
"string" : "This plugin is to monitor status changes of different services or websites."
}],
"database_column_aliases":{ "database_column_aliases":{
"Plugins_Events":{ "Plugins_Events":{
"Index":{ "Index":[{
"en_us" : "Index" "language_code":"en_us",
}, "string" : "Index"
"Object_PrimaryID":{ }],
"en_us" : "Monitored URL" "Object_PrimaryID":[{
}, "language_code":"en_us",
"DateTime":{ "string" : "Monitored URL"
"en_us" : "Checked on" }],
}, "DateTime":[{
"Watched_Value1":{ "language_code":"en_us",
"en_us" : "Status code" "string" : "Checked on"
}, }],
"Watched_Value2":{ "Watched_Value1":[{
"en_us" : "Latency" "language_code":"en_us",
} "string" : "Status code"
}],
"Watched_Value2":[{
"language_code":"en_us",
"string" : "Latency"
}]
} }
}, },
"settings":[ "settings":[
{
"type": "ENABLE",
"default_value":"False",
"options": [],
"localized": ["name", "description"],
"name" : [{
"language_code":"en_us",
"string" : "Enable plugin"
}],
"description": [{
"language_code":"en_us",
"string" : "Enable a regular scan of your services. You need to enable this setting for anything to be executed regarding this plugin."
}]
},
{ {
"type": "RUN", "type": "RUN",
"default_value":"none", "default_value":"none",
"options": ["none","once","schedule"], "options": ["none","once","schedule"],
"name" : { "localized": ["name", "description"],
"en_us" : "Schedule" "name" :[{
}, "language_code":"en_us",
"description": "string" : "Schedule"
{ }],
"en_us" : "Enable a regular scan of your services. If you select <code>schedule</code> the scheduling settings from below are applied. If you select <code>once</code> the scan is run only once on start of the application (container) for the time specified in <a href=\"#WEBMON_TIMEOUT\"><code>WEBMON_TIMEOUT</code> setting</a>." "description": [{
} "language_code":"en_us",
"string" : "Enable a regular scan of your services. If you select <code>schedule</code> the scheduling settings from below are applied. If you select <code>once</code> the scan is run only once on start of the application (container) for the time specified in <a href=\"#WEBMON_TIMEOUT\"><code>WEBMON_TIMEOUT</code> setting</a>."
}]
},
{
"type": "FORCE_REPORT",
"default_value": false,
"options": [],
"localized": ["name", "description"],
"name" : [{
"language_code":"en_us",
"string" : "Force report"
}],
"description": [{
"language_code":"en_us",
"string" : "Force a notification message even if there are nochanges detected."
}]
}, },
{ {
"type": "RUN_SCHD", "type": "RUN_SCHD",
"default_value":"0 2 * * *", "default_value":"0 2 * * *",
"name" : { "options": [],
"en_us" : "Schedule" "localized": ["name", "description"],
}, "name" : [{
"description": "language_code":"en_us",
{ "string" : "Schedule"
"en_us" : "Only enabled if you select <code>schedule</code> in the <a href=\"#WEBMON_RUN\"><code>WEBMON_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes." }],
} "description": [{
"language_code":"en_us",
"string" : "Only enabled if you select <code>schedule</code> in the <a href=\"#WEBMON_RUN\"><code>WEBMON_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
}]
}, },
{ {
"type": "API_SQL", "type": "API_SQL",
"default_value":"SELECT * FROM plugin_website_monitor", "default_value":"SELECT * FROM plugin_website_monitor",
"name" : { "options": [],
"en_us" : "API endpoint" "localized": ["name", "description"],
}, "name" : [{
"description": "language_code":"en_us",
{ "string" : "API endpoint"
"en_us" : "You can specify a custom SQL query which will generate a JSON file and then expose it via the <a href=\"/api/plugin_website_monitor.json\" target=\"_blank\"><code>plugin_website_monitor.json</code> file endpoint</a>." }],
} "description": [{
"language_code":"en_us",
"string" : "You can specify a custom SQL query which will generate a JSON file and then expose it via the <a href=\"/api/plugin_website_monitor.json\" target=\"_blank\"><code>plugin_website_monitor.json</code> file endpoint</a>."
}]
}, },
{ {
"type": "TIMEOUT", "type": "RUN_TIMEOUT",
"default_value":5, "default_value":5,
"name" : { "options": [],
"en_us" : "Run timeout" "localized": ["name", "description"],
}, "name" : [{
"description": "language_code":"en_us",
{ "string" : "Run timeout"
"en_us" : "Maximum time in seconds to wait for a Website monitor check to finish for any url." }],
} "description": [{
"language_code":"en_us",
"string" : "Maximum time in seconds to wait for a Website monitor check to finish for any url."
}]
}, },
{ {
"type": "NOTIFY_ON", "type": "WATCH",
"default_value":["Watched_Value1"], "default_value":["Watched_Value1"],
"options": ["Watched_Value1","Watched_Value2","Watched_Value3","Watched_Value4"], "options": ["Watched_Value1","Watched_Value2","Watched_Value3","Watched_Value4"],
"name" : { "localized": ["name", "description"],
"en_us" : "Notify on" "name" :[{
}, "language_code":"en_us",
"description": "string" : "Notify on"
{ }] ,
"en_us" : "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is response status code (e.g.: 200, 404)</li><li><code>Watched_Value2</code> is Latency (not recommended)</li><li><code>Watched_Value3</code> unused </li><li><code>Watched_Value4</code> unused </li></ul>" "description":[{
} "language_code":"en_us",
"string" : "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is response status code (e.g.: 200, 404)</li><li><code>Watched_Value2</code> is Latency (not recommended)</li><li><code>Watched_Value3</code> unused </li><li><code>Watched_Value4</code> unused </li></ul>"
}]
}, },
{ {
"type": "ARGS", "type": "ARGS",
"default_value":"", "default_value":"",
"name" : { "options": [],
"en_us" : "Run timeout" "localized": ["name", "description"],
}, "name" : [{
"description": "language_code":"en_us",
{ "string" : "Arguments"
"en_us" : "Change the <a href=\"https://linux.die.net/man/1/dig\" target=\"_blank\">dig utility</a> arguments if you have issues resolving your Internet IP. Arguments are added at the end of the following command: <code>dig +short </code>." }],
} "description": [{
"language_code":"en_us",
"string" : "Change the <a href=\"https://linux.die.net/man/1/dig\" target=\"_blank\">dig utility</a> arguments if you have issues resolving your Internet IP. Arguments are added at the end of the following command: <code>dig +short </code>."
}]
} }
] ]
@@ -185,4 +263,5 @@ https://www.google.com|null|2023-01-02 15:56:30|200|0.7898|
``` ```

View File

@@ -1,132 +1,170 @@
{ {
"code_name": "website_monitor", "code_name": "website_monitor",
"settings_short_prefix": "WEBMON", "settings_short_prefix": "WEBMON",
"display_name" : "Website monitor", "localized": ["display_name", "description", "icon"],
"font_awesome_icon_classses": "fa-solid fa-globe", "display_name" : [{
"description": { "language_code":"en_us",
"en_us" : "This plugin is to monitor status changes of different services or websites." "string" : "Website monitor"
}],
"icon":[{
"language_code":"en_us",
"string" : "<i class=\"fa-solid fa-globe\"></i>"
}],
"description": [{
"language_code":"en_us",
"string" : "This plugin is to monitor status changes of different services or websites."
}],
"params" : [{
"name" : "macs",
"type" : "sql",
"value" : "SELECT dev_MAC from DEVICES"
}, },
{
"name" : "sites",
"type" : "setting",
"value" : "WEBMON_LIST"
}],
"database_column_aliases":{ "database_column_aliases":{
"Plugins_Events":{ "Plugins_Events":{
"Index":{ "Index":[{
"en_us" : "Index" "language_code":"en_us",
}, "string" : "Index"
"Object_PrimaryID":{ }],
"en_us" : "Monitored URL" "Object_PrimaryID":[{
}, "language_code":"en_us",
"DateTime":{ "string" : "Monitored URL"
"en_us" : "Checked on" }],
}, "DateTime":[{
"Watched_Value1":{ "language_code":"en_us",
"en_us" : "Status code" "string" : "Checked on"
}, }],
"Watched_Value2":{ "Watched_Value1":[{
"en_us" : "Latency" "language_code":"en_us",
} "string" : "Status code"
}],
"Watched_Value2":[{
"language_code":"en_us",
"string" : "Latency"
}]
} }
}, },
"settings":[ "settings":[
{
"type": "ENABLE",
"default_value":"False",
"options": [],
"name" : {
"en_us" : "Enable plugin"
},
"description":
{
"en_us" : "Enable a regular scan of your services. You need to enable this setting for anything to be executed regarding this plugin."
}
},
{ {
"type": "RUN", "type": "RUN",
"default_value":"none", "default_value":"disabled",
"options": ["none","once","schedule"], "options": ["disabled", "once", "schedule", "always_after_scan", "on_new_device"],
"name" : { "localized": ["name", "description"],
"en_us" : "Schedule" "name" :[{
}, "language_code":"en_us",
"description": "string" : "Run condition"
{ }],
"en_us" : "Enable a regular scan of your services. If you select <code>schedule</code> the scheduling settings from below are applied. If you select <code>once</code> the scan is run only once on start of the application (container) for the time specified in <a href=\"#WEBMON_TIMEOUT\"><code>WEBMON_TIMEOUT</code> setting</a>." "description": [{
} "language_code":"en_us",
"string" : "Enable a regular scan of your services. If you select <code>schedule</code> the scheduling settings from below are applied. If you select <code>once</code> the scan is run only once on start of the application (container) for the time specified in <a href=\"#WEBMON_TIMEOUT\"><code>WEBMON_TIMEOUT</code> setting</a>."
}]
}, },
{ {
"type": "FORCE_REPORT", "type": "FORCE_REPORT",
"default_value": false, "default_value": false,
"options": [], "options": [],
"name" : { "localized": ["name", "description"],
"en_us" : "Schedule" "name" : [{
"language_code":"en_us",
"string" : "Force report"
}, },
"description": {
{ "language_code":"de_de",
"en_us" : "Enable a regular scan of your services. If you select <code>schedule</code> the scheduling settings from below are applied. If you select <code>once</code> the scan is run only once on start of the application (container) for the time specified in <a href=\"#WEBMON_TIMEOUT\"><code>WEBMON_TIMEOUT</code> setting</a>." "string" : "Zwing Bericht"
} }],
"description": [{
"language_code":"en_us",
"string" : "Force a notification message even if there are no changes detected."
}]
}, },
{ {
"type": "RUN_SCHD", "type": "RUN_SCHD",
"default_value":"0 2 * * *", "default_value":"0 2 * * *",
"options": [], "options": [],
"name" : { "localized": ["name", "description"],
"en_us" : "Schedule" "name" : [{
}, "language_code":"en_us",
"description": "string" : "Schedule"
{ }],
"en_us" : "Only enabled if you select <code>schedule</code> in the <a href=\"#WEBMON_RUN\"><code>WEBMON_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes." "description": [{
} "language_code":"en_us",
"string" : "Only enabled if you select <code>schedule</code> in the <a href=\"#WEBMON_RUN\"><code>WEBMON_RUN</code> setting</a>. Make sure you enter the schedule in the correct cron-like format (e.g. validate at <a href=\"https://crontab.guru/\" target=\"_blank\">crontab.guru</a>). For example entering <code>0 4 * * *</code> will run the scan after 4 am in the <a onclick=\"toggleAllSettings()\" href=\"#TIMEZONE\"><code>TIMEZONE</code> you set above</a>. Will be run NEXT time the time passes."
}]
}, },
{ {
"type": "API_SQL", "type": "API_SQL",
"default_value":"SELECT * FROM plugin_website_monitor", "default_value":"SELECT * FROM plugin_website_monitor",
"options": [], "options": [],
"name" : { "localized": ["name", "description"],
"en_us" : "API endpoint" "name" : [{
}, "language_code":"en_us",
"description": "string" : "API endpoint"
{ }],
"en_us" : "You can specify a custom SQL query which will generate a JSON file and then expose it via the <a href=\"/api/plugin_website_monitor.json\" target=\"_blank\"><code>plugin_website_monitor.json</code> file endpoint</a>." "description": [{
} "language_code":"en_us",
"string" : "You can specify a custom SQL query which will generate a JSON file and then expose it via the <a href=\"/api/plugin_website_monitor.json\" target=\"_blank\"><code>plugin_website_monitor.json</code> file endpoint</a>."
}]
}, },
{ {
"type": "RUN_TIMEOUT", "type": "RUN_TIMEOUT",
"default_value":5, "default_value":5,
"options": [], "options": [],
"name" : { "localized": ["name", "description"],
"en_us" : "Run timeout" "name" : [{
}, "language_code":"en_us",
"description": "string" : "Run timeout"
{ }],
"en_us" : "Maximum time in seconds to wait for a Website monitor check to finish for any url." "description": [{
} "language_code":"en_us",
"string" : "Maximum time in seconds to wait for a Website monitor check to finish for any url."
}]
}, },
{ {
"type": "NOTIFY_ON", "type": "WATCH",
"default_value":["Watched_Value1"], "default_value":["Watched_Value1"],
"options": ["Watched_Value1","Watched_Value2","Watched_Value3","Watched_Value4"], "options": ["Watched_Value1","Watched_Value2","Watched_Value3","Watched_Value4"],
"name" : { "localized": ["name", "description"],
"en_us" : "Notify on" "name" :[{
}, "language_code":"en_us",
"description": "string" : "Notify on"
{ }] ,
"en_us" : "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is response status code (e.g.: 200, 404)</li><li><code>Watched_Value2</code> is Latency (not recommended)</li><li><code>Watched_Value3</code> unused </li><li><code>Watched_Value4</code> unused </li></ul>" "description":[{
} "language_code":"en_us",
"string" : "Send a notification if selected values change. Use <code>CTRL + Click</code> to select/deselect. <ul> <li><code>Watched_Value1</code> is response status code (e.g.: 200, 404)</li><li><code>Watched_Value2</code> is Latency (not recommended)</li><li><code>Watched_Value3</code> unused </li><li><code>Watched_Value4</code> unused </li></ul>"
}]
}, },
{ {
"type": "ARGS", "type": "CMD",
"default_value":"python3 script.py",
"options": [],
"localized": ["name", "description"],
"name" : [{
"language_code":"en_us",
"string" : "Command"
}],
"description": [{
"language_code":"en_us",
"string" : "Change the <a href=\"https://linux.die.net/man/1/dig\" target=\"_blank\">dig utility</a> arguments if you have issues resolving your Internet IP. Arguments are added at the end of the following command: <code>dig +short </code>."
}]
},
{
"type": "LIST",
"default_value":"", "default_value":"",
"options": [], "options": [],
"name" : { "localized": ["name", "description"],
"en_us" : "Run timeout" "name" : [{
}, "language_code":"en_us",
"description": "string" : "Arguments"
{ }],
"en_us" : "Change the <a href=\"https://linux.die.net/man/1/dig\" target=\"_blank\">dig utility</a> arguments if you have issues resolving your Internet IP. Arguments are added at the end of the following command: <code>dig +short </code>." "description": [{
} "language_code":"en_us",
"string" : "Change the <a href=\"https://linux.die.net/man/1/dig\" target=\"_blank\">dig utility</a> arguments if you have issues resolving your Internet IP. Arguments are added at the end of the following command: <code>dig +short </code>."
}]
} }
] ]

View File

@@ -14,6 +14,17 @@ $confPath = "../config/pialert.conf";
checkPermissions([$dbPath, $confPath]); checkPermissions([$dbPath, $confPath]);
// get settings from the API json file
// path to your JSON file
$file = '../front/api/table_settings.json';
// put the content of the file in a variable
$data = file_get_contents($file);
// JSON decode
$settingsJson = json_decode($data);
// get settings from the DB
global $db; global $db;
$result = $db->query("SELECT * FROM Settings"); $result = $db->query("SELECT * FROM Settings");
@@ -72,7 +83,7 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
$html = $html.'<div class=" box panel panel-default"> $html = $html.'<div class=" box panel panel-default">
<a data-toggle="collapse" data-parent="#accordion_gen" href="#'.$group.'"> <a data-toggle="collapse" data-parent="#accordion_gen" href="#'.$group.'">
<div class="panel-heading"> <div class="panel-heading">
<h4 class="panel-title">'.lang($group.'_settings_group').'</h4> <h4 class="panel-title">'.lang($group.'_icon')." ".lang($group.'_display_name').'</h4>
</div> </div>
</a> </a>
<div id="'.$group.'" data-myid="collapsible" class="panel-collapse collapse '.$isIn.'"> <div id="'.$group.'" data-myid="collapsible" class="panel-collapse collapse '.$isIn.'">
@@ -280,7 +291,10 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
<script> <script>
// number of settings has to be equal to // number of settings has to be equal to
var settingsNumber = 68;
// display the name of the first person
// echo $settingsJson[0]->name;
var settingsNumber = <?php echo count($settingsJson->data)?>;
// Wrong number of settings processing // Wrong number of settings processing
if(<?php echo count($settings)?> != settingsNumber) if(<?php echo count($settings)?> != settingsNumber)
@@ -288,8 +302,6 @@ while ($row = $result -> fetchArray (SQLITE3_ASSOC)) {
showModalOk('WARNING', "<?= lang("settings_missing")?>"); showModalOk('WARNING', "<?= lang("settings_missing")?>");
} }
// --------------------------------------------------------- // ---------------------------------------------------------
function addInterface() function addInterface()
{ {