Completed
Push — master ( 9c742a...1858b1 )
by Fèvre
14s
created

src/Controller/UsersController.php (12 issues)

Upgrade to new PHP Analysis Engine

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
        //Handle Maintenances
89
        if (Configure::read('User.Login.enabled') === false) {
90
            $this->Flash->error(__("The Login action is disabled for the moment, please try again later."));
91
        }
92
93
        if (Configure::read('User.Register.enabled') === false && Configure::read('Site.maintenance') === false) {
94
            $this->Flash->error(__("The Register action is disabled for the moment, please try again later."));
95
        }
96
97
        if (Configure::read('Site.maintenance') === true) {
98
            $this->Flash->error(__("While the site is in maintenance, you can not register a new account."));
99
        }
100
101
        if ($this->request->is('post')) {
102
            $method = ($this->request->data['method']) ? $this->request->data['method'] : false;
103
104
            switch ($method) {
105
                case "login":
106
                    if (Configure::read('User.Login.enabled') === false) {
107
                        $userRegister = $userRegister = $this->Users->newEntity($this->request->data);
108
109
                        break;
110
                    }
111
                    $userLogin = $this->Auth->identify();
112
113
                    if ($userLogin) {
114
                        if ($userLogin['is_deleted'] == true) {
115
                            $this->Flash->error(__("This account has been deleted."));
116
117
                            $userRegister = $this->Users->newEntity($this->request->data);
118
119
                            break;
120
                        }
121
122
                        //Check the 2FA if the user has enabled it.
123
                        if ($userLogin['two_factor_auth_enabled'] == true && $this->TwoFactorAuth->isAuthorized($userLogin['id']) === false) {
124
                            //Write the cookie
125
                            $cookie = base64_encode(Security::encrypt($userLogin['id'], Configure::read('Security.key')));
126
                            $this->Cookie->configKey('CookieTfa', [
127
                                'expires' => '+1 hour',
128
                                'httpOnly' => true
129
                            ]);
130
                            $this->Cookie->write('CookieTfa', $cookie);
131
132
                            return $this->redirect(['action' => 'tfa']);
133
                        }
134
135
                        $this->_handleLogin($userLogin);
136
137
                        $this->Auth->setUser($userLogin);
138
139
                        $user = $this->Users->newEntity($userLogin, ['accessibleFields' => ['id' => true]]);
140
                        $user->isNew(false);
141
142
                        $user->last_login = new Time();
143
                        $user->last_login_ip = $this->request->clientIp();
144
145
                        $this->Users->save($user);
146
147
                        //Cookies.
148
                        $this->Cookie->configKey('CookieAuth', [
149
                            'expires' => '+1 year',
150
                            'httpOnly' => true
151
                        ]);
152
                        $this->Cookie->write('CookieAuth', [
153
                            'username' => $this->request->data('username'),
154
                            'password' => $this->request->data('password')
155
                        ]);
156
157
                        //Badge Event.
158
                        $this->eventManager()->attach(new Badges($this));
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
159
                        $user = new Event('Model.Users.register', $this, [
160
                            'user' => $user
161
                        ]);
162
                        $this->eventManager()->dispatch($user);
163
164
                        $url = $this->Auth->redirectUrl();
165 View Code Duplication
                        if (substr($this->Auth->redirectUrl(), -5) == 'login') {
166
                            $url = ['controller' => 'pages', 'action' => 'home'];
167
                        }
168
169
                        return $this->redirect($url);
170
                    }
171
172
                    $user = $this->Users
173
                        ->find()
174
                        ->where([
175
                            'username' => $this->request->data['username']
176
                        ])
177
                        ->select([
178
                            'id',
179
                            'group_id',
180
                            'username',
181
                            'email'
182
                        ])
183
                        ->first();
184
185
                    if (!is_null($user)) {
186
                        //Users Event.
187
                        $this->eventManager()->attach(new Users());
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
188
                        $event = new Event('Users.login.failed', $this, [
189
                            'user_id' => $user->id,
190
                            'username' => $user->username,
191
                            'group_id' => $user->group_id,
192
                            'user_ip' => $this->request->clientIp(),
193
                            'user_email' => $user->email,
194
                            'user_agent' => $this->request->header('User-Agent'),
195
                            'action' => 'user.connection.manual.failed'
196
                        ]);
197
                        $this->eventManager()->dispatch($event);
198
                    }
199
200
                    $this->Flash->error(__("Your username or password doesn't match."));
201
202
                    $userRegister = $this->Users->newEntity($this->request->data);
203
204
                    break;
205
206
                case "register":
207
                    $userRegister = $this->Users->newEntity($this->request->data, ['validate' => 'create']);
208
209
                    //Handle Maintenances
210
                    if (Configure::read('Site.maintenance') === true || Configure::read('User.Register.enabled') === false) {
211
                        break;
212
                    }
213
214
                    $userRegister->register_ip = $this->request->clientIp();
215
                    $userRegister->last_login_ip = $this->request->clientIp();
216
                    $userRegister->last_login = new Time();
217
218
                    if ($this->Recaptcha->verify() || Configure::read('Recaptcha.bypass') === true) {
219
                        if ($this->Users->save($userRegister)) {
220
                            $user = $this->Auth->identify();
221
222
                            if ($user) {
223
                                $this->Auth->setUser($user);
224
                            }
225
226
                            $user = $this->Users->get($user['id']);
227
228
                            //Statistics Event.
229
                            $this->eventManager()->attach(new Statistics());
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
230
                            $stats = new Event('Model.Users.register', $this);
231
                            $this->eventManager()->dispatch($stats);
232
233
                            //Notification Events.
234
                            $this->eventManager()->attach(new Notifications());
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
235
                            $event = new Event('Model.Notifications.new', $this, [
236
                                'user_id' => $user->id,
237
                                'type' => 'bot'
238
                            ]);
239
                            $this->eventManager()->dispatch($event);
240
241
                            $viewVars = [
242
                                'user' => $user,
243
                                'name' => $user->full_name
244
                            ];
245
246
                            $this->getMailer('User')->send('register', [$user, $viewVars]);
247
248
                            $this->Flash->success(__("Your account has been created successfully !"));
249
250
                            $url = $this->Auth->redirectUrl();
251 View Code Duplication
                            if (substr($this->Auth->redirectUrl(), -5) == 'login') {
252
                                $url = ['controller' => 'pages', 'action' => 'home'];
253
                            }
254
255
                            return $this->redirect($url);
256
                        }
257
258
                        $this->Flash->error(__("Please, correct your mistake."));
259
                    } else {
260
                        $this->Flash->error(__("Please, correct your Captcha."));
261
                    }
262
263
                    break;
264
            }
265
        } else {
266
            //Save the referer URL before the user send the login/register request else it will delete the referer.
267
            $this->request->session()->write('Auth.redirect', $this->referer());
268
269
            $userRegister = $this->Users->newEntity($this->request->data, ['validate' => 'create']);
270
        }
