AutorÃa | Ultima modificación | Ver Log |
<?php// This file is part of Moodle - http://moodle.org///// Moodle is free software: you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// Moodle is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with Moodle. If not, see <http://www.gnu.org/licenses/>.namespace tool_brickfield;/*** Class registration contains the functions to manage registration validation.** @package tool_brickfield* @author 2021 Onwards Mike Churchward <mike@brickfieldlabs.ie>* @license http://www.gnu.org/copyleft/gpl.html GNU GPL*/class registration {/** @var int Registration information has not been entered. */const NOT_ENTERED = 0;/** @var int Registration information has been entered but not externally validated. */const PENDING = 1;/** @var int Registration information was entered but was not validated within the defined grace periods. */const INVALID = 2;/** @var int Registration information has been externally validated. */const VALIDATED = 3;/** @var int Registration information has expired and needs to be revalidated. */const EXPIRED = 4;/** @var int Registration validation attempted, but failed. */const ERROR = 5;/** @var string Name of variable storing the registration status. */const STATUS = 'bfregstatus';/** @var string Name of variable storing the last time the registration information was checked. */const VALIDATION_CHECK_TIME = 'bfregvalidationchecktime';/** @var string Name of variable storing the time the registration information was validated. */const VALIDATION_TIME = 'bfregvalidationtime';/** @var string Name of variable storing the time the summary data was last sent. */const SUMMARY_TIME = 'bfsummarytime';/** @var string Name of variable storing the registration API key. */const API_KEY = 'key';/** @var string Name of variable storing the registration API key. */const SECRET_KEY = 'hash';/** @var string Name of the variable storing the site id. */const SITEID = 'id';/** @var int The current validation status. */protected $validation;/** @var int The last time the validation was checked. */protected $checktime;/** @var int The last time the validation time was confirmed. */protected $validationtime;/** @var int The last time the summary data was sent. */protected $summarytime;/** @var string The API key required for registration. */protected $apikey;/** @var string The secret key required for registration. */protected $secretkey;/** @var string The registered site id. */protected $siteid;/** @var string The URL to register at. */private static $regurl = 'https://account.mybrickfield.ie/register';/** @var string The URL to view terms at. */private static $termsurl = 'https://account.mybrickfield.ie/terms';/*** Object registration constructor.* @throws \dml_exception*/public function __construct() {$this->validation = $this->get_status();$this->checktime = $this->get_check_time();$this->validationtime = $this->get_validation_time();$this->summarytime = $this->get_summary_time();$this->apikey = $this->get_api_key();$this->secretkey = $this->get_secret_key();$this->siteid = $this->get_siteid();}/*** System can be used when it has been validated, or when its still awaiting validation.* @return bool*/public function toolkit_is_active(): bool {return $this->status_is_validated() || $this->validation_pending();}/*** The "not validated" state also needs the grace period to still be in effect.* @return bool*/public function validation_pending(): bool {return ($this->status_is_pending() || $this->status_is_error()) && $this->grace_period_valid();}/*** Return true if there was a validation error.* @return bool*/public function validation_error(): bool {return $this->status_is_error();}/*** Perform all necessary steps when new keys are added. Also check that they actually look like keys.* @param string $apikey* @param string $secretkey* @return bool*/public function set_keys_for_registration(string $apikey, string $secretkey): bool {if ($this->keys_are_valid($apikey, $secretkey)) {$this->set_api_key($apikey);$this->set_secret_key($secretkey);$this->set_not_validated();if ($this->summarytime <= 0) {$this->set_summary_time();}return true;} else {$this->set_api_key('');$this->set_secret_key('');$this->set_not_entered();return false;}}/*** If the registration is not already valid, validate it. This may connect to the registration site.* @return bool* @throws \dml_exception*/public function validate(): bool {// If this is currently valid, return true, unless its time to check again.if ($this->status_is_validated()) {// If the summary data has not been sent in over a week, invalidate the registration.if ($this->summarydata_grace_period_expired()) {$this->set_invalid();return false;}// Confirm registration after the grace period has expired.if ($this->grace_period_valid()) {return true;} else {// Recheck the registration.return $this->revalidate();}}// Check for valid keys, and possibly move status to validation stage.if (!$this->keys_are_valid()) {// The current stored keys are not valid format, set the status to "not entered".$this->set_not_entered();return false;} else if ($this->status_is_not_entered()) {// If no keys have previously been seen, move to validation stage.$this->set_not_validated();}// If no validation has been confirmed, check the registration site.if ($this->validation_pending()) {$brickfieldconnect = $this->get_registration_connection();$this->set_check_time();if ($brickfieldconnect->is_registered() || $brickfieldconnect->update_registration($this->apikey, $this->secretkey)) {// Keys are present and have been validated.$this->set_valid();return true;} else {// Keys are present but were not validated.$this->set_error();}}// If any of the grace periods have passed without a validation, invalidate the registration.if (!$this->grace_period_valid() || $this->summarydata_grace_period_expired()) {$this->set_invalid();return false;} else {return true;}}/*** Even if the regisration is currently valid, validate it again.* @return bool* @throws \dml_exception*/public function revalidate(): bool {if ($this->status_is_validated()) {$this->set_not_validated();}return $this->validate();}/*** Get api key.* @return string* @throws \dml_exception*/public function get_api_key(): string {$key = get_config(manager::PLUGINNAME, self::API_KEY);if ($key === false) {// Not set in config yet, so default it to "".$key = '';$this->set_api_key($key);}return $key;}/*** Get secret key.* @return string* @throws \dml_exception*/public function get_secret_key(): string {$key = get_config(manager::PLUGINNAME, self::SECRET_KEY);if ($key === false) {// Not set in config yet, so default it to "".$key = '';$this->set_secret_key($key);}return $key;}/*** Get the registration URL.* @return string*/public function get_regurl(): string {return self::$regurl;}/*** Get the terms and conditions URL.* @return string*/public function get_termsurl(): string {return self::$termsurl;}/*** Perform all actions needed to note that the summary data was sent.*/public function mark_summary_data_sent() {$this->set_summary_time();}/*** Set the registered site id.* @param int $id* @return bool*/public function set_siteid(int $id): bool {$this->siteid = $id;return set_config(self::SITEID, $id, manager::PLUGINNAME);}/*** Return the registered site id.* @return int* @throws \dml_exception*/public function get_siteid(): int {$siteid = get_config(manager::PLUGINNAME, self::SITEID);if ($siteid === false) {// Not set in config yet, so default it to 0.$siteid = 0;$this->set_siteid($siteid);}return (int)$siteid;}/*** Set the status as keys "not entered".* @return bool*/protected function set_not_entered(): bool {return $this->set_status(self::NOT_ENTERED);}/*** "Not validated" means we have keys, but have not confirmed them yet. Set the validation time to start the grace period.* @return bool*/protected function set_not_validated(): bool {$this->set_validation_time();return $this->set_status(self::PENDING);}/*** Set the registration as invalid.* @return bool*/protected function set_invalid(): bool {$this->set_api_key('');$this->set_secret_key('');$this->set_siteid(0);return $this->set_status(self::INVALID);}/*** Set the registration as valid.* @return bool*/protected function set_valid(): bool {$this->set_validation_time();$this->set_summary_time();return $this->set_status(self::VALIDATED);}/*** Set the status to "expired".* @return bool*/protected function set_expired(): bool {return $this->set_status(self::EXPIRED);}/*** Set the status to "error".* @return bool*/protected function set_error(): bool {return $this->set_status(self::ERROR);}/*** Set the configured api key value.* @param string $keyvalue* @return bool*/protected function set_api_key(string $keyvalue): bool {$this->apikey = $keyvalue;return set_config(self::API_KEY, $keyvalue, manager::PLUGINNAME);}/*** Set the configured secret key value.* @param string $keyvalue* @return bool*/protected function set_secret_key(string $keyvalue): bool {$this->secretkey = $keyvalue;return set_config(self::SECRET_KEY, $keyvalue, manager::PLUGINNAME);}/*** Return true if the logic says that the registration is valid.* @return bool*/protected function status_is_validated(): bool {return $this->validation == self::VALIDATED;}/*** Return true if the current status is "not entered".* @return bool*/protected function status_is_not_entered(): bool {return $this->validation == self::NOT_ENTERED;}/*** Return true if the current status is "pending".* @return bool*/protected function status_is_pending(): bool {return $this->validation == self::PENDING;}/*** Return true if the current status is "expired".* @return bool*/protected function status_is_expired(): bool {return $this->validation == self::EXPIRED;}/*** Return true if the current status is "invalid".* @return bool*/protected function status_is_invalid(): bool {return $this->validation == self::INVALID;}/*** Return true if the current status is "error".* @return bool*/protected function status_is_error() {return $this->validation == self::ERROR;}/*** Set the current registration status.* @param int $status* @return bool*/protected function set_status(int $status): bool {$this->validation = $status;return set_config(self::STATUS, $status, manager::PLUGINNAME);}/*** Return the current registration status.* @return int* @throws \dml_exception*/protected function get_status(): int {$status = get_config(manager::PLUGINNAME, self::STATUS);if ($status === false) {// Not set in config yet, so default it to "NOT_ENTERED".$status = self::NOT_ENTERED;$this->set_status($status);}return (int)$status;}/*** Set the time of the last registration check.* @param int $time* @return bool*/protected function set_check_time(int $time = 0): bool {$time = ($time == 0) ? time() : $time;$this->checktime = $time;return set_config(self::VALIDATION_CHECK_TIME, $time, manager::PLUGINNAME);}/*** Get the time of the last registration check.* @return int* @throws \dml_exception*/protected function get_check_time(): int {$time = get_config(manager::PLUGINNAME, self::VALIDATION_CHECK_TIME);if ($time === false) {// Not set in config yet, so default it to 0.$time = 0;$this->set_check_time($time);}return (int)$time;}/*** Set the registration validation time.* @param int $time* @return bool*/protected function set_validation_time(int $time = 0): bool {$time = ($time == 0) ? time() : $time;$this->validationtime = $time;return set_config(self::VALIDATION_TIME, $time, manager::PLUGINNAME);}/*** Return the time of the registration validation.* @return int* @throws \dml_exception*/protected function get_validation_time(): int {$time = get_config(manager::PLUGINNAME, self::VALIDATION_TIME);if ($time === false) {// Not set in config yet, so default it to 0.$time = 0;$this->set_validation_time($time);}return (int)$time;}/*** Set the time of the summary update.* @param int $time* @return bool*/protected function set_summary_time(int $time = 0): bool {$time = ($time == 0) ? time() : $time;$this->summarytime = $time;return set_config(self::SUMMARY_TIME, $time, manager::PLUGINNAME);}/*** Return the time of the last summary update.* @return int* @throws \dml_exception*/protected function get_summary_time(): int {$time = get_config(manager::PLUGINNAME, self::SUMMARY_TIME);if ($time === false) {// Not set in config yet, so default it to 0.$time = 0;$this->set_summary_time($time);}return (int)$time;}/*** Return true if all keys have valid format.* @param string|null $apikey* @param string|null $secretkey* @return bool*/protected function keys_are_valid(?string $apikey = null, ?string $secretkey = null): bool {$apikey = $apikey ?? $this->apikey;$secretkey = $secretkey ?? $this->secretkey;return $this->apikey_is_valid($apikey) && $this->secretkey_is_valid($secretkey);}/*** Validates that the entered API key is in the expected format.* @param string $apikey* @return bool*/protected function apikey_is_valid(string $apikey): bool {return $this->valid_key_format($apikey);}/*** Validates that the entered Secret key is in the expected format.* @param string $secretkey* @return bool*/protected function secretkey_is_valid(string $secretkey): bool {return $this->valid_key_format($secretkey);}/*** Validates that the passed in key looks like an MD5 hash.* @param string $key* @return bool*/protected function valid_key_format(string $key): bool {return !empty($key) && (preg_match('/^[a-f0-9]{32}$/', $key) === 1);}/*** Get the registration grace period.* @return int*/protected function get_grace_period(): int {return WEEKSECS;}/*** Check if the unvalidated time is still within the grace period.* @return bool*/protected function grace_period_valid(): bool {return (time() - $this->validationtime) < $this->get_grace_period();}/*** Check if the last time the summary data was sent is within the grace period.* @return bool*/protected function summarydata_grace_period_expired(): bool {return (time() - $this->summarytime) > $this->get_grace_period();}/*** Return an instance of the connection class.* @return brickfieldconnect*/protected function get_registration_connection(): brickfieldconnect {return new brickfieldconnect();}}