Compare commits

...

43 Commits

Author SHA1 Message Date
Eric Espie
5475b9fbbe N°3454 - MoveToProd in 2 steps - fix utils::GetCurrentModuleName() 2023-07-25 17:44:43 +02:00
Eric Espie
6f8e7c7002 N°3454 - MoveToProd in 2 steps - fix utils::GetCurrentModuleUrl() 2023-07-25 17:20:37 +02:00
Pierre Goiffon
bc7c1b4744 N°6590 Fix DictionariesConsistencyTest for PL dict files 2023-07-24 11:14:37 +02:00
Eric Espie
4d8246c4d8 N°6436 - Integrate Performance Audit pre requisite in iTop Pro 2.7.9 (changed config variable name) 2023-07-19 15:13:43 +02:00
Eric Espie
5c61d725e1 N°6436 - Integrate Performance Audit pre requisite in iTop Pro 2.7.9 (changed config variable name) 2023-07-19 15:06:00 +02:00
Eric Espie
2c4cad4dac N°6436 - Integrate Performance Audit pre requisite in iTop Pro 2.7.9 (avoid unnecessary calls) 2023-07-19 10:37:41 +02:00
Eric Espie
da45651121 Merge branch 'feature/6548_Hide_DBHost_and_DBUser_in_log' into support/2.7 2023-07-18 09:34:48 +02:00
Eric Espie
d388ce9a06 Merge branch 'feature/6548_Hide_DBHost_and_DBUser_in_log' into support/2.7 2023-07-18 09:17:40 +02:00
Eric Espie
47e71d8838 Merge branch 'feature/6436-Integrate_Performance_Audit_extensibility' into support/2.7 2023-07-18 09:17:05 +02:00
Stephen Abello
2b5973ec67 N°6436 - Integrate Performance Audit pre requisite in iTop Pro 2.7.9 2023-07-18 09:15:37 +02:00
Eric Espie
78396d8e4a 6548 - [ER] Hide DBHost and DBUser in log 2023-07-10 17:37:27 +02:00
Stephen Abello
9afc22bd8f N°6123 - Add tests and comments 2023-07-07 09:29:15 +02:00
Pierre Goiffon
264a8cd70a N°6494 - Some tests are run twice, some never
(cherry picked from commit a2a0b2cd0b)

(cherry picked from commit 4c9ea0c9d4)

