Completed
Push — master ( a7b0c2...fe24f6 )
by Wanderson
02:20
created

User::setPassword()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 2
dl 0
loc 5
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Win\Authentication;
4
5
use Local\Person\Person;
6
use Local\Person\PersonDAO;
7
use Win\Alert\AlertError;
8
use Win\Authentication\UserDAO;
9
use Win\Calendar\Date;
10
use Win\File\Image;
11
use Win\Helper\Url;
12
use Win\Mvc\Application;
13
14
/**
15
 * Usuários do sistema
16
 */
17
class User {
18
19
	const ACCESS_DENIED = 0;
20
	const ACCESS_ALLOWED = 1;
21
	const ACCESS_ADMIN = 2;
22
23
	/* Lock after many login fails */
24
	const LOCK_TRIES = 5;
25
	const LOCK_TIME_MINUTES = 10;
26
27
	public $id;
28
	public $isEnabled;
29
	private $isLogged;
30
	public $accessLevel;
31
	public $name;
32
	private $email;
33
	private $confirmEmail;
34
	private $password;
35
	private $confirmPassword;
36
	public $passwordHash;
37
	public $recoreryHash;
38
39
	/** @var Date */
40
	public $loginDate;
41
42
	/** @var Date */
43
	public $loginLockDate;
44
	public $loginFailCount = 0;
45
46
	/** @var Image */
47
	public $image;
48
49
	/** @var Group */
50
	private $group;
51
	public $groupId;
52
53
	/** @var Person */
54
	private $person;
55
56
	public function __construct() {
57
		$this->id = 0;
58
		$this->isEnabled = true;
59
		$this->isLogged = false;
60
		$this->accessLevel = self::ACCESS_DENIED;
61
		$this->name = '';
62
		$this->email = '';
63
		$this->confirmEmail = '';
64
		$this->password = null;
65
		$this->confirmPassword = null;
66
		$this->passwordHash = null;
67
		$this->recoreryHash = null;
68
		$this->image = new Image();
69
		$this->image->setDirectory('data/upload/user');
70
		$this->loginDate = new Date('00/00/0000');
71
		$this->loginLockDate = new Date('00/00/0000');
72
		$this->group = null;
73
		$this->groupId = 0;
74
		$this->person = null;
75
	}
76
77
	public function getId() {
78
		return $this->id;
79
	}
80
81
	public function isLogged() {
82
		return $this->isLogged;
83
	}
84
85
	public function accessIsDenied() {
86
		return ($this->accessLevel == self::ACCESS_DENIED);
87
	}
88
89
	/** @return boolean */
90
	public function isAdmin() {
91
		return ($this->accessLevel == self::ACCESS_ADMIN);
92
	}
93
94
	public function getGroup() {
95
		if (is_null($this->group)) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
96
			// groupDAO
97
		}
98
		return $this->group;
99
	}
100
101
	public function getPassword() {
102
		return $this->password;
103
	}
104
105
	public function getEmail() {
106
		return $this->email;
107
	}
108
109
	/** @return Person */
110
	public function getPerson() {
111
		if (is_null($this->person)) {
112
			$pDAO = new PersonDAO();
113
			$this->person = $pDAO->fetchById($this->id);
114
		}
115
		return $this->person;
116
	}
117
118
	/** @return Date retorna data que poderá logar novamente sem bloqueio */
119
	public function getLoginUnlockDate() {
120
		$date = clone $this->loginLockDate;
121
		$date->sumTime(static::LOCK_TIME_MINUTES, 'minutes');
122
		return $date;
123
	}
124
125
	public function getLockedMsg() {
126
		return 'Você foi bloqueado por realizar ' . static::LOCK_TRIES . ' tentativas de login.<br /> Você poderá tentar novamente ' . $this->getLoginUnlockDate()->toTimeAgo() . '.';
127
	}
128
129
	public function setId($id) {
130
		$this->id = $id;
131
	}
132
133
	public function setPerson(Person $person) {
134
		$this->person = $person;
135
	}
136
137
	public function setEmail($email, $confirmEmail = null) {
138
		$this->email = $email;
139
		$this->confirmEmail = $confirmEmail;
140
	}
141
142
	public function setPassword($password, $confirmPassword = null) {
143
		$this->password = $password;
144
		$this->confirmPassword = $confirmPassword;
145
		$this->passwordHash = Password::encrypt($password);
146
	}
