mirror of
https://github.com/Combodo/iTop.git
synced 2026-03-04 00:24:14 +01:00
Compare commits
8 Commits
issue/8543
...
feature/69
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86133b52b2 | ||
|
|
e47556e73e | ||
|
|
8f39d07271 | ||
|
|
43fc6f8d4e | ||
|
|
e0dfab0575 | ||
|
|
ec00c052dd | ||
|
|
4be4c9f673 | ||
|
|
f0e6224a2b |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -58,9 +58,6 @@ tests/*/vendor/*
|
||||
/tests/php-unit-tests/phpunit.xml
|
||||
/tests/php-unit-tests/postbuild_integration.xml
|
||||
|
||||
# PHP CS Fixer: Cache file
|
||||
/.php-cs-fixer.cache
|
||||
|
||||
|
||||
# Jetbrains
|
||||
/.idea/**
|
||||
|
||||
@@ -181,9 +181,6 @@ class utils
|
||||
|
||||
protected static function LoadParamFile($sParamFile)
|
||||
{
|
||||
if (utils::RealPath($sParamFile, APPROOT) !== false) {
|
||||
throw new Exception("File '".utils::HtmlEntities($sParamFile)."' should be outside iTop");
|
||||
}
|
||||
if (!file_exists($sParamFile)) {
|
||||
throw new Exception("Could not find the parameter file: '".utils::HtmlEntities($sParamFile)."'");
|
||||
}
|
||||
|
||||
@@ -1738,14 +1738,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'security.force_login_when_no_execution_policy' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true, when no execution policy is defined, the user will be forced to log in (instead of being automatically logged in with the default profile)',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
],
|
||||
'behind_reverse_proxy' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true, then proxies custom header (X-Forwarded-*) are taken into account. Use only if the webserver is not publicly accessible (reachable only by the reverse proxy)',
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\Helper\ExportHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
@@ -13,7 +14,6 @@ use Combodo\iTop\Application\UI\Base\Component\Input\Select\SelectUIBlockFactory
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\Helper\ExportHelper;
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
@@ -55,6 +55,8 @@ class CSVBulkExport extends TabularBulkExport
|
||||
$this->aStatusInfo['charset'] = strtoupper(utils::ReadParam('charset', 'UTF-8', true, 'raw_data'));
|
||||
$this->aStatusInfo['formatted_text'] = (bool)utils::ReadParam('formatted_text', 0, true);
|
||||
|
||||
$this->aStatusInfo['ignore_excel_sanitization'] = (bool)utils::ReadParam('ignore_excel_sanitization', 0, true, utils::ENUM_SANITIZATION_FILTER_INTEGER);
|
||||
|
||||
$sDateFormatRadio = utils::ReadParam('csv_date_format_radio', '');
|
||||
switch ($sDateFormatRadio) {
|
||||
case 'default':
|
||||
@@ -223,6 +225,10 @@ class CSVBulkExport extends TabularBulkExport
|
||||
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oFieldSetDate->AddSubBlock($oRadioCustom);
|
||||
|
||||
$oFieldSetSecurity = FieldSetUIBlockFactory::MakeStandard(Dict::S('Core:BulkExport:Security'));
|
||||
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oFieldSetSecurity));
|
||||
$oFieldSetSecurity->AddSubBlock(ExportHelper::GetInputForSanitizeExcelExport());
|
||||
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#form_part_csv_options').on('preview_updated', function() { FormatDatesInPreview('csv', 'csv'); });
|
||||
@@ -264,6 +270,13 @@ EOF
|
||||
default:
|
||||
$sRet = trim($oObj->GetAsCSV($sAttCode), '"');
|
||||
}
|
||||
|
||||
// If the option to ignore Excel sanitization is not set or explicitly set to false, apply sanitization
|
||||
if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) {
|
||||
return ExportHelper::SanitizeField($sRet, $this->aStatusInfo['text_qualifier'] ?? '');
|
||||
}
|
||||
|
||||
// The option to ignore Excel sanitization is explicitly set to true: return the raw value without sanitization
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
@@ -337,6 +350,12 @@ EOF
|
||||
$sField = $oObj->GetAsCSV($sAttCode, $this->aStatusInfo['separator'], $this->aStatusInfo['text_qualifier'], $this->bLocalizeOutput, !$this->aStatusInfo['formatted_text']);
|
||||
}
|
||||
}
|
||||
|
||||
// If the option to ignore Excel sanitization is not set or absent, sanitize the field
|
||||
if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) {
|
||||
$sField = ExportHelper::SanitizeField($sField, $this->aStatusInfo['text_qualifier']);
|
||||
}
|
||||
|
||||
if ($this->aStatusInfo['charset'] != 'UTF-8') {
|
||||
// Note: due to bugs in the glibc library it's safer to call iconv on the smallest possible string
|
||||
// and thus to convert field by field and not the whole row or file at once (see ticket N°991)
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\Helper\ExportHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\FieldSet\FieldSetUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Html\Html;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Panel\PanelUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\Column\ColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Layout\MultiColumn\MultiColumnUIBlockFactory;
|
||||
use Combodo\iTop\Application\Helper\ExportHelper;
|
||||
use Combodo\iTop\Application\WebPage\Page;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
@@ -63,6 +63,8 @@ class ExcelBulkExport extends TabularBulkExport
|
||||
// Export from the command line (or scripted) => default format is SQL, as in previous versions of iTop, unless specified otherwise
|
||||
$this->aStatusInfo['date_format'] = utils::ReadParam('date_format', (string)AttributeDateTime::GetSQLFormat(), true, 'raw_data');
|
||||
}
|
||||
|
||||
$this->aStatusInfo['ignore_excel_sanitization'] = (bool)utils::ReadParam('ignore_excel_sanitization', 0, true, utils::ENUM_SANITIZATION_FILTER_INTEGER);
|
||||
}
|
||||
|
||||
public function EnumFormParts()
|
||||
@@ -121,6 +123,10 @@ class ExcelBulkExport extends TabularBulkExport
|
||||
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oFieldSetDate->AddSubBlock($oRadioCustom);
|
||||
|
||||
$oFieldSetSecurity = FieldSetUIBlockFactory::MakeStandard(Dict::S('Core:BulkExport:Security'));
|
||||
$oMulticolumn->AddColumn(ColumnUIBlockFactory::MakeForBlock($oFieldSetSecurity));
|
||||
$oFieldSetSecurity->AddSubBlock(ExportHelper::GetInputForSanitizeExcelExport());
|
||||
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#form_part_xlsx_options').on('preview_updated', function() { FormatDatesInPreview('excel', 'xlsx'); });
|
||||
@@ -216,6 +222,12 @@ EOF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the option to ignore Excel sanitization is not set or absent, sanitize the field
|
||||
if (!(array_key_exists('ignore_excel_sanitization', $this->aStatusInfo)) || $this->aStatusInfo['ignore_excel_sanitization'] === false) {
|
||||
return ExportHelper::SanitizeField($sRet, '');
|
||||
}
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,3 +4,4 @@
|
||||
*/
|
||||
|
||||
@import "bulk-modify";
|
||||
@import "bulk-export";
|
||||
|
||||
10
css/backoffice/application/bulk/_bulk-export.scss
Normal file
10
css/backoffice/application/bulk/_bulk-export.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
#form_part_csv_options:has(#ibo-sanitize-excel-export--input:checked), #form_part_xlsx_options:has(#ibo-sanitize-excel-export--input:checked){
|
||||
#ibo-sanitize-excel-export--alert {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -199,15 +199,15 @@ function RaiseAlarm($sMessage)
|
||||
//////////
|
||||
// Main
|
||||
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
echo "Error: ".$e->GetMessage()."\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if (utils::IsModeCLI()) {
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
echo 'Error: '.$e->GetMessage()."\n";
|
||||
exit;
|
||||
}
|
||||
$oP = new CLIPage('Check backup utility');
|
||||
SetupUtils::CheckPhpAndExtensionsForCli($oP);
|
||||
SetupUtils::CheckPhpAndExtensionsForCli(new CLIPage('Check backup utility'));
|
||||
|
||||
echo date('Y-m-d H:i:s')." - running check-backup utility\n";
|
||||
try {
|
||||
|
||||
@@ -88,15 +88,16 @@ if (utils::IsModeCLI()) {
|
||||
$oP = new CLIPage(GetOperationName());
|
||||
|
||||
SetupUtils::CheckPhpAndExtensionsForCli($oP);
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
ExitError($oP, $e->GetMessage());
|
||||
}
|
||||
} else {
|
||||
$oP = new WebPage(GetOperationName());
|
||||
}
|
||||
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
ExitError($oP, $e->GetMessage());
|
||||
}
|
||||
|
||||
ExecuteMainOperation($oP);
|
||||
|
||||
$oP->output();
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'Dieses Attribut kann in einer Massenänderung nicht bearbeitet werden.',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel-Sicherheitswarnung',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Das Öffnen einer Datei mit nicht vertrauenswürdigen Daten in Microsoft Excel kann zu einer Formel-Injektion führen. Stellen Sie sicher, dass Ihre Excel-Einstellungen so konfiguriert sind, dass Dateien sicher verarbeitet werden. <a href="%1$s">Erfahren Sie mehr in unserer Dokumentation.</a>',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -24,4 +24,7 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.',
|
||||
'Core:BulkExport:Security' => 'Security',
|
||||
]);
|
||||
|
||||
@@ -11,4 +11,7 @@ Dict::Add('EN GB', 'British English', 'British English', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.',
|
||||
'Core:BulkExport:Security' => 'Security',
|
||||
]);
|
||||
|
||||
@@ -12,4 +12,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'Este atributo no se puede editar en contexto masivo',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Advertencia de seguridad de Excel',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Abrir un archivo con datos que no son de confianza en Microsoft Excel puede provocar la inyección de fórmulas. Asegúrese de que la configuración de Excel esté configurada para manejar archivos de forma segura. <a href="%1$s">Obtenga más información en nuestra documentación.</a>',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'Cet attribut ne peut être édité dans une modification en masse',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Avertissement sur la sécurité d\'Excel',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'L\'ouverture d\'un fichier contenant des données non fiables dans Microsoft Excel peut entraîner l\'injection de formules. Assurez-vous que vos paramètres Excel sont configurés pour traiter les fichiers en toute sécurité. <a href="%1$s">Pour en savoir plus, consultez notre documentation.</a>',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitiser les valeurs potentiellement dangereuses',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'Lorsqu\'elle est activée, les valeurs potentiellement dangereuses seront sanitizées lors de l\'exportation. Cela empêchera Microsoft Excel de les interpréter comme des formules. Notez que cela peut altérer les données originales en les préfixant avec une simple quote (\') pour s\'assurer qu\'elles soient traitées comme du texte.',
|
||||
'Core:BulkExport:Security' => 'Sécurité',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'Questo attributo non può essere modificato nel contesto di modifica bulk',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Avviso di sicurezza di Excel',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'L\'apertura di un file con dati non fidati in Microsoft Excel potrebbe comportare l\'iniezione di formule. Assicurati che le impostazioni di Excel siano configurate per gestire i file in modo sicuro. <a href="%1$s">Ulteriori informazioni nella nostra documentazione.</a>',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'Tego atrybutu nie można edytować zbiorczo',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Ostrzeżenie dotyczące bezpieczeństwa programu Excel',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Otwarcie pliku z niezaufanymi danymi w programie Microsoft Excel może spowodować wstrzyknięcie formuły. Upewnij się, że ustawienia programu Excel są skonfigurowane tak, aby bezpiecznie obsługiwać pliki. <a href="%1$s">Dowiedz się więcej w naszej dokumentacji.</a>',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -14,4 +14,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => 'This attribute can\'t be edited in bulk context~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel security warning~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => 'Opening a file with untrusted data in Microsoft Excel may lead to formula injection. Ensure that your Excel settings are configured to handle files safely. <a href="%1$s">Learn more in our documentation.</a>~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -23,4 +23,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
||||
'UI:Bulk:modify:IncompatibleAttribute' => '此属性无法在批量操作中编辑',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Title' => 'Excel 安全警告',
|
||||
'UI:Bulk:Export:MaliciousInjection:Alert:Message' => '在 Microsoft Excel 中打开不信任的文件可能导致公式注入. 请确保 Excel 设置能够安全的处理该文件. <a href="%1$s">进入我们的文档了解更多.</a>',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Label' => 'Sanitize potentially dangerous values~~',
|
||||
'UI:Bulk:Export:MaliciousInjection:Input:Tooltip' => 'When enabled, potentially dangerous values will be sanitized during export. This will prevent Microsoft Excel from interpreting them as formulas. Note that this may alter the original data by prefixing it with a single quote (\') to ensure it is treated as text.~~',
|
||||
'Core:BulkExport:Security' => 'Security~~',
|
||||
]);
|
||||
|
||||
@@ -487,6 +487,12 @@ function ExportStartExport() {
|
||||
oParams.expression = $('#export-form :input[name=expression]').val();
|
||||
oParams.query = $('#export-form :input[name=query]').val();
|
||||
}
|
||||
|
||||
// Read the "sanitize_excel_export" checkbox if it exists, and set the corresponding "ignore_excel_sanitization" parameter
|
||||
if($(':input[name=sanitize_excel_export]').length > 0) {
|
||||
oParams.ignore_excel_sanitization = $(':input[name=sanitize_excel_export]').is(':checked') ? 0 : 1;
|
||||
}
|
||||
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function (data) {
|
||||
if (data == null) {
|
||||
ExportError('Export failed (no data provided), please contact your administrator');
|
||||
|
||||
@@ -97,29 +97,4 @@ if ($sTargetPage === false) {
|
||||
//
|
||||
// GO!
|
||||
//
|
||||
// check module white list
|
||||
// check conf param
|
||||
// force login if needed
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
|
||||
$aModuleDelegatedExecutionPolicy = GetModuleDelegatedExecutionPolicy($sModule);
|
||||
if (is_null($aModuleDelegatedExecutionPolicy) || !in_array($sPage, $aModuleDelegatedExecutionPolicy)) {
|
||||
$bForceLoginWhenNoExecutionPolicy = MetaModel::GetConfig()->Get('security.force_login_when_no_execution_policy');
|
||||
// TODO in N°9343 : remove the conf and this 'if' condition to perform login by default when no execution policy is defined
|
||||
LoginWebPage::DoLoginEx();
|
||||
}
|
||||
if (is_array($aModuleDelegatedExecutionPolicy) && !in_array($sPage, $aModuleDelegatedExecutionPolicy)) {
|
||||
// if module defined a delegated execution policy but not for the current page, we consider that the page is not allowed to be executed without login
|
||||
LoginWebPage::DoLoginEx();
|
||||
}
|
||||
|
||||
require_once($sTargetPage);
|
||||
|
||||
function GetModuleDelegatedExecutionPolicy(string $sModuleName): ?array
|
||||
{
|
||||
$sModuleFile = APPROOT.'/env-'.utils::GetCurrentEnvironment().'/'.$sModuleName.'/module.'.$sModuleName.'.php';
|
||||
|
||||
$oExtensionMap = new iTopExtensionsMap();
|
||||
$aModuleParam = $oExtensionMap->GetModuleInfo($sModuleFile)[2];
|
||||
return $aModuleParam['execution_policy'] ?? null;
|
||||
}
|
||||
|
||||
@@ -390,7 +390,7 @@ class iTopExtensionsMap
|
||||
* @param string $sModuleFile
|
||||
* @return array
|
||||
*/
|
||||
public function GetModuleInfo($sModuleFile)
|
||||
protected function GetModuleInfo($sModuleFile)
|
||||
{
|
||||
static $iDummyClassIndex = 0;
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
namespace Combodo\iTop\Application\Helper;
|
||||
|
||||
use Combodo\iTop\Application\UI\Base\Component\Alert\AlertUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputUIBlockFactory;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Input\InputWithLabel;
|
||||
use Combodo\iTop\Application\UI\Base\UIBlock;
|
||||
use Dict;
|
||||
use utils;
|
||||
|
||||
@@ -17,12 +20,91 @@ use utils;
|
||||
*/
|
||||
class ExportHelper
|
||||
{
|
||||
/**
|
||||
* @since 3.2.3 3.3.0 N°6977
|
||||
*/
|
||||
public const EXCEL_FORMULA_CHARACTERS = ['=', '=', '+', '+', '-', '-', '@', '@', '|', "\t", "\n", "\r"];
|
||||
|
||||
public static function GetAlertForExcelMaliciousInjection()
|
||||
{
|
||||
$sWikiUrl = 'https://www.itophub.io/wiki/page?id='.utils::GetItopVersionWikiSyntax().'%3Auser%3Alists#excel_export';
|
||||
$oAlert = AlertUIBlockFactory::MakeForWarning(Dict::S('UI:Bulk:Export:MaliciousInjection:Alert:Title'), Dict::Format('UI:Bulk:Export:MaliciousInjection:Alert:Message', $sWikiUrl), 'ibo-excel-malicious-injection-alert');
|
||||
$oAlert = AlertUIBlockFactory::MakeForWarning(Dict::S('UI:Bulk:Export:MaliciousInjection:Alert:Title'), Dict::Format('UI:Bulk:Export:MaliciousInjection:Alert:Message', $sWikiUrl), 'ibo-sanitize-excel-export--alert');
|
||||
$oAlert->EnableSaveCollapsibleState(true)
|
||||
->SetIsClosable(false);
|
||||
return $oAlert;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return InputWithLabel
|
||||
*
|
||||
* @since 3.2.3
|
||||
*/
|
||||
public static function GetInputForSanitizeExcelExport(): UIBlock
|
||||
{
|
||||
|
||||
$oSanitizeInput = InputUIBlockFactory::MakeForInputWithLabel(Dict::S('UI:Bulk:Export:MaliciousInjection:Input:Label'), 'sanitize_excel_export', 1, 'ibo-sanitize-excel-export--input', 'checkbox');
|
||||
$oSanitizeInput->GetInput()->SetIsChecked(true);
|
||||
$oSanitizeInput->SetBeforeInput(false);
|
||||
$oSanitizeInput->SetDescription(Dict::S('UI:Bulk:Export:MaliciousInjection:Input:Tooltip'));
|
||||
$oSanitizeInput->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
|
||||
return $oSanitizeInput;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sValue
|
||||
* @return bool
|
||||
*
|
||||
* @since 3.2.3
|
||||
*/
|
||||
public static function IsValueFormulaCandidate(string $sValue): bool
|
||||
{
|
||||
// An empty value cannot be a formula, so we can skip all the checks in this case
|
||||
if ($sValue === '') {
|
||||
return false;
|
||||
}
|
||||
|
||||
$bHasFormulaCandidate = false;
|
||||
$sFirstChar = mb_substr($sValue, 0, 1);
|
||||
$bHasFormulaCandidate |= in_array($sFirstChar, static::EXCEL_FORMULA_CHARACTERS, true);
|
||||
|
||||
// If the string is less than 3 characters long, it cannot start with a url encoded formula character, so we can skip this check in this case
|
||||
if (mb_strlen($sValue) < 3) {
|
||||
return $bHasFormulaCandidate;
|
||||
}
|
||||
|
||||
// Additionally, check if the first three character could be a formula character url encoded
|
||||
$sFirstThreeChars = mb_strtoupper(mb_substr($sValue, 0, 3));
|
||||
|
||||
$aUrlEncodedFormulaCharacters = array_map('urlencode', static::EXCEL_FORMULA_CHARACTERS);
|
||||
$bHasFormulaCandidate |= in_array($sFirstThreeChars, $aUrlEncodedFormulaCharacters, true);
|
||||
|
||||
return $bHasFormulaCandidate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sField
|
||||
* @param string $sTextQualifier
|
||||
* @return string
|
||||
*
|
||||
* @since 3.2.3
|
||||
*/
|
||||
public static function SanitizeField(string $sField, string $sTextQualifier = ''): string
|
||||
{
|
||||
if ($sField === '') {
|
||||
return $sField;
|
||||
}
|
||||
|
||||
$sQualifier = $sTextQualifier;
|
||||
if ($sQualifier !== '' && str_starts_with($sField, $sQualifier)) {
|
||||
$sAfterQualifier = substr($sField, strlen($sQualifier));
|
||||
if (self::IsValueFormulaCandidate($sAfterQualifier)) {
|
||||
return $sQualifier."'".$sAfterQualifier;
|
||||
}
|
||||
} elseif (self::IsValueFormulaCandidate($sField)) {
|
||||
return "'".$sField;
|
||||
}
|
||||
|
||||
return $sField;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,18 +67,18 @@ function ReadMandatoryParam($oP, $sParam, $sSanitizationFilter = 'parameter')
|
||||
if (utils::IsModeCLI()) {
|
||||
$oP = new CLIPage(Dict::S("TitleSynchroExecution"));
|
||||
SetupUtils::CheckPhpAndExtensionsForCli($oP, -2);
|
||||
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
$oP->p('Error: '.$e->GetMessage());
|
||||
$oP->output();
|
||||
exit - 2;
|
||||
}
|
||||
} else {
|
||||
$oP = new WebPage(Dict::S("TitleSynchroExecution"));
|
||||
}
|
||||
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
$oP->p("Error: ".$e->GetMessage());
|
||||
$oP->output();
|
||||
exit -2;
|
||||
}
|
||||
|
||||
if (utils::IsModeCLI()) {
|
||||
$sAuthUser = ReadMandatoryParam($oP, 'auth_user', 'raw_data');
|
||||
$sAuthPwd = ReadMandatoryParam($oP, 'auth_pwd', 'raw_data');
|
||||
|
||||
@@ -224,18 +224,18 @@ function ChangeDateFormat($sProposedDate, $sFormat, $bDateOnly)
|
||||
if (utils::IsModeCLI()) {
|
||||
$oP = new CLIPage(Dict::S('TitleSynchroExecution'));
|
||||
SetupUtils::CheckPhpAndExtensionsForCli($oP, -2);
|
||||
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
$oP->p('Error: '.$e->GetMessage());
|
||||
$oP->output();
|
||||
exit - 2;
|
||||
}
|
||||
} else {
|
||||
$oP = new CLILikeWebPage(Dict::S('TitleSynchroExecution'));
|
||||
}
|
||||
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
$oP->p("Error: ".$e->GetMessage());
|
||||
$oP->output();
|
||||
exit -2;
|
||||
}
|
||||
|
||||
if (utils::IsModeCLI()) {
|
||||
// Next steps:
|
||||
// specific arguments: 'csvfile'
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Application;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
|
||||
class LoginWebPageTest extends ItopDataTestCase
|
||||
{
|
||||
public const USE_TRANSACTION = false;
|
||||
|
||||
public const PASSWORD = 'a209320P!ù;ralùqpi,pàcqi"nr';
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->BackupConfiguration();
|
||||
$sFolderPath = APPROOT.'env-production/extension-with-execution-policy';
|
||||
if (file_exists($sFolderPath)) {
|
||||
throw new Exception("Folder $sFolderPath already exists, please remove it before running the test");
|
||||
}
|
||||
mkdir($sFolderPath);
|
||||
$this->RecurseCopy(__DIR__.'/extension-with-execution-policy', $sFolderPath);
|
||||
|
||||
$sFolderPath = APPROOT.'env-production/extension-without-execution-policy';
|
||||
if (file_exists($sFolderPath)) {
|
||||
throw new Exception("Folder $sFolderPath already exists, please remove it before running the test");
|
||||
}
|
||||
mkdir($sFolderPath);
|
||||
$this->RecurseCopy(__DIR__.'/extension-without-execution-policy', $sFolderPath);
|
||||
}
|
||||
public function tearDown(): void
|
||||
{
|
||||
parent::tearDown();
|
||||
$sFolderPath = APPROOT.'env-production/extension-with-execution-policy';
|
||||
if (file_exists($sFolderPath)) {
|
||||
$this->RecurseRmdir($sFolderPath);
|
||||
} else {
|
||||
throw new Exception("Folder $sFolderPath does not exist, it should have been created in setUp");
|
||||
}
|
||||
$sFolderPath = APPROOT.'env-production/extension-without-execution-policy';
|
||||
if (file_exists($sFolderPath)) {
|
||||
$this->RecurseRmdir($sFolderPath);
|
||||
} else {
|
||||
throw new Exception("Folder $sFolderPath does not exist, it should have been created in setUp");
|
||||
}
|
||||
}
|
||||
|
||||
protected function GivenConfigFileAllowedLoginTypes($aAllowedLoginTypes): void
|
||||
{
|
||||
@chmod(MetaModel::GetConfig()->GetLoadedFile(), 0770);
|
||||
MetaModel::GetConfig()->SetAllowedLoginTypes($aAllowedLoginTypes);
|
||||
MetaModel::GetConfig()->WriteToFile();
|
||||
@chmod(MetaModel::GetConfig()->GetLoadedFile(), 0444);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function testInExecutionPolicyFile()
|
||||
{
|
||||
// generate random login
|
||||
$sUserLogin = 'user-'.date('YmdHis');
|
||||
$this->CreateUser($sUserLogin, self::$aURP_Profiles['Administrator'], self::PASSWORD);
|
||||
$this->GivenConfigFileAllowedLoginTypes(explode('|', 'form'));
|
||||
|
||||
$sPageContent = $this->CallItopUri(
|
||||
"pages/exec.php?exec_module=extension-with-execution-policy&exec_page=src/Controller/CheckAnything.php",
|
||||
[
|
||||
'auth_user' => $sUserLogin,
|
||||
'auth_pwd' => self::PASSWORD,
|
||||
],
|
||||
[],
|
||||
true
|
||||
);
|
||||
|
||||
$this->assertStringNotContainsString('<title>iTop login</title>', $sPageContent); // in execution policy file (in the module), login should not be proposed, file handle its own policy
|
||||
}
|
||||
|
||||
public function testNotInExecutionPolicyFileWithForceLoginConf()
|
||||
{
|
||||
MetaModel::GetConfig()->Set('security.force_login_when_no_execution_policy', true);
|
||||
|
||||
$sPageContent = $this->CallItopUri(
|
||||
"pages/exec.php?exec_module=extension-with-execution-policy&exec_page=src/Controller/AnotherFile.php",
|
||||
);
|
||||
|
||||
$this->assertStringContainsString('<title>iTop login</title>', $sPageContent); // if itop is configured to force login when no execution policy, then login should be proposed since file is not in execution policy file
|
||||
}
|
||||
|
||||
public function testNotInExecutionPolicyFileWithoutForceLoginConf()
|
||||
{
|
||||
$sPageContent = $this->CallItopUri(
|
||||
"pages/exec.php?exec_module=extension-with-execution-policy&exec_page=src/Controller/AnotherFile.php",
|
||||
);
|
||||
|
||||
$this->assertStringNotContainsString('<title>iTop login</title>', $sPageContent); // by default (until N°9343) if no execution policy is defined, login is not forced
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
<?php
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'extension-with-execution-policy/0.0.1',
|
||||
[
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Templates foundation',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [],
|
||||
'mandatory' => true,
|
||||
'visible' => false,
|
||||
'installer' => 'TemplatesBaseInstaller',
|
||||
|
||||
// Security
|
||||
'execution_policy' => [
|
||||
'src/Controller/CheckAnything.php',
|
||||
],
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => [
|
||||
'model.templates-base.php',
|
||||
],
|
||||
'webservice' => [],
|
||||
'data.struct' => [// add your 'structure' definition XML files here,
|
||||
],
|
||||
'data.sample' => [// add your sample data XML files here,
|
||||
],
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
|
||||
'doc.more_information' => '', // hyperlink to more information, if any
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => [
|
||||
// Select where, in the main UI, the extra data should be displayed:
|
||||
// tab (dedicated tab)
|
||||
// properties (right after the properties, but before the log if any)
|
||||
// none (extra data accessed only by programs)
|
||||
'view_extra_data' => 'relations',
|
||||
],
|
||||
]
|
||||
);
|
||||
@@ -1,3 +0,0 @@
|
||||
<?php
|
||||
|
||||
echo 'Yo !';
|
||||
@@ -1,3 +0,0 @@
|
||||
<?php
|
||||
|
||||
echo 'Yo !';
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'extension-without-execution-policy/0.0.1',
|
||||
[
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Templates foundation',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => [],
|
||||
'mandatory' => true,
|
||||
'visible' => false,
|
||||
'installer' => 'TemplatesBaseInstaller',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => [
|
||||
'model.templates-base.php',
|
||||
],
|
||||
'webservice' => [],
|
||||
'data.struct' => [// add your 'structure' definition XML files here,
|
||||
],
|
||||
'data.sample' => [// add your sample data XML files here,
|
||||
],
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
|
||||
'doc.more_information' => '', // hyperlink to more information, if any
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => [
|
||||
// Select where, in the main UI, the extra data should be displayed:
|
||||
// tab (dedicated tab)
|
||||
// properties (right after the properties, but before the log if any)
|
||||
// none (extra data accessed only by programs)
|
||||
'view_extra_data' => 'relations',
|
||||
],
|
||||
]
|
||||
);
|
||||
@@ -1,3 +0,0 @@
|
||||
<?php
|
||||
|
||||
echo 'Yo !';
|
||||
@@ -1,3 +0,0 @@
|
||||
<?php
|
||||
|
||||
echo 'Yo !';
|
||||
@@ -123,7 +123,7 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
\IssueLog::Info("Running phpunit test: ".$this->getName());
|
||||
\IssueLog::Error($this->getName());
|
||||
|
||||
$this->PrepareEnvironment();
|
||||
|
||||
@@ -1446,6 +1446,9 @@ abstract class ItopDataTestCase extends ItopTestCase
|
||||
{
|
||||
$sConfigPath = MetaModel::GetConfig()->GetLoadedFile();
|
||||
clearstatcache();
|
||||
echo sprintf("rights via ls on %s:\n %s \n", $sConfigPath, exec("ls -al $sConfigPath"));
|
||||
$sFilePermOutput = substr(sprintf('%o', fileperms('/etc/passwd')), -4);
|
||||
echo sprintf("rights via fileperms on %s:\n %s \n", $sConfigPath, $sFilePermOutput);
|
||||
|
||||
$this->sConfigTmpBackupFile = tempnam(sys_get_temp_dir(), "config_");
|
||||
MetaModel::GetConfig()->WriteToFile($this->sConfigTmpBackupFile);
|
||||
|
||||
@@ -996,46 +996,4 @@ HTML,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function testLoadParamFile()
|
||||
{
|
||||
$sTmpFileInsideItop = APPROOT.'data/test/testLoadParamFile.params';
|
||||
$sDir = dirname($sTmpFileInsideItop);
|
||||
if (!is_dir($sDir)) {
|
||||
mkdir($sDir, 0777, true);
|
||||
}
|
||||
$sParamName = 'IP1';
|
||||
$sParamValue = 'IV1';
|
||||
$sParams = <<<INI
|
||||
# comment
|
||||
$sParamName = $sParamValue
|
||||
INI;
|
||||
file_put_contents($sTmpFileInsideItop, $sParams);
|
||||
|
||||
try {
|
||||
$this->expectException(\Exception::class);
|
||||
$this->expectExceptionMessage("File '$sTmpFileInsideItop' should be outside iTop");
|
||||
self::InvokeNonPublicStaticMethod(utils::class, 'LoadParamFile', [$sTmpFileInsideItop]);
|
||||
self::assertNotEquals($sParamValue, utils::ReadParam($sParamName, null), "utils::LoadParamFile() should NOT have loaded the file: $sTmpFileInsideItop");
|
||||
} finally {
|
||||
if (file_exists($sTmpFileInsideItop)) {
|
||||
unlink($sTmpFileInsideItop);
|
||||
}
|
||||
}
|
||||
|
||||
$sParamName = 'OP2';
|
||||
$sParamValue = 'OV2';
|
||||
|
||||
$sTmpFileOutsideItop = tempnam(sys_get_temp_dir(), 'utils-test');
|
||||
$sParams = <<<INI
|
||||
# comment
|
||||
$sParamName = $sParamValue
|
||||
INI;
|
||||
|
||||
file_put_contents($sTmpFileOutsideItop, $sParams);
|
||||
self::InvokeNonPublicStaticMethod(utils::class, 'LoadParamFile', [$sTmpFileOutsideItop]);
|
||||
self::assertEquals($sParamValue, utils::ReadParam($sParamName, null), "utils::LoadParamFile() should have loaded the file: $sTmpFileOutsideItop");
|
||||
|
||||
unlink($sTmpFileOutsideItop);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,4 +158,173 @@ EOF;
|
||||
$this->assertEquals($sExpectedValue, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider OrganizationsForExportSanitizeExcelExportProvider
|
||||
*
|
||||
* @param $aListOrg
|
||||
* @param $aExpectedValues
|
||||
* @return void
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function testExportWithSanitizeExcelExport(
|
||||
$aListOrg,
|
||||
$aExpectedValues,
|
||||
) {
|
||||
// Create tests organizations to have enough data
|
||||
$iFirstOrg = 0;
|
||||
foreach ($aListOrg as $aOrg) {
|
||||
$oObj = $this->CreateOrganization($aOrg[0]);
|
||||
if ($aOrg[1] === false) {
|
||||
$oObj->Set('status', 'inactive');
|
||||
$oObj->DBUpdate();
|
||||
}
|
||||
if ($iFirstOrg === 0) {
|
||||
$iFirstOrg = $oObj->GetKey();
|
||||
}
|
||||
}
|
||||
|
||||
$aStatusInfo = [
|
||||
"fields" => [
|
||||
[
|
||||
"sFieldSpec" => "name",
|
||||
"sAlias" => "Organization",
|
||||
"sClass" => "Organization",
|
||||
"sAttCode" => "name",
|
||||
"sLabel" => "Name",
|
||||
"sColLabel" => "Name",
|
||||
],
|
||||
],
|
||||
"text_qualifier" => "\"",
|
||||
"charset" => "UTF-8",
|
||||
"separator" => ",",
|
||||
"date_format" => "Y-m-d H:i:s",
|
||||
"formatted_text" => false,
|
||||
"show_obsolete_data" => false,
|
||||
'ignore_excel_sanitization' => false,
|
||||
];
|
||||
$sStatus = [];
|
||||
$oSearch = DBObjectSearch::FromOQL('SELECT Organization');
|
||||
$oExporter = BulkExport::FindExporter('csv', $oSearch);
|
||||
$oExporter->SetStatusInfo($aStatusInfo);
|
||||
$oExporter->SetObjectList($oSearch);
|
||||
$oExporter->SetChunkSize(EXPORTER_DEFAULT_CHUNK_SIZE);
|
||||
|
||||
$data = $oExporter->GetHeader();
|
||||
$data .= $oExporter->GetNextChunk($sStatus);
|
||||
|
||||
// Check that the value is sanitized as expected (with a ' prefix)
|
||||
foreach ($aExpectedValues as $sExpectedValue) {
|
||||
$this->assertStringContainsString($sExpectedValue, $data, "The value $sExpectedValue is expected to be found in the export result");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider OrganizationsForExportSanitizeExcelExportProvider
|
||||
*
|
||||
* @param $aListOrg
|
||||
* @param $aExpectedValues
|
||||
* @return void
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function testExportWithoutSanitizeExcelExport(
|
||||
$aListOrg,
|
||||
$aExpectedValues,
|
||||
) {
|
||||
// Create tests organizations to have enough data
|
||||
$iFirstOrg = 0;
|
||||
foreach ($aListOrg as $aOrg) {
|
||||
$oObj = $this->CreateOrganization($aOrg[0]);
|
||||
if ($aOrg[1] === false) {
|
||||
$oObj->Set('status', 'inactive');
|
||||
$oObj->DBUpdate();
|
||||
}
|
||||
if ($iFirstOrg === 0) {
|
||||
$iFirstOrg = $oObj->GetKey();
|
||||
}
|
||||
}
|
||||
|
||||
$aStatusInfo = [
|
||||
"fields" => [
|
||||
[
|
||||
"sFieldSpec" => "name",
|
||||
"sAlias" => "Organization",
|
||||
"sClass" => "Organization",
|
||||
"sAttCode" => "name",
|
||||
"sLabel" => "Name",
|
||||
"sColLabel" => "Name",
|
||||
],
|
||||
],
|
||||
"text_qualifier" => "\"",
|
||||
"charset" => "UTF-8",
|
||||
"separator" => ",",
|
||||
"date_format" => "Y-m-d H:i:s",
|
||||
"formatted_text" => false,
|
||||
"show_obsolete_data" => false,
|
||||
'ignore_excel_sanitization' => true,
|
||||
];
|
||||
$sStatus = [];
|
||||
$oSearch = DBObjectSearch::FromOQL('SELECT Organization');
|
||||
$oExporter = BulkExport::FindExporter('csv', $oSearch);
|
||||
$oExporter->SetStatusInfo($aStatusInfo);
|
||||
$oExporter->SetObjectList($oSearch);
|
||||
$oExporter->SetChunkSize(EXPORTER_DEFAULT_CHUNK_SIZE);
|
||||
|
||||
$data = $oExporter->GetHeader();
|
||||
$data .= $oExporter->GetNextChunk($sStatus);
|
||||
|
||||
// Check that the value is not sanitized
|
||||
foreach ($aListOrg as $sExpectedValue) {
|
||||
$this->assertStringContainsString($sExpectedValue[0], $data, "The value $sExpectedValue[0] is expected to be found in the export result");
|
||||
}
|
||||
}
|
||||
|
||||
public function OrganizationsForExportSanitizeExcelExportProvider()
|
||||
{
|
||||
return [
|
||||
'Page1' => [
|
||||
'list_org' => [
|
||||
['=org1', true],
|
||||
['+org2', true],
|
||||
['-org3', true],
|
||||
['@org4', true],
|
||||
["\t=org5", true],
|
||||
["\rorg6", true],
|
||||
["\r\t\r =org7", true],
|
||||
['=org8', true],
|
||||
['+org9', true],
|
||||
['-org10', true],
|
||||
['@org11', true],
|
||||
['|org12', true],
|
||||
['%3Dorg13', true],
|
||||
['%3dorg14', true],
|
||||
['org15', true],
|
||||
],
|
||||
'export_org' => [
|
||||
"'=org1",
|
||||
"'+org2",
|
||||
"'-org3",
|
||||
"'@org4",
|
||||
"'\t=org5",
|
||||
"'\rorg6",
|
||||
"'\r\t\r =org7",
|
||||
"'=org8",
|
||||
"'+org9",
|
||||
"'-org10",
|
||||
"'@org11",
|
||||
"'|org12",
|
||||
"'%3Dorg13",
|
||||
"'%3dorg14",
|
||||
"org15",
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,16 +446,18 @@ function ReSyncProcesses($oP, $bVerbose, $bDebug)
|
||||
//
|
||||
|
||||
set_time_limit(0); // Some background actions may really take long to finish (like backup)
|
||||
try {
|
||||
$bIsModeCLI = utils::IsModeCLI();
|
||||
if ($bIsModeCLI) {
|
||||
$oP = new CLIPage("iTop - cron");
|
||||
|
||||
SetupUtils::CheckPhpAndExtensionsForCli($oP, EXIT_CODE_FATAL);
|
||||
utils::UseParamFile();
|
||||
} else {
|
||||
$oP = new WebPage("iTop - cron");
|
||||
}
|
||||
$bIsModeCLI = utils::IsModeCLI();
|
||||
if ($bIsModeCLI) {
|
||||
$oP = new CLIPage("iTop - cron");
|
||||
|
||||
SetupUtils::CheckPhpAndExtensionsForCli($oP, EXIT_CODE_FATAL);
|
||||
} else {
|
||||
$oP = new WebPage("iTop - cron");
|
||||
}
|
||||
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
|
||||
$bVerbose = utils::ReadParam('verbose', false, true /* Allow CLI */);
|
||||
$bDebug = utils::ReadParam('debug', false, true /* Allow CLI */);
|
||||
|
||||
@@ -43,12 +43,10 @@ const EXIT_CODE_ERROR = -1;
|
||||
const EXIT_CODE_FATAL = -2;
|
||||
|
||||
try {
|
||||
if (utils::IsModeCLI()) {
|
||||
// Do this before logging, in order to allow setting user credentials from within the file
|
||||
utils::UseParamFile();
|
||||
}
|
||||
// Do this before loging, in order to allow setting user credentials from within the file
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
echo "Error: ".$e->GetMessage()."\n";
|
||||
echo "Error: ".$e->GetMessage()."<br/>\n";
|
||||
exit(EXIT_CODE_FATAL);
|
||||
}
|
||||
|
||||
|
||||
@@ -208,18 +208,18 @@ $oCtx = new ContextTag(ContextTag::TAG_IMPORT);
|
||||
if (utils::IsModeCLI()) {
|
||||
$oP = new CLIPage("iTop - Bulk import");
|
||||
SetupUtils::CheckPhpAndExtensionsForCli($oP, -2);
|
||||
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
$oP->p('Error: '.$e->GetMessage());
|
||||
$oP->output();
|
||||
exit(-2);
|
||||
}
|
||||
} else {
|
||||
$oP = new CSVPage("iTop - Bulk import");
|
||||
}
|
||||
|
||||
try {
|
||||
utils::UseParamFile();
|
||||
} catch (Exception $e) {
|
||||
$oP->p("Error: ".$e->GetMessage());
|
||||
$oP->output();
|
||||
exit(-2);
|
||||
}
|
||||
|
||||
if (utils::IsModeCLI()) {
|
||||
// Next steps:
|
||||
// specific arguments: 'csvfile'
|
||||
|
||||
@@ -91,8 +91,10 @@ if (empty($sJsonString)) {
|
||||
|
||||
$sProvider = '';
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
try {
|
||||
$oKPI = new ExecutionKPI();
|
||||
utils::UseParamFile();
|
||||
|
||||
$oKPI->ComputeAndReport('Data model loaded');
|
||||
|
||||
// N°6358 - force credentials for REST calls
|
||||
|
||||
Reference in New Issue
Block a user