Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
13 / 13
CRAP
100.00% covered (success)
100.00%
1 / 1
UserInfo
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
13 / 13
25
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 newAnonymous
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 newFromId
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 newFromName
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 newFromUser
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isAnon
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 isVerified
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getId
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getToken
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
3
 getUser
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 verified
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 __toString
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2/**
3 * MediaWiki session user 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
24namespace MediaWiki\Session;
25
26use InvalidArgumentException;
27use MediaWiki\MediaWikiServices;
28use MediaWiki\User\User;
29use MediaWiki\User\UserRigorOptions;
30use Stringable;
31
32/**
33 * Object holding data about a session's user
34 *
35 * In general, this class exists for two purposes:
36 * - User doesn't distinguish between "anonymous user" and "non-anonymous user
37 *   that doesn't exist locally", while we do need to.
38 * - We also need the "verified" property described below; tracking it via
39 *   another data item to SessionInfo's constructor makes things much more
40 *   confusing.
41 *
42 * A UserInfo may be "verified". This indicates that the creator knows that the
43 * request really comes from that user, whether that's by validating OAuth
44 * credentials, SSL client certificates, or by having both the user ID and
45 * token available from cookies.
46 *
47 * An "unverified" UserInfo should be used when it's not possible to
48 * authenticate the user, e.g. the user ID cookie is set but the user Token
49 * cookie isn't. If the Token is available but doesn't match, don't return a
50 * UserInfo at all.
51 *
52 * @ingroup Session
53 * @since 1.27
54 */
55final class UserInfo implements Stringable {
56    /** @var bool */
57    private $verified = false;
58
59    /** @var User|null */
60    private $user = null;
61
62    private function __construct( ?User $user, $verified ) {
63        $userNameUtils = MediaWikiServices::getInstance()->getUserNameUtils();
64        if ( $user && $user->isAnon() && !$userNameUtils->isUsable( $user->getName() ) ) {
65            $this->verified = true;
66            $this->user = null;
67        } else {
68            $this->verified = $verified;
69            $this->user = $user;
70        }
71    }
72
73    /**
74     * Create an instance for an anonymous (i.e. not logged in) user
75     *
76     * Logged-out users are always "verified".
77     *
78     * @return UserInfo
79     */
80    public static function newAnonymous() {
81        return new self( null, true );
82    }
83
84    /**
85     * Create an instance for a logged-in user by ID
86     * @param int $id User ID
87     * @param bool $verified True if the user is verified
88     * @return UserInfo
89     */
90    public static function newFromId( $id, $verified = false ) {
91        $user = MediaWikiServices::getInstance()->getUserFactory()->newFromId( (int)$id );
92
93        // Ensure the ID actually exists
94        $user->load();
95        if ( $user->isAnon() ) {
96            throw new InvalidArgumentException( 'Invalid ID' );
97        }
98
99        return new self( $user, $verified );
100    }
101
102    /**
103     * Create an instance for a logged-in user by name
104     * @param string $name User name (need not exist locally)
105     * @param bool $verified True if the user is verified
106     * @return UserInfo
107     */
108    public static function newFromName( $name, $verified = false ) {
109        $user = MediaWikiServices::getInstance()->getUserFactory()->newFromName(
110            (string)$name,
111            UserRigorOptions::RIGOR_USABLE
112        );
113        if ( !$user ) {
114            throw new InvalidArgumentException( 'Invalid user name' );
115        }
116        return new self( $user, $verified );
117    }
118
119    /**
120     * Create an instance from an existing User object
121     * @param User $user (need not exist locally)
122     * @param bool $verified True if the user is verified
123     * @return UserInfo
124     */
125    public static function newFromUser( User $user, $verified = false ) {
126        return new self( $user, $verified );
127    }
128
129    /**
130     * Return whether this is an anonymous user
131     * @return bool
132     */
133    public function isAnon() {
134        return $this->user === null;
135    }
136
137    /**
138     * Return whether this represents a verified user
139     * @return bool
140     */
141    public function isVerified() {
142        return $this->verified;
143    }
144
145    /**
146     * Return the user ID
147     * @note Do not use this to test for anonymous users!
148     * @return int
149     */
150    public function getId() {
151        return $this->user === null ? 0 : $this->user->getId();
152    }
153
154    /**
155     * Return the user name
156     * @return string|null
157     */
158    public function getName() {
159        return $this->user === null ? null : $this->user->getName();
160    }
161
162    /**
163     * Return the user token
164     * @return string
165     */
166    public function getToken() {
167        return $this->user === null || $this->user->getId() === 0 ? '' : $this->user->getToken( false );
168    }
169
170    /**
171     * Return a User object
172     * @return User
173     */
174    public function getUser() {
175        return $this->user ?? MediaWikiServices::getInstance()->getUserFactory()->newAnonymous();
176    }
177
178    /**
179     * Return a verified version of this object
180     * @return UserInfo
181     */
182    public function verified() {
183        return $this->verified ? $this : new self( $this->user, true );
184    }
185
186    public function __toString() {
187        if ( $this->user === null ) {
188            return '<anon>';
189        }
190        return '<' .
191            ( $this->verified ? '+' : '-' ) . ':' .
192            $this->getId() . ':' . $this->getName() .
193            '>';
194    }
195
196}