Test Failed
Push — master ( 647c72...cd42b5 )
by
unknown
10:25
created

WebAppSession::isDestroySessionRequest()   B

Complexity

Conditions 7
Paths 3

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 7
nc 3
nop 1
dl 0
loc 15
rs 8.8333
c 0
b 0
f 0
1
<?php
2
3
//Includes. Will probably already be included.
4
require_once(BASE_PATH . 'config.php');
5
require_once(BASE_PATH . 'defaults.php');
6
require_once(BASE_PATH . 'server/includes/util.php');
7
require_once(BASE_PATH . 'server/includes/exceptions/class.JSONException.php');
8
9
/**
10
 * A class with helper functions for the PHP session
11
 * @singleton
12
 */
13
class WebAppSession
14
{
15
	// Holds the instance of this class
16
	// Use public static method getInstance() to retrieve its value
17
	private static $instance = null;
18
19
	// Set to true when the the session has timed out
20
	// Use public method hasTimedOut() to retrieve its value
21
	private $timeout = false;
22
23
	/**
24
	 * Constructor
25
	 */
26
	private function __construct(){
27
		$secure = useSecureCookies();
28
		if (defined('COOKIE_NAME')) {
29
			//Create a named session (otherwise use the PHP default, normally PHPSESSID)
30
			if ($secure){
31
				//Create a named session and set secure cookies params.
32
				session_name('__Secure-' . COOKIE_NAME);
0 ignored issues
show
Bug introduced by
The constant COOKIE_NAME was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
33
			} else {
34
				session_name(COOKIE_NAME);
35
			}
36
		}
37
		$lifetime = ini_get('session.cookie_lifetime');
38
		$path = ini_get('session.cookie_path');
39
		$domain = ini_get('session.cookie_domain');
40
		session_set_cookie_params($lifetime, $path, $domain, $secure, true);
0 ignored issues
show
Bug introduced by
$lifetime of type string is incompatible with the type array expected by parameter $options of session_set_cookie_params(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

40
		session_set_cookie_params(/** @scrutinizer ignore-type */ $lifetime, $path, $domain, $secure, true);
Loading history...
41
42
		// Start the session so we can use it for timeout checking
43
		$this->start();
44
45
		if ( basename($_SERVER['PHP_SELF']) != 'grommunio.php' ){
46
			//We will only check for timeout in the grommunio.php page
47
			$this->setStartTime();
48
		} else {
49
			$this->checkForTimeout();
50
		}
51
	}
52
53
	/**
54
	 * returns the instance of this class. Creates one if it doesn't exist yet.
55
	 * To force this class to be used as singleton, the constructor is private
56
	 * and the single instance can be created/retrieved with this static method
57
	 * e.g.: $session = WebAppSession::createInstance()
58
	 *
59
	 * @return WebAppSession the only available instance of this class
60
	 */
61
	public static function getInstance()
62
	{
63
		if ( !isset(WebAppSession::$instance) ){
64
			WebAppSession::$instance = new WebAppSession();
65
		}
66
		return WebAppSession::$instance;
67
	}
68
69
	/**
70
	 * The method getInstance() was first called createInstance(), so
71
	 * for backward compatibility we also define createInstance as an alias
72
	 */
73
	public static function createInstance()
74
	{
75
		return WebAppSession::getInstance();
76
	}
77
78
	/**
79
	 * Starts the session
80
	 */
81
	public function start()
82
	{
83
		session_start();
84
	}
85
86
	/**
87
	 * Closes the session
88
	 */
89
	public function close()
90
	 {
91
	 	session_write_close();
92
	 }
93
94
	/**
95
	 * Destroy the session
96
	 */
97
	public function destroy()
98
	{
99
		// Make sure the session is open
100
		if ( session_status() !== PHP_SESSION_ACTIVE ){
101
			session_start();
102
		}
103
104
		// Destroy the session cookie
105
		if (isset($_COOKIE[session_name()])) {
106
			setcookie(session_name(), '', time()-42000, '/');
107
		}
108
109
		// Destroy the session
110
		$_SESSION = array();
111
		session_destroy();
112
	}
113
114
	/**
115
	 * Sets the start time in the session to current timestamp.
116
	 * This is used to logout the user when CLIENT_TIMEOUT has
117
	 * been set in config.php
118
	 */
119
	public function setStartTime()
120
	{
121
		$_SESSION['starttime'] = time();
122
	}
123
124
	/**
125
	 * gets the start time from the session. This is used to logout the user
126
	 * when CLIENT_TIMEOUT has been set in config.php
127
	 *
128
	 * @return integer|false The starttime (timestamp) when set, false otherwise
129
	 */
130
	public function getStartTime()
131
	{
132
		if ( isset($_SESSION['starttime']) ){
133
			return $_SESSION['starttime'];
134
		} else {
135
			return false;
136
		}
137
	}
138
139
	/**
140
	 * Checks if the session should timeout and destroys the session if it should.
141
	 */
142
	private function checkForTimeout()
143
	{
144
		if ( !defined('CLIENT_TIMEOUT') || !CLIENT_TIMEOUT ){
0 ignored issues
show
Bug introduced by
The constant CLIENT_TIMEOUT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
145
			//Timeout was not set in configuration, so do nothing
146
			return;
147
		}
148
149
		if (array_key_exists('HTTP_CONTENT_TYPE', $_SERVER) && strpos($_SERVER['HTTP_CONTENT_TYPE'], 'application/json') === false) {
150
			return;
151
		}
152
153
		$starttime = $this->getStartTime();
154
		// let's add 5 seconds to the CLIENT_TIMEOUT to handle possible latency
155
		if ( $starttime && (time()-$starttime > CLIENT_TIMEOUT+5) ){
0 ignored issues
show
Bug Best Practice introduced by
The expression $starttime of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
156
			$this->destroy();
157
			$this->timeout = true;
158
		} else {
159
			try{
160
				// decode JSON data
161
				$requestJsonString = readData();
162
				$requestJson = json_decode_data($requestJsonString, true);
163
			}catch(JSONException $e){
164
				// Invalid json sent with the request
165
				// Log the error and do nothing is best option
166
				dump($e->getMessage());
167
				return;
168
			}
169
170
			$isReminderlistRequest = $this->isReminderListRequest($requestJson);
171
			$isDestroySessionRequest = $this->isDestroySessionRequest($requestJson);
172
173
			if ( !$isReminderlistRequest && !$isDestroySessionRequest){
174
				//Set a new session start time
175
				$this->setStartTime();
176
			} elseif ( $isDestroySessionRequest ){
177
				// sessiondestroy is sent because of timeout at client side
178
				$this->timeout = true;
179
				$this->destroy();
180
			}
181
		}
182
	}
183
184
	/**
185
	 * Checks if the current request is a destroysession request
186
	 *
187
	 * @param array $requestJson The JSON that was sent as the current request
188
	 * @return boolean
189
	 */
190
	private function isDestroySessionRequest($requestJson)
191
	{
192
		$isDestroySession = false;
193
194
		if ( isset($requestJson) && isset($requestJson['zarafa']) ){
195
			if ( isset($requestJson['zarafa']['hierarchymodule']) ){
196
				foreach ( $requestJson['zarafa']['hierarchymodule'] as $requestId=>$action ){
197
					if ( isset($action) && isset($action['destroysession']) ){
198
						$isDestroySession = true;
199
					}
200
				}
201
			}
202
		}
203
204
		return $isDestroySession;
205
	}
206
207
	/**
208
	 * Checks if the current request is a reminderlist request
209
	 *
210
	 * @param array $requestJson The JSON that was sent as the current request
211
	 * @return boolean
212
	 */
213
	private function isReminderListRequest($requestJson)
214
	{
215
		return isset($requestJson) && isset($requestJson['zarafa']) && isset($requestJson['zarafa']['reminderlistmodule']);
216
	}
217
218
	/**
219
	 * Returns true if the current session has timed out, false otherwise
220
	 *
221
	 * @return boolean
222
	 */
223
	public function hasTimedOut()
224
	{
225
		return $this->timeout;
226
	}
227
}
228