Test Failed
Push — v2 ( 220402...d76e51 )
by Berend
02:43
created

Password::hasPasswordBeenSet()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
namespace miBadger\ActiveRecord\Traits;
4
5
use miBadger\ActiveRecord\ColumnProperty;
6
use miBadger\ActiveRecord\ActiveRecordTraitException;
7
8
const TRAIT_PASSWORD_FIELD_PASSWORD = "password";
9
const TRAIT_PASSWORD_ENCRYPTION = \PASSWORD_BCRYPT;
10
const TRAIT_PASSWORD_STRENTH = 10;
11
const TRAIT_PASSWORD_FIELD_PASSWORD_RESET_TOKEN = "password_reset_token";
12
const TRAIT_PASSWORD_MIN_LENGTH = 8;
13
14
trait Password
15
{
16
	/** @var string The password hash. */
17
	protected $password;
18
19
	/** @var string|null The password reset token. */
20
	protected $passwordResetToken;
21
22
	/**
23
	 * this method is required to be called in the constructor for each class that uses this trait. 
24
	 * It adds the fields necessary for the passwords struct to the table definition
25
	 */
26
	protected function initPassword()
27
	{
28
		$this->extendTableDefinition(TRAIT_PASSWORD_FIELD_PASSWORD, [
0 ignored issues
show
Bug introduced by
It seems like extendTableDefinition() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
29
			'value' => &$this->password,
30
			'validate' => null,
31
			'type' => 'VARCHAR',
32
			'length' => 1024,
33
			'properties' => null
34
		]);
35
36
		$this->extendTableDefinition(TRAIT_PASSWORD_FIELD_PASSWORD_RESET_TOKEN, [
0 ignored issues
show
Bug introduced by
It seems like extendTableDefinition() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
37
			'value' => &$this->passwordResetToken,
38
			'validate' => null,
39
			'default' => 0,
40
			'type' => 'VARCHAR',
41
			'length' => 1024
42
		]);
43
	}
44
45
46
	/**
47
	 * Returns whether the users password has been set
48
	 * @return boolean true if the user has a password
49
	 */
50
	public function hasPasswordBeenSet()
51
	{
52
		return $this->password !== null;
53
	}
54
55
	/**
56
	 * Returns true if the credentials are correct.
57
	 *
58
	 * @param string $password
59
	 * @return boolean true if the credentials are correct
60
	 */
61
	public function isPassword($password)
62
	{ 
63
		if (!$this->hasPasswordBeenSet())
64
		{
65
			throw new ActiveRecordTraitException("Password field has not been set");
66
		}
67
68
		if (!password_verify($password, $this->password)) {
69
			return false;
70
		}
71
72
		if (password_needs_rehash($this->password, TRAIT_PASSWORD_ENCRYPTION, ['cost' => TRAIT_PASSWORD_STRENTH])) {
73
			$this->setPassword($password)->sync();
0 ignored issues
show
Bug introduced by
It seems like sync() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
74
		}
75
76
		return true;
77
	}
78
79
	/**
80
	 * Set the password.
81
	 *
82
	 * @param string $password
83
	 * @return $this
84
	 * @throws \Exception
85
	 */
86
	public function setPassword($password)
87
	{
88
		if (strlen($password) < TRAIT_PASSWORD_MIN_LENGTH) {
89
			throw new ActiveRecordTraitException(sprintf('\'Password\' must be atleast %s characters long. %s characters provied.', self::PASSWORD_MIN_LENGTH, strlen($password)));
90
		}
91
92
		$passwordHash = \password_hash($password, TRAIT_PASSWORD_ENCRYPTION, ['cost' => TRAIT_PASSWORD_STRENTH]);
93
94
		if ($passwordHash === false) {
95
			throw new ActiveRecordTraitException('\'Password\' hash failed.');
96
		}
97
98
		$this->password = $passwordHash;
99
100
		return $this;
101
	}
102
103
	/**
104
	 * @return string The Hash of the password
105
	 */
106
	public function getPasswordHash()
107
	{
108
		return $this->password;
109
	}
110
111
	/**
112
	 * Returns the currently set password token for the entity, or null if not set
113
	 * @return string|null The password reset token
114
	 */
115
	public function getPasswordResetToken()
116
	{
117
		return $this->passwordResetToken;
118
	}
119
120
	/**
121
	 * Generates a new password reset token for the user
122
	 */
123
	public function generatePasswordResetToken()
124
	{
125
		$this->passwordResetToken = md5(uniqid(mt_rand(), true));
126
	}
127
128
	/**
129
	 * Clears the current password reset token
130
	 */
131
	public function clearPasswordResetToken()
132
	{
133
	$this->passwordResetToken = null;
134
	}
135
}