<commit_before><?php
namespace Slim\Csrf;

use ArrayAccess;
use Countable;
use Traversable;
use IteratorAggregate;
use RuntimeException;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * CSRF protection middleware based
 * on the OWASP example linked below.
 *
 * @link https://www.owasp.org/index.php/PHP_CSRF_Guard
 */
class Guard
{
    /**
     * Prefix for CSRF parameters (omit trailing "_" underscore)
     *
     * @var string
     */
    protected $prefix;

    /**
     * CSRF storage
     *
     * Should be either an array or an object. If an object is used, then it must
     * implement ArrayAccess and should implement Countable and Iterator (or
     * IteratorAggregate) if storage limit enforcement is required.
     *
     * @var array|ArrayAccess
     */
    protected $storage;

    /**
     * Number of elements to store in the storage array
     *
     * Default is 200, set via constructor
     *
     * @var integer
     */
    protected $storageLimit;

    /**
     * CSRF Strength
     *
     * @var int
     */
     protected $strength = 16;

    /**
     * Callable to be executed if the CSRF validation fails
     *
     * Signature of callable is:
     *    function($request, $response, $next)
     * and a $response must be returned.
     *
     * @var callable
     */
    protected $failureCallable;

    /**
     * Stores the latest key-pair generated by the class
     *
     * @var array
     */
    protected $keyPair;

    /**
     * Create new CSRF guard
     *
     * @param string                 $prefix
     * @param null|array|ArrayAccess $storage
     * @param null|callable          $failureCallable
     * @param integer                $storageLimit
     * @throws RuntimeException if the session cannot be found
     */
    public function __construct($prefix = 'csrf', &$storage = null, callable $failureCallable = null, $storageLimit = 200)
    {
        $this->prefix = rtrim($prefix, '_');
        if (is_array($storage)) {
            $this->storage = &$storage;
        } elseif ($storage instanceof ArrayAccess) {
            $this->storage = $storage;
        } else {
            if (!isset($_SESSION)) {
                throw new RuntimeException('CSRF middleware failed. Session not found.');
            }
            if (!array_key_exists($prefix, $_SESSION)) {
                $_SESSION[$prefix] = [];
            }
            $this->storage = &$_SESSION[$prefix];
        }

        $this->setFailureCallable($failureCallable);
        $this->setStorageLimit($storageLimit);

        $this->keyPair = null;
    }

    /**
     * Retrieve token name key
     *
     * @return string
     */
    public function getTokenNameKey()
    {
        return $this->prefix . '_name';
    }

    /**
     * Retrieve token value key
     *
     * @return string
     */
    public function getTokenValueKey()
    {
        return $this->prefix . '_value';
    }

    /**
     * Invoke middleware
     *
     * @param  RequestInterface  $request  PSR7 request object
     * @param  ResponseInterface $response PSR7 response object
     * @param  callable          $next     Next middleware callable
     *
     * @return ResponseInterface PSR7 response object
     */
    public function __invoke(RequestInterface $request, ResponseInterface $response, callable $next)
    {
        // Validate POST, PUT, DELETE, PATCH requests
        if (in_array($request->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
            $body = $request->getParsedBody();
            $body = $body ? (array)$body : [];
            $name = isset($body[$this->prefix . '_name']) ? $body[$this->prefix . '_name'] : false;
            $value = isset($body[$this->prefix . '_value']) ? $body[$this->prefix . '_value'] : false;
            if (!$name || !$value || !$this->validateToken($name, $value)) {
                // Need to regenerate a new token, as the validateToken removed the current one.
                $request = $this->generateNewToken($request);

                $failureCallable = $this->getFailureCallable();
                return $failureCallable($request, $response, $next);
            }
        }
        // Generate new CSRF token
        $request = $this->generateNewToken($request);

        // Enforce the storage limit
        $this->enforceStorageLimit();

        return $next($request, $response);
    }

    /**
     * Generates a new CSRF token and appends it to the request.
     *
     * @param  RequestInterface $request PSR7 response object.
     *
     * @return RequestInterface PSR7 response object.
     */
    protected function generateNewToken($request)
    {
        // Generate new CSRF token
        $name = $this->prefix . mt_rand(0, mt_getrandmax());
        $value = $this->createToken();
        $this->saveToStorage($name, $value);
        $this->keyPair[$name] = $value;
        $request = $request->withAttribute($this->prefix . '_name', $name)
            ->withAttribute($this->prefix . '_value', $value);

        return $request;
    }

    /**
     * Validate CSRF token from current request
     * against token value stored in $_SESSION
     *
     * @param  string $name  CSRF name
     * @param  string $value CSRF token value
     *
     * @return bool<commit_msg>Changed the structure of keyPair<commit_after><?php
namespace Slim\Csrf;

use ArrayAccess;
use Countable;
use Traversable;
use IteratorAggregate;
use RuntimeException;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

/**
 * CSRF protection middleware based
 * on the OWASP example linked below.
 *
 * @link https://www.owasp.org/index.php/PHP_CSRF_Guard
 */
class Guard
{
    /**
     * Prefix for CSRF parameters (omit trailing "_" underscore)
     *
     * @var string
     */
    protected $prefix;

    /**
     * CSRF storage
     *
     * Should be either an array or an object. If an object is used, then it must
     * implement ArrayAccess and should implement Countable and Iterator (or
     * IteratorAggregate) if storage limit enforcement is required.
     *
     * @var array|ArrayAccess
     */
    protected $storage;

    /**
     * Number of elements to store in the storage array
     *
     * Default is 200, set via constructor
     *
     * @var integer
     */
    protected $storageLimit;

    /**
     * CSRF Strength
     *
     * @var int
     */
     protected $strength = 16;

    /**
     * Callable to be executed if the CSRF validation fails
     *
     * Signature of callable is:
     *    function($request, $response, $next)
     * and a $response must be returned.
     *
     * @var callable
     */
    protected $failureCallable;

    /**
     * Stores the latest key-pair generated by the class
     *
     * @var array
     */
    protected $keyPair;

    /**
     * Create new CSRF guard
     *
     * @param string                 $prefix
     * @param null|array|ArrayAccess $storage
     * @param null|callable          $failureCallable
     * @param integer                $storageLimit
     * @throws RuntimeException if the session cannot be found
     */
    public function __construct($prefix = 'csrf', &$storage = null, callable $failureCallable = null, $storageLimit = 200)
    {
        $this->prefix = rtrim($prefix, '_');
        if (is_array($storage)) {
            $this->storage = &$storage;
        } elseif ($storage instanceof ArrayAccess) {
            $this->storage = $storage;
        } else {
            if (!isset($_SESSION)) {
                throw new RuntimeException('CSRF middleware failed. Session not found.');
            }
            if (!array_key_exists($prefix, $_SESSION)) {
                $_SESSION[$prefix] = [];
            }
            $this->storage = &$_SESSION[$prefix];
        }

        $this->setFailureCallable($failureCallable);
        $this->setStorageLimit($storageLimit);

        $this->keyPair = null;
    }

    /**
     * Retrieve token name key
     *
     * @return string
     */
    public function getTokenNameKey()
    {
        return $this->prefix . '_name';
    }

    /**
     * Retrieve token value key
     *
     * @return string
     */
    public function getTokenValueKey()
    {
        return $this->prefix . '_value';
    }

    /**
     * Invoke middleware
     *
     * @param  RequestInterface  $request  PSR7 request object
     * @param  ResponseInterface $response PSR7 response object
     * @param  callable          $next     Next middleware callable
     *
     * @return ResponseInterface PSR7 response object
     */
    public function __invoke(RequestInterface $request, ResponseInterface $response, callable $next)
    {
        // Validate POST, PUT, DELETE, PATCH requests
        if (in_array($request->getMethod(), ['POST', 'PUT', 'DELETE', 'PATCH'])) {
            $body = $request->getParsedBody();
            $body = $body ? (array)$body : [];
            $name = isset($body[$this->prefix . '_name']) ? $body[$this->prefix . '_name'] : false;
            $value = isset($body[$this->prefix . '_value']) ? $body[$this->prefix . '_value'] : false;
            if (!$name || !$value || !$this->validateToken($name, $value)) {
                // Need to regenerate a new token, as the validateToken removed the current one.
                $request = $this->generateNewToken($request);

                $failureCallable = $this->getFailureCallable();
                return $failureCallable($request, $response, $next);
            }
        }
        // Generate new CSRF token
        $request = $this->generateNewToken($request);

        // Enforce the storage limit
        $this->enforceStorageLimit();

        return $next($request, $response);
    }

    /**
     * Generates a new CSRF token and appends it to the request.
     *
     * @param  RequestInterface $request PSR7 response object.
     *
     * @return RequestInterface PSR7 response object.
     */
    protected function generateNewToken($request)
    {
        // Generate new CSRF token
        $name = $this->prefix . mt_rand(0, mt_getrandmax());
        $value = $this->createToken();
        $this->saveToStorage($name, $value);

        $this->keyPair = [
            $this->prefix . '_name' => $name,
            $this->prefix . '_value' => $value
        ];

        $request = $request->withAttribute($this->prefix . '_name', $name)
            ->withAttribute($this->prefix . '_value', $value);

        return $request;
    }

    /**
     * Validate CSRF token from current request
     * against token value stored in $_SESSION
     *
     * @param  string $name  CSRF name
     * @param  string $value CSRF token value
     *
     * @return bool
{'fraction_non_alphanumeric': 0.11960784313725491, 'fraction_numerical': 0.00261437908496732, 'mean_word_length': 2.083189407023604, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 63, 'https://': 2, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1247654', 'n_tokens_mistral': 3033, 'n_tokens_neox': 2964, 'n_words': 832}