master

laravel/framework

Last updated at: 29/12/2023 09:21

EncryptCookies.php

TLDR

This file EncryptCookies.php is a part of the Illuminate\Cookie\Middleware namespace in the Laravel framework. It contains a class called EncryptCookies which is responsible for encrypting and decrypting cookies in the application. The class handles the encryption and decryption of cookies, as well as disabling encryption for specific cookies.

Methods

__construct

This method is the constructor of the EncryptCookies class. It accepts an instance of the EncrypterContract interface and initializes the encrypter property.

disableFor

This method is used to disable encryption for the given cookie name(s). It accepts a string or an array of cookie names and merges them with the except property.

handle

This method is used to handle an incoming request. It accepts a Request instance and a Closure as parameters. It calls the decrypt method to decrypt the cookies on the request, then passes the decrypted request through the $next closure. Finally, it calls the encrypt method to encrypt the cookies on the outgoing response.

decrypt

This method is used to decrypt the cookies on the request. It accepts a Request instance and loops through each cookie on the request. If the cookie is not disabled (based on the isDisabled method), it attempts to decrypt the cookie value using the encrypter. If decryption fails, the cookie value is set to null.

validateValue

This method is used to validate and remove the cookie value prefix from the value. It accepts a string $key and a value, and returns the validated value. If the value is an array, it calls the validateArray method.

validateArray

This method is used to validate and remove the cookie value prefix from all values of an array. It accepts a string $key and an array $value. It loops through each value in the array and recursively calls the validateValue method to validate each value.

decryptCookie

This method is used to decrypt the given cookie and return the value. It accepts a string $name and a value $cookie. If the value is an array, it calls the decryptArray method. Otherwise, it calls the decrypt method of the encrypter to perform the decryption.

decryptArray

This method is used to decrypt an array based cookie. It accepts an array $cookie and decrypts each value recursively by calling the decrypt method of the encrypter.

encrypt

This method is used to encrypt the cookies on an outgoing response. It accepts a Response instance and loops through each cookie in the response headers. If the cookie is not disabled, it encrypts the cookie value by prepending a value prefix and encrypting the entire value using the encrypter. It sets the encrypted cookie on the response headers using the duplicate method.

duplicate

This method is used to duplicate a cookie with a new value. It accepts a Cookie instance and a new value and returns a new Cookie instance with the updated value.

isDisabled

This method is used to determine whether encryption has been disabled for the given cookie. It accepts a string $name and checks if the cookie name is present in the except property or the static::$neverEncrypt property.

except

This method is used to indicate that the given cookies should never be encrypted. It accepts an array or a string of cookie names and merges them with the static::$neverEncrypt property.

serialized

This method is used to determine if the cookie contents should be serialized. It accepts a string $name and returns the value of the static::$serialize property.

Classes

There are no additional classes in the file.

<?php

namespace Illuminate\Cookie\Middleware;

use Closure;
use Illuminate\Contracts\Encryption\DecryptException;
use Illuminate\Contracts\Encryption\Encrypter as EncrypterContract;
use Illuminate\Cookie\CookieValuePrefix;
use Illuminate\Support\Arr;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

class EncryptCookies
{
    /**
     * The encrypter instance.
     *
     * @var \Illuminate\Contracts\Encryption\Encrypter
     */
    protected $encrypter;

    /**
     * The names of the cookies that should not be encrypted.
     *
     * @var array<int, string>
     */
    protected $except = [];

    /**
     * The globally ignored cookies that should not be encrypted.
     *
     * @var array
     */
    protected static $neverEncrypt = [];

    /**
     * Indicates if cookies should be serialized.
     *
     * @var bool
     */
    protected static $serialize = false;

    /**
     * Create a new CookieGuard instance.
     *
     * @param  \Illuminate\Contracts\Encryption\Encrypter  $encrypter
     * @return void
     */
    public function __construct(EncrypterContract $encrypter)
    {
        $this->encrypter = $encrypter;
    }

