Including security review as a submodule - with patched for Yaffs.
[yaffs-website] / web / modules / contrib / security_review / src / Checklist.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\security_review\Checklist.
6  */
7
8 namespace Drupal\security_review;
9
10 use Drupal\Core\Access\AccessException;
11 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
12 use Drupal\Core\Extension\ModuleHandlerInterface;
13 use Drupal\Core\Session\AccountProxyInterface;
14
15 /**
16  * Contains static functions for handling checks throughout every module.
17  */
18 class Checklist {
19
20   use DependencySerializationTrait;
21
22   /**
23    * The current user.
24    *
25    * @var \Drupal\Core\Session\AccountProxyInterface
26    */
27   protected $currentUser;
28
29   /**
30    * The security_review service.
31    *
32    * @var \Drupal\security_review\SecurityReview
33    */
34   protected $securityReview;
35
36   /**
37    * The module handler.
38    *
39    * @var \Drupal\Core\Extension\ModuleHandlerInterface
40    */
41   protected $moduleHandler;
42
43   /**
44    * Constructs a Checklist instance.
45    *
46    * @param \Drupal\security_review\SecurityReview $security_review
47    *   The SecurityReview service.
48    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
49    *   The module handler.
50    * @param \Drupal\Core\Session\AccountProxyInterface $current_user
51    *   The current user.
52    */
53   public function __construct(SecurityReview $security_review, ModuleHandlerInterface $module_handler, AccountProxyInterface $current_user) {
54     $this->securityReview = $security_review;
55     $this->moduleHandler = $module_handler;
56     $this->currentUser = $current_user;
57   }
58
59   /**
60    * Array of cached Checks.
61    *
62    * @var \Drupal\security_review\Check[]
63    */
64   private static $cachedChecks = [];
65
66   /**
67    * Clears the cached checks.
68    */
69   public static function clearCache() {
70     static::$cachedChecks = [];
71   }
72
73   /**
74    * Returns every Check.
75    *
76    * @return \Drupal\security_review\Check[]
77    *   Array of Checks.
78    */
79   public function getChecks() {
80     $checks = &static::$cachedChecks;
81     if (!empty($checks)) {
82       return $checks;
83     }
84
85     // Get checks.
86     $raw_checks = $this->moduleHandler->invokeAll('security_review_checks');
87
88     // Filter invalid checks.
89     $checks = [];
90     foreach ($raw_checks as $raw_check) {
91       if ($raw_check instanceof Check) {
92         $checks[] = $raw_check;
93       }
94     }
95
96     // Sort the checks.
97     usort($checks, [$this, 'compareChecks']);
98
99     return $checks;
100   }
101
102   /**
103    * Returns the enabled Checks.
104    *
105    * @return \Drupal\security_review\Check[]
106    *   Array of enabled Checks.
107    */
108   public function getEnabledChecks() {
109     $enabled = [];
110
111     foreach (static::getChecks() as $check) {
112       if (!$check->isSkipped()) {
113         $enabled[] = $check;
114       }
115     }
116
117     return $enabled;
118   }
119
120   /**
121    * Groups an array of checks by their namespaces.
122    *
123    * @param \Drupal\security_review\Check[] $checks
124    *   The array of Checks to group.
125    *
126    * @return array
127    *   Array containing Checks grouped by their namespaces.
128    */
129   public function groupChecksByNamespace(array $checks) {
130     $output = [];
131
132     foreach ($checks as $check) {
133       $output[$check->getMachineNamespace()][] = $check;
134     }
135
136     return $output;
137   }
138
139   /**
140    * Runs enabled checks and stores their results.
141    */
142   public function runChecklist() {
143     if ($this->currentUser->hasPermission('run security checks')) {
144       $checks = $this->getEnabledChecks();
145       $results = $this->runChecks($checks);
146       $this->storeResults($results);
147       $this->securityReview->setLastRun(time());
148     }
149     else {
150       throw new AccessException();
151     }
152   }
153
154   /**
155    * Runs an array of checks.
156    *
157    * @param \Drupal\security_review\Check[] $checks
158    *   The array of Checks to run.
159    * @param bool $cli
160    *   Whether to call runCli() instead of run().
161    *
162    * @return \Drupal\security_review\CheckResult[]
163    *   The array of CheckResults generated.
164    */
165   public function runChecks(array $checks, $cli = FALSE) {
166     $results = [];
167
168     foreach ($checks as $check) {
169       if ($cli) {
170         $result = $check->runCli();
171       }
172       else {
173         $result = $check->run();
174       }
175       $this->securityReview->logCheckResult($result);
176       $results[] = $result;
177     }
178
179     return $results;
180   }
181
182   /**
183    * Stores an array of CheckResults.
184    *
185    * @param \Drupal\security_review\CheckResult[] $results
186    *   The CheckResults to store.
187    */
188   public function storeResults(array $results) {
189     foreach ($results as $result) {
190       $result->check()->storeResult($result);
191     }
192   }
193
194   /**
195    * Finds a check by its namespace and title.
196    *
197    * @param string $namespace
198    *   The machine namespace of the requested check.
199    * @param string $title
200    *   The machine title of the requested check.
201    *
202    * @return null|\Drupal\security_review\Check
203    *   The Check or null if it doesn't exist.
204    */
205   public function getCheck($namespace, $title) {
206     foreach (static::getChecks() as $check) {
207       $same_namespace = $check->getMachineNamespace() == $namespace;
208       $same_title = $check->getMachineTitle() == $title;
209       if ($same_namespace && $same_title) {
210         return $check;
211       }
212     }
213
214     return NULL;
215   }
216
217   /**
218    * Finds a Check by its id.
219    *
220    * @param string $id
221    *   The machine namespace of the requested check.
222    *
223    * @return null|\Drupal\security_review\Check
224    *   The Check or null if it doesn't exist.
225    */
226   public function getCheckById($id) {
227     foreach (static::getChecks() as $check) {
228       if ($check->id() == $id) {
229         return $check;
230       }
231     }
232
233     return NULL;
234   }
235
236   /**
237    * Helper function for sorting checks.
238    *
239    * @param \Drupal\security_review\Check $a
240    *   Check A.
241    * @param \Drupal\security_review\Check $b
242    *   Check B.
243    *
244    * @return int
245    *   The comparison's result.
246    */
247   public function compareChecks(Check $a, Check $b) {
248     // If one comes from security_review and the other doesn't, prefer the one
249     // with the security_review namespace.
250     $a_is_local = $a->getMachineNamespace() == 'security_review';
251     $b_is_local = $b->getMachineNamespace() == 'security_review';
252     if ($a_is_local && !$b_is_local) {
253       return -1;
254     }
255     elseif (!$a_is_local && $b_is_local) {
256       return 1;
257     }
258     else {
259       if ($a->getNamespace() == $b->getNamespace()) {
260         // If the namespaces match, sort by title.
261         return strcmp($a->getTitle(), $b->getTitle());
262       }
263       else {
264         // If the namespaces don't mach, sort by namespace.
265         return strcmp($a->getNamespace(), $b->getNamespace());
266       }
267     }
268   }
269
270 }