Commit 6708d691 authored by Giannis Economou's avatar Giannis Economou Committed by Susanne Moog
Browse files

[BUGFIX] Properly escape "dropzone-target" selector in DragUploader.js

We properly escape some characters of "dropzone-target" data attribute,
since it is being used as a CSS selector to insert the dropzone in
our DOM. The "dropzone-target" might contain characters that have a
special meaning in CSS, like for example a dot. Especially the dot
is typical for cases like flexforms fields.

This allows drag and drop file uploads even on such cases (like for
example working drag and drop file uploads in DCE content elements).

Resolves: #81812
Releases: master, 8.7
Change-Id: Ib1f5b5063e390f08436fd3a51978842754b698ef
Reviewed-on: https://review.typo3.org/53416


Tested-by: default avatarTYPO3com <no-reply@typo3.com>
Reviewed-by: Markus Klein's avatarMarkus Klein <markus.klein@typo3.org>
Tested-by: Markus Klein's avatarMarkus Klein <markus.klein@typo3.org>
Reviewed-by: Susanne Moog's avatarSusanne Moog <susanne.moog@typo3.org>
Tested-by: Susanne Moog's avatarSusanne Moog <susanne.moog@typo3.org>
parent bffeb737
......@@ -25,6 +25,7 @@ use TYPO3\CMS\Core\Resource\Folder;
use TYPO3\CMS\Core\Resource\OnlineMedia\Helpers\OnlineMediaHelperRegistry;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Core\Utility\MathUtility;
use TYPO3\CMS\Core\Utility\StringUtility;
/**
* Inline element entry container.
......@@ -438,8 +439,9 @@ class InlineControlContainer extends AbstractContainer
$foreign_table = $inlineConfiguration['foreign_table'];
$allowed = $groupFieldConfiguration['allowed'];
$objectPrefix = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']) . '-' . $foreign_table;
$nameObject = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']);
$currentStructureDomObjectIdPrefix = $this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid']);
$objectPrefix = $currentStructureDomObjectIdPrefix . '-' . $foreign_table;
$nameObject = $currentStructureDomObjectIdPrefix;
$mode = 'db';
$showUpload = false;
$elementBrowserEnabled = true;
......@@ -501,7 +503,7 @@ class InlineControlContainer extends AbstractContainer
$maxFileSize = GeneralUtility::getMaxUploadFileSize() * 1024;
$item .= ' <a href="#" class="btn btn-default t3js-drag-uploader inlineNewFileUploadButton ' . $this->inlineData['config'][$nameObject]['md5'] . '"
' . $buttonStyle . '
data-dropzone-target="#' . htmlspecialchars($this->inlineStackProcessor->getCurrentStructureDomObjectIdPrefix($this->data['inlineFirstPid'])) . '"
data-dropzone-target="#' . htmlspecialchars(StringUtility::escapeCssSelector($currentStructureDomObjectIdPrefix)) . '"
data-insert-dropzone-before="1"
data-file-irre-object="' . htmlspecialchars($objectPrefix) . '"
data-file-allowed="' . htmlspecialchars($allowed) . '"
......
......@@ -57,15 +57,16 @@ define(['jquery',
var me = this;
me.$body = $('body');
me.$element = $(element);
me.$trigger = $(me.$element.data('dropzone-trigger'));
me.$trigger = $(me.$element.data('dropzoneTrigger'));
me.$dropzone = $('<div />').addClass('dropzone').hide();
me.irreObjectUid = me.$element.data('file-irre-object');
if (me.irreObjectUid && me.$element.nextAll(me.$element.data('dropzone-target')).length !== 0) {
me.irreObjectUid = me.$element.data('fileIrreObject');
var dropZoneEscapedTarget = me.$element.data('dropzoneTarget');
if (me.irreObjectUid && me.$element.nextAll(dropZoneEscapedTarget).length !== 0) {
me.dropZoneInsertBefore = true;
me.$dropzone.insertBefore(me.$element.data('dropzone-target'));
me.$dropzone.insertBefore(dropZoneEscapedTarget);
} else {
me.dropZoneInsertBefore = false;
me.$dropzone.insertAfter(me.$element.data('dropzone-target'));
me.$dropzone.insertAfter(dropZoneEscapedTarget);
}
me.$dropzoneMask = $('<div />').addClass('dropzone-mask').appendTo(me.$dropzone);
me.$fileInput = $('<input type="file" multiple name="files[]" />').addClass('upload-file-picker').appendTo(me.$body);
......
......@@ -93,4 +93,18 @@ class StringUtility
$uniqueId = uniqid($prefix, true);
return str_replace('.', '', $uniqueId);
}
/**
* Escape a CSS selector to be used for DOM queries
*
* This method takes care to escape any CSS selector meta character.
* The result may be used to query the DOM like $('#' + escapedSelector)
*
* @param string $selector
* @return string
*/
public static function escapeCssSelector(string $selector) : string
{
return preg_replace('([#:.\\[\\],=@])', '\\$1', $selector);
}
}
......@@ -217,4 +217,28 @@ class StringUtilityTest extends \TYPO3\TestingFramework\Core\Unit\UnitTestCase
{
$this->assertNotContains('.', StringUtility::getUniqueId());
}
/**
* @param string $selector
* @param string $expectedValue
* @dataProvider escapeCssSelectorDataProvider
*/
public function escapeCssSelector(string $selector, string $expectedValue)
{
$this->assertEquals($expectedValue, StringUtility::escapeCssSelector($selector));
}
/**
* @return array
*/
public function escapeCssSelectorDataProvider() : array
{
return [
['data.field', 'data\\.field'],
['#theId', '\\#theId'],
['.theId:hover', '\\.theId\\:hover'],
['.theId:hover', '\\.theId\\:hover'],
['input[name=foo]', 'input\\[name\\=foo\\]'],
];
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment