Issues (71)

Security Analysis    no request data  

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.

src/Element/EntityBrowserElement.php (1 issue)

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
namespace Drupal\entity_browser\Element;
4
5
use Drupal\Component\Utility\Html;
6
use Drupal\Core\Form\FormStateInterface;
7
use Drupal\Core\Render\Element\FormElement;
8
use Drupal\entity_browser\Entity\EntityBrowser;
9
use Drupal\Core\Entity\EntityInterface;
10
11
/**
12
 * Provides an Entity Browser form element.
13
 *
14
 * Properties:
15
 * - #entity_browser: Entity browser or ID of the Entity browser to be used.
16
 * - #cardinality: (optional) Maximum number of items that are expected from
17
 *     the entity browser. Unlimited by default.
18
 * - #default_value: (optional) Array of entities that Entity browser should be
19
 *     initialized with. It's only applicable when edit selection mode is used.
20
 * - #entity_browser_validators: (optional) Array of validators that are to be
21
 *     passed to the entity browser. Array keys are plugin IDs and array values
22
 *     are plugin configuration values. Cardinality validator will be set
23
 *     automatically.
24
 * - #selection_mode: (optional) Determines how selection in entity browser will
25
 *     be handled. Will selection be appended/prepended or it will be replaced
26
 *     in case of editing. Defaults to append.
27
 * - #widget_context: (optional) Widget configuration overrides which enable
28
 *     use cases where the instance of a widget needs awareness of contextual
29
 *     configuration like field settings.
30
 *
31
 * Return value will be an array of selected entities, which will appear under
32
 * 'entities' key on the root level of the element's values in the form state.
33
 *
34
 * @FormElement("entity_browser")
35
 */
