self::WINDOW ) { return false; } return hash_equals( self::sign( $secret, $request_signature, $status, $body, (int) $timestamp ), $signature ); } /** Whether a route (or a URL ending in one) is answered with a signature. */ public static function covers( string $route_or_url ): bool { $path = (string) strtok( $route_or_url, '?' ); foreach ( self::UNSIGNED_ROUTES as $unsigned ) { if ( str_ends_with( $path, $unsigned ) ) { return false; } } return true; } /** * The body a caller reads out of an admin-ajax envelope: the `data` member, encoded again. * Both ends build it here, so the signature is of the same bytes whatever the transport did. */ public static function envelope_body( mixed $data ): string { return is_array( $data ) ? (string) wp_json_encode( $data ) : (string) ( $data ?? '' ); } private static function payload( string $request_signature, int $status, string $body, string $timestamp ): string { return "RESPONSE\n" . $status . "\n" . $request_signature . "\n" . $timestamp . "\n" . hash( 'sha256', $body, false ); } }