271
272
        if ($this->Auth->user()) {
273
            return $this->redirect($this->Auth->redirectUrl());
274
        }
275
276
        $this->set(compact('userRegister'));
277
    }
278
279
    /**
280
     * Handle the login part after all verification.
281
     *
282
     * @param array $userLogin The user information.
283
     *
284
     * @return void
285
     */
286
    protected function _handleLogin($userLogin)
287
    {
288
        $this->Auth->setUser($userLogin);
289
290
        $user = $this->Users->newEntity($userLogin);
291
        $user->isNew(false);
292
        $user->id = $userLogin['id'];
293
294
        $user->last_login = new Time();
295
        $user->last_login_ip = $this->request->clientIp();
296
297
        $this->Users->save($user);
298
299
        //Cookies.
300
        $this->Cookie->configKey('CookieAuth', [
301
            'expires' => '+1 year',
302
            'httpOnly' => true
303
        ]);
304
        $this->Cookie->write('CookieAuth', [
305
            'username' => $this->request->data('username'),
306
            'password' => $this->request->data('password')
307
        ]);
308
309
        //Badge Event.
310
        $this->eventManager()->attach(new Badges($this));
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
311
        $badge = new Event('Model.Users.register', $this, [
312
            'user' => $user
313
        ]);
314
        $this->eventManager()->dispatch($badge);
315
316
        //Logs Event.
317
        $this->eventManager()->attach(new Logs());
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
318
        $event = new Event('Log.User', $this, [
319
            'user_id' => $user->id,
320
            'username' => $user->username,
321
            'user_ip' => $this->request->clientIp(),
322
            'user_agent' => $this->request->header('User-Agent'),
323
            'action' => 'user.connection.manual.success'
324
        ]);
325
        $this->eventManager()->dispatch($event);
326
327
        $this->request->session()->write('Notification', ['type' => 'primary', 'message' => __('Happy to see you again {0} ! ', h($user->username))]);
328
    }
