Subida del módulo y tema de PrestaShop

This commit is contained in:
Kaloyan
2026-04-09 18:31:51 +02:00
parent 12c253296f
commit 16b3ff9424
39262 changed files with 7418797 additions and 0 deletions

View File

@@ -0,0 +1,113 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Http\RememberMe;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
/**
* @author Wouter de Jong <wouter@wouterj.nl>
*/
abstract class AbstractRememberMeHandler implements RememberMeHandlerInterface
{
private UserProviderInterface $userProvider;
protected $requestStack;
protected $options;
protected $logger;
public function __construct(UserProviderInterface $userProvider, RequestStack $requestStack, array $options = [], ?LoggerInterface $logger = null)
{
$this->userProvider = $userProvider;
$this->requestStack = $requestStack;
$this->options = $options + [
'name' => 'REMEMBERME',
'lifetime' => 31536000,
'path' => '/',
'domain' => null,
'secure' => false,
'httponly' => true,
'samesite' => null,
'always_remember_me' => false,
'remember_me_parameter' => '_remember_me',
];
$this->logger = $logger;
}
/**
* Checks if the RememberMeDetails is a valid cookie to login the given User.
*
* This method should also:
* - Create a new remember-me cookie to be sent with the response (using {@see createCookie()});
* - If you store the token somewhere else (e.g. in a database), invalidate the stored token.
*
* @throws AuthenticationException If the remember-me details are not accepted
*/
abstract protected function processRememberMe(RememberMeDetails $rememberMeDetails, UserInterface $user): void;
public function consumeRememberMeCookie(RememberMeDetails $rememberMeDetails): UserInterface
{
try {
$user = $this->userProvider->loadUserByIdentifier($rememberMeDetails->getUserIdentifier());
} catch (AuthenticationException $e) {
throw $e;
}
if (!$user instanceof UserInterface) {
throw new \LogicException(\sprintf('The UserProviderInterface implementation must return an instance of UserInterface, but returned "%s".', get_debug_type($user)));
}
$this->processRememberMe($rememberMeDetails, $user);
$this->logger?->info('Remember-me cookie accepted.');
return $user;
}
public function clearRememberMeCookie(): void
{
$this->logger?->debug('Clearing remember-me cookie.', ['name' => $this->options['name']]);
$this->createCookie(null);
}
/**
* Creates the remember-me cookie using the correct configuration.
*
* @param RememberMeDetails|null $rememberMeDetails The details for the cookie, or null to clear the remember-me cookie
*
* @return void
*/
protected function createCookie(?RememberMeDetails $rememberMeDetails)
{
$request = $this->requestStack->getMainRequest();
if (!$request) {
throw new \LogicException('Cannot create the remember-me cookie; no master request available.');
}
// the ResponseListener configures the cookie saved in this attribute on the final response object
$request->attributes->set(ResponseListener::COOKIE_ATTR_NAME, new Cookie(
$this->options['name'],
$rememberMeDetails?->toString(),
$rememberMeDetails?->getExpires() ?? 1,
$this->options['path'],
$this->options['domain'],
$this->options['secure'] ?? $request->isSecure(),
$this->options['httponly'],
false,
$this->options['samesite']
));
}
}

View File

