mirror of
https://github.com/tips-of-mine/GLPI-Plugin-CVE-Prototype.git
synced 2025-06-27 22:58:45 +02:00
494 lines
15 KiB
PHP
494 lines
15 KiB
PHP
<?php
|
|
/**
|
|
* GLPI CVE Plugin - CVE Ticket Class
|
|
* Manages links between CVEs and GLPI Tickets
|
|
*/
|
|
|
|
if (!defined('GLPI_ROOT')) {
|
|
die("Sorry. You can't access this file directly");
|
|
}
|
|
|
|
/**
|
|
* PluginCveCveTicket class for managing CVE-Ticket relations
|
|
*/
|
|
class PluginCveCveTicket extends CommonDBRelation {
|
|
|
|
// From CommonDBRelation
|
|
static public $itemtype_1 = 'PluginCveCve';
|
|
static public $items_id_1 = 'cves_id';
|
|
static public $itemtype_2 = 'Ticket';
|
|
static public $items_id_2 = 'tickets_id';
|
|
|
|
static $rightname = 'plugin_cve_ticket';
|
|
|
|
/**
|
|
* 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 Ticket', 'CVE Tickets', $nb, 'cve');
|
|
}
|
|
|
|
/**
|
|
* 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' => 'id',
|
|
'name' => __('ID', 'cve'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'number'
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '2',
|
|
'table' => 'glpi_plugin_cve_cves',
|
|
'field' => 'cve_id',
|
|
'name' => __('CVE ID', 'cve'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'dropdown',
|
|
'joinparams' => [
|
|
'jointype' => 'child',
|
|
'condition' => 'AND NEWTABLE.`id` = REFTABLE.`cves_id`'
|
|
]
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '3',
|
|
'table' => 'glpi_tickets',
|
|
'field' => 'name',
|
|
'name' => __('Ticket', 'cve'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'dropdown',
|
|
'joinparams' => [
|
|
'jointype' => 'child',
|
|
'condition' => 'AND NEWTABLE.`id` = REFTABLE.`tickets_id`'
|
|
]
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '4',
|
|
'table' => $this->getTable(),
|
|
'field' => 'creation_type',
|
|
'name' => __('Creation Type', 'cve'),
|
|
'massiveaction' => false,
|
|
'datatype' => 'specific',
|
|
'searchtype' => ['equals', 'notequals']
|
|
];
|
|
|
|
$tab[] = [
|
|
'id' => '5',
|
|
'table' => $this->getTable(),
|
|
'field' => 'date_creation',
|
|
'name' => __('Creation date', 'cve'),
|
|
'datatype' => 'datetime',
|
|
'massiveaction' => false
|
|
];
|
|
|
|
return $tab;
|
|
}
|
|
|
|
/**
|
|
* Show tickets for a CVE
|
|
*
|
|
* @param PluginCveCve $cve CVE object
|
|
* @return void
|
|
*/
|
|
static function showForCVE(PluginCveCve $cve) {
|
|
global $DB;
|
|
|
|
$ID = $cve->getField('id');
|
|
if (!$cve->can($ID, READ)) {
|
|
return false;
|
|
}
|
|
|
|
$canedit = $cve->can($ID, UPDATE);
|
|
$rand = mt_rand();
|
|
|
|
$iterator = $DB->request([
|
|
'SELECT' => [
|
|
'glpi_plugin_cve_tickets.*',
|
|
'glpi_tickets.name AS ticket_name',
|
|
'glpi_tickets.status AS ticket_status',
|
|
'glpi_tickets.date AS ticket_date',
|
|
'glpi_tickets.priority AS ticket_priority'
|
|
],
|
|
'FROM' => 'glpi_plugin_cve_tickets',
|
|
'LEFT JOIN' => [
|
|
'glpi_tickets' => [
|
|
'ON' => [
|
|
'glpi_plugin_cve_tickets' => 'tickets_id',
|
|
'glpi_tickets' => 'id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
'glpi_plugin_cve_tickets.cves_id' => $ID
|
|
],
|
|
'ORDER' => [
|
|
'glpi_tickets.date DESC'
|
|
]
|
|
]);
|
|
|
|
$tickets = [];
|
|
$used = [];
|
|
|
|
foreach ($iterator as $data) {
|
|
$tickets[$data['id']] = $data;
|
|
$used[$data['tickets_id']] = $data['tickets_id'];
|
|
}
|
|
|
|
if ($canedit) {
|
|
echo "<div class='firstbloc'>";
|
|
echo "<form name='cveticket_form$rand' id='cveticket_form$rand' method='post'
|
|
action='" . Toolbox::getItemTypeFormURL(__CLASS__) . "'>";
|
|
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr class='tab_bg_2'><th colspan='2'>" . __('Add a ticket', 'cve') . "</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td class='right'>";
|
|
echo "<input type='hidden' name='cves_id' value='$ID'>";
|
|
Ticket::dropdown([
|
|
'used' => $used,
|
|
'entity' => $cve->getEntityID(),
|
|
'entity_sons' => $cve->isRecursive(),
|
|
'displaywith' => ['id']
|
|
]);
|
|
echo "</td><td class='center'>";
|
|
echo "<input type='submit' name='add' value=\"" . _sx('button', 'Add') . "\" class='submit'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
|
|
if ($canedit && count($tickets)) {
|
|
$massiveactionparams = [
|
|
'num_displayed' => min($_SESSION['glpilist_limit'], count($tickets)),
|
|
'container' => 'mass' . __CLASS__ . $rand,
|
|
'specific_actions' => [
|
|
'purge' => _x('button', 'Delete permanently')
|
|
]
|
|
];
|
|
Html::showMassiveActions($massiveactionparams);
|
|
}
|
|
|
|
echo "<table class='tab_cadre_fixehov'>";
|
|
$header_begin = "<tr>";
|
|
$header_top = '';
|
|
$header_bottom = '';
|
|
$header_end = '';
|
|
|
|
if ($canedit && count($tickets)) {
|
|
$header_top .= "<th width='10'>" . Html::getCheckAllAsCheckbox('mass' . __CLASS__ . $rand) . "</th>";
|
|
$header_bottom .= "<th width='10'>" . Html::getCheckAllAsCheckbox('mass' . __CLASS__ . $rand) . "</th>";
|
|
}
|
|
|
|
$header_end .= "<th>" . __('Ticket', 'cve') . "</th>";
|
|
$header_end .= "<th>" . __('Status', 'cve') . "</th>";
|
|
$header_end .= "<th>" . __('Priority', 'cve') . "</th>";
|
|
$header_end .= "<th>" . __('Opening date', 'cve') . "</th>";
|
|
$header_end .= "<th>" . __('Creation type', 'cve') . "</th>";
|
|
$header_end .= "</tr>";
|
|
|
|
echo $header_begin . $header_top . $header_end;
|
|
|
|
foreach ($tickets as $data) {
|
|
echo "<tr class='tab_bg_1'>";
|
|
|
|
if ($canedit) {
|
|
echo "<td width='10'>";
|
|
Html::showMassiveActionCheckBox(__CLASS__, $data['id']);
|
|
echo "</td>";
|
|
}
|
|
|
|
$ticket = new Ticket();
|
|
$ticket->getFromDB($data['tickets_id']);
|
|
|
|
echo "<td class='center'>";
|
|
if ($ticket->can($data['tickets_id'], READ)) {
|
|
echo "<a href=\"" . Ticket::getFormURLWithID($data['tickets_id']) . "\">";
|
|
echo $data['ticket_name'] . " (" . $data['tickets_id'] . ")";
|
|
echo "</a>";
|
|
} else {
|
|
echo $data['ticket_name'] . " (" . $data['tickets_id'] . ")";
|
|
}
|
|
echo "</td>";
|
|
|
|
// Status
|
|
echo "<td class='center'>";
|
|
echo Ticket::getStatus($data['ticket_status']);
|
|
echo "</td>";
|
|
|
|
// Priority
|
|
echo "<td class='center'>";
|
|
echo Ticket::getPriorityName($data['ticket_priority']);
|
|
echo "</td>";
|
|
|
|
// Date
|
|
echo "<td class='center'>";
|
|
echo Html::convDateTime($data['ticket_date']);
|
|
echo "</td>";
|
|
|
|
// Creation type
|
|
echo "<td class='center'>";
|
|
echo $data['creation_type'] == 'AUTO' ? __('Automatic', 'cve') : __('Manual', 'cve');
|
|
echo "</td>";
|
|
|
|
echo "</tr>";
|
|
}
|
|
|
|
if ($header_bottom) {
|
|
echo $header_begin . $header_bottom . $header_end;
|
|
}
|
|
echo "</table>";
|
|
|
|
if ($canedit && count($tickets)) {
|
|
$massiveactionparams['ontop'] = false;
|
|
Html::showMassiveActions($massiveactionparams);
|
|
Html::closeForm();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show CVEs for a ticket
|
|
*
|
|
* @param Ticket $ticket Ticket object
|
|
* @return void
|
|
*/
|
|
static function showForTicket(Ticket $ticket) {
|
|
global $DB;
|
|
|
|
$ID = $ticket->getField('id');
|
|
if (!$ticket->can($ID, READ)) {
|
|
return false;
|
|
}
|
|
|
|
$canedit = $ticket->can($ID, UPDATE);
|
|
$rand = mt_rand();
|
|
|
|
$iterator = $DB->request([
|
|
'SELECT' => [
|
|
'glpi_plugin_cve_tickets.*',
|
|
'glpi_plugin_cve_cves.cve_id',
|
|
'glpi_plugin_cve_cves.severity',
|
|
'glpi_plugin_cve_cves.cvss_score',
|
|
'glpi_plugin_cve_cves.status AS cve_status'
|
|
],
|
|
'FROM' => 'glpi_plugin_cve_tickets',
|
|
'LEFT JOIN' => [
|
|
'glpi_plugin_cve_cves' => [
|
|
'ON' => [
|
|
'glpi_plugin_cve_tickets' => 'cves_id',
|
|
'glpi_plugin_cve_cves' => 'id'
|
|
]
|
|
]
|
|
],
|
|
'WHERE' => [
|
|
'glpi_plugin_cve_tickets.tickets_id' => $ID
|
|
]
|
|
]);
|
|
|
|
$cvetickets = [];
|
|
$used = [];
|
|
|
|
foreach ($iterator as $data) {
|
|
$cvetickets[$data['id']] = $data;
|
|
$used[$data['cves_id']] = $data['cves_id'];
|
|
}
|
|
|
|
if ($canedit) {
|
|
echo "<div class='firstbloc'>";
|
|
echo "<form name='ticketcve_form$rand' id='ticketcve_form$rand' method='post'
|
|
action='" . Toolbox::getItemTypeFormURL(__CLASS__) . "'>";
|
|
|
|
echo "<table class='tab_cadre_fixe'>";
|
|
echo "<tr class='tab_bg_2'><th colspan='2'>" . __('Add a CVE', 'cve') . "</th></tr>";
|
|
|
|
echo "<tr class='tab_bg_1'><td class='right'>";
|
|
echo "<input type='hidden' name='tickets_id' value='$ID'>";
|
|
|
|
$cve = new PluginCveCve();
|
|
$cve->dropdown([
|
|
'name' => 'cves_id',
|
|
'entity' => $ticket->getEntityID(),
|
|
'used' => $used
|
|
]);
|
|
|
|
echo "</td><td class='center'>";
|
|
echo "<input type='submit' name='add' value=\"" . _sx('button', 'Add') . "\" class='submit'>";
|
|
echo "</td></tr>";
|
|
|
|
echo "</table>";
|
|
Html::closeForm();
|
|
echo "</div>";
|
|
}
|
|
|
|
if ($canedit && count($cvetickets)) {
|
|
$massiveactionparams = [
|
|
'num_displayed' => min($_SESSION['glpilist_limit'], count($cvetickets)),
|
|
'container' => 'mass' . __CLASS__ . $rand,
|
|
'specific_actions' => [
|
|
'purge' => _x('button', 'Delete permanently')
|
|
]
|
|
];
|
|
Html::showMassiveActions($massiveactionparams);
|
|
}
|
|
|
|
echo "<table class='tab_cadre_fixehov'>";
|
|
$header_begin = "<tr>";
|
|
$header_top = '';
|
|
$header_bottom = '';
|
|
$header_end = '';
|
|
|
|
if ($canedit && count($cvetickets)) {
|
|
$header_top .= "<th width='10'>" . Html::getCheckAllAsCheckbox('mass' . __CLASS__ . $rand) . "</th>";
|
|
$header_bottom .= "<th width='10'>" . Html::getCheckAllAsCheckbox('mass' . __CLASS__ . $rand) . "</th>";
|
|
}
|
|
|
|
$header_end .= "<th>" . __('CVE ID', 'cve') . "</th>";
|
|
$header_end .= "<th>" . __('Severity', 'cve') . "</th>";
|
|
$header_end .= "<th>" . __('CVSS Score', 'cve') . "</th>";
|
|
$header_end .= "<th>" . __('Status', 'cve') . "</th>";
|
|
$header_end .= "<th>" . __('Creation Type', 'cve') . "</th>";
|
|
$header_end .= "</tr>";
|
|
|
|
echo $header_begin . $header_top . $header_end;
|
|
|
|
foreach ($cvetickets as $data) {
|
|
echo "<tr class='tab_bg_1'>";
|
|
|
|
if ($canedit) {
|
|
echo "<td width='10'>";
|
|
Html::showMassiveActionCheckBox(__CLASS__, $data['id']);
|
|
echo "</td>";
|
|
}
|
|
|
|
$cve = new PluginCveCve();
|
|
$cve->getFromDB($data['cves_id']);
|
|
|
|
echo "<td class='center'>";
|
|
if ($cve->can($data['cves_id'], READ)) {
|
|
echo "<a href=\"" . PluginCveCve::getFormURLWithID($data['cves_id']) . "\">";
|
|
echo $data['cve_id'];
|
|
echo "</a>";
|
|
} else {
|
|
echo $data['cve_id'];
|
|
}
|
|
echo "</td>";
|
|
|
|
// Severity
|
|
echo "<td class='center'>";
|
|
echo "<span class='" . PluginCveCve::getSeverityClass($data['severity']) . "'>";
|
|
echo $data['severity'];
|
|
echo "</span>";
|
|
echo "</td>";
|
|
|
|
// CVSS Score
|
|
echo "<td class='center'>";
|
|
echo $data['cvss_score'];
|
|
echo "</td>";
|
|
|
|
// Status
|
|
echo "<td class='center'>";
|
|
echo "<span class='" . PluginCveCve::getStatusClass($data['cve_status']) . "'>";
|
|
echo $data['cve_status'];
|
|
echo "</span>";
|
|
echo "</td>";
|
|
|
|
// Creation type
|
|
echo "<td class='center'>";
|
|
echo $data['creation_type'] == 'AUTO' ? __('Automatic', 'cve') : __('Manual', 'cve');
|
|
echo "</td>";
|
|
|
|
echo "</tr>";
|
|
}
|
|
|
|
if ($header_bottom) {
|
|
echo $header_begin . $header_bottom . $header_end;
|
|
}
|
|
echo "</table>";
|
|
|
|
if ($canedit && count($cvetickets)) {
|
|
$massiveactionparams['ontop'] = false;
|
|
Html::showMassiveActions($massiveactionparams);
|
|
Html::closeForm();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add events to ticket notifications
|
|
*
|
|
* @param array $events Events array
|
|
* @return array Modified events array
|
|
*/
|
|
static function addEvents(&$events) {
|
|
$events['cve_added'] = __('CVE linked to ticket', 'cve');
|
|
return $events;
|
|
}
|
|
|
|
/**
|
|
* 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,
|
|
`cves_id` int(11) NOT NULL,
|
|
`tickets_id` int(11) NOT NULL,
|
|
`creation_type` enum('AUTO','MANUAL') DEFAULT 'MANUAL',
|
|
`date_creation` datetime DEFAULT NULL,
|
|
PRIMARY KEY (`id`),
|
|
UNIQUE KEY `cves_id_tickets_id` (`cves_id`,`tickets_id`),
|
|
KEY `cves_id` (`cves_id`),
|
|
KEY `tickets_id` (`tickets_id`),
|
|
KEY `creation_type` (`creation_type`),
|
|
KEY `date_creation` (`date_creation`)
|
|
) 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;
|
|
}
|
|
} |