login consent app sql
This commit is contained in:
25
vendor/symfony/password-hasher/Hasher/CheckPasswordLengthTrait.php
vendored
Normal file
25
vendor/symfony/password-hasher/Hasher/CheckPasswordLengthTrait.php
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
trait CheckPasswordLengthTrait
|
||||
{
|
||||
private function isPasswordTooLong(string $password): bool
|
||||
{
|
||||
return PasswordHasherInterface::MAX_PASSWORD_LENGTH < \strlen($password);
|
||||
}
|
||||
}
|
98
vendor/symfony/password-hasher/Hasher/MessageDigestPasswordHasher.php
vendored
Normal file
98
vendor/symfony/password-hasher/Hasher/MessageDigestPasswordHasher.php
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
use Symfony\Component\PasswordHasher\Exception\LogicException;
|
||||
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* MessageDigestPasswordHasher uses a message digest algorithm.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class MessageDigestPasswordHasher implements LegacyPasswordHasherInterface
|
||||
{
|
||||
use CheckPasswordLengthTrait;
|
||||
|
||||
private $algorithm;
|
||||
private $encodeHashAsBase64;
|
||||
private $iterations = 1;
|
||||
private $hashLength = -1;
|
||||
|
||||
/**
|
||||
* @param string $algorithm The digest algorithm to use
|
||||
* @param bool $encodeHashAsBase64 Whether to base64 encode the password hash
|
||||
* @param int $iterations The number of iterations to use to stretch the password hash
|
||||
*/
|
||||
public function __construct(string $algorithm = 'sha512', bool $encodeHashAsBase64 = true, int $iterations = 5000)
|
||||
{
|
||||
$this->algorithm = $algorithm;
|
||||
$this->encodeHashAsBase64 = $encodeHashAsBase64;
|
||||
|
||||
try {
|
||||
$this->hashLength = \strlen($this->hash('', 'salt'));
|
||||
} catch (\LogicException $e) {
|
||||
// ignore algorithm not supported
|
||||
}
|
||||
|
||||
$this->iterations = $iterations;
|
||||
}
|
||||
|
||||
public function hash(string $plainPassword, string $salt = null): string
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
if (!\in_array($this->algorithm, hash_algos(), true)) {
|
||||
throw new LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
|
||||
}
|
||||
|
||||
$salted = $this->mergePasswordAndSalt($plainPassword, $salt);
|
||||
$digest = hash($this->algorithm, $salted, true);
|
||||
|
||||
// "stretch" hash
|
||||
for ($i = 1; $i < $this->iterations; ++$i) {
|
||||
$digest = hash($this->algorithm, $digest.$salted, true);
|
||||
}
|
||||
|
||||
return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, string $plainPassword, string $salt = null): bool
|
||||
{
|
||||
if (\strlen($hashedPassword) !== $this->hashLength || false !== strpos($hashedPassword, '$')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !$this->isPasswordTooLong($plainPassword) && hash_equals($hashedPassword, $this->hash($plainPassword, $salt));
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function mergePasswordAndSalt(string $password, ?string $salt): string
|
||||
{
|
||||
if (!$salt) {
|
||||
return $password;
|
||||
}
|
||||
|
||||
if (false !== strrpos($salt, '{') || false !== strrpos($salt, '}')) {
|
||||
throw new \InvalidArgumentException('Cannot use { or } in salt.');
|
||||
}
|
||||
|
||||
return $password.'{'.$salt.'}';
|
||||
}
|
||||
}
|
64
vendor/symfony/password-hasher/Hasher/MigratingPasswordHasher.php
vendored
Normal file
64
vendor/symfony/password-hasher/Hasher/MigratingPasswordHasher.php
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* Hashes passwords using the best available hasher.
|
||||
* Verifies them using a chain of hashers.
|
||||
*
|
||||
* /!\ Don't put a PlaintextPasswordHasher in the list as that'd mean a leaked hash
|
||||
* could be used to authenticate successfully without knowing the cleartext password.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
final class MigratingPasswordHasher implements PasswordHasherInterface
|
||||
{
|
||||
private $bestHasher;
|
||||
private $extraHashers;
|
||||
|
||||
public function __construct(PasswordHasherInterface $bestHasher, PasswordHasherInterface ...$extraHashers)
|
||||
{
|
||||
$this->bestHasher = $bestHasher;
|
||||
$this->extraHashers = $extraHashers;
|
||||
}
|
||||
|
||||
public function hash(string $plainPassword, string $salt = null): string
|
||||
{
|
||||
return $this->bestHasher->hash($plainPassword, $salt);
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, string $plainPassword, string $salt = null): bool
|
||||
{
|
||||
if ($this->bestHasher->verify($hashedPassword, $plainPassword, $salt)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$this->bestHasher->needsRehash($hashedPassword)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this->extraHashers as $hasher) {
|
||||
if ($hasher->verify($hashedPassword, $plainPassword, $salt)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
return $this->bestHasher->needsRehash($hashedPassword);
|
||||
}
|
||||
}
|
120
vendor/symfony/password-hasher/Hasher/NativePasswordHasher.php
vendored
Normal file
120
vendor/symfony/password-hasher/Hasher/NativePasswordHasher.php
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* Hashes passwords using password_hash().
|
||||
*
|
||||
* @author Elnur Abdurrakhimov <elnur@elnur.pro>
|
||||
* @author Terje Bråten <terje@braten.be>
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
*/
|
||||
final class NativePasswordHasher implements PasswordHasherInterface
|
||||
{
|
||||
use CheckPasswordLengthTrait;
|
||||
|
||||
private $algorithm = \PASSWORD_BCRYPT;
|
||||
private $options;
|
||||
|
||||
/**
|
||||
* @param string|null $algorithm An algorithm supported by password_hash() or null to use the best available algorithm
|
||||
*/
|
||||
public function __construct(int $opsLimit = null, int $memLimit = null, int $cost = null, string $algorithm = null)
|
||||
{
|
||||
$cost = $cost ?? 13;
|
||||
$opsLimit = $opsLimit ?? max(4, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE : 4);
|
||||
$memLimit = $memLimit ?? max(64 * 1024 * 1024, \defined('SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE : 64 * 1024 * 1024);
|
||||
|
||||
if (3 > $opsLimit) {
|
||||
throw new \InvalidArgumentException('$opsLimit must be 3 or greater.');
|
||||
}
|
||||
|
||||
if (10 * 1024 > $memLimit) {
|
||||
throw new \InvalidArgumentException('$memLimit must be 10k or greater.');
|
||||
}
|
||||
|
||||
if ($cost < 4 || 31 < $cost) {
|
||||
throw new \InvalidArgumentException('$cost must be in the range of 4-31.');
|
||||
}
|
||||
|
||||
if (null !== $algorithm) {
|
||||
$algorithms = [1 => \PASSWORD_BCRYPT, '2y' => \PASSWORD_BCRYPT];
|
||||
|
||||
if (\defined('PASSWORD_ARGON2I')) {
|
||||
$algorithms[2] = $algorithms['argon2i'] = \PASSWORD_ARGON2I;
|
||||
}
|
||||
|
||||
if (\defined('PASSWORD_ARGON2ID')) {
|
||||
$algorithms[3] = $algorithms['argon2id'] = \PASSWORD_ARGON2ID;
|
||||
}
|
||||
|
||||
$this->algorithm = $algorithms[$algorithm] ?? $algorithm;
|
||||
}
|
||||
|
||||
$this->options = [
|
||||
'cost' => $cost,
|
||||
'time_cost' => $opsLimit,
|
||||
'memory_cost' => $memLimit >> 10,
|
||||
'threads' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
public function hash(string $plainPassword): string
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
if (\PASSWORD_BCRYPT === $this->algorithm && (72 < \strlen($plainPassword) || false !== strpos($plainPassword, "\0"))) {
|
||||
$plainPassword = base64_encode(hash('sha512', $plainPassword, true));
|
||||
}
|
||||
|
||||
return password_hash($plainPassword, $this->algorithm, $this->options);
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, string $plainPassword): bool
|
||||
{
|
||||
if ('' === $plainPassword || $this->isPasswordTooLong($plainPassword)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 !== strpos($hashedPassword, '$argon')) {
|
||||
// Bcrypt cuts on NUL chars and after 72 bytes
|
||||
if (0 === strpos($hashedPassword, '$2') && (72 < \strlen($plainPassword) || false !== strpos($plainPassword, "\0"))) {
|
||||
$plainPassword = base64_encode(hash('sha512', $plainPassword, true));
|
||||
}
|
||||
|
||||
return password_verify($plainPassword, $hashedPassword);
|
||||
}
|
||||
|
||||
if (\extension_loaded('sodium') && version_compare(\SODIUM_LIBRARY_VERSION, '1.0.14', '>=')) {
|
||||
return sodium_crypto_pwhash_str_verify($hashedPassword, $plainPassword);
|
||||
}
|
||||
|
||||
if (\extension_loaded('libsodium') && version_compare(phpversion('libsodium'), '1.0.14', '>=')) {
|
||||
return \Sodium\crypto_pwhash_str_verify($hashedPassword, $plainPassword);
|
||||
}
|
||||
|
||||
return password_verify($plainPassword, $hashedPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
return password_needs_rehash($hashedPassword, $this->algorithm, $this->options);
|
||||
}
|
||||
}
|
26
vendor/symfony/password-hasher/Hasher/PasswordHasherAwareInterface.php
vendored
Normal file
26
vendor/symfony/password-hasher/Hasher/PasswordHasherAwareInterface.php
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
/**
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
interface PasswordHasherAwareInterface
|
||||
{
|
||||
/**
|
||||
* Gets the name of the password hasher used to hash the password.
|
||||
*
|
||||
* If the method returns null, the standard way to retrieve the password hasher
|
||||
* will be used instead.
|
||||
*/
|
||||
public function getPasswordHasherName(): ?string;
|
||||
}
|
242
vendor/symfony/password-hasher/Hasher/PasswordHasherFactory.php
vendored
Normal file
242
vendor/symfony/password-hasher/Hasher/PasswordHasherFactory.php
vendored
Normal file
@ -0,0 +1,242 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\LogicException;
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
use Symfony\Component\Security\Core\Encoder\EncoderAwareInterface;
|
||||
use Symfony\Component\Security\Core\Encoder\PasswordEncoderInterface;
|
||||
use Symfony\Component\Security\Core\Encoder\PasswordHasherAdapter;
|
||||
|
||||
/**
|
||||
* A generic hasher factory implementation.
|
||||
*
|
||||
* @author Nicolas Grekas <p@tchwork.com>
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
*/
|
||||
class PasswordHasherFactory implements PasswordHasherFactoryInterface
|
||||
{
|
||||
private $passwordHashers;
|
||||
|
||||
/**
|
||||
* @param array<string, PasswordHasherInterface|array> $passwordHashers
|
||||
*/
|
||||
public function __construct(array $passwordHashers)
|
||||
{
|
||||
$this->passwordHashers = $passwordHashers;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getPasswordHasher($user): PasswordHasherInterface
|
||||
{
|
||||
$hasherKey = null;
|
||||
|
||||
if (($user instanceof PasswordHasherAwareInterface && null !== $hasherName = $user->getPasswordHasherName()) || ($user instanceof EncoderAwareInterface && null !== $hasherName = $user->getEncoderName())) {
|
||||
if (!\array_key_exists($hasherName, $this->passwordHashers)) {
|
||||
throw new \RuntimeException(sprintf('The password hasher "%s" was not configured.', $hasherName));
|
||||
}
|
||||
|
||||
$hasherKey = $hasherName;
|
||||
} else {
|
||||
foreach ($this->passwordHashers as $class => $hasher) {
|
||||
if ((\is_object($user) && $user instanceof $class) || (!\is_object($user) && (is_subclass_of($user, $class) || $user == $class))) {
|
||||
$hasherKey = $class;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $hasherKey) {
|
||||
throw new \RuntimeException(sprintf('No password hasher has been configured for account "%s".', \is_object($user) ? get_debug_type($user) : $user));
|
||||
}
|
||||
|
||||
return $this->createHasherUsingAdapter($hasherKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the actual hasher instance.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function createHasher(array $config, bool $isExtra = false): PasswordHasherInterface
|
||||
{
|
||||
if (isset($config['algorithm'])) {
|
||||
$rawConfig = $config;
|
||||
$config = $this->getHasherConfigFromAlgorithm($config);
|
||||
}
|
||||
if (!isset($config['class'])) {
|
||||
throw new \InvalidArgumentException('"class" must be set in '.json_encode($config));
|
||||
}
|
||||
if (!isset($config['arguments'])) {
|
||||
throw new \InvalidArgumentException('"arguments" must be set in '.json_encode($config));
|
||||
}
|
||||
|
||||
$hasher = new $config['class'](...$config['arguments']);
|
||||
if (!$hasher instanceof PasswordHasherInterface && $hasher instanceof PasswordEncoderInterface) {
|
||||
$hasher = new PasswordHasherAdapter($hasher);
|
||||
}
|
||||
|
||||
if ($isExtra || !\in_array($config['class'], [NativePasswordHasher::class, SodiumPasswordHasher::class], true)) {
|
||||
return $hasher;
|
||||
}
|
||||
|
||||
if ($rawConfig ?? null) {
|
||||
$extrapasswordHashers = array_map(function (string $algo) use ($rawConfig): PasswordHasherInterface {
|
||||
$rawConfig['algorithm'] = $algo;
|
||||
|
||||
return $this->createHasher($rawConfig);
|
||||
}, ['pbkdf2', $rawConfig['hash_algorithm'] ?? 'sha512']);
|
||||
} else {
|
||||
$extrapasswordHashers = [new Pbkdf2PasswordHasher(), new MessageDigestPasswordHasher()];
|
||||
}
|
||||
|
||||
return new MigratingPasswordHasher($hasher, ...$extrapasswordHashers);
|
||||
}
|
||||
|
||||
private function createHasherUsingAdapter(string $hasherKey): PasswordHasherInterface
|
||||
{
|
||||
if (!$this->passwordHashers[$hasherKey] instanceof PasswordHasherInterface) {
|
||||
$this->passwordHashers[$hasherKey] = $this->passwordHashers[$hasherKey] instanceof PasswordEncoderInterface
|
||||
? new PasswordHasherAdapter($this->passwordHashers[$hasherKey])
|
||||
: $this->createHasher($this->passwordHashers[$hasherKey])
|
||||
;
|
||||
}
|
||||
|
||||
return $this->passwordHashers[$hasherKey];
|
||||
}
|
||||
|
||||
private function getHasherConfigFromAlgorithm(array $config): array
|
||||
{
|
||||
if ('auto' === $config['algorithm']) {
|
||||
// "plaintext" is not listed as any leaked hashes could then be used to authenticate directly
|
||||
if (SodiumPasswordHasher::isSupported()) {
|
||||
$algorithms = ['native', 'sodium', 'pbkdf2'];
|
||||
} else {
|
||||
$algorithms = ['native', 'pbkdf2'];
|
||||
}
|
||||
|
||||
if ($config['hash_algorithm'] ?? '') {
|
||||
$algorithms[] = $config['hash_algorithm'];
|
||||
}
|
||||
|
||||
$hasherChain = [];
|
||||
foreach ($algorithms as $algorithm) {
|
||||
$config['algorithm'] = $algorithm;
|
||||
$hasherChain[] = $this->createHasher($config, true);
|
||||
}
|
||||
|
||||
return [
|
||||
'class' => MigratingPasswordHasher::class,
|
||||
'arguments' => $hasherChain,
|
||||
];
|
||||
}
|
||||
|
||||
if ($frompasswordHashers = ($config['migrate_from'] ?? false)) {
|
||||
unset($config['migrate_from']);
|
||||
$hasherChain = [$this->createHasher($config, true)];
|
||||
|
||||
foreach ($frompasswordHashers as $name) {
|
||||
if (isset($this->passwordHashers[$name])) {
|
||||
$hasher = $this->createHasherUsingAdapter($name);
|
||||
} else {
|
||||
$hasher = $this->createHasher(['algorithm' => $name], true);
|
||||
}
|
||||
|
||||
$hasherChain[] = $hasher;
|
||||
}
|
||||
|
||||
return [
|
||||
'class' => MigratingPasswordHasher::class,
|
||||
'arguments' => $hasherChain,
|
||||
];
|
||||
}
|
||||
|
||||
switch ($config['algorithm']) {
|
||||
case 'plaintext':
|
||||
return [
|
||||
'class' => PlaintextPasswordHasher::class,
|
||||
'arguments' => [$config['ignore_case'] ?? false],
|
||||
];
|
||||
|
||||
case 'pbkdf2':
|
||||
return [
|
||||
'class' => Pbkdf2PasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['hash_algorithm'] ?? 'sha512',
|
||||
$config['encode_as_base64'] ?? true,
|
||||
$config['iterations'] ?? 1000,
|
||||
$config['key_length'] ?? 40,
|
||||
],
|
||||
];
|
||||
|
||||
case 'bcrypt':
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_BCRYPT;
|
||||
|
||||
return $this->getHasherConfigFromAlgorithm($config);
|
||||
|
||||
case 'native':
|
||||
return [
|
||||
'class' => NativePasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['time_cost'] ?? null,
|
||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||
$config['cost'] ?? null,
|
||||
] + (isset($config['native_algorithm']) ? [3 => $config['native_algorithm']] : []),
|
||||
];
|
||||
|
||||
case 'sodium':
|
||||
return [
|
||||
'class' => SodiumPasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['time_cost'] ?? null,
|
||||
(($config['memory_cost'] ?? 0) << 10) ?: null,
|
||||
],
|
||||
];
|
||||
|
||||
case 'argon2i':
|
||||
if (SodiumPasswordHasher::isSupported() && !\defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||
$config['algorithm'] = 'sodium';
|
||||
} elseif (\defined('PASSWORD_ARGON2I')) {
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_ARGON2I;
|
||||
} else {
|
||||
throw new LogicException(sprintf('Algorithm "argon2i" is not available. Use "%s" instead.', \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13') ? 'argon2id" or "auto' : 'auto'));
|
||||
}
|
||||
|
||||
return $this->getHasherConfigFromAlgorithm($config);
|
||||
|
||||
case 'argon2id':
|
||||
if (($hasSodium = SodiumPasswordHasher::isSupported()) && \defined('SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13')) {
|
||||
$config['algorithm'] = 'sodium';
|
||||
} elseif (\defined('PASSWORD_ARGON2ID')) {
|
||||
$config['algorithm'] = 'native';
|
||||
$config['native_algorithm'] = \PASSWORD_ARGON2ID;
|
||||
} else {
|
||||
throw new LogicException(sprintf('Algorithm "argon2id" is not available. Either use "%s", upgrade to PHP 7.3+ or use libsodium 1.0.15+ instead.', \defined('PASSWORD_ARGON2I') || $hasSodium ? 'argon2i", "auto' : 'auto'));
|
||||
}
|
||||
|
||||
return $this->getHasherConfigFromAlgorithm($config);
|
||||
}
|
||||
|
||||
return [
|
||||
'class' => MessageDigestPasswordHasher::class,
|
||||
'arguments' => [
|
||||
$config['algorithm'],
|
||||
$config['encode_as_base64'] ?? true,
|
||||
$config['iterations'] ?? 5000,
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
33
vendor/symfony/password-hasher/Hasher/PasswordHasherFactoryInterface.php
vendored
Normal file
33
vendor/symfony/password-hasher/Hasher/PasswordHasherFactoryInterface.php
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
|
||||
/**
|
||||
* PasswordHasherFactoryInterface to support different password hashers for different user accounts.
|
||||
*
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface PasswordHasherFactoryInterface
|
||||
{
|
||||
/**
|
||||
* Returns the password hasher to use for the given user.
|
||||
*
|
||||
* @param PasswordHasherAwareInterface|PasswordAuthenticatedUserInterface|string $user
|
||||
*
|
||||
* @throws \RuntimeException When no password hasher could be found for the user
|
||||
*/
|
||||
public function getPasswordHasher($user): PasswordHasherInterface;
|
||||
}
|
90
vendor/symfony/password-hasher/Hasher/Pbkdf2PasswordHasher.php
vendored
Normal file
90
vendor/symfony/password-hasher/Hasher/Pbkdf2PasswordHasher.php
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
use Symfony\Component\PasswordHasher\Exception\LogicException;
|
||||
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* Pbkdf2PasswordHasher uses the PBKDF2 (Password-Based Key Derivation Function 2).
|
||||
*
|
||||
* Providing a high level of Cryptographic security,
|
||||
* PBKDF2 is recommended by the National Institute of Standards and Technology (NIST).
|
||||
*
|
||||
* But also warrants a warning, using PBKDF2 (with a high number of iterations) slows down the process.
|
||||
* PBKDF2 should be used with caution and care.
|
||||
*
|
||||
* @author Sebastiaan Stok <s.stok@rollerscapes.net>
|
||||
* @author Andrew Johnson
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
final class Pbkdf2PasswordHasher implements LegacyPasswordHasherInterface
|
||||
{
|
||||
use CheckPasswordLengthTrait;
|
||||
|
||||
private $algorithm;
|
||||
private $encodeHashAsBase64;
|
||||
private $iterations = 1;
|
||||
private $length;
|
||||
private $encodedLength = -1;
|
||||
|
||||
/**
|
||||
* @param string $algorithm The digest algorithm to use
|
||||
* @param bool $encodeHashAsBase64 Whether to base64 encode the password hash
|
||||
* @param int $iterations The number of iterations to use to stretch the password hash
|
||||
* @param int $length Length of derived key to create
|
||||
*/
|
||||
public function __construct(string $algorithm = 'sha512', bool $encodeHashAsBase64 = true, int $iterations = 1000, int $length = 40)
|
||||
{
|
||||
$this->algorithm = $algorithm;
|
||||
$this->encodeHashAsBase64 = $encodeHashAsBase64;
|
||||
$this->length = $length;
|
||||
|
||||
try {
|
||||
$this->encodedLength = \strlen($this->hash('', 'salt'));
|
||||
} catch (\LogicException $e) {
|
||||
// ignore unsupported algorithm
|
||||
}
|
||||
|
||||
$this->iterations = $iterations;
|
||||
}
|
||||
|
||||
public function hash(string $plainPassword, string $salt = null): string
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
if (!\in_array($this->algorithm, hash_algos(), true)) {
|
||||
throw new LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
|
||||
}
|
||||
|
||||
$digest = hash_pbkdf2($this->algorithm, $plainPassword, $salt, $this->iterations, $this->length, true);
|
||||
|
||||
return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, string $plainPassword, string $salt = null): bool
|
||||
{
|
||||
if (\strlen($hashedPassword) !== $this->encodedLength || false !== strpos($hashedPassword, '$')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !$this->isPasswordTooLong($plainPassword) && hash_equals($hashedPassword, $this->hash($plainPassword, $salt));
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
82
vendor/symfony/password-hasher/Hasher/PlaintextPasswordHasher.php
vendored
Normal file
82
vendor/symfony/password-hasher/Hasher/PlaintextPasswordHasher.php
vendored
Normal file
@ -0,0 +1,82 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
use Symfony\Component\PasswordHasher\LegacyPasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* PlaintextPasswordHasher does not do any hashing but is useful in testing environments.
|
||||
*
|
||||
* As this hasher is not cryptographically secure, usage of it in production environments is discouraged.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class PlaintextPasswordHasher implements LegacyPasswordHasherInterface
|
||||
{
|
||||
use CheckPasswordLengthTrait;
|
||||
|
||||
private $ignorePasswordCase;
|
||||
|
||||
/**
|
||||
* @param bool $ignorePasswordCase Compare password case-insensitive
|
||||
*/
|
||||
public function __construct(bool $ignorePasswordCase = false)
|
||||
{
|
||||
$this->ignorePasswordCase = $ignorePasswordCase;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function hash(string $plainPassword, string $salt = null): string
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
return $this->mergePasswordAndSalt($plainPassword, $salt);
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, string $plainPassword, string $salt = null): bool
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pass2 = $this->mergePasswordAndSalt($plainPassword, $salt);
|
||||
|
||||
if (!$this->ignorePasswordCase) {
|
||||
return hash_equals($hashedPassword, $pass2);
|
||||
}
|
||||
|
||||
return hash_equals(strtolower($hashedPassword), strtolower($pass2));
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private function mergePasswordAndSalt(string $password, ?string $salt): string
|
||||
{
|
||||
if (empty($salt)) {
|
||||
return $password;
|
||||
}
|
||||
|
||||
if (false !== strrpos($salt, '{') || false !== strrpos($salt, '}')) {
|
||||
throw new \InvalidArgumentException('Cannot use { or } in salt.');
|
||||
}
|
||||
|
||||
return $password.'{'.$salt.'}';
|
||||
}
|
||||
}
|
114
vendor/symfony/password-hasher/Hasher/SodiumPasswordHasher.php
vendored
Normal file
114
vendor/symfony/password-hasher/Hasher/SodiumPasswordHasher.php
vendored
Normal file
@ -0,0 +1,114 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\PasswordHasher\Exception\InvalidPasswordException;
|
||||
use Symfony\Component\PasswordHasher\Exception\LogicException;
|
||||
use Symfony\Component\PasswordHasher\PasswordHasherInterface;
|
||||
|
||||
/**
|
||||
* Hashes passwords using libsodium.
|
||||
*
|
||||
* @author Robin Chalas <robin.chalas@gmail.com>
|
||||
* @author Zan Baldwin <hello@zanbaldwin.com>
|
||||
* @author Dominik Müller <dominik.mueller@jkweb.ch>
|
||||
*/
|
||||
final class SodiumPasswordHasher implements PasswordHasherInterface
|
||||
{
|
||||
use CheckPasswordLengthTrait;
|
||||
|
||||
private $opsLimit;
|
||||
private $memLimit;
|
||||
|
||||
public function __construct(int $opsLimit = null, int $memLimit = null)
|
||||
{
|
||||
if (!self::isSupported()) {
|
||||
throw new LogicException('Libsodium is not available. You should either install the sodium extension or use a different password hasher.');
|
||||
}
|
||||
|
||||
$this->opsLimit = $opsLimit ?? max(4, \defined('SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE : 4);
|
||||
$this->memLimit = $memLimit ?? max(64 * 1024 * 1024, \defined('SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE') ? \SODIUM_CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE : 64 * 1024 * 1024);
|
||||
|
||||
if (3 > $this->opsLimit) {
|
||||
throw new \InvalidArgumentException('$opsLimit must be 3 or greater.');
|
||||
}
|
||||
|
||||
if (10 * 1024 > $this->memLimit) {
|
||||
throw new \InvalidArgumentException('$memLimit must be 10k or greater.');
|
||||
}
|
||||
}
|
||||
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return version_compare(\extension_loaded('sodium') ? \SODIUM_LIBRARY_VERSION : phpversion('libsodium'), '1.0.14', '>=');
|
||||
}
|
||||
|
||||
public function hash(string $plainPassword): string
|
||||
{
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
throw new InvalidPasswordException();
|
||||
}
|
||||
|
||||
if (\function_exists('sodium_crypto_pwhash_str')) {
|
||||
return sodium_crypto_pwhash_str($plainPassword, $this->opsLimit, $this->memLimit);
|
||||
}
|
||||
|
||||
if (\extension_loaded('libsodium')) {
|
||||
return \Sodium\crypto_pwhash_str($plainPassword, $this->opsLimit, $this->memLimit);
|
||||
}
|
||||
|
||||
throw new LogicException('Libsodium is not available. You should either install the sodium extension or use a different password hasher.');
|
||||
}
|
||||
|
||||
public function verify(string $hashedPassword, string $plainPassword): bool
|
||||
{
|
||||
if ('' === $plainPassword) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isPasswordTooLong($plainPassword)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 !== strpos($hashedPassword, '$argon')) {
|
||||
if (0 === strpos($hashedPassword, '$2') && (72 < \strlen($plainPassword) || false !== strpos($plainPassword, "\0"))) {
|
||||
$plainPassword = base64_encode(hash('sha512', $plainPassword, true));
|
||||
}
|
||||
|
||||
// Accept validating non-argon passwords for seamless migrations
|
||||
return password_verify($plainPassword, $hashedPassword);
|
||||
}
|
||||
|
||||
if (\function_exists('sodium_crypto_pwhash_str_verify')) {
|
||||
return sodium_crypto_pwhash_str_verify($hashedPassword, $plainPassword);
|
||||
}
|
||||
|
||||
if (\extension_loaded('libsodium')) {
|
||||
return \Sodium\crypto_pwhash_str_verify($hashedPassword, $plainPassword);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function needsRehash(string $hashedPassword): bool
|
||||
{
|
||||
if (\function_exists('sodium_crypto_pwhash_str_needs_rehash')) {
|
||||
return sodium_crypto_pwhash_str_needs_rehash($hashedPassword, $this->opsLimit, $this->memLimit);
|
||||
}
|
||||
|
||||
if (\extension_loaded('libsodium')) {
|
||||
return \Sodium\crypto_pwhash_str_needs_rehash($hashedPassword, $this->opsLimit, $this->memLimit);
|
||||
}
|
||||
|
||||
throw new LogicException('Libsodium is not available. You should either install the sodium extension or use a different password hasher.');
|
||||
}
|
||||
}
|
116
vendor/symfony/password-hasher/Hasher/UserPasswordHasher.php
vendored
Normal file
116
vendor/symfony/password-hasher/Hasher/UserPasswordHasher.php
vendored
Normal file
@ -0,0 +1,116 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
/**
|
||||
* Hashes passwords based on the user and the PasswordHasherFactory.
|
||||
*
|
||||
* @author Ariel Ferrandini <arielferrandini@gmail.com>
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class UserPasswordHasher implements UserPasswordHasherInterface
|
||||
{
|
||||
private $hasherFactory;
|
||||
|
||||
public function __construct(PasswordHasherFactoryInterface $hasherFactory)
|
||||
{
|
||||
$this->hasherFactory = $hasherFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PasswordAuthenticatedUserInterface $user
|
||||
*/
|
||||
public function hashPassword($user, string $plainPassword): string
|
||||
{
|
||||
if (!$user instanceof PasswordAuthenticatedUserInterface) {
|
||||
if (!$user instanceof UserInterface) {
|
||||
throw new \TypeError(sprintf('Expected an instance of "%s" as first argument, but got "%s".', UserInterface::class, get_debug_type($user)));
|
||||
}
|
||||
trigger_deprecation('symfony/password-hasher', '5.3', 'The "%s()" method expects a "%s" instance as first argument. Not implementing it in class "%s" is deprecated.', __METHOD__, PasswordAuthenticatedUserInterface::class, get_debug_type($user));
|
||||
}
|
||||
|
||||
$salt = null;
|
||||
|
||||
if ($user instanceof LegacyPasswordAuthenticatedUserInterface) {
|
||||
$salt = $user->getSalt();
|
||||
} elseif ($user instanceof UserInterface) {
|
||||
$salt = method_exists($user, 'getSalt') ? $user->getSalt() : null;
|
||||
|
||||
if ($salt) {
|
||||
trigger_deprecation('symfony/password-hasher', '5.3', 'Returning a string from "getSalt()" without implementing the "%s" interface is deprecated, the "%s" class should implement it.', LegacyPasswordAuthenticatedUserInterface::class, get_debug_type($user));
|
||||
}
|
||||
}
|
||||
|
||||
$hasher = $this->hasherFactory->getPasswordHasher($user);
|
||||
|
||||
return $hasher->hash($plainPassword, $salt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PasswordAuthenticatedUserInterface $user
|
||||
*/
|
||||
public function isPasswordValid($user, string $plainPassword): bool
|
||||
{
|
||||
if (!$user instanceof PasswordAuthenticatedUserInterface) {
|
||||
if (!$user instanceof UserInterface) {
|
||||
throw new \TypeError(sprintf('Expected an instance of "%s" as first argument, but got "%s".', UserInterface::class, get_debug_type($user)));
|
||||
}
|
||||
trigger_deprecation('symfony/password-hasher', '5.3', 'The "%s()" method expects a "%s" instance as first argument. Not implementing it in class "%s" is deprecated.', __METHOD__, PasswordAuthenticatedUserInterface::class, get_debug_type($user));
|
||||
}
|
||||
|
||||
$salt = null;
|
||||
|
||||
if ($user instanceof LegacyPasswordAuthenticatedUserInterface) {
|
||||
$salt = $user->getSalt();
|
||||
} elseif ($user instanceof UserInterface) {
|
||||
$salt = $user->getSalt();
|
||||
|
||||
if (null !== $salt) {
|
||||
trigger_deprecation('symfony/password-hasher', '5.3', 'Returning a string from "getSalt()" without implementing the "%s" interface is deprecated, the "%s" class should implement it.', LegacyPasswordAuthenticatedUserInterface::class, get_debug_type($user));
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $user->getPassword()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$hasher = $this->hasherFactory->getPasswordHasher($user);
|
||||
|
||||
return $hasher->verify($user->getPassword(), $plainPassword, $salt);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PasswordAuthenticatedUserInterface $user
|
||||
*/
|
||||
public function needsRehash($user): bool
|
||||
{
|
||||
if (null === $user->getPassword()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$user instanceof PasswordAuthenticatedUserInterface) {
|
||||
if (!$user instanceof UserInterface) {
|
||||
throw new \TypeError(sprintf('Expected an instance of "%s" as first argument, but got "%s".', UserInterface::class, get_debug_type($user)));
|
||||
}
|
||||
trigger_deprecation('symfony/password-hasher', '5.3', 'The "%s()" method expects a "%s" instance as first argument. Not implementing it in class "%s" is deprecated.', __METHOD__, PasswordAuthenticatedUserInterface::class, get_debug_type($user));
|
||||
}
|
||||
|
||||
$hasher = $this->hasherFactory->getPasswordHasher($user);
|
||||
|
||||
return $hasher->needsRehash($user->getPassword());
|
||||
}
|
||||
}
|
27
vendor/symfony/password-hasher/Hasher/UserPasswordHasherInterface.php
vendored
Normal file
27
vendor/symfony/password-hasher/Hasher/UserPasswordHasherInterface.php
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
<?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\PasswordHasher\Hasher;
|
||||
|
||||
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
|
||||
|
||||
/**
|
||||
* Interface for the user password hasher service.
|
||||
*
|
||||
* @author Ariel Ferrandini <arielferrandini@gmail.com>
|
||||
*
|
||||
* @method string hashPassword(PasswordAuthenticatedUserInterface $user, string $plainPassword) Hashes the plain password for the given user.
|
||||
* @method bool isPasswordValid(PasswordAuthenticatedUserInterface $user, string $plainPassword) Checks if the plaintext password matches the user's password.
|
||||
* @method bool needsRehash(PasswordAuthenticatedUserInterface $user) Checks if an encoded password would benefit from rehashing.
|
||||
*/
|
||||
interface UserPasswordHasherInterface
|
||||
{
|
||||
}
|
Reference in New Issue
Block a user