@@ -0,0 +1,180 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Http\RememberMe;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
use Symfony\Component\Security\Core\Authentication\RememberMe\TokenProviderInterface;
use Symfony\Component\Security\Core\Authentication\RememberMe\TokenVerifierInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CookieTheftException;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
/**
* Implements remember-me tokens using a {@see TokenProviderInterface}.
*
* This requires storing remember-me tokens in a database. This allows
* more control over the invalidation of remember-me tokens. See
* {@see SignatureRememberMeHandler} if you don't want to use a database.
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
final class PersistentRememberMeHandler extends AbstractRememberMeHandler
{
private TokenProviderInterface $tokenProvider;
private ?TokenVerifierInterface $tokenVerifier;
/**
* @param UserProviderInterface $userProvider
* @param RequestStack $requestStack
* @param array $options
* @param LoggerInterface|null $logger
* @param TokenVerifierInterface|null $tokenVerifier
*/
public function __construct(TokenProviderInterface $tokenProvider, #[\SensitiveParameter] $userProvider, $requestStack, $options, $logger = null, $tokenVerifier = null)
{
if (\is_string($userProvider)) {
trigger_deprecation('symfony/security-http', '6.3', 'Calling "%s()" with the secret as the second argument is deprecated. The argument will be dropped in 7.0.', __CLASS__);
$userProvider = $requestStack;
$requestStack = $options;
$options = $logger;
$logger = $tokenVerifier;
$tokenVerifier = \func_num_args() > 6 ? func_get_arg(6) : null;
}
if (!$userProvider instanceof UserProviderInterface) {
throw new \TypeError(\sprintf('Argument 2 passed to "%s()" must be an instance of "%s", "%s" given.', __CLASS__, UserProviderInterface::class, get_debug_type($userProvider)));
}
if (!$requestStack instanceof RequestStack) {
throw new \TypeError(\sprintf('Argument 3 passed to "%s()" must be an instance of "%s", "%s" given.', __CLASS__, RequestStack::class, get_debug_type($userProvider)));
}
if (!\is_array($options)) {
throw new \TypeError(\sprintf('Argument 4 passed to "%s()" must be an array, "%s" given.', __CLASS__, get_debug_type($userProvider)));
}
if (null !== $logger && !$logger instanceof LoggerInterface) {
throw new \TypeError(\sprintf('Argument 5 passed to "%s()" must be an instance of "%s", "%s" given.', __CLASS__, LoggerInterface::class, get_debug_type($userProvider)));
}
if (null !== $tokenVerifier && !$tokenVerifier instanceof TokenVerifierInterface) {
throw new \TypeError(\sprintf('Argument 6 passed to "%s()" must be an instance of "%s", "%s" given.', __CLASS__, TokenVerifierInterface::class, get_debug_type($userProvider)));
}
parent::__construct($userProvider, $requestStack, $options, $logger);
if (!$tokenVerifier && $tokenProvider instanceof TokenVerifierInterface) {
$tokenVerifier = $tokenProvider;
}
$this->tokenProvider = $tokenProvider;
$this->tokenVerifier = $tokenVerifier;
}
public function createRememberMeCookie(UserInterface $user): void
{
$series = random_bytes(66);
$tokenValue = strtr(base64_encode(substr($series, 33)), '+/=', '-_~');
$series = strtr(base64_encode(substr($series, 0, 33)), '+/=', '-_~');
$token = new PersistentToken($user::class, $user->getUserIdentifier(), $series, $tokenValue, new \DateTimeImmutable());
$this->tokenProvider->createNewToken($token);
$this->createCookie(RememberMeDetails::fromPersistentToken($token, time() + $this->options['lifetime']));
}
public function consumeRememberMeCookie(RememberMeDetails $rememberMeDetails): UserInterface
{
if (!str_contains($rememberMeDetails->getValue(), ':')) {
throw new AuthenticationException('The cookie is incorrectly formatted.');
}
[$series, $tokenValue] = explode(':', $rememberMeDetails->getValue(), 2);
$persistentToken = $this->tokenProvider->loadTokenBySeries($series);
if ($persistentToken->getUserIdentifier() !== $rememberMeDetails->getUserIdentifier() || $persistentToken->getClass() !== $rememberMeDetails->getUserFqcn()) {
throw new AuthenticationException('The cookie\'s hash is invalid.');
}
// content of $rememberMeDetails is not trustable. this prevents use of this class
unset($rememberMeDetails);
if ($this->tokenVerifier) {
$isTokenValid = $this->tokenVerifier->verifyToken($persistentToken, $tokenValue);
} else {
$isTokenValid = hash_equals($persistentToken->getTokenValue(), $tokenValue);
}
if (!$isTokenValid) {
throw new CookieTheftException('This token was already used. The account is possibly compromised.');
}
$expires = $persistentToken->getLastUsed()->getTimestamp() + $this->options['lifetime'];
if ($expires < time()) {
throw new AuthenticationException('The cookie has expired.');
}
return parent::consumeRememberMeCookie(new RememberMeDetails(
$persistentToken->getClass(),
$persistentToken->getUserIdentifier(),
$expires,
$persistentToken->getLastUsed()->getTimestamp().':'.$series.':'.$tokenValue.':'.$persistentToken->getClass()
));
}
public function processRememberMe(RememberMeDetails $rememberMeDetails, UserInterface $user): void
{
[$lastUsed, $series, $tokenValue, $class] = explode(':', $rememberMeDetails->getValue(), 4);
$persistentToken = new PersistentToken($class, $rememberMeDetails->getUserIdentifier(), $series, $tokenValue, new \DateTimeImmutable('@'.$lastUsed));
// if a token was regenerated less than a minute ago, there is no need to regenerate it
// if multiple concurrent requests reauthenticate a user we do not want to update the token several times
if ($persistentToken->getLastUsed()->getTimestamp() + 60 >= time()) {
return;
}
$tokenValue = strtr(base64_encode(random_bytes(33)), '+/=', '-_~');
$tokenLastUsed = new \DateTime();
$this->tokenVerifier?->updateExistingToken($persistentToken, $tokenValue, $tokenLastUsed);
$this->tokenProvider->updateToken($series, $tokenValue, $tokenLastUsed);
$this->createCookie($rememberMeDetails->withValue($series.':'.$tokenValue));
}
public function clearRememberMeCookie(): void
{
parent::clearRememberMeCookie();
$cookie = $this->requestStack->getMainRequest()->cookies->get($this->options['name']);
if (null === $cookie) {
return;
}
try {
$rememberMeDetails = RememberMeDetails::fromRawCookie($cookie);
} catch (AuthenticationException) {
// malformed cookie should not fail the response and can be simply ignored
return;
}
[$series] = explode(':', $rememberMeDetails->getValue());
$this->tokenProvider->deleteTokenBySeries($series);
}
/**
* @internal
*/
public function getTokenProvider(): TokenProviderInterface
{
return $this->tokenProvider;
}
}

