diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..b14cfa0
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+version: 2
+updates:
+ - package-ecosystem: "composer"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 10
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ open-pull-requests-limit: 10
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 0000000..e447119
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,45 @@
+name: "CodeQL"
+
+on:
+ push:
+ branches: [main, master, develop]
+ paths-ignore:
+ - "**/*.md"
+ pull_request:
+ branches: [main, master, develop]
+ paths-ignore:
+ - "**/*.md"
+ schedule:
+ - cron: "30 1 * * 1"
+ workflow_dispatch:
+
+concurrency:
+ group: codeql-${{ github.ref }}
+ cancel-in-progress: true
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+ permissions:
+ actions: read
+ contents: read
+ security-events: write
+ strategy:
+ fail-fast: false
+ matrix:
+ language: ["javascript-typescript"]
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3
+ with:
+ languages: ${{ matrix.language }}
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@b56ba49b26e50535fa1e7f7db0f4f7b4bf65d80d # v3
+ with:
+ category: "/language:${{ matrix.language }}"
diff --git a/.github/workflows/plugin-ci-workflow.yml b/.github/workflows/plugin-ci-workflow.yml
index 87991cc..438da27 100644
--- a/.github/workflows/plugin-ci-workflow.yml
+++ b/.github/workflows/plugin-ci-workflow.yml
@@ -86,7 +86,7 @@ jobs:
run: sudo apt-get update
- name: Install System Dependencies
- run: sudo apt-get install -y apache2 snmp snmpd rrdtool fping libapache2-mod-php${{ matrix.php }}
+ run: sudo apt-get install -y apache2 snmp snmpd rrdtool fping
- name: Start SNMPD Agent and Test
run: |
@@ -222,4 +222,3 @@ jobs:
exit 1
fi
-
diff --git a/.gitignore b/.gitignore
index 3dd84d9..d20187c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,4 @@
locales/po/*.mo
+.omc/
diff --git a/audit.php b/audit.php
index dffed41..81994b8 100644
--- a/audit.php
+++ b/audit.php
@@ -28,23 +28,23 @@
set_default_action();
switch(get_request_var('action')) {
-case 'export':
- audit_export_rows();
+ case 'export':
+ audit_export_rows();
- break;
-case 'purge':
- audit_purge();
+ break;
+ case 'purge':
+ audit_purge();
- top_header();
- audit_log();
- bottom_footer();
+ top_header();
+ audit_log();
+ bottom_footer();
- break;
+ break;
case 'getdata':
$data = db_fetch_row_prepared('SELECT *
FROM audit_log
WHERE id = ?',
- array(get_filter_request_var('id')));
+ [get_filter_request_var('id')]);
$output = '';
@@ -61,8 +61,9 @@
} elseif (cacti_sizeof($data)) {
$attribs = json_decode($data['post']);
- $nattribs = array();
- foreach($attribs as $field => $content) {
+ $nattribs = [];
+
+ foreach ($attribs as $field => $content) {
$nattribs[$field] = $content;
}
ksort($nattribs);
@@ -91,10 +92,11 @@
}
$i = 0;
+
if (cacti_sizeof($nattribs)) {
- foreach($nattribs as $field => $content) {
+ foreach ($nattribs as $field => $content) {
if ($i % $columns == 0) {
- $output .= ($output != '' ? '':'') . '
';
+ $output .= ($output != '' ? ' ' : '') . '';
}
if (is_array($content)) {
@@ -113,6 +115,7 @@
// Display the Record Data under selected_items if it is not empty
$recordData = json_decode($data['object_data']);
+
if (!empty($recordData)) {
$output .= '';
$output .= ' ';
@@ -127,14 +130,13 @@
}
// Output the final result
- echo $output;
+ print $output;
-
- break;
-default:
- top_header();
- audit_log();
- bottom_footer();
+ break;
+ default:
+ top_header();
+ audit_log();
+ bottom_footer();
}
function audit_purge() {
@@ -150,21 +152,21 @@ function audit_purge() {
function audit_export_rows() {
process_request_vars();
- /* form the 'where' clause for our main sql query */
+ // form the 'where' clause for our main sql query
if (get_request_var('filter') != '') {
$sql_where = 'WHERE (
- page LIKE ' . db_qstr('%' . get_request_var('filter') . '%') . '
+ page LIKE ' . db_qstr('%' . get_request_var('filter') . '%') . '
OR post LIKE ' . db_qstr('%' . get_request_var('filter') . '%') . ')';
} else {
$sql_where = '';
}
if (get_request_var('event_page') != '-1') {
- $sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . ' page = ' . db_qstr(get_request_var('event_page'));
+ $sql_where .= ($sql_where != '' ? ' AND ' : 'WHERE ') . ' page = ' . db_qstr(get_request_var('event_page'));
}
if (!isempty_request_var('user_id') && get_request_var('user_id') > '-1') {
- $sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . ' user_id = ' . get_request_var('user_id');
+ $sql_where .= ($sql_where != '' ? ' AND ' : 'WHERE ') . ' user_id = ' . get_request_var('user_id');
}
$events = db_fetch_assoc("SELECT audit_log.*, user_auth.username
@@ -178,26 +180,26 @@ function audit_export_rows() {
print __x('Column Header used for CSV log export. Ensure that you do NOT(!) remove one of the commas. The output needs to be CSV compliant.','page, user_id, username, action, ip_address, user_agent, event_time, post', 'audit') . "\n";
- foreach($events as $event) {
- $post = json_decode($event['post']);
+ foreach ($events as $event) {
+ $post = json_decode($event['post']);
$poster = '';
- foreach($post as $var => $value) {
+
+ foreach ($post as $var => $value) {
if (is_array($value)) {
- $poster .= ($poster != '' ? '|':'') . $var . ':' . implode('%', $value);
+ $poster .= ($poster != '' ? '|' : '') . $var . ':' . implode('%', $value);
} else {
- $poster .= ($poster != '' ? '|':'') . $var . ':' . $value;
+ $poster .= ($poster != '' ? '|' : '') . $var . ':' . $value;
}
}
- print
- $event['page'] . ', ' .
- $event['user_id'] . ', ' .
- get_username($event['user_id']) . ', ' .
- $event['action'] . ', ' .
- $event['ip_address'] . ', ' .
- $event['user_agent'] . ', ' .
- $event['event_time'] . ', ' .
- $poster . "\n";
+ print $event['page'] . ', ' .
+ $event['user_id'] . ', ' .
+ get_username($event['user_id']) . ', ' .
+ $event['action'] . ', ' .
+ $event['ip_address'] . ', ' .
+ $event['user_agent'] . ', ' .
+ $event['event_time'] . ', ' .
+ $poster . "\n";
}
}
}
@@ -205,51 +207,52 @@ function audit_export_rows() {
function audit_csv_escape($string) {
$string = str_replace('"', '', $string);
$string = str_replace(',', '|', $string);
+
return $string;
}
function process_request_vars() {
- /* ================= input validation and session storage ================= */
- $filters = array(
- 'rows' => array(
- 'filter' => FILTER_VALIDATE_INT,
+ // ================= input validation and session storage =================
+ $filters = [
+ 'rows' => [
+ 'filter' => FILTER_VALIDATE_INT,
'pageset' => true,
'default' => '-1'
- ),
- 'page' => array(
- 'filter' => FILTER_VALIDATE_INT,
+ ],
+ 'page' => [
+ 'filter' => FILTER_VALIDATE_INT,
'default' => '1'
- ),
- 'filter' => array(
- 'filter' => FILTER_DEFAULT,
+ ],
+ 'filter' => [
+ 'filter' => FILTER_DEFAULT,
'pageset' => true,
'default' => ''
- ),
- 'sort_column' => array(
- 'filter' => FILTER_CALLBACK,
+ ],
+ 'sort_column' => [
+ 'filter' => FILTER_CALLBACK,
'default' => 'event_time',
- 'options' => array('options' => 'sanitize_search_string')
- ),
- 'sort_direction' => array(
- 'filter' => FILTER_CALLBACK,
+ 'options' => ['options' => 'sanitize_search_string']
+ ],
+ 'sort_direction' => [
+ 'filter' => FILTER_CALLBACK,
'default' => 'DESC',
- 'options' => array('options' => 'sanitize_search_string')
- ),
- 'user_id' => array(
- 'filter' => FILTER_VALIDATE_INT,
+ 'options' => ['options' => 'sanitize_search_string']
+ ],
+ 'user_id' => [
+ 'filter' => FILTER_VALIDATE_INT,
'pageset' => true,
'default' => '-1'
- ),
- 'event_page' => array(
- 'filter' => FILTER_CALLBACK,
+ ],
+ 'event_page' => [
+ 'filter' => FILTER_CALLBACK,
'pageset' => true,
'default' => '-1',
- 'options' => array('options' => 'sanitize_search_string')
- )
- );
+ 'options' => ['options' => 'sanitize_search_string']
+ ]
+ ];
validate_store_request_vars($filters, 'sess_audit');
- /* ================= input validation ================= */
+ // ================= input validation =================
}
function audit_log() {
@@ -272,71 +275,87 @@ function audit_log() {
-
+
- '>
+ '>
-
+
- ':'>') . __('All', 'audit');?>
+ ' : '>') . __('All', 'audit'); ?>
' . htmlspecialchars($page) . "\n";
- }
- }
- ?>
+
+ if (cacti_sizeof($pages)) {
+ foreach ($pages as $page) {
+ print "' . htmlspecialchars($page) . " \n";
+ }
+ }
+ ?>
-
+
- ':'>') . __('All', 'audit');?>
- ':'>') . __('cli', 'audit');?>
+ ' : '>') . __('All', 'audit'); ?>
+ ' : '>') . __('cli', 'audit'); ?>
' . htmlspecialchars(get_username($user)) . "\n";
- }
- }
- ?>
+ $users = array_rekey(db_fetch_assoc('SELECT DISTINCT user_id FROM audit_log ORDER BY user_id'), 'user_id', 'user_id');
+
+ if (cacti_sizeof($users)) {
+ foreach ($users as $user) {
+ if ($user == 0) {
+ continue;
+ }
+ print "' . htmlspecialchars(get_username($user)) . " \n";
+ }
+ }
+ ?>
-
+
- ':'>') . __('Default', 'audit');?>
+ ' : '>') . __('Default', 'audit'); ?>
$value) {
- print "' . htmlspecialchars($value) . " \n";
- }
- }
- ?>
+ if (cacti_sizeof($item_rows)) {
+ foreach ($item_rows as $key => $value) {
+ print "' . htmlspecialchars($value) . " \n";
+ }
+ }
+ ?>
- '>
- '>
- '>
- '>
+ '>
+ '>
+ '>
+ '>
- '>
+ '>
@@ -344,21 +363,21 @@ function audit_log() {
html_end_box();
- /* form the 'where' clause for our main sql query */
+ // form the 'where' clause for our main sql query
if (get_request_var('filter') != '') {
$sql_where = 'WHERE (
- page LIKE ' . db_qstr('%' . get_request_var('filter') . '%') . '
+ page LIKE ' . db_qstr('%' . get_request_var('filter') . '%') . '
OR post LIKE ' . db_qstr('%' . get_request_var('filter') . '%') . ')';
} else {
$sql_where = '';
}
if (get_request_var('event_page') != '-1') {
- $sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . ' page = ' . db_qstr(get_request_var('event_page'));
+ $sql_where .= ($sql_where != '' ? ' AND ' : 'WHERE ') . ' page = ' . db_qstr(get_request_var('event_page'));
}
if (!isempty_request_var('user_id') && get_request_var('user_id') > '-1') {
- $sql_where .= ($sql_where != '' ? ' AND ':'WHERE ') . ' user_id = ' . get_request_var('user_id');
+ $sql_where .= ($sql_where != '' ? ' AND ' : 'WHERE ') . ' user_id = ' . get_request_var('user_id');
}
$total_rows = db_fetch_cell("SELECT
@@ -369,7 +388,7 @@ function audit_log() {
$sql_where");
$sql_order = get_order_string();
- $sql_limit = ' LIMIT ' . ($rows*(get_request_var('page')-1)) . ',' . $rows;
+ $sql_limit = ' LIMIT ' . ($rows * (get_request_var('page') - 1)) . ',' . $rows;
$events = db_fetch_assoc("SELECT audit_log.*, user_auth.username
FROM audit_log
@@ -379,54 +398,55 @@ function audit_log() {
$sql_order
$sql_limit");
- $nav = html_nav_bar('audit.php?filter=' . get_request_var('filter'), MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 5, __('Audit Events', 'audit'), 'page', 'main');
+ $nav = html_nav_bar('audit.php?filter=' . get_request_var('filter'), MAX_DISPLAY_PAGES, get_request_var('page'), $rows, $total_rows, 5, __('Audit Events', 'audit'), 'page', 'main');
- print $nav;
+ print $nav;
html_start_box('', '100%', '', '3', 'center', '');
- $display_text = array(
- 'page' => array(
+ $display_text = [
+ 'page' => [
'display' => __('Page Name', 'audit'),
- 'align' => 'left',
- 'sort' => 'ASC',
- 'tip' => __('The page where the event was generated.', 'audit')
- ),
- 'username' => array(
+ 'align' => 'left',
+ 'sort' => 'ASC',
+ 'tip' => __('The page where the event was generated.', 'audit')
+ ],
+ 'username' => [
'display' => __('User Name', 'audit'),
- 'align' => 'left',
- 'sort' => 'ASC',
- 'tip' => __('The user who generated the event.', 'audit')
- ),
- 'action' => array(
+ 'align' => 'left',
+ 'sort' => 'ASC',
+ 'tip' => __('The user who generated the event.', 'audit')
+ ],
+ 'action' => [
'display' => __('Action', 'audit'),
- 'align' => 'left',
- 'sort' => 'ASC',
- 'tip' => __('The Cacti Action requested. Hover over action to see $_POST data.', 'audit')
- ),
- 'user_agent' => array(
+ 'align' => 'left',
+ 'sort' => 'ASC',
+ 'tip' => __('The Cacti Action requested. Hover over action to see $_POST data.', 'audit')
+ ],
+ 'user_agent' => [
'display' => __('User Agent', 'audit'),
- 'align' => 'left',
- 'sort' => 'ASC',
- 'tip' => __('The browser type of the requester.', 'audit')
- ),
- 'ip_address' => array(
+ 'align' => 'left',
+ 'sort' => 'ASC',
+ 'tip' => __('The browser type of the requester.', 'audit')
+ ],
+ 'ip_address' => [
'display' => __('IP Address', 'audit'),
- 'align' => 'right',
- 'sort' => 'ASC',
- 'tip' => __('The IP Address of the requester.', 'audit')
- ),
- 'event_time' => array(
+ 'align' => 'right',
+ 'sort' => 'ASC',
+ 'tip' => __('The IP Address of the requester.', 'audit')
+ ],
+ 'event_time' => [
'display' => __('Event Time', 'audit'),
- 'align' => 'right',
- 'sort' => 'DESC',
- 'tip' => __('The time the Event took place.', 'audit')
- )
- );
+ 'align' => 'right',
+ 'sort' => 'DESC',
+ 'tip' => __('The time the Event took place.', 'audit')
+ ]
+ ];
html_header_sort($display_text, get_request_var('sort_column'), get_request_var('sort_direction'), false);
$i = 0;
+
if (cacti_sizeof($events)) {
foreach ($events as $e) {
if ($e['action'] == 'cli') {
@@ -463,4 +483,3 @@ function audit_log() {
$value) {
if (preg_match('/pass|phrase/i', $key)) {
unset($post[$key]);
}
}
- /* check if drp_action is present and update action accordingly */
+ // check if drp_action is present and update action accordingly
if (isset($post['drp_action']) && $post['drp_action'] == 1) {
$action = 'delete';
- } else if (isset($post['drp_action']) && $post['drp_action'] == 4) {
+ } elseif (isset($post['drp_action']) && $post['drp_action'] == 4) {
$action = 'disable';
}
- /* sanitize and serialize selected items */
+ // sanitize and serialize selected items
if (isset($post['selected_items'])) {
- $selected_items = unserialize(stripslashes($post['selected_items']), array('allowed_classes' => false));
+ $selected_items = unserialize(stripslashes($post['selected_items']), ['allowed_classes' => false]);
$drop_action = $post['drp_action'];
} else {
- $selected_items = array();
+ $selected_items = [];
$drop_action = false;
}
@@ -160,10 +163,10 @@ function audit_config_insert() {
$user_id = (isset($_SESSION['sess_user_id']) ? $_SESSION['sess_user_id'] : 0);
$event_time = date('Y-m-d H:i:s');
- /* Retrieve IP address */
+ // Retrieve IP address
$ip_address = get_client_addr();
- /* Get the User Agent */
+ // Get the User Agent
$user_agent = $_SERVER['HTTP_USER_AGENT'];
if (empty($action) && isset_request_var('action')) {
@@ -179,9 +182,11 @@ function audit_config_insert() {
switch ($drop_action) {
case 2:
$action = 'Delete Device';
+
break;
case 1:
$action = 'Create Device';
+
break;
}
@@ -190,9 +195,11 @@ function audit_config_insert() {
switch ($drop_action) {
case 2:
$action = 'Host Enabled';
+
break;
case 3:
$action = 'Host Disabled';
+
break;
}
@@ -209,7 +216,7 @@ function audit_config_insert() {
db_execute_prepared('INSERT INTO audit_log (page, user_id, action, ip_address, user_agent, event_time, post, object_data)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
- array($page, $user_id, $action, $ip_address, $user_agent, $event_time, $post, $object_data));
+ [$page, $user_id, $action, $ip_address, $user_agent, $event_time, $post, $object_data]);
if ($audit_log == '') {
set_config_option('audit_log_external_path', $base . '/log/audit.log');
@@ -225,8 +232,8 @@ function audit_config_insert() {
}
}
- if (read_config_option('audit_log_external') == 'on' && $audit_log != '' && file_exists($audit_log)) {
- $log_data = array(
+ if (read_config_option('audit_log_external') == 'on' && $audit_log != '' && file_exists($audit_log)) {
+ $log_data = [
'page' => $page,
'user_id' => $user_id,
'action' => $action,
@@ -235,7 +242,7 @@ function audit_config_insert() {
'event_time' => $event_time,
'post' => $post,
'object_data' => $object_data
- );
+ ];
$log_msg = json_encode($log_data) . "\n";
$file = fopen($audit_log, 'a');
@@ -249,21 +256,20 @@ function audit_config_insert() {
$page = basename($_SERVER['argv'][0]);
$user_id = 0;
$action = 'cli';
- $ip_address = getHostByName(php_uname('n'));
+ $ip_address = gethostbyname(php_uname('n'));
$user_agent = get_current_user();
$event_time = date('Y-m-d H:i:s');
$post = implode(' ', $_SERVER['argv']);
- /* don't insert poller records */
- if (strpos($_SERVER['argv'][0], 'poller') === false &&
- strpos($_SERVER['argv'][0], 'cmd.php') === false &&
- strpos($_SERVER['argv'][0], '/scripts/') === false &&
+ // don't insert poller records
+ if (strpos($_SERVER['argv'][0], 'poller') === false &&
+ strpos($_SERVER['argv'][0], 'cmd.php') === false &&
+ strpos($_SERVER['argv'][0], '/scripts/') === false &&
strpos($_SERVER['argv'][0], 'script_server.php') === false &&
- strpos($_SERVER['argv'][0], '_process.php') === false) {
-
+ strpos($_SERVER['argv'][0], '_process.php') === false) {
db_execute_prepared('INSERT INTO audit_log (page, user_id, action, ip_address, user_agent, event_time, post)
VALUES (?, ?, ?, ?, ?, ?, ?)',
- array($page, $user_id, $action, $ip_address, $user_agent, $event_time, $post));
+ [$page, $user_id, $action, $ip_address, $user_agent, $event_time, $post]);
}
}
-}
\ No newline at end of file
+}
diff --git a/composer.json b/composer.json
new file mode 100644
index 0000000..3446f78
--- /dev/null
+++ b/composer.json
@@ -0,0 +1,18 @@
+{
+ "name": "cacti/plugin_audit",
+ "description": "plugin_audit plugin for Cacti",
+ "license": "GPL-2.0-or-later",
+ "require-dev": {
+ "pestphp/pest": "^1.23"
+ },
+ "config": {
+ "allow-plugins": {
+ "pestphp/pest-plugin": true
+ }
+ },
+ "autoload-dev": {
+ "files": [
+ "tests/bootstrap.php"
+ ]
+ }
+}
diff --git a/index.php b/index.php
index 2e22b8c..828ecbe 100644
--- a/index.php
+++ b/index.php
@@ -22,4 +22,4 @@
+-------------------------------------------------------------------------+
*/
-header("Location:../index.php");
+header('Location:../index.php');
diff --git a/locales/LC_MESSAGES/index.php b/locales/LC_MESSAGES/index.php
index 2e22b8c..828ecbe 100644
--- a/locales/LC_MESSAGES/index.php
+++ b/locales/LC_MESSAGES/index.php
@@ -22,4 +22,4 @@
+-------------------------------------------------------------------------+
*/
-header("Location:../index.php");
+header('Location:../index.php');
diff --git a/locales/index.php b/locales/index.php
index 2e22b8c..828ecbe 100644
--- a/locales/index.php
+++ b/locales/index.php
@@ -22,4 +22,4 @@
+-------------------------------------------------------------------------+
*/
-header("Location:../index.php");
+header('Location:../index.php');
diff --git a/setup.php b/setup.php
index ca1af13..26becd3 100644
--- a/setup.php
+++ b/setup.php
@@ -33,7 +33,7 @@ function plugin_audit_install() {
api_plugin_register_hook('audit', 'utilities_array', 'audit_utilities_array', 'setup.php');
api_plugin_register_hook('audit', 'is_console_page', 'audit_is_console_page', 'setup.php');
- /* hook for table replication */
+ // hook for table replication
api_plugin_register_hook('audit', 'replicate_out', 'audit_replicate_out', 'setup.php');
api_plugin_register_realm('audit', 'audit.php', __('View Cacti Audit Log', 'audit'), 1);
@@ -43,6 +43,7 @@ function plugin_audit_install() {
function plugin_audit_uninstall() {
db_execute('DROP TABLE IF EXISTS audit_log');
+
return true;
}
@@ -67,17 +68,19 @@ function audit_check_upgrade() {
include_once($config['library_path'] . '/database.php');
include_once($config['library_path'] . '/functions.php');
- $files = array('plugins.php', 'audit.php');
- if (isset($_SERVER['PHP_SELF']) && !in_array(basename($_SERVER['PHP_SELF']), $files)) {
+ $files = ['plugins.php', 'audit.php'];
+
+ if (isset($_SERVER['PHP_SELF']) && !in_array(basename($_SERVER['PHP_SELF']), $files, true)) {
return;
}
$info = plugin_audit_version();
$current = $info['version'];
$old = db_fetch_cell("SELECT version FROM plugin_config WHERE directory='audit'");
+
if ($current != $old) {
if (api_plugin_is_enabled('audit')) {
- # may sound ridiculous, but enables new hooks
+ // may sound ridiculous, but enables new hooks
api_plugin_enable_hooks('audit');
db_execute('ALTER TABLE audit_log ADD COLUMN IF NOT EXISTS object_data LONGBLOB');
@@ -88,13 +91,13 @@ function audit_check_upgrade() {
WHERE directory='audit'");
db_execute("UPDATE plugin_config SET
- version='" . $info['version'] . "',
- name='" . $info['longname'] . "',
- author='" . $info['author'] . "',
+ version='" . $info['version'] . "',
+ name='" . $info['longname'] . "',
+ author='" . $info['author'] . "',
webpage='" . $info['homepage'] . "'
WHERE directory='" . $info['name'] . "' ");
- /* hook for table replication */
+ // hook for table replication
api_plugin_register_hook('audit', 'replicate_out', 'audit_replicate_out', 'setup.php', '1');
api_plugin_register_hook('audit', 'is_console_page', 'audit_is_console_page', 'setup.php', 1);
}
@@ -192,6 +195,7 @@ function audit_setup_table() {
function plugin_audit_version() {
global $config;
$info = parse_ini_file($config['base_path'] . '/plugins/audit/INFO', true);
+
return $info['info'];
}
@@ -235,12 +239,12 @@ function audit_utilities_array() {
if (api_plugin_user_realm_auth('audit.php')) {
$utilities[__('Technical Support', 'audit')] = array_merge(
$utilities[__('Technical Support', 'audit')],
- array(
- __('View Audit Log', 'audit') => array(
- 'link' => 'plugins/audit/audit.php',
+ [
+ __('View Audit Log', 'audit') => [
+ 'link' => 'plugins/audit/audit.php',
'description' => __('Allows Administrators to view change activity on the Cacti server. Administrators can also export the audit log for analysis purposes.', 'audit')
- )
- )
+ ]
+ ]
);
}
}
@@ -250,10 +254,10 @@ function audit_config_arrays() {
global $menu, $messages, $audit_retentions, $utilities;
if (isset($_SESSION['audit_message']) && $_SESSION['audit_message'] != '') {
- $messages['audit_message'] = array('message' => $_SESSION['audit_message'], 'type' => 'info');
+ $messages['audit_message'] = ['message' => $_SESSION['audit_message'], 'type' => 'info'];
}
- $audit_retentions = array(
+ $audit_retentions = [
-1 => __('Indefinitely', 'audit'),
14 => __('%d Weeks', 2, 'audit'),
30 => __('%d Month', 1, 'audit'),
@@ -264,12 +268,12 @@ function audit_config_arrays() {
365 => __('%d Year', 1, 'audit'),
730 => __('%d Years', 2, 'audit'),
1095 => __('%d Years', 3, 'audit')
- );
+ ];
$menu[__('Utilities')]['plugins/audit/audit.php'] = __('Audit Log', 'audit');
if (function_exists('auth_augment_roles')) {
- auth_augment_roles(__('System Administration'), array('audit.php'));
+ auth_augment_roles(__('System Administration'), ['audit.php']);
}
audit_check_upgrade();
@@ -278,38 +282,38 @@ function audit_config_arrays() {
function audit_config_settings() {
global $tabs, $settings, $item_rows, $audit_retentions;
- $temp = array(
- 'audit_header' => array(
+ $temp = [
+ 'audit_header' => [
'friendly_name' => __('Audit Log Settings', 'audit'),
- 'method' => 'spacer',
- ),
- 'audit_enabled' => array(
+ 'method' => 'spacer',
+ ],
+ 'audit_enabled' => [
'friendly_name' => __('Enable Audit Log', 'audit'),
- 'description' => __('Check this box, if you want the Audit Log to track GUI activities.', 'audit'),
- 'method' => 'checkbox',
- 'default' => 'on'
- ),
- 'audit_retention' => array(
+ 'description' => __('Check this box, if you want the Audit Log to track GUI activities.', 'audit'),
+ 'method' => 'checkbox',
+ 'default' => 'on'
+ ],
+ 'audit_retention' => [
'friendly_name' => __('Audit Log Retention', 'audit'),
- 'description' => __('How long do you wish Audit Log entries to be retained?', 'audit'),
- 'method' => 'drop_array',
- 'default' => '90',
- 'array' => $audit_retentions
- ),
- 'audit_log_external' => array(
+ 'description' => __('How long do you wish Audit Log entries to be retained?', 'audit'),
+ 'method' => 'drop_array',
+ 'default' => '90',
+ 'array' => $audit_retentions
+ ],
+ 'audit_log_external' => [
'friendly_name' => __('External Audit Log', 'audit'),
- 'description' => __('Check this box, if you want the Audit Log to be written to an external file.', 'audit'),
- 'method' => 'checkbox',
- 'default' => 'off'
- ),
- 'audit_log_external_path' => array(
+ 'description' => __('Check this box, if you want the Audit Log to be written to an external file.', 'audit'),
+ 'method' => 'checkbox',
+ 'default' => 'off'
+ ],
+ 'audit_log_external_path' => [
'friendly_name' => __('External Audit Log Log file Path', 'audit'),
- 'description' => __('Enter the path to the external audit log file.', 'audit'),
- 'method' => 'filepath',
- 'default' => '/var/www/html/cacti/log/audit.log',
- 'max_length' => '255'
- ),
- );
+ 'description' => __('Enter the path to the external audit log file.', 'audit'),
+ 'method' => 'filepath',
+ 'default' => '/var/www/html/cacti/log/audit.log',
+ 'max_length' => '255'
+ ],
+ ];
$tabs['audit'] = __('Audit', 'audit');
@@ -321,12 +325,12 @@ function audit_config_settings() {
}
function audit_draw_navigation_text($nav) {
- $nav['audit.php:'] = array(
+ $nav['audit.php:'] = [
'title' => __('Audit Event Log', 'audit'),
'mapping' => 'index.php:',
'url' => 'audit.php',
'level' => '1'
- );
+ ];
return $nav;
}
diff --git a/tests/Pest.php b/tests/Pest.php
new file mode 100644
index 0000000..675e214
--- /dev/null
+++ b/tests/Pest.php
@@ -0,0 +1,12 @@
+toBe(0,
+ "{$relativeFile} uses str_contains() which requires PHP 8.0"
+ );
+ }
+ });
+
+ it('does not use str_starts_with (PHP 8.0)', function () use ($files) {
+ foreach ($files as $relativeFile) {
+ $path = realpath(__DIR__ . '/../../' . $relativeFile);
+
+ if ($path === false) {
+ continue;
+ }
+
+ $contents = file_get_contents($path);
+
+ if ($contents === false) {
+ continue;
+ }
+
+ expect(preg_match('/\bstr_starts_with\s*\(/', $contents))->toBe(0,
+ "{$relativeFile} uses str_starts_with() which requires PHP 8.0"
+ );
+ }
+ });
+
+ it('does not use str_ends_with (PHP 8.0)', function () use ($files) {
+ foreach ($files as $relativeFile) {
+ $path = realpath(__DIR__ . '/../../' . $relativeFile);
+
+ if ($path === false) {
+ continue;
+ }
+
+ $contents = file_get_contents($path);
+
+ if ($contents === false) {
+ continue;
+ }
+
+ expect(preg_match('/\bstr_ends_with\s*\(/', $contents))->toBe(0,
+ "{$relativeFile} uses str_ends_with() which requires PHP 8.0"
+ );
+ }
+ });
+
+ it('does not use nullsafe operator (PHP 8.0)', function () use ($files) {
+ foreach ($files as $relativeFile) {
+ $path = realpath(__DIR__ . '/../../' . $relativeFile);
+
+ if ($path === false) {
+ continue;
+ }
+
+ $contents = file_get_contents($path);
+
+ if ($contents === false) {
+ continue;
+ }
+
+ expect(preg_match('/\?->/', $contents))->toBe(0,
+ "{$relativeFile} uses nullsafe operator which requires PHP 8.0"
+ );
+ }
+ });
+});
diff --git a/tests/Security/PreparedStatementConsistencyTest.php b/tests/Security/PreparedStatementConsistencyTest.php
new file mode 100644
index 0000000..d7ab2b5
--- /dev/null
+++ b/tests/Security/PreparedStatementConsistencyTest.php
@@ -0,0 +1,59 @@
+toBe(0,
+ "File {$relativeFile} contains raw (unprepared) DB calls"
+ );
+ }
+ });
+});
diff --git a/tests/Security/SetupStructureTest.php b/tests/Security/SetupStructureTest.php
new file mode 100644
index 0000000..8e07ec4
--- /dev/null
+++ b/tests/Security/SetupStructureTest.php
@@ -0,0 +1,34 @@
+toContain('function plugin_audit_install');
+ });
+
+ it('defines plugin_audit_version function', function () use ($source) {
+ expect($source)->toContain('function plugin_audit_version');
+ });
+
+ it('defines plugin_audit_uninstall function', function () use ($source) {
+ expect($source)->toContain('function plugin_audit_uninstall');
+ });
+
+ it('returns version array with name key', function () use ($source) {
+ expect($source)->toMatch('/[\'\""]name[\'\""]\s*=>/');
+ });
+
+ it('returns version array with version key', function () use ($source) {
+ expect($source)->toMatch('/[\'\""]version[\'\""]\s*=>/');
+ });
+});
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
new file mode 100644
index 0000000..bb20bc6
--- /dev/null
+++ b/tests/bootstrap.php
@@ -0,0 +1,202 @@
+ 'db_execute', 'sql' => $sql, 'params' => []];
+
+ return true;
+ }
+}
+
+if (!function_exists('db_execute_prepared')) {
+ function db_execute_prepared($sql, $params = []) {
+ $GLOBALS['__test_db_calls'][] = ['fn' => 'db_execute_prepared', 'sql' => $sql, 'params' => $params];
+
+ return true;
+ }
+}
+
+if (!function_exists('db_fetch_assoc')) {
+ function db_fetch_assoc($sql) {
+ return [];
+ }
+}
+
+if (!function_exists('db_fetch_assoc_prepared')) {
+ function db_fetch_assoc_prepared($sql, $params = []) {
+ return [];
+ }
+}
+
+if (!function_exists('db_fetch_row')) {
+ function db_fetch_row($sql) {
+ return [];
+ }
+}
+
+if (!function_exists('db_fetch_row_prepared')) {
+ function db_fetch_row_prepared($sql, $params = []) {
+ return [];
+ }
+}
+
+if (!function_exists('db_fetch_cell')) {
+ function db_fetch_cell($sql) {
+ return '';
+ }
+}
+
+if (!function_exists('db_fetch_cell_prepared')) {
+ function db_fetch_cell_prepared($sql, $params = []) {
+ return '';
+ }
+}
+
+if (!function_exists('db_index_exists')) {
+ function db_index_exists($table, $index) {
+ return false;
+ }
+}
+
+if (!function_exists('db_column_exists')) {
+ function db_column_exists($table, $column) {
+ return false;
+ }
+}
+
+if (!function_exists('api_plugin_db_add_column')) {
+ function api_plugin_db_add_column($plugin, $table, $data) {
+ return true;
+ }
+}
+
+if (!function_exists('api_plugin_db_table_create')) {
+ function api_plugin_db_table_create($plugin, $table, $data) {
+ return true;
+ }
+}
+
+if (!function_exists('read_config_option')) {
+ function read_config_option($name, $force = false) {
+ return '';
+ }
+}
+
+if (!function_exists('set_config_option')) {
+ function set_config_option($name, $value) {
+ }
+}
+
+if (!function_exists('html_escape')) {
+ function html_escape($string) {
+ return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
+ }
+}
+
+if (!function_exists('__')) {
+ function __($text, $domain = '') {
+ return $text;
+ }
+}
+
+if (!function_exists('__esc')) {
+ function __esc($text, $domain = '') {
+ return htmlspecialchars($text, ENT_QUOTES | ENT_HTML5, 'UTF-8');
+ }
+}
+
+if (!function_exists('cacti_log')) {
+ function cacti_log($message, $also_print = false, $log_type = '', $level = 0) {
+ }
+}
+
+if (!function_exists('cacti_sizeof')) {
+ function cacti_sizeof($array) {
+ return is_array($array) ? count($array) : 0;
+ }
+}
+
+if (!function_exists('is_realm_allowed')) {
+ function is_realm_allowed($realm) {
+ return true;
+ }
+}
+
+if (!function_exists('raise_message')) {
+ function raise_message($id, $text = '', $level = 0) {
+ }
+}
+
+if (!function_exists('get_request_var')) {
+ function get_request_var($name) {
+ return '';
+ }
+}
+
+if (!function_exists('get_nfilter_request_var')) {
+ function get_nfilter_request_var($name) {
+ return '';
+ }
+}
+
+if (!function_exists('get_filter_request_var')) {
+ function get_filter_request_var($name) {
+ return '';
+ }
+}
+
+if (!function_exists('form_input_validate')) {
+ function form_input_validate($value, $name, $regex, $optional, $error) {
+ return $value;
+ }
+}
+
+if (!function_exists('is_error_message')) {
+ function is_error_message() {
+ return false;
+ }
+}
+
+if (!function_exists('sql_save')) {
+ function sql_save($array, $table, $key = 'id') {
+ return isset($array['id']) ? $array['id'] : 1;
+ }
+}
+
+if (!defined('CACTI_PATH_BASE')) {
+ define('CACTI_PATH_BASE', '/var/www/html/cacti');
+}
+
+if (!defined('POLLER_VERBOSITY_LOW')) {
+ define('POLLER_VERBOSITY_LOW', 2);
+}
+
+if (!defined('POLLER_VERBOSITY_MEDIUM')) {
+ define('POLLER_VERBOSITY_MEDIUM', 3);
+}
+
+if (!defined('POLLER_VERBOSITY_DEBUG')) {
+ define('POLLER_VERBOSITY_DEBUG', 5);
+}
+
+if (!defined('POLLER_VERBOSITY_NONE')) {
+ define('POLLER_VERBOSITY_NONE', 6);
+}
+
+if (!defined('MESSAGE_LEVEL_ERROR')) {
+ define('MESSAGE_LEVEL_ERROR', 1);
+}