%PDF- %PDF-
| Direktori : /backups/router/usr/local/opnsense/mvc/app/controllers/OPNsense/Core/Api/ |
| Current File : //backups/router/usr/local/opnsense/mvc/app/controllers/OPNsense/Core/Api/DashboardController.php |
<?php
/*
* Copyright (C) 2024 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Core\Api;
use OPNsense\Base\ApiControllerBase;
use OPNsense\Core\ACL;
use OPNsense\Core\Config;
use SimpleXMLElement;
class DashboardController extends ApiControllerBase
{
private $metadataFileLocation = "/usr/local/opnsense/www/js/widgets/Metadata";
private $acl = null;
public function __construct()
{
$this->acl = new ACL();
}
private function canAccessEndpoints($endpoints)
{
foreach ($endpoints as $endpoint) {
if (!$this->acl->isPageAccessible($this->getUserName(), $endpoint)) {
return false;
}
}
return true;
}
private function getMetadata()
{
$combinedXml = new \DOMDocument('1.0');
$root = $combinedXml->createElement('metadata');
$combinedXml->appendChild($root);
foreach (glob($this->metadataFileLocation . '/*.xml') as $file) {
$metadataXml = simplexml_load_file($file);
if ($metadataXml === false) {
// not a valid xml file
continue;
}
if ($metadataXml->getName() !== "metadata") {
// wrong type
continue;
}
$node = dom_import_simplexml($metadataXml);
$node = $root->ownerDocument->importNode($node, true);
$root->appendChild($node);
}
return simplexml_import_dom($combinedXml);
}
private function getDefaultDashboard()
{
return [
'options' => [],
'widgets' => [
['id' => 'systeminformation', 'x' => 0, 'y' => 0, 'w' => 2],
['id' => 'memory', 'x' => 2, 'y' => 0],
['id' => 'disk', 'x' => 3, 'y' => 0],
['id' => 'interfacestatistics', 'x' => 4, 'y' => 0, 'w' => 4],
['id' => 'firewall', 'x' => 8, 'y' => 0, 'w' => 4],
['id' => 'gateways', 'x' => 2, 'y' => 1, 'w' => 2],
['id' => 'services', 'x' => 4, 'y' => 1, 'w' => '4'],
['id' => 'traffic', 'x' => 8, 'y' => 1, 'w' => 4],
['id' => 'cpu', 'x' => 0, 'y' => 1, 'w' => 2],
['id' => 'announcements', 'x' => 2, 'y' => 2, 'w' => 2],
]
];
}
public function getDashboardAction()
{
$result = [];
$dashboard = null;
$config = Config::getInstance()->object();
foreach ($config->system->user as $node) {
if ($this->getUserName() === (string)$node->name) {
// json_decode returns null if json is invalid
$dashboard = json_decode(base64_decode((string)$node->dashboard), true);
break;
}
}
if (empty($dashboard)) {
$dashboard = $this->getDefaultDashboard();
}
$result['modules'] = [];
$metadata = $this->getMetadata();
foreach ($metadata as $md) {
foreach ($md as $widgetId => $metadataAttributes) {
$widgetId = (string)$widgetId;
$fname = (string)$metadataAttributes->filename;
$link = (string)$metadataAttributes->link;
$endpoints = (array)($metadataAttributes->endpoints->endpoint ?? []);
$translations = (array)($metadataAttributes->translations ?? []);
if (!empty($link) && !$this->canAccessEndpoints([$link])) {
$link = '';
}
if (!$this->canAccessEndpoints($endpoints)) {
continue;
}
if (!file_exists('/usr/local/opnsense/www/js/widgets/' . $fname)) {
continue;
}
foreach ($translations as $key => $value) {
$translations[$key] = gettext($value);
}
$result['modules'][] = [
'id' => $widgetId,
'module' => $fname,
'link' => $link,
'translations' => $translations
];
}
}
// filter widgets according to metadata
$moduleIds = array_column($result['modules'], 'id');
$filteredWidgets = array_filter($dashboard['widgets'], function ($widget) use ($moduleIds) {
return in_array($widget['id'], $moduleIds);
});
$dashboard['widgets'] = array_values($filteredWidgets);
$result['dashboard'] = $dashboard;
return $result;
}
public function saveWidgetsAction()
{
$result = ['result' => 'failed'];
if ($this->request->isPost() && $this->request->hasPost('widgets')) {
$dashboard = json_encode($this->request->getPost());
if (strlen($dashboard) > (1024 * 1024)) {
// prevent saving large blobs of data
$result['message'] = 'dashboard size limit reached';
return $result;
}
$encoded = base64_encode($dashboard);
$config = Config::getInstance()->object();
$name = $this->getUserName();
foreach ($config->system->user as $node) {
if ($name === (string)$node->name) {
$node->dashboard = $encoded;
Config::getInstance()->save();
$result = ['result' => 'saved'];
break;
}
}
}
return $result;
}
public function restoreDefaultsAction()
{
$result = ['result' => 'failed'];
if ($this->request->isPost()) {
$config = Config::getInstance()->object();
$name = $this->getUserName();
foreach ($config->system->user as $node) {
if ($name === (string)$node->name) {
$node->dashboard = null;
Config::getInstance()->save();
$result = ['result' => 'saved'];
break;
}
}
}
return $result;
}
public function productInfoFeedAction()
{
$result = ['items' => []];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://forum.opnsense.org/index.php?board=11.0&action=.xml;limit=5;type=rss2');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec($ch);
curl_close($ch);
$payload = @simplexml_load_string($output);
if (empty($payload)) {
return $result;
}
foreach ($payload->channel->children() as $key => $node) {
if ($key == 'item') {
$result['items'][] = [
'title' => (string)$node->title,
'description' => (string)$node->description,
'link' => (string)$node->link,
'pubDate' => (string)$node->pubDate,
'guid' => (string)$node->guid
];
}
}
return $result;
}
public function pictureAction()
{
$result = ['result' => 'failed'];
$config = Config::getInstance()->object();
if (!empty($config->system->picture) && !empty($config->system->picture_filename)) {
$ext = pathinfo((string)$config->system->picture_filename, PATHINFO_EXTENSION);
if (empty($ext)) {
return $result;
}
return [
'result' => 'ok',
'mime' => 'image/' . $ext,
'picture' => (string)$config->system->picture,
];
}
return $result;
}
}