Completed
Push — master ( 5b6d3c...e19d53 )
by Marcel
03:17
created

ForgotPasswordController::change()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 26
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 16
CRAP Score 5.0342

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 18
c 1
b 0
f 0
nc 5
nop 3
dl 0
loc 26
ccs 16
cts 18
cp 0.8889
crap 5.0342
rs 9.3554
1
<?php
2
3
namespace App\Controller;
4
5
use App\Entity\PasswordResetToken;
6
use App\Repository\UserRepositoryInterface;
7
use App\Security\ForgotPassword\ForgotPasswordManager;
8
use App\Security\PasswordStrengthHelper;
9
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
10
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
11
use Symfony\Component\HttpFoundation\Request;
12
use Symfony\Component\Routing\Annotation\Route;
13
use Symfony\Component\Security\Csrf\CsrfToken;
14
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
15
use Symfony\Contracts\Translation\TranslatorInterface;
16
17
class ForgotPasswordController extends AbstractController {
18
19
    private const CSRF_TOKEN_ID = 'forgot_pw';
20
21
    private const CSRF_TOKEN_KEY = '_csrf_token';
22
    private const USERNAME_KEY = '_username';
23
    private const PASSWORD_KEY = '_password';
24
    private const REPEAT_PASSWORD_KEY = '_repeat_password';
25
26
    private $manager;
27
    private $csrfTokenManager;
28
    private $translator;
29
30 1
    public function __construct(ForgotPasswordManager $manager, CsrfTokenManagerInterface $csrfTokenManager, TranslatorInterface $translator) {
31 1
        $this->manager = $manager;
32 1
        $this->csrfTokenManager = $csrfTokenManager;
33 1
        $this->translator = $translator;
34 1
    }
35
36 1
    private function isCsrfTokenFromRequestValid(Request $request): bool {
37 1
        $tokenValue = $request->request->get(static::CSRF_TOKEN_KEY);
38 1
        $token = new CsrfToken(static::CSRF_TOKEN_ID, $tokenValue);
39
40 1
        return $this->csrfTokenManager->isTokenValid($token);
41
    }
42
43
    private function getCsrfTokenMessage(): string {
44
        return $this->translator->trans('Invalid CSRF token.', [], 'security');
45
    }
46
47
    /**
48
     * @Route("/forgot_pw", name="forgot_password")
49
     */
50 1
    public function request(Request $request, CsrfTokenManagerInterface $csrfTokenManager, TranslatorInterface $translator, UserRepositoryInterface $userRepository) {
51 1
        if($request->isMethod('POST')) {
52 1
            $username = $request->request->get('_username');
53 1
            $user = $userRepository->findOneByUsername($username);
54
55 1
            if($this->isCsrfTokenFromRequestValid($request) !== true) {
56
                $this->addFlash('error', $this->getCsrfTokenMessage());
57 1
            } else if ($username === null) {
58
                $this->addFlash('error', 'forgot_pw.request.username_empty');
59 1
            } else if($user !== null && $this->manager->canResetPassword($user) !== true) {
60
                $this->addFlash('error', 'forgot_pw.request.cannot_change');
61
                return $this->redirectToRoute('login');
62
            } else {
63 1
                $this->manager->resetPassword($user);
64 1
                $this->addFlash('success', 'forgot_pw.request.success');
65
66 1
                return $this->redirectToRoute('login');
67
            }
68
        }
69
70 1
        return $this->render('auth/forgot_pw.html.twig', [
71 1
            'csrfTokenId' => static::CSRF_TOKEN_ID
72
        ]);
73
    }
74
75
    /**
76
     * @Route("/forgot_pw/{token}", name="change_password")
77
     * @ParamConverter("token", options={"mapping": {"token": "token"}})
78
     */
79 1
    public function change(PasswordResetToken $token, Request $request, PasswordStrengthHelper $passwordStrengthHelper) {
80 1
        if($request->isMethod('POST')) {
81 1
            $password = $request->request->get('_password');
82 1
            $repeatPassword = $request->request->get('_repeat_password');
83
84 1
            $violations = $passwordStrengthHelper->validatePassword($password);
85
86 1
            if($this->isCsrfTokenFromRequestValid($request) !== true) {
87
                $this->addFlash('error', $this->getCsrfTokenMessage());
88 1
            } else if($violations->count() > 0) {
89
                // flashes are added in twig template
90 1
            } else if($password !== $repeatPassword) {
91
                $this->addFlash('error', 'forgot_pw.change.password_error');
92
            } else {
93 1
                $this->manager->updatePassword($token, $password);
94 1
                $this->addFlash('success', 'forgot_pw.change.success');
95
96 1
                return $this->redirectToRoute('login');
97
            }
98
        }
99
100 1
        return $this->render('auth/change_pw.twig', [
101 1
            'user' => $token->getUser(),
102 1
            'csrfTokenId' => static::CSRF_TOKEN_ID,
103 1
            'token' => $token,
104 1
            'violations' => $violations ?? null
105
        ]);
106
    }
107
}