mirror of
https://github.com/catalyst/moodle-auth_outage.git
synced 2026-05-17 05:48:43 +02:00
Issue #2 - IP Block implementation.
This commit is contained in:
@@ -135,7 +135,7 @@ class outagedb {
|
||||
}
|
||||
|
||||
// Trigger outages modified events.
|
||||
outagelib::outages_modified();
|
||||
outagelib::prepare_next_outage();
|
||||
|
||||
// All done, return the id.
|
||||
return $outage->id;
|
||||
@@ -165,7 +165,7 @@ class outagedb {
|
||||
calendar::delete($id);
|
||||
|
||||
// Trigger events.
|
||||
outagelib::outages_modified();
|
||||
outagelib::prepare_next_outage();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -358,4 +358,35 @@ class outagedb {
|
||||
// Allowing multiple records still raises an internal error.
|
||||
return (count($data) == 0) ? null : new outage(array_shift($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an ongoing outage (between start and stop time but not finished).
|
||||
* @param int|null $time Timestamp considered to check for outages, null for current date/time.
|
||||
* @return outage|null The outage or null if no active outages were found.
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public static function get_ongoing($time = null) {
|
||||
global $DB;
|
||||
|
||||
if ($time === null) {
|
||||
$time = time();
|
||||
}
|
||||
if (!is_int($time) || ($time <= 0)) {
|
||||
throw new coding_exception('$time must be null or a positive int.', $time);
|
||||
}
|
||||
|
||||
$data = $DB->get_records_select(
|
||||
'auth_outage',
|
||||
'starttime <= :datetime1 AND :datetime2 <= stoptime AND finished IS NULL',
|
||||
['datetime1' => $time, 'datetime2' => $time, 'datetime3' => $time],
|
||||
'starttime ASC, stoptime DESC, title ASC',
|
||||
'*',
|
||||
0,
|
||||
1
|
||||
);
|
||||
|
||||
// Not using $DB->get_record_select instead because there is no 'limit' parameter.
|
||||
// Allowing multiple records still raises an internal error.
|
||||
return (count($data) == 0) ? null : new outage(array_shift($data));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,26 +124,25 @@ class infopage {
|
||||
|
||||
/**
|
||||
* Updates the static info page by (re)creating or deleting it as needed.
|
||||
* @param outage|null $outage Outage or null if no scheduled outage.
|
||||
* @param string|null $file File to update. Null to use default.
|
||||
* @throws coding_exception
|
||||
* @throws file_exception
|
||||
*/
|
||||
public static function update_static_page($file = null) {
|
||||
public static function update_static_page($outage, $file = null) {
|
||||
if (is_null($file)) {
|
||||
$file = self::get_defaulttemplatefile();
|
||||
}
|
||||
if (!is_string($file)) {
|
||||
throw new coding_exception('$file is not a string.', $file);
|
||||
}
|
||||
if (!is_null($outage) && !($outage instanceof outage)) {
|
||||
throw new coding_exception('$outage must be null or an outage object.');
|
||||
}
|
||||
|
||||
$outage = outagedb::get_next_starting();
|
||||
if (is_null($outage)) {
|
||||
if (file_exists($file)) {
|
||||
if (is_file($file) && is_writable($file)) {
|
||||
unlink($file);
|
||||
} else {
|
||||
throw new file_exception('Cannot remove: '.$file);
|
||||
}
|
||||
unlink($file);
|
||||
}
|
||||
} else {
|
||||
self::save_static_page($outage, $file);
|
||||
|
||||
@@ -30,6 +30,8 @@ use auth_outage\local\controllers\infopage;
|
||||
use auth_outage\output\renderer;
|
||||
use coding_exception;
|
||||
use Exception;
|
||||
use file_exception;
|
||||
use invalid_parameter_exception;
|
||||
use stdClass;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@@ -130,29 +132,36 @@ class outagelib {
|
||||
*/
|
||||
public static function get_config_defaults() {
|
||||
return [
|
||||
'allowedips' => '',
|
||||
'css' => '',
|
||||
'default_autostart' => '0',
|
||||
'default_duration' => (string)(60 * 60),
|
||||
'default_warning_duration' => (string)(60 * 60),
|
||||
'default_title' => get_string('defaulttitlevalue', 'auth_outage'),
|
||||
'default_description' => get_string('defaultdescriptionvalue', 'auth_outage'),
|
||||
'css' => '',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Executed when outages are modified (created, updated or deleted).
|
||||
*/
|
||||
public static function outages_modified() {
|
||||
infopage::update_static_page();
|
||||
self::update_maintenance_later();
|
||||
public static function prepare_next_outage() {
|
||||
// If there is an ongoing outage, prepare it instead.
|
||||
$outage = outagedb::get_ongoing();
|
||||
if (is_null($outage)) {
|
||||
$outage = outagedb::get_next_starting();
|
||||
}
|
||||
infopage::update_static_page($outage);
|
||||
self::update_climaintenance_code($outage);
|
||||
self::update_maintenance_later($outage);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls Moodle API - set_maintenance_later() to set when the next outage starts.
|
||||
* @param outage|null $outage Outage or null if no scheduled outage.
|
||||
*/
|
||||
private static function update_maintenance_later() {
|
||||
$next = outagedb::get_next_autostarting();
|
||||
if (is_null($next)) {
|
||||
private static function update_maintenance_later($outage) {
|
||||
if (is_null($outage) || !$outage->autostart) {
|
||||
unset_config('maintenance_later');
|
||||
} else {
|
||||
$message = get_config('moodle', 'maintenance_message');
|
||||
@@ -162,7 +171,7 @@ class outagelib {
|
||||
// We cannot do much if forced config, but the logs will show the error.
|
||||
unset_config('maintenance_message');
|
||||
}
|
||||
set_config('maintenance_later', $next->starttime);
|
||||
set_config('maintenance_later', $outage->starttime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,4 +196,90 @@ class outagelib {
|
||||
// Nothing preventing the injection.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the code to put in sitedata/climaintenance.php when needed.
|
||||
* @param int $starttime Outage start time.
|
||||
* @param int $stoptime Outage stop time.
|
||||
* @param string $allowedips List of IPs allowed.
|
||||
* @return string
|
||||
* @throws invalid_parameter_exception
|
||||
*/
|
||||
public static function create_climaintenancephp_code($starttime, $stoptime, $allowedips) {
|
||||
if (!is_int($starttime) || !is_int($stoptime)) {
|
||||
throw new invalid_parameter_exception('Make sure $startime and $stoptime are integers.');
|
||||
}
|
||||
if (!is_string($allowedips) || (trim($allowedips) == '')) {
|
||||
throw new invalid_parameter_exception('$allowedips must be a valid string.');
|
||||
}
|
||||
// I know Moodle validation would clean up this field, but just in case, let's ensure no
|
||||
// single-quotes (and double for the sake of it) are present otherwise it would break the code.
|
||||
$allowedips = str_replace('\'"', '', $allowedips);
|
||||
|
||||
$code = <<<'EOT'
|
||||
<?php
|
||||
if (time() >= {{STARTTIME}}) {
|
||||
if (!defined('CLI_SCRIPT') || !CLI_SCRIPT) {
|
||||
define('MOODLE_INTERNAL', true);
|
||||
require_once($CFG->dirroot.'/lib/moodlelib.php');
|
||||
if (!remoteip_in_list('{{ALLOWEDIPS}}')) {
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 503 Moodle under maintenance');
|
||||
header('Status: 503 Moodle under maintenance');
|
||||
header('Retry-After: 300');
|
||||
header('Content-type: text/html; charset=utf-8');
|
||||
header('X-UA-Compatible: IE=edge');
|
||||
header('Cache-Control: no-store, no-cache, must-revalidate');
|
||||
header('Cache-Control: post-check=0, pre-check=0', false);
|
||||
header('Pragma: no-cache');
|
||||
header('Expires: Mon, 20 Aug 1969 09:23:00 GMT');
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT');
|
||||
header('Accept-Ranges: none');
|
||||
echo '<!-- Blocked by ip, your ip: '.getremoteaddr('n/a').' -->';
|
||||
if (file_exists($CFG->dataroot.'/climaintenance.template.html')) {
|
||||
require($CFG->dataroot.'/climaintenance.template.html');
|
||||
exit(0);
|
||||
}
|
||||
// The file above should always exist, but just in case...
|
||||
die('We are currently under maintentance, please try again later.');
|
||||
}
|
||||
}
|
||||
}
|
||||
$CFG->auth_outage_check = 1;
|
||||
EOT;
|
||||
$search = ['{{STARTTIME}}', '{{ALLOWEDIPS}}', '{{YOURIP}}'];
|
||||
$replace = [$starttime, $allowedips, getremoteaddr('n/a')];
|
||||
return str_replace($search, $replace, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the static info page by (re)creating or deleting it as needed.
|
||||
* @param outage|null $outage Outage or null if no scheduled outage.
|
||||
* @throws coding_exception
|
||||
* @throws file_exception
|
||||
*/
|
||||
public static function update_climaintenance_code($outage) {
|
||||
global $CFG;
|
||||
$file = $CFG->dataroot.'/climaintenance.php';
|
||||
|
||||
if (!is_null($outage) && !($outage instanceof outage)) {
|
||||
throw new coding_exception('$outage must be null or an outage object.');
|
||||
}
|
||||
|
||||
$config = self::get_config();
|
||||
$allowedips = trim($config->allowedips);
|
||||
|
||||
if (is_null($outage) || ($allowedips == '')) {
|
||||
if (file_exists($file)) {
|
||||
unlink($file);
|
||||
}
|
||||
} else {
|
||||
$code = self::create_climaintenancephp_code($outage->starttime, $outage->stoptime, $allowedips);
|
||||
|
||||
$dir = dirname($file);
|
||||
if (!file_exists($dir) || !is_dir($dir)) {
|
||||
throw new file_exception('Directory must exists: '.$dir);
|
||||
}
|
||||
file_put_contents($file, $code);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
namespace auth_outage\task;
|
||||
|
||||
use auth_outage\local\controllers\infopage;
|
||||
use auth_outage\local\outagelib;
|
||||
use core\task\scheduled_task;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
@@ -51,6 +52,6 @@ class update_static_page extends scheduled_task {
|
||||
* Executes the event.
|
||||
*/
|
||||
public function execute() {
|
||||
infopage::update_static_page();
|
||||
outagelib::prepare_next_outage();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user