Added the Porter Stemmer module to improve searches. This doesn't deal with some...
[yaffs-website] / web / modules / contrib / security_review / src / SecurityReview.php
1 <?php
2
3 namespace Drupal\security_review;
4
5 use Drupal\Core\Config\ConfigFactoryInterface;
6 use Drupal\Core\DependencyInjection\DependencySerializationTrait;
7 use Drupal\Core\Extension\ModuleHandlerInterface;
8 use Drupal\Core\Logger\RfcLogLevel;
9 use Drupal\Core\Session\AccountProxyInterface;
10 use Drupal\Core\State\StateInterface;
11
12 /**
13  * A class containing static methods regarding the module's configuration.
14  */
15 class SecurityReview {
16
17   use DependencySerializationTrait;
18
19   /**
20    * Temporary logging setting.
21    *
22    * @var null|bool
23    */
24   protected static $temporaryLogging = NULL;
25
26   /**
27    * The config factory.
28    *
29    * @var \Drupal\Core\Config\ConfigFactoryInterface
30    */
31   protected $configFactory;
32
33   /**
34    * The config storage.
35    *
36    * @var \Drupal\Core\Config\Config
37    */
38   protected $config;
39
40   /**
41    * The state storage.
42    *
43    * @var \Drupal\Core\State\StateInterface
44    */
45   protected $state;
46
47   /**
48    * The module handler.
49    *
50    * @var \Drupal\Core\Extension\ModuleHandlerInterface
51    */
52   protected $moduleHandler;
53
54   /**
55    * The current user.
56    *
57    * @var \Drupal\Core\Session\AccountProxyInterface
58    */
59   protected $currentUser;
60
61   /**
62    * Constructs a SecurityReview instance.
63    *
64    * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
65    *   The config factory.
66    * @param \Drupal\Core\State\StateInterface $state
67    *   The state storage.
68    * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
69    *   The module handler.
70    * @param \Drupal\Core\Session\AccountProxyInterface $current_user
71    *   The current user.
72    */
73   public function __construct(ConfigFactoryInterface $config_factory, StateInterface $state, ModuleHandlerInterface $module_handler, AccountProxyInterface $current_user) {
74     // Store the dependencies.
75     $this->configFactory = $config_factory;
76     $this->config = $config_factory->getEditable('security_review.settings');
77     $this->state = $state;
78     $this->moduleHandler = $module_handler;
79     $this->currentUser = $current_user;
80   }
81
82   /**
83    * Returns whether the module has been configured.
84    *
85    * If the module has been configured on the settings page this function
86    * returns true. Otherwise it returns false.
87    *
88    * @return bool
89    *   A boolean indicating whether the module has been configured.
90    */
91   public function isConfigured() {
92     return $this->config->get('configured') === TRUE;
93   }
94
95   /**
96    * Returns true if logging is enabled, otherwise returns false.
97    *
98    * @return bool
99    *   A boolean indicating whether logging is enabled.
100    */
101   public function isLogging() {
102     // Check for temporary logging.
103     if (static::$temporaryLogging !== NULL) {
104       return static::$temporaryLogging;
105     }
106
107     return $this->config->get('log') === TRUE;
108   }
109
110   /**
111    * Returns the last time Security Review has been run.
112    *
113    * @return int
114    *   The last time Security Review has been run.
115    */
116   public function getLastRun() {
117     return $this->state->get('last_run', 0);
118   }
119
120   /**
121    * Returns the IDs of the stored untrusted roles.
122    *
123    * @return string[]
124    *   Stored untrusted roles' IDs.
125    */
126   public function getUntrustedRoles() {
127     return $this->config->get('untrusted_roles');
128   }
129
130   /**
131    * Sets the 'configured' flag.
132    *
133    * @param bool $configured
134    *   The new value of the 'configured' setting.
135    */
136   public function setConfigured($configured) {
137     $this->config->set('configured', $configured);
138     $this->config->save();
139   }
140
141   /**
142    * Sets the 'logging' flag.
143    *
144    * @param bool $logging
145    *   The new value of the 'logging' setting.
146    * @param bool $temporary
147    *   Whether to set only temporarily.
148    */
149   public function setLogging($logging, $temporary = FALSE) {
150     if (!$temporary) {
151       $this->config->set('log', $logging);
152       $this->config->save();
153     }
154     else {
155       static::$temporaryLogging = ($logging == TRUE);
156     }
157   }
158
159   /**
160    * Sets the 'last_run' value.
161    *
162    * @param int $last_run
163    *   The new value for 'last_run'.
164    */
165   public function setLastRun($last_run) {
166     $this->state->set('last_run', $last_run);
167   }
168
169   /**
170    * Stores the given 'untrusted_roles' setting.
171    *
172    * @param string[] $untrusted_roles
173    *   The new untrusted roles' IDs.
174    */
175   public function setUntrustedRoles(array $untrusted_roles) {
176     $this->config->set('untrusted_roles', $untrusted_roles);
177     $this->config->save();
178   }
179
180   /**
181    * Logs an event.
182    *
183    * @param \Drupal\security_review\Check $check
184    *   The Check the message is about.
185    * @param string $message
186    *   The message.
187    * @param array $context
188    *   The context of the message.
189    * @param int $level
190    *   Severity (RfcLogLevel).
191    */
192   public function log(Check $check, $message, array $context, $level) {
193     if (static::isLogging()) {
194       $this->moduleHandler->invokeAll(
195         'security_review_log',
196         [
197           'check' => $check,
198           'message' => $message,
199           'context' => $context,
200           'level' => $level,
201         ]
202       );
203     }
204   }
205
206   /**
207    * Logs a check result.
208    *
209    * @param \Drupal\security_review\CheckResult $result
210    *   The result to log.
211    */
212   public function logCheckResult(CheckResult $result = NULL) {
213     if ($this->isLogging()) {
214       if ($result == NULL) {
215         $check = $result->check();
216         $context = [
217           '@check' => $check->getTitle(),
218           '@namespace' => $check->getNamespace(),
219         ];
220         $this->log($check, '@check of @namespace produced a null result', $context, RfcLogLevel::CRITICAL);
221         return;
222       }
223
224       $check = $result->check();
225
226       // Fallback log message.
227       $level = RfcLogLevel::NOTICE;
228       $message = '@name check invalid result';
229
230       // Set log message and level according to result.
231       switch ($result->result()) {
232         case CheckResult::SUCCESS:
233           $level = RfcLogLevel::INFO;
234           $message = '@name check succeeded';
235           break;
236
237         case CheckResult::FAIL:
238           $level = RfcLogLevel::ERROR;
239           $message = '@name check failed';
240           break;
241
242         case CheckResult::WARN:
243           $level = RfcLogLevel::WARNING;
244           $message = '@name check raised a warning';
245           break;
246
247         case CheckResult::INFO:
248           $level = RfcLogLevel::INFO;
249           $message = '@name check returned info';
250           break;
251       }
252
253       $context = ['@name' => $check->getTitle()];
254       $this->log($check, $message, $context, $level);
255     }
256   }
257
258   /**
259    * Deletes orphaned check data.
260    */
261   public function cleanStorage() {
262     /** @var \Drupal\security_review\Checklist $checklist */
263     $checklist = \Drupal::service('security_review.checklist');
264
265     // Get list of check configuration names.
266     $orphaned = $this->configFactory->listAll('security_review.check.');
267
268     // Remove items that are used by the checks.
269     foreach ($checklist->getChecks() as $check) {
270       $key = array_search('security_review.check.' . $check->id(), $orphaned);
271       if ($key !== FALSE) {
272         unset($orphaned[$key]);
273       }
274     }
275
276     // Delete orphaned configuration data.
277     foreach ($orphaned as $config_name) {
278       $config = $this->configFactory->getEditable($config_name);
279       $config->delete();
280     }
281   }
282
283   /**
284    * Stores information about the server into the State system.
285    */
286   public function setServerData() {
287     if (!static::isServerPosix() || PHP_SAPI === 'cli') {
288       return;
289     }
290     // Determine web server's uid and groups.
291     $uid = posix_getuid();
292     $groups = posix_getgroups();
293
294     // Store the data in the State system.
295     $this->state->set('security_review.server.uid', $uid);
296     $this->state->set('security_review.server.groups', $groups);
297   }
298
299   /**
300    * Returns whether the server is POSIX.
301    *
302    * @return bool
303    *   Whether the web server is POSIX based.
304    */
305   public function isServerPosix() {
306     return function_exists('posix_getuid');
307   }
308
309   /**
310    * Returns the UID of the web server.
311    *
312    * @return int
313    *   UID of the web server's user.
314    */
315   public function getServerUid() {
316     return $this->state->get('security_review.server.uid');
317   }
318
319   /**
320    * Returns the GIDs of the web server.
321    *
322    * @return int[]
323    *   GIDs of the web server's user.
324    */
325   public function getServerGids() {
326     return $this->state->get('security_review.server.groups');
327   }
328
329 }