fix(security): implement WASA compliance hardening and vulnerability remediation

This commit is contained in:
DevSoftTech Server 2026-10-14 10:27:32 +05:30
parent ec377dafcd
commit 81f3501157
23 changed files with 266 additions and 1019 deletions

1
.gitignore vendored
View File

@ -141,6 +141,7 @@ NiceAdmin-pro/
public/uploads/*
!public/uploads/.gitkeep
!public/uploads/.htaccess
# Always allow branding assets to be committed when present
!public/assets/

View File

@ -221,7 +221,7 @@ class App extends BaseConfig
* secure, the user will be redirected to a secure version of the page
* and the HTTP Strict Transport Security (HSTS) header will be set.
*/
public bool $forceGlobalSecureRequests = false;
public bool $forceGlobalSecureRequests = (ENVIRONMENT === 'production');
/**
* --------------------------------------------------------------------------

View File

@ -56,6 +56,15 @@ class Cookie extends BaseConfig
*/
public bool $secure = false;
public function __construct()
{
parent::__construct();
if (ENVIRONMENT === 'production' || (! empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')) {
$this->secure = true;
}
}
/**
* --------------------------------------------------------------------------
* Cookie HTTPOnly

View File

@ -74,25 +74,23 @@ class Filters extends BaseFilters
public array $globals = [
'before' => [
'singleSession',
'invalidchars',
'csrf' => [
'except' => [
'api/*',
'AbdmGateway/*',
'AbdmHiu/*',
'HealthplixCallback/*',
'HealthplixGateway/*',
'stt-proxy',
'stt-proxy/*',
],
],
// 'honeypot',
// 'csrf',
// 'invalidchars',
],
'after' => [
'toolbar' => [
'except' => [
'Opd/*',
'Opd_prescription/*',
'billing/patient/abdm_*',
'billing/patient/abdm_*/*',
'AbdmHiu',
'AbdmHiu/*',
'AbdmGateway/*',
'api/*',
],
],
'secureheaders',
// 'honeypot',
// 'secureheaders',
],
];

View File

