Compare commits

...
Author SHA1 Message Date
Benjamin Walker 0bc716aeba Display creation info on manage outage page 2026-08-07 13:23:26 +10:00
Vlad Kidanov 0da0542663 Merge pull request #420 from catalyst/general-fixes-501
Bug fixes and improvements
2026-08-05 10:05:41 +01:00
vlad.kidanov a093165caf Bug fixes and improvements
WR492688: Issue #32

Fix: the 'static' flag can no longer be set from a raw client value. It
is now only true if the request presents a 'statickey' matching an
HMAC-SHA256 of the outage id keyed with a per-site secret
(infopage::statickey(), lazily generated via set_config()/get_config()).
maintenance_static_page::create_from_outage() now sends that computed
statickey instead of static=1 when it internally fetches info.php, so
the legitimate static-generation path keeps working while external
forgery of the flag is no longer possible.

WR492688: Issue #33

WR492688: Version bump

Bug fixes and improvements

WR492688: Issue #32

Fix: the 'static' flag can no longer be set from a raw client value. It
is now only true if the request presents a 'statickey' matching an
HMAC-SHA256 of the outage id keyed with a per-site secret
(infopage::statickey(), lazily generated via set_config()/get_config()).
maintenance_static_page::create_from_outage() now sends that computed
statickey instead of static=1 when it internally fetches info.php, so
the legitimate static-generation path keeps working while external
forgery of the flag is no longer possible.

WR492688: Issue #33

WR492688: Version bump

