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:
11
README.md
11
README.md
@@ -77,6 +77,17 @@ https://github.com/catalyst/moodle-auth_outage/issues
|
||||
3. Go to `Dashboard ► Site administration ► Plugins ► Authentication ► Manage authentication`,
|
||||
enable the `Outage manager` plugin and place it on the top.
|
||||
|
||||
4. If you need to use the IP Blocking, please add the following lines into your `config.php`
|
||||
after your `$CFG->dataroot` is set:
|
||||
|
||||
```
|
||||
if (file_exists("$CFG->dataroot/climaintenance.php")) {
|
||||
$CFG->dirroot = __DIR__;
|
||||
require("$CFG->dataroot/climaintenance.php");
|
||||
} else {
|
||||
$CFG->auth_outage_check = 1;
|
||||
}
|
||||
```
|
||||
|
||||
How to use
|
||||
----------
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,10 @@ $string['infountil'] = 'Until:';
|
||||
$string['infostart'] = 'start';
|
||||
$string['infostartofwarning'] = 'start of warning';
|
||||
$string['infopagestaticgenerated'] = 'This warning was generated on {$a->time}.';
|
||||
$string['allowedipsempty'] = 'When the allowed IPs list is empty we will not block anyone. You can add your own IP address (<i>{$a->ip}</i>) and block all other IPs.';
|
||||
$string['allowedipshasmyip'] = 'Your IP (<i>{$a->ip}</i>) is in the list and you will not be blocked out during an Outage.';
|
||||
$string['allowedipshasntmyip'] = 'Your IP (<i>{$a->ip}</i>) is not in the list and you will be blocked out during an outage.';
|
||||
$string['allowedipsnoconfig'] = 'Your config.php does not have the extra setup to allow blocking via IP.<br />Please refer to our <a href="https://github.com/catalyst/moodle-auth_outage#installation" target="_blank">README.md</a> file for more information.';
|
||||
$string['menusettings'] = 'Settings';
|
||||
$string['menumanage'] = 'Manage';
|
||||
$string['messageoutagebackonline'] = 'We are back online!';
|
||||
@@ -108,6 +112,10 @@ $string['outagefinishwarning'] = 'You are about to mark this outage as finished.
|
||||
$string['outageslistfuture'] = 'Planned outages';
|
||||
$string['outageslistpast'] = 'Outage history';
|
||||
$string['pluginname'] = 'Outage manager';
|
||||
$string['settingssectiondefaults'] = 'Default Outage Parameters';
|
||||
$string['settingssectiondefaultsdescription'] = 'Configure the default values used when creating new outages.';
|
||||
$string['settingssectionplugin'] = 'Plugin Configuration';
|
||||
$string['settingssectionplugindescription'] = 'General outage management plugin settings.';
|
||||
$string['starttime'] = 'Start date and time';
|
||||
$string['starttime_help'] = 'At which date and time the outage starts, preventing general access to the system.';
|
||||
$string['tableheaderduration'] = 'Duration';
|
||||
|
||||
42
settings.php
42
settings.php
@@ -28,8 +28,12 @@ defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
if ($hassiteconfig && is_enabled_auth('outage')) {
|
||||
$defaults = outagelib::get_config_defaults();
|
||||
// Configure default settings page.
|
||||
$settings->visiblename = get_string('menusettings', 'auth_outage');
|
||||
|
||||
$settings->add(new admin_setting_heading(
|
||||
'defaults',
|
||||
get_string('settingssectiondefaults', 'auth_outage'),
|
||||
get_string('settingssectiondefaultsdescription', 'auth_outage')));
|
||||
$settings->add(new admin_setting_configcheckbox(
|
||||
'auth_outage/default_autostart',
|
||||
get_string('defaultoutageautostart', 'auth_outage'),
|
||||
@@ -64,6 +68,12 @@ if ($hassiteconfig && is_enabled_auth('outage')) {
|
||||
$defaults['default_description'],
|
||||
PARAM_RAW
|
||||
));
|
||||
|
||||
$settings->add(new admin_setting_heading(
|
||||
'plugin',
|
||||
get_string('settingssectionplugin', 'auth_outage'),
|
||||
get_string('settingssectionplugindescription', 'auth_outage')));
|
||||
|
||||
$settings->add(new admin_setting_configtextarea(
|
||||
'auth_outage/css',
|
||||
get_string('defaultlayoutcss', 'auth_outage'),
|
||||
@@ -71,6 +81,36 @@ if ($hassiteconfig && is_enabled_auth('outage')) {
|
||||
$defaults['css'],
|
||||
PARAM_RAW
|
||||
));
|
||||
|
||||
// Create 'Allowed IPs' settings.
|
||||
$allowedips = outagelib::get_config()->allowedips;
|
||||
$description = '';
|
||||
|
||||
if (!isset($CFG->auth_outage_check) || !$CFG->auth_outage_check) {
|
||||
$description .= $OUTPUT->notification(get_string('allowedipsnoconfig', 'auth_outage'), 'notifyfailure');
|
||||
}
|
||||
|
||||
if (trim($allowedips) == '') {
|
||||
$message = 'allowedipsempty';
|
||||
$type = 'notifymessage';
|
||||
} else if (remoteip_in_list($allowedips)) {
|
||||
$message = 'allowedipshasmyip';
|
||||
$type = 'notifysuccess';
|
||||
} else {
|
||||
$message = 'allowedipshasntmyip';
|
||||
$type = 'notifyfailure';
|
||||
};
|
||||
$description .= $OUTPUT->notification(get_string($message, 'auth_outage', ['ip' => getremoteaddr()]), $type);
|
||||
|
||||
$description .= '<p>'.get_string('ipblockersyntax', 'admin').'</p>';
|
||||
|
||||
$settings->add(new admin_setting_configiplist(
|
||||
'auth_outage/allowedips',
|
||||
get_string('allowediplist', 'admin'),
|
||||
$description,
|
||||
$defaults['allowedips']
|
||||
));
|
||||
|
||||
// Create category for Outage.
|
||||
$ADMIN->add('authsettings', new admin_category('auth_outage', get_string('pluginname', 'auth_outage')));
|
||||
// Add settings page toconfigure defaults.
|
||||
|
||||
@@ -154,6 +154,21 @@ class behat_auth_outage extends behat_base {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @Then /^I should see an empty settings text area "([^"]*)"$/
|
||||
* @param string $name
|
||||
*/
|
||||
public function i_should_see_an_empty_settings_text_area($name) {
|
||||
$this->assertSession()->fieldValueEquals('s_auth_outage_'.$name, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* @When /^I go to the "Outage Settings" page$/
|
||||
*/
|
||||
public function i_go_to_the_outage_settings_page() {
|
||||
$this->getSession()->visit($this->locate_path('/admin/settings.php?section=authsettingoutage'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts how many times an specific action is visible.
|
||||
* @param string $action Action to check.
|
||||
|
||||
21
tests/behat/ipblock.feature
Normal file
21
tests/behat/ipblock.feature
Normal file
@@ -0,0 +1,21 @@
|
||||
@dev @auth @auth_outage @javascript
|
||||
Feature: IP Blocker
|
||||
In order to allow admins to access the system during an outage
|
||||
As an admin
|
||||
I need to be able to login into Moodle
|
||||
|
||||
Terminology:
|
||||
- An ongoing outage does not block Moodle execution, although it can trigger maintenance mode.
|
||||
- Maintenance mode completely blocks Moodle and can only be deactivated using the CLI.
|
||||
|
||||
|
||||
Background:
|
||||
Given the authentication plugin "outage" is enabled
|
||||
|
||||
|
||||
Scenario: Default IP Whitelist Settings
|
||||
Given I am an administrator
|
||||
And I am on homepage
|
||||
When I navigate to "Settings" node in "Site administration > Plugins > Authentication > Outage manager"
|
||||
Then I should see "Allowed IP list"
|
||||
And I should see an empty settings text area "allowedips"
|
||||
@@ -1,4 +1,4 @@
|
||||
@dev @auth @auth_outage @javascript
|
||||
@auth @auth_outage @javascript
|
||||
Feature: Warning bar
|
||||
In order alert users about an outage
|
||||
As any user
|
||||
|
||||
@@ -257,7 +257,7 @@ class infopagecontroller_test extends auth_outage_base_testcase {
|
||||
* Tests updating the static page when there is no outage.
|
||||
*/
|
||||
public function test_updatestaticpage_nooutage() {
|
||||
infopage::update_static_page();
|
||||
infopage::update_static_page(null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -267,7 +267,7 @@ class infopagecontroller_test extends auth_outage_base_testcase {
|
||||
$file = infopage::get_defaulttemplatefile();
|
||||
touch($file);
|
||||
self::assertFileExists($file);
|
||||
infopage::update_static_page();
|
||||
infopage::update_static_page(null);
|
||||
self::assertFileNotExists($file);
|
||||
}
|
||||
|
||||
@@ -276,7 +276,15 @@ class infopagecontroller_test extends auth_outage_base_testcase {
|
||||
*/
|
||||
public function test_updatestaticpage_invalidfile() {
|
||||
$this->set_expected_exception('coding_exception');
|
||||
infopage::update_static_page(123);
|
||||
infopage::update_static_page(null, 123);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests updating the static page with an invalid outage.
|
||||
*/
|
||||
public function test_updatestaticpage_invalidoutage() {
|
||||
$this->set_expected_exception('coding_exception');
|
||||
infopage::update_static_page("foobar");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,6 +347,7 @@ class infopagecontroller_test extends auth_outage_base_testcase {
|
||||
* Checks if we can create and execute a task to update outage pages.
|
||||
*/
|
||||
public function test_tasks() {
|
||||
$this->resetAfterTest(true);
|
||||
$task = new update_static_page();
|
||||
self::assertNotEmpty($task->get_name());
|
||||
$task->execute();
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
*/
|
||||
|
||||
use auth_outage\dml\outagedb;
|
||||
use auth_outage\local\controllers\infopage;
|
||||
use auth_outage\local\outage;
|
||||
use auth_outage\local\outagelib;
|
||||
|
||||
@@ -70,7 +71,7 @@ class outagelib_test extends advanced_testcase {
|
||||
$this->resetAfterTest(true);
|
||||
set_config('maintenance_later', time() + (60 * 60 * 24 * 7)); // In 1 week.
|
||||
self::assertNotEmpty(get_config('moodle', 'maintenance_later'));
|
||||
outagelib::outages_modified();
|
||||
outagelib::prepare_next_outage();
|
||||
self::assertEmpty(get_config('moodle', 'maintenance_later'));
|
||||
}
|
||||
|
||||
@@ -194,6 +195,7 @@ class outagelib_test extends advanced_testcase {
|
||||
'default_duration',
|
||||
'default_title',
|
||||
'default_warning_duration',
|
||||
'allowedips',
|
||||
];
|
||||
// Set config with values.
|
||||
foreach ($keys as $k) {
|
||||
@@ -206,12 +208,33 @@ class outagelib_test extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that config has key.
|
||||
*/
|
||||
public function test_config_keys() {
|
||||
$this->resetAfterTest(true);
|
||||
$keys = [
|
||||
'allowedips',
|
||||
'css',
|
||||
'default_autostart',
|
||||
'default_description',
|
||||
'default_duration',
|
||||
'default_title',
|
||||
'default_warning_duration',
|
||||
];
|
||||
$defaults = outagelib::get_config_defaults();
|
||||
foreach ($keys as $k) {
|
||||
self::assertArrayHasKey($k, $defaults);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if get config works getting defaults when needed.
|
||||
*/
|
||||
public function test_get_config_invalid() {
|
||||
$this->resetAfterTest(true);
|
||||
// Set config with invalid values.
|
||||
set_config('allowedips', " \n", 'auth_outage');
|
||||
set_config('css', " \n", 'auth_outage');
|
||||
set_config('default_autostart', " \n", 'auth_outage');
|
||||
set_config('default_description', " \n", 'auth_outage');
|
||||
@@ -221,7 +244,7 @@ class outagelib_test extends advanced_testcase {
|
||||
// Get defaults.
|
||||
$defaults = outagelib::get_config_defaults();
|
||||
$config = outagelib::get_config();
|
||||
// Ensure it is using all defailts.
|
||||
// Ensure it is using all defaults.
|
||||
foreach ($defaults as $k => $v) {
|
||||
self::assertSame($v, $config->$k);
|
||||
}
|
||||
@@ -255,5 +278,165 @@ class outagelib_test extends advanced_testcase {
|
||||
|
||||
self::assertEmpty($CFG->additionalhtmltopofbody);
|
||||
}
|
||||
}
|
||||
|
||||
public function test_createmaintenancephpcode() {
|
||||
$expected = <<<'EOT'
|
||||
<?php
|
||||
if (time() >= 123) {
|
||||
if (!defined('CLI_SCRIPT') || !CLI_SCRIPT) {
|
||||
define('MOODLE_INTERNAL', true);
|
||||
require_once($CFG->dirroot.'/lib/moodlelib.php');
|
||||
if (!remoteip_in_list('heyyou
|
||||
a.b.c.d
|
||||
e.e.e.e/20')) {
|
||||
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;
|
||||
$found = outagelib::create_climaintenancephp_code(123, 456, "hey'\"you\na.b.c.d\ne.e.e.e/20");
|
||||
self::assertSame($expected, $found);
|
||||
}
|
||||
|
||||
public function test_createmaintenancephpcode_withoutage() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$expected = <<<'EOT'
|
||||
<?php
|
||||
if (time() >= 123) {
|
||||
if (!defined('CLI_SCRIPT') || !CLI_SCRIPT) {
|
||||
define('MOODLE_INTERNAL', true);
|
||||
require_once($CFG->dirroot.'/lib/moodlelib.php');
|
||||
if (!remoteip_in_list('127.0.0.1')) {
|
||||
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;
|
||||
$outage = new outage([
|
||||
'starttime' => 123,
|
||||
'stoptime' => 456,
|
||||
]);
|
||||
$file = $CFG->dataroot.'/climaintenance.php';
|
||||
set_config('allowedips', '127.0.0.1', 'auth_outage');
|
||||
|
||||
outagelib::update_climaintenance_code($outage);
|
||||
self::assertFileExists($file);
|
||||
$found = file_get_contents($file);
|
||||
self::assertSame($found, $expected);
|
||||
}
|
||||
|
||||
public function test_createmaintenancephpcode_withoutips() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$outage = new outage([
|
||||
'starttime' => 123,
|
||||
'stoptime' => 456,
|
||||
]);
|
||||
$file = $CFG->dataroot.'/climaintenance.php';
|
||||
set_config('allowedips', '', 'auth_outage');
|
||||
|
||||
touch($file);
|
||||
outagelib::update_climaintenance_code($outage);
|
||||
self::assertFileNotExists($file);
|
||||
}
|
||||
|
||||
public function test_createmaintenancephpcode_withoutoutage() {
|
||||
global $CFG;
|
||||
$file = $CFG->dataroot.'/climaintenance.php';
|
||||
|
||||
touch($file);
|
||||
outagelib::update_climaintenance_code(null);
|
||||
self::assertFileNotExists($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Related to Issue #70: Creating ongoing outage does not trigger maintenance file creation.
|
||||
*/
|
||||
public function test_preparenextoutage_notautostart() {
|
||||
global $CFG;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
self::setAdminUser();
|
||||
$now = time();
|
||||
$outage = new outage([
|
||||
'autostart' => false,
|
||||
'warntime' => $now - 200,
|
||||
'starttime' => $now - 100,
|
||||
'stoptime' => $now + 200,
|
||||
'title' => 'Title',
|
||||
'description' => 'Description',
|
||||
]);
|
||||
set_config('allowedips', '127.0.0.1', 'auth_outage');
|
||||
outagedb::save($outage);
|
||||
|
||||
// The method outagelib::prepare_next_outage() should have been called by save().
|
||||
foreach ([infopage::get_defaulttemplatefile(), $CFG->dataroot.'/climaintenance.php'] as $file) {
|
||||
self::assertFileExists($file);
|
||||
unlink($file);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Related to Issue #72: IP Block still triggers cli maintenance mode even without autostart.
|
||||
*/
|
||||
public function test_preparenextoutage_noautostarttrigger() {
|
||||
global $CFG;
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
self::setAdminUser();
|
||||
$now = time();
|
||||
$outage = new outage([
|
||||
'autostart' => false,
|
||||
'warntime' => $now - 200,
|
||||
'starttime' => $now - 100,
|
||||
'stoptime' => $now + 200,
|
||||
'title' => 'Title',
|
||||
'description' => 'Description',
|
||||
]);
|
||||
outagedb::save($outage);
|
||||
|
||||
// The method outagelib::prepare_next_outage() should have been called by save().
|
||||
self::assertFalse(get_config('moodle', 'maintenance_later'));
|
||||
// This file should not exist even if the statement above fails as Moodle does not create it immediately but test anyway.
|
||||
self::assertFileNotExists($CFG->dataroot.'/climaintenance.html');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = "auth_outage";
|
||||
$plugin->version = 2016110200; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->release = '1.0.5'; // Human-readable release information.
|
||||
$plugin->version = 2016110700; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->release = '1.0.6'; // Human-readable release information.
|
||||
$plugin->requires = 2014051200; // Requires Moodle 2.7 or later. Moodle 3.0 or later recommended.
|
||||
$plugin->maturity = MATURITY_STABLE; // Suitable for PRODUCTION environments!
|
||||
|
||||
Reference in New Issue
Block a user