329
330
    /**
331
     * Logout an user.
332
     *
333
     * @return \Cake\Network\Response
334
     */
335
    public function logout()
336
    {
337
        $this->request->session()->write('Notification', ['type' => 'danger', 'message' => __('See you later {0} ! ', h($this->Auth->user('username')))]);
338
339
        return $this->redirect($this->Auth->logout());
340
    }
341
342
    /**
343
     * Ask to the user the 2FA code and verify it.
344
     *
345
     * @return \Cake\Network\Response|void
346
     */
347
    public function tfa()
348
    {
349
        if ($this->Auth->user()) {
350
            return $this->redirect($this->Auth->redirectUrl());
351
        }
352
353
        if ($this->request->is('post')) {
354
            $this->loadModel('UsersTwoFactorAuth');
355
356
            $id = $this->Cookie->read('CookieTfa');
357
358 View Code Duplication
            if (empty($id) || $id == false) {
359
                $this->Cookie->delete('CookieTfa');
360
361
                return $this->redirect($this->Auth->config('loginAction'));
362
            }
363
364
            try {
365
                $id = Security::decrypt(base64_decode($id), Configure::read('Security.key'));
366
            } catch (\Exception $e) {
367
                $this->Flash->error(__('The link used for the Two-factor Authentication is incorrect.'));
368
369
                return $this->redirect($this->Auth->config('loginAction'));
370
            }
371
372
            $userTfa = $this->UsersTwoFactorAuth
373
                ->find()
374
                ->where([
375
                    'user_id' => $id
376
                ])
377
                ->first();
378
379
            $tfa = new TwoFactorAuth('Xeta');
380
381
            $isAuthorized = false;
382
            $recoveryCodeUsed = false;
383
384
            if ($tfa->verifyCode($userTfa->secret, $this->request->data['code']) === true && $this->request->data['code'] !== $userTfa->current_code) {
385
                $isAuthorized = true;
386
            //Check recovery code and verify if the recovery code is not already used.
387
            } elseif ($userTfa->recovery_code === $this->request->data['code'] && $userTfa->recovery_code_used == false && $this->request->data['code'] !== $userTfa->current_code) {
388
                $isAuthorized = true;
389
                $recoveryCodeUsed = true;
390
            }
391
392
            if ($isAuthorized === true) {
393
                $data = [
394
                    'session' => $this->request->clientIp() . $this->request->header('User-Agent') . gethostbyaddr($this->request->clientIp()),
395
                    'current_code' => $recoveryCodeUsed === true ? 'recovery' : $this->request->data['code'],
396
                    'recovery_code_used' => $recoveryCodeUsed === true ? 1 : $userTfa->recovery_code_used
397
                ];
398
399
                $this->UsersTwoFactorAuth->patchEntity($userTfa, $data);
400
                $this->UsersTwoFactorAuth->save($userTfa);
401
402
                //Login the user.
403
                $userLogin = $this->Users
404
                    ->find()
405
                    ->where([
406
                        'id' => $id
407
                    ])
408
                    ->hydrate(false)
409
                    ->first();
410
411
                unset($userLogin['password']);
412
413
                $this->_handleLogin($userLogin);
414
415
                $this->Cookie->delete('CookieTfa');
416
417
                //Logs Event.
418
                $this->eventManager()->attach(new Logs());
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
419
                $event = new Event('Log.User', $this, [
420
                    'user_id' => $userLogin['id'],
421
                    'username' => $userLogin['username'],
422
                    'user_ip' => $this->request->clientIp(),
423
                    'user_agent' => $this->request->header('User-Agent'),
424
                    'action' => '2FA.recovery_code.used'
425
                ]);
426
                $this->eventManager()->dispatch($event);
427
428
                return $this->redirect(['controller' => 'pages', 'action' => 'home']);
429
            } else {
430
                $this->Flash->error(__('Two-factor secret verification failed. Please verify your code and try again.'));
431
            }
432
        }
433
434
        $id = $this->Cookie->read('CookieTfa');
435
436 View Code Duplication
        if (empty($id) || $id == false) {
437
            $this->Cookie->delete('CookieTfa');
438
439
            return $this->redirect($this->Auth->config('loginAction'));
440
        }
441
    }