fix
2026-07-20 14:51:01 +01:00
9 changed files with 87 additions and 8 deletions
+23 -2
View File
@@ -53,10 +53,14 @@ class infopage {
$CFG->svgicons = true;
if (is_null($params)) {
$id = optional_param('id', null, PARAM_INT);
$params = [
'id' => optional_param('id', null, PARAM_INT),
'id' => $id,
'outage' => null,
'static' => optional_param('static', false, PARAM_BOOL),
'static' => !is_null($id) && hash_equals(
self::statickey($id),
optional_param('statickey', '', PARAM_ALPHANUM)
),
];
} else {
$defaults = [
@@ -152,4 +156,21 @@ class infopage {
$this->outage = $params['outage'];
$this->static = $params['static'];
}
/**
* Computes the secret token that proves a request to view an outage's static
* rendering came from this plugin's own static-page generator, not an external
* client forging the request. Used to gate the 'static' flag (see constructor).
*
* @param int $outageid
* @return string
*/
public static function statickey($outageid) {
$secret = get_config('auth_outage', 'staticsecret');
if (empty($secret)) {
$secret = random_string(64);
set_config('staticsecret', $secret, 'auth_outage');
}
return hash_hmac('sha256', (string)$outageid, $secret);
}
}
@@ -56,7 +56,8 @@ class maintenance_static_page {
header('X-Outage-EndTime: ' . $outage->stoptime);
}
$data = maintenance_static_page_io::file_get_data(
$CFG->wwwroot . '/auth/outage/info.php?auth_outage_hide_warning=1&static=1&id=' . $outage->id
$CFG->wwwroot . '/auth/outage/info.php?auth_outage_hide_warning=1&id=' . $outage->id
. '&statickey=' . infopage::statickey($outage->id)
);
$html = $data['contents'];
}
+35
View File
@@ -64,6 +64,41 @@ class base_table extends flexible_table {
$this->set_attribute('class', 'generaltable admintable');
}
/**
* Displays a user by their fullname with a link to a profile.
* @param int $userid
* @return string HTML link to user profile
*/
private function format_user(int $userid): string {
if ($userid == 0 || !$user = \core_user::get_user($userid)) {
return get_string('na', 'auth_outage');
}
$url = new moodle_url('/user/profile.php', ['id' => $userid]);
return html_writer::link($url, fullname($user));
}
/**
* Formats created by column.
* @param outage $outage
* @return string The user who created the outage.
*/
protected function format_created(outage $outage): string {
return $this->format_user($outage->createdby);
}
/**
* Formats modified by column.
* @param outage $outage
* @return string The user who last modiifed the outage and the last modified time.
*/
protected function format_modified(outage $outage): string {
$timestamp = html_writer::div(
userdate($outage->lastmodified, get_string('datetimeformat', 'auth_outage')),
'small text-muted'
);
return $this->format_user($outage->modifiedby) . $timestamp;
}
/**
* Create the action buttons HTML code for a specific outage.
* @param outage $outage The outage to generate the buttons.
+5 -1
View File
@@ -36,7 +36,7 @@ class history_table extends base_table {
public function __construct() {
parent::__construct();
$this->define_columns(['warning', 'starts', 'durationplanned', 'durationactual', 'title', 'actions']);
$this->define_columns(['warning', 'starts', 'duration', 'durationactual', 'title', 'created', 'modified', 'actions']);
$this->define_headers([
get_string('tableheaderwarnbefore', 'auth_outage'),
@@ -44,6 +44,8 @@ class history_table extends base_table {
get_string('tableheaderdurationplanned', 'auth_outage'),
get_string('tableheaderdurationactual', 'auth_outage'),
get_string('tableheadertitle', 'auth_outage'),
get_string('tableheadercreatedby', 'auth_outage'),
get_string('tableheadermodifiedby', 'auth_outage'),
get_string('actions'),
]);
@@ -64,6 +66,8 @@ class history_table extends base_table {
format_time($outage->get_duration_planned()),
$finished,
$outage->get_title(),
$this->format_created($outage),
$this->format_modified($outage),
$this->create_data_buttons($outage, false),
]);
}
+5 -1
View File
@@ -38,13 +38,15 @@ class planned_table extends base_table {
public function __construct() {
parent::__construct();
$this->define_columns(['warning', 'starts', 'duration', 'title', 'actions']);
$this->define_columns(['warning', 'starts', 'duration', 'title', 'created', 'modified', 'actions']);
$this->define_headers([
get_string('tableheaderwarnbefore', 'auth_outage'),
get_string('tableheaderstarttime', 'auth_outage'),
get_string('tableheaderduration', 'auth_outage'),
get_string('tableheadertitle', 'auth_outage'),
get_string('tableheadercreatedby', 'auth_outage'),
get_string('tableheadermodifiedby', 'auth_outage'),
get_string('actions'),
]);
@@ -68,6 +70,8 @@ class planned_table extends base_table {
self::create_starttime_string($outage->starttime),
format_time($outage->get_duration_planned()),
$title,
$this->format_created($outage),
$this->format_modified($outage),
$this->create_data_buttons($outage, true),
]);
}
+2
View File
@@ -150,9 +150,11 @@ $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['tableheadercreatedby'] = 'Created by';
$string['tableheaderduration'] = 'Duration';
$string['tableheaderdurationactual'] = 'Actual duration';
$string['tableheaderdurationplanned'] = 'Planned duration';
$string['tableheadermodifiedby'] = 'Last modified by';
$string['tableheaderstartedtime'] = 'Started on';
$string['tableheaderstarttime'] = 'Starts on';
$string['tableheadertitle'] = 'Title';
+4
View File
@@ -30,7 +30,11 @@ use auth_outage\local\controllers\maintenance_static_page;
// @codingStandardsIgnoreStart
require_once(__DIR__.'/../../config.php');
require_once($CFG->libdir . '/adminlib.php');
// @codingStandardsIgnoreEnd
admin_externalpage_setup('auth_outage_manage');
$id = optional_param('id', null, PARAM_INT);
$outage = is_null($id) ? outagedb::get_next_starting() : outagedb::get_by_id($id);
if (is_null($outage)) {
+2 -2
View File
@@ -28,8 +28,8 @@
defined('MOODLE_INTERNAL') || die();
$plugin->component = "auth_outage";
$plugin->version = 2026011306; // The current plugin version (Date: YYYYMMDDXX).
$plugin->release = 2026011305; // Human-readable release information.
$plugin->version = 2026011308; // The current plugin version (Date: YYYYMMDDXX).
$plugin->release = 2026011308; // Human-readable release information.
$plugin->requires = 2025100600; // Moodle 5.1.
$plugin->maturity = MATURITY_STABLE; // Suitable for PRODUCTION environments!
$plugin->supported = [501, 501]; // A range of branch numbers of supported moodle versions.
+9 -1
View File
@@ -39,7 +39,15 @@ defined('MOODLE_INTERNAL') || die();
<b><?php echo get_string('infountil', 'auth_outage'); ?></b>
<?php echo userdate($viewbag['outage']->stoptime, get_string('datetimeformat', 'auth_outage')); ?>
</div>
<div class="auth_outage_info_description"><?php echo $viewbag['outage']->get_description(); ?></div>
<div class="auth_outage_info_description">
<?php
echo format_text(
$viewbag['outage']->get_description(),
FORMAT_HTML,
['context' => context_system::instance()]
);
?>
</div>
<?php if ($viewbag['admin']) : ?>
<?php