More updates to stop using dev or alpha or beta versions.
[yaffs-website] / web / modules / contrib / security_review / src / Checks / UploadExtensions.php
diff --git a/web/modules/contrib/security_review/src/Checks/UploadExtensions.php b/web/modules/contrib/security_review/src/Checks/UploadExtensions.php
new file mode 100644 (file)
index 0000000..8cfe5ad
--- /dev/null
@@ -0,0 +1,186 @@
+<?php
+
+namespace Drupal\security_review\Checks;
+
+use Drupal\Core\Link;
+use Drupal\Core\Url;
+use Drupal\field\Entity\FieldConfig;
+use Drupal\security_review\Check;
+use Drupal\security_review\CheckResult;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
+
+/**
+ * Checks for unsafe extensions in the allowed extensions settings of fields.
+ */
+class UploadExtensions extends Check {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getNamespace() {
+    return 'Security Review';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getTitle() {
+    return 'Allowed upload extensions';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMachineTitle() {
+    return 'upload_extensions';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function run() {
+    // If field is not enabled return with INFO.
+    if (!$this->moduleHandler()->moduleExists('field')) {
+      return $this->createResult(CheckResult::INFO);
+    }
+
+    $result = CheckResult::SUCCESS;
+    $findings = [];
+
+    // Check field configuration entities.
+    foreach (FieldConfig::loadMultiple() as $entity) {
+      /** @var FieldConfig $entity */
+      $extensions = $entity->getSetting('file_extensions');
+      if ($extensions != NULL) {
+        $extensions = explode(' ', $extensions);
+        $intersect = array_intersect($extensions, $this->security()->unsafeExtensions());
+        // $intersect holds the unsafe extensions this entity allows.
+        foreach ($intersect as $unsafe_extension) {
+          $findings[$entity->id()][] = $unsafe_extension;
+        }
+      }
+    }
+
+    if (!empty($findings)) {
+      $result = CheckResult::FAIL;
+    }
+
+    return $this->createResult($result, $findings);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function help() {
+    $paragraphs = [];
+    $paragraphs[] = $this->t(
+      'File and image fields allow for uploaded files. Some extensions are considered dangerous because the files can be evaluated and then executed in the browser. A malicious user could use this opening to gain control of your site. Review <a href=":url">all fields on your site</a>.',
+      [':url' => Url::fromRoute('entity.field_storage_config.collection')->toString()]
+    );
+
+    return [
+      '#theme' => 'check_help',
+      '#title' => 'Allowed upload extensions',
+      '#paragraphs' => $paragraphs,
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function evaluate(CheckResult $result) {
+    $findings = $result->findings();
+    if (empty($findings)) {
+      return [];
+    }
+
+    $paragraphs = [];
+    $paragraphs[] = $this->t('The following extensions are considered unsafe and should be removed or limited from use. Or, be sure you are not granting untrusted users the ability to upload files.');
+
+    $items = [];
+    foreach ($findings as $entity_id => $unsafe_extensions) {
+      $entity = FieldConfig::load($entity_id);
+      /** @var FieldConfig $entity */
+
+      foreach ($unsafe_extensions as $extension) {
+        $item = $this->t(
+          'Review @type in <em>@field</em> field on @bundle',
+          [
+            '@type' => $extension,
+            '@field' => $entity->label(),
+            '@bundle' => $entity->getTargetBundle(),
+          ]
+        );
+
+        // Try to get an edit url.
+        try {
+          $url_params = ['field_config' => $entity->id()];
+          if ($entity->getTargetEntityTypeId() == 'node') {
+            $url_params['node_type'] = $entity->getTargetBundle();
+          }
+          $items[] = Link::createFromRoute(
+            $item,
+            sprintf('entity.field_config.%s_field_edit_form', $entity->getTargetEntityTypeId()),
+            $url_params
+          );
+        }
+        catch (RouteNotFoundException $e) {
+          $items[] = $item;
+        }
+      }
+    }
+
+    return [
+      '#theme' => 'check_evaluation',
+      '#paragraphs' => $paragraphs,
+      '#items' => $items,
+    ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function evaluatePlain(CheckResult $result) {
+    $findings = $result->findings();
+    if (empty($findings)) {
+      return '';
+    }
+
+    $output = '';
+    foreach ($findings as $entity_id => $unsafe_extensions) {
+      $entity = FieldConfig::load($entity_id);
+      /** @var FieldConfig $entity */
+
+      $output .= $this->t(
+        '@bundle: field @field',
+        [
+          '@bundle' => $entity->getTargetBundle(),
+          '@field' => $entity->label(),
+        ]
+      );
+      $output .= "\n\t" . implode(', ', $unsafe_extensions) . "\n";
+    }
+
+    return $output;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getMessage($result_const) {
+    switch ($result_const) {
+      case CheckResult::SUCCESS:
+        return $this->t('Only safe extensions are allowed for uploaded files and images.');
+
+      case CheckResult::FAIL:
+        return $this->t('Unsafe file extensions are allowed in uploads.');
+
+      case CheckResult::INFO:
+        return $this->t('Module field is not enabled.');
+
+      default:
+        return $this->t('Unexpected result.');
+    }
+  }
+
+}