PasswordHistory   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 141
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 23
lcom 1
cbo 4
dl 0
loc 141
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A tableName() 0 4 1
A validatePassword() 0 7 2
A isUsed() 0 14 4
A setPassword() 0 4 1
A judgePasswordHash() 0 4 1
A add() 0 14 4
A passHashIsUsed() 0 14 4
A addHash() 0 9 2
A first() 0 7 2
A last() 0 7 2
1
<?php
2
3
/**
4
 *   _   __ __ _____ _____ ___  ____  _____
5
 *  | | / // // ___//_  _//   ||  __||_   _|
6
 *  | |/ // /(__  )  / / / /| || |     | |
7
 *  |___//_//____/  /_/ /_/ |_||_|     |_|
8
 * @link https://vistart.me/
9
 * @copyright Copyright (c) 2016 - 2017 vistart
10
 * @license https://vistart.me/license/
11
 */
12
13
namespace rhosocial\user\security;
14
15
use rhosocial\user\User;
16
use rhosocial\base\models\models\BaseBlameableModel;
17
use Yii;
18
use yii\base\InvalidParamException;
19
20
/**
21
 * This model holds passwords that have been used.
22
 *
23
 * @property-write string $password
24
 *
25
 * @version 1.0
26
 * @author vistart <[email protected]>
27
 */
28
class PasswordHistory extends BaseBlameableModel
29
{
30
    public $idAttribute = false;
31
    public $updatedAtAttribute = false;
32
    public $updatedByAttribute = false;
33
    public $enableIP = false;
34
    public $contentAttribute = false;
35
    public $passwordHashAttribute = 'pass_hash';
36
    
37
    public static function tableName()
38
    {
39
        return '{{%password_history}}';
40
    }
41
    
42
    /**
43
     * Validate password.
44
     *
45
     * @param string $password Password or Password Hash.
46
     * @return boolean
47
     */
48
    public function validatePassword($password)
49
    {
50
        if (static::judgePasswordHash($password)) {
51
            return $this->{$this->passwordHashAttribute} == $password;
52
        }
53
        return Yii::$app->security->validatePassword($password, $this->{$this->passwordHashAttribute});
54
    }
55
    
56
    /**
57
     * Check whether the password has been used.
58
     * @param string $password Password or Password Hash.
59
     * @param User $user
60
     * @return false|static The first validated password model, or false if not validated.
61
     */
62
    public static function isUsed($password, $user = null)
63
    {
64
        if (!User::isValid($user)) {
65
            throw new InvalidParamException('User Invalid.');
66
        }
67
        $passwords = static::find()->createdBy($user)->all();
68
        foreach ($passwords as $p) {
69
            /* @var $p static */
70
            if ($p->validatePassword($password)) {
71
                return $p;
72
            }
73
        }
74
        return false;
75
    }
76
    
77
    /**
78
     * Set password.
79
     * @param string $password
80
     */
81
    public function setPassword($password)
82
    {
83
        $this->{$this->passwordHashAttribute} = Yii::$app->security->generatePasswordHash($password);
84
    }
85
    
86
    protected static function judgePasswordHash($password)
87
    {
88
        return strpos($password, '$2y$') !== false;
89
    }
90
    
91
    /**
92
     * Add password to history.
93
     *
94
     * @param string $password Password or Password Hash.
95
     * @param User $user
96
     * @return boolean
97
     * @throws InvalidParamException throw if password existed.
98
     */
99
    public static function add($password, $user = null)
100
    {
101
        if (static::isUsed($password, $user) && !$user->allowUsedPassword) {
102
            throw new InvalidParamException('Password existed.');
103
        }
104
        if (static::judgePasswordHash($password)) {
105
            $passwordHistory = $user->create(static::class);
0 ignored issues
show
Bug introduced by
It seems like $user is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
106
            $passwordHistory->{$passwordHistory->passwordHashAttribute} = $password;
107
        } else {
108
            $passwordHistory = $user->create(static::class, ['password' => $password]);
109
        }
110
        /* @var $passwordHistory static */
111
        return $passwordHistory->save();
112
    }
113
    
114
    public static function passHashIsUsed($passHash, $user = null)
115
    {
116
        if (!User::isValid($user)) {
117
            throw new InvalidParamException('User Invalid.');
118
        }
119
        $passwords = static::find()->createdBy($user)->all();
120
        foreach ($passwords as $passwordHistory) {
121
            /* @var $passwordHistory static */
122
            if ($passwordHistory->{$passwordHistory->passwordHashAttribute} == $passHash) {
123
                return $passwordHistory;
124
            }
125
        }
126
        return false;
127
    }
128
    
129
    public static function addHash($passHash, $user = null)
130
    {
131
        if (static::passHashIsUsed($passHash, $user)) {
132
            throw new InvalidParamException('Password existed.');
133
        }
134
        $noInit = static::buildNoInitModel();
135
        $passwordHistory = $user->create(static::class, [$noInit->passwordHashAttribute => $passHash]);
136
        return $passwordHistory->save();
137
    }
138
    
139
    /**
140
     * Get first password hash.
141
     *
142
     * @param User $user
143
     * @return static
144
     * @throws InvalidParamException throw if user invalid.
145
     */
146
    public static function first($user = null)
147
    {
148
        if (!User::isValid($user)) {
149
            throw new InvalidParamException('User Invalid.');
150
        }
151
        return static::find()->createdBy($user)->orderByCreatedAt()->one();
152
    }
153
    
154
    /**
155
     * Get last password hash.
156
     *
157
     * @param User $user
158
     * @return static
159
     * @throws InvalidParamException throw if user invalid.
160
     */
161
    public static function last($user = null)
162
    {
163
        if (!User::isValid($user)) {
164
            throw new InvalidParamException('User Invalid.');
165
        }
166
        return static::find()->createdBy($user)->orderByCreatedAt(SORT_DESC)->one();
167
    }
168
}
169