Skip to content

Commit

Permalink
Bug/18884 fix stored xss in surveygroup (#3241)
Browse files Browse the repository at this point in the history
* Dev: code styling

* Fixed issue #18884: updated gridview columns for surveygroups

* Fixed issue #18884: updated CLSGridView with rowLink that allows to set a default url that will be applied to all td elements of a row

* Fixed issue #18884: also update survey-grid (survey list) with link changes

* Fixed issue 18903: [security] Stored XSS in Survey Groups title
  • Loading branch information
ptelu committed Jun 23, 2023
1 parent 240f7d8 commit f0416da
Show file tree
Hide file tree
Showing 11 changed files with 71 additions and 87 deletions.
2 changes: 1 addition & 1 deletion application/controllers/admin/SurveysGroupsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ public function update(int $id)
$aData = array(
'model' => $model,
'action' => App()->createUrl("admin/surveysgroups/sa/update", array('id' => $model->gsid, '#' => 'settingsForThisGroup')),
'pageTitle' => gT('Update survey group: ') . $model->title,
'pageTitle' => gT('Update survey group: ') . CHtml::encode($model->title),
);

$aData['oSurveySearch'] = $oSurveySearch;
Expand Down
20 changes: 10 additions & 10 deletions application/core/LSYii_Validators.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,21 @@ class LSYii_Validators extends CValidator

public function __construct()
{
if (Yii::app()->getConfig('DBVersion') < 172) {
if (App()->getConfig('DBVersion') < 172) {
// Permission::model exist only after 172 DB version
return $this->xssfilter = ($this->xssfilter && Yii::app()->getConfig('filterxsshtml'));
return $this->xssfilter = ($this->xssfilter && App()->getConfig('filterxsshtml'));
}
// If run from console there is no user
$this->xssfilter = (
$this->xssfilter && // this
(
(defined('PHP_ENV') && PHP_ENV == 'test') || // phpunit test : don't check controller
(
($controller = Yii::app()->getController()) !== null && // no controller
(get_class($controller) !== 'ConsoleApplication') // ConsoleApplication
$this->xssfilter
&& ((defined('PHP_ENV') // phpunit test : don't check controller
&& PHP_ENV == 'test'
)
) &&
Yii::app()->user->isXssFiltered() // user
|| (($controller = App()->getController()) !== null // no controller
&& (get_class($controller) !== 'ConsoleApplication') // ConsoleApplication
)
)
&& App()->user->isXssFiltered() // user
);
return;
}
Expand Down
29 changes: 27 additions & 2 deletions application/extensions/admin/grid/CLSGridView.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ class CLSGridView extends TbGridView
*/
public $lsAfterAjaxUpdate;

/**
* string for a link that is on every row
* @var string
*/
public $rowLink;

/**
* Initializes the widget.
* @throws CException
Expand All @@ -28,6 +34,7 @@ public function init()
$this->htmlOptions['class'] = 'grid-view-ls';
$classes = ['table', 'table-hover'];
$this->template = $this->render('template', ['massiveActionTemplate' => $this->massiveActionTemplate], true);
$this->rowLink();
$this->lsAfterAjaxUpdate();
if (!empty($classes)) {
$classes = implode(' ', $classes);
Expand Down Expand Up @@ -64,6 +71,7 @@ protected function lsAfterAjaxUpdate(): void
$this->afterAjaxUpdate .= $jsCode;
}
$this->afterAjaxUpdate .= 'LS.actionDropdown.create();';
$this->afterAjaxUpdate .= 'if (typeof LS.actionDropdown.create() !== "undefined"){ LS.actionDropdown.create();}';
$this->afterAjaxUpdate .= '}';
} else {
// trigger action_dropdown() as a default although no lsAfterAjaxUpdate param passed.
Expand All @@ -72,14 +80,31 @@ protected function lsAfterAjaxUpdate(): void
}
}

protected function rowLink()
{
if (!empty($this->rowLink) && empty($this->rowHtmlOptionsExpression)) {
$this->rowHtmlOptionsExpression = function ($row, $data, $grid) {
$options = [];
$options['data-rowlink'] = eval('return ' . $this->rowLink . ';');
return $options;
};
}
}

private function registerGridviewScripts()
{
// Scrollbar
App()->clientScript->registerScriptFile(
App()->getConfig("extensionsurl") . 'admin/grid/assets/gridScrollbar.js',
CClientScript::POS_BEGIN,
['test321' => "something"]
CClientScript::POS_BEGIN
);
// Link for each row
if (!empty($this->rowLink)) {
App()->clientScript->registerScriptFile(
App()->getConfig("extensionsurl") . 'admin/grid/assets/rowLink.js',
CClientScript::POS_BEGIN
);
}

// ========== this is added for pagination size working by referencing from old limegridview ==============
$id = $this->getId();
Expand Down
11 changes: 11 additions & 0 deletions application/extensions/admin/grid/assets/rowLink.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use strict';
document.addEventListener('DOMContentLoaded', () => {
document.querySelectorAll('.grid-view-ls [data-rowlink]').forEach(tr => {
let link = tr.getAttribute('data-rowlink');
tr.querySelectorAll('td:not(.ls-sticky-column)').forEach(td => {
td.addEventListener('click', function () {
window.location.href = link;
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
'ajaxUpdate' => 'survey-grid',
'afterAjaxUpdate' => 'function(id, data){window.LS.doToolTip();bindListItemclick();}',
'lsAfterAjaxUpdate' => ['window.LS.doToolTip();', 'bindListItemclick();'],
'rowLink' => 'Yii::app()->createUrl("surveyAdministration/view/",array("iSurveyID"=>$data->sid))',
// 'template' => $this->template,
'massiveActionTemplate' => $this->render('massive_actions/_selector', [], true, false),
'columns' => [
Expand All @@ -49,8 +50,7 @@
[
'header' => gT('Survey ID'),
'name' => 'survey_id',
'type' => 'raw',
'value' => 'CHtml::link($data->sid, Yii::app()->createUrl("surveyAdministration/view/",array("iSurveyID"=>$data->sid)))',
'value' => '$data->sid',
'headerHtmlOptions' => ['class' => 'd-none d-sm-table-cell text-nowrap'],
'htmlOptions' => ['class' => 'd-none d-sm-table-cell has-link'],
],
Expand All @@ -65,69 +65,61 @@
[
'header' => gT('Title'),
'name' => 'title',
'type' => 'raw',
'value' => 'isset($data->defaultlanguage) ? CHtml::link(flattenText($data->defaultlanguage->surveyls_title), Yii::app()->createUrl("surveyAdministration/view/",array("surveyid"=>$data->sid))) : ""',
'value' => '$data->defaultlanguage->surveyls_title',
'htmlOptions' => ['class' => 'has-link'],
'headerHtmlOptions' => ['class' => 'text-nowrap'],
],
[
'header' => gT('Group'),
'name' => 'group',
'type' => 'raw',
'value' => 'isset($data->surveygroup) ? CHtml::link(flattenText($data->surveygroup->title), Yii::app()->createUrl("surveyAdministration/view/",array("surveyid"=>$data->sid))) : ""',
'value' => '$data->surveygroup->title',
'htmlOptions' => ['class' => 'has-link'],
'headerHtmlOptions' => ['class' => 'text-nowrap'],
],
[
'header' => gT('Created'),
'name' => 'creation_date',
'type' => 'raw',
'value' => 'CHtml::link($data->creationdate, Yii::app()->createUrl("surveyAdministration/view/",array("surveyid"=>$data->sid)))',
'value' => '$data->creationdate',
'headerHtmlOptions' => ['class' => 'd-none d-sm-table-cell text-nowrap'],
'htmlOptions' => ['class' => 'd-none d-sm-table-cell has-link'],
],
[
'header' => gT('Owner'),
'name' => 'owner',
'type' => 'raw',
'value' => 'CHtml::link(CHtml::encode($data->ownerUserName), Yii::app()->createUrl("surveyAdministration/view/",array("surveyid"=>$data->sid)))',
'value' => '$data->ownerUserName',
'headerHtmlOptions' => ['class' => 'd-md-none d-xl-table-cell text-nowrap'],
'htmlOptions' => ['class' => 'd-md-none d-xl-table-cell has-link'],
],
[
'header' => gT('Anonymized responses'),
'name' => 'anonymized_responses',
'type' => 'raw',
'value' => 'CHtml::link($data->anonymizedResponses, Yii::app()->createUrl("surveyAdministration/view/",array("surveyid"=>$data->sid)))',
'value' => '$data->anonymizedResponses',
'headerHtmlOptions' => ['class' => 'd-md-none d-lg-table-cell'],
'htmlOptions' => ['class' => 'd-md-none d-lg-table-cell has-link'],
],
[
'header' => gT('Partial'),
'type' => 'raw',
'value' => 'CHtml::link($data->countPartialAnswers, Yii::app()->createUrl("surveyAdministration/view/",array("surveyid"=>$data->sid)))',
'value' => '$data->countPartialAnswers',
'name' => 'partial',
'htmlOptions' => ['class' => 'has-link'],
],
[
'header' => gT('Full'),
'name' => 'full',
'type' => 'raw',
'value' => 'CHtml::link($data->countFullAnswers, Yii::app()->createUrl("surveyAdministration/view/",array("surveyid"=>$data->sid)))',
'value' => '$data->countFullAnswers',
'htmlOptions' => ['class' => 'has-link'],
],
[
'header' => gT('Total'),
'name' => 'total',
'type' => 'raw',
'value' => 'CHtml::link($data->countTotalAnswers, Yii::app()->createUrl("surveyAdministration/view/",array("surveyid"=>$data->sid)))',
'value' => '$data->countTotalAnswers',
'htmlOptions' => ['class' => 'has-link'],
],
[
'header' => gT('Closed group'),
'name' => 'uses_tokens',
'type' => 'raw',
'value' => 'CHtml::link($data->hasTokensTable ? gT("Yes"):gT("No"), Yii::app()->createUrl("surveyAdministration/view/",array("surveyid"=>$data->sid)))',
'value' => '$data->hasTokensTable ? gT("Yes"):gT("No")',
'htmlOptions' => ['class' => 'has-link'],
],
[
Expand Down
30 changes: 8 additions & 22 deletions application/models/SurveysGroups.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,71 +122,57 @@ public function getColumns()
array(
'header' => gT('Survey group ID'),
'name' => 'gsid',
'value' => '$data->hasViewSurveyGroupRight ? CHtml::link($data->gsid, Yii::app()->createUrl("admin/surveysgroups/sa/update/",array("id"=>$data->gsid))) : $data->gsid',
'type' => 'raw',
'headerHtmlOptions' => array('class' => ''),
'value' => '$data->gsid',
'htmlOptions' => ['class' => 'has-link'],
),


array(
'header' => gT('Code'),
'name' => 'name',
'value' => '$data->hasViewSurveyGroupRight ? CHtml::link($data->name, Yii::app()->createUrl("admin/surveysgroups/sa/update/",array("id"=>$data->gsid))) : $data->name',
'type' => 'raw',
'value' => '$data->name',
'htmlOptions' => ['class' => 'has-link'],
),

array(
'header' => gT('Title'),
'name' => 'title',
'value' => '$data->hasViewSurveyGroupRight ? CHtml::link($data->title, Yii::app()->createUrl("admin/surveysgroups/sa/update/",array("id"=>$data->gsid))) : $data->title',
'type' => 'raw',
'value' => '$data->title',
'htmlOptions' => ['class' => 'has-link'],
),

array(
'header' => gT('Description'),
'name' => 'description',
'value' => '$data->hasViewSurveyGroupRight ? CHtml::link($data->description, Yii::app()->createUrl("admin/surveysgroups/sa/update/",array("id"=>$data->gsid))) : $data->description',
'type' => 'raw',
'headerHtmlOptions' => array('class' => ''),
'value' => '$data->description',
'htmlOptions' => ['class' => 'has-link'],
),

array(
'header' => gT('Parent group'),
'name' => 'parent',
'value' => '$data->hasViewSurveyGroupRight ? CHtml::link($data->parentTitle, Yii::app()->createUrl("admin/surveysgroups/sa/update/",array("id"=>$data->gsid))) : $data->parentTitle',
'type' => 'raw',
'headerHtmlOptions' => array('class' => ''),
'value' => '$data->parentTitle',
'htmlOptions' => ['class' => 'has-link'],
),

array(
'header' => gT('Available'),
'name' => 'alwaysavailable',
'value' => '$data->hasViewSurveyGroupRight ? CHtml::link($data->alwaysavailable, Yii::app()->createUrl("admin/surveysgroups/sa/update/",array("id"=>$data->gsid))) : $data->alwaysavailable',
'type' => 'raw',
'headerHtmlOptions' => array('class' => ''),
'value' => '$data->alwaysavailable',
'htmlOptions' => ['class' => 'has-link'],
),

array(
'header' => gT('Owner'),
'name' => 'owner',
'value' => '$data->hasViewSurveyGroupRight && !empty($data->owner) ? CHtml::link($data->owner->users_name, Yii::app()->createUrl("admin/surveysgroups/sa/update/",array("id"=>$data->gsid))) : ""',
'type' => 'raw',
'headerHtmlOptions' => array('class' => ''),
'value' => '$data->owner->users_name',
'htmlOptions' => ['class' => 'has-link'],
),

array(
'header' => gT('Order'),
'name' => 'sortorder',
'value' => '$data->hasViewSurveyGroupRight ? CHtml::link($data->sortorder, Yii::app()->createUrl("admin/surveysgroups/sa/update/",array("id"=>$data->gsid))) : $data->sortorder',
'type' => 'raw',
'headerHtmlOptions' => array('class' => ''),
'value' => '$data->sortorder',
'htmlOptions' => ['class' => 'has-link'],
),
array(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
'dataProvider' => $groupModel->search(),
'lsAfterAjaxUpdate' => [],
'columns' => $groupModel->columns,
'rowLink' => 'App()->createUrl("admin/surveysgroups/sa/update/",array("id"=>$data->gsid))',
'summaryText' => gT('Displaying {start}-{end} of {count} result(s).') . ' '
. sprintf(
gT('%s rows per page'),
Expand Down
14 changes: 0 additions & 14 deletions assets/packages/adminbasics/build/adminbasics.js
Original file line number Diff line number Diff line change
Expand Up @@ -17604,18 +17604,6 @@
}
};

/**
* Methods to load when a the surveygrid is available
* if($('#survey-grid').length>0)
*/

const onExistBinding = () => {
$(document).on('click', '.has-link', function () {
const linkUrl = $(this).find('a').attr('href');
window.location.href = linkUrl;
});
};

/**
* Check the browsers console capabilities and bundle them into general functions
* If the build environment was "production" only put out error messages.
Expand Down Expand Up @@ -28898,7 +28886,6 @@
};
const onLoadRegister = () => {
globalStartUpMethods.bootstrapping();
onExistBinding();
appendToLoad(function () {
adminCoreLSConsole.log('TRIGGERWARNING', 'Document ready triggered');
}, 'ready');
Expand Down Expand Up @@ -28958,7 +28945,6 @@
}
});
});
onExistBinding();
},
addToNamespace = function (object) {
let name = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "globalAddition";
Expand Down
4 changes: 2 additions & 2 deletions assets/packages/adminbasics/build/adminbasics.min.js

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions assets/packages/adminbasics/src/adminbasicsmain.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import './components/bootstrap-remote-modals';
import questionEdit from './pages/questionEditing';
//import * as quickAction from './pages/quickaction'; ->temporary deprecated
import {subquestionAndAnswersGlobalMethods} from './pages/subquestionandanswers';
import {onExistBinding as surveyGrid} from './pages/surveyGrid';

//import parts for globalscope
import confirmationModal from './parts/confirmationModal';
Expand Down Expand Up @@ -75,7 +74,6 @@ const AdminCore = function(){
const
onLoadRegister = () => {
globalStartUpMethods.bootstrapping();
surveyGrid();
appendToLoad(function(){LOG.log('TRIGGERWARNING','Document ready triggered')}, 'ready');
appendToLoad(function(){LOG.log('TRIGGERWARNING','Document scriptcomplete triggered')}, 'pjax:scriptcomplete');
appendToLoad(saveBindings);
Expand Down Expand Up @@ -118,7 +116,6 @@ const AdminCore = function(){
}
});
});
surveyGrid();
},
addToNamespace = (object, name="globalAddition") => {
window.LS[name] = window.LS[name] || {};
Expand Down
14 changes: 0 additions & 14 deletions assets/packages/adminbasics/src/pages/surveyGrid.js

This file was deleted.

0 comments on commit f0416da

Please sign in to comment.