Skip to content

Commit ba2b781

Browse files
committed
SA-CORE-2021-008 by klausi, xjm, larowlan, alexpott, samuel.mortenson, mcdruid, kim.pepper
1 parent 6359b3e commit ba2b781

File tree

2 files changed

+64
-9
lines changed

2 files changed

+64
-9
lines changed

modules/file/src/Plugin/rest/resource/FileUploadResource.php

+24-4
Original file line numberDiff line numberDiff line change
@@ -255,15 +255,27 @@ public function post(Request $request, $entity_type_id, $bundle, $field_name) {
255255
$file->setOwnerId($this->currentUser->id());
256256
$file->setFilename($prepared_filename);
257257
$file->setMimeType($this->mimeTypeGuesser->guess($prepared_filename));
258-
$file->setFileUri($file_uri);
258+
$file->setFileUri($temp_file_path);
259259
// Set the size. This is done in File::preSave() but we validate the file
260260
// before it is saved.
261261
$file->setSize(@filesize($temp_file_path));
262262

263-
// Validate the file entity against entity-level validation and field-level
264-
// validators.
265-
$this->validate($file, $validators);
263+
// Validate the file against field-level validators first while the file is
264+
// still a temporary file. Validation is split up in 2 steps to be the same
265+
// as in _file_save_upload_single().
266+
// For backwards compatibility this part is copied from ::validate() to
267+
// leave that method behavior unchanged.
268+
// @todo Improve this with a file uploader service in
269+
// https://www.drupal.org/project/drupal/issues/2940383
270+
$errors = file_validate($file, $validators);
266271

272+
if (!empty($errors)) {
273+
$message = "Unprocessable Entity: file validation failed.\n";
274+
$message .= implode("\n", array_map([PlainTextOutput::class, 'renderFromHtml'], $errors));
275+
throw new UnprocessableEntityHttpException($message);
276+
}
277+
278+
$file->setFileUri($file_uri);
267279
// Move the file to the correct location after validation. Use
268280
// FileSystemInterface::EXISTS_ERROR as the file location has already been
269281
// determined above in FileSystem::getDestinationFilename().
@@ -274,6 +286,9 @@ public function post(Request $request, $entity_type_id, $bundle, $field_name) {
274286
throw new HttpException(500, 'Temporary file could not be moved to file location');
275287
}
276288

289+
// Second step of the validation on the file object itself now.
290+
$this->resourceValidate($file);
291+
277292
$file->save();
278293

279294
$this->lock->release($lock_id);
@@ -426,6 +441,11 @@ protected function validateAndLoadFieldDefinition($entity_type_id, $bundle, $fie
426441
/**
427442
* Validates the file.
428443
*
444+
* @todo this method is unused in this class because file validation needs to
445+
* be split up in 2 steps in ::post(). Add a deprecation notice as soon as a
446+
* central core file upload service can be used in this class.
447+
* See https://www.drupal.org/project/drupal/issues/2940383
448+
*
429449
* @param \Drupal\file\FileInterface $file
430450
* The file entity to validate.
431451
* @param array $validators

modules/jsonapi/src/Controller/TemporaryJsonapiFileFieldUploader.php

+40-5
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Drupal\Core\Session\AccountInterface;
1919
use Drupal\Core\Utility\Token;
2020
use Drupal\Component\Render\PlainTextOutput;
21+
use Drupal\Core\Entity\EntityConstraintViolationList;
2122
use Drupal\file\Entity\File;
2223
use Drupal\file\Plugin\Field\FieldType\FileFieldItemList;
2324
use Psr\Log\LoggerInterface;
@@ -174,18 +175,37 @@ public function handleFileUploadForField(FieldDefinitionInterface $field_definit
174175
$file->setOwnerId($owner->id());
175176
$file->setFilename($prepared_filename);
176177
$file->setMimeType($this->mimeTypeGuesser->guess($prepared_filename));
177-
$file->setFileUri($file_uri);
178+
$file->setFileUri($temp_file_path);
178179
// Set the size. This is done in File::preSave() but we validate the file
179180
// before it is saved.
180181
$file->setSize(@filesize($temp_file_path));
181182

182-
// Validate the file entity against entity-level validation and field-level
183-
// validators.
184-
$violations = $this->validate($file, $validators);
185-
if ($violations->count() > 0) {
183+
// Validate the file against field-level validators first while the file is
184+
// still a temporary file. Validation is split up in 2 steps to be the same
185+
// as in _file_save_upload_single().
186+
// For backwards compatibility this part is copied from ::validate() to
187+
// leave that method behavior unchanged.
188+
// @todo Improve this with a file uploader service in
189+
// https://www.drupal.org/project/drupal/issues/2940383
190+
$errors = file_validate($file, $validators);
191+
if (!empty($errors)) {
192+
$violations = new EntityConstraintViolationList($file);
193+
$translator = new DrupalTranslator();
194+
$entity = EntityAdapter::createFromEntity($file);
195+
foreach ($errors as $error) {
196+
$violation = new ConstraintViolation($translator->trans($error),
197+
$error,
198+
[],
199+
$entity,
200+
'',
201+
NULL
202+
);
203+
$violations->add($violation);
204+
}
186205
return $violations;
187206
}
188207

208+
$file->setFileUri($file_uri);
189209
// Move the file to the correct location after validation. Use
190210
// FileSystemInterface::EXISTS_ERROR as the file location has already been
191211
// determined above in FileSystem::getDestinationFilename().
@@ -196,6 +216,16 @@ public function handleFileUploadForField(FieldDefinitionInterface $field_definit
196216
throw new HttpException(500, 'Temporary file could not be moved to file location');
197217
}
198218

219+
// Second step of the validation on the file object itself now.
220+
$violations = $file->validate();
221+
222+
// Remove violations of inaccessible fields as they cannot stem from our
223+
// changes.
224+
$violations->filterByFieldAccess();
225+
if ($violations->count() > 0) {
226+
return $violations;
227+
}
228+
199229
$file->save();
200230

201231
$this->lock->release($lock_id);
@@ -334,6 +364,11 @@ protected function streamUploadData() {
334364
/**
335365
* Validates the file.
336366
*
367+
* @todo this method is unused in this class because file validation needs to
368+
* be split up in 2 steps in ::handleFileUploadForField(). Add a deprecation
369+
* notice as soon as a central core file upload service can be used in this
370+
* class. See https://www.drupal.org/project/drupal/issues/2940383
371+
*
337372
* @param \Drupal\file\FileInterface $file
338373
* The file entity to validate.
339374
* @param array $validators

0 commit comments

Comments
 (0)