147
148
	/**
149
	 * Tenta realizar login
150
	 * @return boolean
151
	 */
152
	public function login() {
153
		$filters = [
154
			'is_enabled = ?' => true,
155
			'access_level > ?' => 0,
156
			'email = ?' => $this->email,
157
			'password_hash = ?' => $this->passwordHash
158
		];
159
		$uDAO = new UserDAO();
160
		$user = $uDAO->fetch($filters);
0 ignored issues
show
Documentation introduced by
$filters is of type array<string,boolean|int...sh = ?":"null|string"}>, but the function expects a array<integer,string>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
161
		$this->setCurrentUser($user);
162
163
		if ($user->id > 0 && !$this->isLocked()) {
164
			$this->isLogged = true;
165
			RecoveryPassword::clearHash($user);
166
			$uDAO->updateLoginDate($user);
167
			$this->loginFailCount = 0;
168
		} else {
169
			$this->incrementLoginFail();
170
		}
171
172
		return $this->isLogged;
173
	}
174
175
	/** @return boolean TRUE se preencheu os emails iguais */
176
	public function confirmEmail() {
177
		return $this->confirmEmail !== null || $this->confirmEmail == $this->email;
178
	}
179
180
	/** @return boolean TRUE se preencheu as senhas iguais */
181
	public function confirmPassword() {
182
		return $this->confirmPassword == null || $this->confirmPassword == $this->password;
183
	}
184
185
	/** Realiza logout */
186
	public function logout() {
187
		unset($_SESSION['user']);
188
	}
189
190
	private function incrementLoginFail() {
191
		$this->loginFailCount++;
192
		if ($this->loginFailCount >= static::LOCK_TRIES && !$this->isLocked()) {
193
			$this->loginLockDate = new Date();
194
			$this->loginFailCount = 0;
195
		}
196
	}
197
198
	/** @return boolean retorna TRUE se está bloqueado por tentativas de login */
199
	public function isLocked() {
200
		$diff = $this->getLoginUnlockDate()->diff(new Date());
201
		return (boolean) ($diff > 0 );
202
	}
203
204
	/** @return int total de tentativas restantes até ser bloqueado */
205
	public function getLoginTriesLeft() {
206
		return (static::LOCK_TRIES - $this->loginFailCount);
207
	}
208
209
	/** Objeto > Sessão */
210
	private function setCurrentUser(User $user) {
211
		$_SESSION['user'] = $this;
212
		$this->id = $user->id;
213
		$this->accessLevel = $user->accessLevel;
214
		$this->name = $user->name;
215
		$this->loginDate = $user->loginDate;
216
		$this->image = $user->image;
217
	}
218
219
	/** Objeto < Sessão */
220
	public static function getCurrentUser() {
221
		/* @var $user User */
222
		$user = (isset($_SESSION['user'])) ? $_SESSION['user'] : new User();
223
		static::preventDeletedAndLogged($user);
0 ignored issues
show
Bug introduced by
Since preventDeletedAndLogged() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of preventDeletedAndLogged() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
224
		return $user;
225
	}
226
227
	/**
228
	 * Evita que um usuário seja removido e continue logado
229
	 * @param User $user
230
	 */
231
	private static function preventDeletedAndLogged(User $user) {
232
		if ($user->isLogged) {
233
			$dao = new UserDAO();
234
			if (!$dao->objExists($user)) {
235
				$user->logout();
236
				new AlertError('Sua sessão foi finalizada, tente realizar o login novamente.');
237
				Application::app()->refresh();
238
			}
239
		}
240
	}
241
242
	/** Obriga o usuário a se logar */
243
	public function requireLogin() {
244
		if (!$this->isLogged) {
245
			Url::instance()->redirect('login');
246
		}
247
	}
248
249
	/** Obriga o usuário a logar como ADMIN */
250
	public function requireAdmin() {
251
		$this->requireLogin();
252
		if ($this->getAccessLevel() != static::ACCESS_ADMIN) {
0 ignored issues
show
Bug introduced by
The method getAccessLevel() does not seem to exist on object<Win\Authentication\User>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
253
			Application::app()->errorPage(403);
254
		}
255
	}
256
257
	/** Define os atributos que são salvos na SESSAO */
258
	public function __sleep() {
259
		return ['id', 'isEnabled', 'isLogged', 'accessLevel', 'name', 'email', 'image', 'loginDate', 'groupId', 'loginFailCount', 'loginLockDate'];
260
	}
261
262
}
263