Validate requests to perfstats

Make some stricter rules for accessing the perfstats module. We only
want to respond to GET request for json data made by a site admin.

This means we also need to pass along the credentials in the request.
Didn't immediately figure out how to do that using `z_fetch_url`, so we
just fall back to using the JavaScript to populate the widget. This
makes it idle for about 5 sec before it gets the first data sample.

I think that's probably OK.

Project......: Performance Profiling
Sponsored-by.: NLnet NGI0 Commons Fund
This commit is contained in:
Harald Eilertsen
2026-02-23 21:05:27 +01:00
parent 04d44c9965
commit 3d3580b23f
3 changed files with 55 additions and 29 deletions

View File

@@ -14,9 +14,37 @@ use Zotlabs\Lib\Queue;
use Zotlabs\Lib\QueueWorkerStats;
use Zotlabs\Web\Controller;
/**
* Controller for the `/perfstats` module.
*
* Collects various performance stats for the site, and reponds with the stats
* as a json array.
*/
class Perfstats extends Controller
{
public function init(): void {
//
// We only accept GET requests
//
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_status_exit(400, 'Unsupported method');
}
//
// We only accept json requests
//
if (getBestSupportedMimeType(['application/json']) === null) {
http_status_exit(400, 'No supported format');
}
//
// Only admins should be given access
//
if (!is_site_admin()) {
http_status(401, 'Access denied');
json_return_and_die(['error' => 'access denied']);
}
$data = $this->getStats();
json_return_and_die($data);
}
@@ -52,4 +80,9 @@ class Perfstats extends Controller
return 0;
}
private function requireJson(): void {
if (getBestSupportedMimeTypes(['application/json']) === null) {
}
}
}

View File

@@ -254,34 +254,26 @@ class Channel_activities {
}
private static function get_system_status(): void {
$response = z_fetch_url(
z_root() . '/perfstats',
false, // binary
0, // redirects
[ 'headers' => [ 'accept: application/json' ] ]
);
if ($response['success'] === true) {
$items = json_decode($response['body'], true);
//$items['debug'] = print_r($response['body'], true);
self::$activities['status'] = [
'label' => t('System status'),
'icon' => 'gpu-card',
'date' => datetime_convert(),
'items' => $items,
'tpl' => 'system_status_widget.tpl',
'labels' => [
'loadavg' => t('Load average'),
'dbqueries' => t('DB queries'),
'outqueue' => t('Output queue'),
'queueworkers' => t('Queue workers'),
'workqsz' => t('Work queue size'),
],
];
} else {
logger("fetching perfstats failed: {$response['return_code']}", LOGGER_NORMAL, LOG_ERR);
}
self::$activities['status'] = [
'label' => t('System status'),
'icon' => 'gpu-card',
'date' => datetime_convert(),
'items' => [
'loadavg' => '0 / 0 / 0',
'dbqueries' => 0,
'outqueue' => 0,
'queueworkers' => 0,
'workqsz' => 0,
],
'tpl' => 'system_status_widget.tpl',
'labels' => [
'loadavg' => t('Load average'),
'dbqueries' => t('DB queries'),
'outqueue' => t('Output queue'),
'queueworkers' => t('Queue workers'),
'workqsz' => t('Work queue size'),
],
];
}
}

View File

@@ -18,7 +18,8 @@ setInterval(() => {
fetch('/perfstats', {
headers: {
"Accept": "application/json",
}
},
credentials: "include",
})
.then((response) => response.json())
.then((json) => {