mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-14 16:04:10 +01:00
Compare commits
26 Commits
support/3.
...
tag
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5232694c04 | ||
|
|
874a5fd2ce | ||
|
|
063bb9680e | ||
|
|
8f8ac46f55 | ||
|
|
07b904ee1b | ||
|
|
affed69999 | ||
|
|
d5754fc568 | ||
|
|
44290db312 | ||
|
|
c49ceae75e | ||
|
|
8980f627e9 | ||
|
|
160bfd714b | ||
|
|
8d58372074 | ||
|
|
37fc1a5723 | ||
|
|
95aa444ee6 | ||
|
|
f5de808c7c | ||
|
|
e03033ce52 | ||
|
|
374b35f78a | ||
|
|
04bd8cc5ce | ||
|
|
8cb701bda3 | ||
|
|
1b29746806 | ||
|
|
fb9c317256 | ||
|
|
0904a21e3f | ||
|
|
82d11eeb47 | ||
|
|
142d6c8993 | ||
|
|
320922a13d | ||
|
|
f03d731b1d |
43
.github/workflows/action.yml
vendored
Normal file
43
.github/workflows/action.yml
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
name: Add PRs to Combodo PRs Dashboard
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
name: Add PR to Combodo Project
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if author is a member of the organization
|
||||
id: check-membership
|
||||
run: |
|
||||
ORG="Combodo"
|
||||
AUTHOR=$(jq -r .pull_request.user.login "$GITHUB_EVENT_PATH")
|
||||
RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
||||
"https://api.github.com/orgs/$ORG/members/$AUTHOR")
|
||||
if [ "$RESPONSE" == "404" ]; then
|
||||
echo "project_url=https://github.com/orgs/Combodo/projects/5" >> $GITHUB_ENV
|
||||
echo "is_member=false" >> $GITHUB_ENV
|
||||
else
|
||||
echo "project_url=https://github.com/orgs/Combodo/projects/4" >> $GITHUB_ENV
|
||||
echo "is_member=true" >> $GITHUB_ENV
|
||||
|
||||
fi
|
||||
|
||||
- name: Add internal tag if member
|
||||
if: env.is_member == 'true'
|
||||
run: |
|
||||
curl -X POST -H "Authorization: token ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
https://api.github.com/repos/Combodo/iTop/issues/${{ github.event.pull_request.number }}/labels \
|
||||
-d '{"labels":["internal"]}'
|
||||
env:
|
||||
is_member: ${{ env.is_member }}
|
||||
|
||||
- name: Add PR to the appropriate project
|
||||
uses: actions/add-to-project@v1.0.2
|
||||
with:
|
||||
project-url: ${{ env.project_url }}
|
||||
github-token: ${{ secrets.PR_AUTOMATICALLY_ADD_TO_PROJECT }}
|
||||
@@ -1316,6 +1316,11 @@ interface iRestServiceProvider
|
||||
public function ExecOperation($sVersion, $sVerb, $aParams);
|
||||
}
|
||||
|
||||
interface iRestInputSanitizer
|
||||
{
|
||||
public function SanitizeJsonInput(string $sJsonInput): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Minimal REST response structure. Derive this structure to add response data and error codes.
|
||||
*
|
||||
@@ -1405,6 +1410,14 @@ class RestResult
|
||||
* @api
|
||||
*/
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* Sanitize the content of this result to hide sensitive information
|
||||
*/
|
||||
public function SanitizeContent()
|
||||
{
|
||||
// The default implementation does nothing
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1193,12 +1193,12 @@ EOF
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Save');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
$sId = utils::HtmlEntities($this->sId);
|
||||
$sLayoutClass = utils::HtmlEntities($this->sLayoutClass);
|
||||
$sId = json_encode($this->sId);
|
||||
$sLayoutClass = json_encode($this->sLayoutClass);
|
||||
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
|
||||
$sAutoReloadSec = (string) $this->iAutoReloadSec;
|
||||
$sTitle = utils::HtmlEntities($this->sTitle);
|
||||
$sFile = utils::HtmlEntities($this->GetDefinitionFile());
|
||||
$sTitle = json_encode($this->sTitle);
|
||||
$sFile = json_encode($this->GetDefinitionFile());
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
|
||||
@@ -1250,15 +1250,15 @@ $('#dashboard_editor').dialog({
|
||||
});
|
||||
|
||||
$('#dashboard_editor .ui-layout-center').runtimedashboard({
|
||||
dashboard_id: '$sId',
|
||||
layout_class: '$sLayoutClass',
|
||||
title: '$sTitle',
|
||||
dashboard_id: $sId,
|
||||
layout_class: $sLayoutClass,
|
||||
title: $sTitle,
|
||||
auto_reload: $sAutoReload,
|
||||
auto_reload_sec: $sAutoReloadSec,
|
||||
submit_to: '$sUrl',
|
||||
submit_parameters: {operation: 'save_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
submit_parameters: {operation: 'save_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
render_to: '$sUrl',
|
||||
render_parameters: {operation: 'render_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
render_parameters: {operation: 'render_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
new_dashlet_parameters: {operation: 'new_dashlet'}
|
||||
});
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ define('APPCONF', APPROOT.'conf/');
|
||||
* @used-by utils::GetItopVersionWikiSyntax()
|
||||
* @used-by iTopModulesPhpVersionIntegrationTest
|
||||
*/
|
||||
define('ITOP_CORE_VERSION', '2.7.10');
|
||||
define('ITOP_CORE_VERSION', '2.7.12');
|
||||
|
||||
|
||||
require_once APPROOT.'bootstrap.inc.php';
|
||||
|
||||
@@ -138,7 +138,7 @@ abstract class AttributeDefinition
|
||||
|
||||
protected $aCSSClasses;
|
||||
|
||||
public function GetType()
|
||||
public function GetType()
|
||||
{
|
||||
return Dict::S('Core:'.get_class($this));
|
||||
}
|
||||
@@ -3775,7 +3775,7 @@ class AttributeFinalClass extends AttributeString
|
||||
*/
|
||||
class AttributePassword extends AttributeString implements iAttributeNoGroupBy
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
@@ -3851,7 +3851,7 @@ class AttributePassword extends AttributeString implements iAttributeNoGroupBy
|
||||
*/
|
||||
class AttributeEncryptedString extends AttributeString implements iAttributeNoGroupBy
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
|
||||
static $sKey = null; // Encryption key used for all encrypted fields
|
||||
static $sLibrary = null; // Encryption library used for all encrypted fields
|
||||
@@ -9243,7 +9243,7 @@ class AttributeSubItem extends AttributeDefinition
|
||||
*/
|
||||
class AttributeOneWayPassword extends AttributeDefinition implements iAttributeNoGroupBy
|
||||
{
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
const SEARCH_WIDGET_TYPE = self::SEARCH_WIDGET_TYPE_RAW;
|
||||
|
||||
/**
|
||||
* Useless constructor, but if not present PHP 7.4.0/7.4.1 is crashing :( (N°2329)
|
||||
|
||||
@@ -95,7 +95,7 @@ class MySQLHasGoneAwayException extends MySQLException
|
||||
{
|
||||
return array(
|
||||
2006,
|
||||
2013
|
||||
2013,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1296,8 +1296,8 @@ class CMDBSource
|
||||
*/
|
||||
public static function IsSameFieldTypes($sItopGeneratedFieldType, $sDbFieldType)
|
||||
{
|
||||
list($sItopFieldDataType, $sItopFieldTypeOptions, $sItopFieldOtherOptions) = static::GetFieldDataTypeAndOptions($sItopGeneratedFieldType);
|
||||
list($sDbFieldDataType, $sDbFieldTypeOptions, $sDbFieldOtherOptions) = static::GetFieldDataTypeAndOptions($sDbFieldType);
|
||||
[$sItopFieldDataType, $sItopFieldTypeOptions, $sItopFieldOtherOptions] = static::GetFieldDataTypeAndOptions($sItopGeneratedFieldType);
|
||||
[$sDbFieldDataType, $sDbFieldTypeOptions, $sDbFieldOtherOptions] = static::GetFieldDataTypeAndOptions($sDbFieldType);
|
||||
|
||||
if (strcasecmp($sItopFieldDataType, $sDbFieldDataType) !== 0)
|
||||
{
|
||||
@@ -1734,8 +1734,20 @@ class CMDBSource
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string query to upgrade database charset and collation if needed, null if not
|
||||
public static function GetClusterNb()
|
||||
{
|
||||
$result = 0;
|
||||
$sSql = "SHOW STATUS LIKE 'wsrep_cluster_size';";
|
||||
$aRows = self::QueryToArray($sSql);
|
||||
if (count($aRows) > 0)
|
||||
{
|
||||
$result = $aRows[0]['Value'];
|
||||
}
|
||||
return intval($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string query to upgrade database charset and collation if needed, null if not
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @since 2.5.0 N°1001 switch to utf8mb4
|
||||
|
||||
@@ -34,7 +34,9 @@
|
||||
*/
|
||||
class ObjectResult
|
||||
{
|
||||
public $code;
|
||||
use SanitizeTrait;
|
||||
|
||||
public $code;
|
||||
public $message;
|
||||
public $class;
|
||||
public $key;
|
||||
@@ -122,6 +124,19 @@ class ObjectResult
|
||||
{
|
||||
$this->fields[$sAttCode] = $this->MakeResultValue($oObject, $sAttCode, $bExtendedOutput);
|
||||
}
|
||||
|
||||
public function SanitizeContent()
|
||||
{
|
||||
foreach($this->fields as $sFieldAttCode => $fieldValue)
|
||||
{
|
||||
try {
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->class, $sFieldAttCode);
|
||||
} catch (Exception $e) { // for special cases like ID
|
||||
continue;
|
||||
}
|
||||
$this->SanitizeFieldIfSensitive($this->fields, $sFieldAttCode, $fieldValue, $oAttDef);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -181,6 +196,16 @@ class RestResultWithObjects extends RestResult
|
||||
$sObjKey = get_class($oObject).'::'.$oObject->GetKey();
|
||||
$this->objects[$sObjKey] = $oObjRes;
|
||||
}
|
||||
|
||||
public function SanitizeContent()
|
||||
{
|
||||
parent::SanitizeContent();
|
||||
|
||||
foreach($this->objects as $sObjKey => $oObjRes)
|
||||
{
|
||||
$oObjRes->SanitizeContent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class RestResultWithRelations extends RestResultWithObjects
|
||||
@@ -247,9 +272,10 @@ class RestDelete
|
||||
*
|
||||
* @package Core
|
||||
*/
|
||||
class CoreServices implements iRestServiceProvider
|
||||
class CoreServices implements iRestServiceProvider, iRestInputSanitizer
|
||||
{
|
||||
/**
|
||||
use SanitizeTrait;
|
||||
/**
|
||||
* Enumerate services delivered by this class
|
||||
*
|
||||
* @param string $sVersion The version (e.g. 1.0) supported by the services
|
||||
@@ -663,6 +689,33 @@ class CoreServices implements iRestServiceProvider
|
||||
}
|
||||
return $oResult;
|
||||
}
|
||||
|
||||
public function SanitizeJsonInput(string $sJsonInput): string
|
||||
{
|
||||
$sSanitizedJsonInput = $sJsonInput;
|
||||
$aJsonData = json_decode($sSanitizedJsonInput, true);
|
||||
$sOperation = $aJsonData['operation'];
|
||||
|
||||
switch ($sOperation) {
|
||||
case 'core/check_credentials':
|
||||
if (isset($aJsonData['password'])) {
|
||||
$aJsonData['password'] = '*****';
|
||||
}
|
||||
break;
|
||||
case 'core/update':
|
||||
case 'core/create':
|
||||
default :
|
||||
$sClass = $aJsonData['class'];
|
||||
if (isset($aJsonData['fields'])) {
|
||||
foreach ($aJsonData['fields'] as $sFieldAttCode => $fieldValue) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sFieldAttCode);
|
||||
$this->SanitizeFieldIfSensitive($aJsonData['fields'], $sFieldAttCode, $fieldValue, $oAttDef);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return json_encode($aJsonData, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for object deletion
|
||||
@@ -802,3 +855,50 @@ class CoreServices implements iRestServiceProvider
|
||||
return $iLimit * max(0, $iPage - 1);
|
||||
}
|
||||
}
|
||||
|
||||
trait SanitizeTrait
|
||||
{
|
||||
/**
|
||||
* Sanitize a field if it is sensitive.
|
||||
*
|
||||
* @param array $fields The fields array
|
||||
* @param string $sFieldAttCode The attribute code
|
||||
* @param mixed $oAttDef The attribute definition
|
||||
* @throws Exception
|
||||
*/
|
||||
private function SanitizeFieldIfSensitive(array &$fields, string $sFieldAttCode, $fieldValue, $oAttDef): void
|
||||
{
|
||||
// for simple attribute
|
||||
if ($oAttDef instanceof iAttributeNoGroupBy) // iAttributeNoGroupBy is equivalent to sensitive attribute
|
||||
{
|
||||
$fields[$sFieldAttCode] = '*****';
|
||||
return;
|
||||
}
|
||||
// for 1-n / n-n relation
|
||||
if ($oAttDef instanceof AttributeLinkedSet) {
|
||||
foreach ($fieldValue as $i => $aLnkValues) {
|
||||
foreach ($aLnkValues as $sLnkAttCode => $sLnkValue) {
|
||||
$oLnkAttDef = MetaModel::GetAttributeDef($oAttDef->GetLinkedClass(), $sLnkAttCode);
|
||||
if ($oLnkAttDef instanceof iAttributeNoGroupBy) { // 1-n relation
|
||||
$fields[$sFieldAttCode][$i][$sLnkAttCode] = '*****';
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeLinkedSetIndirect && $oLnkAttDef instanceof AttributeExternalField) { // for n-n relation
|
||||
$oExtKeyAttDef = MetaModel::GetAttributeDef($oLnkAttDef->GetTargetClass(), $oLnkAttDef->GetExtAttCode());
|
||||
if ($oExtKeyAttDef instanceof iAttributeNoGroupBy) {
|
||||
$fields[$sFieldAttCode][$i][$sLnkAttCode] = '*****';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// for external attribute
|
||||
if ($oAttDef instanceof AttributeExternalField) {
|
||||
$oExtKeyAttDef = MetaModel::GetAttributeDef($oAttDef->GetTargetClass(), $oAttDef->GetExtAttCode());
|
||||
if ($oExtKeyAttDef instanceof iAttributeNoGroupBy) {
|
||||
$fields[$sFieldAttCode] = '*****';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
|
||||
// Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0
|
||||
$version: "v2.7.10";
|
||||
$version: "v2.7.12";
|
||||
$approot-relative: "../../../../../" !default; // relative to env-***/branding/themes/***/main.css
|
||||
|
||||
// Base colors
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-cas/2.7.10',
|
||||
'authent-cas/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-external/2.7.10',
|
||||
'authent-external/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -9,7 +9,7 @@ if (function_exists('ldap_connect'))
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-ldap/2.7.10',
|
||||
'authent-ldap/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-local/2.7.10',
|
||||
'authent-local/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'combodo-db-tools/2.7.10',
|
||||
'combodo-db-tools/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-attachments/2.7.10',
|
||||
'itop-attachments/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-backup/2.7.10',
|
||||
'itop-backup/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-bridge-virtualization-storage/2.7.10',
|
||||
'itop-bridge-virtualization-storage/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-change-mgmt-itil/2.7.10',
|
||||
'itop-change-mgmt-itil/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-change-mgmt/2.7.10',
|
||||
'itop-change-mgmt/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-config-mgmt/2.7.10',
|
||||
'itop-config-mgmt/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-config/2.7.10',
|
||||
'itop-config/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-core-update/2.7.10',
|
||||
'itop-core-update/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-datacenter-mgmt/2.7.10',
|
||||
'itop-datacenter-mgmt/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-endusers-devices/2.7.10',
|
||||
'itop-endusers-devices/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-files-information/2.7.10',
|
||||
'itop-files-information/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-full-itil/2.7.10',
|
||||
'itop-full-itil/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-hub-connector/2.7.10',
|
||||
'itop-hub-connector/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-incident-mgmt-itil/2.7.10',
|
||||
'itop-incident-mgmt-itil/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-knownerror-mgmt/2.7.10',
|
||||
'itop-knownerror-mgmt/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-oauth-client/2.7.10',
|
||||
'itop-oauth-client/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-portal-base/2.7.10', array(
|
||||
'itop-portal-base/2.7.12', array(
|
||||
// Identification
|
||||
'label' => 'Portal Development Library',
|
||||
'category' => 'Portal',
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
p_user_profile_brick_edit_person:
|
||||
path: '/user/edit_person'
|
||||
defaults:
|
||||
_controller: 'Combodo\iTop\Portal\Controller\UserProfileBrickController::EditPerson'
|
||||
|
||||
p_user_profile_brick:
|
||||
path: '/user/{sBrickId}'
|
||||
defaults:
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1246,7 +1246,12 @@ class ObjectController extends BrickController
|
||||
$bIgnoreSilos = $oScopeValidator->IsAllDataAllowedForScope(UserRights::ListProfiles(), $sObjectClass);
|
||||
$aParams = array('objects_id' => $aObjectIds);
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT $sObjectClass WHERE id IN (:objects_id)");
|
||||
if ($bIgnoreSilos === true)
|
||||
if (!$oScopeValidator->AddScopeToQuery($oSearch, $sObjectClass)
|
||||
) {
|
||||
IssueLog::Warning(__METHOD__ . ' at line ' . __LINE__ . ' : User #' . UserRights::GetUserId() . ' not allowed to read ' . $sObjectClass . ' object.');
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
if ($bIgnoreSilos === true)
|
||||
{
|
||||
$oSearch->AllowAllData();
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ use Symfony\Component\HttpFoundation\Response;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use UserRights;
|
||||
use utils;
|
||||
|
||||
use Dict;
|
||||
/**
|
||||
* Class UserProfileBrickController
|
||||
*
|
||||
@@ -66,34 +66,9 @@ class UserProfileBrickController extends BrickController
|
||||
$oRequestManipulator = $this->get('request_manipulator');
|
||||
/** @var \Combodo\iTop\Portal\Helper\ObjectFormHandlerHelper $ObjectFormHandler */
|
||||
$ObjectFormHandler = $this->get('object_form_handler');
|
||||
/** @var \Combodo\iTop\Portal\Brick\BrickCollection $oBrickCollection */
|
||||
$oBrickCollection = $this->get('brick_collection');
|
||||
$oBrick = $this->GetBrick($sBrickId);
|
||||
|
||||
// If the brick id was not specified, we get the first one registered that is an instance of UserProfileBrick as default
|
||||
if ($sBrickId === null)
|
||||
{
|
||||
/** @var \Combodo\iTop\Portal\Brick\PortalBrick $oTmpBrick */
|
||||
foreach ($oBrickCollection->GetBricks() as $oTmpBrick)
|
||||
{
|
||||
if ($oTmpBrick instanceof UserProfileBrick)
|
||||
{
|
||||
$oBrick = $oTmpBrick;
|
||||
}
|
||||
}
|
||||
|
||||
// We make sure a UserProfileBrick was found
|
||||
if (!isset($oBrick) || $oBrick === null)
|
||||
{
|
||||
$oBrick = new UserProfileBrick();
|
||||
//throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'UserProfileBrick : Brick could not be loaded as there was no UserProfileBrick loaded in the application.');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oBrick = $oBrickCollection->GetBrickById($sBrickId);
|
||||
}
|
||||
|
||||
$aData = array();
|
||||
$aData = array();
|
||||
|
||||
// Setting form mode regarding the demo mode parameter
|
||||
$bDemoMode = MetaModel::GetConfig()->Get('demo_mode');
|
||||
@@ -130,11 +105,12 @@ class UserProfileBrickController extends BrickController
|
||||
$oCurContact = UserRights::GetContactObject();
|
||||
$sCurContactClass = get_class($oCurContact);
|
||||
$sCurContactId = $oCurContact->GetKey();
|
||||
|
||||
$aForm = $oBrick->GetForm();
|
||||
$aForm['submit_endpoint'] = $this->generateUrl('p_user_profile_brick_edit_person', ['sBrickId' => $sBrickId]);
|
||||
// Preparing forms
|
||||
$aData['forms']['contact'] = $ObjectFormHandler->HandleForm($oRequest, $sFormMode, $sCurContactClass, $sCurContactId,
|
||||
$oBrick->GetForm());
|
||||
$aData['forms']['preferences'] = $this->HandlePreferencesForm($oRequest, $sFormMode);
|
||||
$aData['forms']['contact'] = $ObjectFormHandler->HandleForm($oRequest, $sFormMode, $sCurContactClass, $sCurContactId,
|
||||
$aForm);
|
||||
$aData['forms']['preferences'] = $this->HandlePreferencesForm($oRequest, $sFormMode);
|
||||
// - If user can change password, we display the form
|
||||
$aData['forms']['password'] = (UserRights::CanChangePassword()) ? $this->HandlePasswordForm($oRequest, $sFormMode) : null;
|
||||
|
||||
@@ -150,6 +126,35 @@ class UserProfileBrickController extends BrickController
|
||||
return $oResponse;
|
||||
}
|
||||
|
||||
public function EditPerson(Request $oRequest)
|
||||
{
|
||||
/** @var \Combodo\iTop\Portal\Helper\ObjectFormHandlerHelper $oObjectFormHandler */
|
||||
$oObjectFormHandler = $this->get('object_form_handler');
|
||||
/** @var \Combodo\iTop\Portal\Helper\SecurityHelper $oSecurityHelper */
|
||||
$oSecurityHelper = $this->get('security_helper');
|
||||
|
||||
$oCurContact = UserRights::GetContactObject();
|
||||
$sObjectClass = get_class($oCurContact);
|
||||
$sObjectId = $oCurContact->GetKey();
|
||||
|
||||
// Checking security layers
|
||||
// Warning : This is a dirty quick fix to allow editing its own contact information
|
||||
$bAllowWrite = ($sObjectClass === 'Person' && $sObjectId == UserRights::GetContactId());
|
||||
if (!$oSecurityHelper->IsActionAllowed(UR_ACTION_MODIFY, $sObjectClass, $sObjectId) && !$bAllowWrite) {
|
||||
IssueLog::Warning(__METHOD__ . ' at line ' . __LINE__ . ' : User #' . UserRights::GetUserId() . ' not allowed to modify ' . $sObjectClass . '::' . $sObjectId . ' object.');
|
||||
throw new HttpException(Response::HTTP_NOT_FOUND, Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
|
||||
$aForm = $this->GetBrick()->GetForm();
|
||||
$aForm['submit_endpoint'] = $this->generateUrl('p_user_profile_brick_edit_person');
|
||||
|
||||
$aData = ['sMode' => 'edit'];
|
||||
$aData['form'] = $oObjectFormHandler->HandleForm($oRequest, $aData['sMode'], $sObjectClass, $sObjectId, $aForm);
|
||||
|
||||
return new JsonResponse($aData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param \Symfony\Component\HttpFoundation\Request $oRequest
|
||||
* @param string $sFormMode
|
||||
@@ -388,4 +393,34 @@ class UserProfileBrickController extends BrickController
|
||||
return $aFormData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sBrickId
|
||||
* @return \Combodo\iTop\Portal\Brick\PortalBrick|UserProfileBrick
|
||||
* @throws \Combodo\iTop\Portal\Brick\BrickNotFoundException
|
||||
*/
|
||||
public function GetBrick($sBrickId = null)
|
||||
{
|
||||
/** @var \Combodo\iTop\Portal\Brick\BrickCollection $oBrickCollection */
|
||||
$oBrickCollection = $this->get('brick_collection');
|
||||
|
||||
// If the brick id was not specified, we get the first one registered that is an instance of UserProfileBrick as default
|
||||
if ($sBrickId === null) {
|
||||
/** @var \Combodo\iTop\Portal\Brick\PortalBrick $oTmpBrick */
|
||||
foreach ($oBrickCollection->GetBricks() as $oTmpBrick) {
|
||||
if ($oTmpBrick instanceof UserProfileBrick) {
|
||||
$oBrick = $oTmpBrick;
|
||||
}
|
||||
}
|
||||
|
||||
// We make sure a UserProfileBrick was found
|
||||
if (!isset($oBrick) || $oBrick === null) {
|
||||
$oBrick = new UserProfileBrick();
|
||||
//throw new HttpException(Response::HTTP_INTERNAL_SERVER_ERROR, 'UserProfileBrick : Brick could not be loaded as there was no UserProfileBrick loaded in the application.');
|
||||
}
|
||||
} else {
|
||||
$oBrick = $oBrickCollection->GetBrickById($sBrickId);
|
||||
}
|
||||
return $oBrick;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -132,10 +132,8 @@ class ObjectFormHandlerHelper
|
||||
$bModal = ($oRequest->isXmlHttpRequest() && empty($sOperation));
|
||||
|
||||
// - Retrieve form properties
|
||||
if ($aFormProperties === null)
|
||||
{
|
||||
$aFormProperties = ApplicationHelper::GetLoadedFormFromClass($this->aCombodoPortalInstanceConf['forms'], $sObjectClass, $sMode);
|
||||
}
|
||||
$aFormProperties = $aFormProperties ?? ApplicationHelper::GetLoadedFormFromClass($this->aCombodoPortalInstanceConf['forms'], $sObjectClass, $sMode);
|
||||
|
||||
// - Create and
|
||||
if (empty($sOperation))
|
||||
{
|
||||
@@ -243,13 +241,17 @@ class ObjectFormHandlerHelper
|
||||
case static::ENUM_MODE_CREATE:
|
||||
case static::ENUM_MODE_EDIT:
|
||||
case static::ENUM_MODE_VIEW:
|
||||
$sFormEndpoint = $this->oUrlGenerator->generate(
|
||||
'p_object_'.$sMode,
|
||||
array(
|
||||
'sObjectClass' => $sObjectClass,
|
||||
'sObjectId' => $sObjectId,
|
||||
)
|
||||
);
|
||||
if(array_key_exists('submit_endpoint', $aFormProperties)) {
|
||||
$sFormEndpoint = $aFormProperties['submit_endpoint'];
|
||||
} else {
|
||||
$sFormEndpoint = $this->oUrlGenerator->generate(
|
||||
'p_object_' . $sMode,
|
||||
array(
|
||||
'sObjectClass' => $sObjectClass,
|
||||
'sObjectId' => $sObjectId,
|
||||
)
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case static::ENUM_MODE_APPLY_STIMULUS:
|
||||
@@ -282,7 +284,8 @@ class ObjectFormHandlerHelper
|
||||
->SetActionRulesToken($sActionRulesToken)
|
||||
->SetRenderer($oFormRenderer)
|
||||
->SetFormProperties($aFormProperties);
|
||||
|
||||
$oFormManager->PrepareFormAndHTMLDocument();
|
||||
$oFormManager->PrepareFields();
|
||||
$oFormManager->Build();
|
||||
$aFormData['hidden_fields'] = $oFormManager->GetHiddenFieldsId();
|
||||
// Check the number of editable fields
|
||||
|
||||
@@ -464,8 +464,8 @@
|
||||
sBody = '{{ 'Error:XHR:Fail'|dict_format(constant('ITOP_APPLICATION_SHORT'))|escape('js') }}';
|
||||
}
|
||||
var oModalElem = $('#modal-for-alert');
|
||||
oModalElem.find('.modal-content .modal-header .modal-title').html(sTitle);
|
||||
oModalElem.find('.modal-content .modal-body .alert').addClass('alert-danger').html(sBody);
|
||||
oModalElem.find('.modal-content .modal-header .modal-title').text(sTitle);
|
||||
oModalElem.find('.modal-content .modal-body .alert').addClass('alert-danger').text(sBody);
|
||||
oModalElem.modal('show');
|
||||
};
|
||||
{% endblock %}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-portal/2.7.10', array(
|
||||
'itop-portal/2.7.12', array(
|
||||
// Identification
|
||||
'label' => 'Enhanced Customer Portal',
|
||||
'category' => 'Portal',
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-problem-mgmt/2.7.10',
|
||||
'itop-problem-mgmt/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-profiles-itil/2.7.10',
|
||||
'itop-profiles-itil/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-request-mgmt-itil/2.7.10',
|
||||
'itop-request-mgmt-itil/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-request-mgmt/2.7.10',
|
||||
'itop-request-mgmt/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-service-mgmt-provider/2.7.10',
|
||||
'itop-service-mgmt-provider/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-service-mgmt/2.7.10',
|
||||
'itop-service-mgmt/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-sla-computation/2.7.10',
|
||||
'itop-sla-computation/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-storage-mgmt/2.7.10',
|
||||
'itop-storage-mgmt/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__,
|
||||
'itop-tickets/2.7.10',
|
||||
'itop-tickets/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-virtualization-mgmt/2.7.10',
|
||||
'itop-virtualization-mgmt/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-welcome-itil/2.7.10',
|
||||
'itop-welcome-itil/2.7.12',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<information>
|
||||
<version>2.7.10</version>
|
||||
<version>2.7.12</version>
|
||||
</information>
|
||||
|
||||
@@ -1218,6 +1218,7 @@ return array(
|
||||
'SQLQuery' => $baseDir . '/core/sqlquery.class.inc.php',
|
||||
'SQLUnionQuery' => $baseDir . '/core/sqlunionquery.class.inc.php',
|
||||
'SVGDOMSanitizer' => $baseDir . '/core/htmlsanitizer.class.inc.php',
|
||||
'SanitizeTrait' => $baseDir . '/core/restservices.class.inc.php',
|
||||
'ScalarExpression' => $baseDir . '/core/oql/expression.class.inc.php',
|
||||
'ScalarOqlExpression' => $baseDir . '/core/oql/oqlquery.class.inc.php',
|
||||
'ScssPhp\\ScssPhp\\Base\\Range' => $vendorDir . '/scssphp/scssphp/src/Base/Range.php',
|
||||
@@ -2732,6 +2733,7 @@ return array(
|
||||
'iPreferencesExtension' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iProcess' => $baseDir . '/core/backgroundprocess.inc.php',
|
||||
'iQueryModifier' => $baseDir . '/core/querymodifier.class.inc.php',
|
||||
'iRestInputSanitizer' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iRestServiceProvider' => $baseDir . '/application/applicationextension.inc.php',
|
||||
'iScheduledProcess' => $baseDir . '/core/backgroundprocess.inc.php',
|
||||
'iSelfRegister' => $baseDir . '/core/userrights.class.inc.php',
|
||||
|
||||
@@ -1586,6 +1586,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
|
||||
'SQLQuery' => __DIR__ . '/../..' . '/core/sqlquery.class.inc.php',
|
||||
'SQLUnionQuery' => __DIR__ . '/../..' . '/core/sqlunionquery.class.inc.php',
|
||||
'SVGDOMSanitizer' => __DIR__ . '/../..' . '/core/htmlsanitizer.class.inc.php',
|
||||
'SanitizeTrait' => __DIR__ . '/../..' . '/core/restservices.class.inc.php',
|
||||
'ScalarExpression' => __DIR__ . '/../..' . '/core/oql/expression.class.inc.php',
|
||||
'ScalarOqlExpression' => __DIR__ . '/../..' . '/core/oql/oqlquery.class.inc.php',
|
||||
'ScssPhp\\ScssPhp\\Base\\Range' => __DIR__ . '/..' . '/scssphp/scssphp/src/Base/Range.php',
|
||||
@@ -3100,6 +3101,7 @@ class ComposerStaticInit0018331147de7601e7552f7da8e3bb8b
|
||||
'iPreferencesExtension' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iProcess' => __DIR__ . '/../..' . '/core/backgroundprocess.inc.php',
|
||||
'iQueryModifier' => __DIR__ . '/../..' . '/core/querymodifier.class.inc.php',
|
||||
'iRestInputSanitizer' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iRestServiceProvider' => __DIR__ . '/../..' . '/application/applicationextension.inc.php',
|
||||
'iScheduledProcess' => __DIR__ . '/../..' . '/core/backgroundprocess.inc.php',
|
||||
'iSelfRegister' => __DIR__ . '/../..' . '/core/userrights.class.inc.php',
|
||||
|
||||
@@ -1230,6 +1230,12 @@ EOF
|
||||
$aResult['checks'][] = new CheckResult(CheckResult::INFO, "MySQL server's max_connections is set to $iMaxConnections.");
|
||||
}
|
||||
|
||||
$iClusters = $oDBSource->GetClusterNb();
|
||||
if ($iClusters > 0) {
|
||||
SetupLog::Warning('Warning - Using Galera will cause malfunctions and data corruptions. Combodo does not support this type of infrastructure.');
|
||||
$aResult['checks'][] = new CheckResult(CheckResult::WARNING, 'Using Galera will cause malfunctions and data corruptions. Combodo does not support this type of infrastructure.');
|
||||
}
|
||||
|
||||
try {
|
||||
$aResult['databases'] = $oDBSource->ListDB();
|
||||
}
|
||||
|
||||
@@ -2,24 +2,72 @@
|
||||
|
||||
This script allows to install and update iTop via CLI.
|
||||
|
||||
For more information, see the official Wiki : [Automated installation [iTop Documentation]](https://www.itophub.io/wiki/page?id=latest:advancedtopics:automatic_install)
|
||||
For more information, see the official Wiki : [Automated installation [iTop Documentation]](https://www.itophub.io/wiki/page?id=latest:advancedtopics:automatic_install)
|
||||
|
||||
# unattended-install.php
|
||||
|
||||
## Usage
|
||||
|
||||
Execution of the unattended installation
|
||||
> Note:
|
||||
> Because the installation runs from the command line, make sure that the current user has enough rights to access the different locations and that the web server will be able to access the files and directories created during the scripted installation. In order to exactly emulate the behavior of
|
||||
the interactive installation it may be a good practice to run this installation from the user account used for running the web server process.
|
||||
|
||||
Launch the script with the following command: ```bash php unattended_install.php --param-file=fresh-install.xml ```
|
||||
|
||||
Where: `fresh-install.xml` is the response file containing your desired settings for the installation (there are 4 models available in the folder `xml_setup`: fresh-install.xml, itil-fresh-install.xml, itil-upgrade.xml, upgrade.xml)
|
||||
|
||||
Fresh installation parameters
|
||||
> Important:
|
||||
> In the case of a fresh installation (<mode>install</mode>), do not forget to complete below mandatory parameters before:
|
||||
|
||||
```xml
|
||||
<database>
|
||||
<server></server>
|
||||
<user></user>
|
||||
<pwd></pwd>
|
||||
<name></name>
|
||||
<db_tls_enabled></db_tls_enabled>
|
||||
<db_tls_ca></db_tls_ca>
|
||||
<prefix></prefix>
|
||||
</database>
|
||||
<url>
|
||||
</url>
|
||||
<graphviz_path>/usr/bin/dot</graphviz_path>
|
||||
<admin_account>
|
||||
<user></user>
|
||||
<pwd></pwd>
|
||||
<language></language>
|
||||
</admin_account>
|
||||
<language></language>
|
||||
```
|
||||
|
||||
## Options
|
||||
|
||||
To get all available options of the script, you can perform the following command :
|
||||
```php unattended-install.php --help```
|
||||
|
||||
# install-itop.sh
|
||||
|
||||
## Usage
|
||||
|
||||
#install-itop.sh
|
||||
You can install your iTop by only using config-itop.php settings and run either
|
||||
|
||||
- a non-ITIL iTop fresh installation (use itil-fresh-install.xml to have ITIL modules instead)
|
||||
|
||||
```
|
||||
./install-itop.sh ./xml_setup/fresh-install.xml
|
||||
```
|
||||
|
||||
- a non-ITIL iTop upgrade (use itil-upgrade.xml to have ITIL modules instead)
|
||||
|
||||
```
|
||||
./install-itop.sh ./xml_setup/upgrade.xml
|
||||
```
|
||||
|
||||
- a specific iTop installation by providing both xml setup file
|
||||
in below example file provided is the one generated by iTop during last setup.
|
||||
in below example file provided is the one generated by iTop during last setup.
|
||||
|
||||
```
|
||||
./install-itop.sh ../../log/install-2024-04-03.xml
|
||||
```
|
||||
|
||||
@@ -41,7 +41,9 @@
|
||||
<testsuite name="Setup">
|
||||
<directory>unitary-tests/setup</directory>
|
||||
</testsuite>
|
||||
<!-- Note: The unitary-tests/sources/application/TwigBase is omitted for now as the test is not working -->
|
||||
<testsuite name="SourcesApplicationTwigBase">
|
||||
<directory>unitary-tests/sources/application/TwigBase</directory>
|
||||
</testsuite>
|
||||
<testsuite name="SourcesApplicationSearch">
|
||||
<directory>unitary-tests/sources/application/search</directory>
|
||||
</testsuite>
|
||||
|
||||
@@ -85,23 +85,6 @@ abstract class ItopTestCase extends TestCase
|
||||
require_once APPROOT . $sFileRelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to load a module file. The caller test must be in that module !
|
||||
* Will browse dir up to find a module.*.php
|
||||
*
|
||||
* @param string $sFileRelPath for example 'portal/src/Helper/ApplicationHelper.php'
|
||||
* @since 2.7.10 3.1.1 3.2.0 N°6709 method creation
|
||||
*/
|
||||
protected function RequireOnceCurrentModuleFile(string $sFileRelPath): void
|
||||
{
|
||||
$aStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1);
|
||||
$sCallerFileFullPath = $aStack[0]['file'];
|
||||
$sCallerDir = dirname($sCallerFileFullPath);
|
||||
|
||||
$sModuleRootPath = static::GetFirstDirUpContainingFile($sCallerDir, 'module.*.php');
|
||||
require_once $sModuleRootPath . $sFileRelPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require once a unit test file (eg. a mock class) from its relative path from the *current* dir.
|
||||
* This ensure that required files don't crash when unit tests dir is moved in the iTop structure (see N°5608)
|
||||
@@ -119,26 +102,6 @@ abstract class ItopTestCase extends TestCase
|
||||
require_once $sCallerDirAbsPath . DIRECTORY_SEPARATOR . $sFileRelPath;
|
||||
}
|
||||
|
||||
private static function GetFirstDirUpContainingFile(string $sSearchPath, string $sFileToFindGlobPattern): ?string
|
||||
{
|
||||
for ($iDepth = 0; $iDepth < 8; $iDepth++) {
|
||||
$aGlobFiles = glob($sSearchPath . '/' . $sFileToFindGlobPattern);
|
||||
if (is_array($aGlobFiles) && (count($aGlobFiles) > 0)) {
|
||||
return $sSearchPath . '/';
|
||||
}
|
||||
$iOffsetSep = strrpos($sSearchPath, '/');
|
||||
if ($iOffsetSep === false) {
|
||||
$iOffsetSep = strrpos($sSearchPath, '\\');
|
||||
if ($iOffsetSep === false) {
|
||||
// Do not throw an exception here as PHPUnit will not show it clearly when determing the list of test to perform
|
||||
return 'Could not find the approot file in ' . $sSearchPath;
|
||||
}
|
||||
}
|
||||
$sSearchPath = substr($sSearchPath, 0, $iOffsetSep);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function debug($sMsg)
|
||||
{
|
||||
if (DEBUG_UNIT_TEST) {
|
||||
@@ -153,7 +116,7 @@ abstract class ItopTestCase extends TestCase
|
||||
|
||||
public function GetMicroTime()
|
||||
{
|
||||
list($uSec, $sec) = explode(" ", microtime());
|
||||
[$uSec, $sec] = explode(" ", microtime());
|
||||
return ((float)$uSec + (float)$sec);
|
||||
}
|
||||
|
||||
@@ -195,7 +158,7 @@ abstract class ItopTestCase extends TestCase
|
||||
/**
|
||||
* @param string $sObjectClass for example DBObject::class
|
||||
* @param string $sMethodName
|
||||
* @param object $oObject
|
||||
* @param object|null $oObject
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return mixed method result
|
||||
@@ -238,7 +201,7 @@ abstract class ItopTestCase extends TestCase
|
||||
* @throws \ReflectionException
|
||||
* @since 2.7.8 3.0.3 3.1.0
|
||||
*/
|
||||
public function GetNonPublicProperty(object $oObject, string $sProperty)
|
||||
public function GetNonPublicProperty($oObject, string $sProperty)
|
||||
{
|
||||
$oProperty = $this->GetProperty(get_class($oObject), $sProperty);
|
||||
|
||||
@@ -307,7 +270,7 @@ abstract class ItopTestCase extends TestCase
|
||||
* @throws \ReflectionException
|
||||
* @since 2.7.8 3.0.3 3.1.0
|
||||
*/
|
||||
public function SetNonPublicProperty(object $oObject, string $sProperty, $value)
|
||||
public function SetNonPublicProperty($oObject, string $sProperty, $value)
|
||||
{
|
||||
$oProperty = $this->GetProperty(get_class($oObject), $sProperty);
|
||||
$oProperty->setValue($oObject, $value);
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.7">
|
||||
<classes>
|
||||
<class id="TestServer" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>test_server</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
<fields>
|
||||
<field id="contact_list" xsi:type="AttributeLinkedSetIndirect">
|
||||
<linked_class>lnkContactTestToServer</linked_class>
|
||||
<ext_key_to_me>test_server_id</ext_key_to_me>
|
||||
<ext_key_to_remote>contact_test_id</ext_key_to_remote>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="password_list" xsi:type="AttributeLinkedSet">
|
||||
<linked_class>PasswordTest</linked_class>
|
||||
<ext_key_to_me>server_test_id</ext_key_to_me>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
<sql>name</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
|
||||
|
||||
<class id="ContactTest" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>contact_test</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
<fields>
|
||||
<field id="password" xsi:type="AttributeEncryptedString">
|
||||
<sql>password</sql>
|
||||
</field>
|
||||
<field id="server_test_list" xsi:type="AttributeLinkedSetIndirect">
|
||||
<linked_class>lnkContactTestToServer</linked_class>
|
||||
<ext_key_to_me>contact_test_id</ext_key_to_me>
|
||||
<ext_key_to_remote>test_server_id</ext_key_to_remote>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
|
||||
|
||||
<class id="lnkContactTestToServer" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>lnk_contact_server_test</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
<fields>
|
||||
<field id="contact_test_password" xsi:type="AttributeExternalField" _delta="define">
|
||||
<extkey_attcode>contact_test_id</extkey_attcode>
|
||||
<target_attcode>password</target_attcode>
|
||||
</field>
|
||||
<field id="test_server_id" xsi:type="AttributeExternalKey" _delta="define">
|
||||
<target_class>TestServer</target_class>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<sql>test_server</sql>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
|
||||
</field>
|
||||
<field id="contact_test_id" xsi:type="AttributeExternalKey" _delta="define">
|
||||
<target_class>ContactTest</target_class>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<sql>contact_test</sql>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
<class id="PasswordTest" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>password_test</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
</properties>
|
||||
<presentation/>
|
||||
<methods/>
|
||||
<fields>
|
||||
<field id="server_test_id" xsi:type="AttributeExternalKey" _delta="define">
|
||||
<target_class>TestServer</target_class>
|
||||
<sql>server_test_id</sql>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
</field>
|
||||
<field id="password" xsi:type="AttributeEncryptedString" _delta="define">
|
||||
<sql>password</sql>
|
||||
</field>
|
||||
</fields>
|
||||
</class>
|
||||
</classes>
|
||||
</itop_design>
|
||||
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use ArchivedObjectException;
|
||||
use AttributeEncryptedString;
|
||||
use Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase;
|
||||
use CoreException;
|
||||
use CoreUnexpectedValue;
|
||||
use Exception;
|
||||
use MetaModel;
|
||||
use ormLinkSet;
|
||||
use PasswordTest;
|
||||
use RestResultWithObjects;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class RestServicesSanitizeOutputTest extends ItopCustomDatamodelTestCase
|
||||
{
|
||||
private const SIMPLE_PASSWORD = '123456';
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
// Workaround to cope with inconsistent settings in itop-config files from the CI
|
||||
AttributeEncryptedString::$sKey = '6eb9d9afa3ee0fbcebe622a33bf57aaeafb7c37998fd24c403c2522c2d60117f';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws CoreException
|
||||
*/
|
||||
public function testSanitizeAttributeOnRequestedObject()
|
||||
{
|
||||
$oContactTest = MetaModel::NewObject('ContactTest', [
|
||||
'password' => self::SIMPLE_PASSWORD]
|
||||
);
|
||||
$oRestResultWithObject = new RestResultWithObjects();
|
||||
$oRestResultWithObject->AddObject(0, 'ok', $oContactTest, ['ContactTest' => ['password']]);
|
||||
$oRestResultWithObject->SanitizeContent();
|
||||
static::assertEquals(
|
||||
'{"objects":{"ContactTest::-1":{"code":0,"message":"ok","class":"ContactTest","key":-1,"fields":{"password":"*****"}}},"code":0,"message":null}',
|
||||
json_encode($oRestResultWithObject));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testSanitizeAttributeExternalFieldOnLink()
|
||||
{
|
||||
$oContactTest = $this->createObject('ContactTest', [
|
||||
'password' => self::SIMPLE_PASSWORD]
|
||||
);
|
||||
|
||||
$oTestServer = $this->createObject('TestServer', [
|
||||
'name' => 'test_server',
|
||||
]);
|
||||
|
||||
|
||||
// create lnkContactTestToServer
|
||||
$oLnkContactTestToServer = $this->createObject('lnkContactTestToServer', [
|
||||
'contact_test_id' => $oContactTest->GetKey(),
|
||||
'test_server_id' => $oTestServer->GetKey()
|
||||
]);
|
||||
|
||||
$oRestResultWithObject = new RestResultWithObjects();
|
||||
$oRestResultWithObject->AddObject(0, 'ok', $oLnkContactTestToServer,
|
||||
['lnkContactTestToServer' => ['contact_test_password']]);
|
||||
|
||||
$oRestResultWithObject->SanitizeContent();
|
||||
|
||||
static::assertContains(
|
||||
'*****',
|
||||
json_encode($oRestResultWithObject));
|
||||
|
||||
static::assertNotContains(
|
||||
self::SIMPLE_PASSWORD,
|
||||
json_encode($oRestResultWithObject));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testSanitizeAttributeOnObjectRelatedThroughNNRelation()
|
||||
{
|
||||
$oContactTest = $this->createObject('ContactTest', [
|
||||
'password' => self::SIMPLE_PASSWORD]);
|
||||
|
||||
$oTestServer = $this->createObject('TestServer', [
|
||||
'name' => 'test_server',
|
||||
]);
|
||||
|
||||
// create lnkContactTestToServer
|
||||
$this->createObject('lnkContactTestToServer', [
|
||||
'contact_test_id' => $oContactTest->GetKey(),
|
||||
'test_server_id' => $oTestServer->GetKey()
|
||||
]);
|
||||
|
||||
$oRestResultWithObject = new RestResultWithObjects();
|
||||
$oRestResultWithObject->AddObject(0, 'ok', $oTestServer,
|
||||
['TestServer' => ['contact_list']]);
|
||||
|
||||
$oRestResultWithObject->SanitizeContent();
|
||||
static::assertContains(
|
||||
'*****',
|
||||
json_encode($oRestResultWithObject));
|
||||
|
||||
static::assertNotContains(
|
||||
self::SIMPLE_PASSWORD,
|
||||
json_encode($oRestResultWithObject));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @throws CoreException
|
||||
* @throws CoreUnexpectedValue
|
||||
* @throws ArchivedObjectException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testSanitizeOnObjectRelatedThrough1NRelation()
|
||||
{
|
||||
$oTestServer = $this->createObject('TestServer', [
|
||||
'name' => 'my_server',
|
||||
]);
|
||||
|
||||
$oPassword = new PasswordTest();
|
||||
$oPassword->Set('password', self::SIMPLE_PASSWORD);
|
||||
$oPassword->Set('server_test_id', $oTestServer->GetKey());
|
||||
|
||||
/** @var ormLinkSet $oContactList */
|
||||
$oContactList = $oTestServer->Get('password_list');
|
||||
$oContactList->AddItem($oPassword);
|
||||
$oTestServer->Set('password_list', $oContactList);
|
||||
|
||||
$oRestResultWithObject = new RestResultWithObjects();
|
||||
$oRestResultWithObject->AddObject(0, 'ok', $oTestServer, ['TestServer' => ['id', 'password_list']]);
|
||||
$oRestResultWithObject->SanitizeContent();
|
||||
|
||||
static::assertContains(
|
||||
'*****',
|
||||
json_encode($oRestResultWithObject));
|
||||
|
||||
static::assertNotContains(
|
||||
self::SIMPLE_PASSWORD,
|
||||
json_encode($oRestResultWithObject));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string Abs path to the XML delta to use for the tests of that class
|
||||
*/
|
||||
public function GetDatamodelDeltaAbsPath(): string
|
||||
{
|
||||
return __DIR__ . '/Delta/delta_test_sanitize_output.xml';
|
||||
}
|
||||
}
|
||||
125
tests/php-unit-tests/unitary-tests/core/RestServicesTest.php
Normal file
125
tests/php-unit-tests/unitary-tests/core/RestServicesTest.php
Normal file
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use CoreException;
|
||||
use CoreServices;
|
||||
use CoreUnexpectedValue;
|
||||
use RestResultWithObjects;
|
||||
use UserLocal;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class RestServicesTest extends ItopDataTestCase
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
* @dataProvider providerTestSanitizeJsonInput
|
||||
*/
|
||||
public function testSanitizeJsonInput($sJsonData, $sExpectedJsonDataSanitized)
|
||||
{
|
||||
$oRS = new CoreServices();
|
||||
$sOutputJson = $oRS->SanitizeJsonInput($sJsonData);
|
||||
static::assertEquals($sExpectedJsonDataSanitized, $sOutputJson);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
public function providerTestSanitizeJsonInput(): array
|
||||
{
|
||||
return [
|
||||
'core/check_credentials' => [
|
||||
'{"operation": "core/check_credentials", "user": "admin", "password": "admin"}',
|
||||
'{
|
||||
"operation": "core/check_credentials",
|
||||
"user": "admin",
|
||||
"password": "*****"
|
||||
}'
|
||||
],
|
||||
'core/update' => [
|
||||
'{"operation": "core/update", "comment": "Update user", "class": "UserLocal", "key": {"id":1}, "output_fields": "first_name, password", "fields": {"password" : "123456"}}',
|
||||
'{
|
||||
"operation": "core/update",
|
||||
"comment": "Update user",
|
||||
"class": "UserLocal",
|
||||
"key": {
|
||||
"id": 1
|
||||
},
|
||||
"output_fields": "first_name, password",
|
||||
"fields": {
|
||||
"password": "*****"
|
||||
}
|
||||
}'
|
||||
],
|
||||
'core/create' => [
|
||||
'{"operation": "core/create", "comment": "Create user", "class": "UserLocal", "fields": {"first_name": "John", "last_name": "Doe", "email": "jd@example/com", "password" : "123456"}}',
|
||||
'{
|
||||
"operation": "core/create",
|
||||
"comment": "Create user",
|
||||
"class": "UserLocal",
|
||||
"fields": {
|
||||
"first_name": "John",
|
||||
"last_name": "Doe",
|
||||
"email": "jd@example/com",
|
||||
"password": "*****"
|
||||
}
|
||||
}'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sOperation
|
||||
* @param $aJsonData
|
||||
* @param $sExpectedJsonDataSanitized
|
||||
* @return void
|
||||
* @throws CoreException
|
||||
* @throws CoreUnexpectedValue
|
||||
* @dataProvider providerTestSanitizeJsonOutput
|
||||
*/
|
||||
public function testSanitizeJsonOutput($sOperation, $aJsonData, $sExpectedJsonDataSanitized)
|
||||
{
|
||||
$oUser = new UserLocal();
|
||||
$oUser->Set('password', '123456');
|
||||
$oRestResultWithObject = new RestResultWithObjects();
|
||||
$oRestResultWithObject->AddObject(0, 'ok', $oUser, ['UserLocal' => ['login', 'password']]);
|
||||
$oRestResultWithObject->SanitizeContent();
|
||||
static::assertEquals($sExpectedJsonDataSanitized, json_encode($oRestResultWithObject));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array[]
|
||||
*/
|
||||
public function providerTestSanitizeJsonOutput(): array
|
||||
{
|
||||
return [
|
||||
|
||||
'core/update' => [
|
||||
'core/update',
|
||||
['comment' => 'Update user', 'class' => 'UserLocal', 'key' => ['login' => 'my_example'], 'output_fields' => 'password', 'fields' => ['password' => 'opkB!req57']],
|
||||
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
|
||||
],
|
||||
'core/create' => [
|
||||
'core/create',
|
||||
['comment' => 'Create user', 'class' => 'UserLocal', 'fields' => ['password' => 'Azertyuiiop*12', 'login' => 'toto', 'profile_list' => [1]]],
|
||||
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
|
||||
],
|
||||
'core/get' => [
|
||||
'core/get',
|
||||
['comment' => 'Get user', 'class' => 'UserLocal', 'key' => ['login' => 'my_example'], 'output_fields' => 'first_name, password'],
|
||||
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
|
||||
],
|
||||
'core/check_credentials' => [
|
||||
'core/check_credentials',
|
||||
['user' => 'admin', 'password' => 'admin'],
|
||||
'{"objects":{"UserLocal::-1":{"code":0,"message":"ok","class":"UserLocal","key":-1,"fields":{"login":"","password":"*****"}}},"code":0,"message":null}'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -1,58 +1,44 @@
|
||||
<?php
|
||||
namespace Combodo\iTop\Test\UnitTest;
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Application\TwigBase;
|
||||
|
||||
use Combodo\iTop\Portal\Twig\AppExtension;
|
||||
use Twig_Environment;
|
||||
use Twig_Loader_Array;
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
use Twig\Environment;
|
||||
use Twig\Loader\FilesystemLoader;
|
||||
|
||||
/**
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
* @backupGlobals disabled
|
||||
*/
|
||||
class TwigTest extends ItopDataTestCase
|
||||
{
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->RequireOnceItopFile('core/config.class.inc.php');
|
||||
}
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->RequireOnceItopFile('core/config.class.inc.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the fix for ticket N°4384
|
||||
*
|
||||
* @dataProvider TemplateProvider
|
||||
*
|
||||
*/
|
||||
public function testTemplate($sFileName, $sExpected)
|
||||
{
|
||||
$sId = 'TestTwig';
|
||||
$oAppExtension = new AppExtension();
|
||||
/**
|
||||
* @covers N°4384 N°7810
|
||||
*
|
||||
*/
|
||||
public function testTemplate()
|
||||
{
|
||||
// Creating sandbox twig env. to load and test the custom form template
|
||||
$oTwig = new Environment(new FilesystemLoader(__DIR__.'/'));
|
||||
|
||||
// Creating sandbox twig env. to load and test the custom form template
|
||||
$oTwig = new Twig_Environment(new Twig_Loader_Array([$sId => $sFileName]));
|
||||
// Manually registering filters and functions as we didn't find how to do it automatically
|
||||
$oAppExtension = new AppExtension();
|
||||
$aFilters = $oAppExtension->getFilters();
|
||||
foreach ($aFilters as $oFilter)
|
||||
{
|
||||
$oTwig->addFilter($oFilter);
|
||||
}
|
||||
$aFunctions = $oAppExtension->getFunctions();
|
||||
foreach ($aFunctions as $oFunction)
|
||||
{
|
||||
$oTwig->addFunction($oFunction);
|
||||
}
|
||||
|
||||
// Manually registering filters and functions as we didn't find how to do it automatically
|
||||
$aFilters = $oAppExtension->getFilters();
|
||||
foreach ($aFilters as $oFilter)
|
||||
{
|
||||
$oTwig->addFilter($oFilter);
|
||||
}
|
||||
$aFunctions = $oAppExtension->getFunctions();
|
||||
foreach ($aFunctions as $oFunction)
|
||||
{
|
||||
$oTwig->addFunction($oFunction);
|
||||
}
|
||||
}
|
||||
$sOutput = $oTwig->render('test.html.twig');
|
||||
|
||||
public static function testTemplateProvider()
|
||||
{
|
||||
$aReturn = array();
|
||||
$aReturn['filter_system'] = [
|
||||
'sFileName' => 'test.html',
|
||||
'expected' =>file_get_contents(dirname(__FILE__).'/test.html'),
|
||||
];
|
||||
|
||||
return $aReturn;
|
||||
}
|
||||
$this->assertEquals(file_get_contents(__DIR__.'/test.html'), $sOutput);
|
||||
}
|
||||
}
|
||||
@@ -42,5 +42,8 @@ Smith, Dupond
|
||||
<div>['echo',1]|sort('system')|join</div>
|
||||
echo1
|
||||
|
||||
<div>[['id','']|sort('system')</div>
|
||||
id
|
||||
|
||||
POST /subscribe?0=cat+/etc/passwd HTTP/1.1
|
||||
email=""@attacker.tld
|
||||
@@ -47,5 +47,8 @@
|
||||
<div>['echo',1]|sort('system')|join</div>
|
||||
{{ ['echo',1]|sort('system')|join }}
|
||||
|
||||
<div>[['id','']|sort('system')</div>
|
||||
{{['id','']|sort('system')|join}}
|
||||
|
||||
POST /subscribe?0=cat+/etc/passwd HTTP/1.1
|
||||
email="{{ app.request.query.filter(0,0,1024,{'options':'system'}) }}"@attacker.tld
|
||||
@@ -209,7 +209,11 @@ try
|
||||
/** @var iRestServiceProvider $oRS */
|
||||
$oRS = $aOpToRestService[$sOperation]['service_provider'];
|
||||
$sProvider = get_class($oRS);
|
||||
|
||||
|
||||
if ($oRS instanceof iRestInputSanitizer) {
|
||||
$sSanitizedJsonInput = $oRS->SanitizeJsonInput($sJsonString);
|
||||
}
|
||||
|
||||
CMDBObject::SetTrackOrigin('webservice-rest');
|
||||
$oResult = $oRS->ExecOperation($sVersion, $sOperation, $aJsonData);
|
||||
}
|
||||
@@ -234,6 +238,7 @@ catch(Exception $e)
|
||||
//
|
||||
$sResponse = json_encode($oResult);
|
||||
|
||||
|
||||
if ($sResponse === false)
|
||||
{
|
||||
$oJsonIssue = new RestResult();
|
||||
@@ -267,7 +272,7 @@ if (MetaModel::GetConfig()->Get('log_rest_service'))
|
||||
$oLog->SetTrim('userinfo', UserRights::GetUser());
|
||||
$oLog->Set('version', $sVersion);
|
||||
$oLog->Set('operation', $sOperation);
|
||||
$oLog->SetTrim('json_input', $sJsonString);
|
||||
$oLog->SetTrim('json_input', $sSanitizedJsonInput ?? $sJsonString);
|
||||
|
||||
$oLog->Set('provider', $sProvider);
|
||||
$sMessage = $oResult->message;
|
||||
@@ -277,7 +282,8 @@ if (MetaModel::GetConfig()->Get('log_rest_service'))
|
||||
}
|
||||
$oLog->SetTrim('message', $sMessage);
|
||||
$oLog->Set('code', $oResult->code);
|
||||
$oLog->SetTrim('json_output', $sResponse);
|
||||
$oResult->SanitizeContent();
|
||||
$oLog->SetTrim('json_output', json_encode($oResult, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
||||
|
||||
$oLog->DBInsertNoReload();
|
||||
$oKPI->ComputeAndReport('Log inserted');
|
||||
|
||||
Reference in New Issue
Block a user