1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the Silverback API Components Bundle Project |
5
|
|
|
* |
6
|
|
|
* (c) Daniel West <[email protected]> |
7
|
|
|
* |
8
|
|
|
* For the full copyright and license information, please view the LICENSE |
9
|
|
|
* file that was distributed with this source code. |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
declare(strict_types=1); |
13
|
|
|
|
14
|
|
|
namespace Silverback\ApiComponentsBundle\Helper\User; |
15
|
|
|
|
16
|
|
|
use Silverback\ApiComponentsBundle\Entity\User\AbstractUser; |
17
|
|
|
use Silverback\ApiComponentsBundle\Exception\InvalidArgumentException; |
18
|
|
|
use Silverback\ApiComponentsBundle\Exception\UnexpectedValueException; |
19
|
|
|
use Silverback\ApiComponentsBundle\Repository\User\UserRepository; |
20
|
|
|
use Silverback\ApiComponentsBundle\Security\TokenGenerator; |
21
|
|
|
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface; |
22
|
|
|
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface; |
23
|
|
|
|
24
|
|
|
/** |
25
|
|
|
* @author Daniel West <[email protected]> |
26
|
|
|
*/ |
27
|
|
|
class UserDataProcessor |
28
|
|
|
{ |
29
|
|
|
private UserPasswordEncoderInterface $passwordEncoder; |
30
|
|
|
private UserRepository $userRepository; |
31
|
|
|
private EncoderFactoryInterface $encoderFactory; |
32
|
|
|
private bool $initialEmailVerifiedState; |
33
|
|
|
private bool $verifyEmailOnRegister; |
34
|
|
|
private bool $verifyEmailOnChange; |
35
|
|
|
private int $tokenTtl; |
36
|
|
|
|
37
|
7 |
|
public function __construct( |
38
|
|
|
UserPasswordEncoderInterface $passwordEncoder, |
39
|
|
|
UserRepository $userRepository, |
40
|
|
|
EncoderFactoryInterface $encoderFactory, |
41
|
|
|
bool $initialEmailVerifiedState, |
42
|
|
|
bool $verifyEmailOnRegister, |
43
|
|
|
bool $verifyEmailOnChange, |
44
|
|
|
int $tokenTtl = 8600 |
45
|
|
|
) { |
46
|
7 |
|
$this->passwordEncoder = $passwordEncoder; |
47
|
7 |
|
$this->userRepository = $userRepository; |
48
|
7 |
|
$this->encoderFactory = $encoderFactory; |
49
|
7 |
|
$this->initialEmailVerifiedState = $initialEmailVerifiedState; |
50
|
7 |
|
$this->verifyEmailOnRegister = $verifyEmailOnRegister; |
51
|
7 |
|
$this->verifyEmailOnChange = $verifyEmailOnChange; |
52
|
7 |
|
$this->tokenTtl = $tokenTtl; |
53
|
7 |
|
} |
54
|
|
|
|
55
|
|
|
public function updatePasswordConfirmationToken(string $usernameQuery): ?AbstractUser |
56
|
|
|
{ |
57
|
|
|
$user = $this->userRepository->findOneBy(['username' => $usernameQuery]); |
58
|
|
|
if (!$user) { |
59
|
|
|
throw new InvalidArgumentException('Username not found'); |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
if ($user->isPasswordRequestLimitReached($this->tokenTtl)) { |
63
|
|
|
return null; |
64
|
|
|
} |
65
|
|
|
|
66
|
|
|
$username = $user->getUsername(); |
67
|
|
|
if (!$username) { |
68
|
|
|
throw new UnexpectedValueException(sprintf('The entity %s should have a username set to send a password reset email.', AbstractUser::class)); |
69
|
|
|
} |
70
|
|
|
$user->setNewPasswordConfirmationToken($this->passwordEncoder->encodePassword($user, $token = TokenGenerator::generateToken())); |
71
|
|
|
$user->plainNewPasswordConfirmationToken = $token; |
72
|
|
|
$user->setPasswordRequestedAt(new \DateTime()); |
73
|
|
|
|
74
|
|
|
return $user; |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
public function passwordReset(string $username, string $token, string $newPassword): ?AbstractUser |
78
|
|
|
{ |
79
|
|
|
$user = $this->userRepository->findOneWithPasswordResetToken($username); |
80
|
|
|
if (!$user) { |
81
|
|
|
return null; |
82
|
|
|
} |
83
|
|
|
$encoder = $this->encoderFactory->getEncoder($user); |
84
|
|
|
if (!$encoder->isPasswordValid($user->getNewPasswordConfirmationToken(), $token, $user->getSalt())) { |
|
|
|
|
85
|
|
|
return null; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
$user->setPlainPassword($newPassword); |
89
|
|
|
$user->setNewPasswordConfirmationToken(null); |
90
|
|
|
$user->setPasswordRequestedAt(null); |
91
|
|
|
$this->encodePassword($user); |
92
|
|
|
|
93
|
|
|
return $user; |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
public function processChanges(AbstractUser $user, ?AbstractUser $previousUser): void |
97
|
|
|
{ |
98
|
|
|
$this->encodePassword($user); |
99
|
|
|
if (!$previousUser) { |
100
|
|
|
$user->setEmailAddressVerified($this->initialEmailVerifiedState); |
101
|
|
|
if (!$this->initialEmailVerifiedState && $this->verifyEmailOnRegister) { |
102
|
|
|
$user->setEmailAddressVerifyToken($this->passwordEncoder->encodePassword($user, $token = TokenGenerator::generateToken())); |
103
|
|
|
$user->plainEmailAddressVerifyToken = $token; |
104
|
|
|
} |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
if ($previousUser) { |
108
|
|
|
if ($this->verifyEmailOnChange && $user->getEmailAddress() !== $previousUser->getEmailAddress()) { |
109
|
|
|
$user->setEmailAddressVerifyToken($this->passwordEncoder->encodePassword($user, $token = TokenGenerator::generateToken())); |
110
|
|
|
$user->plainEmailAddressVerifyToken = $token; |
111
|
|
|
} |
112
|
|
|
if (($newEmail = $user->getNewEmailAddress()) !== $previousUser->getNewEmailAddress()) { |
113
|
|
|
if ($newEmail) { |
114
|
|
|
$user->setNewEmailConfirmationToken($this->passwordEncoder->encodePassword($user, $token = TokenGenerator::generateToken())); |
115
|
|
|
$user->plainNewEmailConfirmationToken = $token; |
116
|
|
|
} else { |
117
|
|
|
// invalidate any existing requests |
118
|
|
|
$user->setNewEmailConfirmationToken(null); |
119
|
|
|
} |
120
|
|
|
} |
121
|
|
|
} |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
private function encodePassword(AbstractUser $entity): bool |
125
|
|
|
{ |
126
|
|
|
if (!$entity->getPlainPassword()) { |
127
|
|
|
return false; |
128
|
|
|
} |
129
|
|
|
$encoded = $this->passwordEncoder->encodePassword($entity, $entity->getPlainPassword()); |
130
|
|
|
$entity->setPassword($encoded); |
131
|
|
|
$entity->eraseCredentials(); |
132
|
|
|
|
133
|
|
|
return true; |
134
|
|
|
} |
135
|
|
|
} |
136
|
|
|
|
This check looks for function or method calls that always return null and whose return value is used.
The method
getObject()
can return nothing but null, so it makes no sense to use the return value.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.