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 ""; + } + echo ""; + + foreach ($recent_cves['rows'] as $row) { + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + } + + echo "
" . $header . "
" . $row['cve_id'] . "" . $row['severity'] . "" . $row['cvss_score'] . "" . Html::convDateTime($row['published']) . "" . $row['status'] . "
"; + echo "
" . __('View all CVEs', 'cve') . "
"; + echo "
"; +} + +// Device Vulnerability Alerts +echo "
"; +echo "

" . __('Alerts by Device', 'cve') . "

"; +echo ""; +echo ""; +echo ""; +echo ""; +echo ""; +echo ""; +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 ""; + echo ""; + + // Critical alerts with badge + echo ""; + + // High alerts with badge + echo ""; + + echo ""; + echo ""; +} + +echo "
" . __('Device', 'cve') . "" . __('Total Alerts', 'cve') . "" . __('Critical', 'cve') . "" . __('High', 'cve') . "
" . $device['name'] . "" . $device['alerts'] . ""; + if ($device['critical'] > 0) { + echo "" . $device['critical'] . ""; + } else { + echo "0"; + } + echo ""; + if ($device['high'] > 0) { + echo "" . $device['high'] . ""; + } else { + echo "0"; + } + echo ""; + echo "" . __('View', 'cve') . ""; + echo "
"; +echo "
" . __('View all alerts', 'cve') . "
"; +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,