|
|
@@ -290,6 +290,36 @@ function sensitive_log(array|string $log): array|string {
|
|
|
return $log;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * @param array<mixed> $curl_params
|
|
|
+ * @return array<mixed>
|
|
|
+ */
|
|
|
+function sanitizeCurlParams(array $curl_params): array {
|
|
|
+ $safe_params = [
|
|
|
+ CURLOPT_COOKIE,
|
|
|
+ CURLOPT_COOKIEFILE,
|
|
|
+ CURLOPT_FOLLOWLOCATION,
|
|
|
+ CURLOPT_HTTPHEADER,
|
|
|
+ CURLOPT_MAXREDIRS,
|
|
|
+ CURLOPT_POST,
|
|
|
+ CURLOPT_POSTFIELDS,
|
|
|
+ CURLOPT_PROXY,
|
|
|
+ CURLOPT_PROXYTYPE,
|
|
|
+ CURLOPT_USERAGENT,
|
|
|
+ ];
|
|
|
+ foreach ($curl_params as $k => $_) {
|
|
|
+ if (!in_array($k, $safe_params, true)) {
|
|
|
+ unset($curl_params[$k]);
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ // Allow only an empty value just to enable the libcurl cookie engine
|
|
|
+ if ($k === CURLOPT_COOKIEFILE) {
|
|
|
+ $curl_params[$k] = '';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return $curl_params;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* @param array<string,mixed> $attributes
|
|
|
* @param array<int,mixed> $curl_options
|
|
|
@@ -318,28 +348,10 @@ function customSimplePie(array $attributes = [], array $curl_options = []): \Sim
|
|
|
$curl_options[CURLOPT_SSL_CIPHER_LIST] = 'DEFAULT@SECLEVEL=1';
|
|
|
}
|
|
|
}
|
|
|
+ $attributes['curl_params'] = sanitizeCurlParams(is_array($attributes['curl_params'] ?? null) ? $attributes['curl_params'] : []);
|
|
|
if (!empty($attributes['curl_params']) && is_array($attributes['curl_params'])) {
|
|
|
- $safe_params = [
|
|
|
- CURLOPT_COOKIE,
|
|
|
- CURLOPT_COOKIEFILE,
|
|
|
- CURLOPT_FOLLOWLOCATION,
|
|
|
- CURLOPT_HTTPHEADER,
|
|
|
- CURLOPT_MAXREDIRS,
|
|
|
- CURLOPT_POST,
|
|
|
- CURLOPT_POSTFIELDS,
|
|
|
- CURLOPT_PROXY,
|
|
|
- CURLOPT_PROXYTYPE,
|
|
|
- CURLOPT_USERAGENT,
|
|
|
- ];
|
|
|
foreach ($attributes['curl_params'] as $co => $v) {
|
|
|
if (is_int($co)) {
|
|
|
- if (!in_array($co, $safe_params, true)) {
|
|
|
- continue;
|
|
|
- }
|
|
|
- if ($co === CURLOPT_COOKIEFILE) {
|
|
|
- // Allow only an empty value just to enable the libcurl cookie engine
|
|
|
- $v = '';
|
|
|
- }
|
|
|
$curl_options[$co] = $v;
|
|
|
}
|
|
|
}
|
|
|
@@ -631,7 +643,7 @@ function httpGet(string $url, string $cachePath, string $type = 'html', array $a
|
|
|
curl_setopt_array($ch, FreshRSS_Context::systemConf()->curl_options);
|
|
|
|
|
|
if (is_array($attributes['curl_params'] ?? null)) {
|
|
|
- $options = $attributes['curl_params'];
|
|
|
+ $options = sanitizeCurlParams($attributes['curl_params']);
|
|
|
if (is_array($options[CURLOPT_HTTPHEADER] ?? null)) {
|
|
|
// Remove headers problematic for security
|
|
|
$options[CURLOPT_HTTPHEADER] = array_filter($options[CURLOPT_HTTPHEADER],
|
|
|
@@ -640,9 +652,8 @@ function httpGet(string $url, string $cachePath, string $type = 'html', array $a
|
|
|
if (preg_grep('/^Accept\\s*:/i', $options[CURLOPT_HTTPHEADER]) === false) {
|
|
|
$options[CURLOPT_HTTPHEADER][] = 'Accept: ' . $accept;
|
|
|
}
|
|
|
- $attributes['curl_params'] = $options;
|
|
|
}
|
|
|
- curl_setopt_array($ch, $attributes['curl_params']);
|
|
|
+ curl_setopt_array($ch, $options);
|
|
|
}
|
|
|
|
|
|
if (isset($attributes['ssl_verify'])) {
|