View File

@@ -0,0 +1,92 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Http\RememberMe;
use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
/**
* @author Wouter de Jong <wouter@wouterj.nl>
*/
class RememberMeDetails
{
public const COOKIE_DELIMITER = ':';
private string $userFqcn;
private string $userIdentifier;
private int $expires;
private string $value;
public function __construct(string $userFqcn, string $userIdentifier, int $expires, string $value)
{
$this->userFqcn = $userFqcn;
$this->userIdentifier = $userIdentifier;
$this->expires = $expires;
$this->value = $value;
}
public static function fromRawCookie(string $rawCookie): self
{
if (!str_contains($rawCookie, self::COOKIE_DELIMITER)) {
$rawCookie = base64_decode($rawCookie);
}
$cookieParts = explode(self::COOKIE_DELIMITER, $rawCookie, 4);
if (4 !== \count($cookieParts)) {
throw new AuthenticationException('The cookie contains invalid data.');
}
if (false === $cookieParts[1] = base64_decode(strtr($cookieParts[1], '-_~', '+/='), true)) {
throw new AuthenticationException('The user identifier contains a character from outside the base64 alphabet.');
}
$cookieParts[0] = strtr($cookieParts[0], '.', '\\');
return new static(...$cookieParts);
}
public static function fromPersistentToken(PersistentToken $persistentToken, int $expires): self
{
return new static($persistentToken->getClass(), $persistentToken->getUserIdentifier(), $expires, $persistentToken->getSeries().':'.$persistentToken->getTokenValue());
}
public function withValue(string $value): self
{
$details = clone $this;
$details->value = $value;
return $details;
}
public function getUserFqcn(): string
{
return $this->userFqcn;
}
public function getUserIdentifier(): string
{
return $this->userIdentifier;
}
public function getExpires(): int
{
return $this->expires;
}
public function getValue(): string
{
return $this->value;
}
public function toString(): string
{
// $userIdentifier is encoded because it might contain COOKIE_DELIMITER, we assume other values don't
return implode(self::COOKIE_DELIMITER, [strtr($this->userFqcn, '\\', '.'), strtr(base64_encode($this->userIdentifier), '+/=', '-_~'), $this->expires, $this->value]);
}
}

View File

