diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3ddf5e163..668f1e4c4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,7 +6,7 @@ jobs: strategy: fail-fast: false matrix: - php: [ '7.4', '8.0', '8.1', '8.2', '8.3', '8.4' ] + php: [ '7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5' ] name: PHP ${{ matrix.php }} steps: diff --git a/.github/workflows/setup-php.sh b/.github/workflows/setup-php.sh index 3852c4089..e978e92a0 100644 --- a/.github/workflows/setup-php.sh +++ b/.github/workflows/setup-php.sh @@ -4,30 +4,52 @@ sudo add-apt-repository -y ppa:ondrej/php # Install all required packages -sudo apt -y install \ - php$1-apcu \ - php$1-bcmath \ - php$1-cli \ - php$1-common \ - php$1-curl \ - php$1-gd \ - php$1-intl \ - php$1-mbstring \ - php$1-mysql \ - php$1-opcache \ - php$1-readline \ - php$1-sqlite3 \ - php$1-xml \ - php$1-zip +if [[ "$1" == "8.5" ]]; then + sudo apt -y install \ + php$1-bcmath \ + php$1-cli \ + php$1-common \ + php$1-curl \ + php$1-gd \ + php$1-intl \ + php$1-mbstring \ + php$1-mysql \ + php$1-readline \ + php$1-sqlite3 \ + php$1-xml \ + php$1-zip +else + sudo apt -y install \ + php$1-apcu \ + php$1-bcmath \ + php$1-cli \ + php$1-common \ + php$1-curl \ + php$1-gd \ + php$1-intl \ + php$1-mbstring \ + php$1-mysql \ + php$1-opcache \ + php$1-readline \ + php$1-sqlite3 \ + php$1-xml \ + php$1-zip +fi -# Enable and tune opcache -sudo bash -c 'echo "opcache.enable = 1" >> /etc/php/$1/cli/conf.d/10-opcache.ini' -sudo bash -c 'echo "opcache.enable_cli = 1" >> /etc/php/$1/cli/conf.d/10-opcache.ini' -sudo bash -c 'echo "opcache.jit = tracing" >> /etc/php/$1/cli/conf.d/10-opcache.ini' -sudo bash -c 'echo "opcache.jit_buffer_size = 128M" >> /etc/php/$1/cli/conf.d/10-opcache.ini' +# Adjust php.ini settings +if [[ "$1" == "8.5" ]]; then + sudo bash -c "echo 'register_argc_argv = On' >> /etc/php/$1/cli/php.ini" +else + sudo bash -c "echo 'opcache.enable = 1' >> /etc/php/$1/cli/conf.d/10-opcache.ini" + sudo bash -c "echo 'opcache.enable_cli = 1' >> /etc/php/$1/cli/conf.d/10-opcache.ini" + sudo bash -c "echo 'opcache.jit = tracing' >> /etc/php/$1/cli/conf.d/10-opcache.ini" + sudo bash -c "echo 'opcache.jit_buffer_size = 128M' >> /etc/php/$1/cli/conf.d/10-opcache.ini" +fi # Enable APCu -sudo bash -c 'echo "apc.enable_cli = 1" >> /etc/php/$1/cli/conf.d/20-apcu.ini' +if [ -f "/etc/php/$1/cli/conf.d/20-apcu.ini" ]; then + sudo bash -c "echo 'apc.enable_cli = 1' >> /etc/php/$1/cli/conf.d/20-apcu.ini" +fi # Disable xdebug sudo phpdismod -v ALL -s ALL xdebug diff --git a/classes/file/FileHandler.class.php b/classes/file/FileHandler.class.php index aa5f6aaba..f80ed9dfd 100644 --- a/classes/file/FileHandler.class.php +++ b/classes/file/FileHandler.class.php @@ -728,6 +728,10 @@ class FileHandler } elseif ($target_type === 'webp' && function_exists('imagewebp')) { + if (!imageistruecolor($thumb)) + { + imagepalettetotruecolor($thumb); + } $output = imagewebp($thumb, $target_file); } else diff --git a/common/framework/Security.php b/common/framework/Security.php index ab708eb08..8e6e3be64 100644 --- a/common/framework/Security.php +++ b/common/framework/Security.php @@ -314,43 +314,61 @@ class Security */ public static function checkCSRF(?string $referer = null): bool { + // If CSRF token checking is enabled, check the token header or parameter first. + // Tokens are allowed to be missing for unauthenticated users. $check_csrf_token = config('security.check_csrf_token') ? true : false; - if ($token = isset($_SERVER['HTTP_X_CSRF_TOKEN']) ? $_SERVER['HTTP_X_CSRF_TOKEN'] : null) + if ($check_csrf_token) { - return Session::verifyToken((string)$token, '', $check_csrf_token); - } - elseif ($token = isset($_REQUEST['_rx_csrf_token']) ? $_REQUEST['_rx_csrf_token'] : null) - { - return Session::verifyToken((string)$token, '', $check_csrf_token); + $token = $_SERVER['HTTP_X_CSRF_TOKEN'] ?? ($_REQUEST['_rx_csrf_token'] ?? null); + if ($token) + { + return Session::verifyToken((string)$token, '', $check_csrf_token); + } + elseif (Session::getMemberSrl()) + { + trigger_error('CSRF token missing in authenticated POST request: ' . (\Context::get('act') ?: '(no act)'), \E_USER_WARNING); + return false; + } } elseif ($token = isset($_REQUEST['_fb_adsense_token']) ? $_REQUEST['_fb_adsense_token'] : null) { return Password::checkPassword($token, 'bb15471de21f33c373abbea6438730ace9bbbacf5f4f9a0cbebdfff7e99c50fe631a78efe3e39736836b5b2082a0c3939e4c4e0f0f2e0028042411c4a8797b73'); } - elseif ($_SERVER['REQUEST_METHOD'] === 'GET') + + // Return early for GET and other "safe" requests. + if (in_array($_SERVER['REQUEST_METHOD'], ['GET', 'HEAD', 'OPTIONS', 'TRACE'])) { return false; } + + // The Sec-Fetch-Site header is the standard way to check whether the request is same-origin. + $sec_fetch_site = $_SERVER['HTTP_SEC_FETCH_SITE'] ?? ''; + if ($sec_fetch_site === 'same-origin' || $sec_fetch_site === 'none') + { + return true; + } + if ($sec_fetch_site === 'cross-site') + { + return false; + } + + // If the Sec-Fetch-Site header is not available, check the Origin header. + $origin = strval($_SERVER['HTTP_ORIGIN'] ?? ''); + if ($origin !== '' && $origin !== 'null') + { + return URL::isInternalURL($origin); + } + + // If the Origin header is not available, fall back to the Referer header. + // The Referer header is NOT allowed to be empty in this case. + $referer = $referer ?? strval($_SERVER['HTTP_REFERER'] ?? ''); + if ($referer !== '' && $referer !== 'null') + { + return URL::isInternalURL($referer); + } else { - $is_logged = Session::getMemberSrl(); - if ($is_logged) - { - trigger_error('CSRF token missing in POST request: ' . (\Context::get('act') ?: '(no act)'), \E_USER_WARNING); - } - - if (!$referer) - { - $referer = strval(($_SERVER['HTTP_ORIGIN'] ?? '') ?: ($_SERVER['HTTP_REFERER'] ?? '')); - } - if ($referer !== '' && $referer !== 'null' && (!$check_csrf_token || !$is_logged)) - { - return URL::isInternalURL($referer); - } - else - { - return false; - } + return false; } } diff --git a/common/framework/parsers/dbquery/VariableBase.php b/common/framework/parsers/dbquery/VariableBase.php index f4e29a0c5..419c74e95 100644 --- a/common/framework/parsers/dbquery/VariableBase.php +++ b/common/framework/parsers/dbquery/VariableBase.php @@ -383,6 +383,12 @@ class VariableBase } } + // If the default value is any other kind of SQL expression, return it as is. + if (isset($column) && preg_match('/^[A-Z_]+\([^)]+\)/', $this->default)) + { + return [true, $this->default]; + } + // Otherwise, just return the literal value. return [false, $this->default]; } diff --git a/common/js/plugins/jquery.fileupload/js/main.js b/common/js/plugins/jquery.fileupload/js/main.js index 40a94dba2..6cd681f1c 100644 --- a/common/js/plugins/jquery.fileupload/js/main.js +++ b/common/js/plugins/jquery.fileupload/js/main.js @@ -384,7 +384,10 @@ } if (html !== '' && data.settings.autoinsertPosition === 'paragraph') { - html = '

' + html + '

\n'; + html = '

' + html + '

\n'; + if (html.match(/