From 95ff43b56647510820b0be42d7ea7d6f3f6fd43a Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Mon, 5 Jan 2026 14:34:44 +0530 Subject: [PATCH 01/18] CHANGE_HR_CHANGES --- app/Controllers/EmployeeController.php | 219 ++++++++++++++++----- app/Controllers/EmployeeRestController.php | 109 +++++++++- app/Controllers/MasterController.php | 1 + app/Helpers/utility_helper.php | 21 ++ app/Models/FileModel.php | 1 + 5 files changed, 300 insertions(+), 51 deletions(-) diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index f6ae2ae..8b9785d 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -179,7 +179,7 @@ class EmployeeController extends AdminController } //handles employee & dependent bulk upload with events like inception,addition,deletion, correction and SI enhancements - public function employeesUplodWithEvents() + public function employeesUplodWithEvents($post_data = []) { // $empDataServiceController = new EmpDataServiceController(); @@ -233,82 +233,184 @@ class EmployeeController extends AdminController // $this->truncateFileData(747, 5) ; // print_rr($this->cloneWorksheet()); // die(); - if ($this->request->getMethod() == 'post') { + + // old + // if ($this->request->getMethod() == 'post') { + + // //validate uploaded file + // $filename = ''; + // $fileSize = ''; + // $validated = $this->validate([ + // 'emplist' => [ + // 'uploaded[emplist]', + // 'mime_in[emplist,application/vnd.ms-excel,application/vnd,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet]', + // 'max_size[emplist,16384]', + // ], + // ]); + + // if ($validated) + // { + // $avatar = $this->request->getFile('emplist'); + // if (!$avatar) { + // $this->myLogger->logme("error", 'File not found'); + // return $this->respond(['dataStatus' => false, 'code' => 400, 'message' => 'File not found'], 400); + // } + + // $is_moved = $avatar->move(WRITEPATH . 'uploads/excel/'); + // if ($is_moved) { + // $filename = $avatar->getName(); + // $fileSize = $avatar->getSize(); // File size in bytes + // $fileSize = $fileSize / (1024 * 1024); // Convert to MB + // // Handle successful upload, e.g., log success or further processing + // $this->myLogger->logme("error", 'File move successful'); + + // } else { + // $this->myLogger->logme("error", 'File move failed'); + // return $this->respond(['dataStatus' => false, 'code' => 500, 'message' => 'File move failed'], 500); + // } + // } else { + // $this->myLogger->logme("error", 'Upload failed Invalid file'); + // return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'Invalid file'], 404); + // } + + // //process post variable entry in file table + // $loggedInUserID = get_session_userid(); + // // dd($loggedInUserID); + // // $loggedInUserID = 8; + + // $client_id = $this->request->getPost('client_id'); + // $policy_id = $this->request->getPost('policy_id'); + // $branch_id = $this->request->getPost('branch_id'); + // $enrollment_open_date = $this->request->getPost('enrollment_open_date'); + // $enrollment_close_date = $this->request->getPost('enrollment_close_date'); + // $action = $this->request->getPost('upload-action-type'); + // $status = 'inprogress'; + + // $enrollment_open_date = change_date_format($enrollment_open_date, 'd/m/Y', 'Y-m-d'); + // $enrollment_close_date = change_date_format($enrollment_close_date, 'd/m/Y', 'Y-m-d'); + + // $file_id = $this->fileModel->insert(['file_name' => $filename, 'client_id' => $client_id, 'policy_id' => $policy_id, 'created_by' => $loggedInUserID, 'status' => $status, 'action' => $action, 'client_branch_id' => $branch_id,'uploaded_by' => 1, 'enrollment_open_date' => $enrollment_open_date, 'enrollment_close_date' => $enrollment_close_date]); //here field policy_id have client_policy_id and not policy id from policy master + // $this->myLogger->logme("error", '{file_id} uploaded success', ['file_id' => $file_id]); + + // //start validation process + // if($fileSize < 1) // if file size less than 1 + // { + // $empServiceController = new EmployeeServiceController(); + // $result = $empServiceController->excelFileFormatValidation(['file_id' => $file_id]); + // $this->myLogger->logme("error", '{file_id} is less than 1MB, validating on the fly', ['file_id' => $file_id]); + // //endof validation process + // if (isset($result['error_summary']) && count($result['error_summary'])) { + // return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'file rejected with errors'], 200); + // } + // } + // else //if file size greater than 1 add the file as job + // { + // $job_details = new Jobs(); + // $r = Jobs::addJob(['job_name' => 'excelFileFormatValidation','payload' => ['file_id' => $file_id]]); + // $this->myLogger->logme("error", '{file_id} is greather than 1MB, validating with job queue', ['file_id' => $file_id]); + // } + + // return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'file upload success'], 200); + // } + + if (!empty($post_data) || $this->request->is('post') == 'post') { //validate uploaded file $filename = ''; $fileSize = ''; - $validated = $this->validate([ - 'emplist' => [ - 'uploaded[emplist]', - 'mime_in[emplist,application/vnd.ms-excel,application/vnd,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet]', - 'max_size[emplist,16384]', - ], - ]); - - if ($validated) - { - $avatar = $this->request->getFile('emplist'); - if (!$avatar) { - $this->myLogger->logme("error", 'File not found'); + + if (empty($post_data)) { + $validated = $this->validate([ + 'emplist' => [ + 'uploaded[emplist]', + 'mime_in[emplist,application/vnd.ms-excel,application/vnd,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,application/vnd.oasis.opendocument.spreadsheet]', + 'max_size[emplist,16384]', + ], + ]); + } else { + $validated = validateExcelFile($post_data['emplist']); + } + + if ($validated) { + + $avatar = isset($post_data['emplist']) ? $post_data['emplist'] : $this->request->getFile('emplist'); + if (!$avatar) { + $this->myLogger->logme("error", 'File not found'); + if (!empty($post_data)) { + return ['status' => false, 'message' => 'File not found']; + } else { return $this->respond(['dataStatus' => false, 'code' => 400, 'message' => 'File not found'], 400); } + } - $is_moved = $avatar->move(WRITEPATH . 'uploads/excel/'); - if ($is_moved) { - $filename = $avatar->getName(); - $fileSize = $avatar->getSize(); // File size in bytes - $fileSize = $fileSize / (1024 * 1024); // Convert to MB - // Handle successful upload, e.g., log success or further processing - $this->myLogger->logme("error", 'File move successful'); - + $is_moved = $avatar->move(WRITEPATH . 'uploads/excel/'); + if ($is_moved) { + $filename = $avatar->getName(); + $fileSize = $avatar->getSize(); // File size in bytes + $fileSize = $fileSize / (1024 * 1024); // Convert to MB + // Handle successful upload, e.g., log success or further processing + $this->myLogger->logme("error", 'File move successful'); + } else { + $this->myLogger->logme("error", 'File move failed'); + if (!empty($post_data)) { + return ['status' => false, 'message' => 'File move failed']; } else { - $this->myLogger->logme("error", 'File move failed'); return $this->respond(['dataStatus' => false, 'code' => 500, 'message' => 'File move failed'], 500); } + } } else { $this->myLogger->logme("error", 'Upload failed Invalid file'); - return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'Invalid file'], 404); + if (!empty($post_data)) { + return ['status' => false, 'message' => 'Invalid file']; + } else { + return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'Invalid file'], 404); + } } //process post variable entry in file table - $loggedInUserID = get_session_userid(); - // dd($loggedInUserID); - // $loggedInUserID = 8; + $loggedInUserID = $post_data['created_by'] ?? get_session_userid(); - $client_id = $this->request->getPost('client_id'); - $policy_id = $this->request->getPost('policy_id'); - $branch_id = $this->request->getPost('branch_id'); - $enrollment_open_date = $this->request->getPost('enrollment_open_date'); - $enrollment_close_date = $this->request->getPost('enrollment_close_date'); - $action = $this->request->getPost('upload-action-type'); - $status = 'inprogress'; + $client_id = isset($post_data['client_id']) ? $post_data['client_id'] : $this->request->getPost('client_id'); + $policy_id = isset($post_data['policy_id']) ? $post_data['policy_id'] : $this->request->getPost('policy_id'); + $branch_id = isset($post_data['client_branch_id']) ? $post_data['client_branch_id'] : $this->request->getPost('branch_id'); + $action = isset($post_data['file_action']) ? $post_data['file_action'] : $this->request->getPost('upload-action-type'); + $enrollment_open_date = isset($post_data['enrollment_open_date']) ? $post_data['enrollment_open_date'] : $this->request->getPost('enrollment_open_date') ?? null; + $enrollment_close_date = isset($post_data['enrollment_close_date']) ? $post_data['enrollment_close_date'] : $this->request->getPost('enrollment_close_date') ?? null; + $status = 'inprogress'; + $hr_id = $post_data['created_by'] ?? null; $enrollment_open_date = change_date_format($enrollment_open_date, 'd/m/Y', 'Y-m-d'); $enrollment_close_date = change_date_format($enrollment_close_date, 'd/m/Y', 'Y-m-d'); - $file_id = $this->fileModel->insert(['file_name' => $filename, 'client_id' => $client_id, 'policy_id' => $policy_id, 'created_by' => $loggedInUserID, 'status' => $status, 'action' => $action, 'client_branch_id' => $branch_id,'uploaded_by' => 1, 'enrollment_open_date' => $enrollment_open_date, 'enrollment_close_date' => $enrollment_close_date]); //here field policy_id have client_policy_id and not policy id from policy master + $file_id = $this->fileModel->insert(['file_name' => $filename, 'client_id' => $client_id, 'policy_id' => $policy_id, 'created_by' => $loggedInUserID, 'status' => $status, 'action' => $action, 'client_branch_id' => $branch_id, 'uploaded_by' => 1, 'enrollment_open_date' => $enrollment_open_date, 'enrollment_close_date' => $enrollment_close_date, 'hr_id' => $hr_id]); //here field policy_id have client_policy_id and not policy id from policy master $this->myLogger->logme("error", '{file_id} uploaded success', ['file_id' => $file_id]); //start validation process - if($fileSize < 1) // if file size less than 1 + if ($fileSize < 1) // if file size less than 1 { $empServiceController = new EmployeeServiceController(); $result = $empServiceController->excelFileFormatValidation(['file_id' => $file_id]); $this->myLogger->logme("error", '{file_id} is less than 1MB, validating on the fly', ['file_id' => $file_id]); //endof validation process if (isset($result['error_summary']) && count($result['error_summary'])) { - return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'file rejected with errors'], 200); + if(!empty($post_data)){ + return ['status' => true, 'message' => 'file rejected with errors', 'file_id' => $file_id]; + }else{ + return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'file rejected with errors'], 200); + } } - } - else //if file size greater than 1 add the file as job + } else //if file size greater than 1 add the file as job { $job_details = new Jobs(); - $r = Jobs::addJob(['job_name' => 'excelFileFormatValidation','payload' => ['file_id' => $file_id]]); + $r = Jobs::addJob(['job_name' => 'excelFileFormatValidation', 'payload' => ['file_id' => $file_id]]); $this->myLogger->logme("error", '{file_id} is greather than 1MB, validating with job queue', ['file_id' => $file_id]); } - return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'file upload success'], 200); + if (!empty($post_data)) { + return ['status' => true, 'message' => 'File upload successs, Data validation is in-progress', 'file_id' => $file_id]; + } else { + return $this->respond(['dataStatus' => true, 'code' => 200, 'data' => 'file upload success'], 200); + } } $data['page_name'] = 'View Inception'; @@ -335,7 +437,7 @@ class EmployeeController extends AdminController ->select([ 'files.id','files.file_name','files.created_by','files.created_at','files.is_active','files.status','files.client_id','files.policy_id','files.client_branch_id','files.action','files.uploaded_by', 'enrollment_open_date', 'enrollment_close_date', 'up.emp_code', - 'up.first_name', + // 'up.first_name', 'c.short_name', 'cb.branch_name', 'cp.id as client_policy_id', @@ -349,8 +451,23 @@ class EmployeeController extends AdminController WHERE e.file_id = files.id AND ep.client_policy_id = files.policy_id) as total', 'policy_type.policy_type' , 'cp.policy_no' , + "CASE + WHEN files.hr_id IS NOT NULL THEN + CONCAT( + ( + SELECT lc.name + FROM level_contacts lc + WHERE lc.id = files.hr_id + LIMIT 1 + ), + ' (HR)' + ) + ELSE up.first_name + END AS first_name + ", + 'files.hr_id' ]) - ->join('user_profiles up', 'files.created_by = up.id') + ->join('user_profiles up', 'files.created_by = up.id', 'left') ->join('client_policy cp', 'files.policy_id = cp.id', 'left') ->join('client_branch cb', 'files.client_branch_id = cb.id', 'left') ->join('policy_type', 'policy_type.id = cp.policy_type_id') @@ -383,14 +500,22 @@ class EmployeeController extends AdminController } } - public function getExcelFileErrors() + public function getExcelFileErrors($file_id, $retun_type) { - $file_id = $this->request->uri->getSegment(3); + // $file_id = $this->request->uri->getSegment(3); $empServiceController = new EmployeeServiceController(); // Render views and capture output $result = $empServiceController->getExcelErrorData($file_id); + if($retun_type == 'api'){ + if(!empty($result)){ + return $this->respond(['status' => true, 'code' => 200, 'message' => 'Error data feteched successfully', 'data' => $result], 200); + }else{ + return $this->respond(['status' => false, 'code' => 404, 'message' => 'Failed to fetch error data', 'data' => []], 200); + } + } + if ($result != 0) { $result['file_id'] = $file_id; @@ -2833,7 +2958,7 @@ class EmployeeController extends AdminController if (!is_dir($exportDir)) { mkdir($exportDir, 0777, true); } else { - chmod($exportDir, 0777); + // chmod($exportDir, 0777); } $filename = 'inception_export_' . date('Ymd_His') . '.xlsx'; diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index ac633a2..f1bd66e 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -786,8 +786,48 @@ class EmployeeRestController extends AdminController } - // Upload the Employee Detail in DB by Sheet Data public function employeeUpload() + { + try{ + + $post_data = [ + 'client_id' => $this->request->getPost('client_id') ?? null, + 'client_branch_id' => $this->request->getPost('client_branch_id'), + 'policy_id' => $this->request->getPost('policy_id'), + 'enrollment_open_date' => $this->request->getPost('enrollment_open_date'), + 'enrollment_close_date' => $this->request->getPost('enrollment_close_date'), + 'file_action' => "enrollment", + 'created_by' => $this->request->getPost('created_by'), + 'emplist' => $this->request->getFile('file') + ]; + // print_r($post_data); die; + + if(empty($post_data['client_id'])){ + return $this->respondCreated(['status' => false, 'message' => 'Client is required', 'data' => []]); + } + + $employeeController = new EmployeeController(); + $responce = $employeeController->employeesUplodWithEvents($post_data); + // print_r($responce); die; + + if($responce['status']){ + $file_data = $this->getDataFromFilesTable(['file_id' => $responce['file_id']]); + $responce['data'] = $file_data; + return $this->respond($responce, 200); + }else{ + $responce['data'] = []; + return $this->respond($responce, 200); + } + + + + }catch(\Exception $e){ + return $this->respondCreated(['status' => false, 'message' => $e->getMessage(), 'data' => []]); + } + } + + // Upload the Employee Detail in DB by Sheet Data (DO NOT REMOVE THIS) + public function employeeUploadOld() { try { $file = $this->request->getFile('file'); @@ -1145,9 +1185,69 @@ class EmployeeRestController extends AdminController return $this->respond(['status' => 'failed','code' => 500,'data' => $th->getMessage(), 'error_data' => $errorData], 500); } - + } - + public function getDataFromFilesTable($search_data) + { + $file_download_base = base_url('util/download-file-list/'); + $builder = $this->fileModel + ->select(" + files.id, + files.client_id, + files.client_branch_id, + files.policy_id, + cp.policy_no, + files.file_name, + files.action, + files.created_at, + files.created_by, + files.updated_at, + files.updated_by, + c.short_name, + cb.branch_name, + lc.name as first_name, + CONCAT(UCASE(LEFT(files.status, 1)), LCASE(SUBSTRING(files.status, 2))) as status, + CASE + WHEN status = 'failed' THEN 1 + ELSE 0 + END AS file_error_status, + CONCAT('{$file_download_base}', files.id, '/api') AS file_download_link + ", false) + ->join('clients c', 'files.client_id = c.id AND c.is_active = 1', 'left') + ->join('client_branch cb', 'files.client_branch_id = cb.id AND cb.is_active = 1', 'left') + ->join('client_policy cp', 'files.policy_id = cp.id AND cp.is_active = 1', 'left') + ->join('level_contacts lc', 'files.hr_id = lc.id AND lc.contact_type = "client" AND lc.is_active = 1', 'left'); + + + if (isset($search_data['policy_id']) && !empty($search_data['policy_id'])) { + $builder->where("files.policy_id", $search_data['policy_id']); + } + + if (isset($search_data['created_by']) && !empty($search_data['created_by'])) { + $builder->where("files.hr_id", $search_data['created_by']); + } + + if (isset($search_data['policy_no']) && !empty($search_data['policy_no'])) { + $builder->where("cp.policy_no", $search_data['policy_no']); + } + + if (isset($search_data['client_id']) && !empty($search_data['client_id'])) { + $builder->where("files.client_id", $search_data['client_id']); + } + + if (isset($search_data['file_id']) && !empty($search_data['file_id'])) { + $builder->where("files.id", $search_data['file_id']); + } + + + // Execute query + $data = $builder->get()->getResultArray(); + + if (!empty($data)) { + return $data; + } + + return []; } @@ -2606,7 +2706,8 @@ class EmployeeRestController extends AdminController $array_list = []; foreach ($client_policy_id as $key => $value) { - $policy = $this->clientPolicyModel->where('id',$value)->where('open_for_enrollment',1)->find(); + // $policy = $this->clientPolicyModel->where('id',$value)->where('open_for_enrollment',1)->find(); + $policy = $this->findThePolicyIsOpenForEnrollment($client_policy_id, $emp_code); if($policy) { $this->myLogger->logme("error", 'client policy id = '.$value.' is open for enrollment'); diff --git a/app/Controllers/MasterController.php b/app/Controllers/MasterController.php index c1722ad..7026c00 100755 --- a/app/Controllers/MasterController.php +++ b/app/Controllers/MasterController.php @@ -1741,6 +1741,7 @@ class MasterController extends AdminController 'cache' => WRITEPATH . 'cache', 'sample_import_excel' => ROOTPATH . 'public/sample_import_excel', 'lead_files' => WRITEPATH . 'uploads/lead_files/', + 'exports' => WRITEPATH . 'exports/', ]; foreach ($folders as $folderName => $folderPath) { diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php index 6adc430..eefba31 100755 --- a/app/Helpers/utility_helper.php +++ b/app/Helpers/utility_helper.php @@ -709,3 +709,24 @@ if (!function_exists('getLatestGMCPolicy')) { } +if (!function_exists('validateExcelFile')) { + + function validateExcelFile($file) + { + $allowed = [ + 'application/vnd.ms-excel', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.oasis.opendocument.spreadsheet' + ]; + + // if ($file->getError() !== UPLOAD_ERR_OK) return 'Upload error'; + // if ($file->getSize() > (16 * 1024 * 1024)) return 'File too large'; + // if (!in_array($file->getClientMimeType(), $allowed, true)) return 'Invalid file type'; + + if ($file->getError() !== UPLOAD_ERR_OK) return false; + if ($file->getSize() > (16 * 1024 * 1024)) return false; + if (!in_array($file->getClientMimeType(), $allowed, true)) return false; + + return true; + } +} \ No newline at end of file diff --git a/app/Models/FileModel.php b/app/Models/FileModel.php index 2029ea9..c61a23b 100755 --- a/app/Models/FileModel.php +++ b/app/Models/FileModel.php @@ -23,6 +23,7 @@ class FileModel extends Model "updated_by", "enrollment_open_date", "enrollment_close_date", + "hr_id", ]; From 95f15d8ca8a520e10713b1908bb49ce6f6536e3b Mon Sep 17 00:00:00 2001 From: velz Date: Tue, 6 Jan 2026 14:54:30 +0530 Subject: [PATCH 02/18] FIX_FILE_RESTRICTION --- .htaccess | 22 ++++ app/Config/Filters.php | 4 +- app/Filters/GlobalPostFileUploadGuard.php | 147 ++++++++++++++++++++++ 3 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 app/Filters/GlobalPostFileUploadGuard.php diff --git a/.htaccess b/.htaccess index cf3c184..6782611 100755 --- a/.htaccess +++ b/.htaccess @@ -5,6 +5,28 @@ Options -Indexes # Rewrite engine # ---------------------------------------------------------------------- + +## ADDED for - block any script execution inside folder of public + + Deny from all + # Disable PHP engine + + php_flag engine off + + + # Disable CGI and other executable handlers + Options -ExecCGI + AddHandler cgi-script .php .pl .py .jsp .asp .sh .cgi + + # Block access to any script-like files entirely + + ForceType text/plain + #Order allow,deny + Deny from all + + + + # Turning on the rewrite engine is necessary for the following rules and features. # FollowSymLinks must be enabled for this to work. diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 76924a2..54e8396 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -16,6 +16,7 @@ use App\Filters\VerifyAppSignature; use App\Filters\AuthJWT; use App\Filters\Cors; +use App\Filters\GlobalPostFileUploadGuard; class Filters extends BaseConfig { @@ -39,6 +40,7 @@ class Filters extends BaseConfig 'CloseDbConnection' => CloseDbConnection::class, 'Cors' => Cors::class, 'appSignature' => VerifyAppSignature::class, + 'GlobalPostFileUploadGuard' => GlobalPostFileUploadGuard::class, ]; @@ -53,7 +55,7 @@ class Filters extends BaseConfig 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], 'Cors', - // 'csrf', + 'GlobalPostFileUploadGuard', // 'invalidchars', ], 'after' => [ diff --git a/app/Filters/GlobalPostFileUploadGuard.php b/app/Filters/GlobalPostFileUploadGuard.php new file mode 100644 index 0000000..4cc82ba --- /dev/null +++ b/app/Filters/GlobalPostFileUploadGuard.php @@ -0,0 +1,147 @@ + ['jpg', 'jpeg'], + 'image/png' => ['png'], + 'image/gif' => ['gif'], + 'image/webp' => ['webp'], + 'image/svg+xml' => ['svg'], + 'application/pdf' => ['pdf'], + 'application/msword' => ['doc'], + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => ['docx'], + 'application/vnd.oasis.opendocument.text' => ['odt'], + 'text/rtf' => ['rtf'], + 'application/rtf' => ['rtf'], + 'application/vnd.ms-excel' => ['xls'], + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => ['xlsx'], + 'application/vnd.oasis.opendocument.spreadsheet' => ['ods'], + 'text/csv' => ['csv'], + 'application/csv' => ['csv'], + 'text/plain' => ['txt', 'csv'], + ]; + + protected array $blockedExtensions = [ + 'php', 'phtml', 'pht', 'phar', 'php3', 'php4', 'php5', 'php7', 'php8', 'phps', + 'cgi', 'fcgi', 'pl', 'py', 'rb', 'lua', 'tcl', 'go', 'rs', 'jar', 'class', + 'exe', 'dll', 'com', 'bat', 'cmd', 'msi', 'vbs', 'ps1', 'scr', + 'sh', 'bash', 'zsh', 'apk', 'app', 'deb', 'rpm', 'bin', 'run', + 'js', 'mjs', 'jsp', 'asp', 'aspx', 'cer', 'swf', + 'env', 'ini', 'user.ini', 'htaccess', 'htpasswd', 'conf', 'config', 'log', 'sql', + 'zip', 'rar', '7z', 'tar', 'gz', 'bz2', 'xz', 'iso', + 'lnk', 'url', 'reg', 'sys', 'drv', 'vxd', 'tmp', 'bak', 'old', 'backup', 'key', 'pem' + ]; + + public function before(RequestInterface $request, $arguments = null) + { + if ($request->getMethod() !== 'post') { + return; + } + + $files = $request->getFiles(); + if (empty($files)) { + return; + } + + foreach ($files as $inputName => $fileData) { + $this->validateFileInput($fileData, $inputName); + } + } + + private function validateFileInput($fileData, string $inputName): void + { + if (is_array($fileData)) { + foreach ($fileData as $file) { + $this->validateSingleFile($file, $inputName); + } + } else { + $this->validateSingleFile($fileData, $inputName); + } + } + + private function validateSingleFile($file, string $inputName): void + { + $request = Services::request(); + $clientIp = $request->getIPAddress(); + $uri = $request->getUri()->getPath(); + + if (!$file->isValid()) { + if ($file->getError() === UPLOAD_ERR_INI_SIZE || $file->getError() === UPLOAD_ERR_FORM_SIZE) { + $this->block("File exceeds server-side size limit", $clientIp, $uri, $inputName, $file->getClientName(), 'unknown', 'unknown', 0); + } + return; + } + + $originalName = $file->getClientName(); + $extension = strtolower($file->getExtension()); + $mime = $file->getMimeType(); + $size = $file->getSize(); + + // --- 1. Fixed Null Byte & Path Traversal Check --- + if (preg_match('/\0|[\/\\\]/', $originalName)) { + $this->block("Malicious filename characters", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + + // --- 2. Double Extension Attack Check --- + if (preg_match('/\.(php|phtml|phar|exe|sh|bat|cmd|js|jsp|asp|aspx|py|pl)\./i', $originalName)) { + $this->block("Double extension attack", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + + // --- 3. Forbidden Extension --- + if (in_array($extension, $this->blockedExtensions, true)) { + $this->block("Forbidden extension", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + + // --- 4. File Size Limit --- + if ($size > $this->maxFileSize) { + $this->block("File too large", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + + // --- 5. MIME Allow-list Check --- + if (!array_key_exists($mime, $this->allowedMimeMap)) { + $this->block("MIME type not allowed ($mime)", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + + // --- 6. MIME-Extension Consistency --- + if (!in_array($extension, $this->allowedMimeMap[$mime], true)) { + $this->block("MIME-extension mismatch", $clientIp, $uri, $inputName, $originalName, $mime, $extension, $size); + } + } + + private function block(string $reason, string $ip, string $uri, string $field, string $filename, string $mime, string $ext, int $size): void + { + log_message('critical', + '[UPLOAD_BLOCKED] {reason} | IP: {ip} | URI: {uri} | Field: {field} | File: {file} | MIME: {mime} | EXT: {ext} | SIZE: {size}', + ['reason'=>$reason, 'ip'=>$ip, 'uri'=>$uri, 'field'=>$field, 'file'=>$filename, 'mime'=>$mime, 'ext'=>$ext, 'size'=>$size] + ); + + $response = Services::response(); + $response->setStatusCode(403) + ->setJSON([ + 'status' => 'error', + 'message' => 'File upload rejected: Security policy violation.', + 'debug' => (ENVIRONMENT === 'development') ? $reason : null + ]) + ->send(); + exit; + } + + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) {} +} \ No newline at end of file From 6ceb2173cc7a53aeae1ab7108a971966ee9451dc Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Thu, 8 Jan 2026 09:51:36 +0530 Subject: [PATCH 03/18] FIX_IOS_LOGIN --- app/Controllers/EmployeeRestController.php | 30 +++++++++++----------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index f1bd66e..d634bc4 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -1563,13 +1563,13 @@ class EmployeeRestController extends AdminController $array->mapped_family_floaters = $data; $array->type = "GMC"; - $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; + $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : '0'; if($array->is_premium_summery == 1){ - $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; - $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; + $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : '0'; + $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : '0'; }else{ - $array->family_floaters_of_dependent_and_si_premium_value = 0; - $array->family_floaters_of_dependent_and_gst_value = 0; + $array->family_floaters_of_dependent_and_si_premium_value = '0'; + $array->family_floaters_of_dependent_and_gst_value = '0'; } $checkGmcParentsPolicyExist = $this->clientPolicyModel->select(" @@ -1875,13 +1875,13 @@ class EmployeeRestController extends AdminController $array->mapped_family_floaters = $data; $array->type = "GMC - Parents"; - $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; + $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : '0'; if($array->is_premium_summery == 1){ - $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; - $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; + $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : '0'; + $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : '0'; }else{ - $array->family_floaters_of_dependent_and_si_premium_value = 0; - $array->family_floaters_of_dependent_and_gst_value = 0; + $array->family_floaters_of_dependent_and_si_premium_value = '0'; + $array->family_floaters_of_dependent_and_gst_value = '0'; } return $array; @@ -2524,13 +2524,13 @@ class EmployeeRestController extends AdminController } $responce['family_floaters_of_dependent_and_si_array'] = $data; - $responce['family_floaters_of_dependent_and_si_value'] = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; + $responce['family_floaters_of_dependent_and_si_value'] = $dependent_and_si_value > 0 ? $dependent_and_si_value : '0'; if($array['is_premium_summery']){ - $responce['family_floaters_of_dependent_and_si_premium_value'] = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; - $responce['family_floaters_of_dependent_and_gst_value'] = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; + $responce['family_floaters_of_dependent_and_si_premium_value'] = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : '0'; + $responce['family_floaters_of_dependent_and_gst_value'] = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : '0'; }else{ - $responce['family_floaters_of_dependent_and_si_premium_value'] = 0; - $responce['family_floaters_of_dependent_and_gst_value'] = 0; + $responce['family_floaters_of_dependent_and_si_premium_value'] = '0'; + $responce['family_floaters_of_dependent_and_gst_value'] = '0'; } From aa42aafe4d5baf7e0542bbc833efee49105d3c46 Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Thu, 8 Jan 2026 11:08:31 +0530 Subject: [PATCH 04/18] FIX_ISSUE --- app/Controllers/EmployeeRestController.php | 47 ++++++++++++++-------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index d634bc4..ee78eda 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -1563,13 +1563,26 @@ class EmployeeRestController extends AdminController $array->mapped_family_floaters = $data; $array->type = "GMC"; - $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : '0'; - if($array->is_premium_summery == 1){ - $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : '0'; - $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : '0'; - }else{ - $array->family_floaters_of_dependent_and_si_premium_value = '0'; - $array->family_floaters_of_dependent_and_gst_value = '0'; + // $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; + // if($array->is_premium_summery == 1){ + // $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; + // $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; + // }else{ + // $array->family_floaters_of_dependent_and_si_premium_value = 0; + // $array->family_floaters_of_dependent_and_gst_value = 0; + // } + + $array->family_floaters_of_dependent_and_si_value = ($dependent_and_si_value > 0) ? (int) $dependent_and_si_value: 0; + + if ($array->is_premium_summery == 1) { + + $array->family_floaters_of_dependent_and_si_premium_value = ($dependent_and_si_premium_value > 0) ? (float) round($dependent_and_si_premium_value) : 0; + $array->family_floaters_of_dependent_and_gst_value =($dependent_and_si_gst_value > 0) ? (float) round($dependent_and_si_gst_value) : 0; + + } else { + + $array->family_floaters_of_dependent_and_si_premium_value = 0; + $array->family_floaters_of_dependent_and_gst_value = 0; } $checkGmcParentsPolicyExist = $this->clientPolicyModel->select(" @@ -1875,13 +1888,13 @@ class EmployeeRestController extends AdminController $array->mapped_family_floaters = $data; $array->type = "GMC - Parents"; - $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : '0'; + $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; if($array->is_premium_summery == 1){ - $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : '0'; - $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : '0'; + $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; + $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; }else{ - $array->family_floaters_of_dependent_and_si_premium_value = '0'; - $array->family_floaters_of_dependent_and_gst_value = '0'; + $array->family_floaters_of_dependent_and_si_premium_value = 0; + $array->family_floaters_of_dependent_and_gst_value = 0; } return $array; @@ -2524,13 +2537,13 @@ class EmployeeRestController extends AdminController } $responce['family_floaters_of_dependent_and_si_array'] = $data; - $responce['family_floaters_of_dependent_and_si_value'] = $dependent_and_si_value > 0 ? $dependent_and_si_value : '0'; + $responce['family_floaters_of_dependent_and_si_value'] = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; if($array['is_premium_summery']){ - $responce['family_floaters_of_dependent_and_si_premium_value'] = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : '0'; - $responce['family_floaters_of_dependent_and_gst_value'] = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : '0'; + $responce['family_floaters_of_dependent_and_si_premium_value'] = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; + $responce['family_floaters_of_dependent_and_gst_value'] = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; }else{ - $responce['family_floaters_of_dependent_and_si_premium_value'] = '0'; - $responce['family_floaters_of_dependent_and_gst_value'] = '0'; + $responce['family_floaters_of_dependent_and_si_premium_value'] = 0; + $responce['family_floaters_of_dependent_and_gst_value'] = 0; } From 27acd4bc69934c3676e943a82027445394d5ea6e Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Thu, 8 Jan 2026 11:26:15 +0530 Subject: [PATCH 05/18] FIX_ISSUE --- app/Controllers/EmployeeRestController.php | 65 +++++++++++++--------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index ee78eda..45d96ee 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -1572,17 +1572,14 @@ class EmployeeRestController extends AdminController // $array->family_floaters_of_dependent_and_gst_value = 0; // } - $array->family_floaters_of_dependent_and_si_value = ($dependent_and_si_value > 0) ? (int) $dependent_and_si_value: 0; - - if ($array->is_premium_summery == 1) { + $array->family_floaters_of_dependent_and_si_value = isset($dependent_and_si_value) ? (float) $dependent_and_si_value : 0.0; - $array->family_floaters_of_dependent_and_si_premium_value = ($dependent_and_si_premium_value > 0) ? (float) round($dependent_and_si_premium_value) : 0; - $array->family_floaters_of_dependent_and_gst_value =($dependent_and_si_gst_value > 0) ? (float) round($dependent_and_si_gst_value) : 0; - + if ($array->is_premium_summery == 1) { + $array->family_floaters_of_dependent_and_si_premium_value = isset($dependent_and_si_premium_value) ? (float) round($dependent_and_si_premium_value, 2) : 0.0; + $array->family_floaters_of_dependent_and_gst_value = isset($dependent_and_si_gst_value) ? (float) round($dependent_and_si_gst_value, 2) : 0.0; } else { - - $array->family_floaters_of_dependent_and_si_premium_value = 0; - $array->family_floaters_of_dependent_and_gst_value = 0; + $array->family_floaters_of_dependent_and_si_premium_value = 0.0; + $array->family_floaters_of_dependent_and_gst_value = 0.0; } $checkGmcParentsPolicyExist = $this->clientPolicyModel->select(" @@ -1888,13 +1885,23 @@ class EmployeeRestController extends AdminController $array->mapped_family_floaters = $data; $array->type = "GMC - Parents"; - $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; - if($array->is_premium_summery == 1){ - $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; - $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; - }else{ - $array->family_floaters_of_dependent_and_si_premium_value = 0; - $array->family_floaters_of_dependent_and_gst_value = 0; + // $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; + // if($array->is_premium_summery == 1){ + // $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; + // $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; + // }else{ + // $array->family_floaters_of_dependent_and_si_premium_value = 0; + // $array->family_floaters_of_dependent_and_gst_value = 0; + // } + + $array->family_floaters_of_dependent_and_si_value = isset($dependent_and_si_value) ? (float) $dependent_and_si_value : 0.0; + + if ($array->is_premium_summery == 1) { + $array->family_floaters_of_dependent_and_si_premium_value = isset($dependent_and_si_premium_value) ? (float) round($dependent_and_si_premium_value, 2) : 0.0; + $array->family_floaters_of_dependent_and_gst_value = isset($dependent_and_si_gst_value) ? (float) round($dependent_and_si_gst_value, 2) : 0.0; + } else { + $array->family_floaters_of_dependent_and_si_premium_value = 0.0; + $array->family_floaters_of_dependent_and_gst_value = 0.0; } return $array; @@ -2537,19 +2544,23 @@ class EmployeeRestController extends AdminController } $responce['family_floaters_of_dependent_and_si_array'] = $data; - $responce['family_floaters_of_dependent_and_si_value'] = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; + // $responce['family_floaters_of_dependent_and_si_value'] = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; + // if($array['is_premium_summery']){ + // $responce['family_floaters_of_dependent_and_si_premium_value'] = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; + // $responce['family_floaters_of_dependent_and_gst_value'] = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; + // }else{ + // $responce['family_floaters_of_dependent_and_si_premium_value'] = 0; + // $responce['family_floaters_of_dependent_and_gst_value'] = 0; + // } + + $responce['family_floaters_of_dependent_and_si_value'] = isset($dependent_and_si_value) ? (float) $dependent_and_si_value : 0.0; if($array['is_premium_summery']){ - $responce['family_floaters_of_dependent_and_si_premium_value'] = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; - $responce['family_floaters_of_dependent_and_gst_value'] = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; + $responce['family_floaters_of_dependent_and_si_premium_value'] = isset($dependent_and_si_premium_value) ? (float) round($dependent_and_si_premium_value, 2) : 0.0; + $responce['family_floaters_of_dependent_and_gst_value'] = isset($dependent_and_si_gst_value) ? (float) round($dependent_and_si_gst_value, 2) : 0.0; }else{ - $responce['family_floaters_of_dependent_and_si_premium_value'] = 0; - $responce['family_floaters_of_dependent_and_gst_value'] = 0; - } - - - - - + $responce['family_floaters_of_dependent_and_si_premium_value'] = 0.0; + $responce['family_floaters_of_dependent_and_gst_value'] = 0.0; + } if($this->request->getGet('policy') == 'GMC-DEPENDENT-ADDON'){ return $this->respond(['status' => 'success','code' => 200,'data' => ['gmc_dependent_addon'=>$responce]], 200); From 8dbbc2a406e475fca8c1eeebadfe0dc623d0126f Mon Sep 17 00:00:00 2001 From: "venkatesh.r" Date: Thu, 8 Jan 2026 13:09:34 +0530 Subject: [PATCH 06/18] FIX_ISSUE --- app/Controllers/EmployeeRestController.php | 70 ++++++++-------------- 1 file changed, 24 insertions(+), 46 deletions(-) diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index 45d96ee..e810120 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -1563,23 +1563,13 @@ class EmployeeRestController extends AdminController $array->mapped_family_floaters = $data; $array->type = "GMC"; - // $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; - // if($array->is_premium_summery == 1){ - // $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; - // $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; - // }else{ - // $array->family_floaters_of_dependent_and_si_premium_value = 0; - // $array->family_floaters_of_dependent_and_gst_value = 0; - // } - - $array->family_floaters_of_dependent_and_si_value = isset($dependent_and_si_value) ? (float) $dependent_and_si_value : 0.0; - - if ($array->is_premium_summery == 1) { - $array->family_floaters_of_dependent_and_si_premium_value = isset($dependent_and_si_premium_value) ? (float) round($dependent_and_si_premium_value, 2) : 0.0; - $array->family_floaters_of_dependent_and_gst_value = isset($dependent_and_si_gst_value) ? (float) round($dependent_and_si_gst_value, 2) : 0.0; - } else { + $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0.0; + if($array->is_premium_summery == 1){ + $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0.0; + $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0.0; + }else{ $array->family_floaters_of_dependent_and_si_premium_value = 0.0; - $array->family_floaters_of_dependent_and_gst_value = 0.0; + $array->family_floaters_of_dependent_and_gst_value = 0.0; } $checkGmcParentsPolicyExist = $this->clientPolicyModel->select(" @@ -1641,7 +1631,8 @@ class EmployeeRestController extends AdminController } if(!empty($result) && $this->request->getGet('policy') == 'GMC'){ - return $this->respond(['status' => 'success','code' => 200,'data' => $result], 200); + // return $this->respond(['status' => 'success','code' => 200,'data' => $result], 200); + echo json_encode(['status' => 'success','code' => 200,'data' => $result], JSON_PRETTY_PRINT | JSON_PRESERVE_ZERO_FRACTION); }else{ return $this->respond(['status' => 'success','code' => 200,'data' => []], 200); } @@ -1885,21 +1876,11 @@ class EmployeeRestController extends AdminController $array->mapped_family_floaters = $data; $array->type = "GMC - Parents"; - // $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; - // if($array->is_premium_summery == 1){ - // $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; - // $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; - // }else{ - // $array->family_floaters_of_dependent_and_si_premium_value = 0; - // $array->family_floaters_of_dependent_and_gst_value = 0; - // } - - $array->family_floaters_of_dependent_and_si_value = isset($dependent_and_si_value) ? (float) $dependent_and_si_value : 0.0; - - if ($array->is_premium_summery == 1) { - $array->family_floaters_of_dependent_and_si_premium_value = isset($dependent_and_si_premium_value) ? (float) round($dependent_and_si_premium_value, 2) : 0.0; - $array->family_floaters_of_dependent_and_gst_value = isset($dependent_and_si_gst_value) ? (float) round($dependent_and_si_gst_value, 2) : 0.0; - } else { + $array->family_floaters_of_dependent_and_si_value = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0.0; + if($array->is_premium_summery == 1){ + $array->family_floaters_of_dependent_and_si_premium_value = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0.0; + $array->family_floaters_of_dependent_and_gst_value = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0.0; + }else{ $array->family_floaters_of_dependent_and_si_premium_value = 0.0; $array->family_floaters_of_dependent_and_gst_value = 0.0; } @@ -2544,26 +2525,23 @@ class EmployeeRestController extends AdminController } $responce['family_floaters_of_dependent_and_si_array'] = $data; - // $responce['family_floaters_of_dependent_and_si_value'] = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0; - // if($array['is_premium_summery']){ - // $responce['family_floaters_of_dependent_and_si_premium_value'] = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0; - // $responce['family_floaters_of_dependent_and_gst_value'] = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0; - // }else{ - // $responce['family_floaters_of_dependent_and_si_premium_value'] = 0; - // $responce['family_floaters_of_dependent_and_gst_value'] = 0; - // } - - $responce['family_floaters_of_dependent_and_si_value'] = isset($dependent_and_si_value) ? (float) $dependent_and_si_value : 0.0; + $responce['family_floaters_of_dependent_and_si_value'] = $dependent_and_si_value > 0 ? $dependent_and_si_value : 0.0; if($array['is_premium_summery']){ - $responce['family_floaters_of_dependent_and_si_premium_value'] = isset($dependent_and_si_premium_value) ? (float) round($dependent_and_si_premium_value, 2) : 0.0; - $responce['family_floaters_of_dependent_and_gst_value'] = isset($dependent_and_si_gst_value) ? (float) round($dependent_and_si_gst_value, 2) : 0.0; + $responce['family_floaters_of_dependent_and_si_premium_value'] = $dependent_and_si_premium_value > 0 ? round($dependent_and_si_premium_value) : 0.0; + $responce['family_floaters_of_dependent_and_gst_value'] = $dependent_and_si_gst_value > 0 ? round($dependent_and_si_gst_value) : 0.0; }else{ $responce['family_floaters_of_dependent_and_si_premium_value'] = 0.0; $responce['family_floaters_of_dependent_and_gst_value'] = 0.0; - } + } + + + + + if($this->request->getGet('policy') == 'GMC-DEPENDENT-ADDON'){ - return $this->respond(['status' => 'success','code' => 200,'data' => ['gmc_dependent_addon'=>$responce]], 200); + // return $this->respond(['status' => 'success','code' => 200,'data' => ['gmc_dependent_addon'=>$responce]], 200); + echo json_encode(['status' => 'success','code' => 200,'data' => ['gmc_dependent_addon'=>$responce]], JSON_PRETTY_PRINT | JSON_PRESERVE_ZERO_FRACTION); } //array_push($PolicyData, $responce); From 5cd6cfb7fad58df0c1145cb7a460469a0af35b13 Mon Sep 17 00:00:00 2001 From: velz Date: Thu, 8 Jan 2026 16:02:00 +0530 Subject: [PATCH 07/18] FEAT_SANITIZATION --- app/Config/Filters.php | 3 + app/Filters/Cors.php | 66 +++++++------- app/Filters/SecurityInputFilter.php | 130 ++++++++++++++++++++++++++++ 3 files changed, 166 insertions(+), 33 deletions(-) create mode 100644 app/Filters/SecurityInputFilter.php diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 54e8396..969dadf 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -17,6 +17,7 @@ use App\Filters\VerifyAppSignature; use App\Filters\AuthJWT; use App\Filters\Cors; use App\Filters\GlobalPostFileUploadGuard; +use App\Filters\SecurityInputFilter; class Filters extends BaseConfig { @@ -41,6 +42,7 @@ class Filters extends BaseConfig 'Cors' => Cors::class, 'appSignature' => VerifyAppSignature::class, 'GlobalPostFileUploadGuard' => GlobalPostFileUploadGuard::class, + 'SecurityInputFilter' => SecurityInputFilter::class, ]; @@ -55,6 +57,7 @@ class Filters extends BaseConfig 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], 'Cors', + 'SecurityInputFilter', 'GlobalPostFileUploadGuard', // 'invalidchars', ], diff --git a/app/Filters/Cors.php b/app/Filters/Cors.php index c47f276..bb8d5b8 100644 --- a/app/Filters/Cors.php +++ b/app/Filters/Cors.php @@ -107,11 +107,11 @@ class Cors implements FilterInterface ); } - $this->log('CORS filter initialized', [ - 'allowed_origins' => $this->allowedOrigins, - 'allow_credentials' => $this->allowCredentials, - 'allowed_methods' => $this->allowedMethods, - ]); + // $this->log('CORS filter initialized', [ + // 'allowed_origins' => $this->allowedOrigins, + // 'allow_credentials' => $this->allowCredentials, + // 'allowed_methods' => $this->allowedMethods, + // ]); } /** @@ -143,7 +143,7 @@ class Cors implements FilterInterface // If wildcard present in configuration, allow any origin if (in_array('*', $this->allowedOrigins, true)) { - $this->log('Origin allowed: wildcard match', ['origin' => $origin]); + // $this->log('Origin allowed: wildcard match', ['origin' => $origin]); return true; } @@ -159,10 +159,10 @@ class Cors implements FilterInterface // 1. Exact match (including scheme and port) // Example: https://example.com matches https://example.com if (strcasecmp($allowed, $origin) === 0) { - $this->log('Origin allowed: exact match', [ - 'origin' => $origin, - 'matched_rule' => $allowed - ]); + // $this->log('Origin allowed: exact match', [ + // 'origin' => $origin, + // 'matched_rule' => $allowed + // ]); return true; } @@ -178,11 +178,11 @@ class Cors implements FilterInterface // Check if origin host ends with the allowed root domain if ($originHost === $allowedRoot || str_ends_with($originHost, '.' . $allowedRoot)) { - $this->log('Origin allowed: wildcard subdomain match', [ - 'origin' => $origin, - 'matched_rule' => $allowed, - 'origin_host' => $originHost - ]); + // $this->log('Origin allowed: wildcard subdomain match', [ + // 'origin' => $origin, + // 'matched_rule' => $allowed, + // 'origin_host' => $originHost + // ]); return true; } } @@ -191,11 +191,11 @@ class Cors implements FilterInterface // Example: example.com matches both http://example.com and https://example.com else { if (strcasecmp($allowed, $originHost) === 0) { - $this->log('Origin allowed: host match (scheme-less)', [ - 'origin' => $origin, - 'matched_rule' => $allowed, - 'origin_host' => $originHost - ]); + // $this->log('Origin allowed: host match (scheme-less)', [ + // 'origin' => $origin, + // 'matched_rule' => $allowed, + // 'origin_host' => $originHost + // ]); return true; } } @@ -320,11 +320,11 @@ class Cors implements FilterInterface // Preflight is sent by browsers before actual cross-origin requests // to check if the actual request is safe to send if ($method === 'OPTIONS') { - $this->log('Preflight request received', [ - 'origin' => $origin, - 'method' => $method, - 'uri' => (string) $request->getUri() - ]); + // $this->log('Preflight request received', [ + // 'origin' => $origin, + // 'method' => $method, + // 'uri' => (string) $request->getUri() + // ]); // Validate origin - reject if not allowed if (empty($origin) || !$this->isOriginAllowed($origin)) { @@ -346,10 +346,10 @@ class Cors implements FilterInterface $response->setStatusCode(204); $response->setBody(''); - $this->log('Preflight approved', [ - 'origin' => $origin, - 'allowed_methods' => $this->allowedMethods - ]); + // $this->log('Preflight approved', [ + // 'origin' => $origin, + // 'allowed_methods' => $this->allowedMethods + // ]); return $response; } @@ -392,10 +392,10 @@ class Cors implements FilterInterface // Add CORS headers to the response $this->addCorsHeaders($response, $request, $origin, false); - $this->log('CORS headers added to response', [ - 'origin' => $origin, - 'status' => $response->getStatusCode() - ]); + // $this->log('CORS headers added to response', [ + // 'origin' => $origin, + // 'status' => $response->getStatusCode() + // ]); } /** diff --git a/app/Filters/SecurityInputFilter.php b/app/Filters/SecurityInputFilter.php new file mode 100644 index 0000000..c23f790 --- /dev/null +++ b/app/Filters/SecurityInputFilter.php @@ -0,0 +1,130 @@ +/i', + + // JavaScript execution vectors + '/javascript\s*:/i', + '/vbscript\s*:/i', + '/data\s*:\s*text\/html/i', + + // Inline event handlers (strong signal) + '/on\w+\s*=\s*["\']?/i', + + // Dangerous HTML tags + '/<\s*iframe\b/i', + '/<\s*object\b/i', + '/<\s*embed\b/i', + '/<\s*applet\b/i', + '/<\s*img\b/i', + + // Image-based execution + '/<\s*img\b[^>]*on\w+/i', + + // SVG-based execution (modern bypass) + '/<\s*svg\b/i', + '/<\s*math\b/i', + + // Meta refresh redirect + '/<\s*meta\b[^>]*http-equiv\s*=\s*["\']?refresh/i', + + // HTML injection via src/href + '/<\s*\w+\b[^>]*(src|href)\s*=\s*["\']?\s*(javascript|data)\s*:/i' + ]; + + + public function before(RequestInterface $request, $arguments = null) + { + $logger = Services::mylogger(); + $response = Services::response(); + + // Collect all user-controlled input + $inputs = array_merge( + $request->getGet(), + $request->getPost() + ); + + if (empty($inputs)) { + return; + } + + foreach ($inputs as $field => $value) { + if (is_array($value)) { + $value = json_encode($value); + } + + // Step 1: Canonicalization (VERY IMPORTANT) + $canonical = $this->canonicalize($value); + + // Step 2: Trim (hygiene) + $canonical = trim($canonical); + + // Step 3: Detection (signal-only) + if ($this->detectXss($canonical)) { + + // 🔐 Log intent, not data + $logger->logme('critical','SECURITY_BLOCKED_REQUEST - '. json_encode([ + 'ip' => $request->getIPAddress(), + 'method' => $request->getMethod(), + 'uri' => current_url(), + 'field' => $field, + 'attack' => 'XSS_PATTERN', + 'length' => strlen($canonical), + 'hash' => hash('sha256', $canonical), + ])); + + // ⛔ Block request + return $response + ->setStatusCode(403) + ->setJSON([ + 'status' => 403, + 'error' => 'Forbidden', + 'message' => 'Malicious input detected' + ]); + } + } + } + + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + // no-op + } + + /** + * Canonicalization prevents encoded bypass + */ + private function canonicalize(string $value): string + { + $value = urldecode($value); + $value = html_entity_decode($value, ENT_QUOTES | ENT_HTML5, 'UTF-8'); + + // Remove invisible control characters + return preg_replace('/[\x00-\x1F\x7F]/u', '', $value); + } + + private function detectXss(string $value): bool + { + foreach ($this->xssPatterns as $pattern) { + if (preg_match($pattern, $value)) { + return true; + } + } + return false; + } +} From 574f9963d10d2ddb7253743af6c5361e3141cef0 Mon Sep 17 00:00:00 2001 From: velz Date: Thu, 8 Jan 2026 16:37:26 +0530 Subject: [PATCH 08/18] FIX_SESSION_REPLAY --- app/Controllers/LoginController.php | 31 ++++++++++++--------- app/Filters/AuthMVC.php | 21 +++++++++++++-- app/Helpers/session_helper.php | 2 +- app/Libraries/AuthLogout.php | 42 +++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 app/Libraries/AuthLogout.php diff --git a/app/Controllers/LoginController.php b/app/Controllers/LoginController.php index 830fb02..eb3d98e 100755 --- a/app/Controllers/LoginController.php +++ b/app/Controllers/LoginController.php @@ -9,6 +9,7 @@ use Psr\Log\LoggerInterface; use App\Models\UserModel; use App\Models\AuthHistoryModel; +use App\Libraries\AuthLogout; class LoginController extends BaseController { @@ -54,25 +55,29 @@ class LoginController extends BaseController $path = getenv('cookie.Path'); $domain = getenv('cookie.Domain'); $https = getenv('ccokie.secure'); - setcookie('session_data', json_encode($session_data), time() + 12 * 60 * 60, $path, $domain, $https, true); + // setcookie('session_data', json_encode($session_data), time() + 12 * 60 * 60, $path, $domain, $https, true); set_session_data($session_data); + // Bind session to device + set_session_data(['fingerprint' => hash('sha256', + ($this->request->getUserAgent()->getAgentString() . '|' . ($this->request->getIPAddress() + )))]); log_message('error', 'Set The UserId : `'. $user->id .'` in Session'); log_message('error', 'User Login Sucessfully'); $this->getUserDeviceInfo($user->id, 'NhanceUser'); - return redirect()->to(base_url('/dashboard/view')); + return AuthLogout::logout(); }else{ log_message('error', 'User Not Active'); session()->setFlashdata('error', 'User Not Active'); - return redirect()->to(base_url('login')); + return AuthLogout::logout(); } }else{ log_message('error', 'User Not Registered'); session()->setFlashdata('error', 'User Not Registered'); - return redirect()->to(base_url('login')); + return AuthLogout::logout(); } } @@ -94,14 +99,16 @@ class LoginController extends BaseController // setcookie('session_data', '', time() - 3600, $path); // return redirect()->to(base_url('login')); - $path = getenv('cookie.Path'); - session()->destroy(); - // setcookie('session_data', '', time() - 3600, $path); - $path = getenv('cookie.Path'); - $domain = getenv('cookie.Domain'); - $https = getenv('cookie.secure'); - setcookie('session_data',null, time() -3600, $path, $domain, $https, true); - return redirect()->to(base_url('login')); + // $path = getenv('cookie.Path'); + // session()->destroy(); + // // setcookie('session_data', '', time() - 3600, $path); + // $path = getenv('cookie.Path'); + // $domain = getenv('cookie.Domain'); + // $https = getenv('cookie.secure'); + // setcookie('session_data',null, time() -3600, $path, $domain, $https, true); + // return redirect()->to(base_url('login')); + + return AuthLogout::logout(); } diff --git a/app/Filters/AuthMVC.php b/app/Filters/AuthMVC.php index 0a9f7a6..e6c6948 100755 --- a/app/Filters/AuthMVC.php +++ b/app/Filters/AuthMVC.php @@ -5,12 +5,29 @@ use CodeIgniter\Filters\FilterInterface; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; +use App\Libraries\AuthLogout; + class AuthMVC implements FilterInterface { public function before(RequestInterface $request, $arguments = null) { - if (!check_session() && !check_cookie()) { - return redirect()->to(base_url('/login')); + if (!check_session()) + { + return AuthLogout::logout(); + } + + // if (!check_cookie()) + // { + // return AuthLogout::logout(); + // } + + // Fingerprint validation + $fp = hash('sha256', + $request->getUserAgent()->getAgentString() . '|' . $request->getIPAddress() + ); + + if (session()->get('fingerprint') !== $fp) { + return AuthLogout::logout(); } } diff --git a/app/Helpers/session_helper.php b/app/Helpers/session_helper.php index 3d312d6..eb9eb9a 100755 --- a/app/Helpers/session_helper.php +++ b/app/Helpers/session_helper.php @@ -21,7 +21,7 @@ if(!function_exists('check_cookie')){ 'userProfile' => $value['userProfile'], 'user_team' => $user_team, ]; - set_session_data($session_data); + // set_session_data($session_data); // $this->getUserDeviceInfo($user->id, 'NhanceUser'); // return redirect()->to(base_url('/dashboard/view')); return true; diff --git a/app/Libraries/AuthLogout.php b/app/Libraries/AuthLogout.php new file mode 100644 index 0000000..cfb1005 --- /dev/null +++ b/app/Libraries/AuthLogout.php @@ -0,0 +1,42 @@ +regenerate(true); + + // Destroy CI session + $session->destroy(); + + // Kill PHP session cookie safely + if (ini_get('session.use_cookies')) { + $params = session_get_cookie_params(); + + setcookie( + session_name(), // DO NOT hardcode cookie name + '', + time() - 42000, + $params['path'], + $params['domain'], + $params['secure'], + $params['httponly'] + ); + } + + session_write_close(); + + // Redirect with anti-cache headers + return redirect()->to(base_url('login')) + ->setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0') + ->setHeader('Pragma', 'no-cache') + ->setHeader('Expires', 'Sat, 26 Jul 1997 05:00:00 GMT'); + } +} From 4d15ddb92a1f9e029595049948a959071007e3ff Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Thu, 8 Jan 2026 16:58:50 +0530 Subject: [PATCH 09/18] GWM : VAPT Scan Vulnerabilities --- app/Config/Routes.php | 2 + .../RestAuthenticationController.php | 81 ++++++++- app/Filters/AuthJWT.php | 160 ++++++++++++------ app/Helpers/JWTToken.php | 93 +++++++--- app/Helpers/utility_helper.php | 26 +++ 5 files changed, 285 insertions(+), 77 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index eaf7741..6524071 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -455,6 +455,8 @@ $routes->group("/api", ["filter" => "authJWT"], function ($routes) { $routes->group("employeeRest", ['filter' => ['appSignature' , 'authJWT'] ], function ($routes) { + $routes->post('logout', 'RestAuthenticationController::logout'); + // $routes->post("getVerifiedUserData", "RestAuthenticationController::getVerifiedUserData"); $routes->post("storeFireBase", "EmployeeRestController::storeFireBase"); diff --git a/app/Controllers/RestAuthenticationController.php b/app/Controllers/RestAuthenticationController.php index 22e834e..15469ec 100755 --- a/app/Controllers/RestAuthenticationController.php +++ b/app/Controllers/RestAuthenticationController.php @@ -166,7 +166,14 @@ class RestAuthenticationController extends AdminController $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - verifyEmployeeWithMobileNumber: Final employee data to verify = " . json_encode($employeeData)); if (isset($employeeData['employee_id'])) - { + { + + //check the resend otp (with in 60 seconds don't allow another otp to send) + $check = canSendOtp($employeeData); + if (!$check['allowed']) { + return $this->respond(['status' => false,'message' => 'OTP already sent. Please wait before retrying.','retry_after_seconds' => $check['retry_after'] ])->setStatusCode(429); // Too Many Requests + } + $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - verifyEmployeeWithMobileNumber: Employee verified with ID = " . $employeeData['employee_id']); log_message('error', ' '); log_message('error', '************************ PRE END ********************************'); @@ -264,10 +271,11 @@ class RestAuthenticationController extends AdminController $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - verifyEmployeeWithEmailId: Received Email ID = " . $email); $empdata = RestAuthHelper::getPreAndPostDataByEmailOrMobile(['email_id' => $email]); - // print_r($empdata); die; + $otp = random_int(100000, 999999); + //only retail policy if(empty($empdata)){ $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - verifyEmployeeWithEmailId: No employee data found both PRE & POST"); log_message('error', ' '); @@ -323,8 +331,15 @@ class RestAuthenticationController extends AdminController $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - verifyEmployeeWithEmailId: Using PRE data"); } + + if (isset($employeeData['employee_id'])) { + //check the resend otp (with in 60 seconds don't allow another otp to send) + $check = canSendOtp($employeeData); + if (!$check['allowed']) { + return $this->respond(['status' => false,'message' => 'OTP already sent. Please wait before retrying.','retry_after_seconds' => $check['retry_after'] ])->setStatusCode(429); // Too Many Requests + } $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - verifyEmployeeWithEmailId: Valid employee found, generating OTP"); @@ -578,6 +593,12 @@ class RestAuthenticationController extends AdminController if ($HrData) { + + //check the resend otp (with in 60 seconds don't allow another otp to send) + $check = canSendOtp($HrData); + if (!$check['allowed']) { + return $this->respond(['status' => false,'message' => 'OTP already sent. Please wait before retrying.','retry_after_seconds' => $check['retry_after'] ])->setStatusCode(429); // Too Many Requests + } $sql = "UPDATE level_contacts SET otp = ? WHERE mobile = ? AND contact_type = 'client' AND is_active = 1"; @@ -637,6 +658,12 @@ class RestAuthenticationController extends AdminController $data->otp = $otp; if ($HrData) { + + //check the resend otp (with in 60 seconds don't allow another otp to send) + $check = canSendOtp($HrData); + if (!$check['allowed']) { + return $this->respond(['status' => false,'message' => 'OTP already sent. Please wait before retrying.','retry_after_seconds' => $check['retry_after'] ])->setStatusCode(429); // Too Many Requests + } @@ -1868,5 +1895,55 @@ class RestAuthenticationController extends AdminController } } + + public function logout() + { + $authHeader = $this->request->getHeaderLine('Authorization'); + + if (!$authHeader) { + return $this->respond([ + 'status' => false, + 'message' => 'Authorization token missing' + ], 401); + } + + // Validate JWT (your hardened function) + $result = JWTToken::validateJWT($authHeader); + + if ($result['status'] !== true) { + return $this->respond([ + 'status' => false, + 'message' => 'Invalid or expired token' + ], 401); + } + + $decoded = $result['decoded']; + $userId = $decoded['id'] ?? null; + + if (!$userId) { + return $this->respond([ + 'status' => false, + 'message' => 'Invalid token payload' + ], 401); + } + + // Identify user type + if (isset($decoded['emp_code'])) { + $model = new EmployeeModel(); + } else { + $model = new LevelContactModel(); + } + + // Invalidate token server-side + $model->update($userId, [ + 'token_time_out' => null + ]); + + return $this->respond([ + 'status' => true, + 'message' => 'Logged out successfully' + ], 200); + } + } diff --git a/app/Filters/AuthJWT.php b/app/Filters/AuthJWT.php index 262a5e5..9530ebd 100755 --- a/app/Filters/AuthJWT.php +++ b/app/Filters/AuthJWT.php @@ -18,65 +18,115 @@ use App\Models\LevelContactModel; class AuthJWT implements FilterInterface { + // public function before(RequestInterface $request, $arguments = null) + // { + // $jwt = $request->getHeaderLine('Authorization'); + + // if ($jwt) { + // if (JWTToken::validateJWT($jwt)) { + // $data = JWTToken::validateJWT($jwt); + // $data = json_decode($data); + + // $id = $data->decoded->id; + // if(isset($data->decoded->emp_code)){ + // $model = new EmployeeModel(); + // $user_data = $model->where('id', $id)->first(); + + // if($user_data['token_time_out'] > time()){ + // $data =["token_time_out" => time() + getenv('TOKENTIMEOUT') ]; + // $model->update($id, $data); + // return true; + // }else{ + + // // if($user_data['token_time_out'] != "" && $user_data['token_time_out'] != NULL) + + // $data =["token_time_out" => '']; + // $model->update($id, $data); + // header('Content-Type: application/json'); + // http_response_code(401); + // // $error = json_encode(["status" => 401, "message" => $data->message]); + // $error = json_encode(["status" => 401, "message" => "Token is Invalid"]); + // echo $error; + // exit; + // } + // }else{ + // $model = new LevelContactModel(); + // $hr_data = $model->where('id', $id)->first(); + + // if($hr_data['token_time_out'] > time()){ + // $data =["token_time_out" => time() + getenv('TOKENTIMEOUT') ]; + // $model->update($id, $data); + // return true; + // }else{ + // $data =["token_time_out" => '']; + // $model->update($id, $data); + // header('Content-Type: application/json'); + // http_response_code(401); + // // $error = json_encode(["status" => 401, "message" => $data->message]); + // $error = json_encode(["status" => 401, "message" => "Token is Invalid"]); + // echo $error; + // exit; + // } + // } + + // } + // } else { + // header('Content-Type: application/json'); + // http_response_code(403); + // $error = json_encode(["status" => 403, "message" => "Access Forbidden!"]); + // echo $error; + // exit(); + // } + // } + public function before(RequestInterface $request, $arguments = null) { - $jwt = $request->getHeaderLine('Authorization'); + $authHeader = $request->getHeaderLine('Authorization'); - if ($jwt) { - if (JWTToken::validateJWT($jwt)) { - $data = JWTToken::validateJWT($jwt); - $data = json_decode($data); - - $id = $data->decoded->id; - if(isset($data->decoded->emp_code)){ - $model = new EmployeeModel(); - $user_data = $model->where('id', $id)->first(); - - if($user_data['token_time_out'] > time()){ - $data =["token_time_out" => time() + getenv('TOKENTIMEOUT') ]; - $model->update($id, $data); - return true; - }else{ - - // if($user_data['token_time_out'] != "" && $user_data['token_time_out'] != NULL) - - $data =["token_time_out" => '']; - $model->update($id, $data); - header('Content-Type: application/json'); - http_response_code(401); - // $error = json_encode(["status" => 401, "message" => $data->message]); - $error = json_encode(["status" => 401, "message" => "Token is Invalid"]); - echo $error; - exit; - } - }else{ - $model = new LevelContactModel(); - $hr_data = $model->where('id', $id)->first(); - - if($hr_data['token_time_out'] > time()){ - $data =["token_time_out" => time() + getenv('TOKENTIMEOUT') ]; - $model->update($id, $data); - return true; - }else{ - $data =["token_time_out" => '']; - $model->update($id, $data); - header('Content-Type: application/json'); - http_response_code(401); - // $error = json_encode(["status" => 401, "message" => $data->message]); - $error = json_encode(["status" => 401, "message" => "Token is Invalid"]); - echo $error; - exit; - } - } - - } - } else { - header('Content-Type: application/json'); - http_response_code(403); - $error = json_encode(["status" => 403, "message" => "Access Forbidden!"]); - echo $error; - exit(); + if (!$authHeader) { + return $this->reject(403, 'Access Forbidden'); } + + $result = JWTToken::validateJWT($authHeader); + + if ($result['status'] !== true) { + return $this->reject(401, $result['message']); + } + + $decoded = $result['decoded']; + $id = $decoded['id'] ?? null; + + if (!$id) { + return $this->reject(401, 'Invalid token payload'); + } + + if (isset($decoded['emp_code'])) { + $model = new EmployeeModel(); + } else { + $model = new LevelContactModel(); + } + + $user = $model->find($id); + + if (!$user || $user['token_time_out'] <= time()) { + $model->update($id, ['token_time_out' => null]); + return $this->reject(401, 'Token expired'); + } + + // Refresh sliding expiration + $model->update($id, [ + 'token_time_out' => time() + getenv('TOKENTIMEOUT') + ]); + + return true; + } + + private function reject(int $code, string $message) + { + return service('response') + ->setStatusCode($code) + ->setJSON(['status' => $code, 'message' => $message]) + ->send(); } public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) diff --git a/app/Helpers/JWTToken.php b/app/Helpers/JWTToken.php index 41d76b5..62b7281 100755 --- a/app/Helpers/JWTToken.php +++ b/app/Helpers/JWTToken.php @@ -18,9 +18,13 @@ use App\Models\LevelContactModel; class JWTToken { + + private const ALLOWED_ALG = 'HS512'; + + public static function encode($data =null) { - $secret_Key ="secret"; + $secret_Key = env('JWT_SECRET'); $request_data = (array)$data; @@ -47,30 +51,79 @@ class JWTToken } } - public static function validateJWT($jwt) + // public static function validateJWT($jwt) + // { + // $jwtParts = explode(' ', $jwt); + + // // print_r($jwtParts); + // if (count($jwtParts) != 2 || $jwtParts[0] == 'Bearer') { + // return false; + // } + + // $token = $jwtParts[1]; + + // try { + // $decoded = JWT::decode($token, new Key(env('JWT_SECRET'), 'HS512')); + // return json_encode(['status' => true, 'message' => 'Token is valid', 'decoded' => (array) $decoded]); + // } catch (ExpiredException $e) { + // return json_encode(['status' => false, 'message' => 'Token has expired']); + // } catch (BeforeValidException $e) { + // return json_encode(['status' => false, 'message' => 'Token is not yet valid']); + // } catch (SignatureInvalidException $e) { + // return json_encode(['status' => false, 'message' => 'Token signature is invalid']); + // } catch (\Exception $e) { + // return json_encode(['status' => false, 'message' => 'An error occurred while decoding the token']); + // } + + // } + + public static function validateJWT(string $authHeader) { - $jwtParts = explode(' ', $jwt); + // 1️⃣ Validate Authorization header + if (!preg_match('/^Bearer\s(\S+)$/', $authHeader, $matches)) { + return ['status' => false, 'message' => 'Invalid Authorization header']; + } - // print_r($jwtParts); - if (count($jwtParts) != 2 || $jwtParts[0] == 'Bearer') { - return false; - } + $token = $matches[1]; - $token = $jwtParts[1]; + // 2️⃣ Decode JWT header manually + $jwtParts = explode('.', $token); + if (count($jwtParts) !== 3) { + return ['status' => false, 'message' => 'Malformed JWT']; + } - try { - $decoded = JWT::decode($token, new Key("secret", 'HS512')); - return json_encode(['status' => true, 'message' => 'Token is valid', 'decoded' => (array) $decoded]); - } catch (ExpiredException $e) { - return json_encode(['status' => false, 'message' => 'Token has expired']); - } catch (BeforeValidException $e) { - return json_encode(['status' => false, 'message' => 'Token is not yet valid']); - } catch (SignatureInvalidException $e) { - return json_encode(['status' => false, 'message' => 'Token signature is invalid']); - } catch (\Exception $e) { - return json_encode(['status' => false, 'message' => 'An error occurred while decoding the token']); - } + $header = json_decode(base64_decode(strtr($jwtParts[0], '-_', '+/')), true); + // 3️⃣ Reject missing or NONE algorithm + if ( + empty($header['alg']) || + $header['alg'] === 'none' || + $header['alg'] !== self::ALLOWED_ALG + ) { + return ['status' => false, 'message' => 'Invalid or unsupported JWT algorithm']; + } + + // 4️⃣ Enforce signature validation + try { + $decoded = JWT::decode( + $token, + new Key(env('JWT_SECRET'), self::ALLOWED_ALG) + ); + + return [ + 'status' => true, + 'decoded' => (array) $decoded + ]; + + } catch (ExpiredException $e) { + return ['status' => false, 'message' => 'Token expired']; + } catch (BeforeValidException $e) { + return ['status' => false, 'message' => 'Token not yet valid']; + } catch (SignatureInvalidException $e) { + return ['status' => false, 'message' => 'Invalid token signature']; + } catch (\Exception $e) { + return ['status' => false, 'message' => 'Token validation failed']; + } } diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php index 3372200..5ddf424 100755 --- a/app/Helpers/utility_helper.php +++ b/app/Helpers/utility_helper.php @@ -666,3 +666,29 @@ if (!function_exists('check_pay_by_employee_or_company')) { } +if (!function_exists('canSendOtp')) { + function canSendOtp(array $row, int $limitSeconds = 60): array + { + // If OTP does not exist → allow + if (empty($row['otp']) || empty($row['updated_at'])) { + return ['allowed' => true]; + } + + $lastUpdated = strtotime($row['updated_at']); + $currentTime = time(); + + // Calculate expiry time + $allowedAfter = $lastUpdated + $limitSeconds; + + // If still within limit → block + if ($currentTime < $allowedAfter) { + return [ + 'allowed' => false, + 'retry_after' => $allowedAfter - $currentTime + ]; + } + + return ['allowed' => true]; + } +} + From 42bd609ad8ee8ef9262b85f0e357170b4f48df9d Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Thu, 8 Jan 2026 18:04:11 +0530 Subject: [PATCH 10/18] GWM : token expiry issue in hr --- app/Filters/AuthJWT.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Filters/AuthJWT.php b/app/Filters/AuthJWT.php index 9530ebd..4eac9e5 100755 --- a/app/Filters/AuthJWT.php +++ b/app/Filters/AuthJWT.php @@ -104,6 +104,7 @@ class AuthJWT implements FilterInterface $model = new EmployeeModel(); } else { $model = new LevelContactModel(); + $id = $decoded['pre_hr_id'] ?? null; } $user = $model->find($id); From 375d0b132e0d180877aec665e77087aca0359bd9 Mon Sep 17 00:00:00 2001 From: velz Date: Fri, 9 Jan 2026 16:02:46 +0530 Subject: [PATCH 11/18] FEAT_RBAC --- .env.sample | 2 + .htaccess | 2 +- app/Config/Acl.php | 85 +++++++++++++++ app/Config/Filters.php | 5 + app/Controllers/LoginController.php | 8 +- app/Filters/AclFilter.php | 156 ++++++++++++++++++++++++++++ app/Libraries/AuthLogout.php | 2 +- 7 files changed, 255 insertions(+), 5 deletions(-) create mode 100644 app/Config/Acl.php create mode 100644 app/Filters/AclFilter.php diff --git a/.env.sample b/.env.sample index 36880c7..c302d13 100644 --- a/.env.sample +++ b/.env.sample @@ -183,3 +183,5 @@ CORS_MAX_AGE=7200 CORS_DEBUG=true APP_SIGNATURE = +TOKENTIMEOUT = +JWT_SECRET = \ No newline at end of file diff --git a/.htaccess b/.htaccess index 6782611..c9db48e 100755 --- a/.htaccess +++ b/.htaccess @@ -7,7 +7,7 @@ Options -Indexes ## ADDED for - block any script execution inside folder of public - + Deny from all # Disable PHP engine diff --git a/app/Config/Acl.php b/app/Config/Acl.php new file mode 100644 index 0000000..1fbea05 --- /dev/null +++ b/app/Config/Acl.php @@ -0,0 +1,85 @@ + ['public' => true], + '#^/logout#' => ['public' => true], + '#^/auth#' => ['public' => true], + '#^/oauth2callback#' => ['public' => true], + '#^/loginPos#' => ['public' => true], + '#^/getVerifyPosMobileNo#' => ['public' => true], + '#^/getVerifiedPosUserData#' => ['public' => true], + '#^/swagger#' => ['roles' => [ADMIN_ROLE_ID]], + '#^/fedeploy#' => ['roles' => [ADMIN_ROLE_ID]], + + // ===================== PUBLIC DOWNLOADS / FORMS ===================== + '#^/download-#' => ['public' => true], + '#^/claim-form-download#' => ['public' => true], + '#^/claims-feedback-form#' => ['public' => true], + '#^/autobookstackLogin#' => ['public' => true], + + // ===================== DASHBOARD ===================== + '#^/dashboard#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, STAFF_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + + // ===================== USER MANAGEMENT ===================== + '#^/user#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID], + 'teams' => [] + ], + + // ===================== CLIENT ===================== + '#^/client#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + + // ===================== EMPLOYEE / ENROLLMENT ===================== + '#^/employee#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [ENROLLMENT_TEAM_ID] + ], + + // ===================== MASTERS ===================== + '#^/master#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID], + 'teams' => [] + ], + '#^/util#' => [ + 'roles' => [ HEAD_ROLE_ID,ADMIN_ROLE_ID, MANAGER_ROLE_ID, ACCOUNT_MANAGER_ROLE_ID,STAFF_ROLE_ID], + 'teams' => [] + ], + + // ===================== LOGS ===================== + '#^/logs#' => [ + 'roles' => [ADMIN_ROLE_ID], + 'teams' => [] + ], + + // ===================== INTERNAL TEST ===================== + '#^/test#' => [ + 'roles' => [ADMIN_ROLE_ID], + 'teams' => [] + ], + + // ===================== API (JWT / SIGNED) ===================== + '#^/api#' => ['public' => true], + '#^/employeeRest#' => ['public' => true], + '#^/clientApi#' => ['public' => true], + // ===================== CLI ===================== + '#^/cli/#' => ['public' => true], + + // ===================== DEFAULT DENY (ZERO TRUST) ===================== + '#^/#' => [ + 'roles' => [ADMIN_ROLE_ID], + 'teams' => [] + ], + ]; +} diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 969dadf..e22e4af 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -18,6 +18,9 @@ use App\Filters\AuthJWT; use App\Filters\Cors; use App\Filters\GlobalPostFileUploadGuard; use App\Filters\SecurityInputFilter; +use App\Filters\AclFilter; + + class Filters extends BaseConfig { @@ -43,6 +46,7 @@ class Filters extends BaseConfig 'appSignature' => VerifyAppSignature::class, 'GlobalPostFileUploadGuard' => GlobalPostFileUploadGuard::class, 'SecurityInputFilter' => SecurityInputFilter::class, + 'AclFilter' => AclFilter::class, ]; @@ -56,6 +60,7 @@ class Filters extends BaseConfig public array $globals = [ 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], + 'AclFilter' => ['except' => 'login', 'logout', 'auth/*', 'oauth2callback', 'download-*', 'claim-form-download', 'claims-feedback-form', 'autobookstackLogin'], 'Cors', 'SecurityInputFilter', 'GlobalPostFileUploadGuard', diff --git a/app/Controllers/LoginController.php b/app/Controllers/LoginController.php index eb3d98e..aa5d9a8 100755 --- a/app/Controllers/LoginController.php +++ b/app/Controllers/LoginController.php @@ -31,20 +31,22 @@ class LoginController extends BaseController public function receiveGoogleOAuthResponse() { $UserModel = new UserModel(); - //echo 'DONE';die(); + // echo 'DONE';die(); if ($this->request->getGet('code')) { $code = (string) $this->request->getGet('code'); log_message('error', 'Get OAuth Responce Code Sucessfully'); log_message('error', 'OAuthResponceCode : `'.$code.'`'); $value = googleOAuthLogin($this->request->getGet('code')); + // log_message('error', "OAuthResponceCode :" . json_encode($value)); if($value){ + // print_r($value);//die; $user = $UserModel->getUserByEmail($value->email); if($user){ if($user->is_active !== '0'){ $user_team = $UserModel->getUserTeamsByUserID($user->id); // dd($user_team); - + session()->regenerate(true); $session_data = [ 'isLoggedIn' => True , 'userid' => $user->id, @@ -66,7 +68,7 @@ class LoginController extends BaseController log_message('error', 'User Login Sucessfully'); $this->getUserDeviceInfo($user->id, 'NhanceUser'); - return AuthLogout::logout(); + return redirect()->to(base_url('/dashboard/view')); }else{ log_message('error', 'User Not Active'); diff --git a/app/Filters/AclFilter.php b/app/Filters/AclFilter.php new file mode 100644 index 0000000..0f6e0c1 --- /dev/null +++ b/app/Filters/AclFilter.php @@ -0,0 +1,156 @@ +getPath(), '/'); + + // Base path: /PHP828APPS/ruc/nhance + $basePath = rtrim(parse_url(base_url(), PHP_URL_PATH), '/'); + + // Remove base path + if ($basePath && str_starts_with($fullPath, $basePath)) { + $path = substr($fullPath, strlen($basePath)); + } else { + $path = $fullPath; + } + + // Remove index.php if present + if (str_starts_with($path, '/index.php')) { + $path = substr($path, strlen('/index.php')); + } + + // Normalize + $path = '/' . ltrim($path, '/'); + + // Fallback + if ($path === '') { + $path = '/'; + } + + // echo'
BASH PATH: ' . base_url(); + // echo'
ACL RAW PATH: ' . $fullPath; + // echo'
ACL BASE PATH: ' . $basePath; + // echo'
ACL FINAL PATH: ' . $path; + // ===================== LOAD ACL ===================== + $acl = new Acl(); + $rules = $acl->rules; + // print_rr($rules);die; + // ===================== MATCH RULE ===================== + $matchedRule = null; + + foreach ($rules as $pattern => $rule) { + // echo "$pattern".'---------
'; + if (preg_match($pattern, $path)) { + // echo "matched - $pattern"; + $matchedRule = $rule; + break; // FIRST MATCH WINS + } + } + + // print_r($matchedRule);//die; + // ===================== NO RULE = DENY ===================== + if ($matchedRule === null) { + return $this->deny($path, 'No ACL rule matched'); + } + + // ===================== PUBLIC ROUTE ===================== + if (!empty($matchedRule['public'])) { + return; // ALLOW + } + + // ===================== AUTH CHECK ===================== + if (!check_session()) { + // For API requests return 401 JSON + if ($request->isAJAX() || str_starts_with($path, '/api') || str_starts_with($path, '/employeeRest')) { + return service('response') + ->setStatusCode(401) + ->setJSON(['error' => 'Unauthorized']); + } + + // For web redirect to login + return AuthLogout::logout(); + } + + // ===================== GET USER CONTEXT ===================== + + $userRole = check_role(); // + $userTeams = user_team(); // must return array of TEAM IDs + + $allowedRoles = $matchedRule['roles'] ?? []; + $allowedTeams = $matchedRule['teams'] ?? []; + // ===================== ROLE FIRST ===================== + if (!empty($allowedRoles) && in_array((int)$userRole, $allowedRoles, true)) { + return; // ALLOW + } + // ===================== TEAM FALLBACK ===================== + if (!empty($allowedTeams) && is_array($userTeams)) { + foreach ($userTeams as $teamId) { + if (in_array($teamId, $allowedTeams, true)) { + return; // ALLOW + } + } + } + // ===================== DENY ===================== + return $this->deny($path, 'Role/Team not permitted'); + } + + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + // nothing + } + + // ===================== DENY HANDLER ===================== + protected function deny(string $path, string $reason) + { + log_message('error', 'ACL BLOCKED: {user} {path} - {reason}', [ + 'user' => session()->get('userid') ?? 'guest', + 'path' => $path, + 'reason' => $reason, + ]); + + // API / AJAX → JSON + $request = service('request'); + if ($request->isAJAX() || str_starts_with($path, '/api') || str_starts_with($path, '/employeeRest')) { + return service('response') + ->setStatusCode(403) + ->setJSON([ + 'error' => 'Forbidden', + 'message' => 'You do not have permission to access this resource' + ]); + } + + $response = service('response'); + $response->setStatusCode(403); + $response->setBody(view('errors/404', [ + 'message' => '403 Access denied - You do not have permission to access this resource' + ])); + + return $response; + // Web → nice 403 page or simple text + return service('response') + ->setStatusCode(403) + ->setBody('403 Forbidden - Access denied - You do not have permission to access this resource'); + } +} diff --git a/app/Libraries/AuthLogout.php b/app/Libraries/AuthLogout.php index cfb1005..ac7786c 100644 --- a/app/Libraries/AuthLogout.php +++ b/app/Libraries/AuthLogout.php @@ -22,7 +22,7 @@ class AuthLogout setcookie( session_name(), // DO NOT hardcode cookie name - '', + null, time() - 42000, $params['path'], $params['domain'], From d59aeae917352b69ddfbc187b3f1524122ac868f Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Mon, 12 Jan 2026 11:57:02 +0530 Subject: [PATCH 12/18] gwm : wrong mpin --- app/Config/Routes.php | 2 +- app/Controllers/RestAuthenticationController.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 2610b9e..4c02e4f 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -453,7 +453,7 @@ $routes->group("/api", ["filter" => "authJWT"], function ($routes) { // $routes->post("employeeRest/createOrUpdateEmployeePolicySiAmount", "EmployeeRestController::createOrUpdateEmployeePolicySiAmount"); // $routes->post("employeeRest/calculatePremium", "EmployeeRestController::calculatePremium"); - + // $routes->post("updateMpin", "RestAuthenticationController::updateMpin"); $routes->group("employeeRest", ['filter' => ['appSignature' , 'authJWT'] ], function ($routes) { $routes->post('logout', 'RestAuthenticationController::logout'); diff --git a/app/Controllers/RestAuthenticationController.php b/app/Controllers/RestAuthenticationController.php index 15469ec..41a716d 100755 --- a/app/Controllers/RestAuthenticationController.php +++ b/app/Controllers/RestAuthenticationController.php @@ -986,7 +986,7 @@ class RestAuthenticationController extends AdminController log_message('error', ' '); log_message('error', '************************ PRE END ********************************'); - $result = ['user_verification' => false , 'message' => "User not found"]; + $result = ['mpin_verification' => false , 'message' => "Wrong Mpin"]; return $this->respond(['status' => 'failed','code' => 404,'data' => $result],200); } From a5628280c680a43d2f4edbf6d0b3d5d00eb6a46e Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Mon, 12 Jan 2026 12:04:44 +0530 Subject: [PATCH 13/18] gwm : wrong mpin --- app/Config/Filters.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Config/Filters.php b/app/Config/Filters.php index e22e4af..78da473 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -46,7 +46,7 @@ class Filters extends BaseConfig 'appSignature' => VerifyAppSignature::class, 'GlobalPostFileUploadGuard' => GlobalPostFileUploadGuard::class, 'SecurityInputFilter' => SecurityInputFilter::class, - 'AclFilter' => AclFilter::class, + // 'AclFilter' => AclFilter::class, ]; From 51689bd82caa08d94b4e5d4ff002c67aeb2db28a Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Mon, 12 Jan 2026 12:07:51 +0530 Subject: [PATCH 14/18] gwm : wrong mpin --- app/Config/Filters.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 78da473..384d143 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -60,7 +60,7 @@ class Filters extends BaseConfig public array $globals = [ 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], - 'AclFilter' => ['except' => 'login', 'logout', 'auth/*', 'oauth2callback', 'download-*', 'claim-form-download', 'claims-feedback-form', 'autobookstackLogin'], + // 'AclFilter' => ['except' => 'login', 'logout', 'auth/*', 'oauth2callback', 'download-*', 'claim-form-download', 'claims-feedback-form', 'autobookstackLogin'], 'Cors', 'SecurityInputFilter', 'GlobalPostFileUploadGuard', From 80e47ce1c9ed6c1c7d4fe9e590492040c5804a12 Mon Sep 17 00:00:00 2001 From: Gowtham M Date: Mon, 12 Jan 2026 12:37:48 +0530 Subject: [PATCH 15/18] gwm : mpin message changed --- app/Controllers/RestAuthenticationController.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/Controllers/RestAuthenticationController.php b/app/Controllers/RestAuthenticationController.php index 41a716d..235f86a 100755 --- a/app/Controllers/RestAuthenticationController.php +++ b/app/Controllers/RestAuthenticationController.php @@ -978,6 +978,12 @@ class RestAuthenticationController extends AdminController $old_mpin = $this->request->getJSON()->old_mpin; $mpin = $this->request->getJSON()->new_mpin; + if($old_mpin == $mpin) + { + $result = ['mpin_verification' => false , 'message' => "New MPIN must be different from the old MPIN"]; + return $this->respond(['status' => 'failed','code' => 404,'data' => $result],200); + } + $empdata = RestAuthHelper::getPreAndPostDataByEmailOrMobile(['email_id' => $email_id, 'mobile_number' => $mobile_number, 'old_mpin' => $old_mpin ]); // print_r($empdata); die; @@ -986,7 +992,7 @@ class RestAuthenticationController extends AdminController log_message('error', ' '); log_message('error', '************************ PRE END ********************************'); - $result = ['mpin_verification' => false , 'message' => "Wrong Mpin"]; + $result = ['mpin_verification' => false , 'message' => "Old MPIN is incorrect"]; return $this->respond(['status' => 'failed','code' => 404,'data' => $result],200); } From ffc6c7f742c730d349a9655b2b3c8772caf6eba9 Mon Sep 17 00:00:00 2001 From: velz Date: Mon, 12 Jan 2026 14:28:13 +0530 Subject: [PATCH 16/18] FIX_ACL&HTTP_REQ_LOG --- app/Config/Filters.php | 2 +- app/Helpers/HttpRequestHelper.php | 177 +++++++++++++++++++++++++++--- 2 files changed, 165 insertions(+), 14 deletions(-) diff --git a/app/Config/Filters.php b/app/Config/Filters.php index e22e4af..08752c5 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -60,7 +60,7 @@ class Filters extends BaseConfig public array $globals = [ 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], - 'AclFilter' => ['except' => 'login', 'logout', 'auth/*', 'oauth2callback', 'download-*', 'claim-form-download', 'claims-feedback-form', 'autobookstackLogin'], + 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','/employeeRest/*']], 'Cors', 'SecurityInputFilter', 'GlobalPostFileUploadGuard', diff --git a/app/Helpers/HttpRequestHelper.php b/app/Helpers/HttpRequestHelper.php index a3a3da6..3e072e8 100755 --- a/app/Helpers/HttpRequestHelper.php +++ b/app/Helpers/HttpRequestHelper.php @@ -4,24 +4,175 @@ namespace App\Helpers; class HttpRequestHelper { - public static function getRequestInfo() + public static function getRequestInfo(): array { $request = service('request'); + + $uaString = $request->getHeaderLine('User-Agent'); + + // Detect platform & browser using robust fallback logic + [$platform, $browser] = self::detectFromUserAgent($uaString); + $data = [ - 'ip' => $request->getIPAddress(), - 'platform' => $request->getUserAgent()->getPlatform(), - 'browser' => ($request->getUserAgent()->getBrowser().' '.$request->getUserAgent()->getVersion()), - 'method' => $request->getMethod(), - 'endpoint' => $request->uri->getPath(), - 'getparams' => $request->uri->getSegments(), - 'postparams' => $request->getPost() + 'ip' => $request->getIPAddress(), + 'platform' => $platform, + 'browser' => $browser, + 'method' => strtoupper($request->getMethod()), + 'endpoint' => $request->uri->getPath(), + 'getparams' => json_encode($request->uri->getSegments(), JSON_UNESCAPED_UNICODE), + 'postparams' => self::sanitizePostForLog($request->getPost()), ]; - $data['method'] = (isset($data['method']) ? strtoupper($data['method']) : $data['method']); - $data['getparams'] = is_array($data['getparams']) ? json_encode($data['getparams']) : $data['getparams']; - $data['postparams'] = is_array($data['postparams']) ? json_encode($data['postparams']) : $data['postparams']; return $data; } - public static function add($payload) - {return $payload['a'] + $payload['b'];} + + /** + * Detect platform & browser from UA string (reliable fallback) + */ + private static function detectFromUserAgent(string $ua): array + { + $uaLower = strtolower($ua); + + // ========================= + // PLATFORM DETECTION + // ========================= + $platform = 'Unknown'; + + if (str_contains($uaLower, 'windows nt 11') || str_contains($uaLower, 'windows 11')) { + $platform = 'Windows 11'; + } elseif (str_contains($uaLower, 'windows nt 10')) { + $platform = 'Windows 10'; + } elseif (str_contains($uaLower, 'windows nt 6.3')) { + $platform = 'Windows 8.1'; + } elseif (str_contains($uaLower, 'windows nt 6.2')) { + $platform = 'Windows 8'; + } elseif (str_contains($uaLower, 'windows nt 6.1')) { + $platform = 'Windows 7'; + } elseif (str_contains($uaLower, 'windows nt 6.0')) { + $platform = 'Windows Vista'; + } elseif (str_contains($uaLower, 'windows nt 5.1') || str_contains($uaLower, 'windows xp')) { + $platform = 'Windows XP'; + } elseif (str_contains($uaLower, 'android')) { + $platform = 'Android'; + } elseif (str_contains($uaLower, 'iphone')) { + $platform = 'iOS (iPhone)'; + } elseif (str_contains($uaLower, 'ipad')) { + $platform = 'iOS (iPad)'; + } elseif (str_contains($uaLower, 'ipod')) { + $platform = 'iOS (iPod)'; + } elseif (str_contains($uaLower, 'mac os') || str_contains($uaLower, 'macintosh')) { + $platform = 'Mac OS'; + } elseif (str_contains($uaLower, 'cros')) { + $platform = 'Chrome OS'; + } elseif (str_contains($uaLower, 'linux')) { + $platform = 'Linux'; + } elseif (str_contains($uaLower, 'freebsd')) { + $platform = 'FreeBSD'; + } elseif (str_contains($uaLower, 'openbsd')) { + $platform = 'OpenBSD'; + } elseif (str_contains($uaLower, 'netbsd')) { + $platform = 'NetBSD'; + } elseif (str_contains($uaLower, 'unix')) { + $platform = 'Unix'; + } elseif (str_contains($uaLower, 'symbian')) { + $platform = 'Symbian'; + } elseif (str_contains($uaLower, 'blackberry')) { + $platform = 'BlackBerry'; + } elseif (str_contains($uaLower, 'tizen')) { + $platform = 'Tizen'; + } elseif (str_contains($uaLower, 'webos')) { + $platform = 'WebOS'; + } elseif (str_contains($uaLower, 'kaios')) { + $platform = 'KaiOS'; + } elseif (str_contains($uaLower, 'harmonyos')) { + $platform = 'HarmonyOS'; + } elseif (str_contains($uaLower, 'watchos')) { + $platform = 'watchOS'; + } elseif (str_contains($uaLower, 'tv os') || str_contains($uaLower, 'tvos')) { + $platform = 'tvOS'; + } + + // ========================= + // BROWSER / CLIENT DETECTION + // ========================= + $browser = 'Unknown'; + + // Bots & tools first + if (preg_match('/googlebot|bingbot|slurp|duckduckbot|baiduspider|yandexbot|sogou|exabot|facebot|ia_archiver/i', $ua)) { + $browser = 'Search Bot'; + } elseif (preg_match('/postman/i', $ua)) { + $browser = 'Postman'; + } elseif (preg_match('/insomnia/i', $ua)) { + $browser = 'Insomnia'; + } elseif (preg_match('/curl/i', $ua)) { + $browser = 'curl'; + } elseif (preg_match('/wget/i', $ua)) { + $browser = 'wget'; + } + + // Real browsers + elseif (preg_match('/edg\/([\d\.]+)/i', $ua, $m)) { + $browser = 'Edge ' . $m[1]; + } elseif (preg_match('/opr\/([\d\.]+)/i', $ua, $m)) { + $browser = 'Opera ' . $m[1]; + } elseif (preg_match('/vivaldi\/([\d\.]+)/i', $ua, $m)) { + $browser = 'Vivaldi ' . $m[1]; + } elseif (preg_match('/brave\/([\d\.]+)/i', $ua, $m)) { + $browser = 'Brave ' . $m[1]; + } elseif (preg_match('/chrome\/([\d\.]+)/i', $ua, $m)) { + $browser = 'Chrome ' . $m[1]; + } elseif (preg_match('/firefox\/([\d\.]+)/i', $ua, $m)) { + $browser = 'Firefox ' . $m[1]; + } elseif (preg_match('/safari\/([\d\.]+)/i', $ua, $m)) { + $browser = 'Safari ' . $m[1]; + } elseif (preg_match('/msie\s([\d\.]+)/i', $ua, $m) || preg_match('/trident\/.*rv:([\d\.]+)/i', $ua, $m)) { + $browser = 'Internet Explorer ' . $m[1]; + } + + // In-app browsers + elseif (preg_match('/fbav|fban/i', $ua)) { + $browser = 'Facebook In-App Browser'; + } elseif (preg_match('/instagram/i', $ua)) { + $browser = 'Instagram In-App Browser'; + } elseif (preg_match('/linkedinapp/i', $ua)) { + $browser = 'LinkedIn In-App Browser'; + } elseif (preg_match('/twitter/i', $ua)) { + $browser = 'Twitter/X In-App Browser'; + } + + return [$platform, $browser]; + } + + + /** + * Remove sensitive fields before logging POST + */ + private static function sanitizePostForLog(array $post): string + { + if (empty($post)) { + return json_encode([]); + } + + $sensitiveKeys = [ + 'password', 'pass', 'pwd', + 'token', 'access_token', 'refresh_token', + 'secret', 'api_key', 'authorization', + 'otp', 'pin' + ]; + + foreach ($post as $k => $v) { + foreach ($sensitiveKeys as $sk) { + if (stripos($k, $sk) !== false) { + $post[$k] = '***MASKED***'; + } + } + } + + return json_encode($post, JSON_UNESCAPED_UNICODE); + } + + public static function add($payload) + { + return $payload['a'] + $payload['b']; + } } From b39eac1f31816ccfedf441c9a5f36d717d583a6b Mon Sep 17 00:00:00 2001 From: velz Date: Tue, 13 Jan 2026 10:36:42 +0530 Subject: [PATCH 17/18] FIX_mPIN_NULl_HANDLED --- app/Config/Filters.php | 2 +- app/Controllers/RestAuthenticationController.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 08752c5..e14b7d8 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -60,7 +60,7 @@ class Filters extends BaseConfig public array $globals = [ 'before' => [ 'HttpRequestLog' => ['except' => 'cli/*'], - 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','/employeeRest/*']], + 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','/employeeRest/*','processjob']], 'Cors', 'SecurityInputFilter', 'GlobalPostFileUploadGuard', diff --git a/app/Controllers/RestAuthenticationController.php b/app/Controllers/RestAuthenticationController.php index 235f86a..af58a6d 100755 --- a/app/Controllers/RestAuthenticationController.php +++ b/app/Controllers/RestAuthenticationController.php @@ -1271,7 +1271,7 @@ class RestAuthenticationController extends AdminController $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - checkMpin: Mpin - Exist"); log_message('error', ' '); log_message('error', '************************ PRE END ********************************'); - return $this->respond(['status' => 'success','code' => 200,'data' => "", 'message' => "Mpin - exist" , 'Mpin' =>$employeeData["mpin"], 'is_mpin_skipped' => $employeeData['is_mpin_skipped'], 'is_biometric_enabled' => $employeeData['is_biometric_enabled']],200); + return $this->respond(['status' => 'success','code' => 200,'data' => "", 'message' => "Mpin - exist" , 'Mpin' =>$employeeData["mpin"], 'is_mpin_skipped' => $employeeData['is_mpin_skipped'] ?? 0, 'is_biometric_enabled' => $employeeData['is_biometric_enabled'] ?? 0 ],200); } else { $this->myLogger->logme("error", "REST-AUTH-CONTROLLER - checkMpin: Mpin - not found in PRE so call the thirdpartapi to the POST to check the MPIN"); log_message('error', ' '); From 59dd0644b684864f2e7a8e13b021de6d90303295 Mon Sep 17 00:00:00 2001 From: velz Date: Tue, 13 Jan 2026 11:08:34 +0530 Subject: [PATCH 18/18] FIX_EMAIL_ROUTE_EXCEPT_IN_I/P_SANITIZATION --- app/Config/Filters.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Config/Filters.php b/app/Config/Filters.php index e14b7d8..ecf5672 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -62,7 +62,7 @@ class Filters extends BaseConfig 'HttpRequestLog' => ['except' => 'cli/*'], 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','/employeeRest/*','processjob']], 'Cors', - 'SecurityInputFilter', + 'SecurityInputFilter' => ['except' => ['notification/create','test_mail'] ], 'GlobalPostFileUploadGuard', // 'invalidchars', ],