]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - includes/session/SessionInfo.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / includes / session / SessionInfo.php
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  *
31  * @ingroup Session
32  * @since 1.27
33  */
34 class SessionInfo {
35         /** Minimum allowed priority */
36         const MIN_PRIORITY = 1;
37
38         /** Maximum allowed priority */
39         const MAX_PRIORITY = 100;
40
41         /** @var SessionProvider|null */
42         private $provider;
43
44         /** @var string */
45         private $id;
46
47         /** @var int */
48         private $priority;
49
50         /** @var UserInfo|null */
51         private $userInfo = null;
52
53         private $persisted = false;
54         private $remembered = false;
55         private $forceHTTPS = false;
56         private $idIsSafe = false;
57         private $forceUse = false;
58
59         /** @var array|null */
60         private $providerMetadata = null;
61
62         /**
63          * @param int $priority Session priority
64          * @param array $data
65          *  - provider: (SessionProvider|null) If not given, the provider will be
66          *    determined from the saved session data.
67          *  - id: (string|null) Session ID
68          *  - userInfo: (UserInfo|null) User known from the request. If
69          *    $provider->canChangeUser() is false, a verified user
70          *    must be provided.
71          *  - persisted: (bool) Whether this session was persisted
72          *  - remembered: (bool) Whether the verified user was remembered.
73          *    Defaults to true.
74          *  - forceHTTPS: (bool) Whether to force HTTPS for this session
75          *  - metadata: (array) Provider metadata, to be returned by
76          *    Session::getProviderMetadata(). See SessionProvider::mergeMetadata()
77          *    and SessionProvider::refreshSessionInfo().
78          *  - idIsSafe: (bool) Set true if the 'id' did not come from the user.
79          *    Generally you'll use this from SessionProvider::newEmptySession(),
80          *    and not from any other method.
81          *  - forceUse: (bool) Set true if the 'id' is from
82          *    SessionProvider::hashToSessionId() to delete conflicting session
83          *    store data instead of discarding this SessionInfo. Ignored unless
84          *    both 'provider' and 'id' are given.
85          *  - copyFrom: (SessionInfo) SessionInfo to copy other data items from.
86          */
87         public function __construct( $priority, array $data ) {
88                 if ( $priority < self::MIN_PRIORITY || $priority > self::MAX_PRIORITY ) {
89                         throw new \InvalidArgumentException( 'Invalid priority' );
90                 }
91
92                 if ( isset( $data['copyFrom'] ) ) {
93                         $from = $data['copyFrom'];
94                         if ( !$from instanceof SessionInfo ) {
95                                 throw new \InvalidArgumentException( 'Invalid copyFrom' );
96                         }
97                         $data += [
98                                 'provider' => $from->provider,
99                                 'id' => $from->id,
100                                 'userInfo' => $from->userInfo,
101                                 'persisted' => $from->persisted,
102                                 'remembered' => $from->remembered,
103                                 'forceHTTPS' => $from->forceHTTPS,
104                                 'metadata' => $from->providerMetadata,
105                                 'idIsSafe' => $from->idIsSafe,
106                                 'forceUse' => $from->forceUse,
107                                 // @codeCoverageIgnoreStart
108                         ];
109                         // @codeCoverageIgnoreEnd
110                 } else {
111                         $data += [
112                                 'provider' => null,
113                                 'id' => null,
114                                 'userInfo' => null,
115                                 'persisted' => false,
116                                 'remembered' => true,
117                                 'forceHTTPS' => false,
118                                 'metadata' => null,
119                                 'idIsSafe' => false,
120                                 'forceUse' => false,
121                                 // @codeCoverageIgnoreStart
122                         ];
123                         // @codeCoverageIgnoreEnd
124                 }
125
126                 if ( $data['id'] !== null && !SessionManager::validateSessionId( $data['id'] ) ) {
127                         throw new \InvalidArgumentException( 'Invalid session ID' );
128                 }
129
130                 if ( $data['userInfo'] !== null && !$data['userInfo'] instanceof UserInfo ) {
131                         throw new \InvalidArgumentException( 'Invalid userInfo' );
132                 }
133
134                 if ( !$data['provider'] && $data['id'] === null ) {
135                         throw new \InvalidArgumentException(
136                                 'Must supply an ID when no provider is given'
137                         );
138                 }
139
140                 if ( $data['metadata'] !== null && !is_array( $data['metadata'] ) ) {
141                         throw new \InvalidArgumentException( 'Invalid metadata' );
142                 }
143
144                 $this->provider = $data['provider'];
145                 if ( $data['id'] !== null ) {
146                         $this->id = $data['id'];
147                         $this->idIsSafe = $data['idIsSafe'];
148                         $this->forceUse = $data['forceUse'] && $this->provider;
149                 } else {
150                         $this->id = $this->provider->getManager()->generateSessionId();
151                         $this->idIsSafe = true;
152                         $this->forceUse = false;
153                 }
154                 $this->priority = (int)$priority;
155                 $this->userInfo = $data['userInfo'];
156                 $this->persisted = (bool)$data['persisted'];
157                 if ( $data['provider'] !== null ) {
158                         if ( $this->userInfo !== null && !$this->userInfo->isAnon() && $this->userInfo->isVerified() ) {
159                                 $this->remembered = (bool)$data['remembered'];
160                         }
161                         $this->providerMetadata = $data['metadata'];
162                 }
163                 $this->forceHTTPS = (bool)$data['forceHTTPS'];
164         }
165
166         /**
167          * Return the provider
168          * @return SessionProvider|null
169          */
170         final public function getProvider() {
171                 return $this->provider;
172         }
173
174         /**
175          * Return the session ID
176          * @return string
177          */
178         final public function getId() {
179                 return $this->id;
180         }
181
182         /**
183          * Indicate whether the ID is "safe"
184          *
185          * The ID is safe in the following cases:
186          * - The ID was randomly generated by the constructor.
187          * - The ID was found in the backend data store.
188          * - $this->getProvider()->persistsSessionId() is false.
189          * - The constructor was explicitly told it's safe using the 'idIsSafe'
190          *   parameter.
191          *
192          * @return bool
193          */
194         final public function isIdSafe() {
195                 return $this->idIsSafe;
196         }
197
198         /**
199          * Force use of this SessionInfo if validation fails
200          *
201          * The normal behavior is to discard the SessionInfo if validation against
202          * the data stored in the session store fails. If this returns true,
203          * SessionManager will instead delete the session store data so this
204          * SessionInfo may still be used. This is important for providers which use
205          * deterministic IDs and so cannot just generate a random new one.
206          *
207          * @return bool
208          */
209         final public function forceUse() {
210                 return $this->forceUse;
211         }
212
213         /**
214          * Return the priority
215          * @return int
216          */
217         final public function getPriority() {
218                 return $this->priority;
219         }
220
221         /**
222          * Return the user
223          * @return UserInfo|null
224          */
225         final public function getUserInfo() {
226                 return $this->userInfo;
227         }
228
229         /**
230          * Return whether the session is persisted
231          * @return bool
232          */
233         final public function wasPersisted() {
234                 return $this->persisted;
235         }
236
237         /**
238          * Return provider metadata
239          * @return array|null
240          */
241         final public function getProviderMetadata() {
242                 return $this->providerMetadata;
243         }
244
245         /**
246          * Return whether the user was remembered
247          *
248          * For providers that can persist the user separately from the session,
249          * the human using it may not actually *want* that to be done. For example,
250          * a cookie-based provider can set cookies that are longer-lived than the
251          * backend session data, but on a public terminal the human likely doesn't
252          * want those cookies set.
253          *
254          * This is false unless a non-anonymous verified user was passed to
255          * the SessionInfo constructor by the provider, and the provider didn't
256          * pass false for the 'remembered' data item.
257          *
258          * @return bool
259          */
260         final public function wasRemembered() {
261                 return $this->remembered;
262         }
263
264         /**
265          * Whether this session should only be used over HTTPS
266          * @return bool
267          */
268         final public function forceHTTPS() {
269                 return $this->forceHTTPS;
270         }
271
272         public function __toString() {
273                 return '[' . $this->getPriority() . ']' .
274                         ( $this->getProvider() ?: 'null' ) .
275                         ( $this->userInfo ?: '<null>' ) . $this->getId();
276         }
277
278         /**
279          * Compare two SessionInfo objects by priority
280          * @param SessionInfo $a
281          * @param SessionInfo $b
282          * @return int Negative if $a < $b, positive if $a > $b, zero if equal
283          */
284         public static function compare( $a, $b ) {
285                 return $a->getPriority() - $b->getPriority();
286         }
287
288 }