Completed
Push — master ( 0ad1f1...60adc9 )
by Blizzz
53:56 queued 32:56
created

Internal::regenerateId()   B

Complexity

Conditions 6
Paths 18

Size

Total Lines 33
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 17
nc 18
nop 2
dl 0
loc 33
rs 8.439
c 0
b 0
f 0
1
<?php
2
declare(strict_types=1);
3
/**
4
 * @copyright Copyright (c) 2016, ownCloud, Inc.
5
 *
6
 * @author Arthur Schiwon <[email protected]>
7
 * @author cetra3 <[email protected]>
8
 * @author Christoph Wurst <[email protected]>
9
 * @author Lukas Reschke <[email protected]>
10
 * @author Morris Jobke <[email protected]>
11
 * @author Robin Appelman <[email protected]>
12
 * @author Thomas Müller <[email protected]>
13
 * @author Victor Dubiniuk <[email protected]>
14
 *
15
 * @license AGPL-3.0
16
 *
17
 * This code is free software: you can redistribute it and/or modify
18
 * it under the terms of the GNU Affero General Public License, version 3,
19
 * as published by the Free Software Foundation.
20
 *
21
 * This program is distributed in the hope that it will be useful,
22
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24
 * GNU Affero General Public License for more details.
25
 *
26
 * You should have received a copy of the GNU Affero General Public License, version 3,
27
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
28
 *
29
 */
30
31
namespace OC\Session;
32
33
use OC\Authentication\Exceptions\InvalidTokenException;
34
use OC\Authentication\Token\IProvider;
35
use OC\SystemConfig;
36
use OCP\IConfig;
37
use OCP\Session\Exceptions\SessionNotAvailableException;
38
39
/**
40
 * Class Internal
41
 *
42
 * wrap php's internal session handling into the Session interface
43
 *
44
 * @package OC\Session
45
 */
46
class Internal extends Session {
47
	/**
48
	 * @param string $name
49
	 * @throws \Exception
50
	 */
51
	public function __construct(string $name) {
52
		set_error_handler([$this, 'trapError']);
53
		$this->invoke('session_name', [$name]);
54
		try {
55
			$this->invoke('session_start');
56
		} catch (\Exception $e) {
57
			setcookie($this->invoke('session_name'), null, -1, \OC::$WEBROOT ?: '/');
58
		}
59
		restore_error_handler();
60
		if (!isset($_SESSION)) {
61
			throw new \Exception('Failed to start session');
62
		}
63
	}
64
65
	/**
66
	 * @param string $key
67
	 * @param integer $value
68
	 */
69
	public function set(string $key, $value) {
70
		$this->validateSession();
71
		$_SESSION[$key] = $value;
72
	}
73
74
	/**
75
	 * @param string $key
76
	 * @return mixed
77
	 */
78
	public function get(string $key) {
79
		if (!$this->exists($key)) {
80
			return null;
81
		}
82
		return $_SESSION[$key];
83
	}
84
85
	/**
86
	 * @param string $key
87
	 * @return bool
88
	 */
89
	public function exists(string $key): bool {
90
		return isset($_SESSION[$key]);
91
	}
92
93
	/**
94
	 * @param string $key
95
	 */
96
	public function remove(string $key) {
97
		if (isset($_SESSION[$key])) {
98
			unset($_SESSION[$key]);
99
		}
100
	}
101
102
	public function clear() {
103
		$this->invoke('session_unset');
104
		$this->regenerateId();
105
		$this->invoke('session_start', [], true);
106
		$_SESSION = [];
107
	}
108
109
	public function close() {
110
		$this->invoke('session_write_close');
111
		parent::close();
112
	}
113
114
	/**
115
	 * Wrapper around session_regenerate_id
116
	 *
117
	 * @param bool $deleteOldSession Whether to delete the old associated session file or not.
118
	 * @param bool $updateToken Wheater to update the associated auth token
119
	 * @return void
120
	 */
121
	public function regenerateId(bool $deleteOldSession = true, bool $updateToken = false) {
122
		$oldId = null;
123
124
		if ($updateToken) {
125
			// Get the old id to update the token
126
			try {
127
				$oldId = $this->getId();
128
			} catch (SessionNotAvailableException $e) {
129
				// We can't update a token if there is no previous id
130
				$updateToken = false;
131
			}
132
		}
133
134
		try {
135
			@session_regenerate_id($deleteOldSession);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
136
		} catch (\Error $e) {
0 ignored issues
show
Bug introduced by
The class Error does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
137
			$this->trapError($e->getCode(), $e->getMessage());
138
		}
139
140
		if ($updateToken) {
141
			// Get the new id to update the token
142
			$newId = $this->getId();
143
144
			/** @var IProvider $tokenProvider */
145
			$tokenProvider = \OC::$server->query(IProvider::class);
146
147
			try {
148
				$tokenProvider->renewSessionToken($oldId, $newId);
149
			} catch (InvalidTokenException $e) {
150
				// Just ignore
151
			}
152
		}
153
	}
154
155
	/**
156
	 * Wrapper around session_id
157
	 *
158
	 * @return string
159
	 * @throws SessionNotAvailableException
160
	 * @since 9.1.0
161
	 */
162
	public function getId(): string {
163
		$id = $this->invoke('session_id', [], true);
164
		if ($id === '') {
165
			throw new SessionNotAvailableException();
166
		}
167
		return $id;
168
	}
169
170
	/**
171
	 * @throws \Exception
172
	 */
173
	public function reopen() {
174
		throw new \Exception('The session cannot be reopened - reopen() is ony to be used in unit testing.');
175
	}
176
177
	/**
178
	 * @param int $errorNumber
179
	 * @param string $errorString
180
	 * @throws \ErrorException
181
	 */
182
	public function trapError(int $errorNumber, string $errorString) {
183
		throw new \ErrorException($errorString);
184
	}
185
186
	/**
187
	 * @throws \Exception
188
	 */
189
	private function validateSession() {
190
		if ($this->sessionClosed) {
191
			throw new SessionNotAvailableException('Session has been closed - no further changes to the session are allowed');
192
		}
193
	}
194
195
	/**
196
	 * @param string $functionName the full session_* function name
197
	 * @param array $parameters
198
	 * @param bool $silence whether to suppress warnings
199
	 * @throws \ErrorException via trapError
200
	 * @return mixed
201
	 */
202
	private function invoke(string $functionName, array $parameters = [], bool $silence = false) {
203
		try {
204
			if($silence) {
205
				return @call_user_func_array($functionName, $parameters);
206
			} else {
207
				return call_user_func_array($functionName, $parameters);
208
			}
209
		} catch(\Error $e) {
0 ignored issues
show
Bug introduced by
The class Error does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
210
			$this->trapError($e->getCode(), $e->getMessage());
211
		}
212
	}
213
}
214