Skip to content

Commit 0216137

Browse files
Merge pull request #17799 from kamil-tekiela/js-escaping
Refactor JS escaping mechanism
2 parents bc71e6c + 7ca71c7 commit 0216137

25 files changed

Lines changed: 137 additions & 364 deletions

libraries/classes/Config/FormDisplay.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -436,35 +436,34 @@ private function displayFieldInput(
436436
$this->setComments($systemPath, $opts);
437437

438438
// send default value to form's JS
439-
$jsLine = '\'' . $translatedPath . '\': ';
439+
$jsLine = '';
440440
switch ($type) {
441441
case 'text':
442442
case 'short_text':
443443
case 'number_text':
444444
case 'password':
445-
$jsLine .= '\'' . Sanitize::escapeJsString($valueDefault) . '\'';
445+
$jsLine = (string) $valueDefault;
446446
break;
447447
case 'checkbox':
448-
$jsLine .= $valueDefault ? 'true' : 'false';
448+
$jsLine = (bool) $valueDefault;
449449
break;
450450
case 'select':
451451
$valueDefaultJs = is_bool($valueDefault)
452452
? (int) $valueDefault
453453
: $valueDefault;
454-
$jsLine .= '[\'' . Sanitize::escapeJsString($valueDefaultJs) . '\']';
454+
$jsLine = (array) $valueDefaultJs;
455455
break;
456456
case 'list':
457457
$val = $valueDefault;
458458
if (isset($val['wrapper_params'])) {
459459
unset($val['wrapper_params']);
460460
}
461461

462-
$jsLine .= '\'' . Sanitize::escapeJsString(implode("\n", $val))
463-
. '\'';
462+
$jsLine = implode("\n", $val);
464463
break;
465464
}
466465

467-
$jsDefault[] = $jsLine;
466+
$jsDefault[$translatedPath] = $jsLine;
468467

469468
return $this->formDisplayTemplate->displayInput(
470469
$translatedPath,

libraries/classes/Config/FormDisplayTemplate.php

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@
88
namespace PhpMyAdmin\Config;
99

1010
use PhpMyAdmin\Config;
11-
use PhpMyAdmin\Sanitize;
1211
use PhpMyAdmin\Template;
1312

1413
use function array_shift;
15-
use function implode;
14+
use function json_encode;
15+
16+
use const JSON_HEX_TAG;
1617

1718
/**
1819
* PhpMyAdmin\Config\FormDisplayTemplate class
@@ -144,12 +145,7 @@ public function addJsValidate($fieldId, $validators, array &$jsArray): void
144145
foreach ((array) $validators as $validator) {
145146
$validator = (array) $validator;
146147
$vName = array_shift($validator);
147-
$vArgs = [];
148-
foreach ($validator as $arg) {
149-
$vArgs[] = Sanitize::escapeJsString($arg);
150-
}
151-
152-
$vArgs = $vArgs ? ", ['" . implode("', '", $vArgs) . "']" : '';
148+
$vArgs = $validator !== [] ? ', ' . json_encode($validator, JSON_HEX_TAG) : '';
153149
$jsArray[] = "window.Config.registerFieldValidator('"
154150
. $fieldId . "', '" . $vName . "', true" . $vArgs . ')';
155151
}

libraries/classes/Controllers/Table/ChangeController.php

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ public function __invoke(ServerRequest $request): void
6363
$GLOBALS['after_insert'] = $GLOBALS['after_insert'] ?? null;
6464
$GLOBALS['comments_map'] = $GLOBALS['comments_map'] ?? null;
6565
$GLOBALS['table_columns'] = $GLOBALS['table_columns'] ?? null;
66-
$GLOBALS['chg_evt_handler'] = $GLOBALS['chg_evt_handler'] ?? null;
6766
$GLOBALS['timestamp_seen'] = $GLOBALS['timestamp_seen'] ?? null;
6867
$GLOBALS['columns_cnt'] = $GLOBALS['columns_cnt'] ?? null;
6968
$GLOBALS['tabindex'] = $GLOBALS['tabindex'] ?? null;
@@ -172,9 +171,6 @@ public function __invoke(ServerRequest $request): void
172171
/**
173172
* Displays the form
174173
*/
175-
// autocomplete feature of IE kills the "onchange" event handler and it
176-
// must be replaced by the "onpropertychange" one in this case
177-
$GLOBALS['chg_evt_handler'] = 'onchange';
178174
// Had to put the URI because when hosted on an https server,
179175
// some browsers send wrongly this form to the http server.
180176

@@ -254,7 +250,6 @@ public function __invoke(ServerRequest $request): void
254250
$GLOBALS['comments_map'],
255251
$GLOBALS['timestamp_seen'],
256252
$GLOBALS['current_result'],
257-
$GLOBALS['chg_evt_handler'],
258253
$GLOBALS['jsvkey'],
259254
$GLOBALS['vkey'],
260255
$GLOBALS['insert_mode'],

libraries/classes/Header.php

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,15 @@
1616
use function gmdate;
1717
use function header;
1818
use function htmlspecialchars;
19-
use function implode;
2019
use function ini_get;
21-
use function is_bool;
20+
use function json_encode;
2221
use function sprintf;
2322
use function strlen;
2423
use function strtolower;
2524
use function urlencode;
2625

26+
use const JSON_HEX_TAG;
27+
2728
/**
2829
* Class used to output the HTTP and HTML headers
2930
*/
@@ -201,15 +202,8 @@ public function getJsParams(): array
201202
public function getJsParamsCode(): string
202203
{
203204
$params = $this->getJsParams();
204-
foreach ($params as $key => $value) {
205-
if (is_bool($value)) {
206-
$params[$key] = $key . ':' . ($value ? 'true' : 'false') . '';
207-
} else {
208-
$params[$key] = $key . ':"' . Sanitize::escapeJsString($value) . '"';
209-
}
210-
}
211205

212-
return 'window.CommonParams.setAll({' . implode(',', $params) . '});';
206+
return 'window.CommonParams.setAll(' . json_encode($params, JSON_HEX_TAG) . ');';
213207
}
214208

215209
/**

libraries/classes/Html/Generator.php

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
use function ini_get;
4040
use function intval;
4141
use function is_array;
42+
use function is_string;
43+
use function json_encode;
4244
use function mb_strlen;
4345
use function mb_strstr;
4446
use function mb_strtolower;
@@ -57,6 +59,7 @@
5759
use function urlencode;
5860

5961
use const ENT_COMPAT;
62+
use const JSON_HEX_TAG;
6063

6164
/**
6265
* HTML Generator
@@ -1055,20 +1058,13 @@ public static function linkOrButton(
10551058
$url = $urlPath . Url::getCommon($urlParams, str_contains($urlPath, '?') ? '&' : '?', false);
10561059
}
10571060

1058-
$urlLength = strlen($url);
1059-
1060-
if (! is_array($tagParams)) {
1061-
$tmp = $tagParams;
1062-
$tagParams = [];
1063-
if (! empty($tmp)) {
1064-
$tagParams['onclick'] = 'return Functions.confirmLink(this, \''
1065-
. Sanitize::escapeJsString($tmp) . '\')';
1066-
}
1067-
1068-
unset($tmp);
1061+
if (is_string($tagParams)) {
1062+
$tagParams = $tagParams !== '' ?
1063+
['onclick' => 'return Functions.confirmLink(this, ' . json_encode($tagParams, JSON_HEX_TAG) . ')'] :
1064+
[];
10691065
}
10701066

1071-
if (! empty($target)) {
1067+
if ($target !== '') {
10721068
$tagParams['target'] = $target;
10731069
if ($target === '_blank' && str_starts_with($url, 'index.php?route=/url&url=')) {
10741070
$tagParams['rel'] = 'noopener noreferrer';
@@ -1077,7 +1073,7 @@ public static function linkOrButton(
10771073

10781074
// Suhosin: Check that each query parameter is not above maximum
10791075
$inSuhosinLimits = true;
1080-
if ($urlLength <= $GLOBALS['cfg']['LinkLengthLimit']) {
1076+
if (strlen($url) <= $GLOBALS['cfg']['LinkLengthLimit']) {
10811077
$suhosinGetMaxValueLength = ini_get('suhosin.get.max_value_length');
10821078
if ($suhosinGetMaxValueLength) {
10831079
$queryParts = Util::splitURLQuery($url);
@@ -1096,7 +1092,7 @@ public static function linkOrButton(
10961092
}
10971093

10981094
$tagParamsStrings = [];
1099-
$isDataPostFormatSupported = ($urlLength > $GLOBALS['cfg']['LinkLengthLimit'])
1095+
$isDataPostFormatSupported = (strlen($url) > $GLOBALS['cfg']['LinkLengthLimit'])
11001096
|| ! $inSuhosinLimits
11011097
|| (
11021098
// Has as sql_query without a signature, to be accepted it needs to be sent using POST

libraries/classes/InsertEdit.php

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use function is_array;
2929
use function is_file;
3030
use function is_string;
31+
use function json_encode;
3132
use function max;
3233
use function mb_stripos;
3334
use function mb_strlen;
@@ -595,7 +596,7 @@ private function getTextarea(
595596
. ' cols="' . $textareaCols . '"'
596597
. ' dir="' . $textDir . '"'
597598
. ' id="field_' . $idindex . '_3"'
598-
. ($onChangeClause ? ' ' . $onChangeClause : '')
599+
. ($onChangeClause ? ' onchange="' . htmlspecialchars($onChangeClause, ENT_COMPAT) . '"' : '')
599600
. ' tabindex="' . ($tabindex + $tabindexForValue) . '"'
600601
. ' data-type="' . $dataType . '">'
601602
. $specialCharsEncoded
@@ -715,7 +716,7 @@ private function getHtmlInput(
715716
. ($readOnly ? ' readonly="readonly"' : '')
716717
. ($inputMinMax ? ' ' . $inputMinMax : '')
717718
. ' data-type="' . $dataType . '"'
718-
. ' class="' . $theClass . '" ' . $onChangeClause
719+
. ' class="' . $theClass . '" onchange="' . htmlspecialchars($onChangeClause, ENT_COMPAT) . '"'
719720
. ' tabindex="' . ($tabindex + $tabindexForValue) . '"'
720721
. ($isInteger ? ' inputmode="numeric"' : '')
721722
. ' id="field_' . $idindex . '_3">';
@@ -1959,7 +1960,6 @@ public function getHtmlForInsertEditFormHeader($hasBlobField, $isUpload): string
19591960
* @param array $commentsMap comments map
19601961
* @param bool $timestampSeen whether timestamp seen
19611962
* @param ResultInterface $currentResult current result
1962-
* @param string $chgEvtHandler javascript change event handler
19631963
* @param string $jsvkey javascript validation key
19641964
* @param string $vkey validation key
19651965
* @param bool $insertMode whether insert mode
@@ -1988,7 +1988,6 @@ private function getHtmlForInsertEditFormColumn(
19881988
array $commentsMap,
19891989
$timestampSeen,
19901990
ResultInterface $currentResult,
1991-
$chgEvtHandler,
19921991
$jsvkey,
19931992
$vkey,
19941993
$insertMode,
@@ -2035,10 +2034,9 @@ private function getHtmlForInsertEditFormColumn(
20352034
}
20362035

20372036
//Call validation when the form submitted...
2038-
$onChangeClause = $chgEvtHandler
2039-
. "=\"return verificationsAfterFieldChange('"
2040-
. Sanitize::escapeJsString($fieldHashMd5) . "', '"
2041-
. Sanitize::escapeJsString($jsvkey) . "','" . $column['pma_type'] . "')\"";
2037+
$onChangeClause = 'return verificationsAfterFieldChange('
2038+
. json_encode($fieldHashMd5) . ', '
2039+
. json_encode($jsvkey) . ',' . json_encode($column['pma_type']) . ')';
20422040

20432041
// Use an MD5 as an array index to avoid having special characters
20442042
// in the name attribute (see bug #1746964 )
@@ -2340,7 +2338,6 @@ private function isColumnBinary(array $column, bool $isUpload): bool
23402338
* @param array $commentsMap comments map
23412339
* @param bool $timestampSeen whether timestamp seen
23422340
* @param ResultInterface $currentResult current result
2343-
* @param string $chgEvtHandler javascript change event handler
23442341
* @param string $jsvkey javascript validation key
23452342
* @param string $vkey validation key
23462343
* @param bool $insertMode whether insert mode
@@ -2367,7 +2364,6 @@ public function getHtmlForInsertEditRow(
23672364
array $commentsMap,
23682365
$timestampSeen,
23692366
ResultInterface $currentResult,
2370-
$chgEvtHandler,
23712367
$jsvkey,
23722368
$vkey,
23732369
$insertMode,
@@ -2420,7 +2416,6 @@ public function getHtmlForInsertEditRow(
24202416
$commentsMap,
24212417
$timestampSeen,
24222418
$currentResult,
2423-
$chgEvtHandler,
24242419
$jsvkey,
24252420
$vkey,
24262421
$insertMode,

libraries/classes/Plugins/Transformations/Abs/DateFormatTransformationsPlugin.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,22 @@
99

1010
use PhpMyAdmin\FieldMetadata;
1111
use PhpMyAdmin\Plugins\TransformationsPlugin;
12-
use PhpMyAdmin\Sanitize;
1312
use PhpMyAdmin\Util;
1413

1514
use function __;
1615
use function checkdate;
1716
use function gmdate;
1817
use function htmlspecialchars;
18+
use function json_encode;
1919
use function mb_strlen;
2020
use function mb_strtolower;
2121
use function mb_substr;
2222
use function mktime;
2323
use function preg_match;
2424
use function strtotime;
2525

26+
use const ENT_COMPAT;
27+
2628
/**
2729
* Provides common methods for all of the date format transformations plugins.
2830
*/
@@ -140,7 +142,7 @@ public function applyTransformation($buffer, array $options = [], ?FieldMetadata
140142
$text = 'INVALID DATE TYPE';
141143
}
142144

143-
return '<dfn onclick="alert(\'' . Sanitize::jsFormat($source, false) . '\');" title="'
145+
return '<dfn onclick="alert(' . htmlspecialchars((string) json_encode($source), ENT_COMPAT) . ');" title="'
144146
. htmlspecialchars((string) $source) . '">' . htmlspecialchars((string) $text) . '</dfn>';
145147
}
146148

0 commit comments

Comments
 (0)