mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-03-12 20:18:02 -04:00
* Fix second-order SQL injection in currency_symbol config The currency_symbol value was concatenated directly into SQL queries without proper escaping, allowing SQL injection attacks via the Summary Discounts report. Changes: - Use $this->db->escape() in Summary_discounts::getData() to properly escape the currency symbol value before concatenation - Add htmlspecialchars() validation in Config::postSaveLocale() to sanitize the input at storage time - Add unit tests to verify escaping of malicious inputs Fixes SQL injection vulnerability described in bug report where attackers with config permissions could inject arbitrary SQL through the currency_symbol field. * Update test to use CIUnitTestCase for consistency Per code review feedback, updated test to extend CIUnitTestCase instead of PHPUnit TestCase to maintain consistency with other tests in the codebase. --------- Co-authored-by: Ollama <ollama@steganos.dev>
50 lines
1.6 KiB
PHP
50 lines
1.6 KiB
PHP
<?php
|
|
|
|
namespace App\Models\Reports;
|
|
|
|
use Config\OSPOS;
|
|
|
|
class Summary_discounts extends Summary_report
|
|
{
|
|
/**
|
|
* @return array[]
|
|
*/
|
|
protected function _get_data_columns(): array // TODO: Hungarian notation
|
|
{
|
|
return [
|
|
['discount' => lang('Reports.discount'), 'sorter' => 'number_sorter'],
|
|
['count' => lang('Reports.count')],
|
|
['total' => lang('Reports.total')]
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array $inputs
|
|
* @return array
|
|
*/
|
|
public function getData(array $inputs): array
|
|
{
|
|
$config = config(OSPOS::class)->settings;
|
|
$builder = $this->db->table('sales_items AS sales_items');
|
|
|
|
if ($inputs['discount_type'] == FIXED) {
|
|
$currency_symbol = $this->db->escape($config['currency_symbol']);
|
|
$builder->select('SUM(sales_items.discount) AS total, MAX(CONCAT(' . $currency_symbol . ', sales_items.discount)) AS discount, count(*) AS count');
|
|
$builder->where('discount_type', FIXED);
|
|
} elseif ($inputs['discount_type'] == PERCENT) {
|
|
$builder->select('SUM(item_unit_price) * sales_items.discount / 100.0 AS total, MAX(CONCAT(sales_items.discount, "%")) AS discount, count(*) AS count');
|
|
$builder->where('discount_type', PERCENT);
|
|
}
|
|
|
|
$builder->where('discount >', 0);
|
|
$builder->groupBy('sales_items.discount');
|
|
$builder->orderBy('sales_items.discount');
|
|
|
|
$builder->join('sales AS sales', 'sales_items.sale_id = sales.sale_id', 'inner');
|
|
|
|
$this->_where($inputs, $builder); // TODO: Hungarian notation
|
|
|
|
return $builder->get()->getResultArray();
|
|
}
|
|
}
|