    /**
     * Disable encryption for the given cookie name(s).
     *
     * @param  string|array  $name
     * @return void
     */
    public function disableFor($name)
    {
        $this->except = array_merge($this->except, (array) $name);
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function handle($request, Closure $next)
    {
        return $this->encrypt($next($this->decrypt($request)));
    }

    /**
     * Decrypt the cookies on the request.
     *
     * @param  \Symfony\Component\HttpFoundation\Request  $request
     * @return \Symfony\Component\HttpFoundation\Request
     */
    protected function decrypt(Request $request)
    {
        foreach ($request->cookies as $key => $cookie) {
            if ($this->isDisabled($key)) {
                continue;
            }

            try {
                $value = $this->decryptCookie($key, $cookie);

                $request->cookies->set($key, $this->validateValue($key, $value));
            } catch (DecryptException) {
                $request->cookies->set($key, null);
            }
        }

        return $request;
    }

    /**
     * Validate and remove the cookie value prefix from the value.
     *
     * @param  string  $key
     * @param  string  $value
     * @return string|array|null
     */
    protected function validateValue(string $key, $value)
    {
        return is_array($value)
                    ? $this->validateArray($key, $value)
                    : CookieValuePrefix::validate($key, $value, $this->encrypter->getKey());
    }

    /**
     * Validate and remove the cookie value prefix from all values of an array.
     *
     * @param  string  $key
     * @param  array  $value
     * @return array
     */
    protected function validateArray(string $key, array $value)
    {
        $validated = [];

        foreach ($value as $index => $subValue) {
            $validated[$index] = $this->validateValue("{$key}[{$index}]", $subValue);
        }

        return $validated;
    }

    /**
     * Decrypt the given cookie and return the value.
     *
     * @param  string  $name
     * @param  string|array  $cookie
     * @return string|array
     */
    protected function decryptCookie($name, $cookie)
    {
        return is_array($cookie)
                        ? $this->decryptArray($cookie)
                        : $this->encrypter->decrypt($cookie, static::serialized($name));
    }

    /**
     * Decrypt an array based cookie.
     *
     * @param  array  $cookie
     * @return array
     */
    protected function decryptArray(array $cookie)
    {
        $decrypted = [];

        foreach ($cookie as $key => $value) {
            if (is_string($value)) {
                $decrypted[$key] = $this->encrypter->decrypt($value, static::serialized($key));
            }

            if (is_array($value)) {
                $decrypted[$key] = $this->decryptArray($value);
            }
        }

        return $decrypted;
    }

    /**
     * Encrypt the cookies on an outgoing response.
     *
     * @param  \Symfony\Component\HttpFoundation\Response  $response
     * @return \Symfony\Component\HttpFoundation\Response
     */
    protected function encrypt(Response $response)
    {
        foreach ($response->headers->getCookies() as $cookie) {
            if ($this->isDisabled($cookie->getName())) {
                continue;
            }

            $response->headers->setCookie($this->duplicate(
                $cookie,
                $this->encrypter->encrypt(
                    CookieValuePrefix::create($cookie->getName(), $this->encrypter->getKey()).$cookie->getValue(),
                    static::serialized($cookie->getName())
                )
            ));
        }

        return $response;
    }

    /**
     * Duplicate a cookie with a new value.
     *
     * @param  \Symfony\Component\HttpFoundation\Cookie  $cookie
     * @param  mixed  $value
     * @return \Symfony\Component\HttpFoundation\Cookie
     */
    protected function duplicate(Cookie $cookie, $value)
    {
        return $cookie->withValue($value);
    }

    /**
     * Determine whether encryption has been disabled for the given cookie.
     *
     * @param  string  $name
     * @return bool
     */
    public function isDisabled($name)
    {
        return in_array($name, array_merge($this->except, static::$neverEncrypt));
    }

    /**
     * Indicate that the given cookies should never be encrypted.
     *
     * @param  array|string  $cookies
     * @return void
     */
    public static function except($cookies)
    {
        static::$neverEncrypt = array_values(array_unique(
            array_merge(static::$neverEncrypt, Arr::wrap($cookies))
        ));
    }

    /**
     * Determine if the cookie contents should be serialized.
     *
     * @param  string  $name
     * @return bool
     */
    public static function serialized($name)
    {
        return static::$serialize;
    }
}