From 449a322bab32fb5c7cecb4ebc453b6d0871cd898 Mon Sep 17 00:00:00 2001
From: tips-of-mine <54597409+tips-of-mine@users.noreply.github.com>
Date: Sat, 31 May 2025 11:14:08 +0200
Subject: [PATCH] Update plugin configuration files for proper GLPI detection
---
css/README | 3 +
css/cve.css | 207 ++++++++++++++++++++++++++++++++++++++++++++
front/cve.form.php | 88 +++++++++++++++++++
front/cve.php | 20 +++++
front/dashboard.php | 176 +++++++++++++++++++++++++++++++++++++
js/README | 3 +
plugin.xml | 6 +-
setup.php | 8 +-
8 files changed, 505 insertions(+), 6 deletions(-)
create mode 100644 css/README
create mode 100644 css/cve.css
create mode 100644 front/cve.form.php
create mode 100644 front/cve.php
create mode 100644 front/dashboard.php
create mode 100644 js/README
diff --git a/css/README b/css/README
new file mode 100644
index 0000000..7f12fa6
--- /dev/null
+++ b/css/README
@@ -0,0 +1,3 @@
+This directory contains all CSS styles for the CVE plugin.
+
+The main file, cve.css, is automatically loaded by GLPI via the plugin's setup.php file.
\ No newline at end of file
diff --git a/css/cve.css b/css/cve.css
new file mode 100644
index 0000000..cd75604
--- /dev/null
+++ b/css/cve.css
@@ -0,0 +1,207 @@
+/**
+ * GLPI CVE Plugin - Main CSS
+ * This file contains styles specific to the CVE plugin
+ */
+
+/* Dashboard styles */
+.dashboard-card-container {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
+ gap: 20px;
+ margin-bottom: 30px;
+}
+
+.dashboard-card {
+ background-color: #fff;
+ border-radius: 4px;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
+ padding: 15px;
+ display: flex;
+ align-items: center;
+}
+
+.dashboard-card-icon {
+ width: 50px;
+ height: 50px;
+ border-radius: 50%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 15px;
+ font-size: 24px;
+}
+
+.dashboard-card-content {
+ flex: 1;
+}
+
+.dashboard-card-title {
+ font-size: 14px;
+ color: #666;
+ margin-bottom: 5px;
+}
+
+.dashboard-card-value {
+ font-size: 28px;
+ font-weight: bold;
+}
+
+/* Card types */
+.dashboard-card-critical .dashboard-card-icon {
+ background-color: #ffcdd2;
+ color: #d32f2f;
+}
+
+.dashboard-card-high .dashboard-card-icon {
+ background-color: #ffe0b2;
+ color: #ef6c00;
+}
+
+.dashboard-card-new .dashboard-card-icon {
+ background-color: #bbdefb;
+ color: #1976d2;
+}
+
+.dashboard-card-resolved .dashboard-card-icon {
+ background-color: #c8e6c9;
+ color: #388e3c;
+}
+
+/* Chart styles */
+.dashboard-chart-container {
+ background-color: #fff;
+ border-radius: 4px;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
+ padding: 15px;
+ margin-bottom: 30px;
+}
+
+.dashboard-chart-container h2 {
+ margin-top: 0;
+ margin-bottom: 20px;
+ font-size: 18px;
+ font-weight: normal;
+}
+
+.severity-chart-bars {
+ display: flex;
+ justify-content: space-around;
+ height: 200px;
+ align-items: flex-end;
+}
+
+.severity-chart-bar-container {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ width: 80px;
+}
+
+.severity-chart-bar {
+ width: 40px;
+ border-radius: 4px 4px 0 0;
+ min-height: 5px;
+}
+
+.severity-chart-label {
+ margin-top: 10px;
+ font-size: 12px;
+ font-weight: bold;
+}
+
+.severity-chart-value {
+ margin-top: 5px;
+ font-size: 14px;
+ color: #666;
+}
+
+/* Table styles */
+.dashboard-table-container {
+ background-color: #fff;
+ border-radius: 4px;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24);
+ padding: 15px;
+ margin-bottom: 30px;
+}
+
+.dashboard-table-container h2 {
+ margin-top: 0;
+ margin-bottom: 20px;
+ font-size: 18px;
+ font-weight: normal;
+}
+
+/* Severity classes */
+.cve-severity-critical {
+ background-color: #d32f2f;
+ color: #fff;
+ padding: 2px 6px;
+ border-radius: 10px;
+ font-size: 12px;
+}
+
+.cve-severity-high {
+ background-color: #f57c00;
+ color: #fff;
+ padding: 2px 6px;
+ border-radius: 10px;
+ font-size: 12px;
+}
+
+.cve-severity-medium {
+ background-color: #fbc02d;
+ color: #333;
+ padding: 2px 6px;
+ border-radius: 10px;
+ font-size: 12px;
+}
+
+.cve-severity-low {
+ background-color: #2196f3;
+ color: #fff;
+ padding: 2px 6px;
+ border-radius: 10px;
+ font-size: 12px;
+}
+
+/* Status classes */
+.cve-status-new {
+ background-color: #2196f3;
+ color: #fff;
+ padding: 2px 6px;
+ border-radius: 10px;
+ font-size: 12px;
+}
+
+.cve-status-analyzed {
+ background-color: #ff9800;
+ color: #fff;
+ padding: 2px 6px;
+ border-radius: 10px;
+ font-size: 12px;
+}
+
+.cve-status-assigned {
+ background-color: #9c27b0;
+ color: #fff;
+ padding: 2px 6px;
+ border-radius: 10px;
+ font-size: 12px;
+}
+
+.cve-status-resolved {
+ background-color: #4caf50;
+ color: #fff;
+ padding: 2px 6px;
+ border-radius: 10px;
+ font-size: 12px;
+}
+
+/* Badge style for dashboard */
+.badge {
+ display: inline-block;
+ padding: 2px 8px;
+ border-radius: 10px;
+ font-size: 11px;
+ font-weight: bold;
+}
\ No newline at end of file
diff --git a/front/cve.form.php b/front/cve.form.php
new file mode 100644
index 0000000..7c1490b
--- /dev/null
+++ b/front/cve.form.php
@@ -0,0 +1,88 @@
+check(-1, CREATE, $_POST);
+ if ($cve->add($_POST)) {
+ Event::log(
+ $cve->fields['id'],
+ "plugin_cve_cve",
+ 4,
+ "inventory",
+ sprintf(__('%1$s adds the CVE %2$s'), $_SESSION["glpiname"], $_POST["cve_id"])
+ );
+ }
+ Html::back();
+} else if (isset($_POST["delete"])) {
+ $cve->check($_POST["id"], DELETE);
+ if ($cve->delete($_POST)) {
+ Event::log(
+ $_POST["id"],
+ "plugin_cve_cve",
+ 4,
+ "inventory",
+ sprintf(__('%1$s deletes the CVE %2$s'), $_SESSION["glpiname"], $_POST["id"])
+ );
+ }
+ $cve->redirectToList();
+} else if (isset($_POST["restore"])) {
+ $cve->check($_POST["id"], DELETE);
+ if ($cve->restore($_POST)) {
+ Event::log(
+ $_POST["id"],
+ "plugin_cve_cve",
+ 4,
+ "inventory",
+ sprintf(__('%1$s restores the CVE %2$s'), $_SESSION["glpiname"], $_POST["id"])
+ );
+ }
+ $cve->redirectToList();
+} else if (isset($_POST["purge"])) {
+ $cve->check($_POST["id"], PURGE);
+ if ($cve->delete($_POST, 1)) {
+ Event::log(
+ $_POST["id"],
+ "plugin_cve_cve",
+ 4,
+ "inventory",
+ sprintf(__('%1$s purges the CVE %2$s'), $_SESSION["glpiname"], $_POST["id"])
+ );
+ }
+ $cve->redirectToList();
+} else if (isset($_POST["update"])) {
+ $cve->check($_POST["id"], UPDATE);
+ if ($cve->update($_POST)) {
+ Event::log(
+ $_POST["id"],
+ "plugin_cve_cve",
+ 4,
+ "inventory",
+ sprintf(__('%1$s updates the CVE %2$s'), $_SESSION["glpiname"], $_POST["id"])
+ );
+ }
+ Html::back();
+} else {
+ Html::header(
+ PluginCveCve::getTypeName(Session::getPluralNumber()),
+ $_SERVER['PHP_SELF'],
+ "tools",
+ "PluginCveCveMenu",
+ "cve"
+ );
+
+ $id = 0;
+ if (isset($_GET["id"])) {
+ $id = $_GET["id"];
+ }
+
+ $cve->display(['id' => $id]);
+ Html::footer();
+}
\ No newline at end of file
diff --git a/front/cve.php b/front/cve.php
new file mode 100644
index 0000000..7ce7f15
--- /dev/null
+++ b/front/cve.php
@@ -0,0 +1,20 @@
+";
+
+// Statistics cards
+echo "
";
+
+// Critical vulnerabilities card
+echo "
";
+echo "
";
+echo "
";
+echo "
" . __('Critical Vulnerabilities', 'cve') . "
";
+echo "
" . ($cve_stats['severity']['CRITICAL'] ?? 0) . "
";
+echo "
";
+echo "
";
+
+// High risk card
+echo "
";
+echo "
";
+echo "
";
+echo "
" . __('High Vulnerabilities', 'cve') . "
";
+echo "
" . ($cve_stats['severity']['HIGH'] ?? 0) . "
";
+echo "
";
+echo "
";
+
+// New alerts card
+echo "
";
+echo "
";
+echo "
";
+echo "
" . __('New Alerts', 'cve') . "
";
+echo "
" . ($alert_stats['by_status']['NEW'] ?? 0) . "
";
+echo "
";
+echo "
";
+
+// Resolved card
+echo "
";
+echo "
";
+echo "
";
+echo "
" . __('Resolved', 'cve') . "
";
+echo "
" . ($cve_stats['status']['RESOLVED'] ?? 0) . "
";
+echo "
";
+echo "
";
+
+echo "
";
+
+// Severity distribution chart
+if (!empty($severity_data)) {
+ echo "";
+ echo "
" . __('CVE Severity Distribution', 'cve') . "
";
+
+ echo "
";
+ // This would be replaced with an actual chart library in production
+ echo "
";
+ foreach ($severity_data['labels'] as $i => $label) {
+ $value = $severity_data['series'][$i]['data'][0] ?? 0;
+ $color = $severity_data['series'][$i]['color'] ?? '#999999';
+
+ echo "
";
+ echo "
" . $label . "
";
+ echo "
";
+ echo "
" . $value . "
";
+ echo "
";
+ }
+ echo "
";
+ echo "
";
+
+ echo "
";
+}
+
+// Recent CVEs table
+if (!empty($recent_cves)) {
+ echo "";
+ echo "
" . __('Recent CVEs', 'cve') . "
";
+
+ echo "
";
+ echo "";
+ foreach ($recent_cves['headers'] as $header) {
+ echo "" . $header . " | ";
+ }
+ echo "
";
+
+ foreach ($recent_cves['rows'] as $row) {
+ echo "";
+ echo "" . $row['cve_id'] . " | ";
+ echo "" . $row['severity'] . " | ";
+ echo "" . $row['cvss_score'] . " | ";
+ echo "" . Html::convDateTime($row['published']) . " | ";
+ echo "" . $row['status'] . " | ";
+ echo "
";
+ }
+
+ echo "
";
+ echo "
";
+ echo "
";
+}
+
+// Device Vulnerability Alerts
+echo "";
+echo "
" . __('Alerts by Device', 'cve') . "
";
+echo "
";
+echo "";
+echo "" . __('Device', 'cve') . " | ";
+echo "" . __('Total Alerts', 'cve') . " | ";
+echo "" . __('Critical', 'cve') . " | ";
+echo "" . __('High', 'cve') . " | ";
+echo " | ";
+echo "
";
+
+// This would be populated with actual data from the database
+// Placeholder for demonstration purposes
+$deviceAlerts = [
+ ['name' => 'Windows Server 2019', 'alerts' => 12, 'critical' => 3, 'high' => 6],
+ ['name' => 'Ubuntu 20.04 LTS', 'alerts' => 8, 'critical' => 2, 'high' => 3],
+ ['name' => 'macOS Monterey', 'alerts' => 5, 'critical' => 0, 'high' => 2],
+ ['name' => 'Cisco IOS Router', 'alerts' => 7, 'critical' => 4, 'high' => 2],
+ ['name' => 'Database Server', 'alerts' => 9, 'critical' => 1, 'high' => 5],
+];
+
+foreach ($deviceAlerts as $device) {
+ echo "";
+ echo "" . $device['name'] . " | ";
+ echo "" . $device['alerts'] . " | ";
+
+ // Critical alerts with badge
+ echo "";
+ if ($device['critical'] > 0) {
+ echo "" . $device['critical'] . "";
+ } else {
+ echo "0";
+ }
+ echo " | ";
+
+ // High alerts with badge
+ echo "";
+ if ($device['high'] > 0) {
+ echo "" . $device['high'] . "";
+ } else {
+ echo "0";
+ }
+ echo " | ";
+
+ echo "";
+ echo "" . __('View', 'cve') . "";
+ echo " | ";
+ echo "
";
+}
+
+echo "
";
+echo "
";
+echo "
";
+
+echo ""; // End of dashboard container
+
+Html::footer();
\ No newline at end of file
diff --git a/js/README b/js/README
new file mode 100644
index 0000000..29f3edf
--- /dev/null
+++ b/js/README
@@ -0,0 +1,3 @@
+This directory contains all JavaScript files for the CVE plugin.
+
+The main file, cve.js, is automatically loaded by GLPI via the plugin's setup.php file.
\ No newline at end of file
diff --git a/plugin.xml b/plugin.xml
index 2e76ace..7433ba4 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -30,7 +30,7 @@
https://github.com/tips-of-mine/GLPI-Plugin-CVE-Prototype/issues
https://github.com/tips-of-mine/GLPI-Plugin-CVE-Prototype/blob/master/README.md
- Hubert C. / Initiativa srl
+ Hubert C. / Tips-Of-Mine
@@ -53,10 +53,12 @@
CVE-Prototype
Security
+ Vulnerability
CVE-Prototype
- Security
+ Sécurité
+ Vulnérabilité
diff --git a/setup.php b/setup.php
index 4a9a8e8..354e4d8 100644
--- a/setup.php
+++ b/setup.php
@@ -4,7 +4,7 @@
* Handles plugin initialization, installation, and hooks
*/
-define('PLUGIN_CVE_VERSION', '1.0.0');
+define('PLUGIN_CVE_VERSION', '0.0.1');
define('PLUGIN_CVE_MIN_GLPI', '10.0.0');
define('PLUGIN_CVE_MAX_GLPI', '10.99.99');
define('PLUGIN_CVE_DIR', __DIR__);
@@ -115,9 +115,9 @@ function plugin_version_cve() {
return [
'name' => __('Vulnérabilité', 'cve'),
'version' => PLUGIN_CVE_VERSION,
- 'author' => 'Your Organization',
- 'license' => 'GPL v2+',
- 'homepage' => 'https://github.com/your-org/glpi-cve-plugin',
+ 'author' => 'Tips-Of-Mine',
+ 'license' => 'GPL v3+',
+ 'homepage' => 'https://github.com/tips-of-mine/GLPI-Plugin-CVE-Prototype',
'requirements' => [
'glpi' => [
'min' => PLUGIN_CVE_MIN_GLPI,