Plugins 0.4 - ForeignKey support added

This commit is contained in:
Jokob-sk
2023-03-11 13:57:25 +11:00
parent d090b29c55
commit 2d0a4b79d8
7 changed files with 145 additions and 85 deletions

View File

@@ -40,6 +40,7 @@ from pathlib import Path
from cron_converter import Cron from cron_converter import Cron
from pytz import timezone from pytz import timezone
from json2table import convert from json2table import convert
import hashlib
#=============================================================================== #===============================================================================
# SQL queries # SQL queries
@@ -54,7 +55,7 @@ sql_settings = "SELECT * FROM Settings"
sql_plugins_objects = "SELECT * FROM Plugins_Objects" sql_plugins_objects = "SELECT * FROM Plugins_Objects"
sql_language_strings = "SELECT * FROM Plugins_Language_Strings" sql_language_strings = "SELECT * FROM Plugins_Language_Strings"
sql_plugins_events = "SELECT * FROM Plugins_Events" sql_plugins_events = "SELECT * FROM Plugins_Events"
sql_plugins_history = "SELECT * FROM Plugins_History ORDER BY 'Index' DESC LIMIT 50" sql_plugins_history = "SELECT * FROM Plugins_History ORDER BY 'Index' DESC"
sql_new_devices = """SELECT * FROM ( SELECT eve_IP as dev_LastIP, eve_MAC as dev_MAC FROM Events_Devices sql_new_devices = """SELECT * FROM ( SELECT eve_IP as dev_LastIP, eve_MAC as dev_MAC FROM Events_Devices
WHERE eve_PendingAlertEmail = 1 WHERE eve_PendingAlertEmail = 1
AND eve_EventType = 'New Device' AND eve_EventType = 'New Device'
@@ -159,7 +160,7 @@ def print_log (pText):
# Print line + time + elapsed time + text # Print line + time + elapsed time + text
file_print ('[LOG_LEVEL=debug] ', file_print ('[LOG_LEVEL=debug] ',
# log_timestamp2, ' ', # log_timestamp2, ' ',
log_timestamp2.replace(microsecond=0) - log_timestamp.replace(microsecond=0), ' ', log_timestamp2.strftime ('%H:%M:%S'), ' ',
pText) pText)
# Save current time to calculate elapsed time until next log # Save current time to calculate elapsed time until next log
@@ -465,10 +466,10 @@ def importConfigs ():
# ----------------- # -----------------
plugins = get_plugins_configs() plugins = get_plugins_configs()
mylog('none', ['[', timeNow(), '] Plugins: Number of dynamically loaded plugins: ', len(plugins.list)]) mylog('none', ['[', timeNow(), '] Plugins: Number of dynamically loaded plugins: ', len(plugins)])
# handle plugins # handle plugins
for plugin in plugins.list: for plugin in plugins:
print_plugin_info(plugin, ['display_name','description']) print_plugin_info(plugin, ['display_name','description'])
pref = plugin["unique_prefix"] pref = plugin["unique_prefix"]
@@ -3157,6 +3158,7 @@ def upgradeDB ():
Status TEXT NOT NULL, Status TEXT NOT NULL,
Extra TEXT NOT NULL, Extra TEXT NOT NULL,
UserData TEXT NOT NULL, UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT) PRIMARY KEY("Index" AUTOINCREMENT)
); """ ); """
sql.execute(sql_Plugins_Objects) sql.execute(sql_Plugins_Objects)
@@ -3176,6 +3178,7 @@ def upgradeDB ():
Status TEXT NOT NULL, Status TEXT NOT NULL,
Extra TEXT NOT NULL, Extra TEXT NOT NULL,
UserData TEXT NOT NULL, UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT) PRIMARY KEY("Index" AUTOINCREMENT)
); """ ); """
sql.execute(sql_Plugins_Events) sql.execute(sql_Plugins_Events)
@@ -3195,6 +3198,7 @@ def upgradeDB ():
Status TEXT NOT NULL, Status TEXT NOT NULL,
Extra TEXT NOT NULL, Extra TEXT NOT NULL,
UserData TEXT NOT NULL, UserData TEXT NOT NULL,
ForeignKey TEXT NOT NULL,
PRIMARY KEY("Index" AUTOINCREMENT) PRIMARY KEY("Index" AUTOINCREMENT)
); """ ); """
sql.execute(sql_Plugins_History) sql.execute(sql_Plugins_History)
@@ -3273,7 +3277,7 @@ def update_api(isNotification = False, updateOnlyDataSources = []):
write_file(folder + 'notification_json_final.json' , json.dumps(json_final)) write_file(folder + 'notification_json_final.json' , json.dumps(json_final))
# Save plugins # Save plugins
write_file(folder + 'plugins.json' , json.dumps({"data" : plugins.list})) write_file(folder + 'plugins.json' , json.dumps({"data" : plugins}))
# prepare databse tables we want to expose # prepare databse tables we want to expose
dataSourcesSQLs = [ dataSourcesSQLs = [
@@ -3666,19 +3670,13 @@ def isNewVersion():
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def get_plugins_configs(): def get_plugins_configs():
pluginsDict = []
pluginsList = [] 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
pluginsList.append(json.loads(get_file_content(pluginsPath + "/" + d + '/config.json'))) pluginsList.append(json.loads(get_file_content(pluginsPath + "/" + d + '/config.json')))
return plugins_class(pluginsDict, pluginsList) return pluginsList
#-------------------------------------------------------------------------------
class plugins_class:
def __init__(self, list):
self.list = list
#------------------------------------------------------------------------------- #-------------------------------------------------------------------------------
def collect_lang_strings(json, pref): def collect_lang_strings(json, pref):
@@ -3710,7 +3708,7 @@ def run_plugin_scripts(runType):
mylog('debug', [' [Plugins] Check if any plugins need to be executed on run type: ', runType]) mylog('debug', [' [Plugins] Check if any plugins need to be executed on run type: ', runType])
for plugin in plugins.list: for plugin in plugins:
shouldRun = False shouldRun = False
@@ -3823,9 +3821,9 @@ def execute_plugin(plugin):
for line in newLines: for line in newLines:
columns = line.split("|") columns = line.split("|")
# There has to be always 8 columns # There has to be always 9 columns
if len(columns) == 8: if len(columns) == 9:
sqlParams.append((plugin["unique_prefix"], columns[0], columns[1], 'null', columns[2], columns[3], columns[4], columns[5], columns[6], 0, columns[7], 'null')) sqlParams.append((plugin["unique_prefix"], columns[0], columns[1], 'null', columns[2], columns[3], columns[4], columns[5], columns[6], 0, columns[7], 'null', columns[8]))
else: else:
mylog('none', [' [Plugins]: Skipped invalid line in the output: ', line]) mylog('none', [' [Plugins]: Skipped invalid line in the output: ', line])
@@ -3844,9 +3842,9 @@ def execute_plugin(plugin):
arr = get_sql_array (q) arr = get_sql_array (q)
for row in arr: for row in arr:
# There has to be always 8 columns # There has to be always 9 columns
if len(row) == 8: if len(row) == 9:
sqlParams.append((plugin["unique_prefix"], row[0], row[1], 'null', row[2], row[3], row[4], row[5], row[6], 0, row[7], 'null')) sqlParams.append((plugin["unique_prefix"], row[0], row[1], 'null', row[2], row[3], row[4], row[5], row[6], 0, row[7], 'null', row[8]))
else: else:
mylog('none', [' [Plugins]: Skipped invalid sql result']) mylog('none', [' [Plugins]: Skipped invalid sql result'])
@@ -3860,9 +3858,9 @@ def execute_plugin(plugin):
# process results if any # process results if any
if len(sqlParams) > 0: if len(sqlParams) > 0:
sql.executemany ("""INSERT INTO Plugins_Events ("Plugin", "Object_PrimaryID", "Object_SecondaryID", "DateTimeCreated", "DateTimeChanged", "Watched_Value1", "Watched_Value2", "Watched_Value3", "Watched_Value4", "Status" ,"Extra", "UserData") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", sqlParams) sql.executemany ("""INSERT INTO Plugins_Events ("Plugin", "Object_PrimaryID", "Object_SecondaryID", "DateTimeCreated", "DateTimeChanged", "Watched_Value1", "Watched_Value2", "Watched_Value3", "Watched_Value4", "Status" ,"Extra", "UserData", "ForeignKey") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", sqlParams)
commitDB () commitDB ()
sql.executemany ("""INSERT INTO Plugins_History ("Plugin", "Object_PrimaryID", "Object_SecondaryID", "DateTimeCreated", "DateTimeChanged", "Watched_Value1", "Watched_Value2", "Watched_Value3", "Watched_Value4", "Status" ,"Extra", "UserData") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", sqlParams) sql.executemany ("""INSERT INTO Plugins_History ("Plugin", "Object_PrimaryID", "Object_SecondaryID", "DateTimeCreated", "DateTimeChanged", "Watched_Value1", "Watched_Value2", "Watched_Value3", "Watched_Value4", "Status" ,"Extra", "UserData", "ForeignKey") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)""", sqlParams)
commitDB () commitDB ()
process_plugin_events(plugin) process_plugin_events(plugin)
@@ -3948,9 +3946,9 @@ def process_plugin_events(plugin):
createdTime = plugObj.changed createdTime = plugObj.changed
sql.execute ("INSERT INTO Plugins_Objects (Plugin, Object_PrimaryID, Object_SecondaryID, DateTimeCreated, DateTimeChanged, Watched_Value1, Watched_Value2, Watched_Value3, Watched_Value4, Status, Extra, UserData) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", (plugObj.pluginPref, plugObj.primaryId , plugObj.secondaryId , createdTime, plugObj.changed , plugObj.watched1 , plugObj.watched2 , plugObj.watched3 , plugObj.watched4 , plugObj.status , plugObj.extra, plugObj.userData )) sql.execute ("INSERT INTO Plugins_Objects (Plugin, Object_PrimaryID, Object_SecondaryID, DateTimeCreated, DateTimeChanged, Watched_Value1, Watched_Value2, Watched_Value3, Watched_Value4, Status, Extra, UserData, ForeignKey) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", (plugObj.pluginPref, plugObj.primaryId , plugObj.secondaryId , createdTime, plugObj.changed , plugObj.watched1 , plugObj.watched2 , plugObj.watched3 , plugObj.watched4 , plugObj.status , plugObj.extra, plugObj.userData, plugObj.foreignKey ))
else: else:
q = f"UPDATE Plugins_Objects set Plugin = '{plugObj.pluginPref}', DateTimeChanged = '{plugObj.changed}', Watched_Value1 = '{plugObj.watched1}', Watched_Value2 = '{plugObj.watched2}', Watched_Value3 = '{plugObj.watched3}', Watched_Value4 = '{plugObj.watched4}', Status = '{plugObj.status}', Extra = '{plugObj.extra}' WHERE 'Index' = {plugObj.index}" q = f"UPDATE Plugins_Objects set Plugin = '{plugObj.pluginPref}', DateTimeChanged = '{plugObj.changed}', Watched_Value1 = '{plugObj.watched1}', Watched_Value2 = '{plugObj.watched2}', Watched_Value3 = '{plugObj.watched3}', Watched_Value4 = '{plugObj.watched4}', Status = '{plugObj.status}', Extra = '{plugObj.extra}', ForeignKey = '{plugObj.foreignKey}' WHERE 'Index' = {plugObj.index}"
sql.execute (q) sql.execute (q)
@@ -3964,7 +3962,7 @@ def process_plugin_events(plugin):
if plugObj.status == 'new': if plugObj.status == 'new':
createdTime = plugObj.changed createdTime = plugObj.changed
sql.execute ("INSERT INTO Plugins_Events (Plugin, Object_PrimaryID, Object_SecondaryID, DateTimeCreated, DateTimeChanged, Watched_Value1, Watched_Value2, Watched_Value3, Watched_Value4, Status, Extra, UserData) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", (plugObj.pluginPref, plugObj.primaryId , plugObj.secondaryId , createdTime, plugObj.changed , plugObj.watched1 , plugObj.watched2 , plugObj.watched3 , plugObj.watched4 , plugObj.status , plugObj.extra, plugObj.userData )) sql.execute ("INSERT INTO Plugins_Events (Plugin, Object_PrimaryID, Object_SecondaryID, DateTimeCreated, DateTimeChanged, Watched_Value1, Watched_Value2, Watched_Value3, Watched_Value4, Status, Extra, UserData, ForeignKey) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?)", (plugObj.pluginPref, plugObj.primaryId , plugObj.secondaryId , createdTime, plugObj.changed , plugObj.watched1 , plugObj.watched2 , plugObj.watched3 , plugObj.watched4 , plugObj.status , plugObj.extra, plugObj.userData, plugObj.foreignKey ))
commitDB() commitDB()
@@ -3984,8 +3982,10 @@ class plugin_object_class:
self.status = objDbRow[10] self.status = objDbRow[10]
self.extra = objDbRow[11] self.extra = objDbRow[11]
self.userData = objDbRow[12] self.userData = objDbRow[12]
self.foreignKey = objDbRow[13]
self.idsHash = str(hash(str(self.primaryId) + str(self.secondaryId))) # self.idsHash = str(hash(str(self.primaryId) + str(self.secondaryId)))
self.idsHash = str(self.primaryId) + str(self.secondaryId)
self.watchedClmns = [] self.watchedClmns = []
self.watchedIndxs = [] self.watchedIndxs = []

View File

@@ -40,8 +40,8 @@
$expireMinutes = $_REQUEST['expireMinutes']; $expireMinutes = $_REQUEST['expireMinutes'];
} }
if (isset ($_REQUEST['key'])) { if (isset ($_REQUEST['columnName'])) {
$key = $_REQUEST['key']; $columnName = $_REQUEST['columnName'];
} }
if (isset ($_REQUEST['id'])) { if (isset ($_REQUEST['id'])) {
@@ -66,8 +66,8 @@
switch ($action) { switch ($action) {
case 'create': create($skipCache, $defaultValue, $expireMinutes, $dbtable, $columns, $values ); break; case 'create': create($skipCache, $defaultValue, $expireMinutes, $dbtable, $columns, $values ); break;
// case 'read' : read($skipCache, $defaultValue, $expireMinutes, $dbtable, $columns, $values); break; // case 'read' : read($skipCache, $defaultValue, $expireMinutes, $dbtable, $columns, $values); break;
case 'update': update($key, $id, $skipCache, $defaultValue, $expireMinutes, $dbtable, $columns, $values); break; case 'update': update($columnName, $id, $skipCache, $defaultValue, $expireMinutes, $dbtable, $columns, $values); break;
case 'delete': delete($key, $id, $dbtable); break; case 'delete': delete($columnName, $id, $dbtable); break;
default: logServerConsole ('Action: '. $action); break; default: logServerConsole ('Action: '. $action); break;
} }
} }
@@ -76,7 +76,7 @@
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// update // update
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
function update($key, $id, $skipCache, $defaultValue, $expireMinutes, $dbtable, $columns, $values) { function update($columnName, $id, $skipCache, $defaultValue, $expireMinutes, $dbtable, $columns, $values) {
global $db; global $db;
@@ -111,7 +111,7 @@ function update($key, $id, $skipCache, $defaultValue, $expireMinutes, $dbtable,
// Update value // Update value
$sql = 'UPDATE '.$dbtable.' SET '. $columnValues .' $sql = 'UPDATE '.$dbtable.' SET '. $columnValues .'
WHERE "'. $key .'"="'. $id.'"'; WHERE "'. $columnName .'"="'. $id.'"';
$result = $db->query($sql); $result = $db->query($sql);
if (! $result == TRUE) { if (! $result == TRUE) {
@@ -155,7 +155,7 @@ function create($skipCache, $defaultValue, $expireMinutes, $dbtable, $columns, $
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
// delete // delete
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
function delete($key, $id, $dbtable) function delete($columnName, $id, $dbtable)
{ {
global $db; global $db;
@@ -168,13 +168,24 @@ function delete($key, $id, $dbtable)
$idsArr = array($id); $idsArr = array($id);
} }
$idsStr = "";
foreach ($idsArr as $item)
{
$idsStr = $idsStr . '"' .$item.'"';
}
// Insert new value // Insert new value
$sql = 'DELETE FROM '.$dbtable.' WHERE "'.$key.'" IN ('. $id .')'; $sql = 'DELETE FROM '.$dbtable.' WHERE "'.$columnName.'" IN ('. $idsStr .')';
$result = $db->query($sql); $result = $db->query($sql);
if (! $result == TRUE) { if (! $result == TRUE) {
echo "Error deleting entry\n\n$sql \n\n". $db->lastErrorMsg(); echo "Error deleting entry\n\n$sql \n\n". $db->lastErrorMsg();
return; return;
} else
{
echo lang('Gen_DataUpdatedUITakesTime');
return;
} }
} }

View File

@@ -13,6 +13,7 @@ $lang['en_us'] = array(
// General // General
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
'Gen_Delete' => 'Delete', 'Gen_Delete' => 'Delete',
'Gen_DeleteAll' => 'Delete all',
'Gen_Cancel' => 'Cancel', 'Gen_Cancel' => 'Cancel',
'Gen_Okay' => 'Ok', 'Gen_Okay' => 'Ok',
'Gen_Save' => 'Save', 'Gen_Save' => 'Save',
@@ -669,6 +670,8 @@ The arp-scan time itself depends on the number of IP addresses to check so set t
'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_display_name' => 'API',
'API_icon' => '<i class="fa fa-arrow-down-up-across-line"></i>',
'API_CUSTOM_SQL_name' => 'Custom endpoint', 'API_CUSTOM_SQL_name' => 'Custom endpoint',
'API_CUSTOM_SQL_description' => 'You can specify a custom SQL query which will generate a JSON file and then expose it via the <a href="/api/table_custom_endpoint.json" target="_blank"><code>table_custom_endpoint.json</code> file endpoint</a>.', 'API_CUSTOM_SQL_description' => 'You can specify a custom SQL query which will generate a JSON file and then expose it via the <a href="/api/table_custom_endpoint.json" target="_blank"><code>table_custom_endpoint.json</code> file endpoint</a>.',

View File

@@ -63,6 +63,9 @@ function getFormControl(dbColumnDef, value, index) {
case 'url': case 'url':
result = `<span><a href="${value}" target="_blank">${value}</a><span>`; result = `<span><a href="${value}" target="_blank">${value}</a><span>`;
break; break;
case 'devicemac':
result = `<span><a href="/deviceDetails.php?mac=${value}" target="_blank">${value}</a><span>`;
break;
case 'threshold': case 'threshold':
$.each(dbColumnDef.options, function(index, obj) { $.each(dbColumnDef.options, function(index, obj) {
if(Number(value) < obj.maximum && result == '') if(Number(value) < obj.maximum && result == '')
@@ -94,7 +97,7 @@ function saveData (id) {
index = $(`#${id}`).attr('data-my-index') index = $(`#${id}`).attr('data-my-index')
columnValue = $(`#${id}`).val() columnValue = $(`#${id}`).val()
$.get(`php/server/dbHelper.php?action=update&dbtable=Plugins_Objects&key=Index&id=${index}&columns=UserData&values=${columnValue}`, function(data) { $.get(`php/server/dbHelper.php?action=update&dbtable=Plugins_Objects&columnName=Index&id=${index}&columns=UserData&values=${columnValue}`, function(data) {
// var result = JSON.parse(data); // var result = JSON.parse(data);
console.log(data) console.log(data)
@@ -242,9 +245,13 @@ function generateTabs()
// Generate the history rows // Generate the history rows
var histCount = 0 var histCount = 0
var histCountDisplayed = 0
for(i=0;i<pluginHistory.length;i++) for(i=0;i<pluginHistory.length;i++)
{ {
if(pluginHistory[i].Plugin == obj.unique_prefix) if(pluginHistory[i].Plugin == obj.unique_prefix)
{
if(histCount < 50) // only display 50 entries to optimize performance
{ {
clm = "" clm = ""
@@ -253,7 +260,10 @@ function generateTabs()
clm += '<td>'+ pluginHistory[i][colDefinitions[j].column] +'</td>' clm += '<td>'+ pluginHistory[i][colDefinitions[j].column] +'</td>'
} }
hiRows += `<tr data-my-index="${pluginHistory[i]["Index"]}" >${clm}</tr>` hiRows += `<tr data-my-index="${pluginHistory[i]["Index"]}" >${clm}</tr>`
histCount++;
histCountDisplayed++;
}
histCount++; // count and display the total
} }
} }
@@ -299,7 +309,7 @@ function generateTabs()
<li > <li >
<a href="#historyTarget_${obj.unique_prefix}" data-toggle="tab" > <a href="#historyTarget_${obj.unique_prefix}" data-toggle="tab" >
<i class="fa fa-clock"></i> <?= lang('Plugins_History');?> (${histCount}) <i class="fa fa-clock"></i> <?= lang('Plugins_History');?> (${histCountDisplayed} out of ${histCount} )
</a> </a>
</li> </li>
@@ -320,7 +330,7 @@ function generateTabs()
</tbody> </tbody>
</table> </table>
<div class="plugin-obj-purge"> <div class="plugin-obj-purge">
<button class="btn btn-primary" onclick="purgeAll('${obj.unique_prefix}', 'Plugins_Objects' )"><?= lang('Gen_Purge');?></button> <button class="btn btn-primary" onclick="purgeAll('${obj.unique_prefix}', 'Plugins_Objects' )"><?= lang('Gen_DeleteAll');?></button>
</div> </div>
</div> </div>
<div id="eventsTarget_${obj.unique_prefix}" class="tab-pane"> <div id="eventsTarget_${obj.unique_prefix}" class="tab-pane">
@@ -334,7 +344,7 @@ function generateTabs()
</tbody> </tbody>
</table> </table>
<div class="plugin-obj-purge"> <div class="plugin-obj-purge">
<button class="btn btn-primary" onclick="purgeAll('${obj.unique_prefix}', 'Plugins_Events' )"><?= lang('Gen_Purge');?></button> <button class="btn btn-primary" onclick="purgeAll('${obj.unique_prefix}', 'Plugins_Events' )"><?= lang('Gen_DeleteAll');?></button>
</div> </div>
</div> </div>
<div id="historyTarget_${obj.unique_prefix}" class="tab-pane"> <div id="historyTarget_${obj.unique_prefix}" class="tab-pane">
@@ -348,7 +358,7 @@ function generateTabs()
</tbody> </tbody>
</table> </table>
<div class="plugin-obj-purge"> <div class="plugin-obj-purge">
<button class="btn btn-primary" onclick="purgeAll('${obj.unique_prefix}', 'Plugins_History' )"><?= lang('Gen_Purge');?></button> <button class="btn btn-primary" onclick="purgeAll('${obj.unique_prefix}', 'Plugins_History' )"><?= lang('Gen_DeleteAll');?></button>
</div> </div>
</div> </div>
@@ -373,8 +383,6 @@ function generateTabs()
// -------------------------------------------------------- // --------------------------------------------------------
// handle first tab (objectsTarget_) display // handle first tab (objectsTarget_) display
var lastPrefix = ''
function initTabs() function initTabs()
{ {
// events on tab change // events on tab change
@@ -384,26 +392,28 @@ function initTabs()
// save the last prefix // save the last prefix
if(target.includes('_') == false ) if(target.includes('_') == false )
{ {
lastPrefix = target.split('#')[1] pref = target.split('#')[1]
} else
{
pref = target.split('_')[1]
} }
everythingHidden = false; everythingHidden = false;
if($('#objectsTarget_'+ lastPrefix) && $('#historyTarget_'+ lastPrefix) && $('#eventsTarget_'+ lastPrefix)) if($('#objectsTarget_'+ pref) != undefined && $('#historyTarget_'+ pref) != undefined && $('#eventsTarget_'+ pref) != undefined)
{ {
everythingHidden = $('#objectsTarget_'+ lastPrefix).attr('class').includes('active') == false && $('#historyTarget_'+ lastPrefix).attr('class').includes('active') == false && $('#eventsTarget_'+ lastPrefix).attr('class').includes('active') == false; everythingHidden = $('#objectsTarget_'+ pref).attr('class').includes('active') == false && $('#historyTarget_'+ pref).attr('class').includes('active') == false && $('#eventsTarget_'+ pref).attr('class').includes('active') == false;
} }
// show the objectsTarget if no specific pane selected or if selected is hidden // show the objectsTarget if no specific pane selected or if selected is hidden
if((target == '#'+lastPrefix ) && everythingHidden) //|| target == '#objectsTarget_'+ lastPrefix if((target == '#'+pref ) && everythingHidden)
{ {
var classTmp = $('#objectsTarget_'+ lastPrefix).attr('class'); var classTmp = $('#objectsTarget_'+ pref).attr('class');
if($('#objectsTarget_'+ lastPrefix).attr('class').includes('active') == false) if($('#objectsTarget_'+ pref).attr('class').includes('active') == false)
{ {
console.log('show')
classTmp += ' active'; classTmp += ' active';
$('#objectsTarget_'+ lastPrefix).attr('class', classTmp) $('#objectsTarget_'+ pref).attr('class', classTmp)
} }
} }
}); });
@@ -422,20 +432,27 @@ function purgeAll(callback) {
} }
// -------------------------------------------------------- // --------------------------------------------------------
dbIndexes = ''
function purgeAllExecute() { function purgeAllExecute() {
$.ajax({
method: "POST",
url: "php/server/dbHelper.php",
data: { action: "delete", dbtable: dbTable, columnName: 'Plugin', id:plugPrefix },
success: function(data, textStatus) {
showModalOk ('Result', data );
}
})
// Execute }
// console.log("targetLogFile:" + targetLogFile)
// console.log("logFileAction:" + logFileAction)
idArr = $('#NMAPSRV table[data-my-dbtable="Plugins_Objects"] tr[data-my-index]').map(function(){return $(this).attr("data-my-index");}).get(); // --------------------------------------------------------
function purgeVisible() {
idArr = $(`#${plugPrefix} table[data-my-dbtable="${dbTable}"] tr[data-my-index]`).map(function(){return $(this).attr("data-my-index");}).get();
$.ajax({ $.ajax({
method: "POST", method: "POST",
url: "php/server/dbHelper.php", url: "php/server/dbHelper.php",
data: { action: "delete", dbtable: 'Plugins_Objects', key: 'Index', id:idArr.toString() }, data: { action: "delete", dbtable: dbTable, columnName: 'Index', id:idArr.toString() },
success: function(data, textStatus) { success: function(data, textStatus) {
showModalOk ('Result', data ); showModalOk ('Result', data );
} }

View File

@@ -1,12 +1,22 @@
# ⚠ Disclaimer # ⚠ Disclaimer
Highly experimental feature. Follow the below very carefully and check example plugin(s). Plugin UI is not my priority right now, happy to approve PRs if you are interested in extending/improvintg the UI experience. Highly experimental feature. Follow the below very carefully and check example plugin(s). Plugin UI is not my priority right now, happy to approve PRs if you are interested in extending/improvintg the UI experience (e.g. making the tables sortable/filterable).
## ❗ Known issues:
These issues will be hopefully fixed with time, so please don't report them. Instead, if you know how, feel free to investigate and submit a PR to fix the below. Keep the PRs small as it's easier to approve them:
* Existing plugin objects sometimes not interpreted correctly and a new object is created instead, resulting in dupliucat entries.
* Occasional (experienced twice) hanging of processing plugin script file.
* UI displaying outdated values until the API endpoints get refreshed.
## Overview ## Overview
PiAlert comes with a simple plugin system to feed events from third-party scripts into the UI and then send notifications if desired. PiAlert comes with a plugin system to feed events from third-party scripts into the UI and then send notifications if desired.
If you wish to develop a plugin, please check the existing plugin structure. Once the settings are saved by the user they need to be removed from the `pialert.conf` file manually if you want to re-initialize them from the `config.json` of teh plugin. If you wish to develop a plugin, please check the existing plugin structure. Once the settings are saved by the user they need to be removed from the `pialert.conf` file manually if you want to re-initialize them from the `config.json` of the plugin.
Again, please read the below carefully if you'd like to contribute with a plugin yourself. This documentation file might be outdated, so double check the sample plugins as well.
## Plugin file structure overview ## Plugin file structure overview
@@ -35,6 +45,8 @@ You need to set the `data_source` to either `pialert-db-query` or `python-script
```json ```json
"data_source": "pialert-db-query" "data_source": "pialert-db-query"
``` ```
Any of the above datasources have to return a "table" of the exact structure as outlined below.
### Column order and values ### Column order and values
| Order | Represented Column | Required | Description | | Order | Represented Column | Required | Description |
@@ -47,6 +59,7 @@ You need to set the `data_source` to either `pialert-db-query` or `python-script
| 5 | `Watched_Value3` | no | As above | | 5 | `Watched_Value3` | no | As above |
| 6 | `Watched_Value4` | no | As above | | 6 | `Watched_Value4` | no | As above |
| 7 | `Extra` | no | Any other data you want to pass and display in PiAlert and the notifications | | 7 | `Extra` | no | Any other data you want to pass and display in PiAlert and the notifications |
| 8 | `ForeignKey` | no | A foreign key that can be used to link to the parent object (usually a MAC address) |
### "data_source": "python-script" ### "data_source": "python-script"
@@ -65,8 +78,8 @@ Valid CSV:
```csv ```csv
https://www.google.com|null|2023-01-02 15:56:30|200|0.7898|null|null|null https://www.google.com|null|2023-01-02 15:56:30|200|0.7898|null|null|null|null
https://www.duckduckgo.com|192.168.0.1|2023-01-02 15:56:30|200|0.9898|null|null|Best search engine https://www.duckduckgo.com|192.168.0.1|2023-01-02 15:56:30|200|0.9898|null|null|Best search engine|ff:ee:ff:11:ff:11
``` ```
@@ -74,9 +87,9 @@ Invalid CSV with different errors on each line:
```csv ```csv
https://www.google.com|null|2023-01-02 15:56:30|200|0.7898||null|null https://www.google.com|null|2023-01-02 15:56:30|200|0.7898||null|null|null
https://www.duckduckgo.com|null|2023-01-02 15:56:30|200|0.9898|null|null|Best search engine| https://www.duckduckgo.com|null|2023-01-02 15:56:30|200|0.9898|null|null|Best search engine|
|https://www.duckduckgo.com|null|2023-01-02 15:56:30|200|0.9898|null|null|Best search engine |https://www.duckduckgo.com|null|2023-01-02 15:56:30|200|0.9898|null|null|Best search engine|null
null|192.168.1.1|2023-01-02 15:56:30|200|0.9898|null|null|Best search engine null|192.168.1.1|2023-01-02 15:56:30|200|0.9898|null|null|Best search engine
https://www.duckduckgo.com|192.168.1.1|2023-01-02 15:56:30|null|0.9898|null|null|Best search engine https://www.duckduckgo.com|192.168.1.1|2023-01-02 15:56:30|null|0.9898|null|null|Best search engine
https://www.google.com|null|2023-01-02 15:56:30|200|0.7898||| https://www.google.com|null|2023-01-02 15:56:30|200|0.7898|||
@@ -100,7 +113,8 @@ SELECT dv.dev_Name as Object_PrimaryID,
ns.State as Watched_Value2, ns.State as Watched_Value2,
'null' as Watched_Value3, 'null' as Watched_Value3,
'null' as Watched_Value4, 'null' as Watched_Value4,
ns.Extra as Extra ns.Extra as Extra,
dv.dev_MAC as ForeignKey
FROM FROM
(SELECT * FROM Nmap_Scan) ns (SELECT * FROM Nmap_Scan) ns
LEFT JOIN LEFT JOIN
@@ -221,7 +235,7 @@ Example:
``` ```
##### UI settings in database_column_definitions ##### UI settings in database_column_definitions
The UI will adjust how columns are displayed in the UI based on teh definition of the `database_column_definitions` object. The UI will adjust how columns are displayed in the UI based on the definition of the `database_column_definitions` object. Thease are the supported form controls and related functionality:
- Only columns with `"show": true` and also with at least an english translation will be shown in the UI. - Only columns with `"show": true` and also with at least an english translation will be shown in the UI.
- Supported types: `label`, `text`, `threshold`, `replace` - Supported types: `label`, `text`, `threshold`, `replace`
@@ -231,6 +245,8 @@ The UI will adjust how columns are displayed in the UI based on teh definition o
- The `options` property is used in conjunction with these types: - The `options` property is used in conjunction with these types:
- `threshold` - The `options` array contains objects from lowest `maximum` to highest with corresponding `hexColor` used for the value background color if it's less than the specified `maximum`, but more than the previous one in the `options` array - `threshold` - The `options` array contains objects from lowest `maximum` to highest with corresponding `hexColor` used for the value background color if it's less than the specified `maximum`, but more than the previous one in the `options` array
- `replace` - The `options` array contains objects with an `equals` property, that is compared to the "value" and if the values are the same, the string in `replacement` is displayed in the UI instead of the actual "value" - `replace` - The `options` array contains objects with an `equals` property, that is compared to the "value" and if the values are the same, the string in `replacement` is displayed in the UI instead of the actual "value"
- `devicemac` - The value is considered to be a mac adress and a link pointing to the device with teh given mac address is generated.
- `url` - The value is considered to be a url so a link is generated.
```json ```json

View File

@@ -150,6 +150,18 @@
"string" : "Extra" "string" : "Extra"
}] }]
}, },
{
"column": "ForeignKey",
"show": true,
"type": "devicemac",
"default_value":"",
"options": [],
"localized": ["name"],
"name":[{
"language_code":"en_us",
"string" : "MAC"
}]
},
{ {
"column": "Status", "column": "Status",
"show": true, "show": true,
@@ -195,7 +207,7 @@
{ {
"function": "CMD", "function": "CMD",
"type": "text", "type": "text",
"default_value":"SELECT dv.dev_Name as Object_PrimaryID, cast('http://' || dv.dev_LastIP as VARCHAR(100)) || ':' || cast( SUBSTR(ns.Port ,0, INSTR(ns.Port , '/')) as VARCHAR(100)) as Object_SecondaryID, datetime() as DateTime, ns.Service as Watched_Value1, ns.State as Watched_Value2, 'null' as Watched_Value3, 'null' as Watched_Value4, ns.Extra as Extra FROM (SELECT * FROM Nmap_Scan) ns LEFT JOIN (SELECT dev_Name, dev_MAC, dev_LastIP FROM Devices) dv ON ns.MAC = dv.dev_MAC", "default_value":"SELECT dv.dev_Name as Object_PrimaryID, cast('http://' || dv.dev_LastIP as VARCHAR(100)) || ':' || cast( SUBSTR(ns.Port ,0, INSTR(ns.Port , '/')) as VARCHAR(100)) as Object_SecondaryID, datetime() as DateTime, ns.Service as Watched_Value1, ns.State as Watched_Value2, 'null' as Watched_Value3, 'null' as Watched_Value4, ns.Extra as Extra, dv.dev_MAC as ForeignKey FROM (SELECT * FROM Nmap_Scan) ns LEFT JOIN (SELECT dev_Name, dev_MAC, dev_LastIP FROM Devices) dv ON ns.MAC = dv.dev_MAC",
"options": [], "options": [],
"localized": ["name", "description"], "localized": ["name", "description"],
"name" : [{ "name" : [{

View File

@@ -51,8 +51,8 @@ def service_monitoring_log(site, status, latency):
) )
) )
with open(last_run, 'a') as last_run_logfile: with open(last_run, 'a') as last_run_logfile:
# https://www.duckduckgo.com|192.168.0.1|2023-01-02 15:56:30|200|0.9898|null|null|Best search engine # https://www.duckduckgo.com|192.168.0.1|2023-01-02 15:56:30|200|0.9898|null|null|Best search engine|null
last_run_logfile.write("{}|{}|{}|{}|{}|{}|{}|{}\n".format( last_run_logfile.write("{}|{}|{}|{}|{}|{}|{}|{}|{}\n".format(
site, site,
'null', 'null',
strftime("%Y-%m-%d %H:%M:%S"), strftime("%Y-%m-%d %H:%M:%S"),
@@ -61,6 +61,7 @@ def service_monitoring_log(site, status, latency):
'null', 'null',
'null', 'null',
'null', 'null',
'null',
) )
) )