Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
100.00% |
66 / 66 |
|
100.00% |
13 / 13 |
CRAP | |
100.00% |
1 / 1 |
SessionInfo | |
100.00% |
66 / 66 |
|
100.00% |
13 / 13 |
33 | |
100.00% |
1 / 1 |
__construct | |
100.00% |
52 / 52 |
|
100.00% |
1 / 1 |
19 | |||
getProvider | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getId | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
isIdSafe | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
forceUse | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getPriority | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getUserInfo | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
wasPersisted | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getProviderMetadata | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
wasRemembered | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
forceHTTPS | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
__toString | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
3 | |||
compare | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 |
1 | <?php |
2 | /** |
3 | * MediaWiki session info |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | * @ingroup Session |
22 | */ |
23 | |
24 | namespace MediaWiki\Session; |
25 | |
26 | /** |
27 | * Value object returned by SessionProvider |
28 | * |
29 | * This holds the data necessary to construct a Session. |
30 | * May require services to be injected into the constructor. |
31 | * |
32 | * @newable |
33 | * |
34 | * @ingroup Session |
35 | * @since 1.27 |
36 | */ |
37 | class SessionInfo { |
38 | /** Minimum allowed priority */ |
39 | public const MIN_PRIORITY = 1; |
40 | |
41 | /** Maximum allowed priority */ |
42 | public const MAX_PRIORITY = 100; |
43 | |
44 | /** @var SessionProvider|null */ |
45 | private $provider; |
46 | |
47 | /** @var string */ |
48 | private $id; |
49 | |
50 | /** @var int */ |
51 | private $priority; |
52 | |
53 | /** @var UserInfo|null */ |
54 | private $userInfo = null; |
55 | |
56 | /** @var bool */ |
57 | private $persisted = false; |
58 | |
59 | /** @var bool */ |
60 | private $remembered = false; |
61 | |
62 | /** @var bool */ |
63 | private $forceHTTPS = false; |
64 | |
65 | /** @var bool */ |
66 | private $idIsSafe = false; |
67 | |
68 | /** @var bool */ |
69 | private $forceUse = false; |
70 | |
71 | /** @var array|null */ |
72 | private $providerMetadata = null; |
73 | |
74 | /** |
75 | * @stable to call |
76 | * |
77 | * @param int $priority Session priority |
78 | * @param array $data |
79 | * - provider: (SessionProvider|null) If not given, the provider will be |
80 | * determined from the saved session data. |
81 | * - id: (string|null) Session ID |
82 | * - userInfo: (UserInfo|null) User known from the request. If |
83 | * $provider->canChangeUser() is false, a verified user |
84 | * must be provided. |
85 | * - persisted: (bool) Whether this session was persisted |
86 | * - remembered: (bool) Whether the verified user was remembered. |
87 | * Defaults to true. |
88 | * - forceHTTPS: (bool) Whether to force HTTPS for this session. This is |
89 | * ignored if $wgForceHTTPS is true. |
90 | * - metadata: (array) Provider metadata, to be returned by |
91 | * Session::getProviderMetadata(). See SessionProvider::mergeMetadata() |
92 | * and SessionProvider::refreshSessionInfo(). |
93 | * - idIsSafe: (bool) Set true if the 'id' did not come from the user. |
94 | * Generally you'll use this from SessionProvider::newEmptySession(), |
95 | * and not from any other method. |
96 | * - forceUse: (bool) Set true if the 'id' is from |
97 | * SessionProvider::hashToSessionId() to delete conflicting session |
98 | * store data instead of discarding this SessionInfo. Ignored unless |
99 | * both 'provider' and 'id' are given. |
100 | * - copyFrom: (SessionInfo) SessionInfo to copy other data items from. |
101 | */ |
102 | public function __construct( $priority, array $data ) { |
103 | if ( $priority < self::MIN_PRIORITY || $priority > self::MAX_PRIORITY ) { |
104 | throw new \InvalidArgumentException( 'Invalid priority' ); |
105 | } |
106 | |
107 | if ( isset( $data['copyFrom'] ) ) { |
108 | $from = $data['copyFrom']; |
109 | if ( !$from instanceof SessionInfo ) { |
110 | throw new \InvalidArgumentException( 'Invalid copyFrom' ); |
111 | } |
112 | $data += [ |
113 | 'provider' => $from->provider, |
114 | 'id' => $from->id, |
115 | 'userInfo' => $from->userInfo, |
116 | 'persisted' => $from->persisted, |
117 | 'remembered' => $from->remembered, |
118 | 'forceHTTPS' => $from->forceHTTPS, |
119 | 'metadata' => $from->providerMetadata, |
120 | 'idIsSafe' => $from->idIsSafe, |
121 | 'forceUse' => $from->forceUse, |
122 | // @codeCoverageIgnoreStart |
123 | ]; |
124 | // @codeCoverageIgnoreEnd |
125 | } else { |
126 | $data += [ |
127 | 'provider' => null, |
128 | 'id' => null, |
129 | 'userInfo' => null, |
130 | 'persisted' => false, |
131 | 'remembered' => true, |
132 | 'forceHTTPS' => false, |
133 | 'metadata' => null, |
134 | 'idIsSafe' => false, |
135 | 'forceUse' => false, |
136 | // @codeCoverageIgnoreStart |
137 | ]; |
138 | // @codeCoverageIgnoreEnd |
139 | } |
140 | |
141 | if ( $data['id'] !== null && !SessionManager::validateSessionId( $data['id'] ) ) { |
142 | throw new \InvalidArgumentException( 'Invalid session ID' ); |
143 | } |
144 | |
145 | if ( $data['userInfo'] !== null && !$data['userInfo'] instanceof UserInfo ) { |
146 | throw new \InvalidArgumentException( 'Invalid userInfo' ); |
147 | } |
148 | |
149 | if ( !$data['provider'] && $data['id'] === null ) { |
150 | throw new \InvalidArgumentException( |
151 | 'Must supply an ID when no provider is given' |
152 | ); |
153 | } |
154 | |
155 | if ( $data['metadata'] !== null && !is_array( $data['metadata'] ) ) { |
156 | throw new \InvalidArgumentException( 'Invalid metadata' ); |
157 | } |
158 | |
159 | $this->provider = $data['provider']; |
160 | if ( $data['id'] !== null ) { |
161 | $this->id = $data['id']; |
162 | $this->idIsSafe = $data['idIsSafe']; |
163 | $this->forceUse = $data['forceUse'] && $this->provider; |
164 | } else { |
165 | $this->id = $this->provider->getManager()->generateSessionId(); |
166 | $this->idIsSafe = true; |
167 | $this->forceUse = false; |
168 | } |
169 | $this->priority = (int)$priority; |
170 | $this->userInfo = $data['userInfo']; |
171 | $this->persisted = (bool)$data['persisted']; |
172 | if ( $data['provider'] !== null ) { |
173 | if ( $this->userInfo !== null && !$this->userInfo->isAnon() && $this->userInfo->isVerified() ) { |
174 | $this->remembered = (bool)$data['remembered']; |
175 | } |
176 | $this->providerMetadata = $data['metadata']; |
177 | } |
178 | $this->forceHTTPS = (bool)$data['forceHTTPS']; |
179 | } |
180 | |
181 | /** |
182 | * Return the provider |
183 | * @return SessionProvider|null |
184 | */ |
185 | final public function getProvider() { |
186 | return $this->provider; |
187 | } |
188 | |
189 | /** |
190 | * Return the session ID |
191 | * @return string |
192 | */ |
193 | final public function getId() { |
194 | return $this->id; |
195 | } |
196 | |
197 | /** |
198 | * Indicate whether the ID is "safe" |
199 | * |
200 | * The ID is safe in the following cases: |
201 | * - The ID was randomly generated by the constructor. |
202 | * - The ID was found in the backend data store. |
203 | * - $this->getProvider()->persistsSessionId() is false. |
204 | * - The constructor was explicitly told it's safe using the 'idIsSafe' |
205 | * parameter. |
206 | * |
207 | * @return bool |
208 | */ |
209 | final public function isIdSafe() { |
210 | return $this->idIsSafe; |
211 | } |
212 | |
213 | /** |
214 | * Force use of this SessionInfo if validation fails |
215 | * |
216 | * The normal behavior is to discard the SessionInfo if validation against |
217 | * the data stored in the session store fails. If this returns true, |
218 | * SessionManager will instead delete the session store data so this |
219 | * SessionInfo may still be used. This is important for providers which use |
220 | * deterministic IDs and so cannot just generate a random new one. |
221 | * |
222 | * @return bool |
223 | */ |
224 | final public function forceUse() { |
225 | return $this->forceUse; |
226 | } |
227 | |
228 | /** |
229 | * Return the priority |
230 | * @return int |
231 | */ |
232 | final public function getPriority() { |
233 | return $this->priority; |
234 | } |
235 | |
236 | /** |
237 | * Return the user |
238 | * @return UserInfo|null |
239 | */ |
240 | final public function getUserInfo() { |
241 | return $this->userInfo; |
242 | } |
243 | |
244 | /** |
245 | * Return whether the session is persisted |
246 | * @return bool |
247 | */ |
248 | final public function wasPersisted() { |
249 | return $this->persisted; |
250 | } |
251 | |
252 | /** |
253 | * Return provider metadata |
254 | * @return array|null |
255 | */ |
256 | final public function getProviderMetadata() { |
257 | return $this->providerMetadata; |
258 | } |
259 | |
260 | /** |
261 | * Return whether the user was remembered |
262 | * |
263 | * For providers that can persist the user separately from the session, |
264 | * the human using it may not actually *want* that to be done. For example, |
265 | * a cookie-based provider can set cookies that are longer-lived than the |
266 | * backend session data, but on a public terminal the human likely doesn't |
267 | * want those cookies set. |
268 | * |
269 | * This is false unless a non-anonymous verified user was passed to |
270 | * the SessionInfo constructor by the provider, and the provider didn't |
271 | * pass false for the 'remembered' data item. |
272 | * |
273 | * @return bool |
274 | */ |
275 | final public function wasRemembered() { |
276 | return $this->remembered; |
277 | } |
278 | |
279 | /** |
280 | * Whether this session should only be used over HTTPS. This should be |
281 | * ignored if $wgForceHTTPS is true. |
282 | * |
283 | * @return bool |
284 | */ |
285 | final public function forceHTTPS() { |
286 | return $this->forceHTTPS; |
287 | } |
288 | |
289 | public function __toString() { |
290 | return '[' . $this->getPriority() . ']' . |
291 | ( $this->getProvider() ?: 'null' ) . |
292 | ( $this->userInfo ?: '<null>' ) . $this->getId(); |
293 | } |
294 | |
295 | /** |
296 | * Compare two SessionInfo objects by priority |
297 | * @param SessionInfo $a |
298 | * @param SessionInfo $b |
299 | * @return int Negative if $a < $b, positive if $a > $b, zero if equal |
300 | */ |
301 | public static function compare( $a, $b ) { |
302 | return $a->getPriority() <=> $b->getPriority(); |
303 | } |
304 | |
305 | } |