Compare commits

..

1 Commits

Author SHA1 Message Date
Benjamin DALSASS
f049a364bd N°8638 - Adapt mysqldump calls to follow iTop SSL configuration 2026-04-13 15:19:33 +02:00
12 changed files with 40 additions and 185 deletions

View File

@@ -1546,21 +1546,12 @@ class ShortcutMenuNode extends MenuNode
public function GetHyperlink($aExtraParams)
{
$sContext = $this->oShortcut->Get('context');
try {
$aContext = utils::Unserialize($sContext);
if (isset($aContext['menu'])) {
unset($aContext['menu']);
}
foreach ($aContext as $sArgName => $sArgValue) {
$aExtraParams[$sArgName] = $sArgValue;
}
} catch (Exception $e) {
IssueLog::Warning("User shortcut corrupted, delete the shortcut", LogChannels::CONSOLE, [
'shortcut_name' => $this->oShortcut->GetName(),
'root_cause' => $e->getMessage(),
]);
// delete the shortcut
$this->oShortcut->DBDelete();
$aContext = unserialize($sContext);
if (isset($aContext['menu'])) {
unset($aContext['menu']);
}
foreach ($aContext as $sArgName => $sArgValue) {
$aExtraParams[$sArgName] = $sArgValue;
}
return parent::GetHyperlink($aExtraParams);
}

View File

@@ -3252,50 +3252,4 @@ TXT
return $aTrace;
}
/**
* PHP unserialize encapsulation, allow throwing exception when not allowed object class is detected (for security hardening)
*
* @param string $data data to unserialize
* @param array $aOptions PHP @unserialise options
* @param bool $bThrowNotAllowedObjectClassException flag to throw exception
*
* @return mixed PHP @unserialise return
* @throws Exception
*/
public static function Unserialize(string $data, array $aOptions = ['allowed_classes' => false], bool $bThrowNotAllowedObjectClassException = true): mixed
{
$data = unserialize($data, $aOptions);
if ($bThrowNotAllowedObjectClassException) {
try {
self::AssertNoIncompleteClassDetected($data);
} catch (Exception $e) {
throw new CoreException('Unserialization failed because an incomplete class was detected.', [], '', $e);
}
}
return $data;
}
/**
* Assert that data provided doesn't contain any incomplete class.
*
* @throws Exception
*/
public static function AssertNoIncompleteClassDetected(mixed $data): void
{
if (is_object($data)) {
if ($data instanceof __PHP_Incomplete_Class) {
throw new Exception('__PHP_Incomplete_Class_Name object detected');
}
foreach (get_object_vars($data) as $property) {
self::AssertNoIncompleteClassDetected($property);
}
} elseif (is_array($data)) {
foreach ($data as $value) {
self::AssertNoIncompleteClassDetected($value);
}
}
}
}

View File

@@ -4829,7 +4829,7 @@ class AttributeCaseLog extends AttributeLongText
}
if (strlen($sIndex) > 0) {
$aIndex = utils::Unserialize($sIndex, ['allowed_classes' => false], false);
$aIndex = unserialize($sIndex);
$value = new ormCaseLog($sLog, $aIndex);
} else {
$value = new ormCaseLog($sLog);

View File

@@ -1592,6 +1592,8 @@ class CMDBSource
if (static::GetDBVendor() === static::ENUM_DB_VENDOR_MYSQL) {
//Mysql 5.7.0 and upper deprecated --ssl and uses --ssl-mode instead
return version_compare(static::GetDBVersion(), '5.7.11', '>=');
} elseif (static::GetDBVendor() === static::ENUM_DB_VENDOR_MARIADB) {
return version_compare(static::GetDBVersion(), '10.2.6', '>=');
}
return false;
}

View File

