Passed
Push — master ( 413ea4...a7ed20 )
by Daniel
22:03 queued 16:10
created

PasswordManager::persistPlainPassword()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 7
ccs 0
cts 5
cp 0
crap 2
rs 10
c 0
b 0
f 0
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\Manager\User;
15
16
use DateTime;
17
use Doctrine\ORM\EntityManagerInterface;
18
use Silverback\ApiComponentsBundle\Entity\User\AbstractUser;
19
use Silverback\ApiComponentsBundle\Exception\InvalidArgumentException;
20
use Silverback\ApiComponentsBundle\Mailer\UserMailer;
21
use Silverback\ApiComponentsBundle\Repository\User\UserRepository;
22
use Silverback\ApiComponentsBundle\Security\TokenGenerator;
23
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
24
use Symfony\Component\Security\Core\Exception\AuthenticationException;
25
use Symfony\Component\Validator\Validator\ValidatorInterface;
26
27
/**
28
 * @author Daniel West <[email protected]>
29
 */
30
class PasswordManager
31
{
32
    private UserMailer $userMailer;
33
    private EntityManagerInterface $entityManager;
34
    private ValidatorInterface $validator;
35
    private UserRepository $userRepository;
36
    private int $tokenTtl;
37
38
    public function __construct(
39
        UserMailer $userMailer,
40
        EntityManagerInterface $entityManager,
41
        ValidatorInterface $validator,
42
        UserRepository $userRepository,
43
        int $tokenTtl = 8600
44
    ) {
45
        $this->userMailer = $userMailer;
46
        $this->entityManager = $entityManager;
47
        $this->validator = $validator;
48
        $this->userRepository = $userRepository;
49
        $this->tokenTtl = $tokenTtl;
50
    }
51
52
    public function requestResetEmail(string $usernameQuery): void
53
    {
54
        $user = $this->userRepository->findOneBy(['username' => $usernameQuery]);
55
        if (!$user) {
56
            throw new NotFoundHttpException();
57
        }
58
59
        if ($user->isPasswordRequestLimitReached($this->tokenTtl)) {
60
            return;
61
        }
62
63
        $username = $user->getUsername();
64
        if (!$username) {
65
            throw new InvalidArgumentException(sprintf('The entity %s should have a username set to send a password reset email.', AbstractUser::class));
66
        }
67
        $user->setNewPasswordConfirmationToken(TokenGenerator::generateToken());
68
        $user->setPasswordRequestedAt(new DateTime());
69
        $this->userMailer->sendPasswordResetEmail($user);
70
        $this->entityManager->flush();
71
    }
72
73
    public function passwordReset(string $username, string $token, string $newPassword): void
74
    {
75
        $user = $this->userRepository->findOneByPasswordResetToken(
76
            $username,
77
            $token
78
        );
79
        if (!$user) {
80
            throw new NotFoundHttpException();
81
        }
82
83
        $user->setPlainPassword($newPassword);
84
        $user->setNewPasswordConfirmationToken(null);
85
        $user->setPasswordRequestedAt(null);
86
        $errors = $this->validator->validate($user, null, ['password_reset']);
87
        if (\count($errors)) {
88
            throw new AuthenticationException('The password entered is not valid');
89
        }
90
        $this->persistPlainPassword($user);
91
    }
92
93
    public function persistPlainPassword(AbstractUser $user): AbstractUser
94
    {
95
        $this->entityManager->persist($user);
96
        $this->entityManager->flush();
97
        $user->eraseCredentials();
98
99
        return $user;
100
    }
101
}
102