Issues (15)

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/ViewDeriverHelperTrait.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\graphql_views;
4
5
use Drupal\Component\Plugin\PluginManagerInterface;
6
use Drupal\Component\Utility\NestedArray;
7
use Drupal\graphql\Utility\StringHelper;
8
use Drupal\graphql_views\Plugin\views\row\GraphQLEntityRow;
9
use Drupal\graphql_views\Plugin\views\row\GraphQLFieldRow;
10
use Drupal\views\Plugin\views\display\DisplayPluginInterface;
11
use Drupal\views\ViewEntityInterface;
12
13
/**
14
 * Helper functions fot view derivers.
15
 */
16
trait ViewDeriverHelperTrait {
17
18
  /**
19
   * Helper function to return the contextual filter argument if any exist.
20
   *
21
   * @param array $arguments
22
   *   The array of available arguments.
23
   * @param string $id
24
   *   The plugin derivative id.
25
   *
26
   * @return array
27
   *   The contextual filter argument if applicable.
28
   */
29
  protected function getContextualArguments(array $arguments, $id) {
30
    if (!empty($arguments)) {
31
      return [
32
        'contextualFilter' => [
33
          'type' => StringHelper::camelCase($id, 'contextual', 'filter', 'input'),
34
        ],
35
      ];
36
    }
37
38
    return [];
39
  }
40
41
  /**
42
   * Helper function to retrieve the sort arguments if any are exposed.
43
   *
44
   * @param \Drupal\views\Plugin\views\display\DisplayPluginInterface $display
45
   *   The display plugin.
46
   * @param string $id
47
   *   The plugin derivative id.
48
   *
49
   * @return array
50
   *   The sort arguments if any exposed sorts are available.
51
   */
52
  protected function getSortArguments(DisplayPluginInterface $display, $id) {
53
    $sorts = array_filter($display->getOption('sorts') ?: [], function ($sort) {
54
      return $sort['exposed'];
55
    });
56
    return $sorts ? [
57
      'sortDirection' => [
58
        'type' => 'ViewSortDirection',
59
        'default' => 'asc',
60
      ],
61
      'sortBy' => [
62
        'type' => StringHelper::camelCase($id, 'sort', 'by'),
63
      ],
64
    ] : [];
65
  }
66
67
  /**
68
   * Helper function to return the filter argument if applicable.
69
   *
70
   * @param \Drupal\views\Plugin\views\display\DisplayPluginInterface $display
71
   *   The display plugin.
72
   * @param string $id
73
   *   The plugin derivative id.
74
   *
75
   * @return array
76
   *   The filter argument if any exposed filters are available.
77
   */
78
  protected function getFilterArguments(DisplayPluginInterface $display, $id) {
0 ignored issues
show
The parameter $id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
79
    $filters = array_filter($display->getOption('filters') ?: [], function ($filter) {
80
      return array_key_exists('exposed', $filter) && $filter['exposed'];
81
    });
82
83
    return !empty($filters) ? [
84
      'filter' => [
85
        'type' => $display->getGraphQLFilterInputName(),
86
      ],
87
    ] : [];
88
  }
89
90
  /**
91
   * Helper function to retrieve the pager arguments if the display is paged.
92
   *
93
   * @param \Drupal\views\Plugin\views\display\DisplayPluginInterface $display
94
   *   The display plugin.
95
   *
96
   * @return array
97
   *   An array of pager arguments if the view display is paged.
98
   */
99
  protected function getPagerArguments(DisplayPluginInterface $display) {
100
    return $this->isPaged($display) ? [
101
      'page' => ['type' => 'Int', 'default' => $this->getPagerOffset($display)],
102
      'pageSize' => [
103
        'type' => 'Int',
104
        'default' => $this->getPagerLimit($display),
105
      ],
106
    ] : [];
107
  }
108
109
  /**
110
   * Helper function to retrieve the types that the view can be attached to.
111
   *
112
   * @param array $arguments
113
   *   An array containing information about the available arguments.
114
   * @param array $types
115
   *   Types where it needs to be added.
116
   *
117
   * @return array
118
   *   An array of additional types the view can be embedded in.
119
   */
120
  protected function getTypes(array $arguments, array $types = ['Root']) {
121
122
    if (empty($arguments)) {
123
      return $types;
124
    }
125
126
    foreach ($arguments as $argument) {
127
      // Depending on whether bundles are known, we expose the view field
128
      // either on the interface (e.g. Node) or on the type (e.g. NodePage)
129
      // level. Here we specify types managed by other graphql_* modules,
130
      // yet we don't define these modules as dependencies. If types are not
131
      // in the schema, the resulting GraphQL field will be attached to
132
      // nowhere, so it won't go into the schema.
133
      if (empty($argument['bundles']) && empty($argument['entity_type'])) {
134
        continue;
135
      }
136
137
      if (empty($argument['bundles'])) {
138
        $types = array_merge($types, [StringHelper::camelCase($argument['entity_type'])]);
139
      }
140
      else {
141
        $types = array_merge($types, array_map(function ($bundle) use ($argument) {
142
          return StringHelper::camelCase($argument['entity_type'], $bundle);
143
        }, array_keys($argument['bundles'])));
144
      }
145
    }
146
147
    return $types;
148
  }
149
150
  /**
151
   * Check if a pager is configured.
152
   *
153
   * @param \Drupal\views\Plugin\views\display\DisplayPluginInterface $display
154
   *   The display configuration.
155
   *
156
   * @return bool
157
   *   Flag indicating if the view is configured with a pager.
158
   */
159
  protected function isPaged(DisplayPluginInterface $display) {
160
    $pagerOptions = $display->getOption('pager');
161
    return isset($pagerOptions['type']) && in_array($pagerOptions['type'], [
162
        'full',
163
        'mini',
164
      ]);
165
  }
166
167
  /**
168
   * Returns a view display object.
169
   *
170
   * @param \Drupal\views\ViewEntityInterface $view
171
   *   The view object.
172
   * @param string $displayId
173
   *   The display ID to use.
174
   *
175
   * @return \Drupal\views\Plugin\views\display\DisplayPluginInterface
176
   *   The view display object.
177
   */
178
  protected function getViewDisplay(ViewEntityInterface $view, $displayId) {
179
    $viewExecutable = $view->getExecutable();
180
    $viewExecutable->setDisplay($displayId);
181
    return $viewExecutable->getDisplay();
182
  }
183
184
  /**
185
   * Get the configured default limit.
186
   *
187
   * @param \Drupal\views\Plugin\views\display\DisplayPluginInterface $display
188
   *   The display configuration.
189
   *
190
   * @return int
191
   *   The default limit.
192
   */
193 View Code Duplication
  protected function getPagerLimit(DisplayPluginInterface $display) {
194
    $pagerOptions = $display->getOption('pager');
195
    return NestedArray::getValue($pagerOptions, [
196
      'options',
197
      'items_per_page',
198
    ]) ?: 0;
199
  }
200
201
  /**
202
   * Get the configured default offset.
203
   *
204
   * @param \Drupal\views\Plugin\views\display\DisplayPluginInterface $display
205
   *   The display configuration.
206
   *
207
   * @return int
208
   *   The default offset.
209
   */
210 View Code Duplication
  protected function getPagerOffset(DisplayPluginInterface $display) {
211
    $pagerOptions = $display->getOption('pager');
212
    return NestedArray::getValue($pagerOptions, [
213
      'options',
214
      'offset',
215
    ]) ?: 0;
216
  }
217
218
  /**
219
   * Check if a certain interface exists.
220
   *
221
   * @param string $interface
222
   *   The GraphQL interface name.
223
   * @param \Drupal\Component\Plugin\PluginManagerInterface $interfacePluginManager
224
   *   Plugin interface manager.
225
   *
226
   * @return bool
227
   *   Boolean flag indicating if the interface exists.
228
   */
229
  protected function interfaceExists($interface, PluginManagerInterface $interfacePluginManager) {
230
    return (bool) array_filter($interfacePluginManager->getDefinitions(), function ($definition) use ($interface) {
231
      return $definition['name'] === $interface;
232
    });
233
  }
234
235
  /**
236
   * Retrieves the type the view's rows resolve to.
237
   *
238
   * @param \Drupal\views\ViewEntityInterface $view
239
   *   The view entity.
240
   * @param string $displayId
241
   *   The id of the current display.
242
   * @param \Drupal\Component\Plugin\PluginManagerInterface $interfacePluginManager
243
   *   Interface plugin manager.
244
   *
245
   * @return null|string
246
   *   The name of the type or NULL if the type could not be derived.
247
   */
248
  protected function getRowResolveType(ViewEntityInterface $view, $displayId, PluginManagerInterface $interfacePluginManager) {
249
    /** @var \Drupal\graphql_views\Plugin\views\display\GraphQL $display */
250
    $display = $this->getViewDisplay($view, $displayId);
251
    $rowPlugin = $display->getPlugin('row');
252
253
    if ($rowPlugin instanceof GraphQLFieldRow) {
254
      return StringHelper::camelCase($display->getGraphQLRowName());
255
    }
256
257
    if ($rowPlugin instanceof GraphQLEntityRow) {
258
      $executable = $view->getExecutable();
259
      $executable->setDisplay($displayId);
260
261
      if ($entityType = $executable->getBaseEntityType()) {
262
        $typeName = $entityType->id();
263
        $typeNameCamel = StringHelper::camelCase($typeName);
264
        if ($this->interfaceExists($typeNameCamel, $interfacePluginManager)) {
265
          $filters = $executable->getDisplay()->getOption('filters');
266
          $dataTable = $entityType->getDataTable();
267
          $bundleKey = $entityType->getKey('bundle');
268
269
          foreach ($filters as $filter) {
270
            $isBundleFilter = $filter['table'] == $dataTable && $filter['field'] == $bundleKey;
271
            $isSingleValued = is_array($filter['value']) && count($filter['value']) == 1;
272
            $isExposed = isset($filter['exposed']) && $filter['exposed'];
273
            if ($isBundleFilter && $isSingleValued && !$isExposed) {
274
              $bundle = reset($filter['value']);
275
              $typeName .= "_$bundle";
276
              break;
277
            }
278
          }
279
280
          return StringHelper::camelCase($typeName);
281
        }
282
      }
283
284
      return 'Entity';
285
    }
286
287
    return NULL;
288
  }
289
290
  /**
291
   * Returns a view style object.
292
   *
293
   * @param \Drupal\views\ViewEntityInterface $view
294
   *   The view object.
295
   * @param string $displayId
296
   *   The display ID to use.
297
   *
298
   * @return \Drupal\views\Plugin\views\style\StylePluginBase
299
   *   The view style object.
300
   */
301
  protected function getViewStyle(ViewEntityInterface $view, $displayId) {
302
    $viewExecutable = $view->getExecutable();
303
    $viewExecutable->setDisplay($displayId);
304
    return $viewExecutable->getStyle();
305
  }
306
307
  /**
308
   * Returns cache metadata plugin definitions.
309
   *
310
   * @param \Drupal\views\ViewEntityInterface $view
311
   *   The view object.
312
   * @param \Drupal\views\Plugin\views\display\DisplayPluginInterface $display
313
   *   The view display.
314
   *
315
   * @return array
316
   *   The cache metadata definitions for the plugin definition.
317
   */
318
  protected function getCacheMetadataDefinition(ViewEntityInterface $view, DisplayPluginInterface $display) {
319
    $metadata = $display->getCacheMetadata()
320
      ->addCacheTags($view->getCacheTags())
321
      ->addCacheContexts($view->getCacheContexts())
322
      ->mergeCacheMaxAge($view->getCacheMaxAge());
323
324
    return [
325
      'schema_cache_tags' => $metadata->getCacheTags(),
326
      'schema_cache_max_age' => $metadata->getCacheMaxAge(),
327
      'response_cache_contexts' => array_filter($metadata->getCacheContexts(), function ($context) {
328
        // Don't emit the url cache contexts.
329
        return $context !== 'url' && strpos($context, 'url.') !== 0;
330
      }),
331
    ];
332
  }
333
334
  /**
335
   * Returns information about view arguments (contextual filters).
336
   *
337
   * @param array $viewArguments
338
   *   The "arguments" option of a view display.
339
   *
340
   * @return array
341
   *   Arguments information keyed by the argument ID. Subsequent array keys:
342
   *     - index: argument index.
343
   *     - entity_type: target entity type.
344
   *     - bundles: target bundles (can be empty).
345
   *
346
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
347
   */
348
  protected function getArgumentsInfo(array $viewArguments) {
349
    $argumentsInfo = [];
350
    /* @var \Drupal\Core\Entity\EntityTypeManager $entityTypeManager */
351
    $entityTypeManager = \Drupal::service('entity_type.manager');
352
353
    $index = 0;
354
    foreach ($viewArguments as $argumentId => $argument) {
355
      $info = [
356
        'index' => $index,
357
        'entity_type' => NULL,
358
        'bundles' => [],
359
      ];
360
361
      if (isset($argument['entity_type']) && isset($argument['entity_field'])) {
362
        $entityType = $entityTypeManager->getDefinition($argument['entity_type']);
363
        if ($entityType) {
364
          $idField = $entityType->getKey('id');
365
          if ($idField === $argument['entity_field']) {
366
            $info['entity_type'] = $argument['entity_type'];
367
            if (
368
              $argument['specify_validation'] &&
369
              strpos($argument['validate']['type'], 'entity:') === 0 &&
370
              !empty($argument['validate_options']['bundles'])
371
            ) {
372
              $info['bundles'] = $argument['validate_options']['bundles'];
373
            }
374
          }
375
        }
376
      }
377
378
      $argumentsInfo[$argumentId] = $info;
379
      $index++;
380
    }
381
382
    return $argumentsInfo;
383
  }
384
385
}
386