@@ -1157,7 +1157,7 @@ class UserRights
return self::$m_oUser->GetKey();
} else {
// find the id out of the login string
$oUser = self::FindUser($sLogin, bAllowDisabledUsers: true);
$oUser = self::FindUser($sLogin);
if (is_null($oUser)) {
return null;
}

View File

@@ -201,9 +201,8 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
}
// N°7982 Default selectize stylesheet override
// N°9468 Dropdown content needs to be a few pixel shorter than the dropdown itself to avoid double scrollbar
.selectize-dropdown-content{
max-height: calc(#{$ibo-input-select-selectize--dropdown--max-height} - 4px);
max-height: $ibo-input-select-selectize--dropdown--max-height;
}
.selectize-dropdown.ui-menu .ui-state-active {

View File

@@ -120,7 +120,6 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
this.sFormAttCode = sFormAttCode;
var me = this;
const iDropdownContentHeightDifference = 4;
this.Init = function () {
// make sure that the form is clean
@@ -172,7 +171,7 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
// To avoid dropdown to be cut by the container's overflow hidden rule
dropdownParent: 'body',
onDropdownOpen: function (oDropdownElem) {
me.UpdateDropdownPosition(this.$control, oDropdownElem, this.$dropdown_content);
me.UpdateDropdownPosition(this.$control, oDropdownElem);
},
});
let $selectize = $select[0].selectize; // This stores the selectize object to a variable (with name 'selectize')
@@ -315,14 +314,13 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
};
/**
* Update the dropdown's position so it always fits in the screen
*
* @param {object} oControlElem jQuery object representing the "control" input (= where the user types) of the external key
* @param {object} oDropdownElem jQuery object representing the results dropdown
* @param {object|undefined} oDropdownContentElem
* @return {void}
*/
this.UpdateDropdownPosition = function (oControlElem, oDropdownElem, oDropdownContentElem) {
* Update the dropdown's position so it always fits in the screen
*
* @param {object} oControlElem jQuery object representing the "control" input (= where the user types) of the external key
* @param {object} oDropdownElem jQuery object representing the results dropdown
* @return {void}
*/
this.UpdateDropdownPosition = function (oControlElem, oDropdownElem) {
// First fix width to ensure it's not too long
const fControlWidth = oControlElem.outerWidth();
oDropdownElem.css('width', fControlWidth);
@@ -330,13 +328,6 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
// Then, fix height / position to ensure it's within the viewport
const fWindowHeight = window.innerHeight;
// Clear previously set rule so the comparison is done with dropdown real height
oDropdownElem.css('max-height', '');
if(oDropdownContentElem) {
oDropdownContentElem.css('max-height', '');
}
const fControlTopY = oControlElem.offset().top;
const fControlHeight = oControlElem.outerHeight();
@@ -347,38 +338,14 @@ function ExtKeyWidget(id, sTargetClass, sFilter, sTitle, bSelectMode, oWizHelper
if (fDropdownBottomY > fWindowHeight) {
// Set dropdown max-height to 1/3 of the screen, this way we are sure the dropdown will fit in either the top / bottom half of the screen
oDropdownElem.css({
maxHeight: '30vh',
});
oDropdownElem.css('max-height', '30vh');
fDropdownHeight = oDropdownElem.outerHeight();
// N°9468 Dropdown content needs to be a few pixel shorter than the dropdown itself to avoid double scrollbar
if(oDropdownContentElem) {
oDropdownContentElem.css('max-height', `calc(30vh - ${iDropdownContentHeightDifference}px)`);
}
/* Position dropdown above input if not enough space on the bottom part of the screen
Doesn't seem to work with selectize as an internal plugin "auto_position" refreshes the top position after
this method is called, input set use a custom plugin to avoid fix this issue "plugin_combodo_auto_position"
This would need to take the potential 4px difference (iDropdownContentHeightDifference) into account if this is fixed.
*/
// Position dropdown above input if not enough space on the bottom part of the screen
if ((fDropdownTopY / fWindowHeight) > 0.6) {
oDropdownElem.css({
top: fDropdownTopY - fDropdownHeight - fControlHeight,
borderTop: oDropdownElem.css('border-bottom')
});
}
else {
oDropdownElem.css({
borderTop: 'none'
})
}
oDropdownElem.css('top', fDropdownTopY - fDropdownHeight - fControlHeight);
}
}
else {
oDropdownElem.css({
borderTop: 'none'
})
}
};
this.ManageScroll = function () {
if ($('#label_'+me.id).scrollParent()[0].tagName != 'HTML') {

View File

@@ -19,11 +19,10 @@ Selectize.define("combodo_auto_position", function (aOptions) {
// Selectize instance
let oSelf = this;
const iDropdownContentHeightDifference = 4;
// Plugin options
aOptions = $.extend({
maxDropDownHeight: '200px',
maxDropDownHeight: 200,
},
aOptions
);
@@ -34,47 +33,28 @@ Selectize.define("combodo_auto_position", function (aOptions) {
// Override position dropdown function
oSelf.positionDropdown = (function () {
return function () {
// Clear previously set rules so the comparison is done with dropdown real height
oSelf.$dropdown.css({
'max-height': '',
});
let iRefHeight = oSelf.$dropdown.outerHeight() < aOptions.maxDropDownHeight ?
oSelf.$dropdown.outerHeight() : aOptions.maxDropDownHeight;
oSelf.$dropdown_content.css({
'max-height': '',
});
if(oSelf.$control.offset().top + oSelf.$control.outerHeight() + iRefHeight > window.innerHeight){
let iDropdownHeight = oSelf.$dropdown.outerHeight();
if(oSelf.$control.offset().top + oSelf.$control.outerHeight() + iDropdownHeight > window.innerHeight){
// Apply max-height as we are overflowing, that'll allow us to calculate where we should place ourselves later
oSelf.$dropdown.css({
maxHeight: `${aOptions.maxDropDownHeight}`,
})
iDropdownHeight = oSelf.$dropdown.outerHeight();
oSelf.$dropdown.css({
top: oSelf.$control.offset().top - iDropdownHeight + iDropdownContentHeightDifference, // Content will be shorter, so our real height too
left: oSelf.$control.offset().left,
oSelf.$dropdown.css({
top: oSelf.$control.offset().top - iRefHeight,
left: oSelf.$control.offset().left,
width: oSelf.$wrapper.outerWidth(),
overflowY: 'auto',
borderTop : oSelf.$dropdown.css('border-bottom')
'max-height': `${aOptions.maxDropDownHeight}px`,
'overflow-y': 'auto',
'border-top': '1px solid #d0d0d0',
});
// N°9468 Dropdown content needs to be a few pixel shorter than the dropdown itself to avoid double scrollbar
oSelf.$dropdown_content.css({
'max-height': `calc(${aOptions.maxDropDownHeight} - ${iDropdownContentHeightDifference}px)`
});
}
else{
oSelf.$dropdown.css({
top: oSelf.$control.offset().top + oSelf.$control.outerHeight(),
left: oSelf.$control.offset().left,
width: oSelf.$wrapper.outerWidth(),
overflowY: 'auto',
borderTop: 'none'
});
'max-height': `${aOptions.maxDropDownHeight}px`,
'overflow-y': 'auto'
});
}
};
}());

View File

@@ -511,7 +511,7 @@ EOF;
{
$bDbTlsEnabled = $oConfig->Get('db_tls.enabled');
if (!$bDbTlsEnabled) {
return '';
return CMDBSource::IsSslModeDBVersion() ? ' --skip-ssl' : '';
}
$sTlsOptions = '';
// Mysql 5.7.11 and upper deprecated --ssl and uses --ssl-mode instead

View File

@@ -8,13 +8,8 @@ use AttributeFriendlyName;
use AttributeLinkedSet;
use cmdbAbstract;
use cmdbAbstractObject;
use CoreException;
use Dict;
use Exception;
use IssueLog;
use LogChannels;
use Metamodel;
use utils;
/**
* Class DataTableSettings
@@ -135,10 +130,7 @@ class DataTableSettings
*/
public function unserialize($sData)
{
$aData = utils::Unserialize($sData);
if (!is_array($aData)) {
throw new CoreException('Wrong data table settings format, expected an array', ['datatable_settings_data' => $aData]);
}
$aData = unserialize($sData);
$this->iDefaultPageSize = $aData['iDefaultPageSize'];
$this->aColumns = $aData['aColumns'];
foreach ($this->aClassAliases as $sAlias => $sClass) {
@@ -277,19 +269,7 @@ class DataTableSettings
return null;
}
}
try {
$oSettings->unserialize($pref);
} catch (Exception $e) {
IssueLog::Warning("User table settings corrupted, back to the default values provided by the data model", LogChannels::CONSOLE, [
'table_id' => $sTableId,
'root_cause' => $e->getMessage(),
]);
// unset the preference
appUserPreferences::UnsetPref($oSettings->GetPrefsKey($sTableId));
// use the default values provided by the data model
return null;
}
$oSettings->unserialize($pref);
return $oSettings;
}

View File

@@ -23,7 +23,7 @@ let oWidget{{ oUIBlock.GetId() }} = $('#{{ oUIBlock.GetId() }}').selectize({
},
{# PLUGIN combodo auto position #}
'combodo_auto_position' : {
maxDropDownHeight: '30vh', {# same value as external key widget #}
maxDropDownHeight: 300, {# in px #}
},
{# PLUGIN combodo add button #}
{% if oUIBlock.HasAddOptionButton() %}

View File

@@ -23,7 +23,6 @@
namespace Combodo\iTop\Test\UnitTest\Application;
use Combodo\iTop\Test\UnitTest\ItopTestCase;
use CoreException;
use ormDocument;
use utils;
@@ -1044,21 +1043,4 @@ INI;
unlink($sTmpFileOutsideItop);
}
public function testUnserialize()
{
// data to unserialize containing an object
$sData = 'a:2:{s:6:"string";s:9:"My string";s:6:"object";O:8:"DateTime":3:{s:4:"date";s:26:"2026-04-13 09:09:23.033175";s:13:"timezone_type";i:3;s:8:"timezone";s:16:"Europe/Amsterdam";}}';
// allow the DateTime object (no exception triggered)
utils::Unserialize($sData, ['allowed_classes' => ['DateTime']]);
// flag to avoid throwing an exception
utils::Unserialize($sData, ['allowed_classes' => false], false);
// flag to require throwing an exception
$this->expectException(CoreException::class);
utils::Unserialize($sData);
}
}