Compare commits

...

27 Commits

Author SHA1 Message Date
Benjamin DALSASS
c63f3e650d N°9392 - wizard helper linkset data validation improvement (#1100)
- fix cs fixer
2026-11-02 11:08:06 +01:00
Benjamin Dalsass
c5a4433d0e N°9392 - wizard helper linkset data validation improvement (#1100) 2026-11-02 10:46:24 +01:00
Benjamin DALSASS
d8b9533697 N°9556 - backup restore improvement
- CI fix
2026-11-02 10:39:59 +01:00
odain
cd469d401c Cherry-pick from 51f0eea8: enhance test sdk: add GetTemporaryFilePath
# Conflicts:
#	tests/php-unit-tests/src/BaseTestCase/ItopTestCase.php
2026-10-30 18:16:53 +01:00
Benjamin DALSASS
aa8a756af9 N°9556 - backup restore improvement
- CI fix
2026-10-30 12:15:45 +01:00
Molkobain
264bd89617 📝 First proposition for AI coding / review instructions (#1086)
* 📝 First proposition for AI coding / review instructions

* Apply suggestion from @greptile-apps[bot]

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* Potential fix for pull request finding 'Scope class-placement rules to avoid false positives'

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-10-30 11:18:36 +01:00
Benjamin DALSASS
4dcd6f9b44 N°9556 - backup restore improvement
- CI fix
2026-10-30 10:45:46 +01:00
Benjamin Dalsass
1578488640 N°9556 - Backup restore improvement (#1103) 2026-10-30 10:31:11 +01:00
Purple Grape
3282130fb7 Update license url for branch 3.2 (#1063) 2026-10-23 17:22:57 +02:00
jf-cbd
da4a810534 N°9641 - improve control access when editing contact (#1082) 2026-10-21 09:14:26 +02:00
Timmy38
6865c845f0 N°10206 Associate icon list to button 2026-10-20 16:31:18 +02:00
Anne-Cath
530c7b2ddd Merge remote-tracking branch 'origin/support/3.2.3' into support/3.2 2026-10-16 15:42:56 +02:00
Anne-Catherine
692c0723ab N°10202 - CEX: Inline image as URL unreadable due to secuirty fix (#1079) 2026-10-16 13:29:11 +02:00
Timmy38
23619ec6cd N°10187 Fix CS 2026-10-15 11:55:10 +02:00
Timmy38
0ba1bf829c N°10187 Do not replace spaces by nbsp in dropdown 2026-10-15 11:38:46 +02:00
Stephen Abello
16cac91c8a N°9181 - Fix object class alignment in summary cards (#1035) 2026-10-14 11:39:09 +02:00
Stephen Abello
01bf120da3 N°10136 - Change the way Profiles are retrieved (#1076) 2026-10-13 10:22:02 +02:00
odain-cbd
6477468572 N°6073 - Not able to run synchro_import or synchro_exec with param max_chunk_size and a password with special char (#1054) 2026-10-12 16:45:16 +02:00
jf-cbd
4639d06a0d N°9578 - Specify allowed protocols for post request (#1069) 2026-10-08 10:31:30 +02:00
jf-cbd
09574d90d5 N°9477 - improve documents output (#1066) 2026-10-06 09:53:11 +02:00
Molkobain
0a4bbfe5a9 🙈 Ensure data/.compilation-symlinks is not commited is deleted 2026-10-01 16:29:57 +02:00
Stephen Abello
31a4e1a0a0 N°10120 - Filtered classes in subqueries produce invalid SQL (#1059)
* N°10120 - Filtered classes in subqueries produce invalid SQL

* Avoid SQL cache to be shared between ids only and full columns queries
2026-10-01 10:44:33 +02:00
Stephen Abello
de74103118 Fix unit test cause by security changes in #1055 2026-10-01 09:35:55 +02:00
Stephen Abello
a2a00cb582 N°10075 - Update configuration parameters default value (#1055) 2026-09-29 10:02:57 +02:00
jf-cbd
4d699f79e8 Add unit test for N°9740 2026-09-28 11:30:54 +02:00
Stephen Abello
873cea1a76 N°9557 - Small improvement to shortcut preferences (#1049)
* N°9557 - Small improvement to shortcut preferences

* Apply code review suggestions
2026-09-25 10:28:05 +02:00
jf-cbd
adc2596b4a Issue/9740 fix attachment removal (#1052)
(cherry picked from commit af972313d7)
2026-09-18 15:40:52 +02:00
261 changed files with 1763 additions and 1178 deletions

1
.gitignore vendored
View File

@@ -33,7 +33,6 @@ tests/*/vendor/*
!/data/index.php
!/data/web.config
!/data/exclude.txt
!/data/.compilation-symlinks
# iTop extensions
/extensions/**

133
AGENTS.md Normal file
View File

@@ -0,0 +1,133 @@
# AGENTS.md: iTop
Instructions for AI coding agents and AI code reviewers working on this repository.
iTop (by Combodo) is an open-source ITSM/CMDB web application: PHP backend, JS/HTML/SCSS front-end, XML datamodel.
Write all code, identifiers, comments and review comments in English.
## Critical rules (security first)
These rules apply to every change. In code review, a violation is a P1 issue.
### Input: sanitize with an explicit filter
- Read request parameters only with `utils::ReadParam()` or `utils::ReadPostedParam()`, never from `$_GET`, `$_POST`, `$_REQUEST` or `$_COOKIE`.
- Always pass the filter explicitly as a `utils::ENUM_SANITIZATION_FILTER_*` constant, the most restrictive that fits (`INTEGER`, `CLASS`, `FIELD_NAME`, `TRANSACTION_ID`, `URL`...).
- `utils::ENUM_SANITIZATION_FILTER_RAW_DATA` requires a comment explaining why no other filter fits.
### Output: escape at consumption time, in the right context
- Sanitizing input is not escaping output. Escape where the value is rendered, never upstream in the backend, and never store escaped values.
- PHP to HTML: `utils::EscapeHtml()`. Not `htmlentities()` nor `utils::HtmlEntities()` (they escape every non-ASCII char).
- Twig: rely on auto-escaping; use `|escape('js')` in JS contexts and `|sanitize(constant('utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME'))` (or `..._ELEMENT_IDENTIFIER`) for generated identifiers. `|raw` only for trusted HTML, with a comment.
- JS to DOM: escape untrusted values with `CombodoSanitizer.EscapeHtml()` before building HTML; prefer `.text()` to `.html()` or `innerHTML`.
- User-provided rich HTML goes through `HTMLSanitizer::Sanitize()`.
### CSRF
- Never change state on a GET request.
- A form that changes state embeds a transaction id from `utils::GetNewTransactionId()`; its handler calls `utils::IsTransactionValid()` before any modification.
- Ajax calls use jQuery or `CombodoHTTP.Fetch()`, which send the `X-Combodo-Ajax` header checked by `pages/ajax.render.php`. Never use raw `fetch()` or `XMLHttpRequest`.
### Data access and permissions
- OQL: use placeholders (`WHERE name = :name`) and pass values in the `$aParams` argument of `DBObjectSearch::FromOQL()`. Never concatenate input into OQL or SQL; raw SQL values go through `CMDBSource::Quote()`.
- Every new entry point (page, ajax operation, controller route, webservice) enforces authentication (`LoginWebPage::DoLogin()` / `DoLoginEx()`) and rights (`UserRights::IsActionAllowed()`, `UserRights::IsAdministrator()`...).
- `AllowAllData()` bypasses user rights and scopes: only when strictly needed, with a comment.
### Secrets and logs
- Never log passwords, tokens, API keys, session ids or personal data. Log security events on `LogChannels::SECURITY`.
### Security configuration parameters: secure by default
- The default value of a configuration parameter is always the secure one.
- An option that weakens a protection is opt-in: a `bool` named `security.disable_<protection>`, default `false`, whose description states the risk when set to `true` (model: `security.disable_inline_documents_sandbox` in `core/config.class.inc.php`). Do not add new `security.enable_*` parameters.
## Project overview
- Supported PHP versions: the `require.php` constraint in `composer.json`. Never use a language feature above its minimum version.
- Branches: `develop` (next version), `support/x.y` (maintained versions).
- Layout:
- `core/`: ORM, `MetaModel`, OQL, configuration (`core/config.class.inc.php`), logs. Legacy structure, meant to be replaced by `sources/` in the long term.
- `application/`: legacy UI layer, `utils` (`application/utils.inc.php`), exceptions (`application/exceptions/`). Legacy structure, meant to be replaced by `sources/` in the long term.
- `sources/`: namespaced code (`Combodo\iTop\...`, namespace matches the folder): services, controllers, UI blocks, forms.
- `pages/`: legacy entry points (`UI.php`, `ajax.render.php`).
- `datamodels/2.x/<module>/`: modules (`module.<module>.php`, `datamodel.<module>.xml`, `dictionaries/`).
- `dictionaries/`: core translations. `templates/`: Twig. `js/`: iTop JS. `css/`: SCSS and compiled CSS.
- `tests/`: PHPUnit (`php-unit-tests/`), PHP-CS-Fixer (`php-code-style/`), PHPStan (`php-static-analysis/`).
- Never edit:
- `lib/` (Composer `vendor-dir`) and `node_modules/` (npm): third-party code.
- `env-*/`: generated by the datamodel compilation, not versioned.
- `data/`: temporary or cached files, not versioned.
## Commands
- Unit tests (needs an installed iTop instance, see `tests/php-unit-tests/README.md`): run `composer install` in `tests/php-unit-tests/`, then `tests/php-unit-tests/vendor/bin/phpunit --configuration tests/php-unit-tests/phpunit.xml.dist <path>`.
- PHP code style: run `composer install` in `tests/php-code-style/`, then `tests/php-code-style/vendor/bin/php-cs-fixer fix --config tests/php-code-style/.php-cs-fixer.dist.php <path>`.
- Static analysis: PHPStan, see `tests/php-static-analysis/README.md` (analyses `env-production`, needs a setup).
- After adding, renaming or moving a PHP class in `core/`, `application/` or `sources/`: run `composer dump-autoload` (the classmap is authoritative: an unlisted class is not found) and commit `lib/composer/autoload_classmap.php` and `lib/composer/autoload_static.php`.
- After changing SCSS: regenerate and commit the compiled CSS (the pre-commit hook rejects SCSS without CSS).
- After changing datamodel XML: the datamodel must be recompiled by the iTop setup or toolkit. An agent cannot do it: tell the user.
## Coding conventions
### PHP
- Formatting is enforced by PHP-CS-Fixer (PSR-12, tabs): do not hand-format.
- Variables: mixed case with a type prefix: `$s` string, `$i` int, `$b` bool, `$a` array, `$o` object, `$f` float, no prefix for mixed types. Loop counters (`$i`, `$j`) are fine.
- Functions and methods: UpperCamelCase starting with a verb (`GetInstance()`, `ReadParam()`). Classes: UpperCamelCase.
- Array keys: snake_case, documented with PHPDoc array shapes (`array{key: type}`) or generics (`array<string, \CheckResult>`).
- New code uses strict comparison (`===`). `==` only with a comment explaining why.
- Test empty strings with `utils::IsNullOrEmptyString()`, not `empty()` (`"0"` is empty).
- Type hints in new code only. Do not add them to existing signatures (it breaks extensions) nor return types to fluent methods.
- PHPDoc: `@since` is mandatory on new classes and on new or changed methods and properties, e.g. `@since 3.3.0 N°1234 - Short description`. Use `bool`, not `boolean`.
- Do not modify existing copyright headers.
- Configuration parameters: lowercase, domain prefix, underscores (`email_transport_smtp.host`), declared in `core/config.class.inc.php`.
### Services
- A new service is a singleton: private constructor, `private static $oInstance`, `public static function GetInstance()`. Model: `sources/Service/Module/ModuleService.php`.
### Exceptions and logs
- Throw iTop exceptions (`CoreException` and its subclasses in `application/exceptions/`) rather than a bare `\Exception`.
- Log a caught exception with `ExceptionLog::LogException($oException)`, not `IssueLog::Error($oException->getMessage())`.
- Other logs: `IssueLog` with a `LogChannels::*` channel.
- Never swallow an exception: an empty `catch` needs a comment explaining why.
### JavaScript, Twig, SCSS
- JS functions: UpperCamelCase starting with a verb. Follow the escaping and Ajax rules above.
- Indentation follows `.editorconfig` (PHP, JS: tabs; SCSS, XML: 2 spaces; Twig: 4 spaces).
### Translations
- No hard-coded UI text: use `Dict::S()`, `Dict::Format()`, or `|dict_s` / `|dict_format` in Twig.
- Add new entries in English in the `en` dictionary file (`dictionaries/en.dictionary.itop.*.php` or `datamodels/2.x/<module>/dictionaries/en.dict.<module>.php`).
- Add new entries in other existing languages as well.
- In other languages, a ~~ suffix marks an untranslated entry: never remove it without translating.
### Commits
- Start either with the ticket reference (`N°*`) or with one of the supported Gitmoji code (`:white_check_mark:`, `:green_heart:`, `:memo:`, `:bookmark:`), imperative present tense, first line 72 characters max, describe the functional change. More details in the body if needed.
## Dependencies and licenses
- Dependencies are versioned in the repository: Composer in `lib/`, npm in `node_modules/`. Change versions in `composer.json` / `package.json` and run Composer or npm; never edit the files directly.
- Every new dependency must have an entry in `setup/licenses/community-licenses.xml`, with a license compatible with AGPL-3.0. For Composer packages, propose to the user to run `php .make/license/updateLicenses.php` (needs bash, composer and jq) and review its diff; npm packages and other bundled assets are added by hand.
## Datamodel
- The datamodel ("DM") is compiled from the XML of the modules (`datamodels/2.x/<module>/datamodel.<module>.xml`) and of installed extensions into `env-<environment>/` (usually `env-production/`), accessed at runtime through `MetaModel`.
- Changing an existing class or attribute impacts every customer upgrade and their extensions (which alter the datamodel through XML deltas): treat it as high-impact and flag it.
## Tests
- Location: `tests/php-unit-tests/unitary-tests/`, mirroring the source path (tests for `application/foo.php` go in `unitary-tests/application/`). Cross-application data consistency: `integration-tests/`.
- Naming: `MyClass` is tested by `MyClassTest`; `MyMethod()` by `testMyMethod()`.
- Use the lightest base class that works:
1. `PHPUnit\Framework\TestCase`: pure logic.
2. `Combodo\iTop\Test\UnitTest\ItopTestCase`: iTop helpers, no datamodel.
3. `Combodo\iTop\Test\UnitTest\ItopDataTestCase`: starts the datamodel (`MetaModel`) and rolls back CRUD operations. Slow: only when the test needs the datamodel or iTop objects.
4. `Combodo\iTop\Test\UnitTest\ItopCustomDatamodelTestCase`: a non-standard datamodel.
- Process isolation (`@runInSeparateProcess`, about 800 ms per `ItopDataTestCase` test) only when needed, on the test, never globally.
- Do not leave static state behind (`ContextTag::AddContext()`, `EventService::RegisterListener()`, `Dict::Add()`): checked by `integration-tests/DetectStaticPollutionTest.php`.
- `markTestSkipped()` only for a temporarily disabled test.
- More details: `tests/php-unit-tests/README.md`.
## Glossary
- **DM / datamodel**: the application data model (classes, attributes, lifecycles, menus), compiled from XML and PHP into `env-*/`.
- **Module**: a unit of iTop code under `datamodels/2.x/<module>/`. **Extension**: a packaged set of modules installed on top of iTop.
- **OQL**: iTop's object query language.
- **Transaction id**: iTop's CSRF token.
- **Console / back-office**: the main UI for agents. **Portal**: the end-user UI (`datamodels/2.x/itop-portal-base/`).
- **N°xxxx**: Combodo internal ticket number, used in commits and `@since`.

30
REVIEW.md Normal file
View File

@@ -0,0 +1,30 @@
# REVIEW.md: AI code review instructions for iTop
For automated reviewers (GitHub Copilot code review, Greptile, ...). Project conventions and security rules are in `AGENTS.md`; this file says what to comment on and how.
## Output
- Write every comment in English.
- Start each comment with its priority: `[P1-Security]`, `[P2-Regression]`, `[P2-Performance]`, `[P2-Architecture]` or `[P3]`.
- Report every P1 and P2 issue. Report at most 3 `[P3]` comments per PR: keep the most useful ones.
- Put test suggestions in a single `[Tests]` comment; it does not count toward the P3 limit.
- If nothing is above P3, say so in one sentence. No praise, no file-by-file summary.
## Priorities
1. **P1 Security**: XSS, CSRF, OQL/SQL injection, missing authentication or rights check, sensitive data in logs, unsafe file or path handling, any breach of the "Critical rules" in `AGENTS.md`, a security option that is not secure by default or not named `security.disable_*`.
2. **P2 Regression**: behavior change in an API extensions rely on (public classes and methods, extension interfaces, events, configuration parameters, REST/webservices); change to an existing datamodel class or attribute; removed or renamed dictionary entry.
3. **P2 Performance**: queries inside loops, loading whole object sets when a count or a subset is enough, loading all attributes of an object in a loop instead of calling `\DBObjectSet::OptimizeColumnLoad`, repeated expensive calls.
4. **P2 Architecture**: logic in the wrong layer, a new service that is not a singleton, a new core production PHP class outside of the `sources/` folder (excluding test classes and module-specific code), a new PHP class in `core/`, `application/` or `sources/` without the updated `lib/composer/autoload_classmap.php`, a new dependency missing from `setup/licenses/community-licenses.xml`, SCSS changed without the compiled CSS.
5. **P3 Other**: unclear names (variables, functions, classes), deviations from `AGENTS.md` conventions, typos and grammar in identifiers, comments and dictionary entries, UI labels that could be clearer or more consistent with existing ones.
## Tests
- When the PR changes behavior, propose the missing test cases: what to assert, in which file of `tests/php-unit-tests/unitary-tests/`.
- Propose missing test cases to ensure maximum coverage of the new code, and that it is not broken by future changes.
- Check readability, and that the base class is the lightest that works: `ItopDataTestCase` only if the test needs the datamodel. Flag unjustified process isolation and static state left behind.
## Do not comment on
- Formatting: indentation, spacing, line breaks, brace placement. PHP-CS-Fixer and `.editorconfig` handle it.
- Third-party code in `lib/` and `node_modules/`, and generated code in `env-*/`. Only check whether `lib/composer/autoload_*.php` should have changed.
- Code the PR does not touch, unless the change breaks it or it needs to be adjusted accordingly.
## Vulnerability fixes
This repository is public. If a change seems to fix an existing vulnerability, never describe the vulnerability, how to exploit it, or which versions are affected: neither in comments nor in the PR summary. Review it as an ordinary change. If the fix looks incomplete, describe only the missing check in neutral technical terms (for example "this value is not escaped here").

View File

@@ -2075,17 +2075,8 @@ class MenuBlock extends DisplayBlock
$aAllowedProfiles = MetaModel::GetConfig()->Get('concurrent_lock_override_profiles');
$bCanKill = false;
$oUser = UserRights::GetUserObject();
$aUserProfiles = [];
if (!is_null($oUser)) {
$oProfileSet = $oUser->Get('profile_list');
while ($oProfile = $oProfileSet->Fetch()) {
$aUserProfiles[$oProfile->Get('profile')] = true;
}
}
foreach ($aAllowedProfiles as $sProfile) {
if (array_key_exists($sProfile, $aUserProfiles)) {
if (UserRights::HasProfile($sProfile)) {
$bCanKill = true;
break;
}

View File

@@ -1202,7 +1202,6 @@ class DesignerComboField extends DesignerFormField
{
$sId = $this->oForm->GetFieldId($this->sCode);
$sName = $this->oForm->GetFieldName($this->sCode);
$sChecked = $this->defaultValue ? 'checked' : '';
$sMandatory = $this->bMandatory ? 'true' : 'false';
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
if ($this->IsSorted()) {
@@ -1245,8 +1244,7 @@ class DesignerComboField extends DesignerFormField
} else {
$sSelected = ($sKey == $this->defaultValue) ? 'selected' : '';
}
// Quick and dirty: display the menu parents as a tree
$sHtmlValue = str_replace(' ', '&nbsp;', $sDisplayValue);
$sHtmlValue = $this->PrepareValueForRendering($sDisplayValue);
$sHtml .= "<option value=\"".utils::EscapeHtml($sKey)."\" $sSelected>$sHtmlValue</option>";
}
$sHtml .= "</select></span>";
@@ -1263,6 +1261,14 @@ EOF
}
protected function PrepareValueForRendering($sValue = null): ?string
{
if (is_null($sValue)) {
$sValue = $this->defaultValue;
}
return $sValue;
}
public function ReadParam(&$aValues)
{
parent::ReadParam($aValues);

View File

@@ -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(); }
});

View File

@@ -1315,8 +1315,8 @@ class utils
}
if (is_null($sAuthUser)) {
$sAuthUser = self::ReadParam('auth_user', '', 'raw_data');
$sAuthPwd = self::ReadParam('auth_pwd', '', 'raw_data');
$sAuthUser = self::ReadParam('auth_user', '', true, 'raw_data');
$sAuthPwd = self::ReadParam('auth_pwd', '', true, 'raw_data');
}
$sParamFile = self::GetParamSourceFile('auth_user');
if (is_null($sParamFile)) {
@@ -1886,6 +1886,9 @@ SQL;
$aHTTPHeaders[] = trim($sHeaderString);
}
// Default options, can be overloaded/extended with the 4th parameter of this method, see above $aCurlOptions
$iCurlAllowedProtocols = self::ConvertProtocolsToCurlOption(
self::GetConfig()->Get('security.post_requests.allowed_protocols')
);
$aOptions = [
CURLOPT_RETURNTRANSFER => true, // return the content of the request
CURLOPT_HEADER => false, // don't return the headers in the output
@@ -1908,6 +1911,9 @@ SQL;
$aAllOptions = $aCurlOptions + $aOptions;
$ch = curl_init($sUrl);
curl_setopt_array($ch, $aAllOptions);
if (!curl_setopt($ch, CURLOPT_PROTOCOLS, $iCurlAllowedProtocols)) {
throw new Exception('Unable to enforce allowed protocols for cURL request');
}
$response = curl_exec($ch);
$iErr = curl_errno($ch);
$sErrMsg = curl_error($ch);
@@ -1929,6 +1935,40 @@ SQL;
return $response;
}
private static function ConvertProtocolsToCurlOption(string $sProtocols): int
{
$aProtocols = explode(',', $sProtocols);
$iCurlProtocols = 0;
foreach ($aProtocols as $sProtocol) {
$iCurlProtocols |= match (strtolower(trim($sProtocol))) {
'dict' => defined('CURLPROTO_DICT') ? CURLPROTO_DICT : 0,
'file' => defined('CURLPROTO_FILE') ? CURLPROTO_FILE : 0,
'ftp' => defined('CURLPROTO_FTP') ? CURLPROTO_FTP : 0,
'ftps' => defined('CURLPROTO_FTPS') ? CURLPROTO_FTPS : 0,
'gopher' => defined('CURLPROTO_GOPHER') ? CURLPROTO_GOPHER : 0,
'http' => defined('CURLPROTO_HTTP') ? CURLPROTO_HTTP : 0,
'https' => defined('CURLPROTO_HTTPS') ? CURLPROTO_HTTPS : 0,
'imap' => defined('CURLPROTO_IMAP') ? CURLPROTO_IMAP : 0,
'imaps' => defined('CURLPROTO_IMAPS') ? CURLPROTO_IMAPS : 0,
'ldap' => defined('CURLPROTO_LDAP') ? CURLPROTO_LDAP : 0,
'ldaps' => defined('CURLPROTO_LDAPS') ? CURLPROTO_LDAPS : 0,
'mqtt' => defined('CURLPROTO_MQTT') ? CURLPROTO_MQTT : 0,
'pop3' => defined('CURLPROTO_POP3') ? CURLPROTO_POP3 : 0,
'pop3s' => defined('CURLPROTO_POP3S') ? CURLPROTO_POP3S : 0,
'rtsp' => defined('CURLPROTO_RTSP') ? CURLPROTO_RTSP : 0,
'scp' => defined('CURLPROTO_SCP') ? CURLPROTO_SCP : 0,
'sftp' => defined('CURLPROTO_SFTP') ? CURLPROTO_SFTP : 0,
'smtp' => defined('CURLPROTO_SMTP') ? CURLPROTO_SMTP : 0,
'smtps' => defined('CURLPROTO_SMTPS') ? CURLPROTO_SMTPS : 0,
'telnet' => defined('CURLPROTO_TELNET') ? CURLPROTO_TELNET : 0,
'tftp' => defined('CURLPROTO_TFTP') ? CURLPROTO_TFTP : 0,
default => throw new Exception("Unsupported protocol: $sProtocol"),
};
}
return $iCurlProtocols;
}
/**
* Get a standard list of character sets
*

View File

@@ -35,10 +35,14 @@ class WizardHelper
public function __construct()
{
}
/**
* Constructs the PHP target object from the parameters sent to the web page by the wizard
*
* @param boolean $bReadUploadedFiles True to also read any uploaded file (for blob/document fields)
*
* @return object
* @throws CoreException
*/
public function GetTargetObject($bReadUploadedFiles = false)
{
@@ -57,7 +61,14 @@ class WizardHelper
// assumes this is handled as an array of objects
// thus encoded in json like: [ { name:'link1', 'id': 123}, { name:'link2', 'id': 124}...]
if (!is_array($value)) {
$aData = json_decode($value, true); // true means decode as a hash array (not an object)
try {
$aData = json_decode($value, associative: true, flags: JSON_THROW_ON_ERROR); // true means decode as a hash array (not an object)
} catch (JsonException $e) {
throw new CoreException('WizardHelper GetTargetObject: invalid data for linked set attribute '.$sAttCode.' of class '.$this->m_aData['m_sClass'], [
'att_code' => $sAttCode,
'linked_class' => $this->m_aData['m_sClass'],
], 'Invalid JSON data', $e);
}
} else {
$aData = $value;
}
@@ -66,9 +77,6 @@ class WizardHelper
$aFields = $this->GetLinkedWizardStructure($oAttDef);
$sLinkedClass = $oAttDef->GetLinkedClass();
$aLinkedObjectsArray = [];
if (!is_array($aData)) {
echo("aData: '$aData' (value: '$value')\n");
}
foreach ($aData as $aLinkedObject) {
$oLinkedObj = MetaModel::NewObject($sLinkedClass);
foreach ($aFields as $sLinkedAttCode) {

View File

@@ -1747,11 +1747,19 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'security.disable_mandatory_authentication_for_inline_images' => [
'type' => 'bool',
'description' => 'If true then image access does not require user authentication, provided the image\'s secret is valid. Note that setting this to true gives a less secure access to inline images!',
'default' => false,
'value' => false,
'source_of_value' => '',
'show_in_conf_sample' => false,
],
'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 +1774,16 @@ 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,
],
'security.post_requests.allowed_protocols' => [
'type' => 'string',
'description' => 'List of allowed protocols that will be used for post requests. Allowed values: dict, file, ftp, ftps, gopher, http, https, imap, imaps, ldap, ldaps, mqtt, pop3, pop3s, rtsp, scp, sftp, smtp, smtps, telnet, tftp',
'default' => 'http,https,ftp,ftps,sftp',
'value' => 'http,https,ftp,ftps,sftp',
'source_of_value' => '',
'show_in_conf_sample' => false,
],

View File

@@ -1704,7 +1704,7 @@ class DBObjectSearch extends DBSearch
* @return array|mixed|\SQLObjectQuery|null
* @throws \CoreException
*/
public function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null)
public function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null, $bSelectOnlyIds = false)
{
// Hide objects that are not visible to the current user
//
@@ -1775,6 +1775,8 @@ class DBObjectSearch extends DBSearch
$aContextData['aSelectExpr'] = $aSelectExpr;
$sRawId .= $bGetCount;
$aContextData['bGetCount'] = $bGetCount;
$sRawId .= 'ids:'.($bSelectOnlyIds ? '1' : '0');
$aContextData['bSelectOnlyIds'] = $bSelectOnlyIds;
if (is_array($aSelectedClasses)) {
$sRawId .= implode(',', $aSelectedClasses); // Unions may alter the list of selected columns
}
@@ -1828,7 +1830,7 @@ class DBObjectSearch extends DBSearch
if (!isset($oSQLQuery)) {
$oKPI = new ExecutionKPI();
$oSQLObjectQueryBuilder = new SQLObjectQueryBuilder($oSearch);
$oSQLQuery = $oSQLObjectQueryBuilder->BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr, $aSelectedClasses, $aSelectExpr);
$oSQLQuery = $oSQLObjectQueryBuilder->BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr, $aSelectedClasses, $aSelectExpr, $bSelectOnlyIds);
$oKPI->ComputeStats('BuildSQLQueryStruct', $sOqlQuery);
if (self::$m_bQueryCacheEnabled) {
@@ -1938,7 +1940,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();
}

View File

@@ -995,7 +995,7 @@ abstract class DBSearch
* @internal
*
*/
public function MakeSelectQuery($aOrderBy = [], $aArgs = [], $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false, $bBeautifulSQL = true)
public function MakeSelectQuery($aOrderBy = [], $aArgs = [], $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false, $bBeautifulSQL = true, $bSelectOnlyIds = false)
{
// Check the order by specification, and prefix with the class alias
// and make sure that the ordering columns are going to be selected
@@ -1036,7 +1036,7 @@ abstract class DBSearch
}
}
$oSQLQuery = $this->GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount);
$oSQLQuery = $this->GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, null, null, $bSelectOnlyIds);
if ($this->m_bNoContextParameters) {
// Only internal parameters
@@ -1120,7 +1120,7 @@ abstract class DBSearch
* @internal
*
*/
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null, $aSelectExpr = null)
protected function GetSQLQuery($aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null, $aSelectExpr = null, $bSelectOnlyIds = false)
{
$oSearch = $this->ApplyDataFilters();
@@ -1142,7 +1142,7 @@ abstract class DBSearch
}
}
$oSQLQuery = $oSearch->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, null, $aSelectExpr);
$oSQLQuery = $oSearch->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, null, $aSelectExpr, $bSelectOnlyIds);
$oSQLQuery->SetSourceOQL($oSearch->ToOQL());
// Join to an additional table, if required...
@@ -1177,7 +1177,8 @@ abstract class DBSearch
$bGetCount,
$aGroupByExpr = null,
$aSelectedClasses = null,
$aSelectExpr = null
$aSelectExpr = null,
$bSelectOnlyIds = false
);
/**

View File

@@ -527,10 +527,10 @@ class DBUnionSearch extends DBSearch
throw new Exception('MakeUpdateQuery is not implemented for the unions!');
}
public function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null)
public function GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null, $bSelectOnlyIds = false)
{
if (count($this->aSearches) == 1) {
return $this->aSearches[0]->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, $aSelectedClasses, $aSelectExpr);
return $this->aSearches[0]->GetSQLQueryStructure($aAttToLoad, $bGetCount, $aGroupByExpr, $aSelectedClasses, $aSelectExpr, $bSelectOnlyIds);
}
$aSQLQueries = [];
@@ -610,7 +610,7 @@ class DBUnionSearch extends DBSearch
}
}
}
$oSubQuery = $oSearch->GetSQLQueryStructure($aQueryAttToLoad, false, $aQueryGroupByExpr, $aSearchSelectedClasses, $aQuerySelectExpr);
$oSubQuery = $oSearch->GetSQLQueryStructure($aQueryAttToLoad, false, $aQueryGroupByExpr, $aSearchSelectedClasses, $aQuerySelectExpr, $bSelectOnlyIds);
if (count($aSearchAliases) > 1) {
// Necessary to make sure that selected columns will match throughout all the queries
// (default order of selected fields depending on the order of JOINS)
@@ -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();
}

File diff suppressed because it is too large Load Diff

View File

@@ -29,13 +29,14 @@ class SQLObjectQueryBuilder
* @param array $aGroupByExpr
* @param array $aSelectedClasses
* @param array $aSelectExpr
* @param bool $bSelectOnlyIds
*
* @return null|SQLObjectQuery
* @throws \CoreException
*/
public function BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null)
public function BuildSQLQueryStruct($aAttToLoad, $bGetCount, $aModifierProperties, $aGroupByExpr = null, $aSelectedClasses = null, $aSelectExpr = null, $bSelectOnlyIds = false)
{
if ($bGetCount || !is_null($aGroupByExpr)) {
if ($bGetCount || !is_null($aGroupByExpr) || $bSelectOnlyIds) {
// Avoid adding all the fields for counts or "group by" requests
$aAttToLoad = [];
foreach ($this->oDBObjetSearch->GetSelectedClasses() as $sClassAlias => $sClass) {

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2013 XXXXX
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('EN US', 'English', 'English', [

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('EN GB', 'British English', 'British English', [

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -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);

View File

@@ -29,6 +29,24 @@ require_once(APPROOT.'/application/application.inc.php');
require_once(APPROOT.'core/mutex.class.inc.php');
const BACKUP_DIR = APPROOT.'data/backups/';
class AjaxBackupException extends CoreException
{
public function __construct(array $aContextData = null, Exception $oPreviousException = null)
{
parent::__construct('Backup/Restore exception occurred', $aContextData, oPrevious: $oPreviousException);
}
}
class AjaxBackupInvalidFileException extends AjaxBackupException
{
public function __construct(array $aContextData = null, Exception $oPreviousException = null)
{
parent::__construct($aContextData, oPreviousException: $oPreviousException);
}
}
/**
* @param WebPage $oPage
* @param string $sHtmlErrorMessage the whole HTML error, cinluding div/p/...
@@ -51,73 +69,79 @@ $sOperation = utils::ReadParam('operation', '');
$oPage = new AjaxPage('');
$oPage->SetContentType('text/html');
/**
* Check security
*/
switch ($sOperation) {
/**
* Can't use normal check methods (DoLogin for ex) as the datamodel can't be loaded here
* So we're only using a token generated in the restore_token operation
*/
case 'restore_exec':
IssueLog::Enable(APPROOT.'log/error.log');
if (utils::GetConfig()->Get('demo_mode')) {
DisplayErrorAndDie(
$oPage,
'<div data-error-stimulus="Error">Sorry, '.ITOP_APPLICATION_SHORT.' is in <b>demonstration mode</b>: the feature is disabled.</div>'
);
}
$sToken = utils::ReadParam('token', '', false, 'raw_data');
$sBasePath = APPROOT.'/data/';
$sTokenFile = $sBasePath.'restore.'.$sToken.'.tok';
$tokenRealPath = utils::RealPath($sTokenFile, $sBasePath);
if (($tokenRealPath === false) || (!is_file($tokenRealPath))) {
IssueLog::Error("ajax.backup.php operation=$sOperation ERROR = inexisting token $sToken");
$sEscapedToken = utils::HtmlEntities($sToken);
DisplayErrorAndDie($oPage, "<p>Error: missing token file: '$sEscapedToken'</p>");
}
break;
default:
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin();
$sTransactionId = utils::ReadParam('transaction_id', '', true, 'transaction_id');
// the consumer page is not reloaded after download, we need to keep the transaction_id
$bRemoveTransactionId = ($sOperation !== 'download');
if (!utils::IsTransactionValid($sTransactionId, $bRemoveTransactionId)) {
$sEscapedOperation = utils::HtmlEntities($sOperation);
DisplayErrorAndDie($oPage, "<div data-error-stimulus=\"Error\">Error: invalid Transaction ID. The operation '$sEscapedOperation' was NOT performed!</div>");
}
ApplicationMenu::CheckMenuIdEnabled('BackupStatus');
if (utils::GetConfig()->Get('demo_mode')) {
DisplayErrorAndDie($oPage, '<div data-error-stimulus="Error">Sorry, '.ITOP_APPLICATION_SHORT.' is in <b>demonstration mode</b>: the feature is disabled.</div>');
}
break;
}
/**
* Backup from an interactive session
*/
try {
/**
* Check security
*/
switch ($sOperation) {
/**
* Can't use normal check methods (DoLogin for ex) as the datamodel can't be loaded here
* So we're only using a token generated in the restore_token operation
*/
case 'restore_exec':
IssueLog::Enable(APPROOT.'log/error.log');
if (utils::GetConfig()->Get('demo_mode')) {
DisplayErrorAndDie(
$oPage,
'<div data-error-stimulus="Error">Sorry, '.ITOP_APPLICATION_SHORT.' is in <b>demonstration mode</b>: the feature is disabled.</div>'
);
}
$sToken = utils::ReadParam('token', '', false, 'raw_data');
$sBasePath = APPROOT.'/data/';
$sTokenFile = $sBasePath.'restore.'.$sToken.'.tok';
$tokenRealPath = utils::RealPath($sTokenFile, $sBasePath);
if (($tokenRealPath === false) || (!is_file($tokenRealPath))) {
throw new AjaxBackupInvalidFileException([
'backup_operation' => $sOperation,
'message' => 'Could not restore backup, invalid token file.',
'token' => $sToken,
]);
}
break;
default:
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin();
$sTransactionId = utils::ReadParam('transaction_id', '', true, 'transaction_id');
// the consumer page is not reloaded after download, we need to keep the transaction_id
$bRemoveTransactionId = ($sOperation !== 'download');
if (!utils::IsTransactionValid($sTransactionId, $bRemoveTransactionId)) {
throw new AjaxBackupException([
'backup_operation' => $sOperation,
'message' => 'Invalid transaction id',
'transaction_id' => $sTransactionId,
]);
}
ApplicationMenu::CheckMenuIdEnabled('BackupStatus');
if (utils::GetConfig()->Get('demo_mode')) {
DisplayErrorAndDie($oPage, '<div data-error-stimulus="Error">Sorry, '.ITOP_APPLICATION_SHORT.' is in <b>demonstration mode</b>: the feature is disabled.</div>');
}
break;
}
/**
* Backup from an interactive session
*/
switch ($sOperation) {
case 'backup':
try {
set_time_limit(0);
$oBB = new BackupExec(APPROOT.'data/backups/manual/', 0 /*iRetentionCount*/);
$sRes = $oBB->Process(time() + 36000); // 10 hours to complete should be sufficient!
$oPage->output();
} catch (Exception $e) {
$oPage->p('Error: '.$e->getMessage());
IssueLog::Error($sOperation.' - '.$e->getMessage());
throw new AjaxBackupException([
'backup_operation' => $sOperation,
'message' => $e->getMessage(),
], $e);
}
$oPage->output();
break;
/*
@@ -138,6 +162,15 @@ try {
}
$sFile = utils::ReadParam('file', '', false, 'raw_data');
$sBackupFilePath = utils::RealPath(BACKUP_DIR.$sFile, BACKUP_DIR);
if ($sBackupFilePath === false) {
throw new AjaxBackupInvalidFileException([
'backup_operation' => $sOperation,
'message' => 'Could not restore backup, invalid file given.',
'backup_file' => $sFile,
]);
}
$sToken = str_replace(' ', '', (string)microtime()).$sTransactionId;
$sTokenFile = APPROOT.'/data/restore.'.$sToken.'.tok';
file_put_contents($sTokenFile, $sFile);
@@ -171,14 +204,15 @@ try {
$oDBRS = new DBRestore($oItopConfig);
$oDBRS->SetMySQLBinDir($sMySQLBinDir);
$sBackupDir = APPROOT.'data/backups/';
$sBackupFile = $sBackupDir.$sFile;
$sBackupFile = BACKUP_DIR.$sFile;
$sRes = $oDBRS->RestoreFromCompressedBackup($sBackupFile, $sEnvironment);
IssueLog::Info('Backup Restore - Done, releasing the LOCK');
} catch (Exception $e) {
$oPage->p('Error: '.$e->getMessage());
IssueLog::Error($sOperation.' - '.$e->getMessage());
throw new AjaxBackupException([
'backup_operation' => $sOperation,
'message' => $e->getMessage(),
], $e);
} finally {
unlink($tokenRealPath);
}
@@ -192,14 +226,33 @@ try {
}
$sFile = utils::ReadParam('file', '', false, 'raw_data');
$oBackup = new DBBackupScheduled();
$sBackupDir = APPROOT.'data/backups/';
$sBackupFilePath = utils::RealPath($sBackupDir.$sFile, $sBackupDir);
$sBackupFilePath = utils::RealPath(BACKUP_DIR.$sFile, BACKUP_DIR);
if ($sBackupFilePath === false) {
throw new CoreUnexpectedValue('Invalid file path');
throw new AjaxBackupInvalidFileException([
'backup_operation' => $sOperation,
'message' => 'Could not download backup, invalid file given.',
'backup_file' => $sFile,
]);
}
$oBackup->DownloadBackup($sBackupFilePath);
break;
}
} catch (AjaxBackupInvalidFileException $e) {
IssueLog::Warning('Unable to perform backup `'.$e->getContextData()['backup_operation'].'` : '.$e->getContextData()['message'], LogChannels::SECURITY, [
'backup_operation' => $e->getContextData()['backup_operation'] ?? null,
'backup_file' => $e->getContextData()['backup_file'] ?? null,
]);
http_response_code(422);
die($e->getContextData()['message']);
} catch (CoreException $e) {
IssueLog::Error('Unable to perform backup `'.$e->getContextData()['backup_operation'].'` : '.$e->getContextData()['message'], LogChannels::BACKUP, [
'backup_operation' => $e->getContextData()['backup_operation'] ?? null,
'backup_file' => $e->getContextData()['backup_file'] ?? null,
]);
http_response_code(500);
die(Dict::S('UI:PageTitle:FatalError'));
} catch (Exception $e) {
IssueLog::Error($sOperation.' - '.$e->getMessage());
IssueLog::Error($e->getMessage());
http_response_code(500);
die(Dict::S('UI:PageTitle:FatalError'));
}

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -443,6 +443,13 @@ function LaunchBackupNow()
window.location.reload();
}
oModal.dialog('close');
}).fail(function(xhr){
var sErrorMessage = xhr.status === 500
? (xhr.responseText || 'Erreur serveur (HTTP 500).')
: (xhr.responseText || 'Erreur HTTP ' + xhr.status + '.');
$('#backup_errors').text(sErrorMessage);
$('#backup_errors').removeClass('ibo-is-hidden');
oModal.dialog('close');
});
}
}
@@ -487,11 +494,25 @@ function LaunchRestoreNow(sBackupFile, sConfirmationMessage)
$('#backup_success').removeClass('ibo-is-hidden');
}
oModal.dialog('close');
}).fail(function(xhr){
var sErrorMessage = xhr.status === 500
? (xhr.responseText || 'Erreur serveur (HTTP 500).')
: (xhr.responseText || 'Erreur HTTP ' + xhr.status + '.');
$('#backup_errors').text(sErrorMessage);
$('#backup_errors').removeClass('ibo-is-hidden');
oModal.dialog('close');
});
} else {
$('button.restore').prop('disabled', true);
oModal.dialog('close');
}
}).fail(function(xhr){
var sErrorMessage = xhr.status === 500
? (xhr.responseText || 'Erreur serveur (HTTP 500).')
: (xhr.responseText || 'Erreur HTTP ' + xhr.status + '.');
$('#backup_errors').text(sErrorMessage);
$('#backup_errors').removeClass('ibo-is-hidden');
oModal.dialog('close');
});
}
JS

View File

@@ -19,7 +19,7 @@
/**
* @author Benjamin Planque <benjamin.planque@combodo.com>
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*/
//////////////////////////////////////////////////////////////////////

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*/
//////////////////////////////////////////////////////////////////////

View File

@@ -19,7 +19,7 @@
/**
* @author Benjamin Planque <benjamin.planque@combodo.com>
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*/
//////////////////////////////////////////////////////////////////////

View File

@@ -19,7 +19,7 @@
/**
* @author Benjamin Planque <benjamin.planque@combodo.com>
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*/
//////////////////////////////////////////////////////////////////////

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

View File

@@ -4,7 +4,7 @@
* Localized data
*
* @copyright Copyright (C) 2010-2024 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
* @license https://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*

Some files were not shown because too many files have changed in this diff Show More