442
443
    /**
444
     * Page to configure our account.
445
     *
446
     * @return void
447
     */
448
    public function account()
449
    {
450
        $user = $this->Users->get($this->Auth->user('id'));
451
452
        if ($this->request->is('put')) {
453
            $user->accessible('avatar_file', true);
454
            $this->Users->patchEntity($user, $this->request->data(), ['validate' => 'account']);
455
456
            if ($this->Users->save($user)) {
457
                $this->request->session()->write('Auth.User.avatar', $user->avatar);
458
459
                //Logs Event.
460
                $this->eventManager()->attach(new Logs());
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
461
                $event = new Event('Log.User', $this, [
462
                    'user_id' => $user->id,
463
                    'username' => $user->username,
464
                    'user_ip' => $this->request->clientIp(),
465
                    'user_agent' => $this->request->header('User-Agent'),
466
                    'action' => 'user.account.modify'
467
                ]);
468
                $this->eventManager()->dispatch($event);
469
470
                $this->Flash->success(__("Your information has been updated !"));
471
            }
472
        }
473
474
        $this->set(compact('user'));
475
    }
476
477
    /**
478
     * Page to configure our settings.
479
     *
480
     * @return \Cake\Network\Response|void
481
     */
482
    public function settings()
483
    {
484
        $user = $this->Users->get($this->Auth->user('id'));
485
486
        $oldEmail = $user->email;
487
488
        if ($this->request->is('put')) {
489
            $method = ($this->request->data['method']) ? $this->request->data['method'] : false;
490
491
            switch ($method) {
492
                case "email":
493
                    if (!isset($this->request->data['email'])) {
494
                        $this->set(compact('user', 'oldEmail'));
495
496
                        return $this->redirect(['action' => 'settings']);
497
                    }
498
499
                    $this->Users->patchEntity($user, $this->request->data(), ['validate' => 'settings']);
500
501 View Code Duplication
                    if ($this->Users->save($user)) {
502
                        $oldEmail = $this->request->data['email'];
503
504
                        //Logs Event.
505
                        $this->eventManager()->attach(new Logs());
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
506
                        $event = new Event('Log.User', $this, [
507
                            'user_id' => $user->id,
508
                            'username' => $user->username,
509
                            'user_ip' => $this->request->clientIp(),
510
                            'user_agent' => $this->request->header('User-Agent'),
511
                            'action' => 'user.email'
512
                        ]);
513
                        $this->eventManager()->dispatch($event);
514
515
                        $this->Flash->success(__("Your E-mail has been changed !"));
516
                    }
517
                    break;
518
519
                case "password":
520
                    $data = $this->request->data;
521
                    if (!isset($data['old_password']) || !isset($data['password']) || !isset($data['password_confirm'])) {
522
                        $this->set(compact('user', 'oldEmail'));
523
524
                        return $this->Flash->error(__("Please, complete all fields !"));
525
                    }
526
527
                    if (!(new DefaultPasswordHasher)->check($data['old_password'], $user->password)) {
528
                        $this->set(compact('user', 'oldEmail'));
529
530
                        return $this->Flash->error(__("Your old password don't match !"));
531
                    }
532
533
                    $this->Users->patchEntity($user, $this->request->data(), ['validate' => 'settings']);
534 View Code Duplication
                    if ($this->Users->save($user)) {
535
                        //Logs Event.
536
                        $this->eventManager()->attach(new Logs());
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
537
                        $event = new Event('Log.User', $this, [
538
                            'user_id' => $user->id,
539
                            'username' => $user->username,
540
                            'user_ip' => $this->request->clientIp(),
541
                            'user_agent' => $this->request->header('User-Agent'),
542
                            'action' => 'user.password.change'
543
                        ]);
544
                        $this->eventManager()->dispatch($event);
545
546
                        $this->Flash->success(__("Your password has been changed !"));
547
                    }
548
                    break;
549
            }
550
        }
551
552
        $this->set(compact('user', 'oldEmail'));
553
    }
