Completed
Push — master ( 4714f7...5c9972 )
by Fèvre
11s
created

src/Controller/UsersController.php (1 issue)

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
        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
The property Users does not exist on object<App\Controller\UsersController>. Since you implemented __get, maybe consider adding a @property annotation.

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.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

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.

Loading history...
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