# Conflicts:
#	tests/php-unit-tests/integration-tests/DictionariesConsistencyTest.php
2023-07-06 15:45:09 +02:00
Stephen Abello
aa1834170b N°6427 - Fix SwiftMailer not retrieving sendmail path 2023-07-06 14:31:54 +02:00
Stephen Abello
f94d67ab35 N°6340 - Fix permission refused when sending an email and renewing OAuth token in synchronous mode 2023-07-06 10:28:10 +02:00
Stephen Abello
3048c8c41f N°5560 - Display an error when trying to regenerate an expired OAuth token 2023-07-06 09:52:00 +02:00
Stephen Abello
246e4a9f50 N°6123 - Fix warnings when launching a backup on MariaDB > v10.6.1 with localhost dbhost 2023-07-06 09:28:01 +02:00
Molkobain
6d58adb6dd N°6359 - Fix JS crash due to new version trying to detect MSIE browser through a dependency that we don't have.
Cherry-picked from f889c53d71
2023-07-05 08:41:00 +02:00
Pierre Goiffon
5a0b5364d6 N°4698 setup/phpinfo.php : if no iTop installation then display a proper message instead of an exception (#265) 2023-06-14 10:18:38 +02:00
Pierre Goiffon
76eed2eba0 N°6098 updateLicenses script : check availability of the required JQ command (#458)
This packaging script requires both bash and the JQ command when running on Windows.
If the later isn't available, it will run without throwing an error...

With this change the script will now check directly at launch for the JQ command availability, and exit in error if it isn't.
2023-06-14 10:17:00 +02:00
Eric Espie
1ec671ef61 N°6351 - code hardening 2023-06-14 09:08:42 +02:00
Eric Espie
72716b7ec8 N°6396 - Protect URL display 2023-06-12 11:36:51 +02:00
Eric Espie
4f999de844 N°6359 - ⬆️ Update jQuery BBQ (from https://github.com/cee-chen/jquery-bbq) 2023-06-08 14:30:09 +02:00
odain
ea49c0a87c enable authent-cas in ci 2023-06-07 21:44:17 +02:00
odain
6cc971849b ci: enhance AddProfile 2023-06-07 21:44:00 +02:00
Pierre Goiffon
2405810864 N°6238 Security hardening 2023-06-07 16:45:35 +02:00
Eric Espie
fff46d99fc N°6358 - Login REST API - renamed test 2023-06-07 15:31:51 +02:00
odain
3a891f707c ci: enhance AddProfile test method to work with any User (not only UserLocal) 2023-06-07 15:06:28 +02:00
odain
8b6ea43ebe N°6358 - Login REST API - fix cas + add tests 2023-06-07 15:05:32 +02:00
Eric Espie
90cf7502e8 N°6358 - Login REST API 2023-06-07 10:09:30 +02:00
Eric Espie
c596fa2967 N°6358 - Login API REST 2023-06-07 09:17:24 +02:00
Timothee
a45177410e N°6350 - Fixing phpunit test 2023-06-06 16:47:06 +02:00
Eric Espie
9e96ea2873 N°6350 - code hardening 2023-06-01 15:35:56 +02:00
Eric Espie
1172159745 N°6351 - code hardening 2023-06-01 15:12:50 +02:00
Pierre Goiffon
fa038ded3d N°6254 ItopDataTestCase::CreateUserRequest : fix new argument default value
Was creating error Too few arguments passed
2023-04-26 16:42:27 +02:00
Pierre Goiffon
e7ea1b831c N°6254 ItopDataTestCase::CreateUserRequest : now pass fields values as array
More versatile way of doing things !
2023-04-26 16:22:26 +02:00
Molkobain
4aff65f98b N°6217 - Add accessiblity meta data for title on "Power menu" 2023-04-25 21:51:32 +02:00
acognet
3c94974d9d N°541 - Dashlets: Improve readability when to much labels (pie chart) or too long labels (bar chart) 2023-04-25 12:09:11 +02:00
Molkobain
fbd72b2783 N°6217 - Add accessiblity meta data for title on "Power menu" 2023-04-20 11:03:43 +02:00
Anne-Catherine
4e95ca3c7b N°541 - Dashlets: Improve readability when to much labels (pie chart) or too long labels (bar chart) (#452)
* N°541 - Dashlets: Improve readability when to much labels (pie chart) or too long labels (bar chart)
2023-04-13 11:23:20 +02:00
Pierre Goiffon
1114ed9562 N°6099 DeadLockLog : improve documentation and use existing constants (#441) 2023-04-12 10:21:34 +02:00
Pierre Goiffon
34368fe795 N°6173 \HTMLSanitizer::Sanitize : Fix handling only svg_sanitizer (#450) 2023-04-11 17:52:41 +02:00
Molkobain
0f016d7511 N°6112 - Dashboard: Improve robustness by trimming dashlet ID returned by server 2023-03-17 15:37:57 +01:00
72 changed files with 1734 additions and 541 deletions

View File

@@ -19,17 +19,24 @@
* The target license file path is in `$xmlFilePath`
*/
$iTopFolder = __DIR__ . "/../../" ;
$xmlFilePath = $iTopFolder . "setup/licenses/community-licenses.xml";
$iTopFolder = __DIR__."/../../";
$xmlFilePath = $iTopFolder."setup/licenses/community-licenses.xml";
function get_scope($product_node)
{
$jqExec = shell_exec("jq -V"); // a param is mandatory otherwise the script will freeze
if ((null === $jqExec) || (false === $jqExec)) {
echo "/!\ JQ is required but cannot be launched :( \n";
echo "Check this script PHPDoc block for instructions\n";
die(-1);
}
function get_scope($product_node) {
$scope = $product_node->getAttribute("scope");
if ($scope === "")
{ //put iTop first
if ($scope === "") { //put iTop first
return "aaaaaaaaa";
}
return $scope;
}

View File

@@ -1857,4 +1857,28 @@ class RestUtils
interface iModuleExtension
{
public function __construct();
}
/**
* KPI logging extensibility point
*
* KPI Logger extension
*/
interface iKPILoggerExtension
{
/**
* Init the statistics collected
*
* @return void
*/
public function InitStats();
/**
* Add a new KPI to the stats
*
* @param \Combodo\iTop\Core\Kpi\KpiLogData $oKPILogData
*
* @return mixed
*/
public function LogOperation($oKPILogData);
}

View File

@@ -4003,7 +4003,9 @@ EOF
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$oExtensionInstance->OnDBInsert($this, self::GetCurrentChange());
$oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBInsert($this, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
}
return $res;
@@ -4020,13 +4022,16 @@ EOF
protected function DBCloneTracked_Internal($newKey = null)
{
$oNewObj = parent::DBCloneTracked_Internal($newKey);
/** @var cmdbAbstractObject $oNewObj */
$oNewObj = MetaModel::GetObject(get_class($this), parent::DBCloneTracked_Internal($newKey));
// Invoke extensions after insertion (the object must exist, have an id, etc.)
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBInsert($oNewObj, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBInsert');
}
return $oNewObj;
@@ -4054,7 +4059,9 @@ EOF
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBUpdate($this, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBUpdate');
}
}
catch (Exception $e)
@@ -4100,7 +4107,9 @@ EOF
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$oKPI = new ExecutionKPI();
$oExtensionInstance->OnDBDelete($this, self::GetCurrentChange());
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnDBDelete');
}
return parent::DBDeleteTracked_Internal($oDeletionPlan);
@@ -4118,7 +4127,10 @@ EOF
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
if ($oExtensionInstance->OnIsModified($this))
$oKPI = new ExecutionKPI();
$bIsModified = $oExtensionInstance->OnIsModified($this);
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnIsModified');
if ($bIsModified)
{
return true;
}
@@ -4162,7 +4174,9 @@ EOF
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$oKPI = new ExecutionKPI();
$aNewIssues = $oExtensionInstance->OnCheckToWrite($this);
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToWrite');
if (is_array($aNewIssues) && (count($aNewIssues) > 0)) // Some extensions return null instead of an empty array
{
$this->m_aCheckIssues = array_merge($this->m_aCheckIssues, $aNewIssues);
@@ -4210,7 +4224,9 @@ EOF
/** @var \iApplicationObjectExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iApplicationObjectExtension') as $oExtensionInstance)
{
$oKPI = new ExecutionKPI();
$aNewIssues = $oExtensionInstance->OnCheckToDelete($this);
$oKPI->ComputeStatsForExtension($oExtensionInstance, 'OnCheckToDelete');
if (is_array($aNewIssues) && count($aNewIssues) > 0)
{
$this->m_aDeleteIssues = array_merge($this->m_aDeleteIssues, $aNewIssues);
@@ -4722,7 +4738,7 @@ EOF
$bResult = (count($aErrors) == 0);
if ($bResult)
{
list($bResult, $aErrors) = $oObj->CheckToWrite();
[$bResult, $aErrors] = $oObj->CheckToWrite();
}
if ($bPreview)
{

View File

@@ -372,7 +372,7 @@ EOF;
if (!$oPage->IsPrintableVersion())
{
$sMenuTitle = Dict::S('UI:ConfigureThisList');
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><i class="fas fa-tools"></i><i class="fas fa-caret-down"></i><ul>';
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li aria-label="'.Dict::S('UI:Menu:Toolkit').'"><i class="fas fa-tools"></i><i class="fas fa-caret-down"></i><ul>';
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
$aActions = array(

View File

@@ -1009,6 +1009,7 @@ EOF
$iTotalCount = 0;
$aValues = array();
$aURLs = array();
foreach ($aRes as $iRow => $aRow)
{
$sValue = $aRow['grouped_by_1'];
@@ -1016,7 +1017,8 @@ EOF
$aGroupBy[(int)$iRow] = (int) $aRow[$sFctVar];
$iTotalCount += $aRow['_itop_count_'];
$aValues[] = array('label' => html_entity_decode(strip_tags($sHtmlValue), ENT_QUOTES, 'UTF-8'), 'label_html' => $sHtmlValue, 'value' => (int) $aRow[$sFctVar]);
// Build the search for this subset
$oSubsetSearch = $this->m_oFilter->DeepClone();
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($sValue));
@@ -1030,16 +1032,23 @@ EOF
{
case 'bars':
$aNames = array();
$iMaxNbCharsInLabel = 0;
foreach($aValues as $idx => $aValue)
{
$aNames[$idx] = $aValue['label'];
if ($iMaxNbCharsInLabel < mb_strlen($aValue['label'])) {
$iMaxNbCharsInLabel = mb_strlen($aValue['label']);
}
}
$sJSNames = json_encode($aNames);
$sJson = json_encode($aValues);
$oPage->add_ready_script(
<<<EOF
var iChartDefaultHeight = 200,
iChartLegendHeight = 6 * $iMaxNbCharsInLabel,
iChartTotalHeight = iChartDefaultHeight + iChartLegendHeight;
$('#my_chart_$sId').height(iChartTotalHeight+ 'px');
var chart = c3.generate({
bindto: d3.select('#my_chart_$sId'),
data: {
@@ -1107,8 +1116,19 @@ EOF
}
$sJSColumns = json_encode($aColumns);
$sJSNames = json_encode($aNames);
$iNbLinesToAddForName = 0;
if (count($aNames) > 50) {
// Calculation of the number of legends line add to the height of the graph to have a maximum of 5 legend columns
$iNbLinesIncludedInChartHeight = 10;
$iNbLinesToAddForName = ceil(count($aNames) / 5) - $iNbLinesIncludedInChartHeight;
}
$oPage->add_ready_script(
<<<EOF
// Calculate height of graph : 200px (minimum height for the chart) + 20*iNbLinesToAddForName for the legend
var iChartDefaultHeight = 200,
iChartLegendHeight = 20 * $iNbLinesToAddForName,
iChartTotalHeight = (iChartDefaultHeight + iChartLegendHeight);
$('#my_chart_$sId').height(iChartTotalHeight + 'px');
var chart = c3.generate({
bindto: d3.select('#my_chart_$sId'),
data: {
@@ -1915,11 +1935,13 @@ class MenuBlock extends DisplayBlock
{
if (count($aFavoriteActions) > 0)
{
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."<i class=\"fas fa-caret-down\"></i>"."\n<ul>\n";
$sActionsMenuLabel = Dict::S('UI:Menu:OtherActions');
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li aria-label=\"{$sActionsMenuLabel}\">{$sActionsMenuLabel}<i class=\"fas fa-caret-down\"></i>"."\n<ul>\n";
}
else
{
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."<i class=\"fas fa-caret-down\"></i>"."\n<ul>\n";
$sActionsMenuLabel = Dict::S('UI:Menu:Actions');
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li aria-label=\"{$sActionsMenuLabel}\">{$sActionsMenuLabel}<i class=\"fas fa-caret-down\"></i>"."\n<ul>\n";
}
$sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions);

View File

@@ -1219,7 +1219,7 @@ EOF;
{
$sLogonMessage = Dict::Format('UI:LoggedAsMessage', $sUserName);
}
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><i class=\"top-right-icon icon-additional-arrow fas fa-power-off\"></i><ul>";
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li aria-label=\"" . Dict::S("UI:PowerMenu") . "\"><i class=\"top-right-icon icon-additional-arrow fas fa-power-off\"></i><ul>";
$sLogOffMenu .= "<li><span>$sLogonMessage</span></li>\n";
$aActions = array();

View File

@@ -51,7 +51,7 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnCheckCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'basic')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'basic')
{
list($sAuthUser, $sAuthPwd) = $this->GetAuthUserAndPassword();
if (!UserRights::CheckCredentials($sAuthUser, $sAuthPwd, $_SESSION['login_mode'], 'internal'))
@@ -67,7 +67,7 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnCredentialsOK(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'basic')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'basic')
{
$sAuthUser = $_SESSION['auth_user'];
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
@@ -77,8 +77,13 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnError(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'basic')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'basic')
{
$iOnExit = LoginWebPage::getIOnExit();
if ($iOnExit === LoginWebPage::EXIT_RETURN)
{
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
}
LoginWebPage::HTTP401Error();
}
return LoginWebPage::LOGIN_FSM_CONTINUE;
@@ -86,7 +91,7 @@ class LoginBasic extends AbstractLoginFSMExtension
protected function OnConnected(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'basic')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'basic')
{
$_SESSION['can_logoff'] = true;
return LoginWebPage::CheckLoggedUser($iErrorCode);

View File

@@ -77,7 +77,7 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
{
self::ResetLoginSession();
$iOnExit = LoginWebPage::getIOnExit();
if ($iOnExit == LoginWebPage::EXIT_RETURN)
if ($iOnExit === LoginWebPage::EXIT_RETURN)
{
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
}
@@ -93,6 +93,12 @@ class LoginDefaultAfter extends AbstractLoginFSMExtension implements iLogoutExte
{
if (!isset($_SESSION['login_mode']))
{
// N°6358 - if EXIT_RETURN was asked, send an error
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
$iErrorCode = LoginWebPage::EXIT_CODE_WRONGCREDENTIALS;
return LoginWebPage::LOGIN_FSM_ERROR;
}
// If no plugin validated the user, exit
self::ResetLoginSession();
exit();

View File

@@ -35,7 +35,7 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnCheckCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'external')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'external')
{
$sAuthUser = $this->GetAuthUser();
if (!UserRights::CheckCredentials($sAuthUser, '', $_SESSION['login_mode'], 'external'))
@@ -51,7 +51,7 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnCredentialsOK(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'external')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'external')
{
$sAuthUser = $_SESSION['auth_user'];
LoginWebPage::OnLoginSuccess($sAuthUser, 'external', $_SESSION['login_mode']);
@@ -61,7 +61,7 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnConnected(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'external')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'external')
{
$_SESSION['can_logoff'] = false;
return LoginWebPage::CheckLoggedUser($iErrorCode);
@@ -71,8 +71,13 @@ class LoginExternal extends AbstractLoginFSMExtension
protected function OnError(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'external')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'external')
{
$iOnExit = LoginWebPage::getIOnExit();
if ($iOnExit === LoginWebPage::EXIT_RETURN)
{
return LoginWebPage::LOGIN_FSM_RETURN; // Error, exit FSM
}
LoginWebPage::HTTP401Error();
}
return LoginWebPage::LOGIN_FSM_CONTINUE;

View File

@@ -43,6 +43,10 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
exit;
}
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
// No credentials yet, display the form
$oPage = LoginWebPage::NewLoginWebPage();
$oPage->DisplayLoginForm($this->bForceFormOnError);
@@ -62,7 +66,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/
protected function OnCheckCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form')
{
$sAuthUser = utils::ReadPostedParam('auth_user', '', 'raw_data');
$sAuthPwd = utils::ReadPostedParam('auth_pwd', null, 'raw_data');
@@ -82,7 +86,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/
protected function OnCredentialsOK(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form')
{
$sAuthUser = $_SESSION['auth_user'];
// Store 'auth_user' in session for further use
@@ -96,7 +100,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/
protected function OnError(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form')
{
$this->bForceFormOnError = true;
}
@@ -108,7 +112,7 @@ class LoginForm extends AbstractLoginFSMExtension implements iLoginUIExtension
*/
protected function OnConnected(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'form')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'form')
{
$_SESSION['can_logoff'] = true;
return LoginWebPage::CheckLoggedUser($iErrorCode);

View File

@@ -40,7 +40,7 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnReadCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'url')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'url')
{
$_SESSION['login_temp_auth_user'] = utils::ReadParam('auth_user', '', false, 'raw_data');
}
@@ -49,7 +49,7 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnCheckCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'url')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'url')
{
$sAuthUser = utils::ReadParam('auth_user', '', false, 'raw_data');
$sAuthPwd = utils::ReadParam('auth_pwd', null, false, 'raw_data');
@@ -66,7 +66,7 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnCredentialsOK(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'url')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'url')
{
$sAuthUser = $_SESSION['auth_user'];
LoginWebPage::OnLoginSuccess($sAuthUser, 'internal', $_SESSION['login_mode']);
@@ -76,7 +76,7 @@ class LoginURL extends AbstractLoginFSMExtension
protected function OnError(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'url')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'url')
{
$this->bErrorOccurred = true;
}

View File

@@ -32,7 +32,7 @@ class LoginWebPage extends NiceWebPage
{
const EXIT_PROMPT = 0;
const EXIT_HTTP_401 = 1;
const EXIT_RETURN = 2;
const EXIT_RETURN = 2; // Non interactive mode (ajax, rest, ...)
const EXIT_CODE_OK = 0;
const EXIT_CODE_MISSINGLOGIN = 1;
@@ -352,14 +352,20 @@ class LoginWebPage extends NiceWebPage
$this->output();
}
public static function ResetSession()
public static function ResetSession($bFullCleanup = false)
{
// Unset all of the session variables.
unset($_SESSION['auth_user']);
unset($_SESSION['login_state']);
unset($_SESSION['can_logoff']);
unset($_SESSION['archive_mode']);
unset($_SESSION['impersonate_user']);
if ($bFullCleanup) {
// Unset all of the session variables.
foreach (array_keys($_SESSION) as $sKey) {
unset($_SESSION[$sKey]);
}
} else {
unset($_SESSION['auth_user']);
unset($_SESSION['login_state']);
unset($_SESSION['can_logoff']);
unset($_SESSION['archive_mode']);
unset($_SESSION['impersonate_user']);
}
UserRights::_ResetSessionCache();
// If it's desired to kill the session, also delete the session cookie.
// Note: This will destroy the session, and not just the session data!
@@ -931,7 +937,7 @@ class LoginWebPage extends NiceWebPage
}
else
{
if ($iOnExit == self::EXIT_RETURN)
if ($iOnExit === self::EXIT_RETURN)
{
return self::EXIT_CODE_PORTALUSERNOTAUTHORIZED;
}
@@ -987,7 +993,7 @@ class LoginWebPage extends NiceWebPage
{
if ($bMustBeAdmin && !UserRights::IsAdministrator())
{
if ($iOnExit == self::EXIT_RETURN)
if ($iOnExit === self::EXIT_RETURN)
{
return self::EXIT_CODE_MUSTBEADMIN;
}
@@ -1003,7 +1009,7 @@ class LoginWebPage extends NiceWebPage
}
$iRet = call_user_func(array(self::$sHandlerClass, 'ChangeLocation'), $sRequestedPortalId, $iOnExit);
}
if ($iOnExit == self::EXIT_RETURN)
if ($iOnExit === self::EXIT_RETURN)
{
return $iRet;
}

View File

@@ -91,4 +91,10 @@ else
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
}
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
try {
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
}
catch (MySQLException $e) {
IssueLog::Debug($e->getMessage());
throw new MySQLException('Could not connect to the DB server', []);
}

View File

@@ -17,6 +17,7 @@
* You should have received a copy of the GNU Affero General Public License
*/
use Combodo\iTop\Service\Module\ModuleService;
use ScssPhp\ScssPhp\Compiler;
@@ -361,7 +362,8 @@ class utils
// For URL
case 'url':
$retValue = filter_var($value, FILTER_SANITIZE_URL);
// N°6350 - returns only valid URLs
$retValue = filter_var($value, FILTER_VALIDATE_URL);
break;
default:
@@ -1945,24 +1947,7 @@ class utils
*/
public static function GetCurrentModuleName($iCallDepth = 0)
{
$sCurrentModuleName = '';
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
foreach(GetModulesInfo() as $sModuleName => $aInfo)
{
if ($aInfo['root_dir'] !== '')
{
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
if(substr($sCallerFile, 0, strlen($sRootDir)) === $sRootDir)
{
$sCurrentModuleName = $sModuleName;
break;
}
}
}
return $sCurrentModuleName;
return ModuleService::GetInstance()->GetCurrentModuleName($iCallDepth + 1);
}
/**
@@ -1978,24 +1963,7 @@ class utils
*/
public static function GetCurrentModuleDir($iCallDepth)
{
$sCurrentModuleDir = '';
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
foreach(GetModulesInfo() as $sModuleName => $aInfo)
{
if ($aInfo['root_dir'] !== '')
{
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
if(substr($sCallerFile, 0, strlen($sRootDir)) === $sRootDir)
{
$sCurrentModuleDir = basename($sRootDir);
break;
}
}
}
return $sCurrentModuleDir;
return ModuleService::GetInstance()->GetCurrentModuleDir($iCallDepth);
}
/**
@@ -2010,12 +1978,7 @@ class utils
*/
public static function GetCurrentModuleUrl()
{
$sDir = static::GetCurrentModuleDir(1);
if ( $sDir !== '')
{
return static::GetAbsoluteUrlModulesRoot().'/'.$sDir;
}
return '';
return ModuleService::GetInstance()->GetCurrentModuleUrl(1);
}
/**
@@ -2025,8 +1988,7 @@ class utils
*/
public static function GetCurrentModuleSetting($sProperty, $defaultvalue = null)
{
$sModuleName = static::GetCurrentModuleName(1);
return MetaModel::GetModuleSetting($sModuleName, $sProperty, $defaultvalue);
return ModuleService::GetInstance()->GetCurrentModuleSetting($sProperty, $defaultvalue);
}
/**
@@ -2035,12 +1997,7 @@ class utils
*/
public static function GetCompiledModuleVersion($sModuleName)
{
$aModulesInfo = GetModulesInfo();
if (array_key_exists($sModuleName, $aModulesInfo))
{
return $aModulesInfo[$sModuleName]['version'];
}
return null;
return ModuleService::GetInstance()->GetCompiledModuleVersion($sModuleName);
}
/**
@@ -2504,4 +2461,5 @@ class utils
return (substr(PHP_OS,0,3) === 'WIN');
}
}

View File

@@ -22,14 +22,8 @@ define('ITOP_DEFAULT_ENV', 'production');
define('MAINTENANCE_MODE_FILE', APPROOT.'data/.maintenance');
define('READONLY_MODE_FILE', APPROOT.'data/.readonly');
if (function_exists('microtime'))
{
$fItopStarted = microtime(true);
}
else
{
$fItopStarted = 1000 * time();
}
$fItopStarted = microtime(true);
$iItopInitialMemory = memory_get_usage(true);
if (! isset($GLOBALS['bBypassAutoload']) || $GLOBALS['bBypassAutoload'] == false)
{

View File

@@ -15,6 +15,7 @@
"combodo/tcpdf": "~6.4.4",
"firebase/php-jwt": "~6.4.0",
"guzzlehttp/guzzle": "^6.5.8",
"guzzlehttp/psr7": "~1.9.1",
"laminas/laminas-mail": "^2.11",
"laminas/laminas-servicemanager": "^3.5",
"league/oauth2-google": "^3.0",
@@ -61,6 +62,7 @@
"sources/application",
"sources/Composer",
"sources/Controller",
"sources/Service",
"sources/Core"
],
"exclude-from-classmap": [

21
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e5c0746c3d1bb9df9151c910e8f50955",
"content-hash": "abee0f7bd244530a88b08e1e338b0ec5",
"packages": [
{
"name": "combodo/tcpdf",
@@ -516,16 +516,16 @@
},
{
"name": "guzzlehttp/psr7",
"version": "1.9.0",
"version": "1.9.1",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318"
"reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318",
"reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b",
"reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b",
"shasum": ""
},
"require": {
@@ -544,11 +544,6 @@
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"autoload": {
"files": [
"src/functions_include.php"
@@ -606,7 +601,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/1.9.0"
"source": "https://github.com/guzzle/psr7/tree/1.9.1"
},
"funding": [
{
@@ -622,7 +617,7 @@
"type": "tidelift"
}
],
"time": "2022-06-20T21:43:03+00:00"
"time": "2023-04-17T16:00:37+00:00"
},
{
"name": "laminas/laminas-loader",
@@ -4757,5 +4752,5 @@
"platform-overrides": {
"php": "7.1.3"
},
"plugin-api-version": "2.1.0"
"plugin-api-version": "2.3.0"
}

View File

@@ -67,8 +67,7 @@ class MyHelpers
// format sss.mmmuuupppnnn
public static function getmicrotime()
{
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
return microtime(true);
}
/*
@@ -420,6 +419,7 @@ class MyHelpers
//}
return $sOutput;
}
}
/**
@@ -524,5 +524,3 @@ class Str
return (strtolower($sString) == $sString);
}
}
?>

View File

@@ -731,8 +731,9 @@ class CMDBSource
{
self::LogDeadLock($e);
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql, $e));
}
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
} finally {
$oKPI->ComputeStats('Query exec (mySQL)', $sSql);
}
if ($oResult === false)
{
$aContext = array('query' => $sSql);

View File

@@ -963,6 +963,14 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'log_kpi_generate_legacy_report' => array(
'type' => 'bool',
'description' => 'Generate the legacy KPI report (kpi.html)',
'default' => true,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'max_linkset_output' => array(
'type' => 'integer',
'description' => 'Maximum number of items shown when getting a list of related items in an email, using the form $this->some_list$. 0 means no limit.',

View File

@@ -188,8 +188,8 @@ final class ItopCounter
if (!$hDBLink)
{
throw new Exception("Could not connect to the DB server (host=$sDBHost, user=$sDBUser): ".mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno().')');
}
throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), array('host' => $sDBHost, 'user' => $sDBUser));
}
return $hDBLink;
}

View File

@@ -2225,7 +2225,7 @@ abstract class DBObject implements iDisplay
$oKPI = new ExecutionKPI();
$this->DoCheckToWrite();
$oKPI->ComputeStats('CheckToWrite', get_class($this));
$oKPI->ComputeStatsForExtension($this, 'DoCheckToWrite');
if (count($this->m_aCheckIssues) == 0)
{
$this->m_bCheckStatus = true;
@@ -2693,8 +2693,12 @@ abstract class DBObject implements iDisplay
$sRootClass = MetaModel::GetRootClass($sClass);
// Ensure the update of the values (we are accessing the data directly)
$oKPI = new ExecutionKPI();
$this->DoComputeValues();
$oKPI->ComputeStatsForExtension($this, 'DoComputeValues');
$oKPI = new ExecutionKPI();
$this->OnInsert();
$oKPI->ComputeStatsForExtension($this, 'OnInsert');
if ($this->m_iKey < 0)
{
@@ -2712,7 +2716,7 @@ abstract class DBObject implements iDisplay
}
// Ultimate check - ensure DB integrity
list($bRes, $aIssues) = $this->CheckToWrite();
[$bRes, $aIssues] = $this->CheckToWrite();
if (!$bRes)
{
throw new CoreCannotSaveObjectException(array('issues' => $aIssues, 'class' => get_class($this), 'id' => $this->GetKey()));
@@ -2818,7 +2822,9 @@ abstract class DBObject implements iDisplay
$this->m_aOrigValues[$sAttCode] = $value;
}
$oKPI = new ExecutionKPI();
$this->AfterInsert();
$oKPI->ComputeStatsForExtension($this, 'AfterInsert');
// Activate any existing trigger
$sClass = get_class($this);
@@ -3094,8 +3100,11 @@ abstract class DBObject implements iDisplay
try
{
$oKPI = new ExecutionKPI();
$this->DoComputeValues();
// Stop watches
$oKPI->ComputeStatsForExtension($this, 'DoComputeValues');
// Stop watches
$sState = $this->GetState();
if ($sState != '')
{
@@ -3114,7 +3123,9 @@ abstract class DBObject implements iDisplay
}
}
}
$this->OnUpdate();
$oKPI = new ExecutionKPI();
$this->OnUpdate();
$oKPI->ComputeStatsForExtension($this, 'OnUpdate');
$aChanges = $this->ListChanges();
if (count($aChanges) == 0)
@@ -3126,7 +3137,7 @@ abstract class DBObject implements iDisplay
}
// Ultimate check - ensure DB integrity
list($bRes, $aIssues) = $this->CheckToWrite();
[$bRes, $aIssues] = $this->CheckToWrite();
if (!$bRes)
{
throw new CoreCannotSaveObjectException(array(
@@ -3326,7 +3337,9 @@ abstract class DBObject implements iDisplay
try
{
$this->AfterUpdate();
$oKPI = new ExecutionKPI();
$this->AfterUpdate();
$oKPI->ComputeStatsForExtension($this, 'AfterUpdate');
// Reload to get the external attributes
if ($bHasANewExternalKeyValue)

View File

@@ -763,7 +763,10 @@ class DBObjectSet implements iDBObjectSetIterator
try
{
$oKPI = new ExecutionKPI();
$this->m_oSQLResult = CMDBSource::Query($sSQL);
$sOQL = $this->GetPseudoOQL($this->m_oFilter, $this->GetRealSortOrder(), $this->m_iLimitCount, $this->m_iLimitStart, false);
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
} catch (MySQLException $e)
{
// 1116 = ER_TOO_MANY_TABLES
@@ -843,8 +846,11 @@ class DBObjectSet implements iDBObjectSetIterator
{
if (is_null($this->m_iNumTotalDBRows))
{
$oKPI = new ExecutionKPI();
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, 0, 0, true);
$resQuery = CMDBSource::Query($sSQL);
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), 0, 0, true);
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
if (!$resQuery) return 0;
$aRow = CMDBSource::FetchArray($resQuery);
@@ -855,6 +861,42 @@ class DBObjectSet implements iDBObjectSetIterator
return $this->m_iNumTotalDBRows + count($this->m_aAddedObjects); // Does it fix Trac #887 ??
}
/**
* @param \DBSearch $oFilter
* @param array $aOrder
* @param int $iLimitCount
* @param int $iLimitStart
* @param bool $bCount
*
* @return string
*/
private function GetPseudoOQL($oFilter, $aOrder, $iLimitCount, $iLimitStart, $bCount)
{
$sOQL = '';
if ($bCount) {
$sOQL .= 'COUNT ';
}
$sOQL .= $oFilter->ToOQL();
if ($iLimitCount > 0) {
$sOQL .= ' LIMIT ';
if ($iLimitStart > 0) {
$sOQL .= "$iLimitStart, ";
}
$sOQL .= "$iLimitCount";
}
if (count($aOrder) > 0) {
$sOQL .= ' ORDER BY ';
$aOrderBy = [];
foreach ($aOrder as $sAttCode => $bAsc) {
$aOrderBy[] = $sAttCode.' '.($bAsc ? 'ASC' : 'DESC');
}
$sOQL .= implode(', ', $aOrderBy);
}
return $sOQL;
}
/**
* Check if the count exceeds a given limit
*
@@ -871,8 +913,11 @@ class DBObjectSet implements iDBObjectSetIterator
{
if (is_null($this->m_iNumTotalDBRows))
{
$oKPI = new ExecutionKPI();
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, $iLimit + 2, 0, true);
$resQuery = CMDBSource::Query($sSQL);
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), $iLimit + 2, 0, true);
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
if ($resQuery)
{
$aRow = CMDBSource::FetchArray($resQuery);
@@ -883,7 +928,7 @@ class DBObjectSet implements iDBObjectSetIterator
{
$iCount = 0;
}
}
}
else
{
$iCount = $this->m_iNumTotalDBRows;
@@ -908,8 +953,11 @@ class DBObjectSet implements iDBObjectSetIterator
{
if (is_null($this->m_iNumTotalDBRows))
{
$oKPI = new ExecutionKPI();
$sSQL = $this->m_oFilter->MakeSelectQuery(array(), $this->m_aArgs, null, null, $iLimit + 2, 0, true);
$resQuery = CMDBSource::Query($sSQL);
$sOQL = $this->GetPseudoOQL($this->m_oFilter, array(), $iLimit + 2, 0, true);
$oKPI->ComputeStats('OQL Query Exec', $sOQL);
if ($resQuery)
{
$aRow = CMDBSource::FetchArray($resQuery);
@@ -920,7 +968,7 @@ class DBObjectSet implements iDBObjectSetIterator
{
$iCount = 0;
}
}
}
else
{
$iCount = $this->m_iNumTotalDBRows;

View File

@@ -49,10 +49,9 @@ abstract class HTMLSanitizer
$sSanitizerClass = 'HTMLDOMSanitizer';
} else if (false === is_subclass_of($sSanitizerClass, HTMLSanitizer::class)) {
if ($sConfigKey === 'html_sanitizer') {
IssueLog::Warning('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a subclass of HTMLSanitizer. Will use HTMLDOMSanitizer as the default sanitizer.');
IssueLog::Warning('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a subclass of '.HTMLSanitizer::class.'. Will use HTMLDOMSanitizer as the default sanitizer.');
$sSanitizerClass = 'HTMLDOMSanitizer';
}
if ($sConfigKey === 'svg_sanitizer') {
} else {
IssueLog::Error('The configured "'.$sConfigKey.'" class "'.$sSanitizerClass.'" is not a subclass of '.HTMLSanitizer::class.' ! Won\'t sanitize string.');
return $sHTML;

View File

@@ -15,6 +15,8 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
use Combodo\iTop\Core\Kpi\KpiLogData;
use Combodo\iTop\Service\Module\ModuleService;
/**
@@ -30,6 +32,8 @@ class ExecutionKPI
static protected $m_bEnabled_Memory = false;
static protected $m_bBlameCaller = false;
static protected $m_sAllowedUser = '*';
static protected $m_bGenerateLegacyReport = true;
static protected $m_fSlowQueries = 0;
static protected $m_aStats = array(); // Recurrent operations
static protected $m_aExecData = array(); // One shot operations
@@ -77,14 +81,39 @@ class ExecutionKPI
return false;
}
static public function SetGenerateLegacyReport($bReportExtensionsOnly)
{
self::$m_bGenerateLegacyReport = $bReportExtensionsOnly;
}
static public function SetSlowQueries($fSlowQueries)
{
self::$m_fSlowQueries = $fSlowQueries;
}
static public function GetDescription()
{
$aFeatures = array();
if (self::$m_bEnabled_Duration) $aFeatures[] = 'Duration';
if (self::$m_bEnabled_Memory) $aFeatures[] = 'Memory usage';
$sFeatures = implode(', ', $aFeatures);
$sFeatures = 'Measures: '.implode(', ', $aFeatures);
$sFor = self::$m_sAllowedUser == '*' ? 'EVERYBODY' : "'".trim(self::$m_sAllowedUser)."'";
return "KPI logging is active for $sFor. Measures: $sFeatures";
$sSlowQueries = '';
if (self::$m_fSlowQueries > 0) {
$sSlowQueries = ". Slow Queries: ".self::$m_fSlowQueries."s";
}
$aExtensions = [];
/** @var \iKPILoggerExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
$aExtensions[] = ModuleService::GetInstance()->GetModuleNameFromObject($oExtensionInstance);
}
$sExtensions = '';
if (count($aExtensions) > 0) {
$sExtensions = '. KPI Extensions: ['.implode(', ', $aExtensions).']';
}
return "KPI logging is active for $sFor. $sFeatures$sSlowQueries$sExtensions";
}
static public function ReportStats()
@@ -92,7 +121,28 @@ class ExecutionKPI
if (!self::IsEnabled()) return;
global $fItopStarted;
global $iItopInitialMemory;
$sExecId = microtime(); // id to differentiate the hrefs!
$sRequest = $_SERVER['REQUEST_URI'].' ('.$_SERVER['REQUEST_METHOD'].')';
if (isset($_POST['operation'])) {
$sRequest .= ' operation: '.$_POST['operation'];
}
$fStop = MyHelpers::getmicrotime();
if (($fStop - $fItopStarted) > self::$m_fSlowQueries) {
// Invoke extensions to log the KPI operation
/** @var \iKPILoggerExtension $oExtensionInstance */
$iCurrentMemory = self::memory_get_usage();
$iPeakMemory = self::memory_get_peak_usage();
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
$oKPILogData = new KpiLogData(KpiLogData::TYPE_REQUEST, 'Page', $sRequest, $fItopStarted, $fStop, '', $iItopInitialMemory, $iCurrentMemory, $iPeakMemory);
$oExtensionInstance->LogOperation($oKPILogData);
}
}
if (!self::$m_bGenerateLegacyReport) {
return;
}
$aBeginTimes = array();
foreach (self::$m_aExecData as $aOpStats)
@@ -105,7 +155,7 @@ class ExecutionKPI
self::Report("<hr/>");
self::Report("<div style=\"background-color: grey; padding: 10px;\">");
self::Report("<h3><a name=\"".md5($sExecId)."\">KPIs</a> - ".$_SERVER['REQUEST_URI']." (".$_SERVER['REQUEST_METHOD'].")</h3>");
self::Report("<h3><a name=\"".md5($sExecId)."\">KPIs</a> - $sRequest</h3>");
self::Report("<p>".date('Y-m-d H:i:s', $fItopStarted)."</p>");
self::Report("<p>log_kpi_user_id: ".UserRights::GetUserId()."</p>");
self::Report("<div>");
@@ -200,8 +250,6 @@ class ExecutionKPI
self::Report("<p><a href=\"#end-".md5($sExecId)."\">Next page stats</a></p>");
$fSlowQueries = MetaModel::GetConfig()->Get('log_kpi_slow_queries');
// Report operation details
foreach (self::$m_aStats as $sOperation => $aOpStats)
{
@@ -245,7 +293,7 @@ class ExecutionKPI
$sTotalInter = round($fTotalInter, 3);
$sMinInter = round($fMinInter, 3);
$sMaxInter = round($fMaxInter, 3);
if (($fTotalInter >= $fSlowQueries))
if (($fTotalInter >= self::$m_fSlowQueries))
{
if ($bDisplayHeader)
{
@@ -271,11 +319,19 @@ class ExecutionKPI
self::Report('<a name="end-'.md5($sExecId).'">&nbsp;</a>');
}
public static function InitStats()
{
// Invoke extensions to initialize the KPI statistics
/** @var \iKPILoggerExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
$oExtensionInstance->InitStats();
}
}
public function __construct()
{
$this->ResetCounters();
}
}
// Get the duration since startup, and reset the counter for the next measure
//
@@ -283,8 +339,14 @@ class ExecutionKPI
{
global $fItopStarted;
if (!self::IsEnabled()) {
return;
}
$aNewEntry = null;
$fStarted = $this->m_fStarted;
$fStopped = $this->m_fStarted;
if (self::$m_bEnabled_Duration)
{
$fStopped = MyHelpers::getmicrotime();
@@ -297,6 +359,9 @@ class ExecutionKPI
$this->m_fStarted = $fStopped;
}
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
$iCurrentMemory = 0;
$iPeakMemory = 0;
if (self::$m_bEnabled_Memory)
{
$iCurrentMemory = self::memory_get_usage();
@@ -306,41 +371,102 @@ class ExecutionKPI
}
$aNewEntry['mem_begin'] = $this->m_iInitialMemory;
$aNewEntry['mem_end'] = $iCurrentMemory;
if (function_exists('memory_get_peak_usage'))
{
$aNewEntry['mem_peak'] = memory_get_peak_usage();
}
$iPeakMemory = self::memory_get_peak_usage();
$aNewEntry['mem_peak'] = $iPeakMemory;
// Reset for the next operation (if the object is recycled)
$this->m_iInitialMemory = $iCurrentMemory;
}
if (!is_null($aNewEntry))
if (self::$m_bEnabled_Duration || self::$m_bEnabled_Memory) {
// Invoke extensions to log the KPI operation
/** @var \iKPILoggerExtension $oExtensionInstance */
foreach(MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance)
{
$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
$oKPILogData = new KpiLogData(
KpiLogData::TYPE_REPORT,
'Step',
$sOperationDesc,
$fStarted,
$fStopped,
$sExtension,
$iInitialMemory,
$iCurrentMemory,
$iPeakMemory);
$oExtensionInstance->LogOperation($oKPILogData);
}
}
if (!is_null($aNewEntry) && self::$m_bGenerateLegacyReport)
{
self::$m_aExecData[] = $aNewEntry;
}
$this->ResetCounters();
}
public function ComputeStatsForExtension($object, $sMethod)
{
if (!self::IsEnabled()) {
return;
}
$sSignature = ModuleService::GetInstance()->GetModuleMethodSignature($object, $sMethod);
if (utils::StartsWith($sSignature, '[')) {
$this->ComputeStats('Extension', $sSignature);
}
}
public function ComputeStats($sOperation, $sArguments)
{
if (!self::IsEnabled()) {
return;
}
if (self::$m_bEnabled_Duration)
{
$fStopped = MyHelpers::getmicrotime();
$fDuration = $fStopped - $this->m_fStarted;
if (self::$m_bBlameCaller)
{
self::$m_aStats[$sOperation][$sArguments][] = array(
'time' => $fDuration,
'callers' => MyHelpers::get_callstack(1),
);
}
else
{
self::$m_aStats[$sOperation][$sArguments][] = array(
'time' => $fDuration
);
}
}
$aCallstack = [];
if (self::$m_bGenerateLegacyReport) {
if (self::$m_bBlameCaller) {
$aCallstack = MyHelpers::get_callstack(1);
self::$m_aStats[$sOperation][$sArguments][] = [
'time' => $fDuration,
'callers' => $aCallstack,
];
} else {
self::$m_aStats[$sOperation][$sArguments][] = [
'time' => $fDuration
];
}
}
$iInitialMemory = is_null($this->m_iInitialMemory) ? 0 : $this->m_iInitialMemory;
$iCurrentMemory = 0;
$iPeakMemory = 0;
if (self::$m_bEnabled_Memory)
{
$iCurrentMemory = self::memory_get_usage();
$iPeakMemory = self::memory_get_peak_usage();
}
// Invoke extensions to log the KPI operation
/** @var \iKPILoggerExtension $oExtensionInstance */
foreach (MetaModel::EnumPlugins('iKPILoggerExtension') as $oExtensionInstance) {
$sExtension = ModuleService::GetInstance()->GetModuleNameFromCallStack(1);
$oKPILogData = new KpiLogData(
KpiLogData::TYPE_STATS,
$sOperation,
$sArguments,
$this->m_fStarted,
$fStopped,
$sExtension,
$iInitialMemory,
$iCurrentMemory,
$iPeakMemory,
$aCallstack);
$oExtensionInstance->LogOperation($oKPILogData);
}
}
}
protected function ResetCounters()
@@ -370,35 +496,7 @@ class ExecutionKPI
static protected function memory_get_usage()
{
if (function_exists('memory_get_usage'))
{
return memory_get_usage(true);
}
// Copied from the PHP manual
//
//If its Windows
//Tested on Win XP Pro SP2. Should work on Win 2003 Server too
//Doesn't work for 2000
//If you need it to work for 2000 look at http://us2.php.net/manual/en/function.memory-get-usage.php#54642
if (substr(PHP_OS,0,3) == 'WIN')
{
$output = array();
exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $output);
return preg_replace( '/[\D]/', '', $output[5] ) * 1024;
}
else
{
//We now assume the OS is UNIX
//Tested on Mac OS X 10.4.6 and Linux Red Hat Enterprise 4
//This should work on most UNIX systems
$pid = getmypid();
exec("ps -eo%mem,rss,pid | grep $pid", $output);
$output = explode(" ", $output[0]);
//rss is given in 1024 byte units
return $output[1] * 1024;
}
return memory_get_usage(true);
}
static public function memory_get_peak_usage($bRealUsage = false)

View File

@@ -741,7 +741,9 @@ class ToolsLog extends LogAPI
/**
* @see \CMDBSource::LogDeadLock()
* @since 2.7.1
* @since 2.7.1 PR #139
*
* @link https://dev.mysql.com/doc/refman/5.7/en/innodb-deadlocks.html
*/
class DeadLockLog extends LogAPI
{
@@ -761,14 +763,15 @@ class DeadLockLog extends LogAPI
parent::Enable($sTargetFile);
}
/** @noinspection PhpUnreachableStatementInspection */
private static function GetChannelFromMysqlErrorNo($iMysqlErrorNo)
{
switch ($iMysqlErrorNo)
{
case 1205:
case CMDBSource::MYSQL_ERRNO_WAIT_TIMEOUT:
return self::CHANNEL_WAIT_TIMEOUT;
break;
case 1213:
case CMDBSource::MYSQL_ERRNO_DEADLOCK:
return self::CHANNEL_DEADLOCK_FOUND;
break;
default:

View File

@@ -2778,7 +2778,7 @@ abstract class MetaModel
// Build the list of available extensions
//
$aInterfaces = array('iApplicationUIExtension', 'iPreferencesExtension', 'iApplicationObjectExtension', 'iLoginFSMExtension', 'iLoginUIExtension', 'iLogoutExtension', 'iQueryModifier', 'iOnClassInitialization', 'iPopupMenuExtension', 'iPageUIExtension', 'iPortalUIExtension', 'ModuleHandlerApiInterface', 'iNewsroomProvider', 'iModuleExtension');
$aInterfaces = array('iApplicationUIExtension', 'iPreferencesExtension', 'iApplicationObjectExtension', 'iLoginFSMExtension', 'iLoginUIExtension', 'iLogoutExtension', 'iQueryModifier', 'iOnClassInitialization', 'iPopupMenuExtension', 'iPageUIExtension', 'iPortalUIExtension', 'ModuleHandlerApiInterface', 'iNewsroomProvider', 'iModuleExtension', 'iKPILoggerExtension');
foreach($aInterfaces as $sInterface)
{
self::$m_aExtensionClasses[$sInterface] = array();
@@ -6348,7 +6348,9 @@ abstract class MetaModel
ExecutionKPI::EnableDuration(self::$m_oConfig->Get('log_kpi_duration'));
ExecutionKPI::EnableMemory(self::$m_oConfig->Get('log_kpi_memory'));
ExecutionKPI::SetAllowedUser(self::$m_oConfig->Get('log_kpi_user_id'));
ExecutionKPI::SetAllowedUser(self::$m_oConfig->Get('log_kpi_user_id'));
ExecutionKPI::SetGenerateLegacyReport(self::$m_oConfig->Get('log_kpi_generate_legacy_report'));
ExecutionKPI::SetSlowQueries(self::$m_oConfig->Get('log_kpi_slow_queries'));
self::$m_bSkipCheckToWrite = self::$m_oConfig->Get('skip_check_to_write');
self::$m_bSkipCheckExtKeys = self::$m_oConfig->Get('skip_check_ext_keys');
@@ -6485,6 +6487,7 @@ abstract class MetaModel
CMDBSource::InitFromConfig(self::$m_oConfig);
// Later when timezone implementation is correctly done: CMDBSource::SetTimezone($sDBTimezone);
ExecutionKPI::InitStats();
}
/**

View File

@@ -257,7 +257,7 @@ class iTopMutex
$this->hDBLink = CMDBSource::GetMysqliInstance($sServer, $sUser, $sPwd, $sSource, $bTlsEnabled, $sTlsCA, false);
if (!$this->hDBLink) {
throw new Exception("Could not connect to the DB server (host=$sServer, user=$sUser): ".mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno().')');
throw new MySQLException('Could not connect to the DB server '.mysqli_connect_error().' (mysql errno: '.mysqli_connect_errno(), array('host' => $sDBHost, 'user' => $sDBUser));
}
// Make sure that the server variable `wait_timeout` is at least 86400 seconds for this connection,

View File

@@ -126,7 +126,9 @@ abstract class Trigger extends cmdbAbstractObject
$oAction = MetaModel::GetObject('Action', $iActionId);
if ($oAction->IsActive())
{
$oKPI = new ExecutionKPI();
$oAction->DoExecute($this, $aContextArgs);
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
}
}
}

View File

@@ -47,6 +47,11 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnReadCredentials(&$iErrorCode)
{
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
// Not allowed if not already connected
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
if (!isset($_SESSION['login_mode']) || ($_SESSION['login_mode'] == 'cas'))
{
static::InitCASClient();
@@ -71,7 +76,8 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
return LoginWebPage::LOGIN_FSM_ERROR;
}
}
$_SESSION['login_mode'] = 'cas';
$_SESSION['login_mode'] = 'cas';
phpCAS::forceAuthentication(); // Redirect to CAS and exit
}
}
@@ -80,7 +86,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnCheckCredentials(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'cas')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'cas')
{
if (!isset($_SESSION['auth_user']))
{
@@ -97,7 +103,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnCredentialsOK(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'cas')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'cas')
{
$sAuthUser = $_SESSION['auth_user'];
if (!LoginWebPage::CheckUser($sAuthUser))
@@ -112,9 +118,15 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnError(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'cas')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'cas')
{
unset($_SESSION['phpCAS']);
unset($_SESSION['phpCAS']);
if (LoginWebPage::getIOnExit() === LoginWebPage::EXIT_RETURN) {
// don't display the login page
return LoginWebPage::LOGIN_FSM_CONTINUE;
}
if ($iErrorCode != LoginWebPage::EXIT_CODE_MISSINGLOGIN)
{
$oLoginWebPage = new LoginWebPage();
@@ -127,7 +139,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
protected function OnConnected(&$iErrorCode)
{
if ($_SESSION['login_mode'] == 'cas')
if (isset($_SESSION['login_mode']) && $_SESSION['login_mode'] == 'cas')
{
$_SESSION['can_logoff'] = true;
return LoginWebPage::CheckLoggedUser($iErrorCode);
@@ -156,7 +168,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
{
phpCAS::setLogger(new CASLogger(APPROOT.'log/cas.log'));
}
// Initialize phpCAS
$sCASVersion = Config::Get('cas_version');
$sCASHost = Config::Get('cas_host');

View File

@@ -202,6 +202,7 @@
$this->Set('refresh_token', $oAccessToken->getRefreshToken());
}
$this->Set('status', 'active');
$this->AllowWrite();
$this->DBUpdate();
}
]]></code>

View File

@@ -11,6 +11,7 @@ use Combodo\iTop\Application\TwigBase\Controller\Controller;
use Combodo\iTop\Core\Authentication\Client\OAuth\OAuthClientProviderFactory;
use Dict;
use IssueLog;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use MetaModel;
use utils;
@@ -64,13 +65,15 @@ class AjaxOauthClientController extends Controller
}
if (isset($aQuery['code'])) {
$sCode = $aQuery['code'];
$oAccessToken = OAuthClientProviderFactory::GetAccessTokenFromCode($oOAuthClient, $sCode);
$oOAuthClient->SetAccessToken($oAccessToken);
$aResult['status'] = 'success';
try {
$oAccessToken = OAuthClientProviderFactory::GetAccessTokenFromCode($oOAuthClient, $sCode);
$oOAuthClient->SetAccessToken($oAccessToken);
$aResult['status'] = 'success';
}
catch (IdentityProviderException $e) {
$aResult['status'] = 'error';
$aResult['error_description'] = $e->getMessage();
}
}
} else {
$aResult['status'] = 'error';

View File

@@ -496,6 +496,7 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:Loading' => 'Loading...',
'UI:Menu:Actions' => 'Actions',
'UI:Menu:OtherActions' => 'Other Actions',
'UI:Menu:Toolkit' => 'Toolkit',
'UI:Menu:New' => 'New...',
'UI:Menu:Add' => 'Add...',
'UI:Menu:Manage' => 'Manage...',
@@ -560,6 +561,7 @@ Dict::Add('EN US', 'English', 'English', array(
'UI:Login:NewPasswordPrompt' => 'New password',
'UI:Login:RetypeNewPasswordPrompt' => 'Retype new password',
'UI:Login:IncorrectOldPassword' => 'Error: the old password is incorrect',
'UI:PowerMenu' => 'Open user menu',
'UI:LogOffMenu' => 'Log off',
'UI:LogOff:ThankYou' => 'Thank you for using '.ITOP_APPLICATION,
'UI:LogOff:ClickHereToLoginAgain' => 'Click here to login again...',

View File

@@ -479,6 +479,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Loading' => 'Chargement...',
'UI:Menu:Actions' => 'Actions',
'UI:Menu:OtherActions' => 'Autres Actions',
'UI:Menu:Toolkit' => 'Trousse à outils',
'UI:Menu:New' => 'Créer...',
'UI:Menu:Add' => 'Ajouter...',
'UI:Menu:Manage' => 'Gérer...',
@@ -543,6 +544,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI:Login:NewPasswordPrompt' => 'Nouveau mot de passe',
'UI:Login:RetypeNewPasswordPrompt' => 'Resaisir le nouveau mot de passe',
'UI:Login:IncorrectOldPassword' => 'Erreur: l\'ancien mot de passe est incorrect',
'UI:PowerMenu' => 'Ouvre le menu utilisateur',
'UI:LogOffMenu' => 'Déconnexion',
'UI:LogOff:ThankYou' => 'Merci d\'avoir utilisé iTop',
'UI:LogOff:ClickHereToLoginAgain' => 'Cliquez ici pour vous reconnecter...',

View File

@@ -77,6 +77,7 @@ $(function()
sBreadCrumbHtml += '<div class="breadcrumb-item breadcrumb-current" breadcrumb-entry="'+iEntry+'" title="'+sTitle+'">'+sIconSpec+'<span class="truncate">'+sLabel+'</span></div>';
} else {
var sSanitizedUrl = StripArchiveArgument(oEntry['url']);
sSanitizedUrl = EncodeHtml(sSanitizedUrl, false);
sBreadCrumbHtml += '<div class="breadcrumb-item"><a class="breadcrumb-link" breadcrumb-entry="'+iEntry+'" href="'+sSanitizedUrl+'" title="'+sTitle+'">'+sIconSpec+'<span class="truncate">'+sLabel+'</span></a></div>';
}
}

View File

@@ -345,7 +345,7 @@ $(function()
oParams.dashletid = sTempDashletId;
$.post(this.options.new_dashletid_endpoint, oParams, function(data) {
var sFinalDashletId = data;
var sFinalDashletId = data.trim();
me.add_dashlet_prepare(options, sFinalDashletId);
});
},

View File

@@ -1,5 +1,13 @@
/*!
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
* Combodo: issued from https://github.com/cee-chen/jquery-bbq
* fork from http://github.com/cowboy/jquery-bbq/
*
* IMPORTANT: Part for detecting MSIE has been removed as it was not present in the previous version and is making the app crash.
* It's far from perfect but as mentioned in the previous commit, we don't have much choices for now
*/
/*!
* jQuery BBQ: Back Button & Query Library - v1.3pre - 8/26/2010
* http://benalman.com/projects/jquery-bbq-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
@@ -9,12 +17,12 @@
// Script: jQuery BBQ: Back Button & Query Library
//
// *Version: 1.2.1, Last updated: 2/17/2010*
// *Version: 1.3pre, Last updated: 8/26/2010*
//
// Project Home - http://benalman.com/projects/jquery-bbq-plugin/
// GitHub - http://github.com/cowboy/jquery-bbq/
// Source - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.js
// (Minified) - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (4.0kb)
// (Minified) - http://github.com/cowboy/jquery-bbq/raw/master/jquery.ba-bbq.min.js (2.2kb gzipped)
//
// About: License
//
@@ -38,13 +46,21 @@
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4,
// Chrome 4-5, Opera 9.6-10.1.
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
// Unit Tests - http://benalman.com/code/projects/jquery-bbq/unit/
//
// About: Release History
//
// 1.3pre - (8/26/2010) Integrated <jQuery hashchange event> v1.3, which adds
// document.title and document.domain support in IE6/7, BlackBerry
// support, better Iframe hiding for accessibility reasons, and the new
// <jQuery.fn.hashchange> "shortcut" method. Added the
// <jQuery.param.sorted> method which reduces the possibility of
// extraneous hashchange event triggering. Added the
// <jQuery.param.fragment.ajaxCrawlable> method which can be used to
// enable Google "AJAX Crawlable mode."
// 1.2.1 - (2/17/2010) Actually fixed the stale window.location Safari bug from
// <jQuery hashchange event> in BBQ, which was the main reason for the
// previous release!
@@ -87,6 +103,7 @@
// Method / object references.
jq_param = $.param,
jq_param_sorted,
jq_param_fragment,
jq_deparam,
jq_deparam_fragment,
@@ -94,22 +111,25 @@
jq_bbq_pushState,
jq_bbq_getState,
jq_elemUrlAttr,
jq_event_special = $.event.special,
special = $.event.special,
// Reused strings.
str_hashchange = 'hashchange',
str_querystring = 'querystring',
str_fragment = 'fragment',
str_elemUrlAttr = 'elemUrlAttr',
str_location = 'location',
str_href = 'href',
str_src = 'src',
// Reused RegExp.
re_trim_querystring = /^.*\?|#.*$/g,
re_trim_fragment = /^.*\#/,
re_params_querystring = /^.*\?|#.*$/g,
re_params_fragment,
re_fragment,
re_no_escape,
ajax_crawlable,
fragment_prefix,
// Used by jQuery.elemUrlAttr.
elemUrlAttr_cache = {};
@@ -132,7 +152,7 @@
// Get location.hash (or what you'd expect location.hash to be) sans any
// leading #. Thanks for making this necessary, Firefox!
function get_fragment( url ) {
return url.replace( /^[^#]*#?(.*)$/, '$1' );
return url.replace( re_fragment, '$2' );
};
// Get location.search (or what you'd expect location.search to be) sans any
@@ -146,7 +166,7 @@
// Method: jQuery.param.querystring
//
// Retrieve the query string from a URL or if no arguments are passed, the
// current window.location.
// current window.location.href.
//
// Usage:
//
@@ -155,7 +175,7 @@
// Arguments:
//
// url - (String) A URL containing query string params to be parsed. If url
// is not passed, the current window.location is used.
// is not passed, the current window.location.href is used.
//
// Returns:
//
@@ -189,13 +209,12 @@
//
// Returns:
//
// (String) Either a params string with urlencoded data or a URL with a
// urlencoded query string in the format 'a=b&c=d&e=f'.
// (String) A URL with a urlencoded query string in the format '?a=b&c=d&e=f'.
// Method: jQuery.param.fragment
//
// Retrieve the fragment (hash) from a URL or if no arguments are passed, the
// current window.location.
// current window.location.href.
//
// Usage:
//
@@ -204,7 +223,7 @@
// Arguments:
//
// url - (String) A URL containing fragment (hash) params to be parsed. If
// url is not passed, the current window.location is used.
// url is not passed, the current window.location.href is used.
//
// Returns:
//
@@ -238,8 +257,7 @@
//
// Returns:
//
// (String) Either a params string with urlencoded data or a URL with a
// urlencoded fragment (hash) in the format 'a=b&c=d&e=f'.
// (String) A URL with a urlencoded fragment (hash) in the format '#a=b&c=d&e=f'.
function jq_param_sub( is_fragment, get_func, url, params, merge_mode ) {
var result,
@@ -254,7 +272,7 @@
// matches[1] = url part that precedes params, not including trailing ?/#
// matches[2] = params, not including leading ?/#
// matches[3] = if in 'querystring' mode, hash including leading #, otherwise ''
matches = url.match( is_fragment ? /^([^#]*)\#?(.*)$/ : /^([^#?]*)\??([^#]*)(#?.*)/ );
matches = url.match( is_fragment ? re_fragment : /^([^#?]*)\??([^#]*)(#?.*)/ );
// Get the hash if in 'querystring' mode, and it exists.
hash = matches[3] || '';
@@ -262,7 +280,7 @@
if ( merge_mode === 2 && is_string( params ) ) {
// If merge_mode is 2 and params is a string, merge the fragment / query
// string into the URL wholesale, without converting it into an object.
qs = params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' );
qs = params.replace( is_fragment ? re_params_fragment : re_params_querystring, '' );
} else {
// Convert relevant params in url to object.
@@ -280,8 +298,8 @@
: merge_mode === 1 ? $.extend( {}, params, url_params ) // url params override passed params
: $.extend( {}, url_params, params ); // passed params override url params
// Convert params object to a string.
qs = jq_param( qs );
// Convert params object into a sorted params string.
qs = jq_param_sorted( qs );
// Unescape characters specified via $.param.noEscape. Since only hash-
// history users have requested this feature, it's only enabled for
@@ -294,12 +312,12 @@
// Build URL from the base url, querystring and hash. In 'querystring'
// mode, ? is only added if a query string exists. In 'fragment' mode, #
// is always added.
result = matches[1] + ( is_fragment ? '#' : qs || !matches[1] ? '?' : '' ) + qs + hash;
result = matches[1] + ( is_fragment ? fragment_prefix : qs || !matches[1] ? '?' : '' ) + qs + hash;
} else {
// If URL was passed in, parse params from URL string, otherwise parse
// params from window.location.
result = get_func( url !== undefined ? url : window[ str_location ][ str_href ] );
// params from window.location.href.
result = get_func( url !== undefined ? url : location.href );
}
return result;
@@ -308,6 +326,56 @@
jq_param[ str_querystring ] = curry( jq_param_sub, 0, get_querystring );
jq_param[ str_fragment ] = jq_param_fragment = curry( jq_param_sub, 1, get_fragment );
// Method: jQuery.param.sorted
//
// Returns a params string equivalent to that returned by the internal
// jQuery.param method, but sorted, which makes it suitable for use as a
// cache key.
//
// For example, in most browsers jQuery.param({z:1,a:2}) returns "z=1&a=2"
// and jQuery.param({a:2,z:1}) returns "a=2&z=1". Even though both the
// objects being serialized and the resulting params strings are equivalent,
// if these params strings were set into the location.hash fragment
// sequentially, the hashchange event would be triggered unnecessarily, since
// the strings are different (even though the data described by them is the
// same). By sorting the params string, unecessary hashchange event triggering
// can be avoided.
//
// Usage:
//
// > jQuery.param.sorted( obj [, traditional ] );
//
// Arguments:
//
// obj - (Object) An object to be serialized.
// traditional - (Boolean) Params deep/shallow serialization mode. See the
// documentation at http://api.jquery.com/jQuery.param/ for more detail.
//
// Returns:
//
// (String) A sorted params string.
jq_param.sorted = jq_param_sorted = function( a, traditional ) {
var arr = [],
obj = {};
$.each( jq_param( a, traditional ).split( '&' ), function(i,v){
var key = v.replace( /(?:%5B|=).*$/, '' ),
key_obj = obj[ key ];
if ( !key_obj ) {
key_obj = obj[ key ] = [];
arr.push( key );
}
key_obj.push( v );
});
return $.map( arr.sort(), function(v){
return obj[ v ];
}).join( '&' );
};
// Method: jQuery.param.fragment.noEscape
//
// Specify characters that will be left unescaped when fragments are created
@@ -346,6 +414,41 @@
// "uglifying up the URL" the most.
jq_param_fragment.noEscape( ',/' );
// Method: jQuery.param.fragment.ajaxCrawlable
//
// TODO: DESCRIBE
//
// Usage:
//
// > jQuery.param.fragment.ajaxCrawlable( [ state ] );
//
// Arguments:
//
// state - (Boolean) TODO: DESCRIBE
//
// Returns:
//
// (Boolean) The current ajaxCrawlable state.
jq_param_fragment.ajaxCrawlable = function( state ) {
if ( state !== undefined ) {
if ( state ) {
re_params_fragment = /^.*(?:#!|#)/;
re_fragment = /^([^#]*)(?:#!|#)?(.*)$/;
fragment_prefix = '#!';
} else {
re_params_fragment = /^.*#/;
re_fragment = /^([^#]*)#?(.*)$/;
fragment_prefix = '#';
}
ajax_crawlable = !!state;
}
return ajax_crawlable;
};
jq_param_fragment.ajaxCrawlable( 0 );
// Section: Deparam (from string)
//
// Method: jQuery.deparam
@@ -369,7 +472,7 @@
// (Object) An object representing the deserialized params string.
$.deparam = jq_deparam = function( params, coerce ) {
var obj = {},
var obj = Object.create(null),
coerce_types = { 'true': !0, 'false': !1, 'null': null };
// Iterate over all name=value pairs.
@@ -426,7 +529,7 @@
for ( ; i <= keys_last; i++ ) {
key = keys[i] === '' ? cur.length : keys[i];
cur = cur[key] = i < keys_last
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? {} : [] )
? cur[key] || ( keys[i+1] && isNaN( keys[i+1] ) ? Object.create(null) : [] )
: val;
}
@@ -462,7 +565,7 @@
// Method: jQuery.deparam.querystring
//
// Parse the query string from a URL or the current window.location,
// Parse the query string from a URL or the current window.location.href,
// deserializing it into an object, optionally coercing numbers, booleans,
// null and undefined values.
//
@@ -473,8 +576,8 @@
// Arguments:
//
// url - (String) An optional params string or URL containing query string
// params to be parsed. If url is omitted, the current window.location
// is used.
// params to be parsed. If url is omitted, the current
// window.location.href is used.
// coerce - (Boolean) If true, coerces any numbers or true, false, null, and
// undefined to their actual value. Defaults to false if omitted.
//
@@ -484,7 +587,7 @@
// Method: jQuery.deparam.fragment
//
// Parse the fragment (hash) from a URL or the current window.location,
// Parse the fragment (hash) from a URL or the current window.location.href,
// deserializing it into an object, optionally coercing numbers, booleans,
// null and undefined values.
//
@@ -495,7 +598,7 @@
// Arguments:
//
// url - (String) An optional params string or URL containing fragment (hash)
// params to be parsed. If url is omitted, the current window.location
// params to be parsed. If url is omitted, the current window.location.href
// is used.
// coerce - (Boolean) If true, coerces any numbers or true, false, null, and
// undefined to their actual value. Defaults to false if omitted.
@@ -511,7 +614,7 @@
url_or_params = jq_param[ is_fragment ? str_fragment : str_querystring ]();
} else {
url_or_params = is_string( url_or_params )
? url_or_params.replace( is_fragment ? re_trim_fragment : re_trim_querystring, '' )
? url_or_params.replace( is_fragment ? re_params_fragment : re_params_querystring, '' )
: url_or_params;
}
@@ -715,13 +818,12 @@
var has_args = params !== undefined,
// Merge params into window.location using $.param.fragment.
url = jq_param_fragment( window[ str_location ][ str_href ],
url = jq_param_fragment( location.href,
has_args ? params : {}, has_args ? merge_mode : 2 );
// Set new window.location.href. If hash is empty, use just # to prevent
// browser from reloading the page. Note that Safari 3 & Chrome barf on
// location.hash = '#'.
window[ str_location ][ str_href ] = url + ( /#/.test( url ) ? '' : '#' );
// Set new window.location.href. Note that Safari 3 & Chrome barf on
// location.hash = '#' so the entire URL is set.
location.href = url;
};
// Method: jQuery.bbq.getState
@@ -850,7 +952,7 @@
// required to enable the augmented event object in jQuery 1.4.2 and newer.
// * See <jQuery hashchange event> for more detailed information.
jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], {
special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
// Augmenting the event object with the .fragment property and .getState
// method requires jQuery 1.4 or newer. Note: with 1.3.2, everything will
@@ -892,7 +994,7 @@
})(jQuery,this);
/*!
* jQuery hashchange event - v1.2 - 2/11/2010
* jQuery hashchange event - v1.3 - 7/21/2010
* http://benalman.com/projects/jquery-hashchange-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
@@ -902,12 +1004,12 @@
// Script: jQuery hashchange event
//
// *Version: 1.2, Last updated: 2/11/2010*
// *Version: 1.3, Last updated: 7/21/2010*
//
// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/
// GitHub - http://github.com/cowboy/jquery-hashchange/
// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js
// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (1.1kb)
// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped)
//
// About: License
//
@@ -917,10 +1019,11 @@
//
// About: Examples
//
// This working example, complete with fully commented code, illustrate one way
// in which this plugin can be used.
// These working examples, complete with fully commented code, illustrate a few
// ways in which this plugin can be used.
//
// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/
// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/
//
// About: Support and Testing
//
@@ -928,24 +1031,40 @@
// tested with, what browsers it has been tested in, and where the unit tests
// reside (so you can test it yourself).
//
// jQuery Versions - 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-3.7, Safari 3-4, Chrome, Opera 9.6-10.1.
// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2
// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5,
// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5.
// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/
//
// About: Known issues
//
// While this jQuery hashchange event implementation is quite stable and robust,
// there are a few unfortunate browser bugs surrounding expected hashchange
// event-based behaviors, independent of any JavaScript window.onhashchange
// abstraction. See the following examples for more information:
// While this jQuery hashchange event implementation is quite stable and
// robust, there are a few unfortunate browser bugs surrounding expected
// hashchange event-based behaviors, independent of any JavaScript
// window.onhashchange abstraction. See the following examples for more
// information:
//
// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/
// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/
// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/
// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/
//
// Also note that should a browser natively support the window.onhashchange
// event, but not report that it does, the fallback polling loop will be used.
//
// About: Release History
//
// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more
// "removable" for mobile-only development. Added IE6/7 document.title
// support. Attempted to make Iframe as hidden as possible by using
// techniques from http://www.paciellogroup.com/blog/?p=604. Added
// support for the "shortcut" format $(window).hashchange( fn ) and
// $(window).hashchange() like jQuery provides for built-in events.
// Renamed jQuery.hashchangeDelay to <jQuery.fn.hashchange.delay> and
// lowered its default value to 50. Added <jQuery.fn.hashchange.domain>
// and <jQuery.fn.hashchange.src> properties plus document-domain.html
// file to address access denied issues when setting document.domain in
// IE6/7.
// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin
// from a page on another domain would cause an error in Safari 4. Also,
// IE6/7 Iframe is now inserted after the body (this actually works),
@@ -964,63 +1083,144 @@
(function($,window,undefined){
'$:nomunge'; // Used by YUI compressor.
// Method / object references.
var fake_onhashchange,
jq_event_special = $.event.special,
// Reused string.
var str_hashchange = 'hashchange',
// Reused strings.
str_location = 'location',
str_hashchange = 'hashchange',
str_href = 'href',
// Method / object references.
doc = document,
fake_onhashchange,
special = $.event.special,
mode = document.documentMode,
is_old_ie = false,
// Does the browser support window.onhashchange? Test for IE version, since
// IE8 incorrectly reports this when in "IE7" or "IE8 Compatibility View"!
supports_onhashchange = 'on' + str_hashchange in window && !is_old_ie;
// Does the browser support window.onhashchange? Note that IE8 running in
// IE7 compatibility mode reports true for 'onhashchange' in window, even
// though the event isn't supported, so also test document.documentMode.
doc_mode = doc.documentMode,
supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 );
// Get location.hash (or what you'd expect location.hash to be) sans any
// leading #. Thanks for making this necessary, Firefox!
function get_fragment( url ) {
url = url || window[ str_location ][ str_href ];
return url.replace( /^[^#]*#?(.*)$/, '$1' );
url = url || location.href;
return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' );
};
// Property: jQuery.hashchangeDelay
// Method: jQuery.fn.hashchange
//
// Bind a handler to the window.onhashchange event or trigger all bound
// window.onhashchange event handlers. This behavior is consistent with
// jQuery's built-in event handlers.
//
// Usage:
//
// > jQuery(window).hashchange( [ handler ] );
//
// Arguments:
//
// handler - (Function) Optional handler to be bound to the hashchange
// event. This is a "shortcut" for the more verbose form:
// jQuery(window).bind( 'hashchange', handler ). If handler is omitted,
// all bound window.onhashchange event handlers will be triggered. This
// is a shortcut for the more verbose
// jQuery(window).trigger( 'hashchange' ). These forms are described in
// the <hashchange event> section.
//
// Returns:
//
// (jQuery) The initial jQuery collection of elements.
// Allow the "shortcut" format $(elem).hashchange( fn ) for binding and
// $(elem).hashchange() for triggering, like jQuery does for built-in events.
$.fn[ str_hashchange ] = function( fn ) {
return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange );
};
// Property: jQuery.fn.hashchange.delay
//
// The numeric interval (in milliseconds) at which the <hashchange event>
// polling loop executes. Defaults to 100.
// polling loop executes. Defaults to 50.
$[ str_hashchange + 'Delay' ] = 100;
// Property: jQuery.fn.hashchange.domain
//
// If you're setting document.domain in your JavaScript, and you want hash
// history to work in IE6/7, not only must this property be set, but you must
// also set document.domain BEFORE jQuery is loaded into the page. This
// property is only applicable if you are supporting IE6/7 (or IE8 operating
// in "IE7 compatibility" mode).
//
// In addition, the <jQuery.fn.hashchange.src> property must be set to the
// path of the included "document-domain.html" file, which can be renamed or
// modified if necessary (note that the document.domain specified must be the
// same in both your main JavaScript as well as in this file).
//
// Usage:
//
// jQuery.fn.hashchange.domain = document.domain;
// Property: jQuery.fn.hashchange.src
//
// If, for some reason, you need to specify an Iframe src file (for example,
// when setting document.domain as in <jQuery.fn.hashchange.domain>), you can
// do so using this property. Note that when using this property, history
// won't be recorded in IE6/7 until the Iframe src file loads. This property
// is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7
// compatibility" mode).
//
// Usage:
//
// jQuery.fn.hashchange.src = 'path/to/file.html';
$.fn[ str_hashchange ].delay = 50;
/*
$.fn[ str_hashchange ].domain = null;
$.fn[ str_hashchange ].src = null;
*/
// Event: hashchange event
//
// Fired when location.hash changes. In browsers that support it, the native
// window.onhashchange event is used (IE8, FF3.6), otherwise a polling loop is
// initialized, running every <jQuery.hashchangeDelay> milliseconds to see if
// the hash has changed. In IE 6 and 7, a hidden Iframe is created to allow
// the back button and hash-based history to work.
// HTML5 window.onhashchange event is used, otherwise a polling loop is
// initialized, running every <jQuery.fn.hashchange.delay> milliseconds to
// see if the hash has changed. In IE6/7 (and IE8 operating in "IE7
// compatibility" mode), a hidden Iframe is created to allow the back button
// and hash-based history to work.
//
// Usage:
// Usage as described in <jQuery.fn.hashchange>:
//
// > $(window).bind( 'hashchange', function(e) {
// > // Bind an event handler.
// > jQuery(window).hashchange( function(e) {
// > var hash = location.hash;
// > ...
// > });
// >
// > // Manually trigger the event handler.
// > jQuery(window).hashchange();
//
// A more verbose usage that allows for event namespacing:
//
// > // Bind an event handler.
// > jQuery(window).bind( 'hashchange', function(e) {
// > var hash = location.hash;
// > ...
// > });
// >
// > // Manually trigger the event handler.
// > jQuery(window).trigger( 'hashchange' );
//
// Additional Notes:
//
// * The polling loop and Iframe are not created until at least one callback
// is actually bound to 'hashchange'.
// * If you need the bound callback(s) to execute immediately, in cases where
// the page 'state' exists on page load (via bookmark or page refresh, for
// example) use $(window).trigger( 'hashchange' );
// * The polling loop and Iframe are not created until at least one handler
// is actually bound to the 'hashchange' event.
// * If you need the bound handler(s) to execute immediately, in cases where
// a location.hash exists on page load, via bookmark or page refresh for
// example, use jQuery(window).hashchange() or the more verbose
// jQuery(window).trigger( 'hashchange' ).
// * The event can be bound before DOM ready, but since it won't be usable
// before then in IE6/7 (due to the necessary Iframe), recommended usage is
// to bind it inside a $(document).ready() callback.
// to bind it inside a DOM ready handler.
jq_event_special[ str_hashchange ] = $.extend( jq_event_special[ str_hashchange ], {
// Override existing $.event.special.hashchange methods (allowing this plugin
// to be defined after jQuery BBQ in BBQ's source code).
special[ str_hashchange ] = $.extend( special[ str_hashchange ], {
// Called only when the first 'hashchange' event is bound to window.
setup: function() {
@@ -1051,83 +1251,44 @@
fake_onhashchange = (function(){
var self = {},
timeout_id,
iframe,
set_history,
get_history;
// Initialize. In IE 6/7, creates a hidden Iframe for history handling.
function init(){
// Most browsers don't need special methods here..
set_history = get_history = function(val){ return val; };
// But IE6/7 do!
if ( is_old_ie ) {
// Create hidden Iframe after the end of the body to prevent initial
// page load from scrolling unnecessarily.
iframe = $('<iframe src="javascript:0"/>').hide().insertAfter( 'body' )[0].contentWindow;
// Get history by looking at the hidden Iframe's location.hash.
get_history = function() {
return get_fragment( iframe.document[ str_location ][ str_href ] );
};
// Set a new history item by opening and then closing the Iframe
// document, *then* setting its location.hash.
set_history = function( hash, history_hash ) {
if ( hash !== history_hash ) {
var doc = iframe.document;
doc.open().close();
doc[ str_location ].hash = '#' + hash;
}
};
// Set initial history.
set_history( get_fragment() );
}
};
// Remember the initial hash so it doesn't get triggered immediately.
last_hash = get_fragment(),
fn_retval = function(val){ return val; },
history_set = fn_retval,
history_get = fn_retval;
// Start the polling loop.
self.start = function() {
// Polling loop is already running!
if ( timeout_id ) { return; }
// Remember the initial hash so it doesn't get triggered immediately.
var last_hash = get_fragment();
// Initialize if not yet initialized.
set_history || init();
// This polling loop checks every $.hashchangeDelay milliseconds to see if
// location.hash has changed, and triggers the 'hashchange' event on
// window when necessary.
(function loopy(){
var hash = get_fragment(),
history_hash = get_history( last_hash );
if ( hash !== last_hash ) {
set_history( last_hash = hash, history_hash );
$(window).trigger( str_hashchange );
} else if ( history_hash !== last_hash ) {
window[ str_location ][ str_href ] = window[ str_location ][ str_href ].replace( /#.*/, '' ) + '#' + history_hash;
}
timeout_id = setTimeout( loopy, $[ str_hashchange + 'Delay' ] );
})();
timeout_id || poll();
};
// Stop the polling loop, but only if an IE6/7 Iframe wasn't created. In
// that case, even if there are no longer any bound event handlers, the
// polling loop is still necessary for back/next to work at all!
// Stop the polling loop.
self.stop = function() {
if ( !iframe ) {
timeout_id && clearTimeout( timeout_id );
timeout_id = 0;
}
timeout_id && clearTimeout( timeout_id );
timeout_id = undefined;
};
// This polling loop checks every $.fn.hashchange.delay milliseconds to see
// if location.hash has changed, and triggers the 'hashchange' event on
// window when necessary.
function poll() {
var hash = get_fragment(),
history_hash = history_get( last_hash );
if ( hash !== last_hash ) {
history_set( last_hash = hash, history_hash );
$(window).trigger( str_hashchange );
} else if ( history_hash !== last_hash ) {
location.href = location.href.replace( /#.*/, '' ) + history_hash;
}
timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay );
};
return self;
})();

View File

@@ -1,9 +1,25 @@
/*!
* Combodo: issued from https://github.com/cee-chen/jquery-bbq
* fork from http://github.com/cowboy/jquery-bbq/
*
* IMPORTANT: Part for detecting MSIE has been removed as it was not present in the previous version and is making the app crash.
* It's far from perfect but as mentioned in the previous commit, we don't have much choices for now
*/
/*
* jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010
* jQuery BBQ: Back Button & Query Library - v1.3pre - 8/26/2010
* http://benalman.com/projects/jquery-bbq-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function(e,t){"$:nomunge";function N(e){return typeof e==="string"}function C(e){var t=r.call(arguments,1);return function(){return e.apply(this,t.concat(r.call(arguments)))}}function k(e){return e.replace(/^[^#]*#?(.*)$/,"$1")}function L(e){return e.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function A(r,o,a,f,l){var c,h,p,d,g;if(f!==n){p=a.match(r?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);g=p[3]||"";if(l===2&&N(f)){h=f.replace(r?S:E,"")}else{d=u(p[2]);f=N(f)?u[r?m:v](f):f;h=l===2?f:l===1?e.extend({},f,d):e.extend({},d,f);h=s(h);if(r){h=h.replace(x,i)}}c=p[1]+(r?"#":h||!p[1]?"?":"")+h+g}else{c=o(a!==n?a:t[y][b])}return c}function O(e,t,r){if(t===n||typeof t==="boolean"){r=t;t=s[e?m:v]()}else{t=N(t)?t.replace(e?S:E,""):t}return u(t,r)}function M(t,r,i,o){if(!N(i)&&typeof i!=="object"){o=i;i=r;r=n}return this.each(function(){var n=e(this),u=r||h()[(this.nodeName||"").toLowerCase()]||"",a=u&&n.attr(u)||"";n.attr(u,s[t](a,i,o))})}var n,r=Array.prototype.slice,i=decodeURIComponent,s=e.param,o,u,a,f=e.bbq=e.bbq||{},l,c,h,p=e.event.special,d="hashchange",v="querystring",m="fragment",g="elemUrlAttr",y="location",b="href",w="src",E=/^.*\?|#.*$/g,S=/^.*\#/,x,T={};s[v]=C(A,0,L);s[m]=o=C(A,1,k);o.noEscape=function(t){t=t||"";var n=e.map(t.split(""),encodeURIComponent);x=new RegExp(n.join("|"),"g")};o.noEscape(",/");e.deparam=u=function(t,r){var s={},o={"true":!0,"false":!1,"null":null};e.each(t.replace(/\+/g," ").split("&"),function(t,u){var a=u.split("="),f=i(a[0]),l,c=s,h=0,p=f.split("]["),d=p.length-1;if(/\[/.test(p[0])&&/\]$/.test(p[d])){p[d]=p[d].replace(/\]$/,"");p=p.shift().split("[").concat(p);d=p.length-1}else{d=0}if(a.length===2){l=i(a[1]);if(r){l=l&&!isNaN(l)?+l:l==="undefined"?n:o[l]!==n?o[l]:l}if(d){for(;h<=d;h++){f=p[h]===""?c.length:p[h];c=c[f]=h<d?c[f]||(p[h+1]&&isNaN(p[h+1])?{}:[]):l}}else{if(e.isArray(s[f])){s[f].push(l)}else if(s[f]!==n){s[f]=[s[f],l]}else{s[f]=l}}}else if(f){s[f]=r?n:""}});return s};u[v]=C(O,0);u[m]=a=C(O,1);e[g]||(e[g]=function(t){return e.extend(T,t)})({a:b,base:b,iframe:w,img:w,input:w,form:"action",link:b,script:w});h=e[g];e.fn[v]=C(M,v);e.fn[m]=C(M,m);f.pushState=l=function(e,r){if(N(e)&&/^#/.test(e)&&r===n){r=2}var i=e!==n,s=o(t[y][b],i?e:{},i?r:2);t[y][b]=s+(/#/.test(s)?"":"#")};f.getState=c=function(e,t){return e===n||typeof e==="boolean"?a(e):a(t)[e]};f.removeState=function(t){var r={};if(t!==n){r=c();e.each(e.isArray(t)?t:arguments,function(e,t){delete r[t]})}l(r,2)};p[d]=e.extend(p[d],{add:function(t){function i(e){var t=e[m]=o();e.getState=function(e,r){return e===n||typeof e==="boolean"?u(t,e):u(t,r)[e]};r.apply(this,arguments)}var r;if(e.isFunction(t)){r=t;return i}else{r=t.handler;t.handler=i}}})})(jQuery,this);(function(e,t,n){"$:nomunge";function c(e){e=e||t[s][u];return e.replace(/^[^#]*#?(.*)$/,"$1")}var r,i=e.event.special,s="location",o="hashchange",u="href",a=document.documentMode,f=false,l="on"+o in t&&!f;e[o+"Delay"]=100;i[o]=e.extend(i[o],{setup:function(){if(l){return false}e(r.start)},teardown:function(){if(l){return false}e(r.stop)}});r=function(){function h(){a=l=function(e){return e};if(f){i=e('<iframe src="javascript:0"/>').hide().insertAfter("body")[0].contentWindow;l=function(){return c(i.document[s][u])};a=function(e,t){if(e!==t){var n=i.document;n.open().close();n[s].hash="#"+e}};a(c())}}var n={},r,i,a,l;n.start=function(){if(r){return}var n=c();a||h();(function i(){var f=c(),h=l(n);if(f!==n){a(n=f,h);e(t).trigger(o)}else if(h!==n){t[s][u]=t[s][u].replace(/#.*/,"")+"#"+h}r=setTimeout(i,e[o+"Delay"])})()};n.stop=function(){if(!i){r&&clearTimeout(r);r=0}};return n}()})(jQuery,this)
(function($,r){var h,n=Array.prototype.slice,t=decodeURIComponent,a=$.param,j,c,m,y,b=$.bbq=$.bbq||{},s,x,k,e=$.event.special,d="hashchange",B="querystring",F="fragment",z="elemUrlAttr",l="href",w="src",p=/^.*\?|#.*$/g,u,H,g,i,C,E={};function G(I){return typeof I==="string"}function D(J){var I=n.call(arguments,1);return function(){return J.apply(this,I.concat(n.call(arguments)))}}function o(I){return I.replace(H,"$2")}function q(I){return I.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(K,P,I,L,J){var R,O,N,Q,M;if(L!==h){N=I.match(K?H:/^([^#?]*)\??([^#]*)(#?.*)/);M=N[3]||"";if(J===2&&G(L)){O=L.replace(K?u:p,"")}else{Q=m(N[2]);L=G(L)?m[K?F:B](L):L;O=J===2?L:J===1?$.extend({},L,Q):$.extend({},Q,L);O=j(O);if(K){O=O.replace(g,t)}}R=N[1]+(K?C:O||!N[1]?"?":"")+O+M}else{R=P(I!==h?I:location.href)}return R}a[B]=D(f,0,q);a[F]=c=D(f,1,o);a.sorted=j=function(J,K){var I=[],L={};$.each(a(J,K).split("&"),function(P,M){var O=M.replace(/(?:%5B|=).*$/,""),N=L[O];if(!N){N=L[O]=[];I.push(O)}N.push(M)});return $.map(I.sort(),function(M){return L[M]}).join("&")};c.noEscape=function(J){J=J||"";var I=$.map(J.split(""),encodeURIComponent);g=new RegExp(I.join("|"),"g")};c.noEscape(",/");c.ajaxCrawlable=function(I){if(I!==h){if(I){u=/^.*(?:#!|#)/;H=/^([^#]*)(?:#!|#)?(.*)$/;C="#!"}else{u=/^.*#/;H=/^([^#]*)#?(.*)$/;C="#"}i=!!I}return i};c.ajaxCrawlable(0);$.deparam=m=function(L,I){var K=Object.create(null),J={"true":!0,"false":!1,"null":null};$.each(L.replace(/\+/g," ").split("&"),function(O,T){var N=T.split("="),S=t(N[0]),M,R=K,P=0,U=S.split("]["),Q=U.length-1;if(/\[/.test(U[0])&&/\]$/.test(U[Q])){U[Q]=U[Q].replace(/\]$/,"");U=U.shift().split("[").concat(U);Q=U.length-1}else{Q=0}if(N.length===2){M=t(N[1]);if(I){M=M&&!isNaN(M)?+M:M==="undefined"?h:J[M]!==h?J[M]:M}if(Q){for(;P<=Q;P++){S=U[P]===""?R.length:U[P];R=R[S]=P<Q?R[S]||(U[P+1]&&isNaN(U[P+1])?Object.create(null):[]):M}}else{if($.isArray(K[S])){K[S].push(M)}else{if(K[S]!==h){K[S]=[K[S],M]}else{K[S]=M}}}}else{if(S){K[S]=I?h:""}}});return K};function A(K,I,J){if(I===h||typeof I==="boolean"){J=I;I=a[K?F:B]()}else{I=G(I)?I.replace(K?u:p,""):I}return m(I,J)}m[B]=D(A,0);m[F]=y=D(A,1);$[z]||($[z]=function(I){return $.extend(E,I)})({a:l,base:l,iframe:w,img:w,input:w,form:"action",link:l,script:w});k=$[z];function v(L,J,K,I){if(!G(K)&&typeof K!=="object"){I=K;K=J;J=h}return this.each(function(){var O=$(this),M=J||k()[(this.nodeName||"").toLowerCase()]||"",N=M&&O.attr(M)||"";O.attr(M,a[L](N,K,I))})}$.fn[B]=D(v,B);$.fn[F]=D(v,F);b.pushState=s=function(L,I){if(G(L)&&/^#/.test(L)&&I===h){I=2}var K=L!==h,J=c(location.href,K?L:{},K?I:2);location.href=J};b.getState=x=function(I,J){return I===h||typeof I==="boolean"?y(I):y(J)[I]};b.removeState=function(I){var J={};if(I!==h){J=x();$.each($.isArray(I)?I:arguments,function(L,K){delete J[K]})}s(J,2)};e[d]=$.extend(e[d],{add:function(I){var K;function J(M){var L=M[F]=c();M.getState=function(N,O){return N===h||typeof N==="boolean"?m(L,N):m(L,O)[N]};K.apply(this,arguments)}if($.isFunction(I)){K=I;return J}else{K=I.handler;I.handler=J}}})})(jQuery,this);
/*
* jQuery hashchange event - v1.3 - 7/21/2010
* http://benalman.com/projects/jquery-hashchange-plugin/
*
* Copyright (c) 2010 "Cowboy" Ben Alman
* Dual licensed under the MIT and GPL licenses.
* http://benalman.com/about/license/
*/
(function($,e,b){var c="hashchange",h=document,f,g=$.event.special,i=h.documentMode,d="on"+c in e&&(i===b||i>7);function a(j){j=j||location.href;return"#"+j.replace(/^[^#]*#?(.*)$/,"$1")}$.fn[c]=function(j){return j?this.bind(c,j):this.trigger(c)};$.fn[c].delay=50;g[c]=$.extend(g[c],{setup:function(){if(d){return false}$(f.start)},teardown:function(){if(d){return false}$(f.stop)}});f=(function(){var j={},p,m=a(),k=function(q){return q},l=k,o=k;j.start=function(){p||n()};j.stop=function(){p&&clearTimeout(p);p=b};function n(){var r=a(),q=o(m);if(r!==m){l(m=r,q);$(e).trigger(c)}else{if(q!==m){location.href=location.href.replace(/#.*/,"")+q}}p=setTimeout(n,$.fn[c].delay)}return j})()})(jQuery,this);

View File

@@ -21,12 +21,14 @@ use Composer\Semver\VersionParser;
* See also https://getcomposer.org/doc/07-runtime.md#installed-versions
*
* To require its presence, you can require `composer-runtime-api ^2.0`
*
* @final
*/
class InstalledVersions
{
/**
* @var mixed[]|null
* @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null
* @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null
*/
private static $installed;
@@ -37,7 +39,7 @@ class InstalledVersions
/**
* @var array[]
* @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static $installedByVendor = array();
@@ -241,7 +243,7 @@ class InstalledVersions
/**
* @return array
* @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}
* @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}
*/
public static function getRootPackage()
{
@@ -255,7 +257,7 @@ class InstalledVersions
*
* @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect.
* @return array[]
* @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}
* @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}
*/
public static function getRawData()
{
@@ -278,7 +280,7 @@ class InstalledVersions
* Returns the raw data of all installed.php which are currently loaded for custom implementations
*
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
public static function getAllRawData()
{
@@ -301,7 +303,7 @@ class InstalledVersions
* @param array[] $data A vendor/composer/installed.php data set
* @return void
*
* @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data
* @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data
*/
public static function reload($data)
{
@@ -311,7 +313,7 @@ class InstalledVersions
/**
* @return array[]
* @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}>
* @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}>
*/
private static function getInstalled()
{

View File

@@ -158,8 +158,10 @@ return array(
'Combodo\\iTop\\Core\\Authentication\\Client\\OAuth\\OAuthClientProviderGoogle' => $baseDir . '/sources/Core/Authentication/Client/OAuth/OAuthClientProviderGoogle.php',
'Combodo\\iTop\\Core\\Email\\EmailFactory' => $baseDir . '/sources/Core/Email/EmailFactory.php',
'Combodo\\iTop\\Core\\Email\\iEMail' => $baseDir . '/sources/Core/Email/iEMail.php',
'Combodo\\iTop\\Core\\Kpi\\KpiLogData' => $baseDir . '/sources/Core/Kpi/KpiLogData.php',
'Combodo\\iTop\\DesignDocument' => $baseDir . '/core/designdocument.class.inc.php',
'Combodo\\iTop\\DesignElement' => $baseDir . '/core/designdocument.class.inc.php',
'Combodo\\iTop\\Service\\Module\\ModuleService' => $baseDir . '/sources/Service/Module/ModuleService.php',
'Combodo\\iTop\\TwigExtension' => $baseDir . '/application/twigextension.class.inc.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
'Config' => $baseDir . '/core/config.class.inc.php',
@@ -2712,6 +2714,7 @@ return array(
'iDBObjectSetIterator' => $baseDir . '/core/dbobjectiterator.php',
'iDBObjectURLMaker' => $baseDir . '/application/applicationcontext.class.inc.php',
'iDisplay' => $baseDir . '/core/dbobject.class.php',
'iKPILoggerExtension' => $baseDir . '/application/applicationextension.inc.php',
'iLogFileNameBuilder' => $baseDir . '/core/log.class.inc.php',
'iLoginExtension' => $baseDir . '/application/applicationextension.inc.php',
'iLoginFSMExtension' => $baseDir . '/application/applicationextension.inc.php',

View File

@@ -526,8 +526,10 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'Combodo\\iTop\\Core\\Authentication\\Client\\OAuth\\OAuthClientProviderGoogle' => __DIR__ . '/../..' . '/sources/Core/Authentication/Client/OAuth/OAuthClientProviderGoogle.php',
'Combodo\\iTop\\Core\\Email\\EmailFactory' => __DIR__ . '/../..' . '/sources/Core/Email/EmailFactory.php',
'Combodo\\iTop\\Core\\Email\\iEMail' => __DIR__ . '/../..' . '/sources/Core/Email/iEMail.php',
'Combodo\\iTop\\Core\\Kpi\\KpiLogData' => __DIR__ . '/../..' . '/sources/Core/Kpi/KpiLogData.php',
'Combodo\\iTop\\DesignDocument' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php',
'Combodo\\iTop\\DesignElement' => __DIR__ . '/../..' . '/core/designdocument.class.inc.php',
'Combodo\\iTop\\Service\\Module\\ModuleService' => __DIR__ . '/../..' . '/sources/Service/Module/ModuleService.php',
'Combodo\\iTop\\TwigExtension' => __DIR__ . '/../..' . '/application/twigextension.class.inc.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
'Config' => __DIR__ . '/../..' . '/core/config.class.inc.php',
@@ -3080,6 +3082,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
'iDBObjectSetIterator' => __DIR__ . '/../..' . '/core/dbobjectiterator.php',
'iDBObjectURLMaker' => __DIR__ . '/../..' . '/application/applicationcontext.class.inc.php',
'iDisplay' => __DIR__ . '/../..' . '/core/dbobject.class.php',
'iKPILoggerExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
'iLogFileNameBuilder' => __DIR__ . '/../..' . '/core/log.class.inc.php',
'iLoginExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
'iLoginFSMExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',

View File

@@ -531,17 +531,17 @@
},
{
"name": "guzzlehttp/psr7",
"version": "1.9.0",
"version_normalized": "1.9.0.0",
"version": "1.9.1",
"version_normalized": "1.9.1.0",
"source": {
"type": "git",
"url": "https://github.com/guzzle/psr7.git",
"reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318"
"reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/e98e3e6d4f86621a9b75f623996e6bbdeb4b9318",
"reference": "e98e3e6d4f86621a9b75f623996e6bbdeb4b9318",
"url": "https://api.github.com/repos/guzzle/psr7/zipball/e4490cabc77465aaee90b20cfc9a770f8c04be6b",
"reference": "e4490cabc77465aaee90b20cfc9a770f8c04be6b",
"shasum": ""
},
"require": {
@@ -559,13 +559,8 @@
"suggest": {
"laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
},
"time": "2022-06-20T21:43:03+00:00",
"time": "2023-04-17T16:00:37+00:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"installation-source": "dist",
"autoload": {
"files": [
@@ -624,7 +619,7 @@
],
"support": {
"issues": "https://github.com/guzzle/psr7/issues",
"source": "https://github.com/guzzle/psr7/tree/1.9.0"
"source": "https://github.com/guzzle/psr7/tree/1.9.1"
},
"funding": [
{

View File

@@ -1,40 +1,40 @@
<?php return array(
'root' => array(
'name' => 'combodo/itop',
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => 'fff46d99fc2a37875ddb8ba2385b89dcfbcd73db',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '18ed5ed526d7f980fb52e936c0d1ddb3062172fb',
'name' => 'combodo/itop',
'dev' => true,
),
'versions' => array(
'combodo/itop' => array(
'pretty_version' => 'dev-develop',
'version' => 'dev-develop',
'reference' => 'fff46d99fc2a37875ddb8ba2385b89dcfbcd73db',
'type' => 'project',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'reference' => '18ed5ed526d7f980fb52e936c0d1ddb3062172fb',
'dev_requirement' => false,
),
'combodo/tcpdf' => array(
'pretty_version' => '6.4.4',
'version' => '6.4.4.0',
'reference' => '0e31c013ccd000aa6762e9186778aa6e259ac8e8',
'type' => 'library',
'install_path' => __DIR__ . '/../combodo/tcpdf',
'aliases' => array(),
'reference' => '0e31c013ccd000aa6762e9186778aa6e259ac8e8',
'dev_requirement' => false,
),
'container-interop/container-interop' => array(
'pretty_version' => '1.2.0',
'version' => '1.2.0.0',
'reference' => '79cbf1341c22ec75643d841642dd5d6acd83bdb8',
'type' => 'library',
'install_path' => __DIR__ . '/../container-interop/container-interop',
'aliases' => array(),
'reference' => '79cbf1341c22ec75643d841642dd5d6acd83bdb8',
'dev_requirement' => false,
),
'container-interop/container-interop-implementation' => array(
@@ -46,208 +46,208 @@
'doctrine/lexer' => array(
'pretty_version' => '1.0.2',
'version' => '1.0.2.0',
'reference' => '1febd6c3ef84253d7c815bed85fc622ad207a9f8',
'type' => 'library',
'install_path' => __DIR__ . '/../doctrine/lexer',
'aliases' => array(),
'reference' => '1febd6c3ef84253d7c815bed85fc622ad207a9f8',
'dev_requirement' => false,
),
'egulias/email-validator' => array(
'pretty_version' => '2.1.25',
'version' => '2.1.25.0',
'reference' => '0dbf5d78455d4d6a41d186da50adc1122ec066f4',
'type' => 'library',
'install_path' => __DIR__ . '/../egulias/email-validator',
'aliases' => array(),
'reference' => '0dbf5d78455d4d6a41d186da50adc1122ec066f4',
'dev_requirement' => false,
),
'firebase/php-jwt' => array(
'pretty_version' => 'v6.4.0',
'version' => '6.4.0.0',
'reference' => '4dd1e007f22a927ac77da5a3fbb067b42d3bc224',
'type' => 'library',
'install_path' => __DIR__ . '/../firebase/php-jwt',
'aliases' => array(),
'reference' => '4dd1e007f22a927ac77da5a3fbb067b42d3bc224',
'dev_requirement' => false,
),
'guzzlehttp/guzzle' => array(
'pretty_version' => '6.5.8',
'version' => '6.5.8.0',
'reference' => 'a52f0440530b54fa079ce76e8c5d196a42cad981',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
'aliases' => array(),
'reference' => 'a52f0440530b54fa079ce76e8c5d196a42cad981',
'dev_requirement' => false,
),
'guzzlehttp/promises' => array(
'pretty_version' => '1.5.1',
'version' => '1.5.1.0',
'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/promises',
'aliases' => array(),
'reference' => 'fe752aedc9fd8fcca3fe7ad05d419d32998a06da',
'dev_requirement' => false,
),
'guzzlehttp/psr7' => array(
'pretty_version' => '1.9.0',
'version' => '1.9.0.0',
'pretty_version' => '1.9.1',
'version' => '1.9.1.0',
'reference' => 'e4490cabc77465aaee90b20cfc9a770f8c04be6b',
'type' => 'library',
'install_path' => __DIR__ . '/../guzzlehttp/psr7',
'aliases' => array(),
'reference' => 'e98e3e6d4f86621a9b75f623996e6bbdeb4b9318',
'dev_requirement' => false,
),
'laminas/laminas-loader' => array(
'pretty_version' => '2.6.1',
'version' => '2.6.1.0',
'reference' => '5d01c2c237ae9e68bec262f339947e2ea18979bc',
'type' => 'library',
'install_path' => __DIR__ . '/../laminas/laminas-loader',
'aliases' => array(),
'reference' => '5d01c2c237ae9e68bec262f339947e2ea18979bc',
'dev_requirement' => false,
),
'laminas/laminas-mail' => array(
'pretty_version' => '2.11.1',
'version' => '2.11.1.0',
'reference' => '7f674afeb38100b1869ce8e56bf2ec3cba3c679c',
'type' => 'library',
'install_path' => __DIR__ . '/../laminas/laminas-mail',
'aliases' => array(),
'reference' => '7f674afeb38100b1869ce8e56bf2ec3cba3c679c',
'dev_requirement' => false,
),
'laminas/laminas-mime' => array(
'pretty_version' => '2.7.4',
'version' => '2.7.4.0',
'reference' => 'e45a7d856bf7b4a7b5bd00d6371f9961dc233add',
'type' => 'library',
'install_path' => __DIR__ . '/../laminas/laminas-mime',
'aliases' => array(),
'reference' => 'e45a7d856bf7b4a7b5bd00d6371f9961dc233add',
'dev_requirement' => false,
),
'laminas/laminas-servicemanager' => array(
'pretty_version' => '3.5.2',
'version' => '3.5.2.0',
'reference' => '0669e1eec8d9f61e35a5bc5012796d49f418b259',
'type' => 'library',
'install_path' => __DIR__ . '/../laminas/laminas-servicemanager',
'aliases' => array(),
'reference' => '0669e1eec8d9f61e35a5bc5012796d49f418b259',
'dev_requirement' => false,
),
'laminas/laminas-stdlib' => array(
'pretty_version' => '3.2.1',
'version' => '3.2.1.0',
'reference' => '2b18347625a2f06a1a485acfbc870f699dbe51c6',
'type' => 'library',
'install_path' => __DIR__ . '/../laminas/laminas-stdlib',
'aliases' => array(),
'reference' => '2b18347625a2f06a1a485acfbc870f699dbe51c6',
'dev_requirement' => false,
),
'laminas/laminas-validator' => array(
'pretty_version' => '2.12.2',
'version' => '2.12.2.0',
'reference' => '0813f234812d9fa9058b6da39eb13dedc90227db',
'type' => 'library',
'install_path' => __DIR__ . '/../laminas/laminas-validator',
'aliases' => array(),
'reference' => '0813f234812d9fa9058b6da39eb13dedc90227db',
'dev_requirement' => false,
),
'laminas/laminas-zendframework-bridge' => array(
'pretty_version' => '1.1.1',
'version' => '1.1.1.0',
'reference' => '6ede70583e101030bcace4dcddd648f760ddf642',
'type' => 'library',
'install_path' => __DIR__ . '/../laminas/laminas-zendframework-bridge',
'aliases' => array(),
'reference' => '6ede70583e101030bcace4dcddd648f760ddf642',
'dev_requirement' => false,
),
'league/oauth2-client' => array(
'pretty_version' => '2.6.1',
'version' => '2.6.1.0',
'reference' => '2334c249907190c132364f5dae0287ab8666aa19',
'type' => 'library',
'install_path' => __DIR__ . '/../league/oauth2-client',
'aliases' => array(),
'reference' => '2334c249907190c132364f5dae0287ab8666aa19',
'dev_requirement' => false,
),
'league/oauth2-google' => array(
'pretty_version' => '3.0.4',
'version' => '3.0.4.0',
'reference' => '6b79441f244040760bed5fdcd092a2bda7cf34c6',
'type' => 'library',
'install_path' => __DIR__ . '/../league/oauth2-google',
'aliases' => array(),
'reference' => '6b79441f244040760bed5fdcd092a2bda7cf34c6',
'dev_requirement' => false,
),
'nikic/php-parser' => array(
'pretty_version' => 'v4.13.2',
'version' => '4.13.2.0',
'reference' => '210577fe3cf7badcc5814d99455df46564f3c077',
'type' => 'library',
'install_path' => __DIR__ . '/../nikic/php-parser',
'aliases' => array(),
'reference' => '210577fe3cf7badcc5814d99455df46564f3c077',
'dev_requirement' => false,
),
'paragonie/random_compat' => array(
'pretty_version' => 'v2.0.18',
'version' => '2.0.18.0',
'reference' => '0a58ef6e3146256cc3dc7cc393927bcc7d1b72db',
'type' => 'library',
'install_path' => __DIR__ . '/../paragonie/random_compat',
'aliases' => array(),
'reference' => '0a58ef6e3146256cc3dc7cc393927bcc7d1b72db',
'dev_requirement' => false,
),
'pear/archive_tar' => array(
'pretty_version' => '1.4.14',
'version' => '1.4.14.0',
'reference' => '4d761c5334c790e45ef3245f0864b8955c562caa',
'type' => 'library',
'install_path' => __DIR__ . '/../pear/archive_tar',
'aliases' => array(),
'reference' => '4d761c5334c790e45ef3245f0864b8955c562caa',
'dev_requirement' => false,
),
'pear/console_getopt' => array(
'pretty_version' => 'v1.4.3',
'version' => '1.4.3.0',
'reference' => 'a41f8d3e668987609178c7c4a9fe48fecac53fa0',
'type' => 'library',
'install_path' => __DIR__ . '/../pear/console_getopt',
'aliases' => array(),
'reference' => 'a41f8d3e668987609178c7c4a9fe48fecac53fa0',
'dev_requirement' => false,
),
'pear/pear-core-minimal' => array(
'pretty_version' => 'v1.10.10',
'version' => '1.10.10.0',
'reference' => '625a3c429d9b2c1546438679074cac1b089116a7',
'type' => 'library',
'install_path' => __DIR__ . '/../pear/pear-core-minimal',
'aliases' => array(),
'reference' => '625a3c429d9b2c1546438679074cac1b089116a7',
'dev_requirement' => false,
),
'pear/pear_exception' => array(
'pretty_version' => 'v1.0.1',
'version' => '1.0.1.0',
'reference' => 'dbb42a5a0e45f3adcf99babfb2a1ba77b8ac36a7',
'type' => 'class',
'install_path' => __DIR__ . '/../pear/pear_exception',
'aliases' => array(),
'reference' => 'dbb42a5a0e45f3adcf99babfb2a1ba77b8ac36a7',
'dev_requirement' => false,
),
'pelago/emogrifier' => array(
'pretty_version' => 'v3.1.0',
'version' => '3.1.0.0',
'reference' => 'f6a5c7d44612d86c3901c93f1592f5440e6b2cd8',
'type' => 'library',
'install_path' => __DIR__ . '/../pelago/emogrifier',
'aliases' => array(),
'reference' => 'f6a5c7d44612d86c3901c93f1592f5440e6b2cd8',
'dev_requirement' => false,
),
'psr/cache' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/cache',
'aliases' => array(),
'reference' => 'd11b50ad223250cf17b86e38383413f5a6764bf8',
'dev_requirement' => false,
),
'psr/cache-implementation' => array(
@@ -259,10 +259,10 @@
'psr/container' => array(
'pretty_version' => '1.0.0',
'version' => '1.0.0.0',
'reference' => 'b7ce3b176482dbbc1245ebf52b181af44c2cf55f',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/container',
'aliases' => array(),
'reference' => 'b7ce3b176482dbbc1245ebf52b181af44c2cf55f',
'dev_requirement' => false,
),
'psr/container-implementation' => array(
@@ -275,10 +275,10 @@
'psr/http-message' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/http-message',
'aliases' => array(),
'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
'dev_requirement' => false,
),
'psr/http-message-implementation' => array(
@@ -290,10 +290,10 @@
'psr/log' => array(
'pretty_version' => '1.1.2',
'version' => '1.1.2.0',
'reference' => '446d54b4cb6bf489fc9d75f55843658e6f25d801',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/log',
'aliases' => array(),
'reference' => '446d54b4cb6bf489fc9d75f55843658e6f25d801',
'dev_requirement' => false,
),
'psr/log-implementation' => array(
@@ -305,10 +305,10 @@
'psr/simple-cache' => array(
'pretty_version' => '1.0.1',
'version' => '1.0.1.0',
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
'type' => 'library',
'install_path' => __DIR__ . '/../psr/simple-cache',
'aliases' => array(),
'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
'dev_requirement' => false,
),
'psr/simple-cache-implementation' => array(
@@ -320,10 +320,10 @@
'ralouphie/getallheaders' => array(
'pretty_version' => '3.0.3',
'version' => '3.0.3.0',
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'type' => 'library',
'install_path' => __DIR__ . '/../ralouphie/getallheaders',
'aliases' => array(),
'reference' => '120b605dfeb996808c31b6477290a714d356e822',
'dev_requirement' => false,
),
'rsky/pear-core-min' => array(
@@ -335,298 +335,298 @@
'scssphp/scssphp' => array(
'pretty_version' => '1.0.6',
'version' => '1.0.6.0',
'reference' => '5b3c9d704950d8f9637f5110c36c281ec47dc13c',
'type' => 'library',
'install_path' => __DIR__ . '/../scssphp/scssphp',
'aliases' => array(),
'reference' => '5b3c9d704950d8f9637f5110c36c281ec47dc13c',
'dev_requirement' => false,
),
'swiftmailer/swiftmailer' => array(
'pretty_version' => 'v6.3.0',
'version' => '6.3.0.0',
'reference' => '8a5d5072dca8f48460fce2f4131fcc495eec654c',
'type' => 'library',
'install_path' => __DIR__ . '/../swiftmailer/swiftmailer',
'aliases' => array(),
'reference' => '8a5d5072dca8f48460fce2f4131fcc495eec654c',
'dev_requirement' => false,
),
'symfony/cache' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'a7a14c4832760bd1fbd31be2859ffedc9b6ff813',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/cache',
'aliases' => array(),
'reference' => 'a7a14c4832760bd1fbd31be2859ffedc9b6ff813',
'dev_requirement' => false,
),
'symfony/class-loader' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'a22265a9f3511c0212bf79f54910ca5a77c0e92c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/class-loader',
'aliases' => array(),
'reference' => 'a22265a9f3511c0212bf79f54910ca5a77c0e92c',
'dev_requirement' => false,
),
'symfony/config' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'bc6b3fd3930d4b53a60b42fe2ed6fc466b75f03f',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/config',
'aliases' => array(),
'reference' => 'bc6b3fd3930d4b53a60b42fe2ed6fc466b75f03f',
'dev_requirement' => false,
),
'symfony/console' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'a10b1da6fc93080c180bba7219b5ff5b7518fe81',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/console',
'aliases' => array(),
'reference' => 'a10b1da6fc93080c180bba7219b5ff5b7518fe81',
'dev_requirement' => false,
),
'symfony/css-selector' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'da3d9da2ce0026771f5fe64cb332158f1bd2bc33',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/css-selector',
'aliases' => array(),
'reference' => 'da3d9da2ce0026771f5fe64cb332158f1bd2bc33',
'dev_requirement' => false,
),
'symfony/debug' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'ab42889de57fdfcfcc0759ab102e2fd4ea72dcae',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/debug',
'aliases' => array(),
'reference' => 'ab42889de57fdfcfcc0759ab102e2fd4ea72dcae',
'dev_requirement' => false,
),
'symfony/dependency-injection' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => '51d2a2708c6ceadad84393f8581df1dcf9e5e84b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/dependency-injection',
'aliases' => array(),
'reference' => '51d2a2708c6ceadad84393f8581df1dcf9e5e84b',
'dev_requirement' => false,
),
'symfony/dotenv' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => '1022723ac4f56b001d99691d96c6025dbf1404f1',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/dotenv',
'aliases' => array(),
'reference' => '1022723ac4f56b001d99691d96c6025dbf1404f1',
'dev_requirement' => false,
),
'symfony/event-dispatcher' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => '31fde73757b6bad247c54597beef974919ec6860',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/event-dispatcher',
'aliases' => array(),
'reference' => '31fde73757b6bad247c54597beef974919ec6860',
'dev_requirement' => false,
),
'symfony/filesystem' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'e58d7841cddfed6e846829040dca2cca0ebbbbb3',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/filesystem',
'aliases' => array(),
'reference' => 'e58d7841cddfed6e846829040dca2cca0ebbbbb3',
'dev_requirement' => false,
),
'symfony/finder' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'b6b6ad3db3edb1b4b1c1896b1975fb684994de6e',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/finder',
'aliases' => array(),
'reference' => 'b6b6ad3db3edb1b4b1c1896b1975fb684994de6e',
'dev_requirement' => false,
),
'symfony/framework-bundle' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => '6c95e747b75ddd2af61152ce93bf87299d15710e',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/framework-bundle',
'aliases' => array(),
'reference' => '6c95e747b75ddd2af61152ce93bf87299d15710e',
'dev_requirement' => false,
),
'symfony/http-foundation' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'b9885fcce6fe494201da4f70a9309770e9d13dc8',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-foundation',
'aliases' => array(),
'reference' => 'b9885fcce6fe494201da4f70a9309770e9d13dc8',
'dev_requirement' => false,
),
'symfony/http-kernel' => array(
'pretty_version' => 'v3.4.49',
'version' => '3.4.49.0',
'reference' => '5aa72405f5bd5583c36ed6e756acb17d3f98ac40',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/http-kernel',
'aliases' => array(),
'reference' => '5aa72405f5bd5583c36ed6e756acb17d3f98ac40',
'dev_requirement' => false,
),
'symfony/polyfill-apcu' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'reference' => 'b44b51e7814c23bfbd793a16ead5d7ce43ed23c5',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-apcu',
'aliases' => array(),
'reference' => 'b44b51e7814c23bfbd793a16ead5d7ce43ed23c5',
'dev_requirement' => false,
),
'symfony/polyfill-ctype' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'reference' => 'aed596913b70fae57be53d86faa2e9ef85a2297b',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-ctype',
'aliases' => array(),
'reference' => 'aed596913b70fae57be53d86faa2e9ef85a2297b',
'dev_requirement' => false,
),
'symfony/polyfill-iconv' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'reference' => '085241787d52fa6f7a774fd034135fef0cfd5496',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-iconv',
'aliases' => array(),
'reference' => '085241787d52fa6f7a774fd034135fef0cfd5496',
'dev_requirement' => false,
),
'symfony/polyfill-intl-idn' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'reference' => '4ad5115c0f5d5172a9fe8147675ec6de266d8826',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-idn',
'aliases' => array(),
'reference' => '4ad5115c0f5d5172a9fe8147675ec6de266d8826',
'dev_requirement' => false,
),
'symfony/polyfill-intl-normalizer' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'reference' => '8db0ae7936b42feb370840cf24de1a144fb0ef27',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-intl-normalizer',
'aliases' => array(),
'reference' => '8db0ae7936b42feb370840cf24de1a144fb0ef27',
'dev_requirement' => false,
),
'symfony/polyfill-mbstring' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'reference' => 'b5f7b932ee6fa802fc792eabd77c4c88084517ce',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
'aliases' => array(),
'reference' => 'b5f7b932ee6fa802fc792eabd77c4c88084517ce',
'dev_requirement' => false,
),
'symfony/polyfill-php56' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'reference' => 'ea19621731cbd973a6702cfedef3419768bf3372',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php56',
'aliases' => array(),
'reference' => 'ea19621731cbd973a6702cfedef3419768bf3372',
'dev_requirement' => false,
),
'symfony/polyfill-php70' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'reference' => '3fe414077251a81a1b15b1c709faf5c2fbae3d4e',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php70',
'aliases' => array(),
'reference' => '3fe414077251a81a1b15b1c709faf5c2fbae3d4e',
'dev_requirement' => false,
),
'symfony/polyfill-php72' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'reference' => 'beecef6b463b06954638f02378f52496cb84bacc',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-php72',
'aliases' => array(),
'reference' => 'beecef6b463b06954638f02378f52496cb84bacc',
'dev_requirement' => false,
),
'symfony/polyfill-util' => array(
'pretty_version' => 'v1.19.0',
'version' => '1.19.0.0',
'reference' => '8df0c3e6a4b85df9a5c6f3f2f46fba5c5c47058a',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/polyfill-util',
'aliases' => array(),
'reference' => '8df0c3e6a4b85df9a5c6f3f2f46fba5c5c47058a',
'dev_requirement' => false,
),
'symfony/routing' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => '3e522ac69cadffd8131cc2b22157fa7662331a6c',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/routing',
'aliases' => array(),
'reference' => '3e522ac69cadffd8131cc2b22157fa7662331a6c',
'dev_requirement' => false,
),
'symfony/stopwatch' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => '298b81faad4ce60e94466226b2abbb8c9bca7462',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/stopwatch',
'aliases' => array(),
'reference' => '298b81faad4ce60e94466226b2abbb8c9bca7462',
'dev_requirement' => true,
),
'symfony/twig-bridge' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => '090d19d6f1ea5b9e1d79f372785aa5e5c9cd4042',
'type' => 'symfony-bridge',
'install_path' => __DIR__ . '/../symfony/twig-bridge',
'aliases' => array(),
'reference' => '090d19d6f1ea5b9e1d79f372785aa5e5c9cd4042',
'dev_requirement' => false,
),
'symfony/twig-bundle' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => '977b3096e2df96bc8a8d2329e83466cfc30c373d',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/twig-bundle',
'aliases' => array(),
'reference' => '977b3096e2df96bc8a8d2329e83466cfc30c373d',
'dev_requirement' => false,
),
'symfony/var-dumper' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => '0719f6cf4633a38b2c1585140998579ce23b4b7d',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/var-dumper',
'aliases' => array(),
'reference' => '0719f6cf4633a38b2c1585140998579ce23b4b7d',
'dev_requirement' => true,
),
'symfony/web-profiler-bundle' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => 'ccb83b3a508f4a683e44f571f127beebdc315ff9',
'type' => 'symfony-bundle',
'install_path' => __DIR__ . '/../symfony/web-profiler-bundle',
'aliases' => array(),
'reference' => 'ccb83b3a508f4a683e44f571f127beebdc315ff9',
'dev_requirement' => true,
),
'symfony/yaml' => array(
'pretty_version' => 'v3.4.47',
'version' => '3.4.47.0',
'reference' => '88289caa3c166321883f67fe5130188ebbb47094',
'type' => 'library',
'install_path' => __DIR__ . '/../symfony/yaml',
'aliases' => array(),
'reference' => '88289caa3c166321883f67fe5130188ebbb47094',
'dev_requirement' => false,
),
'tecnickcom/tcpdf' => array(
@@ -638,28 +638,28 @@
'thenetworg/oauth2-azure' => array(
'pretty_version' => 'v2.1.1',
'version' => '2.1.1.0',
'reference' => '06fb2d620fb6e6c934f632c7ec7c5ea2e978a844',
'type' => 'library',
'install_path' => __DIR__ . '/../thenetworg/oauth2-azure',
'aliases' => array(),
'reference' => '06fb2d620fb6e6c934f632c7ec7c5ea2e978a844',
'dev_requirement' => false,
),
'true/punycode' => array(
'pretty_version' => 'v2.1.1',
'version' => '2.1.1.0',
'reference' => 'a4d0c11a36dd7f4e7cd7096076cab6d3378a071e',
'type' => 'library',
'install_path' => __DIR__ . '/../true/punycode',
'aliases' => array(),
'reference' => 'a4d0c11a36dd7f4e7cd7096076cab6d3378a071e',
'dev_requirement' => false,
),
'twig/twig' => array(
'pretty_version' => 'v1.42.5',
'version' => '1.42.5.0',
'reference' => '87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e',
'type' => 'library',
'install_path' => __DIR__ . '/../twig/twig',
'aliases' => array(),
'reference' => '87b2ea9d8f6fd014d0621ca089bb1b3769ea3f8e',
'dev_requirement' => false,
),
'zendframework/zend-loader' => array(

View File

@@ -6,7 +6,7 @@ on:
jobs:
build:
name: Build
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
strategy:
max-parallel: 10
matrix:
@@ -21,11 +21,7 @@ jobs:
extensions: mbstring
- name: Checkout code
uses: actions/checkout@v2
- name: Mimic PHP 8.0
run: composer config platform.php 8.0.999
if: matrix.php > 8
uses: actions/checkout@v3
- name: Install dependencies
run: composer update --no-interaction --no-progress

View File

@@ -4,14 +4,13 @@ on:
pull_request:
jobs:
build:
name: Test
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
strategy:
max-parallel: 10
matrix:
php: ['7.2', '7.3', '7.4', '8.0']
php: ['7.2', '7.3', '7.4', '8.0', '8.1']
steps:
- name: Set up PHP
@@ -21,7 +20,7 @@ jobs:
coverage: none
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Download dependencies
uses: ramsey/composer-install@v1

View File

@@ -6,11 +6,11 @@ on:
jobs:
php-cs-fixer:
name: PHP-CS-Fixer
runs-on: ubuntu-latest
runs-on: ubuntu-22.04
steps:
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Setup PHP
uses: shivammathur/setup-php@v2

View File

@@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
## 1.9.1 - 2023-04-17
### Fixed
- Fixed header validation issue
## 1.9.0 - 2022-06-20
### Added

View File

@@ -61,11 +61,6 @@
"GuzzleHttp\\Tests\\Psr7\\": "tests/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
}
},
"config": {
"preferred-install": "dist",
"sort-packages": true,

View File

@@ -226,12 +226,9 @@ trait MessageTrait
throw new \InvalidArgumentException('Header name can not be empty.');
}
if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/', $header)) {
if (! preg_match('/^[a-zA-Z0-9\'`#$%&*+.^_|~!-]+$/D', $header)) {
throw new \InvalidArgumentException(
sprintf(
'"%s" is not valid header name',
$header
)
sprintf('"%s" is not valid header name.', $header)
);
}
}
@@ -263,8 +260,10 @@ trait MessageTrait
// Clients must not send a request with line folding and a server sending folded headers is
// likely very rare. Line folding is a fairly obscure feature of HTTP/1.1 and thus not accepting
// folding is not likely to break any legitimate use case.
if (! preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/', $value)) {
throw new \InvalidArgumentException(sprintf('"%s" is not valid header value', $value));
if (! preg_match('/^[\x20\x09\x21-\x7E\x80-\xFF]*$/D', $value)) {
throw new \InvalidArgumentException(
sprintf('"%s" is not valid header value.', $value)
);
}
}
}

