mirror of
https://github.com/tips-of-mine/GLPI-Plugin-CVE-Prototype.git
synced 2025-06-28 07:08:44 +02:00
Start repository
This commit is contained in:
752
inc/cve.class.php
Normal file
752
inc/cve.class.php
Normal file
@ -0,0 +1,752 @@
|
||||
<?php
|
||||
/**
|
||||
* GLPI CVE Plugin - Main CVE Class
|
||||
* Handles the CVE entity operations
|
||||
*/
|
||||
|
||||
if (!defined('GLPI_ROOT')) {
|
||||
die("Sorry. You can't access this file directly");
|
||||
}
|
||||
|
||||
/**
|
||||
* PluginCveCve class for managing CVEs
|
||||
*/
|
||||
class PluginCveCve extends CommonDBTM {
|
||||
|
||||
// Rights management constants
|
||||
const RIGHT_NONE = 0;
|
||||
const RIGHT_READ = 1;
|
||||
const RIGHT_WRITE = 2;
|
||||
|
||||
static $rightname = 'plugin_cve_cve';
|
||||
|
||||
/**
|
||||
* Get name of this type by language of the user connected
|
||||
*
|
||||
* @param integer $nb number of elements
|
||||
* @return string name of this type
|
||||
*/
|
||||
static function getTypeName($nb = 0) {
|
||||
return _n('CVE', 'CVEs', $nb, 'cve');
|
||||
}
|
||||
|
||||
/**
|
||||
* Define tabs to display
|
||||
*
|
||||
* @param array $options
|
||||
* @return array containing the tabs
|
||||
*/
|
||||
function defineTabs($options = []) {
|
||||
$tabs = [];
|
||||
$this->addDefaultFormTab($tabs);
|
||||
$this->addStandardTab('PluginCveTicket', $tabs, $options);
|
||||
$this->addStandardTab('Log', $tabs, $options);
|
||||
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the CVE form
|
||||
*
|
||||
* @param integer $ID ID of the item
|
||||
* @param array $options
|
||||
* @return boolean
|
||||
*/
|
||||
function showForm($ID, $options = []) {
|
||||
global $CFG_GLPI;
|
||||
|
||||
$this->initForm($ID, $options);
|
||||
$this->showFormHeader($options);
|
||||
|
||||
$canedit = $this->can($ID, UPDATE);
|
||||
|
||||
echo "<tr class='tab_bg_1'>";
|
||||
|
||||
// CVE ID
|
||||
echo "<td>" . __('CVE ID', 'cve') . "</td>";
|
||||
echo "<td>";
|
||||
echo Html::input('cve_id', ['value' => $this->fields['cve_id'], 'size' => 20]);
|
||||
echo "</td>";
|
||||
|
||||
// Severity
|
||||
echo "<td>" . __('Severity', 'cve') . "</td>";
|
||||
echo "<td>";
|
||||
$severity_options = [
|
||||
'CRITICAL' => __('Critical', 'cve'),
|
||||
'HIGH' => __('High', 'cve'),
|
||||
'MEDIUM' => __('Medium', 'cve'),
|
||||
'LOW' => __('Low', 'cve')
|
||||
];
|
||||
Dropdown::showFromArray('severity', $severity_options,
|
||||
['value' => $this->fields['severity']]);
|
||||
echo "</td>";
|
||||
|
||||
echo "</tr>";
|
||||
|
||||
echo "<tr class='tab_bg_1'>";
|
||||
|
||||
// CVSS Score
|
||||
echo "<td>" . __('CVSS Score', 'cve') . "</td>";
|
||||
echo "<td>";
|
||||
echo Html::input('cvss_score', ['value' => $this->fields['cvss_score'], 'size' => 5]);
|
||||
echo "</td>";
|
||||
|
||||
// CVSS Vector
|
||||
echo "<td>" . __('CVSS Vector', 'cve') . "</td>";
|
||||
echo "<td>";
|
||||
echo Html::input('cvss_vector', ['value' => $this->fields['cvss_vector'], 'size' => 40]);
|
||||
echo "</td>";
|
||||
|
||||
echo "</tr>";
|
||||
|
||||
echo "<tr class='tab_bg_1'>";
|
||||
|
||||
// Published date
|
||||
echo "<td>" . __('Published Date', 'cve') . "</td>";
|
||||
echo "<td>";
|
||||
Html::showDateField('published_date', ['value' => $this->fields['published_date']]);
|
||||
echo "</td>";
|
||||
|
||||
// Modified date
|
||||
echo "<td>" . __('Modified Date', 'cve') . "</td>";
|
||||
echo "<td>";
|
||||
Html::showDateField('modified_date', ['value' => $this->fields['modified_date']]);
|
||||
echo "</td>";
|
||||
|
||||
echo "</tr>";
|
||||
|
||||
echo "<tr class='tab_bg_1'>";
|
||||
|
||||
// Status
|
||||
echo "<td>" . __('Status', 'cve') . "</td>";
|
||||
echo "<td>";
|
||||
$status_options = [
|
||||
'NEW' => __('New', 'cve'),
|
||||
'ANALYZED' => __('Analyzed', 'cve'),
|
||||
'ASSIGNED' => __('Assigned', 'cve'),
|
||||
'RESOLVED' => __('Resolved', 'cve')
|
||||
];
|
||||
Dropdown::showFromArray('status', $status_options,
|
||||
['value' => $this->fields['status']]);
|
||||
echo "</td>";
|
||||
|
||||
// Add entity dropdown if needed
|
||||
echo "<td>" . __('Entity', 'cve') . "</td>";
|
||||
echo "<td>";
|
||||
Entity::dropdown(['value' => $this->fields['entities_id']]);
|
||||
echo "</td>";
|
||||
|
||||
echo "</tr>";
|
||||
|
||||
echo "<tr class='tab_bg_1'>";
|
||||
|
||||
// Description
|
||||
echo "<td>" . __('Description', 'cve') . "</td>";
|
||||
echo "<td colspan='3'>";
|
||||
echo "<textarea name='description' cols='90' rows='4'>".$this->fields['description']."</textarea>";
|
||||
echo "</td>";
|
||||
|
||||
echo "</tr>";
|
||||
|
||||
echo "<tr class='tab_bg_1'>";
|
||||
|
||||
// References
|
||||
echo "<td>" . __('References', 'cve') . "</td>";
|
||||
echo "<td colspan='3'>";
|
||||
$references = json_decode($this->fields['references'], true) ?: [];
|
||||
echo "<textarea name='references' cols='90' rows='4'>".implode("\n", $references)."</textarea>";
|
||||
echo "<br><i>" . __('Enter one URL per line', 'cve') . "</i>";
|
||||
echo "</td>";
|
||||
|
||||
echo "</tr>";
|
||||
|
||||
echo "<tr class='tab_bg_1'>";
|
||||
|
||||
// Affected Products
|
||||
echo "<td>" . __('Affected Products', 'cve') . "</td>";
|
||||
echo "<td colspan='3'>";
|
||||
$affected_products = json_decode($this->fields['affected_products'], true) ?: [];
|
||||
echo "<textarea name='affected_products' cols='90' rows='4'>".implode("\n", $affected_products)."</textarea>";
|
||||
echo "<br><i>" . __('Enter one product per line', 'cve') . "</i>";
|
||||
echo "</td>";
|
||||
|
||||
echo "</tr>";
|
||||
|
||||
$this->showFormButtons($options);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-process data before add or update
|
||||
*
|
||||
* @param array $input Data to process
|
||||
* @return array Processed data
|
||||
*/
|
||||
function prepareInputForAddOrUpdate($input) {
|
||||
// Process references from textarea to JSON
|
||||
if (isset($input['references'])) {
|
||||
$references = explode("\n", $input['references']);
|
||||
$references = array_map('trim', $references);
|
||||
$references = array_filter($references);
|
||||
$input['references'] = json_encode(array_values($references));
|
||||
}
|
||||
|
||||
// Process affected products from textarea to JSON
|
||||
if (isset($input['affected_products'])) {
|
||||
$products = explode("\n", $input['affected_products']);
|
||||
$products = array_map('trim', $products);
|
||||
$products = array_filter($products);
|
||||
$input['affected_products'] = json_encode(array_values($products));
|
||||
}
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-process input data before adding
|
||||
*
|
||||
* @param array $input Input data
|
||||
* @return array|false Processed input data or false on error
|
||||
*/
|
||||
function prepareInputForAdd($input) {
|
||||
// Set creation date if not provided
|
||||
if (!isset($input['date_creation'])) {
|
||||
$input['date_creation'] = $_SESSION['glpi_currenttime'];
|
||||
}
|
||||
|
||||
// Set default entity if not provided
|
||||
if (!isset($input['entities_id'])) {
|
||||
$input['entities_id'] = $_SESSION['glpiactive_entity'];
|
||||
}
|
||||
|
||||
// Process the input for references and affected products
|
||||
$input = $this->prepareInputForAddOrUpdate($input);
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-process input data before updating
|
||||
*
|
||||
* @param array $input Input data
|
||||
* @return array|false Processed input data or false on error
|
||||
*/
|
||||
function prepareInputForUpdate($input) {
|
||||
// Set modification date
|
||||
$input['date_mod'] = $_SESSION['glpi_currenttime'];
|
||||
|
||||
// Process the input for references and affected products
|
||||
$input = $this->prepareInputForAddOrUpdate($input);
|
||||
|
||||
return $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get search function for the class
|
||||
*
|
||||
* @return array of search options
|
||||
*/
|
||||
function rawSearchOptions() {
|
||||
$tab = [];
|
||||
|
||||
$tab[] = [
|
||||
'id' => 'common',
|
||||
'name' => self::getTypeName(2)
|
||||
];
|
||||
|
||||
$tab[] = [
|
||||
'id' => '1',
|
||||
'table' => $this->getTable(),
|
||||
'field' => 'cve_id',
|
||||
'name' => __('CVE ID', 'cve'),
|
||||
'datatype' => 'itemlink',
|
||||
'massiveaction' => false
|
||||
];
|
||||
|
||||
$tab[] = [
|
||||
'id' => '2',
|
||||
'table' => $this->getTable(),
|
||||
'field' => 'description',
|
||||
'name' => __('Description', 'cve'),
|
||||
'datatype' => 'text',
|
||||
'massiveaction' => false
|
||||
];
|
||||
|
||||
$tab[] = [
|
||||
'id' => '3',
|
||||
'table' => $this->getTable(),
|
||||
'field' => 'cvss_score',
|
||||
'name' => __('CVSS Score', 'cve'),
|
||||
'datatype' => 'decimal',
|
||||
'massiveaction' => false
|
||||
];
|
||||
|
||||
$tab[] = [
|
||||
'id' => '4',
|
||||
'table' => $this->getTable(),
|
||||
'field' => 'severity',
|
||||
'name' => __('Severity', 'cve'),
|
||||
'datatype' => 'specific',
|
||||
'searchtype' => ['equals', 'notequals']
|
||||
];
|
||||
|
||||
$tab[] = [
|
||||
'id' => '5',
|
||||
'table' => $this->getTable(),
|
||||
'field' => 'published_date',
|
||||
'name' => __('Published Date', 'cve'),
|
||||
'datatype' => 'datetime',
|
||||
'massiveaction' => false
|
||||
];
|
||||
|
||||
$tab[] = [
|
||||
'id' => '6',
|
||||
'table' => $this->getTable(),
|
||||
'field' => 'status',
|
||||
'name' => __('Status', 'cve'),
|
||||
'datatype' => 'specific',
|
||||
'searchtype' => ['equals', 'notequals']
|
||||
];
|
||||
|
||||
$tab[] = [
|
||||
'id' => '16',
|
||||
'table' => $this->getTable(),
|
||||
'field' => 'date_creation',
|
||||
'name' => __('Creation date', 'cve'),
|
||||
'datatype' => 'datetime',
|
||||
'massiveaction' => false
|
||||
];
|
||||
|
||||
$tab[] = [
|
||||
'id' => '19',
|
||||
'table' => $this->getTable(),
|
||||
'field' => 'date_mod',
|
||||
'name' => __('Last update', 'cve'),
|
||||
'datatype' => 'datetime',
|
||||
'massiveaction' => false
|
||||
];
|
||||
|
||||
return $tab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has the right to perform an action
|
||||
*
|
||||
* @param $action integer ID of the action
|
||||
* @param $right string|integer Expected right [default READ]
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
static function canAction($action, $right = READ) {
|
||||
|
||||
// Get the active entity
|
||||
$active_entity = $_SESSION['glpiactive_entity'];
|
||||
|
||||
// Check if the user can perform the action
|
||||
return Session::haveRight(self::$rightname, $right);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a ticket from a CVE
|
||||
*
|
||||
* @param integer $cves_id ID of the CVE
|
||||
* @param array $options Additional options
|
||||
*
|
||||
* @return boolean|integer ID of the created ticket or false
|
||||
*/
|
||||
function createTicket($cves_id, $options = []) {
|
||||
global $DB;
|
||||
|
||||
// Load the CVE
|
||||
$cve = new self();
|
||||
if (!$cve->getFromDB($cves_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create a new ticket
|
||||
$ticket = new Ticket();
|
||||
|
||||
// Set ticket fields
|
||||
$ticketData = [
|
||||
'entities_id' => $cve->fields['entities_id'],
|
||||
'name' => __('Vulnerability', 'cve') . ' ' . $cve->fields['cve_id'],
|
||||
'content' => __('Vulnerability details', 'cve') . ":\n\n" .
|
||||
$cve->fields['description'] . "\n\n" .
|
||||
__('References', 'cve') . ":\n" . $cve->fields['references'],
|
||||
'status' => Ticket::INCOMING,
|
||||
'date' => $_SESSION['glpi_currenttime'],
|
||||
'type' => Ticket::INCIDENT_TYPE,
|
||||
'urgency' => $this->getCVSStoPriority($cve->fields['cvss_score']),
|
||||
'impact' => $this->getCVSStoPriority($cve->fields['cvss_score']),
|
||||
'priority' => $this->getCVSStoPriority($cve->fields['cvss_score']),
|
||||
'itilcategories_id' => 0, // Default or security category if configured
|
||||
'users_id_recipient' => Session::getLoginUserID(),
|
||||
];
|
||||
|
||||
// Apply any custom options
|
||||
if (count($options)) {
|
||||
foreach ($options as $key => $val) {
|
||||
$ticketData[$key] = $val;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the ticket
|
||||
$tickets_id = $ticket->add($ticketData);
|
||||
|
||||
if ($tickets_id) {
|
||||
// Create the link between CVE and ticket
|
||||
$cveTicket = new PluginCveTicket();
|
||||
$cveTicketData = [
|
||||
'cves_id' => $cves_id,
|
||||
'tickets_id' => $tickets_id,
|
||||
'creation_type' => 'MANUAL', // Or AUTO if created by rules
|
||||
'date_creation' => $_SESSION['glpi_currenttime']
|
||||
];
|
||||
|
||||
$cveTicket->add($cveTicketData);
|
||||
|
||||
// Update CVE status to ASSIGNED if it was NEW
|
||||
if ($cve->fields['status'] == 'NEW') {
|
||||
$cve->update([
|
||||
'id' => $cves_id,
|
||||
'status' => 'ASSIGNED'
|
||||
]);
|
||||
}
|
||||
|
||||
return $tickets_id;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert CVSS score to GLPI priority
|
||||
*
|
||||
* @param float $cvss_score CVSS Score
|
||||
*
|
||||
* @return integer GLPI priority
|
||||
*/
|
||||
private function getCVSStoPriority($cvss_score) {
|
||||
// Convert CVSS score to GLPI priority (1-5)
|
||||
if ($cvss_score >= 9) {
|
||||
return 5; // Very high
|
||||
} else if ($cvss_score >= 7) {
|
||||
return 4; // High
|
||||
} else if ($cvss_score >= 4) {
|
||||
return 3; // Medium
|
||||
} else if ($cvss_score >= 1) {
|
||||
return 2; // Low
|
||||
} else {
|
||||
return 1; // Very low
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the severity class for display
|
||||
*
|
||||
* @param string $severity Severity level
|
||||
*
|
||||
* @return string CSS class
|
||||
*/
|
||||
static function getSeverityClass($severity) {
|
||||
switch ($severity) {
|
||||
case 'CRITICAL':
|
||||
return 'cve-severity-critical';
|
||||
case 'HIGH':
|
||||
return 'cve-severity-high';
|
||||
case 'MEDIUM':
|
||||
return 'cve-severity-medium';
|
||||
case 'LOW':
|
||||
return 'cve-severity-low';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the status class for display
|
||||
*
|
||||
* @param string $status Status value
|
||||
*
|
||||
* @return string CSS class
|
||||
*/
|
||||
static function getStatusClass($status) {
|
||||
switch ($status) {
|
||||
case 'NEW':
|
||||
return 'cve-status-new';
|
||||
case 'ANALYZED':
|
||||
return 'cve-status-analyzed';
|
||||
case 'ASSIGNED':
|
||||
return 'cve-status-assigned';
|
||||
case 'RESOLVED':
|
||||
return 'cve-status-resolved';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dashboard statistics data
|
||||
*
|
||||
* @return array Dashboard data
|
||||
*/
|
||||
static function getCVEStatsDashboard() {
|
||||
global $DB;
|
||||
|
||||
$stats = [];
|
||||
|
||||
// Count by severity
|
||||
$query = "SELECT severity, COUNT(*) as count
|
||||
FROM `" . self::getTable() . "`
|
||||
GROUP BY severity";
|
||||
|
||||
$result = $DB->query($query);
|
||||
|
||||
$stats['severity'] = [
|
||||
'CRITICAL' => 0,
|
||||
'HIGH' => 0,
|
||||
'MEDIUM' => 0,
|
||||
'LOW' => 0
|
||||
];
|
||||
|
||||
if ($result) {
|
||||
while ($data = $DB->fetchAssoc($result)) {
|
||||
$stats['severity'][$data['severity']] = $data['count'];
|
||||
}
|
||||
}
|
||||
|
||||
// Count by status
|
||||
$query = "SELECT status, COUNT(*) as count
|
||||
FROM `" . self::getTable() . "`
|
||||
GROUP BY status";
|
||||
|
||||
$result = $DB->query($query);
|
||||
|
||||
$stats['status'] = [
|
||||
'NEW' => 0,
|
||||
'ANALYZED' => 0,
|
||||
'ASSIGNED' => 0,
|
||||
'RESOLVED' => 0
|
||||
];
|
||||
|
||||
if ($result) {
|
||||
while ($data = $DB->fetchAssoc($result)) {
|
||||
$stats['status'][$data['status']] = $data['count'];
|
||||
}
|
||||
}
|
||||
|
||||
// Get recent CVEs (last 30 days)
|
||||
$query = "SELECT COUNT(*) as count
|
||||
FROM `" . self::getTable() . "`
|
||||
WHERE date_creation > DATE_SUB(NOW(), INTERVAL 30 DAY)";
|
||||
|
||||
$result = $DB->query($query);
|
||||
|
||||
$stats['recent'] = 0;
|
||||
|
||||
if ($result && $data = $DB->fetchAssoc($result)) {
|
||||
$stats['recent'] = $data['count'];
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get severity distribution for dashboard
|
||||
*
|
||||
* @return array Dashboard data
|
||||
*/
|
||||
static function getCVESeverityDashboard() {
|
||||
global $DB;
|
||||
|
||||
$data = [];
|
||||
|
||||
// Count by severity
|
||||
$query = "SELECT severity, COUNT(*) as count
|
||||
FROM `" . self::getTable() . "`
|
||||
GROUP BY severity";
|
||||
|
||||
$result = $DB->query($query);
|
||||
|
||||
$labels = [
|
||||
'CRITICAL' => __('Critical', 'cve'),
|
||||
'HIGH' => __('High', 'cve'),
|
||||
'MEDIUM' => __('Medium', 'cve'),
|
||||
'LOW' => __('Low', 'cve')
|
||||
];
|
||||
|
||||
$colors = [
|
||||
'CRITICAL' => '#d32f2f',
|
||||
'HIGH' => '#f57c00',
|
||||
'MEDIUM' => '#fbc02d',
|
||||
'LOW' => '#2196f3'
|
||||
];
|
||||
|
||||
if ($result) {
|
||||
$series = [];
|
||||
$series_labels = [];
|
||||
|
||||
while ($row = $DB->fetchAssoc($result)) {
|
||||
$series[] = [
|
||||
'name' => $labels[$row['severity']] ?? $row['severity'],
|
||||
'data' => [(int)$row['count']],
|
||||
'color' => $colors[$row['severity']] ?? '#999999'
|
||||
];
|
||||
$series_labels[] = $labels[$row['severity']] ?? $row['severity'];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'labels' => $series_labels,
|
||||
'series' => $series
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get recent CVEs for dashboard
|
||||
*
|
||||
* @return array Dashboard data
|
||||
*/
|
||||
static function getRecentCVEsDashboard() {
|
||||
global $DB;
|
||||
|
||||
$data = [];
|
||||
|
||||
// Get recent CVEs
|
||||
$query = "SELECT id, cve_id, severity, cvss_score, published_date, status
|
||||
FROM `" . self::getTable() . "`
|
||||
ORDER BY date_creation DESC
|
||||
LIMIT 10";
|
||||
|
||||
$result = $DB->query($query);
|
||||
|
||||
if ($result) {
|
||||
$data['headers'] = [
|
||||
__('CVE ID', 'cve'),
|
||||
__('Severity', 'cve'),
|
||||
__('CVSS', 'cve'),
|
||||
__('Published', 'cve'),
|
||||
__('Status', 'cve')
|
||||
];
|
||||
|
||||
$data['rows'] = [];
|
||||
|
||||
while ($row = $DB->fetchAssoc($result)) {
|
||||
$data['rows'][] = [
|
||||
'cve_id' => $row['cve_id'],
|
||||
'severity' => $row['severity'],
|
||||
'cvss_score' => $row['cvss_score'],
|
||||
'published' => $row['published_date'],
|
||||
'status' => $row['status']
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cron task for cleaning old CVEs
|
||||
*
|
||||
* @param CronTask $task CronTask object
|
||||
* @return integer
|
||||
*/
|
||||
static function cronCleanOldCVEs($task) {
|
||||
global $DB;
|
||||
|
||||
// Default to cleaning CVEs older than 1 year
|
||||
$retention_days = 365;
|
||||
|
||||
// Get retention configuration if exists
|
||||
$config = new Config();
|
||||
$config->getFromDBByCrit(['context' => 'plugin:cve', 'name' => 'retention_days']);
|
||||
|
||||
if (isset($config->fields['value'])) {
|
||||
$retention_days = (int)$config->fields['value'];
|
||||
}
|
||||
|
||||
// Only clean resolved CVEs
|
||||
$query = "DELETE FROM `" . self::getTable() . "`
|
||||
WHERE `status` = 'RESOLVED'
|
||||
AND `date_mod` < DATE_SUB(NOW(), INTERVAL $retention_days DAY)";
|
||||
|
||||
$result = $DB->query($query);
|
||||
|
||||
if ($result) {
|
||||
$affected = $DB->affectedRows();
|
||||
$task->addVolume($affected);
|
||||
Toolbox::logInFile('cve_plugin', "Cleaned $affected old resolved CVEs older than $retention_days days");
|
||||
|
||||
return ($affected > 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Install the plugin database schema
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
static function install(Migration $migration) {
|
||||
global $DB;
|
||||
|
||||
$table = self::getTable();
|
||||
|
||||
if (!$DB->tableExists($table)) {
|
||||
$migration->displayMessage("Installing $table");
|
||||
|
||||
$query = "CREATE TABLE IF NOT EXISTS `$table` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`cve_id` varchar(20) NOT NULL,
|
||||
`description` text DEFAULT NULL,
|
||||
`cvss_score` decimal(3,1) DEFAULT NULL,
|
||||
`cvss_vector` varchar(100) DEFAULT NULL,
|
||||
`severity` enum('LOW','MEDIUM','HIGH','CRITICAL') DEFAULT NULL,
|
||||
`published_date` datetime DEFAULT NULL,
|
||||
`modified_date` datetime DEFAULT NULL,
|
||||
`status` enum('NEW','ANALYZED','ASSIGNED','RESOLVED') DEFAULT 'NEW',
|
||||
`references` text DEFAULT NULL,
|
||||
`affected_products` text DEFAULT NULL,
|
||||
`entities_id` int(11) NOT NULL DEFAULT '0',
|
||||
`is_recursive` tinyint(1) NOT NULL DEFAULT '0',
|
||||
`date_creation` datetime DEFAULT NULL,
|
||||
`date_mod` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `cve_id` (`cve_id`),
|
||||
KEY `severity` (`severity`),
|
||||
KEY `status` (`status`),
|
||||
KEY `published_date` (`published_date`),
|
||||
KEY `cvss_score` (`cvss_score`),
|
||||
KEY `entities_id` (`entities_id`),
|
||||
KEY `date_creation` (`date_creation`),
|
||||
KEY `date_mod` (`date_mod`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci";
|
||||
|
||||
$DB->query($query) or die("Error creating $table " . $DB->error());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall the plugin database schema
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
static function uninstall(Migration $migration) {
|
||||
global $DB;
|
||||
|
||||
$table = self::getTable();
|
||||
|
||||
if ($DB->tableExists($table)) {
|
||||
$migration->displayMessage("Uninstalling $table");
|
||||
$migration->dropTable($table);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user