Completed
Push — master ( d27d79...effeb0 )
by Craig
05:53
created

LostPasswordVerificationHelper   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 127
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 1
Bugs 1 Features 0
Metric Value
dl 0
loc 127
rs 10
c 1
b 1
f 0
wmc 11
lcom 1
cbo 4

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A createLostPasswordId() 0 23 3
B decodeLostPasswordId() 0 23 4
A checkConfirmationCode() 0 17 3
1
<?php
2
3
/*
4
 * This file is part of the Zikula package.
5
 *
6
 * Copyright Zikula Foundation - http://zikula.org/
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
namespace Zikula\ZAuthModule\Helper;
13
14
use Zikula\ExtensionsModule\Api\VariableApi;
15
use Zikula\ZAuthModule\Api\PasswordApi;
16
use Zikula\ZAuthModule\Entity\AuthenticationMappingEntity;
17
use Zikula\ZAuthModule\Entity\RepositoryInterface\UserVerificationRepositoryInterface;
18
use Zikula\ZAuthModule\Entity\UserVerificationEntity;
19
use Zikula\ZAuthModule\ZAuthConstant;
20
21
class LostPasswordVerificationHelper
22
{
23
    /**
24
     * @var UserVerificationRepositoryInterface
25
     */
26
    private $userVerificationRepository;
27
28
    /**
29
     * @var VariableApi
30
     */
31
    private $variableApi;
32
33
    /**
34
     * @var PasswordApi
35
     */
36
    private $passwordApi;
37
38
    /**
39
     * LostPasswordVerificationHelper constructor.
40
     *
41
     * @param UserVerificationRepositoryInterface $userVerificationRepository
42
     * @param VariableApi                         $variableApi
43
     */
44
    public function __construct(UserVerificationRepositoryInterface $userVerificationRepository, VariableApi $variableApi, PasswordApi $passwordApi)
45
    {
46
        $this->userVerificationRepository = $userVerificationRepository;
47
        $this->variableApi = $variableApi;
48
        $this->passwordApi = $passwordApi;
49
    }
50
51
    /**
52
     * Concatenation delimiter
53
     */
54
    private $delimiter = '#';
55
56
    /**
57
     * Amount of encoding iterations
58
     */
59
    private $iterations = 3;
60
61
    /**
62
     * Creates an identifier for the lost password link.
63
     * This link carries the user's id, name and email address as well as the actual confirmation code.
64
     *
65
     * @param AuthenticationMappingEntity $mapping
66
     * @return string The created identifier
67
     */
68
    public function createLostPasswordId(AuthenticationMappingEntity $mapping)
69
    {
70
        $confirmationCode = $this->delimiter;
71
        while (false !== strpos($confirmationCode, $this->delimiter)) {
72
            $confirmationCode = $this->passwordApi->generatePassword();
73
        }
74
        $this->userVerificationRepository->setVerificationCode($mapping->getUid(), ZAuthConstant::VERIFYCHGTYPE_PWD, $this->passwordApi->getHashedPassword($confirmationCode));
75
76
        $params = [
77
            $mapping->getUid(),
78
            $mapping->getUname(),
79
            $mapping->getEmail(),
80
            $confirmationCode
81
        ];
82
83
        $id = implode($this->delimiter, $params);
84
85
        for ($i = 1; $i <= $this->iterations; $i++) {
86
            $id = base64_encode($id);
87
        }
88
89
        return $id;
90
    }
91
92
    /**
93
     * Decodes a given link identifier.
94
     *
95
     * @param string $identifier
96
     * @return array The extracted values
97
     * @throws \Exception
98
     */
99
    public function decodeLostPasswordId($identifier = '')
100
    {
101
        if (empty($identifier)) {
102
            throw new \Exception('Invalid id in lost password verification helper.');
103
        }
104
105
        $id = $identifier;
106
        for ($i = 1; $i <= $this->iterations; $i++) {
107
            $id = base64_decode($id);
108
        }
109
110
        $params = explode($this->delimiter, $id);
111
        if (count($params) != 4) {
112
            throw new \Exception('Unexpected extraction results in lost password verification helper.');
113
        }
114
115
        return [
116
            'userId' => $params[0],
117
            'userName' => $params[1],
118
            'emailAddress' => $params[2],
119
            'confirmationCode' => $params[3]
120
        ];
121
    }
122
123
    /**
124
     * Check if confirmation code is neither expired nor invalid.
125
     *
126
     * @param integer $userId
127
     * @param string  $code
128
     * @return bool True if code is valid, false otherwise
129
     */
130
    public function checkConfirmationCode($userId, $code)
131
    {
132
        $changePasswordExpireDays = $this->variableApi->get('ZikulaZAuthModule', ZAuthConstant::MODVAR_EXPIRE_DAYS_CHANGE_PASSWORD, ZAuthConstant::DEFAULT_EXPIRE_DAYS_CHANGE_PASSWORD);
133
        $this->userVerificationRepository->purgeExpiredRecords($changePasswordExpireDays);
134
135
        /** @var UserVerificationEntity $userVerificationEntity */
136
        $userVerificationEntity = $this->userVerificationRepository->findOneBy([
137
            'uid' => $userId,
138
            'changetype' => ZAuthConstant::VERIFYCHGTYPE_PWD
139
        ]);
140
141
        if (!isset($userVerificationEntity) || (!$this->passwordApi->passwordsMatch($code, $userVerificationEntity->getVerifycode()))) {
0 ignored issues
show
Unused Code introduced by
This if statement, and the following return statement can be replaced with return !(!isset($userVer...ity->getVerifycode()));.
Loading history...
142
            return false;
143
        }
144
145
        return true;
146
    }
147
}
148