refactor: deduplicate selected-item bulk action dispatch#279
refactor: deduplicate selected-item bulk action dispatch#279somethingwithproof wants to merge 2 commits intoCacti:developfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors the Syslog plugin’s rule pages (alerts/reports/removal) to remove duplicated “selected items” bulk-action dispatch logic by introducing a shared helper in functions.php, while keeping per-page action maps local to preserve behavior.
Changes:
- Add
syslog_apply_selected_items_action()helper to centralize selected-item action dispatch and export session storage. - Update
form_actions()handlers in alerts/reports/removal pages to use the shared helper. - Add a small regression test to assert the helper exists and is referenced by all three pages; update changelog for issue #276.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
functions.php |
Introduces shared selected-item bulk-action dispatch helper (including export session handling). |
syslog_alerts.php |
Refactors bulk action dispatch in form_actions() to call the shared helper. |
syslog_reports.php |
Refactors bulk action dispatch in form_actions() to call the shared helper. |
syslog_removal.php |
Refactors bulk action dispatch in form_actions() to call the shared helper. |
tests/regression/issue276_bulk_action_dispatch_helper_test.php |
Adds regression coverage to detect removal/non-usage of the shared helper (string-based). |
CHANGELOG.md |
Adds issue #276 entry under develop. |
| exit(1); | ||
| } | ||
|
|
||
| if (strpos($functions, 'function syslog_apply_selected_items_action(') === false) { |
There was a problem hiding this comment.
This check uses strpos() with an exact substring ('function syslog_apply_selected_items_action('), which is brittle to harmless formatting changes (whitespace/newlines) and can match inside comments. Consider using preg_match() (whitespace-tolerant) or token_get_all() to assert the helper function is actually defined.
| if (strpos($functions, 'function syslog_apply_selected_items_action(') === false) { | |
| $tokens = token_get_all($functions); | |
| $helper_found = false; | |
| for ($i = 0, $len = count($tokens); $i < $len; $i++) { | |
| if (is_array($tokens[$i]) && $tokens[$i][0] === T_FUNCTION) { | |
| // Skip any whitespace or comments after 'function' | |
| $j = $i + 1; | |
| while ($j < $len && is_array($tokens[$j]) && in_array($tokens[$j][0], [T_WHITESPACE, T_COMMENT, T_DOC_COMMENT], true)) { | |
| $j++; | |
| } | |
| if ($j < $len && is_array($tokens[$j]) && $tokens[$j][0] === T_STRING && $tokens[$j][1] === 'syslog_apply_selected_items_action') { | |
| $helper_found = true; | |
| break; | |
| } | |
| } | |
| } | |
| if (!$helper_found) { |
There was a problem hiding this comment.
Fixed — using preg_match() now.
| if (strpos($content, 'syslog_apply_selected_items_action(') === false) { | ||
| fwrite(STDERR, "Shared selected-items action helper is not used in $target\n"); | ||
| exit(1); | ||
| } |
There was a problem hiding this comment.
This usage assertion relies on strpos($content, 'syslog_apply_selected_items_action('), which will fail if the call is reformatted (e.g., syslog_apply_selected_items_action () and can be satisfied by a commented-out string. Consider switching this to a whitespace-tolerant regex or token-based search to make the regression test stable.
There was a problem hiding this comment.
Fixed — using preg_match() now.
functions.php
Outdated
| $action_function($selected_item); | ||
| } | ||
| } elseif ($export_action != '' && $drp_action == $export_action) { | ||
| $_SESSION['exporter'] = $export_items; |
There was a problem hiding this comment.
syslog_apply_selected_items_action stores the raw selected_items request parameter ($export_items from get_nfilter_request_var('selected_items')) directly in $_SESSION['exporter'], which is later embedded into a JavaScript document.location string in the alert/report/removal pages without any escaping. An attacker can tamper with the selected_items POST value to include characters that break out of the single-quoted JS string (for example by appending data after a valid serialized array), leading to arbitrary script execution in the context of an authenticated user when the auto-export redirect runs. To fix this, avoid propagating the raw request value into the session for use in HTML/JS; instead derive the export parameter from the sanitized $selected_items array and ensure it is properly URL-encoded or otherwise safely escaped before being inserted into HTML or JavaScript contexts.
| $_SESSION['exporter'] = $export_items; | |
| /* Derive exporter from sanitized selected items, not raw request data */ | |
| if (is_array($selected_items) && cacti_sizeof($selected_items)) { | |
| $_SESSION['exporter'] = rawurlencode(serialize($selected_items)); | |
| } else { | |
| unset($_SESSION['exporter']); | |
| } |
There was a problem hiding this comment.
Fixed — rawurlencode(serialize($selected_items)) now.
Fixes Cacti#276 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
rawurlencode(serialize($selected_items)) replaces storing the raw request string directly in $_SESSION['exporter']. The raw value was later embedded verbatim in a document.location JS string, which allowed XSS if the serialized payload contained quote or bracket characters. Use the already-sanitized $selected_items array, re-serialize it, then URL-encode before session storage so the JS embed is always safe. Also tighten the regression test to use preg_match instead of strpos so whitespace variations in the function signature do not cause false failures. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
0fa3c47 to
620318c
Compare
Summary
Fixes #276
Validation