Passed
Branch tests1.5 (e599bd)
by Wanderson
01:46
created

User   A

Complexity

Total Complexity 36

Size/Duplication

Total Lines 213
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 99
dl 0
loc 213
rs 9.52
c 0
b 0
f 0
wmc 36

25 Methods

Rating   Name   Duplication   Size   Complexity  
A isLogged() 0 2 1
A accessIsDenied() 0 2 1
A preventDeletedAndLogged() 0 7 3
A getLoginTriesLeft() 0 2 1
A isLocked() 0 3 1
A setPassword() 0 4 1
A confirmEmail() 0 2 2
A requireAdmin() 0 4 2
A getLoginUnlockDate() 0 4 1
A __sleep() 0 2 1
A setCurrentUser() 0 7 1
A isAdmin() 0 2 1
A getCurrentUser() 0 5 2
A __construct() 0 16 1
A login() 0 21 3
A getEmail() 0 2 1
A setId() 0 2 1
A requireLogin() 0 3 2
A confirmPassword() 0 2 2
A getLockedMsg() 0 2 1
A getPassword() 0 2 1
A logout() 0 2 1
A getId() 0 2 1
A incrementLoginFail() 0 5 3
A setEmail() 0 3 1
1
<?php
2
3
namespace Win\Authentication;
4
5
use Win\Alert\AlertError;
6
use Win\Calendar\Date;
7
use Win\File\Image;
8
use Win\Request\Url;
9
use Win\Mvc\Application;
10
11
/**
12
 * Usuários do sistema
13
 */