View File

@@ -1,13 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.webServer>
<security>
<requestFiltering>
<fileExtensions applyToWebDAV="false" allowUnlisted="false"></fileExtensions>
</requestFiltering>
<authorization>
<deny users="*" /> <!-- Denies all users -->
</authorization>
</security>
</system.webServer>
<system.web>
<authorization>
<deny users="*" /> <!-- Denies all users -->
</authorization>
</system.web>
</configuration>

View File

@@ -37,10 +37,7 @@ try
$oKPI->ComputeAndReport('Data model loaded');
$oKPI = new ExecutionKPI();
if (LoginWebPage::EXIT_CODE_OK != LoginWebPage::DoLoginEx('backoffice', false, LoginWebPage::EXIT_RETURN))
{
throw new SecurityException('You must be logged in');
}
LoginWebPage::DoLogin();
$sParams = utils::ReadParam('params', '', false, 'raw_data');
if (!$sParams)
@@ -75,7 +72,7 @@ try
if (array_key_exists('table_inner_id', $aListParams))
{
$sListId = $aListParams['table_inner_id'];
$sListId = utils::Sanitize($aListParams['table_inner_id'], '', 'element_identifier');
}
if (array_key_exists('json', $aListParams))

View File

@@ -96,5 +96,11 @@ if ($bLoginDebug)
IssueLog::Info("--> Display logout page");
}
LoginWebPage::ResetSession(true);
if ($bLoginDebug) {
$sSessionLog = session_id().' '.utils::GetSessionLog();
IssueLog::Info("SESSION: $sSessionLog");
}
$oPage = LoginWebPage::NewLoginWebPage();
$oPage->DisplayLogoutPage($bPortal);