554
555
    /**
556
     * View a profile page of an user.
557
     *
558
     * @return \Cake\Network\Response|void
559
     */
560
    public function profile()
561
    {
562
        $user = $this->Users
563
            ->find()
564
            ->where([
565
                'Users.id' => $this->request->id
566
            ])
567
            ->contain([
568
                'Groups' => function ($q) {
569
                    return $q->select(['id', 'name', 'css', 'is_staff', 'is_member']);
570
                },
571
                'BlogArticles' => function ($q) {
572
                    return $q
573
                        ->limit(Configure::read('User.Profile.max_blog_articles'))
574
                        ->order(['BlogArticles.created' => 'DESC']);
575
                },
576
                'BlogArticlesComments' => function ($q) {
577
                    return $q
578
                        ->limit(Configure::read('User.Profile.max_blog_comments'))
579
                        ->contain([
580
                            'BlogArticles' => function ($q) {
581
                                return $q->select(['id', 'title']);
582
                            }
583
                        ])
584
                        ->order(['BlogArticlesComments.created' => 'DESC']);
585
                },
586
                'BadgesUsers' => function ($q) {
587
                    return $q
588
                        ->contain([
589
                            'Badges' => function ($q) {
590
                                return $q
591
                                    ->select([
592
                                        'name',
593
                                        'picture'
594
                                    ]);
595
                            }
596
                        ])
597
                        ->order([
598
                            'BadgesUsers.id' => 'DESC'
599
                        ]);
600
                }
601
            ])
602
            ->map(function ($user) {
603
                $user->online = $this->SessionsActivity->getOnlineStatus($user);
604
                $user->background_profile = UsersUtility::getProfileBackground();
605
606
                return $user;
607
            })
608
            ->first();
609
610 View Code Duplication
        if (is_null($user) || $user->is_deleted == true) {
611
            $this->Flash->error(__('This user doesn\'t exist or has been deleted.'));
612
613
            return $this->redirect(['controller' => 'pages', 'action' => 'home']);
614
        }
615
616
        $this->set(compact('user'));
617
    }
618
619
    /**
620
     * Delete an user with all his comments, articles and likes.
621
     *
622
     * @return \Cake\Network\Response
623
     */
624
    public function delete()
