mirror of
https://github.com/Combodo/iTop.git
synced 2026-09-30 05:19:09 +02:00
Compare commits
6 Commits
3.3.0-rc1
...
support/3.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a2a00cb582 | ||
|
|
4d699f79e8 | ||
|
|
873cea1a76 | ||
|
|
adc2596b4a | ||
|
|
2ac4229ee0 | ||
|
|
4a6af15237 |
@@ -61,7 +61,7 @@ foreach ($aTcpdfFontsDirContent as $sTcpdfFontResourceName) {
|
||||
* 2) Then adding the DroidSansFallback font (useful for CJK data for example)
|
||||
*/
|
||||
echo $sCurrentScriptFileName.": ---2) Copying font files to TCPDF ($sTcPdfFontsFolder)...\n";
|
||||
$aFontFilesToCopy = glob(__DIR__.'\droidsansfallback.*');
|
||||
$aFontFilesToCopy = glob(__DIR__.DIRECTORY_SEPARATOR.'droidsansfallback.*');
|
||||
foreach ($aFontFilesToCopy as $sFontFileToCopy) {
|
||||
$sFontFileName = basename($sFontFileToCopy);
|
||||
echo $sCurrentScriptFileName.': copying '.$sFontFileName."\n";
|
||||
|
||||
@@ -109,10 +109,18 @@ $('#shortcut_rename_dlg').dialog({
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sOkButtonLabel", click: ShortcutRenameOK},
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
$(this).dialog( "close" ); $(this).remove();
|
||||
} },
|
||||
{
|
||||
text: "$sCancelButtonLabel",
|
||||
click: function() {
|
||||
$(this).dialog( "close" ); $(this).remove();
|
||||
},
|
||||
'class': 'ibo-button ibo-is-alternative ibo-is-neutral action cancel'
|
||||
},
|
||||
{
|
||||
text: "$sOkButtonLabel",
|
||||
click: ShortcutRenameOK,
|
||||
'class': 'ibo-is-regular ibo-is-primary'
|
||||
},
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
|
||||
@@ -1750,8 +1750,8 @@ class Config
|
||||
'security.disable_joined_classes_filter' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true, scope filters aren\'t applied to joined classes or union classes not directly listed in the SELECT clause.',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
@@ -1766,8 +1766,8 @@ class Config
|
||||
'security.disable_exec_forced_login_for_all_enpoints' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true, when no delegated authentication module is defined, no login will be forced on modules exec endpoints',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
|
||||
@@ -1938,7 +1938,7 @@ class DBObjectSearch extends DBSearch
|
||||
$oSearch = $this;
|
||||
$aClassesToFilter = $this->GetSelectedClasses();
|
||||
|
||||
// Opt-in for joined classes filtering, otherwise only filter the selected class(es)
|
||||
// Joined classes filtering can be disabled through the configuration.
|
||||
if (MetaModel::GetConfig()->Get('security.disable_joined_classes_filter') === false) {
|
||||
$aClassesToFilter = $this->GetJoinedClasses();
|
||||
}
|
||||
|
||||
@@ -683,7 +683,7 @@ class DBUnionSearch extends DBSearch
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Opt-in for joined classes filtering, otherwise fallback on DBSearch filtering
|
||||
// Joined classes filtering can be disabled through the configuration.
|
||||
if (MetaModel::GetConfig()->Get('security.disable_joined_classes_filter') === true) {
|
||||
return parent::ApplyDataFilters();
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ function RenderAttachments(AjaxPage $oPage, $iTransactionId)
|
||||
try {
|
||||
require_once APPROOT.'/application/startup.inc.php';
|
||||
require_once APPROOT.'/application/loginwebpage.class.inc.php';
|
||||
LoginWebPage::DoLoginEx(null /* any portal */, false);
|
||||
LoginWebPage::DoLogin(); // No user portal should access this endpoint.
|
||||
|
||||
$oPage = new AjaxPage("");
|
||||
|
||||
@@ -105,15 +105,6 @@ try {
|
||||
$oPage->SetData($aResult);
|
||||
break;
|
||||
|
||||
case 'remove':
|
||||
$iAttachmentId = utils::ReadParam('att_id', '');
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE id = :id");
|
||||
$oSet = new DBObjectSet($oSearch, [], ['id' => $iAttachmentId]);
|
||||
while ($oAttachment = $oSet->Fetch()) {
|
||||
$oAttachment->DBDelete();
|
||||
}
|
||||
break;
|
||||
|
||||
case 'refresh_attachments_render':
|
||||
$sTempId = utils::ReadParam('temp_id', '', false, 'transaction_id');
|
||||
RenderAttachments($oPage, $sTempId);
|
||||
|
||||
19
js/pages/backoffice/dialog.js
Normal file
19
js/pages/backoffice/dialog.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
// Overload of the default dialog widget
|
||||
$.widget('ui.dialog', $.ui.dialog, {
|
||||
_allowInteraction: function (oEvent) {
|
||||
const oTarget = $(oEvent.target);
|
||||
// If we interact with a CKEditor instance in fullscreen mode, we need to allow it
|
||||
// We could check if the current instance is in the dialog, but it's easier to always allow it in fullscreen
|
||||
if (oTarget.closest('.ck.ck-fullscreen__main-wrapper, .ck-body-wrapper').length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If that's not a specific case, fall back to the default behavior
|
||||
return this._super(oEvent);
|
||||
}
|
||||
});
|
||||
BIN
lib/tecnickcom/tcpdf/fonts/droidsansfallback.ctg.z
Normal file
BIN
lib/tecnickcom/tcpdf/fonts/droidsansfallback.ctg.z
Normal file
Binary file not shown.
2975
lib/tecnickcom/tcpdf/fonts/droidsansfallback.php
Normal file
2975
lib/tecnickcom/tcpdf/fonts/droidsansfallback.php
Normal file
File diff suppressed because it is too large
Load Diff
BIN
lib/tecnickcom/tcpdf/fonts/droidsansfallback.z
Normal file
BIN
lib/tecnickcom/tcpdf/fonts/droidsansfallback.z
Normal file
Binary file not shown.
@@ -1239,13 +1239,32 @@ JS
|
||||
$oSearch = new DBObjectSearch('Shortcut');
|
||||
$aShortcuts = utils::ReadMultipleSelection($oSearch);
|
||||
$iShortcut = $aShortcuts[0];
|
||||
$oShortcut = MetaModel::GetObject('Shortcut', $iShortcut);
|
||||
$oShortcutSearch = new DBObjectSearch('Shortcut');
|
||||
$oShortcutSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oShortcutSearch->AddCondition('id', $iShortcut, '=');
|
||||
$oShortcutSet = new CMDBObjectSet($oShortcutSearch);
|
||||
|
||||
$oShortcut = $oShortcutSet->Fetch();
|
||||
|
||||
if ($oShortcut === null) {
|
||||
throw new SecurityException(Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
|
||||
$oShortcut->StartRenameDialog($oPage);
|
||||
break;
|
||||
|
||||
case 'shortcut_rename_go':
|
||||
$iShortcut = utils::ReadParam('id', 0);
|
||||
$oShortcut = MetaModel::GetObject('Shortcut', $iShortcut);
|
||||
|
||||
$oShortcutSearch = new DBObjectSearch('Shortcut');
|
||||
$oShortcutSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oShortcutSearch->AddCondition('id', $iShortcut, '=');
|
||||
$oShortcutSet = new CMDBObjectSet($oShortcutSearch);
|
||||
$oShortcut = $oShortcutSet->Fetch();
|
||||
|
||||
if ($oShortcut === null) {
|
||||
throw new SecurityException(Dict::S('UI:ObjectDoesNotExist'));
|
||||
}
|
||||
|
||||
$sName = utils::ReadParam('attr_name', '', false, 'raw_data');
|
||||
if (strlen($sName) > 0) {
|
||||
|
||||
@@ -243,7 +243,7 @@ JS
|
||||
);
|
||||
$oShortcutsToolBar->AddSubBlock($oShortcutsRenameButton);
|
||||
// - Delete button
|
||||
$oShortcutsDeleteButton = ButtonUIBlockFactory::MakeForSecondaryAction(
|
||||
$oShortcutsDeleteButton = ButtonUIBlockFactory::MakeForDestructiveAction(
|
||||
Dict::S('UI:Button:Delete'),
|
||||
null,
|
||||
null,
|
||||
|
||||
@@ -209,6 +209,7 @@ class iTopWebPage extends NiceWebPage implements iTabbedPage
|
||||
$this->LinkScriptFromAppRoot('js/pages/backoffice/keyboard-shortcuts.js');
|
||||
|
||||
// Used throughout the app.
|
||||
$this->LinkScriptFromAppRoot('js/pages/backoffice/dialog.js');
|
||||
$this->LinkScriptFromAppRoot('js/pages/backoffice/toolbox.js');
|
||||
$this->LinkScriptFromAppRoot('js/pages/backoffice/on-ready.js');
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ class LoginWebPageTest extends ItopDataTestCase
|
||||
$this->assertStringContainsString('<title>iTop login</title>', $sPageContent, 'if itop is configured to force login when no there is no delegated authentication endpoints list, then login should be required.');
|
||||
}
|
||||
|
||||
public function testWithoutDelegatedAuthenticationEndpointsListWithDefaultConfiguration()
|
||||
public function testWithoutDelegatedAuthenticationEndpointsListRequiresLoginByDefault()
|
||||
{
|
||||
$sPageContent = $this->CallItopUri(
|
||||
"pages/exec.php?exec_module=extension-without-delegated-authentication-endpoints-list&exec_page=src/Controller/File.php",
|
||||
@@ -120,7 +120,24 @@ class LoginWebPageTest extends ItopDataTestCase
|
||||
true
|
||||
);
|
||||
|
||||
$this->assertStringContainsString('Yo', $sPageContent, 'by default (until N°9343) if no delegated authentication endpoints list is defined, not logged in persons should access pages');
|
||||
$this->assertStringContainsString('<title>iTop login</title>', $sPageContent, 'by default, login should be required when no delegated authentication endpoints list is defined');
|
||||
}
|
||||
|
||||
public function testWithoutDelegatedAuthenticationEndpointsListWithCompatibilityOptOut()
|
||||
{
|
||||
@chmod($this->oConfig->GetLoadedFile(), 0770);
|
||||
$this->oConfig->Set('security.disable_exec_forced_login_for_all_enpoints', true, 'AnythingButEmptyOrUnknownValue');
|
||||
$this->oConfig->WriteToFile();
|
||||
@chmod($this->oConfig->GetLoadedFile(), 0444);
|
||||
|
||||
$sPageContent = $this->CallItopUri(
|
||||
"pages/exec.php?exec_module=extension-without-delegated-authentication-endpoints-list&exec_page=src/Controller/File.php",
|
||||
[],
|
||||
[],
|
||||
true
|
||||
);
|
||||
|
||||
$this->assertStringContainsString('Yo !', $sPageContent, 'the compatibility opt-out should allow anonymous access when no delegated authentication endpoints list is defined');
|
||||
}
|
||||
|
||||
public function testNotInDelegatedAuthenticationEndpointsList()
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\DotMake\Dependencies\Composer\Tcpdf;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopTestCase;
|
||||
|
||||
/**
|
||||
* @coversNothing
|
||||
*/
|
||||
class TcpdfUpdateFontsTest extends ItopTestCase
|
||||
{
|
||||
public function testThatDroidSansFallbackFilesAreCopiedToTcpdfFontsFolderAfterLibraryUpdate(): void
|
||||
{
|
||||
$sSourcePattern = APPROOT
|
||||
.'.make'.DIRECTORY_SEPARATOR.'dependencies'.DIRECTORY_SEPARATOR.'composer'.DIRECTORY_SEPARATOR.'tcpdf'.DIRECTORY_SEPARATOR.'droidsansfallback.*';
|
||||
$aSourceFiles = glob($sSourcePattern);
|
||||
$this->assertIsArray($aSourceFiles, 'Unable to read source TCPDF custom font files.');
|
||||
$this->assertNotEmpty($aSourceFiles, 'No source files found for pattern droidsansfallback.*');
|
||||
|
||||
foreach ($aSourceFiles as $sSourceFilePath) {
|
||||
$sFontFileName = basename($sSourceFilePath);
|
||||
$sDestinationFilePath = APPROOT
|
||||
.'lib'.DIRECTORY_SEPARATOR.'tecnickcom'.DIRECTORY_SEPARATOR.'tcpdf'.DIRECTORY_SEPARATOR.'fonts'.DIRECTORY_SEPARATOR.$sFontFileName;
|
||||
|
||||
$this->assertFileExists($sDestinationFilePath, "Missing copied font file: {$sFontFileName}");
|
||||
$this->assertSame(
|
||||
hash_file('sha256', $sSourceFilePath),
|
||||
hash_file('sha256', $sDestinationFilePath),
|
||||
"Copied font file content mismatch: {$sFontFileName}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Combodo\iTop\Test\UnitTest\Module\ItopAttachment;
|
||||
|
||||
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||
|
||||
class AttachmentAjaxEndpointTest extends ItopDataTestCase
|
||||
{
|
||||
public const USE_TRANSACTION = false;
|
||||
private const AUTHENTICATION_PASSWORD = 'tagada-Secret,007';
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->BackupConfiguration();
|
||||
$this->AddLoginModeAndSaveConfiguration('url');
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider AjaxEndpointAccessProvider
|
||||
*/
|
||||
public function testAjaxEndpointAccess(string $sProfile, int $iExpectedHttpCode): void
|
||||
{
|
||||
$sLogin = 'user-'.uniqid();
|
||||
$this->CreateUser($sLogin, self::$aURP_Profiles[$sProfile], self::AUTHENTICATION_PASSWORD);
|
||||
|
||||
$iHttpCode = $this->CallAttachmentEndpointAs($sLogin);
|
||||
|
||||
$this->assertSame($iExpectedHttpCode, $iHttpCode);
|
||||
}
|
||||
|
||||
public function AjaxEndpointAccessProvider(): array
|
||||
{
|
||||
return [
|
||||
'console user' => ['Service Desk Agent', 200],
|
||||
'portal user' => ['Portal user', 302], // redirect to portal
|
||||
];
|
||||
}
|
||||
|
||||
private function CallAttachmentEndpointAs(string $sLogin): int
|
||||
{
|
||||
$this->CallItopUri(
|
||||
'env-production/itop-attachments/ajax.itop-attachment.php?operation=add&'.http_build_query([
|
||||
'auth_user' => $sLogin,
|
||||
'auth_pwd' => self::AUTHENTICATION_PASSWORD,
|
||||
]),
|
||||
[],
|
||||
[
|
||||
CURLOPT_HTTPHEADER => ['X-Combodo-Ajax:1'],
|
||||
CURLOPT_POST => 0,
|
||||
],
|
||||
true
|
||||
);
|
||||
|
||||
return $this->aLastCurlGetInfo['http_code'];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user