View File

@@ -307,6 +307,7 @@ class DBBackup
$sPortOption = self::GetMysqliCliSingleOption('port', $this->iDBPort);
$sTlsOptions = self::GetMysqlCliTlsOptions($this->oConfig);
$sProtocolOption = self::GetMysqlCliTransportOption($this->sDBHost);
$sMysqlVersion = CMDBSource::GetDBVersion();
$bIsMysqlSupportUtf8mb4 = (version_compare($sMysqlVersion, self::MYSQL_VERSION_WITH_UTF8MB4_IN_PROGRAMS) === -1);
@@ -327,8 +328,8 @@ EOF;
// Note: opt implicitely sets lock-tables... which cancels the benefit of single-transaction!
// skip-lock-tables compensates and allows for writes during a backup
$sCommand = "$sMySQLDump --defaults-extra-file=\"$sMySQLDumpCnfFile\" --opt --skip-lock-tables --default-character-set=".$sMysqldumpCharset." --add-drop-database --single-transaction --host=$sHost $sPortOption --user=$sUser $sTlsOptions --result-file=$sTmpFileName $sDBName $sTables 2>&1";
$sCommandDisplay = "$sMySQLDump --defaults-extra-file=\"$sMySQLDumpCnfFile\" --opt --skip-lock-tables --default-character-set=".$sMysqldumpCharset." --add-drop-database --single-transaction --host=$sHost $sPortOption --user=xxxxx $sTlsOptions --result-file=$sTmpFileName $sDBName $sTables";
$sCommand = "$sMySQLDump --defaults-extra-file=\"$sMySQLDumpCnfFile\" --opt --skip-lock-tables --default-character-set=".$sMysqldumpCharset." --add-drop-database --single-transaction --host=$sHost $sPortOption $sProtocolOption --user=$sUser $sTlsOptions --result-file=$sTmpFileName $sDBName $sTables 2>&1";
$sCommandDisplay = "$sMySQLDump --defaults-extra-file=\"$sMySQLDumpCnfFile\" --opt --skip-lock-tables --default-character-set=".$sMysqldumpCharset." --add-drop-database --single-transaction --host=$sHost $sPortOption $sProtocolOption --user=xxxxx $sTlsOptions --result-file=$sTmpFileName $sDBName $sTables";
// Now run the command for real
$this->LogInfo("backup: generate data file with command: $sCommandDisplay");
@@ -416,8 +417,8 @@ EOF;
if ($oMysqli->connect_errno)
{
$sHost = is_null($this->iDBPort) ? $this->sDBHost : $this->sDBHost.' on port '.$this->iDBPort;
throw new BackupException("Cannot connect to the MySQL server '$sHost' (".$oMysqli->connect_errno.") ".$oMysqli->connect_error);
}
throw new MySQLException('Could not connect to the DB server '.$oMysqli->connect_errno.' (mysql errno: '.$oMysqli->connect_error, array('host' => $sHost, 'user' => $sUser));
}
if (!$oMysqli->select_db($this->sDBName))
{
throw new BackupException("The database '$this->sDBName' does not seem to exist");
@@ -521,6 +522,28 @@ EOF;
return ' --'.$sCliArgName.'='.self::EscapeShellArg($sData);
}
/**
* Define if we should force a transport option
*
* @param string $sHost
*
* @return string .
* @since 2.7.9 3.0.4 3.1.1 N°6123
*/
public static function GetMysqlCliTransportOption(string $sHost)
{
$sTransportOptions = '';
/** N°6123 As we're using a --port option, if we use localhost as host,
* MariaDB > 10.6 will implicitly change its protocol from socket to tcp and throw a warning **/
if($sHost === 'localhost'){
$sTransportOptions = '--protocol=tcp';
}
return $sTransportOptions;
}
/**
* @return string the command to launch mysqldump (without its params)
*/

