Including security review as a submodule - with patched for Yaffs.
[yaffs-website] / web / modules / contrib / security_review / src / Checks / Field.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\security_review\Checks\Field.
6  */
7
8 namespace Drupal\security_review\Checks;
9
10 use Drupal\Core\Entity\Entity;
11 use Drupal\Core\Entity\FieldableEntityInterface;
12 use Drupal\Core\TypedData\TypedDataInterface;
13 use Drupal\security_review\Check;
14 use Drupal\security_review\CheckResult;
15 use Drupal\text\Plugin\Field\FieldType\TextItemBase;
16
17 /**
18  * Checks for Javascript and PHP in submitted content.
19  */
20 class Field extends Check {
21
22   /**
23    * {@inheritdoc}
24    */
25   public function getNamespace() {
26     return 'Security Review';
27   }
28
29   /**
30    * {@inheritdoc}
31    */
32   public function getTitle() {
33     return 'Content';
34   }
35
36   /**
37    * {@inheritdoc}
38    */
39   public function getMachineTitle() {
40     return 'field';
41   }
42
43   /**
44    * {@inheritdoc}
45    */
46   public function run() {
47     $result = CheckResult::SUCCESS;
48     $findings = [];
49
50     $tags = [
51       'Javascript' => 'script',
52       'PHP' => '?php',
53     ];
54
55     // Load all of the entities.
56     $entities = [];
57     $bundle_info = $this->entityManager()->getAllBundleInfo();
58     foreach ($bundle_info as $entity_type_id => $bundles) {
59       $current = $this->entityManager()
60         ->getStorage($entity_type_id)
61         ->loadMultiple();
62       $entities = array_merge($entities, $current);
63     }
64
65     // Search for text fields.
66     $text_items = [];
67     foreach ($entities as $entity) {
68       if ($entity instanceof FieldableEntityInterface) {
69         /** @var FieldableEntityInterface $entity */
70         foreach ($entity->getFields() as $field_list) {
71           foreach ($field_list as $field_item) {
72             if ($field_item instanceof TextItemBase) {
73               /** @var TextItemBase $item */
74               // Text field found.
75               $text_items[] = $field_item;
76             }
77           }
78         }
79       }
80     }
81
82     // Scan the text items for vulnerabilities.
83     foreach ($text_items as $item) {
84       $entity = $item->getEntity();
85       foreach ($item->getProperties() as $property) {
86         /** @var TypedDataInterface $property */
87         $value = $property->getValue();
88         if (is_string($value)) {
89           $field_name = $item->getFieldDefinition()->getLabel();
90           foreach ($tags as $vulnerability => $tag) {
91             if (strpos($value, '<' . $tag) !== FALSE) {
92               // Vulnerability found.
93               $findings[$entity->getEntityTypeId()][$entity->id()][$field_name][] = $vulnerability;
94             }
95           }
96         }
97       }
98     }
99
100     if (!empty($findings)) {
101       $result = CheckResult::FAIL;
102     }
103
104     return $this->createResult($result, $findings);
105   }
106
107   /**
108    * {@inheritdoc}
109    */
110   public function help() {
111     $paragraphs = [];
112     $paragraphs[] = $this->t('Script and PHP code in content does not align with Drupal best practices and may be a vulnerability if an untrusted user is allowed to edit such content. It is recommended you remove such contents.');
113
114     return [
115       '#theme' => 'check_help',
116       '#title' => $this->t('Dangerous tags in content'),
117       '#paragraphs' => $paragraphs,
118     ];
119   }
120
121   /**
122    * {@inheritdoc}
123    */
124   public function evaluate(CheckResult $result) {
125     $findings = $result->findings();
126     if (empty($findings)) {
127       return [];
128     }
129
130     $paragraphs = [];
131     $paragraphs[] = $this->t('The following items potentially have dangerous tags.');
132
133     $items = [];
134     foreach ($findings as $entity_type_id => $entities) {
135       foreach ($entities as $entity_id => $fields) {
136         $entity = $this->entityManager()
137           ->getStorage($entity_type_id)
138           ->load($entity_id);
139
140         foreach ($fields as $field => $finding) {
141           $url = $entity->toUrl('edit-form')->toString();
142           if ($url === NULL) {
143             $url = $entity->toUrl()->toString();
144           }
145           $items[] = $this->t(
146             '@vulnerabilities found in <em>@field</em> field of <a href=":url">@label</a>',
147             [
148               '@vulnerabilities' => implode(' and ', $finding),
149               '@field' => $field,
150               '@label' => $entity->label(),
151               ':url' => $url,
152             ]
153           );
154         }
155       }
156     }
157
158     return [
159       '#theme' => 'check_evaluation',
160       '#paragraphs' => $paragraphs,
161       '#items' => $items,
162     ];
163   }
164
165   /**
166    * {@inheritdoc}
167    */
168   public function evaluatePlain(CheckResult $result) {
169     $findings = $result->findings();
170     if (empty($findings)) {
171       return '';
172     }
173
174     $output = '';
175     foreach ($findings as $entity_type_id => $entities) {
176       foreach ($entities as $entity_id => $fields) {
177         $entity = $this->entityManager()
178           ->getStorage($entity_type_id)
179           ->load($entity_id);
180
181         foreach ($fields as $field => $finding) {
182           $url = $entity->urlInfo('edit-form');
183           if ($url === NULL) {
184             $url = $entity->url();
185           }
186           $output .= "\t" . $this->t(
187               '@vulnerabilities in @field of :link',
188               [
189                 '@vulnerabilities' => implode(' and ', $finding),
190                 '@field' => $field,
191                 ':link' => $url->toString(),
192               ]
193             ) . "\n";
194         }
195       }
196     }
197
198     return $output;
199   }
200
201   /**
202    * {@inheritdoc}
203    */
204   public function getMessage($result_const) {
205     switch ($result_const) {
206       case CheckResult::SUCCESS:
207         return $this->t('Dangerous tags were not found in any submitted content (fields).');
208
209       case CheckResult::FAIL:
210         return $this->t('Dangerous tags were found in submitted content (fields).');
211
212       default:
213         return $this->t('Unexpected result.');
214     }
215   }
216
217 }