Push Notifications (Mobile and PC) (#13277)
* Update manifest and add service worker cleanup icons a bit * Push notifications WIP * navigate working * cleanup * acknowledge wired up * Set VAPID keys on composer install * Component to control notification permissions. * Allow all user option to validate * Enable on browser load if transport exists. * Check for transport before showing user permissions translations * Documentation * style fixes * access via the attribute model * fix alerting test * update schema * cleanup subscription on disable * non-configurable db and table for webpush subscriptions (respect system connection) * revert AlertTransport change hopefully phpstan can figure it out * phpstan fixes * Support custom details display * Match transport names to brand's preferred display * less duplicate id errors * Tests are done in Laravel code now so remove legacy function usage... could be better, but ok * Style fixes * Style fixes 2 * Fix alert test * Doc updates requires HTTPS and GMP * unregister subscription when permission is set to denied * cleanup after user deletion * delete the right thing * fix whitespace * update install docs to include php-gmp * suggest ext-gmp * update javascript * Update functions.php Co-authored-by: Jellyfrog <Jellyfrog@users.noreply.github.com>
@ -521,7 +521,7 @@ class RunAlerts
|
||||
}
|
||||
|
||||
foreach ($transport_maps as $item) {
|
||||
$class = 'LibreNMS\\Alert\\Transport\\' . ucfirst($item['transport_type']);
|
||||
$class = Transport::getClass($item['transport_type']);
|
||||
if (class_exists($class)) {
|
||||
//FIXME remove Deprecated transport
|
||||
$transport_title = "Transport {$item['transport_type']}";
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace LibreNMS\Alert;
|
||||
|
||||
use App\Models\AlertTransport;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Support\Str;
|
||||
use LibreNMS\Config;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
@ -10,20 +12,53 @@ use LibreNMS\Interfaces\Alert\Transport as TransportInterface;
|
||||
abstract class Transport implements TransportInterface
|
||||
{
|
||||
protected $config;
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
public static function make(string $type): TransportInterface
|
||||
{
|
||||
$class = self::getClass($type);
|
||||
|
||||
return new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transport constructor.
|
||||
*
|
||||
* @param null $transport_id
|
||||
* @param null $transport
|
||||
*/
|
||||
public function __construct($transport_id = null)
|
||||
public function __construct($transport = null)
|
||||
{
|
||||
if (! empty($transport_id)) {
|
||||
$sql = 'SELECT `transport_config` FROM `alert_transports` WHERE `transport_id`=?';
|
||||
$this->config = json_decode(dbFetchCell($sql, [$transport_id]), true);
|
||||
if (! empty($transport)) {
|
||||
if ($transport instanceof AlertTransport) {
|
||||
$this->config = $transport->transport_config;
|
||||
} else {
|
||||
try {
|
||||
$model = \App\Models\AlertTransport::findOrFail($transport); /** @var AlertTransport $model */
|
||||
$this->config = $model->transport_config;
|
||||
} catch (ModelNotFoundException $e) {
|
||||
$this->config = [];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The display name of this transport
|
||||
*/
|
||||
public function name(): string
|
||||
{
|
||||
if ($this->name !== null) {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
$path = explode('\\', get_called_class());
|
||||
|
||||
return array_pop($path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to parse free form text box defined in ini style to key value pairs
|
||||
*
|
||||
@ -61,4 +96,50 @@ abstract class Transport implements TransportInterface
|
||||
|
||||
return isset($colors[$state]) ? $colors[$state] : '#337AB7';
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the configuration details of this alert transport
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function displayDetails(): string
|
||||
{
|
||||
$output = '';
|
||||
|
||||
// Iterate through transport config template to display config details
|
||||
$config = static::configTemplate();
|
||||
foreach ($config['config'] as $item) {
|
||||
if ($item['type'] == 'oauth') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$val = $this->config[$item['name']];
|
||||
if ($item['type'] == 'password') {
|
||||
$val = '<b>••••••••</b>';
|
||||
} elseif ($item['type'] == 'select') {
|
||||
// Match value to key name for select inputs
|
||||
$val = array_search($val, $item['options']);
|
||||
}
|
||||
|
||||
$output .= $item['title'] . ': ' . $val . PHP_EOL;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the alert transport class from transport type.
|
||||
*
|
||||
* @param string $type
|
||||
* @return string
|
||||
*/
|
||||
public static function getClass(string $type): string
|
||||
{
|
||||
return 'LibreNMS\\Alert\\Transport\\' . ucfirst($type);
|
||||
}
|
||||
|
||||
protected function isHtmlContent($content): bool
|
||||
{
|
||||
return $content !== strip_tags($content);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ namespace LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Config;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Alerta extends Transport
|
||||
{
|
||||
@ -63,7 +64,7 @@ class Alerta extends Transport
|
||||
'type' => $obj['title'],
|
||||
];
|
||||
$alert_message = json_encode($data);
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
$headers = ['Content-Type: application/json', 'Authorization: Key ' . $opts['apikey']];
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
|
||||
curl_setopt($curl, CURLOPT_URL, $host);
|
||||
|
@ -25,9 +25,12 @@ namespace LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Config;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Alertmanager extends Transport
|
||||
{
|
||||
protected $name = 'Alert Manager';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
$alertmanager_opts = $this->parseUserOptions($this->config['alertmanager-options']);
|
||||
@ -72,7 +75,7 @@ class Alertmanager extends Transport
|
||||
public static function postAlerts($url, $data)
|
||||
{
|
||||
$curl = curl_init();
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, 5);
|
||||
|
@ -25,9 +25,12 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Api extends Transport
|
||||
{
|
||||
protected $name = 'API';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
$url = $this->config['api-url'];
|
||||
@ -70,7 +73,7 @@ class Api extends Transport
|
||||
}
|
||||
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$request_opts['proxy'] = get_guzzle_proxy();
|
||||
$request_opts['proxy'] = Proxy::forGuzzle();
|
||||
if (isset($auth) && ! empty($auth[0])) {
|
||||
$request_opts['auth'] = $auth;
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ namespace LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Config;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Boxcar extends Transport
|
||||
{
|
||||
@ -101,7 +102,7 @@ class Boxcar extends Transport
|
||||
}
|
||||
$data['notification[long_message]'] = $message_text;
|
||||
$curl = curl_init();
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://new.boxcar.io/api/notifications');
|
||||
curl_setopt($curl, CURLOPT_SAFE_UPLOAD, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
|
||||
|
89
LibreNMS/Alert/Transport/Browserpush.php
Normal file
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/*
|
||||
* BrowserPush.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2021 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use App\Models\User;
|
||||
use App\Notifications\AlertNotification;
|
||||
use LibreNMS\Alert\Transport;
|
||||
use Notification;
|
||||
|
||||
class Browserpush extends Transport
|
||||
{
|
||||
protected $name = 'Browser Push';
|
||||
|
||||
public function deliverAlert($alert_data, $opts)
|
||||
{
|
||||
$users = User::when($this->config['user'] ?? 0, function ($query, $user_id) {
|
||||
return $query->where('user_id', $user_id);
|
||||
})->get();
|
||||
|
||||
Notification::send($users, new AlertNotification(
|
||||
$alert_data['alert_id'],
|
||||
$alert_data['title'],
|
||||
$alert_data['msg'],
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function configTemplate()
|
||||
{
|
||||
$users = [__('All Users') => 0];
|
||||
foreach (User::get(['user_id', 'username', 'realname']) as $user) {
|
||||
$users[$user->realname ?: $user->username] = $user->user_id;
|
||||
}
|
||||
|
||||
return [
|
||||
'config' => [
|
||||
[
|
||||
'title' => 'User',
|
||||
'name' => 'user',
|
||||
'descr' => 'LibreNMS User',
|
||||
'type' => 'select',
|
||||
'options' => $users,
|
||||
],
|
||||
],
|
||||
'validation' => [
|
||||
'user' => 'required|zero_or_exists:users,user_id',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function displayDetails(): string
|
||||
{
|
||||
if ($this->config['user'] == 0) {
|
||||
$count = \DB::table('push_subscriptions')->count();
|
||||
|
||||
return "All users: $count subscriptions";
|
||||
} elseif ($user = User::find($this->config['user'])) {
|
||||
$count = $user->pushSubscriptions()->count();
|
||||
|
||||
return "User: $user->username ($count subscriptions)";
|
||||
}
|
||||
|
||||
return 'User not found';
|
||||
}
|
||||
}
|
@ -13,9 +13,12 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Ciscospark extends Transport
|
||||
{
|
||||
protected $name = 'Cisco Spark';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
if (empty($this->config)) {
|
||||
@ -57,7 +60,7 @@ class Ciscospark extends Transport
|
||||
$data[$akey] = $text;
|
||||
|
||||
$curl = curl_init();
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://api.ciscospark.com/v1/messages');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, [
|
||||
|
@ -24,6 +24,7 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Clickatell extends Transport
|
||||
{
|
||||
@ -40,7 +41,7 @@ class Clickatell extends Transport
|
||||
$url = 'https://platform.clickatell.com/messages/http/send?apiKey=' . $opts['token'] . '&to=' . implode(',', $opts['to']) . '&content=' . urlencode($obj['title']);
|
||||
|
||||
$curl = curl_init($url);
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
|
@ -29,10 +29,11 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Discord extends Transport
|
||||
{
|
||||
const ALERT_FIELDS_TO_DISCORD_FIELDS = [
|
||||
public const ALERT_FIELDS_TO_DISCORD_FIELDS = [
|
||||
'timestamp' => 'Timestamp',
|
||||
'severity' => 'Severity',
|
||||
'hostname' => 'Hostname',
|
||||
@ -80,7 +81,7 @@ class Discord extends Transport
|
||||
|
||||
$alert_message = json_encode($data);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, $host);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
|
@ -19,6 +19,7 @@ namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Elasticsearch extends Transport
|
||||
{
|
||||
@ -41,7 +42,6 @@ class Elasticsearch extends Transport
|
||||
$index = strftime('librenms-%Y.%m.%d');
|
||||
$type = 'alert';
|
||||
$severity = $obj['severity'];
|
||||
$device = device_by_id_cache($obj['device_id']); // for event logging
|
||||
|
||||
if (! empty($opts['es_host'])) {
|
||||
if (preg_match('/[a-zA-Z]/', $opts['es_host'])) {
|
||||
@ -168,7 +168,7 @@ class Elasticsearch extends Transport
|
||||
$alert_message = json_encode($data);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||
if ($opts['es_proxy'] === true) {
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_URL, $host);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
@ -186,7 +186,7 @@ class Elasticsearch extends Transport
|
||||
$alert_message = json_encode($data);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||
if ($opts['es_proxy'] === true) {
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_URL, $host);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
@ -25,6 +25,7 @@ namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Gitlab extends Transport
|
||||
{
|
||||
@ -43,8 +44,6 @@ class Gitlab extends Transport
|
||||
{
|
||||
// Don't create tickets for resolutions
|
||||
if ($obj['state'] != AlertState::CLEAR) {
|
||||
$device = device_by_id_cache($obj['device_id']); // for event logging
|
||||
|
||||
$project_id = $opts['project-id'];
|
||||
$project_key = $opts['key'];
|
||||
$details = 'Librenms alert for: ' . $obj['hostname'];
|
||||
@ -60,7 +59,7 @@ class Gitlab extends Transport
|
||||
$postdata = ['fields' => $data];
|
||||
$datastring = json_encode($postdata);
|
||||
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
|
||||
$headers = ['Accept: application/json', 'Content-Type: application/json', 'PRIVATE-TOKEN: ' . $project_key];
|
||||
|
||||
@ -75,7 +74,7 @@ class Gitlab extends Transport
|
||||
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
if ($code == 200) {
|
||||
$gitlabout = json_decode($ret, true);
|
||||
d_echo('Created GitLab issue ' . $gitlabout['key'] . ' for ' . $device);
|
||||
d_echo('Created GitLab issue ' . $gitlabout['key'] . ' for ' . $obj['hostname']);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
@ -24,10 +24,13 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
use Log;
|
||||
|
||||
class Googlechat extends Transport
|
||||
{
|
||||
protected $name = 'Google Chat';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
$googlechat_conf['webhookurl'] = $this->config['googlechat-webhook'];
|
||||
@ -43,6 +46,7 @@ class Googlechat extends Transport
|
||||
|
||||
// Create a new cURL resource
|
||||
$ch = curl_init($data['webhookurl']);
|
||||
Proxy::applyToCurl($ch);
|
||||
|
||||
// Attach encoded JSON string to the POST fields
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||
|
@ -25,9 +25,12 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Hipchat extends Transport
|
||||
{
|
||||
protected $name = 'HipChat';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
$hipchat_opts = $this->parseUserOptions($this->config['hipchat-options']);
|
||||
@ -85,7 +88,7 @@ class Hipchat extends Transport
|
||||
$data[] = 'message_format=' . urlencode($option['message_format']);
|
||||
|
||||
$data = implode('&', $data);
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
|
@ -26,6 +26,7 @@ namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
/**
|
||||
* The Hue API currently is fairly limited for alerts.
|
||||
@ -51,7 +52,6 @@ class Hue extends Transport
|
||||
if ($obj['state'] == AlertState::RECOVERED) {
|
||||
return true;
|
||||
} else {
|
||||
$device = device_by_id_cache($obj['device_id']); // for event logging
|
||||
$hue_user = $opts['user'];
|
||||
$url = $opts['bridge'] . "/api/$hue_user/groups/0/action";
|
||||
$curl = curl_init();
|
||||
@ -59,7 +59,7 @@ class Hue extends Transport
|
||||
$data = ['alert' => $duration];
|
||||
$datastring = json_encode($data);
|
||||
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
|
||||
$headers = ['Accept: application/json', 'Content-Type: application/json'];
|
||||
|
||||
@ -73,7 +73,7 @@ class Hue extends Transport
|
||||
$ret = curl_exec($curl);
|
||||
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
if ($code == 200) {
|
||||
d_echo('Sent alert to Phillips Hue Bridge ' . $opts['host'] . ' for ' . $device);
|
||||
d_echo('Sent alert to Phillips Hue Bridge ' . $opts['host'] . ' for ' . $obj['hostname']);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
@ -28,6 +28,8 @@ use LibreNMS\Config;
|
||||
|
||||
class Irc extends Transport
|
||||
{
|
||||
protected $name = 'IRC';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
return $this->contactIrc($obj, $opts);
|
||||
|
@ -24,6 +24,7 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Jira extends Transport
|
||||
{
|
||||
@ -47,8 +48,6 @@ class Jira extends Transport
|
||||
return true;
|
||||
}
|
||||
|
||||
$device = device_by_id_cache($obj['device_id']); // for event logging
|
||||
|
||||
$username = $opts['username'];
|
||||
$password = $opts['password'];
|
||||
$prjkey = $opts['prjkey'];
|
||||
@ -65,7 +64,7 @@ class Jira extends Transport
|
||||
$postdata = ['fields' => $data];
|
||||
$datastring = json_encode($postdata);
|
||||
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
|
||||
$headers = ['Accept: application/json', 'Content-Type: application/json'];
|
||||
|
||||
@ -81,7 +80,7 @@ class Jira extends Transport
|
||||
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
if ($code == 200) {
|
||||
$jiraout = json_decode($ret, true);
|
||||
d_echo('Created jira issue ' . $jiraout['key'] . ' for ' . $device);
|
||||
d_echo('Created jira issue ' . $jiraout['key'] . ' for ' . $obj['hostname']);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
|
@ -14,6 +14,7 @@ namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Config;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Kayako extends Transport
|
||||
{
|
||||
@ -60,6 +61,7 @@ class Kayako extends Transport
|
||||
$post_data = http_build_query($protocol, '', '&');
|
||||
|
||||
$curl = curl_init();
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
|
@ -6,9 +6,12 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Linenotify extends Transport
|
||||
{
|
||||
protected $name = 'LINE Notify';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
$opts['line-notify-access-token'] = $this->config['line-notify-access-token'];
|
||||
@ -23,6 +26,7 @@ class Linenotify extends Transport
|
||||
$lineFields = ['message' => $obj['msg']];
|
||||
|
||||
$curl = curl_init();
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, $lineUrl);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, $lineHead);
|
||||
curl_setopt($curl, CURLOPT_NOBODY, false);
|
||||
|
@ -46,7 +46,7 @@ class Mail extends Transport
|
||||
$msg = preg_replace("/(?<!\r)\n/", "\r\n", $obj['msg']);
|
||||
}
|
||||
|
||||
return send_mail($email, $obj['title'], $msg, $html);
|
||||
return \LibreNMS\Util\Mail::send($email, $obj['title'], $msg, $html);
|
||||
}
|
||||
|
||||
public static function configTemplate()
|
||||
@ -65,9 +65,4 @@ class Mail extends Transport
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function isHtmlContent($content): bool
|
||||
{
|
||||
return $content !== strip_tags($content);
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Matrix extends Transport
|
||||
{
|
||||
@ -57,7 +58,7 @@ class Matrix extends Transport
|
||||
$body = ['body'=>$message, 'msgtype'=>'m.text'];
|
||||
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$request_opts['proxy'] = get_guzzle_proxy();
|
||||
$request_opts['proxy'] = Proxy::forGuzzle();
|
||||
$request_opts['headers'] = $request_heads;
|
||||
$request_opts['body'] = json_encode($body);
|
||||
$res = $client->request('PUT', $host, $request_opts);
|
||||
|
@ -24,6 +24,7 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Mattermost extends Transport
|
||||
{
|
||||
@ -62,9 +63,7 @@ class Mattermost extends Transport
|
||||
'icon_url' => $api['icon'],
|
||||
];
|
||||
|
||||
$device = device_by_id_cache($obj['device_id']);
|
||||
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
|
||||
$httpheaders = ['Accept: application/json', 'Content-Type: application/json'];
|
||||
$alert_payload = json_encode($data);
|
||||
@ -82,7 +81,7 @@ class Mattermost extends Transport
|
||||
|
||||
return 'HTTP Status code ' . $code;
|
||||
} else {
|
||||
d_echo('Mattermost message sent for ' . $device);
|
||||
d_echo('Mattermost message sent for ' . $obj['hostname']);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -13,9 +13,12 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Msteams extends Transport
|
||||
{
|
||||
protected $name = 'Microsoft Teams';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
if (! empty($this->config)) {
|
||||
@ -34,7 +37,7 @@ class Msteams extends Transport
|
||||
'text' => strip_tags($obj['msg'], '<strong><em><h1><h2><h3><strike><ul><ol><li><pre><blockquote><a><img><p>'),
|
||||
];
|
||||
$curl = curl_init();
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, [
|
||||
|
@ -24,6 +24,7 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Opsgenie extends Transport
|
||||
{
|
||||
@ -42,7 +43,7 @@ class Opsgenie extends Transport
|
||||
|
||||
$curl = curl_init();
|
||||
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
|
@ -14,9 +14,12 @@ namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Config;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Osticket extends Transport
|
||||
{
|
||||
protected $name = 'osTicket';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
if (! empty($this->config)) {
|
||||
@ -47,7 +50,7 @@ class Osticket extends Transport
|
||||
'attachments' => [],
|
||||
];
|
||||
$curl = curl_init();
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, [
|
||||
|
@ -28,11 +28,13 @@ use GuzzleHttp\Exception\GuzzleException;
|
||||
use Illuminate\Http\Request;
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
use LibreNMS\Util\Proxy;
|
||||
use Log;
|
||||
use Validator;
|
||||
|
||||
class Pagerduty extends Transport
|
||||
{
|
||||
protected $name = 'PagerDuty';
|
||||
public static $integrationKey = '2fc7c9f3c8030e74aae6';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
@ -81,7 +83,7 @@ class Pagerduty extends Transport
|
||||
$client = new Client();
|
||||
|
||||
$request_opts = ['json' => $data];
|
||||
$request_opts['proxy'] = get_proxy();
|
||||
$request_opts['proxy'] = Proxy::forGuzzle();
|
||||
|
||||
try {
|
||||
$result = $client->request('POST', $url, $request_opts);
|
||||
|
@ -24,9 +24,12 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Playsms extends Transport
|
||||
{
|
||||
protected $name = 'playSMS';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
$playsms_opts['url'] = $this->config['playsms-url'];
|
||||
@ -47,7 +50,7 @@ class Playsms extends Transport
|
||||
$url = $opts['url'] . '&op=pv&' . http_build_query($data);
|
||||
$curl = curl_init($url);
|
||||
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Pushbullet extends Transport
|
||||
{
|
||||
@ -44,7 +45,7 @@ class Pushbullet extends Transport
|
||||
$data = json_encode($data);
|
||||
|
||||
$curl = curl_init('https://api.pushbullet.com/v2/pushes');
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
|
@ -39,6 +39,7 @@ namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Pushover extends Transport
|
||||
{
|
||||
@ -83,7 +84,7 @@ class Pushover extends Transport
|
||||
$data = array_merge($data, $api['options']);
|
||||
}
|
||||
$curl = curl_init();
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, 'https://api.pushover.net/1/messages.json');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_SAFE_UPLOAD, true);
|
||||
|
@ -24,6 +24,7 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Rocket extends Transport
|
||||
{
|
||||
@ -57,7 +58,7 @@ class Rocket extends Transport
|
||||
];
|
||||
$alert_message = json_encode($data);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, $host);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
|
@ -28,14 +28,15 @@ use Illuminate\Support\Facades\Log;
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Config;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Sensu extends Transport
|
||||
{
|
||||
// Sensu alert coding
|
||||
const OK = 0;
|
||||
const WARNING = 1;
|
||||
const CRITICAL = 2;
|
||||
const UNKNOWN = 3;
|
||||
public const OK = 0;
|
||||
public const WARNING = 1;
|
||||
public const CRITICAL = 2;
|
||||
public const UNKNOWN = 3;
|
||||
|
||||
private static $status = [
|
||||
'ok' => Sensu::OK,
|
||||
@ -51,6 +52,9 @@ class Sensu extends Transport
|
||||
'better' => AlertState::BETTER,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var Client
|
||||
*/
|
||||
private static $client = null;
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
@ -74,7 +78,8 @@ class Sensu extends Transport
|
||||
{
|
||||
// The Sensu agent should be running on the poller - events can be sent directly to the backend but this has not been tested, and likely needs mTLS.
|
||||
// The agent API is documented at https://docs.sensu.io/sensu-go/latest/reference/agent/#create-monitoring-events-using-the-agent-api
|
||||
if (Sensu::$client->request('GET', $opts['url'] . '/healthz')->getStatusCode() !== 200) {
|
||||
$request_options = ['proxy' => Proxy::forGuzzle()];
|
||||
if (Sensu::$client->request('GET', $opts['url'] . '/healthz', $request_options)->getStatusCode() !== 200) {
|
||||
return 'Sensu API is not responding';
|
||||
}
|
||||
|
||||
@ -83,7 +88,8 @@ class Sensu extends Transport
|
||||
$data = Sensu::generateData($obj, $opts, Sensu::OK, round(Config::get('rrd.step', 300) / 2));
|
||||
Log::debug('Sensu transport sent last good event to socket: ', $data);
|
||||
|
||||
$result = Sensu::$client->request('POST', $opts['url'] . '/events', ['json' => $data]);
|
||||
$request_options['json'] = $data;
|
||||
$result = Sensu::$client->request('POST', $opts['url'] . '/events', $request_options);
|
||||
if ($result->getStatusCode() !== 202) {
|
||||
return $result->getReasonPhrase();
|
||||
}
|
||||
@ -94,7 +100,8 @@ class Sensu extends Transport
|
||||
$data = Sensu::generateData($obj, $opts, Sensu::calculateStatus($obj['state'], $obj['severity']));
|
||||
Log::debug('Sensu transport sent event to socket: ', $data);
|
||||
|
||||
$result = Sensu::$client->request('POST', $opts['url'] . '/events', ['json' => $data]);
|
||||
$request_options['json'] = $data;
|
||||
$result = Sensu::$client->request('POST', $opts['url'] . '/events', $request_options);
|
||||
if ($result->getStatusCode() === 202) {
|
||||
return true;
|
||||
}
|
||||
|
@ -18,9 +18,12 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Signalwire extends Transport
|
||||
{
|
||||
protected $name = 'SignalWire';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
$signalwire_opts['spaceUrl'] = $this->config['signalwire-spaceUrl'];
|
||||
@ -54,7 +57,7 @@ class Signalwire extends Transport
|
||||
|
||||
$curl = curl_init($url);
|
||||
|
||||
// set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
|
@ -24,6 +24,7 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Slack extends Transport
|
||||
{
|
||||
@ -58,7 +59,7 @@ class Slack extends Transport
|
||||
];
|
||||
$alert_message = json_encode($data);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, $host);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
|
@ -25,9 +25,12 @@ namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use Illuminate\Support\Str;
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Smseagle extends Transport
|
||||
{
|
||||
protected $name = 'SMSEagle';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
$smseagle_opts['url'] = $this->config['smseagle-url'];
|
||||
@ -50,7 +53,7 @@ class Smseagle extends Transport
|
||||
$url .= $opts['url'] . '/index.php/http_api/send_sms?' . http_build_query($params);
|
||||
$curl = curl_init($url);
|
||||
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
|
@ -24,9 +24,12 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Smsfeedback extends Transport
|
||||
{
|
||||
protected $name = 'SMSfeedback';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
$smsfeedback_opts['user'] = $this->config['smsfeedback-user'];
|
||||
@ -49,7 +52,7 @@ class Smsfeedback extends Transport
|
||||
$url = 'http://' . $opts['user'] . ':' . $opts['token'] . '@' . 'api.smsfeedback.ru/messages/v2/send/?' . http_build_query($params);
|
||||
$curl = curl_init($url);
|
||||
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Telegram extends Transport
|
||||
{
|
||||
@ -41,7 +42,7 @@ class Telegram extends Transport
|
||||
public static function contactTelegram($obj, $data)
|
||||
{
|
||||
$curl = curl_init();
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
$text = urlencode($obj['msg']);
|
||||
$format = '';
|
||||
if ($data['format']) {
|
||||
|
@ -16,6 +16,7 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Twilio extends Transport
|
||||
{
|
||||
@ -50,7 +51,7 @@ class Twilio extends Transport
|
||||
|
||||
$curl = curl_init($url);
|
||||
|
||||
// set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
|
@ -24,9 +24,12 @@
|
||||
namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Ukfastpss extends Transport
|
||||
{
|
||||
protected $name = 'UKFast PSS';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
return $this->contactUkfastpss($obj, $opts);
|
||||
@ -57,7 +60,7 @@ class Ukfastpss extends Transport
|
||||
$request_headers['Accept'] = 'application/json';
|
||||
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$request_opts['proxy'] = get_guzzle_proxy();
|
||||
$request_opts['proxy'] = Proxy::forGuzzle();
|
||||
$request_opts['headers'] = $request_headers;
|
||||
$request_opts['body'] = json_encode($body);
|
||||
|
||||
|
@ -26,9 +26,12 @@ namespace LibreNMS\Alert\Transport;
|
||||
|
||||
use LibreNMS\Alert\Transport;
|
||||
use LibreNMS\Enum\AlertState;
|
||||
use LibreNMS\Util\Proxy;
|
||||
|
||||
class Victorops extends Transport
|
||||
{
|
||||
protected $name = 'VictorOps';
|
||||
|
||||
public function deliverAlert($obj, $opts)
|
||||
{
|
||||
if (! empty($this->config)) {
|
||||
@ -62,7 +65,7 @@ class Victorops extends Transport
|
||||
}
|
||||
|
||||
$curl = curl_init();
|
||||
set_curl_proxy($curl);
|
||||
Proxy::applyToCurl($curl);
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, ['Content-type' => 'application/json']);
|
||||
|
@ -28,6 +28,7 @@ namespace LibreNMS;
|
||||
use Composer\Script\Event;
|
||||
use LibreNMS\Exceptions\FileWriteFailedException;
|
||||
use LibreNMS\Util\EnvHelper;
|
||||
use Minishlink\WebPush\VAPID;
|
||||
|
||||
class ComposerHelper
|
||||
{
|
||||
@ -94,6 +95,8 @@ class ComposerHelper
|
||||
|
||||
try {
|
||||
EnvHelper::init();
|
||||
$vapid = VAPID::createVapidKeys();
|
||||
|
||||
EnvHelper::writeEnv([
|
||||
'NODE_ID' => uniqid(),
|
||||
'DB_HOST' => $config['db_host'],
|
||||
@ -105,6 +108,8 @@ class ComposerHelper
|
||||
'APP_URL' => $config['base_url'],
|
||||
'LIBRENMS_USER' => $config['user'],
|
||||
'LIBRENMS_GROUP' => $config['group'],
|
||||
'VAPID_PUBLIC_KEY' => $vapid['publicKey'],
|
||||
'VAPID_PRIVATE_KEY' => $vapid['privateKey'],
|
||||
]);
|
||||
} catch (FileWriteFailedException $exception) {
|
||||
echo $exception->getMessage() . PHP_EOL;
|
||||
|
@ -27,6 +27,11 @@ namespace LibreNMS\Interfaces\Alert;
|
||||
|
||||
interface Transport
|
||||
{
|
||||
/**
|
||||
* @return string The display name of this transport.
|
||||
*/
|
||||
public function name(): string;
|
||||
|
||||
/**
|
||||
* Gets called when an alert is sent
|
||||
*
|
||||
@ -40,4 +45,11 @@ interface Transport
|
||||
* @return array
|
||||
*/
|
||||
public static function configTemplate();
|
||||
|
||||
/**
|
||||
* Display the configuration details of this alert transport
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function displayDetails(): string;
|
||||
}
|
||||
|
127
LibreNMS/Util/Mail.php
Normal file
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
/*
|
||||
* Mail.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2021 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace LibreNMS\Util;
|
||||
|
||||
use Exception;
|
||||
use LibreNMS\Config;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
|
||||
class Mail
|
||||
{
|
||||
/**
|
||||
* Parse string with emails. Return array with email (as key) and name (as value)
|
||||
*
|
||||
* @param string $emails
|
||||
* @return array|false
|
||||
*/
|
||||
public static function parseEmails($emails)
|
||||
{
|
||||
$result = [];
|
||||
$regex = '/^[\"\']?([^\"\']+)[\"\']?\s{0,}<([^@]+@[^>]+)>$/';
|
||||
if (is_string($emails)) {
|
||||
$emails = preg_split('/[,;]\s{0,}/', $emails);
|
||||
foreach ($emails as $email) {
|
||||
if (preg_match($regex, $email, $out, PREG_OFFSET_CAPTURE)) {
|
||||
$result[$out[2][0]] = $out[1][0];
|
||||
} else {
|
||||
if (strpos($email, '@')) {
|
||||
$from_name = Config::get('email_user');
|
||||
$result[$email] = $from_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Return FALSE if input not string
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send email with PHPMailer
|
||||
*
|
||||
* @param string $emails
|
||||
* @param string $subject
|
||||
* @param string $message
|
||||
* @param bool $html
|
||||
* @return bool|string
|
||||
*/
|
||||
public static function send($emails, $subject, $message, bool $html = false)
|
||||
{
|
||||
if (is_array($emails) || ($emails = self::parseEmails($emails))) {
|
||||
d_echo("Attempting to email $subject to: " . implode('; ', array_keys($emails)) . PHP_EOL);
|
||||
$mail = new PHPMailer(true);
|
||||
try {
|
||||
$mail->Hostname = php_uname('n');
|
||||
|
||||
foreach (self::parseEmails(Config::get('email_from')) as $from => $from_name) {
|
||||
$mail->setFrom($from, $from_name);
|
||||
}
|
||||
foreach ($emails as $email => $email_name) {
|
||||
$mail->addAddress($email, $email_name);
|
||||
}
|
||||
$mail->Subject = $subject;
|
||||
$mail->XMailer = Config::get('project_name');
|
||||
$mail->CharSet = 'utf-8';
|
||||
$mail->WordWrap = 76;
|
||||
$mail->Body = $message;
|
||||
if ($html) {
|
||||
$mail->isHTML(true);
|
||||
}
|
||||
switch (strtolower(trim(Config::get('email_backend')))) {
|
||||
case 'sendmail':
|
||||
$mail->Mailer = 'sendmail';
|
||||
$mail->Sendmail = Config::get('email_sendmail_path');
|
||||
break;
|
||||
case 'smtp':
|
||||
$mail->isSMTP();
|
||||
$mail->Host = Config::get('email_smtp_host');
|
||||
$mail->Timeout = Config::get('email_smtp_timeout');
|
||||
$mail->SMTPAuth = Config::get('email_smtp_auth');
|
||||
$mail->SMTPSecure = Config::get('email_smtp_secure');
|
||||
$mail->Port = Config::get('email_smtp_port');
|
||||
$mail->Username = Config::get('email_smtp_username');
|
||||
$mail->Password = Config::get('email_smtp_password');
|
||||
$mail->SMTPAutoTLS = Config::get('email_auto_tls');
|
||||
$mail->SMTPDebug = 0;
|
||||
break;
|
||||
default:
|
||||
$mail->Mailer = 'mail';
|
||||
break;
|
||||
}
|
||||
|
||||
return $mail->send();
|
||||
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
||||
return $e->errorMessage();
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return 'No contacts found';
|
||||
}
|
||||
}
|
84
LibreNMS/Util/Proxy.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/*
|
||||
* Proxy.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2021 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace LibreNMS\Util;
|
||||
|
||||
use LibreNMS\Config;
|
||||
|
||||
class Proxy
|
||||
{
|
||||
/**
|
||||
* Return the proxy url
|
||||
*
|
||||
* @return array|bool|false|string
|
||||
*/
|
||||
public static function get()
|
||||
{
|
||||
if (getenv('http_proxy')) {
|
||||
return getenv('http_proxy');
|
||||
} elseif (getenv('https_proxy')) {
|
||||
return getenv('https_proxy');
|
||||
} elseif ($callback_proxy = Config::get('callback_proxy')) {
|
||||
return $callback_proxy;
|
||||
} elseif ($http_proxy = Config::get('http_proxy')) {
|
||||
return $http_proxy;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the proxy url in guzzle format "tcp://127.0.0.1:8888"
|
||||
*/
|
||||
public static function forGuzzle(): string
|
||||
{
|
||||
$proxy = self::forCurl();
|
||||
|
||||
return empty($proxy) ? '' : ('tcp://' . $proxy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the ip and port of the proxy
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function forCurl(): string
|
||||
{
|
||||
return str_replace(['http://', 'https://'], '', rtrim(self::get(), '/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the proxy on a curl handle
|
||||
*
|
||||
* @param resource $curl
|
||||
*/
|
||||
public static function applyToCurl($curl): void
|
||||
{
|
||||
$proxy = self::forCurl();
|
||||
if (! empty($proxy)) {
|
||||
curl_setopt($curl, CURLOPT_PROXY, $proxy);
|
||||
}
|
||||
}
|
||||
}
|
58
app/Http/Controllers/AlertController.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Alert;
|
||||
use Illuminate\Http\Request;
|
||||
use LibreNMS\Config;
|
||||
use Log;
|
||||
|
||||
class AlertController extends Controller
|
||||
{
|
||||
public function ack(Request $request, Alert $alert): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$this->validate($request, [
|
||||
'state' => 'required|int',
|
||||
'ack_msg' => 'nullable|string',
|
||||
'ack_until_clear' => 'nullable|in:0,1,true,false',
|
||||
]);
|
||||
|
||||
$state = $request->get('state');
|
||||
$state_description = '';
|
||||
if ($state == 2) {
|
||||
$alert->state = 1;
|
||||
$state_description = 'UnAck';
|
||||
$alert->open = 1;
|
||||
} elseif ($state >= 1) {
|
||||
$alert->state = 2;
|
||||
$state_description = 'Ack';
|
||||
$alert->open = 1;
|
||||
}
|
||||
|
||||
$info = $alert->info;
|
||||
$info['until_clear'] = filter_var($request->get('ack_until_clear'), FILTER_VALIDATE_BOOLEAN);
|
||||
$alert->info = $info;
|
||||
|
||||
$timestamp = date(Config::get('dateformat.long'));
|
||||
$username = $request->user()->username;
|
||||
$ack_msg = $request->get('ack_msg');
|
||||
$alert->note = trim($alert->note . PHP_EOL . "$timestamp - $state_description ($username) " . $ack_msg);
|
||||
|
||||
if ($alert->save()) {
|
||||
if (in_array($state, [2, 22])) {
|
||||
$rule_name = $alert->rule->name;
|
||||
Log::event("$username acknowledged alert $rule_name note: $ack_msg", $alert->device_id, 'alert', 2, $alert->id);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => "Alert {$state_description}nowledged.",
|
||||
'status' => 'ok',
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Alert has not been acknowledged.',
|
||||
'status' => 'error',
|
||||
]);
|
||||
}
|
||||
}
|
55
app/Http/Controllers/AlertTransportController.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\AlertTransport;
|
||||
use App\Models\Device;
|
||||
use Illuminate\Http\Request;
|
||||
use LibreNMS\Alert\AlertUtil;
|
||||
use LibreNMS\Config;
|
||||
|
||||
class AlertTransportController extends Controller
|
||||
{
|
||||
public function test(Request $request, AlertTransport $transport): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$device = Device::with('location')->first();
|
||||
$obj = [
|
||||
'hostname' => $device->hostname,
|
||||
'device_id' => $device->device_id,
|
||||
'sysDescr' => $device->sysDescr,
|
||||
'version' => $device->version,
|
||||
'hardware' => $device->hardware,
|
||||
'location' => $device->location,
|
||||
'title' => 'Testing transport from ' . Config::get('project_name'),
|
||||
'elapsed' => '11s',
|
||||
'alert_id' => '000',
|
||||
'id' => '000',
|
||||
'faults' => false,
|
||||
'uid' => '000',
|
||||
'severity' => 'critical',
|
||||
'rule' => 'macros.device = 1',
|
||||
'name' => 'Test-Rule',
|
||||
'string' => '#1: test => string;',
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'contacts' => AlertUtil::getContacts($device->toArray()),
|
||||
'state' => '1',
|
||||
'msg' => 'This is a test alert',
|
||||
];
|
||||
|
||||
$opts = Config::get('alert.transports.' . $transport->transport_type);
|
||||
try {
|
||||
$result = $transport->instance()->deliverAlert($obj, $opts);
|
||||
|
||||
if ($result === true) {
|
||||
return response()->json(['status' => 'ok']);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$result = $e->getMessage();
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => $result,
|
||||
]);
|
||||
}
|
||||
}
|
55
app/Http/Controllers/PushNotificationController.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class PushNotificationController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware('auth');
|
||||
}
|
||||
|
||||
public function token(): string
|
||||
{
|
||||
return csrf_token();
|
||||
}
|
||||
|
||||
public function key(): string
|
||||
{
|
||||
return config('webpush.vapid.public_key');
|
||||
}
|
||||
|
||||
public function register(Request $request): \Illuminate\Http\JsonResponse
|
||||
{
|
||||
$this->validate($request, [
|
||||
'description' => 'string',
|
||||
'subscription.endpoint' => 'required|url',
|
||||
'subscription.keys.auth' => 'required|string',
|
||||
'subscription.keys.p256dh' => 'required|string',
|
||||
]);
|
||||
|
||||
$subscription = $request->user()
|
||||
->updatePushSubscription(
|
||||
$request->input('subscription.endpoint'),
|
||||
$request->input('subscription.keys.p256dh'),
|
||||
$request->input('subscription.keys.auth')
|
||||
);
|
||||
|
||||
$subscription->description = $request->get('description');
|
||||
$success = $subscription->save();
|
||||
|
||||
return response()->json(['success' => $success], 200);
|
||||
}
|
||||
|
||||
public function unregister(Request $request): void
|
||||
{
|
||||
$this->validate($request, [
|
||||
'endpoint' => 'required|url',
|
||||
]);
|
||||
|
||||
$request->user()
|
||||
->deletePushSubscription($request->input('endpoint'));
|
||||
}
|
||||
}
|
@ -250,6 +250,8 @@ class MenuComposer
|
||||
// Search bar
|
||||
$vars['typeahead_limit'] = Config::get('webui.global_search_result_limit');
|
||||
|
||||
$vars['browser_push'] = $user->hasBrowserPushTransport();
|
||||
|
||||
$view->with($vars);
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ use LibreNMS\Enum\AlertState;
|
||||
class Alert extends Model
|
||||
{
|
||||
public $timestamps = false;
|
||||
public $casts = [
|
||||
'info' => 'array',
|
||||
];
|
||||
|
||||
// ---- Query scopes ----
|
||||
|
||||
|
45
app/Models/AlertTransport.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use LibreNMS\Alert\Transport;
|
||||
|
||||
/**
|
||||
* \App\Models\AlertTransport
|
||||
*
|
||||
* @property int $transport_id
|
||||
* @property string $transport_name
|
||||
* @property string $transport_type
|
||||
* @property bool $is_default
|
||||
* @property array|null $transport_config
|
||||
*
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AlertTransport newModelQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AlertTransport newQuery()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AlertTransport query()
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AlertTransport whereIsDefault($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AlertTransport whereTransportConfig($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AlertTransport whereTransportId($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AlertTransport whereTransportName($value)
|
||||
* @method static \Illuminate\Database\Eloquent\Builder|AlertTransport whereTransportType($value)
|
||||
* @mixin \Eloquent
|
||||
*/
|
||||
class AlertTransport extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $primaryKey = 'transport_id';
|
||||
public $timestamps = false;
|
||||
protected $casts = [
|
||||
'is_default' => 'boolean',
|
||||
'transport_config' => 'array',
|
||||
];
|
||||
|
||||
public function instance(): Transport
|
||||
{
|
||||
$class = Transport::getClass($this->transport_type);
|
||||
|
||||
return new $class($this);
|
||||
}
|
||||
}
|
@ -7,11 +7,11 @@ use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOne;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Illuminate\Notifications\Notifiable;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use LibreNMS\Authentication\LegacyAuth;
|
||||
use NotificationChannels\WebPush\HasPushSubscriptions;
|
||||
use Permissions;
|
||||
|
||||
/**
|
||||
@ -19,7 +19,7 @@ use Permissions;
|
||||
*/
|
||||
class User extends Authenticatable
|
||||
{
|
||||
use Notifiable, HasFactory;
|
||||
use Notifiable, HasFactory, HasPushSubscriptions;
|
||||
|
||||
protected $primaryKey = 'user_id';
|
||||
protected $fillable = ['realname', 'username', 'email', 'level', 'descr', 'can_modify_passwd', 'auth_type', 'auth_id', 'enabled'];
|
||||
@ -124,6 +124,21 @@ class User extends Authenticatable
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this user has a browser push notification transport configured.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasBrowserPushTransport(): bool
|
||||
{
|
||||
$user_id = \Auth::id();
|
||||
|
||||
return AlertTransport::query()
|
||||
->where('transport_type', 'browserpush')
|
||||
->where('transport_config', 'regexp', "\"user\":\"(0|$user_id)\"")
|
||||
->exists();
|
||||
}
|
||||
|
||||
// ---- Query scopes ----
|
||||
|
||||
/**
|
||||
@ -189,9 +204,9 @@ class User extends Authenticatable
|
||||
|
||||
// ---- Define Relationships ----
|
||||
|
||||
public function apiToken(): HasOne
|
||||
public function apiTokens(): HasMany
|
||||
{
|
||||
return $this->hasOne(\App\Models\ApiToken::class, 'user_id', 'user_id');
|
||||
return $this->hasMany(\App\Models\ApiToken::class, 'user_id', 'user_id');
|
||||
}
|
||||
|
||||
public function devices()
|
||||
@ -222,6 +237,11 @@ class User extends Authenticatable
|
||||
return $this->hasMany(\App\Models\Dashboard::class, 'user_id');
|
||||
}
|
||||
|
||||
public function notificationAttribs(): HasMany
|
||||
{
|
||||
return $this->hasMany(NotificationAttrib::class, 'user_id');
|
||||
}
|
||||
|
||||
public function preferences(): HasMany
|
||||
{
|
||||
return $this->hasMany(\App\Models\UserPref::class, 'user_id');
|
||||
|
78
app/Notifications/AlertNotification.php
Normal file
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
/*
|
||||
* AlertNotification.php
|
||||
*
|
||||
* -Description-
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @package LibreNMS
|
||||
* @link http://librenms.org
|
||||
* @copyright 2021 Tony Murray
|
||||
* @author Tony Murray <murraytony@gmail.com>
|
||||
*/
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Notifications\Notification;
|
||||
use NotificationChannels\WebPush\WebPushChannel;
|
||||
use NotificationChannels\WebPush\WebPushMessage;
|
||||
|
||||
class AlertNotification extends Notification
|
||||
{
|
||||
/**
|
||||
* @var \NotificationChannels\WebPush\WebPushMessage
|
||||
*/
|
||||
public $message;
|
||||
|
||||
public function __construct(int $alert_id, string $title, string $body)
|
||||
{
|
||||
$this->message = (new WebPushMessage)
|
||||
->title($title)
|
||||
->icon(asset('/images/mstile-144x144.png'))
|
||||
->body($body)
|
||||
->action('Acknowledge', 'alert.acknowledge')
|
||||
->action('View', 'alert.view')
|
||||
->options(['TTL' => 2000])
|
||||
->data(['id' => $alert_id])
|
||||
// ->badge()
|
||||
// ->dir()
|
||||
// ->image()
|
||||
// ->lang()
|
||||
// ->renotify()
|
||||
// ->requireInteraction()
|
||||
// ->tag()
|
||||
// ->vibrate()
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $notifiable
|
||||
* @return string[]
|
||||
*/
|
||||
public function via($notifiable): array
|
||||
{
|
||||
return [WebPushChannel::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $notifiable
|
||||
* @param \Illuminate\Notifications\Notification $notification
|
||||
* @return \NotificationChannels\WebPush\WebPushMessage
|
||||
*/
|
||||
public function toWebPush($notifiable, Notification $notification): WebPushMessage
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
}
|
22
app/Observers/UserObserver.php
Normal file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Observers;
|
||||
|
||||
use App\Models\User;
|
||||
|
||||
class UserObserver
|
||||
{
|
||||
/**
|
||||
* Handle the user "deleted" event.
|
||||
*
|
||||
* @param \App\Models\User $user
|
||||
* @return void
|
||||
*/
|
||||
public function deleted(User $user)
|
||||
{
|
||||
$user->apiTokens()->delete();
|
||||
$user->notificationAttribs()->delete();
|
||||
$user->preferences()->delete();
|
||||
$user->pushSubscriptions()->delete();
|
||||
}
|
||||
}
|
@ -123,6 +123,7 @@ class AppServiceProvider extends ServiceProvider
|
||||
{
|
||||
\App\Models\Device::observe(\App\Observers\DeviceObserver::class);
|
||||
\App\Models\Service::observe(\App\Observers\ServiceObserver::class);
|
||||
\App\Models\User::observe(\App\Observers\UserObserver::class);
|
||||
}
|
||||
|
||||
private function bootCustomValidators()
|
||||
|
33
app/View/Components/NotificationSubscriptionStatus.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\View\Components;
|
||||
|
||||
use Illuminate\View\Component;
|
||||
|
||||
class NotificationSubscriptionStatus extends Component
|
||||
{
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
public $userHasTransport;
|
||||
|
||||
/**
|
||||
* Create a new component instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->userHasTransport = \Auth::user()->hasBrowserPushTransport();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view / contents that represent the component.
|
||||
*
|
||||
* @return \Illuminate\Contracts\View\View|\Closure|string
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
return view('components.notification-subscription-status');
|
||||
}
|
||||
}
|
@ -35,6 +35,7 @@
|
||||
"guzzlehttp/guzzle": "^7.0.1",
|
||||
"influxdb/influxdb-php": "^1.14",
|
||||
"justinrainbow/json-schema": "^5.2",
|
||||
"laravel-notification-channels/webpush": "^5.1",
|
||||
"laravel/framework": "^8.12",
|
||||
"laravel/tinker": "^2.5",
|
||||
"laravel/ui": "^3.0",
|
||||
@ -70,8 +71,9 @@
|
||||
"staudenmeir/dusk-updater": "^1.1"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-gmp": "Used for browser push notifications",
|
||||
"ext-ldap": "*",
|
||||
"ext-memcached": "Required if you utilize distributed polling",
|
||||
"ext-memcached": "Required if you utilize wrapper based distributed polling",
|
||||
"ext-mysqlnd": "*",
|
||||
"ext-posix": "Allows for additional validation tests"
|
||||
},
|
||||
|
633
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "4756600b7d329eed706b8a224e47fb4a",
|
||||
"content-hash": "7d318d5eaf5bfcc28029dfc6acd19ebc",
|
||||
"packages": [
|
||||
{
|
||||
"name": "amenadiel/jpgraph",
|
||||
@ -1061,6 +1061,81 @@
|
||||
},
|
||||
"time": "2020-06-29T00:56:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fgrosse/phpasn1",
|
||||
"version": "v2.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fgrosse/PHPASN1.git",
|
||||
"reference": "20299033c35f4300eb656e7e8e88cf52d1d6694e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/20299033c35f4300eb656e7e8e88cf52d1d6694e",
|
||||
"reference": "20299033c35f4300eb656e7e8e88cf52d1d6694e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~6.3",
|
||||
"satooshi/php-coveralls": "~2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "BCmath is the fallback extension for big integer calculations",
|
||||
"ext-curl": "For loading OID information from the web if they have not bee defined statically",
|
||||
"ext-gmp": "GMP is the preferred extension for big integer calculations",
|
||||
"phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"FG\\": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Friedrich Große",
|
||||
"email": "friedrich.grosse@gmail.com",
|
||||
"homepage": "https://github.com/FGrosse",
|
||||
"role": "Author"
|
||||
},
|
||||
{
|
||||
"name": "All contributors",
|
||||
"homepage": "https://github.com/FGrosse/PHPASN1/contributors"
|
||||
}
|
||||
],
|
||||
"description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.",
|
||||
"homepage": "https://github.com/FGrosse/PHPASN1",
|
||||
"keywords": [
|
||||
"DER",
|
||||
"asn.1",
|
||||
"asn1",
|
||||
"ber",
|
||||
"binary",
|
||||
"decoding",
|
||||
"encoding",
|
||||
"x.509",
|
||||
"x.690",
|
||||
"x509",
|
||||
"x690"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/fgrosse/PHPASN1/issues",
|
||||
"source": "https://github.com/fgrosse/PHPASN1/tree/v2.3.0"
|
||||
},
|
||||
"time": "2021-04-24T19:01:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "fico7489/laravel-pivot",
|
||||
"version": "3.0.7",
|
||||
@ -1741,6 +1816,64 @@
|
||||
},
|
||||
"time": "2021-07-22T09:24:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel-notification-channels/webpush",
|
||||
"version": "5.1.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel-notification-channels/webpush.git",
|
||||
"reference": "a7ace910dfe7f0ef1677a7fa51361ebce2456fdb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel-notification-channels/webpush/zipball/a7ace910dfe7f0ef1677a7fa51361ebce2456fdb",
|
||||
"reference": "a7ace910dfe7f0ef1677a7fa51361ebce2456fdb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"illuminate/notifications": "^5.3|^6.0|^7.0|^8.0",
|
||||
"illuminate/support": "^5.1|^6.0|^7.0|^8.0",
|
||||
"minishlink/web-push": "^6.0",
|
||||
"php": "^7.2|^8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"mockery/mockery": "~1.0",
|
||||
"orchestra/testbench": "^4.0",
|
||||
"phpunit/phpunit": "^8.5"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"NotificationChannels\\WebPush\\WebPushServiceProvider"
|
||||
]
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"NotificationChannels\\WebPush\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Cretu Eusebiu",
|
||||
"email": "me@cretueusebiu.com",
|
||||
"homepage": "http://cretueusebiu.com",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Web Push Notifications driver for Laravel.",
|
||||
"homepage": "https://github.com/laravel-notification-channels/webpush",
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel-notification-channels/webpush/issues",
|
||||
"source": "https://github.com/laravel-notification-channels/webpush/tree/5.1.1"
|
||||
},
|
||||
"time": "2021-01-08T15:12:09+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v8.62.0",
|
||||
@ -2412,6 +2545,69 @@
|
||||
},
|
||||
"time": "2020-09-25T08:51:26+00:00"
|
||||
},
|
||||
{
|
||||
"name": "minishlink/web-push",
|
||||
"version": "v6.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/web-push-libs/web-push-php.git",
|
||||
"reference": "d87e9e3034ca2b95b1822b1b335e7761c14b89f6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/web-push-libs/web-push-php/zipball/d87e9e3034ca2b95b1822b1b335e7761c14b89f6",
|
||||
"reference": "d87e9e3034ca2b95b1822b1b335e7761c14b89f6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-curl": "*",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"ext-openssl": "*",
|
||||
"guzzlehttp/guzzle": "^7.0.1|^6.2",
|
||||
"php": ">=7.2",
|
||||
"web-token/jwt-key-mgmt": "^2.0",
|
||||
"web-token/jwt-signature": "^2.0",
|
||||
"web-token/jwt-signature-algorithm-ecdsa": "^2.0",
|
||||
"web-token/jwt-util-ecc": "^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"friendsofphp/php-cs-fixer": "^2.14",
|
||||
"phpstan/phpstan": "^0.11|^0.12",
|
||||
"phpunit/phpunit": "^8.0|^9.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Minishlink\\WebPush\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Louis Lagrange",
|
||||
"email": "lagrange.louis@gmail.com",
|
||||
"homepage": "https://github.com/Minishlink"
|
||||
}
|
||||
],
|
||||
"description": "Web Push library for PHP",
|
||||
"homepage": "https://github.com/web-push-libs/web-push-php",
|
||||
"keywords": [
|
||||
"Push API",
|
||||
"WebPush",
|
||||
"notifications",
|
||||
"push",
|
||||
"web"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/web-push-libs/web-push-php/issues",
|
||||
"source": "https://github.com/web-push-libs/web-push-php/tree/v6.0.5"
|
||||
},
|
||||
"time": "2021-04-08T15:22:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "monolog/monolog",
|
||||
"version": "2.3.5",
|
||||
@ -4247,6 +4443,71 @@
|
||||
},
|
||||
"time": "2021-06-04T09:56:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spomky-labs/base64url",
|
||||
"version": "v2.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Spomky-Labs/base64url.git",
|
||||
"reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Spomky-Labs/base64url/zipball/7752ce931ec285da4ed1f4c5aa27e45e097be61d",
|
||||
"reference": "7752ce931ec285da4ed1f4c5aa27e45e097be61d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=7.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpstan/extension-installer": "^1.0",
|
||||
"phpstan/phpstan": "^0.11|^0.12",
|
||||
"phpstan/phpstan-beberlei-assert": "^0.11|^0.12",
|
||||
"phpstan/phpstan-deprecation-rules": "^0.11|^0.12",
|
||||
"phpstan/phpstan-phpunit": "^0.11|^0.12",
|
||||
"phpstan/phpstan-strict-rules": "^0.11|^0.12"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Base64Url\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Florent Morselli",
|
||||
"homepage": "https://github.com/Spomky-Labs/base64url/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Base 64 URL Safe Encoding/Decoding PHP Library",
|
||||
"homepage": "https://github.com/Spomky-Labs/base64url",
|
||||
"keywords": [
|
||||
"base64",
|
||||
"rfc4648",
|
||||
"safe",
|
||||
"url"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/Spomky-Labs/base64url/issues",
|
||||
"source": "https://github.com/Spomky-Labs/base64url/tree/v2.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/Spomky",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://www.patreon.com/FlorentMorselli",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-03T09:10:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "swiftmailer/swiftmailer",
|
||||
"version": "v6.2.7",
|
||||
@ -6988,6 +7249,376 @@
|
||||
],
|
||||
"time": "2020-11-12T00:07:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "web-token/jwt-core",
|
||||
"version": "v2.2.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/web-token/jwt-core.git",
|
||||
"reference": "53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/web-token/jwt-core/zipball/53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678",
|
||||
"reference": "53beb6f6c1eec4fa93c1c3e5d9e5701e71fa1678",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.8.17|^0.9",
|
||||
"ext-json": "*",
|
||||
"ext-mbstring": "*",
|
||||
"fgrosse/phpasn1": "^2.0",
|
||||
"php": ">=7.2",
|
||||
"spomky-labs/base64url": "^1.0|^2.0"
|
||||
},
|
||||
"conflict": {
|
||||
"spomky-labs/jose": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Jose\\Component\\Core\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Florent Morselli",
|
||||
"homepage": "https://github.com/Spomky"
|
||||
},
|
||||
{
|
||||
"name": "All contributors",
|
||||
"homepage": "https://github.com/web-token/jwt-framework/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Core component of the JWT Framework.",
|
||||
"homepage": "https://github.com/web-token",
|
||||
"keywords": [
|
||||
"JOSE",
|
||||
"JWE",
|
||||
"JWK",
|
||||
"JWKSet",
|
||||
"JWS",
|
||||
"Jot",
|
||||
"RFC7515",
|
||||
"RFC7516",
|
||||
"RFC7517",
|
||||
"RFC7518",
|
||||
"RFC7519",
|
||||
"RFC7520",
|
||||
"bundle",
|
||||
"jwa",
|
||||
"jwt",
|
||||
"symfony"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/web-token/jwt-core/tree/v2.2.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.patreon.com/FlorentMorselli",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-17T14:55:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "web-token/jwt-key-mgmt",
|
||||
"version": "v2.2.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/web-token/jwt-key-mgmt.git",
|
||||
"reference": "0b116379515700d237b4e5de86879078ccb09d8a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/web-token/jwt-key-mgmt/zipball/0b116379515700d237b4e5de86879078ccb09d8a",
|
||||
"reference": "0b116379515700d237b4e5de86879078ccb09d8a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"psr/http-client": "^1.0",
|
||||
"psr/http-factory": "^1.0",
|
||||
"web-token/jwt-core": "^2.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-sodium": "Sodium is required for OKP key creation, EdDSA signature algorithm and ECDH-ES key encryption with OKP keys",
|
||||
"php-http/httplug": "To enable JKU/X5U support.",
|
||||
"php-http/message-factory": "To enable JKU/X5U support.",
|
||||
"web-token/jwt-util-ecc": "To use EC key analyzers."
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Jose\\Component\\KeyManagement\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Florent Morselli",
|
||||
"homepage": "https://github.com/Spomky"
|
||||
},
|
||||
{
|
||||
"name": "All contributors",
|
||||
"homepage": "https://github.com/web-token/jwt-key-mgmt/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Key Management component of the JWT Framework.",
|
||||
"homepage": "https://github.com/web-token",
|
||||
"keywords": [
|
||||
"JOSE",
|
||||
"JWE",
|
||||
"JWK",
|
||||
"JWKSet",
|
||||
"JWS",
|
||||
"Jot",
|
||||
"RFC7515",
|
||||
"RFC7516",
|
||||
"RFC7517",
|
||||
"RFC7518",
|
||||
"RFC7519",
|
||||
"RFC7520",
|
||||
"bundle",
|
||||
"jwa",
|
||||
"jwt",
|
||||
"symfony"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/web-token/jwt-key-mgmt/tree/v2.2.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.patreon.com/FlorentMorselli",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-17T14:55:52+00:00"
|
||||
},
|
||||
{
|
||||
"name": "web-token/jwt-signature",
|
||||
"version": "v2.2.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/web-token/jwt-signature.git",
|
||||
"reference": "015b59aaf3b6e8fb9f5bd1338845b7464c7d8103"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/web-token/jwt-signature/zipball/015b59aaf3b6e8fb9f5bd1338845b7464c7d8103",
|
||||
"reference": "015b59aaf3b6e8fb9f5bd1338845b7464c7d8103",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"web-token/jwt-core": "^2.1"
|
||||
},
|
||||
"suggest": {
|
||||
"web-token/jwt-signature-algorithm-ecdsa": "ECDSA Based Signature Algorithms",
|
||||
"web-token/jwt-signature-algorithm-eddsa": "EdDSA Based Signature Algorithms",
|
||||
"web-token/jwt-signature-algorithm-experimental": "Experimental Signature Algorithms",
|
||||
"web-token/jwt-signature-algorithm-hmac": "HMAC Based Signature Algorithms",
|
||||
"web-token/jwt-signature-algorithm-none": "None Signature Algorithm",
|
||||
"web-token/jwt-signature-algorithm-rsa": "RSA Based Signature Algorithms"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Jose\\Component\\Signature\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Florent Morselli",
|
||||
"homepage": "https://github.com/Spomky"
|
||||
},
|
||||
{
|
||||
"name": "All contributors",
|
||||
"homepage": "https://github.com/web-token/jwt-signature/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Signature component of the JWT Framework.",
|
||||
"homepage": "https://github.com/web-token",
|
||||
"keywords": [
|
||||
"JOSE",
|
||||
"JWE",
|
||||
"JWK",
|
||||
"JWKSet",
|
||||
"JWS",
|
||||
"Jot",
|
||||
"RFC7515",
|
||||
"RFC7516",
|
||||
"RFC7517",
|
||||
"RFC7518",
|
||||
"RFC7519",
|
||||
"RFC7520",
|
||||
"bundle",
|
||||
"jwa",
|
||||
"jwt",
|
||||
"symfony"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/web-token/jwt-signature/tree/v2.2.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.patreon.com/FlorentMorselli",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-01T19:55:28+00:00"
|
||||
},
|
||||
{
|
||||
"name": "web-token/jwt-signature-algorithm-ecdsa",
|
||||
"version": "v2.2.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/web-token/jwt-signature-algorithm-ecdsa.git",
|
||||
"reference": "44cbbb4374c51f1cf48b82ae761efbf24e1a8591"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/web-token/jwt-signature-algorithm-ecdsa/zipball/44cbbb4374c51f1cf48b82ae761efbf24e1a8591",
|
||||
"reference": "44cbbb4374c51f1cf48b82ae761efbf24e1a8591",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-openssl": "*",
|
||||
"web-token/jwt-signature": "^2.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Jose\\Component\\Signature\\Algorithm\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Florent Morselli",
|
||||
"homepage": "https://github.com/Spomky"
|
||||
},
|
||||
{
|
||||
"name": "All contributors",
|
||||
"homepage": "https://github.com/web-token/jwt-framework/contributors"
|
||||
}
|
||||
],
|
||||
"description": "ECDSA Based Signature Algorithms the JWT Framework.",
|
||||
"homepage": "https://github.com/web-token",
|
||||
"keywords": [
|
||||
"JOSE",
|
||||
"JWE",
|
||||
"JWK",
|
||||
"JWKSet",
|
||||
"JWS",
|
||||
"Jot",
|
||||
"RFC7515",
|
||||
"RFC7516",
|
||||
"RFC7517",
|
||||
"RFC7518",
|
||||
"RFC7519",
|
||||
"RFC7520",
|
||||
"bundle",
|
||||
"jwa",
|
||||
"jwt",
|
||||
"symfony"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/web-token/jwt-signature-algorithm-ecdsa/tree/v2.2.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.patreon.com/FlorentMorselli",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2021-01-21T19:18:03+00:00"
|
||||
},
|
||||
{
|
||||
"name": "web-token/jwt-util-ecc",
|
||||
"version": "v2.2.11",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/web-token/jwt-util-ecc.git",
|
||||
"reference": "915f3fde86f5236c205620d61177b9ef43863deb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/web-token/jwt-util-ecc/zipball/915f3fde86f5236c205620d61177b9ef43863deb",
|
||||
"reference": "915f3fde86f5236c205620d61177b9ef43863deb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"brick/math": "^0.8.17|^0.9"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-bcmath": "GMP or BCMath is highly recommended to improve the library performance",
|
||||
"ext-gmp": "GMP or BCMath is highly recommended to improve the library performance"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Jose\\Component\\Core\\Util\\Ecc\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Florent Morselli",
|
||||
"homepage": "https://github.com/Spomky"
|
||||
},
|
||||
{
|
||||
"name": "All contributors",
|
||||
"homepage": "https://github.com/web-token/jwt-framework/contributors"
|
||||
}
|
||||
],
|
||||
"description": "ECC Tools for the JWT Framework.",
|
||||
"homepage": "https://github.com/web-token",
|
||||
"keywords": [
|
||||
"JOSE",
|
||||
"JWE",
|
||||
"JWK",
|
||||
"JWKSet",
|
||||
"JWS",
|
||||
"Jot",
|
||||
"RFC7515",
|
||||
"RFC7516",
|
||||
"RFC7517",
|
||||
"RFC7518",
|
||||
"RFC7519",
|
||||
"RFC7520",
|
||||
"bundle",
|
||||
"jwa",
|
||||
"jwt",
|
||||
"symfony"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/web-token/jwt-util-ecc/tree/v2.2.11"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://www.patreon.com/FlorentMorselli",
|
||||
"type": "patreon"
|
||||
}
|
||||
],
|
||||
"time": "2021-03-24T13:35:17+00:00"
|
||||
},
|
||||
{
|
||||
"name": "webmozart/assert",
|
||||
"version": "1.10.0",
|
||||
|
@ -25,6 +25,7 @@ return [
|
||||
'enabled' => env('DEBUGBAR_ENABLED', null),
|
||||
'except' => [
|
||||
'api*',
|
||||
'push*',
|
||||
],
|
||||
|
||||
/*
|
||||
|
48
config/webpush.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
|
||||
/**
|
||||
* These are the keys for authentication (VAPID).
|
||||
* These keys must be safely stored and should not change.
|
||||
*/
|
||||
'vapid' => [
|
||||
'subject' => env('VAPID_SUBJECT'),
|
||||
'public_key' => env('VAPID_PUBLIC_KEY'),
|
||||
'private_key' => env('VAPID_PRIVATE_KEY'),
|
||||
'pem_file' => env('VAPID_PEM_FILE'),
|
||||
],
|
||||
|
||||
/**
|
||||
* This is model that will be used to for push subscriptions.
|
||||
*/
|
||||
'model' => \NotificationChannels\WebPush\PushSubscription::class,
|
||||
|
||||
/**
|
||||
* This is the name of the table that will be created by the migration and
|
||||
* used by the PushSubscription model shipped with this package.
|
||||
*/
|
||||
'table_name' => 'push_subscriptions',
|
||||
|
||||
/**
|
||||
* This is the database connection that will be used by the migration and
|
||||
* the PushSubscription model shipped with this package.
|
||||
*/
|
||||
'database_connection' => null,
|
||||
|
||||
/**
|
||||
* The Guzzle client options used by Minishlink\WebPush.
|
||||
*/
|
||||
'client_options' => [],
|
||||
|
||||
/**
|
||||
* Google Cloud Messaging.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
'gcm' => [
|
||||
'key' => env('GCM_KEY'),
|
||||
'sender_id' => env('GCM_SENDER_ID'),
|
||||
],
|
||||
|
||||
];
|
@ -283,7 +283,7 @@ if ($options['f'] === 'purgeusers') {
|
||||
if ($purge > 0) {
|
||||
$users = \App\Models\AuthLog::where('datetime', '>=', \Carbon\Carbon::now()->subDays($purge))
|
||||
->distinct()->pluck('user')
|
||||
->merge(\App\Models\User::has('apiToken')->pluck('username')) // don't purge users with api tokens
|
||||
->merge(\App\Models\User::has('apiTokens')->pluck('username')) // don't purge users with api tokens
|
||||
->unique();
|
||||
|
||||
if (\App\Models\User::thisAuth()->whereNotIn('username', $users)->delete()) {
|
||||
|
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreatePushSubscriptionsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('push_subscriptions', function (Blueprint $table) {
|
||||
$table->bigIncrements('id');
|
||||
$table->morphs('subscribable');
|
||||
$table->string('endpoint', 500)->unique();
|
||||
$table->string('public_key')->nullable();
|
||||
$table->string('auth_token')->nullable();
|
||||
$table->string('content_encoding')->nullable();
|
||||
$table->string('description')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('push_subscriptions');
|
||||
}
|
||||
}
|
@ -174,6 +174,15 @@ website and setup the transport.
|
||||
| ------ | ------- |
|
||||
| Access Token | i23f23mr23rwerw |
|
||||
|
||||
## Browser Push
|
||||
|
||||
Browser push notifications can send a notification to the user's device even when the browser is not open.
|
||||
This requires HTTPS, the PHP GMP extension, [Push API](https://developer.mozilla.org/en-US/docs/Web/API/Push_API) support,
|
||||
and permissions on each device to send alerts.
|
||||
|
||||
Simply configure an alert transport and allow notification permission on the device(s) you
|
||||
wish to receive alerts on. You may disable alerts on a browser on the user preferences page.
|
||||
|
||||
## Canopsis
|
||||
|
||||
Canopsis is a hypervision tool. LibreNMS can send alerts to Canopsis
|
||||
|
@ -26,6 +26,7 @@ Table of Content:
|
||||
- [Transports](Transports.md)
|
||||
- [E-Mail](Transports.md#e-mail)
|
||||
- [API](Transports.md#api)
|
||||
- [Browser Push](Transports.md#browser-push)
|
||||
- [Nagios-Compatible](Transports.md#nagios-compatible)
|
||||
- [IRC](Transports.md#irc)
|
||||
- [Slack](Transports.md#slack)
|
||||
|
@ -26,7 +26,7 @@ Connect to the server command line and follow the instructions below.
|
||||
apt install software-properties-common
|
||||
add-apt-repository universe
|
||||
apt update
|
||||
apt install acl curl composer fping git graphviz imagemagick mariadb-client mariadb-server mtr-tiny nginx-full nmap php7.4-cli php7.4-curl php7.4-fpm php7.4-gd php7.4-json php7.4-mbstring php7.4-mysql php7.4-snmp php7.4-xml php7.4-zip rrdtool snmp snmpd whois unzip python3-pymysql python3-dotenv python3-redis python3-setuptools python3-systemd
|
||||
apt install acl curl composer fping git graphviz imagemagick mariadb-client mariadb-server mtr-tiny nginx-full nmap php7.4-cli php7.4-curl php7.4-fpm php7.4-gd php7.4-gmp php7.4-json php7.4-mbstring php7.4-mysql php7.4-snmp php7.4-xml php7.4-zip rrdtool snmp snmpd whois unzip python3-pymysql python3-dotenv python3-redis python3-setuptools python3-systemd
|
||||
```
|
||||
|
||||
=== "Apache"
|
||||
@ -34,7 +34,7 @@ Connect to the server command line and follow the instructions below.
|
||||
apt install software-properties-common
|
||||
add-apt-repository universe
|
||||
apt update
|
||||
apt install acl curl apache2 composer fping git graphviz imagemagick libapache2-mod-fcgid mariadb-client mariadb-server mtr-tiny nmap php7.4-cli php7.4-curl php7.4-fpm php7.4-gd php7.4-json php7.4-mbstring php7.4-mysql php7.4-snmp php7.4-xml php7.4-zip rrdtool snmp snmpd whois python3-pymysql python3-dotenv python3-redis python3-setuptools python3-systemd
|
||||
apt install acl curl apache2 composer fping git graphviz imagemagick libapache2-mod-fcgid mariadb-client mariadb-server mtr-tiny nmap php7.4-cli php7.4-curl php7.4-fpm php7.4-gd php7.4-gmp php7.4-json php7.4-mbstring php7.4-mysql php7.4-snmp php7.4-xml php7.4-zip rrdtool snmp snmpd whois python3-pymysql python3-dotenv python3-redis python3-setuptools python3-systemd
|
||||
```
|
||||
|
||||
=== "CentOS 8"
|
||||
@ -43,7 +43,7 @@ Connect to the server command line and follow the instructions below.
|
||||
dnf -y install epel-release
|
||||
dnf module reset php
|
||||
dnf module enable php:7.3
|
||||
dnf install bash-completion cronie fping git ImageMagick mariadb-server mtr net-snmp net-snmp-utils nginx nmap php-fpm php-cli php-common php-curl php-gd php-json php-mbstring php-process php-snmp php-xml php-zip php-mysqlnd python3 python3-PyMySQL python3-redis python3-memcached python3-pip python3-systemd rrdtool unzip
|
||||
dnf install bash-completion cronie fping git ImageMagick mariadb-server mtr net-snmp net-snmp-utils nginx nmap php-fpm php-cli php-common php-curl php-gd php-gmp php-json php-mbstring php-process php-snmp php-xml php-zip php-mysqlnd python3 python3-PyMySQL python3-redis python3-memcached python3-pip python3-systemd rrdtool unzip
|
||||
```
|
||||
|
||||
=== "Apache"
|
||||
@ -51,13 +51,13 @@ Connect to the server command line and follow the instructions below.
|
||||
dnf -y install epel-release
|
||||
dnf module reset php
|
||||
dnf module enable php:7.3
|
||||
dnf install bash-completion cronie fping git httpd ImageMagick mariadb-server mtr net-snmp net-snmp-utils nmap php-fpm php-cli php-common php-curl php-gd php-json php-mbstring php-process php-snmp php-xml php-zip php-mysqlnd python3 python3-PyMySQL python3-redis python3-memcached python3-pip python3-systemd rrdtool unzip
|
||||
dnf install bash-completion cronie fping git httpd ImageMagick mariadb-server mtr net-snmp net-snmp-utils nmap php-fpm php-cli php-common php-curl php-gd php-gmp php-json php-mbstring php-process php-snmp php-xml php-zip php-mysqlnd python3 python3-PyMySQL python3-redis python3-memcached python3-pip python3-systemd rrdtool unzip
|
||||
```
|
||||
|
||||
=== "Debian 10"
|
||||
=== "NGINX"
|
||||
```
|
||||
apt install acl curl composer fping git graphviz imagemagick mariadb-client mariadb-server mtr-tiny nginx-full nmap php7.3-cli php7.3-curl php7.3-fpm php7.3-gd php7.3-json php7.3-mbstring php7.3-mysql php7.3-snmp php7.3-xml php7.3-zip python3-dotenv python3-pymysql python3-redis python3-setuptools python3-systemd rrdtool snmp snmpd whois
|
||||
apt install acl curl composer fping git graphviz imagemagick mariadb-client mariadb-server mtr-tiny nginx-full nmap php7.3-cli php7.3-curl php7.3-fpm php7.3-gd php7.3-gmp php7.3-json php7.3-mbstring php7.3-mysql php7.3-snmp php7.3-xml php7.3-zip python3-dotenv python3-pymysql python3-redis python3-setuptools python3-systemd rrdtool snmp snmpd whois
|
||||
```
|
||||
|
||||
## Add librenms user
|
||||
|
BIN
html/images/android-chrome-144x144.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 2.2 KiB |
@ -1,6 +1,13 @@
|
||||
{
|
||||
"name": "LibreNMS",
|
||||
"short_name": "LibreNMS",
|
||||
"name": "LibreNMS: Network Monitoring",
|
||||
"description": "A fully featured network monitoring system that provides a wealth of features and device support",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/images/mstile-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/images/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
@ -14,5 +21,34 @@
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
"display_override": ["window-control-overlay", "minimal-ui"],
|
||||
"display": "standalone",
|
||||
"start_url": "/overview",
|
||||
"scope": "/",
|
||||
"shortcuts": [
|
||||
{
|
||||
"name": "Alerts",
|
||||
"description": "View active alerts",
|
||||
"url": "/alerts",
|
||||
"icons": [{ "src": "/images/icons/bell.svg", "purpose": "any maskable", "type": "image/svg+xml", "sizes": "256x256" }]
|
||||
},
|
||||
{
|
||||
"name": "Devices",
|
||||
"description": "View device list",
|
||||
"url": "/devices",
|
||||
"icons": [{ "src": "/images/icons/server.svg", "purpose": "any maskable", "type": "image/svg+xml", "sizes": "256x256" }]
|
||||
},
|
||||
{
|
||||
"name": "Status",
|
||||
"description": "View overview of device availability",
|
||||
"url": "/availability-map",
|
||||
"icons": [{ "src": "/images/icons/arrow-circle-up.svg", "purpose": "any maskable", "type": "image/svg+xml", "sizes": "256x256" }]
|
||||
},
|
||||
{
|
||||
"name": "Map",
|
||||
"description": "View geographical map",
|
||||
"url": "/fullscreenmap",
|
||||
"icons": [{ "src": "/images/icons/map-marked.svg", "purpose": "any maskable", "type": "image/svg+xml", "sizes": "256x256" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 107 B |
@ -469,3 +469,8 @@ function humanize_duration(seconds) {
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
function popUp(URL)
|
||||
{
|
||||
window.open(URL, '_blank', 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=550,height=600');
|
||||
}
|
||||
|
79
html/js/register-service-worker.js
Normal file
@ -0,0 +1,79 @@
|
||||
if ('serviceWorker' in navigator) {
|
||||
// Register a Service Worker.
|
||||
navigator.serviceWorker.register('/service-worker.js');
|
||||
|
||||
navigator.serviceWorker.ready
|
||||
.then(function (registration) {
|
||||
return registration.pushManager.getSubscription()
|
||||
.then(async function (subscription) {
|
||||
if (subscription) {
|
||||
return subscription;
|
||||
}
|
||||
|
||||
if (Notification.permission === "granted") {
|
||||
// Get the server's public key
|
||||
const response = await fetch('./push/key');
|
||||
const vapidPublicKey = await response.text();
|
||||
const convertedVapidKey = urlBase64ToUint8Array(vapidPublicKey);
|
||||
|
||||
return registration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: convertedVapidKey
|
||||
});
|
||||
}
|
||||
});
|
||||
}).then(function (subscription) {
|
||||
if (! subscription) {
|
||||
console.log('no subscription');
|
||||
return;
|
||||
}
|
||||
|
||||
const token = document.querySelector('meta[name=csrf-token]').getAttribute('content');
|
||||
|
||||
if (localStorage.getItem('notifications') === 'disabled' || Notification.permission === "denied") {
|
||||
// disabled by user remove the subscription
|
||||
fetch('./push/unregister', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': token
|
||||
},
|
||||
body: JSON.stringify({
|
||||
endpoint: subscription.endpoint
|
||||
}),
|
||||
});
|
||||
|
||||
} else {
|
||||
// Send the subscription details to the server
|
||||
fetch('./push/register', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': token
|
||||
},
|
||||
body: JSON.stringify({
|
||||
description: navigator.userAgent,
|
||||
subscription: subscription
|
||||
}),
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function urlBase64ToUint8Array(base64String) {
|
||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||
const base64 = (base64String + padding)
|
||||
.replace(/\-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
const rawData = window.atob(base64);
|
||||
const outputArray = new Uint8Array(rawData.length);
|
||||
|
||||
for (let i = 0; i < rawData.length; ++i) {
|
||||
outputArray[i] = rawData.charCodeAt(i);
|
||||
}
|
||||
return outputArray;
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"/js/app.js": "/js/app.js?id=cc34801c36c263f094da",
|
||||
"/js/app.js": "/js/app.js?id=f86bb54abe9f728932a7",
|
||||
"/js/manifest.js": "/js/manifest.js?id=8d61162bb0caf92f60ff",
|
||||
"/css/vendor.css": "/css/vendor.css?id=8d7b2ecb46047fe813e4",
|
||||
"/css/app.css": "/css/app.css?id=54a173acc7d587a9afa4",
|
||||
|
70
html/service-worker.js
Normal file
@ -0,0 +1,70 @@
|
||||
self.addEventListener('fetch', function (event) {
|
||||
});
|
||||
|
||||
self.addEventListener('push', function (e) {
|
||||
if (!(self.Notification && self.Notification.permission === 'granted') && localStorage.getItem('notifications') !== 'disabled') {
|
||||
//notifications aren't supported or permission not granted!
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.data) {
|
||||
const msg = e.data.json();
|
||||
// console.log(msg)
|
||||
e.waitUntil(self.registration.showNotification(msg.title, {
|
||||
body: msg.body,
|
||||
icon: msg.icon,
|
||||
actions: msg.actions,
|
||||
data: msg.data
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
self.addEventListener('notificationclick', function (event) {
|
||||
event.notification.close();
|
||||
|
||||
if (event.action === 'alert.acknowledge') {
|
||||
post(`./alert/${event.notification.data.id}/ack`, {state: 1})
|
||||
} else if (event.action === 'alert.view') {
|
||||
// navigate to alert
|
||||
event.waitUntil(self.clients.claim().then(() => self.clients.matchAll({type: 'window'}))
|
||||
.then(clients => {
|
||||
return clients.map(client => {
|
||||
let alert_url = '/alerts?alert_id=' + event.notification.data.id;
|
||||
// Check to make sure WindowClient.navigate() is supported.
|
||||
if ('navigate' in client) {
|
||||
return client.navigate(alert_url);
|
||||
}
|
||||
|
||||
return self.clients.openWindow(alert_url);
|
||||
});
|
||||
}));
|
||||
}
|
||||
}, false);
|
||||
|
||||
let csrf;
|
||||
|
||||
function post(url, data, retry = true) {
|
||||
if (!self.csrf) {
|
||||
return self.post(url, data, true);
|
||||
}
|
||||
|
||||
return fetch(url, {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': self.csrf
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
}).then((response) => {
|
||||
if (response.status === 419 && retry === true) {
|
||||
self.csrf = null; // reset csrf and try again
|
||||
return self.post(url, data, false);
|
||||
}
|
||||
}).catch(e => console.log(e));
|
||||
}
|
||||
|
||||
const fetchCsrf = async () => {
|
||||
const response = await fetch('/push/token')
|
||||
self.csrf = await response.text();
|
||||
}
|
@ -21,7 +21,6 @@ use LibreNMS\Modules\Core;
|
||||
use LibreNMS\Util\Debug;
|
||||
use LibreNMS\Util\IPv4;
|
||||
use LibreNMS\Util\IPv6;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
|
||||
function array_sort_by_column($array, $on, $order = SORT_ASC)
|
||||
{
|
||||
@ -715,82 +714,12 @@ function log_event($text, $device = null, $type = null, $severity = 2, $referenc
|
||||
// Parse string with emails. Return array with email (as key) and name (as value)
|
||||
function parse_email($emails)
|
||||
{
|
||||
$result = [];
|
||||
$regex = '/^[\"\']?([^\"\']+)[\"\']?\s{0,}<([^@]+@[^>]+)>$/';
|
||||
if (is_string($emails)) {
|
||||
$emails = preg_split('/[,;]\s{0,}/', $emails);
|
||||
foreach ($emails as $email) {
|
||||
if (preg_match($regex, $email, $out, PREG_OFFSET_CAPTURE)) {
|
||||
$result[$out[2][0]] = $out[1][0];
|
||||
} else {
|
||||
if (strpos($email, '@')) {
|
||||
$from_name = Config::get('email_user');
|
||||
$result[$email] = $from_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Return FALSE if input not string
|
||||
return false;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return \LibreNMS\Util\Mail::parseEmails($emails);
|
||||
}
|
||||
|
||||
function send_mail($emails, $subject, $message, $html = false)
|
||||
{
|
||||
if (is_array($emails) || ($emails = parse_email($emails))) {
|
||||
d_echo("Attempting to email $subject to: " . implode('; ', array_keys($emails)) . PHP_EOL);
|
||||
$mail = new PHPMailer(true);
|
||||
try {
|
||||
$mail->Hostname = php_uname('n');
|
||||
|
||||
foreach (parse_email(Config::get('email_from')) as $from => $from_name) {
|
||||
$mail->setFrom($from, $from_name);
|
||||
}
|
||||
foreach ($emails as $email => $email_name) {
|
||||
$mail->addAddress($email, $email_name);
|
||||
}
|
||||
$mail->Subject = $subject;
|
||||
$mail->XMailer = Config::get('project_name');
|
||||
$mail->CharSet = 'utf-8';
|
||||
$mail->WordWrap = 76;
|
||||
$mail->Body = $message;
|
||||
if ($html) {
|
||||
$mail->isHTML(true);
|
||||
}
|
||||
switch (strtolower(trim(Config::get('email_backend')))) {
|
||||
case 'sendmail':
|
||||
$mail->Mailer = 'sendmail';
|
||||
$mail->Sendmail = Config::get('email_sendmail_path');
|
||||
break;
|
||||
case 'smtp':
|
||||
$mail->isSMTP();
|
||||
$mail->Host = Config::get('email_smtp_host');
|
||||
$mail->Timeout = Config::get('email_smtp_timeout');
|
||||
$mail->SMTPAuth = Config::get('email_smtp_auth');
|
||||
$mail->SMTPSecure = Config::get('email_smtp_secure');
|
||||
$mail->Port = Config::get('email_smtp_port');
|
||||
$mail->Username = Config::get('email_smtp_username');
|
||||
$mail->Password = Config::get('email_smtp_password');
|
||||
$mail->SMTPAutoTLS = Config::get('email_auto_tls');
|
||||
$mail->SMTPDebug = false;
|
||||
break;
|
||||
default:
|
||||
$mail->Mailer = 'mail';
|
||||
break;
|
||||
}
|
||||
$mail->send();
|
||||
|
||||
return true;
|
||||
} catch (\PHPMailer\PHPMailer\Exception $e) {
|
||||
return $e->errorMessage();
|
||||
} catch (Exception $e) {
|
||||
return $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
return 'No contacts found';
|
||||
return \LibreNMS\Util\Mail::send($emails, $subject, $message, $html);
|
||||
}
|
||||
|
||||
function hex2str($hex)
|
||||
@ -1058,13 +987,7 @@ function guidv4($data)
|
||||
*/
|
||||
function set_curl_proxy($curl)
|
||||
{
|
||||
$proxy = get_proxy();
|
||||
|
||||
$tmp = rtrim($proxy, '/');
|
||||
$proxy = str_replace(['http://', 'https://'], '', $tmp);
|
||||
if (! empty($proxy)) {
|
||||
curl_setopt($curl, CURLOPT_PROXY, $proxy);
|
||||
}
|
||||
\LibreNMS\Util\Proxy::applyToCurl($curl);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1074,12 +997,7 @@ function set_curl_proxy($curl)
|
||||
*/
|
||||
function get_guzzle_proxy()
|
||||
{
|
||||
$proxy = get_proxy();
|
||||
|
||||
$tmp = rtrim($proxy, '/');
|
||||
$proxy = str_replace(['http://', 'https://'], '', $tmp);
|
||||
|
||||
return empty($proxy) ? '' : ('tcp://' . $proxy);
|
||||
return \LibreNMS\Util\Proxy::forGuzzle();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1089,17 +1007,7 @@ function get_guzzle_proxy()
|
||||
*/
|
||||
function get_proxy()
|
||||
{
|
||||
if (getenv('http_proxy')) {
|
||||
return getenv('http_proxy');
|
||||
} elseif (getenv('https_proxy')) {
|
||||
return getenv('https_proxy');
|
||||
} elseif ($callback_proxy = Config::get('callback_proxy')) {
|
||||
return $callback_proxy;
|
||||
} elseif ($http_proxy = Config::get('http_proxy')) {
|
||||
return $http_proxy;
|
||||
}
|
||||
|
||||
return false;
|
||||
return \LibreNMS\Util\Proxy::get();
|
||||
}
|
||||
|
||||
function target_to_id($target)
|
||||
|
@ -164,6 +164,7 @@ if (defined('SHOW_SETTINGS')) {
|
||||
</form>
|
||||
';
|
||||
} else {
|
||||
$alert_id = $vars['alert_id'] ?? 0;
|
||||
$device_id = $device['device_id'];
|
||||
$acknowledged = $widget_settings['acknowledged'];
|
||||
$fired = $widget_settings['fired'];
|
||||
@ -255,6 +256,9 @@ var alerts_grid = $("#alerts_' . $unique_id . '").bootgrid({
|
||||
return {
|
||||
id: "alerts",
|
||||
';
|
||||
if (is_numeric($alert_id)) {
|
||||
$common_output[] = "alert_id: '$alert_id',\n";
|
||||
}
|
||||
|
||||
if (is_numeric($acknowledged)) {
|
||||
$common_output[] = "acknowledged: '$acknowledged',\n";
|
||||
|
@ -4,10 +4,10 @@ echo "<div style='margin:auto; text-align: center; margin-top: 50px; max-width:6
|
||||
print_optionbar_start(100, 600);
|
||||
echo "
|
||||
<table height=100% width=100%><tr>
|
||||
<td><img src='images/no-48.png' valign=absmiddle></td>
|
||||
<td style='color: darkred'><i class='fa fa-3x fa-ban'></i></td>
|
||||
<td width=10></td>
|
||||
<td>
|
||||
<span style='color: #990000; font-weight: bold;'>
|
||||
<span style='color: darkred; font-weight: bold;'>
|
||||
<span style='font-size: 16px; font-weight: bold;'>Error</span>
|
||||
<br />
|
||||
<span style='font-size: 12px;'>You have insufficient permissions to view this page.</span>
|
||||
|
@ -1,90 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* ack-alert.inc.php
|
||||
*
|
||||
* LibreNMS ack-alert.inc.php
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @link https://www.librenms.org
|
||||
*
|
||||
* @copyright 2018 Neil Lathwood
|
||||
* @author Neil Lathwood <gh+n@laf.io>
|
||||
*/
|
||||
|
||||
use LibreNMS\Config;
|
||||
|
||||
header('Content-type: application/json');
|
||||
|
||||
$alert_id = $vars['alert_id'];
|
||||
$state = $vars['state'];
|
||||
$ack_msg = $vars['ack_msg'];
|
||||
$until_clear = $vars['ack_until_clear'];
|
||||
|
||||
$status = 'error';
|
||||
|
||||
if (! is_numeric($alert_id)) {
|
||||
$message = 'No alert selected';
|
||||
} elseif (! is_numeric($state)) {
|
||||
$message = 'No state passed';
|
||||
} else {
|
||||
if ($state == 2) {
|
||||
$state = 1;
|
||||
$state_descr = 'UnAck';
|
||||
$open = 1;
|
||||
} elseif ($state >= 1) {
|
||||
$state = 2;
|
||||
$state_descr = 'Ack';
|
||||
$open = 1;
|
||||
}
|
||||
|
||||
if ($until_clear === 'true') {
|
||||
$until_clear = true;
|
||||
} else {
|
||||
$until_clear = false;
|
||||
}
|
||||
|
||||
$info = json_encode([
|
||||
'until_clear' => $until_clear,
|
||||
]);
|
||||
|
||||
$username = Auth::user()->username;
|
||||
$data = [
|
||||
'state' => $state,
|
||||
'open' => $open,
|
||||
'info' => $info,
|
||||
];
|
||||
|
||||
$note = dbFetchCell('SELECT note FROM alerts WHERE id=?', [$alert_id]);
|
||||
if (! empty($note)) {
|
||||
$note .= PHP_EOL;
|
||||
}
|
||||
$data['note'] = $note . date(Config::get('dateformat.long')) . " - $state_descr ($username) $ack_msg";
|
||||
|
||||
if (dbUpdate($data, 'alerts', 'id=?', [$alert_id]) >= 0) {
|
||||
if (in_array($state, [2, 22])) {
|
||||
$alert_info = dbFetchRow('SELECT `alert_rules`.`name`,`alerts`.`device_id` FROM `alert_rules` LEFT JOIN `alerts` ON `alerts`.`rule_id` = `alert_rules`.`id` WHERE `alerts`.`id` = ?', [$alert_id]);
|
||||
log_event("$username acknowledged alert {$alert_info['name']} note: $ack_msg", $alert_info['device_id'], 'alert', 2, $alert_id);
|
||||
}
|
||||
$message = 'Alert acknowledged status changed.';
|
||||
$status = 'ok';
|
||||
} else {
|
||||
$message = 'Alert has not been acknowledged.';
|
||||
}
|
||||
}//end if
|
||||
|
||||
exit(json_encode([
|
||||
'status' => $status,
|
||||
'message' => $message,
|
||||
]));
|
@ -22,13 +22,6 @@
|
||||
* @copyright 2018 Vivia Nguyen-Tran
|
||||
* @author Vivia Nguyen-Tran <vivia@ualberta.ca>
|
||||
*/
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Filesystem\Filesystem;
|
||||
use Illuminate\Translation\FileLoader;
|
||||
use Illuminate\Translation\Translator;
|
||||
use Illuminate\Validation\Factory;
|
||||
|
||||
header('Content-type: application/json');
|
||||
|
||||
if (! Auth::user()->hasGlobalAdmin()) {
|
||||
@ -79,10 +72,7 @@ if (empty($name)) {
|
||||
|
||||
// Build config values
|
||||
$result = call_user_func_array($class . '::configTemplate', []);
|
||||
$loader = new FileLoader(new Filesystem, "$install_dir/resources/lang");
|
||||
$translator = new Translator($loader, 'en');
|
||||
$validation = new Factory($translator, new Container);
|
||||
$validator = $validation->make($vars, $result['validation']);
|
||||
$validator = Validator::make($vars, $result['validation']);
|
||||
if ($validator->fails()) {
|
||||
$errors = $validator->errors();
|
||||
foreach ($errors->all() as $error) {
|
||||
|
@ -1,67 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* LibreNMS
|
||||
*
|
||||
* Copyright (c) 2014 Neil Lathwood <https://github.com/laf/ http://www.lathwood.co.uk/fa>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation, either version 3 of the License, or (at your
|
||||
* option) any later version. Please see LICENSE.txt at the top level of
|
||||
* the source code distribution for details.
|
||||
*/
|
||||
|
||||
use LibreNMS\Alert\AlertUtil;
|
||||
use LibreNMS\Config;
|
||||
|
||||
if (! Auth::user()->hasGlobalAdmin()) {
|
||||
header('Content-type: text/plain');
|
||||
exit('ERROR: You need to be admin');
|
||||
}
|
||||
|
||||
$transport = $vars['transport'] ?: null;
|
||||
$transport_id = $vars['transport_id'] ?: null;
|
||||
|
||||
$tmp = [dbFetchRow('select device_id,hostname,sysDescr,version,hardware,location_id from devices order by device_id asc limit 1')];
|
||||
$tmp['contacts'] = AlertUtil::getContacts($tmp);
|
||||
$obj = [
|
||||
'hostname' => $tmp[0]['hostname'],
|
||||
'device_id' => $tmp[0]['device_id'],
|
||||
'sysDescr' => $tmp[0]['sysDescr'],
|
||||
'version' => $tmp[0]['version'],
|
||||
'hardware' => $tmp[0]['hardware'],
|
||||
'location' => $tmp[0]['location'],
|
||||
'title' => 'Testing transport from ' . Config::get('project_name'),
|
||||
'elapsed' => '11s',
|
||||
'id' => '000',
|
||||
'faults' => false,
|
||||
'uid' => '000',
|
||||
'severity' => 'critical',
|
||||
'rule' => 'macros.device = 1',
|
||||
'name' => 'Test-Rule',
|
||||
'string' => '#1: test => string;',
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'contacts' => $tmp['contacts'],
|
||||
'state' => '1',
|
||||
'msg' => 'This is a test alert',
|
||||
];
|
||||
|
||||
$response = ['status' => 'error'];
|
||||
|
||||
if ($transport_id) {
|
||||
$transport = dbFetchCell('SELECT `transport_type` FROM `alert_transports` WHERE `transport_id` = ?', [$transport_id]);
|
||||
}
|
||||
$class = 'LibreNMS\\Alert\\Transport\\' . ucfirst($transport);
|
||||
if (class_exists($class)) {
|
||||
$opts = Config::get("alert.transports.$transport");
|
||||
$instance = new $class($transport_id);
|
||||
$result = $instance->deliverAlert($obj, $opts);
|
||||
if ($result === true) {
|
||||
$response['status'] = 'ok';
|
||||
} else {
|
||||
$response['message'] = $result;
|
||||
}
|
||||
}
|
||||
header('Content-type: application/json');
|
||||
echo json_encode($response);
|
@ -58,9 +58,9 @@ use LibreNMS\Config;
|
||||
var ack_until_clear = $("#ack_until_clear").bootstrapSwitch('state');
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "ajax_form.php",
|
||||
url: '<?php echo route('alert.ack', ['alert' => ':alert_id']) ?>'.replace(':alert_id', ack_alert_id),
|
||||
dataType: "json",
|
||||
data: { type: "ack-alert", alert_id: ack_alert_id, state: ack_alert_state, ack_msg: ack_alert_note, ack_until_clear: ack_until_clear },
|
||||
data: { state: ack_alert_state, ack_msg: ack_alert_note, ack_until_clear: ack_until_clear },
|
||||
success: function (data) {
|
||||
if (data.status === "ok") {
|
||||
toastr.success(data.message);
|
||||
@ -70,7 +70,7 @@ use LibreNMS\Config;
|
||||
$table.bootgrid("sort", sortDictionary);
|
||||
$("#alert_ack_modal").modal('hide');
|
||||
} else {
|
||||
toastr.error(data.message);
|
||||
toastr.error(data.message || 'Failed to update acknowledgement');
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
|
@ -37,8 +37,8 @@ if (Auth::user()->hasGlobalAdmin()) {
|
||||
</div>
|
||||
<div class="form-group" title="The type of transport.">
|
||||
<label for='transport-choice' class='col-sm-3 col-md-2 control-label'>Transport type: </label>
|
||||
<div class="col-sm-3">
|
||||
<select name='transport-choice' id='transport-choice' class='form-control'>
|
||||
<div class="col-sm-9 col-md-10">
|
||||
<select name='transport-choice' id='transport-choice' class='form-control' style="width: auto">
|
||||
<?php
|
||||
|
||||
// Create list of transport
|
||||
@ -49,10 +49,12 @@ if (Auth::user()->hasGlobalAdmin()) {
|
||||
if (empty($transport)) {
|
||||
continue;
|
||||
}
|
||||
$transports_list[] = $transport;
|
||||
$class = "\LibreNMS\Alert\Transport\\$transport";
|
||||
$instance = new $class;
|
||||
$transports_list[$transport] = $instance->name();
|
||||
}
|
||||
foreach ($transports_list as $transport) {
|
||||
echo '<option value="' . strtolower($transport) . '-form">' . $transport . '</option>';
|
||||
foreach ($transports_list as $transport => $name) {
|
||||
echo '<option value="' . strtolower($transport) . '-form">' . $name . '</option>';
|
||||
} ?>
|
||||
</select>
|
||||
</div>
|
||||
@ -67,7 +69,7 @@ if (Auth::user()->hasGlobalAdmin()) {
|
||||
<?php
|
||||
|
||||
$switches = []; // store names of bootstrap switches
|
||||
foreach ($transports_list as $transport) {
|
||||
foreach ($transports_list as $transport => $name) {
|
||||
$class = 'LibreNMS\\Alert\\Transport\\' . $transport;
|
||||
|
||||
if (! method_exists($class, 'configTemplate')) {
|
||||
@ -77,7 +79,7 @@ if (Auth::user()->hasGlobalAdmin()) {
|
||||
|
||||
echo '<form method="post" role="form" id="' . strtolower($transport) . '-form" class="form-horizontal transport">';
|
||||
echo csrf_field();
|
||||
echo '<input type="hidden" name="transport-type" id="transport-type" value="' . strtolower($transport) . '">';
|
||||
echo '<input type="hidden" name="transport-type" value="' . strtolower($transport) . '">';
|
||||
|
||||
$tmp = call_user_func($class . '::configTemplate');
|
||||
|
||||
|
@ -32,5 +32,3 @@ $page_title = 'Alerts';
|
||||
unset($device['device_id']);
|
||||
?>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -467,26 +467,6 @@ if ($count < 1) {
|
||||
$("[data-toggle='modal'], [data-toggle='popover']").popover({
|
||||
trigger: 'hover'
|
||||
});
|
||||
$('#ack-alert').on("click", function(e) {
|
||||
event.preventDefault();
|
||||
var alert_id = $(this).data("alert_id");
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "ajax_form.php",
|
||||
data: { type: "ack-alert", alert_id: alert_id },
|
||||
success: function(msg){
|
||||
$("#message").html('<div class="alert alert-info">'+msg+'</div>');
|
||||
if(msg.indexOf("ERROR:") <= -1) {
|
||||
setTimeout(function() {
|
||||
location.reload(1);
|
||||
}, 1000);
|
||||
}
|
||||
},
|
||||
error: function(){
|
||||
$("#message").html('<div class="alert alert-info">An error occurred acking this alert.</div>');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("[name='alert-rule']").bootstrapSwitch('offColor','danger');
|
||||
$('input[name="alert-rule"]').on('switchChange.bootstrapSwitch', function(event, state) {
|
||||
|
@ -31,54 +31,21 @@ if (Auth::user()->hasGlobalAdmin()) {
|
||||
<?php
|
||||
|
||||
// Iterate through each alert transport
|
||||
$query = 'SELECT `transport_id` AS `id`, `transport_name` AS `name`, `transport_type` AS `type`, `is_default`, `transport_config` AS `config` FROM `alert_transports` order by `name`';
|
||||
foreach (dbFetchRows($query) as $transport) {
|
||||
echo "<tr id=\"alert-transport-{$transport['id']}\">";
|
||||
echo '<td>' . $transport['name'] . '</td>';
|
||||
echo '<td>' . $transport['type'] . '</td>';
|
||||
if ($transport['is_default'] == true) {
|
||||
echo '<td>Yes</td>';
|
||||
} else {
|
||||
echo '<td>No</td>';
|
||||
}
|
||||
foreach (\App\Models\AlertTransport::all() as $transport) {
|
||||
$instance = $transport->instance();
|
||||
echo "<tr id=\"alert-transport-{$transport->transport_id}\">";
|
||||
echo '<td>' . $transport->transport_name . '</td>';
|
||||
echo '<td>' . $instance->name() . '</td>';
|
||||
echo $transport->is_default ? '<td>Yes</td>' : '<td>No</td>';
|
||||
echo '<td class="col-sm-4"><i>' . nl2br($instance->displayDetails()) . '</i></td>';
|
||||
|
||||
echo "<td class='col-sm-4'>";
|
||||
|
||||
// Iterate through transport config template to display config details
|
||||
$class = 'LibreNMS\\Alert\\Transport\\' . ucfirst($transport['type']);
|
||||
if (! method_exists($class, 'configTemplate')) {
|
||||
//skip
|
||||
continue;
|
||||
}
|
||||
$tmp = call_user_func($class . '::configTemplate');
|
||||
$transport_config = json_decode($transport['config'], true);
|
||||
|
||||
foreach ($tmp['config'] as $item) {
|
||||
if ($item['type'] == 'oauth') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$val = $transport_config[$item['name']];
|
||||
if ($item['type'] == 'password') {
|
||||
$val = '<b>••••••••</b>';
|
||||
}
|
||||
// Match value to key name for select inputs
|
||||
if ($item['type'] == 'select') {
|
||||
$val = array_search($val, $item['options']);
|
||||
}
|
||||
|
||||
echo '<i>' . $item['title'] . ': ' . $val . '<br/></i>';
|
||||
}
|
||||
|
||||
echo '</td>';
|
||||
echo '<td>';
|
||||
|
||||
// Add action buttons for admin users only
|
||||
if (Auth::user()->hasGlobalAdmin()) {
|
||||
echo "<div class='btn-group btn-group-sm' role='group'>";
|
||||
echo "<button type='button' class='btn btn-primary btn-sm' data-toggle='modal' data-target='#edit-alert-transport' data-transport_id='" . $transport['id'] . "' name='edit-alert-rule' data-container='body' data-toggle='popover' data-content='Edit transport'><i class='fa fa-lg fa-pencil' aria-hidden='true'></i></button> ";
|
||||
echo "<button type='button' class='btn btn-danger btn-sm' aria-label='Delete' data-toggle='modal' data-target='#delete-alert-transport' data-transport_id='" . $transport['id'] . "' name='delete-alert-transport' data-container='body' data-toggle='popover' data-content='Delete transport'><i class='fa fa-lg fa-trash' aria-hidden='true'></i></button>";
|
||||
echo "<button type='button' class='btn btn-warning btn-sm' data-transport_id='" . $transport['id'] . "' data-transport='{$transport['type']}' name='test-transport' id='test-transport' data-toggle='popover' data-content='Test transport'><i class='fa fa-lg fa-check' aria-hidden='true'></i></button> ";
|
||||
echo "<button type='button' class='btn btn-primary btn-sm' data-toggle='modal' data-target='#edit-alert-transport' data-transport_id='" . $transport->transport_id . "' name='edit-alert-rule' data-container='body' data-toggle='popover' data-content='Edit transport'><i class='fa fa-lg fa-pencil' aria-hidden='true'></i></button> ";
|
||||
echo "<button type='button' class='btn btn-danger btn-sm' aria-label='Delete' data-toggle='modal' data-target='#delete-alert-transport' data-transport_id='" . $transport->transport_id . "' name='delete-alert-transport' data-container='body' data-toggle='popover' data-content='Delete transport'><i class='fa fa-lg fa-trash' aria-hidden='true'></i></button>";
|
||||
echo "<button type='button' class='btn btn-warning btn-sm' data-transport_id='" . $transport->transport_id . "' data-transport='{$transport->transport_type}' name='test-transport' id='test-transport' data-toggle='popover' data-content='Test transport'><i class='fa fa-lg fa-check' aria-hidden='true'></i></button> ";
|
||||
echo '</div>';
|
||||
}
|
||||
echo '</td>';
|
||||
@ -140,7 +107,7 @@ foreach (dbFetchRows($query) as $group) {
|
||||
var transport = $this.data("transport");
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: 'ajax_form.php',
|
||||
url: '<?php echo route('alert.transports.test', ['transport' => ':transport_id']) ?>'.replace(':transport_id', transport_id),
|
||||
data: { type: "test-transport", transport_id: transport_id },
|
||||
dataType: "json",
|
||||
success: function(data){
|
||||
|
@ -26,6 +26,11 @@ $alert_states = [
|
||||
|
||||
$show_recovered = false;
|
||||
|
||||
if (is_numeric($vars['alert_id']) && $vars['alert_id'] > 0) {
|
||||
$where .= ' AND `alerts`.`id` = ?';
|
||||
$param[] = $vars['alert_id'];
|
||||
}
|
||||
|
||||
if (is_numeric($vars['device_id']) && $vars['device_id'] > 0) {
|
||||
$where .= ' AND `alerts`.`device_id`=' . $vars['device_id'];
|
||||
}
|
||||
|
@ -1739,6 +1739,22 @@ pseudowires:
|
||||
- { Field: pw_descr, Type: varchar(128), 'Null': false, Extra: '' }
|
||||
Indexes:
|
||||
PRIMARY: { Name: PRIMARY, Columns: [pseudowire_id], Unique: true, Type: BTREE }
|
||||
push_subscriptions:
|
||||
Columns:
|
||||
- { Field: id, Type: 'bigint unsigned', 'Null': false, Extra: auto_increment }
|
||||
- { Field: subscribable_type, Type: varchar(255), 'Null': false, Extra: '' }
|
||||
- { Field: subscribable_id, Type: 'bigint unsigned', 'Null': false, Extra: '' }
|
||||
- { Field: endpoint, Type: varchar(500), 'Null': false, Extra: '' }
|
||||
- { Field: public_key, Type: varchar(255), 'Null': true, Extra: '' }
|
||||
- { Field: auth_token, Type: varchar(255), 'Null': true, Extra: '' }
|
||||
- { Field: content_encoding, Type: varchar(255), 'Null': true, Extra: '' }
|
||||
- { Field: description, Type: varchar(255), 'Null': true, Extra: '' }
|
||||
- { Field: created_at, Type: timestamp, 'Null': true, Extra: '' }
|
||||
- { Field: updated_at, Type: timestamp, 'Null': true, Extra: '' }
|
||||
Indexes:
|
||||
PRIMARY: { Name: PRIMARY, Columns: [id], Unique: true, Type: BTREE }
|
||||
push_subscriptions_endpoint_unique: { Name: push_subscriptions_endpoint_unique, Columns: [endpoint], Unique: true, Type: BTREE }
|
||||
push_subscriptions_subscribable_type_subscribable_id_index: { Name: push_subscriptions_subscribable_type_subscribable_id_index, Columns: [subscribable_type, subscribable_id], Unique: false, Type: BTREE }
|
||||
route:
|
||||
Columns:
|
||||
- { Field: route_id, Type: 'int unsigned', 'Null': false, Extra: auto_increment }
|
||||
|
12
resources/lang/en/components.php
Normal file
@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'notification-subscription-status' => [
|
||||
'no-support' => 'This browser does not support notifications',
|
||||
'no-transport' => 'To enable browser notifications, there must be an alert transport referencing this user',
|
||||
'enabled' => 'Notifications enabled for this browser',
|
||||
'disabled' => 'Notifications disabled for this browser',
|
||||
'enable' => 'Enable',
|
||||
'disable' => 'Disable',
|
||||
],
|
||||
];
|
@ -55,11 +55,9 @@
|
||||
var ack_until_clear = $("#ack_until_clear").bootstrapSwitch('state');
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "ajax_form.php",
|
||||
url: '{{ route('alert.ack', ['alert' => ':alert_id']) }}'.replace(':alert_id', ack_alert_id),
|
||||
dataType: "json",
|
||||
data: {
|
||||
type: "ack-alert",
|
||||
alert_id: ack_alert_id,
|
||||
state: ack_alert_state,
|
||||
ack_msg: ack_alert_note,
|
||||
ack_until_clear: ack_until_clear
|
||||
|
@ -0,0 +1,64 @@
|
||||
<div<div x-data="notificationSubscriptionStatus()">
|
||||
<div x-show="! supported">@lang('components.notification-subscription-status.no-support')</div>
|
||||
@if($userHasTransport)
|
||||
<div x-show="supported">
|
||||
<div>
|
||||
<span x-text="enabled ? '@lang('components.notification-subscription-status.enabled')' : '@lang('components.notification-subscription-status.disabled')'"></span>
|
||||
<button x-on:click="toggle()" type="button" class="tw-float-right tw-border tw-border-gray-500 tw-text-gray-500 hover:tw-bg-gray-500 hover:tw-text-gray-100 tw-rounded tw-px-4 tw-py-2" x-text="enabled ? '@lang('components.notification-subscription-status.disable')' : '@lang('components.notification-subscription-status.enable')'"></button>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div x-show="supported">
|
||||
@admin
|
||||
<a href="{{ url('alert-transports') }}">
|
||||
@lang('components.notification-subscription-status.no-transport')
|
||||
</a>
|
||||
@else
|
||||
@lang('components.notification-subscription-status.no-transport')
|
||||
@endadmin
|
||||
</div>
|
||||
@endif
|
||||
<script>
|
||||
function notificationSubscriptionStatus() {
|
||||
return {
|
||||
supported: 'Notification' in window,
|
||||
enabled: 'Notification' in window && Notification.permission === 'granted' && localStorage.getItem('notifications') !== 'disabled',
|
||||
toggle() {
|
||||
if (this.enabled) {
|
||||
localStorage.setItem('notifications', 'disabled');
|
||||
this.enabled = false;
|
||||
navigator.serviceWorker.ready.then(function(serviceWorkerRegistration) {
|
||||
serviceWorkerRegistration.pushManager.getSubscription()
|
||||
.then(function(subscription) {
|
||||
if (subscription) {
|
||||
subscription.unsubscribe().then(function(success) {
|
||||
if (success) {
|
||||
fetch('./push/unregister', {
|
||||
method: 'post',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRF-Token': '{{ csrf_token() }}'
|
||||
},
|
||||
body: JSON.stringify({
|
||||
endpoint: subscription.endpoint
|
||||
}),
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
} else if (Notification.permission === 'granted') {
|
||||
localStorage.setItem('notifications', 'enabled');
|
||||
this.enabled = true;
|
||||
} else {
|
||||
Notification.requestPermission().then((permission) => {
|
||||
localStorage.setItem('notifications', 'enabled');
|
||||
this.enabled = permission === 'granted';
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</di</div>
|
@ -75,17 +75,7 @@
|
||||
});
|
||||
var ajax_url = "{{ url('/ajax') }}";
|
||||
</script>
|
||||
<script src="{{ asset('js/librenms.js?ver=05072021') }}"></script>
|
||||
<script type="text/javascript">
|
||||
<!-- Begin
|
||||
function popUp(URL)
|
||||
{
|
||||
day = new Date();
|
||||
id = day.getTime();
|
||||
eval("page" + id + " = window.open(URL, '" + id + "', 'toolbar=0,scrollbars=1,location=0,statusbar=0,menubar=0,resizable=1,width=550,height=600');");
|
||||
}
|
||||
// End -->
|
||||
</script>
|
||||
<script src="{{ asset('js/librenms.js?ver=09072021') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/overlib_mini.js') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/toastr.min.js?ver=05072021') }}"></script>
|
||||
<script type="text/javascript" src="{{ asset('js/boot.js') }}"></script>
|
||||
@ -97,6 +87,9 @@
|
||||
document.documentElement.classList.remove('tw-dark')
|
||||
}
|
||||
</script>
|
||||
@auth
|
||||
<script src="{{ asset('js/register-service-worker.js') }}" defer></script>
|
||||
@endauth
|
||||
@yield('javascript')
|
||||
</head>
|
||||
<body>
|
||||
|
@ -748,4 +748,14 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@if($browser_push)
|
||||
if (localStorage.getItem('notifications') !== 'disabled') {
|
||||
Notification.requestPermission().then(function (permission) {
|
||||
if (permission === "denied") {
|
||||
localStorage.setItem('notifications', 'disabled');
|
||||
}
|
||||
});
|
||||
}
|
||||
@endif
|
||||
</script>
|
||||
|
@ -18,6 +18,10 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<x-panel title="{{ __('Push Notifications') }}">
|
||||
<x-notification-subscription-status></x-notification-subscription-status>
|
||||
</x-panel>
|
||||
|
||||
@if($can_change_password)
|
||||
<x-panel title="{{ __('Change Password') }}">
|
||||
<form method="POST" action="{{ route('users.update', [$user->user_id]) }}" class="form-horizontal" role="form">
|
||||
|