@ -24,7 +24,7 @@ class Security extends BaseConfig
*
* Randomize the CSRF Token for added security.
*/
public bool $tokenRandomize = false;
public bool $tokenRandomize = true;
/**
* --------------------------------------------------------------------------

View File

@ -90,7 +90,7 @@ class Session extends BaseConfig
* when auto-regenerating the session ID. When set to FALSE, the data
* will be later deleted by the garbage collector.
*/
public bool $regenerateDestroy = false;
public bool $regenerateDestroy = true;
/**
* --------------------------------------------------------------------------

View File

@ -33,11 +33,27 @@ class AbdmFhirInspector extends BaseController
}
}
private function ensureAuthenticated()
{
if (! function_exists('auth') || ! auth()->loggedIn()) {
if ($this->request->isAJAX() || str_contains((string) $this->request->getHeaderLine('Accept'), 'application/json')) {
return $this->response->setStatusCode(401)->setJSON(['ok' => 0, 'error' => 'Authentication required']);
}
return redirect()->to(base_url('login'))->with('error', 'Please log in to access the FHIR Inspector.');
}
return null;
}
/**
* Main page view for ABHA Filter & FHIR Inspector
*/
public function index()
{
if ($deny = $this->ensureAuthenticated()) {
return $deny;
}
$filterAbha = trim((string) ($this->request->getGet('abha_address') ?? $this->request->getGet('abha') ?? ''));
$patientId = (int) ($this->request->getGet('patient_id') ?? $this->request->getGet('id') ?? 0);
$uhid = trim((string) ($this->request->getGet('uhid') ?? ''));
@ -59,6 +75,10 @@ class AbdmFhirInspector extends BaseController
*/
public function patientData()
{
if ($deny = $this->ensureAuthenticated()) {
return $deny;
}
$patientId = (int) ($this->request->getGet('patient_id') ?? 0);
$abhaAddress = trim((string) ($this->request->getGet('abha_address') ?? $this->request->getGet('abha') ?? ''));
$pCode = trim((string) ($this->request->getGet('p_code') ?? $this->request->getGet('uhid') ?? ''));
@ -87,6 +107,10 @@ class AbdmFhirInspector extends BaseController
*/
public function gatewayCheck()
{
if ($deny = $this->ensureAuthenticated()) {
return $deny;
}
$abha = trim((string) ($this->request->getGet('abha_address') ?? $this->request->getGet('abha') ?? ''));
if ($abha === '') {
return $this->response->setJSON(['ok' => 0, 'error_text' => 'ABHA address is required']);
@ -131,6 +155,10 @@ class AbdmFhirInspector extends BaseController
*/
public function previewBundle()
{
if ($deny = $this->ensureAuthenticated()) {
return $deny;
}
$ref = trim((string) ($this->request->getGet('ref') ?? $this->request->getPost('ref') ?? $_GET['ref'] ?? $_REQUEST['ref'] ?? ''));
$patientId = (int) ($this->request->getGet('patient_id') ?? $this->request->getPost('patient_id') ?? $_GET['patient_id'] ?? $_REQUEST['patient_id'] ?? 0);
$abha = trim((string) ($this->request->getGet('abha') ?? $this->request->getPost('abha') ?? $_GET['abha'] ?? $_REQUEST['abha'] ?? ''));

View File

@ -104,12 +104,29 @@ class DoctorApi extends BaseController
]);
}
$clientIp = (string) $this->request->getIPAddress();
$rateKey = 'doc_pin_' . md5($clientIp . '_' . $docId);
$cache = service('cache');
$failedAttempts = (int) ($cache->get($rateKey) ?? 0);
if ($failedAttempts >= 5) {
return $this->response->setStatusCode(429)->setJSON([
'status' => 0,
'message' => 'Too many failed PIN attempts. Account temporarily locked for 10 minutes.',
]);
}
$isValid = password_verify($pin, $hashedPin) || ($pin === $hashedPin);
if (! $isValid) {
$cache->save($rateKey, $failedAttempts + 1, 600);
return $this->response->setStatusCode(401)->setJSON(['status' => 0, 'message' => 'Incorrect Security PIN']);
}
$cache->delete($rateKey);
if (session_status() === PHP_SESSION_ACTIVE || ! session_id()) {
session()->set('pwa_auth_doctor_id', (int) $doctorRow->id);
}
return $this->response->setJSON([
'status' => 1,
'message' => 'Authentication successful',

View File

@ -150,12 +150,29 @@ class NursingApi extends BaseController
]);
}
$clientIp = (string) $this->request->getIPAddress();
$rateKey = 'nurse_pin_' . md5($clientIp . '_' . ($nurseRow['id'] ?? 0));
$cache = service('cache');
$failedAttempts = (int) ($cache->get($rateKey) ?? 0);
if ($failedAttempts >= 5) {
return $this->response->setStatusCode(429)->setJSON([
'status' => 0,
'message' => 'Too many failed PIN attempts. Account temporarily locked for 10 minutes.',
]);
}
$isValid = password_verify($pin, $hashedPin) || ($pin === $hashedPin);
if (! $isValid) {
$cache->save($rateKey, $failedAttempts + 1, 600);
return $this->response->setStatusCode(401)->setJSON(['status' => 0, 'message' => 'Incorrect Security PIN']);
}
$cache->delete($rateKey);
if (session_status() === PHP_SESSION_ACTIVE || ! session_id()) {
session()->set('pwa_auth_nurse_id', (int) $nurseRow['id']);
}
return $this->response->setJSON([
'status' => 1,
'message' => 'Authentication successful',

View File

@ -706,9 +706,9 @@ class CaseMaster extends BaseController
$invoiceId = (int) $invoiceItem[0]->inv_master_id;
}
$data['invoiceDetails'] = $this->db->query('select i.*,t.group_desc from invoice_item i join hc_item_type t on i.item_type=t.itype_id where i.inv_master_id=' . $invoiceId)->getResult();
$data['invoiceDetails'] = $this->db->query('select i.*,t.group_desc from invoice_item i join hc_item_type t on i.item_type=t.itype_id where i.inv_master_id = ?', [$invoiceId])->getResult();
$data['invoiceGtotal'] = $this->db->table('invoice_item')->selectSum('item_amount', 'Gtotal')->where('inv_master_id', $invoiceId)->get()->getResult();
$data['invoice_master'] = $this->db->query("select *,(case payment_mode when 1 Then 'Cash' when 2 then 'Bank Card' when 3 then 'IPD Credit' when 4 then 'Org. Credit' else 'Pending' end) as Payment_type_str from invoice_master where id=" . $invoiceId)->getResult();
$data['invoice_master'] = $this->db->query("select *,(case payment_mode when 1 Then 'Cash' when 2 then 'Bank Card' when 3 then 'IPD Credit' when 4 then 'Org. Credit' else 'Pending' end) as Payment_type_str from invoice_master where id = ?", [$invoiceId])->getResult();
$discountAmount = (float) ($data['invoice_master'][0]->discount_amount ?? 0);
$correctionAmount = (float) ($data['invoice_master'][0]->correction_amount ?? 0);
@ -1131,18 +1131,18 @@ class CaseMaster extends BaseController
$data['MedInvoice'] = $this->db->query('select sum(m.net_amount) as Med_Amount,o.id ,count(m.id) as no_inv
from invoice_med_master m join ipd_master p join organization_case_master o
on m.ipd_id=p.id and p.case_id=o.id and m.ipd_credit=1 and m.ipd_credit_type=1
where o.id=' . $caseid . ' group by o.id')->getResult();
where o.id = ? group by o.id', [$caseid])->getResult();
$data['ipd_package'] = $this->db->query('SELECT p.* FROM ipd_package p JOIN ipd_master m ON p.ipd_id=m.id WHERE m.case_id=' . $caseid)->getResult();
$data['ipd_package'] = $this->db->query('SELECT p.* FROM ipd_package p JOIN ipd_master m ON p.ipd_id=m.id WHERE m.case_id = ?', [$caseid])->getResult();
if (count($data['MedInvoice']) === 0) {
$data['MedInvoice'] = $this->db->query('select sum(m.net_amount) as Med_Amount,o.id ,count(m.id) as no_inv
from invoice_med_master m join organization_case_master o
on m.case_id=o.id and m.case_credit=1
where o.id=' . $caseid . ' group by o.id')->getResult();
where o.id = ? group by o.id', [$caseid])->getResult();
}
$ipdMaster = $this->db->query('select p.* from ipd_master p join organization_case_master o on p.case_id=o.id where o.id=' . $caseid)->getResult();
$ipdMaster = $this->db->query('select p.* from ipd_master p join organization_case_master o on p.case_id=o.id where o.id = ?', [$caseid])->getResult();
$tableHead = '<table border="1" cellpadding="1" cellspacing="0" style="width:100%">'
. '<tr><th style="width:50px">Sr.No.</th><th style="width:100px">Date</th><th>Details of Expenditure</th><th colspan="2">Number or Quantity</th><th style="width:100px;align:right;">Rate</th><th style="width:100px;align:right;">Per</th><th style="width:100px;align:right;">Amount</th></tr>';
@ -1284,10 +1284,10 @@ class CaseMaster extends BaseController
$orgId = (int) $data['org_info'][0]->id;
$data['ipd_info'] = $this->db->query("select * from v_ipd_list where org_id='" . $orgId . "' ")->getResult();
$data['ipd_info'] = $this->db->query("select * from v_ipd_list where org_id = ?", [$orgId])->getResult();
$sql = "select *,if(gender=1,'Male','Female') as xgender from patient_master where id='" . $data['org_info'][0]->p_id . "' ";
$data['person_info'] = $this->db->query($sql)->getResult();
$sql = "select *,if(gender=1,'Male','Female') as xgender from patient_master where id = ?";
$data['person_info'] = $this->db->query($sql, [$data['org_info'][0]->p_id])->getResult();
$this->applyAge($data['person_info'], 'str_age');
return view('Invoice/org_case_payment', $data);
@ -1295,17 +1295,17 @@ class CaseMaster extends BaseController
public function load_model_box(string $caseidcode)
{
$data['org_info'] = $this->db->query("select * from organization_case_master where case_id_code='" . $caseidcode . "' ")->getResult();
$data['org_info'] = $this->db->query("select * from organization_case_master where case_id_code = ?", [$caseidcode])->getResult();
if (empty($data['org_info'])) {
return $this->response->setStatusCode(404)->setBody('Case not found');
}
$orgId = (int) $data['org_info'][0]->id;
$data['ipd_info'] = $this->db->query("select * from v_ipd_list where org_id='" . $orgId . "' ")->getResult();
$data['ipd_info'] = $this->db->query("select * from v_ipd_list where org_id = ?", [$orgId])->getResult();
$sql = "select *,if(gender=1,'Male','Female') as xgender from patient_master where id='" . $data['org_info'][0]->p_id . "' ";
$data['person_info'] = $this->db->query($sql)->getResult();
$sql = "select *,if(gender=1,'Male','Female') as xgender from patient_master where id = ?";
$data['person_info'] = $this->db->query($sql, [$data['org_info'][0]->p_id])->getResult();
$this->applyAge($data['person_info'], 'str_age');
return view('Invoice/org_case_payment', $data);
@ -1340,7 +1340,7 @@ class CaseMaster extends BaseController
if (! empty($orgInfo)) {
$patientId = (int) $orgInfo[0]->p_id;
$personInfo = $this->db->query("select *,if(gender=1,'Male','Female') as xgender from patient_master where id='" . $patientId . "' ")->getResult();
$personInfo = $this->db->query("select *,if(gender=1,'Male','Female') as xgender from patient_master where id = ?", [$patientId])->getResult();
$this->applyAge($personInfo, 'str_age');
$orgDate = $orgInfo[0]->insert_datetime;
$patientName = $personInfo[0]->p_fname ?? '';
@ -1403,7 +1403,7 @@ class CaseMaster extends BaseController
if (! empty($orgInfo)) {
$patientId = (int) $orgInfo[0]->p_id;
$personInfo = $this->db->query("select *,if(gender=1,'Male','Female') as xgender from patient_master where id='" . $patientId . "' ")->getResult();
$personInfo = $this->db->query("select *,if(gender=1,'Male','Female') as xgender from patient_master where id = ?", [$patientId])->getResult();
$this->applyAge($personInfo, 'str_age');
$orgDate = $orgInfo[0]->insert_datetime;
$patientName = $personInfo[0]->p_fname ?? '';

View File

@ -512,15 +512,31 @@ class DoctorDocument extends BaseController
}
$origName = $file->getClientName();
$ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION) ?: 'pdf');
$ext = strtolower(pathinfo($origName, PATHINFO_EXTENSION) ?: '');
$allowedExts = ['pdf', 'jpg', 'jpeg', 'png', 'webp'];
if (! in_array($ext, $allowedExts, true)) {
return $this->response->setStatusCode(400)->setJSON([
'status' => 'error',
'message' => 'Invalid file format. Only PDF, JPG, PNG, and WEBP files are allowed.',
]);
}
$mimeType = $file->getClientMimeType() ?: 'application/pdf';
$allowedMimes = ['application/pdf', 'image/jpeg', 'image/png', 'image/webp'];
if (! in_array($mimeType, $allowedMimes, true)) {
return $this->response->setStatusCode(400)->setJSON([
'status' => 'error',
'message' => 'Invalid file type. Only PDF and image uploads are permitted.',
]);
}
$uploadDir = FCPATH . 'uploads' . DIRECTORY_SEPARATOR . 'nabh_ipd' . DIRECTORY_SEPARATOR;
if (! is_dir($uploadDir)) {
@mkdir($uploadDir, 0755, true);
}
$newFileName = 'NABH_IPD_' . $ipdId . '_' . str_replace('-', '_', $nabhCategory) . '_' . date('Ymd_His') . '.' . $ext;
$safeCategory = preg_replace('/[^A-Za-z0-9_]/', '_', $nabhCategory);
$newFileName = 'NABH_IPD_' . $ipdId . '_' . $safeCategory . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
$file->move($uploadDir, $newFileName);
$fileFullPath = $uploadDir . $newFileName;

View File

@ -12,9 +12,9 @@ class HealthplixCallback extends BaseController
$expectedSecret = $this->resolveExpectedSecret();
$providedSecret = trim((string) $this->request->getHeaderLine('X-Healthplix-Secret'));
if ($expectedSecret !== '' && ! hash_equals($expectedSecret, $providedSecret)) {
if ($expectedSecret === '' || ! hash_equals($expectedSecret, $providedSecret)) {
$this->logFetchEvent('error', 401, [
'message' => 'Invalid callback secret',
'message' => 'Missing or invalid callback secret',
'payload_bytes' => strlen($rawBody),
'payload_keys' => array_keys($payload),
], 'Unauthorized callback request');

View File

@ -6,8 +6,21 @@ use App\Libraries\HealthplixService;
class HealthplixGateway extends BaseController
{
private function ensureAuthenticated()
{
if (! function_exists('auth') || ! auth()->loggedIn()) {
return $this->response->setStatusCode(401)->setJSON(['ok' => 0, 'error_text' => 'Authentication required']);
}
return null;
}
public function generateToken()
{
if ($deny = $this->ensureAuthenticated()) {
return $deny;
}
if (! $this->request->isAJAX()) {
return $this->response->setStatusCode(400)->setJSON(['ok' => 0, 'error_text' => 'Invalid request']);
}
@ -30,6 +43,10 @@ class HealthplixGateway extends BaseController
public function registerPatient()
{
if ($deny = $this->ensureAuthenticated()) {
return $deny;
}
if (! $this->request->isAJAX()) {
return $this->response->setStatusCode(400)->setJSON(['ok' => 0, 'error_text' => 'Invalid request']);
}
@ -61,6 +78,10 @@ class HealthplixGateway extends BaseController
public function bookAppointment()
{
if ($deny = $this->ensureAuthenticated()) {
return $deny;
}
if (! $this->request->isAJAX()) {
return $this->response->setStatusCode(400)->setJSON(['ok' => 0, 'error_text' => 'Invalid request']);
}

View File

@ -79,8 +79,8 @@ class OcasePathLap extends BaseController
public function showinvoice(int $invoiceId)
{
$sql = 'select i.*,t.desc from invoice_item i join hc_item_type t on i.item_type=t.itype_id where i.inv_master_id=' . $invoiceId;
$data['invoiceDetails'] = $this->db->query($sql)->getResult();
$sql = 'select i.*,t.desc from invoice_item i join hc_item_type t on i.item_type=t.itype_id where i.inv_master_id = ?';
$data['invoiceDetails'] = $this->db->query($sql, [$invoiceId])->getResult();
$data['invoiceGtotal'] = $this->db->table('invoice_item')
->selectSum('item_amount', 'Gtotal')
@ -97,8 +97,8 @@ class OcasePathLap extends BaseController
return $this->response->setStatusCode(404)->setBody('Invoice not found');
}
$sql = 'select *,if(gender=1,\'Male\',\'Female\') as xgender from patient_master where id=' . (int) $data['invoice_master'][0]->attach_id;
$data['patient_master'] = $this->db->query($sql)->getResult();
$sql = 'select *,if(gender=1,\'Male\',\'Female\') as xgender from patient_master where id = ?';
$data['patient_master'] = $this->db->query($sql, [(int) $data['invoice_master'][0]->attach_id])->getResult();
$this->applyAge($data['patient_master']);
$insCompId = (int) $data['invoice_master'][0]->insurance_id;
@ -119,7 +119,7 @@ class OcasePathLap extends BaseController
->get()
->getResult();
$data['payment_history'] = $this->db->query('select sum(if(credit_debit>0,amount*-1,amount)) as paid_amount from payment_history where payof_type=2 and payof_id=' . $invoiceId)->getResult();
$data['payment_history'] = $this->db->query('select sum(if(credit_debit>0,amount*-1,amount)) as paid_amount from payment_history where payof_type=2 and payof_id = ?', [$invoiceId])->getResult();
$discountAmount = (float) $data['invoice_master'][0]->discount_amount;
$totalAmount = (float) ($data['invoiceGtotal'][0]->Gtotal ?? 0);
@ -378,7 +378,7 @@ class OcasePathLap extends BaseController
->get()
->getResult();
$data['payment_history'] = $this->db->query('select *,(case payment_mode when 1 Then \'cash\' when 2 then \'Bank Card\' when 3 then \'Org Credit\' else \'Pending\' end) as Payment_type_str from payment_history where payof_type=2 and payof_id=' . $invoiceId)->getResult();
$data['payment_history'] = $this->db->query('select *,(case payment_mode when 1 Then \'cash\' when 2 then \'Bank Card\' when 3 then \'Org Credit\' else \'Pending\' end) as Payment_type_str from payment_history where payof_type=2 and payof_id = ?', [$invoiceId])->getResult();
return view('Invoice/Organization_invoice_print_v', $data);
}

View File

@ -3859,6 +3859,11 @@ class Patient extends BaseController
$file = $this->request->getFile('upload_file');
if ($file && $file->isValid() && !$file->hasMoved()) {
$ext = strtolower((string) ($file->getClientExtension() ?: pathinfo((string) $file->getName(), PATHINFO_EXTENSION)));
$allowedExts = ['pdf', 'jpg', 'jpeg', 'png', 'webp', 'doc', 'docx'];
if (! in_array($ext, $allowedExts, true)) {
$message = 'Invalid file format. Upload PDF, image, or document only.';
} else {
$uploadPath = rtrim(FCPATH, '\\/') . '/uploads/patient';
if (!is_dir($uploadPath)) {
mkdir($uploadPath, 0755, true);
@ -3879,6 +3884,7 @@ class Patient extends BaseController
} else {
$message = 'Unable to save the file.';
}
}
} elseif ($file && !$file->isValid()) {
$message = $file->getErrorString();
}

View File

@ -7,8 +7,40 @@ use App\Libraries\SystemOperations;
class SystemOps extends BaseController
{
public function index(): string
private function ensureAdminAccess()
{
if (! function_exists('auth') || ! auth()->loggedIn()) {
if ($this->request->isAJAX() || str_contains((string) $this->request->getHeaderLine('Accept'), 'application/json')) {
return $this->response->setStatusCode(401)->setJSON(['ok' => 0, 'error' => 'Authentication required']);
}
return redirect()->to(base_url('login'))->with('error', 'Authentication required.');
}
$user = auth()->user();
$isAllowed = false;
if ($user && method_exists($user, 'inGroup')) {
$isAllowed = $user->inGroup('superadmin', 'admin', 'developer');
}
if (! $isAllowed && $user && method_exists($user, 'can')) {
$isAllowed = $user->can('admin.settings');
}
if (! $isAllowed) {
if ($this->request->isAJAX() || str_contains((string) $this->request->getHeaderLine('Accept'), 'application/json')) {
return $this->response->setStatusCode(403)->setJSON(['ok' => 0, 'error' => 'Administrative privileges required']);
}
return $this->response->setStatusCode(403)->setBody('Access denied. Administrator privileges required.');
}
return null;
}
public function index()
{
if ($deny = $this->ensureAdminAccess()) {
return $deny;
}
$ops = new SystemOperations();
$data = [
'status' => $ops->collectStatus(),
@ -18,8 +50,12 @@ class SystemOps extends BaseController
return view('Setting/Admin/system_ops', $data);
}
public function panel(): string
public function panel()
{
if ($deny = $this->ensureAdminAccess()) {
return $deny;
}
$ops = new SystemOperations();
$data = [
'status' => $ops->collectStatus(),
@ -31,6 +67,10 @@ class SystemOps extends BaseController
public function updateDirect()
{
if ($deny = $this->ensureAdminAccess()) {
return $deny;
}
$ops = new SystemOperations();
$result = $ops->runUpdateDirect();
@ -39,6 +79,10 @@ class SystemOps extends BaseController
public function diagnose()
{
if ($deny = $this->ensureAdminAccess()) {
return $deny;
}
$ops = new SystemOperations();
$diag = $ops->getGitDiagnosticsForWeb();

View File

@ -6,35 +6,35 @@
<div class="row">
<div class="col-md-12">
<p>
<strong>Name :</strong><?=$person_info[0]->p_fname?> {<i><?=$person_info[0]->p_rname?></i>}
<strong>/ Age :</strong><?=$person_info[0]->str_age?>
<strong>/ Gender :</strong><?=$person_info[0]->xgender?>
<strong>/ P Code :</strong><?=$person_info[0]->p_code?>
<strong>Name :</strong><?= esc($person_info[0]->p_fname ?? '') ?> {<i><?= esc($person_info[0]->p_rname ?? '') ?></i>}
<strong>/ Age :</strong><?= esc($person_info[0]->str_age ?? '') ?>
<strong>/ Gender :</strong><?= esc($person_info[0]->xgender ?? '') ?>
<strong>/ P Code :</strong><?= esc($person_info[0]->p_code ?? '') ?>
</p>
<input type="hidden" value="<?=$org_info[0]->id ?>" id="org_id" name="org_id" />
<input type="hidden" value="<?= (int) ($org_info[0]->id ?? 0) ?>" id="org_id" name="org_id" />
</div>
</div>
<div class="row">
<div class="col-md-12">
<p>
<strong>Org Code :</strong><?=$org_info[0]->case_id_code?>
<strong>/ Org. Name :</strong><?=$org_info[0]->insurance_company_name?>
<strong>/ Card No :</strong><?=$org_info[0]->insurance_no?>
<?=$org_info[0]->insurance_no_1?>
<?=$org_info[0]->insurance_no_2?>
<strong>Org Code :</strong><?= esc($org_info[0]->case_id_code ?? '') ?>
<strong>/ Org. Name :</strong><?= esc($org_info[0]->insurance_company_name ?? '') ?>
<strong>/ Card No :</strong><?= esc($org_info[0]->insurance_no ?? '') ?>
<?= esc($org_info[0]->insurance_no_1 ?? '') ?>
<?= esc($org_info[0]->insurance_no_2 ?? '') ?>
</p>
<input type="hidden" value="<?=$org_info[0]->id ?>" id="org_id" name="org_id" />
<input type="hidden" value="<?= (int) ($org_info[0]->id ?? 0) ?>" id="org_id" name="org_id" />
</div>
</div>
<?php if(count($ipd_info)>0){ ?>
<div class="row">
<div class="col-md-12">
<p>
<strong>IPD Code :</strong><?=$ipd_info[0]->ipd_code?>
<strong>/ Admit Date :</strong><?=$ipd_info[0]->str_register_date?>
<strong>/ Dis. Date :</strong><?=$ipd_info[0]->str_discharge_date?>
<strong>/ Charge Amt :</strong><?=$ipd_info[0]->charge_amount?>
<strong>/ Medical Bill :</strong><?=$ipd_info[0]->med_amount?>
<strong>IPD Code :</strong><?= esc($ipd_info[0]->ipd_code ?? '') ?>
<strong>/ Admit Date :</strong><?= esc($ipd_info[0]->str_register_date ?? '') ?>
<strong>/ Dis. Date :</strong><?= esc($ipd_info[0]->str_discharge_date ?? '') ?>
<strong>/ Charge Amt :</strong><?= esc($ipd_info[0]->charge_amount ?? '') ?>
<strong>/ Medical Bill :</strong><?= esc($ipd_info[0]->med_amount ?? '') ?>
</p>
</div>
</div>
@ -50,7 +50,7 @@
<div class="col-md-6">
<div class="form-group">
<label >Payment Bank Info</label>
<input class="form-control varchar" id="input_pay_info" placeholder="Bank , NEFT Info" type="text" value="<?=$org_info[0]->amount_payment_info?>">
<input class="form-control varchar" id="input_pay_info" placeholder="Bank , NEFT Info" type="text" value="<?= esc($org_info[0]->amount_payment_info ?? '') ?>">
</div>
</div>
<div class="col-md-3">

29
composer.lock generated
View File

@ -8,16 +8,16 @@
"packages": [
{
"name": "codeigniter4/framework",
"version": "v4.7.0",
"version": "v4.7.5",
"source": {
"type": "git",
"url": "https://github.com/codeigniter4/framework.git",
"reference": "e7753bc03f8b74af428f46b5e2bb74925487c930"
"reference": "a1f129d56df3278702a8d1048af955d0ebf68c03"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/codeigniter4/framework/zipball/e7753bc03f8b74af428f46b5e2bb74925487c930",
"reference": "e7753bc03f8b74af428f46b5e2bb74925487c930",
"url": "https://api.github.com/repos/codeigniter4/framework/zipball/a1f129d56df3278702a8d1048af955d0ebf68c03",
"reference": "a1f129d56df3278702a8d1048af955d0ebf68c03",
"shasum": ""
},
"require": {
@ -81,7 +81,7 @@
"slack": "https://codeigniterchat.slack.com",
"source": "https://github.com/codeigniter4/CodeIgniter4"
},
"time": "2026-02-01T20:39:35+00:00"
"time": "2026-10-09T15:41:56+00:00"
},
{
"name": "codeigniter4/settings",
@ -726,30 +726,29 @@
},
{
"name": "setasign/fpdi",
"version": "v2.6.4",
"version": "v2.6.9",
"source": {
"type": "git",
"url": "https://github.com/Setasign/FPDI.git",
"reference": "4b53852fde2734ec6a07e458a085db627c60eada"
"reference": "d97ade6368aa0b51b6316d5dc16a567e2bf60167"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/4b53852fde2734ec6a07e458a085db627c60eada",
"reference": "4b53852fde2734ec6a07e458a085db627c60eada",
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/d97ade6368aa0b51b6316d5dc16a567e2bf60167",
"reference": "d97ade6368aa0b51b6316d5dc16a567e2bf60167",
"shasum": ""
},
"require": {
"ext-zlib": "*",
"php": "^7.1 || ^8.0"
"php": ">=7.2 <=8.6.99999"
},
"conflict": {
"setasign/tfpdf": "<1.31"
},
"require-dev": {
"phpunit/phpunit": "^7",
"setasign/fpdf": "~1.8.6",
"phpunit/phpunit": "^8.5.52",
"setasign/fpdf": "^1.9.0",
"setasign/tfpdf": "~1.33",
"squizlabs/php_codesniffer": "^3.5",
"tecnickcom/tcpdf": "^6.8"
},
"suggest": {
@ -786,7 +785,7 @@
],
"support": {
"issues": "https://github.com/Setasign/FPDI/issues",
"source": "https://github.com/Setasign/FPDI/tree/v2.6.4"
"source": "https://github.com/Setasign/FPDI/tree/v2.6.9"
},
"funding": [
{
@ -794,7 +793,7 @@
"type": "tidelift"
}
],
"time": "2025-08-05T09:57:14+00:00"
"time": "2026-10-13T07:36:28+00:00"
}
],
"packages-dev": [

813
har_1.txt

File diff suppressed because one or more lines are too long

View File

@ -1,119 +0,0 @@
<?php
declare(strict_types=1);
header('Content-Type: text/plain; charset=utf-8');
$projectRoot = dirname(__DIR__);
$envPath = $projectRoot . DIRECTORY_SEPARATOR . '.env';
$envKey = '';
if (is_readable($envPath)) {
$lines = file($envPath, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
if (is_array($lines)) {
foreach ($lines as $line) {
$line = trim((string) $line);
if ($line === '' || strpos($line, '#') === 0) {
continue;
}
if (stripos($line, 'setup.dbToolsKey') !== 0) {
continue;
}
$parts = explode('=', $line, 2);
$envKey = trim((string) ($parts[1] ?? ''), " \t\n\r\0\x0B\"'");
break;
}
}
}
$requestKey = trim((string) ($_GET['key'] ?? ''));
if ($envKey === '') {
http_response_code(403);
echo "setup.dbToolsKey is not configured in .env\n";
exit(1);
}
if ($requestKey === '' || !hash_equals($envKey, $requestKey)) {
http_response_code(403);
echo "Invalid or missing key. Use: /setup_fs.php?key=YOUR_KEY\n";
exit(1);
}
$paths = [
$projectRoot . DIRECTORY_SEPARATOR . 'writable',
$projectRoot . DIRECTORY_SEPARATOR . 'writable' . DIRECTORY_SEPARATOR . 'cache',
$projectRoot . DIRECTORY_SEPARATOR . 'writable' . DIRECTORY_SEPARATOR . 'logs',
$projectRoot . DIRECTORY_SEPARATOR . 'writable' . DIRECTORY_SEPARATOR . 'session',
$projectRoot . DIRECTORY_SEPARATOR . 'writable' . DIRECTORY_SEPARATOR . 'uploads',
$projectRoot . DIRECTORY_SEPARATOR . 'writable' . DIRECTORY_SEPARATOR . 'debugbar',
$projectRoot . DIRECTORY_SEPARATOR . 'writable' . DIRECTORY_SEPARATOR . 'tmp',
$projectRoot . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR . 'uploads',
];
$created = [];
$chmodOk = [];
$writableOk = [];
$failed = [];
foreach ($paths as $path) {
if (!is_dir($path)) {
if (@mkdir($path, 0775, true)) {
$created[] = $path;
}
}
if (is_dir($path)) {
if (@chmod($path, 0775)) {
$chmodOk[] = $path;
}
$probe = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . '.write_test_' . str_replace('.', '', uniqid('', true)) . '.tmp';
$written = @file_put_contents($probe, 'ok');
if ($written !== false) {
@unlink($probe);
$writableOk[] = $path;
} else {
$failed[] = $path;
}
} else {
$failed[] = $path;
}
}
echo "Filesystem preparation complete\n";
echo "Project root: {$projectRoot}\n";
echo "Created dirs: " . count($created) . "\n";
echo "chmod attempted: " . count($chmodOk) . "\n";
echo "Writable OK: " . count($writableOk) . "/" . count($paths) . "\n\n";
if (!empty($created)) {
echo "Created:\n";
foreach ($created as $item) {
echo " - {$item}\n";
}
echo "\n";
}
if (!empty($failed)) {
echo "FAILED paths (need server shell fix):\n";
foreach (array_values(array_unique($failed)) as $item) {
echo " - {$item}\n";
}
$writablePath = $projectRoot . '/writable';
$uploadsPath = $projectRoot . '/public/uploads';
echo "\nRun these on server shell (example www-data):\n";
echo "sudo chown -R www-data:www-data \"{$writablePath}\" \"{$uploadsPath}\"\n";
echo "sudo find \"{$writablePath}\" -type d -exec chmod 775 {} \\;\n";
echo "sudo find \"{$writablePath}\" -type f -exec chmod 664 {} \\;\n";
echo "sudo chmod -R 775 \"{$uploadsPath}\"\n";
} else {
echo "All required paths are writable.\n";
}
echo "\nNext:\n";
echo "1) Open /setup/db-tools?key=... again\n";
echo "2) Delete this file after success: public/setup_fs.php\n";

27
public/uploads/.htaccess Normal file
View File

@ -0,0 +1,27 @@
# Deny direct execution of scripts in uploads directory
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule \.(php|phtml|php3|php4|php5|php7|php8|phps|phar|cgi|pl|py|sh|asp|aspx|jsp|exe|bat|cmd)$ - [F,L,NC]
</IfModule>
<FilesMatch "\.(php|phtml|php3|php4|php5|php7|php8|phps|phar|cgi|pl|py|sh|asp|aspx|jsp|exe|bat|cmd)$">
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
<IfModule !mod_authz_core.c>
Order Deny,Allow
Deny from all
</IfModule>
</FilesMatch>
Options -Indexes -ExecCGI
<IfModule mod_php.c>
php_flag engine off
</IfModule>
<IfModule mod_php7.c>
php_flag engine off
</IfModule>
<IfModule mod_php8.c>
php_flag engine off
</IfModule>

View File

@ -1,5 +0,0 @@
set timeout 300
spawn scp -o StrictHostKeyChecking=no "d:\\Workplace\\HMS_CI4_OLD\\abdm-bridge-le-ssl.conf" root@159.89.175.190:/etc/apache2/sites-enabled/abdm-bridge-le-ssl.conf
expect \"password:\"
send \"bishT@9720958717H\r\"
expect eof

View File

@ -0,0 +1 @@
Setup locked on 2026-10-14 for WASA compliance.