Current File : /home/giriqfky/chahida.co.in/wp-content/plugins/sucuri-scanner/src//cors.lib.php
<?php
/**
* Code related to the CORS (Cross-Origin Resource Sharing) headers settings.
*
* PHP version 5
*
* @category Library
* @package Sucuri
* @subpackage SucuriScanner
*/
if (!defined('SUCURISCAN_INIT') || SUCURISCAN_INIT !== true) {
if (!headers_sent()) {
/* Report invalid access if possible. */
header('HTTP/1.1 403 Forbidden');
}
exit(1);
}
/**
* CORS headers library.
*
* This class is responsible for setting the CORS headers based on the user's settings.
*
* @category Library
* @package Sucuri
* @subpackage SucuriScanner
*/
class SucuriScanCORSHeaders extends SucuriScan
{
/**
* Sets the CORS headers according to the stored plugin options.
*
* @return void
*/
public function setCORSHeaders()
{
if (headers_sent()) {
return;
}
$corsMode = SucuriScanOption::getOption(':headers_cors');
if ($corsMode === 'disabled') {
return;
}
$corsOptions = SucuriScanOption::getOption(':headers_cors_options');
if (!is_array($corsOptions)) {
$corsOptions = array();
}
foreach ($corsOptions as $directive => $option) {
// If the directive is not enforced, skip
if (!isset($option['enforced']) || !$option['enforced']) {
continue;
}
// Collect the directive’s raw value (may be from 'value' or multi_checkbox 'options')
$rawValue = $this->collectDirectiveValue($option);
if (empty($rawValue)) {
continue;
}
switch ($directive) {
case 'Access-Control-Allow-Origin':
$cleanValue = $this->sanitizeSimpleValue($rawValue);
if (!empty($cleanValue)) {
header('Access-Control-Allow-Origin: ' . $cleanValue);
}
break;
case 'Access-Control-Expose-Headers':
$csv = $this->sanitizeCommaSeparatedValue($rawValue);
if (!empty($csv)) {
header('Access-Control-Expose-Headers: ' . $csv);
}
break;
case 'Access-Control-Allow-Methods':
$methods = $this->sanitizeMultiMethodValue($rawValue);
if (!empty($methods)) {
header('Access-Control-Allow-Methods: ' . $methods);
}
break;
case 'Access-Control-Allow-Headers':
$csv = $this->sanitizeCommaSeparatedValue($rawValue);
if (!empty($csv)) {
header('Access-Control-Allow-Headers: ' . $csv);
}
break;
case 'Access-Control-Allow-Credentials':
if (!empty($rawValue)) {
header('Access-Control-Allow-Credentials: true');
}
break;
case 'Access-Control-Max-Age':
$numeric = $this->sanitizeNumericValue($rawValue);
if (!empty($numeric)) {
header('Access-Control-Max-Age: ' . $numeric);
}
break;
}
}
}
/**
* Collects a string representing the directive value:
* If it's a normal text directive, use 'value' directly;
* if it's a multi_checkbox directive, gather sub-options that are enforced.
*
* @param array $option Directive config array (type, value, options, enforced, etc.).
*
* @return string A space-separated list if multi_checkbox, or the text value otherwise.
*/
protected function collectDirectiveValue($option)
{
if (isset($option['type']) && $option['type'] === 'multi_checkbox') {
if (!isset($option['options']) || !is_array($option['options'])) {
return '';
}
$subTokens = array();
foreach ($option['options'] as $token => $tokenObj) {
if ($tokenObj['enforced']) {
$subTokens[] = $token;
}
}
return implode(' ', $subTokens);
}
if (isset($option['value']) && is_string($option['value'])) {
return trim($option['value']);
}
return '';
}
/**
* Removes HTML tags, replaces newlines, and trims whitespace.
*
* @param string $value The raw input string.
*
* @return string The cleaned string (could be empty).
*/
protected function sanitizeSimpleValue($value)
{
$value = strip_tags($value);
$value = preg_replace('/[\r\n]+/', ' ', $value);
return trim($value);
}
/**
* Splits a comma-delimited string into tokens, sanitizes each to valid
* header token characters, and rejoins them with a comma.
*
* @param string $rawValue The raw input string.
*
* @return string The cleaned, comma-separated string.
*/
protected function sanitizeCommaSeparatedValue($rawValue)
{
$rawValue = $this->sanitizeSimpleValue($rawValue);
if (empty($rawValue)) {
return '';
}
$tokens = preg_split('/\s*,\s*/', $rawValue, -1, PREG_SPLIT_NO_EMPTY);
$final = array();
foreach ($tokens as $token) {
$token = $this->sanitizeHeaderToken($token);
if (!empty($token)) {
$final[] = $token;
}
}
return implode(', ', $final);
}
/**
* Splits a space-delimited string of HTTP methods, e.g. "GET POST OPTIONS",
* and returns them as uppercase comma-separated tokens.
*
* @param string $rawValue The raw input string.
*
* @return string The cleaned, comma-separated string of uppercase methods.
*/
protected function sanitizeMultiMethodValue($rawValue)
{
$rawValue = $this->sanitizeSimpleValue($rawValue);
if (empty($rawValue)) {
return '';
}
$tokens = preg_split('/\s+/', $rawValue, -1, PREG_SPLIT_NO_EMPTY);
$final = array();
foreach ($tokens as $t) {
$t = strtoupper(preg_replace('/[^A-Z]/', '', $t));
if (!empty($t)) {
$final[] = $t;
}
}
return implode(', ', $final);
}
/**
* Restricts characters to typical token chars from RFC 7230:
* ^[!#$%&'*+-.^_`|~0-9A-Za-z]+$
*
* @param string $value Potential header token.
*
* @return string Cleaned header token (could be empty).
*/
protected function sanitizeHeaderToken($value)
{
$value = preg_replace("/[^!#$%&'*+\-.\^_`|~0-9A-Za-z]/", '', $value);
return trim($value);
}
/**
* For numeric-only directives like Access-Control-Max-Age.
*
* @param string $rawValue The raw input string.
*
* @return string Digits only (could be empty).
*/
protected function sanitizeNumericValue($rawValue)
{
$cleaned = $this->sanitizeSimpleValue($rawValue);
$digitsOnly = preg_replace('/\D/', '', $cleaned);
return trim($digitsOnly);
}
}