diff --git a/composer.json b/composer.json index d4d04a003069a298a1438770906278b8bec5b1ec..30e32b85a7003a8a43db8475194b946c3fbe097c 100644 --- a/composer.json +++ b/composer.json @@ -111,7 +111,7 @@ "drupal/ctools": "3.7", "drupal/dropzonejs": "2.6", "drupal/editor_advanced_link": "1.9", - "drupal/embed": "1.4", + "drupal/embed": "1.5", "drupal/entity": "1.2", "drupal/entity_browser": "2.6", "drupal/entity_clone": "1.0.0-beta5", diff --git a/composer.lock b/composer.lock index b8234fb54d1456041b0aa0aaccb747714c43da2d..e73c7874e1b7b89dc255ead77c22c667d09db7e8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fd7b3eb06f5fdb84f21d52eb13948e13", + "content-hash": "4d692bfd0abd7ce37d05150a17a6ccc3", "packages": [ { "name": "alchemy/zippy", @@ -3706,17 +3706,17 @@ }, { "name": "drupal/embed", - "version": "1.4.0", + "version": "1.5.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/embed.git", - "reference": "8.x-1.4" + "reference": "8.x-1.5" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/embed-8.x-1.4.zip", - "reference": "8.x-1.4", - "shasum": "09a2bda039bfbb3fff01c91964384bf3d924b8c5" + "url": "https://ftp.drupal.org/files/projects/embed-8.x-1.5.zip", + "reference": "8.x-1.5", + "shasum": "88a447329d16988459e82392443e96d441d651b2" }, "require": { "drupal/core": "^8.7.7 || ^9" @@ -3724,8 +3724,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.4", - "datestamp": "1590176831", + "version": "8.x-1.5", + "datestamp": "1653500382", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json index fa42a73416296dc96a48a18ee42be0c3fafe8f3e..2a308be898607272a7c7feda305a04e2d7deccaa 100644 --- a/vendor/composer/installed.json +++ b/vendor/composer/installed.json @@ -3815,18 +3815,18 @@ }, { "name": "drupal/embed", - "version": "1.4.0", - "version_normalized": "1.4.0.0", + "version": "1.5.0", + "version_normalized": "1.5.0.0", "source": { "type": "git", "url": "https://git.drupalcode.org/project/embed.git", - "reference": "8.x-1.4" + "reference": "8.x-1.5" }, "dist": { "type": "zip", - "url": "https://ftp.drupal.org/files/projects/embed-8.x-1.4.zip", - "reference": "8.x-1.4", - "shasum": "09a2bda039bfbb3fff01c91964384bf3d924b8c5" + "url": "https://ftp.drupal.org/files/projects/embed-8.x-1.5.zip", + "reference": "8.x-1.5", + "shasum": "88a447329d16988459e82392443e96d441d651b2" }, "require": { "drupal/core": "^8.7.7 || ^9" @@ -3834,8 +3834,8 @@ "type": "drupal-module", "extra": { "drupal": { - "version": "8.x-1.4", - "datestamp": "1590176831", + "version": "8.x-1.5", + "datestamp": "1653500382", "security-coverage": { "status": "covered", "message": "Covered by Drupal's security advisory policy" diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php index fc0123ccd881c500c014bac89ad1fad6b4498d71..6747ed7fa5cd13cc49e2ddab66cee3f0eb21aa67 100644 --- a/vendor/composer/installed.php +++ b/vendor/composer/installed.php @@ -5,7 +5,7 @@ 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => '23979be14f23e4b071f4479471ad8168d4d4756c', + 'reference' => '1784cbbe082a76726d14fa068153b49c93796384', 'name' => 'osu-asc-webservices/d8-upstream', 'dev' => true, ), @@ -857,12 +857,12 @@ 'dev_requirement' => false, ), 'drupal/embed' => array( - 'pretty_version' => '1.4.0', - 'version' => '1.4.0.0', + 'pretty_version' => '1.5.0', + 'version' => '1.5.0.0', 'type' => 'drupal-module', 'install_path' => __DIR__ . '/../../web/modules/embed', 'aliases' => array(), - 'reference' => '8.x-1.4', + 'reference' => '8.x-1.5', 'dev_requirement' => false, ), 'drupal/entity' => array( @@ -2101,7 +2101,7 @@ 'type' => 'project', 'install_path' => __DIR__ . '/../../', 'aliases' => array(), - 'reference' => '23979be14f23e4b071f4479471ad8168d4d4756c', + 'reference' => '1784cbbe082a76726d14fa068153b49c93796384', 'dev_requirement' => false, ), 'pantheon-systems/quicksilver-pushback' => array( diff --git a/web/modules/embed/embed.info.yml b/web/modules/embed/embed.info.yml index 5a710757321cb0123218a69763a27ee53417b1b0..5917bad1f894b5923741f3c6b3ed1660eb2df551 100644 --- a/web/modules/embed/embed.info.yml +++ b/web/modules/embed/embed.info.yml @@ -4,7 +4,7 @@ description: 'Provides a framework for different types of embeds in text editors core_version_requirement: ^8.7.7 || ^9 configure: entity.embed_button.collection -# Information added by Drupal.org packaging script on 2020-05-22 -version: '8.x-1.4' +# Information added by Drupal.org packaging script on 2022-05-25 +version: '8.x-1.5' project: 'embed' -datestamp: 1590176834 +datestamp: 1653494372 diff --git a/web/modules/embed/js/embed.js b/web/modules/embed/js/embed.js index 683b8a244ef3823427b122c57be5faf2e04438af..0d896dfa140d3f5d1c2f7b614a473d9a2cc57b78 100644 --- a/web/modules/embed/js/embed.js +++ b/web/modules/embed/js/embed.js @@ -68,5 +68,4 @@ }; - })(jQuery, Drupal); diff --git a/web/modules/embed/src/Access/EmbedButtonEditorAccessCheck.php b/web/modules/embed/src/Access/EmbedButtonEditorAccessCheck.php index 70fc5f4aea2db300956fb6ea95304ee3382dc428..01463b6ce716500a5980ac8146c5a7f07860eda6 100644 --- a/web/modules/embed/src/Access/EmbedButtonEditorAccessCheck.php +++ b/web/modules/embed/src/Access/EmbedButtonEditorAccessCheck.php @@ -10,6 +10,9 @@ use Drupal\embed\EmbedButtonInterface; use Symfony\Component\HttpKernel\Exception\HttpException; +/** + * Routing requirement access check for embed buttons and text editors. + */ class EmbedButtonEditorAccessCheck implements AccessInterface { /** diff --git a/web/modules/embed/src/Controller/EmbedController.php b/web/modules/embed/src/Controller/EmbedController.php index 42c6009368e25a86c5e50d5ff51b7a5cc4b1161f..23088a4710ffb4a47b252a21363c07fb9fae946a 100644 --- a/web/modules/embed/src/Controller/EmbedController.php +++ b/web/modules/embed/src/Controller/EmbedController.php @@ -7,6 +7,7 @@ use Drupal\Core\Controller\ControllerBase; use Drupal\Core\Language\LanguageInterface; use Drupal\Core\Render\RendererInterface; +use Drupal\Core\Session\AccountInterface; use Drupal\editor\EditorInterface; use Drupal\embed\Ajax\EmbedInsertCommand; use Drupal\embed\EmbedButtonInterface; @@ -14,6 +15,7 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -52,7 +54,7 @@ public static function create(ContainerInterface $container) { /** * Returns an Ajax response to generate preview of embedded items. * - * Expects the the HTML element as GET parameter. + * Expects the HTML element as GET parameter. * * @param \Symfony\Component\HttpFoundation\Request $request * The request object. @@ -66,6 +68,8 @@ public static function create(ContainerInterface $container) { * The preview of the embedded item specified by the data attributes. */ public function preview(Request $request, FilterFormatInterface $filter_format) { + self::checkCsrf($request, \Drupal::currentUser()); + $text = $request->get('text') ?: $request->get('value'); if (empty($text)) { throw new NotFoundHttpException(); @@ -101,7 +105,7 @@ public function preview(Request $request, FilterFormatInterface $filter_format) /** * Returns an Ajax response to generate preview of an entity. * - * Expects the the HTML element as GET parameter. + * Expects the HTML element as GET parameter. * * @param \Symfony\Component\HttpFoundation\Request $request * The request object. @@ -120,4 +124,30 @@ public function previewEditor(Request $request, EditorInterface $editor, EmbedBu return $this->preview($request, $editor->getFilterFormat()); } + /** + * Throws an AccessDeniedHttpException if the request fails CSRF validation. + * + * This is used instead of \Drupal\Core\Access\CsrfAccessCheck, in order to + * allow access for anonymous users. + * + * @todo Refactor this to an access checker. + */ + private static function checkCsrf(Request $request, AccountInterface $account) { + $header = 'X-Drupal-EmbedPreview-CSRF-Token'; + + if (!$request->headers->has($header)) { + throw new AccessDeniedHttpException(); + } + if ($account->isAnonymous()) { + // For anonymous users, just the presence of the custom header is + // sufficient protection. + return; + } + // For authenticated users, validate the token value. + $token = $request->headers->get($header); + if (!\Drupal::csrfToken()->validate($token, $header)) { + throw new AccessDeniedHttpException(); + } + } + } diff --git a/web/modules/embed/src/EmbedButtonInterface.php b/web/modules/embed/src/EmbedButtonInterface.php index 907c213e81ad7cf8dad18c4481d4c23798f7e407..8e81c22b52887d7cd2b13692f9497dafc3a4aa3b 100644 --- a/web/modules/embed/src/EmbedButtonInterface.php +++ b/web/modules/embed/src/EmbedButtonInterface.php @@ -60,8 +60,10 @@ public function getTypeSettings(); * @return \Drupal\file\FileInterface * The file entity of the button icon. * - * @deprecated in embed:1.2 and will be removed in embed:1.3. Use + * @deprecated in embed:8.x-1.2 and is removed from embed:2.0.0. Use * \Drupal\embed\EmbedButtonInterface::getIconUrl() instead. + * + * @see https://www.drupal.org/project/embed/issues/3039598 */ public function getIconFile(); diff --git a/web/modules/embed/src/Entity/EmbedButton.php b/web/modules/embed/src/Entity/EmbedButton.php index 7a653095ffdff6d18ddaacd81ca6849de1e67eda..26aa9bd79ad04fa09f23b406e149d9cd0eae9251 100644 --- a/web/modules/embed/src/Entity/EmbedButton.php +++ b/web/modules/embed/src/Entity/EmbedButton.php @@ -114,7 +114,7 @@ public function getTypePlugin() { * {@inheritdoc} */ public function getIconFile() { - @trigger_error(__METHOD__ . ' is deprecated in Embed 1.2 and will be removed before 1.3.', E_USER_DEPRECATED); + @trigger_error(__METHOD__ . ' is deprecated in embed:8.x-1.2 and will be removed in embed:2.0.0. Use \Drupal\embed\Entity\EmbedButton::getIconUrl instead. See https://www.drupal.org/node/3139211', E_USER_DEPRECATED); if (!empty($this->icon_uuid)) { $files = $this->entityTypeManager()->getStorage('file')->loadByProperties(['uuid' => $this->icon_uuid]); return reset($files); diff --git a/web/modules/embed/src/Form/EmbedSettingsForm.php b/web/modules/embed/src/Form/EmbedSettingsForm.php index 4cc7ef841c8ac09714ceb8b223cc142d50b7c694..a090db8b3117745428a20a3bee7fec58f24d804e 100644 --- a/web/modules/embed/src/Form/EmbedSettingsForm.php +++ b/web/modules/embed/src/Form/EmbedSettingsForm.php @@ -38,7 +38,7 @@ public function __construct(ConfigFactoryInterface $config_factory, StreamWrappe * {@inheritdoc} */ public static function create(ContainerInterface $container) { - return new static ( + return new static( $container->get('config.factory'), $container->get('stream_wrapper_manager') ); @@ -88,8 +88,8 @@ public function buildForm(array $form, FormStateInterface $form_state) { * Form API callback. * * Removes slashes from the beginning and end of the destination value and - * ensures that the file directory path is not included at the beginning of the - * value. + * ensures that the file directory path is not included at the beginning of + * the value. * * This function is assigned as an #element_validate callback in * fieldSettingsForm(). diff --git a/web/modules/embed/tests/embed_test/embed_test.info.yml b/web/modules/embed/tests/embed_test/embed_test.info.yml index 2aeb758413f31e1a901b020e2c153fbe8d6b60ca..43dbb8e325862e3ccf0d3abb17ebce437d6b4356 100644 --- a/web/modules/embed/tests/embed_test/embed_test.info.yml +++ b/web/modules/embed/tests/embed_test/embed_test.info.yml @@ -8,7 +8,7 @@ dependencies: - embed - node -# Information added by Drupal.org packaging script on 2020-05-22 -version: '8.x-1.4' +# Information added by Drupal.org packaging script on 2022-05-25 +version: '8.x-1.5' project: 'embed' -datestamp: 1590176834 +datestamp: 1653494372 diff --git a/web/modules/embed/tests/embed_test/embed_test.routing.yml b/web/modules/embed/tests/embed_test/embed_test.routing.yml index e03db02edb4d25fa93c63f7e18b416c2cd533251..0fc900ed3d568387bdb2d12f18e1511070789530 100644 --- a/web/modules/embed/tests/embed_test/embed_test.routing.yml +++ b/web/modules/embed/tests/embed_test/embed_test.routing.yml @@ -4,3 +4,9 @@ embed_test.test_access: _controller: '\Drupal\embed_test\Controller\EmbedTestController::testAccess' requirements: _embed_button_editor_access: 'TRUE' +embed_test_csrf.csrftoken: + path: '/embed-test/get_csrf_token' + defaults: + _controller: '\Drupal\embed_test\Controller\EmbedTestController::getCsrfToken' + requirements: + _access: 'TRUE' diff --git a/web/modules/embed/tests/embed_test/src/Controller/EmbedTestController.php b/web/modules/embed/tests/embed_test/src/Controller/EmbedTestController.php index e19a960e3bdc5452e2ccb8973090761af31e2252..d88bd092fa53726c73b82df257a9df0c1a43ee6a 100644 --- a/web/modules/embed/tests/embed_test/src/Controller/EmbedTestController.php +++ b/web/modules/embed/tests/embed_test/src/Controller/EmbedTestController.php @@ -6,6 +6,7 @@ use Drupal\Core\Render\HtmlResponse; use Drupal\editor\EditorInterface; use Drupal\embed\EmbedButtonInterface; +use Symfony\Component\HttpFoundation\JsonResponse; use Symfony\Component\HttpFoundation\Request; /** @@ -30,4 +31,14 @@ public function testAccess(Request $request, EditorInterface $editor, EmbedButto return $response; } + /** + * Return CSRF token. + * + * @return \Symfony\Component\HttpFoundation\Response + * CSRF token. + */ + public function getCsrfToken() { + return new JsonResponse(\Drupal::csrfToken()->get('X-Drupal-EmbedPreview-CSRF-Token')); + } + } diff --git a/web/modules/embed/tests/embed_test/src/Plugin/EmbedType/EmbedTestDefault.php b/web/modules/embed/tests/embed_test/src/Plugin/EmbedType/EmbedTestDefault.php index 00f7bb8e2f037e8413f872b9e7ecb5c50a428668..ee5660cac52c6fb6cbfa4ff9d2e785f498cc0383 100644 --- a/web/modules/embed/tests/embed_test/src/Plugin/EmbedType/EmbedTestDefault.php +++ b/web/modules/embed/tests/embed_test/src/Plugin/EmbedType/EmbedTestDefault.php @@ -1,10 +1,5 @@ <?php -/** - * @file - * Contains \Drupal\embed_test\Plugin\EmbedType\EmbedTestDefault. - */ - namespace Drupal\embed_test\Plugin\EmbedType; use Drupal\embed\EmbedType\EmbedTypeBase; diff --git a/web/modules/embed/tests/src/Functional/EmbedPreviewTest.php b/web/modules/embed/tests/src/Functional/EmbedPreviewTest.php index bf2e581b93f28342a38949333bb1eff37bd58d21..9511d775fcee47bfda480c8b78dda6e3953c2862 100644 --- a/web/modules/embed/tests/src/Functional/EmbedPreviewTest.php +++ b/web/modules/embed/tests/src/Functional/EmbedPreviewTest.php @@ -62,6 +62,20 @@ public function testPreview() { ], ]); + $this->assertSession()->statusCodeEquals(403); + + // Now test with a CSRF token + $this->drupalGet('embed-test/get_csrf_token'); + $token = json_decode($this->getSession()->getPage()->getContent()); + $headers = ['X-Drupal-EmbedPreview-CSRF-Token' => $token]; + + $response = $this->drupalGet('/embed/preview/foo', [ + 'query' => [ + 'value' => 'node:' . $node->id(), + '_wrapper_format' => 'drupal_ajax', + ], + ], $headers); + $this->assertSession()->statusCodeEquals(200); // Assert the presence of commands to add out-of-band assets to the page, as diff --git a/web/modules/embed/tests/src/Functional/EmbedTestBase.php b/web/modules/embed/tests/src/Functional/EmbedTestBase.php index 17f990a3c46510d4802de2332e3fc716b56a3b4e..8999e1222b3eb47e3f50e2740fa69f5f2dc85211 100644 --- a/web/modules/embed/tests/src/Functional/EmbedTestBase.php +++ b/web/modules/embed/tests/src/Functional/EmbedTestBase.php @@ -28,6 +28,11 @@ abstract class EmbedTestBase extends BrowserTestBase { 'ckeditor', ]; + /** + * {@inheritdoc} + */ + protected $defaultTheme = 'stark'; + /** * The test administrative user. * @@ -93,11 +98,21 @@ protected function setUp() { /** * Retrieves a sample file of the specified type. * + * @param string $type + * File type, possible values: 'binary', 'html', 'image', 'javascript', + * 'php', 'sql', 'text'. + * @param int $size + * (optional) File size in bytes to match. Defaults to NULL, which will not + * filter the returned list by size. + * * @return \Drupal\file\FileInterface + * The file entity. + * + * @see \Drupal\Tests\TestFileCreationTrait::getTestFiles() */ - protected function getTestFile($type_name, $size = NULL) { + protected function getTestFile($type, $size = NULL) { // Get a file to upload. - $file = current($this->getTestFiles($type_name, $size)); + $file = current($this->getTestFiles($type, $size)); // Add a filesize property to files as would be read by // \Drupal\file\Entity\File::load(). diff --git a/web/modules/embed/tests/src/Functional/PreviewTest.php b/web/modules/embed/tests/src/Functional/PreviewTest.php index 1163240327a5239e9afa37e8d1cf78df925136b6..c64ae5d81e6437cb19e363256bb1096d14e829ee 100644 --- a/web/modules/embed/tests/src/Functional/PreviewTest.php +++ b/web/modules/embed/tests/src/Functional/PreviewTest.php @@ -65,7 +65,15 @@ public function getRoute($filter_format_id, $value = NULL) { if (!isset($value)) { $value = static::SUCCESS; } - return $this->drupalGet($url, ['query' => ['text' => $value]]); + if ($this->drupalUserIsLoggedIn($this->webUser)) { + $this->drupalGet('embed-test/get_csrf_token'); + $token = json_decode($this->getSession()->getPage()->getContent()); + } + else { + $token = 'Any value will do for Anonymous'; + } + $headers = ['X-Drupal-EmbedPreview-CSRF-Token' => $token]; + return $this->drupalGet($url, ['query' => ['text' => $value]], $headers); } } diff --git a/web/modules/embed/tests/src/FunctionalJavascript/EmbedButtonAdminTest.php b/web/modules/embed/tests/src/FunctionalJavascript/EmbedButtonAdminTest.php index 767cf43e318f80e431b5ad5c8ad46f898b6db52d..93ef79d1f757bec85f916ed272616437aa5dfa52 100644 --- a/web/modules/embed/tests/src/FunctionalJavascript/EmbedButtonAdminTest.php +++ b/web/modules/embed/tests/src/FunctionalJavascript/EmbedButtonAdminTest.php @@ -113,10 +113,9 @@ public function testEmbedButtonAdmin() { $button_id = strtolower($button_label); $page->fillField('label', $button_label); $this->assertNotEmpty($assert_session->waitForText("Machine name: $button_id")); - $edit = [ - 'type_id' => 'embed_test_default', - ]; - $this->drupalPostForm(NULL, $edit, 'Save'); + $page->selectFieldOption('type_id', 'embed_test_default'); + $assert_session->assertWaitOnAjaxRequest(); + $this->drupalPostForm(NULL, [], 'Save'); // Ensure that the newly created button is listed. $this->drupalGet('admin/config/content/embed'); $assert_session->pageTextContains($button_label);