View File

@@ -17,11 +17,27 @@
* You should have received a copy of the GNU Affero General Public License
*/
/**
* Since N°1934 this page is accessible only to iTop admin users
* @since 2.5.2 2.6.1 2.7.0 N°1934 must login as admin user to use
* to check if PHP is up and running, use phpcheck.php !
*/
require_once('../approot.inc.php');
require_once(APPROOT.'/application/startup.inc.php');
try {
require_once(APPROOT.'/application/startup.inc.php');
} catch (Exception $e) {
// This means we don't have a valid iTop installation running
echo <<<EOF
No valid installation found, cannot continue !<br>
If you need to check that PHP is running, use <a href="phpcheck.php">phpcheck.php</a>
EOF;
die(-1);
}
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (N°1934)
/** @noinspection ForgottenDebugOutputInspection */
phpinfo();
?>

View File

@@ -74,6 +74,7 @@ class OAuthClientProviderFactory
* @return AccessTokenInterface
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \League\OAuth2\Client\Provider\Exception\IdentityProviderException
*/
public static function GetAccessTokenFromCode(OAuthClient $oOAuthClient, $sCode)
{
@@ -109,7 +110,7 @@ class OAuthClientProviderFactory
/**
* @param \DBObject $oOAuthClient
*
* @return mixed
* @return OAuthClientProviderAbstract
* @throws \ArchivedObjectException
* @throws \CoreException
*/

View File

@@ -181,7 +181,11 @@ class EmailSwiftMailer extends EMail
case 'PHPMail':
default:
$oTransport = new Swift_SendmailTransport();
// Retrieve sendmail path or select a default one as SwiftMailer is not doing it anymore
$sSendmailPath = ini_get('sendmail_path');
$sSendmailPath = ($sSendmailPath === false || $sSendmailPath === '') ? '/usr/sbin/sendmail -bs' : $sSendmailPath;
$oTransport = new Swift_SendmailTransport($sSendmailPath);
}
$oMailer = new Swift_Mailer($oTransport);

