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/revisiondelete/RevisionDeleter.php (5 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
 * Revision/log/file deletion backend
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 RevisionDelete
22
 */
23
24
/**
25
 * General controller for RevDel, used by both SpecialRevisiondelete and
26
 * ApiRevisionDelete.
27
 * @ingroup RevisionDelete
28
 */
29
class RevisionDeleter {
30
	/** List of known revdel types, with their corresponding list classes */
31
	private static $allowedTypes = [
32
		'revision' => 'RevDelRevisionList',
33
		'archive' => 'RevDelArchiveList',
34
		'oldimage' => 'RevDelFileList',
35
		'filearchive' => 'RevDelArchivedFileList',
36
		'logging' => 'RevDelLogList',
37
	];
38
39
	/** Type map to support old log entries */
40
	private static $deprecatedTypeMap = [
41
		'oldid' => 'revision',
42
		'artimestamp' => 'archive',
43
		'oldimage' => 'oldimage',
44
		'fileid' => 'filearchive',
45
		'logid' => 'logging',
46
	];
47
48
	/**
49
	 * Lists the valid possible types for revision deletion.
50
	 *
51
	 * @since 1.22
52
	 * @return array
53
	 */
54
	public static function getTypes() {
55
		return array_keys( self::$allowedTypes );
56
	}
57
58
	/**
59
	 * Gets the canonical type name, if any.
60
	 *
61
	 * @since 1.22
62
	 * @param string $typeName
63
	 * @return string|null
64
	 */
65
	public static function getCanonicalTypeName( $typeName ) {
66
		if ( isset( self::$deprecatedTypeMap[$typeName] ) ) {
67
			$typeName = self::$deprecatedTypeMap[$typeName];
68
		}
69
		return isset( self::$allowedTypes[$typeName] ) ? $typeName : null;
70
	}
71
72
	/**
73
	 * Instantiate the appropriate list class for a given list of IDs.
74
	 *
75
	 * @since 1.22
76
	 * @param string $typeName RevDel type, see RevisionDeleter::getTypes()
77
	 * @param IContextSource $context
78
	 * @param Title $title
79
	 * @param array $ids
80
	 * @return RevDelList
81
	 * @throws MWException
82
	 */
83
	public static function createList( $typeName, IContextSource $context, Title $title, array $ids ) {
84
		$typeName = self::getCanonicalTypeName( $typeName );
85
		if ( !$typeName ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $typeName of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
86
			throw new MWException( __METHOD__ . ": Unknown RevDel type '$typeName'" );
87
		}
88
		$class = self::$allowedTypes[$typeName];
89
		return new $class( $context, $title, $ids );
90
	}
91
92
	/**
93
	 * Checks for a change in the bitfield for a certain option and updates the
94
	 * provided array accordingly.
95
	 *
96
	 * @param string $desc Description to add to the array if the option was
97
	 * enabled / disabled.
98
	 * @param int $field The bitmask describing the single option.
99
	 * @param int $diff The xor of the old and new bitfields.
100
	 * @param int $new The new bitfield
101
	 * @param array $arr The array to update.
102
	 */
103
	protected static function checkItem( $desc, $field, $diff, $new, &$arr ) {
104
		if ( $diff & $field ) {
105
			$arr[( $new & $field ) ? 0 : 1][] = $desc;
106
		}
107
	}
108
109
	/**
110
	 * Gets an array of message keys describing the changes made to the
111
	 * visibility of the revision.
112
	 *
113
	 * If the resulting array is $arr, then $arr[0] will contain an array of
114
	 * keys describing the items that were hidden, $arr[1] will contain
115
	 * an array of keys describing the items that were unhidden, and $arr[2]
116
	 * will contain an array with a single message key, which can be one of
117
	 * "revdelete-restricted", "revdelete-unrestricted" indicating (un)suppression
118
	 * or null to indicate nothing in particular.
119
	 * You can turn the keys in $arr[0] and $arr[1] into message keys by
120
	 * appending -hid and -unhid to the keys respectively.
121
	 *
122
	 * @param int $n The new bitfield.
123
	 * @param int $o The old bitfield.
124
	 * @return array An array as described above.
125
	 * @since 1.19 public
126
	 */
127
	public static function getChanges( $n, $o ) {
128
		$diff = $n ^ $o;
129
		$ret = [ 0 => [], 1 => [], 2 => [] ];
130
		// Build bitfield changes in language
131
		self::checkItem( 'revdelete-content',
132
			Revision::DELETED_TEXT, $diff, $n, $ret );
133
		self::checkItem( 'revdelete-summary',
134
			Revision::DELETED_COMMENT, $diff, $n, $ret );
135
		self::checkItem( 'revdelete-uname',
136
			Revision::DELETED_USER, $diff, $n, $ret );
137
		// Restriction application to sysops
138
		if ( $diff & Revision::DELETED_RESTRICTED ) {
139
			if ( $n & Revision::DELETED_RESTRICTED ) {
140
				$ret[2][] = 'revdelete-restricted';
141
			} else {
142
				$ret[2][] = 'revdelete-unrestricted';
143
			}
144
		}
145
		return $ret;
146
	}
147
148
	/** Get DB field name for URL param...
149
	 * Future code for other things may also track
150
	 * other types of revision-specific changes.
151
	 * @param string $typeName
152
	 * @return string One of log_id/rev_id/fa_id/ar_timestamp/oi_archive_name
153
	 */
154 View Code Duplication
	public static function getRelationType( $typeName ) {
155
		$typeName = self::getCanonicalTypeName( $typeName );
156
		if ( !$typeName ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $typeName of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
157
			return null;
158
		}
159
		return call_user_func( [ self::$allowedTypes[$typeName], 'getRelationType' ] );
160
	}
161
162
	/**
163
	 * Get the user right required for the RevDel type
164
	 * @since 1.22
165
	 * @param string $typeName
166
	 * @return string User right
167
	 */
168 View Code Duplication
	public static function getRestriction( $typeName ) {
169
		$typeName = self::getCanonicalTypeName( $typeName );
170
		if ( !$typeName ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $typeName of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
171
			return null;
172
		}
173
		return call_user_func( [ self::$allowedTypes[$typeName], 'getRestriction' ] );
174
	}
175
176
	/**
177
	 * Get the revision deletion constant for the RevDel type
178
	 * @since 1.22
179
	 * @param string $typeName
180
	 * @return int RevDel constant
181
	 */
182 View Code Duplication
	public static function getRevdelConstant( $typeName ) {
183
		$typeName = self::getCanonicalTypeName( $typeName );
184
		if ( !$typeName ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $typeName of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
185
			return null;
186
		}
187
		return call_user_func( [ self::$allowedTypes[$typeName], 'getRevdelConstant' ] );
188
	}
189
190
	/**
191
	 * Suggest a target for the revision deletion
192
	 * @since 1.22
193
	 * @param string $typeName
194
	 * @param Title|null $target User-supplied target
195
	 * @param array $ids
196
	 * @return Title|null
197
	 */
198
	public static function suggestTarget( $typeName, $target, array $ids ) {
199
		$typeName = self::getCanonicalTypeName( $typeName );
200
		if ( !$typeName ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $typeName of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
201
			return $target;
202
		}
203
		return call_user_func( [ self::$allowedTypes[$typeName], 'suggestTarget' ], $target, $ids );
204
	}
205
206
	/**
207
	 * Checks if a revision still exists in the revision table.
208
	 * If it doesn't, returns the corresponding ar_timestamp field
209
	 * so that this key can be used instead.
210
	 *
211
	 * @param Title $title
212
	 * @param int $revid
213
	 * @return bool|mixed
214
	 */
215
	public static function checkRevisionExistence( $title, $revid ) {
216
		$dbr = wfGetDB( DB_REPLICA );
217
		$exists = $dbr->selectField( 'revision', '1',
218
				[ 'rev_id' => $revid ], __METHOD__ );
219
220
		if ( $exists ) {
221
			return true;
222
		}
223
224
		$timestamp = $dbr->selectField( 'archive', 'ar_timestamp',
225
				[ 'ar_namespace' => $title->getNamespace(),
226
					'ar_title' => $title->getDBkey(),
227
					'ar_rev_id' => $revid ], __METHOD__ );
228
229
		return $timestamp;
230
	}
231
232
	/**
233
	 * Put together a rev_deleted bitfield
234
	 * @since 1.22
235
	 * @param array $bitPars ExtractBitParams() params
236
	 * @param int $oldfield Current bitfield
237
	 * @return integer
238
	 */
239
	public static function extractBitfield( array $bitPars, $oldfield ) {
240
		// Build the actual new rev_deleted bitfield
241
		$newBits = 0;
242
		foreach ( $bitPars as $const => $val ) {
243
			if ( $val == 1 ) {
244
				$newBits |= $const; // $const is the *_deleted const
245
			} elseif ( $val == -1 ) {
246
				$newBits |= ( $oldfield & $const ); // use existing
247
			}
248
		}
249
		return $newBits;
250
	}
251
}
252