diff --git a/core/modules/dblog/src/Controller/DbLogController.php b/core/modules/dblog/src/Controller/DbLogController.php
index 44828e4..fd77c64 100644
--- a/core/modules/dblog/src/Controller/DbLogController.php
+++ b/core/modules/dblog/src/Controller/DbLogController.php
@@ -8,8 +8,9 @@
namespace Drupal\dblog\Controller;
use Drupal\Component\Utility\Html;
-use Drupal\Component\Utility\Unicode;
+use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\String;
+use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Database\Connection;
@@ -229,7 +230,6 @@ public function overview() {
* @return array
* If the ID is located in the Database Logging table, a build array in the
* format expected by drupal_render();
- *
*/
public function eventDetails($event_id) {
$build = array();
@@ -240,6 +240,14 @@ public function eventDetails($event_id) {
'#theme' => 'username',
'#account' => user_load($dblog->uid),
);
+ // Validate the event link if it is safe.
+ if (!SafeMarkup::isSafe($dblog->link)) {
+ $event_link = Xss::filterAdmin($dblog->link);
+ }
+ else {
+ $event_link = $dblog->link;
+ }
+
$rows = array(
array(
array('data' => $this->t('Type'), 'header' => TRUE),
@@ -275,7 +283,7 @@ public function eventDetails($event_id) {
),
array(
array('data' => $this->t('Operations'), 'header' => TRUE),
- $dblog->link,
+ $event_link,
),
);
$build['dblog_table'] = array(
diff --git a/core/modules/dblog/src/Tests/DbLogTest.php b/core/modules/dblog/src/Tests/DbLogTest.php
index d6a59ad..5f263db 100644
--- a/core/modules/dblog/src/Tests/DbLogTest.php
+++ b/core/modules/dblog/src/Tests/DbLogTest.php
@@ -7,9 +7,11 @@
namespace Drupal\dblog\Tests;
+use Drupal\Component\Utility\String;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\Xss;
use Drupal\Core\Logger\RfcLogLevel;
+use Drupal\Core\Url;
use Drupal\dblog\Controller\DbLogController;
use Drupal\simpletest\WebTestBase;
@@ -50,7 +52,12 @@ protected function setUp() {
$this->drupalPlaceBlock('system_breadcrumb_block');
// Create users with specific permissions.
- $this->adminUser = $this->drupalCreateUser(array('administer site configuration', 'access administration pages', 'access site reports', 'administer users'));
+ $this->adminUser = $this->drupalCreateUser(array(
+ 'administer site configuration',
+ 'access administration pages',
+ 'access site reports',
+ 'administer users',
+ ));
$this->webUser = $this->drupalCreateUser(array());
}
@@ -71,6 +78,8 @@ function testDbLog() {
$this->verifyEvents();
$this->verifyReports();
$this->verifyBreadcrumbs();
+ $this->verifyLinkEscaping();
+ $this->verifyMessageEscaping();
// Verify the overview table sorting.
$orders = array('Date', 'Type', 'User');
$sorts = array('asc', 'desc');
@@ -247,6 +256,82 @@ public function verifySort($sort = 'asc', $order = 'Date') {
}
/**
+ * Tests the escaping of links in the operation row of a database log detail
+ * page.
+ */
+ private function verifyLinkEscaping() {
+ $link = \Drupal::l('View', Url::fromRoute('entity.node.canonical', array('node' => 1)));
+ $message = 'Log entry added to do the verifyLinkEscaping test.';
+ $this->generateLogEntries(1, array(
+ 'message' => $message,
+ 'link' => $link,
+ ));
+
+ $result = db_query_range('SELECT wid FROM {watchdog} ORDER BY wid DESC', 0, 1);
+ $this->drupalGet('admin/reports/dblog/event/' . $result->fetchField());
+
+ // Check if the link exists (unescaped).
+ $this->assertRaw($link);
+
+ // Check for XSS filtering.
+ $js_txt = 'This should not pop up!';
+ $js = '';
+ $this->generateLogEntries(1, array(
+ 'message' => $message,
+ 'link' => $link . $js,
+ ));
+
+ $result = db_query_range('SELECT wid FROM {watchdog} ORDER BY wid DESC', 0, 1);
+ $this->drupalGet('admin/reports/dblog/event/' . $result->fetchField());
+
+ // Check if the link exists (unescaped).
+ $this->assertRaw($link);
+
+ // Check if javascript was escaped.
+ $this->assertNoRaw($js, 'Detail view: javascript in link is blocked');
+ $this->assertRaw($js_txt, 'Detail view: javascript text exists');
+ }
+
+ /**
+ * Test the escaping of message in the operation row of a database log detail
+ * page.
+ */
+ private function verifyMessageEscaping() {
+ $link = \Drupal::l('View', Url::fromRoute('entity.node.canonical', array('node' => 1)));
+ $message = String::format('%message', array(
+ '%message' => 'Log entry added to do the verifyMessageEscaping test.',
+ ));
+ $this->generateLogEntries(1, array(
+ 'message' => $message,
+ 'link' => $link,
+ ));
+
+ $result = db_query_range('SELECT wid FROM {watchdog} ORDER BY wid DESC', 0, 1);
+ $this->drupalGet('admin/reports/dblog/event/' . $result->fetchField());
+
+ // Check if the link exists (unescaped).
+ $this->assertRaw($message);
+
+ // Check for XSS filtering.
+ $js_txt = 'This should not pop up!';
+ $js = '';
+ $this->generateLogEntries(1, array(
+ 'message' => $message . $js,
+ 'link' => $link,
+ ));
+
+ $result = db_query_range('SELECT wid FROM {watchdog} ORDER BY wid DESC', 0, 1);
+ $this->drupalGet('admin/reports/dblog/event/' . $result->fetchField());
+
+ // Check if the link exists (unescaped).
+ $this->assertRaw($message);
+
+ // Check if javascript was escaped.
+ $this->assertNoRaw($js, 'Detail view: javascript in message is blocked');
+ $this->assertRaw($js_txt, 'Detail view: javascript text exists ');
+ }
+
+ /**
* Generates and then verifies some user events.
*/
private function doUser() {