mirror of
https://github.com/Cacti/cacti.git
synced 2026-10-23 03:27:02 +09:00
fix(security): close validator migration regressions (#7240)
* feat(validator): add settings constraint validation pilot Routes saved settings through Symfony Validator so include/global_settings.php can declare per-setting constraints inline. The save handler runs one validator pass and surfaces violations via the existing raise_message() pattern, replacing scattered ad-hoc checks. Pilot covers 12 high-value settings; the rest stay on the existing implicit form-render checks. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci(infection): allow infection/extension-installer composer plugin Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs(validator): document must-be-posted-to-validate contract Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(bootstrap): guard Symfony autoload in global_settings before use declarations Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(test): remove redundant autoload require in CactiSettingsTest Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(test): restore require_once for CactiSettings (not in Composer autoload) Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * feat(validator): fold helper into settings pilot * fix(validator): translate default Symfony constraint messages Default Symfony NotBlank/Length/Range/Choice/Positive messages render in English regardless of Cacti locale because the validator runs without a Symfony Translator. Pass explicit __()-wrapped message, minMessage, maxMessage, and notInRangeMessage options on each bare constraint in include/global_settings.php so violations participate in Cacti's gettext pipeline. Documents the no-Translator decision in CactiValidator so future contributors know to translate at the call site. Addresses Copilot PR #7077 review feedback. Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * fix(graph): improve remote agent parsing and RRD path validation * feat(validator): migrate automation_graph_rules.php to symfony validator * refactor(validator): move automation validator helper to shared library and enhance tests * feat(validator): migrate automation_networks.php to symfony validator * feat(validator): migrate automation_snmp.php to symfony validator * feat(validator): migrate automation_templates.php to symfony validator * feat(validator): migrate automation_tree_rules.php to symfony validator * refactor(automation): move api_networks_save to shared library for testability * feat(validator): add validateInput helper and migrate color_templates.php * feat(validator): migrate host_templates.php to symfony validator * feat(validator): migrate graph_templates.php to symfony validator * feat(validator): migrate data_templates.php to symfony validator * feat(validator): migrate data_input.php to symfony validator * feat(validator): migrate data_queries.php to symfony validator * feat(validator): migrate graphs_new.php to symfony validator * feat(validator): migrate graphs.php to symfony validator * feat(validator): migrate data_sources.php to symfony validator * feat(validator): migrate user_group_admin.php to symfony validator * feat(validator): migrate managers.php to symfony validator * feat(validator): migrate package_repos.php to symfony validator * Refactor pollers.php to use CactiValidator * fix(security): close validator migration regressions * test(snmp): add spine docker harness * fix(review): address validator migration feedback * fix(deps): include validator runtime packages * chore(deps): normalize composer.json require-block indentation The validator migration introduced tab-indented entries in an otherwise space-indented require block. Re-indent the stevenmaguire/* and symfony/* lines to 8 spaces so the block is consistent. Co-Authored-By: Oz <oz-agent@warp.dev> * fix(graphs): repair graph json response branch * fix(validation): apply php cs fixer * ci(codeql): skip autobuild for interpreted scans * fix(link): satisfy phpstan path guard * chore(pr): remove branch pollution * ci(codeql): align autobuild pin with init and analyze Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * refactor(automation): use CactiValidator::validateInput, drop wrapper automation_validate_input() in lib/api_automation.php was a byte-for-byte duplicate of CactiValidator::validateInput() (identical session handling and raise_message() semantics, and it already delegated to CactiValidator::validate internally). Per review feedback, use the shared class directly everywhere instead of a parallel automation-only wrapper. - Remove automation_validate_input() from lib/api_automation.php - Replace all call sites with CactiValidator::validateInput() (automation_templates/graph_rules/tree_rules/snmp and api_networks_save) - Update the automation validator unit tests to match - Add @param/@return PHPDoc to CactiValidator specific-validator methods Co-Authored-By: Oz <oz-agent@warp.dev> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: Thomas Vincent <thomas@vincent.dev> Co-authored-by: Oz <oz-agent@warp.dev> Co-authored-by: TheWitness <thewitness@cacti.net>
This commit is contained in:
51 files changed
+2743
-420
No files matched your search
+20
-17
@@ -25,6 +25,9 @@
|
||||
require('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/api_automation.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/data_query.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
AUTOMATION_ACTION_GRAPH_DUPLICATE => __('Duplicate'),
|
||||
@@ -265,9 +268,9 @@ function form_save() : void {
|
||||
|
||||
$save['id'] = gnrv('id');
|
||||
$save['hash'] = get_hash_automation(grv('id'), 'automation_graph_rules');
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save['snmp_query_id'] = form_input_validate(gnrv('snmp_query_id'), 'snmp_query_id', '^[0-9]+$', false, 3);
|
||||
$save['graph_type_id'] = (isrv('graph_type_id')) ? form_input_validate(gnrv('graph_type_id'), 'graph_type_id', '^[0-9]+$', false, 3) : 0;
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()]);
|
||||
$save['snmp_query_id'] = CactiValidator::validateInput(gnrv('snmp_query_id'), 'snmp_query_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['graph_type_id'] = (isrv('graph_type_id')) ? CactiValidator::validateInput(gnrv('graph_type_id'), 'graph_type_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]) : 0;
|
||||
$save['enabled'] = (isrv('enabled') ? 'on' : '');
|
||||
|
||||
if (!is_error_message()) {
|
||||
@@ -288,14 +291,14 @@ function form_save() : void {
|
||||
// ====================================================
|
||||
|
||||
$save = [];
|
||||
$save['id'] = form_input_validate(grv('item_id'), 'item_id', '^[0-9]+$', false, 3);
|
||||
$save['id'] = CactiValidator::validateInput(grv('item_id'), 'item_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['hash'] = get_hash_automation(grv('id_item'), 'automation_graph_rule_items');
|
||||
$save['rule_id'] = form_input_validate(grv('id'), 'id', '^[0-9]+$', false, 3);
|
||||
$save['sequence'] = form_input_validate(gnrv('sequence'), 'sequence', '^[0-9]+$', false, 3);
|
||||
$save['operation'] = form_input_validate(gnrv('operation'), 'operation', '^[-0-9]+$', true, 3);
|
||||
$save['field'] = form_input_validate(((isrv('field') && gnrv('field') != '0') ? gnrv('field') : ''), 'field', '', true, 3);
|
||||
$save['operator'] = form_input_validate((isrv('operator') ? gnrv('operator') : ''), 'operator', '^[0-9]+$', true, 3);
|
||||
$save['pattern'] = form_input_validate((isrv('pattern') ? gnrv('pattern') : ''), 'pattern', '', true, 3);
|
||||
$save['rule_id'] = CactiValidator::validateInput(grv('id'), 'id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['sequence'] = CactiValidator::validateInput(gnrv('sequence'), 'sequence', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['operation'] = CactiValidator::validateInput(gnrv('operation'), 'operation', [new Assert\Regex('/^[-0-9]+$/')]);
|
||||
$save['field'] = CactiValidator::validateInput(((isrv('field') && gnrv('field') != '0') ? gnrv('field') : ''), 'field', []);
|
||||
$save['operator'] = CactiValidator::validateInput((isrv('operator') ? gnrv('operator') : ''), 'operator', [new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['pattern'] = CactiValidator::validateInput((isrv('pattern') ? gnrv('pattern') : ''), 'pattern', []);
|
||||
|
||||
// Test for SQL injections
|
||||
$field_name = str_replace(['ht.', 'h.', 'gt.', 'gtg.'], '', $save['field']);
|
||||
@@ -346,15 +349,15 @@ function form_save() : void {
|
||||
|
||||
$save = [];
|
||||
|
||||
$save['id'] = form_input_validate(grv('item_id'), 'item_id', '^[0-9]+$', false, 3);
|
||||
$save['id'] = CactiValidator::validateInput(grv('item_id'), 'item_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['hash'] = get_hash_automation(grv('item_idid'), 'automation_match_rule_items');
|
||||
$save['rule_id'] = form_input_validate(grv('id'), 'id', '^[0-9]+$', false, 3);
|
||||
$save['rule_id'] = CactiValidator::validateInput(grv('id'), 'id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['rule_type'] = AUTOMATION_RULE_TYPE_GRAPH_MATCH;
|
||||
$save['sequence'] = form_input_validate(gnrv('sequence'), 'sequence', '^[0-9]+$', false, 3);
|
||||
$save['operation'] = form_input_validate(gnrv('operation'), 'operation', '^[-0-9]+$', true, 3);
|
||||
$save['field'] = form_input_validate(((isrv('field') && gnrv('field') != '0') ? gnrv('field') : ''), 'field', '', true, 3);
|
||||
$save['operator'] = form_input_validate((isrv('operator') ? gnrv('operator') : ''), 'operator', '^[0-9]+$', true, 3);
|
||||
$save['pattern'] = form_input_validate((isrv('pattern') ? gnrv('pattern') : ''), 'pattern', '', true, 3);
|
||||
$save['sequence'] = CactiValidator::validateInput(gnrv('sequence'), 'sequence', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['operation'] = CactiValidator::validateInput(gnrv('operation'), 'operation', [new Assert\Regex('/^[-0-9]+$/')]);
|
||||
$save['field'] = CactiValidator::validateInput(((isrv('field') && gnrv('field') != '0') ? gnrv('field') : ''), 'field', []);
|
||||
$save['operator'] = CactiValidator::validateInput((isrv('operator') ? gnrv('operator') : ''), 'operator', [new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['pattern'] = CactiValidator::validateInput((isrv('pattern') ? gnrv('pattern') : ''), 'pattern', []);
|
||||
|
||||
// Test for SQL injections
|
||||
$field_name = str_replace(['ht.', 'h.', 'gt.'], '', $save['field']);
|
||||
|
||||
+3
-81
@@ -27,6 +27,9 @@ require('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/api_scheduler.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/snmp.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
1 => __('Delete'),
|
||||
@@ -358,87 +361,6 @@ function api_networks_discover(int $network_id, bool $discover_debug, bool $disc
|
||||
force_session_data();
|
||||
}
|
||||
|
||||
function api_networks_save(array $post) : mixed {
|
||||
if (empty($post['network_id'])) {
|
||||
$save['id'] = form_input_validate($post['id'], 'id', '^[0-9]+$', false, 3);
|
||||
$save['hash'] = get_hash_automation($post['id'], 'automation_networks');
|
||||
|
||||
// general information
|
||||
$save['name'] = form_input_validate($post['name'], 'name', '', false, 3);
|
||||
$save['poller_id'] = form_input_validate($post['poller_id'], 'poller_id', '^[0-9]+$', false, 3);
|
||||
$save['site_id'] = form_input_validate($post['site_id'], 'site_id', '^[0-9]+$', false, 3);
|
||||
$save['subnet_range'] = form_input_validate($post['subnet_range'], 'subnet_range', '', false, 3);
|
||||
$save['ignore_ips'] = form_input_validate($post['ignore_ips'], 'ignore_ips', '', true, 3);
|
||||
$save['dns_servers'] = form_input_validate($post['dns_servers'], 'dns_servers', '', true, 3);
|
||||
|
||||
$save['threads'] = form_input_validate($post['threads'], 'threads', '^[0-9]+$', false, 3);
|
||||
$save['run_limit'] = form_input_validate($post['run_limit'], 'run_limit', '^[0-9]+$', false, 3);
|
||||
|
||||
$save['enabled'] = (isset($post['enabled']) ? 'on' : '');
|
||||
|
||||
// notification settings
|
||||
$save['notification_enabled'] = (isset($post['notification_enabled']) ? 'on' : '');
|
||||
$save['notification_email'] = form_input_validate($post['notification_email'], 'notification_email', '', true, 3);
|
||||
|
||||
$save['notification_fromname'] = form_input_validate($post['notification_fromname'], 'notification_fromname', '', true, 3);
|
||||
$save['notification_fromemail'] = form_input_validate($post['notification_fromemail'], 'notification_fromemail', '', true, 3);
|
||||
|
||||
$save['enable_netbios'] = (isset($post['enable_netbios']) ? 'on' : '');
|
||||
$save['add_to_cacti'] = (isset($post['add_to_cacti']) ? 'on' : '');
|
||||
$save['same_sysname'] = (isset($post['same_sysname']) ? 'on' : '');
|
||||
$save['rerun_data_queries'] = (isset($post['rerun_data_queries']) ? 'on' : '');
|
||||
|
||||
// discovery connectivity settings
|
||||
$save['snmp_id'] = form_input_validate($post['snmp_id'], 'snmp_id', '^[0-9]+$', false, 3);
|
||||
$save['ping_method'] = form_input_validate($post['ping_method'], 'ping_method', '^[0-9]+$', false, 3);
|
||||
$save['ping_port'] = form_input_validate($post['ping_port'], 'ping_port', '^[0-9]+$', false, 3);
|
||||
$save['ping_timeout'] = form_input_validate($post['ping_timeout'], 'ping_timeout', '^[0-9]+$', false, 3);
|
||||
$save['ping_retries'] = form_input_validate($post['ping_retries'], 'ping_retries', '^[0-9]+$', false, 3);
|
||||
|
||||
$save = api_scheduler_augment_save($save, $post);
|
||||
|
||||
// validate the network definitions and rais error if failed
|
||||
$continue = true;
|
||||
$total_ips = 0;
|
||||
$networks = explode(',', $save['subnet_range']);
|
||||
|
||||
if (cacti_sizeof($networks)) {
|
||||
foreach ($networks as $net) {
|
||||
$ips = automation_calculate_total_ips($net);
|
||||
|
||||
if ($ips !== false) {
|
||||
$total_ips += $ips;
|
||||
} else {
|
||||
$continue = false;
|
||||
raise_message('automation_message', __esc('ERROR: Network \'%s\' is Invalid.', $net), MESSAGE_LEVEL_ERROR);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($continue) {
|
||||
$save['total_ips'] = $total_ips;
|
||||
|
||||
$network_id = 0;
|
||||
|
||||
if (!is_error_message()) {
|
||||
$network_id = sql_save($save, 'automation_networks');
|
||||
|
||||
if ($network_id) {
|
||||
raise_message(1);
|
||||
} else {
|
||||
raise_message(2);
|
||||
}
|
||||
}
|
||||
|
||||
return $network_id;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function form_actions() : void {
|
||||
global $actions;
|
||||
|
||||
|
||||
+21
-18
@@ -25,6 +25,9 @@
|
||||
require('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/api_automation.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/snmp.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
1 => __('Delete'),
|
||||
@@ -274,7 +277,7 @@ function form_save() : void {
|
||||
|
||||
$save['id'] = grv('id');
|
||||
$save['hash'] = get_hash_automation(grv('id'), 'automation_snmp');
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()]);
|
||||
|
||||
if (!is_error_message()) {
|
||||
$id = sql_save($save, 'automation_snmp');
|
||||
@@ -295,24 +298,24 @@ function form_save() : void {
|
||||
|
||||
$save = [];
|
||||
|
||||
$save['id'] = form_input_validate(grv('item_id'), '', '^[0-9]+$', false, 3);
|
||||
$save['id'] = CactiValidator::validateInput(grv('item_id'), 'item_id', [new Assert\NotBlank(), new Assert\Type('numeric'), new Assert\GreaterThanOrEqual(0)]);
|
||||
$save['hash'] = get_hash_automation(grv('item_id'), 'automation_snmp_items');
|
||||
$save['snmp_id'] = form_input_validate(gnrv('id'), 'snmp_id', '^[0-9]+$', false, 3);
|
||||
$save['sequence'] = form_input_validate(gnrv('sequence'), 'sequence', '^[0-9]+$', false, 3);
|
||||
$save['snmp_community'] = form_input_validate(gnrv('snmp_community'), 'snmp_community', '', false, 3);
|
||||
$save['snmp_version'] = form_input_validate(gnrv('snmp_version'), 'snmp_version', '', false, 3);
|
||||
$save['snmp_username'] = form_input_validate(gnrv('snmp_username'), 'snmp_username', '', true, 3);
|
||||
$save['snmp_password'] = form_input_validate(gnrv('snmp_password'), 'snmp_password', '', true, 3);
|
||||
$save['snmp_auth_protocol'] = form_input_validate(gnrv('snmp_auth_protocol'), 'snmp_auth_protocol', '', true, 3);
|
||||
$save['snmp_priv_passphrase'] = form_input_validate(gnrv('snmp_priv_passphrase'), 'snmp_priv_passphrase', '', true, 3);
|
||||
$save['snmp_priv_protocol'] = form_input_validate(gnrv('snmp_priv_protocol'), 'snmp_priv_protocol', '', true, 3);
|
||||
$save['snmp_context'] = form_input_validate(gnrv('snmp_context'), 'snmp_context', '', true, 3);
|
||||
$save['snmp_engine_id'] = form_input_validate(gnrv('snmp_engine_id'), 'snmp_engine_id', '', true, 3);
|
||||
$save['snmp_port'] = form_input_validate(gnrv('snmp_port'), 'snmp_port', '^[0-9]+$', false, 3);
|
||||
$save['snmp_timeout'] = form_input_validate(gnrv('snmp_timeout'), 'snmp_timeout', '^[0-9]+$', false, 3);
|
||||
$save['snmp_retries'] = form_input_validate(gnrv('snmp_retries'), 'snmp_retries', '^[0-9]+$', false, 3);
|
||||
$save['max_oids'] = form_input_validate(gnrv('max_oids'), 'max_oids', '^[0-9]+$', false, 3);
|
||||
$save['bulk_walk_size'] = form_input_validate(gnrv('bulk_walk_size'), 'bulk_walk_size', '^[\-0-9]+$', false, 3);
|
||||
$save['snmp_id'] = CactiValidator::validateInput(gnrv('id'), 'snmp_id', [new Assert\NotBlank(), new Assert\Type('numeric'), new Assert\GreaterThanOrEqual(0)]);
|
||||
$save['sequence'] = CactiValidator::validateInput(gnrv('sequence'), 'sequence', [new Assert\NotBlank(), new Assert\Type('numeric'), new Assert\GreaterThanOrEqual(0)]);
|
||||
$save['snmp_community'] = CactiValidator::validateInput(gnrv('snmp_community'), 'snmp_community', [new Assert\NotBlank()]);
|
||||
$save['snmp_version'] = CactiValidator::validateInput(gnrv('snmp_version'), 'snmp_version', [new Assert\NotBlank(), new Assert\Choice(['1', '2', '3'])]);
|
||||
$save['snmp_username'] = CactiValidator::validateInput(gnrv('snmp_username'), 'snmp_username', []);
|
||||
$save['snmp_password'] = CactiValidator::validateInput(gnrv('snmp_password'), 'snmp_password', []);
|
||||
$save['snmp_auth_protocol'] = CactiValidator::validateInput(gnrv('snmp_auth_protocol'), 'snmp_auth_protocol', []);
|
||||
$save['snmp_priv_passphrase'] = CactiValidator::validateInput(gnrv('snmp_priv_passphrase'), 'snmp_priv_passphrase', []);
|
||||
$save['snmp_priv_protocol'] = CactiValidator::validateInput(gnrv('snmp_priv_protocol'), 'snmp_priv_protocol', []);
|
||||
$save['snmp_context'] = CactiValidator::validateInput(gnrv('snmp_context'), 'snmp_context', []);
|
||||
$save['snmp_engine_id'] = CactiValidator::validateInput(gnrv('snmp_engine_id'), 'snmp_engine_id', []);
|
||||
$save['snmp_port'] = CactiValidator::validateInput(gnrv('snmp_port'), 'snmp_port', [new Assert\NotBlank(), new Assert\Range(min: 1, max: 65535)]);
|
||||
$save['snmp_timeout'] = CactiValidator::validateInput(gnrv('snmp_timeout'), 'snmp_timeout', [new Assert\NotBlank(), new Assert\Type('numeric'), new Assert\GreaterThan(0)]);
|
||||
$save['snmp_retries'] = CactiValidator::validateInput(gnrv('snmp_retries'), 'snmp_retries', [new Assert\NotBlank(), new Assert\Type('numeric'), new Assert\GreaterThanOrEqual(0)]);
|
||||
$save['max_oids'] = CactiValidator::validateInput(gnrv('max_oids'), 'max_oids', [new Assert\NotBlank(), new Assert\Type('numeric'), new Assert\GreaterThan(0)]);
|
||||
$save['bulk_walk_size'] = CactiValidator::validateInput(gnrv('bulk_walk_size'), 'bulk_walk_size', [new Assert\NotBlank(), new Assert\Type('numeric')]);
|
||||
|
||||
$item_id = null;
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@
|
||||
|
||||
require('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/api_automation.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
require_once(CACTI_PATH_LIBRARY . '/api_tree.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
||||
@@ -658,9 +662,9 @@ function form_save() : void {
|
||||
$redirect_back = false;
|
||||
|
||||
$save['id'] = gnrv('id');
|
||||
$save['hash'] = get_hash_automation(grv('id'), 'automation_templates');
|
||||
$save['host_template'] = form_input_validate(gnrv('host_template'), 'host_template', '', false, 3);
|
||||
$save['availability_method'] = form_input_validate(gnrv('availability_method'), 'availability_method', '', false, 3);
|
||||
$save['hash'] = get_hash_automation(gnrv('id'), 'automation_templates');
|
||||
$save['host_template'] = CactiValidator::validateInput(gnrv('host_template'), 'host_template', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['availability_method'] = CactiValidator::validateInput(gnrv('availability_method'), 'availability_method', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['sysDescr'] = gnrv('sysDescr');
|
||||
$save['sysName'] = gnrv('sysName');
|
||||
$save['sysOid'] = gnrv('sysOid');
|
||||
|
||||
+22
-19
@@ -26,6 +26,9 @@ require('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/api_automation.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/api_tree.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/data_query.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
AUTOMATION_ACTION_TREE_DUPLICATE => __('Duplicate'),
|
||||
@@ -279,11 +282,11 @@ function form_save() : void {
|
||||
|
||||
$save['id'] = grv('id');
|
||||
$save['hash'] = get_hash_automation(grv('id'), 'automation_tree_rules');
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', true, 3);
|
||||
$save['tree_id'] = form_input_validate(gnrv('tree_id'), 'tree_id', '^[0-9]+$', false, 3);
|
||||
$save['tree_item_id'] = isrv('tree_item_id') ? form_input_validate(gnrv('tree_item_id'), 'tree_item_id', '^[0-9]+$', false, 3) : 0;
|
||||
$save['leaf_type'] = (isrv('leaf_type')) ? form_input_validate(gnrv('leaf_type'), 'leaf_type', '^[0-9]+$', false, 3) : 0;
|
||||
$save['host_grouping_type'] = isrv('host_grouping_type') ? form_input_validate(gnrv('host_grouping_type'), 'host_grouping_type', '^[0-9]+$', false, 3) : 0;
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [], 3);
|
||||
$save['tree_id'] = CactiValidator::validateInput(gnrv('tree_id'), 'tree_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['tree_item_id'] = isrv('tree_item_id') ? CactiValidator::validateInput(gnrv('tree_item_id'), 'tree_item_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3) : 0;
|
||||
$save['leaf_type'] = (isrv('leaf_type')) ? CactiValidator::validateInput(gnrv('leaf_type'), 'leaf_type', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3) : 0;
|
||||
$save['host_grouping_type'] = isrv('host_grouping_type') ? CactiValidator::validateInput(gnrv('host_grouping_type'), 'host_grouping_type', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3) : 0;
|
||||
$save['enabled'] = (isrv('enabled') ? 'on' : '');
|
||||
|
||||
if (!is_error_message()) {
|
||||
@@ -304,15 +307,15 @@ function form_save() : void {
|
||||
// ====================================================
|
||||
|
||||
$save = [];
|
||||
$save['id'] = form_input_validate(grv('item_id'), 'item_id', '^[0-9]+$', false, 3);
|
||||
$save['id'] = CactiValidator::validateInput(grv('item_id'), 'item_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['hash'] = get_hash_automation(grv('item_id'), 'automation_match_rule_items');
|
||||
$save['rule_id'] = form_input_validate(grv('id'), 'id', '^[0-9]+$', false, 3);
|
||||
$save['rule_id'] = CactiValidator::validateInput(grv('id'), 'id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['rule_type'] = AUTOMATION_RULE_TYPE_TREE_MATCH;
|
||||
$save['sequence'] = form_input_validate(gnrv('sequence'), 'sequence', '^[0-9]+$', false, 3);
|
||||
$save['operation'] = form_input_validate(gnrv('operation'), 'operation', '^[-0-9]+$', true, 3);
|
||||
$save['field'] = form_input_validate(((isrv('field') && gnrv('field') != '0') ? gnrv('field') : ''), 'field', '', true, 3);
|
||||
$save['operator'] = form_input_validate((isrv('operator') ? gnrv('operator') : ''), 'operator', '^[0-9]+$', true, 3);
|
||||
$save['pattern'] = form_input_validate((isrv('pattern') ? gnrv('pattern') : ''), 'pattern', '', true, 3);
|
||||
$save['sequence'] = CactiValidator::validateInput(gnrv('sequence'), 'sequence', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['operation'] = CactiValidator::validateInput(gnrv('operation'), 'operation', [new Assert\Regex('/^[-0-9]+$/')], 3);
|
||||
$save['field'] = CactiValidator::validateInput(((isrv('field') && gnrv('field') != '0') ? gnrv('field') : ''), 'field', [], 3);
|
||||
$save['operator'] = CactiValidator::validateInput((isrv('operator') ? gnrv('operator') : ''), 'operator', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['pattern'] = CactiValidator::validateInput((isrv('pattern') ? gnrv('pattern') : ''), 'pattern', [], 3);
|
||||
|
||||
// Test for SQL injections
|
||||
$field_name = str_replace(['ht.', 'h.', 'gt.'], '', $save['field']);
|
||||
@@ -350,15 +353,15 @@ function form_save() : void {
|
||||
|
||||
$save = [];
|
||||
|
||||
$save['id'] = form_input_validate(grv('item_id'), 'item_id', '^[0-9]+$', false, 3);
|
||||
$save['id'] = CactiValidator::validateInput(grv('item_id'), 'item_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['hash'] = get_hash_automation(grv('item_id'), 'automation_tree_rule_items');
|
||||
$save['rule_id'] = form_input_validate(grv('id'), 'id', '^[0-9]+$', false, 3);
|
||||
$save['sequence'] = form_input_validate(gnrv('sequence'), 'sequence', '^[0-9]+$', false, 3);
|
||||
$save['field'] = form_input_validate((isrv('field') ? gnrv('field') : ''), 'field', '', true, 3);
|
||||
$save['sort_type'] = form_input_validate(gnrv('sort_type'), 'sort_type', '^[0-9]+$', false, 3);
|
||||
$save['rule_id'] = CactiValidator::validateInput(grv('id'), 'id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['sequence'] = CactiValidator::validateInput(gnrv('sequence'), 'sequence', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['field'] = CactiValidator::validateInput((isrv('field') ? gnrv('field') : ''), 'field', [], 3);
|
||||
$save['sort_type'] = CactiValidator::validateInput(gnrv('sort_type'), 'sort_type', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['propagate_changes'] = (isrv('propagate_changes') ? 'on' : '');
|
||||
$save['search_pattern'] = isrv('search_pattern') ? form_input_validate(gnrv('search_pattern'), 'search_pattern', '', false, 3) : '';
|
||||
$save['replace_pattern'] = isrv('replace_pattern') ? form_input_validate(gnrv('replace_pattern'), 'replace_pattern', '', true, 3) : '';
|
||||
$save['search_pattern'] = isrv('search_pattern') ? CactiValidator::validateInput(gnrv('search_pattern'), 'search_pattern', [new Assert\NotBlank()], 3) : '';
|
||||
$save['replace_pattern'] = isrv('replace_pattern') ? CactiValidator::validateInput(gnrv('replace_pattern'), 'replace_pattern', [], 3) : '';
|
||||
|
||||
$automation_graph_rule_item_id = null;
|
||||
|
||||
|
||||
+5
-2
@@ -23,6 +23,9 @@
|
||||
*/
|
||||
|
||||
require_once('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
1 => __('Delete'),
|
||||
@@ -190,7 +193,7 @@ function form_save() : void {
|
||||
$save1['color_template_id'] = 0;
|
||||
}
|
||||
|
||||
$save1['name'] = form_input_validate(gfrv('name', FILTER_SANITIZE_SPECIAL_CHARS), 'name', '', false, 3);
|
||||
$save1['name'] = CactiValidator::validateInput(gfrv('name', FILTER_SANITIZE_SPECIAL_CHARS), 'name', [new Assert\NotBlank()], 3);
|
||||
|
||||
cacti_log('Saved ID: ' . $save1['color_template_id'] . ' Name: ' . $save1['name'], false, 'AGGREGATE', POLLER_VERBOSITY_DEBUG);
|
||||
|
||||
@@ -232,7 +235,7 @@ function form_save() : void {
|
||||
|
||||
$save['color_template_item_id'] = gfrv('color_template_item_id');
|
||||
$save['color_template_id'] = gfrv('color_template_id');
|
||||
$save['color_id'] = form_input_validate(gnrv('color_id'), 'color_id', '', true, 3);
|
||||
$save['color_id'] = CactiValidator::validateInput(gnrv('color_id'), 'color_id', [new Assert\Type('numeric')], 3);
|
||||
$save['sequence'] = $sequence;
|
||||
|
||||
if (!is_error_message()) {
|
||||
|
||||
+4
-2
@@ -58,7 +58,8 @@
|
||||
"stevenmaguire/oauth2-keycloak": "^6.1.0",
|
||||
"stevenmaguire/oauth2-microsoft": "^2.2",
|
||||
"symfony/filesystem": "^6.0",
|
||||
"symfony/http-foundation": "^6.0"
|
||||
"symfony/http-foundation": "^6.0",
|
||||
"symfony/validator": "^6.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"composer/xdebug-handler": "^3.0",
|
||||
@@ -100,7 +101,8 @@
|
||||
"block-insecure": false
|
||||
},
|
||||
"allow-plugins": {
|
||||
"pestphp/pest-plugin": true
|
||||
"pestphp/pest-plugin": true,
|
||||
"infection/extension-installer": true
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-9
@@ -27,6 +27,9 @@ require_once(CACTI_PATH_LIBRARY . '/api_data_source.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/template.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
1 => __('Delete'),
|
||||
@@ -94,9 +97,9 @@ function form_save() : void {
|
||||
|
||||
$save['id'] = gnrv('id');
|
||||
$save['hash'] = get_hash_data_input(gnrv('id'));
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save['input_string'] = form_input_validate(gnrv('input_string'), 'input_string', '', true, 3);
|
||||
$save['type_id'] = form_input_validate(gnrv('type_id'), 'type_id', '^[0-9]+$', true, 3);
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()], 3);
|
||||
$save['input_string'] = CactiValidator::validateInput(gnrv('input_string'), 'input_string', [], 3);
|
||||
$save['type_id'] = CactiValidator::validateInput(gnrv('type_id'), 'type_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
if (!is_error_message()) {
|
||||
$data_input_id = sql_save($save, 'data_input');
|
||||
@@ -131,14 +134,14 @@ function form_save() : void {
|
||||
$save['id'] = grv('id');
|
||||
$save['hash'] = get_hash_data_input(gnrv('id'), 'data_input_field');
|
||||
$save['data_input_id'] = grv('data_input_id');
|
||||
$save['name'] = form_input_validate(gnrv('fname'), 'fname', '', false, 3);
|
||||
$save['data_name'] = form_input_validate(gnrv('data_name'), 'data_name', '', false, 3);
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('fname'), 'fname', [new Assert\NotBlank()], 3);
|
||||
$save['data_name'] = CactiValidator::validateInput(gnrv('data_name'), 'data_name', [new Assert\NotBlank()], 3);
|
||||
$save['input_output'] = gnrv('input_output');
|
||||
$save['update_rra'] = form_input_validate((isrv('update_rra') ? gnrv('update_rra') : ''), 'update_rra', '', true, 3);
|
||||
$save['update_rra'] = CactiValidator::validateInput((isrv('update_rra') ? gnrv('update_rra') : ''), 'update_rra', [], 3);
|
||||
$save['sequence'] = grv('sequence');
|
||||
$save['type_code'] = form_input_validate((isrv('type_code') ? gnrv('type_code') : ''), 'type_code', '', true, 3);
|
||||
$save['regexp_match'] = form_input_validate((isrv('regexp_match') ? gnrv('regexp_match') : ''), 'regexp_match', '', true, 3);
|
||||
$save['allow_nulls'] = form_input_validate((isrv('allow_nulls') ? gnrv('allow_nulls') : ''), 'allow_nulls', '', true, 3);
|
||||
$save['type_code'] = CactiValidator::validateInput((isrv('type_code') ? gnrv('type_code') : ''), 'type_code', [], 3);
|
||||
$save['regexp_match'] = CactiValidator::validateInput((isrv('regexp_match') ? gnrv('regexp_match') : ''), 'regexp_match', [], 3);
|
||||
$save['allow_nulls'] = CactiValidator::validateInput((isrv('allow_nulls') ? gnrv('allow_nulls') : ''), 'allow_nulls', [], 3);
|
||||
|
||||
if (is_error_message() === false) {
|
||||
$data_input_field_id = sql_save($save, 'data_input_fields');
|
||||
|
||||
+7
-4
@@ -26,6 +26,9 @@ require('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/data_query.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
1 => __('Delete'),
|
||||
@@ -119,9 +122,9 @@ function form_save() : void {
|
||||
|
||||
$save['id'] = grv('id');
|
||||
$save['hash'] = get_hash_data_query(gnrv('id'));
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save['description'] = form_input_validate(gnrv('description'), 'description', '', true, 3);
|
||||
$save['xml_path'] = form_input_validate(trim(gnrv('xml_path')), 'xml_path', '', false, 3);
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()], 3);
|
||||
$save['description'] = CactiValidator::validateInput(gnrv('description'), 'description', [], 3);
|
||||
$save['xml_path'] = CactiValidator::validateInput(trim(gnrv('xml_path')), 'xml_path', [new Assert\NotBlank()], 3);
|
||||
$save['data_input_id'] = grv('data_input_id');
|
||||
|
||||
// Detect changing input id
|
||||
@@ -159,7 +162,7 @@ function form_save() : void {
|
||||
$save['id'] = grv('id');
|
||||
$save['hash'] = get_hash_data_query(gnrv('id'), 'data_query_graph');
|
||||
$save['snmp_query_id'] = grv('snmp_query_id');
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()], 3);
|
||||
$save['graph_template_id'] = grv('graph_template_id');
|
||||
|
||||
$errors = false;
|
||||
|
||||
+26
-13
@@ -32,6 +32,9 @@ require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/rrd.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/template.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
1 => __('Delete'),
|
||||
@@ -189,7 +192,17 @@ function form_save() : void {
|
||||
}
|
||||
|
||||
// run regexp match on input string
|
||||
$form_value = form_input_validate($form_value, 'value_' . $input_field['id'], $input_field['regexp_match'], $allow_nulls, 3);
|
||||
$constraints = [];
|
||||
|
||||
if ($allow_nulls === false) {
|
||||
$constraints[] = new Assert\NotBlank();
|
||||
}
|
||||
|
||||
if ($input_field['regexp_match'] != '') {
|
||||
$constraints[] = new Assert\Regex(['pattern' => '/' . $input_field['regexp_match'] . '/']);
|
||||
}
|
||||
|
||||
$form_value = CactiValidator::validateInput($form_value, 'value_' . $input_field['id'], $constraints, 3);
|
||||
|
||||
if (is_error_message() == false) {
|
||||
db_execute_prepared("REPLACE INTO data_input_data
|
||||
@@ -229,12 +242,12 @@ function form_save() : void {
|
||||
$save2['id'] = gfrv('data_template_data_id');
|
||||
$save2['local_data_template_data_id'] = gfrv('local_data_template_data_id');
|
||||
$save2['data_template_id'] = gfrv('data_template_id');
|
||||
$save2['data_input_id'] = form_input_validate(grv('data_input_id'), 'data_input_id', '^[0-9]+$', true, 3);
|
||||
$save2['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save2['data_source_path'] = form_input_validate(gnrv('data_source_path'), 'data_source_path', '', true, 3);
|
||||
$save2['active'] = form_input_validate((isrv('active') ? gnrv('active') : ''), 'active', '', true, 3);
|
||||
$save2['data_source_profile_id'] = form_input_validate(grv('data_source_profile_id'), 'data_source_profile_id', '^[0-9]+$', false, 3);
|
||||
$save2['rrd_step'] = form_input_validate(grv('rrd_step'), 'rrd_step', '^[0-9]+$', false, 3);
|
||||
$save2['data_input_id'] = CactiValidator::validateInput(grv('data_input_id'), 'data_input_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()], 3);
|
||||
$save2['data_source_path'] = CactiValidator::validateInput(gnrv('data_source_path'), 'data_source_path', [], 3);
|
||||
$save2['active'] = CactiValidator::validateInput((isrv('active') ? gnrv('active') : ''), 'active', [], 3);
|
||||
$save2['data_source_profile_id'] = CactiValidator::validateInput(grv('data_source_profile_id'), 'data_source_profile_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['rrd_step'] = CactiValidator::validateInput(grv('rrd_step'), 'rrd_step', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
if (is_error_message() == false) {
|
||||
$local_data_id = sql_save($save1, 'data_local');
|
||||
@@ -290,17 +303,17 @@ function form_save() : void {
|
||||
|
||||
$save3['data_template_id'] = gfrv('data_template_id');
|
||||
|
||||
$save3['rrd_maximum'] = form_input_validate(gnrv("rrd_maximum$name_modifier"), "rrd_maximum$name_modifier", '^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U|\|query_ifSpeed\||\|query_ifHighSpeed\|)\z', false, 3);
|
||||
$save3['rrd_maximum'] = CactiValidator::validateInput(gnrv("rrd_maximum$name_modifier"), "rrd_maximum$name_modifier", [new Assert\Regex('/^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U|\|query_ifSpeed\||\|query_ifHighSpeed\|)\z/')]);
|
||||
|
||||
$save3['rrd_minimum'] = form_input_validate(gnrv("rrd_minimum$name_modifier"), "rrd_minimum$name_modifier", '^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U|\|query_ifSpeed\||\|query_ifHighSpeed\|)\z', false, 3);
|
||||
$save3['rrd_minimum'] = CactiValidator::validateInput(gnrv("rrd_minimum$name_modifier"), "rrd_minimum$name_modifier", [new Assert\Regex('/^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U|\|query_ifSpeed\||\|query_ifHighSpeed\|)\z/')]);
|
||||
|
||||
$save3['rrd_heartbeat'] = form_input_validate(gnrv("rrd_heartbeat$name_modifier"), "rrd_heartbeat$name_modifier", '^[0-9]+$', false, 3);
|
||||
$save3['rrd_heartbeat'] = CactiValidator::validateInput(gnrv("rrd_heartbeat$name_modifier"), "rrd_heartbeat$name_modifier", [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
$save3['data_source_type_id'] = form_input_validate(gnrv("data_source_type_id$name_modifier"), "data_source_type_id$name_modifier", '^[0-9]+$', false, 3);
|
||||
$save3['data_source_type_id'] = CactiValidator::validateInput(gnrv("data_source_type_id$name_modifier"), "data_source_type_id$name_modifier", [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
$save3['data_source_name'] = form_input_validate(gnrv("data_source_name$name_modifier"), "data_source_name$name_modifier", '^[a-zA-Z0-9_-]{1,19}$', false, 3);
|
||||
$save3['data_source_name'] = CactiValidator::validateInput(gnrv("data_source_name$name_modifier"), "data_source_name$name_modifier", [new Assert\Regex('/^[a-zA-Z0-9_-]{1,19}$/')], 3);
|
||||
|
||||
$save3['data_input_field_id'] = form_input_validate((isrv("data_input_field_id$name_modifier") ? gnrv("data_input_field_id$name_modifier") : '0'), "data_input_field_id$name_modifier", '', true, 3);
|
||||
$save3['data_input_field_id'] = CactiValidator::validateInput((isrv("data_input_field_id$name_modifier") ? gnrv("data_input_field_id$name_modifier") : '0'), "data_input_field_id$name_modifier", [], 3);
|
||||
|
||||
if ($save3['rrd_minimum'] != 'U' && $save3['rrd_maximum'] != 'U') {
|
||||
if ($save3['rrd_minimum'] >= $save3['rrd_maximum']) {
|
||||
|
||||
+32
-19
@@ -29,6 +29,9 @@ require_once(CACTI_PATH_LIBRARY . '/html_tree.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/template.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
1 => __('Delete'),
|
||||
@@ -85,18 +88,18 @@ function form_save() : void {
|
||||
// save: data_template
|
||||
$save1['id'] = grv('data_template_id');
|
||||
$save1['hash'] = get_hash_data_template(grv('data_template_id'));
|
||||
$save1['name'] = form_input_validate(gnrv('template_name'), 'template_name', '', false, 3);
|
||||
$save1['name'] = CactiValidator::validateInput(gnrv('template_name'), 'template_name', [new Assert\NotBlank()], 3);
|
||||
|
||||
// save: data_template_data
|
||||
$save2['id'] = grv('data_template_data_id');
|
||||
$save2['local_data_template_data_id'] = 0;
|
||||
$save2['local_data_id'] = 0;
|
||||
|
||||
$save2['data_input_id'] = form_input_validate(grv('data_input_id'), 'data_input_id', '^[0-9]+$', true, 3);
|
||||
$save2['t_name'] = form_input_validate((isrv('t_name') ? gnrv('t_name') : ''), 't_name', '', true, 3);
|
||||
$save2['name'] = form_input_validate(gnrv('name'), 'name', '', (isrv('t_name') ? true : false), 3);
|
||||
$save2['t_active'] = form_input_validate((isrv('t_active') ? gnrv('t_active') : ''), 't_active', '', true, 3);
|
||||
$save2['active'] = form_input_validate((isrv('active') ? gnrv('active') : ''), 'active', '', true, 3);
|
||||
$save2['data_input_id'] = CactiValidator::validateInput(grv('data_input_id'), 'data_input_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['t_name'] = CactiValidator::validateInput((isrv('t_name') ? gnrv('t_name') : ''), 't_name', [], 3);
|
||||
$save2['name'] = CactiValidator::validateInput(gnrv('name'), 'name', (isrv('t_name') ? [] : [new Assert\NotBlank()]), 3);
|
||||
$save2['t_active'] = CactiValidator::validateInput((isrv('t_active') ? gnrv('t_active') : ''), 't_active', [], 3);
|
||||
$save2['active'] = CactiValidator::validateInput((isrv('active') ? gnrv('active') : ''), 'active', [], 3);
|
||||
|
||||
$rrd_step = db_fetch_cell_prepared('SELECT step
|
||||
FROM data_source_profiles
|
||||
@@ -110,8 +113,8 @@ function form_save() : void {
|
||||
|
||||
$save2['rrd_step'] = $rrd_step;
|
||||
|
||||
$save2['t_data_source_profile_id'] = form_input_validate((isrv('t_data_source_profile_id') ? gnrv('t_data_source_profile_id') : ''), 't_data_source_profile_id', '', true, 3);
|
||||
$save2['data_source_profile_id'] = form_input_validate(grv('data_source_profile_id'), 'data_source_profile_id', '^[0-9]+$', (isrv('data_source_profile_id') ? true : false), 3);
|
||||
$save2['t_data_source_profile_id'] = CactiValidator::validateInput((isrv('t_data_source_profile_id') ? gnrv('t_data_source_profile_id') : ''), 't_data_source_profile_id', [], 3);
|
||||
$save2['data_source_profile_id'] = CactiValidator::validateInput(grv('data_source_profile_id'), 'data_source_profile_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
// save: data_template_rrd
|
||||
$save3['id'] = grv('data_template_rrd_id');
|
||||
@@ -119,27 +122,27 @@ function form_save() : void {
|
||||
$save3['local_data_template_rrd_id'] = 0;
|
||||
$save3['local_data_id'] = 0;
|
||||
|
||||
$save3['t_rrd_maximum'] = form_input_validate((isrv('t_rrd_maximum') ? gnrv('t_rrd_maximum') : ''), 't_rrd_maximum', '', true, 3);
|
||||
$save3['t_rrd_maximum'] = CactiValidator::validateInput((isrv('t_rrd_maximum') ? gnrv('t_rrd_maximum') : ''), 't_rrd_maximum', [], 3);
|
||||
|
||||
$save3['rrd_maximum'] = form_input_validate(gnrv('rrd_maximum'), 'rrd_maximum', '^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U|\|query_ifSpeed\|)\z', (isrv('t_rrd_maximum') ? true : false), 3);
|
||||
$save3['rrd_maximum'] = CactiValidator::validateInput(gnrv('rrd_maximum'), 'rrd_maximum', [new Assert\Regex('/^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U|\|query_ifSpeed\|)\z/')], 3);
|
||||
|
||||
$save3['t_rrd_minimum'] = form_input_validate((isrv('t_rrd_minimum') ? gnrv('t_rrd_minimum') : ''), 't_rrd_minimum', '', true, 3);
|
||||
$save3['t_rrd_minimum'] = CactiValidator::validateInput((isrv('t_rrd_minimum') ? gnrv('t_rrd_minimum') : ''), 't_rrd_minimum', [], 3);
|
||||
|
||||
$save3['rrd_minimum'] = form_input_validate(gnrv('rrd_minimum'), 'rrd_minimum', '^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U)\z', (isrv('t_rrd_minimum') ? true : false), 3);
|
||||
$save3['rrd_minimum'] = CactiValidator::validateInput(gnrv('rrd_minimum'), 'rrd_minimum', [new Assert\Regex('/^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U)\z/')], 3);
|
||||
|
||||
$save3['rrd_heartbeat'] = $rrd_heartbeat;
|
||||
|
||||
$save3['t_data_source_type_id'] = form_input_validate((isrv('t_data_source_type_id') ? gnrv('t_data_source_type_id') : ''), 't_data_source_type_id', '', true, 3);
|
||||
$save3['t_data_source_type_id'] = CactiValidator::validateInput((isrv('t_data_source_type_id') ? gnrv('t_data_source_type_id') : ''), 't_data_source_type_id', [], 3);
|
||||
|
||||
$save3['data_source_type_id'] = form_input_validate(grv('data_source_type_id'), 'data_source_type_id', '^[0-9]+$', true, 3);
|
||||
$save3['data_source_type_id'] = CactiValidator::validateInput(grv('data_source_type_id'), 'data_source_type_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
$save3['t_data_source_name'] = form_input_validate((isrv('t_data_source_name') ? gnrv('t_data_source_name') : ''), 't_data_source_name', '', true, 3);
|
||||
$save3['t_data_source_name'] = CactiValidator::validateInput((isrv('t_data_source_name') ? gnrv('t_data_source_name') : ''), 't_data_source_name', [], 3);
|
||||
|
||||
$save3['data_source_name'] = form_input_validate(gnrv('data_source_name'), 'data_source_name', '^[a-zA-Z0-9_]{1,19}$', (isrv('t_data_source_name') ? true : false), 3);
|
||||
$save3['data_source_name'] = CactiValidator::validateInput(gnrv('data_source_name'), 'data_source_name', [new Assert\Regex('/^[a-zA-Z0-9_]{1,19}$/')], 3);
|
||||
|
||||
$save3['t_data_input_field_id'] = form_input_validate((isrv('t_data_input_field_id') ? gnrv('t_data_input_field_id') : ''), 't_data_input_field_id', '', true, 3);
|
||||
$save3['t_data_input_field_id'] = CactiValidator::validateInput((isrv('t_data_input_field_id') ? gnrv('t_data_input_field_id') : ''), 't_data_input_field_id', [], 3);
|
||||
|
||||
$save3['data_input_field_id'] = form_input_validate((isrv('data_input_field_id') ? gnrv('data_input_field_id') : '0'), 'data_input_field_id', '', true, 3);
|
||||
$save3['data_input_field_id'] = CactiValidator::validateInput((isrv('data_input_field_id') ? gnrv('data_input_field_id') : '0'), 'data_input_field_id', [], 3);
|
||||
|
||||
if ($save3['rrd_minimum'] != 'U' && $save3['rrd_maximum'] != 'U') {
|
||||
if ($save3['rrd_minimum'] >= $save3['rrd_maximum']) {
|
||||
@@ -186,7 +189,17 @@ function form_save() : void {
|
||||
$not_required = false;
|
||||
}
|
||||
|
||||
form_input_validate(gnrv($form_value), 'value_' . $input_field['data_name'], $input_field['regexp_match'], $not_required, 3);
|
||||
$constraints = [];
|
||||
|
||||
if (!$not_required) {
|
||||
$constraints[] = new Assert\NotBlank();
|
||||
}
|
||||
|
||||
if (!empty($input_field['regexp_match'])) {
|
||||
$constraints[] = new Assert\Regex('/' . $input_field['regexp_match'] . '/');
|
||||
}
|
||||
|
||||
CactiValidator::validateInput(gnrv($form_value), 'value_' . $input_field['data_name'], $constraints, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
# Settings Validation
|
||||
|
||||
## Why this exists
|
||||
|
||||
Cacti settings are written from several places: the web UI (`settings.php`),
|
||||
CLI utilities under `cli/`, and (planned) JSON-RPC endpoints. Each of those
|
||||
paths previously carried its own ad-hoc checks for the same setting, and the
|
||||
checks drifted apart as code was added. The intent of `CactiSettings::validate()`
|
||||
is to put the constraint definition next to the setting itself so every write
|
||||
path uses the same rules.
|
||||
|
||||
A setting in `include/global_settings.php` declares its constraints alongside
|
||||
the existing keys (`method`, `default`, `max_length`, ...). The validator runs
|
||||
the entire posted set in one pass and returns a `{name => message}` map. An
|
||||
empty map means the input is valid.
|
||||
|
||||
### Why constraints are declared as closures
|
||||
|
||||
`include/global_settings.php` is loaded from `include/global.php` *before*
|
||||
`include/vendor/autoload.php`. Eagerly instantiating `new Assert\NotBlank()`
|
||||
inside the array literal would fatal at file-load time because the Symfony
|
||||
Validator classes are not yet loadable. Wrapping each constraint in an arrow
|
||||
function (`fn() => new Assert\NotBlank()`) defers the instantiation until
|
||||
`CactiSettings::validate()` runs the closures. The `use Symfony\Component\Validator\Constraints as Assert;`
|
||||
import at the top of the file is a compile-time alias and does not trigger
|
||||
autoloading.
|
||||
|
||||
## How `CactiSettings::validate` is used in `settings.php`
|
||||
|
||||
`save_settings()` builds a snapshot of posted values via Cacti's request-var
|
||||
helpers (`gnrv`) and calls the validator before writing any rows:
|
||||
|
||||
```php
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiSettings.php');
|
||||
|
||||
$snapshot = [];
|
||||
foreach ($settings[grv('tab')] as $field_name => $field_array) {
|
||||
$snapshot[$field_name] = gnrv($field_name);
|
||||
}
|
||||
|
||||
$violations = CactiSettings::validate($snapshot, $settings);
|
||||
|
||||
if (cacti_sizeof($violations) > 0) {
|
||||
foreach ($violations as $name => $message) {
|
||||
$_SESSION['sess_error_fields'][$name] = $name;
|
||||
$_SESSION['sess_field_values'][$name] = $snapshot[$name] ?? '';
|
||||
raise_message('cacti_settings_' . $name, ..., MESSAGE_LEVEL_ERROR);
|
||||
}
|
||||
header('Location: settings.php?tab=...');
|
||||
exit;
|
||||
}
|
||||
```
|
||||
|
||||
When violations are present the request is rejected before any `REPLACE INTO settings`
|
||||
runs. The user is redirected back to the same tab with the error highlighted.
|
||||
|
||||
## How to add constraints to a setting
|
||||
|
||||
1. Open `include/global_settings.php` and find the setting definition.
|
||||
2. Add a `'constraints'` key holding an array of closures, each returning a
|
||||
Symfony constraint instance.
|
||||
3. The `use Symfony\Component\Validator\Constraints as Assert;` alias is
|
||||
already imported at the top of the file, so constraints read as
|
||||
`fn() => new Assert\Range(...)`.
|
||||
4. Wrap any custom `message:` argument in `__()` so the message participates
|
||||
in Cacti i18n.
|
||||
|
||||
Example:
|
||||
|
||||
```php
|
||||
'snmp_timeout' => [
|
||||
'friendly_name' => __('Timeout'),
|
||||
'method' => 'textbox',
|
||||
'default' => '500',
|
||||
'max_length' => '10',
|
||||
'constraints' => [
|
||||
fn() => new Assert\Regex(pattern: '/^\d+$/', message: __('must be a positive integer (milliseconds).')),
|
||||
fn() => new Assert\Range(min: 1, max: 600000),
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
When a `Choice` list duplicates a canonical array from `global_arrays.php`,
|
||||
derive the choices from that array inside the closure rather than restating
|
||||
the values:
|
||||
|
||||
```php
|
||||
'constraints' => [
|
||||
fn() => new Assert\Choice(choices: array_merge(
|
||||
array_keys($GLOBALS['poller_intervals']),
|
||||
array_map('strval', array_keys($GLOBALS['poller_intervals']))
|
||||
)),
|
||||
],
|
||||
```
|
||||
|
||||
Both string and integer forms of the keys are accepted because `$_POST`
|
||||
values arrive as strings while the canonical keys are integers.
|
||||
|
||||
## Constraint types used in the pilot
|
||||
|
||||
See the [Symfony Validator reference](https://symfony.com/doc/6.4/validation.html)
|
||||
for the full catalog. The pilot uses:
|
||||
|
||||
- `Assert\NotBlank` -- value is present and non-empty.
|
||||
- `Assert\Length` -- string length within `min`/`max`.
|
||||
- `Assert\Range` -- numeric value within `min`/`max`.
|
||||
- `Assert\Choice` -- value is one of an enumerated list. Use this for any
|
||||
setting that is rendered as a `drop_array`.
|
||||
- `Assert\Regex` -- value matches a pattern. Useful for "is this an integer
|
||||
string" since `$_POST` values arrive as strings.
|
||||
- `Assert\Positive` -- value is strictly greater than zero.
|
||||
|
||||
## Migration template for the next batch
|
||||
|
||||
For each setting you want to constrain:
|
||||
|
||||
1. Identify the setting's existing implicit rule (e.g. `method` is `drop_array`
|
||||
with a fixed key set, or `max_length` is `'255'`).
|
||||
2. Translate that rule to a constraint object. `drop_array` becomes
|
||||
`Assert\Choice` over the array keys. `max_length` becomes `Assert\Length`.
|
||||
Numeric textboxes typically need `Assert\Regex` plus `Assert\Range`.
|
||||
3. Add a unit test in `tests/Unit/CactiSettingsTest.php` that exercises the
|
||||
new constraint with a synthetic definition (do not depend on
|
||||
`include/global_settings.php` from the test).
|
||||
4. Run `composer test` and confirm the new case passes.
|
||||
|
||||
## Translator wiring (known limitation)
|
||||
|
||||
`CactiSettings::validator()` builds the validator with
|
||||
`Validation::createValidator()` and does not pass a `TranslatorInterface`.
|
||||
Symfony's default English messages render regardless of the active Cacti
|
||||
locale. Custom messages declared in `global_settings.php` should be wrapped
|
||||
in `__()` so the operator-facing text is translatable through Cacti's own
|
||||
i18n stack. Wiring a `TranslatorInterface` so that the framework's built-in
|
||||
constraint messages also translate is a planned follow-up.
|
||||
|
||||
## Defense in depth
|
||||
|
||||
The constraint layer supplements existing checks rather than replacing them.
|
||||
|
||||
- The form-render method (`drop_array`, `dirpath`, `filepath`, `textbox_password`)
|
||||
still enforces its implicit rules in `save_settings()`. For example,
|
||||
`dirpath` continues to verify the directory exists before storing.
|
||||
- Any post-save handler (cache-clear, poller restart, log rotation) keeps
|
||||
whatever validation it already performs.
|
||||
- The constraint check runs first and short-circuits the write, so downstream
|
||||
handlers see only values that already cleared the declared rules.
|
||||
+11
-7
@@ -153,21 +153,25 @@ if (POLLER_ID == 1 || read_config_option('storage_location')) { // @phpstan-igno
|
||||
|
||||
$output = call_remote_data_collector(1, $url);
|
||||
|
||||
if (is_array($output) && isset($output['image'])) {
|
||||
$output = $output['image'];
|
||||
}
|
||||
|
||||
if ($output !== false && $output != '') {
|
||||
$decoded = json_decode($output, true);
|
||||
|
||||
if (is_array($decoded) && isset($decoded['image'])) {
|
||||
$output = base64_decode($decoded['image'], true);
|
||||
} elseif (str_contains($output, 'image = ')) {
|
||||
// Find the beginning of the image definition row
|
||||
$image_begin_pos = strpos($output, 'image = ');
|
||||
|
||||
if ($image_begin_pos !== false) {
|
||||
// Find the end of the line of the image definition row, after this the raw image data will come
|
||||
$image_data_pos = strpos($output, "\n", $image_begin_pos);
|
||||
$image_data_line_end = strpos($output, "\n", $image_begin_pos);
|
||||
|
||||
if ($image_data_pos !== false) {
|
||||
if ($image_data_line_end !== false) {
|
||||
// Insert the raw image data to the array
|
||||
$output = substr($output, $image_data_pos + 1);
|
||||
$output = substr($output, $image_data_line_end + 1);
|
||||
} else {
|
||||
$output = false;
|
||||
}
|
||||
} else {
|
||||
$output = false;
|
||||
}
|
||||
|
||||
+34
-9
@@ -175,42 +175,59 @@ if (POLLER_ID == 1 || read_config_option('storage_location')) { // @phpstan-igno
|
||||
$url .= '&rra_id=' . $rra_id;
|
||||
|
||||
foreach ($graph_data_array as $variable => $value) {
|
||||
$url .= '&' . $variable . '=' . $value;
|
||||
$url .= '&' . rawurlencode((string)$variable) . '=' . rawurlencode((string)$value);
|
||||
}
|
||||
|
||||
$output = call_remote_data_collector(1, $url);
|
||||
}
|
||||
|
||||
$output = trim($output);
|
||||
$oarray = ['type' => $gtype, 'local_graph_id' => grv('local_graph_id'), 'rra_id' => $rra_id];
|
||||
|
||||
// Check if we received back something populated from rrdtool
|
||||
if ($output != false && $output != '' && str_contains($output, 'image = ')) {
|
||||
if ($output !== false && $output != '') {
|
||||
$decoded = json_decode($output, true);
|
||||
|
||||
if (is_array($decoded) && isset($decoded['image'])) {
|
||||
$oarray = array_merge($oarray, $decoded);
|
||||
// No further parsing needed if it was already JSON
|
||||
} elseif (str_contains($output, 'image = ')) {
|
||||
// Find the beginning of the image definition row
|
||||
$image_begin_pos = strpos($output, 'image = ');
|
||||
|
||||
// Parse and populate everything before the image definition row
|
||||
$header_lines = explode("\n", substr($output, 0, $image_begin_pos - 1));
|
||||
if ($image_begin_pos > 0) {
|
||||
$header_lines = explode("\n", substr($output, 0, $image_begin_pos));
|
||||
} else {
|
||||
$header_lines = [];
|
||||
}
|
||||
|
||||
// Check for additional data points from graphv output
|
||||
$graph_start_pos = strpos($output, 'graph_start =', $image_begin_pos);
|
||||
|
||||
if (!$graph_start_pos) {
|
||||
// Find the end of the line of the image definition row, after this the raw image data will come
|
||||
$image_data_pos = strpos($output, "\n" , $image_begin_pos) + 1;
|
||||
$image_data_line_end = strpos($output, "\n", $image_begin_pos);
|
||||
|
||||
if ($image_data_line_end !== false) {
|
||||
$image_data_pos = $image_data_line_end + 1;
|
||||
|
||||
// Insert the raw image data to the array
|
||||
$oarray['image'] = base64_encode(substr($output, $image_data_pos));
|
||||
}
|
||||
} else {
|
||||
// Find the end of the line of the image definition row, after this the raw image data will come
|
||||
$image_data_pos = strpos($output, "\n" , $image_begin_pos) + 1;
|
||||
$image_data_line_end = strpos($output, "\n", $image_begin_pos);
|
||||
|
||||
if ($image_data_line_end !== false) {
|
||||
$image_data_pos = $image_data_line_end + 1;
|
||||
|
||||
// Insert the raw image data to the array
|
||||
$oarray['image'] = base64_encode(substr($output, $image_data_pos, $graph_start_pos - $image_data_pos));
|
||||
}
|
||||
|
||||
// Get the datapoints to the end of the file.
|
||||
$datapoints_start_pos = strpos($output, 'datapoints =');
|
||||
|
||||
if ($datapoints_start_pos !== false) {
|
||||
$datapoints = substr($output, $datapoints_start_pos);
|
||||
|
||||
// Get rid of the 'datapoints =' line
|
||||
@@ -219,18 +236,27 @@ if ($output != false && $output != '' && str_contains($output, 'image = ')) {
|
||||
|
||||
$datapoints = json_decode(implode("\n", $dp_output), true);
|
||||
|
||||
if (is_array($datapoints)) {
|
||||
foreach ($datapoints as $name => $value) {
|
||||
$oarray[$name] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($header_lines as $line) {
|
||||
if (str_contains($line, ' = ')) {
|
||||
$parts = explode(' = ', $line);
|
||||
$oarray[$parts[0]] = trim($parts[1]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$output = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($output !== false && $output != '') {
|
||||
if (isset($oarray['meta'])) {
|
||||
if (isset($oarray['meta']['legend']) & isset($xport_meta['legend'])) {
|
||||
foreach ($oarray['meta']['legend'] as $key => $value) {
|
||||
$legend = trim(preg_replace('/[^a-z0-9 _()]/i', '', $value));
|
||||
|
||||
@@ -242,7 +268,6 @@ if ($output != false && $output != '' && str_contains($output, 'image = ')) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$replacement_legend = rrdtool_replacement_legend(grv('local_graph_id'));
|
||||
|
||||
|
||||
+90
-87
@@ -30,6 +30,9 @@ require_once(CACTI_PATH_LIBRARY . '/html_tree.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/template.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
ini_set('max_execution_time', '0');
|
||||
|
||||
@@ -219,9 +222,9 @@ function form_save() : void {
|
||||
|
||||
$save1['id'] = $graph_template_id;
|
||||
$save1['hash'] = get_hash_graph_template($graph_template_id);
|
||||
$save1['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save1['class'] = form_input_validate(gnrv('class'), 'class', '', true, 3);
|
||||
$save1['version'] = form_input_validate(gnrv('version'), 'version', '', true, 3);
|
||||
$save1['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()], 3);
|
||||
$save1['class'] = CactiValidator::validateInput(gnrv('class'), 'class', [], 3);
|
||||
$save1['version'] = CactiValidator::validateInput(gnrv('version'), 'version', [], 3);
|
||||
$save1['multiple'] = isrv('multiple') ? 'on' : '';
|
||||
$save1['test_source'] = isrv('test_source') ? 'on' : '';
|
||||
|
||||
@@ -229,67 +232,67 @@ function form_save() : void {
|
||||
$save2['local_graph_template_graph_id'] = 0;
|
||||
$save2['local_graph_id'] = 0;
|
||||
$save2['t_image_format_id'] = (isrv('t_image_format_id') ? gnrv('t_image_format_id') : '');
|
||||
$save2['image_format_id'] = form_input_validate(gnrv('image_format_id'), 'image_format_id', '^[0-9]+$', true, 3);
|
||||
$save2['t_title'] = form_input_validate((isrv('t_title') ? gnrv('t_title') : ''), 't_title', '', true, 3);
|
||||
$save2['title'] = form_input_validate(gnrv('title'), 'title', '', (isrv('t_title') ? true : false), 3);
|
||||
$save2['t_height'] = form_input_validate((isrv('t_height') ? gnrv('t_height') : ''), 't_height', '', true, 3);
|
||||
$save2['height'] = form_input_validate(gnrv('height'), 'height', '^[0-9]+$', (isrv('t_height') ? true : false), 3);
|
||||
$save2['t_width'] = form_input_validate((isrv('t_width') ? gnrv('t_width') : ''), 't_width', '', true, 3);
|
||||
$save2['width'] = form_input_validate(gnrv('width'), 'width', '^[0-9]+$', (isrv('t_width') ? true : false), 3);
|
||||
$save2['t_upper_limit'] = form_input_validate((isrv('t_upper_limit') ? gnrv('t_upper_limit') : ''), 't_upper_limit', '', true, 3);
|
||||
$save2['upper_limit'] = form_input_validate(gnrv('upper_limit'), 'upper_limit', '^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U)\z', ((isrv('t_upper_limit') || (strlen(gnrv('upper_limit')) === 0)) ? true : false), 3);
|
||||
$save2['t_lower_limit'] = form_input_validate((isrv('t_lower_limit') ? gnrv('t_lower_limit') : ''), 't_lower_limit', '', true, 3);
|
||||
$save2['lower_limit'] = form_input_validate(gnrv('lower_limit'), 'lower_limit', '^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U)\z', ((isrv('t_lower_limit') || (strlen(gnrv('lower_limit')) === 0)) ? true : false), 3);
|
||||
$save2['t_vertical_label'] = form_input_validate((isrv('t_vertical_label') ? gnrv('t_vertical_label') : ''), 't_vertical_label', '', true, 3);
|
||||
$save2['vertical_label'] = form_input_validate(gnrv('vertical_label'), 'vertical_label', '', true, 3);
|
||||
$save2['t_slope_mode'] = form_input_validate((isrv('t_slope_mode') ? gnrv('t_slope_mode') : ''), 't_slope_mode', '', true, 3);
|
||||
$save2['slope_mode'] = form_input_validate((isrv('slope_mode') ? gnrv('slope_mode') : ''), 'slope_mode', '', true, 3);
|
||||
$save2['t_auto_scale'] = form_input_validate((isrv('t_auto_scale') ? gnrv('t_auto_scale') : ''), 't_auto_scale', '', true, 3);
|
||||
$save2['auto_scale'] = form_input_validate((isrv('auto_scale') ? gnrv('auto_scale') : ''), 'auto_scale', '', true, 3);
|
||||
$save2['t_auto_scale_opts'] = form_input_validate((isrv('t_auto_scale_opts') ? gnrv('t_auto_scale_opts') : ''), 't_auto_scale_opts', '', true, 3);
|
||||
$save2['auto_scale_opts'] = form_input_validate(gnrv('auto_scale_opts'), 'auto_scale_opts', '', true, 3);
|
||||
$save2['t_auto_scale_log'] = form_input_validate((isrv('t_auto_scale_log') ? gnrv('t_auto_scale_log') : ''), 't_auto_scale_log', '', true, 3);
|
||||
$save2['auto_scale_log'] = form_input_validate((isrv('auto_scale_log') ? gnrv('auto_scale_log') : ''), 'auto_scale_log', '', true, 3);
|
||||
$save2['t_scale_log_units'] = form_input_validate((isrv('t_scale_log_units') ? gnrv('t_scale_log_units') : ''), 't_scale_log_units', '', true, 3);
|
||||
$save2['scale_log_units'] = form_input_validate((isrv('scale_log_units') ? gnrv('scale_log_units') : ''), 'scale_log_units', '', true, 3);
|
||||
$save2['t_auto_scale_rigid'] = form_input_validate((isrv('t_auto_scale_rigid') ? gnrv('t_auto_scale_rigid') : ''), 't_auto_scale_rigid', '', true, 3);
|
||||
$save2['auto_scale_rigid'] = form_input_validate((isrv('auto_scale_rigid') ? gnrv('auto_scale_rigid') : ''), 'auto_scale_rigid', '', true, 3);
|
||||
$save2['t_auto_padding'] = form_input_validate((isrv('t_auto_padding') ? gnrv('t_auto_padding') : ''), 't_auto_padding', '', true, 3);
|
||||
$save2['auto_padding'] = form_input_validate((isrv('auto_padding') ? gnrv('auto_padding') : ''), 'auto_padding', '', true, 3);
|
||||
$save2['t_base_value'] = form_input_validate((isrv('t_base_value') ? gnrv('t_base_value') : ''), 't_base_value', '', true, 3);
|
||||
$save2['base_value'] = form_input_validate(gnrv('base_value'), 'base_value', '^[0-9]+$', (isrv('t_base_value') ? true : false), 3);
|
||||
$save2['t_unit_value'] = form_input_validate((isrv('t_unit_value') ? gnrv('t_unit_value') : ''), 't_unit_value', '', true, 3);
|
||||
$save2['unit_value'] = form_input_validate(gnrv('unit_value'), 'unit_value', '', true, 3);
|
||||
$save2['t_unit_exponent_value'] = form_input_validate((isrv('t_unit_exponent_value') ? gnrv('t_unit_exponent_value') : ''), 't_unit_exponent_value', '', true, 3);
|
||||
$save2['unit_exponent_value'] = form_input_validate(gnrv('unit_exponent_value'), 'unit_exponent_value', '^-?[0-9]+$', true, 3);
|
||||
$save2['t_alt_y_grid'] = form_input_validate((isrv('t_alt_y_grid') ? gnrv('t_alt_y_grid') : ''), 't_alt_y_grid', '', true, 3);
|
||||
$save2['alt_y_grid'] = form_input_validate((isrv('alt_y_grid') ? gnrv('alt_y_grid') : ''), 'alt_y_grid', '', true, 3);
|
||||
$save2['t_right_axis'] = form_input_validate((isrv('t_right_axis') ? gnrv('t_right_axis') : ''), 't_right_axis', '', true, 3);
|
||||
$save2['right_axis'] = form_input_validate((isrv('right_axis') ? gnrv('right_axis') : ''), 'right_axis', '^-?([0-9]+(\.[0-9]*)?|\.[0-9]+):-?([0-9]+(\.[0-9]*)?|\.[0-9]+)$', true, 3);
|
||||
$save2['t_right_axis_label'] = form_input_validate((isrv('t_right_axis_label') ? gnrv('t_right_axis_label') : ''), 't_right_axis_label', '', true, 3);
|
||||
$save2['right_axis_label'] = form_input_validate((isrv('right_axis_label') ? gnrv('right_axis_label') : ''), 'right_axis_label', '', true, 3);
|
||||
$save2['t_right_axis_format'] = form_input_validate((isrv('t_right_axis_format') ? gnrv('t_right_axis_format') : ''), 't_right_axis_format', '', true, 3);
|
||||
$save2['right_axis_format'] = form_input_validate((isrv('right_axis_format') ? gnrv('right_axis_format') : ''), 'right_axis_format', '^[0-9]+$', true, 3);
|
||||
$save2['t_no_gridfit'] = form_input_validate((isrv('t_no_gridfit') ? gnrv('t_no_gridfit') : ''), 't_no_gridfit', '', true, 3);
|
||||
$save2['no_gridfit'] = form_input_validate((isrv('no_gridfit') ? gnrv('no_gridfit') : ''), 'no_gridfit', '', true, 3);
|
||||
$save2['t_unit_length'] = form_input_validate((isrv('t_unit_length') ? gnrv('t_unit_length') : ''), 't_unit_length', '', true, 3);
|
||||
$save2['unit_length'] = form_input_validate((isrv('unit_length') ? gnrv('unit_length') : ''), 'unit_length', '^[0-9]+$', true, 3);
|
||||
$save2['t_tab_width'] = form_input_validate((isrv('t_tab_width') ? gnrv('t_tab_width') : ''), 't_tab_width', '', true, 3);
|
||||
$save2['tab_width'] = form_input_validate((isrv('tab_width') ? gnrv('tab_width') : ''), 'tab_width', '^[0-9]*$', true, 3);
|
||||
$save2['t_dynamic_labels'] = form_input_validate((isrv('t_dynamic_labels') ? gnrv('t_dynamic_labels') : ''), 't_dynamic_labels', '', true, 3);
|
||||
$save2['dynamic_labels'] = form_input_validate((isrv('dynamic_labels') ? gnrv('dynamic_labels') : ''), 'dynamic_labels', '', true, 3);
|
||||
$save2['t_force_rules_legend'] = form_input_validate((isrv('t_force_rules_legend') ? gnrv('t_force_rules_legend') : ''), 't_force_rules_legend', '', true, 3);
|
||||
$save2['force_rules_legend'] = form_input_validate((isrv('force_rules_legend') ? gnrv('force_rules_legend') : ''), 'force_rules_legend', '', true, 3);
|
||||
$save2['t_legend_position'] = form_input_validate((isrv('t_legend_position') ? gnrv('t_legend_position') : ''), 't_legend_position', '', true, 3);
|
||||
$save2['legend_position'] = form_input_validate((isrv('legend_position') ? gnrv('legend_position') : ''), 'legend_position', '', true, 3);
|
||||
$save2['t_legend_direction'] = form_input_validate((isrv('t_legend_direction') ? gnrv('t_legend_direction') : ''), 't_legend_direction', '', true, 3);
|
||||
$save2['legend_direction'] = form_input_validate((isrv('legend_direction') ? gnrv('legend_direction') : ''), 'legend_direction', '', true, 3);
|
||||
$save2['t_right_axis_formatter'] = form_input_validate((isrv('t_right_axis_formatter') ? gnrv('t_right_axis_formatter') : ''), 't_right_axis_formatter', '', true, 3);
|
||||
$save2['right_axis_formatter'] = form_input_validate((isrv('right_axis_formatter') ? gnrv('right_axis_formatter') : ''), 'right_axis_formatter', '', true, 3);
|
||||
$save2['t_left_axis_format'] = form_input_validate((isrv('t_left_axis_format') ? gnrv('t_left_axis_format') : ''), 't_left_axis_format', '', true, 3);
|
||||
$save2['left_axis_format'] = form_input_validate((isrv('left_axis_format') ? gnrv('left_axis_format') : ''), 'left_axis_format', '^[0-9]+$', true, 3);
|
||||
$save2['t_left_axis_formatter'] = form_input_validate((isrv('t_left_axis_formatter') ? gnrv('t_left_axis_formatter') : ''), 't_left_axis_formatter', '', true, 3);
|
||||
$save2['left_axis_formatter'] = form_input_validate((isrv('left_axis_formatter') ? gnrv('left_axis_formatter') : ''), 'left_axis_formatter', '', true, 3);
|
||||
$save2['image_format_id'] = CactiValidator::validateInput(gnrv('image_format_id'), 'image_format_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['t_title'] = CactiValidator::validateInput((isrv('t_title') ? gnrv('t_title') : ''), 't_title', [], 3);
|
||||
$save2['title'] = CactiValidator::validateInput(gnrv('title'), 'title', (isrv('t_title') ? [] : [new Assert\NotBlank()]), 3);
|
||||
$save2['t_height'] = CactiValidator::validateInput((isrv('t_height') ? gnrv('t_height') : ''), 't_height', [], 3);
|
||||
$save2['height'] = CactiValidator::validateInput(gnrv('height'), 'height', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['t_width'] = CactiValidator::validateInput((isrv('t_width') ? gnrv('t_width') : ''), 't_width', [], 3);
|
||||
$save2['width'] = CactiValidator::validateInput(gnrv('width'), 'width', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['t_upper_limit'] = CactiValidator::validateInput((isrv('t_upper_limit') ? gnrv('t_upper_limit') : ''), 't_upper_limit', [], 3);
|
||||
$save2['upper_limit'] = CactiValidator::validateInput(gnrv('upper_limit'), 'upper_limit', [new Assert\Regex('/^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U)\z/')], 3);
|
||||
$save2['t_lower_limit'] = CactiValidator::validateInput((isrv('t_lower_limit') ? gnrv('t_lower_limit') : ''), 't_lower_limit', [], 3);
|
||||
$save2['lower_limit'] = CactiValidator::validateInput(gnrv('lower_limit'), 'lower_limit', [new Assert\Regex('/^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U)\z/')], 3);
|
||||
$save2['t_vertical_label'] = CactiValidator::validateInput((isrv('t_vertical_label') ? gnrv('t_vertical_label') : ''), 't_vertical_label', [], 3);
|
||||
$save2['vertical_label'] = CactiValidator::validateInput(gnrv('vertical_label'), 'vertical_label', [], 3);
|
||||
$save2['t_slope_mode'] = CactiValidator::validateInput((isrv('t_slope_mode') ? gnrv('t_slope_mode') : ''), 't_slope_mode', [], 3);
|
||||
$save2['slope_mode'] = CactiValidator::validateInput((isrv('slope_mode') ? gnrv('slope_mode') : ''), 'slope_mode', [], 3);
|
||||
$save2['t_auto_scale'] = CactiValidator::validateInput((isrv('t_auto_scale') ? gnrv('t_auto_scale') : ''), 't_auto_scale', [], 3);
|
||||
$save2['auto_scale'] = CactiValidator::validateInput((isrv('auto_scale') ? gnrv('auto_scale') : ''), 'auto_scale', [], 3);
|
||||
$save2['t_auto_scale_opts'] = CactiValidator::validateInput((isrv('t_auto_scale_opts') ? gnrv('t_auto_scale_opts') : ''), 't_auto_scale_opts', [], 3);
|
||||
$save2['auto_scale_opts'] = CactiValidator::validateInput(gnrv('auto_scale_opts'), 'auto_scale_opts', [], 3);
|
||||
$save2['t_auto_scale_log'] = CactiValidator::validateInput((isrv('t_auto_scale_log') ? gnrv('t_auto_scale_log') : ''), 't_auto_scale_log', [], 3);
|
||||
$save2['auto_scale_log'] = CactiValidator::validateInput((isrv('auto_scale_log') ? gnrv('auto_scale_log') : ''), 'auto_scale_log', [], 3);
|
||||
$save2['t_scale_log_units'] = CactiValidator::validateInput((isrv('t_scale_log_units') ? gnrv('t_scale_log_units') : ''), 't_scale_log_units', [], 3);
|
||||
$save2['scale_log_units'] = CactiValidator::validateInput((isrv('scale_log_units') ? gnrv('scale_log_units') : ''), 'scale_log_units', [], 3);
|
||||
$save2['t_auto_scale_rigid'] = CactiValidator::validateInput((isrv('t_auto_scale_rigid') ? gnrv('t_auto_scale_rigid') : ''), 't_auto_scale_rigid', [], 3);
|
||||
$save2['auto_scale_rigid'] = CactiValidator::validateInput((isrv('auto_scale_rigid') ? gnrv('auto_scale_rigid') : ''), 'auto_scale_rigid', [], 3);
|
||||
$save2['t_auto_padding'] = CactiValidator::validateInput((isrv('t_auto_padding') ? gnrv('t_auto_padding') : ''), 't_auto_padding', [], 3);
|
||||
$save2['auto_padding'] = CactiValidator::validateInput((isrv('auto_padding') ? gnrv('auto_padding') : ''), 'auto_padding', [], 3);
|
||||
$save2['t_base_value'] = CactiValidator::validateInput((isrv('t_base_value') ? gnrv('t_base_value') : ''), 't_base_value', [], 3);
|
||||
$save2['base_value'] = CactiValidator::validateInput(gnrv('base_value'), 'base_value', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['t_unit_value'] = CactiValidator::validateInput((isrv('t_unit_value') ? gnrv('t_unit_value') : ''), 't_unit_value', [], 3);
|
||||
$save2['unit_value'] = CactiValidator::validateInput(gnrv('unit_value'), 'unit_value', [], 3);
|
||||
$save2['t_unit_exponent_value'] = CactiValidator::validateInput((isrv('t_unit_exponent_value') ? gnrv('t_unit_exponent_value') : ''), 't_unit_exponent_value', [], 3);
|
||||
$save2['unit_exponent_value'] = CactiValidator::validateInput(gnrv('unit_exponent_value'), 'unit_exponent_value', [new Assert\Regex('/^-?[0-9]+$/')], 3);
|
||||
$save2['t_alt_y_grid'] = CactiValidator::validateInput((isrv('t_alt_y_grid') ? gnrv('t_alt_y_grid') : ''), 't_alt_y_grid', [], 3);
|
||||
$save2['alt_y_grid'] = CactiValidator::validateInput((isrv('alt_y_grid') ? gnrv('alt_y_grid') : ''), 'alt_y_grid', [], 3);
|
||||
$save2['t_right_axis'] = CactiValidator::validateInput((isrv('t_right_axis') ? gnrv('t_right_axis') : ''), 't_right_axis', [], 3);
|
||||
$save2['right_axis'] = CactiValidator::validateInput((isrv('right_axis') ? gnrv('right_axis') : ''), 'right_axis', [new Assert\Regex('/^-?([0-9]+(\.[0-9]*)?|\.[0-9]+):-?([0-9]+(\.[0-9]*)?|\.[0-9]+)$/')], 3);
|
||||
$save2['t_right_axis_label'] = CactiValidator::validateInput((isrv('t_right_axis_label') ? gnrv('t_right_axis_label') : ''), 't_right_axis_label', [], 3);
|
||||
$save2['right_axis_label'] = CactiValidator::validateInput((isrv('right_axis_label') ? gnrv('right_axis_label') : ''), 'right_axis_label', [], 3);
|
||||
$save2['t_right_axis_format'] = CactiValidator::validateInput((isrv('t_right_axis_format') ? gnrv('t_right_axis_format') : ''), 't_right_axis_format', [], 3);
|
||||
$save2['right_axis_format'] = CactiValidator::validateInput((isrv('right_axis_format') ? gnrv('right_axis_format') : ''), 'right_axis_format', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['t_no_gridfit'] = CactiValidator::validateInput((isrv('t_no_gridfit') ? gnrv('t_no_gridfit') : ''), 't_no_gridfit', [], 3);
|
||||
$save2['no_gridfit'] = CactiValidator::validateInput((isrv('no_gridfit') ? gnrv('no_gridfit') : ''), 'no_gridfit', [], 3);
|
||||
$save2['t_unit_length'] = CactiValidator::validateInput((isrv('t_unit_length') ? gnrv('t_unit_length') : ''), 't_unit_length', [], 3);
|
||||
$save2['unit_length'] = CactiValidator::validateInput((isrv('unit_length') ? gnrv('unit_length') : ''), 'unit_length', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['t_tab_width'] = CactiValidator::validateInput((isrv('t_tab_width') ? gnrv('t_tab_width') : ''), 't_tab_width', [], 3);
|
||||
$save2['tab_width'] = CactiValidator::validateInput((isrv('tab_width') ? gnrv('tab_width') : ''), 'tab_width', [new Assert\Regex('/^[0-9]*$/')], 3);
|
||||
$save2['t_dynamic_labels'] = CactiValidator::validateInput((isrv('t_dynamic_labels') ? gnrv('t_dynamic_labels') : ''), 't_dynamic_labels', [], 3);
|
||||
$save2['dynamic_labels'] = CactiValidator::validateInput((isrv('dynamic_labels') ? gnrv('dynamic_labels') : ''), 'dynamic_labels', [], 3);
|
||||
$save2['t_force_rules_legend'] = CactiValidator::validateInput((isrv('t_force_rules_legend') ? gnrv('t_force_rules_legend') : ''), 't_force_rules_legend', [], 3);
|
||||
$save2['force_rules_legend'] = CactiValidator::validateInput((isrv('force_rules_legend') ? gnrv('force_rules_legend') : ''), 'force_rules_legend', [], 3);
|
||||
$save2['t_legend_position'] = CactiValidator::validateInput((isrv('t_legend_position') ? gnrv('t_legend_position') : ''), 't_legend_position', [], 3);
|
||||
$save2['legend_position'] = CactiValidator::validateInput((isrv('legend_position') ? gnrv('legend_position') : ''), 'legend_position', [], 3);
|
||||
$save2['t_legend_direction'] = CactiValidator::validateInput((isrv('t_legend_direction') ? gnrv('t_legend_direction') : ''), 't_legend_direction', [], 3);
|
||||
$save2['legend_direction'] = CactiValidator::validateInput((isrv('legend_direction') ? gnrv('legend_direction') : ''), 'legend_direction', [], 3);
|
||||
$save2['t_right_axis_formatter'] = CactiValidator::validateInput((isrv('t_right_axis_formatter') ? gnrv('t_right_axis_formatter') : ''), 't_right_axis_formatter', [], 3);
|
||||
$save2['right_axis_formatter'] = CactiValidator::validateInput((isrv('right_axis_formatter') ? gnrv('right_axis_formatter') : ''), 'right_axis_formatter', [], 3);
|
||||
$save2['t_left_axis_format'] = CactiValidator::validateInput((isrv('t_left_axis_format') ? gnrv('t_left_axis_format') : ''), 't_left_axis_format', [], 3);
|
||||
$save2['left_axis_format'] = CactiValidator::validateInput((isrv('left_axis_format') ? gnrv('left_axis_format') : ''), 'left_axis_format', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['t_left_axis_formatter'] = CactiValidator::validateInput((isrv('t_left_axis_formatter') ? gnrv('t_left_axis_formatter') : ''), 't_left_axis_formatter', [], 3);
|
||||
$save2['left_axis_formatter'] = CactiValidator::validateInput((isrv('left_axis_formatter') ? gnrv('left_axis_formatter') : ''), 'left_axis_formatter', [], 3);
|
||||
|
||||
if (!is_error_message()) {
|
||||
$save1['last_updated'] = date('Y-m-d H:i:s');
|
||||
@@ -466,9 +469,9 @@ function form_save() : void {
|
||||
$save['hash'] = get_hash_graph_template(grv('graph_template_item_id'), 'graph_template_item');
|
||||
$save['graph_template_id'] = grv('graph_template_id');
|
||||
$save['local_graph_id'] = 0;
|
||||
$save['task_item_id'] = form_input_validate(grv('task_item_id'), 'task_item_id', '^[0-9]+$', true, 3);
|
||||
$save['color_id'] = form_input_validate((isset($item['color_id']) ? $item['color_id'] : grv('color_id')), 'color_id', '', true, 3);
|
||||
$save['color2_id'] = form_input_validate((isset($item['color2_id']) ? $item['color2_id'] : grv('color2_id')), 'color2_id', '', true, 3);
|
||||
$save['task_item_id'] = CactiValidator::validateInput(grv('task_item_id'), 'task_item_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['color_id'] = CactiValidator::validateInput((isset($item['color_id']) ? $item['color_id'] : grv('color_id')), 'color_id', [], 3);
|
||||
$save['color2_id'] = CactiValidator::validateInput((isset($item['color2_id']) ? $item['color2_id'] : grv('color2_id')), 'color2_id', [], 3);
|
||||
|
||||
// if alpha is disabled, use invisible_alpha instead
|
||||
if (!isrv('alpha')) {
|
||||
@@ -479,14 +482,14 @@ function form_save() : void {
|
||||
srv('alpha2', gnrv('invisible_alpha'));
|
||||
}
|
||||
|
||||
$save['alpha'] = form_input_validate((isset($item['alpha']) ? $item['alpha'] : gnrv('alpha')), 'alpha', '', true, 3);
|
||||
$save['alpha2'] = form_input_validate((isset($item['alpha2']) ? $item['alpha2'] : gnrv('alpha2')), 'alpha2', '', true, 3);
|
||||
$save['gradheight'] = form_input_validate((isset($item['gradheight']) ? $item['gradheight'] : gnrv('gradheight')), 'gradheight', '', true, 3);
|
||||
$save['alpha'] = CactiValidator::validateInput((isset($item['alpha']) ? $item['alpha'] : gnrv('alpha')), 'alpha', [], 3);
|
||||
$save['alpha2'] = CactiValidator::validateInput((isset($item['alpha2']) ? $item['alpha2'] : gnrv('alpha2')), 'alpha2', [], 3);
|
||||
$save['gradheight'] = CactiValidator::validateInput((isset($item['gradheight']) ? $item['gradheight'] : gnrv('gradheight')), 'gradheight', [], 3);
|
||||
|
||||
$save['graph_type_id'] = form_input_validate((isset($item['graph_type_id']) ? $item['graph_type_id'] : gfrv('graph_type_id')), 'graph_type_id', '^[0-9]+$', true, 3);
|
||||
$save['graph_type_id'] = CactiValidator::validateInput((isset($item['graph_type_id']) ? $item['graph_type_id'] : gfrv('graph_type_id')), 'graph_type_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
if (isrv('line_width') || isset($item['line_width'])) {
|
||||
$save['line_width'] = form_input_validate((isset($item['line_width']) ? $item['line_width'] : gnrv('line_width')), 'line_width', '(^[0-9]+[\.,0-9]+$|^[0-9]+$)', true, 3);
|
||||
$save['line_width'] = CactiValidator::validateInput((isset($item['line_width']) ? $item['line_width'] : gnrv('line_width')), 'line_width', [new Assert\Regex('/(^[0-9]+[\.,0-9]+$|^[0-9]+$)/')], 3);
|
||||
} else {
|
||||
// make sure to transfer old LINEx style into line_width on save
|
||||
switch ($save['graph_type_id']) {
|
||||
@@ -507,23 +510,23 @@ function form_save() : void {
|
||||
}
|
||||
}
|
||||
|
||||
$save['dashes'] = form_input_validate((isrv('dashes') ? gnrv('dashes') : ''), 'dashes', '^[0-9]+[,0-9]*$', true, 3);
|
||||
$save['dash_offset'] = form_input_validate((isrv('dash_offset') ? gnrv('dash_offset') : ''), 'dash_offset', '^[0-9]+$', true, 3);
|
||||
$save['cdef_id'] = form_input_validate(gnrv('cdef_id'), 'cdef_id', '^[0-9]+$', true, 3);
|
||||
$save['vdef_id'] = form_input_validate(gnrv('vdef_id'), 'vdef_id', '^[0-9]+$', true, 3);
|
||||
$save['shift'] = form_input_validate((isrv('shift') ? gnrv('shift') : ''), 'shift', '^((on)|)$', true, 3);
|
||||
$save['consolidation_function_id'] = form_input_validate((isset($item['consolidation_function_id']) ? $item['consolidation_function_id'] : gnrv('consolidation_function_id')), 'consolidation_function_id', '^[0-9]+$', true, 3);
|
||||
$save['dashes'] = CactiValidator::validateInput((isrv('dashes') ? gnrv('dashes') : ''), 'dashes', [new Assert\Regex('/^[0-9]+[,0-9]*$/')], 3);
|
||||
$save['dash_offset'] = CactiValidator::validateInput((isrv('dash_offset') ? gnrv('dash_offset') : ''), 'dash_offset', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['cdef_id'] = CactiValidator::validateInput(gnrv('cdef_id'), 'cdef_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['vdef_id'] = CactiValidator::validateInput(gnrv('vdef_id'), 'vdef_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['shift'] = CactiValidator::validateInput((isrv('shift') ? gnrv('shift') : ''), 'shift', [new Assert\Regex('/^((on)|)$/')], 3);
|
||||
$save['consolidation_function_id'] = CactiValidator::validateInput((isset($item['consolidation_function_id']) ? $item['consolidation_function_id'] : gnrv('consolidation_function_id')), 'consolidation_function_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
$save['textalign'] = form_input_validate((isrv('textalign') ? gnrv('textalign') : ''), 'textalign', '^[a-z]+$', true, 3);
|
||||
$save['textalign'] = CactiValidator::validateInput((isrv('textalign') ? gnrv('textalign') : ''), 'textalign', [new Assert\Regex('/^[a-z]+$/')], 3);
|
||||
|
||||
$save['text_format'] = form_input_validate((isset($item['text_format']) ? $item['text_format'] : gnrv('text_format')), 'text_format', '', true, 3);
|
||||
$save['legend'] = form_input_validate((isset($item['legend']) ? $item['legend'] : gnrv('legend')), 'legend', '', true, 3);
|
||||
$save['text_format'] = CactiValidator::validateInput((isset($item['text_format']) ? $item['text_format'] : gnrv('text_format')), 'text_format', [], 3);
|
||||
$save['legend'] = CactiValidator::validateInput((isset($item['legend']) ? $item['legend'] : gnrv('legend')), 'legend', [], 3);
|
||||
|
||||
$save['value'] = form_input_validate(gnrv('value'), 'value', '', true, 3);
|
||||
$save['value'] = CactiValidator::validateInput(gnrv('value'), 'value', [], 3);
|
||||
|
||||
$save['hard_return'] = form_input_validate(((isset($item['hard_return']) ? $item['hard_return'] : (isrv('hard_return') ? gnrv('hard_return') : ''))), 'hard_return', '', true, 3);
|
||||
$save['hard_return'] = CactiValidator::validateInput(((isset($item['hard_return']) ? $item['hard_return'] : (isrv('hard_return') ? gnrv('hard_return') : ''))), 'hard_return', [], 3);
|
||||
|
||||
$save['gprint_id'] = form_input_validate(gnrv('gprint_id'), 'gprint_id', '^[0-9]+$', true, 3);
|
||||
$save['gprint_id'] = CactiValidator::validateInput(gnrv('gprint_id'), 'gprint_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['sequence'] = $sequence;
|
||||
|
||||
if (!is_error_message()) {
|
||||
@@ -640,9 +643,9 @@ function form_save() : void {
|
||||
$save['id'] = gnrv('graph_template_input_id');
|
||||
$save['hash'] = get_hash_graph_template(gnrv('graph_template_input_id'), 'graph_template_input');
|
||||
$save['graph_template_id'] = gnrv('graph_template_id');
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save['description'] = form_input_validate(gnrv('description'), 'description', '', true, 3);
|
||||
$save['column_name'] = form_input_validate(gnrv('column_name'), 'column_name', '', true, 3);
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()], 3);
|
||||
$save['description'] = CactiValidator::validateInput(gnrv('description'), 'description', [], 3);
|
||||
$save['column_name'] = CactiValidator::validateInput(gnrv('column_name'), 'column_name', [], 3);
|
||||
|
||||
if (is_error_message() === false) {
|
||||
$graph_template_input_id = sql_save($save, 'graph_template_input');
|
||||
|
||||
+62
-59
@@ -38,6 +38,9 @@ require_once(CACTI_PATH_LIBRARY . '/reports.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/rrd.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/template.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
// set default action
|
||||
set_default_action();
|
||||
@@ -385,36 +388,36 @@ function form_save() : void {
|
||||
$save2['id'] = gnrv('graph_template_graph_id');
|
||||
$save2['local_graph_template_graph_id'] = gnrv('local_graph_template_graph_id');
|
||||
$save2['graph_template_id'] = gnrv('graph_template_id');
|
||||
$save2['image_format_id'] = form_input_validate(gnrv('image_format_id'), 'image_format_id', '^[0-9]+$', true, 3);
|
||||
$save2['title'] = form_input_validate(gnrv('title'), 'title', '', false, 3);
|
||||
$save2['height'] = form_input_validate(gnrv('height'), 'height', '^[0-9]+$', false, 3);
|
||||
$save2['width'] = form_input_validate(gnrv('width'), 'width', '^[0-9]+$', false, 3);
|
||||
$save2['upper_limit'] = form_input_validate(gnrv('upper_limit'), 'upper_limit', '^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U)\z', ((strlen(gnrv('upper_limit')) === 0) ? true : false), 3);
|
||||
$save2['lower_limit'] = form_input_validate(gnrv('lower_limit'), 'lower_limit', '^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U)\z', ((strlen(gnrv('lower_limit')) === 0) ? true : false), 3);
|
||||
$save2['vertical_label'] = form_input_validate(gnrv('vertical_label'), 'vertical_label', '', true, 3);
|
||||
$save2['slope_mode'] = form_input_validate((isrv('slope_mode') ? gnrv('slope_mode') : ''), 'slope_mode', '', true, 3);
|
||||
$save2['auto_scale'] = form_input_validate((isrv('auto_scale') ? gnrv('auto_scale') : ''), 'auto_scale', '', true, 3);
|
||||
$save2['auto_scale_opts'] = form_input_validate(gnrv('auto_scale_opts'), 'auto_scale_opts', '', true, 3);
|
||||
$save2['auto_scale_log'] = form_input_validate((isrv('auto_scale_log') ? gnrv('auto_scale_log') : ''), 'auto_scale_log', '', true, 3);
|
||||
$save2['scale_log_units'] = form_input_validate((isrv('scale_log_units') ? gnrv('scale_log_units') : ''), 'scale_log_units', '', true, 3);
|
||||
$save2['auto_scale_rigid'] = form_input_validate((isrv('auto_scale_rigid') ? gnrv('auto_scale_rigid') : ''), 'auto_scale_rigid', '', true, 3);
|
||||
$save2['auto_padding'] = form_input_validate((isrv('auto_padding') ? gnrv('auto_padding') : ''), 'auto_padding', '', true, 3);
|
||||
$save2['base_value'] = form_input_validate(gnrv('base_value'), 'base_value', '^[0-9]+$', false, 3);
|
||||
$save2['unit_value'] = form_input_validate(gnrv('unit_value'), 'unit_value', '', true, 3);
|
||||
$save2['unit_exponent_value'] = form_input_validate(gnrv('unit_exponent_value'), 'unit_exponent_value', '^-?[0-9]+$', true, 3);
|
||||
$save2['alt_y_grid'] = form_input_validate((isrv('alt_y_grid') ? gnrv('alt_y_grid') : ''), 'alt_y_grid', '', true, 3);
|
||||
$save2['right_axis'] = form_input_validate((isrv('right_axis') ? gnrv('right_axis') : ''), 'right_axis', '^-?([0-9]+(\.[0-9]*)?|\.[0-9]+):-?([0-9]+(\.[0-9]*)?|\.[0-9]+)$', true, 3);
|
||||
$save2['right_axis_label'] = form_input_validate((isrv('right_axis_label') ? gnrv('right_axis_label') : ''), 'right_axis_label', '', true, 3);
|
||||
$save2['right_axis_format'] = form_input_validate((isrv('right_axis_format') ? gnrv('right_axis_format') : ''), 'right_axis_format', '^[0-9]+$', true, 3);
|
||||
$save2['no_gridfit'] = form_input_validate((isrv('no_gridfit') ? gnrv('no_gridfit') : ''), 'no_gridfit', '', true, 3);
|
||||
$save2['unit_length'] = form_input_validate((isrv('unit_length') ? gnrv('unit_length') : ''), 'unit_length', '^[0-9]+$', true, 3);
|
||||
$save2['tab_width'] = form_input_validate((isrv('tab_width') ? gnrv('tab_width') : ''), 'tab_width', '^[0-9]*$', true, 3);
|
||||
$save2['dynamic_labels'] = form_input_validate((isrv('dynamic_labels') ? gnrv('dynamic_labels') : ''), 'dynamic_labels', '', true, 3);
|
||||
$save2['force_rules_legend'] = form_input_validate((isrv('force_rules_legend') ? gnrv('force_rules_legend') : ''), 'force_rules_legend', '', true, 3);
|
||||
$save2['legend_position'] = form_input_validate((isrv('legend_position') ? gnrv('legend_position') : ''), 'legend_position', '', true, 3);
|
||||
$save2['legend_direction'] = form_input_validate((isrv('legend_direction') ? gnrv('legend_direction') : ''), 'legend_direction', '', true, 3);
|
||||
$save2['right_axis_formatter'] = form_input_validate((isrv('right_axis_formatter') ? gnrv('right_axis_formatter') : ''), 'right_axis_formatter', '', true, 3);
|
||||
$save2['left_axis_format'] = form_input_validate((isrv('left_axis_format') ? gnrv('left_axis_format') : ''), 'left_axis_format', '^[0-9]+$', true, 3);
|
||||
$save2['image_format_id'] = CactiValidator::validateInput(gnrv('image_format_id'), 'image_format_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['title'] = CactiValidator::validateInput(gnrv('title'), 'title', [new Assert\NotBlank()], 3);
|
||||
$save2['height'] = CactiValidator::validateInput(gnrv('height'), 'height', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['width'] = CactiValidator::validateInput(gnrv('width'), 'width', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['upper_limit'] = CactiValidator::validateInput(gnrv('upper_limit'), 'upper_limit', [new Assert\Regex('/^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U)\z/')], 3);
|
||||
$save2['lower_limit'] = CactiValidator::validateInput(gnrv('lower_limit'), 'lower_limit', [new Assert\Regex('/^(-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?|U)\z/')], 3);
|
||||
$save2['vertical_label'] = CactiValidator::validateInput(gnrv('vertical_label'), 'vertical_label', [], 3);
|
||||
$save2['slope_mode'] = CactiValidator::validateInput((isrv('slope_mode') ? gnrv('slope_mode') : ''), 'slope_mode', [], 3);
|
||||
$save2['auto_scale'] = CactiValidator::validateInput((isrv('auto_scale') ? gnrv('auto_scale') : ''), 'auto_scale', [], 3);
|
||||
$save2['auto_scale_opts'] = CactiValidator::validateInput(gnrv('auto_scale_opts'), 'auto_scale_opts', [], 3);
|
||||
$save2['auto_scale_log'] = CactiValidator::validateInput((isrv('auto_scale_log') ? gnrv('auto_scale_log') : ''), 'auto_scale_log', [], 3);
|
||||
$save2['scale_log_units'] = CactiValidator::validateInput((isrv('scale_log_units') ? gnrv('scale_log_units') : ''), 'scale_log_units', [], 3);
|
||||
$save2['auto_scale_rigid'] = CactiValidator::validateInput((isrv('auto_scale_rigid') ? gnrv('auto_scale_rigid') : ''), 'auto_scale_rigid', [], 3);
|
||||
$save2['auto_padding'] = CactiValidator::validateInput((isrv('auto_padding') ? gnrv('auto_padding') : ''), 'auto_padding', [], 3);
|
||||
$save2['base_value'] = CactiValidator::validateInput(gnrv('base_value'), 'base_value', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['unit_value'] = CactiValidator::validateInput(gnrv('unit_value'), 'unit_value', [], 3);
|
||||
$save2['unit_exponent_value'] = CactiValidator::validateInput(gnrv('unit_exponent_value'), 'unit_exponent_value', [new Assert\Regex('/^-?[0-9]+$/')], 3);
|
||||
$save2['alt_y_grid'] = CactiValidator::validateInput((isrv('alt_y_grid') ? gnrv('alt_y_grid') : ''), 'alt_y_grid', [], 3);
|
||||
$save2['right_axis'] = CactiValidator::validateInput((isrv('right_axis') ? gnrv('right_axis') : ''), 'right_axis', [new Assert\Regex('/^-?([0-9]+(\.[0-9]*)?|\.[0-9]+):-?([0-9]+(\.[0-9]*)?|\.[0-9]+)$/')], 3);
|
||||
$save2['right_axis_label'] = CactiValidator::validateInput((isrv('right_axis_label') ? gnrv('right_axis_label') : ''), 'right_axis_label', [], 3);
|
||||
$save2['right_axis_format'] = CactiValidator::validateInput((isrv('right_axis_format') ? gnrv('right_axis_format') : ''), 'right_axis_format', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['no_gridfit'] = CactiValidator::validateInput((isrv('no_gridfit') ? gnrv('no_gridfit') : ''), 'no_gridfit', [], 3);
|
||||
$save2['unit_length'] = CactiValidator::validateInput((isrv('unit_length') ? gnrv('unit_length') : ''), 'unit_length', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['tab_width'] = CactiValidator::validateInput((isrv('tab_width') ? gnrv('tab_width') : ''), 'tab_width', [new Assert\Regex('/^[0-9]*$/')], 3);
|
||||
$save2['dynamic_labels'] = CactiValidator::validateInput((isrv('dynamic_labels') ? gnrv('dynamic_labels') : ''), 'dynamic_labels', [], 3);
|
||||
$save2['force_rules_legend'] = CactiValidator::validateInput((isrv('force_rules_legend') ? gnrv('force_rules_legend') : ''), 'force_rules_legend', [], 3);
|
||||
$save2['legend_position'] = CactiValidator::validateInput((isrv('legend_position') ? gnrv('legend_position') : ''), 'legend_position', [], 3);
|
||||
$save2['legend_direction'] = CactiValidator::validateInput((isrv('legend_direction') ? gnrv('legend_direction') : ''), 'legend_direction', [], 3);
|
||||
$save2['right_axis_formatter'] = CactiValidator::validateInput((isrv('right_axis_formatter') ? gnrv('right_axis_formatter') : ''), 'right_axis_formatter', [], 3);
|
||||
$save2['left_axis_format'] = CactiValidator::validateInput((isrv('left_axis_format') ? gnrv('left_axis_format') : ''), 'left_axis_format', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save2['left_axis_formatter'] = form_input_validate((isrv('left_axis_formatter') ? gnrv('left_axis_formatter') : ''), 'left_axis_formatter', '', true, 3);
|
||||
|
||||
if (!is_error_message()) {
|
||||
@@ -648,9 +651,9 @@ function form_save() : void {
|
||||
$save['graph_template_id'] = gnrv('graph_template_id');
|
||||
$save['local_graph_template_item_id'] = gnrv('local_graph_template_item_id');
|
||||
$save['local_graph_id'] = gnrv('local_graph_id');
|
||||
$save['task_item_id'] = form_input_validate(gnrv('task_item_id'), 'task_item_id', '^[0-9]+$', true, 3);
|
||||
$save['color_id'] = form_input_validate((isset($item['color_id']) ? $item['color_id'] : gnrv('color_id')), 'color_id', '^[0-9]+$', true, 3);
|
||||
$save['color2_id'] = form_input_validate((isset($item['color2_id']) ? $item['color2_id'] : gnrv('color2_id')), 'color2_id', '^[0-9]+$', true, 3);
|
||||
$save['task_item_id'] = CactiValidator::validateInput(gnrv('task_item_id'), 'task_item_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['color_id'] = CactiValidator::validateInput((isset($item['color_id']) ? $item['color_id'] : gnrv('color_id')), 'color_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['color2_id'] = CactiValidator::validateInput((isset($item['color2_id']) ? $item['color2_id'] : gnrv('color2_id')), 'color2_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
// if alpha is disabled, use invisible_alpha instead
|
||||
if (!isrv('alpha')) {
|
||||
@@ -661,14 +664,14 @@ function form_save() : void {
|
||||
srv('alpha2', gnrv('invisible_alpha'));
|
||||
}
|
||||
|
||||
$save['alpha'] = form_input_validate((isset($item['alpha']) ? $item['alpha'] : gnrv('alpha')), 'alpha', '', true, 3);
|
||||
$save['alpha2'] = form_input_validate((isset($item['alpha2']) ? $item['alpha2'] : gnrv('alpha2')), 'alpha2', '', true, 3);
|
||||
$save['gradheight'] = form_input_validate(gnrv('gradheight'), 'gradheight', '', true, 3);
|
||||
$save['alpha'] = CactiValidator::validateInput((isset($item['alpha']) ? $item['alpha'] : gnrv('alpha')), 'alpha', [], 3);
|
||||
$save['alpha2'] = CactiValidator::validateInput((isset($item['alpha2']) ? $item['alpha2'] : gnrv('alpha2')), 'alpha2', [], 3);
|
||||
$save['gradheight'] = CactiValidator::validateInput(gnrv('gradheight'), 'gradheight', [], 3);
|
||||
|
||||
$save['graph_type_id'] = form_input_validate((isset($item['graph_type_id']) ? $item['graph_type_id'] : gnrv('graph_type_id')), 'graph_type_id', '^[0-9]+$', true, 3);
|
||||
$save['graph_type_id'] = CactiValidator::validateInput((isset($item['graph_type_id']) ? $item['graph_type_id'] : gnrv('graph_type_id')), 'graph_type_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
if (isrv('line_width')) {
|
||||
$save['line_width'] = form_input_validate(gnrv('line_width'), 'line_width', '(^[0-9]+[\.,0-9]+$|^[0-9]+$)', true, 3);
|
||||
$save['line_width'] = CactiValidator::validateInput(gnrv('line_width'), 'line_width', [new Assert\Regex('/(^[0-9]+[\.,0-9]+$|^[0-9]+$)/')], 3);
|
||||
} else { // make sure to transfer old LINEx style into line_width on save
|
||||
switch ($save['graph_type_id']) {
|
||||
case GRAPH_ITEM_TYPE_LINE1:
|
||||
@@ -688,19 +691,19 @@ function form_save() : void {
|
||||
}
|
||||
}
|
||||
|
||||
$save['dashes'] = form_input_validate((isrv('dashes') ? gnrv('dashes') : ''), 'dashes', '', true, 3);
|
||||
$save['dash_offset'] = form_input_validate((isrv('dash_offset') ? gnrv('dash_offset') : ''), 'dash_offset', '^[0-9]+$', true, 3);
|
||||
$save['cdef_id'] = form_input_validate(gnrv('cdef_id'), 'cdef_id', '^[0-9]+$', true, 3);
|
||||
$save['vdef_id'] = form_input_validate(gnrv('vdef_id'), 'vdef_id', '^[0-9]+$', true, 3);
|
||||
$save['shift'] = form_input_validate((isrv('shift') ? gnrv('shift') : ''), 'shift', '^((on)|)$', true, 3);
|
||||
$save['consolidation_function_id'] = form_input_validate((isset($item['consolidation_function_id']) ? $item['consolidation_function_id'] : gnrv('consolidation_function_id')), 'consolidation_function_id', '^[0-9]+$', true, 3);
|
||||
$save['textalign'] = form_input_validate((isrv('textalign') ? gnrv('textalign') : ''), 'textalign', '^[a-z]+$', true, 3);
|
||||
$save['text_format'] = form_input_validate((isset($item['text_format']) ? $item['text_format'] : gnrv('text_format')), 'text_format', '', true, 3);
|
||||
$save['legend'] = form_input_validate(gnrv('legend'), 'legend', '', true, 3);
|
||||
$save['dashes'] = CactiValidator::validateInput((isrv('dashes') ? gnrv('dashes') : ''), 'dashes', [], 3);
|
||||
$save['dash_offset'] = CactiValidator::validateInput((isrv('dash_offset') ? gnrv('dash_offset') : ''), 'dash_offset', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['cdef_id'] = CactiValidator::validateInput(gnrv('cdef_id'), 'cdef_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['vdef_id'] = CactiValidator::validateInput(gnrv('vdef_id'), 'vdef_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['shift'] = CactiValidator::validateInput((isrv('shift') ? gnrv('shift') : ''), 'shift', [new Assert\Regex('/^((on)|)$/')], 3);
|
||||
$save['consolidation_function_id'] = CactiValidator::validateInput((isset($item['consolidation_function_id']) ? $item['consolidation_function_id'] : gnrv('consolidation_function_id')), 'consolidation_function_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['textalign'] = CactiValidator::validateInput((isrv('textalign') ? gnrv('textalign') : ''), 'textalign', [new Assert\Regex('/^[a-z]+$/')], 3);
|
||||
$save['text_format'] = CactiValidator::validateInput((isset($item['text_format']) ? $item['text_format'] : gnrv('text_format')), 'text_format', [], 3);
|
||||
$save['legend'] = CactiValidator::validateInput(gnrv('legend'), 'legend', [], 3);
|
||||
|
||||
$save['value'] = form_input_validate(gnrv('value'), 'value', '', true, 3);
|
||||
$save['hard_return'] = form_input_validate(((isset($item['hard_return']) ? $item['hard_return'] : (isrv('hard_return') ? gnrv('hard_return') : ''))), 'hard_return', '', true, 3);
|
||||
$save['gprint_id'] = form_input_validate(gnrv('gprint_id'), 'gprint_id', '^[0-9]+$', true, 3);
|
||||
$save['value'] = CactiValidator::validateInput(gnrv('value'), 'value', [], 3);
|
||||
$save['hard_return'] = CactiValidator::validateInput(((isset($item['hard_return']) ? $item['hard_return'] : (isrv('hard_return') ? gnrv('hard_return') : ''))), 'hard_return', [], 3);
|
||||
$save['gprint_id'] = CactiValidator::validateInput(gnrv('gprint_id'), 'gprint_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['sequence'] = $sequence;
|
||||
|
||||
if (!is_error_message()) {
|
||||
@@ -1421,7 +1424,7 @@ function form_actions() : void {
|
||||
// get common info - not dependent on template/no template
|
||||
$local_graph_id = 0; // this will be a new graph
|
||||
$member_graphs = $selected_items;
|
||||
$graph_title = form_input_validate(gnrv('title_format'), 'title_format', '', true, 3);
|
||||
$graph_title = CactiValidator::validateInput(gnrv('title_format'), 'title_format', [], 3);
|
||||
|
||||
// future aggregate_graphs entry
|
||||
$ag_data = [];
|
||||
@@ -1446,18 +1449,18 @@ function form_actions() : void {
|
||||
srv('aggregate_order_type', 0);
|
||||
}
|
||||
|
||||
$item_no = form_input_validate(gnrv('item_no'), 'item_no', '^[0-9]+$', true, 3);
|
||||
$item_no = CactiValidator::validateInput(gnrv('item_no'), 'item_no', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
|
||||
$ag_data['aggregate_template_id'] = 0;
|
||||
$ag_data['template_propogation'] = '';
|
||||
$ag_data['graph_template_id'] = form_input_validate(gnrv('graph_template_id'), 'graph_template_id', '^[0-9]+$', true, 3);
|
||||
$ag_data['gprint_prefix'] = form_input_validate(gnrv('gprint_prefix'), 'gprint_prefix', '', true, 3);
|
||||
$ag_data['graph_template_id'] = CactiValidator::validateInput(gnrv('graph_template_id'), 'graph_template_id', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$ag_data['gprint_prefix'] = CactiValidator::validateInput(gnrv('gprint_prefix'), 'gprint_prefix', [], 3);
|
||||
$ag_data['gprint_format'] = isset_request_var('gprint_format') ? 'on' : '';
|
||||
$ag_data['graph_type'] = form_input_validate(gnrv('aggregate_graph_type'), 'aggregate_graph_type', '^[0-9]+$', true, 3);
|
||||
$ag_data['total'] = form_input_validate(gnrv('aggregate_total'), 'aggregate_total', '^[0-9]+$', true, 3);
|
||||
$ag_data['total_type'] = form_input_validate(gnrv('aggregate_total_type'), 'aggregate_total_type', '^[0-9]+$', true, 3);
|
||||
$ag_data['total_prefix'] = form_input_validate(gnrv('aggregate_total_prefix'), 'aggregate_total_prefix', '', true, 3);
|
||||
$ag_data['order_type'] = form_input_validate(gnrv('aggregate_order_type'), 'aggregate_order_type', '^[0-9]+$', true, 3);
|
||||
$ag_data['graph_type'] = CactiValidator::validateInput(gnrv('aggregate_graph_type'), 'aggregate_graph_type', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$ag_data['total'] = CactiValidator::validateInput(gnrv('aggregate_total'), 'aggregate_total', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$ag_data['total_type'] = CactiValidator::validateInput(gnrv('aggregate_total_type'), 'aggregate_total_type', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$ag_data['total_prefix'] = CactiValidator::validateInput(gnrv('aggregate_total_prefix'), 'aggregate_total_prefix', [], 3);
|
||||
$ag_data['order_type'] = CactiValidator::validateInput(gnrv('aggregate_order_type'), 'aggregate_order_type', [new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
} else {
|
||||
$template_data = db_fetch_row_prepared('SELECT *
|
||||
FROM aggregate_graph_templates
|
||||
|
||||
+14
-1
@@ -34,6 +34,9 @@ require_once(CACTI_PATH_LIBRARY . '/snmp.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/template.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
// set default action
|
||||
set_default_action();
|
||||
@@ -242,7 +245,17 @@ function host_new_graphs_save(int $host_id) : void {
|
||||
WHERE id = ?',
|
||||
[$input_field_id]);
|
||||
|
||||
$val = form_input_validate($val, $var, $idata['regexp_match'], $idata['allow_nulls'], 3);
|
||||
$constraints = [];
|
||||
|
||||
if ($idata['allow_nulls'] != 'on') {
|
||||
$constraints[] = new Assert\NotBlank();
|
||||
}
|
||||
|
||||
if (!empty($idata['regexp_match'])) {
|
||||
$constraints[] = new Assert\Regex('/' . $idata['regexp_match'] . '/');
|
||||
}
|
||||
|
||||
$val = CactiValidator::validateInput($val, $var, $constraints, 3);
|
||||
|
||||
if (empty($matches[1])) { // this is a new graph from template field
|
||||
$values['cg'][$matches[2]]['custom_data'][$matches[3]][$matches[4]] = $val;
|
||||
|
||||
+12
-9
@@ -35,6 +35,9 @@ require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/template.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/xml.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
if (!isrv('action') || gnrv('action') == 'templates' || gnrv('action_type') == 'templates') {
|
||||
$actions = [
|
||||
@@ -142,15 +145,15 @@ function form_save() : void {
|
||||
if (isrv('save_component_template')) {
|
||||
$save['id'] = gnrv('id');
|
||||
$save['hash'] = get_hash_host_template(gnrv('id'));
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save['version'] = form_input_validate(gnrv('version'), 'version', '', false, 3);
|
||||
$save['class'] = form_input_validate(gnrv('class'), 'class', '', false, 3);
|
||||
$save['tags'] = form_input_validate(gnrv('tags'), 'tags', '', true, 3);
|
||||
$save['author'] = form_input_validate(gnrv('author'), 'author', '', true, 3);
|
||||
$save['email'] = form_input_validate(gnrv('email'), 'email', '', true, 3);
|
||||
$save['homepage'] = form_input_validate(gnrv('homepage'), 'homepage', '', true, 3);
|
||||
$save['copyright'] = form_input_validate(gnrv('copyright'), 'copyright', '', false, 3);
|
||||
$save['installation'] = form_input_validate(gnrv('installation'), 'installation', '', true, 3);
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()], 3);
|
||||
$save['version'] = CactiValidator::validateInput(gnrv('version'), 'version', [new Assert\NotBlank()], 3);
|
||||
$save['class'] = CactiValidator::validateInput(gnrv('class'), 'class', [new Assert\NotBlank()], 3);
|
||||
$save['tags'] = CactiValidator::validateInput(gnrv('tags'), 'tags', [], 3);
|
||||
$save['author'] = CactiValidator::validateInput(gnrv('author'), 'author', [], 3);
|
||||
$save['email'] = CactiValidator::validateInput(gnrv('email'), 'email', [new Assert\Email(mode: 'html5')], 3);
|
||||
$save['homepage'] = CactiValidator::validateInput(gnrv('homepage'), 'homepage', [], 3);
|
||||
$save['copyright'] = CactiValidator::validateInput(gnrv('copyright'), 'copyright', [new Assert\NotBlank()], 3);
|
||||
$save['installation'] = CactiValidator::validateInput(gnrv('installation'), 'installation', [], 3);
|
||||
|
||||
if (!is_error_message()) {
|
||||
$host_template_id = sql_save($save, 'host_template');
|
||||
|
||||
@@ -22,6 +22,16 @@
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
// Symfony Validator is an optional composer dependency. global_settings.php is
|
||||
// included by global.php before vendor/autoload.php is registered (line 625 vs
|
||||
// 636). Guard the require so that the autoloader is available when the closures
|
||||
// in the constraints arrays are eventually invoked by CactiSettings::validate().
|
||||
if (file_exists(CACTI_PATH_INCLUDE . '/vendor/autoload.php')) {
|
||||
require_once(CACTI_PATH_INCLUDE . '/vendor/autoload.php');
|
||||
}
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$dir = dir(CACTI_PATH_INCLUDE . '/themes/');
|
||||
|
||||
// Work around issue where phpstan is not detecting globals
|
||||
@@ -184,14 +194,20 @@ $settings['path'] = [
|
||||
'description' => __('The path to your snmpwalk binary.'),
|
||||
'method' => 'filepath',
|
||||
'file_type' => 'binary',
|
||||
'max_length' => '255'
|
||||
'max_length' => '255',
|
||||
'constraints' => [
|
||||
fn () => new Assert\Length(min: 1, max: 255, minMessage: __('must not be empty.'), maxMessage: __('must be 255 characters or fewer.')),
|
||||
],
|
||||
],
|
||||
'path_snmpget' => [
|
||||
'friendly_name' => __('snmpget Binary Path'),
|
||||
'description' => __('The path to your snmpget binary.'),
|
||||
'method' => 'filepath',
|
||||
'file_type' => 'binary',
|
||||
'max_length' => '255'
|
||||
'max_length' => '255',
|
||||
'constraints' => [
|
||||
fn () => new Assert\Length(min: 1, max: 255, minMessage: __('must not be empty.'), maxMessage: __('must be 255 characters or fewer.')),
|
||||
],
|
||||
],
|
||||
'path_snmpbulkwalk' => [
|
||||
'friendly_name' => __('snmpbulkwalk Binary Path'),
|
||||
@@ -219,14 +235,22 @@ $settings['path'] = [
|
||||
'description' => __('The path to the rrdtool binary.'),
|
||||
'method' => 'filepath',
|
||||
'file_type' => 'binary',
|
||||
'max_length' => '255'
|
||||
'max_length' => '255',
|
||||
'constraints' => [
|
||||
fn () => new Assert\NotBlank(message: __('must not be empty.')),
|
||||
fn () => new Assert\Length(min: 1, max: 255, minMessage: __('must not be empty.'), maxMessage: __('must be 255 characters or fewer.')),
|
||||
],
|
||||
],
|
||||
'path_php_binary' => [
|
||||
'friendly_name' => __('PHP Binary Path'),
|
||||
'description' => __('The path to your PHP binary file (may require a php recompile to get this file).'),
|
||||
'method' => 'filepath',
|
||||
'file_type' => 'binary',
|
||||
'max_length' => '255'
|
||||
'max_length' => '255',
|
||||
'constraints' => [
|
||||
fn () => new Assert\NotBlank(message: __('must not be empty.')),
|
||||
fn () => new Assert\Length(min: 1, max: 255, minMessage: __('must not be empty.'), maxMessage: __('must be 255 characters or fewer.')),
|
||||
],
|
||||
],
|
||||
'path_composer' => [
|
||||
'friendly_name' => __('Composer Binary Path'),
|
||||
@@ -1008,7 +1032,11 @@ $settings['snmp'] = [
|
||||
'method' => 'textbox',
|
||||
'default' => '500',
|
||||
'max_length' => '10',
|
||||
'size' => '5'
|
||||
'size' => '5',
|
||||
'constraints' => [
|
||||
fn () => new Assert\Regex(pattern: '/^\d+$/', message: __('must be a positive integer (milliseconds).')),
|
||||
fn () => new Assert\Range(min: 1, max: 600000, notInRangeMessage: __('must be between {{ min }} and {{ max }}.')),
|
||||
],
|
||||
],
|
||||
'snmp_retries' => [
|
||||
'friendly_name' => __('Retries'),
|
||||
@@ -1016,7 +1044,11 @@ $settings['snmp'] = [
|
||||
'method' => 'textbox',
|
||||
'default' => '3',
|
||||
'max_length' => '10',
|
||||
'size' => '5'
|
||||
'size' => '5',
|
||||
'constraints' => [
|
||||
fn () => new Assert\Regex(pattern: '/^\d+$/', message: __('must be a non-negative integer.')),
|
||||
fn () => new Assert\Range(min: 0, max: 100, notInRangeMessage: __('must be between {{ min }} and {{ max }}.')),
|
||||
],
|
||||
],
|
||||
'snmp_bulk_walk_size' => [
|
||||
'friendly_name' => __('Bulkwalk Fetch Size'),
|
||||
@@ -1395,6 +1427,11 @@ $settings['visual'] = [
|
||||
'default' => CACTI_PATH_CACHE . '/realtime/',
|
||||
'max_length' => 255,
|
||||
'size' => 40,
|
||||
'constraints' => [
|
||||
fn () => new Assert\NotBlank(message: __('must not be empty.')),
|
||||
fn () => new Assert\Regex(pattern: '#^([A-Za-z]:\\\\|/)#', message: __('must be an absolute path.')),
|
||||
fn () => new Assert\Length(max: 255, maxMessage: __('must be 255 characters or fewer.')),
|
||||
],
|
||||
],
|
||||
'rrdtool_header' => [
|
||||
'friendly_name' => __('RRDtool Graph Options'),
|
||||
@@ -1534,6 +1571,18 @@ $settings['poller'] = [
|
||||
'method' => 'drop_array',
|
||||
'default' => 300,
|
||||
'array' => $poller_intervals,
|
||||
// Choices derive from $poller_intervals (keys are interval seconds).
|
||||
// Both string and int forms are accepted because $_POST values arrive
|
||||
// as strings while the canonical keys are int.
|
||||
'constraints' => [
|
||||
fn () => new Assert\Choice(
|
||||
choices: array_merge(
|
||||
array_keys($GLOBALS['poller_intervals']),
|
||||
array_map('strval', array_keys($GLOBALS['poller_intervals']))
|
||||
),
|
||||
message: __('is not a valid choice.')
|
||||
),
|
||||
],
|
||||
],
|
||||
'cron_interval' => [
|
||||
'friendly_name' => __('Cron/Daemon Interval'),
|
||||
@@ -1541,6 +1590,16 @@ $settings['poller'] = [
|
||||
'method' => 'drop_array',
|
||||
'default' => 300,
|
||||
'array' => $cron_intervals,
|
||||
// Choices derive from $cron_intervals (keys are interval seconds).
|
||||
'constraints' => [
|
||||
fn () => new Assert\Choice(
|
||||
choices: array_merge(
|
||||
array_keys($GLOBALS['cron_intervals']),
|
||||
array_map('strval', array_keys($GLOBALS['cron_intervals']))
|
||||
),
|
||||
message: __('is not a valid choice.')
|
||||
),
|
||||
],
|
||||
],
|
||||
'process_leveling' => [
|
||||
'friendly_name' => __('Balance Process Load'),
|
||||
@@ -2275,6 +2334,13 @@ $settings['mail'] = [
|
||||
'method' => 'textbox',
|
||||
'default' => 'localhost',
|
||||
'max_length' => 255,
|
||||
// NotBlank is intentionally NOT applied: SMTP hostname is only
|
||||
// load-bearing when settings_how is CACTI_MAIL_SMTP. Sites using
|
||||
// PHP's mail() / sendmail can leave this empty without harm.
|
||||
// Length cap is still enforced to keep DB inserts well-formed.
|
||||
'constraints' => [
|
||||
fn () => new Assert\Length(max: 255, maxMessage: __('must be 255 characters or fewer.')),
|
||||
],
|
||||
],
|
||||
'settings_smtp_port' => [
|
||||
'friendly_name' => __('SMTP Port'),
|
||||
@@ -2282,7 +2348,11 @@ $settings['mail'] = [
|
||||
'method' => 'textbox',
|
||||
'max_length' => 255,
|
||||
'default' => 25,
|
||||
'size' => 5
|
||||
'size' => 5,
|
||||
'constraints' => [
|
||||
fn () => new Assert\Regex(pattern: '/^\d+$/', message: __('must be a positive integer.')),
|
||||
fn () => new Assert\Range(min: 1, max: 65535, notInRangeMessage: __('must be between {{ min }} and {{ max }}.')),
|
||||
],
|
||||
],
|
||||
'settings_smtp_username' => [
|
||||
'friendly_name' => __('SMTP Username'),
|
||||
@@ -3137,7 +3207,11 @@ $settings_user = [
|
||||
'description' => __('The default RRA to use in rare occasions.'),
|
||||
'method' => 'drop_sql',
|
||||
'sql' => 'SELECT id, name FROM data_source_profiles_rra ORDER BY steps',
|
||||
'default' => '1'
|
||||
'default' => '1',
|
||||
'constraints' => [
|
||||
fn () => new Assert\Regex(pattern: '/^\d+$/', message: __('must be a positive integer id.')),
|
||||
fn () => new Assert\Positive(message: __('must be a positive number.')),
|
||||
],
|
||||
],
|
||||
'default_timespan' => [
|
||||
'friendly_name' => __('Default Timespan'),
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
| |
|
||||
| This program is distributed in the hope that it will be useful, |
|
||||
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
||||
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
||||
| GNU General Public License for more details. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
| This code is designed, written, and maintained by the Cacti Group. See |
|
||||
| about.php and/or the AUTHORS file for specific developer information. |
|
||||
| http://www.cacti.net/ |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/CactiValidator.php';
|
||||
|
||||
/**
|
||||
* Declarative settings validation backed by Symfony Validator.
|
||||
*
|
||||
* Settings in include/global_settings.php may declare a 'constraints' key
|
||||
* holding an array of callables. Each callable returns a Symfony Constraint
|
||||
* instance. The closure form is required because global_settings.php is
|
||||
* loaded before include/vendor/autoload.php, so eager instantiation of
|
||||
* Symfony classes in the array literal would fatal at file-load time. The
|
||||
* closures defer class resolution until validate() runs, by which point the
|
||||
* autoloader is registered.
|
||||
*
|
||||
* CactiSettings::validate() runs the entire posted set through the validator
|
||||
* in one pass and returns a map of {setting_name => first violation message}
|
||||
* suitable for surfacing via raise_message().
|
||||
*
|
||||
* The implicit type hints from 'method' (textbox/drop_array/...) are not
|
||||
* touched. Callers can mix them with explicit constraints; explicit always
|
||||
* wins where both apply.
|
||||
*/
|
||||
class CactiSettings {
|
||||
/**
|
||||
* Validate posted settings against their declared Symfony constraints.
|
||||
*
|
||||
* CONTRACT: only keys present in $posted_settings run their constraints.
|
||||
* Unposted keys (an unchecked checkbox, an inactive tab, a multiselect
|
||||
* that submitted nothing) are silently skipped. NotBlank-style guards
|
||||
* therefore only fire on fields that always post a value (textboxes,
|
||||
* required selects). For settings that may legitimately not post, write
|
||||
* the constraint as a closure that tolerates an empty string, or
|
||||
* enforce the requirement at the consumer site instead.
|
||||
*
|
||||
* @param array $posted_settings Map of {name => raw posted value} (typically $_POST).
|
||||
* @param array $settings_definitions Settings definition array as built by global_settings.php.
|
||||
* Either a flat name=>def map or a tab=>name=>def map; both
|
||||
* shapes are tolerated. The 'constraints' key on each entry
|
||||
* is array<callable>: callables that return a Constraint
|
||||
* instance. Plain Constraint instances are also accepted.
|
||||
*
|
||||
* @return array Map of {setting_name => first violation message}. Empty array means valid.
|
||||
*/
|
||||
public static function validate(array $posted_settings, array $settings_definitions) : array {
|
||||
$violations = [];
|
||||
$flat = self::flatten_definitions($settings_definitions);
|
||||
|
||||
foreach ($posted_settings as $name => $value) {
|
||||
if (!is_string($name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($flat[$name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$definition = $flat[$name];
|
||||
|
||||
if (!is_array($definition) || !isset($definition['constraints'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$constraints = $definition['constraints'];
|
||||
|
||||
if (!is_array($constraints) || empty($constraints)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Resolve closure-wrapped constraints. The closure form is what
|
||||
// global_settings.php uses; instantiation happens here, after the
|
||||
// autoloader is registered. Plain Constraint instances are still
|
||||
// accepted so unit tests and any post-autoload caller can pass
|
||||
// them directly.
|
||||
$resolved = [];
|
||||
|
||||
foreach ($constraints as $constraint) {
|
||||
if (is_callable($constraint)) {
|
||||
$resolved[] = $constraint();
|
||||
} else {
|
||||
$resolved[] = $constraint;
|
||||
}
|
||||
}
|
||||
|
||||
$result = CactiValidator::validate($value, $resolved);
|
||||
|
||||
if (count($result) === 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Single-message-per-setting matches the existing raise_message() UX
|
||||
// where one message renders per error.
|
||||
$violations[$name] = (string) $result->get(0)->getMessage();
|
||||
}
|
||||
|
||||
return $violations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accept either {name => def} or {tab => {name => def}} and return the
|
||||
* flat form. The settings array in global_settings.php is grouped by tab,
|
||||
* but callers may pass a single tab's slice instead. Both work.
|
||||
*
|
||||
* @param array $definitions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function flatten_definitions(array $definitions) : array {
|
||||
$flat = [];
|
||||
|
||||
foreach ($definitions as $key => $entry) {
|
||||
if (!is_array($entry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// A real setting definition has a 'method' key. A tab is a map
|
||||
// of names to definitions and lacks 'method' at the top level.
|
||||
if (isset($entry['method'])) {
|
||||
$flat[$key] = $entry;
|
||||
} else {
|
||||
foreach ($entry as $sub_name => $sub_entry) {
|
||||
if (is_array($sub_entry)) {
|
||||
$flat[$sub_name] = $sub_entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $flat;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
declare(strict_types = 1);
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Symfony\Component\Validator\Validation;
|
||||
use Symfony\Component\Validator\ConstraintViolationListInterface;
|
||||
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||
|
||||
class CactiValidator {
|
||||
private static ?ValidatorInterface $validator = null;
|
||||
|
||||
/**
|
||||
* The validator is built without a Symfony Translator. Cacti uses its
|
||||
* own gettext-based __() pipeline, so call sites are expected to pass
|
||||
* already-translated strings via each constraint's message option
|
||||
* (e.g. message: __('...'), notInRangeMessage: __('...')). Default
|
||||
* Symfony constraint messages render in English; if a constraint
|
||||
* requires localization, supply an explicit __() message argument.
|
||||
*/
|
||||
private static function getValidator(): ValidatorInterface {
|
||||
if (self::$validator === null) {
|
||||
self::$validator = Validation::createValidator();
|
||||
}
|
||||
|
||||
return self::$validator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the cached validator (for tests).
|
||||
*/
|
||||
public static function reset(): void {
|
||||
self::$validator = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a value against a set of constraints.
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
* @param array $constraints The Symfony constraints to apply.
|
||||
*
|
||||
* @return bool True if valid, false otherwise.
|
||||
*/
|
||||
public static function isValid(mixed $value, array $constraints): bool {
|
||||
return count(self::validate($value, $constraints)) === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate a value and return the raw Symfony violations.
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
* @param array $constraints The Symfony constraints to apply.
|
||||
*
|
||||
* @return ConstraintViolationListInterface
|
||||
*/
|
||||
public static function validate(mixed $value, array $constraints): ConstraintViolationListInterface {
|
||||
return self::getValidator()->validate($value, $constraints);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifically validate a Host ID (numeric and >= 0).
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
*
|
||||
* @return bool True if the value is a valid host id, false otherwise.
|
||||
*/
|
||||
public static function isValidHostId(mixed $value): bool {
|
||||
return self::isValid($value, [
|
||||
new Assert\NotNull(),
|
||||
new Assert\Type('numeric'),
|
||||
new Assert\GreaterThanOrEqual(0),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specifically validate an RRD path to prevent traversal.
|
||||
*
|
||||
* When $rraRoot is supplied, the path is also checked against the real
|
||||
* resolved root to defeat symlink-based escapes. The path must already
|
||||
* exist on disk for this branch to succeed; callers validating a
|
||||
* not-yet-created file should pass $rraRoot = null and check
|
||||
* containment after creation.
|
||||
*
|
||||
* @param string $path The relative RRD path to validate.
|
||||
* @param string|null $rraRoot Optional real RRA root to enforce containment against.
|
||||
*
|
||||
* @return bool True if the path is safe and (when $rraRoot is set) contained, false otherwise.
|
||||
*/
|
||||
public static function isValidRrdPath(string $path, ?string $rraRoot = null): bool {
|
||||
if ($path === '' || strpos($path, "\0") !== false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9_\-\.\/]+$/', $path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (str_contains($path, '..')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($path[0] === '/') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($rraRoot !== null) {
|
||||
$realRoot = realpath($rraRoot);
|
||||
|
||||
if ($realRoot === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find the deepest existing parent directory to validate containment
|
||||
// for files that don't exist yet.
|
||||
$testPath = $rraRoot . DIRECTORY_SEPARATOR . $path;
|
||||
$current = $testPath;
|
||||
|
||||
while (!file_exists($current) && $current !== dirname($current)) {
|
||||
$current = dirname($current);
|
||||
}
|
||||
|
||||
$realPath = realpath($current);
|
||||
|
||||
if ($realPath === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($realPath !== $realRoot && strncmp($realPath, $realRoot . DIRECTORY_SEPARATOR, strlen($realRoot) + 1) !== 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an IP address (v4 or v6).
|
||||
*
|
||||
* @param string $ip The IP address to validate.
|
||||
*
|
||||
* @return bool True if the value is a valid IPv4 or IPv6 address, false otherwise.
|
||||
*/
|
||||
public static function isValidIpAddress(string $ip): bool {
|
||||
return self::isValid($ip, [
|
||||
new Assert\Ip(['version' => 'all']),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an email address (HTML5 syntax, max 254 chars).
|
||||
*
|
||||
* @param string $email The email address to validate.
|
||||
*
|
||||
* @return bool True if the value is a valid email address, false otherwise.
|
||||
*/
|
||||
public static function isValidEmail(string $email): bool {
|
||||
return self::isValid($email, [
|
||||
new Assert\Email(mode: 'html5'),
|
||||
new Assert\Length(max: 254),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate an SNMP community string (non-blank, max 255 chars, no control bytes).
|
||||
*
|
||||
* @param string $community The SNMP community string to validate.
|
||||
*
|
||||
* @return bool True if the value is a valid community string, false otherwise.
|
||||
*/
|
||||
public static function isValidSnmpCommunity(string $community): bool {
|
||||
return self::isValid($community, [
|
||||
new Assert\NotBlank(),
|
||||
new Assert\Length(max: 255),
|
||||
new Assert\Regex('/^[^\x00-\x1F\x7F]+$/'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Common input validation helper.
|
||||
* Populates $_SESSION with the value and any error states.
|
||||
*
|
||||
* @param mixed $value The value to validate.
|
||||
* @param string $name The field name (used in $_SESSION).
|
||||
* @param array $constraints The Symfony Validator constraints.
|
||||
* @param mixed $message_id The Cacti message ID to raise on failure.
|
||||
*
|
||||
* @return mixed The original value.
|
||||
*/
|
||||
public static function validateInput(mixed $value, string $name, array $constraints, mixed $message_id = 3): mixed {
|
||||
$_SESSION[SESS_FIELD_VALUES][$name] = $value;
|
||||
|
||||
$violations = self::validate($value, $constraints);
|
||||
|
||||
if ($violations->count() > 0) {
|
||||
$_SESSION[SESS_ERROR_FIELDS][$name] = $message_id;
|
||||
raise_message($message_id);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,8 @@
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
/**
|
||||
* Creates a filter for tree devices.
|
||||
*
|
||||
@@ -6438,3 +6440,91 @@ function automation_log(string $string, int $level = AUTOMATION_LOG_LOW) : void
|
||||
cacti_log($string, false, 'AUTOMATION');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* api_networks_save - Saves an automation network.
|
||||
*
|
||||
* @param array $post The post variables from the form.
|
||||
*
|
||||
* @return mixed The ID of the saved network or false on failure.
|
||||
*/
|
||||
function api_networks_save(array $post) : mixed {
|
||||
if (empty($post['network_id'])) {
|
||||
$save['id'] = CactiValidator::validateInput($post['id'], 'id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['hash'] = get_hash_automation($post['id'], 'automation_networks');
|
||||
|
||||
// general information
|
||||
$save['name'] = CactiValidator::validateInput($post['name'], 'name', [new Assert\NotBlank()]);
|
||||
$save['poller_id'] = CactiValidator::validateInput($post['poller_id'], 'poller_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['site_id'] = CactiValidator::validateInput($post['site_id'], 'site_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['subnet_range'] = CactiValidator::validateInput($post['subnet_range'], 'subnet_range', [new Assert\NotBlank()]);
|
||||
$save['ignore_ips'] = CactiValidator::validateInput($post['ignore_ips'], 'ignore_ips', []);
|
||||
$save['dns_servers'] = CactiValidator::validateInput($post['dns_servers'], 'dns_servers', []);
|
||||
|
||||
$save['threads'] = CactiValidator::validateInput($post['threads'], 'threads', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['run_limit'] = CactiValidator::validateInput($post['run_limit'], 'run_limit', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
|
||||
$save['enabled'] = (isset($post['enabled']) ? 'on' : '');
|
||||
|
||||
// notification settings
|
||||
$save['notification_enabled'] = (isset($post['notification_enabled']) ? 'on' : '');
|
||||
$save['notification_email'] = CactiValidator::validateInput($post['notification_email'], 'notification_email', [new Assert\Email(mode: 'html5')]);
|
||||
|
||||
$save['notification_fromname'] = CactiValidator::validateInput($post['notification_fromname'], 'notification_fromname', []);
|
||||
$save['notification_fromemail'] = CactiValidator::validateInput($post['notification_fromemail'], 'notification_fromemail', [new Assert\Email(mode: 'html5')]);
|
||||
|
||||
$save['enable_netbios'] = (isset($post['enable_netbios']) ? 'on' : '');
|
||||
$save['add_to_cacti'] = (isset($post['add_to_cacti']) ? 'on' : '');
|
||||
$save['same_sysname'] = (isset($post['same_sysname']) ? 'on' : '');
|
||||
$save['rerun_data_queries'] = (isset($post['rerun_data_queries']) ? 'on' : '');
|
||||
|
||||
// discovery connectivity settings
|
||||
$save['snmp_id'] = CactiValidator::validateInput($post['snmp_id'], 'snmp_id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['ping_method'] = CactiValidator::validateInput($post['ping_method'], 'ping_method', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['ping_port'] = CactiValidator::validateInput($post['ping_port'], 'ping_port', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['ping_timeout'] = CactiValidator::validateInput($post['ping_timeout'], 'ping_timeout', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
$save['ping_retries'] = CactiValidator::validateInput($post['ping_retries'], 'ping_retries', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')]);
|
||||
|
||||
$save = api_scheduler_augment_save($save, $post);
|
||||
|
||||
// validate the network definitions and rais error if failed
|
||||
$continue = true;
|
||||
$total_ips = 0;
|
||||
$networks = explode(',', $save['subnet_range']);
|
||||
|
||||
if (cacti_sizeof($networks)) {
|
||||
foreach ($networks as $net) {
|
||||
$ips = automation_calculate_total_ips($net);
|
||||
|
||||
if ($ips !== false) {
|
||||
$total_ips += $ips;
|
||||
} else {
|
||||
$continue = false;
|
||||
raise_message('automation_message', __esc('ERROR: Network \'%s\' is Invalid.', $net), MESSAGE_LEVEL_ERROR);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($continue) {
|
||||
$save['total_ips'] = $total_ips;
|
||||
|
||||
$network_id = 0;
|
||||
|
||||
if (!is_error_message()) {
|
||||
$network_id = sql_save($save, 'automation_networks');
|
||||
|
||||
if ($network_id) {
|
||||
raise_message(1);
|
||||
} else {
|
||||
raise_message(2);
|
||||
}
|
||||
}
|
||||
|
||||
return $network_id;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -84,10 +84,10 @@ if (!cacti_sizeof($page)) {
|
||||
} else {
|
||||
print '<div id="content">';
|
||||
|
||||
$basepath = CACTI_PATH_INCLUDE . '/content';
|
||||
$file = realpath($basepath . '/' . $page['contentfile']);
|
||||
$basepath = realpath(CACTI_PATH_INCLUDE . '/content');
|
||||
$file = ($basepath !== false) ? realpath($basepath . '/' . $page['contentfile']) : false;
|
||||
|
||||
if ($file !== false && str_starts_with($file, $basepath)) {
|
||||
if ($file && is_file($file) && str_starts_with($file, $basepath . DIRECTORY_SEPARATOR)) {
|
||||
require_once($file);
|
||||
} else {
|
||||
print '<h1>The file \'' . htmle($page['contentfile']) . '\' does not exist!!</h1>';
|
||||
|
||||
+17
-14
@@ -23,6 +23,9 @@
|
||||
*/
|
||||
|
||||
require('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
1 => __('Delete'),
|
||||
@@ -700,20 +703,20 @@ function form_save() : void {
|
||||
break;
|
||||
default:
|
||||
$save['id'] = grv('id');
|
||||
$save['description'] = form_input_validate(trim(gnrv('description')), 'description', '', false, 3);
|
||||
$save['hostname'] = form_input_validate(trim(gnrv('hostname')), 'hostname', '', false, 3);
|
||||
$save['disabled'] = form_input_validate(gnrv('disabled'), 'disabled', '^on$', true, 3);
|
||||
$save['description'] = CactiValidator::validateInput(trim(gnrv('description')), 'description', [new Assert\NotBlank()], 3);
|
||||
$save['hostname'] = CactiValidator::validateInput(trim(gnrv('hostname')), 'hostname', [new Assert\NotBlank()], 3);
|
||||
$save['disabled'] = CactiValidator::validateInput(gnrv('disabled'), 'disabled', [new Assert\Regex('/^(on)?$/')], 3);
|
||||
$save['max_log_size'] = gnrv('max_log_size');
|
||||
$save['snmp_version'] = form_input_validate(gnrv('snmp_version'), 'snmp_version', '^[1-3]$', false, 3);
|
||||
$save['snmp_community'] = form_input_validate(gnrv('snmp_community'), 'snmp_community', '', true, 3);
|
||||
$save['snmp_version'] = CactiValidator::validateInput(gnrv('snmp_version'), 'snmp_version', [new Assert\NotBlank(), new Assert\Regex('/^[1-3]$/')], 3);
|
||||
$save['snmp_community'] = CactiValidator::validateInput(gnrv('snmp_community'), 'snmp_community', [], 3);
|
||||
|
||||
if ($save['snmp_version'] == 3) {
|
||||
$save['snmp_username'] = form_input_validate(gnrv('snmp_username'), 'snmp_username', '', true, 3);
|
||||
$save['snmp_password'] = form_input_validate(gnrv('snmp_password'), 'snmp_password', '', true, 3);
|
||||
$save['snmp_auth_protocol'] = form_input_validate(gnrv('snmp_auth_protocol'), 'snmp_auth_protocol', "^\[None\]|MD5|SHA|SHA224|SHA256|SHA392|SHA512$", true, 3);
|
||||
$save['snmp_priv_passphrase'] = form_input_validate(gnrv('snmp_priv_passphrase'), 'snmp_priv_passphrase', '', true, 3);
|
||||
$save['snmp_priv_protocol'] = form_input_validate(gnrv('snmp_priv_protocol'), 'snmp_priv_protocol', "^\[None\]|DES|AES|AES128|AES192|AES192C|AES256|AES256C$", true, 3);
|
||||
$save['snmp_engine_id'] = form_input_validate(get_request_var_post('snmp_engine_id'), 'snmp_engine_id', '', false, 3);
|
||||
$save['snmp_username'] = CactiValidator::validateInput(gnrv('snmp_username'), 'snmp_username', [], 3);
|
||||
$save['snmp_password'] = CactiValidator::validateInput(gnrv('snmp_password'), 'snmp_password', [], 3);
|
||||
$save['snmp_auth_protocol'] = CactiValidator::validateInput(gnrv('snmp_auth_protocol'), 'snmp_auth_protocol', [new Assert\Regex('/^(\[None\]|MD5|SHA|SHA224|SHA256|SHA392|SHA512)?$/')], 3);
|
||||
$save['snmp_priv_passphrase'] = CactiValidator::validateInput(gnrv('snmp_priv_passphrase'), 'snmp_priv_passphrase', [], 3);
|
||||
$save['snmp_priv_protocol'] = CactiValidator::validateInput(gnrv('snmp_priv_protocol'), 'snmp_priv_protocol', [new Assert\Regex('/^(\[None\]|DES|AES|AES128|AES192|AES192C|AES256|AES256C)?$/')], 3);
|
||||
$save['snmp_engine_id'] = CactiValidator::validateInput(get_request_var_post('snmp_engine_id'), 'snmp_engine_id', [new Assert\NotBlank()], 3);
|
||||
} else {
|
||||
$save['snmp_username'] = '';
|
||||
$save['snmp_password'] = '';
|
||||
@@ -723,9 +726,9 @@ function form_save() : void {
|
||||
$save['snmp_engine_id'] = '';
|
||||
}
|
||||
|
||||
$save['snmp_port'] = form_input_validate(gnrv('snmp_port'), 'snmp_port', '^[0-9]+$', false, 3);
|
||||
$save['snmp_message_type'] = form_input_validate(gnrv('snmp_message_type'), 'snmp_message_type', '^[1-2]$', false, 3);
|
||||
$save['notes'] = form_input_validate(gnrv('notes'), 'notes', '', true, 3);
|
||||
$save['snmp_port'] = CactiValidator::validateInput(gnrv('snmp_port'), 'snmp_port', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['snmp_message_type'] = CactiValidator::validateInput(gnrv('snmp_message_type'), 'snmp_message_type', [new Assert\NotBlank(), new Assert\Regex('/^[1-2]$/')], 3);
|
||||
$save['notes'] = CactiValidator::validateInput(gnrv('notes'), 'notes', [], 3);
|
||||
|
||||
if ($save['snmp_version'] == 3 && ($save['snmp_password'] != gnrv('snmp_password_confirm'))) {
|
||||
raise_message(4);
|
||||
|
||||
+10
-10
@@ -26,6 +26,9 @@ require('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/PackageListFilter.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/utility.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
$actions = [
|
||||
1 => __('Delete'),
|
||||
@@ -75,18 +78,15 @@ function form_save() : void {
|
||||
|
||||
if (isrv('save_component_repo')) {
|
||||
// ================= input validation =================
|
||||
gfrv('id');
|
||||
gfrv('repo_type');
|
||||
// ====================================================
|
||||
|
||||
$save['id'] = gnrv('id');
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save['repo_type'] = gnrv('repo_type');
|
||||
$save['repo_location'] = gnrv('repo_location');
|
||||
$save['repo_branch'] = gnrv('repo_branch');
|
||||
$save['repo_api_key'] = gnrv('repo_api_key');
|
||||
$save['id'] = CactiValidator::validateInput(gnrv('id'), 'id', [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')], 3);
|
||||
$save['repo_type'] = CactiValidator::validateInput(gnrv('repo_type'), 'repo_type', [new Assert\NotBlank(), new Assert\Regex('/^[0-2]$/')], 3);
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank(), new Assert\Length(max: 32)], 3);
|
||||
$save['repo_location'] = CactiValidator::validateInput(gnrv('repo_location'), 'repo_location', [new Assert\NotBlank(), new Assert\Length(max: 128)], 3);
|
||||
$save['repo_branch'] = CactiValidator::validateInput(gnrv('repo_branch'), 'repo_branch', [new Assert\Length(max: 128)], 3);
|
||||
$save['repo_api_key'] = CactiValidator::validateInput(gnrv('repo_api_key'), 'repo_api_key', [new Assert\Length(max: 128)], 3);
|
||||
$save['enabled'] = (isrv('enabled') ? 'on' : '');
|
||||
$save['default'] = (isrv('default') ? 'on' : '');
|
||||
// ====================================================
|
||||
|
||||
if (!is_error_message()) {
|
||||
$id = sql_save($save, 'package_repositories', 'id');
|
||||
|
||||
+21
-18
@@ -24,6 +24,9 @@
|
||||
|
||||
require('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/poller.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
// performing a full sync can take a lot of memory and time
|
||||
ini_set('memory_limit', '-1');
|
||||
@@ -312,31 +315,31 @@ function form_save() : void {
|
||||
if (isrv('save_component_poller')) {
|
||||
// Common data
|
||||
$save['id'] = gfrv('id');
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save['hostname'] = form_input_validate(gnrv('hostname'), 'hostname', '', false, 3);
|
||||
$save['log_level'] = form_input_validate(gnrv('log_level'), 'log_level', '', false, 3);
|
||||
$save['timezone'] = form_input_validate(gnrv('timezone'), 'timezone', '', false, 3);
|
||||
$save['notes'] = form_input_validate(gnrv('notes'), 'notes', '', true, 3);
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()]);
|
||||
$save['hostname'] = CactiValidator::validateInput(gnrv('hostname'), 'hostname', [new Assert\NotBlank()]);
|
||||
$save['log_level'] = CactiValidator::validateInput(gnrv('log_level'), 'log_level', [new Assert\NotBlank()]);
|
||||
$save['timezone'] = CactiValidator::validateInput(gnrv('timezone'), 'timezone', [new Assert\NotBlank()]);
|
||||
$save['notes'] = CactiValidator::validateInput(gnrv('notes'), 'notes', []);
|
||||
|
||||
// Process settings
|
||||
$save['processes'] = form_input_validate(gnrv('processes'), 'processes', '^[0-9]+$', false, 3);
|
||||
$save['threads'] = form_input_validate(gnrv('threads'), 'threads', '^[0-9]+$', false, 3);
|
||||
$save['processes'] = CactiValidator::validateInput(gnrv('processes'), 'processes', [new Assert\NotBlank(), new Assert\Regex(pattern: '/^[0-9]+$/')]);
|
||||
$save['threads'] = CactiValidator::validateInput(gnrv('threads'), 'threads', [new Assert\NotBlank(), new Assert\Regex(pattern: '/^[0-9]+$/')]);
|
||||
|
||||
if ($save['id'] != 1) {
|
||||
$save['sync_interval'] = form_input_validate(gnrv('sync_interval'), 'sync_interval', '^[0-9]+$', false, 3);
|
||||
$save['sync_interval'] = CactiValidator::validateInput(gnrv('sync_interval'), 'sync_interval', [new Assert\NotBlank(), new Assert\Regex(pattern: '/^[0-9]+$/')]);
|
||||
|
||||
// Database settings
|
||||
$save['dbdefault'] = form_input_validate(gnrv('dbdefault'), 'dbdefault', '', true, 3);
|
||||
$save['dbhost'] = form_input_validate(gnrv('dbhost'), 'dbhost', '', true, 3);
|
||||
$save['dbuser'] = form_input_validate(gnrv('dbuser'), 'dbuser', '', true, 3);
|
||||
$save['dbpass'] = form_input_validate(gnrv('dbpass'), 'dbpass', '', true, 3);
|
||||
$save['dbport'] = form_input_validate(gnrv('dbport'), 'dbport', '^[0-9]+$', true, 3);
|
||||
$save['dbretries'] = form_input_validate(gnrv('dbretries'), 'dbretries', '^[0-9]+$', true, 3);
|
||||
$save['dbdefault'] = CactiValidator::validateInput(gnrv('dbdefault'), 'dbdefault', []);
|
||||
$save['dbhost'] = CactiValidator::validateInput(gnrv('dbhost'), 'dbhost', []);
|
||||
$save['dbuser'] = CactiValidator::validateInput(gnrv('dbuser'), 'dbuser', []);
|
||||
$save['dbpass'] = CactiValidator::validateInput(gnrv('dbpass'), 'dbpass', []);
|
||||
$save['dbport'] = CactiValidator::validateInput(gnrv('dbport'), 'dbport', [new Assert\Regex(pattern: '/^[0-9]+$/')]);
|
||||
$save['dbretries'] = CactiValidator::validateInput(gnrv('dbretries'), 'dbretries', [new Assert\Regex(pattern: '/^[0-9]+$/')]);
|
||||
$save['dbssl'] = isrv('dbssl') ? 'on' : '';
|
||||
$save['dbsslkey'] = form_input_validate(gnrv('dbsslkey'), 'dbsslkey', '', true, 3);
|
||||
$save['dbsslcert'] = form_input_validate(gnrv('dbsslcert'), 'dbsslcert', '', true, 3);
|
||||
$save['dbsslca'] = form_input_validate(gnrv('dbsslca'), 'dbsslca', '', true, 3);
|
||||
$save['dbsslcapath'] = form_input_validate(gnrv('dbsslcapath'), 'dbsslcapath', '', true, 3);
|
||||
$save['dbsslkey'] = CactiValidator::validateInput(gnrv('dbsslkey'), 'dbsslkey', []);
|
||||
$save['dbsslcert'] = CactiValidator::validateInput(gnrv('dbsslcert'), 'dbsslcert', []);
|
||||
$save['dbsslca'] = CactiValidator::validateInput(gnrv('dbsslca'), 'dbsslca', []);
|
||||
$save['dbsslcapath'] = CactiValidator::validateInput(gnrv('dbsslcapath'), 'dbsslcapath', []);
|
||||
$save['dbsslverifyservercert'] = isrv('dbsslverifyservercert') ? 'on' : '';
|
||||
}
|
||||
|
||||
|
||||
@@ -1349,6 +1349,51 @@ function save_settings() : void {
|
||||
$errors = [];
|
||||
$inserts = [];
|
||||
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiSettings.php');
|
||||
|
||||
// Build a snapshot of posted values keyed by setting name using Cacti's
|
||||
// request-var helpers (gnrv) instead of touching $_POST directly. Only
|
||||
// fields declared in the active tab are forwarded; the validator already
|
||||
// ignores unknown keys so no behavior changes.
|
||||
$tab = (string) grv('tab');
|
||||
$snapshot = [];
|
||||
|
||||
if (isset($settings[$tab]) && is_array($settings[$tab])) {
|
||||
foreach ($settings[$tab] as $field_name => $field_array) {
|
||||
if (!is_string($field_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$snapshot[$field_name] = gnrv($field_name);
|
||||
|
||||
if (isset($field_array['items']) && is_array($field_array['items'])) {
|
||||
foreach ($field_array['items'] as $sub_name => $sub_def) {
|
||||
if (is_string($sub_name)) {
|
||||
$snapshot[$sub_name] = gnrv($sub_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$violations = CactiSettings::validate($snapshot, $settings);
|
||||
|
||||
if (cacti_sizeof($violations) > 0) {
|
||||
foreach ($violations as $name => $message) {
|
||||
$_SESSION['sess_error_fields'][$name] = $name;
|
||||
$_SESSION['sess_field_values'][$name] = isset($snapshot[$name]) && is_scalar($snapshot[$name]) ? $snapshot[$name] : '';
|
||||
|
||||
raise_message(
|
||||
'cacti_settings_' . $name,
|
||||
__esc('Setting \'%s\': %s', $name, $message),
|
||||
MESSAGE_LEVEL_ERROR
|
||||
);
|
||||
}
|
||||
|
||||
header('Location: settings.php?tab=' . urlencode($tab));
|
||||
exit;
|
||||
}
|
||||
|
||||
foreach ($settings[grv('tab')] as $field_name => $field_array) {
|
||||
if (($field_array['method'] == 'header') || ($field_array['method'] == 'spacer')) {
|
||||
// do nothing
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/api_automation.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates graph rule name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('My Rule', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates graph rule numeric fields (NotBlank + Regex)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('123', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates operation field (Regex allowing empty)', function () {
|
||||
$constraints = [new Assert\Regex('/^[-0-9]+$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('-1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates operator field (Regex allowing empty)', function () {
|
||||
$constraints = [new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('verifies CactiValidator::validateInput populates session and raises message on failure', function () {
|
||||
// Define constants if not present
|
||||
if (!defined('SESS_FIELD_VALUES')) define('SESS_FIELD_VALUES', 'sess_field_values');
|
||||
if (!defined('SESS_ERROR_FIELDS')) define('SESS_ERROR_FIELDS', 'sess_error_fields');
|
||||
|
||||
// Mock raise_message if it doesn't exist
|
||||
if (!function_exists('raise_message')) {
|
||||
function raise_message($id) { $GLOBALS['raised_message'] = $id; }
|
||||
}
|
||||
|
||||
$_SESSION = [];
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
|
||||
// Test valid input
|
||||
CactiValidator::validateInput('valid', 'test_field', $constraints);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['test_field'])->toBe('valid');
|
||||
expect(isset($_SESSION[SESS_ERROR_FIELDS]['test_field']))->toBeFalse();
|
||||
|
||||
// Test invalid input
|
||||
$_SESSION = [];
|
||||
$GLOBALS['raised_message'] = null;
|
||||
CactiValidator::validateInput('', 'test_field', $constraints, 999);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['test_field'])->toBe('');
|
||||
expect($_SESSION[SESS_ERROR_FIELDS]['test_field'])->toBe(999);
|
||||
expect($GLOBALS['raised_message'])->toBe(999);
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/api_automation.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates network rule name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('My Network', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates numeric fields (NotBlank + Regex)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('123', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates notification email (Email)', function () {
|
||||
$constraints = [new Assert\Email(mode: 'html5')];
|
||||
expect(CactiValidator::isValid('test@example.com', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('invalid-email', $constraints))->toBeFalse();
|
||||
// Email is allowed to be empty in automation_networks.php for some fields (ignore_ips, dns_servers)
|
||||
// but here we are testing the Email constraint itself.
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue(); // Symfony Email allows empty if not combined with NotBlank
|
||||
});
|
||||
|
||||
it('verifies CactiValidator::validateInput populates session for networks', function () {
|
||||
if (!defined('SESS_FIELD_VALUES')) define('SESS_FIELD_VALUES', 'sess_field_values');
|
||||
if (!defined('SESS_ERROR_FIELDS')) define('SESS_ERROR_FIELDS', 'sess_error_fields');
|
||||
|
||||
if (!function_exists('raise_message')) {
|
||||
function raise_message($id) { $GLOBALS['raised_message'] = $id; }
|
||||
}
|
||||
|
||||
$_SESSION = [];
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
|
||||
CactiValidator::validateInput('valid_net', 'name', $constraints);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['name'])->toBe('valid_net');
|
||||
expect(isset($_SESSION[SESS_ERROR_FIELDS]['name']))->toBeFalse();
|
||||
|
||||
$_SESSION = [];
|
||||
$GLOBALS['raised_message'] = null;
|
||||
CactiValidator::validateInput('', 'name', $constraints, 3);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['name'])->toBe('');
|
||||
expect($_SESSION[SESS_ERROR_FIELDS]['name'])->toBe(3);
|
||||
expect($GLOBALS['raised_message'])->toBe(3);
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/api_automation.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates automation name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Default SNMP', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates SNMP community (NotBlank + Regex)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[a-zA-Z0-9_\-\.]+$/')];
|
||||
expect(CactiValidator::isValid('public', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('v2-community.string_123', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('comm unity', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('comm!unity', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates SNMP version (Choice)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Choice(['1', '2', '3'])];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('2', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('3', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('4', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates SNMP port (Range)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Range(min: 1, max: 65535)];
|
||||
expect(CactiValidator::isValid('161', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('65535', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('65536', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('-1', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates numeric fields (NotBlank + GreaterThanOrEqual)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Type('numeric'), new Assert\GreaterThanOrEqual(0)];
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('100', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('-1', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates bulk_walk_size (NotBlank + numeric)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Type('numeric')];
|
||||
expect(CactiValidator::isValid('20', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('-1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('verifies CactiValidator::validateInput behavior for SNMP', function () {
|
||||
if (!defined('SESS_FIELD_VALUES')) define('SESS_FIELD_VALUES', 'sess_field_values');
|
||||
if (!defined('SESS_ERROR_FIELDS')) define('SESS_ERROR_FIELDS', 'sess_error_fields');
|
||||
|
||||
if (!function_exists('raise_message')) {
|
||||
function raise_message($id) { $GLOBALS['raised_message'] = $id; }
|
||||
}
|
||||
|
||||
$_SESSION = [];
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
|
||||
CactiValidator::validateInput('snmp_opt', 'name', $constraints);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['name'])->toBe('snmp_opt');
|
||||
expect(isset($_SESSION[SESS_ERROR_FIELDS]['name']))->toBeFalse();
|
||||
|
||||
$_SESSION = [];
|
||||
$GLOBALS['raised_message'] = null;
|
||||
CactiValidator::validateInput('', 'name', $constraints, 3);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['name'])->toBe('');
|
||||
expect($_SESSION[SESS_ERROR_FIELDS]['name'])->toBe(3);
|
||||
expect($GLOBALS['raised_message'])->toBe(3);
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/api_automation.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates host_template (NotBlank + Regex)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates availability_method (NotBlank + Regex)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('verifies CactiValidator::validateInput populates session and raises message on failure', function () {
|
||||
// Define constants if not present
|
||||
if (!defined('SESS_FIELD_VALUES')) define('SESS_FIELD_VALUES', 'sess_field_values');
|
||||
if (!defined('SESS_ERROR_FIELDS')) define('SESS_ERROR_FIELDS', 'sess_error_fields');
|
||||
|
||||
// Mock raise_message if it doesn't exist
|
||||
if (!function_exists('raise_message')) {
|
||||
function raise_message($id) { $GLOBALS['raised_message'] = $id; }
|
||||
}
|
||||
|
||||
$_SESSION = [];
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')];
|
||||
|
||||
// Test valid input
|
||||
CactiValidator::validateInput('123', 'host_template', $constraints);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['host_template'])->toBe('123');
|
||||
expect(isset($_SESSION[SESS_ERROR_FIELDS]['host_template']))->toBeFalse();
|
||||
|
||||
// Test invalid input
|
||||
$_SESSION = [];
|
||||
$GLOBALS['raised_message'] = null;
|
||||
CactiValidator::validateInput('', 'host_template', $constraints, 3);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['host_template'])->toBe('');
|
||||
expect($_SESSION[SESS_ERROR_FIELDS]['host_template'])->toBe(3);
|
||||
expect($GLOBALS['raised_message'])->toBe(3);
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/api_automation.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates tree rule name (optional)', function () {
|
||||
$constraints = [];
|
||||
expect(CactiValidator::isValid('My Tree Rule', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue();
|
||||
});
|
||||
|
||||
it('validates numeric fields (NotBlank + Regex)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('123', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates operation field (Regex allowing empty)', function () {
|
||||
$constraints = [new Assert\Regex('/^[-0-9]+$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('-1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates operator field (Regex allowing empty)', function () {
|
||||
$constraints = [new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates search_pattern (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('pattern', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('verifies CactiValidator::validateInput populates session and raises message on failure', function () {
|
||||
// Define constants if not present
|
||||
if (!defined('SESS_FIELD_VALUES')) define('SESS_FIELD_VALUES', 'sess_field_values');
|
||||
if (!defined('SESS_ERROR_FIELDS')) define('SESS_ERROR_FIELDS', 'sess_error_fields');
|
||||
|
||||
// Mock raise_message if it doesn't exist
|
||||
if (!function_exists('raise_message')) {
|
||||
function raise_message($id) { $GLOBALS['raised_message'] = $id; }
|
||||
}
|
||||
|
||||
$_SESSION = [];
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
|
||||
// Test valid input
|
||||
CactiValidator::validateInput('valid', 'test_field', $constraints);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['test_field'])->toBe('valid');
|
||||
expect(isset($_SESSION[SESS_ERROR_FIELDS]['test_field']))->toBeFalse();
|
||||
|
||||
// Test invalid input
|
||||
$_SESSION = [];
|
||||
$GLOBALS['raised_message'] = null;
|
||||
CactiValidator::validateInput('', 'test_field', $constraints, 999);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['test_field'])->toBe('');
|
||||
expect($_SESSION[SESS_ERROR_FIELDS]['test_field'])->toBe(999);
|
||||
expect($GLOBALS['raised_message'])->toBe(999);
|
||||
});
|
||||
@@ -0,0 +1,305 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiSettings.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
// =====================================================================
|
||||
// CactiSettings::validate -- input shapes
|
||||
//
|
||||
// Constraints are declared as closures that return Constraint instances,
|
||||
// matching the form used in include/global_settings.php. The closure form
|
||||
// is required there because that file loads before vendor/autoload.php.
|
||||
// =====================================================================
|
||||
|
||||
test('empty posted settings returns empty violations', function () {
|
||||
$definitions = [
|
||||
'foo' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\NotBlank()],
|
||||
],
|
||||
];
|
||||
|
||||
expect(CactiSettings::validate([], $definitions))->toBe([]);
|
||||
});
|
||||
|
||||
test('valid posted value passes all constraints', function () {
|
||||
$definitions = [
|
||||
'snmp_port' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [
|
||||
fn () => new Assert\Regex(pattern: '/^\d+$/'),
|
||||
fn () => new Assert\Range(min: 1, max: 65535),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
expect(CactiSettings::validate(['snmp_port' => '161'], $definitions))->toBe([]);
|
||||
});
|
||||
|
||||
test('failing constraint returns map keyed by setting name', function () {
|
||||
$definitions = [
|
||||
'snmp_port' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [
|
||||
fn () => new Assert\Range(min: 1, max: 65535),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['snmp_port' => '70000'], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('snmp_port')
|
||||
->and($result['snmp_port'])->toBeString()
|
||||
->and($result['snmp_port'])->not->toBe('');
|
||||
});
|
||||
|
||||
test('multiple failing constraints on same setting return only the first message', function () {
|
||||
$definitions = [
|
||||
'name' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [
|
||||
fn () => new Assert\NotBlank(message: 'first violation'),
|
||||
fn () => new Assert\Length(min: 3, minMessage: 'second violation'),
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['name' => ''], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('name')
|
||||
->and($result['name'])->toBe('first violation');
|
||||
});
|
||||
|
||||
test('posted setting with no matching definition is ignored', function () {
|
||||
$definitions = [
|
||||
'known' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\NotBlank()],
|
||||
],
|
||||
];
|
||||
|
||||
expect(CactiSettings::validate(['unknown' => ''], $definitions))->toBe([]);
|
||||
});
|
||||
|
||||
test('definition without constraints key is ignored', function () {
|
||||
$definitions = [
|
||||
'plain' => [
|
||||
'method' => 'textbox',
|
||||
],
|
||||
];
|
||||
|
||||
expect(CactiSettings::validate(['plain' => ''], $definitions))->toBe([]);
|
||||
});
|
||||
|
||||
test('definition with empty constraints array is ignored', function () {
|
||||
$definitions = [
|
||||
'empty' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [],
|
||||
],
|
||||
];
|
||||
|
||||
expect(CactiSettings::validate(['empty' => ''], $definitions))->toBe([]);
|
||||
});
|
||||
|
||||
test('tab-grouped definitions are flattened transparently', function () {
|
||||
// Mirrors the actual shape of $settings in include/global_settings.php
|
||||
// where the outer key is the tab name and the inner array is the
|
||||
// {setting_name => def} map.
|
||||
$definitions = [
|
||||
'snmp' => [
|
||||
'snmp_port' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\Range(min: 1, max: 65535)],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['snmp_port' => '70000'], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('snmp_port');
|
||||
});
|
||||
|
||||
test('plain Constraint instances (non-closure) are still accepted', function () {
|
||||
// Backward-compatible form for callers that run after vendor autoload.
|
||||
$definitions = [
|
||||
'host' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [new Assert\NotBlank()],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['host' => ''], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('host');
|
||||
});
|
||||
|
||||
// =====================================================================
|
||||
// Constraint type coverage -- each pilot constraint type
|
||||
// =====================================================================
|
||||
|
||||
test('NotBlank rejects empty string', function () {
|
||||
$definitions = [
|
||||
'host' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\NotBlank()],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['host' => ''], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('host');
|
||||
});
|
||||
|
||||
test('NotBlank accepts non-empty string', function () {
|
||||
$definitions = [
|
||||
'host' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\NotBlank()],
|
||||
],
|
||||
];
|
||||
|
||||
expect(CactiSettings::validate(['host' => 'localhost'], $definitions))->toBe([]);
|
||||
});
|
||||
|
||||
test('Length enforces max bound', function () {
|
||||
$definitions = [
|
||||
'path' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\Length(max: 5)],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['path' => 'too-long'], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('path');
|
||||
});
|
||||
|
||||
test('Length accepts string within bounds', function () {
|
||||
$definitions = [
|
||||
'path' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\Length(min: 1, max: 255)],
|
||||
],
|
||||
];
|
||||
|
||||
expect(CactiSettings::validate(['path' => '/usr/bin/rrdtool'], $definitions))->toBe([]);
|
||||
});
|
||||
|
||||
test('Range rejects value above max', function () {
|
||||
$definitions = [
|
||||
'port' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\Range(min: 1, max: 65535)],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['port' => '70000'], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('port');
|
||||
});
|
||||
|
||||
test('Range rejects value below min', function () {
|
||||
$definitions = [
|
||||
'port' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\Range(min: 1, max: 65535)],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['port' => '0'], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('port');
|
||||
});
|
||||
|
||||
test('Choice rejects value not in list', function () {
|
||||
$definitions = [
|
||||
'interval' => [
|
||||
'method' => 'drop_array',
|
||||
'constraints' => [fn () => new Assert\Choice(choices: ['60', '300', 60, 300])],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['interval' => '42'], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('interval');
|
||||
});
|
||||
|
||||
test('Choice accepts value in list', function () {
|
||||
$definitions = [
|
||||
'interval' => [
|
||||
'method' => 'drop_array',
|
||||
'constraints' => [fn () => new Assert\Choice(choices: ['60', '300', 60, 300])],
|
||||
],
|
||||
];
|
||||
|
||||
expect(CactiSettings::validate(['interval' => '300'], $definitions))->toBe([]);
|
||||
});
|
||||
|
||||
test('Regex rejects non-numeric string', function () {
|
||||
$definitions = [
|
||||
'count' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\Regex(pattern: '/^\d+$/')],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['count' => 'abc'], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('count');
|
||||
});
|
||||
|
||||
test('Regex accepts matching string', function () {
|
||||
$definitions = [
|
||||
'count' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\Regex(pattern: '/^\d+$/')],
|
||||
],
|
||||
];
|
||||
|
||||
expect(CactiSettings::validate(['count' => '42'], $definitions))->toBe([]);
|
||||
});
|
||||
|
||||
test('Positive rejects zero and negatives', function () {
|
||||
$definitions = [
|
||||
'id' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\Positive()],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['id' => '0'], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('id');
|
||||
});
|
||||
|
||||
test('multiple settings with mixed pass/fail report only the failing ones', function () {
|
||||
$definitions = [
|
||||
'good' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\NotBlank()],
|
||||
],
|
||||
'bad' => [
|
||||
'method' => 'textbox',
|
||||
'constraints' => [fn () => new Assert\NotBlank()],
|
||||
],
|
||||
];
|
||||
|
||||
$result = CactiSettings::validate(['good' => 'ok', 'bad' => ''], $definitions);
|
||||
|
||||
expect($result)->toHaveKey('bad')
|
||||
->and($result)->not->toHaveKey('good');
|
||||
});
|
||||
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates a numeric host id', function () {
|
||||
expect(CactiValidator::isValidHostId(123))->toBeTrue();
|
||||
expect(CactiValidator::isValidHostId('456'))->toBeTrue();
|
||||
expect(CactiValidator::isValidHostId(0))->toBeTrue();
|
||||
});
|
||||
|
||||
it('rejects a negative host id', function () {
|
||||
expect(CactiValidator::isValidHostId(-1))->toBeFalse();
|
||||
});
|
||||
|
||||
it('rejects a non-numeric host id', function () {
|
||||
expect(CactiValidator::isValidHostId('abc'))->toBeFalse();
|
||||
expect(CactiValidator::isValidHostId(''))->toBeFalse();
|
||||
expect(CactiValidator::isValidHostId(null))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates a safe rrd path', function () {
|
||||
expect(CactiValidator::isValidRrdPath('host_1/traffic_in.rrd'))->toBeTrue();
|
||||
expect(CactiValidator::isValidRrdPath('archive/2023-01-01.rrd'))->toBeTrue();
|
||||
expect(CactiValidator::isValidRrdPath('local.rrd'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('rejects rrd path with traversal', function () {
|
||||
expect(CactiValidator::isValidRrdPath('../../etc/passwd'))->toBeFalse();
|
||||
expect(CactiValidator::isValidRrdPath('..'))->toBeFalse();
|
||||
expect(CactiValidator::isValidRrdPath('/var/www/html/cacti/rra/../config.php'))->toBeFalse();
|
||||
});
|
||||
|
||||
it('rejects rrd path with invalid characters', function () {
|
||||
expect(CactiValidator::isValidRrdPath('my graph; rm -rf /'))->toBeFalse();
|
||||
expect(CactiValidator::isValidRrdPath('host_1/<script>alert(1)</script>.rrd'))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates ipv4 and ipv6 addresses', function () {
|
||||
expect(CactiValidator::isValidIpAddress('127.0.0.1'))->toBeTrue();
|
||||
expect(CactiValidator::isValidIpAddress('192.168.1.1'))->toBeTrue();
|
||||
expect(CactiValidator::isValidIpAddress('::1'))->toBeTrue();
|
||||
expect(CactiValidator::isValidIpAddress('2001:0db8:85a3:0000:0000:8a2e:0370:7334'))->toBeTrue();
|
||||
|
||||
expect(CactiValidator::isValidIpAddress('not-an-ip'))->toBeFalse();
|
||||
expect(CactiValidator::isValidIpAddress('256.256.256.256'))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates email addresses', function () {
|
||||
expect(CactiValidator::isValidEmail('test@example.com'))->toBeTrue();
|
||||
expect(CactiValidator::isValidEmail('user.name+tag@domain.co.uk'))->toBeTrue();
|
||||
|
||||
expect(CactiValidator::isValidEmail('invalid-email'))->toBeFalse();
|
||||
expect(CactiValidator::isValidEmail('test@example'))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates snmp community strings', function () {
|
||||
expect(CactiValidator::isValidSnmpCommunity('public'))->toBeTrue();
|
||||
expect(CactiValidator::isValidSnmpCommunity('my-community_123'))->toBeTrue();
|
||||
expect(CactiValidator::isValidSnmpCommunity('public@site'))->toBeTrue();
|
||||
expect(CactiValidator::isValidSnmpCommunity('read only/community:1'))->toBeTrue();
|
||||
|
||||
expect(CactiValidator::isValidSnmpCommunity(''))->toBeFalse();
|
||||
expect(CactiValidator::isValidSnmpCommunity("comm\nunity"))->toBeFalse();
|
||||
expect(CactiValidator::isValidSnmpCommunity("comm\x7funity"))->toBeFalse();
|
||||
});
|
||||
|
||||
it('can validate against custom constraints', function () {
|
||||
$constraints = [
|
||||
new Assert\Email(mode: 'html5'),
|
||||
new Assert\NotBlank(),
|
||||
];
|
||||
|
||||
expect(CactiValidator::isValid('test@example.com', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('invalid-email', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('rejects rrd path with absolute root', function () {
|
||||
expect(CactiValidator::isValidRrdPath('/etc/passwd_no_dots'))->toBeFalse();
|
||||
expect(CactiValidator::isValidRrdPath('/var/www/html/cacti/rra/host_1.rrd'))->toBeFalse();
|
||||
});
|
||||
|
||||
it('rejects rrd path with NUL byte', function () {
|
||||
expect(CactiValidator::isValidRrdPath("foo\0..rrd"))->toBeFalse();
|
||||
});
|
||||
|
||||
it('rejects empty rrd path', function () {
|
||||
expect(CactiValidator::isValidRrdPath(''))->toBeFalse();
|
||||
});
|
||||
|
||||
it('enforces rraRoot containment when supplied', function () {
|
||||
$root = sys_get_temp_dir() . '/cacti_rra_' . uniqid();
|
||||
mkdir($root, 0700, true);
|
||||
file_put_contents($root . '/host_1.rrd', '');
|
||||
try {
|
||||
expect(CactiValidator::isValidRrdPath('host_1.rrd', $root))->toBeTrue();
|
||||
// Improved: allow missing files if containment can be verified
|
||||
expect(CactiValidator::isValidRrdPath('missing.rrd', $root))->toBeTrue();
|
||||
} finally {
|
||||
// nosemgrep: php.lang.security.unlink-use.unlink-use - test cleanup of file we just created in temp dir
|
||||
@unlink($root . '/host_1.rrd');
|
||||
@rmdir($root);
|
||||
}
|
||||
});
|
||||
|
||||
it('validates ipv4-mapped ipv6 and reserved ranges as syntactically valid', function () {
|
||||
expect(CactiValidator::isValidIpAddress('::ffff:127.0.0.1'))->toBeTrue();
|
||||
});
|
||||
|
||||
it('rejects malformed ipv4 with leading zeros that some parsers accept', function () {
|
||||
// Symfony Ip validator accepts "192.168.001.001" - assert current behavior so regressions are visible.
|
||||
$value = CactiValidator::isValidIpAddress('192.168.001.001');
|
||||
expect($value)->toBeBool();
|
||||
});
|
||||
|
||||
it('rejects email with header injection attempt', function () {
|
||||
expect(CactiValidator::isValidEmail("a@b.com\r\nBcc: c@d.com"))->toBeFalse();
|
||||
});
|
||||
|
||||
it('rejects oversize email', function () {
|
||||
$local = str_repeat('a', 320);
|
||||
expect(CactiValidator::isValidEmail($local . '@example.com'))->toBeFalse();
|
||||
});
|
||||
|
||||
it('rejects snmp community with non-ascii', function () {
|
||||
expect(CactiValidator::isValidSnmpCommunity("p\xc3\xa9blic"))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,62 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates color template name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Default Colors', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates color_id (Type numeric)', function () {
|
||||
$constraints = [new Assert\Type('numeric')];
|
||||
expect(CactiValidator::isValid('123', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
// Symfony Type('numeric') handles numeric strings correctly.
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('verifies CactiValidator::validateInput behavior', function () {
|
||||
if (!defined('SESS_FIELD_VALUES')) define('SESS_FIELD_VALUES', 'sess_field_values');
|
||||
if (!defined('SESS_ERROR_FIELDS')) define('SESS_ERROR_FIELDS', 'sess_error_fields');
|
||||
|
||||
if (!function_exists('raise_message')) {
|
||||
function raise_message($id) { $GLOBALS['raised_message'] = $id; }
|
||||
}
|
||||
|
||||
$_SESSION = [];
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
|
||||
// Test valid input
|
||||
CactiValidator::validateInput('valid', 'name', $constraints);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['name'])->toBe('valid');
|
||||
expect(isset($_SESSION[SESS_ERROR_FIELDS]['name']))->toBeFalse();
|
||||
|
||||
// Test invalid input
|
||||
$_SESSION = [];
|
||||
$GLOBALS['raised_message'] = null;
|
||||
CactiValidator::validateInput('', 'name', $constraints, 999);
|
||||
expect($_SESSION[SESS_FIELD_VALUES]['name'])->toBe('');
|
||||
expect($_SESSION[SESS_ERROR_FIELDS]['name'])->toBe(999);
|
||||
expect($GLOBALS['raised_message'])->toBe(999);
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates data input name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Get SNMP Data', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates type_id (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates data field name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Community String', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates data query name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('SNMP - Interface Statistics', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates xml_path (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('<path_cacti>/resource/snmp_queries/interface.xml', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates data source name (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^[a-zA-Z0-9_-]{1,19}$/')];
|
||||
expect(CactiValidator::isValid('traffic_in', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('too_long_name_for_rrd', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('invalid!', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates rrd limits with ifSpeed (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^((-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?)|U|\|query_ifSpeed\||\|query_ifHighSpeed\|)$/')];
|
||||
expect(CactiValidator::isValid('100', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('U', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('|query_ifSpeed|', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('|query_ifHighSpeed|', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('invalid', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('100;payload', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('abcU', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('x|query_ifSpeed|y', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates data source profile id (NotBlank + Regex)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates data template name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Interface - Traffic', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates data source name (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^[a-zA-Z0-9_]{1,19}$/')];
|
||||
expect(CactiValidator::isValid('traffic_in', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('too_long_name_for_rrd_data_source', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('invalid-char!', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates rrd_maximum with ifSpeed macro (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^((-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?)|U|\|query_ifSpeed\|)$/')];
|
||||
expect(CactiValidator::isValid('100', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('U', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('|query_ifSpeed|', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('100;payload', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('abcU', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('x|query_ifSpeed|y', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates dynamic regex from database', function () {
|
||||
$dynamic_regex = '^[0-9]+$';
|
||||
$constraints = [new Assert\Regex('/' . $dynamic_regex . '/')];
|
||||
expect(CactiValidator::isValid('123', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates graph template name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Interface - Traffic (bits/sec)', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates numeric fields (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('123', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates floating point limits (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^((-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?)|U)$/')];
|
||||
expect(CactiValidator::isValid('100', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('100.5', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('-50.2', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('1.2e10', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('U', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('100;payload', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('abcU', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates dashes pattern (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^[0-9]+[,0-9]*$/')];
|
||||
expect(CactiValidator::isValid('5,5', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('10', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates textalign (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^[a-z]+$/')];
|
||||
expect(CactiValidator::isValid('left', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('CENTER', $constraints))->toBeFalse(); // Only lowercase a-z
|
||||
expect(CactiValidator::isValid('123', $constraints))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates dynamic custom data (Regex)', function () {
|
||||
$dynamic_regex = '^[0-9]+$';
|
||||
$constraints = [new Assert\Regex('/' . $dynamic_regex . '/')];
|
||||
expect(CactiValidator::isValid('123', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates custom data with NotBlank', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('some data', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates graph title (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Traffic - eth0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates graph height and width (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('120', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates graph limits (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^((-?([0-9]+(\.[0-9]*)?|[0-9]*\.[0-9]+)([eE][+\-]?[0-9]+)?)|U)$/')];
|
||||
expect(CactiValidator::isValid('1000', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0.001', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('U', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('invalid', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('100;payload', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('abcU', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates right axis (Regex)', function () {
|
||||
$constraints = [new Assert\Regex('/^-?([0-9]+(\.[0-9]*)?|\.[0-9]+):-?([0-9]+(\.[0-9]*)?|\.[0-9]+)$/')];
|
||||
expect(CactiValidator::isValid('1:0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0.5:100', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('invalid', $constraints))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates host template name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Generic SNMP Device', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid(null, $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates host template version (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('1.2.0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates host template class (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Device', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates host template copyright (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('2024 The Cacti Group', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates optional fields (no NotBlank)', function () {
|
||||
$constraints = []; // Optional fields in legacy were just form_input_validate(..., true)
|
||||
expect(CactiValidator::isValid('something', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue();
|
||||
});
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates description (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Notification Receiver', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates hostname (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('localhost', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates disabled status (Regex /^on$/ optional)', function () {
|
||||
$constraints = [new Assert\Regex('/^(on)?$/')];
|
||||
expect(CactiValidator::isValid('on', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('off', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates snmp_version (NotBlank, Regex /^[1-3]$/)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[1-3]$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('2', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('3', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('4', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates snmp_auth_protocol (Regex optional)', function () {
|
||||
$constraints = [new Assert\Regex('/^(\[None\]|MD5|SHA|SHA224|SHA256|SHA392|SHA512)?$/')];
|
||||
expect(CactiValidator::isValid('MD5', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('[None]', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('INVALID', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates snmp_priv_protocol (Regex optional)', function () {
|
||||
$constraints = [new Assert\Regex('/^(\[None\]|DES|AES|AES128|AES192|AES192C|AES256|AES256C)?$/')];
|
||||
expect(CactiValidator::isValid('AES128', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('[None]', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('INVALID', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates snmp_port (NotBlank, Regex /^[0-9]+$/)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('161', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates snmp_message_type (NotBlank, Regex /^[1-2]$/)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[1-2]$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('2', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('3', $constraints))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates repo name (NotBlank + Length)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Length(max: 32)];
|
||||
expect(CactiValidator::isValid('Main Repo', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid(str_repeat('a', 33), $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates repo type (Regex /^[0-2]$/)', function () {
|
||||
$constraints = [new Assert\Regex('/^[0-2]$/')];
|
||||
expect(CactiValidator::isValid('0', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('2', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('3', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates repo location (NotBlank + Length)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Length(max: 128)];
|
||||
expect(CactiValidator::isValid('https://github.com/Cacti/cacti', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Main Poller', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates hostname (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('localhost', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates log_level (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates processes (NotBlank, Regex /^[0-9]+$/)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('10', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates threads (NotBlank, Regex /^[0-9]+$/)', function () {
|
||||
$constraints = [new Assert\NotBlank(), new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('1', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('50', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
expect(CactiValidator::isValid('xyz', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates dbport (Regex /^[0-9]+$/ optional)', function () {
|
||||
$constraints = [new Assert\Regex('/^[0-9]+$/')];
|
||||
expect(CactiValidator::isValid('3306', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue(); // allow null/empty if optional
|
||||
expect(CactiValidator::isValid('abc', $constraints))->toBeFalse();
|
||||
});
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
/*
|
||||
+-------------------------------------------------------------------------+
|
||||
| Copyright (C) 2004-2026 The Cacti Group |
|
||||
| |
|
||||
| This program is free software; you can redistribute it and/or |
|
||||
| modify it under the terms of the GNU General Public License |
|
||||
| as published by the Free Software Foundation; either version 2 |
|
||||
| of the License, or (at your option) any later version. |
|
||||
+-------------------------------------------------------------------------+
|
||||
| Cacti: The Complete RRDtool-based Graphing Solution |
|
||||
+-------------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 2) . '/include/vendor/autoload.php';
|
||||
require_once dirname(__DIR__, 2) . '/lib/CactiValidator.php';
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
beforeEach(function () {
|
||||
CactiValidator::reset();
|
||||
});
|
||||
|
||||
it('validates user group name (NotBlank)', function () {
|
||||
$constraints = [new Assert\NotBlank()];
|
||||
expect(CactiValidator::isValid('Admins', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeFalse();
|
||||
});
|
||||
|
||||
it('validates optional description', function () {
|
||||
$constraints = [];
|
||||
expect(CactiValidator::isValid('Some group', $constraints))->toBeTrue();
|
||||
expect(CactiValidator::isValid('', $constraints))->toBeTrue();
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
FROM debian:bookworm
|
||||
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
RUN printf '#!/bin/sh\nexit 101\n' > /usr/sbin/policy-rc.d \
|
||||
&& chmod +x /usr/sbin/policy-rc.d \
|
||||
&& apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
libcap2 \
|
||||
libmariadb3 \
|
||||
libsnmp40 \
|
||||
&& mkdir -p /etc/spine \
|
||||
&& apt-get download cacti-spine \
|
||||
&& dpkg-deb -x cacti-spine_*.deb / \
|
||||
&& rm -f cacti-spine_*.deb \
|
||||
&& ln -sf /usr/sbin/spine /usr/local/bin/spine \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /var/www/html/cacti
|
||||
|
||||
ENTRYPOINT ["spine"]
|
||||
@@ -0,0 +1,38 @@
|
||||
services:
|
||||
db:
|
||||
image: mariadb:11.8
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: cacti
|
||||
MYSQL_USER: cacti
|
||||
MYSQL_PASSWORD: cacti
|
||||
volumes:
|
||||
- snmpv3_db:/var/lib/mysql
|
||||
- ../../cacti.sql:/docker-entrypoint-initdb.d/cacti.sql:ro
|
||||
command:
|
||||
- --character-set-server=utf8mb4
|
||||
- --collation-server=utf8mb4_unicode_ci
|
||||
- --max-connections=200
|
||||
- --max-heap-table-size=128M
|
||||
- --tmp-table-size=128M
|
||||
healthcheck:
|
||||
test: ["CMD", "healthcheck.sh", "--connect", "--innodb_initialized"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
|
||||
spine:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: tests/snmpv3/Dockerfile
|
||||
depends_on:
|
||||
db:
|
||||
condition: service_healthy
|
||||
volumes:
|
||||
- ../../:/var/www/html/cacti:ro
|
||||
- ./spine.conf:/etc/spine/spine.conf:ro
|
||||
command: ["--conf=/etc/spine/spine.conf", "-f", "1", "-l", "1", "-S"]
|
||||
|
||||
volumes:
|
||||
snmpv3_db:
|
||||
@@ -0,0 +1,6 @@
|
||||
DB_Host db
|
||||
DB_Database cacti
|
||||
DB_User cacti
|
||||
DB_Pass cacti
|
||||
DB_Port 3306
|
||||
Cacti_Log /tmp/cacti-spine.log
|
||||
+11
-8
@@ -23,6 +23,9 @@
|
||||
*/
|
||||
|
||||
require('./include/auth.php');
|
||||
require_once(CACTI_PATH_LIBRARY . '/CactiValidator.php');
|
||||
|
||||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
|
||||
set_default_action();
|
||||
|
||||
@@ -504,14 +507,14 @@ function form_save() : void {
|
||||
}
|
||||
|
||||
$save['id'] = gnrv('id');
|
||||
$save['name'] = form_input_validate(gnrv('name'), 'name', '', false, 3);
|
||||
$save['description'] = form_input_validate(gnrv('description'), 'description', '', true, 3);
|
||||
$save['show_tree'] = form_input_validate(gnrv('show_tree', ''), 'show_tree', '', true, 3);
|
||||
$save['show_list'] = form_input_validate(gnrv('show_list', ''), 'show_list', '', true, 3);
|
||||
$save['show_preview'] = form_input_validate(gnrv('show_preview', ''), 'show_preview', '', true, 3);
|
||||
$save['graph_settings'] = form_input_validate(gnrv('graph_settings', ''), 'graph_settings', '', true, 3);
|
||||
$save['login_opts'] = form_input_validate(gnrv('login_opts'), 'login_opts', '', true, 3);
|
||||
$save['enabled'] = form_input_validate(gnrv('enabled', ''), 'enabled', '', true, 3);
|
||||
$save['name'] = CactiValidator::validateInput(gnrv('name'), 'name', [new Assert\NotBlank()], 3);
|
||||
$save['description'] = CactiValidator::validateInput(gnrv('description'), 'description', [], 3);
|
||||
$save['show_tree'] = CactiValidator::validateInput(gnrv('show_tree', ''), 'show_tree', [], 3);
|
||||
$save['show_list'] = CactiValidator::validateInput(gnrv('show_list', ''), 'show_list', [], 3);
|
||||
$save['show_preview'] = CactiValidator::validateInput(gnrv('show_preview', ''), 'show_preview', [], 3);
|
||||
$save['graph_settings'] = CactiValidator::validateInput(gnrv('graph_settings', ''), 'graph_settings', [], 3);
|
||||
$save['login_opts'] = CactiValidator::validateInput(gnrv('login_opts'), 'login_opts', [], 3);
|
||||
$save['enabled'] = CactiValidator::validateInput(gnrv('enabled', ''), 'enabled', [], 3);
|
||||
|
||||
$save = api_plugin_hook_function('user_group_admin_setup_sql_save', $save);
|
||||
|
||||
|
||||
Reference in new issue
Block a user