diff --git a/.gitignore b/.gitignore index b5bdab5..d8c819c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ dist/ node_modules/ vendor/ .gh_token +.phpunit.result.cache diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e35e73..cd74d30 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased] + +### Fixed + +- Validate entity access in consumeVoucher before recording + ## [1.14.2] - 2026-06-24 ### Fixed diff --git a/inc/ticket.class.php b/inc/ticket.class.php index d6ab675..af118dd 100644 --- a/inc/ticket.class.php +++ b/inc/ticket.class.php @@ -612,7 +612,18 @@ public static function consumeVoucher(CommonDBTM $item) $credit_ticket = new self(); $credit_entity = new PluginCreditEntity(); - $credit_entity->getFromDB($item->input['plugin_credit_entities_id']); + if (!$credit_entity->getFromDB($item->input['plugin_credit_entities_id'])) { + return; + } + + if (!Session::haveAccessToEntity($credit_entity->getField('entities_id'), $credit_entity->getField('is_recursive'))) { + Session::addMessageAfterRedirect( + __('You are not allowed to consume credits from the selected entity', 'credit'), + true, + ERROR + ); + return; + } $quantity_sold = (int)$credit_entity->fields['quantity']; $quantity_consumed = $credit_ticket->getConsumedForCreditEntity($item->input['plugin_credit_entities_id']); diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..e9f60d9 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,7 @@ + + + + tests/Units + + + diff --git a/tests/Units/ConsumeVoucherTest.php b/tests/Units/ConsumeVoucherTest.php new file mode 100644 index 0000000..235e907 --- /dev/null +++ b/tests/Units/ConsumeVoucherTest.php @@ -0,0 +1,91 @@ +. + * ------------------------------------------------------------------------- + * @author François Legastelois + * @copyright Copyright (C) 2017-2023 by Credit plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/credit + * ------------------------------------------------------------------------- + */ + +namespace GlpiPlugin\Credit\Tests\Units; + +use Entity; +use Glpi\Tests\DbTestCase; +use ITILFollowup; +use PluginCreditEntity; +use PluginCreditTicket; +use Session; +use Ticket; + +final class ConsumeVoucherTest extends DbTestCase +{ + public function testVoucherConsumptionIsRejectedWhenCreditEntityIsNotAccessible(): void + { + $this->login(); + + $accessible_entity_id = $this->createItem(Entity::class, [ + 'name' => 'Accessible entity', + 'entities_id' => 0, + ])->getID(); + + $restricted_entity_id = $this->createItem(Entity::class, [ + 'name' => 'Restricted entity', + 'entities_id' => 0, + ])->getID(); + + $credit_entity_id = $this->createItem(PluginCreditEntity::class, [ + 'name' => 'Restricted credit voucher', + 'entities_id' => $restricted_entity_id, + 'is_recursive' => 0, + 'is_active' => 1, + 'quantity' => 10, + ])->getID(); + + $ticket_id = $this->createItem(Ticket::class, [ + 'name' => 'Consume voucher test', + 'content' => 'Test', + 'entities_id' => $accessible_entity_id, + ])->getID(); + + $this->assertTrue(Session::changeActiveEntities($accessible_entity_id)); + + $followup = new ITILFollowup(); + $followup_id = $followup->add([ + 'itemtype' => Ticket::class, + 'items_id' => $ticket_id, + 'content' => 'Followup consuming a voucher from an inaccessible entity', + 'plugin_credit_consumed_voucher' => 1, + 'plugin_credit_entities_id' => $credit_entity_id, + 'plugin_credit_quantity' => 1, + ]); + $this->assertGreaterThan(0, $followup_id); + + $credit_ticket = new PluginCreditTicket(); + $this->assertFalse( + $credit_ticket->getFromDBByCrit(['tickets_id' => $ticket_id]), + 'Voucher consumption must not be recorded when the credit entity is outside the accessible entities' + ); + } +} diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 0000000..7205715 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,40 @@ +. + * ------------------------------------------------------------------------- + * @author François Legastelois + * @copyright Copyright (C) 2017-2023 by Credit plugin team. + * @license GPLv3 https://www.gnu.org/licenses/gpl-3.0.html + * @link https://github.com/pluginsGLPI/credit + * ------------------------------------------------------------------------- + */ + +require __DIR__ . '/../../../tests/bootstrap.php'; + +if (file_exists(__DIR__ . '/../vendor/autoload.php')) { + require __DIR__ . '/../vendor/autoload.php'; +} + +if (!Plugin::isPluginActive('credit')) { + throw new RuntimeException('Plugin credit is not active in the test database'); +}