From 35215cf62fa5378c0a745a899e456aa6029b7832 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Thu, 26 Nov 2020 18:34:07 +0100 Subject: [PATCH 01/21] :globe_with_meridians: Fix typo in comma (2 "m" !!) --- dictionaries/en.dictionary.itop.ui.php | 2 +- dictionaries/hu.dictionary.itop.ui.php | 2 +- dictionaries/sk.dictionary.itop.ui.php | 2 +- dictionaries/tr.dictionary.itop.ui.php | 2 +- webservices/export.php | 9 +++------ 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/dictionaries/en.dictionary.itop.ui.php b/dictionaries/en.dictionary.itop.ui.php index 81e4d5f21..431360ec0 100644 --- a/dictionaries/en.dictionary.itop.ui.php +++ b/dictionaries/en.dictionary.itop.ui.php @@ -89,7 +89,7 @@ Dict::Add('EN US', 'English', 'English', array( 'Class:Query/Attribute:description' => 'Description', 'Class:Query/Attribute:description+' => 'Long description for the query (purpose, usage, etc.)', 'Class:QueryOQL/Attribute:fields' => 'Fields', - 'Class:QueryOQL/Attribute:fields+' => 'Coma separated list of attributes (or alias.attribute) to export', + 'Class:QueryOQL/Attribute:fields+' => 'Comma separated list of attributes (or alias.attribute) to export', 'Class:QueryOQL' => 'OQL Query', 'Class:QueryOQL+' => 'A query based on the Object Query Language', 'Class:QueryOQL/Attribute:oql' => 'Expression', diff --git a/dictionaries/hu.dictionary.itop.ui.php b/dictionaries/hu.dictionary.itop.ui.php index 05ac7ee17..0af1f5d71 100755 --- a/dictionaries/hu.dictionary.itop.ui.php +++ b/dictionaries/hu.dictionary.itop.ui.php @@ -72,7 +72,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array( 'Class:Query/Attribute:description' => 'Description~~', 'Class:Query/Attribute:description+' => 'Long description for the query (purpose, usage, etc.)~~', 'Class:QueryOQL/Attribute:fields' => 'Fields~~', - 'Class:QueryOQL/Attribute:fields+' => 'Coma separated list of attributes (or alias.attribute) to export~~', + 'Class:QueryOQL/Attribute:fields+' => 'Comma separated list of attributes (or alias.attribute) to export~~', 'Class:QueryOQL' => 'OQL Query~~', 'Class:QueryOQL+' => 'A query based on the Object Query Language~~', 'Class:QueryOQL/Attribute:oql' => 'Expression~~', diff --git a/dictionaries/sk.dictionary.itop.ui.php b/dictionaries/sk.dictionary.itop.ui.php index 8a3cb7e62..77da4e591 100644 --- a/dictionaries/sk.dictionary.itop.ui.php +++ b/dictionaries/sk.dictionary.itop.ui.php @@ -71,7 +71,7 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', array( 'Class:Query/Attribute:description' => 'Popis', 'Class:Query/Attribute:description+' => '', 'Class:QueryOQL/Attribute:fields' => 'Polia', - 'Class:QueryOQL/Attribute:fields+' => 'Coma separated list of attributes (or alias.attribute) to export~~', + 'Class:QueryOQL/Attribute:fields+' => 'Comma separated list of attributes (or alias.attribute) to export~~', 'Class:QueryOQL' => 'OQL Dopyt', 'Class:QueryOQL+' => '', 'Class:QueryOQL/Attribute:oql' => 'Výraz', diff --git a/dictionaries/tr.dictionary.itop.ui.php b/dictionaries/tr.dictionary.itop.ui.php index 09bd477bb..b6b613762 100644 --- a/dictionaries/tr.dictionary.itop.ui.php +++ b/dictionaries/tr.dictionary.itop.ui.php @@ -86,7 +86,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array( 'Class:Query/Attribute:description' => 'Description~~', 'Class:Query/Attribute:description+' => 'Long description for the query (purpose, usage, etc.)~~', 'Class:QueryOQL/Attribute:fields' => 'Fields~~', - 'Class:QueryOQL/Attribute:fields+' => 'Coma separated list of attributes (or alias.attribute) to export~~', + 'Class:QueryOQL/Attribute:fields+' => 'Comma separated list of attributes (or alias.attribute) to export~~', 'Class:QueryOQL' => 'OQL Query~~', 'Class:QueryOQL+' => 'A query based on the Object Query Language~~', 'Class:QueryOQL/Attribute:oql' => 'Expression~~', diff --git a/webservices/export.php b/webservices/export.php index ee127ca32..56a7f16f6 100644 --- a/webservices/export.php +++ b/webservices/export.php @@ -336,17 +336,14 @@ if (!$oP) $oP->p("Parameters:"); $oP->p(" * expression: an OQL expression (URL encoded if needed)"); $oP->p(" * query: (alternative to 'expression') the id of an entry from the query phrasebook"); - if (Utils::IsModeCLI()) - { + if (Utils::IsModeCLI()) { $oP->p(" * with_archive: (optional, defaults to 0) if set to 1 then the result set will include archived objects"); - } - else - { + } else { $oP->p(" * with_archive: (optional, defaults to the current mode) if set to 1 then the result set will include archived objects"); } $oP->p(" * arg_xxx: (needed if the query has parameters) the value of the parameter 'xxx'"); $oP->p(" * format: (optional, default is html) the desired output format. Can be one of 'html', 'spreadsheet', 'csv', 'xlsx' or 'xml'"); - $oP->p(" * fields: (optional, no effect on XML format) list of fields (attribute codes, or alias.attcode) separated by a coma"); + $oP->p(" * fields: (optional, no effect on XML format) list of fields (attribute codes, or alias.attcode) separated by a comma"); $oP->p(" * fields_advanced: (optional, no effect on XML/HTML formats ; ignored is fields is specified) If set to 1, the default list of fields will include the external keys and their reconciliation keys"); $oP->p(" * filename: (optional, no effect in CLI mode) if set then the results will be downloaded as a file"); } From a2a4cd4e7afc56ec3a729cd57198234a59faee7f Mon Sep 17 00:00:00 2001 From: acognet Date: Fri, 27 Nov 2020 15:20:20 +0100 Subject: [PATCH 02/21] =?UTF-8?q?N=C2=B03426=20-=20Wrong=20tab=20is=20disp?= =?UTF-8?q?layed=20when=20a=20creation=20or=20modification=20form=20is=20i?= =?UTF-8?q?nvalidated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/forms-json-utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/forms-json-utils.js b/js/forms-json-utils.js index c1eb96c36..5cba285ed 100644 --- a/js/forms-json-utils.js +++ b/js/forms-json-utils.js @@ -192,7 +192,7 @@ function activateFirstTabWithError(sFormId) { if ($fieldsWithError.length > 0) { $tabsContainer.tabs("option", "active", index); - return; + return false; } }); } @@ -218,7 +218,7 @@ function ReportFieldValidationStatus(sFieldId, sFormId, bValid, sExplain) if ($('#v_'+sFieldId+' img').length == 0) { $('#v_'+sFieldId).html(''); - } + }X //Avoid replacing exisiting tooltip for periodically checked element (like CKeditor fields) if($('#v_'+sFieldId).tooltip( "instance" ) === undefined) { From eb537f45f4b04b6ce3195bf2d2026df414275d60 Mon Sep 17 00:00:00 2001 From: acognet Date: Mon, 30 Nov 2020 09:24:35 +0100 Subject: [PATCH 03/21] =?UTF-8?q?N=C2=B03421=20-=20Attributes=20of=20class?= =?UTF-8?q?=20Person=20are=20not=20accessible=20from=20:current=5Fcontact?= =?UTF-8?q?=20in=20portal=20anymore.=20Only=20attributes=20of=20class=20Co?= =?UTF-8?q?ntact=20are.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core/metamodel.class.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/core/metamodel.class.php b/core/metamodel.class.php index 7872cc6e7..bf26e01a5 100644 --- a/core/metamodel.class.php +++ b/core/metamodel.class.php @@ -4166,11 +4166,7 @@ abstract class MetaModel } if (count($aCurrentUser) > 0) { - $oSearch = DBObjectSearch::FromOQL("SELECT User WHERE id = :id"); - $oSearch->AllowAllData(); - $oSet = new DBObjectSet($oSearch, array(), array('id' => UserRights::GetUserId())); - $oSet->OptimizeColumnLoad($aCurrentUser); - $oUser = $oSet->fetch(); + $oUser = MetaModel::GetObject("User", UserRights::GetUserId(),true,true); $aPlaceholders['current_user->object()'] = $oUser; foreach ($aCurrentUser as $sField) { @@ -4179,10 +4175,7 @@ abstract class MetaModel } if (count($aCurrentContact) > 0) { - $oSearch = DBObjectSearch::FromOQL("SELECT Contact WHERE id = :id"); - $oSet = new DBObjectSet($oSearch, array(), array('id' => UserRights::GetContactId())); - $oSet->OptimizeColumnLoad(['Contact' => $aCurrentContact]); - $oUser = $oSet->fetch(); + $oUser = MetaModel::GetObject("Person", UserRights::GetContactId(),true,true); foreach ($aCurrentContact as $sField) { $aPlaceholders['current_contact->'.$sField] = $oUser->Get($sField); From 539fa435035505979fe81e5d5d04e446f4ff5e3a Mon Sep 17 00:00:00 2001 From: acognet Date: Mon, 30 Nov 2020 18:27:25 +0100 Subject: [PATCH 04/21] =?UTF-8?q?N=C2=B03461=20-=20Setup=20Broken=20with?= =?UTF-8?q?=20Chrome=20v87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup/wizardsteps.class.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/wizardsteps.class.inc.php b/setup/wizardsteps.class.inc.php index 0db8640e8..5795c62fc 100644 --- a/setup/wizardsteps.class.inc.php +++ b/setup/wizardsteps.class.inc.php @@ -716,7 +716,7 @@ class WizStepLicense extends WizardStep $aLicenses = SetupUtils::GetLicenses(); $oPage->add_style( << Date: Wed, 2 Dec 2020 15:44:58 +0100 Subject: [PATCH 05/21] =?UTF-8?q?N=C2=B03416=20Fix=20DocumentFile=20previe?= =?UTF-8?q?w=20not=20working=20anymore=20Was=20caused=20by=20X-Frame-Optio?= =?UTF-8?q?ns=20http=20header=20added=20with=20N=C2=B03317?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/ajax.render.php | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/ajax.render.php b/pages/ajax.render.php index c50178a25..8fe1dcd00 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -961,6 +961,7 @@ try if (!empty($sClass) && ($sClass != 'InlineImage') && !empty($id) && !empty($sField)) { $oKPI = new ExecutionKPI(); + $oPage->add_header('X-Frame-Options:'); // resets header, see N°3416 ormDocument::DownloadDocument($oPage, $sClass, $id, $sField, 'inline'); $oKPI->ComputeAndReport('Data fetch and format'); } From aa43425df3f53dcf65a80e183f2965c39851931a Mon Sep 17 00:00:00 2001 From: Molkobain Date: Wed, 2 Dec 2020 16:59:13 +0100 Subject: [PATCH 06/21] =?UTF-8?q?N=C2=B03469=20-=20Portal:=20Fix=20modal?= =?UTF-8?q?=20created=20without=20an=20ID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- datamodels/2.x/itop-portal-base/portal/public/js/toolbox.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/datamodels/2.x/itop-portal-base/portal/public/js/toolbox.js b/datamodels/2.x/itop-portal-base/portal/public/js/toolbox.js index f37c36c69..1d572dbda 100644 --- a/datamodels/2.x/itop-portal-base/portal/public/js/toolbox.js +++ b/datamodels/2.x/itop-portal-base/portal/public/js/toolbox.js @@ -106,7 +106,11 @@ var CombodoPortalToolbox = { if (oOptions.base_modal.usage === 'clone') { oModalElem = oSelectorElem.clone(); - oModalElem.attr('id', oOptions.id) + + // Force modal to have an HTML ID, otherwise it can lead to complications, especially with the portal_leave_handle.js + // See N°3469 + let sModalID = (oOptions.id !== null) ? oOptions.id : 'modal-with-generated-id-'+Date.now(); + oModalElem.attr('id', sModalID) .appendTo('body'); } // - Get an existing modal in the DOM From 1cf1473d6b755afe583ad98dd6848f9b180eab5a Mon Sep 17 00:00:00 2001 From: Molkobain Date: Wed, 2 Dec 2020 17:01:00 +0100 Subject: [PATCH 07/21] =?UTF-8?q?N=C2=B03469=20-=20Fix=20variable=20declar?= =?UTF-8?q?ation=20(let=20=3D>=20var)=20=F0=9F=A4=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- datamodels/2.x/itop-portal-base/portal/public/js/toolbox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datamodels/2.x/itop-portal-base/portal/public/js/toolbox.js b/datamodels/2.x/itop-portal-base/portal/public/js/toolbox.js index 1d572dbda..55b92f703 100644 --- a/datamodels/2.x/itop-portal-base/portal/public/js/toolbox.js +++ b/datamodels/2.x/itop-portal-base/portal/public/js/toolbox.js @@ -109,7 +109,7 @@ var CombodoPortalToolbox = { // Force modal to have an HTML ID, otherwise it can lead to complications, especially with the portal_leave_handle.js // See N°3469 - let sModalID = (oOptions.id !== null) ? oOptions.id : 'modal-with-generated-id-'+Date.now(); + var sModalID = (oOptions.id !== null) ? oOptions.id : 'modal-with-generated-id-'+Date.now(); oModalElem.attr('id', sModalID) .appendTo('body'); } From 8bfcb14d0c1ace1e515dea3e2cd9d457e203c8fb Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Wed, 2 Dec 2020 16:47:28 +0100 Subject: [PATCH 08/21] =?UTF-8?q?N=C2=B03416=20XFrame-Options=20header=20i?= =?UTF-8?q?s=20now=20set=20using=20a=20config=20parameter,=20defaults=20to?= =?UTF-8?q?=20SAMEORIGIN=20Also=20adds=20an=20indirection=20(\WebPage::add?= =?UTF-8?q?=5Fxframe=5Foptions)=20to=20set=20header?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/ajaxwebpage.class.inc.php | 2 +- application/csvpage.class.inc.php | 2 +- application/itopwebpage.class.inc.php | 2 +- application/loginwebpage.class.inc.php | 2 +- application/webpage.class.inc.php | 19 ++++++++++++++- application/xmlpage.class.inc.php | 2 +- core/config.class.inc.php | 8 +++++++ .../hubconnectorpage.class.inc.php | 18 +++++++------- pages/ajax.document.php | 10 ++++---- pages/ajax.render.php | 2 +- .../TwigBase/Controller/Controller.php | 2 +- webservices/export-v2.php | 24 ++++++++----------- 12 files changed, 58 insertions(+), 35 deletions(-) diff --git a/application/ajaxwebpage.class.inc.php b/application/ajaxwebpage.class.inc.php index 12f47ffa3..bbe93367d 100644 --- a/application/ajaxwebpage.class.inc.php +++ b/application/ajaxwebpage.class.inc.php @@ -44,7 +44,7 @@ class ajax_page extends WebPage implements iTabbedPage $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); $this->m_oTabs = new TabManager(); $this->sContentType = 'text/html'; $this->sContentDisposition = 'inline'; diff --git a/application/csvpage.class.inc.php b/application/csvpage.class.inc.php index f6a4639bd..9a34dbb53 100644 --- a/application/csvpage.class.inc.php +++ b/application/csvpage.class.inc.php @@ -35,7 +35,7 @@ class CSVPage extends WebPage $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); //$this->add_header("Content-Transfer-Encoding: binary"); } diff --git a/application/itopwebpage.class.inc.php b/application/itopwebpage.class.inc.php index 2e9a86275..328a472de 100644 --- a/application/itopwebpage.class.inc.php +++ b/application/itopwebpage.class.inc.php @@ -74,7 +74,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); $this->add_linked_stylesheet("../css/jquery.treeview.css"); $this->add_linked_stylesheet("../css/jquery.autocomplete.css"); $this->add_linked_stylesheet("../css/jquery-ui-timepicker-addon.css"); diff --git a/application/loginwebpage.class.inc.php b/application/loginwebpage.class.inc.php index 07a2fd69d..d3f0c6cde 100644 --- a/application/loginwebpage.class.inc.php +++ b/application/loginwebpage.class.inc.php @@ -87,7 +87,7 @@ class LoginWebPage extends NiceWebPage $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); } public function SetStyleSheet() diff --git a/application/webpage.class.inc.php b/application/webpage.class.inc.php index 344d91542..111bc43f5 100644 --- a/application/webpage.class.inc.php +++ b/application/webpage.class.inc.php @@ -482,6 +482,23 @@ class WebPage implements Page $this->a_headers[] = $s_header; } + /** + * @param string|null $sHeaderValue for example `SAMESITE`. If null will set the header using the config parameter value. + * + * @since 2.7.2-2 3.0.0 N°3416 + * @uses security_header_xframe config parameter + * @uses \utils::GetConfig() + * @link https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options + */ + public function add_xframe_options($sHeaderValue = null) + { + if (is_null($sHeaderValue)) { + $sHeaderValue = utils::GetConfig()->Get('security_header_xframe'); + } + + $this->add_header('X-Frame-Options: '.$sHeaderValue); + } + /** * Add needed headers to the page so that it will no be cached */ @@ -490,7 +507,7 @@ class WebPage implements Page $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); //FIXME shouldn't be done here !!!!! } /** diff --git a/application/xmlpage.class.inc.php b/application/xmlpage.class.inc.php index 3310f3772..0ac2dcc6d 100644 --- a/application/xmlpage.class.inc.php +++ b/application/xmlpage.class.inc.php @@ -46,7 +46,7 @@ class XMLPage extends WebPage $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); $this->add_header("Content-location: export.xml"); } diff --git a/core/config.class.inc.php b/core/config.class.inc.php index de0df09a8..0947b20b1 100644 --- a/core/config.class.inc.php +++ b/core/config.class.inc.php @@ -1249,6 +1249,14 @@ class Config 'source_of_value' => '', 'show_in_conf_sample' => false, ), + 'security_header_xframe' => [ + 'type' => 'string', + 'description' => 'Value of the X-Frame-Options HTTP header sent by iTop. Possible values : DENY, SAMEORIGIN, or empty string.', + 'default' => 'SAMEORIGIN', + 'value' => '', + 'source_of_value' => '', + 'show_in_conf_sample' => false, + ], ); diff --git a/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php b/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php index 9bbb2da35..1a01bc88f 100644 --- a/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php +++ b/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php @@ -4,20 +4,20 @@ class HubConnectorPage extends NiceWebPage { public function __construct($sTitle) { - parent::__construct($sTitle); + parent::__construct($sTitle); $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_header('X-Frame-Options: deny'); + $this->add_xframe_options(); - $sImagesDir = utils::GetAbsoluteUrlAppRoot().'images'; - $sModuleImagesDir = utils::GetAbsoluteUrlModulesRoot().'itop-hub-connector/images'; - - $sUserPrefs = appUserPreferences::GetAsJSON(); - $this->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js'); - $this->add_script( -<<add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/utils.js'); + $this->add_script( + << 0) { - $oPage->add_header("Expires: "); // Reset the value set in ajax_page $oPage->add_header("Cache-Control: no-transform,public,max-age=$iCacheSec,s-maxage=$iCacheSec"); $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? + $oPage->add_header("Expires: "); // Reset the value set in ajax_page + $oPage->add_xframe_options(''); $oPage->add_header("Last-Modified: Wed, 15 Jun 2015 13:21:15 GMT"); // An arbitrary date in the past is ok } } @@ -76,12 +77,12 @@ try $id = utils::ReadParam('id', ''); $sSecret = utils::ReadParam('s', ''); $iCacheSec = 31556926; // One year ahead: an inline image cannot change - if (!empty($id) && !empty($sSecret)) - { + if (!empty($id) && !empty($sSecret)) { ormDocument::DownloadDocument($oPage, 'InlineImage', $id, 'contents', 'inline', 'secret', $sSecret); - $oPage->add_header("Expires: "); // Reset the value set in ajax_page $oPage->add_header("Cache-Control: no-transform,public,max-age=$iCacheSec,s-maxage=$iCacheSec"); $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? + $oPage->add_header("Expires: "); // Reset the value set in ajax_page + $oPage->add_xframe_options(''); $oPage->add_header("Last-Modified: Wed, 15 Jun 2016 13:21:15 GMT"); // An arbitrary date in the past is ok } break; @@ -92,6 +93,7 @@ try $oPage->SetContentType('text/javascript'); $oPage->add_header('Cache-control: public, max-age=86400'); // Cache for 24 hours $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? + $oPage->add_xframe_options(''); $oPage->add(file_get_contents(Utils::GetCachePath().$sSignature.'.js')); break; diff --git a/pages/ajax.render.php b/pages/ajax.render.php index 8fe1dcd00..e15a8f621 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -961,7 +961,7 @@ try if (!empty($sClass) && ($sClass != 'InlineImage') && !empty($id) && !empty($sField)) { $oKPI = new ExecutionKPI(); - $oPage->add_header('X-Frame-Options:'); // resets header, see N°3416 + $oPage->add_xframe_options(''); // resets header, see N°3416 ormDocument::DownloadDocument($oPage, $sClass, $id, $sField, 'inline'); $oKPI->ComputeAndReport('Data fetch and format'); } diff --git a/sources/application/TwigBase/Controller/Controller.php b/sources/application/TwigBase/Controller/Controller.php index 0a1309916..68b0e8887 100644 --- a/sources/application/TwigBase/Controller/Controller.php +++ b/sources/application/TwigBase/Controller/Controller.php @@ -558,7 +558,7 @@ abstract class Controller { case 'html': $this->m_oPage = new iTopWebPage($this->GetOperationTitle()); - $this->m_oPage->add_header('X-Frame-Options: deny'); + $this->m_oPage->add_xframe_options(); break; case 'ajax': diff --git a/webservices/export-v2.php b/webservices/export-v2.php index 0efd4243f..64c850bfb 100644 --- a/webservices/export-v2.php +++ b/webservices/export-v2.php @@ -44,7 +44,7 @@ function ReportErrorAndExit($sErrorMessage) else { $oP = new WebPage("iTop - Export"); - $oP->add_header('X-Frame-Options: deny'); + $oP->add_xframe_options(); $oP->p('ERROR: '.$sErrorMessage); $oP->output(); exit(-1); @@ -61,10 +61,9 @@ function ReportErrorAndUsage($sErrorMessage) $oP->output(); exit(-1); } - else - { + else { $oP = new WebPage("iTop - Export"); - $oP->add_header('X-Frame-Options: deny'); + $oP->add_xframe_options(); $oP->p('ERROR: '.$sErrorMessage); Usage($oP); $oP->output(); @@ -728,19 +727,17 @@ try if ($sMimeType == 'text/html') { // Note: Using NiceWebPage only for HTML export as it includes JS scripts & files, which makes no sense in other export formats. More over, it breaks Excel spreadsheet import. - if($oExporter instanceof HTMLBulkExport) - { + if($oExporter instanceof HTMLBulkExport) { $oP = new NiceWebPage('iTop export'); - $oP->add_header('X-Frame-Options: deny'); + $oP->add_xframe_options(); $oP->add_ready_script("$('table.listResults').tablesorter({widgets: ['MyZebra']});"); $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css'); $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/v4-shims.min.css'); } - else - { + else { $oP = new WebPage('iTop export'); - $oP->add_header('X-Frame-Options: deny'); - $oP->add_style("table br { mso-data-placement:same-cell; }"); // Trick for Excel: keep line breaks inside the same cell ! + $oP->add_xframe_options(); + $oP->add_style("table br { mso-data-placement:same-cell; }"); // Trick for Excel: keep line breaks inside the same cell ! } $oP->add_style("body { overflow: auto; }"); } @@ -760,10 +757,9 @@ catch (BulkExportMissingParameterException $e) Usage($oP); $oP->output(); } -catch (Exception $e) -{ +catch (Exception $e) { $oP = new WebPage('iTop Export'); - $oP->add_header('X-Frame-Options: deny'); + $oP->add_xframe_options(); $oP->add('Error: '.$e->getMessage()); IssueLog::Error($e->getMessage()."\n".$e->getTraceAsString()); $oP->output(); From ecebe4ecd52f2b1438def9190cb52c7f4ea0aa03 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Wed, 2 Dec 2020 16:55:16 +0100 Subject: [PATCH 09/21] =?UTF-8?q?N=C2=B03416=20XFrame=20and=20cache=20head?= =?UTF-8?q?ers=20optimizations=20*=20Remove=20XFrame=20header=20set=20in?= =?UTF-8?q?=20\WebPage::no=5Fcache=20:=20not=20this=20method=20responsabil?= =?UTF-8?q?ity,=20was=20confusing=20:/=20*=20Remove=20no=5Fcache()=20calls?= =?UTF-8?q?=20when=20already=20set=20in=20page=20constructor=20(ajax=5Fpag?= =?UTF-8?q?e=20mainly)=20*=20Also=20calls=20everywhere=20the=20\WebPage::n?= =?UTF-8?q?o=5Fcache=20method=20instead=20of=20setting=20headers=20manuall?= =?UTF-8?q?y?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/ajaxwebpage.class.inc.php | 4 +-- application/csvpage.class.inc.php | 4 +-- application/itopwebpage.class.inc.php | 7 ++--- application/loginwebpage.class.inc.php | 4 +-- application/webpage.class.inc.php | 1 - application/xmlpage.class.inc.php | 4 +-- core/spreadsheetbulkexport.class.inc.php | 4 +-- datamodels/2.x/combodo-db-tools/dbtools.php | 2 +- .../itop-attachments/ajax.itop-attachment.php | 1 - datamodels/2.x/itop-backup/ajax.backup.php | 1 - datamodels/2.x/itop-hub-connector/ajax.php | 1 - .../hubconnectorpage.class.inc.php | 4 +-- pages/ajax.csvimport.php | 1 - pages/ajax.document.php | 1 - pages/ajax.render.php | 7 ++--- pages/ajax.searchform.php | 1 - setup/email.test.php | 11 ++++--- .../TwigBase/Controller/Controller.php | 8 ++--- test/benchmark.php | 15 ++++----- webservices/export.php | 31 +++++++++---------- 20 files changed, 44 insertions(+), 68 deletions(-) diff --git a/application/ajaxwebpage.class.inc.php b/application/ajaxwebpage.class.inc.php index bbe93367d..2c9a61b1f 100644 --- a/application/ajaxwebpage.class.inc.php +++ b/application/ajaxwebpage.class.inc.php @@ -41,9 +41,7 @@ class ajax_page extends WebPage implements iTabbedPage parent::__construct($s_title, $bPrintable); $this->m_sReadyScript = ""; //$this->add_header("Content-type: text/html; charset=utf-8"); - $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); - $this->add_header('Pragma: no-cache'); - $this->add_header('Expires: 0'); + $this->no_cache(); $this->add_xframe_options(); $this->m_oTabs = new TabManager(); $this->sContentType = 'text/html'; diff --git a/application/csvpage.class.inc.php b/application/csvpage.class.inc.php index 9a34dbb53..78ddce6ad 100644 --- a/application/csvpage.class.inc.php +++ b/application/csvpage.class.inc.php @@ -32,9 +32,7 @@ class CSVPage extends WebPage function __construct($s_title) { parent::__construct($s_title); $this->add_header("Content-type: text/plain; charset=".self::PAGES_CHARSET); - $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); - $this->add_header('Pragma: no-cache'); - $this->add_header('Expires: 0'); + $this->no_cache(); $this->add_xframe_options(); //$this->add_header("Content-Transfer-Encoding: binary"); } diff --git a/application/itopwebpage.class.inc.php b/application/itopwebpage.class.inc.php index 328a472de..fdd00e4a1 100644 --- a/application/itopwebpage.class.inc.php +++ b/application/itopwebpage.class.inc.php @@ -60,8 +60,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage // Create a breadcrumb entry for the current page, but get its title as late as possible (page title could be changed later) $this->bBreadCrumbEnabled = true; } - else - { + else { $this->bBreadCrumbEnabled = false; } @@ -71,9 +70,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage $this->m_aMessages = array(); $this->SetRootUrl(utils::GetAbsoluteUrlAppRoot()); $this->add_header("Content-type: text/html; charset=".self::PAGES_CHARSET); - $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); - $this->add_header('Pragma: no-cache'); - $this->add_header('Expires: 0'); + $this->no_cache(); $this->add_xframe_options(); $this->add_linked_stylesheet("../css/jquery.treeview.css"); $this->add_linked_stylesheet("../css/jquery.autocomplete.css"); diff --git a/application/loginwebpage.class.inc.php b/application/loginwebpage.class.inc.php index d3f0c6cde..db06af42b 100644 --- a/application/loginwebpage.class.inc.php +++ b/application/loginwebpage.class.inc.php @@ -84,9 +84,7 @@ class LoginWebPage extends NiceWebPage parent::__construct($sTitle); $this->SetStyleSheet(); - $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); - $this->add_header('Pragma: no-cache'); - $this->add_header('Expires: 0'); + $this->no_cache(); $this->add_xframe_options(); } diff --git a/application/webpage.class.inc.php b/application/webpage.class.inc.php index 111bc43f5..15beec651 100644 --- a/application/webpage.class.inc.php +++ b/application/webpage.class.inc.php @@ -507,7 +507,6 @@ class WebPage implements Page $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); $this->add_header('Pragma: no-cache'); $this->add_header('Expires: 0'); - $this->add_xframe_options(); //FIXME shouldn't be done here !!!!! } /** diff --git a/application/xmlpage.class.inc.php b/application/xmlpage.class.inc.php index 0ac2dcc6d..ce98884a1 100644 --- a/application/xmlpage.class.inc.php +++ b/application/xmlpage.class.inc.php @@ -43,9 +43,7 @@ class XMLPage extends WebPage $this->m_bPassThrough = $bPassThrough; $this->m_bHeaderSent = false; $this->add_header("Content-type: text/xml; charset=".self::PAGES_CHARSET); - $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); - $this->add_header('Pragma: no-cache'); - $this->add_header('Expires: 0'); + $this->no_cache(); $this->add_xframe_options(); $this->add_header("Content-location: export.xml"); } diff --git a/core/spreadsheetbulkexport.class.inc.php b/core/spreadsheetbulkexport.class.inc.php index a742bc780..36e97f05f 100644 --- a/core/spreadsheetbulkexport.class.inc.php +++ b/core/spreadsheetbulkexport.class.inc.php @@ -199,8 +199,8 @@ EOF // Integration within MS-Excel web queries + HTTPS + IIS: // MS-IIS set these header values with no-cache... while Excel fails to do the job if using HTTPS // Then the fix is to force the reset of header values Pragma and Cache-control - $oPage->add_header("Pragma:", true); - $oPage->add_header("Cache-control:", true); + $oPage->add_header("Pragma:"); + $oPage->add_header("Cache-control:"); } public function GetHeader() diff --git a/datamodels/2.x/combodo-db-tools/dbtools.php b/datamodels/2.x/combodo-db-tools/dbtools.php index 869c4d337..40822becb 100644 --- a/datamodels/2.x/combodo-db-tools/dbtools.php +++ b/datamodels/2.x/combodo-db-tools/dbtools.php @@ -212,9 +212,9 @@ function DisplayInconsistenciesReport($aResults) header('Content-Description: File Transfer'); header('Content-Type: multipart/x-zip'); header('Content-Disposition: inline; filename="'.basename($sZipReport).'"'); - header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); + header('Expires: 0'); header('Content-Length: '.filesize($sZipReport)); readfile($sZipReport); unlink($sZipReport); diff --git a/datamodels/2.x/itop-attachments/ajax.itop-attachment.php b/datamodels/2.x/itop-attachments/ajax.itop-attachment.php index b603773f1..6ad463491 100644 --- a/datamodels/2.x/itop-attachments/ajax.itop-attachment.php +++ b/datamodels/2.x/itop-attachments/ajax.itop-attachment.php @@ -61,7 +61,6 @@ try LoginWebPage::DoLoginEx(null /* any portal */, false); $oPage = new ajax_page(""); - $oPage->no_cache(); $sOperation = utils::ReadParam('operation', ''); diff --git a/datamodels/2.x/itop-backup/ajax.backup.php b/datamodels/2.x/itop-backup/ajax.backup.php index 528a48916..754a1ba17 100644 --- a/datamodels/2.x/itop-backup/ajax.backup.php +++ b/datamodels/2.x/itop-backup/ajax.backup.php @@ -51,7 +51,6 @@ function DisplayErrorAndDie($oPage, $sHtmlErrorMessage, $exitCode = null) $sOperation = utils::ReadParam('operation', ''); $oPage = new ajax_page(''); -$oPage->no_cache(); $oPage->SetContentType('text/html'); diff --git a/datamodels/2.x/itop-hub-connector/ajax.php b/datamodels/2.x/itop-hub-connector/ajax.php index f9e44d81e..b83977e59 100644 --- a/datamodels/2.x/itop-hub-connector/ajax.php +++ b/datamodels/2.x/itop-hub-connector/ajax.php @@ -111,7 +111,6 @@ function DoBackup($sTargetFile) function ReportStatus($sMessage, $bSuccess, $iErrorCode = 0, $aMoreFields = array()) { $oPage = new ajax_page(""); - $oPage->no_cache(); $oPage->SetContentType('application/json'); $aResult = array( 'code' => $iErrorCode, diff --git a/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php b/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php index 1a01bc88f..1ee703e02 100644 --- a/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php +++ b/datamodels/2.x/itop-hub-connector/hubconnectorpage.class.inc.php @@ -6,9 +6,7 @@ class HubConnectorPage extends NiceWebPage { parent::__construct($sTitle); - $this->add_header('Cache-control: no-cache, no-store, must-revalidate'); - $this->add_header('Pragma: no-cache'); - $this->add_header('Expires: 0'); + $this->no_cache(); $this->add_xframe_options(); $sImagesDir = utils::GetAbsoluteUrlAppRoot().'images'; diff --git a/pages/ajax.csvimport.php b/pages/ajax.csvimport.php index e833817e4..ed4138e3a 100644 --- a/pages/ajax.csvimport.php +++ b/pages/ajax.csvimport.php @@ -242,7 +242,6 @@ try { case 'parser_preview': $oPage = new ajax_page(""); - $oPage->no_cache(); $oPage->SetContentType('text/html'); $sSeparator = utils::ReadParam('separator', ',', false, 'raw_data'); if ($sSeparator == 'tab') $sSeparator = "\t"; diff --git a/pages/ajax.document.php b/pages/ajax.document.php index 732130189..dada3ad23 100644 --- a/pages/ajax.document.php +++ b/pages/ajax.document.php @@ -38,7 +38,6 @@ try require_once(APPROOT.'/application/loginwebpage.class.inc.php'); $oPage = new ajax_page(""); - $oPage->no_cache(); $operation = utils::ReadParam('operation', ''); $sClass = utils::ReadParam('class', 'MissingAjaxParam', false, 'class'); diff --git a/pages/ajax.render.php b/pages/ajax.render.php index e15a8f621..0881a155e 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -68,8 +68,6 @@ try LoginWebPage::DoLoginEx($sRequestedPortalId, false); $oPage = new ajax_page(""); - $oPage->no_cache(); - $sFilter = utils::ReadParam('filter', '', false, 'raw_data'); $sEncoding = utils::ReadParam('encoding', 'serialize'); @@ -889,13 +887,12 @@ try case 'chart': // Workaround for IE8 + IIS + HTTPS // See TRAC #363, fix described here: http://forums.codecharge.com/posts.php?post_id=97771 - $oPage->add_header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); $oPage->add_header("Cache-Control: cache, must-revalidate"); $oPage->add_header("Pragma: public"); + $oPage->add_header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); $aParams = utils::ReadParam('params', array(), false, 'raw_data'); - if ($sFilter != '') - { + if ($sFilter != '') { $oFilter = DBSearch::unserialize($sFilter); $oKPI = new ExecutionKPI(); $oDisplayBlock = new DisplayBlock($oFilter, 'chart_ajax', false); diff --git a/pages/ajax.searchform.php b/pages/ajax.searchform.php index 99cfeda1f..cf6ebae27 100644 --- a/pages/ajax.searchform.php +++ b/pages/ajax.searchform.php @@ -49,7 +49,6 @@ try } $oPage = new ajax_page(""); - $oPage->no_cache(); $oPage->SetContentType('text/html'); $sListParams = utils::ReadParam('list_params', '{}', false, 'raw_data'); diff --git a/setup/email.test.php b/setup/email.test.php index dc7f22770..45f5a2fb8 100644 --- a/setup/email.test.php +++ b/setup/email.test.php @@ -255,11 +255,12 @@ try break; case 'step2': - $oP->no_cache(); - $sTo = Utils::ReadParam('to', '', false, 'raw_data'); - $sFrom = Utils::ReadParam('from', '', false, 'raw_data'); - DisplayStep2($oP, $sFrom, $sTo); - break; + $oP->no_cache(); + $oP->add_xframe_options('DENY'); + $sTo = Utils::ReadParam('to', '', false, 'raw_data'); + $sFrom = Utils::ReadParam('from', '', false, 'raw_data'); + DisplayStep2($oP, $sFrom, $sTo); + break; default: $oP->error("Error: unsupported operation '$sOperation'"); diff --git a/sources/application/TwigBase/Controller/Controller.php b/sources/application/TwigBase/Controller/Controller.php index 68b0e8887..8243f7bfe 100644 --- a/sources/application/TwigBase/Controller/Controller.php +++ b/sources/application/TwigBase/Controller/Controller.php @@ -435,18 +435,16 @@ abstract class Controller $sFileMimeType = utils::GetFileMimeType($sFilePath); header('Content-Type: '.$sFileMimeType); - if ($bFileTransfer) - { + if ($bFileTransfer) { header('Content-Description: File Transfer'); header('Content-Disposition: inline; filename="'.$sDownloadArchiveName); } - header('Expires: 0'); header('Cache-Control: must-revalidate'); header('Pragma: public'); + header('Expires: 0'); - foreach ($aHeaders as $sKey => $sValue) - { + foreach ($aHeaders as $sKey => $sValue) { header($sKey.': '.$sValue); } diff --git a/test/benchmark.php b/test/benchmark.php index 4a9997bd7..96f0f8ea0 100644 --- a/test/benchmark.php +++ b/test/benchmark.php @@ -782,14 +782,15 @@ try case 'create_structure': $oP->no_cache(); - $iPlannedContacts = Utils::ReadParam('plannedcontacts'); - $iPlannedContracts = Utils::ReadParam('plannedcontracts'); + $oP->add_xframe_options('DENY'); + $iPlannedContacts = Utils::ReadParam('plannedcontacts'); + $iPlannedContracts = Utils::ReadParam('plannedcontracts'); - $oDataCreation = new BenchmarkDataCreation(); - $oDataCreation->PlanStructure($iPlannedContacts, $iPlannedContracts); - $oDataCreation->ShowPlans($oP); - $oDataCreation->ShowForm($oP, 'create_structure_go'); - break; + $oDataCreation = new BenchmarkDataCreation(); + $oDataCreation->PlanStructure($iPlannedContacts, $iPlannedContracts); + $oDataCreation->ShowPlans($oP); + $oDataCreation->ShowForm($oP, 'create_structure_go'); + break; case 'create_structure_go': $oP->no_cache(); diff --git a/webservices/export.php b/webservices/export.php index 56a7f16f6..5dea33432 100644 --- a/webservices/export.php +++ b/webservices/export.php @@ -190,24 +190,23 @@ if (!empty($sExpression)) { case 'html': $oP = new NiceWebPage("iTop - Export"); - $oP->add_style('body { overflow: auto; }'); // Show scroll bars if needed - $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css'); - $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/v4-shims.min.css'); - - // Integration within MS-Excel web queries + HTTPS + IIS: - // MS-IIS set these header values with no-cache... while Excel fails to do the job if using HTTPS - // Then the fix is to force the reset of header values Pragma and Cache-control - header("Pragma:", true); - header("Cache-control:", true); + $oP->add_style('body { overflow: auto; }'); // Show scroll bars if needed + $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css'); + $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/v4-shims.min.css'); - // The HTML output is made for pages located in the /pages/ folder - // since this page is in a different folder, let's adjust the HTML 'base' attribute - // to make the relative hyperlinks in the page work - $sUrl = utils::GetAbsoluteUrlAppRoot(); - $oP->set_base($sUrl.'pages/'); + // Integration within MS-Excel web queries + HTTPS + IIS: + // MS-IIS set these header values with no-cache... while Excel fails to do the job if using HTTPS + // Then the fix is to force the reset of header values Pragma and Cache-control + header("Cache-control:", true); + header("Pragma:", true); - if(count($aFields) > 0) - { + // The HTML output is made for pages located in the /pages/ folder + // since this page is in a different folder, let's adjust the HTML 'base' attribute + // to make the relative hyperlinks in the page work + $sUrl = utils::GetAbsoluteUrlAppRoot(); + $oP->set_base($sUrl.'pages/'); + + if (count($aFields) > 0) { $iSearch = array_search('id', $aFields); if ($iSearch !== false) { From 80e1e0e61a7806b891ae2778a48f145463999a70 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Wed, 2 Dec 2020 18:02:00 +0100 Subject: [PATCH 10/21] =?UTF-8?q?N=C2=B03426=20Fix=20no=20navigation=20men?= =?UTF-8?q?u=20on=20User=20object=20creation=20Caused=20by=20a=20typo=20in?= =?UTF-8?q?=20js/forms-json-utils.js=20Thanks=20@Molkobain=20!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/forms-json-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/forms-json-utils.js b/js/forms-json-utils.js index 5cba285ed..0eec9508d 100644 --- a/js/forms-json-utils.js +++ b/js/forms-json-utils.js @@ -218,7 +218,7 @@ function ReportFieldValidationStatus(sFieldId, sFormId, bValid, sExplain) if ($('#v_'+sFieldId+' img').length == 0) { $('#v_'+sFieldId).html(''); - }X + } //Avoid replacing exisiting tooltip for periodically checked element (like CKeditor fields) if($('#v_'+sFieldId).tooltip( "instance" ) === undefined) { From b9ca2ac13dac402502dcad0629638d692c1a1b21 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Wed, 2 Dec 2020 15:44:58 +0100 Subject: [PATCH 11/21] =?UTF-8?q?N=C2=B03416=20Fix=20DocumentFile=20previe?= =?UTF-8?q?w=20not=20working=20anymore=20Was=20caused=20by=20X-Frame-Optio?= =?UTF-8?q?ns=20http=20header=20added=20with=20N=C2=B03317?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit 35d77ff64292e4f3e8be00b0bef7da254e1ee6ab) # Conflicts: # pages/ajax.render.php --- pages/ajax.render.php | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/ajax.render.php b/pages/ajax.render.php index 9db4992a7..41373f279 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -902,6 +902,7 @@ try $sField = utils::ReadParam('field', ''); if (!empty($sClass) && ($sClass != 'InlineImage') && !empty($id) && !empty($sField)) { + $oPage->add_header('X-Frame-Options:'); // resets header, see N°3416 ormDocument::DownloadDocument($oPage, $sClass, $id, $sField, 'inline'); } break; From aa15e009cb442ec5fcdecc1b985631ade1d149d1 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Thu, 3 Dec 2020 10:05:37 +0100 Subject: [PATCH 12/21] :bookmark: Prepare 2.7.2-2 version --- css/css-variables.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/css/css-variables.scss b/css/css-variables.scss index 852edd207..5c81c6b7b 100644 --- a/css/css-variables.scss +++ b/css/css-variables.scss @@ -17,7 +17,7 @@ */ // Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0 -$version: "v2.7.2"; +$version: "v2.7.2-2"; $approot-relative: "../../../../../" !default; // relative to env-***/branding/themes/***/main.css // Base colors From cece15d10c26f304b517908a3c419ec670d92713 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Thu, 3 Dec 2020 17:38:11 +0100 Subject: [PATCH 13/21] =?UTF-8?q?N=C2=B03416=20Updates=20after=20code=20re?= =?UTF-8?q?view=20Many=20thanks=20@bruno-ds=20!=20*=20add=20comments=20to?= =?UTF-8?q?=20explain=20intentions=20*=20fix=20indentations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/ajax.document.php | 6 ++--- pages/ajax.render.php | 2 +- setup/email.test.php | 7 ++++-- test/benchmark.php | 2 +- webservices/export.php | 51 ++++++++++++++++++++++++----------------- 5 files changed, 40 insertions(+), 28 deletions(-) diff --git a/pages/ajax.document.php b/pages/ajax.document.php index dada3ad23..80de595b0 100644 --- a/pages/ajax.document.php +++ b/pages/ajax.document.php @@ -64,7 +64,7 @@ try $oPage->add_header("Cache-Control: no-transform,public,max-age=$iCacheSec,s-maxage=$iCacheSec"); $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? $oPage->add_header("Expires: "); // Reset the value set in ajax_page - $oPage->add_xframe_options(''); + $oPage->add_xframe_options(''); // the header is set in page constructor, we reset its value ! See N°3416 $oPage->add_header("Last-Modified: Wed, 15 Jun 2015 13:21:15 GMT"); // An arbitrary date in the past is ok } } @@ -81,7 +81,7 @@ try $oPage->add_header("Cache-Control: no-transform,public,max-age=$iCacheSec,s-maxage=$iCacheSec"); $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? $oPage->add_header("Expires: "); // Reset the value set in ajax_page - $oPage->add_xframe_options(''); + $oPage->add_xframe_options(''); // the header is set in page constructor, we reset its value ! See N°3416 $oPage->add_header("Last-Modified: Wed, 15 Jun 2016 13:21:15 GMT"); // An arbitrary date in the past is ok } break; @@ -92,7 +92,7 @@ try $oPage->SetContentType('text/javascript'); $oPage->add_header('Cache-control: public, max-age=86400'); // Cache for 24 hours $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? - $oPage->add_xframe_options(''); + $oPage->add_xframe_options(''); // the header is set in page constructor, we reset its value ! See N°3416 $oPage->add(file_get_contents(Utils::GetCachePath().$sSignature.'.js')); break; diff --git a/pages/ajax.render.php b/pages/ajax.render.php index 0881a155e..b2f167be9 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -958,7 +958,7 @@ try if (!empty($sClass) && ($sClass != 'InlineImage') && !empty($id) && !empty($sField)) { $oKPI = new ExecutionKPI(); - $oPage->add_xframe_options(''); // resets header, see N°3416 + $oPage->add_xframe_options(''); // the header is set in page constructor, we reset its value ! See N°3416 ormDocument::DownloadDocument($oPage, $sClass, $id, $sField, 'inline'); $oKPI->ComputeAndReport('Data fetch and format'); } diff --git a/setup/email.test.php b/setup/email.test.php index 45f5a2fb8..07bec1b2c 100644 --- a/setup/email.test.php +++ b/setup/email.test.php @@ -33,10 +33,14 @@ LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be $sOperation = Utils::ReadParam('operation', 'step1'); $oP = new SetupPage('iTop email test utility'); +// Although this page doesn't expose sensitive info, with it we can send multiple emails +// So we're adding this http header to reduce CSRF exposure... +$oP->add_xframe_options('DENY'); + /** * Helper to check server setting required to send an email - */ + */ function CheckEmailSetting($oP) { $bRet = true; @@ -256,7 +260,6 @@ try case 'step2': $oP->no_cache(); - $oP->add_xframe_options('DENY'); $sTo = Utils::ReadParam('to', '', false, 'raw_data'); $sFrom = Utils::ReadParam('from', '', false, 'raw_data'); DisplayStep2($oP, $sFrom, $sTo); diff --git a/test/benchmark.php b/test/benchmark.php index 96f0f8ea0..1f5d9428e 100644 --- a/test/benchmark.php +++ b/test/benchmark.php @@ -781,7 +781,7 @@ try break; case 'create_structure': - $oP->no_cache(); + $oP->no_cache(); $oP->add_xframe_options('DENY'); $iPlannedContacts = Utils::ReadParam('plannedcontacts'); $iPlannedContracts = Utils::ReadParam('plannedcontracts'); diff --git a/webservices/export.php b/webservices/export.php index 5dea33432..9179912eb 100644 --- a/webservices/export.php +++ b/webservices/export.php @@ -189,7 +189,7 @@ if (!empty($sExpression)) switch($sFormat) { case 'html': - $oP = new NiceWebPage("iTop - Export"); + $oP = new NiceWebPage("iTop - Export"); $oP->add_style('body { overflow: auto; }'); // Show scroll bars if needed $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css'); $oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/v4-shims.min.css'); @@ -207,28 +207,37 @@ if (!empty($sExpression)) $oP->set_base($sUrl.'pages/'); if (count($aFields) > 0) { - $iSearch = array_search('id', $aFields); - if ($iSearch !== false) - { - $bViewLink = true; - unset($aFields[$iSearch]); + $iSearch = array_search('id', $aFields); + if ($iSearch !== false) { + $bViewLink = true; + unset($aFields[$iSearch]); + } else { + $bViewLink = false; + } + $sFields = implode(',', $aFields); + $aExtraParams = array( + 'menu' => false, + 'toolkit_menu' => false, + 'display_limit' => false, + 'localize_values' => $bLocalize, + 'zlist' => false, + 'extra_fields' => $sFields, + 'view_link' => $bViewLink, + ); + } else { + $aExtraParams = array( + 'menu' => false, + 'toolkit_menu' => false, + 'display_limit' => false, + 'localize_values' => $bLocalize, + 'zlist' => 'details', + ); } - else - { - $bViewLink = false; - } - $sFields = implode(',', $aFields); - $aExtraParams = array('menu' => false, 'toolkit_menu' => false, 'display_limit' => false, 'localize_values' => $bLocalize, 'zlist' => false, 'extra_fields' => $sFields, 'view_link' => $bViewLink); - } - else - { - $aExtraParams = array('menu' => false, 'toolkit_menu' => false, 'display_limit' => false, 'localize_values' => $bLocalize, 'zlist' => 'details'); - } - $oResultBlock = new DisplayBlock($oFilter, 'list', false, $aExtraParams); - $oResultBlock->Display($oP, 'expresult'); - break; - + $oResultBlock = new DisplayBlock($oFilter, 'list', false, $aExtraParams); + $oResultBlock->Display($oP, 'expresult'); + break; + case 'csv': $oP = new CSVPage("iTop - Export"); $sFields = implode(',', $aFields); From 4aaa237bf9f7df3e21aea62ab90b7562d299c4ff Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Thu, 3 Dec 2020 18:15:58 +0100 Subject: [PATCH 14/21] :bookmark: Prepare 2.7.3 version --- css/css-variables.scss | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/css/css-variables.scss b/css/css-variables.scss index 5c81c6b7b..a51c7c80e 100644 --- a/css/css-variables.scss +++ b/css/css-variables.scss @@ -17,17 +17,17 @@ */ // Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0 -$version: "v2.7.2-2"; +$version: "v2.7.3"; $approot-relative: "../../../../../" !default; // relative to env-***/branding/themes/***/main.css // Base colors -$gray-base: #000 !default; -$gray-darker: lighten($gray-base, 13.5%) !default; // #222 -$gray-dark: #444 !default; -$gray: #777 !default; -$gray-light: #808080 !default; -$gray-lighter: #ddd !default; -$gray-extra-light: #F1F1F1 !default; +$gray-base: #000 !default; +$gray-darker: lighten($gray-base, 13.5%) !default; // #222 +$gray-dark: #444 !default; +$gray: #777 !default; +$gray-light: #808080 !default; +$gray-lighter: #ddd !default; +$gray-extra-light: #F1F1F1 !default; $white: #FFFFFF !default; From 1304e2eb2d422deb8abd89cc7570828f18ae504d Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Fri, 4 Dec 2020 08:43:09 +0100 Subject: [PATCH 15/21] =?UTF-8?q?N=C2=B03416=20Updates=20after=20code=20re?= =?UTF-8?q?view=20v2=20:)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pages/ajax.document.php | 18 +++++++++++++++--- pages/ajax.render.php | 6 +++++- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/pages/ajax.document.php b/pages/ajax.document.php index 80de595b0..c1bb4c667 100644 --- a/pages/ajax.document.php +++ b/pages/ajax.document.php @@ -64,7 +64,11 @@ try $oPage->add_header("Cache-Control: no-transform,public,max-age=$iCacheSec,s-maxage=$iCacheSec"); $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? $oPage->add_header("Expires: "); // Reset the value set in ajax_page - $oPage->add_xframe_options(''); // the header is set in page constructor, we reset its value ! See N°3416 + + // X-Frame http header : set in page constructor, but we need to allow frame integration for this specific page + // so we're resetting its value ! (see N°3416) + $oPage->add_xframe_options(''); + $oPage->add_header("Last-Modified: Wed, 15 Jun 2015 13:21:15 GMT"); // An arbitrary date in the past is ok } } @@ -81,7 +85,11 @@ try $oPage->add_header("Cache-Control: no-transform,public,max-age=$iCacheSec,s-maxage=$iCacheSec"); $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? $oPage->add_header("Expires: "); // Reset the value set in ajax_page - $oPage->add_xframe_options(''); // the header is set in page constructor, we reset its value ! See N°3416 + + // X-Frame http header : set in page constructor, but we need to allow frame integration for this specific page + // so we're resetting its value ! (see N°3416) + $oPage->add_xframe_options(''); + $oPage->add_header("Last-Modified: Wed, 15 Jun 2016 13:21:15 GMT"); // An arbitrary date in the past is ok } break; @@ -92,7 +100,11 @@ try $oPage->SetContentType('text/javascript'); $oPage->add_header('Cache-control: public, max-age=86400'); // Cache for 24 hours $oPage->add_header("Pragma: cache"); // Reset the value set .... where ? - $oPage->add_xframe_options(''); // the header is set in page constructor, we reset its value ! See N°3416 + + // X-Frame http header : set in page constructor, but we need to allow frame integration for this specific page + // so we're resetting its value ! (see N°3416) + $oPage->add_xframe_options(''); + $oPage->add(file_get_contents(Utils::GetCachePath().$sSignature.'.js')); break; diff --git a/pages/ajax.render.php b/pages/ajax.render.php index b2f167be9..688b670d1 100644 --- a/pages/ajax.render.php +++ b/pages/ajax.render.php @@ -958,7 +958,11 @@ try if (!empty($sClass) && ($sClass != 'InlineImage') && !empty($id) && !empty($sField)) { $oKPI = new ExecutionKPI(); - $oPage->add_xframe_options(''); // the header is set in page constructor, we reset its value ! See N°3416 + + // X-Frame http header : set in page constructor, but we need to allow frame integration for this specific page + // so we're resetting its value ! (see N°3416) + $oPage->add_xframe_options(''); + ormDocument::DownloadDocument($oPage, $sClass, $id, $sField, 'inline'); $oKPI->ComputeAndReport('Data fetch and format'); } From cf1b61392327d4c49a3878b2182da07d1fc72e2d Mon Sep 17 00:00:00 2001 From: odain Date: Sun, 6 Dec 2020 23:54:27 +0100 Subject: [PATCH 16/21] =?UTF-8?q?N=C2=B03464=20REST=20comment=20field=20no?= =?UTF-8?q?t=20working=20anymore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/applicationextension.inc.php | 5 + test/webservices/RestTest.php | 245 +++++++++++++++++++++++ 2 files changed, 250 insertions(+) create mode 100644 test/webservices/RestTest.php diff --git a/application/applicationextension.inc.php b/application/applicationextension.inc.php index 7b1baa97d..d40870065 100644 --- a/application/applicationextension.inc.php +++ b/application/applicationextension.inc.php @@ -1345,6 +1345,11 @@ class RestUtils { $sComment = self::GetMandatoryParam($oData, 'comment'); CMDBObject::SetTrackInfo($sComment); + + /** @var \CMDBChange $oChange */ + $oChange = CMDBObject::GetCurrentChange(); + $oChange->Set("userinfo", $sComment); + $oChange->DBUpdate(); } /** diff --git a/test/webservices/RestTest.php b/test/webservices/RestTest.php new file mode 100644 index 000000000..0b3d9c9b4 --- /dev/null +++ b/test/webservices/RestTest.php @@ -0,0 +1,245 @@ +sTmpFile)){ + unlink($this->sTmpFile); + } + } + + /** + * @dataProvider BasicProvider + * @param bool $bPassJsonDataAsFile + */ + public function testCreateApi($bPassJsonDataAsFile) + { + $this->bPassJsonDataAsFile = $bPassJsonDataAsFile; + + //create ticket + $description = date('dmY H:i:s'); + $sOuputJson = $this->CreateTicketViaApi($description); + $aJson = json_decode($sOuputJson, true); + $this->assertContains("0", "".$aJson['code']); + $sUserRequestKey = array_key_first($aJson['objects']); + $this->assertContains('UserRequest::', $sUserRequestKey); + $iId = $aJson['objects'][$sUserRequestKey]['key']; + $sExpectedJsonOuput=<<assertEquals($sExpectedJsonOuput, $sOuputJson); + + $sExpectedJsonOuput=<<$description<\/p>"}}},"code":0,"message":"Found: 1"} +JSON; + $this->assertEquals($sExpectedJsonOuput, $this->GetTicketViaRest($iId)); + + $aCmdbChangeUserInfo = $this->GetCmdbChangeUserInfo($iId); + $this->assertEquals(['CMDBChangeOpCreate' => 'test'], $aCmdbChangeUserInfo); + + //delete ticket + $this->DeleteTicketFromApi($iId); + } + + /** + * @dataProvider BasicProvider + * @param bool $bPassJsonDataAsFile + */ + public function testUpdateApi($bPassJsonDataAsFile) + { + $this->bPassJsonDataAsFile = $bPassJsonDataAsFile; + + //create ticket + $description = date('dmY H:i:s'); + $sOuputJson = $this->CreateTicketViaApi($description); + $aJson = json_decode($sOuputJson, true); + $this->assertContains("0", "".$aJson['code']); + $sUserRequestKey = array_key_first($aJson['objects']); + $this->assertContains('UserRequest::', $sUserRequestKey); + $iId = $aJson['objects'][$sUserRequestKey]['key']; + + //update ticket + $description = date('Ymd H:i:s'); + $sExpectedJsonOuput=<<$description<\/p>"}}},"code":0,"message":null} +JSON; + $this->assertEquals($sExpectedJsonOuput, $this->UpdateTicketViaApi($iId, $description)); + + $aCmdbChangeUserInfo = $this->GetCmdbChangeUserInfo($iId); + $this->assertEquals(['CMDBChangeOpCreate' => 'test', 'CMDBChangeOpSetAttributeHTML' => 'test'], $aCmdbChangeUserInfo); + + + //delete ticket + $this->DeleteTicketFromApi($iId); + } + /** + * @dataProvider BasicProvider + * @param bool $bPassJsonDataAsFile + */ + public function testDeleteApi($bPassJsonDataAsFile) + { + $this->bPassJsonDataAsFile = $bPassJsonDataAsFile; + + //create ticket + $description = date('dmY H:i:s'); + + $sOuputJson = $this->CreateTicketViaApi($description); + $aJson = json_decode($sOuputJson, true); + $this->assertContains("0", "".$aJson['code']); + $sUserRequestKey = array_key_first($aJson['objects']); + $this->assertContains('UserRequest::', $sUserRequestKey); + $iId = $aJson['objects'][$sUserRequestKey]['key']; + + //delete ticket + $sExpectedJsonOuput=<<assertContains($sExpectedJsonOuput, $this->DeleteTicketFromApi($iId)); + + $sExpectedJsonOuput=<<assertEquals($sExpectedJsonOuput, $this->GetTicketViaRest($iId)); + } + + private function GetTicketViaRest($iId){ + $sJsonGetContent = <<CallRestApi($sJsonGetContent); + } + + public function BasicProvider(){ + return [ + 'call rest call' => [ 'bCallApiViaFile' => false], + //'pass json_data as file' => [ 'bCallApiViaFile' => true] + ]; + } + + private function UpdateTicketViaApi($iId, $description){ + $sJsonUpdateContent = <<CallRestApi($sJsonUpdateContent); + } + + private function CreateTicketViaApi($description){ + $sJsonCreateContent = <<CallRestApi($sJsonCreateContent); + } + + private function DeleteTicketFromApi($iId){ + $sJson = <<CallRestApi($sJson); + + } + + private function CallRestApi($sJsonDataContent){ + $ch = curl_init(); + $aPostFields = [ + 'version' => '1.3', + 'auth_user' => 'admin', + 'auth_pwd' => 'admin', + ]; + + if ($this->bPassJsonDataAsFile){ + $this->sTmpFile = tempnam(sys_get_temp_dir(), 'jsondata_'); + file_put_contents($this->sTmpFile, $sJsonDataContent); + + $oCurlFile = curl_file_create($this->sTmpFile); + $aPostFields['json_data'] = $oCurlFile; + }else{ + $aPostFields['json_data'] = $sJsonDataContent; + } + + curl_setopt($ch, CURLOPT_URL, "http://localhost/iTop/webservices/rest.php"); + curl_setopt($ch, CURLOPT_POST, 1);// set post data to true + curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + $sJson = curl_exec($ch); + curl_close ($ch); + + return $sJson; + } + + /** + * @param $iId + * Get CMDBChangeOp info to test + * @return array + */ + private function GetCmdbChangeUserInfo($iId){ + $sJsonGetContent = <<CallRestApi($sJsonGetContent); + $aJson = json_decode($sOutput, true); + if (is_array($aJson) && array_key_exists('objects', $aJson)){ + $aObjects = $aJson['objects']; + if (!empty($aObjects)){ + foreach ($aObjects as $aObject){ + $sClass = $aObject['class']; + $sUserInfo = $aObject['fields']['userinfo']; + $aUserInfo[$sClass] = $sUserInfo; + } + } + } + return $aUserInfo; + } +} From 4d61c14f80c151fc1741097e0cb205fd5e5b2661 Mon Sep 17 00:00:00 2001 From: odain Date: Mon, 7 Dec 2020 00:12:31 +0100 Subject: [PATCH 17/21] =?UTF-8?q?N=C2=B03464=20add=20test=20in=20phpunit.x?= =?UTF-8?q?ml.dit=20to=20validate=20the=20fix?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/phpunit.xml.dist | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/phpunit.xml.dist b/test/phpunit.xml.dist index 7cf47b272..2929c7e78 100644 --- a/test/phpunit.xml.dist +++ b/test/phpunit.xml.dist @@ -47,6 +47,9 @@ core + + webservices + itop-tickets From 00195959235090cd3fcff6da9db2e9809276aff7 Mon Sep 17 00:00:00 2001 From: odain Date: Mon, 7 Dec 2020 00:44:39 +0100 Subject: [PATCH 18/21] =?UTF-8?q?N=C2=B03464:=20fix=20ci?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/webservices/RestTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/webservices/RestTest.php b/test/webservices/RestTest.php index 0b3d9c9b4..08625c3fa 100644 --- a/test/webservices/RestTest.php +++ b/test/webservices/RestTest.php @@ -141,7 +141,7 @@ JSON; //'pass json_data as file' => [ 'bCallApiViaFile' => true] ]; } - + private function UpdateTicketViaApi($iId, $description){ $sJsonUpdateContent = << Date: Mon, 7 Dec 2020 00:44:39 +0100 Subject: [PATCH 19/21] =?UTF-8?q?N=C2=B03464:=20move=20fix=20in=20itop-fen?= =?UTF-8?q?ce=20+=20fix/enhance=20rest=20api=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- application/applicationextension.inc.php | 5 --- test/ItopDataTestCase.php | 33 ++++++++++++++-- test/webservices/RestTest.php | 50 +++++++++++++++++++----- 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/application/applicationextension.inc.php b/application/applicationextension.inc.php index d40870065..7b1baa97d 100644 --- a/application/applicationextension.inc.php +++ b/application/applicationextension.inc.php @@ -1345,11 +1345,6 @@ class RestUtils { $sComment = self::GetMandatoryParam($oData, 'comment'); CMDBObject::SetTrackInfo($sComment); - - /** @var \CMDBChange $oChange */ - $oChange = CMDBObject::GetCurrentChange(); - $oChange->Set("userinfo", $sComment); - $oChange->DBUpdate(); } /** diff --git a/test/ItopDataTestCase.php b/test/ItopDataTestCase.php index eddbffcc6..70b0a06f4 100644 --- a/test/ItopDataTestCase.php +++ b/test/ItopDataTestCase.php @@ -73,7 +73,7 @@ class ItopDataTestCase extends ItopTestCase protected function setUp() { parent::setUp(); - //require_once(APPROOT.'/application/startup.inc.php'); + require_once(APPROOT.'/application/startup.inc.php'); require_once(APPROOT.'application/utils.inc.php'); @@ -408,8 +408,12 @@ class ItopDataTestCase extends ItopTestCase * @return \DBObject * @throws Exception */ - protected function CreateUser($sLogin, $iProfileId) + protected function CreateUser($sLogin, $iProfileId, $sPassword=null) { + if (empty($sPassword)){ + $sPassword = $sLogin; + } + $oUserProfile = new URP_UserProfile(); $oUserProfile->Set('profileid', $iProfileId); $oUserProfile->Set('reason', 'UNIT Tests'); @@ -417,7 +421,7 @@ class ItopDataTestCase extends ItopTestCase $oUser = $this->createObject('UserLocal', array( 'contactid' => 2, 'login' => $sLogin, - 'password' => $sLogin, + 'password' => $sPassword, 'language' => 'EN US', 'profile_list' => $oSet, )); @@ -426,6 +430,29 @@ class ItopDataTestCase extends ItopTestCase return $oUser; } + /** + * @param \DBObject $oUser + * @param int $iProfileId + * + * @return \DBObject + * @throws Exception + */ + protected function AddProfileToUser($oUser, $iProfileId) + { + $oUserProfile = new URP_UserProfile(); + $oUserProfile->Set('profileid', $iProfileId); + $oUserProfile->Set('reason', 'UNIT Tests'); + /** @var DBObjectSet $oSet */ + $oSet = $oUser->Get('profile_list'); + $oSet->AddObject($oUserProfile); + $oUser = $this->updateObject('UserLocal', $oUser->GetKey(), array( + 'profile_list' => $oSet, + )); + $this->debug("Updated {$oUser->GetName()} ({$oUser->GetKey()})"); + + return $oUser; + } + /** * Create a Hypervisor in database diff --git a/test/webservices/RestTest.php b/test/webservices/RestTest.php index 08625c3fa..46ebb24d9 100644 --- a/test/webservices/RestTest.php +++ b/test/webservices/RestTest.php @@ -13,8 +13,12 @@ use Exception; */ class RestTest extends ItopDataTestCase { + const USE_TRANSACTION = false; + private $sTmpFile = ""; private $bPassJsonDataAsFile = false; + private $sLogin; + private $sPassword = "Iuytrez9876543ç_è-("; /** * @throws Exception @@ -22,10 +26,22 @@ class RestTest extends ItopDataTestCase protected function setUp() { parent::setUp(); + require_once(APPROOT.'application/startup.inc.php'); + $this->sLogin = "rest-user-" . date('dmYHis'); + $this->CreateTestOrganization(); if (!empty($this->sTmpFile)){ unlink($this->sTmpFile); } + + $oRestProfile = \MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'REST Services User'), true); + $oAdminProfile = \MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'Administrator'), true); + + if (is_object($oRestProfile) && is_object($oAdminProfile)) + { + $oUser = $this->CreateUser($this->sLogin, $oRestProfile->GetKey(), $this->sPassword); + $this->AddProfileToUser($oUser, $oAdminProfile->GetKey()); + } } /** @@ -40,8 +56,8 @@ class RestTest extends ItopDataTestCase $description = date('dmY H:i:s'); $sOuputJson = $this->CreateTicketViaApi($description); $aJson = json_decode($sOuputJson, true); - $this->assertContains("0", "".$aJson['code']); - $sUserRequestKey = array_key_first($aJson['objects']); + $this->assertContains("0", "".$aJson['code'], $sOuputJson); + $sUserRequestKey = $this->array_key_first($aJson['objects']); $this->assertContains('UserRequest::', $sUserRequestKey); $iId = $aJson['objects'][$sUserRequestKey]['key']; $sExpectedJsonOuput=<<DeleteTicketFromApi($iId); } + /** + * array_key_first comes with PHP7.3 + * itop should also work with previous PHP versions + */ + private function array_key_first($aTab){ + if (!is_array($aTab) || empty($aTab)){ + return false; + } + + foreach ($aTab as $sKey => $sVal){ + return $sKey; + } + } + /** * @dataProvider BasicProvider * @param bool $bPassJsonDataAsFile @@ -73,8 +103,8 @@ JSON; $description = date('dmY H:i:s'); $sOuputJson = $this->CreateTicketViaApi($description); $aJson = json_decode($sOuputJson, true); - $this->assertContains("0", "".$aJson['code']); - $sUserRequestKey = array_key_first($aJson['objects']); + $this->assertContains("0", "".$aJson['code'], $sOuputJson); + $sUserRequestKey = $this->array_key_first($aJson['objects']); $this->assertContains('UserRequest::', $sUserRequestKey); $iId = $aJson['objects'][$sUserRequestKey]['key']; @@ -105,8 +135,8 @@ JSON; $sOuputJson = $this->CreateTicketViaApi($description); $aJson = json_decode($sOuputJson, true); - $this->assertContains("0", "".$aJson['code']); - $sUserRequestKey = array_key_first($aJson['objects']); + $this->assertContains("0", "".$aJson['code'], $sOuputJson); + $sUserRequestKey = $this->array_key_first($aJson['objects']); $this->assertContains('UserRequest::', $sUserRequestKey); $iId = $aJson['objects'][$sUserRequestKey]['key']; @@ -188,8 +218,8 @@ JSON; $ch = curl_init(); $aPostFields = [ 'version' => '1.3', - 'auth_user' => 'admin', - 'auth_pwd' => 'admin', + 'auth_user' => $this->sLogin, + 'auth_pwd' => $this->sPassword, ]; if ($this->bPassJsonDataAsFile){ @@ -202,14 +232,14 @@ JSON; $aPostFields['json_data'] = $sJsonDataContent; } - curl_setopt($ch, CURLOPT_URL, "http://webserver/iTop/webservices/rest.php"); + $sUrl = \MetaModel::GetConfig()->Get('app_root_url'); + curl_setopt($ch, CURLOPT_URL, "$sUrl/webservices/rest.php"); curl_setopt($ch, CURLOPT_POST, 1);// set post data to true curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $sJson = curl_exec($ch); curl_close ($ch); - var_dump($sJson); return $sJson; } From 37351d6b3e3141ca7eca412c5656ac0d8474cdc3 Mon Sep 17 00:00:00 2001 From: odain Date: Mon, 7 Dec 2020 16:23:17 +0100 Subject: [PATCH 20/21] =?UTF-8?q?N=C2=B03464:=20fix=20ci?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test/webservices/RestTest.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/webservices/RestTest.php b/test/webservices/RestTest.php index 46ebb24d9..d600660db 100644 --- a/test/webservices/RestTest.php +++ b/test/webservices/RestTest.php @@ -17,6 +17,7 @@ class RestTest extends ItopDataTestCase private $sTmpFile = ""; private $bPassJsonDataAsFile = false; + private $sUrl; private $sLogin; private $sPassword = "Iuytrez9876543ç_è-("; @@ -34,6 +35,11 @@ class RestTest extends ItopDataTestCase unlink($this->sTmpFile); } + $sConfigFile = \utils::GetConfig()->GetLoadedFile(); + @chmod($sConfigFile, 0770); + $this->sUrl = \MetaModel::GetConfig()->Get('app_root_url'); + @chmod($sConfigFile, 0444); // Read-only + $oRestProfile = \MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'REST Services User'), true); $oAdminProfile = \MetaModel::GetObjectFromOQL("SELECT URP_Profiles WHERE name = :name", array('name' => 'Administrator'), true); @@ -232,8 +238,7 @@ JSON; $aPostFields['json_data'] = $sJsonDataContent; } - $sUrl = \MetaModel::GetConfig()->Get('app_root_url'); - curl_setopt($ch, CURLOPT_URL, "$sUrl/webservices/rest.php"); + curl_setopt($ch, CURLOPT_URL, "$this->sUrl/webservices/rest.php"); curl_setopt($ch, CURLOPT_POST, 1);// set post data to true curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); From c4756e8cec170739efc3105869442529529f7492 Mon Sep 17 00:00:00 2001 From: Pierre Goiffon Date: Tue, 8 Dec 2020 18:47:24 +0100 Subject: [PATCH 21/21] =?UTF-8?q?Upgrade=20version=20n=C2=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- datamodels/2.x/version.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datamodels/2.x/version.xml b/datamodels/2.x/version.xml index 85c3a9797..c72a68d13 100755 --- a/datamodels/2.x/version.xml +++ b/datamodels/2.x/version.xml @@ -1,4 +1,4 @@ - 2.7.2 + 2.7.3