Files
iTop/datamodels/2.x/itop-hub-connector/launch.php

455 lines
17 KiB
PHP

<?php
// Copyright (C) 2017-2024 Combodo SAS
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
/**
* iTop Hub Launch Page
* Collect the information to be posted to iTopHub
*
* @copyright Copyright (c) 2017-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
/**
* Collect the configuration information to be posted to the hub
*
* @return string[][]
*/
/*
*
* json schema available on itop hub, under this url : /bundles/combodoremoteitop/json_schema/itop-configuration.schema.json
*
* syntactically valid fictional file sample, :
*
*
* {
* "itop_hub_target_route": "view_dashboard|browse_extensions|deploy_extensions|read_documentation"
* ,
* "itop_stack":{
* "uuidBdd" : "11a90082-b8a6-11e6-90f5-56524dec1a20",
* "uuidFile" : "11a90082-b8a6-11e6-90f5-56352dec71a2",
* "instance_friendly_name" : "example friendly name",
* "instance_host" : "http://example.com",
* "application_name" : "iTop",
* "application_version" : "2.4.0",
* "itop_user_id" : "42",
* "itop_user_lang" : "fr",
* "itop_modules" : {
* "foo-bar": "1.0.1",
* "barBaz": "1.3-dev"
* },
* "itop_extensions" : {
* "itop-extra-extension": {
* "label": "Super Nice Addon for iTop",
* "value": "1.2.0"
* },
* "itop-hyper-extension": {
* "label": "Hyper Fabulous Extension",
* "value": "2.5.1"
* },
* },
* "itop_installation_options" : {
* "itop-service-mgmt": {
* "label": "Service Management for Enterprises",
* "value": "2.4.0"
* },
* "itop-simple-tickets": {
* "label": "Simple Ticket Managment",
* "value": "2.4.0"
* },
* }
* },
*
* "server_stack":{
* "os_name": "Linux",
* "web_server_name": "apache",
* "web_server_version": "2.4.12",
* "database_name": "MySQL",
* "database_version": "5.7-ubuntu",
* "database_settings":{
* "max_allowed_packet": "314116"
* },
* "php_version": "7.1",
* "php_settings":{
* "timezone": "Europe/Paris",
* "memory_limit": "128M"
* },
* "php_extensions":{
* "php-mysql": "1.2",
* "php-mcrypt": "3.1.6"
* }
* }
* }
*
*
*/
use Combodo\iTop\Application\WebPage\ErrorPage;
use Combodo\iTop\Application\WebPage\NiceWebPage;
/**
* Return a cleaned (i.e.
* properly truncated) versin number from
* a very long version number like "7.0.18-0unbuntu0-16.04.1"
*
* @param string $sString
*
* @return string
*/
function CleanVersionNumber($sString)
{
$aMatches = [];
if (preg_match("|^([0-9\\.]+)-|", $sString, $aMatches)) {
return $aMatches[1];
}
return $sString;
}
function collect_configuration()
{
$aConfiguration = [
'php' => [],
'mysql' => [],
'apache' => [],
];
// Database information
$m_oMysqli = CMDBSource::GetMysqli();
$aConfiguration['database_settings']['server'] = (string)$m_oMysqli->server_version;
$aConfiguration['database_settings']['client'] = (string)$m_oMysqli->client_version;
/** @var mysqli_result $resultSet */
$result = CMDBSource::Query('SHOW VARIABLES LIKE "%max_allowed_packet%"');
if ($result) {
$row = $result->fetch_object();
$aConfiguration['database_settings']['max_allowed_packet'] = (string)$row->Value;
}
/** @var mysqli_result $resultSet */
$result = CMDBSource::Query('SHOW VARIABLES LIKE "%version_comment%"');
if ($result) {
$row = $result->fetch_object();
if (preg_match('/mariadb/i', $row->Value)) {
$aConfiguration['database_name'] = 'MariaDB';
}
}
// Web server information
if (function_exists('apache_get_version')) {
$aConfiguration['web_server_name'] = 'apache';
$aConfiguration['web_server_version'] = apache_get_version();
} else {
// The format of the variable $_SERVER["SERVER_SOFTWARE"] seems to be the following:
// PHP 7 FPM with Apache on Ubuntu: "Apache/2.4.18 (Ubuntu)"
// IIS 7.5 on Windows 7: "Microsoft-IIS/7.5"
// Nginx with PHP FPM on Ubuntu: "nginx/1.10.0"
$aConfiguration['web_server_name'] = substr($_SERVER["SERVER_SOFTWARE"], 0, strpos($_SERVER["SERVER_SOFTWARE"], '/'));
$sWebServerVersion = trim(substr($_SERVER["SERVER_SOFTWARE"], 1 + strpos($_SERVER["SERVER_SOFTWARE"], '/')));
if ($sWebServerVersion == '') {
$sWebServerVersion = 'Unknown';
}
$aConfiguration['web_server_version'] = $sWebServerVersion;
}
// PHP extensions
if (!MetaModel::GetConfig()->GetModuleSetting('itop-hub-connector', 'php_extensions_enable', true)) {
$aConfiguration['php_extensions'] = [];
} else {
foreach (get_loaded_extensions() as $extension) {
$aConfiguration['php_extensions'][$extension] = $extension;
}
}
// Collect some PHP settings having a known impact on iTop
$aIniGet = MetaModel::GetConfig()->GetModuleSetting('itop-hub-connector', 'php_settings_array', []); // by default, on the time of the writting, it values are : array('post_max_size', 'upload_max_filesize', 'apc.enabled', 'timezone', 'memory_limit', 'max_execution_time');
$aConfiguration['php_settings'] = [];
foreach ($aIniGet as $iniGet) {
$aConfiguration['php_settings'][$iniGet] = (string)ini_get($iniGet);
}
// iTop modules
$oConfig = MetaModel::GetConfig();
$sLatestInstallationDate = CMDBSource::QueryToScalar("SELECT max(installed) FROM ".$oConfig->Get('db_subname')."priv_module_install");
// Get the latest installed modules, without the "root" ones (iTop version and datamodel version)
$aInstalledModules = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install WHERE installed = '".$sLatestInstallationDate."' AND parent_id != 0");
foreach ($aInstalledModules as $aDBInfo) {
$aConfiguration['itop_modules'][$aDBInfo['name']] = $aDBInfo['version'];
}
// iTop Installation Options, i.e. "Extensions"
$oExtensionMap = new iTopExtensionsMap();
$oExtensionMap->LoadChoicesFromDatabase($oConfig);
$aConfiguration['itop_extensions'] = [];
foreach ($oExtensionMap->GetChoices() as $oExtension) {
switch ($oExtension->sSource) {
case iTopExtension::SOURCE_MANUAL:
case iTopExtension::SOURCE_REMOTE:
$aConfiguration['itop_extensions'][$oExtension->sCode] = [
'label' => $oExtension->sLabel,
'value' => $oExtension->sInstalledVersion,
];
break;
default:
$aConfiguration['itop_installation_options'][$oExtension->sCode] = [
'label' => $oExtension->sLabel,
'value' => true,
];
}
}
return $aConfiguration;
}
function MakeDataToPost($sTargetRoute)
{
if (MetaModel::GetConfig()->Get('demo_mode')) {
// Don't expose such information in demo mode
$aDataToPost = ['disabled' => true, 'reason' => 'demo_mode'];
} else {
$aConfiguration = collect_configuration();
$aDataToPost = [
'itop_hub_target_route' => $sTargetRoute,
'itop_stack' => [
"uuidBdd" => (string)trim(DBProperty::GetProperty('database_uuid', ''), '{}'), // TODO check if empty and... regenerate a new UUID ??
"uuidFile" => (string)trim(@file_get_contents(utils::GetDataPath()."instance.txt"), "{} \n"), // TODO check if empty and... regenerate a new UUID ??
'instance_friendly_name' => (string)$_SERVER['SERVER_NAME'],
'instance_host' => (string)utils::GetAbsoluteUrlAppRoot(),
'application_name' => (string)ITOP_APPLICATION,
'application_version' => (string)ITOP_VERSION,
'application_version_full' => (string)Dict::Format('UI:iTopVersion:Long', ITOP_APPLICATION, ITOP_VERSION, ITOP_REVISION, ITOP_BUILD_DATE),
'itop_user_id' => (string)(UserRights::GetUserId() === null) ? "1" : UserRights::GetUserId(),
'itop_user_lang' => (string)UserRights::GetUserLanguage(),
'itop_modules' => (object)$aConfiguration['itop_modules'],
'itop_extensions' => (object)$aConfiguration['itop_extensions'],
'itop_installation_options' => (object)$aConfiguration['itop_installation_options'],
],
'server_stack' => [
'os_name' => (string)PHP_OS,
'web_server_name' => (string)$aConfiguration['web_server_name'],
'web_server_version' => (string)$aConfiguration['web_server_version'],
'database_name' => (string)isset($aConfiguration['database_name']) ? $aConfiguration['database_name'] : 'MySQL', // if we do not detect MariaDB, we assume this is mysql
'database_version' => (string)CMDBSource::GetDBVersion(),
'database_settings' => (object)$aConfiguration['database_settings'],
'php_version' => (string)CleanVersionNumber(phpversion()),
'php_settings' => (object)$aConfiguration['php_settings'],
'php_extensions' => (object)$aConfiguration['php_extensions'],
],
];
}
return $aDataToPost;
}
try {
require_once(APPROOT.'/application/application.inc.php');
require_once(APPROOT.'/setup/extensionsmap.class.inc.php');
require_once('hubconnectorpage.class.inc.php');
require_once(APPROOT.'/application/startup.inc.php');
require_once('TokenValidation.php');
$sTargetRoute = utils::ReadParam('target', ''); // ||browse_extensions|deploy_extensions|
if ($sTargetRoute != 'inform_after_setup') {
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLoginEx(null, true /* $bMustBeAdmin */); // Check user rights and prompt if needed
}
$sHubUrlStateless = MetaModel::GetModuleSetting('itop-hub-connector', 'url').MetaModel::GetModuleSetting('itop-hub-connector', 'route_landing_stateless');
$sHubUrl = MetaModel::GetModuleSetting('itop-hub-connector', 'url').MetaModel::GetModuleSetting('itop-hub-connector', 'route_landing');
// Display... or not... the page
switch ($sTargetRoute) {
case 'inform_after_setup':
// Hidden IFRAME at the end of the setup
$sParamToken = utils::ReadParam('setup_token');
$oTokenValidation = new TokenValidation();
$bIsTokenValid = $oTokenValidation->isSetupTokenValid($sParamToken);
if (UserRights::IsAdministrator() || $bIsTokenValid) {
$oPage = new NiceWebPage('');
$aDataToPost = MakeDataToPost($sTargetRoute);
$oPage->add('<form id="hub_launch_form" action="'.$sHubUrlStateless.'" method="post">');
$oPage->add('<input type="hidden" name="json" value="'.utils::EscapeHtml(json_encode($aDataToPost)).'">');
$oPage->add_ready_script('$("#hub_launch_form").trigger(\'submit\');');
} else {
IssueLog::Error('TokenValidation failed on inform_after_setup page');
throw new Exception("Not allowed");
}
break;
default:
// All other cases, special "Hub like" web page
if ($sTargetRoute == 'view_dashboard') {
$sTitle = Dict::S('Menu:iTopHub:Register');
$sLabel = Dict::S('Menu:iTopHub:Register+');
$sText = Dict::S('Menu:iTopHub:Register:Description');
} else {
$sTitle = Dict::S('Menu:iTopHub:BrowseExtensions');
$sLabel = Dict::S('Menu:iTopHub:BrowseExtensions+');
$sText = Dict::S('Menu:iTopHub:BrowseExtensions:Description');
}
$sLogoUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/itophub-logo.svg';
$sArrowUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/white-arrow-right.svg';
$sCloseUrl = utils::GetAbsoluteUrlModulesRoot().'/itop-hub-connector/images/black-close.svg';
$oPage = new HubConnectorPage(Dict::S('iTopHub:Connect'));
$oPage->LinkScriptFromModule('itop-hub-connector/js/hub.js');
$oPage->LinkStylesheetFromAppRoot('css/font-combodo/font-combodo.css');
$oPage->LinkStylesheetFromModule('itop-hub-connector/css/hub.css');
$aDataToPost = MakeDataToPost($sTargetRoute);
if (MetaModel::GetConfig()->Get('demo_mode')) {
$oPage->add("<div class=\"header_message message_info\">Sorry, iTop is in <b>demonstration mode</b>: the connection to iTop Hub is disabled.</div>");
}
$oPage->add('<div id="hub_top_banner"></div>');
$oPage->add('<div id="hub_launch_content">');
$oPage->add('<div id="hub_launch_container">');
$oPage->add('<div id="hub_launch_image">');
$oPage->add(file_get_contents(__DIR__.'/images/rocket.svg'));
$oPage->add('</div>');
$oPage->add('<h1 class="ibo-title--text title is-size-3"><img src="'.$sLogoUrl.'"><span>'.$sTitle.'</span></h1>');
$oPage->add($sText);
$sButtonLabelClose = Dict::S('iTopHub:CloseBtn');
$sButtonLabelGo = Dict::S('iTopHub:GoBtn');
$sButtonLabelTooltip = Dict::S('iTopHub:GoBtn:Tooltip');
$oPage->add(
<<<HTML
<p>
<button type="button" class="ibo-button" id="CancelBtn" title="Go back to iTop"><img src="$sCloseUrl"><span class="ibo-button--label">$sButtonLabelClose</span></button>
<span class="horiz-spacer"></span>
<button type="button" class="ibo-button positive" id="GoToHubBtn" title="$sButtonLabelTooltip"><span class="ibo-button--label">$sButtonLabelGo</span><img src="$sArrowUrl"></button>
</p>
HTML
);
$sFormTarget = appUserPreferences::GetPref('itophub_open_in_new_window', 1) ? 'target="_blank"' : '';
$oPage->add('<form '.$sFormTarget.' id="hub_launch_form" action="'.$sHubUrl.'" method="post">');
$oPage->add('<input type="hidden" name="json" value="'.utils::EscapeHtml(json_encode($aDataToPost)).'">');
// $sNewWindowChecked = appUserPreferences::GetPref('itophub_open_in_new_window', 1) == 1 ? 'checked' : '';
// $oPage->add('<p><input type="checkbox" class="userpref" id="itophub_open_in_new_window" '.$sNewWindowChecked.'><label for="itophub_open_in_new_window">'.Dict::S('iTopHub:OpenInNewWindow').'</label><br/>');
// Beware the combination auto-submit and open in new window (cf above) is blocked by (some) browsers (namely Chrome)
$sAutoSubmitChecked = appUserPreferences::GetPref('itophub_auto_submit', 0) == 1 ? 'checked' : '';
$oPage->add('<label><input type="checkbox" class="userpref" id="itophub_auto_submit" '.$sAutoSubmitChecked.'>&nbsp;'.Dict::S('iTopHub:AutoSubmit').'</label></p>');
$oPage->add('</form>');
$oPage->add('<div style="clear:both"></div>');
$oPage->add('</div>');
$oPage->add('</div>');
$oPage->add_ready_script('$(".userpref").on("click", function() { var value = $(this).prop("checked") ? 1 : 0; var code = $(this).attr("id"); SetUserPreference(code, value, true); });');
if (MetaModel::GetConfig()->Get('demo_mode')) {
$oPage->add_ready_script(
<<<JS
$("#GoToHubBtn").prop('disabled', true);
$("#itophub_auto_submit").prop('disabled', true).prop('checked', false);
$("#CancelBtn").on("click", function() {
window.history.back();
});
JS
);
} else {
$oPage->add_ready_script(
<<<JS
$("#GoToHubBtn").on("click", function() {
$(this).prop('disabled', true);
$("#hub_launch_image").addClass("animate");
window.setTimeout(function () {
var bNewWindow = $('#itophub_open_in_new_window').prop("checked");
if(bNewWindow) { $("#hub_launch_form").attr("target", "_blank"); } else { $("#hub_launch_form").removeAttr("target"); }
$('#hub_launch_form').trigger('submit');
window.setTimeout(function () {
$("#GoToHubBtn").prop('disabled', false);
$("#hub_launch_image").removeClass("animate");
}, 5000);
}, 1000);
});
$("#CancelBtn").on("click", function() {
window.history.back();
});
JS
);
}
if (appUserPreferences::GetPref('itophub_auto_submit', 0) == 1) {
$oPage->add_ready_script('$("#GoToHubBtn").trigger("click");');
}
if (utils::ReadParam('show-json', false)) {
$oPage->add('<h1>DEBUG : json</h1>');
$oPage->add('<pre class="wizContainer">'.json_encode($aDataToPost, JSON_PRETTY_PRINT).'</pre>');
}
}
$oPage->output();
} catch (CoreException $e) {
require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
$oP->error(Dict::Format('UI:Error_Details', $e->getHtmlDesc()));
$oP->output();
if (MetaModel::IsLogEnabledIssue()) {
if (MetaModel::IsValidClass('EventIssue')) {
$oLog = new EventIssue();
$oLog->Set('message', $e->getMessage());
$oLog->Set('userinfo', '');
$oLog->Set('issue', $e->GetIssue());
$oLog->Set('impact', 'Page could not be displayed');
$oLog->Set('callstack', $e->getTrace());
$oLog->Set('data', $e->getContextData());
$oLog->DBInsertNoReload();
}
IssueLog::Error($e->getMessage());
}
// For debugging only
// throw $e;
} catch (Exception $e) {
require_once(APPROOT.'/setup/setuppage.class.inc.php');
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
$oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
$oP->output();
if (MetaModel::IsLogEnabledIssue()) {
if (MetaModel::IsValidClass('EventIssue')) {
$oLog = new EventIssue();
$oLog->Set('message', $e->getMessage());
$oLog->Set('userinfo', '');
$oLog->Set('issue', 'PHP Exception');
$oLog->Set('impact', 'Page could not be displayed');
$oLog->Set('callstack', $e->getTrace());
$oLog->Set('data', []);
$oLog->DBInsertNoReload();
}
IssueLog::Error($e->getMessage());
}
}