Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## ChangeLog

--- develop ---
* security: Replace the confirmation pages' inline `onClick='cactiReturnTo()'` Cancel buttons with the CSP-safe `cactiReturnTo` class so they no longer trip Cacti's Content-Security-Policy `script-src-attr` directive
* security: Move the filter controls' inline `onChange`/`onClick` handlers into jQuery `ready()` event bindings on the threshold, notification list, notification queue, template and device/log status pages so they no longer trip Cacti's Content-Security-Policy `script-src-attr` directive
* dev: Remove the inert COMPOSER_ROOT_VERSION env from the Pest CI step
* feature: Restyle the Thold, Host status and Log status legends as rounded, evenly-spaced solid-colour chips for a clearer, more readable status key across every theme
* dev: Keep the status-legend chips equal width (sized to the longest label) as the legend wraps responsively
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ changes through Email, Syslog, and either SNMP Trap or Inform.
NOTE: The Thold plugin that is in GitHub is ONLY compatible with Cacti 1.0.0 and
above!

## 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

To install the plugin, simply copy the plugin_thold directory to Cacti's plugins
Expand Down
2 changes: 1 addition & 1 deletion locales/po/cacti.pot
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Cacti \n"
"Report-Msgid-Bugs-To: developers@cacti.net\n"
"POT-Creation-Date: 2026-09-30 21:27-0400\n"
"POT-Creation-Date: 2026-10-07 15:19-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Cacti Developers <developers@cacti.net>>\n"
"Language-Team: Cacti Developers <developers@cacti.net>\n"
Expand Down
82 changes: 57 additions & 25 deletions notify_lists.php
Original file line number Diff line number Diff line change
Expand Up @@ -718,7 +718,7 @@ function form_actions() {
</td>
</tr>";

$save_html = "<input type='button' value='" . __esc('Cancel', 'thold') . "' onClick='cactiReturnTo()'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Delete Notification List(s)', 'thold') . "'>";
$save_html = "<input class='cactiReturnTo' type='button' value='" . __esc('Cancel', 'thold') . "'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Delete Notification List(s)', 'thold') . "'>";
} elseif (get_request_var('drp_action') == '2') { // duplicate
print "<tr>
<td class='textArea'>
Expand All @@ -730,7 +730,7 @@ function form_actions() {
print '</p></td>
</tr>';

$save_html = "<input type='button' value='" . __esc('Cancel', 'thold') . "' onClick='cactiReturnTo()'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Duplicate Notification List(s)', 'thold') . "'>";
$save_html = "<input class='cactiReturnTo' type='button' value='" . __esc('Cancel', 'thold') . "'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Duplicate Notification List(s)', 'thold') . "'>";
}
} else {
raise_message(40);
Expand Down Expand Up @@ -792,7 +792,7 @@ function form_actions() {
</td>
</tr>';

$save_html = "<input type='button' value='" . __esc('Cancel', 'thold') . "' onClick='cactiReturnTo()'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Associate Notification List(s)', 'thold') . "'>";
$save_html = "<input class='cactiReturnTo' type='button' value='" . __esc('Cancel', 'thold') . "'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Associate Notification List(s)', 'thold') . "'>";
} elseif (get_request_var('drp_action') == '2') { // disassociate
print "<tr>
<td class='textArea'>
Expand All @@ -807,7 +807,7 @@ function form_actions() {
</td>
</tr>';

$save_html = "<input type='button' value='" . __esc('Cancel', 'thold') . "' onClick='cactiReturnTo()'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Disassociate Notification List(s)', 'thold') . "'>";
$save_html = "<input class='cactiReturnTo' type='button' value='" . __esc('Cancel', 'thold') . "'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Disassociate Notification List(s)', 'thold') . "'>";
}
} else {
raise_message(40);
Expand Down Expand Up @@ -870,7 +870,7 @@ function form_actions() {
</td>
</tr>';

$save_html = "<input type='button' value='" . __esc('Cancel', 'thold') . "' onClick='cactiReturnTo()'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Associate Notification List(s)', 'thold') . "'>";
$save_html = "<input class='cactiReturnTo' type='button' value='" . __esc('Cancel', 'thold') . "'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Associate Notification List(s)', 'thold') . "'>";
} elseif (get_request_var('drp_action') == '2') { // disassociate
print "<tr>
<td class='textArea'>
Expand All @@ -885,7 +885,7 @@ function form_actions() {
</td>
</tr>';

$save_html = "<input type='button' value='" . __esc('Cancel', 'thold') . "' onClick='cactiReturnTo()'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Disassociate Notification List(s)', 'thold') . "'>";
$save_html = "<input class='cactiReturnTo' type='button' value='" . __esc('Cancel', 'thold') . "'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Disassociate Notification List(s)', 'thold') . "'>";
}
} else {
raise_message(40);
Expand Down Expand Up @@ -951,7 +951,7 @@ function form_actions() {
</td>
</tr>';

$save_html = "<input type='button' value='" . __esc('Cancel', 'thold') . "' onClick='cactiReturnTo()'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Associate Notification List(s)', 'thold') . "'>";
$save_html = "<input class='cactiReturnTo' type='button' value='" . __esc('Cancel', 'thold') . "'>&nbsp;<input type='submit' value='" . __esc('Continue', 'thold') . "' title='" . __esc('Associate Notification List(s)', 'thold') . "'>";
} elseif (get_request_var('drp_action') == '2') { // disassociate
print "<tr>
<td class='textArea'>
Expand All @@ -970,7 +970,7 @@ function form_actions() {
</td>
</tr>';

$save_html = "<input type='button' value='" . __esc('Cancel', 'thold') . "' onClick='cactiReturnTo()'>&nbsp;<input type='submit' value='" . __('Continue', 'thold') . "' title='" . __esc('Disassociate Notification List(s)', 'thold') . "'>";
$save_html = "<input class='cactiReturnTo' type='button' value='" . __esc('Cancel', 'thold') . "'>&nbsp;<input type='submit' value='" . __('Continue', 'thold') . "' title='" . __esc('Disassociate Notification List(s)', 'thold') . "'>";
}
} else {
raise_message(40);
Expand Down Expand Up @@ -1258,7 +1258,7 @@ function hosts($header_label) {
<?php print __('Search', 'thold'); ?>
</td>
<td>
<input type='text' id='rfilter' size='30' value='<?php print html_escape_request_var('rfilter'); ?>' onChange='applyFilter()'>
<input type='text' id='rfilter' size='30' value='<?php print html_escape_request_var('rfilter'); ?>'>
</td>
<td>
<?php print __('Site'); ?>
Expand All @@ -1282,7 +1282,7 @@ function hosts($header_label) {
<?php print __('Device Template', 'thold'); ?>
</td>
<td>
<select id='host_template_id' onChange='applyFilter()'>
<select id='host_template_id'>
<option value='-1'<?php if (get_request_var('host_template_id') == '-1') {?> selected<?php }?>><?php print __('Any', 'thold'); ?></option>
<option value='0'<?php if (get_request_var('host_template_id') == '0') {?> selected<?php }?>><?php print __('None', 'thold'); ?></option>
<?php
Expand All @@ -1302,7 +1302,7 @@ function hosts($header_label) {
<?php print __('Devices', 'thold'); ?>
</td>
<td>
<select id='rows' onChange='applyFilter()'>
<select id='rows'>
<option value='-1'<?php if (get_request_var('rows') == '-1') {?> selected<?php }?>><?php print __('Default', 'thold'); ?></option>
<?php
if (cacti_sizeof($item_rows)) {
Expand All @@ -1315,14 +1315,14 @@ function hosts($header_label) {
</td>
<td>
<span>
<input type='checkbox' id='associated' onChange='applyFilter()' <?php print(get_request_var('associated') == 'true' || get_request_var('associated') == 'on' ? 'checked' : ''); ?>>
<input type='checkbox' id='associated' <?php print(get_request_var('associated') == 'true' || get_request_var('associated') == 'on' ? 'checked' : ''); ?>>
<label for='associated'><?php print __('Associated', 'thold'); ?></label>
</span>
</td>
<td>
<span>
<input type='submit' value='<?php print __esc('Go', 'thold'); ?>' title='<?php print __esc('Set/Refresh Filters', 'thold'); ?>'>
<input type='button' name='clear' value='<?php print __esc('Clear', 'thold'); ?>' onClick='clearFilter()' title='<?php print __esc('Clear Filters', 'thold'); ?>'>
<input type='button' id='clear' value='<?php print __esc('Clear', 'thold'); ?>' title='<?php print __esc('Clear Filters', 'thold'); ?>'>
</span>
</td>
</tr>
Expand Down Expand Up @@ -1354,6 +1354,14 @@ function clearFilter() {
$('#site_id').off('change').on('change', function() {
applyFilter();
});

$('#rfilter, #host_template_id, #rows, #associated').off('change').on('change', function() {
applyFilter();
});

$('#clear').click(function() {
clearFilter();
});
});

</script>
Expand Down Expand Up @@ -1636,7 +1644,7 @@ function tholds($header_label) {
<?php print __('Search', 'thold'); ?>
</td>
<td>
<input type='text' id='rfilter' size='30' value='<?php print html_escape_request_var('rfilter'); ?>' onChange='applyFilter()'>
<input type='text' id='rfilter' size='30' value='<?php print html_escape_request_var('rfilter'); ?>'>
</td>
<td>
<?php print __('Site'); ?>
Expand All @@ -1660,7 +1668,7 @@ function tholds($header_label) {
<?php print __('Template', 'thold'); ?>
</td>
<td>
<select id='template' onChange='applyFilter()'>
<select id='template'>
<option value='-1'><?php print __('Any', 'thold'); ?></option>
<?php
foreach ($data_templates as $row) {
Expand All @@ -1673,7 +1681,7 @@ function tholds($header_label) {
<?php print __('State', 'thold'); ?>
</td>
<td>
<select id='state' onChange='applyFilter()'>
<select id='state'>
<option value='-1'<?php if (get_request_var('state') == '-1') {?> selected<?php }?>><?php print __('All', 'thold'); ?></option>
<option value='1'<?php if (get_request_var('state') == '1') {?> selected<?php }?>><?php print __('Breached', 'thold'); ?></option>
<option value='3'<?php if (get_request_var('state') == '3') {?> selected<?php }?>><?php print __('Triggered', 'thold'); ?></option>
Expand All @@ -1685,7 +1693,7 @@ function tholds($header_label) {
<?php print __('Thresholds', 'thold'); ?>
</td>
<td>
<select id='rows' onChange='applyFilter()'>
<select id='rows'>
<option value='-1'<?php if (get_request_var('rows') == '-1') {?> selected<?php }?>><?php print __('Default', 'thold'); ?></option>
<?php
if (cacti_sizeof($item_rows)) {
Expand All @@ -1698,14 +1706,14 @@ function tholds($header_label) {
</td>
<td>
<span>
<input type='checkbox' id='associated' onChange='applyFilter()' <?php print(get_request_var('associated') == 'true' || get_request_var('associated') == 'on' ? 'checked' : ''); ?>>
<input type='checkbox' id='associated' <?php print(get_request_var('associated') == 'true' || get_request_var('associated') == 'on' ? 'checked' : ''); ?>>
<label for='associated'><?php print __('Associated', 'thold'); ?></label>
</span>
</td>
<td>
<span>
<input type='submit' value='<?php print __esc('Go', 'thold'); ?>' title='<?php print __esc('Set/Refresh Filters', 'thold'); ?>'>
<input type='button' name='clear' value='<?php print __esc('Clear', 'thold'); ?>' onClick='clearFilter()' title='<?php print __esc('Clear Filters', 'thold'); ?>'>
<input type='button' id='clear' value='<?php print __esc('Clear', 'thold'); ?>' title='<?php print __esc('Clear Filters', 'thold'); ?>'>
</span>
</td>
</tr>
Expand Down Expand Up @@ -1738,6 +1746,14 @@ function clearFilter() {
$('#site_id').off('change').on('change', function() {
applyFilter();
});

$('#rfilter, #template, #state, #rows, #associated').off('change').on('change', function() {
applyFilter();
});

$('#clear').click(function() {
clearFilter();
});
});

</script>
Expand Down Expand Up @@ -1982,13 +1998,13 @@ function templates($header_label) {
<?php print __('Search', 'thold'); ?>
</td>
<td>
<input type='text' id='rfilter' size='30' value='<?php print html_escape_request_var('rfilter'); ?>' onChange='applyFilter()'>
<input type='text' id='rfilter' size='30' value='<?php print html_escape_request_var('rfilter'); ?>'>
</td>
<td>
<?php print __('Rows', 'thold'); ?>
</td>
<td>
<select id='rows' onChange='applyFilter()'>
<select id='rows'>
<option value='-1'<?php if (get_request_var('rows') == '-1') {?> selected<?php }?>><?php print __('Default', 'thold'); ?></option>
<?php
if (cacti_sizeof($item_rows)) {
Expand All @@ -2001,14 +2017,14 @@ function templates($header_label) {
</td>
<td>
<span>
<input type='checkbox' id='associated' onChange='applyFilter()' <?php print(get_request_var('associated') == 'true' || get_request_var('associated') == 'on' ? 'checked' : ''); ?>>
<input type='checkbox' id='associated' <?php print(get_request_var('associated') == 'true' || get_request_var('associated') == 'on' ? 'checked' : ''); ?>>
<label for='associated'><?php print __('Associated', 'thold'); ?></label>
</span>
</td>
<td>
<span>
<input type='submit' value='<?php print __esc('Go', 'thold'); ?>' title='<?php print __esc('Set/Refresh Filters', 'thold'); ?>'>
<input type='button' id='clear' value='<?php print __esc('Clear', 'thold'); ?>' onClick='clearFilter()' title='<?php print __esc('Clear Filters', 'thold'); ?>'>
<input type='button' id='clear' value='<?php print __esc('Clear', 'thold'); ?>' title='<?php print __esc('Clear Filters', 'thold'); ?>'>
</span>
</td>
</tr>
Expand All @@ -2034,6 +2050,14 @@ function clearFilter() {
event.preventDefault();
applyFilter();
});

$('#rfilter, #rows, #associated').off('change').on('change', function() {
applyFilter();
});

$('#clear').click(function() {
clearFilter();
});
});

</script>
Expand Down Expand Up @@ -2343,7 +2367,7 @@ function lists() {
<?php print __('Lists', 'thold')?>
</td>
<td>
<select id='rows' onChange='applyFilter()'>
<select id='rows'>
<option value='-1'<?php if (get_request_var('rows') == '-1') {?> selected<?php }?>><?php print __('Default', 'thold'); ?></option>
<?php
if (cacti_sizeof($item_rows)) {
Expand All @@ -2358,7 +2382,7 @@ function lists() {
<input id='refresh' type='button' value='<?php print __esc('Go', 'thold'); ?>' title='<?php print __esc('Set/Refresh Filters', 'thold'); ?>'>
</td>
<td>
<input id='clear' type='button' value='<?php print __esc('Clear', 'thold'); ?>' title='<?php print __esc('Clear Filters', 'thold'); ?>' onClick='clearFilter()'>
<input id='clear' type='button' value='<?php print __esc('Clear', 'thold'); ?>' title='<?php print __esc('Clear Filters', 'thold'); ?>'>
</td>
</tr>
</table>
Expand All @@ -2382,6 +2406,14 @@ function clearFilter() {
event.preventDefault();
applyFilter();
});

$('#rows').off('change').on('change', function() {
applyFilter();
});

$('#clear').click(function() {
clearFilter();
});
});

</script>
Expand Down
12 changes: 8 additions & 4 deletions notify_queue.php
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ function form_actions() {
</td>
</tr>";

$save_html = "<input type='button' class='ui-button ui-corner-all ui-widget' value='" . __esc('Cancel') . "' onClick='cactiReturnTo()'>&nbsp;<input type='submit' class='ui-button ui-corner-all ui-widget' value='" . __esc('Continue') . "' title='" . __n('Delete Notification', 'Delete Notifications', cacti_sizeof($notify_array)) . "'>";
$save_html = "<input type='button' class='ui-button ui-corner-all ui-widget cactiReturnTo' value='" . __esc('Cancel') . "'>&nbsp;<input type='submit' class='ui-button ui-corner-all ui-widget' value='" . __esc('Continue') . "' title='" . __n('Delete Notification', 'Delete Notifications', cacti_sizeof($notify_array)) . "'>";
}
} else {
raise_message(40);
Expand Down Expand Up @@ -295,7 +295,7 @@ function notify_queue() {
<?php print __('Topic', 'thold'); ?>
</td>
<td>
<select id='topic' onChange='applyFilter()'>
<select id='topic'>
<option value='-1'<?php print (get_request_var('topic') == '-1' ? ' selected>' : '>') . __('All', 'thold'); ?></option>
<?php
if (cacti_sizeof($thold_notification_topics)) {
Expand All @@ -314,7 +314,7 @@ function notify_queue() {
<?php print __('Processed', 'thold'); ?>
</td>
<td>
<select id='processed' onChange='applyFilter()'>
<select id='processed'>
<option value='-1'<?php print (get_request_var('processed') == '-1' ? ' selected>' : '>') . __('All', 'thold'); ?></option>
<option value='0'<?php print (get_request_var('processed') == '0' ? ' selected>' : '>') . __('No', 'thold'); ?></option>
<option value='1'<?php print (get_request_var('processed') == '1' ? ' selected>' : '>') . __('Yes', 'thold'); ?></option>
Expand All @@ -324,7 +324,7 @@ function notify_queue() {
<?php print __('Rows', 'thold'); ?>
</td>
<td>
<select id='rows' onChange='applyFilter()'>
<select id='rows'>
<option value='-1'<?php print (get_request_var('rows') == '-1' ? ' selected>' : '>') . __('Default', 'thold'); ?></option>
<?php
if (cacti_sizeof($item_rows) > 0) {
Expand Down Expand Up @@ -368,6 +368,10 @@ function clearFilter() {
}

$(function() {
$('#topic, #processed, #rows').change(function() {
applyFilter();
});

$('#refresh').click(function() {
applyFilter();
});
Expand Down
Loading
Loading