diff options
author | webchick | 2015-07-02 07:36:31 (GMT) |
---|---|---|
committer | webchick | 2015-07-02 07:36:31 (GMT) |
commit | c57b3db64465c301d22f2753d87d4c204cc03341 (patch) | |
tree | 3bb6a522998d345726928888903c381920421b21 | |
parent | eb3e64a0ae31ed9620f9173c085bfaa8d75c0db8 (diff) |
Issue #2309215 by googletorp, subhojit777, lokeoke, tadityar, crowdcg, aneek, joelpittet, jhedstrom, alexpott, lauriii, amankanoria: HTML double-escaping in revision messages
-rw-r--r-- | core/modules/node/src/Controller/NodeController.php | 99 | ||||
-rw-r--r-- | core/modules/node/src/Tests/NodeRevisionsUiTest.php | 78 |
2 files changed, 125 insertions, 52 deletions
diff --git a/core/modules/node/src/Controller/NodeController.php b/core/modules/node/src/Controller/NodeController.php index 1cb43be..5889912 100644 --- a/core/modules/node/src/Controller/NodeController.php +++ b/core/modules/node/src/Controller/NodeController.php @@ -172,53 +172,66 @@ class NodeController extends ControllerBase implements ContainerInjectionInterfa $vids = $node_storage->revisionIds($node); foreach (array_reverse($vids) as $vid) { - if ($revision = $node_storage->loadRevision($vid)) { - $row = array(); - - $revision_author = $revision->uid->entity; - - if ($vid == $node->getRevisionId()) { - $username = array( - '#theme' => 'username', - '#account' => $revision_author, - ); - $row[] = array('data' => $this->t('!date by !username', array('!date' => $node->link($this->dateFormatter->format($revision->revision_timestamp->value, 'short')), '!username' => drupal_render($username))) - . (($revision->revision_log->value != '') ? '<p class="revision-log">' . Xss::filter($revision->revision_log->value) . '</p>' : ''), - 'class' => array('revision-current')); - $row[] = array('data' => SafeMarkup::placeholder($this->t('current revision')), 'class' => array('revision-current')); + $revision = $node_storage->loadRevision($vid); + $username = [ + '#theme' => 'username', + '#account' => $revision->uid->entity, + ]; + + // Use revision link to link to revisions that are not active. + $date = $this->dateFormatter->format($revision->revision_timestamp->value, 'short'); + if ($vid != $node->getRevisionId()) { + $link = $this->l($date, new Url('entity.node.revision', ['node' => $node->id(), 'node_revision' => $vid])); + } + else { + $link = $node->link($date); + } + + $row = []; + $row[] = [ + 'data' => [ + '#type' => 'inline_template', + '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}', + '#context' => [ + 'date' => $link, + 'username' => $this->renderer->render($username), + 'message' => Xss::filter($revision->revision_log->value), + ], + ], + ]; + + if ($vid == $node->getRevisionId()) { + $row[0]['class'] = ['revision-current']; + $row[] = [ + 'data' => SafeMarkup::placeholder($this->t('current revision')), + 'class' => ['revision-current'], + ]; + } + else { + $links = []; + if ($revert_permission) { + $links['revert'] = [ + 'title' => $this->t('Revert'), + 'url' => Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $vid]), + ]; } - else { - $username = array( - '#theme' => 'username', - '#account' => $revision_author, - ); - $row[] = $this->t('!date by !username', array('!date' => $this->l($this->dateFormatter->format($revision->revision_timestamp->value, 'short'), new Url('entity.node.revision', array('node' => $node->id(), 'node_revision' => $vid))), '!username' => drupal_render($username))) - . (($revision->revision_log->value != '') ? '<p class="revision-log">' . Xss::filter($revision->revision_log->value) . '</p>' : ''); - - if ($revert_permission) { - $links['revert'] = array( - 'title' => $this->t('Revert'), - 'url' => Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $vid]), - ); - } - - if ($delete_permission) { - $links['delete'] = array( - 'title' => $this->t('Delete'), - 'url' => Url::fromRoute('node.revision_delete_confirm', ['node' => $node->id(), 'node_revision' => $vid]), - ); - } - - $row[] = array( - 'data' => array( - '#type' => 'operations', - '#links' => $links, - ), - ); + + if ($delete_permission) { + $links['delete'] = [ + 'title' => $this->t('Delete'), + 'url' => Url::fromRoute('node.revision_delete_confirm', ['node' => $node->id(), 'node_revision' => $vid]), + ]; } - $rows[] = $row; + $row[] = [ + 'data' => [ + '#type' => 'operations', + '#links' => $links, + ], + ]; } + + $rows[] = $row; } $build['node_revisions_table'] = array( diff --git a/core/modules/node/src/Tests/NodeRevisionsUiTest.php b/core/modules/node/src/Tests/NodeRevisionsUiTest.php index 6527984..4fdd543 100644 --- a/core/modules/node/src/Tests/NodeRevisionsUiTest.php +++ b/core/modules/node/src/Tests/NodeRevisionsUiTest.php @@ -7,6 +7,8 @@ namespace Drupal\node\Tests; +use Drupal\Core\Url; +use Drupal\node\Entity\Node; use Drupal\node\Entity\NodeType; /** @@ -17,26 +19,30 @@ use Drupal\node\Entity\NodeType; class NodeRevisionsUiTest extends NodeTestBase { /** + * @var \Drupal\user\Entity\User + */ + protected $editor; + + /** * {@inheritdoc} */ protected function setUp() { parent::setUp(); - // Create and log in user. - $web_user = $this->drupalCreateUser( - array( - 'administer nodes', - 'edit any page content' - ) - ); - - $this->drupalLogin($web_user); + // Create users. + $this->editor = $this->drupalCreateUser([ + 'administer nodes', + 'edit any page content', + 'view page revisions', + 'access user profiles', + ]); } /** * Checks that unchecking 'Create new revision' works when editing a node. */ function testNodeFormSaveWithoutRevision() { + $this->drupalLogin($this->editor); $node_storage = $this->container->get('entity.manager')->getStorage('node'); // Set page revision setting 'create new revision'. This will mean new @@ -73,6 +79,60 @@ class NodeRevisionsUiTest extends NodeTestBase { $node_storage->resetCache(array($node->id())); $node_revision = $node_storage->load($node->id()); $this->assertNotEqual($node_revision->getRevisionId(), $node->getRevisionId(), "After an existing node is saved with 'Create new revision' checked, a new revision is created."); + } + + /** + * Checks HTML double escaping of revision logs. + */ + public function testNodeRevisionDoubleEscapeFix() { + $this->drupalLogin($this->editor); + $nodes = []; + + // Create the node. + $node = $this->drupalCreateNode(); + $username = [ + '#theme' => 'username', + '#account' => $this->editor, + ]; + $editor = \Drupal::service('renderer')->render($username); + + // Get original node. + $nodes[] = clone $node; + + // Create revision with a random title and body and update variables. + $node->title = $this->randomMachineName(); + $node->body = [ + 'value' => $this->randomMachineName(32), + 'format' => filter_default_format(), + ]; + $node->setNewRevision(); + $revision_log = 'Revision <em>message</em> with markup.'; + $node->revision_log->value = $revision_log; + $node->save(); + // Make sure we get revision information. + $node = Node::load($node->id()); + $nodes[] = clone $node; + + $this->drupalGet('node/' . $node->id() . '/revisions'); + + // Assert the old revision message. + $date = format_date($nodes[0]->revision_timestamp->value, 'short'); + $url = new Url('entity.node.revision', ['node' => $nodes[0]->id(), 'node_revision' => $nodes[0]->getRevisionId()]); + $old_revision_message = t('!date by !username', [ + '!date' => \Drupal::l($date, $url), + '!username' => $editor, + ]); + $this->assertRaw($old_revision_message); + + // Assert the current revision message. + $date = format_date($nodes[1]->revision_timestamp->value, 'short'); + $current_revision_message = t('!date by !username', [ + '!date' => $nodes[1]->link($date), + '!username' => $editor, + ]); + $current_revision_message .= '<p class="revision-log">' . $revision_log . '</p>'; + $this->assertRaw($current_revision_message); } + } |