LoginAttemptNotifications::init()   B
last analyzed

Complexity

Conditions 11
Paths 10

Size

Total Lines 72
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
cc 11
eloc 44
c 1
b 1
f 0
nc 10
nop 0
dl 0
loc 72
rs 7.3166

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace CWP\Core\Extension;
4
5
use SilverStripe\Admin\LeftAndMain;
6
use SilverStripe\Core\Extension;
7
use SilverStripe\ORM\FieldType\DBDatetime;
8
use SilverStripe\Security\LoginAttempt;
9
use SilverStripe\Security\Security;
10
use SilverStripe\View\Requirements;
11
12
/**
13
 * TODO: describe.
14
 * TODO: bug when using default admin - always shows the message...
15
 * Requires Security::login_recording config to be set to true.
16
 *
17
 * @property LeftAndMain $owner
18
 */
19
class LoginAttemptNotifications extends Extension
20
{
21
22
    /**
23
     *
24
     * @return mixed null
25
     */
26
    public function init()
27
    {
28
29
        // Exclude default admin.
30
        $member = Security::getCurrentUser();
31
        if (!$member || !$member->ID) {
0 ignored issues
show
introduced by
$member is of type SilverStripe\Security\Member, thus it always evaluated to true.
Loading history...
32
            return;
33
        }
34
35
        $message = null;
36
        $session = $this->owner->getRequest()->getSession();
37
38
        Requirements::javascript('cwp/cwp-core:javascript/LoginAttemptNotifications.js');
39
        $sessionLastVisited = $session->get('LoginAttemptNotifications.SessionLastVisited');
40
        if ($sessionLastVisited) {
41
            // Session already in progress. Show all attempts since the session was last visited.
42
43
            $meantimeLoginAttempts = LoginAttempt::get()->filter([
44
                'MemberID' => $member->ID,
45
                'Created:GreaterThan' => $sessionLastVisited
46
            ]);
47
48
            $attempts = $meantimeLoginAttempts->count();
49
            if ($attempts) {
50
                $lastVisitedObj = DBDatetime::create();
51
                $lastVisitedObj->setValue($sessionLastVisited);
52
                $elapsed = $lastVisitedObj->TimeDiff();
53
                $failures = $meantimeLoginAttempts->filter(['Status' => 'Failure'])->count();
54
                $IPs = array_unique($meantimeLoginAttempts->column('IP'));
55
56
                if ($attempts == 1) {
57
                    $statusString = $failures ? "a failed" : "a successful";
58
                    $message = "In the last $elapsed $statusString login attempt to your account was "
59
                        . "registered. The attempt was made from ${IPs[0]}. ";
60
                } else {
61
                    if ($failures == $attempts) {
62
                        $statusString = $failures ? "failed" : "successful";
63
                        $message = "In the last $elapsed $attempts $statusString login "
64
                            . "attempts to your account were registered. ";
65
                    } else {
66
                        $message = "In the last $elapsed $attempts login attempts to your "
67
                            . "account were registered, of which $failures failed. ";
68
                    }
69
70
                    $message .= "The attempts were from " . implode(', ', $IPs) . '. ';
71
72
                    // TODO: add this call to action in a way that doesn't break out of the availabel space. Fix CSS?
73
                    // $message .= "If you suspect somebody else might be trying to access
74
                    //  . "your account, please contact support.";
75
                }
76
            }
77
        } else {
78
            // New session - show last login attempt.
79
            // TODO: this currently does NOT surface to the frontend in any way.
80
            $lastLoginAttempt = LoginAttempt::get()->filter([
81
                        'MemberID' => $member->ID
82
            ])->sort('Created DESC')->First();
83
84
            if ($lastLoginAttempt) {
0 ignored issues
show
introduced by
$lastLoginAttempt is of type SilverStripe\ORM\DataObject, thus it always evaluated to true.
Loading history...
85
                $date = $lastLoginAttempt->Created;
0 ignored issues
show
Unused Code introduced by
The assignment to $date is dead and can be removed.
Loading history...
86
                $message = "Last login attempt to your account was on $lastLoginAttempt->Created "
87
                    . "from $lastLoginAttempt->IP";
88
                $message .= $lastLoginAttempt->Status == 'Failure' ? " and was successful." : "and has failed.";
89
            }
90
        }
91
92
        $session->set(
93
            'LoginAttemptNotifications.SessionLastVisited',
94
            DBDatetime::now()->Format(DBDatetime::ISO_DATETIME)
95
        );
96
97
        $this->owner->getResponse()->addHeader('X-LoginAttemptNotifications', $message);
98
    }
99
}
100