14
class User {
15
16
	const ACCESS_DENIED = 0;
17
	const ACCESS_ALLOWED = 1;
18
	const ACCESS_ADMIN = 2;
19
20
	/* Lock after many login fails */
21
	const LOCK_TRIES = 5;
22
	const LOCK_TIME_MINUTES = 10;
23
24
	public $id;
25
	public $isEnabled;
26
	private $isLogged;
27
	public $accessLevel;
28
	public $name;
29
	private $email;
30
	private $confirmEmail;
31
	private $password;
32
	private $confirmPassword;
33
	public $passwordHash;
34
	public $recoreryHash;
35
36
	/** @var Date */
37
	public $loginDate;
38
39
	/** @var Date */
40
	public $loginLockDate;
41
	public $loginFailCount = 0;
42
43
	/** @var Image */
44
	public $image;
45
46
	public function __construct() {
47
		$this->id = 0;
48
		$this->isEnabled = true;
49
		$this->isLogged = false;
50
		$this->accessLevel = self::ACCESS_DENIED;
51
		$this->name = '';
52
		$this->email = '';
53
		$this->confirmEmail = '';
54
		$this->password = null;
55
		$this->confirmPassword = null;
56
		$this->passwordHash = null;
57
		$this->recoreryHash = null;
58
		$this->image = new Image();
59
		$this->image->setDirectory('data/upload/user');
60
		$this->loginDate = new Date('00/00/0000');
61
		$this->loginLockDate = new Date('00/00/0000');
62
	}
63
64
	public function getId() {
65
		return $this->id;
66
	}
67
68
	public function isLogged() {
69
		return $this->isLogged;
70
	}
71
72
	public function accessIsDenied() {
73
		return ($this->accessLevel == self::ACCESS_DENIED);
74
	}
75
76
	/** @return boolean */
77
	public function isAdmin() {
78
		return ($this->accessLevel == self::ACCESS_ADMIN);
79
	}
80
81
	public function getPassword() {
82
		return $this->password;
83
	}
84
85
	public function getEmail() {
86
		return $this->email;
87
	}
88
89
	/** @return Date retorna data que poderá logar novamente sem bloqueio */
90
	public function getLoginUnlockDate() {
91
		$date = clone $this->loginLockDate;
92
		$date->sumTime(static::LOCK_TIME_MINUTES, 'minutes');
93
		return $date;
94
	}
95
96
	public function getLockedMsg() {
97
		return 'Você foi bloqueado por realizar ' . static::LOCK_TRIES . ' tentativas de login.<br /> Você poderá tentar novamente ' . $this->getLoginUnlockDate()->toTimeAgo() . '.';
98
	}
99
100
	public function setId($id) {
101
		$this->id = $id;
102
	}
103
104
	public function setEmail($email, $confirmEmail = null) {
105
		$this->email = $email;
106
		$this->confirmEmail = $confirmEmail;
107
	}
108
109
	public function setPassword($password, $confirmPassword = null) {
110
		$this->password = $password;
111
		$this->confirmPassword = $confirmPassword;
112
		$this->passwordHash = Password::encrypt($password);
113
	}
114
115
	/**
116
	 * Tenta realizar login
117
	 * @return boolean
118
	 */
119
	public function login() {
120
		$filters = [
121
			'is_enabled = ?' => true,
122
			'access_level > ?' => 0,
123
			'email = ?' => $this->email,
124
			'password_hash = ?' => $this->passwordHash
125
		];
126
		$uDAO = new UserDAO();
127
		$user = $uDAO->fetch($filters);
128
		$this->setCurrentUser($user);
129
130
		if ($user->id > 0 && !$this->isLocked()) {
131
			$this->isLogged = true;
132
			RecoveryPassword::clearHash($user);
133
			$uDAO->updateLoginDate($user);
134
			$this->loginFailCount = 0;
135
		} else {
136
			$this->incrementLoginFail();
137
		}
138
139
		return $this->isLogged;
140
	}
141
142
	/** @return boolean TRUE se preencheu os emails iguais */
143
	public function confirmEmail() {
144
		return $this->confirmEmail !== null || $this->confirmEmail == $this->email;
145
	}
146
147
	/** @return boolean TRUE se preencheu as senhas iguais */
148
	public function confirmPassword() {
149
		return $this->confirmPassword == null || $this->confirmPassword == $this->password;
150
	}
151
152
	/** Realiza logout */
153
	public function logout() {
154
		unset($_SESSION['user']);
155
	}
156
157
	private function incrementLoginFail() {
158
		$this->loginFailCount++;
159
		if ($this->loginFailCount >= static::LOCK_TRIES && !$this->isLocked()) {
160
			$this->loginLockDate = new Date();
161
			$this->loginFailCount = 0;
162
		}
163
	}
164
165
	/** @return boolean retorna TRUE se está bloqueado por tentativas de login */
166
	public function isLocked() {
167
		$diff = $this->getLoginUnlockDate()->diff(new Date());
168
		return (boolean) ($diff > 0);
169
	}
170
171
	/** @return int total de tentativas restantes até ser bloqueado */
172
	public function getLoginTriesLeft() {
173
		return (static::LOCK_TRIES - $this->loginFailCount);
174
	}
175
176
	/** Objeto > Sessão */
177
	private function setCurrentUser(User $user) {
178
		$_SESSION['user'] = $this;
179
		$this->id = $user->id;
180
		$this->accessLevel = $user->accessLevel;
181
		$this->name = $user->name;
182
		$this->loginDate = $user->loginDate;
183
		$this->image = $user->image;
184
	}
185
186
	/** Objeto < Sessão */
187
	public static function getCurrentUser() {
188
		/* @var $user User */
189
		$user = (isset($_SESSION['user'])) ? $_SESSION['user'] : new User();
190
		static::preventDeletedAndLogged($user);
191
		return $user;
192
	}
193
194
	/**
195
	 * Evita que um usuário seja removido e continue logado
196
	 * @param User $user
197
	 */
198
	private static function preventDeletedAndLogged(User $user) {
199
		if ($user->isLogged) {
200
			$dao = new UserDAO();
201
			if (!$dao->objExists($user)) {
202
				$user->logout();
203
				new AlertError('Sua sessão foi finalizada, tente realizar o login novamente.');
204
				Application::app()->refresh();
205
			}
206
		}
207
	}
208
209
	/** Obriga o usuário a se logar */
210
	public function requireLogin() {
211
		if (!$this->isLogged) {
212
			Url::instance()->redirect('login');
213
		}
214
	}
215
216
	/** Obriga o usuário a logar como ADMIN */
217
	public function requireAdmin() {
218
		$this->requireLogin();
219
		if ($this->accessLevel != static::ACCESS_ADMIN) {
220
			Application::app()->errorPage(403);
221
		}
222
	}
223
224
	/** Define os atributos que são salvos na SESSAO */
225
	public function __sleep() {
226
		return ['id', 'isEnabled', 'isLogged', 'accessLevel', 'name', 'email', 'image', 'loginDate', 'loginFailCount', 'loginLockDate'];
227
	}
228
229
}
230