Files
opensourcepos/tests/Controllers/ItemKitsControllerTest.php
T
objecttothis d63d31700d Ensure payload data is escaped to prevent XSS (#4664)
fix(barcode): escape payload fields to prevent XSS; PSR-12 refactor

- Apply `esc()` to name, ID, item number, category, and company name in `Barcode_lib` payloads
- Remove redundant `urldecode()` in `Item_kitsController` to prevent triple decoding
- Rename variables and methods to camelCase across barcode, item_kits, and tests
- Add type hint for `$layoutType` parameter in `manageDisplayLayout`
- Add/update unit tests covering escaping and HTTP response assertions

Signed-off-by: objecttothis <17935339+objecttothis@users.noreply.github.com>
2026-08-28 10:08:31 +04:00

140 lines
4.3 KiB
PHP

<?php
namespace Tests\Controllers;
use CodeIgniter\Config\Factories;
use CodeIgniter\Database\Config;
use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;
use CodeIgniter\Test\FeatureTestTrait;
use App\Models\Item;
use App\Models\Item_kit;
use Config\OSPOS;
use Exception;
class ItemKitsControllerTest extends CIUnitTestCase
{
use DatabaseTestTrait;
use FeatureTestTrait;
protected $migrate = true;
protected $migrateOnce = true;
protected $seedOnce = true;
protected $refresh = false;
protected $namespace = null;
private static bool $doneBootstrap = false;
protected Item $item;
protected Item_kit $itemKit;
protected function setUp(): void
{
if (self::$doneBootstrap === false) {
Config::seeder($this->DBGroup)->call('App\Database\Seeds\TestDatabaseBootstrapSeeder');
Config::connect($this->DBGroup)->close();
self::$doneBootstrap = true;
}
parent::setUp();
$ospos = new OSPOS();
$ospos->settings = [
'company' => 'Test Co',
'barcode_content' => 'id',
'barcode_type' => 'C128',
'barcode_font' => 'inconsolata.ttf',
'barcode_font_size' => 10,
'barcode_height' => 40,
'barcode_width' => 2,
'barcode_first_row' => 'item_code',
'barcode_second_row' => 'none',
'barcode_third_row' => 'none',
'barcode_num_in_row' => 1,
'barcode_page_width' => 8,
'barcode_page_cellspacing' => 1,
'barcode_generate_if_empty' => 0,
'barcode_formats' => 'null',
];
Factories::injectMock('config', OSPOS::class, $ospos);
$this->item = model(Item::class);
$this->itemKit = model(Item_kit::class);
}
protected function tearDown(): void
{
Factories::reset();
parent::tearDown();
}
protected function loginAsAdmin(): void
{
$this->withSession([
'person_id' => 1,
'menu_group' => 'office'
]);
}
private function createItemKit(): int
{
$itemData = [
'item_id' => null,
'name' => 'Kit Base Item',
'category' => 'Test',
'cost_price' => 10.00,
'unit_price' => 20.00,
'deleted' => 0
];
$this->assertTrue($this->item->save_value($itemData));
$itemKitData = [
'name' => 'Test Kit',
'description' => 'Test Kit Description',
'item_id' => $itemData['item_id'],
'kit_discount' => 0,
'kit_discount_type' => 0,
'price_option' => 0,
'print_option' => 0
];
$this->assertTrue($this->itemKit->save_value($itemKitData));
return (int) $itemKitData['item_kit_id'];
}
/**
* @throws Exception
*/
public function testGenerateBarcodesDoesNotDecodeTripleEncodedPayload(): void
{
$itemKitId = $this->createItemKit();
$this->loginAsAdmin();
// <svg onload=alert(document.domain)> URL-encoded three times (GHSA-3vpv-jqr3-7256 PoC).
// The framework's router decodes this twice before routing; the controller used to apply
// a third urldecode(), turning the remaining %3C.../%3E into a live <svg onload=...> tag.
// With that urldecode() removed, the value must stay percent-encoded text and never
// become a raw '<' in the response.
$payload = $itemKitId . '%25253Csvg%252520onload%25253Dalert%252528document.domain%252529%25253E';
$response = $this->get('/item_kits/generateBarcodes/' . $payload);
$response->assertStatus(200);
$body = $response->getBody();
$this->assertStringNotContainsString('<svg onload', $body);
$this->assertStringContainsString('%3Csvg', $body);
}
public function testGenerateBarcodesWorksForPlainItemKitId(): void
{
$itemKitId = $this->createItemKit();
$this->loginAsAdmin();
$response = $this->get('/item_kits/generateBarcodes/' . $itemKitId);
$response->assertStatus(200);
$this->assertStringContainsString('KIT ' . $itemKitId, $response->getBody());
}
}