Completed
Push — master ( 85aed2...e3f8d4 )
by Charles
04:40
created

ResetPassword   A

Complexity

Total Complexity 18

Size/Duplication

Total Lines 165
Duplicated Lines 10.91 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
wmc 18
c 0
b 0
f 0
lcom 1
cbo 3
dl 18
loc 165
rs 10

7 Methods

Rating   Name   Duplication   Size   Complexity  
A scenarios() 0 7 1
A rules() 0 14 1
A validatePassword() 0 8 3
A validateUser() 0 10 3
A validateResetToken() 18 20 4
A setUser() 0 5 1
B reset() 0 23 5

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
namespace yrc\api\forms;
4
5
use Base32\Base32;
6
use Yii;
7
8
abstract class ResetPassword extends \yii\base\model
9
{
10
    const SCENARIO_INIT = 'init';
11
    const SCENARIO_RESET = 'reset';
12
13
    const EXPIRY_TIME = '+4 hours';
14
15
    /**
16
     * The email
17
     * @var string $email
18
     */
19
    public $email;
20
21
    /**
22
     * The reset token
23
     * @var string $reset_token
24
     */
25
    public $reset_token;
26
27
    /**
28
     * The new password
29
     * @var string $password
30
     */
31
    public $password;
32
33
    /**
34
     * The new password (again)
35
     * @var string $password_verify
36
     */
37
    public $password_verify;
38
39
    /**
40
     * The user's current password
41
     * @var string $password_current
42
     */
43
    public $password_current;
44
45
    /**
46
     * The user associated to the email
47
     * @var User $user
48
     */
49
    private $user = null;
50
51
    /**
52
     * Validation scenarios
53
     * @return array
54
     */
55
    public function scenarios()
56
    {
57
        return [
58
            self::SCENARIO_INIT => ['email'],
59
            self::SCENARIO_RESET => ['reset_token'],
60
        ];
61
    }
62
63
    /**
64
     * Validation rules
65
     * @return array
66
     */
67
    public function rules()
68
    {
69
        return [
70
            [['email'], 'required', 'on' => self::SCENARIO_INIT],
71
            [['email'], 'email', 'on' =>  self::SCENARIO_INIT],
72
            [['email'], 'validateUser', 'on' =>  self::SCENARIO_INIT],
73
74
            [['reset_token', 'password', 'password_verify', 'password_current'], 'required', 'on' => self::SCENARIO_RESET],
75
            [['reset_token'], 'validateResetToken', 'on' => self::SCENARIO_RESET],
76
            [['password_current'], 'validatePassword', 'on' => self::SCENARIO_RESET],
77
            [['password', 'password_verify', 'current_password'], 'string', 'min' => 8, 'on' => self::SCENARIO_RESET],
78
            [['password_verify'], 'compare', 'compareAttribute' => 'password', 'on' => self::SCENARIO_RESET]
79
        ];
80
    }
81
82
    /**
83
     * Validates the user's current password
84
     * @inheritdoc
85
     */
86
    public function validatePassword($attributes, $params)
0 ignored issues
show
Unused Code introduced by
The parameter $attributes is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
87
    {
88
        if (!$this->hasErrors()) {
89
            if (!$this->user->validatePassword($this->password_current)) {
90
                $this->addError('password_current', Yii::t('yrc', 'The provided password is not valid'));
91
            }
92
        }
93
    }
94
    
95
    /**
96
     * Validates the users email
97
     * @inheritdoc
98
     */
99
    public function validateUser($attributes, $params)
0 ignored issues
show
Unused Code introduced by
The parameter $attributes is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
100
    {
101
        if (!$this->hasErrors()) {
102
            $this->user = Yii::$app->yrc->userClass::findOne(['email' => $this->email]);
103
104
            if ($this->user === null) {
105
                $this->addError('email', Yii::t('yrc', 'The provided email address is not valid'));
106
            }
107
        }
108
    }
109
110
    /**
111
     * Reset token validator
112
     * @inheritdoc
113
     */
114 View Code Duplication
    public function validateResetToken($attributes, $params)
0 ignored issues
show
Unused Code introduced by
The parameter $attributes is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $params is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
115
    {
116
        if (!$this->hasErrors()) {
117
            $tokenInfo = Yii::$app->cache->get(
118
                hash('sha256', $this->reset_token . '_reset_token')
119
            );
120
            
121
            if ($tokenInfo === null) {
122
                $this->addError('reset_token', Yii::t('yrc', 'The password reset token provided is not valid.'));
123
            }
124
125
            $this->user = Yii::$app->yrc->userClass::find()->where([
126
                'id' => $tokenInfo['id']
127
            ])->one();
128
129
            if ($this->user === null) {
130
                $this->addError('reset_token', Yii::t('yrc', 'The password reset token provided is not valid.'));
131
            }
132
        }
133
    }
134
135
    /**
136
     * Sets the user object
137
     * @param User $user
138
     */
139
    public function setUser($user)
140
    {
141
        $this->user = $user;
142
        $this->email = $user->email;
143
    }
144
145
    /**
146
     * Changes the password for the user
147
     * @return boolean
148
     */
149
    public function reset()
150
    {
151
        if ($this->validate()) {
152
            if ($this->getScenario() === self::SCENARIO_INIT) {
153
                // Create an reset token for the user, and store it in the cache
154
                $token = Base32::encode(\random_bytes(64));
155
                
156
                Yii::$app->cache->set(hash('sha256', $token . '_reset_token'), [
157
                    'id' => $this->user->id
158
                ], strtotime(self::EXPIRY_TIME));
159
160
                return Yii::$app->yrc->sendEmail('password_reset', Yii::t('app', 'A request has been made to change your password'), $this->user->email, ['token' => $token]);
161
            } elseif ($this->getScenario() === self::SCENARIO_RESET) {
162
                $this->user->password = $this->password;
163
164
                if ($this->user->save()) {
165
                    return Yii::$app->yrc->sendEmail('password_change', Yii::t('app', 'Your password has been changed'), $this->email);
166
                }
167
            }
168
        }
169
170
        return false;
171
    }
172
}