-
-
Notifications
You must be signed in to change notification settings - Fork 859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[8.0] Only escape callable output of add and edit column. #1852
Conversation
Thanks, can you please fix the failing tests?
Yeah, will try to refactor more when I got the chance. :) -- Edit -- |
OIC, thanks for pointing that out. It seems the tests are still failing though. |
@yajra I doubt if they are cause of my code. |
@sharifzadesina ok thanks, will to review this later. |
Just tested this with my app and it breaks my DT with the same error on the tests. Please fix. Thanks! exception: "Symfony\Component\Debug\Exception\FatalThrowableError"
file: "/www/yajra/dataTables/core/src/Processors/DataProcessor.php"
line: 241
message: "Argument 1 passed to Yajra\DataTables\Processors\DataProcessor::escapeRow() must be of the type array, integer given, called in /www/yajra/dataTables/core/src/Processors/DataProcessor.php on line 223" |
@yajra Bro I fixed the error, and improved the package a lot. |
@sharifzadesina thanks but it's failing on the indexColumn. I think it should be the last item on row manipulations as per the original code before PR. |
src/Processors/DataProcessor.php
Outdated
|
||
$data = $this->escapeRow(Helper::convertToArray($row)); | ||
$value = $this->addColumns($data, $row); | ||
$value = $this->addIndexColumn($value, $row); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be the last item in row processing or maybe second to the last then escape the row.
@yajra Fixed, but it was cause of an other error actually. |
The changes looks good. However, there are some columns on my project that should be raw but are being escaped. It's not blade but a closure that returns a view. ->rawColumns(['filename_html', 'deleted_html', 'cooked_html']); Need to review this further. I think we are missing some tests on raw columns. |
@yajra This should be fixed now. |
Still not working and I think I found where the issue was:
foreach ($this->results as $row) {
$data = Helper::convertToArray($row);
$value = $this->addColumns($data, $row);
$value = $this->editColumns($value, $row);
$value = $this->setupRowVariables($value, $row);
$value = $this->selectOnlyNeededColumns($value);
$value = $this->removeExcessColumns($value);
$value = $this->addIndexColumn($value);
$value = $this->escapeRow($value);
$this->output[] = $object ? $value : $this->flatten($value);
}
protected function shouldEscapeColumn($key)
{
foreach ($this->appendColumns as $column) {
if ($column['name'] == $key && is_string($column['content'])) {
return false;
}
}
foreach ($this->editColumns as $column) {
if ($column['name'] == $key && is_string($column['content'])) {
return false;
}
}
if ($this->escapeColumns === '*') {
return ! in_array($key, $this->rawColumns); // escape if is not a raw column
} elseif (is_array($this->escapeColumns)) {
return in_array($key, array_diff($this->escapeColumns, $this->rawColumns));
} else {
return true;
}
} |
$value[$indexColumn] = ++$this->start; | ||
} | ||
|
||
$data = $this->escapeRow(Helper::convertToArray($row)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be the last process in order to capture added / edited data.
@@ -125,13 +126,28 @@ public function process($object = false) | |||
protected function addColumns($data, $row) | |||
{ | |||
foreach ($this->appendColumns as $key => $value) { | |||
$value['content'] = Helper::compileContent($value['content'], $data, $row); | |||
$value['content'] = Helper::compileContent($value['content'], $data, $row, $this->shouldEscapeColumn($key)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the escape flag here is not needed since escaping will be done on escapeRow
process.
@@ -142,7 +158,7 @@ protected function addColumns($data, $row) | |||
protected function editColumns($data, $row) | |||
{ | |||
foreach ($this->editColumns as $key => $value) { | |||
$value['content'] = Helper::compileContent($value['content'], $data, $row); | |||
$value['content'] = Helper::compileContent($value['content'], $data, $row, $this->shouldEscapeColumn($key)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not needed like on addColumns
.
{ | ||
if (is_string($content)) { | ||
return static::compileBlade($content, static::getMixedValue($data, $param)); | ||
} elseif (is_callable($content)) { | ||
return $content($param); | ||
return $escape ? e($content($param)) : $content($param); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be reverted back to original since all data here is callable.
*/ | ||
protected function shouldEscapeColumn($key) | ||
{ | ||
if ($this->escapeColumns === '*') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can add the logic here to figure out if added/edited columns are to be escaped.
foreach ($this->appendColumns as $column) {
if ($column['name'] == $key && is_string($column['content'])) {
return false;
}
}
foreach ($this->editColumns as $column) {
if ($column['name'] == $key && is_string($column['content'])) {
return false;
}
}
@yajra we are not doing escaping at "escapeRow", cause we don't know the content was a blade string or a callable, we need to escape output of callables, that's why we only escape database data using |
@sharifzadesina we can identify the content by checking the append columns structure: foreach ($this->appendColumns as $column) {
if ($column['name'] == $key && is_string($column['content'])) {
return false;
}
}
Good point on this one. |
But I think we should still escape added/edited columns since we can still directly return a database value from a closure. |
@yajra function () {
return '<b>XSS</b>';
} The |
For closure like that, I would still prefer to be explicit and add it on the For a straight blade string, It's ok to be raw. addColumn('xss', function ($model) {
return '<b>XSS</b>'; // should be added to rawColumns
})
addColumn('xss', function ($model) {
return $model->xss; // should be added to rawColumns
})
addColumn('xss', 'path.to.view'); // can bypass escape
addColumn('xss', '<a href="#">{{ $xss }}</a>'); // can bypass escape |
See this gist for my debugged processor. It's not yet optimized though but my project does not seem to break. |
@yajra The problem is if you add it to |
Already created the gist. Yes, we should by default escape all rows for xss protection unless explicitly set as raw column.That is why I agreed of allowing |
@yajra no I mean the script you use to test my PR |
It's just a standard dataTable with multiple addColumns. Anyways, I added it on the gist. |
@yajra Bro I tested the PR on my own apps, it works without problem, are you sure you are using whole pull request? |
@yajra Any opinion on this? Why we don't merge it? |
It's still failing the last time I checked. For now I think the safest implementation would be:
->addColumn('extra', 'some string')
->editColumn('extra', 'some string')
->addColumn('extra', 'path.to.blade')
->editColumn('extra', 'path.to.blade')
->addColumn('extra', function($model) {
return 'html';
})
->rawColumns(['extra']) |
@yajra It is exactly like that, that's why I told "this is not a BC". |
Ok, will try to do an actual test again when I got the chance. |
It seems to work well now but it breaks the index column. Reverting, please resubmit the PR and fix the index column part. Thanks! |
Or you can alternatively send another PR to fix the index column? Will hold the revert and release of this feature until it's fixed. Thanks! |
Fixed the index column and added some tests. Released on v8.13.0 🚀 If you can, please also submit a PR on docs. Thanks! |
Resume discussion on #1916. |
Fixes #1849
P.S. bro I think you need to rewrite whole package again, you use nesting extremely.