625
    {
626
        if (!$this->request->is('post')) {
627
            return $this->redirect(['action' => 'settings']);
628
        }
629
630
        $user = $this->Users->get($this->Auth->user('id'));
631
632
        if (!(new DefaultPasswordHasher)->check($this->request->data['password'], $user->password)) {
633
            $this->Flash->error(__("Your password doesn't match !"));
634
635
            return $this->redirect(['action' => 'settings']);
636
        }
637
638
        $user->is_deleted = true;
639
640
        if ($this->Users->save($user)) {
641
            $this->Flash->success(__("Your account has been deleted successfully ! Thanks for your visit !"));
642
643
            return $this->redirect($this->Auth->logout());
644
        }
645
646
        $this->Flash->error(__("Unable to delete your account, please try again."));
647
648
        return $this->redirect(['action' => 'settings']);
649
    }
650
651
    /**
652
     * Display all notifications related to the user.
653
     *
654
     * @return void
655
     */
656 View Code Duplication
    public function notifications()
657
    {
658
        $this->loadModel('Notifications');
659
660
        $this->paginate = [
661
            'maxLimit' => Configure::read('User.notifications_per_page')
662
        ];
663
664
        $notifications = $this->Notifications
665
            ->find()
666
            ->where([
667
                'user_id' => $this->Auth->user('id')
668
            ])
669
            ->order([
670
                'is_read' => 'ASC',
671
                'created' => 'DESC'
672
            ])
673
            ->find('map', [
674
                'session' => $this->request->session()
675
            ]);
676
677
        $notifications = $this->paginate($notifications);
678
679
        $this->set(compact('notifications'));
680
    }
681
682
    /**
683
     * Display the form to reset the password.
684
     *
685
     * @return \Cake\Network\Response|void
686
     */
687
    public function forgotPassword()
688
    {
689
        if ($this->Auth->user()) {
690
            return $this->redirect(['controller' => 'pages', 'action' => 'home']);
691
        }
692
693
        if ($this->request->is('post')) {
694
            $user = $this->Users
695
                ->find()
696
                ->where([
697
                    'Users.email' => $this->request->data['email']
698
                ])
699
                ->first();
700
701
            if (is_null($user)) {
702
                $this->Flash->error(__("This E-mail doesn't exist or the account has been deleted."));
703
704
                $this->set(compact('user'));
705
706
                return;
707
            }
708
709
            if (!$this->Recaptcha->verify()) {
710
                $this->Flash->error(__("Please, correct your Captcha."));
711
712
                $this->set(compact('user'));
713
714
                return;
715
            }
716
717
            //Generate the unique code
718
            $code = md5(rand() . uniqid() . time());
719
720
            //Update the user's information
721
            $user->password_code = $code;
722
            $user->password_code_expire = new Time();
723
724
            $this->Users->save($user);
725
726
            $viewVars = [
727
                'userId' => $user->id,
728
                'name' => $user->full_name,
729
                'username' => $user->username,
730
                'code' => $code
731
            ];
732
733
            $this->getMailer('User')->send('forgotPassword', [$user, $viewVars]);
734
735
            //Logs Event.
736
            $this->eventManager()->attach(new Logs());
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
737
            $event = new Event('Log.User', $this, [
738
                'user_id' => $user->id,
739
                'username' => $user->username,
740
                'user_ip' => $this->request->clientIp(),
741
                'user_agent' => $this->request->header('User-Agent'),
742
                'action' => 'user.password.reset'
743
            ]);
744
            $this->eventManager()->dispatch($event);
745
746
            $this->Flash->success(__("An E-mail has been send to <strong>{0}</strong>. Please follow the instructions in the E-mail.", h($user->email)));
747
        }
748
749
        $this->set(compact('user'));
750
    }
751
752
    /**
753
     * Display the form to reset his password.
754
     *
755
     * @return \Cake\Network\Response|void
756
     */
757
    public function resetPassword()
