Update to Drupal 8.2.2. For more information, see https://www.drupal.org/project/drupal/releases/8.2.2
This commit is contained in:
parent
23ffed3665
commit
507b45a0ed
378 changed files with 11434 additions and 5542 deletions
|
@ -467,6 +467,78 @@ function _editor_delete_file_usage(array $uuids, EntityInterface $entity, $count
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_file_download().
|
||||
*
|
||||
* @see file_file_download()
|
||||
* @see file_get_file_references()
|
||||
*/
|
||||
function editor_file_download($uri) {
|
||||
// Get the file record based on the URI. If not in the database just return.
|
||||
/** @var \Drupal\file\FileInterface[] $files */
|
||||
$files = \Drupal::entityTypeManager()
|
||||
->getStorage('file')
|
||||
->loadByProperties(['uri' => $uri]);
|
||||
if (count($files)) {
|
||||
foreach ($files as $item) {
|
||||
// Since some database servers sometimes use a case-insensitive comparison
|
||||
// by default, double check that the filename is an exact match.
|
||||
if ($item->getFileUri() === $uri) {
|
||||
$file = $item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isset($file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Temporary files are handled by file_file_download(), so nothing to do here
|
||||
// about them.
|
||||
// @see file_file_download()
|
||||
|
||||
// Find out if any editor-backed field contains the file.
|
||||
$usage_list = \Drupal::service('file.usage')->listUsage($file);
|
||||
|
||||
// Stop processing if there are no references in order to avoid returning
|
||||
// headers for files controlled by other modules. Make an exception for
|
||||
// temporary files where the host entity has not yet been saved (for example,
|
||||
// an image preview on a node creation form) in which case, allow download by
|
||||
// the file's owner.
|
||||
if (empty($usage_list['editor']) && ($file->isPermanent() || $file->getOwnerId() != \Drupal::currentUser()->id())) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Editor.module MUST NOT call $file->access() here (like file_file_download()
|
||||
// does) as checking the 'download' access to a file entity would end up in
|
||||
// FileAccessControlHandler->checkAccess() and ->getFileReferences(), which
|
||||
// calls file_get_file_references(). This latter one would allow downloading
|
||||
// files only handled by the file.module, which is exactly not the case right
|
||||
// here. So instead we must check if the current user is allowed to view any
|
||||
// of the entities that reference the image using the 'editor' module.
|
||||
if ($file->isPermanent()) {
|
||||
$referencing_entity_is_accessible = FALSE;
|
||||
$references = empty($usage_list['editor']) ? [] : $usage_list['editor'];
|
||||
foreach ($references as $entity_type => $entity_ids) {
|
||||
$referencing_entities = entity_load_multiple($entity_type, $entity_ids);
|
||||
/** @var \Drupal\Core\Entity\EntityInterface $referencing_entity */
|
||||
foreach ($referencing_entities as $referencing_entity) {
|
||||
if ($referencing_entity->access('view', NULL, TRUE)->isAllowed()) {
|
||||
$referencing_entity_is_accessible = TRUE;
|
||||
break 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$referencing_entity_is_accessible) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// Access is granted.
|
||||
$headers = file_get_content_headers($file);
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all files referenced (data-entity-uuid) by formatted text fields.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
<?php
|
||||
|
||||
namespace Drupal\editor\Tests;
|
||||
|
||||
use Drupal\file\Entity\File;
|
||||
use Drupal\Tests\BrowserTestBase;
|
||||
use Drupal\user\Entity\Role;
|
||||
use Drupal\user\RoleInterface;
|
||||
|
||||
/**
|
||||
* Tests Editor module's file reference filter with private files.
|
||||
*
|
||||
* @group editor
|
||||
*/
|
||||
class EditorPrivateFileReferenceFilterTest extends BrowserTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = [
|
||||
// Needed for the config: this is the only module in core that utilizes the
|
||||
// functionality in editor.module to be tested, and depends on that.
|
||||
'ckeditor',
|
||||
// Depends on filter.module (indirectly).
|
||||
'node',
|
||||
// Pulls in the config we're using during testing which create a text format
|
||||
// - with the filter_html_image_secure filter DISABLED,
|
||||
// - with the editor set to CKEditor,
|
||||
// - with drupalimage.image_upload.scheme set to 'private',
|
||||
// - with drupalimage.image_upload.directory set to ''.
|
||||
'editor_private_test',
|
||||
];
|
||||
|
||||
/**
|
||||
* Tests the editor file reference filter with private files.
|
||||
*/
|
||||
function testEditorPrivateFileReferenceFilter() {
|
||||
$author = $this->drupalCreateUser();
|
||||
$this->drupalLogin($author);
|
||||
|
||||
// Create a content type with a body field.
|
||||
$this->drupalCreateContentType(['type' => 'page', 'name' => 'Basic page']);
|
||||
|
||||
// Create a file in the 'private:// ' stream.
|
||||
$filename = 'test.png';
|
||||
$src = '/system/files/' . $filename;
|
||||
/** @var \Drupal\file\FileInterface $file */
|
||||
$file = File::create([
|
||||
'uri' => 'private://' . $filename,
|
||||
]);
|
||||
$file->setTemporary();
|
||||
$file->setOwner($author);
|
||||
// Create the file itself.
|
||||
file_put_contents($file->getFileUri(), $this->randomString());
|
||||
$file->save();
|
||||
|
||||
// The image should be visible for its author.
|
||||
$this->drupalGet($src);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
// The not-yet-permanent image should NOT be visible for anonymous.
|
||||
$this->drupalLogout();
|
||||
$this->drupalGet($src);
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
|
||||
// Resave the file to be permanent.
|
||||
$file->setPermanent();
|
||||
$file->save();
|
||||
|
||||
// Create a node with its body field properly pointing to the just-created
|
||||
// file.
|
||||
$node = $this->drupalCreateNode([
|
||||
'type' => 'page',
|
||||
'body' => [
|
||||
'value' => '<img alt="alt" data-entity-type="file" data-entity-uuid="' . $file->uuid() . '" src="' . $src . '" />',
|
||||
'format' => 'private_images',
|
||||
],
|
||||
'uid' => $author->id(),
|
||||
]);
|
||||
|
||||
// Do the actual test. The image should be visible for anonymous users,
|
||||
// because they can view the referencing entity.
|
||||
$this->drupalGet($node->toUrl());
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
$this->drupalGet($src);
|
||||
$this->assertSession()->statusCodeEquals(200);
|
||||
|
||||
// Disallow anonymous users to view the entity, which then should also
|
||||
// disallow them to view the image.
|
||||
Role::load(RoleInterface::ANONYMOUS_ID)
|
||||
->revokePermission('access content')
|
||||
->save();
|
||||
$this->drupalGet($node->toUrl());
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
$this->drupalGet($src);
|
||||
$this->assertSession()->statusCodeEquals(403);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
format: private_images
|
||||
status: true
|
||||
langcode: en
|
||||
editor: ckeditor
|
||||
settings:
|
||||
toolbar:
|
||||
rows:
|
||||
-
|
||||
-
|
||||
name: Media
|
||||
items:
|
||||
- DrupalImage
|
||||
-
|
||||
name: Tools
|
||||
items:
|
||||
- Source
|
||||
plugins:
|
||||
language:
|
||||
language_list: un
|
||||
stylescombo:
|
||||
styles: ''
|
||||
image_upload:
|
||||
status: true
|
||||
scheme: private
|
||||
directory: ''
|
||||
max_size: ''
|
||||
max_dimensions:
|
||||
width: null
|
||||
height: null
|
||||
dependencies:
|
||||
config:
|
||||
- filter.format.private_images
|
||||
module:
|
||||
- ckeditor
|
|
@ -0,0 +1,23 @@
|
|||
format: private_images
|
||||
name: 'Private images'
|
||||
status: true
|
||||
langcode: en
|
||||
filters:
|
||||
editor_file_reference:
|
||||
id: editor_file_reference
|
||||
provider: editor
|
||||
status: true
|
||||
weight: 0
|
||||
settings: { }
|
||||
filter_html:
|
||||
id: filter_html
|
||||
provider: filter
|
||||
status: false
|
||||
weight: -10
|
||||
settings:
|
||||
allowed_html: '<img src alt data-entity-type data-entity-uuid>'
|
||||
filter_html_help: true
|
||||
filter_html_nofollow: false
|
||||
dependencies:
|
||||
module:
|
||||
- editor
|
|
@ -0,0 +1,9 @@
|
|||
name: 'Text Editor Private test'
|
||||
type: module
|
||||
description: 'Support module for the Text Editor Private module tests.'
|
||||
core: 8.x
|
||||
package: Testing
|
||||
version: VERSION
|
||||
dependencies:
|
||||
- filter
|
||||
- ckeditor
|
Reference in a new issue