View File

@@ -0,0 +1,125 @@
<?php
/**
* @copyright Copyright (C) 2010-2023 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Core\Kpi;
class KpiLogData
{
const TYPE_REPORT = 'report';
const TYPE_STATS = 'stats';
const TYPE_REQUEST = 'request';
/** @var string */
public $sType;
/** @var string */
public $sOperation;
/** @var string */
public $sArguments;
/** @var float */
public $fStartTime;
/** @var float */
public $fStopTime;
/** @var string */
public $sExtension;
/** @var int */
public $iInitialMemory;
/** @var int */
public $iCurrentMemory;
/** @var int */
public $iPeakMemory;
/** @var array */
public $aData;
/**
* @param string $sType
* @param string $sOperation
* @param string $sArguments
* @param float $fStartTime
* @param float $fStopTime
* @param string $sExtension
* @param int $iInitialMemory
* @param int $iCurrentMemory
* @param array $aData
*/
public function __construct($sType, $sOperation, $sArguments, $fStartTime, $fStopTime, $sExtension, $iInitialMemory = 0, $iCurrentMemory = 0, $iPeakMemory = 0, $aData = [])
{
$this->sType = $sType;
$this->sOperation = $sOperation;
$this->sArguments = @iconv(mb_detect_encoding($sArguments, mb_detect_order(), true), 'UTF-8', $sArguments);
$this->fStartTime = $fStartTime;
$this->fStopTime = $fStopTime;
$this->sExtension = $sExtension;
$this->iInitialMemory = $iInitialMemory;
$this->iCurrentMemory = $iCurrentMemory;
$this->iPeakMemory = $iPeakMemory;
$this->aData = $aData;
}
/**
* Return the CSV Header
*
* @return string
*/
public static function GetCSVHeader()
{
return "Type,Operation,Arguments,StartTime,StopTime,Duration,Extension,InitialMemory,CurrentMemory,PeakMemory";
}
/**
* Return the CSV line for the values
* @return string
*/
public function GetCSV()
{
$fDuration = sprintf('%01.4f', $this->fStopTime - $this->fStartTime);
$sType = $this->RemoveQuotes($this->sType);
$sOperation = $this->RemoveQuotes($this->sOperation);
$sArguments = $this->RemoveQuotes($this->sArguments);
$sExtension = $this->RemoveQuotes($this->sExtension);
return "\"$sType\",\"$sOperation\",\"$sArguments\",$this->fStartTime,$this->fStopTime,$fDuration,\"$sExtension\",$this->iInitialMemory,$this->iCurrentMemory,$this->iPeakMemory";
}
private function RemoveQuotes(string $sEntry): string
{
return str_replace('"', "'", $sEntry);
}
/**
* @param \Combodo\iTop\Core\Kpi\KpiLogData $oOther
*
* @return float
*/
public function Compare(KpiLogData $oOther): float
{
if ($oOther->fStartTime > $this->fStartTime) {
return -1;
}
return 1;
}
public function Contains(KpiLogData $oOther): bool
{
if ($oOther->fStartTime < $this->fStartTime) {
return false;
}
if ($oOther->fStartTime > $this->fStopTime) {
return false;
}
return true;
}
public function __toString()
{
return "$this->sType:$this->sOperation:$this->sArguments";
}
public function GetUUID(): string
{
return sha1($this->__toString());
}
}

