b41bc8554dc6551794b540d319851602f79cef24
[yaffs-website] / web / modules / contrib / security_review / src / Checks / Field.php
1 <?php
2
3 namespace Drupal\security_review\Checks;
4
5 use Drupal\Core\Entity\Entity;
6 use Drupal\Core\Entity\Exception\UndefinedLinkTemplateException;
7 use Drupal\field\Entity\FieldStorageConfig;
8 use Drupal\security_review\Check;
9 use Drupal\security_review\CheckResult;
10
11 /**
12  * Checks for Javascript and PHP in submitted content.
13  */
14 class Field extends Check {
15
16   /**
17    * {@inheritdoc}
18    */
19   public function getNamespace() {
20     return 'Security Review';
21   }
22
23   /**
24    * {@inheritdoc}
25    */
26   public function getTitle() {
27     return 'Content';
28   }
29
30   /**
31    * {@inheritdoc}
32    */
33   public function getMachineTitle() {
34     return 'field';
35   }
36
37   /**
38    * {@inheritdoc}
39    */
40   public function run() {
41     $result = CheckResult::SUCCESS;
42     $findings = [];
43
44     $field_types = [
45       'text_with_summary',
46       'text_long',
47     ];
48     $tags = [
49       'Javascript' => 'script',
50       'PHP' => '?php',
51     ];
52
53     /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
54     $entity_type_manager = \Drupal::service('entity_type.manager');
55     /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $field_manager */
56     $field_manager = \Drupal::service('entity_field.manager');
57     foreach ($field_manager->getFieldMap() as $entity_type_id => $fields) {
58       $field_storage_definitions = $field_manager->getFieldStorageDefinitions($entity_type_id);
59       foreach ($fields as $field_name => $field) {
60         if (!isset($field_storage_definitions[$field_name])) {
61           continue;
62         }
63         $field_storage_definition = $field_storage_definitions[$field_name];
64         if (in_array($field_storage_definition->getType(), $field_types)) {
65           if ($field_storage_definition instanceof FieldStorageConfig) {
66             $table = $entity_type_id . '__' . $field_name;
67             $separator = '_';
68             $id = 'entity_id';
69           }
70           else {
71             $table = $entity_type_id . '_field_data';
72             $separator = '__';
73             $id = $entity_type_manager->getDefinition($entity_type_id)->getKey('id');
74           }
75           $rows = \Drupal::database()->select($table, 't')
76             ->fields('t')
77             ->execute()
78             ->fetchAll();
79           foreach ($rows as $row) {
80             foreach (array_keys($field_storage_definition->getSchema()['columns']) as $column) {
81               $column_name = $field_name . $separator . $column;
82               foreach ($tags as $vulnerability => $tag) {
83                 if (strpos($row->{$column_name}, '<' . $tag) !== FALSE) {
84                   // Vulnerability found.
85                   $findings[$entity_type_id][$row->{$id}][$field_name][] = $vulnerability;
86                 }
87               }
88             }
89           }
90         }
91       }
92     }
93
94     if (!empty($findings)) {
95       $result = CheckResult::FAIL;
96     }
97
98     return $this->createResult($result, $findings);
99   }
100
101   /**
102    * {@inheritdoc}
103    */
104   public function help() {
105     $paragraphs = [];
106     $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.');
107
108     return [
109       '#theme' => 'check_help',
110       '#title' => $this->t('Dangerous tags in content'),
111       '#paragraphs' => $paragraphs,
112     ];
113   }
114
115   /**
116    * {@inheritdoc}
117    */
118   public function evaluate(CheckResult $result) {
119     $findings = $result->findings();
120     if (empty($findings)) {
121       return [];
122     }
123
124     $paragraphs = [];
125     $paragraphs[] = $this->t('The following items potentially have dangerous tags.');
126
127     $items = [];
128     foreach ($findings as $entity_type_id => $entities) {
129       foreach ($entities as $entity_id => $fields) {
130         $entity = $this->entityManager()
131           ->getStorage($entity_type_id)
132           ->load($entity_id);
133
134         foreach ($fields as $field => $finding) {
135           $items[] = $this->t(
136             '@vulnerabilities found in <em>@field</em> field of <a href=":url">@label</a>',
137             [
138               '@vulnerabilities' => implode(' and ', $finding),
139               '@field' => $field,
140               '@label' => $entity->label(),
141               ':url' => $this->getEntityLink($entity),
142             ]
143           );
144         }
145       }
146     }
147
148     return [
149       '#theme' => 'check_evaluation',
150       '#paragraphs' => $paragraphs,
151       '#items' => $items,
152     ];
153   }
154
155   /**
156    * Attempt to get a good link for the given entity.
157    *
158    * Falls back on a string with entity type id and id if no good link can
159    * be found.
160    *
161    * @param \Drupal\Core\Entity\Entity $entity
162    *   The entity.
163    *
164    * @return string
165    */
166   protected function getEntityLink(Entity $entity) {
167     try {
168       $url = $entity->toUrl('edit-form');
169     }
170     catch (UndefinedLinkTemplateException $e) {
171       $url = NULL;
172     }
173     if ($url === NULL) {
174       try {
175         $url = $entity->toUrl();
176       }
177       catch (UndefinedLinkTemplateException $e) {
178         $url = NULL;
179       }
180     }
181
182     return $url !== NULL ? $url->toString() : ($entity->getEntityTypeId() . ':' . $entity->id());
183   }
184
185   /**
186    * {@inheritdoc}
187    */
188   public function evaluatePlain(CheckResult $result) {
189     $findings = $result->findings();
190     if (empty($findings)) {
191       return '';
192     }
193
194     $output = '';
195     foreach ($findings as $entity_type_id => $entities) {
196       foreach ($entities as $entity_id => $fields) {
197         $entity = $this->entityManager()
198           ->getStorage($entity_type_id)
199           ->load($entity_id);
200
201         foreach ($fields as $field => $finding) {
202           $output .= "\t" . $this->t(
203               '@vulnerabilities in @field of :link',
204               [
205                 '@vulnerabilities' => implode(' and ', $finding),
206                 '@field' => $field,
207                 ':link' => $this->getEntityLink($entity),
208               ]
209             ) . "\n";
210         }
211       }
212     }
213
214     return $output;
215   }
216
217   /**
218    * {@inheritdoc}
219    */
220   public function getMessage($result_const) {
221     switch ($result_const) {
222       case CheckResult::SUCCESS:
223         return $this->t('Dangerous tags were not found in any submitted content (fields).');
224
225       case CheckResult::FAIL:
226         return $this->t('Dangerous tags were found in submitted content (fields).');
227
228       default:
229         return $this->t('Unexpected result.');
230     }
231   }
232
233 }