mirror of
https://github.com/unraid/webgui.git
synced 2025-12-31 22:50:25 -06:00
315 lines
11 KiB
PHP
Executable File
315 lines
11 KiB
PHP
Executable File
#!/usr/bin/php -q
|
|
<?PHP
|
|
/* Copyright 2005-2023, Lime Technology
|
|
* Copyright 2012-2023, Bergware International.
|
|
* Copyright 2012, Andrew Hamer-Adams, http://www.pixeleyes.co.nz.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License version 2,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*/
|
|
?>
|
|
<?
|
|
$docroot ??= ($_SERVER['DOCUMENT_ROOT'] ?: '/usr/local/emhttp');
|
|
require_once "$docroot/webGui/include/Wrappers.php";
|
|
require_once "$docroot/webGui/include/Encryption.php";
|
|
|
|
function usage() {
|
|
echo <<<EOT
|
|
notify [-e "event"] [-s "subject"] [-d "description"] [-i "normal|warning|alert"] [-m "message"] [-x] [-t] [-b] [add]
|
|
create a notification
|
|
use -e to specify the event
|
|
use -s to specify a subject
|
|
use -d to specify a short description
|
|
use -i to specify the severity
|
|
use -m to specify a message (long description)
|
|
use -l to specify a link (clicking the notification will take you to that location)
|
|
use -x to create a single notification ticket
|
|
use -r to specify recipients and not use default
|
|
use -t to force send email only (for testing)
|
|
use -b to NOT send a browser notification
|
|
all options are optional
|
|
|
|
notify init
|
|
Initialize the notification subsystem.
|
|
|
|
notify smtp-init
|
|
Initialize sendmail configuration (ssmtp in our case).
|
|
|
|
notify get
|
|
Output a json-encoded list of all the unread notifications.
|
|
|
|
notify archive file
|
|
Move file from 'unread' state to 'archive' state.
|
|
|
|
EOT;
|
|
return 1;
|
|
}
|
|
|
|
function generate_email($event, $subject, $description, $importance, $message, $recipients, $fqdnlink) {
|
|
global $ssmtp;
|
|
$rcpt = $ssmtp['RcptTo'];
|
|
if (!$recipients)
|
|
$to = implode(',', explode(' ', trim($rcpt)));
|
|
else
|
|
$to = $recipients;
|
|
if (empty($to)) return;
|
|
$subj = "{$ssmtp['Subject']}$subject";
|
|
$headers = [];
|
|
$headers[] = "MIME-Version: 1.0";
|
|
$headers[] = "X-Mailer: PHP/".phpversion();
|
|
$headers[] = "Content-type: text/plain; charset=utf-8";
|
|
$headers[] = "From: {$ssmtp['root']}";
|
|
$headers[] = "Reply-To: {$ssmtp['root']}";
|
|
if (($importance == "warning" || $importance == "alert") && $ssmtp['SetEmailPriority']=="True") {
|
|
$headers[] = "X-Priority: 1 (highest)";
|
|
$headers[] = "X-Mms-Priority: High";
|
|
}
|
|
$headers[] = "";
|
|
$body = [];
|
|
if (!empty($fqdnlink)) {
|
|
$body[] = "Link: $fqdnlink";
|
|
$body[] = "";
|
|
}
|
|
$body[] = "Event: $event";
|
|
$body[] = "Subject: $subject";
|
|
$body[] = "Description: $description";
|
|
$body[] = "Importance: $importance";
|
|
if (!empty($message)) {
|
|
$body[] = "";
|
|
foreach (explode('\n',$message) as $line)
|
|
$body[] = $line;
|
|
}
|
|
$body[] = "";
|
|
return mail($to, $subj, implode("\n", $body), implode("\n", $headers));
|
|
}
|
|
|
|
function safe_filename($string) {
|
|
$special_chars = ["?", "[", "]", "/", "\\", "=", "<", ">", ":", ";", ",", "'", "\"", "&", "$", "#", "*", "(", ")", "|", "~", "`", "!", "{", "}"];
|
|
$string = trim(str_replace($special_chars, "", $string));
|
|
$string = preg_replace('~[^0-9a-z -_]~i', '', $string);
|
|
$string = preg_replace('~[- ]~i', '_', $string);
|
|
return trim($string);
|
|
}
|
|
|
|
/*
|
|
Call this when using the subject field in email or agents. Do not use when showing the subject in a browser.
|
|
Removes all HTML entities from subject line, is specifically targetting the my_temp() function, which adds ' °'
|
|
*/
|
|
function clean_subject($subject) {
|
|
$subject = preg_replace("/&#?[a-z0-9]{2,8};/i"," ",$subject);
|
|
return $subject;
|
|
}
|
|
|
|
/**
|
|
* Wrap string values in double quotes for INI compatibility and escape quotes/backslashes.
|
|
* Numeric types remain unquoted so they can be parsed as-is.
|
|
*/
|
|
function ini_encode_value($value) {
|
|
if (is_int($value) || is_float($value)) return $value;
|
|
if (is_bool($value)) return $value ? 'true' : 'false';
|
|
$value = (string)$value;
|
|
return '"'.strtr($value, ["\\"=>"\\\\", '"' => '\\"']).'"';
|
|
}
|
|
|
|
function build_ini_string(array $data) {
|
|
$lines = [];
|
|
foreach ($data as $key => $value) {
|
|
$lines[] = "{$key}=".ini_encode_value($value);
|
|
}
|
|
return implode("\n", $lines)."\n";
|
|
}
|
|
|
|
/**
|
|
* Trims and unescapes strings (eg quotes, backslashes) if necessary.
|
|
*/
|
|
function ini_decode_value($value) {
|
|
$value = trim($value);
|
|
$length = strlen($value);
|
|
if ($length >= 2 && $value[0] === '"' && $value[$length-1] === '"') {
|
|
return stripslashes(substr($value, 1, -1));
|
|
}
|
|
return $value;
|
|
}
|
|
|
|
// start
|
|
if ($argc == 1) exit(usage());
|
|
|
|
extract(parse_plugin_cfg("dynamix",true));
|
|
|
|
$path = _var($notify,'path','/tmp/notifications');
|
|
$unread = "$path/unread";
|
|
$archive = "$path/archive";
|
|
$agents_dir = "/boot/config/plugins/dynamix/notifications/agents";
|
|
if (is_dir($agents_dir)) {
|
|
$agents = [];
|
|
foreach (array_diff(scandir($agents_dir), ['.','..']) as $p) {
|
|
if (file_exists("{$agents_dir}/{$p}")) $agents[] = "{$agents_dir}/{$p}";
|
|
}
|
|
} else {
|
|
$agents = NULL;
|
|
}
|
|
|
|
switch ($argv[1][0]=='-' ? 'add' : $argv[1]) {
|
|
case 'init':
|
|
$files = glob("$unread/*.notify", GLOB_NOSORT);
|
|
foreach ($files as $file) if (!is_readable($file)) chmod($file,0666);
|
|
break;
|
|
|
|
case 'smtp-init':
|
|
@mkdir($unread,0755,true);
|
|
@mkdir($archive,0755,true);
|
|
$conf = [];
|
|
$conf[] = "# Generated settings:";
|
|
$conf[] = "Root={$ssmtp['root']}";
|
|
$domain = strtok($ssmtp['root'],'@');
|
|
$domain = strtok('@');
|
|
$conf[] = "rewriteDomain=$domain";
|
|
$conf[] = "FromLineOverride=YES";
|
|
$conf[] = "Mailhub={$ssmtp['server']}:{$ssmtp['port']}";
|
|
$conf[] = "UseTLS={$ssmtp['UseTLS']}";
|
|
$conf[] = "UseSTARTTLS={$ssmtp['UseSTARTTLS']}";
|
|
if ($ssmtp['AuthMethod'] != "none") {
|
|
$conf[] = "AuthMethod={$ssmtp['AuthMethod']}";
|
|
$conf[] = "AuthUser={$ssmtp['AuthUser']}";
|
|
$conf[] = "AuthPass=".base64_decrypt($ssmtp['AuthPass']);
|
|
}
|
|
$conf[] = "";
|
|
file_put_contents("/etc/ssmtp/ssmtp.conf", implode("\n", $conf));
|
|
break;
|
|
|
|
case 'cron-init':
|
|
@mkdir($unread,0755,true);
|
|
@mkdir($archive,0755,true);
|
|
$text = empty($notify['status']) ? "" : "# Generated array status check schedule:\n{$notify['status']} $docroot/plugins/dynamix/scripts/statuscheck &> /dev/null\n\n";
|
|
parse_cron_cfg("dynamix", "status-check", $text);
|
|
$text = empty($notify['unraidos']) ? "" : "# Generated Unraid OS update check schedule:\n{$notify['unraidos']} $docroot/plugins/dynamix.plugin.manager/scripts/unraidcheck &> /dev/null\n\n";
|
|
parse_cron_cfg("dynamix", "unraid-check", $text);
|
|
$text = empty($notify['version']) ? "" : "# Generated plugins version check schedule:\n{$notify['version']} $docroot/plugins/dynamix.plugin.manager/scripts/plugincheck &> /dev/null\n\n";
|
|
parse_cron_cfg("dynamix", "plugin-check", $text);
|
|
$text = empty($notify['system']) ? "" : "# Generated system monitoring schedule:\n{$notify['system']} $docroot/plugins/dynamix/scripts/monitor &> /dev/null\n\n";
|
|
parse_cron_cfg("dynamix", "monitor", $text);
|
|
$text = empty($notify['docker_update']) ? "" : "# Generated docker monitoring schedule:\n{$notify['docker_update']} $docroot/plugins/dynamix.docker.manager/scripts/dockerupdate check &> /dev/null\n\n";
|
|
parse_cron_cfg("dynamix", "docker-update", $text);
|
|
$text = empty($notify['language_update']) ? "" : "# Generated languages version check schedule:\n{$notify['language_update']} $docroot/plugins/dynamix.plugin.manager/scripts/languagecheck &> /dev/null\n\n";
|
|
parse_cron_cfg("dynamix", "language-check", $text);
|
|
break;
|
|
|
|
case 'add':
|
|
$event = 'Unraid Status';
|
|
$subject = 'Notification';
|
|
$description = 'No description';
|
|
$importance = 'normal';
|
|
$message = $recipients = $link = $fqdnlink = '';
|
|
$timestamp = time();
|
|
$ticket = $timestamp;
|
|
$mailtest = false;
|
|
$overrule = false;
|
|
$noBrowser = false;
|
|
|
|
$options = getopt("l:e:s:d:i:m:r:xtb");
|
|
foreach ($options as $option => $value) {
|
|
switch ($option) {
|
|
case 'e':
|
|
$event = $value;
|
|
break;
|
|
case 's':
|
|
$subject = $value;
|
|
break;
|
|
case 'd':
|
|
$description = $value;
|
|
break;
|
|
case 'i':
|
|
$importance = strtok($value,' ');
|
|
$overrule = strtok(' ');
|
|
break;
|
|
case 'm':
|
|
$message = $value;
|
|
break;
|
|
case 'r':
|
|
$recipients = $value;
|
|
break;
|
|
case 'x':
|
|
$ticket = 'ticket';
|
|
break;
|
|
case 't':
|
|
$mailtest = true;
|
|
break;
|
|
case 'b':
|
|
$noBrowser = true;
|
|
break;
|
|
case 'l':
|
|
$nginx = (array)@parse_ini_file('/var/local/emhttp/nginx.ini');
|
|
$link = $value;
|
|
$fqdnlink = (strpos($link,"http") === 0) ? $link : ($nginx['NGINX_DEFAULTURL']??'').$link;
|
|
break;
|
|
}
|
|
}
|
|
|
|
$unread = "{$unread}/".safe_filename("{$event}-{$ticket}.notify");
|
|
$archive = "{$archive}/".safe_filename("{$event}-{$ticket}.notify");
|
|
if (file_exists($archive)) break;
|
|
$entity = $overrule===false ? $notify[$importance] : $overrule;
|
|
$cleanSubject = clean_subject($subject);
|
|
$archiveData = [
|
|
'timestamp' => $timestamp,
|
|
'event' => $event,
|
|
'subject' => $cleanSubject,
|
|
'description' => $description,
|
|
'importance' => $importance,
|
|
];
|
|
if ($message) $archiveData['message'] = str_replace('\n','<br>',$message);
|
|
if (!$mailtest) file_put_contents($archive, build_ini_string($archiveData));
|
|
if (($entity & 1)==1 && !$mailtest && !$noBrowser) {
|
|
$unreadData = [
|
|
'timestamp' => $timestamp,
|
|
'event' => $event,
|
|
'subject' => $cleanSubject,
|
|
'description' => $description,
|
|
'importance' => $importance,
|
|
'link' => $link,
|
|
];
|
|
file_put_contents($unread, build_ini_string($unreadData));
|
|
}
|
|
if (($entity & 2)==2 || $mailtest) generate_email($event, $cleanSubject, str_replace('<br>','. ',$description), $importance, $message, $recipients, $fqdnlink);
|
|
if (($entity & 4)==4 && !$mailtest) { if (is_array($agents)) {foreach ($agents as $agent) {exec("TIMESTAMP='$timestamp' EVENT=".escapeshellarg($event)." SUBJECT=".escapeshellarg($cleanSubject)." DESCRIPTION=".escapeshellarg($description)." IMPORTANCE=".escapeshellarg($importance)." CONTENT=".escapeshellarg($message)." LINK=".escapeshellarg($fqdnlink)." bash ".$agent);};}};
|
|
break;
|
|
|
|
case 'get':
|
|
$output = [];
|
|
$json = [];
|
|
$files = glob("$unread/*.notify", GLOB_NOSORT);
|
|
usort($files, function($a,$b){return filemtime($a)-filemtime($b);});
|
|
$i = 0;
|
|
foreach ($files as $file) {
|
|
$fields = file($file,FILE_IGNORE_NEW_LINES|FILE_SKIP_EMPTY_LINES);
|
|
$time = true;
|
|
$output[$i]['file'] = basename($file);
|
|
$output[$i]['show'] = (fileperms($file) & 0x0FFF)==0400 ? 0 : 1;
|
|
foreach ($fields as $field) {
|
|
if (!$field) continue;
|
|
# limit the explode('=', …) used during reads to two pieces so values containing = remain intact
|
|
[$key,$val] = array_pad(explode('=', $field, 2),2,'');
|
|
if ($time) {$val = date($notify['date'].' '.$notify['time'], $val); $time = false;}
|
|
# unescape the value before emitting JSON, so the browser UI
|
|
# and any scripts calling `notify get` still see plain strings
|
|
$output[$i][trim($key)] = ini_decode_value($val);
|
|
}
|
|
$i++;
|
|
}
|
|
echo json_encode($output, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
|
|
break;
|
|
|
|
case 'archive':
|
|
if ($argc != 3) exit(usage());
|
|
$file = $argv[2];
|
|
if (strpos(realpath("$unread/$file"),$unread.'/')===0) @unlink("$unread/$file");
|
|
break;
|
|
}
|
|
|
|
exit(0);
|
|
?>
|