@@ -0,0 +1,54 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Http\RememberMe;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserInterface;
/**
* Handles creating and validating remember-me cookies.
*
* If you want to add a custom implementation, you want to extend from
* {@see AbstractRememberMeHandler} instead.
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
interface RememberMeHandlerInterface
{
/**
* Creates a remember-me cookie.
*
* The actual cookie should be set as an attribute on the main request,
* which is transformed into a response cookie by {@see ResponseListener}.
*/
public function createRememberMeCookie(UserInterface $user): void;
/**
* Validates the remember-me cookie and returns the associated User.
*
* Every cookie should only be used once. This means that this method should also:
* - Create a new remember-me cookie to be sent with the response (using the
* {@see ResponseListener::COOKIE_ATTR_NAME} request attribute);
* - If you store the token somewhere else (e.g. in a database), invalidate the
* stored token.
*
* @throws AuthenticationException
*/
public function consumeRememberMeCookie(RememberMeDetails $rememberMeDetails): UserInterface;
/**
* Clears the remember-me cookie.
*
* This should set a cookie with a `null` value on the request attribute.
*/
public function clearRememberMeCookie(): void;
}

View File

@@ -0,0 +1,51 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Http\RememberMe;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Adds remember-me cookies to the Response.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*
* @final
*/
class ResponseListener implements EventSubscriberInterface
{
/**
* This attribute name can be used by the implementation if it needs to set
* a cookie on the Request when there is no actual Response, yet.
*/
public const COOKIE_ATTR_NAME = '_security_remember_me_cookie';
public function onKernelResponse(ResponseEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
$response = $event->getResponse();
if ($request->attributes->has(self::COOKIE_ATTR_NAME)) {
$response->headers->setCookie($request->attributes->get(self::COOKIE_ATTR_NAME));
}
}
public static function getSubscribedEvents(): array
{
return [KernelEvents::RESPONSE => 'onKernelResponse'];
}
}

View File

@@ -0,0 +1,78 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\Security\Http\RememberMe;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Signature\Exception\ExpiredSignatureException;
use Symfony\Component\Security\Core\Signature\Exception\InvalidSignatureException;
use Symfony\Component\Security\Core\Signature\SignatureHasher;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
/**
* Implements safe remember-me cookies using the {@see SignatureHasher}.
*
* This handler doesn't require a database for the remember-me tokens.
* However, it cannot invalidate a specific user session, all sessions for
* that user will be invalidated instead. Use {@see PersistentRememberMeHandler}
* if you need this.
*
* @author Wouter de Jong <wouter@wouterj.nl>
*/
final class SignatureRememberMeHandler extends AbstractRememberMeHandler
{
private SignatureHasher $signatureHasher;
public function __construct(SignatureHasher $signatureHasher, UserProviderInterface $userProvider, RequestStack $requestStack, array $options, ?LoggerInterface $logger = null)
{
parent::__construct($userProvider, $requestStack, $options, $logger);
$this->signatureHasher = $signatureHasher;
}
public function createRememberMeCookie(UserInterface $user): void
{
$expires = time() + $this->options['lifetime'];
$value = $this->signatureHasher->computeSignatureHash($user, $expires);
$details = new RememberMeDetails($user::class, $user->getUserIdentifier(), $expires, $value);
$this->createCookie($details);
}
public function consumeRememberMeCookie(RememberMeDetails $rememberMeDetails): UserInterface
{
try {
$this->signatureHasher->acceptSignatureHash($rememberMeDetails->getUserIdentifier(), $rememberMeDetails->getExpires(), $rememberMeDetails->getValue());
} catch (InvalidSignatureException $e) {
throw new AuthenticationException('The cookie\'s hash is invalid.', 0, $e);
} catch (ExpiredSignatureException $e) {
throw new AuthenticationException('The cookie has expired.', 0, $e);
}
return parent::consumeRememberMeCookie($rememberMeDetails);
}
public function processRememberMe(RememberMeDetails $rememberMeDetails, UserInterface $user): void
{
try {
$this->signatureHasher->verifySignatureHash($user, $rememberMeDetails->getExpires(), $rememberMeDetails->getValue());
} catch (InvalidSignatureException $e) {
throw new AuthenticationException('The cookie\'s hash is invalid.', 0, $e);
} catch (ExpiredSignatureException $e) {
throw new AuthenticationException('The cookie has expired.', 0, $e);
}
$this->createRememberMeCookie($user);
}
}