Skip to content

Commit 1c09408

Browse files
authored
Fix HTML encodings in e.g. cURL options (FreshRSS#6821)
* Fix HTML encodings in e.g. cURL options * Trim headers whitespace
1 parent c599ff4 commit 1c09408

File tree

7 files changed

+35
-29
lines changed

7 files changed

+35
-29
lines changed

app/Controllers/feedController.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -170,15 +170,15 @@ public function addAction(): void {
170170
$http_auth = $user . ':' . $pass;
171171
}
172172

173-
$cookie = Minz_Request::paramString('curl_params_cookie');
173+
$cookie = Minz_Request::paramString('curl_params_cookie', plaintext: true);
174174
$cookie_file = Minz_Request::paramBoolean('curl_params_cookiefile');
175175
$max_redirs = Minz_Request::paramInt('curl_params_redirects');
176-
$useragent = Minz_Request::paramString('curl_params_useragent');
177-
$proxy_address = Minz_Request::paramString('curl_params');
178-
$proxy_type = Minz_Request::paramString('proxy_type');
179-
$request_method = Minz_Request::paramString('curl_method');
180-
$request_fields = Minz_Request::paramString('curl_fields', true);
181-
$headers = Minz_Request::paramTextToArray('http_headers');
176+
$useragent = Minz_Request::paramString('curl_params_useragent', plaintext: true);
177+
$proxy_address = Minz_Request::paramString('curl_params', plaintext: true);
178+
$proxy_type = Minz_Request::paramString('proxy_type', plaintext: true);
179+
$request_method = Minz_Request::paramString('curl_method', plaintext: true);
180+
$request_fields = Minz_Request::paramString('curl_fields', plaintext: true);
181+
$headers = Minz_Request::paramTextToArray('http_headers', plaintext: true);
182182

183183
$opts = [];
184184
if ($proxy_type !== '') {
@@ -210,6 +210,7 @@ public function addAction(): void {
210210
}
211211
}
212212
if(!empty($headers)) {
213+
$headers = array_filter(array_map('trim', $headers));
213214
$opts[CURLOPT_HTTPHEADER] = array_merge($headers, $opts[CURLOPT_HTTPHEADER] ?? []);
214215
}
215216

app/Controllers/subscriptionController.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,15 +138,15 @@ public function feedAction(): void {
138138
}
139139
$feed->_attribute('read_when_same_title_in_feed', $read_when_same_title_in_feed);
140140

141-
$cookie = Minz_Request::paramString('curl_params_cookie');
141+
$cookie = Minz_Request::paramString('curl_params_cookie', plaintext: true);
142142
$cookie_file = Minz_Request::paramBoolean('curl_params_cookiefile');
143143
$max_redirs = Minz_Request::paramInt('curl_params_redirects');
144-
$useragent = Minz_Request::paramString('curl_params_useragent');
145-
$proxy_address = Minz_Request::paramString('curl_params');
146-
$proxy_type = Minz_Request::paramString('proxy_type');
147-
$request_method = Minz_Request::paramString('curl_method');
148-
$request_fields = Minz_Request::paramString('curl_fields', true);
149-
$headers = Minz_Request::paramTextToArray('http_headers');
144+
$useragent = Minz_Request::paramString('curl_params_useragent', plaintext: true);
145+
$proxy_address = Minz_Request::paramString('curl_params', plaintext: true);
146+
$proxy_type = Minz_Request::paramString('proxy_type', plaintext: true);
147+
$request_method = Minz_Request::paramString('curl_method', plaintext: true);
148+
$request_fields = Minz_Request::paramString('curl_fields', plaintext: true);
149+
$headers = Minz_Request::paramTextToArray('http_headers', plaintext: true);
150150
$opts = [];
151151
if ($proxy_type !== '') {
152152
$opts[CURLOPT_PROXY] = $proxy_address;
@@ -179,6 +179,7 @@ public function feedAction(): void {
179179
}
180180

181181
if(!empty($headers)) {
182+
$headers = array_filter(array_map('trim', $headers));
182183
$opts[CURLOPT_HTTPHEADER] = array_merge($headers, $opts[CURLOPT_HTTPHEADER] ?? []);
183184
}
184185

app/layout/aside_configure.phtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<ul>
88
<li class="item nav-section">
9-
<div class="item nav-header"><?= _t('gen.menu.account') ?>: <?= htmlspecialchars(Minz_User::name() ?? '', ENT_NOQUOTES, 'UTF-8')?></div>
9+
<div class="item nav-header"><?= _t('gen.menu.account') ?>: <?= htmlspecialchars(Minz_User::name() ?? '', ENT_NOQUOTES, 'UTF-8') ?></div>
1010
<ul>
1111
<li class="item<?= Minz_Request::controllerName() === 'user' && Minz_Request::actionName() === 'profile' ? ' active' : '' ?>">
1212
<a href="<?= _url('user', 'profile') ?>"><?= _t('gen.menu.user_profile') ?></a>

app/views/helpers/feed/update.phtml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@
646646
<label class="group-name" for="curl_params_cookie"><?= _t('sub.feed.css_cookie') ?></label>
647647
<div class="group-controls">
648648
<input type="text" name="curl_params_cookie" id="curl_params_cookie" class="w100" value="<?=
649-
!empty($curlParams[CURLOPT_COOKIE]) ? $curlParams[CURLOPT_COOKIE] : ''
649+
htmlspecialchars((string)($curlParams[CURLOPT_COOKIE] ?? ''), ENT_COMPAT, 'UTF-8')
650650
?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
651651
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.css_cookie_help') ?></p>
652652
<label for="curl_params_cookiefile">
@@ -684,7 +684,7 @@
684684
<label class="group-name" for="curl_params_useragent"><?= _t('sub.feed.useragent') ?></label>
685685
<div class="group-controls">
686686
<input type="text" name="curl_params_useragent" id="curl_params_useragent" class="w100" value="<?=
687-
!empty($curlParams[CURLOPT_USERAGENT]) ? $curlParams[CURLOPT_USERAGENT] : ''
687+
htmlspecialchars((string)($curlParams[CURLOPT_USERAGENT] ?? ''), ENT_COMPAT, 'UTF-8')
688688
?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
689689
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.useragent_help') ?></p>
690690
</div>
@@ -701,7 +701,7 @@
701701
?>
702702
</select>
703703
<input type="text" name="curl_params" id="curl_params" value="<?=
704-
!empty($curlParams[CURLOPT_PROXY]) ? $curlParams[CURLOPT_PROXY] : ''
704+
htmlspecialchars((string)($curlParams[CURLOPT_PROXY] ?? ''), ENT_COMPAT, 'UTF-8')
705705
?>" placeholder="<?= _t('gen.short.blank_to_disable') ?>" />
706706
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.proxy_help') ?></p>
707707
</div>
@@ -722,8 +722,7 @@
722722
</select>
723723
<div class="stick">
724724
<input type="text" name="curl_fields" id="curl_fields" value="<?=
725-
$this->feed->attributeArray('curl_params') !== null && !empty($this->feed->attributeArray('curl_params')[CURLOPT_POSTFIELDS]) ?
726-
htmlentities($this->feed->attributeArray('curl_params')[CURLOPT_POSTFIELDS], ENT_COMPAT) : ''
725+
htmlspecialchars($this->feed->attributeArray('curl_params')[CURLOPT_POSTFIELDS] ?? '', ENT_COMPAT, 'UTF-8')
727726
?>" placeholder="<?= _t('sub.feed.method_postparams') ?>" />
728727
</div>
729728
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.method_help') ?></p>
@@ -751,7 +750,11 @@
751750
<div class="form-group">
752751
<label class="group-name" for="http_headers"><?= _t('sub.feed.http_headers') ?></label>
753752
<div class="group-controls">
754-
<textarea class="valid-json" id="http_headers" name="http_headers" rows="3" cols="64" spellcheck="false"><?= !empty($this->feed->attributeArray('curl_params')) ? implode(PHP_EOL, $this->feed->attributeArray('curl_params')[CURLOPT_HTTPHEADER]) : '' ?></textarea>
753+
<textarea class="valid-json" id="http_headers" name="http_headers" rows="3" cols="64" spellcheck="false"><?php
754+
foreach ($this->feed->attributeArray('curl_params')[CURLOPT_HTTPHEADER] ?? [] as $header) {
755+
echo htmlspecialchars($header, ENT_NOQUOTES, 'UTF-8'), PHP_EOL;
756+
}
757+
?></textarea>
755758
<p class="help"><?= _i('help') ?> <?= _t('sub.feed.http_headers_help') ?></p>
756759
</div>
757760
</div>

lib/Minz/Request.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,14 +142,15 @@ public static function paramString(string $key, bool $plaintext = false): string
142142
* It will return an array where each cell contains one line of a text. The new line
143143
* character is used to break the text into lines. This method is well suited to use
144144
* to split textarea content.
145-
* @param array<string> $default
145+
* @param bool $plaintext `true` to return special characters without any escaping (unsafe), `false` (default) to XML-encode them
146146
* @return array<string>
147147
*/
148-
public static function paramTextToArray(string $key, array $default = []): array {
148+
public static function paramTextToArray(string $key, bool $plaintext = false): array {
149149
if (isset(self::$params[$key]) && is_string(self::$params[$key])) {
150-
return preg_split('/\R/u', self::$params[$key]) ?: [];
150+
$result = preg_split('/\R/u', self::$params[$key]) ?: [];
151+
return $plaintext ? $result : Minz_Helper::htmlspecialchars_utf8($result);
151152
}
152-
return $default;
153+
return [];
153154
}
154155

155156
public static function defaultControllerName(): string {

lib/core-extensions/UserCSS/extension.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ public function handleConfigureAction(): void {
2222
$this->registerTranslates();
2323

2424
if (Minz_Request::isPost()) {
25-
$css_rules = html_entity_decode(Minz_Request::paramString('css-rules'));
25+
$css_rules = Minz_Request::paramString('css-rules', plaintext: true);
2626
$this->saveFile(self::FILENAME, $css_rules);
2727
}
2828

2929
$this->css_rules = '';
3030
if ($this->hasFile(self::FILENAME)) {
31-
$this->css_rules = htmlentities($this->getFile(self::FILENAME) ?? '');
31+
$this->css_rules = htmlspecialchars($this->getFile(self::FILENAME) ?? '', ENT_NOQUOTES, 'UTF-8');
3232
}
3333
}
3434
}

lib/core-extensions/UserJS/extension.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ public function handleConfigureAction(): void {
2222
$this->registerTranslates();
2323

2424
if (Minz_Request::isPost()) {
25-
$js_rules = html_entity_decode(Minz_Request::paramString('js-rules'));
25+
$js_rules = Minz_Request::paramString('js-rules', plaintext: true);
2626
$this->saveFile(self::FILENAME, $js_rules);
2727
}
2828

2929
$this->js_rules = '';
3030
if ($this->hasFile(self::FILENAME)) {
31-
$this->js_rules = htmlentities($this->getFile(self::FILENAME) ?? '');
31+
$this->js_rules = htmlspecialchars($this->getFile(self::FILENAME) ?? '', ENT_NOQUOTES, 'UTF-8');
3232
}
3333
}
3434
}

0 commit comments

Comments
 (0)