Passed
Pull Request — master (#72)
by Daniel
05:33
created

EmailAddressManager::confirmNewEmailAddress()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 35
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 30

Importance

Changes 0
Metric Value
cc 5
eloc 24
nc 5
nop 3
dl 0
loc 35
ccs 0
cts 23
cp 0
crap 30
rs 9.2248
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\Helper\User;
15
16
use Doctrine\ORM\EntityManagerInterface;
17
use Silverback\ApiComponentsBundle\EventListener\Api\UserEventListener;
18
use Silverback\ApiComponentsBundle\Exception\InvalidArgumentException;
19
use Silverback\ApiComponentsBundle\Exception\UnexpectedValueException;
20
use Silverback\ApiComponentsBundle\Repository\User\UserRepository;
21
use Symfony\Component\Security\Core\Encoder\EncoderFactoryInterface;
22
23
/**
24
 * @author Daniel West <[email protected]>
25
 */
26
class EmailAddressManager
27
{
28
    private EntityManagerInterface $entityManager;
29
    private UserRepository $userRepository;
30
    private EncoderFactoryInterface $encoderFactory;
31
    private UserDataProcessor $userDataProcessor;
32
    private UserEventListener $userEventListener;
33
34
    public function __construct(
35
        EntityManagerInterface $entityManager,
36
        UserRepository $userRepository,
37
        EncoderFactoryInterface $encoderFactory,
38
        UserDataProcessor $userDataProcessor,
39
        UserEventListener $userEventListener
40
    ) {
41
        $this->entityManager = $entityManager;
42
        $this->userRepository = $userRepository;
43
        $this->encoderFactory = $encoderFactory;
44
        $this->userDataProcessor = $userDataProcessor;
45
        $this->userEventListener = $userEventListener;
46
    }
47
48
    public function confirmNewEmailAddress(string $username, string $email, string $token): void
49
    {
50
        if ('' === $email) {
51
            throw new InvalidArgumentException('User not found');
52
        }
53
        $user = $this->userRepository->findOneByUsernameAndNewEmailAddress($username, $email);
54
        if (!$user) {
55
            throw new InvalidArgumentException('User not found');
56
        }
57
        $previousUser = clone $user;
58
        $encoder = $this->encoderFactory->getEncoder($user);
59
        if (!$encoder->isPasswordValid($user->getNewEmailConfirmationToken(), $token, $user->getSalt())) {
0 ignored issues
show
Bug introduced by
It seems like $user->getNewEmailConfirmationToken() can also be of type null; however, parameter $encoded of Symfony\Component\Securi...face::isPasswordValid() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

59
        if (!$encoder->isPasswordValid(/** @scrutinizer ignore-type */ $user->getNewEmailConfirmationToken(), $token, $user->getSalt())) {
Loading history...
Bug introduced by
Are you sure the usage of $user->getSalt() targeting Silverback\ApiComponents...AbstractUser::getSalt() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

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.

Loading history...
60
            throw new InvalidArgumentException('Invalid token');
61
        }
62
63
        // Check if another user now exists with this new email address before persisting!
64
        $existingUser = $this->userRepository->findExistingUserByNewEmail($user);
65
        if ($existingUser) {
66
            $user
67
                ->setNewEmailAddress(null)
68
                ->setNewEmailConfirmationToken(null);
69
70
            $this->entityManager->flush();
71
            throw new UnexpectedValueException('Another user now exists with that email. Verification aborted.');
72
        }
73
74
        $user
75
            ->setEmailAddress($user->getNewEmailAddress())
76
            ->setNewEmailAddress(null)
77
            ->setEmailAddressVerified(false)
78
            ->setNewEmailConfirmationToken(null);
79
80
        $this->userDataProcessor->processChanges($user, $previousUser);
81
        $this->entityManager->flush();
82
        $this->userEventListener->postWrite($user, $previousUser);
83
    }
84
85
    public function verifyEmailAddress(string $username, string $token): void
86
    {
87
        $user = $this->userRepository->findOneBy([
88
            'username' => $username,
89
        ]);
90
        if (!$user) {
91
            throw new InvalidArgumentException('User not found');
92
        }
93
94
        $encoder = $this->encoderFactory->getEncoder($user);
95
        if (!$encoder->isPasswordValid($user->getEmailAddressVerifyToken(), $token, $user->getSalt())) {
0 ignored issues
show
Bug introduced by
It seems like $user->getEmailAddressVerifyToken() can also be of type null; however, parameter $encoded of Symfony\Component\Securi...face::isPasswordValid() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

95
        if (!$encoder->isPasswordValid(/** @scrutinizer ignore-type */ $user->getEmailAddressVerifyToken(), $token, $user->getSalt())) {
Loading history...
Bug introduced by
Are you sure the usage of $user->getSalt() targeting Silverback\ApiComponents...AbstractUser::getSalt() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

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.

Loading history...
96
            throw new InvalidArgumentException('Invalid token');
97
        }
98
99
        $user->setEmailAddressVerified(true);
100
        $this->entityManager->flush();
101
    }
102
}
103