summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwebchick2015-07-02 07:36:31 (GMT)
committerwebchick2015-07-02 07:36:31 (GMT)
commitc57b3db64465c301d22f2753d87d4c204cc03341 (patch)
tree3bb6a522998d345726928888903c381920421b21
parenteb3e64a0ae31ed9620f9173c085bfaa8d75c0db8 (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.php99
-rw-r--r--core/modules/node/src/Tests/NodeRevisionsUiTest.php78
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);
}
+
}