View File

@@ -0,0 +1,214 @@
<?php
/**
* @copyright Copyright (C) 2010-2023 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\Service\Module;
use MetaModel;
use ReflectionClass;
use ReflectionMethod;
use utils;
class ModuleService
{
/** @var ModuleService */
private static $oInstance;
private function __construct()
{
}
public static function GetInstance(): ModuleService
{
if (!isset(static::$oInstance)) {
static::$oInstance = new ModuleService();
}
return static::$oInstance;
}
/**
* Get a "signature" of the method of an extension in the form of: "[module-name] class::method()"
*
* @param object|string $object Object or class
* @param string $sMethod
*
* @return string
* @throws \ReflectionException
*/
public function GetModuleMethodSignature($object, string $sMethod): string
{
$sSignature = '';
$oReflectionMethod = new ReflectionMethod($object, $sMethod);
$oReflectionClass = $oReflectionMethod->getDeclaringClass();
$sExtension = $this->GetModuleNameFromObject($oReflectionClass->getName());
if (strlen($sExtension) !== 0) {
$sSignature .= '['.$sExtension.'] ';
}
$sSignature .= $oReflectionClass->getShortName().'::'.$sMethod.'()';
return $sSignature;
}
/**
* Get the module name from an object or class
*
* @param object|string $object
*
* @return string
* @throws \ReflectionException
*/
public function GetModuleNameFromObject($object): string
{
$oReflectionClass = new ReflectionClass($object);
$sPath = str_replace('\\', '/', $oReflectionClass->getFileName());
$sPattern = str_replace('\\', '/', '@'.APPROOT.'env-'.utils::GetCurrentEnvironment()).'/(?<ext>.+)/@U';
if (preg_match($sPattern, $sPath, $aMatches) !== false) {
if (isset($aMatches['ext'])) {
return $aMatches['ext'];
}
}
return '';
}
/**
* **Warning** : returned result can be invalid as we're using backtrace to find the module dir name
*
* @param int $iCallDepth The depth of the module in the callstack. Zero when called directly from within the module
*
* @return string the relative (to MODULESROOT) path of the root directory of the module containing the file where the call to
* this function is made
* or an empty string if no such module is found (or not called within a module file)
*
* @uses \debug_backtrace()
*/
public function GetCurrentModuleDir(int $iCallDepth): string
{
$sCurrentModuleDir = '';
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
foreach(GetModulesInfo() as $sModuleName => $aInfo)
{
if ($aInfo['root_dir'] !== '')
{
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
if(substr($sCallerFile, 0, strlen($sRootDir)) === $sRootDir)
{
$sCurrentModuleDir = basename($sRootDir);
break;
}
}
}
return $sCurrentModuleDir;
}
/**
* **Warning** : as this method uses {@see GetCurrentModuleDir} it produces hazardous results.
* You should better uses directly {@see GetAbsoluteUrlModulesRoot} and add the module dir name yourself ! See N°4573
*
* @return string the base URL for all files in the current module from which this method is called
* or an empty string if no such module is found (or not called within a module file)
* @throws \Exception
*
* @uses GetCurrentModuleDir
*/
public function GetCurrentModuleUrl(int $iCallDepth = 0): string
{
$sDir = $this->GetCurrentModuleDir(1 + $iCallDepth);
if ( $sDir !== '')
{
return utils::GetAbsoluteUrlModulesRoot().'/'.$sDir;
}
return '';
}
/**
* @param string $sProperty The name of the property to retrieve
* @param mixed $defaultValue
*
* @return mixed the value of a given setting for the current module
*/
public function GetCurrentModuleSetting(string $sProperty, $defaultValue = null)
{
$sModuleName = $this->GetCurrentModuleName(1);
return MetaModel::GetModuleSetting($sModuleName, $sProperty, $defaultValue);
}
/**
* @param string $sModuleName
*
* @return string|NULL compiled version of a given module, as it was seen by the compiler
*/
public function GetCompiledModuleVersion(string $sModuleName): ?string
{
$aModulesInfo = GetModulesInfo();
if (array_key_exists($sModuleName, $aModulesInfo))
{
return $aModulesInfo[$sModuleName]['version'];
}
return null;
}
/**
* Returns the name of the module containing the file where the call to this function is made
* or an empty string if no such module is found (or not called within a module file)
*
* @param int $iCallDepth The depth of the module in the callstack. Zero when called directly from within the module
*
* @return string
*/
public function GetCurrentModuleName(int $iCallDepth = 0): string
{
$sCurrentModuleName = '';
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$sCallerFile = realpath($aCallStack[$iCallDepth]['file']);
return $this->GetModuleNameFromPath($sCallerFile);
}
private function GetModuleNameFromPath($sPath)
{
foreach (GetModulesInfo() as $sModuleName => $aInfo) {
if ($aInfo['root_dir'] !== '') {
$sRootDir = realpath(APPROOT.$aInfo['root_dir']);
if (substr($sPath, 0, strlen($sRootDir)) === $sRootDir) {
return $sModuleName;
}
}
}
return '';
}
/**
* Get the extension code from the call stack.
* Scan the call stack until a module is found.
*
* @param int $iLevelsToIgnore
*
* @return string module name
*/
public function GetModuleNameFromCallStack(int $iLevelsToIgnore = 0): string
{
$aCallStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
$aCallStack = array_slice($aCallStack, $iLevelsToIgnore);
foreach ($aCallStack as $aCallInfo) {
$sFile = realpath(empty($aCallInfo['file']) ? '' : $aCallInfo['file']);
$sModuleName = $this->GetModuleNameFromPath($sFile);
if (strlen($sModuleName) > 0) {
return $sModuleName;
}
}
return '';
}
}

View File

