From 0dbfc8a521624fde2d4031a63b80d48ebc4c6d7d Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 7 Oct 2026 18:32:29 -0400 Subject: [PATCH 1/2] security: move inline event handlers to CSP-safe bindings Cacti's Content-Security-Policy script-src-attr directive blocks inline event-handler attributes. This converts slowlog's remaining inline handlers: - The charts, summary and details filter views (slowlog.php) drop their inline onClick/onChange on the Go/Clear buttons, filter selects, time-shift icons and timespan select; each control is bound in its own view's ready block to the same applyFilter/clearFilter/applyChartsFilter/applyGraphTimespan/ timeshift functions it already called. Go submit buttons rely on the existing form-submit binding; Clear buttons are bound form-scoped (they share a class, not an id). - The confirmation Cancel button switches from onClick='window.location.assign' to the cactiReturnTo class + data-url. - The per-field clear glyph (slowlog_details_filter_clear_glyph in includes/slowlog_functions.php) drops its inline onclick for a slowlogClearFilter class + data-url, bound by a delegated handler. includes/slowlog_functions.php is measured; a new SlowlogClearGlyphTest covers the changed glyph line. slowlog.php is already in the patch-coverage allowlist. No i18n calls changed, so cacti.pot is untouched. Cacti 1.2.31+ binds the cactiReturnTo class automatically; the README documents a one-time applySkin() snippet for earlier releases. --- CHANGELOG.md | 1 + README.md | 14 ++++++ includes/slowlog_functions.php | 2 +- slowlog.php | 71 +++++++++++++++++++++------- tests/Unit/SlowlogClearGlyphTest.php | 30 ++++++++++++ 5 files changed, 101 insertions(+), 17 deletions(-) create mode 100644 tests/Unit/SlowlogClearGlyphTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index ed5e7df..f90b782 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ --- 2.6 --- +* security: Move the slow-query views' inline event handlers to CSP-safe bindings so the pages no longer trip Cacti's Content-Security-Policy script-src-attr directive: the charts/summary/details filter selects, Go/Clear buttons, time-shift icons and per-field clear glyph are bound in each view's ready block, and the confirmation Cancel button uses the `cactiReturnTo` class * perf: Stream the slow query log a line at a time during import (`fgets()`) instead of slurping the whole file into memory with `file()`, so importing a multi-gigabyte slow query log no longer costs many times its own size in PHP array overhead - the detail rows were already flushed to the database in `SLOWLOG_IMPORT_BATCH_SIZE` batches as parsing proceeds * bug: Distinguish a read error from end-of-file when streaming the import - `fgets()` returns `false` for both, so a mid-file I/O error was being treated as a clean EOF and the partial import was finalized (and post-processed) as successful. `import_logfile()` now checks `feof()` before closing the handle and fails the import (status 3, "Read Error - Import Aborted, Log May Be Truncated") instead of ingesting a truncated log * perf: Drop the `SELECT DISTINCT sld.*` from the details list query - the association tables' composite primary keys already make every `plugin_slowlog_details` x method x table join row unique, so the DISTINCT never removed a row and only forced a filesort/hash over the `mediumtext` query columns on every page of the Details view diff --git a/README.md b/README.md index 56406d3..b1630e0 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,20 @@ Very simple analysis. I use it to see the forest through the tree's. Cacti 1.2.x +## Cacti compatibility + +If you are running a version of Cacti below 1.2.31, please add the function +below to the `applySkin()` function in `include/layout.js` to enable the Cancel +buttons on forms to work: + +```js +$(document).off('click.cactiReturnTo', '.cactiReturnTo') + .on('click.cactiReturnTo', '.cactiReturnTo', function(event) { + event.preventDefault(); + cactiReturnTo($(this).attr('data-url')); + }); +``` + ## Installation Simply place in the plugins directory and install like any other Cacti Plugin. diff --git a/includes/slowlog_functions.php b/includes/slowlog_functions.php index 3a5bd5e..433eedc 100644 --- a/includes/slowlog_functions.php +++ b/includes/slowlog_functions.php @@ -3038,7 +3038,7 @@ function slowlog_details_filter_clear_glyph(string $field): string { $defaults = slowlog_details_filter_defaults(); $url = slowlog_details_filter_url($field, $defaults[$field]) . '&header=false'; - return " "; + return " "; } /** diff --git a/slowlog.php b/slowlog.php index 829debc..36f9ad7 100644 --- a/slowlog.php +++ b/slowlog.php @@ -1544,8 +1544,8 @@ function slowlog_charts_filter(string $method, int $id): void { - '> - '> + '> + '> @@ -1569,6 +1569,15 @@ function clearChartsFilter() { } $(function() { + $('#chartsfilter').submit(function(event) { + event.preventDefault(); + applyChartsFilter(); + }); + + $('#chartsfilter .button_clear').click(function() { + clearChartsFilter(); + }); + var $scope = $('#chart_scope'); // Cacti core turns this select into a select2 (via the select2-multi-count @@ -1977,7 +1986,7 @@ function slowlog_save_button(string $cancel_action = '', string $action = 'save' - ')' name='cancel'> + @@ -2013,8 +2022,8 @@ function filter(): void { - - + + @@ -2037,6 +2046,10 @@ function clearFilter() { event.preventDefault(); applyFilter(); }); + + $('#summary .button_clear').click(function() { + clearFilter(); + }); }); @@ -2077,7 +2090,7 @@ function slowlog_details_filter(): void { - - - @@ -2144,7 +2157,7 @@ function slowlog_details_filter(): void { - - '> - '> + '> + '> @@ -2175,7 +2188,7 @@ function slowlog_details_filter(): void { - 0) { @@ -2203,7 +2216,7 @@ function slowlog_details_filter(): void { - 0) { @@ -2251,7 +2264,7 @@ function slowlog_details_filter(): void { - '> + '> - '> + '> - __('Custom', 'slowlog')], $graph_timespans); @@ -2350,6 +2363,32 @@ function timeshiftFilterRight() { applyFilter(); }); + $('#logid, #mmethod, #table, #rows, #myuser, #host').change(function() { + applyFilter(); + }); + + $('#predefined_timespan').change(function() { + applyGraphTimespan(); + }); + + $('#details .button_clear').click(function() { + clearFilter(); + }); + + $(document).off('click.slowlogClear', '.slowlogClearFilter') + .on('click.slowlogClear', '.slowlogClearFilter', function(event) { + event.preventDefault(); + loadPageNoHeader($(this).data('url')); + }); + + $('.shiftArrow.fa-backward').click(function() { + timeshiftGraphFilterLeft(); + }); + + $('.shiftArrow.fa-forward').click(function() { + timeshiftGraphFilterRight(); + }); + $('#startDate').click(function() { if (date1Open) { date1Open = false; diff --git a/tests/Unit/SlowlogClearGlyphTest.php b/tests/Unit/SlowlogClearGlyphTest.php new file mode 100644 index 0000000..223c6e2 --- /dev/null +++ b/tests/Unit/SlowlogClearGlyphTest.php @@ -0,0 +1,30 @@ +toContain('slowlogClearFilter'); + expect($output)->toContain('data-url='); + expect($output)->not->toContain('onclick'); +}); From 8fd2fbe176b7e40c402c5b6ae8a6f1d3aef690d8 Mon Sep 17 00:00:00 2001 From: TheWitness Date: Wed, 7 Oct 2026 21:10:43 -0400 Subject: [PATCH 2/2] Remove charts filter submission handler Removed event handler for charts filter submission. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- slowlog.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/slowlog.php b/slowlog.php index 36f9ad7..10bb8fb 100644 --- a/slowlog.php +++ b/slowlog.php @@ -1569,11 +1569,6 @@ function clearChartsFilter() { } $(function() { - $('#chartsfilter').submit(function(event) { - event.preventDefault(); - applyChartsFilter(); - }); - $('#chartsfilter .button_clear').click(function() { clearChartsFilter(); });