Issues (4122)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

includes/user/UserRightsProxy.php (6 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Representation of an user on a other locally-hosted wiki.
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
 */
22
23
/**
24
 * Cut-down copy of User interface for local-interwiki-database
25
 * user rights manipulation.
26
 */
27
class UserRightsProxy {
0 ignored issues
show
Since you have declared the constructor as private, maybe you should also declare the class as final.
Loading history...
28
29
	/**
30
	 * Constructor.
31
	 *
32
	 * @see newFromId()
33
	 * @see newFromName()
34
	 * @param IDatabase $db Db connection
35
	 * @param string $database Database name
36
	 * @param string $name User name
37
	 * @param int $id User ID
38
	 */
39
	private function __construct( $db, $database, $name, $id ) {
40
		$this->db = $db;
0 ignored issues
show
The property db does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
41
		$this->database = $database;
0 ignored issues
show
The property database does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
42
		$this->name = $name;
0 ignored issues
show
The property name does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
43
		$this->id = intval( $id );
0 ignored issues
show
The property id does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
44
		$this->newOptions = [];
0 ignored issues
show
The property newOptions does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
45
	}
46
47
	/**
48
	 * Accessor for $this->database
49
	 *
50
	 * @return string Database name
51
	 */
52
	public function getDBName() {
53
		return $this->database;
54
	}
55
56
	/**
57
	 * Confirm the selected database name is a valid local interwiki database name.
58
	 *
59
	 * @param string $database Database name
60
	 * @return bool
61
	 */
62
	public static function validDatabase( $database ) {
63
		global $wgLocalDatabases;
64
		return in_array( $database, $wgLocalDatabases );
65
	}
66
67
	/**
68
	 * Same as User::whoIs()
69
	 *
70
	 * @param string $database Database name
71
	 * @param int $id User ID
72
	 * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
73
	 * @return string User name or false if the user doesn't exist
74
	 */
75
	public static function whoIs( $database, $id, $ignoreInvalidDB = false ) {
76
		$user = self::newFromId( $database, $id, $ignoreInvalidDB );
77
		if ( $user ) {
78
			return $user->name;
79
		} else {
80
			return false;
81
		}
82
	}
83
84
	/**
85
	 * Factory function; get a remote user entry by ID number.
86
	 *
87
	 * @param string $database Database name
88
	 * @param int $id User ID
89
	 * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
90
	 * @return UserRightsProxy|null If doesn't exist
91
	 */
92
	public static function newFromId( $database, $id, $ignoreInvalidDB = false ) {
93
		return self::newFromLookup( $database, 'user_id', intval( $id ), $ignoreInvalidDB );
94
	}
95
96
	/**
97
	 * Factory function; get a remote user entry by name.
98
	 *
99
	 * @param string $database Database name
100
	 * @param string $name User name
101
	 * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
102
	 * @return UserRightsProxy|null If doesn't exist
103
	 */
104
	public static function newFromName( $database, $name, $ignoreInvalidDB = false ) {
105
		return self::newFromLookup( $database, 'user_name', $name, $ignoreInvalidDB );
106
	}
107
108
	/**
109
	 * @param string $database
110
	 * @param string $field
111
	 * @param string $value
112
	 * @param bool $ignoreInvalidDB
113
	 * @return null|UserRightsProxy
114
	 */
115
	private static function newFromLookup( $database, $field, $value, $ignoreInvalidDB = false ) {
116
		global $wgSharedDB, $wgSharedTables;
117
		// If the user table is shared, perform the user query on it,
118
		// but don't pass it to the UserRightsProxy,
119
		// as user rights are normally not shared.
120
		if ( $wgSharedDB && in_array( 'user', $wgSharedTables ) ) {
121
			$userdb = self::getDB( $wgSharedDB, $ignoreInvalidDB );
122
		} else {
123
			$userdb = self::getDB( $database, $ignoreInvalidDB );
124
		}
125
126
		$db = self::getDB( $database, $ignoreInvalidDB );
127
128
		if ( $db && $userdb ) {
129
			$row = $userdb->selectRow( 'user',
130
				[ 'user_id', 'user_name' ],
131
				[ $field => $value ],
132
				__METHOD__ );
133
134
			if ( $row !== false ) {
135
				return new UserRightsProxy( $db, $database,
136
					$row->user_name,
137
					intval( $row->user_id ) );
138
			}
139
		}
140
		return null;
141
	}
142
143
	/**
144
	 * Open a database connection to work on for the requested user.
145
	 * This may be a new connection to another database for remote users.
146
	 *
147
	 * @param string $database
148
	 * @param bool $ignoreInvalidDB If true, don't check if $database is in $wgLocalDatabases
149
	 * @return IDatabase|null If invalid selection
150
	 */
151
	public static function getDB( $database, $ignoreInvalidDB = false ) {
152
		global $wgDBname;
153
		if ( $ignoreInvalidDB || self::validDatabase( $database ) ) {
154
			if ( $database == $wgDBname ) {
155
				// Hmm... this shouldn't happen though. :)
156
				return wfGetDB( DB_MASTER );
157
			} else {
158
				return wfGetDB( DB_MASTER, [], $database );
159
			}
160
		}
161
		return null;
162
	}
163
164
	/**
165
	 * @return int
166
	 */
167
	public function getId() {
168
		return $this->id;
169
	}
170
171
	/**
172
	 * @return bool
173
	 */
174
	public function isAnon() {
175
		return $this->getId() == 0;
176
	}
177
178
	/**
179
	 * Same as User::getName()
180
	 *
181
	 * @return string
182
	 */
183
	public function getName() {
184
		return $this->name . '@' . $this->database;
185
	}
186
187
	/**
188
	 * Same as User::getUserPage()
189
	 *
190
	 * @return Title
191
	 */
192
	public function getUserPage() {
193
		return Title::makeTitle( NS_USER, $this->getName() );
194
	}
195
196
	/**
197
	 * Replaces User::getUserGroups()
198
	 * @return array
199
	 */
200
	function getGroups() {
201
		$res = $this->db->select( 'user_groups',
202
			[ 'ug_group' ],
203
			[ 'ug_user' => $this->id ],
204
			__METHOD__ );
205
		$groups = [];
206
		foreach ( $res as $row ) {
207
			$groups[] = $row->ug_group;
208
		}
209
		return $groups;
210
	}
211
212
	/**
213
	 * Replaces User::addUserGroup()
214
	 * @param string $group
215
	 *
216
	 * @return bool
217
	 */
218
	function addGroup( $group ) {
219
		$this->db->insert( 'user_groups',
220
			[
221
				'ug_user' => $this->id,
222
				'ug_group' => $group,
223
			],
224
			__METHOD__,
225
			[ 'IGNORE' ] );
226
227
		return true;
228
	}
229
230
	/**
231
	 * Replaces User::removeUserGroup()
232
	 * @param string $group
233
	 *
234
	 * @return bool
235
	 */
236
	function removeGroup( $group ) {
237
		$this->db->delete( 'user_groups',
238
			[
239
				'ug_user' => $this->id,
240
				'ug_group' => $group,
241
			],
242
			__METHOD__ );
243
244
		return true;
245
	}
246
247
	/**
248
	 * Replaces User::setOption()
249
	 * @param string $option
250
	 * @param mixed $value
251
	 */
252
	public function setOption( $option, $value ) {
253
		$this->newOptions[$option] = $value;
254
	}
255
256
	public function saveSettings() {
257
		$rows = [];
258
		foreach ( $this->newOptions as $option => $value ) {
259
			$rows[] = [
260
				'up_user' => $this->id,
261
				'up_property' => $option,
262
				'up_value' => $value,
263
			];
264
		}
265
		$this->db->replace( 'user_properties',
266
			[ [ 'up_user', 'up_property' ] ],
267
			$rows, __METHOD__
268
		);
269
		$this->invalidateCache();
270
	}
271
272
	/**
273
	 * Replaces User::touchUser()
274
	 */
275
	function invalidateCache() {
276
		$this->db->update(
277
			'user',
278
			[ 'user_touched' => $this->db->timestamp() ],
279
			[ 'user_id' => $this->id ],
280
			__METHOD__
281
		);
282
283
		$wikiId = $this->db->getWikiID();
284
		$userId = $this->id;
285
		$this->db->onTransactionPreCommitOrIdle(
286
			function () use ( $wikiId, $userId ) {
287
				User::purge( $wikiId, $userId );
288
			},
289
			__METHOD__
290
		);
291
	}
292
}
293