@@ -111,7 +111,36 @@ if (utils::IsModeCLI())
else
{
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
LoginWebPage::ResetSession(true);
$iRet = LoginWebPage::DoLogin(false, false, LoginWebPage::EXIT_RETURN);
if ($iRet !== LoginWebPage::EXIT_CODE_OK) {
switch ($iRet) {
case LoginWebPage::EXIT_CODE_MISSINGLOGIN:
$oP->p("Missing parameter 'auth_user'");
break;
case LoginWebPage::EXIT_CODE_MISSINGPASSWORD:
$oP->p("Missing parameter 'auth_pwd'");
break;
case LoginWebPage::EXIT_CODE_WRONGCREDENTIALS:
$oP->p('Invalid login');
break;
case LoginWebPage::EXIT_CODE_PORTALUSERNOTAUTHORIZED:
$oP->p('Portal user is not allowed');
break;
case LoginWebPage::EXIT_CODE_NOTAUTHORIZED:
$oP->p('This user is not authorized to use the web services. (The profile REST Services User is required to access the REST web services)');
break;
default:
$oP->p("Unknown authentication error (retCode=$iRet)");
}
$oP->output();
exit -1;
}
$sDataSourcesList = utils::ReadParam('data_sources', null, true, 'raw_data');

View File

@@ -303,7 +303,36 @@ if (utils::IsModeCLI())
else
{
require_once APPROOT.'/application/loginwebpage.class.inc.php';
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
LoginWebPage::ResetSession(true);
$iRet = LoginWebPage::DoLogin(false, false, LoginWebPage::EXIT_RETURN);
if ($iRet !== LoginWebPage::EXIT_CODE_OK) {
switch ($iRet) {
case LoginWebPage::EXIT_CODE_MISSINGLOGIN:
$oP->p("Missing parameter 'auth_user'");
break;
case LoginWebPage::EXIT_CODE_MISSINGPASSWORD:
$oP->p("Missing parameter 'auth_pwd'");
break;
case LoginWebPage::EXIT_CODE_WRONGCREDENTIALS:
$oP->p('Invalid login');
break;
case LoginWebPage::EXIT_CODE_PORTALUSERNOTAUTHORIZED:
$oP->p('Portal user is not allowed');
break;
case LoginWebPage::EXIT_CODE_NOTAUTHORIZED:
$oP->p('This user is not authorized to use the web services. (The profile REST Services User is required to access the REST web services)');
break;
default:
$oP->p("Unknown authentication error (retCode=$iRet)");
}
$oP->output();
exit -1;
}
$sCSVData = utils::ReadPostedParam('csvdata', '', 'raw_data');
}

View File

@@ -45,6 +45,7 @@ use Server;
use TagSetFieldData;
use Ticket;
use URP_UserProfile;
use User;
use VirtualHost;
use VirtualMachine;
@@ -293,25 +294,31 @@ class ItopDataTestCase extends ItopTestCase
* Create a UserRequest in database
*
* @param int $iNum
* @param int $iTimeSpent
* @param int $iOrgId
* @param int $iCallerId
* @param array $aUserRequestCustomParams set fields values for the UserRequest : attcode as key, att value as value.
* If the attcode is already present in the default values, custom value will be kept (see array_merge documentation)
*
* @return \UserRequest
* @throws Exception
* @throws \ArchivedObjectException
* @throws \CoreException
*
* @link https://www.php.net/manual/en/function.array-merge.php array_merge PHP function documentation
*
* @uses \array_merge()
* @uses createObject
*/
protected function CreateUserRequest($iNum, $iTimeSpent = 0, $iOrgId = 0, $iCallerId = 0)
{
/** @var \UserRequest $oTicket */
$oTicket = $this->createObject('UserRequest', array(
protected function CreateUserRequest($iNum, $aUserRequestCustomParams = []) {
$aUserRequestDefaultParams = [
'ref' => 'Ticket_'.$iNum,
'title' => 'BUG 1161_'.$iNum,
//'request_type' => 'incident',
'description' => 'Add aggregate functions',
'time_spent' => $iTimeSpent,
'caller_id' => $iCallerId,
'org_id' => ($iOrgId == 0 ? $this->getTestOrgId() : $iOrgId),
));
'org_id' => $this->getTestOrgId(),
];
$aUserRequestParams = array_merge($aUserRequestDefaultParams, $aUserRequestCustomParams);
/** @var \UserRequest $oTicket */
$oTicket = $this->createObject('UserRequest', $aUserRequestParams);
$this->debug("Created {$oTicket->Get('title')} ({$oTicket->Get('ref')})");
return $oTicket;
@@ -449,7 +456,7 @@ class ItopDataTestCase extends ItopTestCase
/** @var DBObjectSet $oSet */
$oSet = $oUser->Get('profile_list');
$oSet->AddObject($oUserProfile);
$oUser = $this->updateObject('UserLocal', $oUser->GetKey(), array(
$oUser = $this->updateObject(User::class, $oUser->GetKey(), array(
'profile_list' => $oSet,
));
$this->debug("Updated {$oUser->GetName()} ({$oUser->GetKey()})");

View File

@@ -18,6 +18,9 @@ namespace Combodo\iTop\Test\UnitTest\Integration;
use Combodo\iTop\Test\UnitTest\ItopTestCase;
/**
* @group beforeSetup
*/
class DictionariesConsistencyTest extends ItopTestCase
{
/**
@@ -29,24 +32,27 @@ class DictionariesConsistencyTest extends ItopTestCase
*/
public function testDictionariesLanguage($sDictFile)
{
// In iTop the language available list is dynamically made during setup, depending on the dict files found
// Here we are using a fixed list
$aPrefixToLanguageData = array(
'cs' => array('CS CZ', 'Czech', 'Čeština'),
'da' => array('DA DA', 'Danish', 'Dansk'),
'de' => array('DE DE', 'German', 'Deutsch'),
'en' => array('EN US', 'English', 'English'),
'cs' => array('CS CZ', 'Czech', 'Čeština'),
'da' => array('DA DA', 'Danish', 'Dansk'),
'de' => array('DE DE', 'German', 'Deutsch'),
'en' => array('EN US', 'English', 'English'),
'es_cr' => array('ES CR', 'Spanish', array(
'Español, Castellaño', // old value
'Español, Castellano', // new value since N°3635
)),
'fr' => array('FR FR', 'French', 'Français'),
'hu' => array('HU HU', 'Hungarian', 'Magyar'),
'it' => array('IT IT', 'Italian', 'Italiano'),
'ja' => array('JA JP', 'Japanese', '日本語'),
'nl' => array('NL NL', 'Dutch', 'Nederlands'),
'fr' => array('FR FR', 'French', 'Français'),
'hu' => array('HU HU', 'Hungarian', 'Magyar'),
'it' => array('IT IT', 'Italian', 'Italiano'),
'ja' => array('JA JP', 'Japanese', '日本語'),
'nl' => array('NL NL', 'Dutch', 'Nederlands'),
'pl' => array('PL PL', 'Polish', 'Polski'),
'pt_br' => array('PT BR', 'Brazilian', 'Brazilian'),
'ru' => array('RU RU', 'Russian', 'Русский'),
'sk' => array('SK SK', 'Slovak', 'Slovenčina'),
'tr' => array('TR TR', 'Turkish', 'Türkçe'),
'ru' => array('RU RU', 'Russian', 'Русский'),
'sk' => array('SK SK', 'Slovak', 'Slovenčina'),
'tr' => array('TR TR', 'Turkish', 'Türkçe'),
'zh_cn' => array('ZH CN', 'Chinese', '简体中文'),
);

View File

@@ -15,7 +15,7 @@ use PHPUnit\Exception;
*
* @package Combodo\iTop\Test\UnitTest\Setup
*/
class TestForITopDesignFormatClass extends ItopTestCase
class iTopDesignFormatChecklistTest extends ItopTestCase
{
protected function setUp(): void
{
@@ -47,7 +47,7 @@ class TestForITopDesignFormatClass extends ItopTestCase
$aErrors[] = "cannot retrieve itop_design datamodel version in $sDataModelFile:1";
continue;
}
$aDatamodelCurrentVersions[$sVersion] = $sVersion;
}
}
@@ -159,4 +159,4 @@ class TestForITopDesignFormatClass extends ItopTestCase
}
return $aDataModelFiles;
}
}
}

View File

@@ -16,6 +16,7 @@
stopOnRisky="false"
stopOnSkipped="false"
verbose="true"
printerClass="Sempro\PHPUnitPrettyPrinter\PrettyPrinter"
>
<php>
@@ -23,6 +24,7 @@
<ini name="display_errors" value="On"/>
<ini name="log_errors" value="On"/>
<ini name="html_errors" value="Off"/>
<env name="PHPUNIT_PRETTY_PRINT_PROGRESS" value="true"/>
</php>
<testsuites>

View File

@@ -495,7 +495,7 @@ class utilsTest extends ItopTestCase
'good element_identifier' => ['element_identifier', 'AD05nb', 'AD05nb'],
'bad element_identifier' => ['element_identifier', 'AD05nb+', 'AD05nb'],
'good url' => ['url', 'https://www.w3schools.com', 'https://www.w3schools.com'],
'bad url' => ['url', 'https://www.w3schoo<6F><6F>ls.co<63>m', 'https://www.w3schools.com'],
'bad url' => ['url', 'https://www.w3schoo<6F><6F>ls.co<63>m', null],
'raw_data' => ['raw_data', '<Test>\s😃😃😃', '<Test>\s😃😃😃'],
];
}

View File

@@ -56,7 +56,7 @@ class DeadLockInjection
if ($this->iRequestCount == $this->iFailAt) {
echo "Generating a FAKE DEADLOCK\n";
IssueLog::Trace("Generating a FAKE DEADLOCK", 'cmdbsource');
throw new MySQLException("FAKE DEADLOCK", [], new Exception("FAKE DEADLOCK", 1213));
throw new MySQLException("FAKE DEADLOCK", [], new Exception("FAKE DEADLOCK", CMDBSource::MYSQL_ERRNO_DEADLOCK));
}
}
}

View File

@@ -161,7 +161,11 @@ class DBSearchTest extends ItopDataTestCase
$i = 0;
foreach($aReq as $aParams)
{
$oObj = $this->CreateUserRequest($i, $aParams[0], $aOrgIds[$aParams[1]], $aPersonIds[$aParams[2]]);
$oObj = $this->CreateUserRequest($i, [
'time_spent' => $aParams[0],
'org_id' => $aOrgIds[$aParams[1]],
'caller_id' => $aPersonIds[$aParams[2]],
]);
self::assertNotNull($oObj);
$i++;
}

View File

@@ -84,4 +84,31 @@ class DBBackupTest extends ItopTestCase
$this->assertStringStartsWith(' --ssl', $sCliArgsCapathCfg);
$this->assertStringEndsWith('--ssl-ca='.DBBackup::EscapeShellArg($sTestCa), $sCliArgsCapathCfg);
}
/**
* Host is localhost, we should be forced into tcp
*
* @return void
*/
public function testGetMysqlCliTransportOptionWithLocalhost()
{
$sHost= 'localhost';
$sTransport = DBBackup::GetMysqlCliTransportOption($sHost);
$this->assertStringStartsWith('--protocol=tcp', $sTransport);
$this->assertStringEndsWith('--protocol=tcp', $sTransport);
}
/**
* Host is not localhost, we shouldn't be forced into tcp
*
* @return void
*/
public function testGetMysqlCliTransportOptionWithoutLocalhost()
{
$sHost= '127.0.0.1';
$sTransport = DBBackup::GetMysqlCliTransportOption($sHost);
$this->assertEmpty($sTransport);
}
}

View File

@@ -0,0 +1,257 @@
<?php
namespace Combodo\iTop\Test\UnitTest\Webservices;
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
use Config;
use Exception;
use MetaModel;
/**
* @runTestsInSeparateProcesses
* @preserveGlobalState disabled
* @backupGlobals disabled
*/
class CliResetSessionTest extends ItopDataTestCase
{
const USE_TRANSACTION = false;
private $sCookieFile = "";
private $sUrl;
private $sLogin;
private $sUserId;
private $sPassword = "Iuytrez9876543ç_è-(";
protected $sConfigTmpBackupFile;
/**
* @throws Exception
*/
protected function setUp(): void
{
parent::setUp();
$this->sConfigTmpBackupFile = tempnam(sys_get_temp_dir(), "config_");
MetaModel::GetConfig()->WriteToFile($this->sConfigTmpBackupFile);
$this->sLogin = "rest-user-".date('dmYHis');
$this->CreateTestOrganization();
$this->sCookieFile = tempnam(sys_get_temp_dir(), 'jsondata_');
$this->sUrl = \MetaModel::GetConfig()->Get('app_root_url');
$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->sUserId = $oUser->GetKey();
$this->AddProfileToUser($oUser, $oAdminProfile->GetKey());
}
}
protected function tearDown(): void {
parent::tearDown();
if (! is_null($this->sConfigTmpBackupFile) && is_file($this->sConfigTmpBackupFile)){
//put config back
$sConfigPath = MetaModel::GetConfig()->GetLoadedFile();
@chmod($sConfigPath, 0770);
$oConfig = new Config($this->sConfigTmpBackupFile);
$oConfig->WriteToFile($sConfigPath);
@chmod($sConfigPath, 0440);
unlink($this->sConfigTmpBackupFile);
}
if (!empty($this->sCookieFile)) {
unlink($this->sCookieFile);
}
}
protected function AddLoginMode($sLoginMode){
@chmod(MetaModel::GetConfig()->GetLoadedFile(), 0770);
$aAllowedLoginTypes = MetaModel::GetConfig()->GetAllowedLoginTypes();
if (! in_array($sLoginMode, $aAllowedLoginTypes)){
$aAllowedLoginTypes[] = $sLoginMode;
MetaModel::GetConfig()->SetAllowedLoginTypes($aAllowedLoginTypes);
MetaModel::GetConfig()->WriteToFile();
}
@chmod(MetaModel::GetConfig()->GetLoadedFile(), 0440);
}
protected function SetLoginModes($aAllowedLoginTypes){
@chmod(MetaModel::GetConfig()->GetLoadedFile(), 0770);
MetaModel::GetConfig()->SetAllowedLoginTypes($aAllowedLoginTypes);
MetaModel::GetConfig()->WriteToFile();
@chmod(MetaModel::GetConfig()->GetLoadedFile(), 0440);
}
public function RestProvider(){
return [
'nominal / no login_mode forced' => [
'sConfiguredLoginModes' => 'form|external|basic',
'sForcedLoginMode' => null,
],
'nominal / form forced' => [
'sConfiguredLoginModes' => 'form|external|basic',
'sForcedLoginMode' => 'form',
],
'nominal / external forced' => [
'sConfiguredLoginModes' => 'form|external|basic',
'sForcedLoginMode' => 'external',
],
'nominal / basic forced' => [
'sConfiguredLoginModes' => 'form|external|basic',
'sForcedLoginMode' => 'basic',
],
'nominal / url forced' => [
'sConfiguredLoginModes' => 'form|external|basic|url',
'sForcedLoginMode' => 'url',
],
'nominal / cas forced' => [
'sConfiguredLoginModes' => 'form|external|basic|cas',
'sForcedLoginMode' => 'cas',
],
];
}
/**
* @dataProvider RestProvider
* @param $aLoginModes
* @param $sForcedLoginMode
*
* @return void
*/
public function testRest($sConfiguredLoginModes=null, $sForcedLoginMode=null, $sExpectedFailHttpCode="200"){
if (! is_null($sConfiguredLoginModes)){
$this->SetLoginModes(explode('|', $sConfiguredLoginModes));
}
$sJsonGetContent = <<<JSON
{
"operation": "core/get",
"class": "User",
"key": $this->sUserId,
"output_fields": "id"
}
JSON;
$aPostFields = [
'version' => '1.2',
'auth_user' => $this->sLogin,
'auth_pwd' => $this->sPassword,
'json_data' => $sJsonGetContent,
];
list($iHttpCode, $sJson) = $this->CallRestApi($aPostFields);
$this->assertEquals(200, $iHttpCode);
$aJson = json_decode($sJson, true);
$this->assertTrue(is_array($aJson), $sJson);
$this->assertEquals("0", $aJson['code'], $sJson);
//2nd call to REST API made with previous session cookie
//no need to pass auth_user/auth_pwd
$aPostFields = [
'version' => '1.2',
'json_data' => $sJsonGetContent,
];
list($iHttpCode, $sJson) = $this->CallRestApi($aPostFields, $sForcedLoginMode);
$this->debug($sJson);
$this->assertEquals($sExpectedFailHttpCode, $iHttpCode);
if ($iHttpCode === "200") {
$this->assertEquals('{"code":1,"message":"Error: Invalid login"}', $sJson);
}
}
public function OtherCliProvider(){
return [
'import' => [ 'webservices/import.php' ],
'synchro_exec' => [ 'synchro/synchro_exec.php' ],
'synchro_import' => [ 'synchro/synchro_import.php' ],
];
}
/**
* @dataProvider OtherCliProvider
*/
public function testImport($sUri){
$sJsonGetContent = <<<JSON
{
"operation": "core/get",
"class": "User",
"key": $this->sUserId,
"output_fields": "id"
}
JSON;
$aPostFields = [
'version' => '1.2',
'auth_user' => $this->sLogin,
'auth_pwd' => $this->sPassword,
'json_data' => $sJsonGetContent,
];
list($iHttpCode, $sOutput) = $this->CallRestApi($aPostFields);
$this->assertEquals(200, $iHttpCode);
$aJson = json_decode($sOutput, true);
$this->assertTrue(is_array($aJson), $sOutput);
$this->assertEquals("0", $aJson['code'], $sOutput);
//2nd call to REST API made with previous session cookie
//no need to pass auth_user/auth_pwd
$aPostFields = [
'version' => '1.2',
'json_data' => $sJsonGetContent,
];
list($iHttpCode, $sOutput) = $this->CallRestApi($aPostFields, null, $sUri);
$this->debug($sOutput);
$this->assertEquals("200", $iHttpCode);
$this->assertContains("Invalid login", $sOutput);
}
/**
* @param $aPostFields
*
* @return array($iHttpCode, $sBody)
*/
private function CallRestApi($aPostFields, $sForcedLoginMode=null, $sUri='webservices/rest.php'): array {
$ch = curl_init();
curl_setopt ($ch, CURLOPT_COOKIEJAR, $this->sCookieFile);
curl_setopt ($ch, CURLOPT_COOKIEFILE, $this->sCookieFile);
$sUrl = "$this->sUrl/$sUri";
if (!is_null($sForcedLoginMode)){
$sUrl .= "?login_mode=$sForcedLoginMode";
}
curl_setopt($ch, CURLOPT_URL, $sUrl);
curl_setopt($ch, CURLOPT_POST, 1);// set post data to true
curl_setopt($ch, CURLOPT_POSTFIELDS, $aPostFields);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 1);
// Force disable of certificate check as most of dev / test env have a self-signed certificate
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$sResponse = curl_exec($ch);
/** $sResponse example
* "HTTP/1.1 200 OK
Date: Wed, 07 Jun 2023 05:00:40 GMT
Server: Apache/2.4.29 (Ubuntu)
Set-Cookie: itop-2e83d2e9b00e354fdc528621cac532ac=q7ldcjq0rvbn33ccr9q8u8e953; path=/
*/
//var_dump($sResponse);
$iHeaderSize = curl_getinfo($ch,CURLINFO_HEADER_SIZE);
$sBody = substr($sResponse, $iHeaderSize);
//$iHttpCode = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
if (preg_match('/HTTP.* (\d*) /', $sResponse, $aMatches)){
$sHttpCode = $aMatches[1];
} else {
$sHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
}
curl_close ($ch);
return array($sHttpCode, $sBody);
}
}

View File

@@ -29,6 +29,7 @@
</admin_account>
<language>EN US</language>
<selected_modules type="array">
<item>authent-cas</item>
<item>authent-external</item>
<item>authent-local</item>
<item>itop-backup</item>

View File

@@ -260,7 +260,36 @@ if (utils::IsModeCLI())
else
{
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
LoginWebPage::ResetSession(true);
$iRet = LoginWebPage::DoLogin(false, false, LoginWebPage::EXIT_RETURN);
if ($iRet !== LoginWebPage::EXIT_CODE_OK) {
switch ($iRet) {
case LoginWebPage::EXIT_CODE_MISSINGLOGIN:
$oP->p("Missing parameter 'auth_user'");
break;
case LoginWebPage::EXIT_CODE_MISSINGPASSWORD:
$oP->p("Missing parameter 'auth_pwd'");
break;
case LoginWebPage::EXIT_CODE_WRONGCREDENTIALS:
$oP->p('Invalid login');
break;
case LoginWebPage::EXIT_CODE_PORTALUSERNOTAUTHORIZED:
$oP->p('Portal user is not allowed');
break;
case LoginWebPage::EXIT_CODE_NOTAUTHORIZED:
$oP->p('This user is not authorized to use the web services. (The profile REST Services User is required to access the REST web services)');
break;
default:
$oP->p("Unknown authentication error (retCode=$iRet)");
}
$oP->output();
exit -1;
}
$sCSVData = utils::ReadPostedParam('csvdata', '', 'raw_data');
}

View File

@@ -80,10 +80,12 @@ try
$oKPI->ComputeAndReport('Data model loaded');
$iRet = LoginWebPage::DoLogin(false, false, LoginWebPage::EXIT_RETURN); // Starting with iTop 2.2.0 portal users are no longer allowed to access the REST/JSON API
$oKPI->ComputeAndReport('User login');
if ($iRet == LoginWebPage::EXIT_CODE_OK)
// N°6358 - force credentials for REST calls
LoginWebPage::ResetSession(true);
$iRet = LoginWebPage::DoLogin(false, false, LoginWebPage::EXIT_RETURN);
$oKPI->ComputeAndReport('User login');
if ($iRet == LoginWebPage::EXIT_CODE_OK)
{
// Extra validation of the profile
if ((MetaModel::GetConfig()->Get('secure_rest_services') == true) && !UserRights::HasProfile('REST Services User'))
@@ -94,7 +96,7 @@ try
}
if ($iRet != LoginWebPage::EXIT_CODE_OK)
{
switch($iRet)
switch($iRet)
{
case LoginWebPage::EXIT_CODE_MISSINGLOGIN:
throw new Exception("Missing parameter 'auth_user'", RestResult::MISSING_AUTH_USER);