5ba075772287328bd9953f3ceb16ce3b9eab3279
[yaffs-website] / web / modules / contrib / security_review / src / Form / SettingsForm.php
1 <?php
2
3 namespace Drupal\security_review\Form;
4
5 use Drupal\Core\Config\ConfigFactoryInterface;
6 use Drupal\Core\Datetime\DateFormatterInterface;
7 use Drupal\Core\Form\ConfigFormBase;
8 use Drupal\Core\Form\FormStateInterface;
9 use Drupal\Core\Session\AccountInterface;
10 use Drupal\security_review\Checklist;
11 use Drupal\security_review\Security;
12 use Drupal\security_review\SecurityReview;
13 use Symfony\Component\DependencyInjection\ContainerInterface;
14
15 /**
16  * Settings page for Security Review.
17  */
18 class SettingsForm extends ConfigFormBase {
19
20   /**
21    * The security_review.checklist service.
22    *
23    * @var \Drupal\security_review\Checklist
24    */
25   protected $checklist;
26
27   /**
28    * The security_review.security service.
29    *
30    * @var \Drupal\security_review\Security
31    */
32   protected $security;
33
34   /**
35    * The security_review service.
36    *
37    * @var \Drupal\security_review\SecurityReview
38    */
39   protected $securityReview;
40
41   /**
42    * The date.formatter service.
43    *
44    * @var \Drupal\Core\Datetime\DateFormatterInterface
45    */
46   private $dateFormatter;
47
48   /**
49    * Constructs a SettingsForm.
50    *
51    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
52    *   The config factory.
53    * @param \Drupal\security_review\Checklist $checklist
54    *   The security_review.checklist service.
55    * @param \Drupal\security_review\Security $security
56    *   The security_review.security service.
57    * @param \Drupal\security_review\SecurityReview $security_review
58    *   The security_review service.
59    * @param \Drupal\Core\Datetime\DateFormatterInterface $dateFormatter
60    *   The date.formatter service.
61    */
62   public function __construct(ConfigFactoryInterface $config_factory, Checklist $checklist, Security $security, SecurityReview $security_review, DateFormatterInterface $dateFormatter) {
63     parent::__construct($config_factory);
64     $this->checklist = $checklist;
65     $this->security = $security;
66     $this->securityReview = $security_review;
67     $this->dateFormatter = $dateFormatter;
68   }
69
70   /**
71    * {@inheritdoc}
72    */
73   public static function create(ContainerInterface $container) {
74     return new static(
75       $container->get('config.factory'),
76       $container->get('security_review.checklist'),
77       $container->get('security_review.security'),
78       $container->get('security_review'),
79       $container->get('date.formatter')
80     );
81   }
82
83   /**
84    * {@inheritdoc}
85    */
86   public function getFormId() {
87     return 'security-review-settings';
88   }
89
90   /**
91    * {@inheritdoc}
92    */
93   public function buildForm(array $form, FormStateInterface $form_state) {
94     // Get the list of checks.
95     $checks = $this->checklist->getChecks();
96
97     // Get the user roles.
98     $roles = user_roles();
99     $options = [];
100     foreach ($roles as $rid => $role) {
101       $options[$rid] = $role->label();
102     }
103
104     // Notify the user if anonymous users can create accounts.
105     $message = '';
106     if (in_array(AccountInterface::AUTHENTICATED_ROLE, $this->security->defaultUntrustedRoles())) {
107       $message = $this->t('You have allowed anonymous users to create accounts without approval so the authenticated role defaults to untrusted.');
108     }
109
110     // Show the untrusted roles form element.
111     $form['untrusted_roles'] = [
112       '#type' => 'checkboxes',
113       '#title' => $this->t('Untrusted roles'),
114       '#description' => $this->t(
115         'Define which roles are for less trusted users. The anonymous role defaults to untrusted. @message Most Security Review checks look for resources usable by untrusted roles.',
116         ['@message' => $message]
117       ),
118       '#options' => $options,
119       '#default_value' => $this->security->untrustedRoles(),
120     ];
121
122     $form['advanced'] = [
123       '#type' => 'details',
124       '#title' => $this->t('Advanced'),
125       '#open' => TRUE,
126     ];
127
128     // Show the logging setting.
129     $form['advanced']['logging'] = [
130       '#type' => 'checkbox',
131       '#title' => $this->t('Log checklist results and skips'),
132       '#description' => $this->t('The result of each check and skip can be logged to watchdog for tracking.'),
133       '#default_value' => $this->securityReview->isLogging(),
134     ];
135
136     // Skipped checks.
137     $values = [];
138     $options = [];
139     foreach ($checks as $check) {
140       // Determine if check is being skipped.
141       if ($check->isSkipped()) {
142         $values[] = $check->id();
143         $label = $this->t(
144           '@name <em>skipped by UID @uid on @date</em>',
145           [
146             '@name' => $check->getTitle(),
147             '@uid' => $check->skippedBy()->id(),
148             '@date' => $this->dateFormatter->format($check->skippedOn()),
149           ]
150         );
151       }
152       else {
153         $label = $check->getTitle();
154       }
155       $options[$check->id()] = $label;
156     }
157     $form['advanced']['skip'] = [
158       '#type' => 'checkboxes',
159       '#title' => $this->t('Checks to skip'),
160       '#description' => $this->t('Skip running certain checks. This can also be set on the <em>Run & review</em> page. It is recommended that you do not skip any checks unless you know the result is wrong or the process times out while running.'),
161       '#options' => $options,
162       '#default_value' => $values,
163     ];
164
165     // Iterate through checklist and get check-specific setting pages.
166     foreach ($checks as $check) {
167       // Get the check's setting form.
168       $check_form = $check->settings()->buildForm();
169
170       // If not empty, add it to the form.
171       if (!empty($check_form)) {
172         // If this is the first non-empty setting page initialize the 'details'
173         if (!isset($form['advanced']['check_specific'])) {
174           $form['advanced']['check_specific'] = [
175             '#type' => 'details',
176             '#title' => $this->t('Check-specific settings'),
177             '#open' => FALSE,
178             '#tree' => TRUE,
179           ];
180         }
181
182         // Add the form.
183         $sub_form = &$form['advanced']['check_specific'][$check->id()];
184
185         $title = $check->getTitle();
186         // If it's an external check, show its namespace.
187         if ($check->getMachineNamespace() != 'security_review') {
188           $title .= $this->t('%namespace', [
189             '%namespace' => $check->getNamespace(),
190           ]);
191         }
192         $sub_form = [
193           '#type' => 'details',
194           '#title' => $title,
195           '#open' => TRUE,
196           '#tree' => TRUE,
197           'form' => $check_form,
198         ];
199       }
200     }
201
202     // Return the finished form.
203     return parent::buildForm($form, $form_state);
204   }
205
206   /**
207    * {@inheritdoc}
208    */
209   public function validateForm(array &$form, FormStateInterface $form_state) {
210     // Run validation for check-specific settings.
211     if (isset($form['advanced']['check_specific'])) {
212       $check_specific_values = $form_state->getValue('check_specific');
213       foreach ($this->checklist->getChecks() as $check) {
214         $check_form = &$form['advanced']['check_specific'][$check->id()];
215         if (isset($check_form)) {
216           $check->settings()
217             ->validateForm($check_form, $check_specific_values[$check->id()]);
218         }
219       }
220     }
221   }
222
223   /**
224    * {@inheritdoc}
225    */
226   public function submitForm(array &$form, FormStateInterface $form_state) {
227     // Frequently used configuration items.
228     $check_settings = $this->config('security_review.checks');
229
230     // Save that the module has been configured.
231     $this->securityReview->setConfigured(TRUE);
232
233     // Save the new untrusted roles.
234     $untrusted_roles = array_keys(array_filter($form_state->getValue('untrusted_roles')));
235     $this->securityReview->setUntrustedRoles($untrusted_roles);
236
237     // Save the new logging setting.
238     $logging = $form_state->getValue('logging') == 1;
239     $this->securityReview->setLogging($logging);
240
241     // Skip selected checks.
242     $skipped = array_keys(array_filter($form_state->getValue('skip')));
243     foreach ($this->checklist->getChecks() as $check) {
244       if (in_array($check->id(), $skipped)) {
245         $check->skip();
246       }
247       else {
248         $check->enable();
249       }
250     }
251
252     // Save the check-specific settings.
253     if (isset($form['advanced']['check_specific'])) {
254       $check_specific_values = $form_state->getValue('check_specific');
255       foreach ($check_specific_values as $id => $values) {
256         // Get corresponding Check.
257         $check = $this->checklist->getCheckById($id);
258
259         // Submit parameters.
260         $check_form = &$form['advanced']['check_specific'][$id]['form'];
261         $check_form_values = $check_specific_values[$id]['form'];
262
263         // Submit.
264         $check->settings()->submitForm($check_form, $check_form_values);
265       }
266     }
267
268     // Commit the settings.
269     $check_settings->save();
270
271     // Finish submitting the form.
272     parent::submitForm($form, $form_state);
273   }
274
275   /**
276    * {@inheritdoc}
277    */
278   protected function getEditableConfigNames() {
279     return ['security_review.checks'];
280   }
281
282 }