These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace App\Controller; |
||
3 | |||
4 | use App\Event\Badges; |
||
5 | use App\Event\Logs; |
||
6 | use App\Event\Notifications; |
||
7 | use App\Event\Statistics; |
||
8 | use App\Event\Users; |
||
9 | use App\Utility\Users as UsersUtility; |
||
10 | use BrowscapPHP\Browscap; |
||
11 | use Cake\Auth\DefaultPasswordHasher; |
||
12 | use Cake\Core\Configure; |
||
13 | use Cake\Event\Event; |
||
14 | use Cake\I18n\Time; |
||
15 | use Cake\Mailer\MailerAwareTrait; |
||
16 | use Cake\Utility\Security; |
||
17 | use RobThree\Auth\TwoFactorAuth; |
||
18 | |||
19 | class UsersController extends AppController |
||
20 | { |
||
21 | use MailerAwareTrait; |
||
22 | |||
23 | /** |
||
24 | * Initialize handle. |
||
25 | * |
||
26 | * @return void |
||
27 | */ |
||
28 | public function initialize() |
||
29 | { |
||
30 | parent::initialize(); |
||
31 | |||
32 | $action = $this->request->action; |
||
33 | |||
34 | if ($action === 'login' || $action === 'forgotPassword') { |
||
35 | $this->loadComponent('Recaptcha.Recaptcha'); |
||
36 | } |
||
37 | |||
38 | if ($action === 'login') { |
||
39 | $this->loadComponent('TwoFactorAuth'); |
||
40 | } |
||
41 | } |
||
42 | |||
43 | /** |
||
44 | * BeforeFilter handle. |
||
45 | * |
||
46 | * @param Event $event The beforeFilter event that was fired. |
||
47 | * |
||
48 | * @return void |
||
49 | */ |
||
50 | public function beforeFilter(Event $event) |
||
51 | { |
||
52 | parent::beforeFilter($event); |
||
53 | |||
54 | $this->Auth->allow(['index', 'tfa', 'logout', 'profile', 'forgotPassword', 'resetPassword']); |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * Display all Users. |
||
59 | * |
||
60 | * @return void |
||
61 | */ |
||
62 | View Code Duplication | public function index() |
|
63 | { |
||
64 | $this->paginate = [ |
||
65 | 'maxLimit' => Configure::read('User.user_per_page') |
||
66 | ]; |
||
67 | $users = $this->Users |
||
68 | ->find() |
||
69 | ->contain([ |
||
70 | 'Groups' |
||
71 | ]) |
||
72 | ->order([ |
||
73 | 'Users.created' => 'desc' |
||
74 | ]); |
||
75 | |||
76 | $users = $this->paginate($users); |
||
77 | |||
78 | $this->set(compact('users')); |
||
79 | } |
||
80 | |||
81 | /** |
||
82 | * Login and register page. |
||
83 | * |
||
84 | * @return \Cake\Network\Response|void |
||
85 | */ |
||
86 | public function login() |
||
87 | { |
||
88 | if ($this->request->is('post')) { |
||
89 | $method = ($this->request->data['method']) ? $this->request->data['method'] : false; |
||
90 | |||
91 | switch ($method) { |
||
92 | case "login": |
||
93 | if (Configure::read('User.Login.enabled') === false) { |
||
94 | $userRegister = $userRegister = $this->Users->newEntity($this->request->data); |
||
95 | |||
96 | break; |
||
97 | } |
||
98 | $userLogin = $this->Auth->identify(); |
||
99 | |||
100 | if ($userLogin) { |
||
101 | if ($userLogin['is_deleted'] == true) { |
||
102 | $this->Flash->error(__("This account has been deleted.")); |
||
103 | |||
104 | $userRegister = $this->Users->newEntity($this->request->data); |
||
105 | |||
106 | break; |
||
107 | } |
||
108 | |||
109 | //Check the 2FA if the user has enabled it. |
||
110 | if ($userLogin['two_factor_auth_enabled'] == true && $this->TwoFactorAuth->isAuthorized($userLogin['id']) === false) { |
||
111 | //Write the cookie |
||
112 | $cookie = base64_encode(Security::encrypt($userLogin['id'], Configure::read('Security.key'))); |
||
113 | $this->Cookie->configKey('CookieTfa', [ |
||
114 | 'expires' => '+1 hour', |
||
115 | 'httpOnly' => true |
||
116 | ]); |
||
117 | $this->Cookie->write('CookieTfa', $cookie); |
||
118 | |||
119 | return $this->redirect(['action' => 'tfa']); |
||
120 | } |
||
121 | |||
122 | $this->_handleLogin($userLogin); |
||
123 | |||
124 | $this->Auth->setUser($userLogin); |
||
125 | |||
126 | $user = $this->Users->newEntity($userLogin, ['accessibleFields' => ['id' => true]]); |
||
127 | $user->isNew(false); |
||
128 | |||
129 | $user->last_login = new Time(); |
||
130 | $user->last_login_ip = $this->request->clientIp(); |
||
131 | |||
132 | $this->Users->save($user); |
||
133 | |||
134 | //Cookies. |
||
135 | $this->Cookie->configKey('CookieAuth', [ |
||
136 | 'expires' => '+1 year', |
||
137 | 'httpOnly' => true |
||
138 | ]); |
||
139 | $this->Cookie->write('CookieAuth', [ |
||
140 | 'username' => $this->request->data('username'), |
||
141 | 'password' => $this->request->data('password') |
||
142 | ]); |
||
143 | |||
144 | //Badge Event. |
||
145 | $this->eventManager()->attach(new Badges($this)); |
||
146 | $user = new Event('Model.Users.register', $this, [ |
||
147 | 'user' => $user |
||
148 | ]); |
||
149 | $this->eventManager()->dispatch($user); |
||
150 | |||
151 | $url = $this->Auth->redirectUrl(); |
||
152 | View Code Duplication | if (substr($this->Auth->redirectUrl(), -5) == 'login') { |
|
153 | $url = ['controller' => 'pages', 'action' => 'home']; |
||
154 | } |
||
155 | |||
156 | return $this->redirect($url); |
||
157 | } |
||
158 | |||
159 | $user = $this->Users |
||
160 | ->find() |
||
161 | ->where([ |
||
162 | 'username' => $this->request->data['username'] |
||
163 | ]) |
||
164 | ->select([ |
||
165 | 'id', |
||
166 | 'group_id', |
||
167 | 'username', |
||
168 | 'email' |
||
169 | ]) |
||
170 | ->first(); |
||
171 | |||
172 | if (!is_null($user)) { |
||
173 | //Users Event. |
||
174 | $this->eventManager()->attach(new Users()); |
||
175 | $event = new Event('Users.login.failed', $this, [ |
||
176 | 'user_id' => $user->id, |
||
177 | 'username' => $user->username, |
||
178 | 'group_id' => $user->group_id, |
||
179 | 'user_ip' => $this->request->clientIp(), |
||
180 | 'user_email' => $user->email, |
||
181 | 'user_agent' => $this->request->header('User-Agent'), |
||
182 | 'action' => 'user.connection.manual.failed' |
||
183 | ]); |
||
184 | $this->eventManager()->dispatch($event); |
||
185 | } |
||
186 | |||
187 | $this->Flash->error(__("Your username or password doesn't match.")); |
||
188 | |||
189 | $userRegister = $this->Users->newEntity($this->request->data); |
||
190 | |||
191 | break; |
||
192 | |||
193 | case "register": |
||
194 | $userRegister = $this->Users->newEntity($this->request->data, ['validate' => 'create']); |
||
195 | |||
196 | $userRegister->register_ip = $this->request->clientIp(); |
||
197 | $userRegister->last_login_ip = $this->request->clientIp(); |
||
198 | $userRegister->last_login = new Time(); |
||
199 | |||
200 | if ($this->Recaptcha->verify() || Configure::read('Recaptcha.bypass') === true) { |
||
201 | if ($this->Users->save($userRegister)) { |
||
202 | $user = $this->Auth->identify(); |
||
203 | |||
204 | if ($user) { |
||
205 | $this->Auth->setUser($user); |
||
206 | } |
||
207 | |||
208 | $user = $this->Users->get($user['id']); |
||
209 | |||
210 | //Statistics Event. |
||
211 | $this->eventManager()->attach(new Statistics()); |
||
212 | $stats = new Event('Model.Users.register', $this); |
||
213 | $this->eventManager()->dispatch($stats); |
||
214 | |||
215 | //Notification Events. |
||
216 | $this->eventManager()->attach(new Notifications()); |
||
217 | $event = new Event('Model.Notifications.new', $this, [ |
||
218 | 'user_id' => $user->id, |
||
219 | 'type' => 'bot' |
||
220 | ]); |
||
221 | $this->eventManager()->dispatch($event); |
||
222 | |||
223 | $viewVars = [ |
||
224 | 'user' => $user, |
||
225 | 'name' => $user->full_name |
||
226 | ]; |
||
227 | |||
228 | $this->getMailer('User')->send('register', [$user, $viewVars]); |
||
229 | |||
230 | $this->Flash->success(__("Your account has been created successfully !")); |
||
231 | |||
232 | $url = $this->Auth->redirectUrl(); |
||
233 | View Code Duplication | if (substr($this->Auth->redirectUrl(), -5) == 'login') { |
|
234 | $url = ['controller' => 'pages', 'action' => 'home']; |
||
235 | } |
||
236 | |||
237 | return $this->redirect($url); |
||
238 | } |
||
239 | |||
240 | $this->Flash->error(__("Please, correct your mistake.")); |
||
241 | } else { |
||
242 | $this->Flash->error(__("Please, correct your Captcha.")); |
||
243 | } |
||
244 | |||
245 | break; |
||
246 | } |
||
247 | } else { |
||
248 | //Save the referer URL before the user send the login/register request else it will delete the referer. |
||
249 | $this->request->session()->write('Auth.redirect', $this->referer()); |
||
250 | |||
251 | $userRegister = $this->Users->newEntity($this->request->data, ['validate' => 'create']); |
||
252 | } |
||
253 | |||
254 | if ($this->Auth->user()) { |
||
255 | return $this->redirect($this->Auth->redirectUrl()); |
||
256 | } |
||
257 | |||
258 | $this->set(compact('userRegister')); |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Handle the login part after all verification. |
||
263 | * |
||
264 | * @param array $userLogin The user information. |
||
265 | * |
||
266 | * @return void |
||
267 | */ |
||
268 | protected function _handleLogin($userLogin) |
||
269 | { |
||
270 | $this->Auth->setUser($userLogin); |
||
271 | |||
272 | $user = $this->Users->newEntity($userLogin); |
||
273 | $user->isNew(false); |
||
274 | $user->id = $userLogin['id']; |
||
275 | |||
276 | $user->last_login = new Time(); |
||
277 | $user->last_login_ip = $this->request->clientIp(); |
||
278 | |||
279 | $this->Users->save($user); |
||
280 | |||
281 | //Cookies. |
||
282 | $this->Cookie->configKey('CookieAuth', [ |
||
283 | 'expires' => '+1 year', |
||
284 | 'httpOnly' => true |
||
285 | ]); |
||
286 | $this->Cookie->write('CookieAuth', [ |
||
287 | 'username' => $this->request->data('username'), |
||
288 | 'password' => $this->request->data('password') |
||
289 | ]); |
||
290 | |||
291 | //Badge Event. |
||
292 | $this->eventManager()->attach(new Badges($this)); |
||
293 | $badge = new Event('Model.Users.register', $this, [ |
||
294 | 'user' => $user |
||
295 | ]); |
||
296 | $this->eventManager()->dispatch($badge); |
||
297 | |||
298 | //Logs Event. |
||
299 | $this->eventManager()->attach(new Logs()); |
||
300 | $event = new Event('Log.User', $this, [ |
||
301 | 'user_id' => $user->id, |
||
302 | 'username' => $user->username, |
||
303 | 'user_ip' => $this->request->clientIp(), |
||
304 | 'user_agent' => $this->request->header('User-Agent'), |
||
305 | 'action' => 'user.connection.manual.success' |
||
306 | ]); |
||
307 | $this->eventManager()->dispatch($event); |
||
308 | |||
309 | $this->request->session()->write('Notification', ['type' => 'primary', 'message' => __('Happy to see you again {0} ! ', h($user->username))]); |
||
310 | } |
||
311 | |||
312 | /** |
||
313 | * Logout an user. |
||
314 | * |
||
315 | * @return \Cake\Network\Response |
||
316 | */ |
||
317 | public function logout() |
||
318 | { |
||
319 | $this->request->session()->write('Notification', ['type' => 'danger', 'message' => __('See you later {0} ! ', h($this->Auth->user('username')))]); |
||
320 | |||
321 | return $this->redirect($this->Auth->logout()); |
||
322 | } |
||
323 | |||
324 | /** |
||
325 | * Ask to the user the 2FA code and verify it. |
||
326 | * |
||
327 | * @return \Cake\Network\Response|void |
||
328 | */ |
||
329 | public function tfa() |
||
330 | { |
||
331 | if ($this->Auth->user()) { |
||
332 | return $this->redirect($this->Auth->redirectUrl()); |
||
333 | } |
||
334 | |||
335 | if ($this->request->is('post')) { |
||
336 | $this->loadModel('UsersTwoFactorAuth'); |
||
337 | |||
338 | $id = $this->Cookie->read('CookieTfa'); |
||
339 | |||
340 | View Code Duplication | if (empty($id) || $id == false) { |
|
341 | $this->Cookie->delete('CookieTfa'); |
||
342 | |||
343 | return $this->redirect($this->Auth->config('loginAction')); |
||
344 | } |
||
345 | |||
346 | try { |
||
347 | $id = Security::decrypt(base64_decode($id), Configure::read('Security.key')); |
||
348 | } catch (\Exception $e) { |
||
349 | $this->Flash->error(__('The link used for the Two-factor Authentication is incorrect.')); |
||
350 | |||
351 | return $this->redirect($this->Auth->config('loginAction')); |
||
352 | } |
||
353 | |||
354 | $userTfa = $this->UsersTwoFactorAuth |
||
355 | ->find() |
||
356 | ->where([ |
||
357 | 'user_id' => $id |
||
358 | ]) |
||
359 | ->first(); |
||
360 | |||
361 | $tfa = new TwoFactorAuth('Xeta'); |
||
362 | |||
363 | $isAuthorized = false; |
||
364 | $recoveryCodeUsed = false; |
||
365 | |||
366 | if ($tfa->verifyCode($userTfa->secret, $this->request->data['code']) === true && $this->request->data['code'] !== $userTfa->current_code) { |
||
367 | $isAuthorized = true; |
||
368 | //Check recovery code and verify if the recovery code is not already used. |
||
369 | } elseif ($userTfa->recovery_code === $this->request->data['code'] && $userTfa->recovery_code_used == false && $this->request->data['code'] !== $userTfa->current_code) { |
||
370 | $isAuthorized = true; |
||
371 | $recoveryCodeUsed = true; |
||
372 | } |
||
373 | |||
374 | if ($isAuthorized === true) { |
||
375 | $data = [ |
||
376 | 'session' => $this->request->clientIp() . $this->request->header('User-Agent') . gethostbyaddr($this->request->clientIp()), |
||
377 | 'current_code' => $recoveryCodeUsed === true ? 'recovery' : $this->request->data['code'], |
||
378 | 'recovery_code_used' => $recoveryCodeUsed === true ? 1 : $userTfa->recovery_code_used |
||
379 | ]; |
||
380 | |||
381 | $this->UsersTwoFactorAuth->patchEntity($userTfa, $data); |
||
382 | $this->UsersTwoFactorAuth->save($userTfa); |
||
383 | |||
384 | //Login the user. |
||
385 | $userLogin = $this->Users |
||
386 | ->find() |
||
387 | ->where([ |
||
388 | 'id' => $id |
||
389 | ]) |
||
390 | ->hydrate(false) |
||
391 | ->first(); |
||
392 | |||
393 | unset($userLogin['password']); |
||
394 | |||
395 | $this->_handleLogin($userLogin); |
||
396 | |||
397 | $this->Cookie->delete('CookieTfa'); |
||
398 | |||
399 | //Logs Event. |
||
400 | $this->eventManager()->attach(new Logs()); |
||
401 | $event = new Event('Log.User', $this, [ |
||
402 | 'user_id' => $userLogin['id'], |
||
403 | 'username' => $userLogin['username'], |
||
404 | 'user_ip' => $this->request->clientIp(), |
||
405 | 'user_agent' => $this->request->header('User-Agent'), |
||
406 | 'action' => '2FA.recovery_code.used' |
||
407 | ]); |
||
408 | $this->eventManager()->dispatch($event); |
||
409 | |||
410 | return $this->redirect(['controller' => 'pages', 'action' => 'home']); |
||
411 | } else { |
||
412 | $this->Flash->error(__('Two-factor secret verification failed. Please verify your code and try again.')); |
||
413 | } |
||
414 | } |
||
415 | |||
416 | $id = $this->Cookie->read('CookieTfa'); |
||
417 | |||
418 | View Code Duplication | if (empty($id) || $id == false) { |
|
419 | $this->Cookie->delete('CookieTfa'); |
||
420 | |||
421 | return $this->redirect($this->Auth->config('loginAction')); |
||
422 | } |
||
423 | } |
||
424 | |||
425 | /** |
||
426 | * Page to configure our account. |
||
427 | * |
||
428 | * @return void |
||
429 | */ |
||
430 | public function account() |
||
431 | { |
||
432 | $user = $this->Users->get($this->Auth->user('id')); |
||
433 | |||
434 | if ($this->request->is('put')) { |
||
435 | $user->accessible('avatar_file', true); |
||
436 | $this->Users->patchEntity($user, $this->request->data(), ['validate' => 'account']); |
||
437 | |||
438 | if ($this->Users->save($user)) { |
||
439 | $this->request->session()->write('Auth.User.avatar', $user->avatar); |
||
440 | |||
441 | //Logs Event. |
||
442 | $this->eventManager()->attach(new Logs()); |
||
443 | $event = new Event('Log.User', $this, [ |
||
444 | 'user_id' => $user->id, |
||
445 | 'username' => $user->username, |
||
446 | 'user_ip' => $this->request->clientIp(), |
||
447 | 'user_agent' => $this->request->header('User-Agent'), |
||
448 | 'action' => 'user.account.modify' |
||
449 | ]); |
||
450 | $this->eventManager()->dispatch($event); |
||
451 | |||
452 | $this->Flash->success(__("Your information has been updated !")); |
||
453 | } |
||
454 | } |
||
455 | |||
456 | $this->set(compact('user')); |
||
457 | } |
||
458 | |||
459 | /** |
||
460 | * Page to configure our settings. |
||
461 | * |
||
462 | * @return \Cake\Network\Response|void |
||
463 | */ |
||
464 | public function settings() |
||
465 | { |
||
466 | $user = $this->Users->get($this->Auth->user('id')); |
||
467 | |||
468 | $oldEmail = $user->email; |
||
469 | |||
470 | if ($this->request->is('put')) { |
||
471 | $method = ($this->request->data['method']) ? $this->request->data['method'] : false; |
||
472 | |||
473 | switch ($method) { |
||
474 | case "email": |
||
475 | if (!isset($this->request->data['email'])) { |
||
476 | $this->set(compact('user', 'oldEmail')); |
||
477 | |||
478 | return $this->redirect(['action' => 'settings']); |
||
479 | } |
||
480 | |||
481 | $this->Users->patchEntity($user, $this->request->data(), ['validate' => 'settings']); |
||
482 | |||
483 | View Code Duplication | if ($this->Users->save($user)) { |
|
484 | $oldEmail = $this->request->data['email']; |
||
485 | |||
486 | //Logs Event. |
||
487 | $this->eventManager()->attach(new Logs()); |
||
488 | $event = new Event('Log.User', $this, [ |
||
489 | 'user_id' => $user->id, |
||
490 | 'username' => $user->username, |
||
491 | 'user_ip' => $this->request->clientIp(), |
||
492 | 'user_agent' => $this->request->header('User-Agent'), |
||
493 | 'action' => 'user.email' |
||
494 | ]); |
||
495 | $this->eventManager()->dispatch($event); |
||
496 | |||
497 | $this->Flash->success(__("Your E-mail has been changed !")); |
||
498 | } |
||
499 | break; |
||
500 | |||
501 | case "password": |
||
502 | $data = $this->request->data; |
||
503 | if (!isset($data['old_password']) || !isset($data['password']) || !isset($data['password_confirm'])) { |
||
504 | $this->set(compact('user', 'oldEmail')); |
||
505 | |||
506 | return $this->Flash->error(__("Please, complete all fields !")); |
||
507 | } |
||
508 | |||
509 | if (!(new DefaultPasswordHasher)->check($data['old_password'], $user->password)) { |
||
510 | $this->set(compact('user', 'oldEmail')); |
||
511 | |||
512 | return $this->Flash->error(__("Your old password don't match !")); |
||
513 | } |
||
514 | |||
515 | $this->Users->patchEntity($user, $this->request->data(), ['validate' => 'settings']); |
||
516 | View Code Duplication | if ($this->Users->save($user)) { |
|
0 ignored issues
–
show
|
|||
517 | //Logs Event. |
||
518 | $this->eventManager()->attach(new Logs()); |
||
519 | $event = new Event('Log.User', $this, [ |
||
520 | 'user_id' => $user->id, |
||
521 | 'username' => $user->username, |
||
522 | 'user_ip' => $this->request->clientIp(), |
||
523 | 'user_agent' => $this->request->header('User-Agent'), |
||
524 | 'action' => 'user.password.change' |
||
525 | ]); |
||
526 | $this->eventManager()->dispatch($event); |
||
527 | |||
528 | $this->Flash->success(__("Your password has been changed !")); |
||
529 | } |
||
530 | break; |
||
531 | } |
||
532 | } |
||
533 | |||
534 | $this->set(compact('user', 'oldEmail')); |
||
535 | } |
||
536 | |||
537 | /** |
||
538 | * View a profile page of an user. |
||
539 | * |
||
540 | * @return \Cake\Network\Response|void |
||
541 | */ |
||
542 | public function profile() |
||
543 | { |
||
544 | $user = $this->Users |
||
545 | ->find() |
||
546 | ->where([ |
||
547 | 'Users.id' => $this->request->id |
||
548 | ]) |
||
549 | ->contain([ |
||
550 | 'Groups' => function ($q) { |
||
551 | return $q->select(['id', 'name', 'css', 'is_staff', 'is_member']); |
||
552 | }, |
||
553 | 'BlogArticles' => function ($q) { |
||
554 | return $q |
||
555 | ->limit(Configure::read('User.Profile.max_blog_articles')) |
||
556 | ->order(['BlogArticles.created' => 'DESC']); |
||
557 | }, |
||
558 | 'BlogArticlesComments' => function ($q) { |
||
559 | return $q |
||
560 | ->limit(Configure::read('User.Profile.max_blog_comments')) |
||
561 | ->contain([ |
||
562 | 'BlogArticles' => function ($q) { |
||
563 | return $q->select(['id', 'title']); |
||
564 | } |
||
565 | ]) |
||
566 | ->order(['BlogArticlesComments.created' => 'DESC']); |
||
567 | }, |
||
568 | 'BadgesUsers' => function ($q) { |
||
569 | return $q |
||
570 | ->contain([ |
||
571 | 'Badges' => function ($q) { |
||
572 | return $q |
||
573 | ->select([ |
||
574 | 'name', |
||
575 | 'picture' |
||
576 | ]); |
||
577 | } |
||
578 | ]) |
||
579 | ->order([ |
||
580 | 'BadgesUsers.id' => 'DESC' |
||
581 | ]); |
||
582 | } |
||
583 | ]) |
||
584 | ->map(function ($user) { |
||
585 | $user->online = $this->SessionsActivity->getOnlineStatus($user); |
||
586 | $user->background_profile = UsersUtility::getProfileBackground(); |
||
587 | |||
588 | return $user; |
||
589 | }) |
||
590 | ->first(); |
||
591 | |||
592 | View Code Duplication | if (is_null($user) || $user->is_deleted == true) { |
|
593 | $this->Flash->error(__('This user doesn\'t exist or has been deleted.')); |
||
594 | |||
595 | return $this->redirect(['controller' => 'pages', 'action' => 'home']); |
||
596 | } |
||
597 | |||
598 | $this->set(compact('user')); |
||
599 | } |
||
600 | |||
601 | /** |
||
602 | * Delete an user with all his comments, articles and likes. |
||
603 | * |
||
604 | * @return \Cake\Network\Response |
||
605 | */ |
||
606 | public function delete() |
||
607 | { |
||
608 | if (!$this->request->is('post')) { |
||
609 | return $this->redirect(['action' => 'settings']); |
||
610 | } |
||
611 | |||
612 | $user = $this->Users->get($this->Auth->user('id')); |
||
613 | |||
614 | if (!(new DefaultPasswordHasher)->check($this->request->data['password'], $user->password)) { |
||
615 | $this->Flash->error(__("Your password doesn't match !")); |
||
616 | |||
617 | return $this->redirect(['action' => 'settings']); |
||
618 | } |
||
619 | |||
620 | $user->is_deleted = true; |
||
621 | |||
622 | if ($this->Users->save($user)) { |
||
623 | $this->Flash->success(__("Your account has been deleted successfully ! Thanks for your visit !")); |
||
624 | |||
625 | return $this->redirect($this->Auth->logout()); |
||
626 | } |
||
627 | |||
628 | $this->Flash->error(__("Unable to delete your account, please try again.")); |
||
629 | |||
630 | return $this->redirect(['action' => 'settings']); |
||
631 | } |
||
632 | |||
633 | /** |
||
634 | * Display all notifications related to the user. |
||
635 | * |
||
636 | * @return void |
||
637 | */ |
||
638 | View Code Duplication | public function notifications() |
|
639 | { |
||
640 | $this->loadModel('Notifications'); |
||
641 | |||
642 | $this->paginate = [ |
||
643 | 'maxLimit' => Configure::read('User.notifications_per_page') |
||
644 | ]; |
||
645 | |||
646 | $notifications = $this->Notifications |
||
647 | ->find() |
||
648 | ->where([ |
||
649 | 'user_id' => $this->Auth->user('id') |
||
650 | ]) |
||
651 | ->order([ |
||
652 | 'is_read' => 'ASC', |
||
653 | 'created' => 'DESC' |
||
654 | ]) |
||
655 | ->find('map', [ |
||
656 | 'session' => $this->request->session() |
||
657 | ]); |
||
658 | |||
659 | $notifications = $this->paginate($notifications); |
||
660 | |||
661 | $this->set(compact('notifications')); |
||
662 | } |
||
663 | |||
664 | /** |
||
665 | * Display the form to reset the password. |
||
666 | * |
||
667 | * @return \Cake\Network\Response|void |
||
668 | */ |
||
669 | public function forgotPassword() |
||
670 | { |
||
671 | if ($this->Auth->user()) { |
||
672 | return $this->redirect(['controller' => 'pages', 'action' => 'home']); |
||
673 | } |
||
674 | |||
675 | if ($this->request->is('post')) { |
||
676 | $user = $this->Users |
||
677 | ->find() |
||
678 | ->where([ |
||
679 | 'Users.email' => $this->request->data['email'] |
||
680 | ]) |
||
681 | ->first(); |
||
682 | |||
683 | if (is_null($user)) { |
||
684 | $this->Flash->error(__("This E-mail doesn't exist or the account has been deleted.")); |
||
685 | |||
686 | $this->set(compact('user')); |
||
687 | |||
688 | return; |
||
689 | } |
||
690 | |||
691 | if (!$this->Recaptcha->verify()) { |
||
692 | $this->Flash->error(__("Please, correct your Captcha.")); |
||
693 | |||
694 | $this->set(compact('user')); |
||
695 | |||
696 | return; |
||
697 | } |
||
698 | |||
699 | //Generate the unique code |
||
700 | $code = md5(rand() . uniqid() . time()); |
||
701 | |||
702 | //Update the user's information |
||
703 | $user->password_code = $code; |
||
704 | $user->password_code_expire = new Time(); |
||
705 | |||
706 | $this->Users->save($user); |
||
707 | |||
708 | $viewVars = [ |
||
709 | 'userId' => $user->id, |
||
710 | 'name' => $user->full_name, |
||
711 | 'username' => $user->username, |
||
712 | 'code' => $code |
||
713 | ]; |
||
714 | |||
715 | $this->getMailer('User')->send('forgotPassword', [$user, $viewVars]); |
||
716 | |||
717 | //Logs Event. |
||
718 | $this->eventManager()->attach(new Logs()); |
||
719 | $event = new Event('Log.User', $this, [ |
||
720 | 'user_id' => $user->id, |
||
721 | 'username' => $user->username, |
||
722 | 'user_ip' => $this->request->clientIp(), |
||
723 | 'user_agent' => $this->request->header('User-Agent'), |
||
724 | 'action' => 'user.password.reset' |
||
725 | ]); |
||
726 | $this->eventManager()->dispatch($event); |
||
727 | |||
728 | $this->Flash->success(__("An E-mail has been send to <strong>{0}</strong>. Please follow the instructions in the E-mail.", h($user->email))); |
||
729 | } |
||
730 | |||
731 | $this->set(compact('user')); |
||
732 | } |
||
733 | |||
734 | /** |
||
735 | * Display the form to reset his password. |
||
736 | * |
||
737 | * @return \Cake\Network\Response|void |
||
738 | */ |
||
739 | public function resetPassword() |
||
740 | { |
||
741 | if ($this->Auth->user()) { |
||
742 | return $this->redirect(['controller' => 'pages', 'action' => 'home']); |
||
743 | } |
||
744 | |||
745 | //Prevent for empty code. |
||
746 | if (empty(trim($this->request->code))) { |
||
747 | $this->Flash->error(__("This code is not associated with this users or is incorrect.")); |
||
748 | |||
749 | return $this->redirect(['controller' => 'pages', 'action' => 'home']); |
||
750 | } |
||
751 | |||
752 | $user = $this->Users |
||
753 | ->find() |
||
754 | ->where([ |
||
755 | 'Users.password_code' => $this->request->code, |
||
756 | 'Users.id' => $this->request->id |
||
757 | ]) |
||
758 | ->first(); |
||
759 | |||
760 | View Code Duplication | if (is_null($user)) { |
|
761 | $this->Flash->error(__("This code is not associated with this users or is incorrect.")); |
||
762 | |||
763 | return $this->redirect(['controller' => 'pages', 'action' => 'home']); |
||
764 | } |
||
765 | |||
766 | $expire = $user->password_code_expire->timestamp + (Configure::read('User.ResetPassword.expire_code') * 60); |
||
767 | |||
768 | if ($expire < time()) { |
||
769 | $this->Flash->error(__("This code is expired, please ask another E-mail code.")); |
||
770 | |||
771 | return $this->redirect(['action' => 'forgotPassword']); |
||
772 | } |
||
773 | |||
774 | if ($this->request->is(['post', 'put'])) { |
||
775 | $this->Users->patchEntity($user, $this->request->data, ['validate' => 'resetpassword']); |
||
776 | |||
777 | if ($this->Users->save($user)) { |
||
778 | $this->Flash->success(__("Your password has been changed !")); |
||
779 | |||
780 | //Reset the code and the time. |
||
781 | $user->password_code = ''; |
||
782 | $user->password_code_expire = new Time(); |
||
783 | $user->password_reset_count = $user->password_reset_count + 1; |
||
784 | $this->Users->save($user); |
||
785 | |||
786 | //Logs Event. |
||
787 | $this->eventManager()->attach(new Logs()); |
||
788 | $event = new Event('Log.User', $this, [ |
||
789 | 'user_id' => $user->id, |
||
790 | 'username' => $user->username, |
||
791 | 'user_ip' => $this->request->clientIp(), |
||
792 | 'user_agent' => $this->request->header('User-Agent'), |
||
793 | 'action' => 'user.password.reset.successful' |
||
794 | ]); |
||
795 | $this->eventManager()->dispatch($event); |
||
796 | |||
797 | return $this->redirect(['controller' => 'users', 'action' => 'login']); |
||
798 | } |
||
799 | } |
||
800 | |||
801 | $this->set(compact('user')); |
||
802 | } |
||
803 | |||
804 | /** |
||
805 | * Display the sessions and logs informations. |
||
806 | * |
||
807 | * @return void |
||
808 | */ |
||
809 | public function security() |
||
810 | { |
||
811 | $records = $this->SessionsActivity->getOnlineSessionsForUser($this->Auth->user('id')); |
||
812 | |||
813 | $browscap = new Browscap(); |
||
814 | $sessions = []; |
||
815 | |||
816 | foreach ($records as $record) { |
||
817 | $infos = $browscap->getBrowser($record->user_agent); |
||
818 | |||
819 | $record->infos = $infos; |
||
820 | |||
821 | array_push($sessions, $record); |
||
822 | } |
||
823 | |||
824 | $this->loadModel('UsersLogs'); |
||
825 | |||
826 | $this->paginate = [ |
||
827 | 'maxLimit' => 25 |
||
828 | ]; |
||
829 | |||
830 | $logs = $this->UsersLogs |
||
831 | ->find() |
||
832 | ->where([ |
||
833 | 'UsersLogs.user_id' => $this->Auth->user('id') |
||
834 | ]) |
||
835 | ->order([ |
||
836 | 'UsersLogs.created' => 'DESC' |
||
837 | ]) |
||
838 | ->formatResults(function ($logs) use ($browscap) { |
||
839 | return $logs->map(function ($log) use ($browscap) { |
||
840 | $log->infos = $browscap->getBrowser($log->user_agent); |
||
841 | |||
842 | return $log; |
||
843 | }); |
||
844 | }); |
||
845 | |||
846 | $logs = $this->paginate($logs); |
||
847 | |||
848 | $user = $this->Users |
||
849 | ->find() |
||
850 | ->where([ |
||
851 | 'Users.id' => $this->Auth->user('id') |
||
852 | ]) |
||
853 | ->select([ |
||
854 | 'id', |
||
855 | 'two_factor_auth_enabled' |
||
856 | ]) |
||
857 | ->first(); |
||
858 | |||
859 | $this->set(compact('sessions', 'logs', 'user')); |
||
860 | } |
||
861 | } |
||
862 |
Since your code implements the magic getter
_get
, this function will be called for any read access on an undefined variable. You can add the@property
annotation to your class or interface to document the existence of this variable.If the property has read access only, you can use the @property-read annotation instead.
Of course, you may also just have mistyped another name, in which case you should fix the error.
See also the PhpDoc documentation for @property.