Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

## [UNRELEASED]

### Fixed
### Added

- Add Links for uninstall templates From Item Form
- Fix SQL errors when uninstalling or replacing peripheral assets
- Fix locales encoding

Expand Down
174 changes: 144 additions & 30 deletions inc/uninstall.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
use Glpi\Asset\Asset_PeripheralAsset;

use function Safe\preg_grep;

/**
* -------------------------------------------------------------------------
* Uninstall plugin for GLPI
Expand Down Expand Up @@ -60,6 +59,10 @@
* -------------------------------------------------------------------------
*/

use function Safe\json_encode;
use function Safe\ob_end_clean;
use function Safe\ob_start;

class PluginUninstallUninstall extends CommonDBTM
{
public const PLUGIN_UNINSTALL_TRANSFER_NAME = "plugin_uninstall";
Expand Down Expand Up @@ -924,13 +927,13 @@ public static function getInfocomPresentForDevice($type, $ID)
* @param $ID
* @param $item
* @param $user_id
**/
public static function showFormUninstallation($ID, $item, $user_id)
**/
public static function showFormUninstallation($ID, $item, $user_id, $templates_id = 0)
{
/**
* @var array $CFG_GLPI
*/
global $CFG_GLPI;
global $CFG_GLPI, $DB;

$type = $item->getType();
echo "<form action='" . $CFG_GLPI['root_doc'] . "/plugins/uninstall/front/action.php'
Expand All @@ -941,41 +944,152 @@ public static function showFormUninstallation($ID, $item, $user_id)

echo "<tr class='tab_bg_1'><td>" . __s("Model") . "</td><td>";
if (class_exists($type) && is_a($type, CommonDBTM::class, true)) {

$item = new $type();
$item->getFromDB($ID);
$rand = self::dropdownUninstallModels(
"model_id",
$_SESSION["glpiID"],
$item->fields["entities_id"],
);

if ($templates_id == 0) {
$rand = self::dropdownUninstallModels(
"model_id",
$_SESSION["glpiID"],
$item->fields["entities_id"],
);
} else {
$used = [];
if (!PluginUninstallModel::canReplace()) {
$used = array_column(
iterator_to_array(
$DB->request([
'SELECT' => ['id'],
'FROM' => 'glpi_plugin_uninstall_models',
'WHERE' => [
'types_id' => [2, 3],
],
]),
),
'id',
);
}

$rand = PluginUninstallModel::dropdown([
'name' => "model_id",
'value' => $templates_id,
'entity' => $item->fields["entities_id"],
'used' => $used,
]);
}


echo "</td></tr>";
if ($templates_id == 0) {
$params = [
'templates_id' => '__VALUE__',
'entity' => $item->fields["entities_id"],
'users_id' => $_SESSION["glpiID"],
];

Ajax::updateItemOnSelectEvent(
'dropdown_model_id' . $rand,
"show_objects",
$CFG_GLPI['root_doc'] . "/plugins/uninstall/ajax/locations.php",
$params,
);
}

$params = ['templates_id' => '__VALUE__',
'entity' => $item->fields["entities_id"],
'users_id' => $_SESSION["glpiID"],
];
echo "<tr class='tab_bg_1'><td>" . __s("Item's location after applying model", "uninstall") . "</td>";
if ($templates_id == 0) {
echo "<td><span id='show_objects'>\n" . Dropdown::EMPTY_VALUE . "</span></td>\n";
} else {
echo "<td>";
$location = PluginUninstallPreference::getLocationByUserByEntity(
$user_id,
$templates_id,
$item->fields["entities_id"],
);
Location::dropdown([
'value' => ($location == '' ? 0 : $location),
'comments' => 1,
'entity' => $item->fields["entities_id"],
'toadd' => [
-1 => __('Keep previous location', 'uninstall'),
0 => __s('Empty location', 'uninstall'),
],
]);
echo "</td>";
}

Ajax::updateItemOnSelectEvent(
'dropdown_model_id' . $rand,
"show_objects",
$CFG_GLPI['root_doc'] . "/plugins/uninstall/ajax/locations.php",
$params,
);
echo "</tr>";

echo "<tr class='tab_bg_1 center'><td colspan='3'>";
echo "<input type='submit' name='uninstall' value=\"" . _sx('button', 'Post') . "\"
class='submit'>";
echo "<input type='hidden' name='id' value='" . $ID . "'>";
echo "</td></tr>";
echo "</table>";
Html::closeForm();
}
}

echo "<tr class='tab_bg_1'><td>" . __s("Item's location after applying model", "uninstall") . "</td>";
echo "<td><span id='show_objects'>\n" . Dropdown::EMPTY_VALUE . "</span></td>\n";
echo "</tr>";
public static function showLinksUninstallation(
$params,
) {
/**
* @var array $UNINSTALL_TYPES
*/
global $DB, $UNINSTALL_TYPES;

echo "<tr class='tab_bg_1 center'><td colspan='3'>";
echo "<input type='submit' name='uninstall' value=\"" . _sx('button', 'Post') . "\"
class='submit'>";
echo "<input type='hidden' name='id' value='" . $ID . "'>";
echo "</td></tr>";
echo "</table>";
Html::closeForm();
$right = Session::haveRight(self::$rightname, READ);

$users_id = Session::getLoginUserID();
$item = $params['item'];
if ($right
&& in_array($item->getType(), $UNINSTALL_TYPES) && $item->getID() > 0) {
echo "<div class='form-button-separator card-body mx-n2 border-top d-flex flex-row-reverse align-items-start flex-wrap'>";

$criteria = [
"FROM" => 'glpi_plugin_uninstall_models',
];

if (!PluginUninstallModel::canReplace()) {
$criteria['WHERE'] = ['NOT' => ['types_id' => [2, 3]]];
}


$iterator = $DB->request($criteria);
foreach ($iterator as $data) {

$templates_id = $data['id'];
echo "<a href='#' id='" . $templates_id . "' class='btn btn-primary me-2'>"
. $data['name']
. "</a>";
Comment on lines +1061 to +1063
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The value of $data['name'] comes from the database and is rendered without proper escaping. It should be sanitized using __s(), to prevent potential security issues such as XSS.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The best approach would be to switch to Twig to remove all the echo statements from the function


// get form for uninstall actions
ob_start();
self::showFormUninstallation($item->getID(), $item, $users_id, $templates_id);
$html_modal = ob_get_contents();
ob_end_clean();
Comment on lines +1066 to +1069
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using output buffering to capture HTML from a method that relies on echo is a fragile pattern and should be avoided.


// we json encore to pass it to js (auto-escaping)

$modal_body = json_encode($html_modal);

$JS = <<<JAVASCRIPT
$(function() {
$("#{$templates_id}").on("click", function(event) {
event.preventDefault();

glpi_html_dialog({
body: {$modal_body}
})
});
});
JAVASCRIPT;
echo Html::scriptBlock($JS);
}

echo "</div>";
}

return null;
}


Expand Down
4 changes: 4 additions & 0 deletions setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ function plugin_init_uninstall()
$PLUGIN_HOOKS[Hooks::PRE_ITEM_ADD]['uninstall'] = [Config::class => PluginUninstallConfig::preConfigSet(...)];
$PLUGIN_HOOKS[Hooks::PRE_ITEM_UPDATE]['uninstall'] = [Config::class => PluginUninstallConfig::preConfigSet(...)];

if (!$uninstallconfig['replace_status_dropdown']) {
$PLUGIN_HOOKS[Hooks::POST_ITEM_FORM]['uninstall'] = PluginUninstallUninstall::showLinksUninstallation(...);
}

$PLUGIN_HOOKS[Hooks::STALE_AGENT_CONFIG]['uninstall'] = [
[
'label' => __s('Apply uninstall profile'),
Expand Down