More updates to stop using dev or alpha or beta versions.
[yaffs-website] / web / modules / contrib / security_review / src / Checks / InputFormats.php
1 <?php
2
3 namespace Drupal\security_review\Checks;
4
5 use Drupal\Core\Link;
6 use Drupal\Core\Url;
7 use Drupal\security_review\Check;
8 use Drupal\security_review\CheckResult;
9
10 /**
11  * Checks for vulnerabilities related to input formats.
12  *
13  * Checks for formats that either do not have HTML filter that can be used by
14  * untrusted users, or if they do check if unsafe tags are allowed.
15  */
16 class InputFormats extends Check {
17
18   /**
19    * {@inheritdoc}
20    */
21   public function getNamespace() {
22     return 'Security Review';
23   }
24
25   /**
26    * {@inheritdoc}
27    */
28   public function getTitle() {
29     return 'Text formats';
30   }
31
32   /**
33    * {@inheritdoc}
34    */
35   public function getMachineTitle() {
36     return 'input_formats';
37   }
38
39   /**
40    * {@inheritdoc}
41    */
42   public function run() {
43     // If filter is not enabled return with INFO.
44     if (!$this->moduleHandler()->moduleExists('filter')) {
45       return $this->createResult(CheckResult::INFO);
46     }
47
48     $result = CheckResult::SUCCESS;
49     $findings = [];
50
51     $formats = filter_formats();
52     $untrusted_roles = $this->security()->untrustedRoles();
53     $unsafe_tags = $this->security()->unsafeTags();
54
55     foreach ($formats as $format) {
56       $format_roles = array_keys(filter_get_roles_by_format($format));
57       $intersect = array_intersect($format_roles, $untrusted_roles);
58
59       if (!empty($intersect)) {
60         // Untrusted users can use this format.
61         // Check format for enabled HTML filter.
62         $filter_html_enabled = FALSE;
63         if ($format->filters()->has('filter_html')) {
64           $filter_html_enabled = $format->filters('filter_html')
65             ->getConfiguration()['status'];
66         }
67         $filter_html_escape_enabled = FALSE;
68         if ($format->filters()->has('filter_html_escape')) {
69           $filter_html_escape_enabled = $format->filters('filter_html_escape')
70             ->getConfiguration()['status'];
71         }
72
73         if ($filter_html_enabled) {
74           $filter = $format->filters('filter_html');
75
76           // Check for unsafe tags in allowed tags.
77           $allowed_tags = array_keys($filter->getHTMLRestrictions()['allowed']);
78           foreach (array_intersect($allowed_tags, $unsafe_tags) as $tag) {
79             // Found an unsafe tag.
80             $findings['tags'][$format->id()] = $tag;
81           }
82         }
83         elseif (!$filter_html_escape_enabled) {
84           // Format is usable by untrusted users but does not contain the HTML
85           // Filter or the HTML escape.
86           $findings['formats'][$format->id()] = $format->label();
87         }
88       }
89     }
90
91     if (!empty($findings)) {
92       $result = CheckResult::FAIL;
93     }
94     return $this->createResult($result, $findings);
95   }
96
97   /**
98    * {@inheritdoc}
99    */
100   public function help() {
101     $paragraphs = [];
102     $paragraphs[] = $this->t("Certain HTML tags can allow an attacker to take control of your site. Drupal's input format system makes use of a set filters to run on incoming text. The 'HTML Filter' strips out harmful tags and Javascript events and should be used on all formats accessible by untrusted users.");
103     $paragraphs[] = new Link(
104       $this->t("Read more about Drupal's input formats in the handbooks."),
105       Url::fromUri('http://drupal.org/node/224921')
106     );
107
108     return [
109       '#theme' => 'check_help',
110       '#title' => $this->t('Allowed HTML tags in text formats'),
111       '#paragraphs' => $paragraphs,
112     ];
113   }
114
115   /**
116    * {@inheritdoc}
117    */
118   public function evaluate(CheckResult $result) {
119     $output = [];
120
121     if (!empty($result->findings()['tags'])) {
122       $paragraphs = [];
123       $paragraphs[] = Link::createFromRoute(
124         $this->t('Review your text formats.'),
125         'filter.admin_overview'
126       );
127       $paragraphs[] = $this->t('It is recommended you remove the following tags from roles accessible by untrusted users.');
128       $output[] = [
129         '#theme' => 'check_evaluation',
130         '#paragraphs' => $paragraphs,
131         '#items' => $result->findings()['tags'],
132       ];
133     }
134
135     if (!empty($result->findings()['formats'])) {
136       $paragraphs = [];
137       $paragraphs[] = $this->t('The following formats are usable by untrusted roles and do not filter or escape allowed HTML tags.');
138       $output[] = [
139         '#theme' => 'check_evaluation',
140         '#paragraphs' => $paragraphs,
141         '#items' => $result->findings()['formats'],
142       ];
143     }
144
145     return $output;
146   }
147
148   /**
149    * {@inheritdoc}
150    */
151   public function evaluatePlain(CheckResult $result) {
152     $output = '';
153
154     if (!empty($result->findings()['tags'])) {
155       $output .= $this->t('Tags') . "\n";
156       foreach ($result->findings()['tags'] as $tag) {
157         $output .= "\t$tag\n";
158       }
159     }
160
161     if (!empty($result->findings()['formats'])) {
162       $output .= $this->t('Formats') . "\n";
163       foreach ($result->findings()['formats'] as $format) {
164         $output .= "\t$format\n";
165       }
166     }
167
168     return $output;
169   }
170
171   /**
172    * {@inheritdoc}
173    */
174   public function getMessage($result_const) {
175     switch ($result_const) {
176       case CheckResult::SUCCESS:
177         return $this->t('Untrusted users are not allowed to input dangerous HTML tags.');
178
179       case CheckResult::FAIL:
180         return $this->t('Untrusted users are allowed to input dangerous HTML tags.');
181
182       case CheckResult::INFO:
183         return $this->t('Module filter is not enabled.');
184
185       default:
186         return $this->t('Unexpected result.');
187     }
188   }
189
190 }