diff --git a/core/modules/dblog/src/Tests/DbLogTest.php b/core/modules/dblog/src/Tests/DbLogTest.php index d6a59ad..f306ad3 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()); } @@ -61,7 +68,7 @@ protected function setUp() { * Database Logging module functionality through both the admin and user * interfaces. */ - function testDbLog() { + public function testDbLog() { // Login the admin user. $this->drupalLogin($this->adminUser); @@ -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'); @@ -129,21 +138,18 @@ private function verifyCron($row_limit) { * * @param int $count * Number of watchdog entries to generate. - * @param string $type - * (optional) The type of watchdog entry. Defaults to 'custom'. - * @param int $severity - * (optional) The severity of the watchdog entry. Defaults to - * \Drupal\Core\Logger\RfcLogLevel::NOTICE. + * @param array $options + * (optional) An array of options that override the default values. */ - private function generateLogEntries($count, $type = 'custom', $severity = RfcLogLevel::NOTICE) { + private function generateLogEntries($count, $options = array()) { global $base_root; - // Prepare the fields to be logged - $log = array( - 'channel' => $type, - 'message' => 'Log entry added to test the dblog row limit.', + // Prepare the fields to be logged. + $log = $options + array( + 'channel' => 'system', + 'message' => 'Dblog test log message', 'variables' => array(), - 'severity' => $severity, + 'severity' => RfcLogLevel::NOTICE, 'link' => NULL, 'user' => $this->adminUser, 'uid' => $this->adminUser->id(), @@ -151,11 +157,18 @@ private function generateLogEntries($count, $type = 'custom', $severity = RfcLog 'referer' => \Drupal::request()->server->get('HTTP_REFERER'), 'ip' => '127.0.0.1', 'timestamp' => REQUEST_TIME, - ); - $message = 'Log entry added to test the dblog row limit. Entry #'; - for ($i = 0; $i < $count; $i++) { - $log['message'] = $message . $i; - $this->container->get('logger.dblog')->log($severity, $log['message'], $log); + ); + + $logger = $this->container->get('logger.dblog'); + if ($count > 1) { + $row_message = $log['message'] . ' Entry #'; + for ($i = 0; $i < $count; $i++) { + $log['message'] = $row_message . $i; + $logger->log($log['severity'], $log['message'], $log); + } + } + else { + $logger->log($log['severity'], $log['message'], $log); } } @@ -240,13 +253,89 @@ private function verifyEvents() { * @param string $order * The order by which the table should be sorted. */ - public function verifySort($sort = 'asc', $order = 'Date') { + protected function verifySort($sort = 'asc', $order = 'Date') { $this->drupalGet('admin/reports/dblog', array('query' => array('sort' => $sort, 'order' => $order))); $this->assertResponse(200); $this->assertText(t('Recent log messages'), 'DBLog report was displayed correctly and sorting went fine.'); } /** + * 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() { @@ -338,7 +427,11 @@ private function doUser() { */ private function doNode($type) { // Create user. - $perm = array('create ' . $type . ' content', 'edit own ' . $type . ' content', 'delete own ' . $type . ' content'); + $perm = array( + 'create ' . $type . ' content', + 'edit own ' . $type . ' content', + 'delete own ' . $type . ' content', + ); $user = $this->drupalCreateUser($perm); // Login user. $this->drupalLogin($user); @@ -497,7 +590,10 @@ protected function testFilter() { 'type' => $type_name, 'severity' => $severity++, ); - $this->generateLogEntries($type['count'], $type['type'], $type['severity']); + $this->generateLogEntries($type['count'], array( + 'channel' => $type['type'], + 'severity' => $type['severity'], + )); } }