Merge remote-tracking branch 'origin/support/2.7' into support/3.0

# Conflicts:
#	pages/ajax.render.php
This commit is contained in:
Pierre Goiffon
2022-11-29 18:12:49 +01:00
4 changed files with 84 additions and 12 deletions

View File

@@ -1549,6 +1549,29 @@ JS
return $this->sDefinitionFile;
}
/**
* @param string $sDashboardFileRelative can also be an absolute path (compatibility with old URL)
*
* @return string full path to the Dashboard file
* @throws \SecurityException if path isn't under approot
* @uses utils::RealPath()
* @since 2.7.8 3.0.3 3.1.0 N°4449 remove FPD
*/
public static function GetDashboardFileFromRelativePath($sDashboardFileRelative)
{
if (utils::RealPath($sDashboardFileRelative, APPROOT)) {
// compatibility with old URL containing absolute path !
return $sDashboardFileRelative;
}
$sDashboardFile = APPROOT.$sDashboardFileRelative;
if (false === utils::RealPath($sDashboardFile, APPROOT)) {
throw new SecurityException('Invalid dashboard file !');
}
return $sDashboardFile;
}
/**
* @param string $sDefinitionFile
*/

View File

@@ -1467,19 +1467,19 @@ class utils
$oDashboard = $param;
$sDashboardId = $oDashboard->GetId();
$sDashboardFile = $oDashboard->GetDefinitionFile();
$sDashboardFileRelative = utils::LocalPath($sDashboardFile);
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
$sDashboardFileJS = addslashes($sDashboardFile);
$sDashboardFileURL = urlencode($sDashboardFile);
$sDashboardFileJS = addslashes($sDashboardFileRelative);
$sDashboardFileURL = urlencode($sDashboardFileRelative);
$sUploadDashboardTransactId = utils::GetNewTransactionId();
$aResult = array(
new SeparatorPopupMenuItem(),
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sDashboardId.'&file='.$sDashboardFileURL),
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '$sDashboardId', file: '$sDashboardFileJS', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn', transaction: '$sUploadDashboardTransactId' })"),
);
if ($oDashboard->GetReloadURL())
{
if ($oDashboard->GetReloadURL()) {
$aResult[] = new SeparatorPopupMenuItem();
$aResult[] = new URLPopupMenuItem('UI:Menu:PrintableVersion', Dict::S('UI:Menu:PrintableVersion'), $oDashboard->GetReloadURL().'&printable=1', '_blank');
}

View File

@@ -876,7 +876,10 @@ try
case 'export_dashboard':
$oPage = new DownloadPage('');
$sDashboardId = utils::ReadParam('id', '', false, 'raw_data');
$sDashboardFile = utils::ReadParam('file', '', false, 'raw_data');
$sDashboardFileRelative = utils::ReadParam('file', '', false, 'raw_data');
$sDashboardFile = RuntimeDashboard::GetDashboardFileFromRelativePath($sDashboardFileRelative);
$oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId);
if (!is_null($oDashboard)) {
$oPage->TrashUnexpectedOutput();
@@ -891,18 +894,18 @@ try
$oPage->SetOutputDataOnly(true);
$sTransactionId = utils::ReadParam('transaction_id', '', false, 'transaction_id');
if (!utils::IsTransactionValid($sTransactionId, true))
{
if (!utils::IsTransactionValid($sTransactionId, true)) {
throw new SecurityException('ajax.render.php import_dashboard : invalid transaction_id');
}
$sDashboardId = utils::ReadParam('id', '', false, 'raw_data');
$sDashboardFile = utils::ReadParam('file', '', false, 'raw_data');
$sDashboardFileRelative = utils::ReadParam('file', '', false, 'raw_data');
$sDashboardFile = RuntimeDashboard::GetDashboardFileFromRelativePath($sDashboardFileRelative);
$oDashboard = RuntimeDashboard::GetDashboard($sDashboardFile, $sDashboardId);
$aResult = array('error' => '');
if (!is_null($oDashboard))
{
try
{
if (!is_null($oDashboard)) {
try {
$oDoc = utils::ReadPostedDocument('dashboard_upload_file');
$oDashboard->FromXml($oDoc->GetData());
$oDashboard->Save();

View File

@@ -0,0 +1,46 @@
<?php
/*
* @copyright Copyright (C) 2010-2022 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
/**
* We need the metamodel started as this is a dependency of {@link RuntimeDashboard}
*
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*
* @since 2.7.8 3.0.3 3.1.0 N°4449 Test Full Path Disclosure in Dashboard
*/
class RuntimeDashboardTest extends ItopDataTestCase
{
const DEFAULT_WELCOME_DASHBOARD_PATH = 'env-production/itop-welcome-itil/welcomemenupage_dashboard.xml';
const SYSTEM_FILE_PATH = '../../system-file';
/** @noinspection PhpUnhandledExceptionInspection */
public function testGetDashboard()
{
$sDashboardFileOk = APPROOT.self::DEFAULT_WELCOME_DASHBOARD_PATH;
$sDashboardId = uniqid(mt_rand(), TRUE);
$oDashboard = RuntimeDashboard::GetDashboard($sDashboardFileOk, $sDashboardId);
$this->assertNotNull($oDashboard);
$this->expectException(SecurityException::class);
$sDashboardFileSuspect = APPROOT.self::SYSTEM_FILE_PATH;;
RuntimeDashboard::GetDashboard($sDashboardFileSuspect, $sDashboardId);
}
/** @noinspection PhpUnhandledExceptionInspection */
public function testGetDefinitionFileRelative()
{
$sFullDashboardPath = RuntimeDashboard::GetDashboardFileFromRelativePath(self::DEFAULT_WELCOME_DASHBOARD_PATH);
$this->assertSame(APPROOT.self::DEFAULT_WELCOME_DASHBOARD_PATH, $sFullDashboardPath);
$this->expectException(SecurityException::class);
RuntimeDashboard::GetDashboardFileFromRelativePath(self::SYSTEM_FILE_PATH);
}
}