diff --git a/core/modules/rest/src/Tests/RESTFileValidationTest.php b/core/modules/rest/src/Tests/RESTFileValidationTest.php index 46e596a..d5507db 100644 --- a/core/modules/rest/src/Tests/RESTFileValidationTest.php +++ b/core/modules/rest/src/Tests/RESTFileValidationTest.php @@ -9,6 +9,8 @@ use Drupal\Component\Serialization\Json; use Drupal\Core\Entity\EntityInterface; +use Drupal\field\Entity\FieldConfig; +use Drupal\field\Entity\FieldStorageConfig; use Drupal\node\Entity\Node; use Drupal\user\RoleInterface; @@ -43,41 +45,67 @@ protected function setUp() { * Tests basic file field validations when attaching to nodes. */ public function testCreateNodeWithFile() { - // Create a test content type that anonymous can post.. - $this->drupalCreateContentType(array('name' => 'Article', 'type' => 'article')); - $type_name = 'article'; - $article_field_name = strtolower($this->randomMachineName()); - $this->createFileField($article_field_name, 'node', $type_name, array('uri_scheme' => 'public'), array('file_extensions' => 'txt')); + // Create a file which should be secret. + + // Create a test entity type that contains the secret file. + $this->drupalCreateContentType(['type' => 'page']); + + // Create a test content type that anonymous can post. + $this->drupalCreateContentType(['type' => 'article']); + $this->createFileField('field_public_file', 'node', 'article', ['uri_scheme' => 'public'], ['file_extensions' => 'txt']); // Enables the REST service for 'node' entity type. $this->enableService('entity:node', 'POST'); - $permissions = array('create article content', 'restful post entity:node'); + $permissions = ['create article content', 'restful post entity:node']; user_role_grant_permissions(RoleInterface::ANONYMOUS_ID, $permissions); - $type_name = 'resttest'; - $resttest_field_name = strtolower($this->randomMachineName()); - $this->createFileField($resttest_field_name, 'node', $type_name, array('uri_scheme' => 'private'), array('file_extensions' => 'pdf')); - $permissions = array('create resttest content'); + // Create a private file and attach it to a node. + $this->createFileField('field_private_file', 'node', 'resttest', ['uri_scheme' => 'private'], ['file_extensions' => 'txt']); + $permissions = ['create resttest content']; $account = $this->drupalCreateUser($permissions); $this->drupalLogin($account); + $private_files = $this->drupalGetTestFiles('text', NULL, FALSE); + $edit = [ + 'title[0][value]' => 'Test private title', + 'files[field_private_file_0]' => drupal_realpath($private_files[0]->uri), + ]; + $this->drupalPostForm('node/add/resttest', $edit, t('Save')); + preg_match('@node/(\d+)@', $this->getUrl(), $matches); + $nid = $matches[1]; + $node = Node::load($nid); $this->drupalLogout(); + $this->drupalGet(file_create_url($private_files[0]->uri)); + $this->assertResponse(403); + // Verify that anonymous user file uploads fail when invalid. - //// Populate some entity properties before creating the entity. - $entity_values = array('title' => $this->randomString(), 'type' => 'article'); - $entity = Node::create($entity_values); + // Populate some entity properties before creating the entity. + $entity = Node::create([ + 'title' => $this->randomString(), + 'type' => 'article' + ]); - // Verify that user cannot create content when trying to write to fields - // where it is not possible. + // Verify that user cannot create content when trying to write to fields + // where it is not possible. $serialized = $this->serializer->serialize($entity, $this->defaultFormat, ['account' => $account]); $this->httpRequest('entity/node', 'POST', $serialized, $this->defaultMimeType); $this->assertResponse(403); // Remove fields where non-administrative users cannot write. $entity = $this->removeNodeFieldsForNonAdminUsers($entity); + $serialized = $this->serializer->serialize($entity, $this->defaultFormat, ['account' => $account]); + $this->httpRequest('entity/node', 'POST', $serialized, $this->defaultMimeType); + $this->assertResponse(201); + // The user should not be able to attach the private file. + $entity = $entity->createDuplicate(); + $entity->field_public_file->target_id = $node->field_private_file->target_id; $serialized = $this->serializer->serialize($entity, $this->defaultFormat, ['account' => $account]); + $this->httpRequest('entity/node', 'POST', $serialized, $this->defaultMimeType); + $this->assertResponse(403); + $this->drupalGet(file_create_url($private_files[0]->uri)); + $this->assertResponse(403); } /** @@ -98,14 +126,14 @@ public function testCreateNodeWithFile() { * * @return \Drupal\Core\Entity\EntityInterface */ - function createFileField($name, $entity_type, $bundle, $storage_settings = array(), $field_settings = array(), $widget_settings = array()) { - $field_storage = entity_create('field_storage_config', array( + function createFileField($name, $entity_type, $bundle, $storage_settings = [], $field_settings = [], $widget_settings = []) { + $field_storage = FieldStorageConfig::create([ 'entity_type' => $entity_type, 'field_name' => $name, 'type' => 'file', 'settings' => $storage_settings, 'cardinality' => !empty($storage_settings['cardinality']) ? $storage_settings['cardinality'] : 1, - )); + ]); $field_storage->save(); $this->attachFileField($name, $entity_type, $bundle, $field_settings, $widget_settings); @@ -126,29 +154,28 @@ function createFileField($name, $entity_type, $bundle, $storage_settings = array * @param array $widget_settings * A list of widget settings that will be added to the widget defaults. */ - function attachFileField($name, $entity_type, $bundle, $field_settings = array(), $widget_settings = array()) { - $field = array( + function attachFileField($name, $entity_type, $bundle, $field_settings = [], $widget_settings = []) { + FieldConfig::create([ 'field_name' => $name, 'label' => $name, 'entity_type' => $entity_type, 'bundle' => $bundle, 'required' => !empty($field_settings['required']), 'settings' => $field_settings, - ); - entity_create('field_config', $field)->save(); + ])->save(); entity_get_form_display($entity_type, $bundle, 'default') - ->setComponent($name, array( + ->setComponent($name, [ 'type' => 'file_generic', 'settings' => $widget_settings, - )) + ]) ->save(); // Assign display settings. entity_get_display($entity_type, $bundle, 'default') - ->setComponent($name, array( + ->setComponent($name, [ 'label' => 'hidden', 'type' => 'file_default', - )) + ]) ->save(); } diff --git a/core/modules/simpletest/simpletest.module b/core/modules/simpletest/simpletest.module index 69742cc..e970824 100644 --- a/core/modules/simpletest/simpletest.module +++ b/core/modules/simpletest/simpletest.module @@ -526,11 +526,13 @@ function simpletest_classloader_register() { * the range of 0 to 31. * - binary-text: The generated file contains random sequence of '0' and '1' * values. + * @param bool $public + * (optional) Whether the test files should be public or private. * * @return string * The name of the file, including the path. */ -function simpletest_generate_file($filename, $width, $lines, $type = 'binary-text') { +function simpletest_generate_file($filename, $width, $lines, $type = 'binary-text', $public = TRUE) { $text = ''; for ($i = 0; $i < $lines; $i++) { // Generate $width - 1 characters to leave space for the "\n" character. @@ -552,7 +554,7 @@ function simpletest_generate_file($filename, $width, $lines, $type = 'binary-tex } // Create filename. - file_put_contents('public://' . $filename . '.txt', $text); + file_put_contents(($public ? 'public://' : 'private://') . $filename . '.txt', $text); return $filename; } diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php index 5b62c50..4b3c547 100644 --- a/core/modules/simpletest/src/WebTestBase.php +++ b/core/modules/simpletest/src/WebTestBase.php @@ -27,6 +27,7 @@ use Drupal\Core\Session\AnonymousUserSession; use Drupal\Core\Session\UserSession; use Drupal\Core\Site\Settings; +use Drupal\Core\StreamWrapper\PrivateStream; use Drupal\Core\StreamWrapper\PublicStream; use Drupal\Core\Url; use Drupal\node\Entity\NodeType; @@ -510,27 +511,27 @@ protected function findBlockInstance(Block $block) { * @return * List of files in public:// that match the filter(s). */ - protected function drupalGetTestFiles($type, $size = NULL) { + protected function drupalGetTestFiles($type, $size = NULL, $public = TRUE) { if (empty($this->generatedTestFiles)) { // Generate binary test files. $lines = array(64, 1024); $count = 0; foreach ($lines as $line) { - simpletest_generate_file('binary-' . $count++, 64, $line, 'binary'); + simpletest_generate_file('binary-' . $count++, 64, $line, 'binary', $public); } // Generate ASCII text test files. $lines = array(16, 256, 1024, 2048, 20480); $count = 0; foreach ($lines as $line) { - simpletest_generate_file('text-' . $count++, 64, $line, 'text'); + simpletest_generate_file('text-' . $count++, 64, $line, 'text', $public); } // Copy other test files from simpletest. $original = drupal_get_path('module', 'simpletest') . '/files'; $files = file_scan_directory($original, '/(html|image|javascript|php|sql)-.*/'); foreach ($files as $file) { - file_unmanaged_copy($file->uri, PublicStream::basePath()); + file_unmanaged_copy($file->uri, $public ? PublicStream::basePath() : PrivateStream::basePath()); } $this->generatedTestFiles = TRUE; @@ -539,7 +540,7 @@ protected function drupalGetTestFiles($type, $size = NULL) { $files = array(); // Make sure type is valid. if (in_array($type, array('binary', 'html', 'image', 'javascript', 'php', 'sql', 'text'))) { - $files = file_scan_directory('public://', '/' . $type . '\-.*/'); + $files = file_scan_directory($public ? 'public://' : 'private://', '/' . $type . '\-.*/'); // If size is set then remove any files that are not of that size. if ($size !== NULL) {