758
    {
759
        if ($this->Auth->user()) {
760
            return $this->redirect(['controller' => 'pages', 'action' => 'home']);
761
        }
762
763
        //Prevent for empty code.
764
        if (empty(trim($this->request->code))) {
765
            $this->Flash->error(__("This code is not associated with this users or is incorrect."));
766
767
            return $this->redirect(['controller' => 'pages', 'action' => 'home']);
768
        }
769
770
        $user = $this->Users
771
            ->find()
772
            ->where([
773
                'Users.password_code' => $this->request->code,
774
                'Users.id' => $this->request->id
775
            ])
776
            ->first();
777
778 View Code Duplication
        if (is_null($user)) {
779
            $this->Flash->error(__("This code is not associated with this users or is incorrect."));
780
781
            return $this->redirect(['controller' => 'pages', 'action' => 'home']);
782
        }
783
784
        $expire = $user->password_code_expire->timestamp + (Configure::read('User.ResetPassword.expire_code') * 60);
785
786
        if ($expire < time()) {
787
            $this->Flash->error(__("This code is expired, please ask another E-mail code."));
788
789
            return $this->redirect(['action' => 'forgotPassword']);
790
        }
791
792
        if ($this->request->is(['post', 'put'])) {
793
            $this->Users->patchEntity($user, $this->request->data, ['validate' => 'resetpassword']);
794
795
            if ($this->Users->save($user)) {
796
                $this->Flash->success(__("Your password has been changed !"));
797
798
                //Reset the code and the time.
799
                $user->password_code = '';
800
                $user->password_code_expire = new Time();
801
                $user->password_reset_count = $user->password_reset_count + 1;
802
                $this->Users->save($user);
803
804
                //Logs Event.
805
                $this->eventManager()->attach(new Logs());
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Event\EventManager::attach() has been deprecated with message: 3.0.0 Use on() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
806
                $event = new Event('Log.User', $this, [
807
                    'user_id' => $user->id,
808
                    'username' => $user->username,
809
                    'user_ip' => $this->request->clientIp(),
810
                    'user_agent' => $this->request->header('User-Agent'),
811
                    'action' => 'user.password.reset.successful'
812
                ]);
813
                $this->eventManager()->dispatch($event);
814
815
                return $this->redirect(['controller' => 'users', 'action' => 'login']);
816
            }
817
        }
818
819
        $this->set(compact('user'));
820
    }
821
822
    /**
823
     * Display the sessions and logs informations.
824
     *
825
     * @return void
826
     */
827
    public function security()
828
    {
829
        $records = $this->SessionsActivity->getOnlineSessionsForUser($this->Auth->user('id'));
830
831
        $browscap = new Browscap();
832
        $sessions = [];
833
834
        foreach ($records as $record) {
835
            $infos = $browscap->getBrowser($record->user_agent);
836
837
            $record->infos = $infos;
838
839
            array_push($sessions, $record);
840
        }
841
842
        $this->loadModel('UsersLogs');
843
844
        $this->paginate = [
845
            'maxLimit' => 25
846
        ];
847
848
        $logs = $this->UsersLogs
849
            ->find()
850
            ->where([
851
                'UsersLogs.user_id' => $this->Auth->user('id')
852
            ])
853
            ->order([
854
                'UsersLogs.created' => 'DESC'
855
            ])
856
            ->formatResults(function ($logs) use ($browscap) {
857
                return $logs->map(function ($log) use ($browscap) {
858
                    $log->infos = $browscap->getBrowser($log->user_agent);
859
860
                    return $log;
861
                });
862
            });
863
864
        $logs = $this->paginate($logs);
865
866
        $user = $this->Users
867
            ->find()
868
            ->where([
869
                'Users.id' => $this->Auth->user('id')
870
            ])
871
            ->select([
872
                'id',
873
                'two_factor_auth_enabled'
874
            ])
875
            ->first();
876
877
        $this->set(compact('sessions', 'logs', 'user'));
878
    }
879
}
880