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