Compare commits

...

30 Commits

Author SHA1 Message Date
Silas
ff04a2ea43
Fix that CSV exports contain empty strings instead of zeros 2025-04-07 13:46:21 +02:00
Johannes Meyer
6c7f1e5466 Dashlet: Properly embed iframe urls
fixes #5346
2025-04-01 11:19:00 +02:00
Johannes Meyer
219b11789b
Release/v2.12.4 (#5345) 2025-03-26 16:42:31 +01:00
Johannes Meyer
41bbf6e35d Update CHANGELOG.md 2025-03-26 16:41:23 +01:00
Johannes Meyer
e98a776509 Raise version to 2.12.4 2025-03-26 16:41:23 +01:00
Johannes Meyer
1ddd04df50 DbUserBackend: Fix broken password hash fetch routine
fixes #5343
2025-03-26 16:40:48 +01:00
Johannes Meyer
15e74ebb0c
Release/v2.12.3 (#5342) 2025-03-26 10:39:37 +01:00
Johannes Meyer
53fa6d57e1 Raise ipl requirement 2025-03-26 10:35:11 +01:00
Johannes Meyer
c07a45096c Update CHANGELOG.md 2025-03-26 10:31:04 +01:00
Johannes Meyer
01fb35dd4a Raise version to 2.12.3 2025-03-26 10:31:04 +01:00
Johannes Meyer
ec40efe157 Only open trusted iframe sources by default
Trusted in this case means, it was Icinga Web that
rendered a link and the user followed it. Whether
a source is trustworthy or not is detected by use
of the user's session id to hash it combined with
the source similar to how CSRF tokens are assembled.
2025-03-26 10:25:31 +01:00
Johannes Meyer
aad020511f js: Only load URLs prefixed by the base URL 2025-03-26 10:25:05 +01:00
Johannes Meyer
484bd26d63 Window: Only accept valid window IDs 2025-03-26 10:24:17 +01:00
Johannes Meyer
2b08d88edf Url: Always compare host and port to identify external urls 2025-03-26 10:23:31 +01:00
Johannes Meyer
191444ccd9 Pdf: Ensure dompdf can create temporary files
This is required since dompdf seems to automatically load
our custom font and complains otherwise.
2025-03-25 13:59:18 +01:00
Johannes Meyer
1a1f96be49 php: Install the same vendor dependencies for all php versions 2025-03-25 13:51:59 +01:00
Sukhwinder Dhillon
f1fe2525bd tabs.less: Don't let icinga-loader element overlap the dropdown nav 2025-03-20 17:48:37 +01:00
Johannes Meyer
d56d10c712 monitoring: Use the (new) icon for the reporting section
The same that the reporting module is using now
2025-03-20 16:58:45 +01:00
Markus Opolka
6c8453062f Fix doc module markdown table rows in light mode
- Replaced the gradient mixin with a simple color
  for odd rows. This fixes and markdown table rows
  in light mode and - since there are very gradients
  in general - it makes the overall look more uniform.

See https://github.com/Icinga/icingaweb2/issues/5320
2025-03-20 16:39:13 +01:00
Johannes Meyer
db851bbe33 Don't mention Twitter anymore, it's gone now for good 2025-03-20 16:36:52 +01:00
Johannes Meyer
d86ede517f
Fix case sensitive authentication with postgres (#5338)
fixes #5223
2025-03-20 16:34:30 +01:00
Johannes Meyer
92dad17a2b DbUserGroupBackend: Match memberships case-insensitive on pgsql 2025-03-20 16:24:21 +01:00
Johannes Meyer
13c9a73842 DbUserBackend: Match usernames case-insensitive on pgsql 2025-03-20 16:24:21 +01:00
Johannes Meyer
acfad5ae52
Fix unescaped error messages (#5329)
In both cases the input, which wasn't escaped before, comes from a form
element that doesn't allow any user to change its content. An ordinary
user would need to access the DOM in order to do that.

Both forms are protected by CSRF, so this mitigates any potential
exploit as well.
2025-03-20 16:20:21 +01:00
Johannes Meyer
14c0748693 Escape resource identifier in monitoring backend form 2025-03-20 14:56:53 +01:00
Johannes Meyer
02dece2a35 Escape invalid module name in error messages 2025-03-20 14:56:53 +01:00
Sukhwinder Dhillon
c6c1e28350 RolesConfig: Add missing column name for quick search 2025-03-20 14:30:45 +01:00
Blerim Sheqa
79971cb1a6 Fix broken links 2025-01-14 11:14:02 +01:00
Johannes Meyer
ca2778eb46 form.js: Ignore buttons again when being asked to render content
This slipped through, as I thought the CSS selector `:input`, which
was used previously, is invalid. Although, it's a jQuery specific
selector -.-, which was also previously used.

fixes #5293
2024-11-28 16:57:19 +01:00
Yoda-BZH
4eadfd0ace
View: Consider letter a legacy icon name 2024-11-28 16:55:59 +01:00
39 changed files with 305 additions and 106 deletions

View File

@ -100,7 +100,9 @@ jobs:
- name: Setup dependencies
run: |
composer require -n --no-progress mockery/mockery ipl/i18n:@dev ipl/web:@dev
composer init -n --require mockery/mockery:* --require ipl/i18n:@dev --require 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
- name: PHPUnit

View File

@ -4,6 +4,47 @@ Please make sure to always read our [Upgrading](doc/80-Upgrading.md) documentati
## 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
You can find all issues related to this release on our Roadmap.

View File

@ -1 +1 @@
v2.12.2
v2.12.4

View File

@ -3,18 +3,108 @@
namespace Icinga\Controllers;
use Icinga\Web\Controller;
use Icinga\Web\Session;
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
*/
class IframeController extends Controller
class IframeController extends CompatController
{
/**
* Display iframe w/ the given URL
*/
public function indexAction()
public function indexAction(): void
{
$this->view->url = $this->params->getRequired('url');
$url = Url::fromPath($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);
}
}

View File

@ -184,15 +184,6 @@ use ipl\Web\Widget\StateBadge;
</div>
<div class="about-social">
<?= $this->qlink(
null,
'https://www.twitter.com/icinga',
null,
array(
'target' => '_blank',
'icon' => 'twitter',
'title' => $this->translate('Icinga on Twitter')
)
) ?> <?= $this->qlink(
null,
'https://www.facebook.com/icinga',
null,

View File

@ -28,18 +28,6 @@
</div>
</div>
<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>
<?= $this->qlink(
null,

View File

@ -6,7 +6,7 @@
<?= $this->tabs->render($this); ?>
<br/>
<div>
<h1>Could not <?= $action; ?> module "<?= $moduleName; ?>"</h1>
<h1>Could not <?= $action; ?> module "<?= $this->escape($moduleName); ?>"</h1>
<p>
While operation the following error occurred:
<br />

View File

@ -23,7 +23,7 @@ $modReason = [];
if (isset($requiredVendor, $requiredProject) && $requiredVendor && $requiredProject) {
// TODO: I don't like this, can we define requirements somewhere else?
$coreDeps = ['icinga-php-library' => '>= 0.13.2', 'icinga-php-thirdparty' => '>= 0.12'];
$coreDeps = ['icinga-php-library' => '>= 0.14.2', 'icinga-php-thirdparty' => '>= 0.12'];
foreach ($coreDeps as $libraryName => $requiredVersion) {
if (! $libraries->has($libraryName)) {

View File

@ -1,8 +0,0 @@
<?php if (! $compact): ?>
<div class="controls">
<?= $tabs ?>
</div>
<?php endif ?>
<div class="iframe-container">
<iframe src="<?= $this->escape($url) ?>" frameborder="no"></iframe>
</div>

View File

@ -399,7 +399,7 @@ You will need to install certain dependencies depending on your setup:
monitor your infrastructure
* A web server, e.g. Apache or Nginx
* PHP version ≥ 7.2
* [Icinga PHP Library (ipl)](https://github.com/Icinga/icinga-php-library) (≥ 0.13.2)
* [Icinga PHP Library (ipl)](https://github.com/Icinga/icinga-php-library) (≥ 0.14.2)
* [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 [pdfexport](https://github.com/Icinga/icingaweb2-module-pdfexport) module (≥0.10) is required for the

View File

@ -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
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](https://icinga.com/icinga/faq/):
When filing a bug report please add the following information additionally to the common ones:
* Output of `semodule -l | grep -e icinga2 -e icingaweb2 -e nagios -e apache`
* Output of `semanage boolean -l | grep icinga`
* Output of `ps -eZ | grep httpd`

View File

@ -8,7 +8,7 @@ namespace Icinga\Application;
*/
class Version
{
const VERSION = '2.12.2';
const VERSION = '2.12.4';
/**
* Get the version of this instance of Icinga Web 2

View File

@ -42,4 +42,9 @@ class RolesConfig extends IniRepository
return $columns;
}
protected function initializeSearchColumns(): array
{
return ['name'];
}
}

View File

@ -11,6 +11,7 @@ use Icinga\Exception\AuthenticationException;
use Icinga\Repository\DbRepository;
use Icinga\User;
use PDO;
use Zend_Db_Expr;
class DbUserBackend extends DbRepository implements UserBackendInterface, Inspectable
{
@ -179,23 +180,28 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
{
if ($this->ds->getDbType() === 'pgsql') {
// Since PostgreSQL version 9.0 the default value for bytea_output is 'hex' instead of 'escape'
$columns = array('password_hash' => 'ENCODE(password_hash, \'escape\')');
$columns = ['password_hash' => new Zend_Db_Expr('ENCODE(password_hash, \'escape\')')];
} else {
$columns = array('password_hash');
// password_hash is intentionally not a valid query column,
// by wrapping it in an expression it is not validated
$columns = ['password_hash' => new Zend_Db_Expr('password_hash')];
}
$nameColumn = 'name';
if ($this->ds->getDbType() === 'mysql') {
$username = strtolower($username);
$nameColumn = 'BINARY LOWER(name)';
}
$query = $this->ds->select()
->from($this->prependTablePrefix('user'), $columns)
->where($nameColumn, $username)
$query = $this
->select()
->from('user', $columns)
->where('active', true);
$statement = $this->ds->getDbAdapter()->prepare($query->getSelectQuery());
if ($this->ds->getDbType() === 'mysql') {
$username = strtolower($username);
$nameColumn = new Zend_Db_Expr('BINARY LOWER(name)');
$query->getQuery()->where($nameColumn, $username);
} else { // pgsql
$query->where('user', $username);
}
$statement = $this->ds->getDbAdapter()->prepare($query->getQuery()->getSelectQuery());
$statement->execute();
$statement->bindColumn(1, $lob, PDO::PARAM_LOB);
$statement->fetch(PDO::FETCH_BOUND);

View File

@ -204,7 +204,7 @@ class DbUserGroupBackend extends DbRepository implements Inspectable, UserGroupB
$membershipQuery = $this
->select()
->from('group_membership', array('group_name'))
->where('user_name', $user->getUsername());
->where('user', $user->getUsername());
$memberships = array();
foreach ($membershipQuery as $membership) {

View File

@ -37,7 +37,7 @@ class Csv
}
$out = array();
foreach ($row as & $val) {
$out[] = '"' . ($val ? str_replace('"', '""', $val) : '') . '"';
$out[] = '"' . ($val == '0' ? '0' : ($val ? str_replace('"', '""', $val) : '')) . '"';
}
$csv .= implode(',', $out) . "\r\n";
}

View File

@ -5,9 +5,11 @@ namespace Icinga\File;
use Dompdf\Dompdf;
use Dompdf\Options;
use Exception;
use Icinga\Application\Icinga;
use Icinga\Exception\ProgrammingError;
use Icinga\Util\Environment;
use Icinga\Web\FileCache;
use Icinga\Web\Hook;
use Icinga\Web\Url;
@ -64,8 +66,17 @@ class Pdf
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->set('defaultPaperSize', 'A4');
$options->set('fontDir', $tmpDir);
$options->set('fontCache', $tmpDir);
$options->set('tempDir', $tmpDir);
$options->set('chroot', $tmpDir);
$dompdf = new Dompdf($options);
$dompdf->loadHtml($html);
$dompdf->render();

View File

@ -7,6 +7,7 @@ use Icinga\Application\Icinga;
use Icinga\Exception\ProgrammingError;
use Icinga\Util\StringHelper;
use Icinga\Web\Navigation\NavigationItem;
use Icinga\Web\Session;
use Icinga\Web\Url;
use Icinga\Web\View;
@ -190,6 +191,10 @@ class NavigationItemRenderer
$target = $item->getTarget();
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));
}

View File

@ -179,10 +179,9 @@ class 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['port']) && $urlParts['port'] != $request->getServer('SERVER_PORT')))
|| (isset($urlParts['port']) && $urlParts['port'] != $request->getServer('SERVER_PORT'))
) {
$urlObject->setIsExternal();
}

View File

@ -205,7 +205,8 @@ class View extends Zend_View_Abstract
'th-thumb-empty' => true,
'github-circled' => true,
'history' => true,
'binoculars' => true
'binoculars' => true,
'letter' => true
//</editor-fold>
];

View File

@ -3,9 +3,9 @@
namespace Icinga\Web\Widget\Dashboard;
use Icinga\Web\Session;
use Icinga\Web\Url;
use Icinga\Data\ConfigObject;
use Icinga\Exception\IcingaException;
/**
* A dashboard pane dashlet
@ -57,18 +57,15 @@ class Dashlet extends UserWidget
*/
private $template =<<<'EOD'
<div class="container" data-icinga-url="{URL}">
<h1><a href="{FULL_URL}" aria-label="{TOOLTIP}" title="{TOOLTIP}" data-base-target="col1">{TITLE}</a></h1>
<div class="container" data-icinga-url="{URL}" data-url-hash="{URL_HASH}">
<h1><a
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>
<noscript>
<div class="iframe-container">
<iframe
src="{IFRAME_URL}"
frameborder="no"
title="{TITLE_PREFIX}{TITLE}">
</iframe>
</div>
</noscript>
</div>
EOD;
@ -250,13 +247,22 @@ EOD;
$url = $this->getUrl();
$url->setParam('showCompact', true);
$iframeUrl = clone $url;
$iframeUrl->setParam('isIframe');
$fullUrl = $url->getUrlWithout(['showCompact', 'limit', 'view']);
$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(
'{URL}',
'{IFRAME_URL}',
'{URL_HASH}',
'{FULL_URL}',
'{FULL_URL_HASH}',
'{TOOLTIP}',
'{TITLE}',
'{TITLE_PREFIX}',
@ -265,8 +271,9 @@ EOD;
$replaceTokens = array(
$url,
$iframeUrl,
$url->getUrlWithout(['showCompact', 'limit', 'view']),
$urlHash,
$fullUrl,
$fullUrlHash,
sprintf($view->translate('Show %s', 'dashboard.dashlet.tooltip'), $view->escape($this->getTitle())),
$view->escape($this->getTitle()),
$view->translate('Dashlet') . ': ',

View File

@ -112,7 +112,7 @@ class Window
{
if (! isset(static::$window)) {
$id = Icinga::app()->getRequest()->getHeader('X-Icinga-WindowId');
if (empty($id) || $id === static::UNDEFINED) {
if (empty($id) || $id === static::UNDEFINED || ! preg_match('/^\w+$/', $id)) {
Icinga::app()->getResponse()->setOverrideWindowId();
$id = static::generateId();
}

View File

@ -1,4 +1,4 @@
Module: doc
Version: 2.12.2
Version: 2.12.4
Description: Documentation module
Extracts, shows and exports documentation for Icinga Web 2 and its modules.

View File

@ -1,17 +1,5 @@
/*! 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
code {
@ -84,7 +72,7 @@ table {
}
tbody > tr:nth-child(odd) {
.gradient()
background: @gray-light;
}
tbody > tr:nth-child(even) {

View File

@ -1,5 +1,5 @@
Module: migrate
Version: 2.12.2
Version: 2.12.4
Description: Migrate module
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.

View File

@ -227,7 +227,7 @@ class BackendConfigForm extends ConfigForm
'autosubmit' => true
)
);
$resourceName = isset($formData['resource']) ? $formData['resource'] : $this->getValue('resource');
$resourceName = $this->getView()->escape($formData['resource'] ?? $this->getValue('resource'));
$this->addElement(
'note',
'resource_note',

View File

@ -284,10 +284,10 @@ $section->add(N_('Timeline'), array(
/*
* Reporting Section
*/
$section = $this->menuSection(N_('Reporting'), array(
'icon' => 'barchart',
$section = $this->menuSection(N_('Reporting'), [
'icon' => 'fa-chart-simple',
'priority' => 100
));
]);
/*
* Current Incidents

View File

@ -1,5 +1,5 @@
Module: monitoring
Version: 2.12.2
Version: 2.12.4
Description: Icinga monitoring module
IDO accessor and UI for your monitoring. This is the initial instalment for a
graphical presentation of Icinga environments. The predecessor of Icinga DB.

View File

@ -602,7 +602,7 @@ class WebWizard extends Wizard implements SetupWizard
)));
$set->add(new WebLibraryRequirement(array(
'condition' => ['icinga-php-library', '>=', '0.13.2'],
'condition' => ['icinga-php-library', '>=', '0.14.2'],
'alias' => 'Icinga PHP library',
'description' => mt(
'setup',

View File

@ -1,5 +1,5 @@
Module: setup
Version: 2.12.2
Version: 2.12.4
Description: Setup module
Web based wizard for setting up Icinga Web 2 and its modules.
This includes the data backends (e.g. relational database, LDAP),

View File

@ -1,5 +1,5 @@
Module: test
Version: 2.12.2
Version: 2.12.4
Description: Translation module
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.

View File

@ -130,7 +130,7 @@ below.
![Untranslated strings](img/poedit_005.png)
And when you want to test your changes, please read more about under the chapter
[Testing Translations](Testing Translations).
[Testing Translations](03-Translation.md#module-translation-tests).
## Testing Translations <a id="module-translation-tests"></a>

View File

@ -1,5 +1,5 @@
Module: translation
Version: 2.12.2
Version: 2.12.4
Description: Translation module
This module allows developers and translators to translate modules for multiple
languages. You do not need this module to run an internationalized web frontend.

View File

@ -282,6 +282,39 @@ a:hover > .icon-cancel {
// 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 {
position: relative;
height: 0;
@ -295,6 +328,7 @@ a:hover > .icon-cancel {
top: 0;
height: 100%;
width: 100%;
border: none;
}
}

View File

@ -70,7 +70,7 @@
border-top: none;
margin-left: -1px;
min-width: 14em;
z-index: 10;
z-index: 1001;
}
.tabs > .dropdown-nav-item > ul > li:hover > a {

View File

@ -83,7 +83,9 @@
if ($container[0].contains(origFocus)
&& origFocus.form
&& ! origFocus.matches(
'input[type=submit], input[type=reset], input[type=button], .autofocus, .autosubmit:not(:hover)'
'input[type=submit], input[type=reset], input[type=button]'
+ ', 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');

View File

@ -170,7 +170,21 @@
var $dashlet = $(this);
var url = $dashlet.data('icingaUrl');
if (typeof url !== 'undefined') {
_this.icinga.loader.loadUrl(url, $dashlet).autorefresh = true;
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;
}
}
});
}
@ -281,6 +295,7 @@
var $eventTarget = $(event.target);
var href = $a.attr('href');
var linkTarget = $a.attr('target');
const urlHash = this.dataset.urlHash;
var $target;
var formerUrl;
@ -391,7 +406,20 @@
}
// Load link URL
icinga.loader.loadUrl(href, $target);
if (urlHash) {
icinga.loader.loadUrl(
href,
$target,
undefined,
undefined,
undefined,
undefined,
undefined,
{ "X-Icinga-URLHash": urlHash }
);
} else {
icinga.loader.loadUrl(href, $target);
}
if ($a.closest('#menu').length > 0) {
// Menu links should remove all but the first layout column

View File

@ -242,6 +242,10 @@
loadUrl: function (url, $target, data, method, action, autorefresh, progressTimer, extraHeaders) {
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
if ('undefined' === typeof method) {
method = 'GET';

View File

@ -71,6 +71,11 @@ class UrlTest extends BaseTestCase
);
}
public function testWhetherProtocolRelativeUrlsAreDetectedAsBeingExternal()
{
$this->assertTrue(Url::fromPath('//testhost/path/to/my/url.html')->isExternal());
}
public function testWhetherGetAbsoluteUrlReturnsTheGivenUsernameAndPassword()
{
$url = Url::fromPath('http://testusername:testpassword@testsite.com/path/to/my/url.html');