mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-06 17:15:38 -08:00
653 lines
18 KiB
PHP
Executable File
653 lines
18 KiB
PHP
Executable File
<?php
|
|
//------------------------------------------------------------------------------
|
|
// NetAlertX
|
|
// Open Source Network Guard / WIFI & LAN intrusion detector
|
|
//
|
|
// util.php - Front module. Server side. Common generic functions
|
|
//------------------------------------------------------------------------------
|
|
# Puche 2021 / 2022+ jokob jokob@duck.com GNU GPLv3
|
|
//------------------------------------------------------------------------------
|
|
|
|
require dirname(__FILE__).'/../templates/globals.php';
|
|
require dirname(__FILE__).'/../templates/skinUI.php';
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// check if authenticated
|
|
require_once $_SERVER['DOCUMENT_ROOT'] . '/php/templates/security.php';
|
|
|
|
$FUNCTION = [];
|
|
$SETTINGS = [];
|
|
$ACTION = "";
|
|
|
|
// init request params
|
|
if(array_key_exists('function', $_REQUEST) != FALSE)
|
|
{
|
|
$FUNCTION = $_REQUEST['function'];
|
|
}
|
|
if(array_key_exists('settings', $_REQUEST) != FALSE)
|
|
{
|
|
$SETTINGS = $_REQUEST['settings'];
|
|
}
|
|
|
|
|
|
// call functions based on requested params
|
|
switch ($FUNCTION) {
|
|
|
|
case 'savesettings':
|
|
|
|
saveSettings();
|
|
break;
|
|
|
|
case 'cleanLog':
|
|
|
|
cleanLog($SETTINGS);
|
|
break;
|
|
|
|
case 'addToExecutionQueue':
|
|
|
|
if(array_key_exists('action', $_REQUEST) != FALSE)
|
|
{
|
|
$ACTION = $_REQUEST['action'];
|
|
}
|
|
|
|
addToExecutionQueue($ACTION);
|
|
break;
|
|
|
|
default:
|
|
// Handle any other cases or errors if needed
|
|
break;
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Formatting data functions
|
|
//------------------------------------------------------------------------------
|
|
// Creates a PHP array from a string representing a python array (input format ['...','...'])
|
|
// Only supports:
|
|
// - one level arrays, not nested ones
|
|
// - single quotes
|
|
function createArray($input){
|
|
|
|
// empty array
|
|
if($input == '[]')
|
|
{
|
|
return [];
|
|
}
|
|
|
|
// regex patterns
|
|
$patternBrackets = '/(^\s*\[)|(\]\s*$)/';
|
|
$patternQuotes = '/(^\s*\')|(\'\s*$)/';
|
|
$replacement = '';
|
|
|
|
// remove brackets
|
|
$noBrackets = preg_replace($patternBrackets, $replacement, $input);
|
|
|
|
$options = array();
|
|
|
|
// create array
|
|
$optionsTmp = explode(",", $noBrackets);
|
|
|
|
// handle only one item in array
|
|
if(count($optionsTmp) == 0)
|
|
{
|
|
return [preg_replace($patternQuotes, $replacement, $noBrackets)];
|
|
}
|
|
|
|
// remove quotes
|
|
foreach ($optionsTmp as $item)
|
|
{
|
|
array_push($options, preg_replace($patternQuotes, $replacement, $item) );
|
|
}
|
|
|
|
return $options;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
// For debugging - Print arrays
|
|
function printArray ($array) {
|
|
echo '[';
|
|
foreach ($array as $val)
|
|
{
|
|
if(is_array($val))
|
|
{
|
|
echo '<br/>';
|
|
printArray($val);
|
|
} else
|
|
{
|
|
echo $val.', ';
|
|
}
|
|
}
|
|
echo ']<br/>';
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
function formatDate ($date1) {
|
|
return date_format (new DateTime ($date1) , 'Y-m-d H:i');
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
function formatDateDiff ($date1, $date2) {
|
|
return date_diff (new DateTime ($date1), new DateTime ($date2 ) )-> format ('%ad %H:%I');
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
function formatDateISO ($date1) {
|
|
return date_format (new DateTime ($date1),'c');
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
function formatEventDate ($date1, $eventType) {
|
|
if (!empty ($date1) ) {
|
|
$ret = formatDate ($date1);
|
|
} elseif ($eventType == '<missing event>') {
|
|
$ret = '<missing event>';
|
|
} else {
|
|
$ret = '<Still Connected>';
|
|
}
|
|
|
|
return $ret;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
function formatIPlong ($IP) {
|
|
return sprintf('%u', ip2long($IP) );
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Other functions
|
|
//------------------------------------------------------------------------------
|
|
function checkPermissions($files)
|
|
{
|
|
foreach ($files as $file)
|
|
{
|
|
|
|
// // make sure the file ownership is correct
|
|
// chown($file, 'nginx');
|
|
// chgrp($file, 'www-data');
|
|
|
|
// check access to database
|
|
if(file_exists($file) != 1)
|
|
{
|
|
$message = "File '".$file."' not found or inaccessible. Correct file permissions, create one yourself or generate a new one in 'Settings' by clicking the 'Save' button.";
|
|
displayMessage($message, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
|
|
// check server/api_server/api_server_start.py for equivalents
|
|
// equivalent: /messaging/in-app/write
|
|
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
|
|
function displayMessage($message, $logAlert = FALSE, $logConsole = TRUE, $logFile = TRUE, $logEcho = FALSE)
|
|
{
|
|
global $logFolderPath, $log_file, $timestamp;
|
|
|
|
// sanitize
|
|
$message = str_replace(array("\n", "\r", PHP_EOL), '', $message);
|
|
|
|
echo "<script>function escape(html, encode) {
|
|
return html.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
|
|
.replace(/\t/g, '')
|
|
}</script>";
|
|
|
|
// Javascript Alert pop-up
|
|
if($logAlert)
|
|
{
|
|
echo '<script>alert(escape("'.$message.'"));</script>';
|
|
}
|
|
|
|
// F12 Browser dev console
|
|
if($logConsole)
|
|
{
|
|
echo '<script>console.log(escape("'.str_replace('"',"'",$message).'"));</script>';
|
|
}
|
|
|
|
//File
|
|
if($logFile)
|
|
{
|
|
|
|
if (is_writable($logFolderPath.$log_file)) {
|
|
|
|
|
|
if(file_exists($logFolderPath.$log_file) != 1) // file doesn't exist, create one
|
|
{
|
|
$log = fopen($logFolderPath.$log_file, "w") or die("Unable to open file!");
|
|
}else // file exists, append
|
|
{
|
|
$log = fopen($logFolderPath.$log_file, "a") or die("Unable to open file - Permissions issue!");
|
|
}
|
|
|
|
fwrite($log, "[".$timestamp. "] " . str_replace('<br>',"\n ",str_replace('<br/>',"\n ",$message)).PHP_EOL."" );
|
|
fclose($log);
|
|
|
|
} else {
|
|
echo 'The file is not writable: '.$logFolderPath.$log_file;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//echo
|
|
if($logEcho)
|
|
{
|
|
echo $message;
|
|
}
|
|
|
|
}
|
|
|
|
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
|
|
// check server/api_server/api_server_start.py for equivalents
|
|
// equivalent: /logs/add-to-execution-queue
|
|
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
|
|
// ----------------------------------------------------------------------------------------
|
|
// Adds an action to perform into the execution_queue.log file
|
|
function addToExecutionQueue($action)
|
|
{
|
|
global $logFolderPath, $timestamp;
|
|
|
|
$logFile = 'execution_queue.log';
|
|
$fullPath = $logFolderPath . $logFile;
|
|
|
|
// Open the file or skip if it can't be opened
|
|
if ($file = fopen($fullPath, 'a')) {
|
|
fwrite($file, "[" . $timestamp . "]|" . $action . PHP_EOL);
|
|
fclose($file);
|
|
displayMessage('Action "'.$action.'" added to the execution queue.', false, true, true, true);
|
|
} else {
|
|
displayMessage('Log file not found or couldn\'t be created.', false, true, true, true);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
|
|
// check server/api_server/api_server_start.py for equivalents
|
|
// equivalent: /logs DELETE
|
|
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
|
|
function cleanLog($logFile)
|
|
{
|
|
global $logFolderPath, $timestamp;
|
|
|
|
$path = "";
|
|
|
|
$allowedFiles = ['app.log', 'app_front.log', 'IP_changes.log', 'stdout.log', 'stderr.log', 'app.php_errors.log', 'execution_queue.log', 'db_is_locked.log', 'nginx-error.log', 'cron.log'];
|
|
|
|
if(in_array($logFile, $allowedFiles))
|
|
{
|
|
$path = $logFolderPath.$logFile;
|
|
}
|
|
|
|
if($path != "")
|
|
{
|
|
// purge content
|
|
$file = fopen($path, "w") or die("Unable to open file!");
|
|
fwrite($file, "");
|
|
fclose($file);
|
|
displayMessage('File <code>'.$logFile.'</code> purged.', FALSE, TRUE, TRUE, TRUE);
|
|
} else
|
|
{
|
|
displayMessage('File <code>'.$logFile.'</code> is not allowed to be purged.', FALSE, TRUE, TRUE, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
function saveSettings()
|
|
{
|
|
global $SETTINGS, $FUNCTION, $config_file, $fullConfPath, $configFolderPath, $timestamp;
|
|
|
|
// save to the file
|
|
$new_name = $config_file.'_'.$timestamp.'.backup';
|
|
$new_location = $configFolderPath.'/'.$new_name;
|
|
|
|
if(file_exists( $fullConfPath) != 1)
|
|
{
|
|
displayMessage('File "'.$fullConfPath.'" not found or missing read permissions. Creating a new <code>'.$config_file.'</code> file.', FALSE, TRUE, TRUE, TRUE);
|
|
}
|
|
// create a backup copy
|
|
elseif (!copy($fullConfPath, $new_location))
|
|
{
|
|
displayMessage("Failed to copy file ".$fullConfPath." to ".$new_location." <br/> Check your permissions to allow read/write access to the /config folder.", FALSE, TRUE, TRUE, TRUE);
|
|
}
|
|
|
|
|
|
// generate a clean .conf file
|
|
$groups = [];
|
|
|
|
$txt = "";
|
|
|
|
$txt = $txt."#-----------------AUTOGENERATED FILE-----------------#\n";
|
|
$txt = $txt."# #\n";
|
|
$txt = $txt."# Generated: ".$timestamp." #\n";
|
|
$txt = $txt."# #\n";
|
|
$txt = $txt."# Config file for the LAN intruder detection app: #\n";
|
|
$txt = $txt."# https://github.com/jokob-sk/NetAlertX #\n";
|
|
$txt = $txt."# #\n";
|
|
$txt = $txt."#-----------------AUTOGENERATED FILE-----------------#\n";
|
|
|
|
// collect all groups
|
|
|
|
$decodedSettings = json_decode((string)$SETTINGS, true);
|
|
|
|
if ($decodedSettings === null) {
|
|
echo "Error: Invalid JSON in settings data.";
|
|
return;
|
|
}
|
|
|
|
foreach ($decodedSettings as $setting) {
|
|
if( in_array($setting[0] , $groups) == false) {
|
|
array_push($groups ,$setting[0]);
|
|
}
|
|
}
|
|
|
|
// go thru the groups and prepare settings to write to file
|
|
foreach ($groups as $group) {
|
|
$txt .= "\n\n# " . $group;
|
|
$txt .= "\n#---------------------------\n";
|
|
|
|
foreach ($decodedSettings as $setting) {
|
|
$settingGroup = $setting[0];
|
|
$setKey = $setting[1];
|
|
$dataType = $setting[2];
|
|
$settingValue = $setting[3];
|
|
|
|
// // Parse the settingType JSON
|
|
// $settingType = json_decode($settingTypeJson, true);
|
|
|
|
// Sanity check
|
|
if($setKey == "UI_LANG" && $settingValue == "") {
|
|
echo "🔴 Error: important settings missing. Refresh the page with 🔃 on the top and try again.";
|
|
return;
|
|
}
|
|
|
|
if ($group == $settingGroup) {
|
|
|
|
if ($dataType == 'string' ) {
|
|
$val = encode_single_quotes($settingValue);
|
|
$txt .= $setKey . "='" . $val . "'\n";
|
|
} elseif ($dataType == 'integer') {
|
|
$txt .= $setKey . "=" . $settingValue . "\n";
|
|
} elseif ($dataType == 'none') {
|
|
$txt .= $setKey . "=''\n";
|
|
} elseif ($dataType == 'json') {
|
|
$txt .= $setKey . "=" . $settingValue . "\n";
|
|
} elseif ($dataType == 'boolean') {
|
|
$val = ($settingValue === true || $settingValue === 1 || strtolower($settingValue) === 'true') ? "True" : "False";
|
|
$txt .= $setKey . "=" . $val . "\n";
|
|
} elseif ($dataType == 'array' ) {
|
|
$temp = '';
|
|
|
|
if(is_array($settingValue) == FALSE)
|
|
{
|
|
$settingValue = json_decode($settingValue);
|
|
}
|
|
// skipping __metadata entries (?)
|
|
if (count($setting) > 3 && is_array($settingValue) == true) {
|
|
foreach ($settingValue as $val) {
|
|
$temp .= "'" . encode_single_quotes($val) . "',";
|
|
}
|
|
|
|
$temp = substr_replace($temp, "", -1); // remove last comma ','
|
|
}
|
|
|
|
$temp = '['.$temp.']'; // wrap brackets
|
|
$txt .= $setKey . "=" . $temp . "\n";
|
|
|
|
} else {
|
|
$txt .= $setKey . "='⭕Not handled⭕'\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
$txt = $txt."\n\n";
|
|
$txt = $txt."#-------------------IMPORTANT INFO-------------------#\n";
|
|
$txt = $txt."# This file is ingested by a python script, so if #\n";
|
|
$txt = $txt."# modified it needs to use python syntax #\n";
|
|
$txt = $txt."#-------------------IMPORTANT INFO-------------------#\n";
|
|
|
|
// open new file and write the new configuration
|
|
// Create a temporary file
|
|
$tempConfPath = $fullConfPath . ".tmp";
|
|
|
|
// Backup the original file
|
|
if (file_exists($fullConfPath)) {
|
|
copy($fullConfPath, $fullConfPath . ".bak");
|
|
}
|
|
|
|
// Open the file for writing without changing permissions
|
|
$file = fopen($fullConfPath, "w") or die("Unable to open file!");
|
|
fwrite($file, $txt);
|
|
fclose($file);
|
|
|
|
// displayMessage(lang('settings_saved'),
|
|
// FALSE, TRUE, TRUE, TRUE);
|
|
|
|
echo "OK";
|
|
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
|
|
// check server/api_server/api_server_start.py for equivalents
|
|
// equivalent: /graphql LangStrings endpoint
|
|
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
|
|
function getString ($setKey, $default) {
|
|
|
|
$result = lang($setKey);
|
|
|
|
if ($result )
|
|
{
|
|
return $result;
|
|
}
|
|
|
|
return $default;
|
|
}
|
|
// -------------------------------------------------------------------------------------------
|
|
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
|
|
// check server/api_server/api_server_start.py for equivalents
|
|
// equivalent: /settings/<key>
|
|
// 🔺----- API ENDPOINTS SUPERSEDED -----🔺
|
|
function getSettingValue($setKey) {
|
|
// Define the JSON endpoint URL
|
|
$apiRoot = rtrim(getenv('NETALERTX_API') ?: '/tmp/api', '/');
|
|
$url = $apiRoot . '/table_settings.json';
|
|
|
|
// Fetch the JSON data
|
|
$json = file_get_contents($url);
|
|
|
|
// Check if the JSON data was successfully fetched
|
|
if ($json === false) {
|
|
return 'Could not get json data';
|
|
}
|
|
|
|
// Decode the JSON data
|
|
$data = json_decode($json, true);
|
|
|
|
// Check if the JSON decoding was successful
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
return 'Could not decode json data';
|
|
}
|
|
|
|
// Search for the setting by setKey
|
|
foreach ($data['data'] as $setting) {
|
|
if ($setting['setKey'] === $setKey) {
|
|
return $setting['setValue'];
|
|
// echo $setting['setValue'];
|
|
}
|
|
}
|
|
|
|
// Return false if the setting was not found
|
|
return 'Could not find setting '.$setKey;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
|
|
|
|
function encode_single_quotes ($val) {
|
|
|
|
$result = str_replace ('\'','{s-quote}',$val);
|
|
|
|
return $result;
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
|
|
function getDateFromPeriod () {
|
|
|
|
$periodDate = $_REQUEST['period'];
|
|
|
|
$periodDateSQL = "";
|
|
$days = "";
|
|
|
|
switch ($periodDate) {
|
|
case '7 days':
|
|
$days = "7";
|
|
break;
|
|
case '1 month':
|
|
$days = "30";
|
|
break;
|
|
case '1 year':
|
|
$days = "365";
|
|
break;
|
|
case '100 years':
|
|
$days = "3650"; //10 years
|
|
break;
|
|
default:
|
|
$days = "1";
|
|
}
|
|
|
|
$periodDateSQL = "-".$days." day";
|
|
|
|
return " date('now', '".$periodDateSQL."') ";
|
|
|
|
// $period = $_REQUEST['period'];
|
|
// return '"'. date ('Y-m-d', strtotime ('+2 day -'. $period) ) .'"';
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
function quotes ($text) {
|
|
return str_replace ('"','""',$text);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
function logServerConsole ($text) {
|
|
$x = array();
|
|
$y = $x['__________'. $text .'__________'];
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
function handleNull ($text, $default = "") {
|
|
if($text == NULL || $text == 'NULL')
|
|
{
|
|
return $default;
|
|
} else
|
|
{
|
|
return $text;
|
|
}
|
|
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
// Encode special chars
|
|
function encodeSpecialChars($str) {
|
|
return str_replace(
|
|
['&', '<', '>', '"', "'"],
|
|
['&', '<', '>', '"', '''],
|
|
$str
|
|
);
|
|
}
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
// Decode special chars
|
|
function decodeSpecialChars($str) {
|
|
return str_replace(
|
|
['&', '<', '>', '"', '''],
|
|
['&', '<', '>', '"', "'"],
|
|
$str
|
|
);
|
|
}
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------
|
|
// used in Export CSV
|
|
function getDevicesColumns(){
|
|
|
|
$columns = ["devMac",
|
|
"devName",
|
|
"devOwner",
|
|
"devType",
|
|
"devVendor",
|
|
"devFavorite",
|
|
"devGroup",
|
|
"devComments",
|
|
"devFirstConnection",
|
|
"devLastConnection",
|
|
"devLastIP",
|
|
"devStaticIP",
|
|
"devScan",
|
|
"devLogEvents",
|
|
"devAlertEvents",
|
|
"devAlertDown",
|
|
"devSkipRepeated",
|
|
"devLastNotification",
|
|
"devPresentLastScan",
|
|
"devIsNew",
|
|
"devLocation",
|
|
"devIsArchived",
|
|
"devParentPort",
|
|
"devParentMAC",
|
|
"devIcon",
|
|
"devGUID",
|
|
"devSyncHubNode",
|
|
"devSite",
|
|
"devSSID",
|
|
"devSourcePlugin",
|
|
"devCustomProps",
|
|
"devFQDN",
|
|
"devParentRelType",
|
|
"devReqNicsOnline"
|
|
];
|
|
|
|
return $columns;
|
|
}
|
|
|
|
|
|
function generateGUID() {
|
|
return sprintf(
|
|
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
|
random_int(0, 0xffff), random_int(0, 0xffff),
|
|
random_int(0, 0xffff),
|
|
random_int(0, 0x0fff) | 0x4000, // Version 4 UUID
|
|
random_int(0, 0x3fff) | 0x8000, // Variant 1
|
|
random_int(0, 0xffff), random_int(0, 0xffff), random_int(0, 0xffff)
|
|
);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Simple cookie cache
|
|
//------------------------------------------------------------------------------
|
|
function getCache($key) {
|
|
if( isset($_COOKIE[$key]))
|
|
{
|
|
return $_COOKIE[$key];
|
|
}else
|
|
{
|
|
return "";
|
|
}
|
|
}
|
|
// -------------------------------------------------------------------------------------------
|
|
function setCache($key, $value, $expireMinutes = 5) {
|
|
setcookie($key, $value, time()+$expireMinutes*60, "/","", 0);
|
|
}
|
|
|
|
|
|
?>
|