Passed
Branch master (7aebe4)
by Peter
05:51 queued 03:30
created

SessionTimeout::afterRequest()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 3
Ratio 50 %

Code Coverage

Tests 5
CRAP Score 3

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 3
loc 6
ccs 5
cts 5
cp 1
rs 9.4285
cc 3
eloc 3
nc 2
nop 1
crap 3
1
<?php
2
3
namespace PeterColes\LiveOrLetDie\Middleware;
4
5
use Closure;
6
use Illuminate\Config\Repository as Config;
7
use Illuminate\Auth\AuthManager as Auth;
8
use Illuminate\Http\Request;
9
use Illuminate\Session\Store as Session;
10
11
class SessionTimeout
12
{
13
    protected $session;
14
15
    protected $timeout;
16
17
    protected $login;
18
19
    protected $logout;
20
21
    protected $auth;
22
23 25
    public function __construct(Session $session, Config $config, Auth $auth)
24
    {
25 25
        $this->session = $session;
26
27 25
        $this->timeout = $config->get('session.lifetime') * 60;
28
29 25
        $this->login = $config->get('liveorletdie.login', 'login');
30 25
        $this->logout = $config->get('liveorletdie.logout', 'logout');
31
32 25
        $this->auth = $auth;
33 25
    }
34
35
    /**
36
     * Handle an incoming request.
37
     *
38
     * @param  \Illuminate\Http\Request  $request
39
     * @param  \Closure  $next
40
     * @return mixed
41
     */
42 25
    public function handle(Request $request, Closure $next)
43
    {
44
        // don't interfere with normal logout requests
45 25
        if ($request->is($this->logout)) {
46 3
            $this->session->forget('last_activity');
47 3
            return $next($request);
48
        }
49
50
        // check if we should the authenticated session to end
51
        // and if yes, terminate it
52 22
        if ($this->endSession($request)) {
53 15
            return $this->terminateAndRespond($request, $next);
54
        }
55
56
        // if we just want the time remaining claculate and return that
57
        // this will stop any further processing, including preventing unintended extension of the underlying session
58 7
        if ($request->is('session/remaining')) {
59 1
            return response($this->timeout - (time() - $this->session->get('last_activity')));
60
        }
61
62
        // for all other requests, including pings to extend the session, we update our timer and continue normally
63 6
        $this->updateActivityCounter($request);
64
65 6
        $response = $next($request);
66
67 6
        $this->afterRequest($request);
68
69 6
        return $response;
70
    }
71
72
    /**
73
     * After the request has been processed, check if it was for login
74
     * and if so and successful initialise the last_activity timer
75
     *
76
     * @param  \Illuminate\Http\Request  $request
77
     * @return void
78
     */
79 6
    protected function afterRequest(Request $request)
80
    {
81 6 View Code Duplication
        if ($request->is($this->login) && !$this->auth->guest()) {
82 1
            $this->session->put('last_activity', time());
83 1
        }
84 6
    }
85
86
    /**
87
     * Determine whether the session should be ended due to timeout or frontend request
88
     * We whitelist the login page from this assessment
89
     *
90
     * @param  \Illuminate\Http\Request $request
91
     * @return boolean 
92
     */
93 22
    protected function endSession(Request $request)
94
    {
95 22
        return !$request->is($this->login) && ($this->timedOut() || $request->is('session/end'));
96
    }
97
98
    /**
99
     * Determine whether timeout has occurred or been forced by other activity on the site
100
     * If there's no data to do the timeout check, then we assume the session has been otherwise ended
101
     *
102
     * @return boolean 
103
     */
104 18
    protected function timedOut()
105
    {
106 18
        return !$this->session->has('last_activity') || (time() - $this->session->get('last_activity')) > $this->timeout || $this->auth->guest();
107
    }
108
109
    /**
110
     * Logout and clear our session var - one or both of which may be redundant, but not harmful
111
     * Then, for our package routes compose a suitable response, anf for other routes continue processing as normal
112
     *
113
     * @param  \Illuminate\Http\Request  $request
114
     * @param  Closure  $next
115
     * @return mixed
116
     */
117 15
    protected function terminateAndRespond(Request $request, Closure $next)
118
    {
119 15
        $this->auth->logout();
120 15
        $this->session->forget('last_activity');
121
122 15
        if ($request->is('session/end')) {
123 4
            return response('session ended', 200);
124
        }
125
126 11
        if ($request->is('session/remaining')) {
127 3
            return response(0, 200);
128
        }
129
130 8
        if ($request->is('session/ping')) {
131 3
            return response('trying to keep alive a session that has already expired', 400);
132
        }
133
134 5
        return $next($request);
135
    }
136
137
    /**
138
     * Update the counter 
139
     * Normally we wouldn't get here unless we are logged in
140
     * But we whitelisted the login page so need to handle that
141
     *
142
     * @param  \Illuminate\Http\Request  $request
143
     * @return void
144
     */
145 6
    protected function updateActivityCounter(Request $request)
146
    {
147 6 View Code Duplication
        if ($request->is($this->login)) {
148 4
            $this->session->forget('last_activity');
149 4
        } else {
150 2
            $this->session->put('last_activity', time());
151
        }
152 6
    }
153
}
154