updated core to 8.6.2

This commit is contained in:
2018-10-23 11:50:40 +02:00
parent afcb9d9c34
commit 5c71ef4c46
34 changed files with 1083 additions and 566 deletions
+7 -1
View File
@@ -191,13 +191,19 @@ function _contextual_links_to_id($contextual_links) {
/**
* Unserializes the result of _contextual_links_to_id().
*
* @see _contextual_links_to_id
* Note that $id is user input. Before calling this method the ID should be
* checked against the token stored in the 'data-contextual-token' attribute
* which is passed via the 'tokens' request parameter to
* \Drupal\contextual\ContextualController::render().
*
* @param string $id
* A serialized representation of a #contextual_links property value array.
*
* @return array
* The value for a #contextual_links property.
*
* @see _contextual_links_to_id()
* @see \Drupal\contextual\ContextualController::render()
*/
function _contextual_id_to_links($id) {
$contextual_links = [];
@@ -0,0 +1,14 @@
<?php
/**
* @file
* Post update functions for Contextual Links.
*/
/**
* Ensure new page loads use the updated JS and get the updated markup.
*/
function contextual_post_update_fixed_endpoint_and_markup() {
// Empty update to trigger a change to css_js_query_string and invalidate
// cached markup.
}
+13 -8
View File
@@ -168,12 +168,16 @@
// Collect the IDs for all contextual links placeholders.
const ids = [];
$placeholders.each(function() {
ids.push($(this).attr('data-contextual-id'));
ids.push({
id: $(this).attr('data-contextual-id'),
token: $(this).attr('data-contextual-token'),
});
});
// Update all contextual links placeholders whose HTML is cached.
const uncachedIDs = _.filter(ids, contextualID => {
const html = storage.getItem(`Drupal.contextual.${contextualID}`);
const uncachedIDs = [];
const uncachedTokens = [];
ids.forEach(contextualID => {
const html = storage.getItem(`Drupal.contextual.${contextualID.id}`);
if (html && html.length) {
// Initialize after the current execution cycle, to make the AJAX
// request for retrieving the uncached contextual links as soon as
@@ -182,13 +186,14 @@
// Drupal.contextual.collection.
window.setTimeout(() => {
initContextual(
$context.find(`[data-contextual-id="${contextualID}"]`),
$context.find(`[data-contextual-id="${contextualID.id}"]`),
html,
);
});
return false;
return;
}
return true;
uncachedIDs.push(contextualID.id);
uncachedTokens.push(contextualID.token);
});
// Perform an AJAX request to let the server render the contextual links
@@ -197,7 +202,7 @@
$.ajax({
url: Drupal.url('contextual/render'),
type: 'POST',
data: { 'ids[]': uncachedIDs },
data: { 'ids[]': uncachedIDs, 'tokens[]': uncachedTokens },
dataType: 'json',
success(results) {
_.each(results, (html, contextualID) => {
+13 -7
View File
@@ -95,25 +95,31 @@
var ids = [];
$placeholders.each(function () {
ids.push($(this).attr('data-contextual-id'));
ids.push({
id: $(this).attr('data-contextual-id'),
token: $(this).attr('data-contextual-token')
});
});
var uncachedIDs = _.filter(ids, function (contextualID) {
var html = storage.getItem('Drupal.contextual.' + contextualID);
var uncachedIDs = [];
var uncachedTokens = [];
ids.forEach(function (contextualID) {
var html = storage.getItem('Drupal.contextual.' + contextualID.id);
if (html && html.length) {
window.setTimeout(function () {
initContextual($context.find('[data-contextual-id="' + contextualID + '"]'), html);
initContextual($context.find('[data-contextual-id="' + contextualID.id + '"]'), html);
});
return false;
return;
}
return true;
uncachedIDs.push(contextualID.id);
uncachedTokens.push(contextualID.token);
});
if (uncachedIDs.length > 0) {
$.ajax({
url: Drupal.url('contextual/render'),
type: 'POST',
data: { 'ids[]': uncachedIDs },
data: { 'ids[]': uncachedIDs, 'tokens[]': uncachedTokens },
dataType: 'json',
success: function success(results) {
_.each(results, function (html, contextualID) {
@@ -2,8 +2,10 @@
namespace Drupal\contextual;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\Site\Settings;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
@@ -63,8 +65,16 @@ class ContextualController implements ContainerInjectionInterface {
throw new BadRequestHttpException(t('No contextual ids specified.'));
}
$tokens = $request->request->get('tokens');
if (!isset($tokens)) {
throw new BadRequestHttpException(t('No contextual ID tokens specified.'));
}
$rendered = [];
foreach ($ids as $id) {
foreach ($ids as $key => $id) {
if (!isset($tokens[$key]) || !Crypt::hashEquals($tokens[$key], Crypt::hmacBase64($id, Settings::getHashSalt() . \Drupal::service('private_key')->get()))) {
throw new BadRequestHttpException('Invalid contextual ID specified.');
}
$element = [
'#type' => 'contextual_links',
'#contextual_links' => _contextual_id_to_links($id),
@@ -2,6 +2,8 @@
namespace Drupal\contextual\Element;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Site\Settings;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Render\Element\RenderElement;
use Drupal\Component\Render\FormattableMarkup;
@@ -43,7 +45,12 @@ class ContextualLinksPlaceholder extends RenderElement {
* @see _contextual_links_to_id()
*/
public static function preRenderPlaceholder(array $element) {
$element['#markup'] = new FormattableMarkup('<div@attributes></div>', ['@attributes' => new Attribute(['data-contextual-id' => $element['#id']])]);
$token = Crypt::hmacBase64($element['#id'], Settings::getHashSalt() . \Drupal::service('private_key')->get());
$attribute = new Attribute([
'data-contextual-id' => $element['#id'],
'data-contextual-token' => $token,
]);
$element['#markup'] = new FormattableMarkup('<div@attributes></div>', ['@attributes' => $attribute]);
return $element;
}
@@ -3,9 +3,10 @@
namespace Drupal\Tests\contextual\Functional;
use Drupal\Component\Serialization\Json;
use Drupal\Component\Utility\Crypt;
use Drupal\Core\Site\Settings;
use Drupal\Core\Url;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Core\Template\Attribute;
use Drupal\Tests\BrowserTestBase;
/**
@@ -140,17 +141,76 @@ class ContextualDynamicContextTest extends BrowserTestBase {
$this->assertRaw('<li class="menu-testcontextual-hidden-manage-edit"><a href="' . base_path() . 'menu-test-contextual/1/edit" class="use-ajax" data-dialog-type="modal" data-is-something>Edit menu - contextual</a></li>');
}
/**
* Tests the contextual placeholder content is protected by a token.
*/
public function testTokenProtection() {
$this->drupalLogin($this->editorUser);
// Create a node that will have a contextual link.
$node1 = $this->drupalCreateNode(['type' => 'article', 'promote' => 1]);
// Now, on the front page, all article nodes should have contextual links
// placeholders, as should the view that contains them.
$id = 'node:node=' . $node1->id() . ':changed=' . $node1->getChangedTime() . '&langcode=en';
// Editor user: can access contextual links and can edit articles.
$this->drupalGet('node');
$this->assertContextualLinkPlaceHolder($id);
$http_client = $this->getHttpClient();
$url = Url::fromRoute('contextual.render', [], [
'query' => [
'_format' => 'json',
'destination' => 'node',
],
])->setAbsolute()->toString();
$response = $http_client->request('POST', $url, [
'cookies' => $this->getSessionCookies(),
'form_params' => ['ids' => [$id], 'tokens' => []],
'http_errors' => FALSE,
]);
$this->assertEquals('400', $response->getStatusCode());
$this->assertContains('No contextual ID tokens specified.', (string) $response->getBody());
$response = $http_client->request('POST', $url, [
'cookies' => $this->getSessionCookies(),
'form_params' => ['ids' => [$id], 'tokens' => ['wrong_token']],
'http_errors' => FALSE,
]);
$this->assertEquals('400', $response->getStatusCode());
$this->assertContains('Invalid contextual ID specified.', (string) $response->getBody());
$response = $http_client->request('POST', $url, [
'cookies' => $this->getSessionCookies(),
'form_params' => ['ids' => [$id], 'tokens' => ['wrong_key' => $this->createContextualIdToken($id)]],
'http_errors' => FALSE,
]);
$this->assertEquals('400', $response->getStatusCode());
$this->assertContains('Invalid contextual ID specified.', (string) $response->getBody());
$response = $http_client->request('POST', $url, [
'cookies' => $this->getSessionCookies(),
'form_params' => ['ids' => [$id], 'tokens' => [$this->createContextualIdToken($id)]],
'http_errors' => FALSE,
]);
$this->assertEquals('200', $response->getStatusCode());
}
/**
* Asserts that a contextual link placeholder with the given id exists.
*
* @param string $id
* A contextual link id.
*
* @return bool
* The result of the assertion.
*/
protected function assertContextualLinkPlaceHolder($id) {
return $this->assertRaw('<div' . new Attribute(['data-contextual-id' => $id]) . '></div>', format_string('Contextual link placeholder with id @id exists.', ['@id' => $id]));
$this->assertSession()->elementAttributeContains(
'css',
'div[data-contextual-id="' . $id . '"]',
'data-contextual-token',
$this->createContextualIdToken($id)
);
}
/**
@@ -158,12 +218,9 @@ class ContextualDynamicContextTest extends BrowserTestBase {
*
* @param string $id
* A contextual link id.
*
* @return bool
* The result of the assertion.
*/
protected function assertNoContextualLinkPlaceHolder($id) {
return $this->assertNoRaw('<div' . new Attribute(['data-contextual-id' => $id]) . '></div>', format_string('Contextual link placeholder with id @id does not exist.', ['@id' => $id]));
$this->assertSession()->elementNotExists('css', 'div[data-contextual-id="' . $id . '"]');
}
/**
@@ -178,6 +235,7 @@ class ContextualDynamicContextTest extends BrowserTestBase {
* The response object.
*/
protected function renderContextualLinks($ids, $current_path) {
$tokens = array_map([$this, 'createContextualIdToken'], $ids);
$http_client = $this->getHttpClient();
$url = Url::fromRoute('contextual.render', [], [
'query' => [
@@ -188,9 +246,22 @@ class ContextualDynamicContextTest extends BrowserTestBase {
return $http_client->request('POST', $this->buildUrl($url), [
'cookies' => $this->getSessionCookies(),
'form_params' => ['ids' => $ids],
'form_params' => ['ids' => $ids, 'tokens' => $tokens],
'http_errors' => FALSE,
]);
}
/**
* Creates a contextual ID token.
*
* @param string $id
* The contextual ID to create a token for.
*
* @return string
* The contextual ID token.
*/
protected function createContextualIdToken($id) {
return Crypt::hmacBase64($id, Settings::getHashSalt() . $this->container->get('private_key')->get());
}
}