36
class EntityBrowserElement extends FormElement {
37
38
  /**
39
   * Indicating an entity browser can return an unlimited number of values.
40
   *
41
   * Note: When entity browser is used in Fields, cardinality is directly
42
   * propagated from Field settings, that's why this constant should be equal to
43
   * FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED.
44
   */
45
  const CARDINALITY_UNLIMITED = -1;
46
47
  /**
48
   * Selection from entity browser will be appended to existing list.
49
   *
50
   * When this selection mode is used, then entity browser will not be
51
   * populated with existing selection. Preselected list will be empty.
52
   *
53
   * Note: This option is also used by "js/entity_browser.common.js".
54
   */
55
  const SELECTION_MODE_APPEND = 'selection_append';
56
57
  /**
58
   * Selection from entity browser will be prepended to existing list.
59
   *
60
   * When this selection mode is used, then entity browser will not be
61
   * populated with existing selection. Preselected list will be empty.
62
   *
63
   * Note: This option is also used by "js/entity_browser.common.js".
64
   */
65
  const SELECTION_MODE_PREPEND = 'selection_prepend';
66
67
  /**
68
   * Selection from entity browser will replace existing.
69
   *
70
   * When this selection mode is used, then entity browser will be populated
71
   * with existing selection and returned selected list will replace existing
72
   * selection. This option requires entity browser selection display with
73
   * preselection support.
74
   *
75
   * Note: This option is also used by "js/entity_browser.common.js".
76
   */
77
  const SELECTION_MODE_EDIT = 'selection_edit';
78
79
  /**
80
   * {@inheritdoc}
81
   */
82
  public function getInfo() {
83
    $class = get_class($this);
84
    return [
85
      '#input' => TRUE,
86
      '#tree' => TRUE,
87
      '#cardinality' => static::CARDINALITY_UNLIMITED,
88
      '#selection_mode' => static::SELECTION_MODE_APPEND,
89
      '#process' => [[$class, 'processEntityBrowser']],
90
      '#default_value' => [],
91
      '#entity_browser_validators' => [],
92
      '#widget_context' => [],
93
      '#attached' => ['library' => ['entity_browser/common']],
94
    ];
95
  }
96
97
  /**
98
   * Get selection mode options.
99
   *
100
   * @return array
101
   *   Selection mode options.
102
   */
103
  public static function getSelectionModeOptions() {
104
    return [
105
      static::SELECTION_MODE_APPEND => t('Append to selection'),
106
      static::SELECTION_MODE_PREPEND => t('Prepend selection'),
107
      static::SELECTION_MODE_EDIT => t('Edit selection'),
108
    ];
109
  }
110
111
  /**
112
   * Check whether entity browser should be available for selection of entities.
113
   *
114
   * @param string $selection_mode
115
   *   Used selection mode.
116
   * @param int $cardinality
117
   *   Used cardinality.
118
   * @param int $preselection_size
119
   *   Preseletion size, if it's available.
120
   *
121
   * @return bool
122
   *   Returns positive if entity browser can be used.
123
   */
124
  public static function isEntityBrowserAvailable($selection_mode, $cardinality, $preselection_size) {
125
    if ($selection_mode == static::SELECTION_MODE_EDIT) {
126
      return TRUE;
127
    }
128
129
    $cardinality_exceeded =
130
      $cardinality != static::CARDINALITY_UNLIMITED
131
      && $preselection_size >= $cardinality;
132
133
    return !$cardinality_exceeded;
134
  }
135
136
  /**
137
   * Render API callback: Processes the entity browser element.
138
   */
139
  public static function processEntityBrowser(&$element, FormStateInterface $form_state, &$complete_form) {
140
    /** @var \Drupal\entity_browser\EntityBrowserInterface $entity_browser */
141
    if (is_string($element['#entity_browser'])) {
142
      $entity_browser = EntityBrowser::load($element['#entity_browser']);
143
    }
144
    else {
145
      $entity_browser = $element['#entity_browser'];
146
    }
147
148
    // Propagate selection if edit selection mode is used.
149
    $entity_browser_preselected_entities = [];
150
    if ($element['#selection_mode'] === static::SELECTION_MODE_EDIT) {
151
      $entity_browser->getSelectionDisplay()->checkPreselectionSupport();
152
153
      $entity_browser_preselected_entities = $element['#default_value'];
154
    }
155
156
    $default_value = implode(' ', array_map(
157
      function (EntityInterface $item) {
158
        return $item->getEntityTypeId() . ':' . $item->id();
159
      },
160
      $entity_browser_preselected_entities
161
    ));
162
    $validators = array_merge(
163
      $element['#entity_browser_validators'],
164
      ['cardinality' => ['cardinality' => $element['#cardinality']]]
165
    );
166
167
    // Display error message if the entity browser was not found.
168
    if (!$entity_browser) {
169
      $element['entity_browser'] = [
170
        '#type' => 'markup',
171
        '#markup' => is_string($element['#entity_browser']) ? t('Entity browser @browser not found.', ['@browser' => $element['#entity_browser']]) : t('Entity browser not found.'),
172
      ];
173
    }
174
    // Display entity_browser
175
    else {
176
      $display = $entity_browser->getDisplay();
177
      $display->setUuid(sha1(implode('-', array_merge([$complete_form['#build_id']], $element['#parents']))));
178
      $element['entity_browser'] = [
179
        '#eb_parents' => array_merge($element['#parents'], ['entity_browser']),
180
      ];
181
      $element['entity_browser'] = $display->displayEntityBrowser(
182
        $element['entity_browser'],
183
        $form_state,
184
        $complete_form,
185
        [
186
          'validators' => $validators,
187
          'selected_entities' => $entity_browser_preselected_entities,
188
          'widget_context' => $element['#widget_context'],
189
        ]
190
      );
191
192
      $hidden_id = Html::getUniqueId($element['#id'] . '-target');
193
      $element['entity_ids'] = [
194
        '#type' => 'hidden',
195
        '#id' => $hidden_id,
196
        // We need to repeat ID here as it is otherwise skipped when rendering.
197
        '#attributes' => ['id' => $hidden_id, 'class' => ['eb-target']],
198
        '#default_value' => $default_value,
199
      ];
200
201
      $element['#attached']['drupalSettings']['entity_browser'] = [
202
        $entity_browser->getDisplay()->getUuid() => [
203
          'cardinality' => $element['#cardinality'],
204
          'selection_mode' => $element['#selection_mode'],
205
          'selector' => '#' . $hidden_id,
206
        ],
207
      ];
208
    }
209
210
    return $element;
211
  }
212
213
  /**
214
   * {@inheritdoc}
215
   */
216
  public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
217
    if ($input === FALSE) {
218
      return $element['#default_value'] ?: [];
219
    }
220
221
    $entities = [];
222
    if ($input['entity_ids']) {
223
      $entities = static::processEntityIds($input['entity_ids']);
224
    }
225
226
    return ['entities' => $entities];
227
  }
228
229
  /**
230
   * Processes entity IDs and gets array of loaded entities.
231
   *
232
   * @param array|string $ids
233
   *   Processes entity IDs as they are returned from the entity browser. They
234
   *   are in [entity_type_id]:[entity_id] form. Array of IDs or a
235
   *   space-delimited string is supported.
236
   *
237
   * @return \Drupal\Core\Entity\EntityInterface[]
238
   *   Array of entity objects.
239
   */
240
  public static function processEntityIds($ids) {
241
    if (!is_array($ids)) {
242
      $ids = array_filter(explode(' ', $ids));
243
    }
244
245
    return array_map(
246
      function ($item) {
247
        list($entity_type, $entity_id) = explode(':', $item);
248
        return \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id);
249
      },
250
      $ids
251
    );
252
  }
253
254
  /**
255
   * Processes entity IDs and gets array of loaded entities.
256
   *
257
   * @param string $id
258
   *   Processes entity ID as it is returned from the entity browser. ID should
259
   *   be in [entity_type_id]:[entity_id] form.
260
   *
261
   * @return \Drupal\Core\Entity\EntityInterface
262
   *   Entity object.
263
   */
264
  public static function processEntityId($id) {
265
    $return = static::processEntityIds([$id]);
266
    return current($return);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The expression current($return); of type Drupal\Core\Entity\EntityInterface|false adds false to the return on line 266 which is incompatible with the return type documented by Drupal\entity_browser\El...lement::processEntityId of type Drupal\Core\Entity\EntityInterface. It seems like you forgot to handle an error condition.
Loading history...
267
  }
268
269
}
270