Issues (2473)

Branch: master

Security Analysis    no vulnerabilities found

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.

engine/lib/plugins.php (3 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
 * Elgg plugins library
4
 * Contains functions for managing plugins
5
 *
6
 * @package Elgg.Core
7
 * @subpackage Plugins
8
 */
9
10
/**
11
 * Tells \ElggPlugin::start() to include the start.php file.
12
 */
13
define('ELGG_PLUGIN_INCLUDE_START', 1);
14
15
/**
16
 * Tells \ElggPlugin::start() to automatically register the plugin's views.
17
 */
18
define('ELGG_PLUGIN_REGISTER_VIEWS', 2);
19
20
/**
21
 * Tells \ElggPlugin::start() to automatically register the plugin's languages.
22
 */
23
define('ELGG_PLUGIN_REGISTER_LANGUAGES', 4);
24
25
/**
26
 * Tells \ElggPlugin::start() to automatically register the plugin's classes.
27
 */
28
define('ELGG_PLUGIN_REGISTER_CLASSES', 8);
29
30
/**
31
 * Prefix for plugin setting names
32
 *
33
 * @todo Can't namespace these because many plugins directly call
34
 * private settings via $entity->$name.
35
 */
36
//define('ELGG_PLUGIN_SETTING_PREFIX', 'plugin:setting:');
37
38
/**
39
 * Prefix for plugin user setting names
40
 */
41
define('ELGG_PLUGIN_USER_SETTING_PREFIX', 'plugin:user_setting:');
42
43
/**
44
 * Internal settings prefix
45
 *
46
 * @todo This could be resolved by promoting \ElggPlugin to a 5th type.
47
 */
48
define('ELGG_PLUGIN_INTERNAL_PREFIX', 'elgg:internal:');
49
50
51
/**
52
 * Returns a list of plugin directory names from a base directory.
53
 *
54
 * @param string $dir A dir to scan for plugins. Defaults to config's plugins_path.
55
 *                    Must have a trailing slash.
56
 *
57
 * @return array Array of directory names (not full paths)
58
 * @since 1.8.0
59
 * @access private
60
 */
61
function _elgg_get_plugin_dirs_in_dir($dir = null) {
62
	return _elgg_services()->plugins->getDirsInDir($dir);
63
}
64
65
/**
66
 * Discovers plugins in the plugins_path setting and creates \ElggPlugin
67
 * entities for them if they don't exist.  If there are plugins with entities
68
 * but not actual files, will disable the \ElggPlugin entities and mark as inactive.
69
 * The \ElggPlugin object holds config data, so don't delete.
70
 *
71
 * @return bool
72
 * @since 1.8.0
73
 * @access private
74
 */
75
function _elgg_generate_plugin_entities() {
76
	return _elgg_services()->plugins->generateEntities();
77
}
78
79
/**
80
 * Cache a reference to this plugin by its ID
81
 * 
82
 * @param \ElggPlugin $plugin
83
 * 
84
 * @access private
85
 */
86
function _elgg_cache_plugin_by_id(\ElggPlugin $plugin) {
87
	return _elgg_services()->plugins->cache($plugin);
88
}
89
90
/**
91
 * Returns an \ElggPlugin object with the path $path.
92
 *
93
 * @param string $plugin_id The id (dir name) of the plugin. NOT the guid.
94
 * @return \ElggPlugin|null
95
 * @since 1.8.0
96
 */
97
function elgg_get_plugin_from_id($plugin_id) {
98
	return _elgg_services()->plugins->get($plugin_id);
99
}
100
101
/**
102
 * Returns if a plugin exists in the system.
103
 *
104
 * @warning This checks only plugins that are registered in the system!
105
 * If the plugin cache is outdated, be sure to regenerate it with
106
 * {@link _elgg_generate_plugin_objects()} first.
107
 *
108
 * @param string $id The plugin ID.
109
 * @since 1.8.0
110
 * @return bool
111
 */
112
function elgg_plugin_exists($id) {
113
	return _elgg_services()->plugins->exists($id);
114
}
115
116
/**
117
 * Returns the highest priority of the plugins
118
 *
119
 * @return int
120
 * @since 1.8.0
121
 * @access private
122
 */
123
function _elgg_get_max_plugin_priority() {
124
	return _elgg_services()->plugins->getMaxPriority();
125
}
126
127
/**
128
 * Returns if a plugin is active for a current site.
129
 *
130
 * @param string $plugin_id The plugin ID
131
 * @param int    $site_guid The site guid
132
 * @since 1.8.0
133
 * @return bool
134
 */
135
function elgg_is_active_plugin($plugin_id, $site_guid = null) {
136
	return _elgg_services()->plugins->isActive($plugin_id, $site_guid);
137
}
138
139
/**
140
 * Loads all active plugins in the order specified in the tool admin panel.
141
 *
142
 * @note This is called on every page load. If a plugin is active and problematic, it
143
 * will be disabled and a visible error emitted. This does not check the deps system because
144
 * that was too slow.
145
 *
146
 * @return bool
147
 * @since 1.8.0
148
 * @access private
149
 */
150
function _elgg_load_plugins() {
151
	return _elgg_services()->plugins->load();
152
}
153
154
/**
155
 * Returns an ordered list of plugins
156
 *
157
 * @param string $status    The status of the plugins. active, inactive, or all.
158
 * @param mixed  $site_guid Optional site guid
159
 * @return \ElggPlugin[]
160
 * @since 1.8.0
161
 */
162
function elgg_get_plugins($status = 'active', $site_guid = null) {
163
	return _elgg_services()->plugins->find($status, $site_guid);
164
}
165
166
/**
167
 * Reorder plugins to an order specified by the array.
168
 * Plugins not included in this array will be appended to the end.
169
 *
170
 * @note This doesn't use the \ElggPlugin->setPriority() method because
171
 *       all plugins are being changed and we don't want it to automatically
172
 *       reorder plugins.
173
 *
174
 * @param array $order An array of plugin ids in the order to set them
175
 * @return bool
176
 * @since 1.8.0
177
 * @access private
178
 */
179
function _elgg_set_plugin_priorities(array $order) {
180
	return _elgg_services()->plugins->setPriorities($order);
181
}
182
183
/**
184
 * Reindexes all plugin priorities starting at 1.
185
 *
186
 * @todo Can this be done in a single sql command?
187
 * @return bool
188
 * @since 1.8.0
189
 * @access private
190
 */
191
function _elgg_reindex_plugin_priorities() {
192
	return _elgg_services()->plugins->reindexPriorities();
193
}
194
195
/**
196
 * Namespaces a string to be used as a private setting name for a plugin.
197
 *
198
 * For user_settings, two namespaces are added: a user setting namespace and the
199
 * plugin id.
200
 *
201
 * For internal (plugin priority), there is a single internal namespace added.
202
 *
203
 * @param string $type The type of setting: user_setting or internal.
204
 * @param string $name The name to namespace.
205
 * @param string $id   The plugin's ID to namespace with.  Required for user_setting.
206
 * @return string
207
 * @since 1.8.0
208
 * @access private
209
 */
210
function _elgg_namespace_plugin_private_setting($type, $name, $id = null) {
211
	return _elgg_services()->plugins->namespacePrivateSetting($type, $name, $id);
212
}
213
214
/**
215
 * Returns an array of all provides from all active plugins.
216
 *
217
 * Array in the form array(
218
 * 	'provide_type' => array(
219
 * 		'provided_name' => array(
220
 * 			'version' => '1.8',
221
 * 			'provided_by' => 'provider_plugin_id'
222
 *  	)
223
 *  )
224
 * )
225
 *
226
 * @param string $type The type of provides to return
227
 * @param string $name A specific provided name to return. Requires $provide_type.
228
 *
229
 * @return array
230
 * @since 1.8.0
231
 * @access private
232
 */
233
function _elgg_get_plugins_provides($type = null, $name = null) {
234
	return _elgg_services()->plugins->getProvides($type, $name);
235
}
236
237
/**
238
 * Deletes all cached data on plugins being provided.
239
 * 
240
 * @return boolean
241
 * @since 1.9.0
242
 * @access private
243
 */
244
function _elgg_invalidate_plugins_provides_cache() {
245
	return _elgg_services()->plugins->invalidateProvidesCache();
246
}
247
248
/**
249
 * Checks if a plugin is currently providing $type and $name, and optionally
250
 * checking a version.
251
 *
252
 * @param string $type       The type of the provide
253
 * @param string $name       The name of the provide
254
 * @param string $version    A version to check against
255
 * @param string $comparison The comparison operator to use in version_compare()
256
 *
257
 * @return array An array in the form array(
258
 * 	'status' => bool Does the provide exist?,
259
 * 	'value' => string The version provided
260
 * )
261
 * @since 1.8.0
262
 * @access private
263
 */
264
function _elgg_check_plugins_provides($type, $name, $version = null, $comparison = 'ge') {
265
	return _elgg_services()->plugins->checkProvides($type, $name, $version, $comparison);
266
}
267
268
/**
269
 * Returns an array of parsed strings for a dependency in the
270
 * format: array(
271
 * 	'type'			=>	requires, conflicts, or provides.
272
 * 	'name'			=>	The name of the requirement / conflict
273
 * 	'value'			=>	A string representing the expected value: <1, >=3, !=enabled
274
 * 	'local_value'	=>	The current value, ("Not installed")
275
 * 	'comment'		=>	Free form text to help resovle the problem ("Enable / Search for plugin <link>")
276
 * )
277
 *
278
 * @param array $dep An \ElggPluginPackage dependency array
279
 * @return array
280
 * @since 1.8.0
281
 * @access private
282
 */
283
function _elgg_get_plugin_dependency_strings($dep) {
284
	return _elgg_services()->plugins->getDependencyStrings($dep);
285
}
286
287
/**
288
 * Returns an array of all plugin user settings for a user.
289
 *
290
 * @param int    $user_guid  The user GUID or 0 for the currently logged in user.
291
 * @param string $plugin_id  The plugin ID (Required)
292
 * @param bool   $return_obj Return settings as an object? This can be used to in reusable
293
 *                           views where the settings are passed as $vars['entity'].
294
 * @return array
295
 * @since 1.8.0
296
 * @see \ElggPlugin::getAllUserSettings()
297
 */
298
function elgg_get_all_plugin_user_settings($user_guid = 0, $plugin_id = null, $return_obj = false) {
299
	return _elgg_services()->plugins->getAllUserSettings($user_guid, $plugin_id, $return_obj);
300
}
301
302
/**
303
 * Set a user specific setting for a plugin.
304
 *
305
 * @param string $name      The name. Note: cannot be "title".
306
 * @param mixed  $value     The value.
307
 * @param int    $user_guid The user GUID or 0 for the currently logged in user.
308
 * @param string $plugin_id The plugin ID (Required)
309
 *
310
 * @return bool
311
 * @since 1.8.0
312
 * @see \ElggPlugin::setUserSetting()
313
 */
314
function elgg_set_plugin_user_setting($name, $value, $user_guid = 0, $plugin_id = null) {
315
	return _elgg_services()->plugins->setUserSetting($name, $value, $user_guid, $plugin_id);
316
}
317
318
/**
319
 * Unsets a user-specific plugin setting
320
 *
321
 * @param string $name      Name of the setting
322
 * @param int    $user_guid The user GUID or 0 for the currently logged in user.
323
 * @param string $plugin_id The plugin ID (Required)
324
 *
325
 * @return bool
326
 * @since 1.8.0
327
 * @see \ElggPlugin::unsetUserSetting()
328
 */
329
function elgg_unset_plugin_user_setting($name, $user_guid = 0, $plugin_id = null) {
330
	return _elgg_services()->plugins->unsetUserSetting($name, $user_guid, $plugin_id);
331
}
332
333
/**
334
 * Get a user specific setting for a plugin.
335
 *
336
 * @param string $name      The name of the setting.
337
 * @param int    $user_guid The user GUID or 0 for the currently logged in user.
338
 * @param string $plugin_id The plugin ID (Required)
339
 * @param mixed  $default   The default value to return if none is set
340
 *
341
 * @return mixed
342
 * @since 1.8.0
343
 * @see \ElggPlugin::getUserSetting()
344
 */
345
function elgg_get_plugin_user_setting($name, $user_guid = 0, $plugin_id = null, $default = null) {
346
	return _elgg_services()->plugins->getUserSetting($name, $user_guid, $plugin_id, $default);
347
}
348
349
/**
350
 * Set a setting for a plugin.
351
 *
352
 * @param string $name      The name of the setting - note, can't be "title".
353
 * @param mixed  $value     The value.
354
 * @param string $plugin_id The plugin ID (Required)
355
 *
356
 * @return bool
357
 * @since 1.8.0
358
 * @see \ElggPlugin::setSetting()
359
 */
360
function elgg_set_plugin_setting($name, $value, $plugin_id = null) {
361
	return _elgg_services()->plugins->setSetting($name, $value, $plugin_id);
362
}
363
364
/**
365
 * Get setting for a plugin.
366
 *
367
 * @param string $name      The name of the setting.
368
 * @param string $plugin_id The plugin ID (Required)
369
 * @param mixed  $default   The default value to return if none is set
370
 *
371
 * @return mixed
372
 * @since 1.8.0
373
 * @see \ElggPlugin::getSetting()
374
 */
375
function elgg_get_plugin_setting($name, $plugin_id = null, $default = null) {
376
	return _elgg_services()->plugins->getSetting($name, $plugin_id, $default);
377
}
378
379
/**
380
 * Unsets a plugin setting.
381
 *
382
 * @param string $name      The name of the setting.
383
 * @param string $plugin_id The plugin ID (Required)
384
 *
385
 * @return bool
386
 * @since 1.8.0
387
 * @see \ElggPlugin::unsetSetting()
388
 */
389
function elgg_unset_plugin_setting($name, $plugin_id = null) {
390
	return _elgg_services()->plugins->unsetSetting($name, $plugin_id);
391
}
392
393
/**
394
 * Unsets all plugin settings for a plugin.
395
 *
396
 * @param string $plugin_id The plugin ID (Required)
397
 *
398
 * @return bool
399
 * @since 1.8.0
400
 * @see \ElggPlugin::unsetAllSettings()
401
 */
402
function elgg_unset_all_plugin_settings($plugin_id = null) {
403
	return _elgg_services()->plugins->unsetAllSettings($plugin_id);
404
}
405
406
/**
407
 * Returns entities based upon plugin user settings.
408
 * Takes all the options for {@link elgg_get_entities_from_private_settings()}
409
 * in addition to the ones below.
410
 *
411
 * @param array $options Array in the format:
412
 *
413
 * 	plugin_id => STR The plugin id. Required.
414
 *
415
 * 	plugin_user_setting_names => null|ARR private setting names
416
 *
417
 * 	plugin_user_setting_values => null|ARR metadata values
418
 *
419
 * 	plugin_user_setting_name_value_pairs => null|ARR (
420
 *                                         name => 'name',
421
 *                                         value => 'value',
422
 *                                         'operand' => '=',
423
 *                                        )
424
 * 	                             Currently if multiple values are sent via
425
 *                               an array (value => array('value1', 'value2')
426
 *                               the pair's operand will be forced to "IN".
427
 *
428
 * 	plugin_user_setting_name_value_pairs_operator => null|STR The operator to use for combining
429
 *                                        (name = value) OPERATOR (name = value); default AND
430
 *
431
 * @return mixed int If count, int. If not count, array. false on errors.
432
 * @since 1.8.0
433
 */
434
function elgg_get_entities_from_plugin_user_settings(array $options = array()) {
435
	return _elgg_services()->plugins->getEntitiesFromUserSettings($options);
436
}
437
438
/**
439
 * Runs unit tests for plugin API.
440
 *
441
 * @param string $hook   unit_test
442
 * @param string $type   system
443
 * @param mixed  $value  Array of tests
444
 * @param mixed  $params Params
445
 *
446
 * @return array
447
 * @access private
448
 */
449
function _elgg_plugins_test($hook, $type, $value, $params) {
450
	global $CONFIG;
451
	$value[] = $CONFIG->path . 'engine/tests/ElggCorePluginsAPITest.php';
452
	return $value;
453
}
454
455
/**
456
 * Checks on deactivate plugin event if disabling it won't create unmet dependencies and blocks disable in such case.
457
 *
458
 * @param string $event  deactivate
459
 * @param string $type   plugin
460
 * @param array  $params Parameters array containing entry with ELggPlugin instance under 'plugin_entity' key
461
 * @return bool  false to block plugin deactivation action
462
 *
463
 * @access private
464
 */
465
function _plugins_deactivate_dependency_check($event, $type, $params) {
466
	$plugin_id = $params['plugin_entity']->getManifest()->getPluginID();
467
	$plugin_name = $params['plugin_entity']->getManifest()->getName();
468
469
	$active_plugins = elgg_get_plugins();
470
471
	$dependents = array();
472
	foreach ($active_plugins as $plugin) {
473
		$manifest = $plugin->getManifest();
474
		$requires = $manifest->getRequires();
475
476
		foreach ($requires as $required) {
477
			if ($required['type'] == 'plugin' && $required['name'] == $plugin_id) {
478
				// there are active dependents
479
				$dependents[$manifest->getPluginID()] = $plugin;
480
			}
481
		}
482
	}
483
484
	if ($dependents) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $dependents of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
485
		$list = '<ul>';
486
		// construct error message and prevent disabling
487
		foreach ($dependents as $dependent) {
488
			$list .= '<li>' . $dependent->getManifest()->getName() . '</li>';
489
		}
490
		$list .= '</ul>';
491
492
		register_error(elgg_echo('ElggPlugin:Dependencies:ActiveDependent', array($plugin_name, $list)));
493
494
		return false;
495
	}
496
}
497
498
/**
499
 * Initialize the plugin system
500
 *
501
 * @return void
502
 * @access private
503
 */
