only in patch2: unchanged: --- /dev/null +++ b/core/modules/file/file.post_update.php @@ -0,0 +1,42 @@ +get('allow_insecure_uploads')) { + return t('The system is configured to allow insecure file uploads. No file field updates are necessary.'); + } + + $updater = function (FieldConfig $field) { + // Determine if this is field uses a item definition that extends FileItem. + if (is_subclass_of($field->getItemDefinition()->getClass(), FileItem::class)) { + $allowed_extensions_string = $field->getSetting('file_extensions'); + $allowed_extensions = array_filter(explode(' ', $allowed_extensions_string)); + if (in_array('txt', $allowed_extensions, TRUE)) { + // .txt is specifically allowed there's nothing to do. + return FALSE; + } + foreach ($allowed_extensions as $extension) { + if (preg_match(FILE_INSECURE_EXTENSION_REGEX, 'test.' . $extension)) { + // Add the txt extension to the list of allowed extensions if an + // insecure is allowed. + $allowed_extensions_string .= ' txt'; + $field->setSetting('file_extensions', $allowed_extensions_string); + return TRUE; + } + } + return FALSE; + } + }; + \Drupal::classResolver(ConfigEntityUpdater::class)->update($sandbox, 'field_config', $updater); +} only in patch2: unchanged: --- a/core/modules/file/src/Plugin/Field/FieldType/FileItem.php +++ b/core/modules/file/src/Plugin/Field/FieldType/FileItem.php @@ -223,14 +223,24 @@ public static function validateDirectory($element, FormStateInterface $form_stat public static function validateExtensions($element, FormStateInterface $form_state) { if (!empty($element['#value'])) { $extensions = preg_replace('/([, ]+\.?)/', ' ', trim(strtolower($element['#value']))); - $extensions = array_filter(explode(' ', $extensions)); - $extensions = implode(' ', array_unique($extensions)); + $extension_array = array_filter(explode(' ', $extensions)); + $extensions = implode(' ', array_unique($extension_array)); if (!preg_match('/^([a-z0-9]+([.][a-z0-9])* ?)+$/', $extensions)) { $form_state->setError($element, t('The list of allowed extensions is not valid, be sure to exclude leading dots and to separate extensions with a comma or space.')); } else { $form_state->setValueForElement($element, $extensions); } + + // If insecure uploads are not allowed then error if txt is not an allowed + // extension. + if (!in_array('txt', $extension_array) && !\Drupal::config('system.file')->get('allow_insecure_uploads')) { + foreach ($extension_array as $extension) { + if (preg_match(FILE_INSECURE_EXTENSION_REGEX, 'test.' . $extension)) { + $form_state->setError($element, t('The extension %extension is insecure. In order to allow it to be uploaded allow the "txt" extension.', ['%extension' => $extension])); + } + } + } } } only in patch2: unchanged: --- a/core/modules/file/tests/src/Functional/SaveUploadFormTest.php +++ b/core/modules/file/tests/src/Functional/SaveUploadFormTest.php @@ -200,7 +200,7 @@ public function testHandleExtension() { } /** - * Tests dangerous file handling. + * Test dangerous file handling. */ public function testHandleDangerousFile() { $config = $this->config('system.file'); @@ -212,7 +212,7 @@ public function testHandleDangerousFile() { 'file_test_replace' => FILE_EXISTS_REPLACE, 'files[file_test_upload][]' => $file_system->realpath($this->phpfile->uri), 'is_image_file' => FALSE, - 'extensions' => 'php', + 'extensions' => 'php txt', ]; $this->drupalPostForm('file-test/save_upload_from_form_test', $edit, t('Submit')); @@ -242,6 +242,24 @@ public function testHandleDangerousFile() { // Turn off insecure uploads. $config->set('allow_insecure_uploads', 0)->save(); + + // Reset the hook counters. + file_test_reset(); + + $edit = [ + 'file_test_replace' => FILE_EXISTS_REPLACE, + 'files[file_test_upload][]' => $file_system->realpath($this->phpfile->uri), + 'is_image_file' => FALSE, + 'extensions' => 'php', + ]; + + $this->drupalPostForm('file-test/save_upload_from_form_test', $edit, t('Submit')); + $this->assertResponse(200, 'Received a 200 response for posted test file.'); + $this->assertSession()->pageTextContains('The file php-2.php could not be uploaded because the extension is insecure.'); + $this->assertSession()->pageTextContains('Epic upload FAIL!'); + + // Check that the correct hooks were called. + $this->assertFileHooksCalled([]); } /**