X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs-website;a=blobdiff_plain;f=web%2Fmodules%2Fcontrib%2Fsecurity_review%2Fsrc%2FCheck.php;fp=web%2Fmodules%2Fcontrib%2Fsecurity_review%2Fsrc%2FCheck.php;h=3b425cf5cb5bc1f48d99d2ce40a0acc748837499;hp=0000000000000000000000000000000000000000;hb=ba1b5c55c66590c41ccc9844d3e62391b0399abb;hpb=93ef30d42f68e55d11d97312531118bbcd4cf318 diff --git a/web/modules/contrib/security_review/src/Check.php b/web/modules/contrib/security_review/src/Check.php new file mode 100644 index 000000000..3b425cf5c --- /dev/null +++ b/web/modules/contrib/security_review/src/Check.php @@ -0,0 +1,551 @@ +container = \Drupal::getContainer(); + + $this->config = $this->configFactory() + ->getEditable('security_review.check.' . $this->id()); + $this->settings = new CheckSettings($this, $this->config); + $this->state = $this->container->get('state'); + $this->statePrefix = 'security_review.check.' . $this->id() . '.'; + + // Set check ID in config. + if ($this->config->get('id') != $this->id()) { + $this->config->set('id', $this->id()); + $this->config->save(); + } + } + + /** + * Returns the namespace of the check. + * + * Usually it's the same as the module's name. + * + * Naming rules (if overridden): + * - All characters should be lowerspace. + * - Use characters only from the english alphabet. + * - Don't use spaces (use "_" instead). + * + * @return string + * Machine namespace of the check. + */ + public function getMachineNamespace() { + $namespace = strtolower($this->getNamespace()); + $namespace = preg_replace("/[^a-z0-9 ]/", '', $namespace); + $namespace = str_replace(' ', '_', $namespace); + + return $namespace; + } + + /** + * Returns the namespace of the check. + * + * Usually it's the same as the module's name. + * + * @return string + * Human-readable namespace of the check. + */ + public abstract function getNamespace(); + + /** + * Returns the machine name of the check. + * + * Naming rules (if overridden): + * - All characters should be lowerspace. + * - Use characters only from the english alphabet. + * - Don't use spaces (use "_" instead). + * + * @return string + * ID of check. + */ + public function getMachineTitle() { + $title = strtolower($this->getTitle()); + $title = preg_replace("/[^a-z0-9 ]/", '', $title); + $title = str_replace(' ', '_', $title); + + return $title; + } + + /** + * Returns the human-readable title of the check. + * + * @return string + * Title of check. + */ + public abstract function getTitle(); + + /** + * Returns the identifier constructed using the namespace and title values. + * + * @return string + * Unique identifier of the check. + */ + public final function id() { + return $this->getMachineNamespace() . '-' . $this->getMachineTitle(); + } + + /** + * Returns whether the findings should be stored or reproduced when needed. + * + * The only case when this function should return false is if the check can + * generate a lot of findings (like the File permissions check for example). + * Turning this off for checks that don't generate findings at all or just a + * few of them actually means more overhead as the check has to be re-run + * in order to get its last result. + * + * @return bool + * Boolean indicating whether findings will be stored. + */ + public function storesFindings() { + return TRUE; + } + + /** + * Returns the check-specific settings' handler. + * + * @return \Drupal\security_review\CheckSettingsInterface + * The settings interface of the check. + */ + public function settings() { + return $this->settings; + } + + /** + * The actual procedure of carrying out the check. + * + * @return \Drupal\security_review\CheckResult + * The result of running the check. + */ + public abstract function run(); + + /** + * Same as run(), but used in CLI context such as Drush. + * + * @return \Drupal\security_review\CheckResult + * The result of running the check. + */ + public function runCli() { + return $this->run(); + } + + /** + * Returns the check-specific help page. + * + * @return array + * The render array of the check's help page. + */ + public abstract function help(); + + /** + * Returns the evaluation page of a result. + * + * Usually this is a list of the findings and an explanation. + * + * @param \Drupal\security_review\CheckResult $result + * The check result to evaluate. + * + * @return array + * The render array of the evaluation page. + */ + public function evaluate(CheckResult $result) { + return []; + } + + /** + * Evaluates a CheckResult and returns a plaintext output. + * + * @param \Drupal\security_review\CheckResult $result + * The check result to evaluate. + * + * @return string + * The evaluation string. + */ + public function evaluatePlain(CheckResult $result) { + return ''; + } + + /** + * Converts a result integer to a human-readable result message. + * + * @param int $result_const + * The result integer. + * + * @return string + * The human-readable result message. + */ + public abstract function getMessage($result_const); + + /** + * Returns the last stored result of the check. + * + * Returns null if no results have been stored yet. + * + * @param bool $get_findings + * Whether to get the findings too. + * + * @return \Drupal\security_review\CheckResult|null + * The last stored result (or null). + */ + public function lastResult($get_findings = FALSE) { + // Get stored data from State system. + $state_prefix = $this->statePrefix . 'last_result.'; + $result = $this->state->get($state_prefix . 'result'); + if ($get_findings) { + $findings = $this->state->get($state_prefix . 'findings'); + } + else { + $findings = []; + } + $time = $this->state->get($state_prefix . 'time'); + // Force boolean value. + $visible = $this->state->get($state_prefix . 'visible') == TRUE; + + // Check validity of stored data. + $valid_result = is_int($result) + && $result >= CheckResult::SUCCESS + && $result <= CheckResult::INFO; + $valid_findings = is_array($findings); + $valid_time = is_int($time) && $time > 0; + + // If invalid, return NULL. + if (!$valid_result || !$valid_findings || !$valid_time) { + return NULL; + } + + // Construct the CheckResult. + $last_result = new CheckResult($this, $result, $findings, $visible, $time); + + // Do a check run for acquiring findings if required. + if ($get_findings && !$this->storesFindings()) { + // Run the check to get the findings. + $fresh_result = $this->run(); + + // If it malfunctioned return the last known good result. + if (!($fresh_result instanceof CheckResult)) { + return $last_result; + } + + if ($fresh_result->result() != $last_result->result()) { + // If the result is not the same store the new result and return it. + $this->storeResult($fresh_result); + $this->securityReview()->logCheckResult($fresh_result); + return $fresh_result; + } + else { + // Else return the old result with the fresh one's findings. + return CheckResult::combine($last_result, $fresh_result); + } + } + + return $last_result; + } + + /** + * Returns the timestamp the check was last run. + * + * Returns 0 if it has not been run yet. + * + * @return int + * The timestamp of the last stored result. + */ + public function lastRun() { + $last_result_time = $this->state + ->get($this->statePrefix . 'last_result.time'); + + if (!is_int($last_result_time)) { + return 0; + } + return $last_result_time; + } + + /** + * Returns whether the check is skipped. Checks are not skipped by default. + * + * @return bool + * Boolean indicating whether the check is skipped. + */ + public function isSkipped() { + $is_skipped = $this->config->get('skipped'); + + if (!is_bool($is_skipped)) { + return FALSE; + } + return $is_skipped; + } + + /** + * Returns the user the check was skipped by. + * + * Returns null if it hasn't been skipped yet or the user that skipped the + * check is not valid anymore. + * + * @return \Drupal\user\Entity\User|null + * The user the check was last skipped by (or null). + */ + public function skippedBy() { + $skipped_by = $this->config->get('skipped_by'); + + if (!is_int($skipped_by)) { + return NULL; + } + return User::load($skipped_by); + } + + /** + * Returns the timestamp the check was last skipped on. + * + * Returns 0 if it hasn't been skipped yet. + * + * @return int + * The UNIX timestamp the check was last skipped on (or 0). + */ + public function skippedOn() { + $skipped_on = $this->config->get('skipped_on'); + + if (!is_int($skipped_on)) { + return 0; + } + return $skipped_on; + } + + /** + * Enables the check. Has no effect if the check was not skipped. + */ + public function enable() { + if ($this->isSkipped()) { + $this->config->set('skipped', FALSE); + $this->config->save(); + + // Log. + $context = ['@name' => $this->getTitle()]; + $this->securityReview()->log($this, '@name check no longer skipped', $context, RfcLogLevel::NOTICE); + } + } + + /** + * Marks the check as skipped. + * + * It still can be ran manually, but will remain skipped on the Run & Review + * page. + */ + public function skip() { + if (!$this->isSkipped()) { + // Store skip data. + $this->config->set('skipped', TRUE); + $this->config->set('skipped_by', $this->currentUser()->id()); + $this->config->set('skipped_on', time()); + $this->config->save(); + + // Log. + $context = ['@name' => $this->getTitle()]; + $this->securityReview()->log($this, '@name check skipped', $context, RfcLogLevel::NOTICE); + } + } + + /** + * Stores a result in the state system. + * + * @param \Drupal\security_review\CheckResult $result + * The result to store. + */ + public function storeResult(CheckResult $result) { + if ($result == NULL) { + $context = [ + '@reviewcheck' => $this->getTitle(), + '@namespace' => $this->getNamespace(), + ]; + $this->securityReview()->log($this, 'Unable to store check @reviewcheck for @namespace', $context, RfcLogLevel::CRITICAL); + return; + } + + $findings = $this->storesFindings() ? $result->findings() : []; + $this->state->setMultiple([ + $this->statePrefix . 'last_result.result' => $result->result(), + $this->statePrefix . 'last_result.time' => $result->time(), + $this->statePrefix . 'last_result.visible' => $result->isVisible(), + $this->statePrefix . 'last_result.findings' => $findings, + ]); + } + + /** + * Creates a new CheckResult for this Check. + * + * @param int $result + * The result integer (see the constants defined in CheckResult). + * @param array $findings + * The findings. + * @param bool $visible + * The visibility of the result. + * @param int $time + * The time the test was run. + * + * @return \Drupal\security_review\CheckResult + * The created CheckResult. + */ + public function createResult($result, array $findings = [], $visible = TRUE, $time = NULL) { + return new CheckResult($this, $result, $findings, $visible, $time); + } + + /** + * Returns the Security Review Checklist service. + * + * @return \Drupal\security_review\Checklist + * Security Review's Checklist service. + */ + protected function checklist() { + return $this->container->get('security_review.checklist'); + } + + /** + * Returns the Config factory. + * + * @return \Drupal\Core\Config\ConfigFactory + * Config factory. + */ + protected function configFactory() { + return $this->container->get('config.factory'); + } + + /** + * Returns the service container. + * + * @return \Symfony\Component\DependencyInjection\ContainerInterface + * Service container. + */ + protected function container() { + return $this->container; + } + + /** + * Returns the current Drupal user. + * + * @return \Drupal\Core\Session\AccountProxy + * Current Drupal user. + */ + protected function currentUser() { + return $this->container->get('current_user'); + } + + /** + * Returns the database connection. + * + * @return \Drupal\Core\Database\Connection + * Database connection. + */ + protected function database() { + return $this->container->get('database'); + } + + /** + * Returns the entity manager. + * + * @return \Drupal\Core\Entity\EntityManagerInterface + * Entity manager. + */ + protected function entityManager() { + return $this->container->get('entity.manager'); + } + + /** + * Returns the Drupal Kernel. + * + * @return \Drupal\Core\DrupalKernel + * Drupal Kernel. + */ + protected function kernel() { + return $this->container->get('kernel'); + } + + /** + * Returns the module handler. + * + * @return \Drupal\Core\Extension\ModuleHandler + * Module handler. + */ + protected function moduleHandler() { + return $this->container->get('module_handler'); + } + + /** + * Returns the Security Review Security service. + * + * @return \Drupal\security_review\Security + * Security Review's Security service. + */ + protected function security() { + return $this->container->get('security_review.security'); + } + + /** + * Returns the Security Review service. + * + * @return \Drupal\security_review\SecurityReview + * Security Review service. + */ + protected function securityReview() { + return $this->container->get('security_review'); + } + +}