Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions litespeed-cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,75 @@ function litespeed_exception_handler($errno, $errstr, $errfile, $errline)
}
}

/**
* Override the WP verify nonce function
* @since 6.3
*/
if (!function_exists('litespeed_define_verify_nonce_func')) {
function litespeed_define_verify_nonce_func()
{
/**
* If the nonce is in none_actions filter, convert it to ESI
*/
function wp_verify_nonce( $nonce, $action = -1 ) {
// If nonce length > 10 then render ESI to nonce value.
if (strlen($nonce) > 10) {
$nonce = \LiteSpeed\ESI::cls()->esi_hash_to_wp_nonce($nonce);
}
/* Reminder of this function is copied from wp-includes/pluggable.php (WP v6.4) */

$nonce = (string) $nonce;
$user = wp_get_current_user();
$uid = (int) $user->ID;
if ( !$uid ) {
/**
* Filters whether the user who generated the nonce is logged out.
*
* @since 3.5.0
*
* @param int $uid ID of the nonce-owning user.
* @param string|int $action The nonce action, or -1 if none was provided.
*/
$uid = apply_filters( 'nonce_user_logged_out', $uid, $action );
}

if ( empty( $nonce ) ) {
return false;
}

$token = wp_get_session_token();
$i = wp_nonce_tick( $action );

// Nonce generated 0-12 hours ago.
$expected = substr( wp_hash( $i . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 1;
}

// Nonce generated 12-24 hours ago.
$expected = substr( wp_hash( ( $i - 1 ) . '|' . $action . '|' . $uid . '|' . $token, 'nonce' ), -12, 10 );
if ( hash_equals( $expected, $nonce ) ) {
return 2;
}

/**
* Fires when nonce verification fails.
*
* @since 4.4.0
*
* @param string $nonce The invalid nonce.
* @param string|int $action The nonce action.
* @param WP_User $user The current user object.
* @param string $token The user's session token.
*/
do_action( 'wp_verify_nonce_failed', $nonce, $action, $user, $token );

// Invalid nonce.
return false;
}
}
}

/**
* Overwride the WP nonce funcs outside of LiteSpeed namespace
* @since 3.0
Expand Down
2 changes: 2 additions & 0 deletions src/core.cls.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ public function __construct()
if ($this->cls('Router')->esi_enabled() && !function_exists('wp_create_nonce')) {
Debug2::debug('[ESI] Overwrite wp_create_nonce()');
litespeed_define_nonce_func();
Debug2::debug('[ESI] Overwrite wp_verify_nonce()');
litespeed_define_verify_nonce_func();
}
}

Expand Down
65 changes: 65 additions & 0 deletions src/esi.cls.php
Original file line number Diff line number Diff line change
Expand Up @@ -1052,4 +1052,69 @@ public function contain_preserve_esi($content)
}
return $hit_list;
}

/**
* Convert nonce that has "<esi..." as content to nonce.
* Fix ESI nonce in PHP code.
*
* @since 6.3
*/
public function esi_hash_to_wp_nonce($nonce){
// Search the nonce in preserved list. If found return the content.
$preserved_found = $this->get_preserve_content( $nonce );
$nonce = $preserved_found ?: $nonce;

// if nonce has <esi in content.
if( strpos( $nonce, '<esi' )!==false ){
// search for esi src data.
preg_match( '/<esi.+src=["\'](.+)["\']/mU', $nonce, $src );

if( !empty( $src[1] ) ){
$parsedUrl = parse_url( $src[1] );

if( $parsedUrl && isset($parsedUrl['query']) ){
parse_str( $parsedUrl['query'], $variables );
$query_qs_param = $this::QS_PARAMS;
$is_esi_nonce = ( $variables[$this::QS_ACTION] ? $variables[$this::QS_ACTION]=='nonce' : false );

if( $is_esi_nonce && $variables[$query_qs_param] ){
// Unecrypt esi url parameter.
$unencrypt = base64_decode( $variables[$query_qs_param] );

if ( $unencrypt ) {
// JSON decode parameter.
$params_esi = json_decode( $unencrypt, true );

if( $params_esi['action'] && !empty( $params_esi['action'] ) ){
if ( function_exists( 'wp_create_nonce_litespeed_esi' ) ) {
$nonce = wp_create_nonce_litespeed_esi( $params_esi['action'] );
} else {
$nonce = wp_create_nonce( $params_esi['action'] );
}
}
}
}
}
}
}

return $nonce;
}

/**
* Test if hash is in preserved list
* @since 6.3
*/
public function get_preserve_content($hash){
$return = false;

foreach ( $this->_esi_preserve_list as $k => $v ) {
if( $k === $hash ){
$return = $v;
break;
}
}

return $return;
}
}