mirror of
https://github.com/tips-of-mine/GLPI-Plugin-CVE-Prototype.git
synced 2025-06-27 22:58:45 +02:00
752 lines
22 KiB
PHP
752 lines
22 KiB
PHP
<?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;
|
|
}
|
|
} |