504
function _elgg_plugins_init() {
505
506
	if (elgg_is_admin_logged_in()) {
507
		elgg_register_ajax_view('object/plugin/full');
508
	}
509
510
	elgg_register_plugin_hook_handler('unit_test', 'system', '_elgg_plugins_test');
511
512
	// note - plugins are booted by the time this handler is registered
513
	// deactivation due to error may have already occurred
514
	elgg_register_event_handler('deactivate', 'plugin', '_plugins_deactivate_dependency_check');
515
516
	/**
517
	 * @see \Elgg\Database\Plugins::invalidateIsActiveCache
518
	 */
519
	$svc = _elgg_services()->plugins;
520
	elgg_register_event_handler('deactivate', 'plugin', array($svc, 'invalidateIsActiveCache'));
0 ignored issues
show
array($svc, 'invalidateIsActiveCache') is of type array<integer,object<Elg...lugins>","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
521
	elgg_register_event_handler('activate', 'plugin', array($svc, 'invalidateIsActiveCache'));
0 ignored issues
show
array($svc, 'invalidateIsActiveCache') is of type array<integer,object<Elg...lugins>","1":"string"}>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
522
523
	elgg_register_action("plugins/settings/save", '', 'admin');
524
	elgg_register_action("plugins/usersettings/save");
525
526
	elgg_register_action('admin/plugins/activate', '', 'admin');
527
	elgg_register_action('admin/plugins/deactivate', '', 'admin');
528
	elgg_register_action('admin/plugins/activate_all', '', 'admin');
529
	elgg_register_action('admin/plugins/deactivate_all', '', 'admin');
530
531
	elgg_register_action('admin/plugins/set_priority', '', 'admin');
532
533
	elgg_register_library('elgg:markdown', elgg_get_root_path() . 'vendors/markdown/markdown.php');
534
}
535
536
return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
537
	$events->registerHandler('init', 'system', '_elgg_plugins_init');
538
};
539