mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-04-08 17:15:08 +02:00
Compare commits
No commits in common. "main" and "v2.12.2" have entirely different histories.
4
.github/workflows/php.yml
vendored
4
.github/workflows/php.yml
vendored
@ -100,9 +100,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup dependencies
|
- name: Setup dependencies
|
||||||
run: |
|
run: |
|
||||||
composer init -n --require mockery/mockery:* --require ipl/i18n:@dev --require ipl/web:@dev
|
composer require -n --no-progress mockery/mockery ipl/i18n:@dev ipl/web:@dev
|
||||||
composer config platform.php 7.2.9
|
|
||||||
composer install -n --no-progress
|
|
||||||
git clone --depth 1 --branch snapshot/nightly https://github.com/Icinga/icinga-php-thirdparty.git vendor/icinga-php-thirdparty
|
git clone --depth 1 --branch snapshot/nightly https://github.com/Icinga/icinga-php-thirdparty.git vendor/icinga-php-thirdparty
|
||||||
|
|
||||||
- name: PHPUnit
|
- name: PHPUnit
|
||||||
|
41
CHANGELOG.md
41
CHANGELOG.md
@ -4,47 +4,6 @@ Please make sure to always read our [Upgrading](doc/80-Upgrading.md) documentati
|
|||||||
|
|
||||||
## What's New
|
## What's New
|
||||||
|
|
||||||
### What's New in Version 2.12.4
|
|
||||||
|
|
||||||
This is a hotfix release which fixes the following issue:
|
|
||||||
|
|
||||||
Database login broken after upgrade [#5343](https://github.com/Icinga/icingaweb2/issues/5343)
|
|
||||||
|
|
||||||
### What's New in Version 2.12.3
|
|
||||||
|
|
||||||
**Notice:** This is a security release. It is recommended to upgrade _immediately_.
|
|
||||||
|
|
||||||
You can find all issues related to this release on our Roadmap.
|
|
||||||
|
|
||||||
#### Vulnerabilities, Closed
|
|
||||||
|
|
||||||
Cross site scripting is one of the worst attacks on web based platforms. Especially, if carrying it out is as easy as
|
|
||||||
the first two mentioned here. You might recognize the open redirect on the login. You are correct, we attempted to fix
|
|
||||||
it already with v2.11.3 but underestimated PHP's quirks. The last is difficult to exploit, hence the lowest severity
|
|
||||||
of all, but don't be fooled by that!
|
|
||||||
|
|
||||||
All four of them are backported to v2.11.5.
|
|
||||||
|
|
||||||
* XSS in embedded content [CVE-2025-27405](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-3x37-fjc3-ch8w)
|
|
||||||
* DOM-based XSS [CVE-2025-27404](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-c6pg-h955-wf66)
|
|
||||||
* Open redirect on login page [CVE-2025-30164](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-8r73-6686-wv8q)
|
|
||||||
* Reflected XSS [CVE-2025-27609](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-5cjw-fwjc-8j38)
|
|
||||||
|
|
||||||
Big thanks to all finders / reporters! :+1:
|
|
||||||
|
|
||||||
#### Bugs, Exterminated
|
|
||||||
|
|
||||||
Did you know, that we started [Icinga Notifications](https://icinga.com/docs/icinga-notifications/latest/) with support
|
|
||||||
for PostgreSQL first? Reason for that is, we wanted to make sure we are fully compatible with it right away. To ensure
|
|
||||||
things like logging in with a PostgreSQL authentication/group backend is case-insensitive, like it was always the case
|
|
||||||
for MySQL. Now it **really** is case-insensitive! There are also two issues fixed, which many of you will probably have
|
|
||||||
noticed since v2.12.2, sorry that it took so long :)
|
|
||||||
|
|
||||||
* Login against Postgres DB is case-sensitive [#5223](https://github.com/Icinga/icingaweb2/issues/5223)
|
|
||||||
* Role list has no functioning quick search [#5300](https://github.com/Icinga/icingaweb2/issues/5300)
|
|
||||||
* After clicking on Check now, the page does not refresh itself [#5293](https://github.com/Icinga/icingaweb2/issues/5293)
|
|
||||||
* Service States display wrong since update to 2.12.2 [#5290](https://github.com/Icinga/icingaweb2/issues/5290)
|
|
||||||
|
|
||||||
### What's New in Version 2.12.2
|
### What's New in Version 2.12.2
|
||||||
|
|
||||||
You can find all issues related to this release on our Roadmap.
|
You can find all issues related to this release on our Roadmap.
|
||||||
|
@ -3,108 +3,18 @@
|
|||||||
|
|
||||||
namespace Icinga\Controllers;
|
namespace Icinga\Controllers;
|
||||||
|
|
||||||
use Icinga\Web\Session;
|
use Icinga\Web\Controller;
|
||||||
use ipl\Html\BaseHtmlElement;
|
|
||||||
use ipl\Html\Html;
|
|
||||||
use ipl\Html\HtmlString;
|
|
||||||
use ipl\Html\Text;
|
|
||||||
use ipl\Web\Compat\CompatController;
|
|
||||||
use ipl\Web\Url;
|
|
||||||
use ipl\Web\Widget\Icon;
|
|
||||||
use ipl\Web\Widget\Tabs;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display external or internal links within an iframe
|
* Display external or internal links within an iframe
|
||||||
*/
|
*/
|
||||||
class IframeController extends CompatController
|
class IframeController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Display iframe w/ the given URL
|
* Display iframe w/ the given URL
|
||||||
*/
|
*/
|
||||||
public function indexAction(): void
|
public function indexAction()
|
||||||
{
|
{
|
||||||
$url = Url::fromPath($this->params->getRequired('url'));
|
$this->view->url = $this->params->getRequired('url');
|
||||||
$urlHash = $this->getRequest()->getHeader('X-Icinga-URLHash');
|
|
||||||
$expectedHash = hash('sha256', $url->getAbsoluteUrl() . Session::getSession()->getId());
|
|
||||||
$iframeUrl = Url::fromPath('iframe', ['url' => $url->getAbsoluteUrl()]);
|
|
||||||
|
|
||||||
if (! in_array($url->getScheme(), ['http', 'https'], true)) {
|
|
||||||
$this->httpBadRequest('Invalid URL scheme');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->injectTabs();
|
|
||||||
|
|
||||||
$this->getTabs()->setRefreshUrl($iframeUrl);
|
|
||||||
|
|
||||||
if ($urlHash) {
|
|
||||||
if ($urlHash !== $expectedHash) {
|
|
||||||
$this->httpBadRequest('Invalid URL hash');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->addContent(Html::tag('div', ['class' => 'iframe-warning'], [
|
|
||||||
Html::tag('h2', $this->translate('Attention!')),
|
|
||||||
Html::tag('p', ['class' => 'note'], $this->translate(
|
|
||||||
'You are about to open untrusted content embedded in Icinga Web! Only proceed,'
|
|
||||||
.' by clicking the link below, if you recognize and trust the source!'
|
|
||||||
)),
|
|
||||||
Html::tag('a', ['data-url-hash' => $expectedHash, 'href' => Html::escape($iframeUrl)], $url),
|
|
||||||
Html::tag('p', ['class' => 'reason'], [
|
|
||||||
new Icon('circle-info'),
|
|
||||||
Text::create($this->translate(
|
|
||||||
'You see this warning because you do not seem to have followed a link in Icinga Web.'
|
|
||||||
. ' You can bypass this in the future by configuring a navigation item instead.'
|
|
||||||
))
|
|
||||||
])
|
|
||||||
]));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getTabs()->setHash($expectedHash);
|
|
||||||
|
|
||||||
$this->addContent(Html::tag(
|
|
||||||
'div',
|
|
||||||
['class' => 'iframe-container'],
|
|
||||||
Html::tag('iframe', [
|
|
||||||
'src' => $url,
|
|
||||||
'sandbox' => 'allow-same-origin allow-scripts allow-popups allow-forms',
|
|
||||||
])
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function injectTabs(): void
|
|
||||||
{
|
|
||||||
$this->tabs = new class extends Tabs {
|
|
||||||
private $hash;
|
|
||||||
|
|
||||||
public function setHash($hash)
|
|
||||||
{
|
|
||||||
$this->hash = $hash;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function assemble()
|
|
||||||
{
|
|
||||||
$tabHtml = substr($this->tabs->render(), 34, -5);
|
|
||||||
if ($this->refreshUrl !== null) {
|
|
||||||
$tabHtml = preg_replace(
|
|
||||||
[
|
|
||||||
'/(?<=class="refresh-container-control spinner" href=")([^"]*)/',
|
|
||||||
'/(\s)(?=href)/'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
$this->refreshUrl->getAbsoluteUrl(),
|
|
||||||
' data-url-hash="' . $this->hash . '" '
|
|
||||||
],
|
|
||||||
$tabHtml
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseHtmlElement::add(HtmlString::create($tabHtml));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->controls->setTabs($this->tabs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,6 +184,15 @@ use ipl\Web\Widget\StateBadge;
|
|||||||
</div>
|
</div>
|
||||||
<div class="about-social">
|
<div class="about-social">
|
||||||
<?= $this->qlink(
|
<?= $this->qlink(
|
||||||
|
null,
|
||||||
|
'https://www.twitter.com/icinga',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'twitter',
|
||||||
|
'title' => $this->translate('Icinga on Twitter')
|
||||||
|
)
|
||||||
|
) ?> <?= $this->qlink(
|
||||||
null,
|
null,
|
||||||
'https://www.facebook.com/icinga',
|
'https://www.facebook.com/icinga',
|
||||||
null,
|
null,
|
||||||
|
@ -28,6 +28,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul id="social">
|
<ul id="social">
|
||||||
|
<li>
|
||||||
|
<?= $this->qlink(
|
||||||
|
null,
|
||||||
|
'https://twitter.com/icinga',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'twitter',
|
||||||
|
'title' => $this->translate('Icinga on Twitter')
|
||||||
|
)
|
||||||
|
) ?>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<?= $this->qlink(
|
<?= $this->qlink(
|
||||||
null,
|
null,
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<?= $this->tabs->render($this); ?>
|
<?= $this->tabs->render($this); ?>
|
||||||
<br/>
|
<br/>
|
||||||
<div>
|
<div>
|
||||||
<h1>Could not <?= $action; ?> module "<?= $this->escape($moduleName); ?>"</h1>
|
<h1>Could not <?= $action; ?> module "<?= $moduleName; ?>"</h1>
|
||||||
<p>
|
<p>
|
||||||
While operation the following error occurred:
|
While operation the following error occurred:
|
||||||
<br />
|
<br />
|
||||||
|
@ -23,7 +23,7 @@ $modReason = [];
|
|||||||
|
|
||||||
if (isset($requiredVendor, $requiredProject) && $requiredVendor && $requiredProject) {
|
if (isset($requiredVendor, $requiredProject) && $requiredVendor && $requiredProject) {
|
||||||
// TODO: I don't like this, can we define requirements somewhere else?
|
// TODO: I don't like this, can we define requirements somewhere else?
|
||||||
$coreDeps = ['icinga-php-library' => '>= 0.14.2', 'icinga-php-thirdparty' => '>= 0.12'];
|
$coreDeps = ['icinga-php-library' => '>= 0.13.2', 'icinga-php-thirdparty' => '>= 0.12'];
|
||||||
|
|
||||||
foreach ($coreDeps as $libraryName => $requiredVersion) {
|
foreach ($coreDeps as $libraryName => $requiredVersion) {
|
||||||
if (! $libraries->has($libraryName)) {
|
if (! $libraries->has($libraryName)) {
|
||||||
|
8
application/views/scripts/iframe/index.phtml
Normal file
8
application/views/scripts/iframe/index.phtml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php if (! $compact): ?>
|
||||||
|
<div class="controls">
|
||||||
|
<?= $tabs ?>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
|
<div class="iframe-container">
|
||||||
|
<iframe src="<?= $this->escape($url) ?>" frameborder="no"></iframe>
|
||||||
|
</div>
|
@ -399,7 +399,7 @@ You will need to install certain dependencies depending on your setup:
|
|||||||
monitor your infrastructure
|
monitor your infrastructure
|
||||||
* A web server, e.g. Apache or Nginx
|
* A web server, e.g. Apache or Nginx
|
||||||
* PHP version ≥ 7.2
|
* PHP version ≥ 7.2
|
||||||
* [Icinga PHP Library (ipl)](https://github.com/Icinga/icinga-php-library) (≥ 0.14.2)
|
* [Icinga PHP Library (ipl)](https://github.com/Icinga/icinga-php-library) (≥ 0.13.2)
|
||||||
* [Icinga PHP Thirdparty](https://github.com/Icinga/icinga-php-thirdparty) (≥ 0.12)
|
* [Icinga PHP Thirdparty](https://github.com/Icinga/icinga-php-thirdparty) (≥ 0.12)
|
||||||
* The following PHP modules must be installed: cURL, json, gettext, fileinfo, intl, dom, OpenSSL and xml
|
* The following PHP modules must be installed: cURL, json, gettext, fileinfo, intl, dom, OpenSSL and xml
|
||||||
* The [pdfexport](https://github.com/Icinga/icingaweb2-module-pdfexport) module (≥0.10) is required for the
|
* The [pdfexport](https://github.com/Icinga/icingaweb2-module-pdfexport) module (≥0.10) is required for the
|
||||||
|
@ -58,8 +58,8 @@ Disabled by default.
|
|||||||
If you experience any problems while running SELinux in enforcing mode try to reproduce it in permissive mode. If the
|
If you experience any problems while running SELinux in enforcing mode try to reproduce it in permissive mode. If the
|
||||||
problem persists, it is not related to SELinux because in permissive mode SELinux will not deny anything.
|
problem persists, it is not related to SELinux because in permissive mode SELinux will not deny anything.
|
||||||
|
|
||||||
When filing a bug report please add the following information additionally to the common ones:
|
When filing a bug report please add the following information additionally to the
|
||||||
|
[common ones](https://icinga.com/icinga/faq/):
|
||||||
* Output of `semodule -l | grep -e icinga2 -e icingaweb2 -e nagios -e apache`
|
* Output of `semodule -l | grep -e icinga2 -e icingaweb2 -e nagios -e apache`
|
||||||
* Output of `semanage boolean -l | grep icinga`
|
* Output of `semanage boolean -l | grep icinga`
|
||||||
* Output of `ps -eZ | grep httpd`
|
* Output of `ps -eZ | grep httpd`
|
||||||
|
@ -8,7 +8,7 @@ namespace Icinga\Application;
|
|||||||
*/
|
*/
|
||||||
class Version
|
class Version
|
||||||
{
|
{
|
||||||
const VERSION = '2.12.4';
|
const VERSION = '2.12.2';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the version of this instance of Icinga Web 2
|
* Get the version of this instance of Icinga Web 2
|
||||||
|
@ -42,9 +42,4 @@ class RolesConfig extends IniRepository
|
|||||||
|
|
||||||
return $columns;
|
return $columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function initializeSearchColumns(): array
|
|
||||||
{
|
|
||||||
return ['name'];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,6 @@ use Icinga\Exception\AuthenticationException;
|
|||||||
use Icinga\Repository\DbRepository;
|
use Icinga\Repository\DbRepository;
|
||||||
use Icinga\User;
|
use Icinga\User;
|
||||||
use PDO;
|
use PDO;
|
||||||
use Zend_Db_Expr;
|
|
||||||
|
|
||||||
class DbUserBackend extends DbRepository implements UserBackendInterface, Inspectable
|
class DbUserBackend extends DbRepository implements UserBackendInterface, Inspectable
|
||||||
{
|
{
|
||||||
@ -180,28 +179,23 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
|
|||||||
{
|
{
|
||||||
if ($this->ds->getDbType() === 'pgsql') {
|
if ($this->ds->getDbType() === 'pgsql') {
|
||||||
// Since PostgreSQL version 9.0 the default value for bytea_output is 'hex' instead of 'escape'
|
// Since PostgreSQL version 9.0 the default value for bytea_output is 'hex' instead of 'escape'
|
||||||
$columns = ['password_hash' => new Zend_Db_Expr('ENCODE(password_hash, \'escape\')')];
|
$columns = array('password_hash' => 'ENCODE(password_hash, \'escape\')');
|
||||||
} else {
|
} else {
|
||||||
// password_hash is intentionally not a valid query column,
|
$columns = array('password_hash');
|
||||||
// by wrapping it in an expression it is not validated
|
|
||||||
$columns = ['password_hash' => new Zend_Db_Expr('password_hash')];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = $this
|
$nameColumn = 'name';
|
||||||
->select()
|
|
||||||
->from('user', $columns)
|
|
||||||
->where('active', true);
|
|
||||||
|
|
||||||
if ($this->ds->getDbType() === 'mysql') {
|
if ($this->ds->getDbType() === 'mysql') {
|
||||||
$username = strtolower($username);
|
$username = strtolower($username);
|
||||||
$nameColumn = new Zend_Db_Expr('BINARY LOWER(name)');
|
$nameColumn = 'BINARY LOWER(name)';
|
||||||
|
|
||||||
$query->getQuery()->where($nameColumn, $username);
|
|
||||||
} else { // pgsql
|
|
||||||
$query->where('user', $username);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$statement = $this->ds->getDbAdapter()->prepare($query->getQuery()->getSelectQuery());
|
$query = $this->ds->select()
|
||||||
|
->from($this->prependTablePrefix('user'), $columns)
|
||||||
|
->where($nameColumn, $username)
|
||||||
|
->where('active', true);
|
||||||
|
|
||||||
|
$statement = $this->ds->getDbAdapter()->prepare($query->getSelectQuery());
|
||||||
$statement->execute();
|
$statement->execute();
|
||||||
$statement->bindColumn(1, $lob, PDO::PARAM_LOB);
|
$statement->bindColumn(1, $lob, PDO::PARAM_LOB);
|
||||||
$statement->fetch(PDO::FETCH_BOUND);
|
$statement->fetch(PDO::FETCH_BOUND);
|
||||||
|
@ -204,7 +204,7 @@ class DbUserGroupBackend extends DbRepository implements Inspectable, UserGroupB
|
|||||||
$membershipQuery = $this
|
$membershipQuery = $this
|
||||||
->select()
|
->select()
|
||||||
->from('group_membership', array('group_name'))
|
->from('group_membership', array('group_name'))
|
||||||
->where('user', $user->getUsername());
|
->where('user_name', $user->getUsername());
|
||||||
|
|
||||||
$memberships = array();
|
$memberships = array();
|
||||||
foreach ($membershipQuery as $membership) {
|
foreach ($membershipQuery as $membership) {
|
||||||
|
@ -37,7 +37,7 @@ class Csv
|
|||||||
}
|
}
|
||||||
$out = array();
|
$out = array();
|
||||||
foreach ($row as & $val) {
|
foreach ($row as & $val) {
|
||||||
$out[] = '"' . ($val == '0' ? '0' : ($val ? str_replace('"', '""', $val) : '')) . '"';
|
$out[] = '"' . ($val ? str_replace('"', '""', $val) : '') . '"';
|
||||||
}
|
}
|
||||||
$csv .= implode(',', $out) . "\r\n";
|
$csv .= implode(',', $out) . "\r\n";
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,9 @@ namespace Icinga\File;
|
|||||||
|
|
||||||
use Dompdf\Dompdf;
|
use Dompdf\Dompdf;
|
||||||
use Dompdf\Options;
|
use Dompdf\Options;
|
||||||
use Exception;
|
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Util\Environment;
|
use Icinga\Util\Environment;
|
||||||
use Icinga\Web\FileCache;
|
|
||||||
use Icinga\Web\Hook;
|
use Icinga\Web\Hook;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
@ -66,17 +64,8 @@ class Pdf
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmpDir = FileCache::instance()->directory('legacy_pdf');
|
|
||||||
if ($tmpDir === false) {
|
|
||||||
throw new Exception('Could not create temporary directory for PDF rendering');
|
|
||||||
}
|
|
||||||
|
|
||||||
$options = new Options();
|
$options = new Options();
|
||||||
$options->set('defaultPaperSize', 'A4');
|
$options->set('defaultPaperSize', 'A4');
|
||||||
$options->set('fontDir', $tmpDir);
|
|
||||||
$options->set('fontCache', $tmpDir);
|
|
||||||
$options->set('tempDir', $tmpDir);
|
|
||||||
$options->set('chroot', $tmpDir);
|
|
||||||
$dompdf = new Dompdf($options);
|
$dompdf = new Dompdf($options);
|
||||||
$dompdf->loadHtml($html);
|
$dompdf->loadHtml($html);
|
||||||
$dompdf->render();
|
$dompdf->render();
|
||||||
|
@ -7,7 +7,6 @@ use Icinga\Application\Icinga;
|
|||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Util\StringHelper;
|
use Icinga\Util\StringHelper;
|
||||||
use Icinga\Web\Navigation\NavigationItem;
|
use Icinga\Web\Navigation\NavigationItem;
|
||||||
use Icinga\Web\Session;
|
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\View;
|
use Icinga\Web\View;
|
||||||
|
|
||||||
@ -191,10 +190,6 @@ class NavigationItemRenderer
|
|||||||
|
|
||||||
$target = $item->getTarget();
|
$target = $item->getTarget();
|
||||||
if ($url->isExternal() && (!$target || in_array($target, $this->internalLinkTargets, true))) {
|
if ($url->isExternal() && (!$target || in_array($target, $this->internalLinkTargets, true))) {
|
||||||
$item->setAttribute('data-url-hash', hash(
|
|
||||||
'sha256',
|
|
||||||
$url->getAbsoluteUrl() . Session::getSession()->getId()
|
|
||||||
));
|
|
||||||
$url = Url::fromPath('iframe', array('url' => $url));
|
$url = Url::fromPath('iframe', array('url' => $url));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,9 +179,10 @@ class Url
|
|||||||
}
|
}
|
||||||
|
|
||||||
$urlParts = parse_url($url);
|
$urlParts = parse_url($url);
|
||||||
if ((isset($urlParts['scheme']) && $urlParts['scheme'] !== $request->getScheme())
|
if (isset($urlParts['scheme']) && (
|
||||||
|
$urlParts['scheme'] !== $request->getScheme()
|
||||||
|| (isset($urlParts['host']) && $urlParts['host'] !== $request->getServer('SERVER_NAME'))
|
|| (isset($urlParts['host']) && $urlParts['host'] !== $request->getServer('SERVER_NAME'))
|
||||||
|| (isset($urlParts['port']) && $urlParts['port'] != $request->getServer('SERVER_PORT'))
|
|| (isset($urlParts['port']) && $urlParts['port'] != $request->getServer('SERVER_PORT')))
|
||||||
) {
|
) {
|
||||||
$urlObject->setIsExternal();
|
$urlObject->setIsExternal();
|
||||||
}
|
}
|
||||||
|
@ -205,8 +205,7 @@ class View extends Zend_View_Abstract
|
|||||||
'th-thumb-empty' => true,
|
'th-thumb-empty' => true,
|
||||||
'github-circled' => true,
|
'github-circled' => true,
|
||||||
'history' => true,
|
'history' => true,
|
||||||
'binoculars' => true,
|
'binoculars' => true
|
||||||
'letter' => true
|
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
namespace Icinga\Web\Widget\Dashboard;
|
namespace Icinga\Web\Widget\Dashboard;
|
||||||
|
|
||||||
use Icinga\Web\Session;
|
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Data\ConfigObject;
|
use Icinga\Data\ConfigObject;
|
||||||
|
use Icinga\Exception\IcingaException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dashboard pane dashlet
|
* A dashboard pane dashlet
|
||||||
@ -57,15 +57,18 @@ class Dashlet extends UserWidget
|
|||||||
*/
|
*/
|
||||||
private $template =<<<'EOD'
|
private $template =<<<'EOD'
|
||||||
|
|
||||||
<div class="container" data-icinga-url="{URL}" data-url-hash="{URL_HASH}">
|
<div class="container" data-icinga-url="{URL}">
|
||||||
<h1><a
|
<h1><a href="{FULL_URL}" aria-label="{TOOLTIP}" title="{TOOLTIP}" data-base-target="col1">{TITLE}</a></h1>
|
||||||
href="{FULL_URL}"
|
|
||||||
aria-label="{TOOLTIP}"
|
|
||||||
title="{TOOLTIP}"
|
|
||||||
data-url-hash="{FULL_URL_HASH}"
|
|
||||||
data-base-target="col1"
|
|
||||||
>{TITLE}</a></h1>
|
|
||||||
<p class="progress-label">{PROGRESS_LABEL}<span>.</span><span>.</span><span>.</span></p>
|
<p class="progress-label">{PROGRESS_LABEL}<span>.</span><span>.</span><span>.</span></p>
|
||||||
|
<noscript>
|
||||||
|
<div class="iframe-container">
|
||||||
|
<iframe
|
||||||
|
src="{IFRAME_URL}"
|
||||||
|
frameborder="no"
|
||||||
|
title="{TITLE_PREFIX}{TITLE}">
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
</noscript>
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
|
|
||||||
@ -247,22 +250,13 @@ EOD;
|
|||||||
|
|
||||||
$url = $this->getUrl();
|
$url = $this->getUrl();
|
||||||
$url->setParam('showCompact', true);
|
$url->setParam('showCompact', true);
|
||||||
$fullUrl = $url->getUrlWithout(['showCompact', 'limit', 'view']);
|
$iframeUrl = clone $url;
|
||||||
|
$iframeUrl->setParam('isIframe');
|
||||||
$urlHash = '';
|
|
||||||
$fullUrlHash = '';
|
|
||||||
if ($url->getPath() === 'iframe') {
|
|
||||||
$urlHash = hash('sha256', Url::fromPath($url->getParam('url'))->getAbsoluteUrl()
|
|
||||||
. Session::getSession()->getId());
|
|
||||||
$fullUrlHash = hash('sha256', Url::fromPath($fullUrl->getParam('url'))->getAbsoluteUrl()
|
|
||||||
. Session::getSession()->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
$searchTokens = array(
|
$searchTokens = array(
|
||||||
'{URL}',
|
'{URL}',
|
||||||
'{URL_HASH}',
|
'{IFRAME_URL}',
|
||||||
'{FULL_URL}',
|
'{FULL_URL}',
|
||||||
'{FULL_URL_HASH}',
|
|
||||||
'{TOOLTIP}',
|
'{TOOLTIP}',
|
||||||
'{TITLE}',
|
'{TITLE}',
|
||||||
'{TITLE_PREFIX}',
|
'{TITLE_PREFIX}',
|
||||||
@ -271,9 +265,8 @@ EOD;
|
|||||||
|
|
||||||
$replaceTokens = array(
|
$replaceTokens = array(
|
||||||
$url,
|
$url,
|
||||||
$urlHash,
|
$iframeUrl,
|
||||||
$fullUrl,
|
$url->getUrlWithout(['showCompact', 'limit', 'view']),
|
||||||
$fullUrlHash,
|
|
||||||
sprintf($view->translate('Show %s', 'dashboard.dashlet.tooltip'), $view->escape($this->getTitle())),
|
sprintf($view->translate('Show %s', 'dashboard.dashlet.tooltip'), $view->escape($this->getTitle())),
|
||||||
$view->escape($this->getTitle()),
|
$view->escape($this->getTitle()),
|
||||||
$view->translate('Dashlet') . ': ',
|
$view->translate('Dashlet') . ': ',
|
||||||
|
@ -112,7 +112,7 @@ class Window
|
|||||||
{
|
{
|
||||||
if (! isset(static::$window)) {
|
if (! isset(static::$window)) {
|
||||||
$id = Icinga::app()->getRequest()->getHeader('X-Icinga-WindowId');
|
$id = Icinga::app()->getRequest()->getHeader('X-Icinga-WindowId');
|
||||||
if (empty($id) || $id === static::UNDEFINED || ! preg_match('/^\w+$/', $id)) {
|
if (empty($id) || $id === static::UNDEFINED) {
|
||||||
Icinga::app()->getResponse()->setOverrideWindowId();
|
Icinga::app()->getResponse()->setOverrideWindowId();
|
||||||
$id = static::generateId();
|
$id = static::generateId();
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Module: doc
|
Module: doc
|
||||||
Version: 2.12.4
|
Version: 2.12.2
|
||||||
Description: Documentation module
|
Description: Documentation module
|
||||||
Extracts, shows and exports documentation for Icinga Web 2 and its modules.
|
Extracts, shows and exports documentation for Icinga Web 2 and its modules.
|
||||||
|
@ -1,5 +1,17 @@
|
|||||||
/*! Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
/*! Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
// Mixins
|
||||||
|
|
||||||
|
.gradient(@a: @gray-lighter; @b: @gray-lightest) {
|
||||||
|
background: @a;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(@a), to(@b));
|
||||||
|
background: -webkit-linear-gradient(top, @a, @b);
|
||||||
|
background: -moz-linear-gradient(top, @a, @b);
|
||||||
|
background: -ms-linear-gradient(top, @a, @b);
|
||||||
|
background: -o-linear-gradient(top, @a, @b);
|
||||||
|
background: linear-gradient(to bottom, @a, @b);
|
||||||
|
}
|
||||||
|
|
||||||
// General styles
|
// General styles
|
||||||
|
|
||||||
code {
|
code {
|
||||||
@ -72,7 +84,7 @@ table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tbody > tr:nth-child(odd) {
|
tbody > tr:nth-child(odd) {
|
||||||
background: @gray-light;
|
.gradient()
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody > tr:nth-child(even) {
|
tbody > tr:nth-child(even) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Module: migrate
|
Module: migrate
|
||||||
Version: 2.12.4
|
Version: 2.12.2
|
||||||
Description: Migrate module
|
Description: Migrate module
|
||||||
This module was introduced with the domain-aware authentication feature in version 2.5.0.
|
This module was introduced with the domain-aware authentication feature in version 2.5.0.
|
||||||
It helps you migrating users and user configurations according to a given domain.
|
It helps you migrating users and user configurations according to a given domain.
|
||||||
|
@ -227,7 +227,7 @@ class BackendConfigForm extends ConfigForm
|
|||||||
'autosubmit' => true
|
'autosubmit' => true
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$resourceName = $this->getView()->escape($formData['resource'] ?? $this->getValue('resource'));
|
$resourceName = isset($formData['resource']) ? $formData['resource'] : $this->getValue('resource');
|
||||||
$this->addElement(
|
$this->addElement(
|
||||||
'note',
|
'note',
|
||||||
'resource_note',
|
'resource_note',
|
||||||
|
@ -284,10 +284,10 @@ $section->add(N_('Timeline'), array(
|
|||||||
/*
|
/*
|
||||||
* Reporting Section
|
* Reporting Section
|
||||||
*/
|
*/
|
||||||
$section = $this->menuSection(N_('Reporting'), [
|
$section = $this->menuSection(N_('Reporting'), array(
|
||||||
'icon' => 'fa-chart-simple',
|
'icon' => 'barchart',
|
||||||
'priority' => 100
|
'priority' => 100
|
||||||
]);
|
));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Current Incidents
|
* Current Incidents
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Module: monitoring
|
Module: monitoring
|
||||||
Version: 2.12.4
|
Version: 2.12.2
|
||||||
Description: Icinga monitoring module
|
Description: Icinga monitoring module
|
||||||
IDO accessor and UI for your monitoring. This is the initial instalment for a
|
IDO accessor and UI for your monitoring. This is the initial instalment for a
|
||||||
graphical presentation of Icinga environments. The predecessor of Icinga DB.
|
graphical presentation of Icinga environments. The predecessor of Icinga DB.
|
||||||
|
@ -602,7 +602,7 @@ class WebWizard extends Wizard implements SetupWizard
|
|||||||
)));
|
)));
|
||||||
|
|
||||||
$set->add(new WebLibraryRequirement(array(
|
$set->add(new WebLibraryRequirement(array(
|
||||||
'condition' => ['icinga-php-library', '>=', '0.14.2'],
|
'condition' => ['icinga-php-library', '>=', '0.13.2'],
|
||||||
'alias' => 'Icinga PHP library',
|
'alias' => 'Icinga PHP library',
|
||||||
'description' => mt(
|
'description' => mt(
|
||||||
'setup',
|
'setup',
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Module: setup
|
Module: setup
|
||||||
Version: 2.12.4
|
Version: 2.12.2
|
||||||
Description: Setup module
|
Description: Setup module
|
||||||
Web based wizard for setting up Icinga Web 2 and its modules.
|
Web based wizard for setting up Icinga Web 2 and its modules.
|
||||||
This includes the data backends (e.g. relational database, LDAP),
|
This includes the data backends (e.g. relational database, LDAP),
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Module: test
|
Module: test
|
||||||
Version: 2.12.4
|
Version: 2.12.2
|
||||||
Description: Translation module
|
Description: Translation module
|
||||||
This module allows developers to run (unit) tests against Icinga Web 2 and
|
This module allows developers to run (unit) tests against Icinga Web 2 and
|
||||||
any of its modules. Usually you do not need to enable this.
|
any of its modules. Usually you do not need to enable this.
|
||||||
|
@ -130,7 +130,7 @@ below.
|
|||||||

|

|
||||||
|
|
||||||
And when you want to test your changes, please read more about under the chapter
|
And when you want to test your changes, please read more about under the chapter
|
||||||
[Testing Translations](03-Translation.md#module-translation-tests).
|
[Testing Translations](Testing Translations).
|
||||||
|
|
||||||
## Testing Translations <a id="module-translation-tests"></a>
|
## Testing Translations <a id="module-translation-tests"></a>
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
Module: translation
|
Module: translation
|
||||||
Version: 2.12.4
|
Version: 2.12.2
|
||||||
Description: Translation module
|
Description: Translation module
|
||||||
This module allows developers and translators to translate modules for multiple
|
This module allows developers and translators to translate modules for multiple
|
||||||
languages. You do not need this module to run an internationalized web frontend.
|
languages. You do not need this module to run an internationalized web frontend.
|
||||||
|
@ -282,39 +282,6 @@ a:hover > .icon-cancel {
|
|||||||
|
|
||||||
// Responsive iFrames
|
// Responsive iFrames
|
||||||
|
|
||||||
.iframe-warning {
|
|
||||||
h2, p, a {
|
|
||||||
display: block;
|
|
||||||
width: fit-content;
|
|
||||||
font-size: 200%;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1000%;
|
|
||||||
color: @state-warning;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note {
|
|
||||||
background: @gray-lighter;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.reason {
|
|
||||||
.icon {
|
|
||||||
color: @text-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
font-size: 100%;
|
|
||||||
background: @gray-lightest;
|
|
||||||
color: @text-color-light;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.iframe-container {
|
.iframe-container {
|
||||||
position: relative;
|
position: relative;
|
||||||
height: 0;
|
height: 0;
|
||||||
@ -328,7 +295,6 @@ a:hover > .icon-cancel {
|
|||||||
top: 0;
|
top: 0;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@
|
|||||||
border-top: none;
|
border-top: none;
|
||||||
margin-left: -1px;
|
margin-left: -1px;
|
||||||
min-width: 14em;
|
min-width: 14em;
|
||||||
z-index: 1001;
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs > .dropdown-nav-item > ul > li:hover > a {
|
.tabs > .dropdown-nav-item > ul > li:hover > a {
|
||||||
|
@ -83,9 +83,7 @@
|
|||||||
if ($container[0].contains(origFocus)
|
if ($container[0].contains(origFocus)
|
||||||
&& origFocus.form
|
&& origFocus.form
|
||||||
&& ! origFocus.matches(
|
&& ! origFocus.matches(
|
||||||
'input[type=submit], input[type=reset], input[type=button]'
|
'input[type=submit], input[type=reset], input[type=button], .autofocus, .autosubmit:not(:hover)'
|
||||||
+ ', button[type=submit], button[type=reset], button[type=button]'
|
|
||||||
+ ', .autofocus, .autosubmit:not(:hover)'
|
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
this.icinga.logger.debug('Not changing content for ' + containerId + ' form has focus');
|
this.icinga.logger.debug('Not changing content for ' + containerId + ' form has focus');
|
||||||
|
@ -170,22 +170,8 @@
|
|||||||
var $dashlet = $(this);
|
var $dashlet = $(this);
|
||||||
var url = $dashlet.data('icingaUrl');
|
var url = $dashlet.data('icingaUrl');
|
||||||
if (typeof url !== 'undefined') {
|
if (typeof url !== 'undefined') {
|
||||||
const urlHash = this.dataset.urlHash;
|
|
||||||
if (urlHash) {
|
|
||||||
_this.icinga.loader.loadUrl(
|
|
||||||
url,
|
|
||||||
$dashlet,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
true,
|
|
||||||
undefined,
|
|
||||||
{ "X-Icinga-URLHash": urlHash }
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
_this.icinga.loader.loadUrl(url, $dashlet).autorefresh = true;
|
_this.icinga.loader.loadUrl(url, $dashlet).autorefresh = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -295,7 +281,6 @@
|
|||||||
var $eventTarget = $(event.target);
|
var $eventTarget = $(event.target);
|
||||||
var href = $a.attr('href');
|
var href = $a.attr('href');
|
||||||
var linkTarget = $a.attr('target');
|
var linkTarget = $a.attr('target');
|
||||||
const urlHash = this.dataset.urlHash;
|
|
||||||
var $target;
|
var $target;
|
||||||
var formerUrl;
|
var formerUrl;
|
||||||
|
|
||||||
@ -406,20 +391,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load link URL
|
// Load link URL
|
||||||
if (urlHash) {
|
|
||||||
icinga.loader.loadUrl(
|
|
||||||
href,
|
|
||||||
$target,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
undefined,
|
|
||||||
{ "X-Icinga-URLHash": urlHash }
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
icinga.loader.loadUrl(href, $target);
|
icinga.loader.loadUrl(href, $target);
|
||||||
}
|
|
||||||
|
|
||||||
if ($a.closest('#menu').length > 0) {
|
if ($a.closest('#menu').length > 0) {
|
||||||
// Menu links should remove all but the first layout column
|
// Menu links should remove all but the first layout column
|
||||||
|
@ -242,10 +242,6 @@
|
|||||||
loadUrl: function (url, $target, data, method, action, autorefresh, progressTimer, extraHeaders) {
|
loadUrl: function (url, $target, data, method, action, autorefresh, progressTimer, extraHeaders) {
|
||||||
var id = null;
|
var id = null;
|
||||||
|
|
||||||
if (url.startsWith('//') || ! url.startsWith(this.baseUrl + '/')) {
|
|
||||||
throw new Error('URL ' + url + ' is not relative to ' + this.baseUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default method is GET
|
// Default method is GET
|
||||||
if ('undefined' === typeof method) {
|
if ('undefined' === typeof method) {
|
||||||
method = 'GET';
|
method = 'GET';
|
||||||
|
@ -71,11 +71,6 @@ class UrlTest extends BaseTestCase
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testWhetherProtocolRelativeUrlsAreDetectedAsBeingExternal()
|
|
||||||
{
|
|
||||||
$this->assertTrue(Url::fromPath('//testhost/path/to/my/url.html')->isExternal());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testWhetherGetAbsoluteUrlReturnsTheGivenUsernameAndPassword()
|
public function testWhetherGetAbsoluteUrlReturnsTheGivenUsernameAndPassword()
|
||||||
{
|
{
|
||||||
$url = Url::fromPath('http://testusername:testpassword@testsite.com/path/to/my/url.html');
|
$url = Url::fromPath('http://testusername:testpassword@testsite.com/path/to/my/url.html');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user