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