diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 0042bda..96d34a1 100755 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -20,6 +20,8 @@ use App\Filters\GlobalPostFileUploadGuard; use App\Filters\SecurityInputFilter; use App\Filters\AclFilter; use App\Filters\RateLimitFilter; +use App\Filters\JwtApiRateLimitFilter; +use App\Filters\AuthApiRateLimitFilter; @@ -49,6 +51,8 @@ class Filters extends BaseConfig 'SecurityInputFilter' => SecurityInputFilter::class, 'AclFilter' => AclFilter::class, 'ratelimit' => RateLimitFilter::class, + 'AuthApiRateLimitFilter' => AuthApiRateLimitFilter::class, + 'JwtApiRateLimitFilter' => JwtApiRateLimitFilter::class, ]; @@ -62,7 +66,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/*','processjob']], + 'AclFilter' => ['except' => ['login', 'logout', 'auth/*', 'oauth2callback','claim-form-download', 'claims-feedback-form', 'autobookstackLogin','/employeeRest/*','processjob', 'getPreEmployeePolicyCount']], 'Cors', 'SecurityInputFilter' => ['except' => ['/client/notification/create','test_mail'] ], 'GlobalPostFileUploadGuard', diff --git a/app/Config/RateLimiter.php b/app/Config/RateLimiter.php new file mode 100644 index 0000000..99d8b60 --- /dev/null +++ b/app/Config/RateLimiter.php @@ -0,0 +1,89 @@ + 60, // max requests + 'window' => 60, // window in seconds + 'violation_soft' => 3, // violations before soft block + ]; + + /* + |-------------------------------------------------------------------------- + | Auth API Routes (verifyMobile, verifyOTP, etc.) + |-------------------------------------------------------------------------- + */ + public array $authApi = [ + 'limit' => 10, // max requests per window + 'window' => 180, // window in seconds (3 min) + 'violation_soft' => 3, // failed attempts before soft block + ]; + + /* + |-------------------------------------------------------------------------- + | User-Level Progressive Block Durations (seconds) + | 0 = permanent until manual unblock + |-------------------------------------------------------------------------- + */ + public array $userBlock = [ + 'soft_duration' => 0, // permanent, manual unblock only + 'medium_duration' => 7200, // 2 hours + 'hard_duration' => 86400, // 24 hours + // attempts while at a block level before escalating to next + 'medium_trigger' => 1, // attempts during soft → medium + 'hard_trigger' => 1, // attempts during medium → hard + ]; + + /* + |-------------------------------------------------------------------------- + | IP-Level Throttle & Progressive Block (independent of user) + |-------------------------------------------------------------------------- + */ + public array $ipBlock = [ + 'limit' => 120, // max requests per window + 'window' => 60, // window in seconds + 'violation_soft' => 5, // violations before soft block + 'soft_duration' => 0, // permanent, manual unblock only + 'medium_duration' => 7200, // 2 hours + 'hard_duration' => 86400, // 24 hours + 'medium_trigger' => 1, // attempts during soft → medium + 'hard_trigger' => 1, // attempts during medium → hard + ]; + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefixes + |-------------------------------------------------------------------------- + */ + public array $cacheKeys = [ + 'ip_count' => 'rl_ip_count_', + 'ip_violations' => 'rl_ip_viol_', + 'ip_block' => 'rl_ip_block_', + 'ip_block_hits' => 'rl_ip_blkhit_', + 'user_count' => 'rl_usr_count_', + 'user_violations' => 'rl_usr_viol_', + 'user_block' => 'rl_usr_block_', + 'user_block_hits' => 'rl_usr_blkhit_', + ]; + + /* + |-------------------------------------------------------------------------- + | HTTP Status Codes per block level + |-------------------------------------------------------------------------- + */ + public array $statusCodes = [ + 'throttle' => 429, + 'soft' => 429, + 'medium' => 403, + 'hard' => 451, + ]; +} diff --git a/app/Config/Routes.php b/app/Config/Routes.php index a0eb3e0..cb4c782 100755 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -454,7 +454,7 @@ $routes->group("/api", ["filter" => [ 'ratelimit' , 'authJWT' ] ], function ($r // $routes->post("employeeRest/createOrUpdateEmployeePolicySiAmount", "EmployeeRestController::createOrUpdateEmployeePolicySiAmount"); // $routes->post("employeeRest/calculatePremium", "EmployeeRestController::calculatePremium"); // $routes->post("updateMpin", "RestAuthenticationController::updateMpin"); -$routes->group("employeeRest", ['filter' => [ 'GlobalPostFileUploadGuard', 'ratelimit' , 'appSignature' , 'authJWT' ] ], function ($routes) { +$routes->group("employeeRest", ['filter' => [ 'GlobalPostFileUploadGuard', 'appSignature' , 'authJWT','JwtApiRateLimitFilter' ] ], function ($routes) { $routes->post('logout', 'RestAuthenticationController::logout'); @@ -507,7 +507,7 @@ $routes->group("employeeRest", ['filter' => [ 'GlobalPostFileUploadGuard', 'rate }); -$routes->group("employeeRest", ['filter' => ['ratelimit' , 'appSignature'] ], function ($routes) { +$routes->group("employeeRest", ['filter' => ['appSignature','AuthApiRateLimitFilter'] ], function ($routes) { //Employee login api's $routes->post("verifyEmployeeNumber", "RestAuthenticationController::verifyEmployeeWithMobileNumber"); diff --git a/app/Config/Services.php b/app/Config/Services.php index fab85a5..d37961a 100755 --- a/app/Config/Services.php +++ b/app/Config/Services.php @@ -8,6 +8,7 @@ use App\Libraries\MyLogger; use App\Libraries\GmailAPI; use App\Libraries\MyGoogleDrive; use App\Libraries\DataServiceSqlite; +use App\Libraries\RateLimiterService; use App\Controllers\Home; /** @@ -80,5 +81,14 @@ class Services extends BaseService return new MyGoogleDrive(); } + + public static function limiter($getShared = true) + { + if ($getShared) { + return static::getSharedInstance('limiter'); + } + + return new RateLimiterService(); + } } diff --git a/app/Controllers/EmployeeController.php b/app/Controllers/EmployeeController.php index 0f40f94..b3718c0 100755 --- a/app/Controllers/EmployeeController.php +++ b/app/Controllers/EmployeeController.php @@ -410,9 +410,9 @@ class EmployeeController extends AdminController //endof validation process if (isset($result['error_summary']) && count($result['error_summary'])) { if(!$is_post_request){ - return ['status' => false, 'message' => 'file rejected with errors', 'file_id' => $file_id]; + return ['status' => false, 'message' => 'File rejected with errors', 'file_id' => $file_id]; }else{ - return $this->respond(['dataStatus' => false, 'code' => 404, 'message' => 'file rejected with errors'], 200); + 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 diff --git a/app/Controllers/EmployeeRestController.php b/app/Controllers/EmployeeRestController.php index 800b172..c5d99b3 100755 --- a/app/Controllers/EmployeeRestController.php +++ b/app/Controllers/EmployeeRestController.php @@ -141,7 +141,7 @@ class EmployeeRestController extends AdminController return $this->respond(['status' => 'success','code' => 200,'data' => $result, 'AccountManagerDetails'=> isset($AccountManagerDetails[0]) ? $AccountManagerDetails[0] : null ],200); } else { $result = "No Match's"; - return $this->respond(['status' => 'failed','code' => 404,'data' => $result],404); + return $this->respond(['status' => 'failed','code' => 404,'data' => $result],200); } } catch (\Throwable $th) { return $this->respond(['status' => 'failed','code' => 500,'data' => $th],500); @@ -162,7 +162,7 @@ class EmployeeRestController extends AdminController return $this->respond(['status' => 'success','code' => 200,'data' => $result],200); } else { $result = "No Match's"; - return $this->respond(['status' => 'failed','code' => 404,'data' => $result],404); + return $this->respond(['status' => 'failed','code' => 404,'data' => $result],200); } } } catch (\Throwable $th) { @@ -190,7 +190,7 @@ class EmployeeRestController extends AdminController } else { - return $this->respond(['status' => 'failed','code' => 404,'data' => []],404); + return $this->respond(['status' => 'failed','code' => 404,'data' => []],200); } } catch (\Throwable $th) { return $this->respond(['status' => 'failed','code' => 500,'data' => $th],500); @@ -220,7 +220,7 @@ class EmployeeRestController extends AdminController return $this->respond(['status' => 'success','code' => 200,'data' => $result], 200); } else { $result = "No Matches"; - return $this->respond(['status' => 'failed','code' => 404,'data' => $result], 404); + return $this->respond(['status' => 'failed','code' => 404,'data' => $result], 200); } } } catch (\Exception $e) { @@ -584,7 +584,7 @@ class EmployeeRestController extends AdminController return $this->respond(['status' => 'success','code' => 200,'data' =>[] ], 200); }else{ - return $this->respond(['status' => 'failed','code' => 404,'data' => [] ], 404); + return $this->respond(['status' => 'failed','code' => 404,'data' => [] ], 200); } @@ -615,7 +615,7 @@ class EmployeeRestController extends AdminController $openForEnrollment = $this->findThePolicyIsOpenForEnrollment($requestData[0]->client_policy_id, $requestData[0]->emp_code); } - if($openForEnrollment == false){ return $this->respond(['status' => 'failed','code' => 404,'data' => 'Enrollment closed'], 404); } + if($openForEnrollment == false){ return $this->respond(['status' => 'failed','code' => 404,'data' => 'Enrollment closed'], 200); } foreach ($requestData as $key => $value) { @@ -692,7 +692,7 @@ class EmployeeRestController extends AdminController if ($empData) { return $this->respond(['status' => 'success', 'code' => 200, 'data' => $empData], 200); } else { - return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 404); + return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 200); } @@ -805,7 +805,7 @@ class EmployeeRestController extends AdminController if ($ClientPolicyData) { return $this->respond(['status' => 'success', 'code' => 200, 'data' => $result], 200); } else { - return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 404); + return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 200); } @@ -1211,7 +1211,7 @@ class EmployeeRestController extends AdminController $this->fileModel->where('id', $file_id)->set(['status' => 'success','reason' => '','error_data' => ''])->update(); return $this->respond(['status' => 'success', 'code' => 200, 'message' => "Success" ], 200); }else{ - return $this->respond(['status' => 'failed', 'code' => 404, 'message' => "Client id and Client Policy id is Not Match!" ], 404); + return $this->respond(['status' => 'failed', 'code' => 404, 'message' => "Client id and Client Policy id is Not Match!" ], 200); } } catch (\Throwable $th) { $this->myLogger->logme("error", ($th->getMessage().' --- '.$th->getLine() . '----' . $th->getTraceAsString())); @@ -2168,10 +2168,10 @@ class EmployeeRestController extends AdminController // return $restAuthController->callThirdPartyGETAPI($queryParams, 'getClientDetails'); // } else { - // return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 404); + // return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 200); // } // } else { - // return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 404); + // return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 200); // } // } catch (\Exception $e) { // return $this->respond(['status' => 'failed', 'code' => 500, 'data' => $e->getMessage()], 500); @@ -2189,15 +2189,19 @@ class EmployeeRestController extends AdminController if (!empty($pre_client_id)) { + if (is_string($pre_client_id) && preg_match('/^[a-f0-9]{32}$/i', $pre_client_id)) { + $client = $this->clientModel->where('MD5(id)', $pre_client_id)->first(); + }else{ + $client = $this->clientModel->where('id', $pre_client_id)->first(); + } - $client = $this->clientModel->where('md5(id)', $pre_client_id)->first(); if ($client) { $client['client_logo'] = base_url() . 'public/uploads/logo/' . $client['client_logo']; $clientPolicy = $this->clientPolicyModel - ->where('md5(client_id)', $pre_client_id) + ->where('client_id', $client['id'] ?? null) ->where('client_branch_id', $pre_branch_id) ->findAll(); @@ -2213,7 +2217,7 @@ class EmployeeRestController extends AdminController ], 200); } else { - return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 404); + return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 200); } } elseif (!empty($post_client_id)) { @@ -2227,7 +2231,7 @@ class EmployeeRestController extends AdminController } else { - return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 404); + return $this->respond(['status' => 'failed', 'code' => 404, 'data' => []], 200); } } catch (\Exception $e) { @@ -3095,7 +3099,7 @@ class EmployeeRestController extends AdminController return $employee_data_group_by_family; }else{ // dd ($employee_data_group_by_family); - return $this->respond(['status' => 'success','code' => (count($employee_data_group_by_family) ? 200 : 404),'data' => [$employee_data_group_by_family] ], 200); + return $this->respond(['status' => 'success','code' => (count($employee_data_group_by_family) ? 200 : 200),'data' => [$employee_data_group_by_family] ], 200); } } @@ -3121,7 +3125,7 @@ class EmployeeRestController extends AdminController } if(count($policyId) == 0){ - return $this->respond(['status' => 'failed','code' => (count($policyId) ? 200 : 404),'data' => [] ], 200); + return $this->respond(['status' => 'failed','code' => (count($policyId) ? 200 : 200),'data' => [] ], 200); } @@ -3169,9 +3173,9 @@ class EmployeeRestController extends AdminController if($result) { - return $this->respond(['status' => 'success','code' => (count($result) ? 200 : 404),'data' => $result ], 200); + return $this->respond(['status' => 'success','code' => (count($result) ? 200 : 200),'data' => $result ], 200); }else{ - return $this->respond(['status' => 'failed','code' => (count($result) ? 200 : 404),'data' => [] ], 200); + return $this->respond(['status' => 'failed','code' => (count($result) ? 200 : 200),'data' => [] ], 200); } } @@ -3572,7 +3576,7 @@ class EmployeeRestController extends AdminController } else { - return $this->respond(['status' => 'failed','code' => 404,'data' => 'No Data'],404); + return $this->respond(['status' => 'failed','code' => 404,'data' => 'No Data'],200); } } catch (\Throwable $th) { return $this->respond(['status' => 'failed','code' => 500,'data' => $th],500); @@ -3596,7 +3600,7 @@ class EmployeeRestController extends AdminController } else { - return $this->respond(['status' => 'failed','code' => 404,'data' => 'No Data'],404); + return $this->respond(['status' => 'failed','code' => 404,'data' => 'No Data'],200); } } catch (\Throwable $th) { return $this->respond(['status' => 'failed','code' => 500,'data' => $th],500); @@ -3657,7 +3661,7 @@ class EmployeeRestController extends AdminController return $this->respond(['status' => 'failed', 'code' => 400, 'message' => 'Firebase Token is required'], 400); } } else { - return $this->respond(['status' => 'failed', 'code' => 404, 'message' => 'Employee not found'], 404); + return $this->respond(['status' => 'failed', 'code' => 404, 'message' => 'Employee not found'], 200); } } catch (\Throwable $th) { log_message('error', 'An error occurred: ' . $th->getMessage()); diff --git a/app/Controllers/MasterController.php b/app/Controllers/MasterController.php index 24527ad..812b23e 100755 --- a/app/Controllers/MasterController.php +++ b/app/Controllers/MasterController.php @@ -156,6 +156,7 @@ class MasterController extends AdminController $this->myLogger->logme('error','Edit Insurer Onboarding function called'); $headerData['page_name'] = 'Edit Insurer Master'; + print_r($headerData);die; $types = array( (object) array('id' => 'pvt', 'name' => 'PVT'), diff --git a/app/Controllers/RestAuthenticationController.php b/app/Controllers/RestAuthenticationController.php index b15d191..e29c0a7 100755 --- a/app/Controllers/RestAuthenticationController.php +++ b/app/Controllers/RestAuthenticationController.php @@ -142,6 +142,7 @@ class RestAuthenticationController extends AdminController log_message('error', ' '); log_message('error', '************************ PRE END ********************************'); $result = ['user_verification' => false , 'message' => "User not found"]; + recordRateLimitFailure(); return $this->respond(['status' => 'failed','code' => 404,'data' => $result],200); } @@ -320,6 +321,7 @@ class RestAuthenticationController extends AdminController } $result = ['user_verification' => false , 'message' => "User not found"]; + recordRateLimitFailure(); return $this->respond(['status' => 'failed','code' => 404,'data' => $result],200); } @@ -445,10 +447,12 @@ class RestAuthenticationController extends AdminController $otp = isset($this->request->getJSON()->otp) ? $this->request->getJSON()->otp : null; if(empty($otp)){ + recordRateLimitFailure(); return $this->respond(['status' => 'OTP is required','code' => 400,'message' => 'OTP is required'], 200); } if (empty($mobile_number) && empty($email_id)) { + recordRateLimitFailure(); return $this->respond(['status' => 'failed','code' => 400,'message' => 'Mobile number or Email ID is required'], 200); } @@ -472,9 +476,11 @@ class RestAuthenticationController extends AdminController // Call the third-party API function $apiResponse = $this->callThirdPartyAPI($retailApiParams, 'getVerifiedRetailUserData'); // print_r($apiResponse); die; + recordRateLimitFailure(); return $this->respond(['status' => 'failed', 'code' => 200, 'data' => [], 'post_enrollment' => json_decode($apiResponse, true)], 200); } + recordRateLimitFailure(); return $this->respond(['status' => 'Invalid OTP','code' => 404,'data' => "", 'message' => "Invalid OTP"],200); } diff --git a/app/Filters/AuthApiRateLimitFilter.php b/app/Filters/AuthApiRateLimitFilter.php new file mode 100644 index 0000000..fd2efca --- /dev/null +++ b/app/Filters/AuthApiRateLimitFilter.php @@ -0,0 +1,131 @@ +post('api/auth/verify-otp', 'AuthController::verifyOtp', ['filter' => 'authApiRateLimit']); + * + * Register in app/Config/Filters.php: + * 'AuthApiRateLimitFilter' => \App\Filters\AuthApiRateLimitFilter::class + */ +class AuthApiRateLimitFilter implements FilterInterface +{ + protected RateLimiterService $limiter; + + public function __construct() + { + $this->limiter = new RateLimiterService(); + } + + // ------------------------------------------------------------------------- + // BEFORE — runs before the controller + // ------------------------------------------------------------------------- + + public function before(RequestInterface $request, $arguments = null) + { + // $this->limiter->unblockUser('9698262411');die; + $fingerprint = generateFingerprint(exclude_ua: true); + // echo $fingerprint;die; + // 1. IP-level check + $ipResult = $this->limiter->checkIp($fingerprint, 'authApi'); + if ($ipResult) { + return $this->jsonResponse($ipResult); + } + + // 2. User-level block check (identity may not be present yet on first hit) + $identity = resolveIdentity($request); + // echo $identity;die; + if ($identity) { + $userResult = $this->limiter->checkUser($identity); + if ($userResult) { + return $this->jsonResponse($userResult); + } + } + + // Store resolved identity in request for use in after() + if ($identity) { + $request->setGlobal('rateLimitIdentity', $identity); + } + $request->setGlobal('rateLimitFingerprint', $fingerprint); + + return null; // pass through + } + + // ------------------------------------------------------------------------- + // AFTER — runs after the controller; records failures on bad responses + // ------------------------------------------------------------------------- + + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + + // Routes where rate-limit failure should be recorded + // $allowedRoutes = [ + // 'employeeRest/verifyEmployeeNumber', + // 'employeeRest/getVerifiedUserData', + // 'employeeRest/verifyEmployeeEmailId', + // 'employeeRest/verifyHrWithMobileNumber', + // 'employeeRest/verifyHrWithEmail', + // 'employeeRest/verifyHrWithEmail', + // 'employeeRest/getVerifiedHrData', + // ]; + + // $currentPath = service('request')->getPath(); + // if (!in_array($currentPath, $allowedRoutes)) { + // return; // Don't record failures for unrelated routes + // } + + // Only act on failed responses (4xx from auth failures) + $statusCode = $response->getStatusCode(); + // print_r($response);die(); + if ($statusCode < 400 || $statusCode === 429 || $statusCode === 403 || $statusCode === 451) { + return; // 2xx/3xx = success; 429/403/451 already handled + } + + $fingerprint = $request->getVar('rateLimitFingerprint') ?? generateFingerprint(exclude_ua: true); + + $identity = $request->getVar('rateLimitIdentity') + ?? resolveIdentity($request); + + // Record failure at IP level + $this->limiter->recordIpFailure($fingerprint); + + // Record failure at user level + if ($identity) { + $this->limiter->recordUserFailure($identity, 'authApi'); + } + } + + /** + * Build and return a JSON response for blocked/throttled requests. + */ + protected function jsonResponse(array $result): ResponseInterface + { + $response = service('response'); + $response->setStatusCode($result['status']); + $response->setContentType('application/json'); + $response->setBody(json_encode([ + 'success' => false, + 'error' => [ + 'code' => strtoupper('RATE_LIMIT_' . $result['level']), + 'message' => $result['message'], + 'type' => $result['type'] ?? 'request', + ], + ])); + return $response; + } +} diff --git a/app/Filters/JwtApiRateLimitFilter.php b/app/Filters/JwtApiRateLimitFilter.php new file mode 100644 index 0000000..6e0b84f --- /dev/null +++ b/app/Filters/JwtApiRateLimitFilter.php @@ -0,0 +1,154 @@ +get('api/profile', 'ProfileController::index', ['filter' => 'jwtApiRateLimit']); + * + * Register in app/Config/Filters.php: + * 'JwtApiRateLimitFilter' => \App\Filters\JwtApiRateLimitFilter::class + */ +class JwtApiRateLimitFilter implements FilterInterface +{ + protected RateLimiterService $limiter; + + public function __construct() + { + $this->limiter = new RateLimiterService(); + } + + // ------------------------------------------------------------------------- + // BEFORE — runs before the controller + // ------------------------------------------------------------------------- + + public function before(RequestInterface $request, $arguments = null) + { + $fingerprint = generateFingerprint(exclude_ua: true); + // echo $fingerprint;die; + // 1. IP-level throttle + block check + $ipResult = $this->limiter->checkIp($fingerprint, 'jwtApi'); + if ($ipResult) { + return $this->jsonResponse($ipResult); + } + + // 2. Resolve user identity from JWT + // Uses your existing JWT helper functions. + // If neither returns a value, fall back to IP-only limiting. + // $identity = $this->resolveIdentityFromJwt(); + $identity = ''; + + if ($identity) { + // User-level throttle (request count based for JWT routes) + $userResult = $this->limiter->checkUserThrottle($identity, 'jwtApi'); + if ($userResult) { + return $this->jsonResponse($userResult); + } + } + + // Stash for after() use + $request->setGlobal('rateLimitFingerprint', $fingerprint); + if ($identity) { + $request->setGlobal('rateLimitIdentity', $identity); + } + + return null; // pass through + } + + // ------------------------------------------------------------------------- + // AFTER — records IP failure on controller-level bad responses + // ------------------------------------------------------------------------- + + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + $statusCode = $response->getStatusCode(); + + // Only act on auth-related failures from the controller (401, 422, etc.) + // 429/403/451 are already handled by before(); skip 2xx/3xx. + if ($statusCode < 400 || in_array($statusCode, [429, 403, 451])) { + return; + } + + $fingerprint = $request->getGlobal('rateLimitFingerprint') ?? generateFingerprint(exclude_ua: true); + + // $identity = $request->getGlobal('rateLimitIdentity') ?? $this->resolveIdentityFromJwt(); + $identity = $request->getGlobal('rateLimitIdentity') ?? ''; + + $this->limiter->recordIpFailure($fingerprint); + + if ($identity) { + $this->limiter->recordUserFailure($identity, 'jwtApi'); + } + } + + // ------------------------------------------------------------------------- + // HELPERS + // ------------------------------------------------------------------------- + + /** + * Resolve user identity from JWT using your existing helper functions. + * Tries email first, then mobile. Returns null if JWT is absent/invalid. + * + * IMPORTANT: Replace getEmailFromJWT() / getMobileFromJWT() with your + * actual function names if they differ. + */ + protected function resolveIdentityFromJwt(): ?string + { + try { + // Try email from JWT + if (function_exists('getEmailFromJWT')) { + $email = getEmailFromJWT(); + if ($email) { + return strtolower(trim($email)); + } + } + + // Try mobile from JWT + if (function_exists('getMobileFromJWT')) { + $mobile = getMobileFromJWT(); + if ($mobile) { + return trim($mobile); + } + } + } catch (\Throwable $e) { + // JWT invalid or expired — fall through to IP-only limiting + log_message('debug', '[RateLimiter] JWT identity resolution failed: ' . $e->getMessage()); + } + + return null; + } + + /** + * Build and return a JSON response for blocked/throttled requests. + */ + protected function jsonResponse(array $result): ResponseInterface + { + $response = service('response'); + $response->setStatusCode($result['status']); + $response->setContentType('application/json'); + $response->setBody(json_encode([ + 'success' => false, + 'error' => [ + 'code' => strtoupper('RATE_LIMIT_' . $result['level']), + 'message' => $result['message'], + 'type' => $result['type'] ?? 'request', + ], + ])); + return $response; + } +} diff --git a/app/Helpers/EmployeeHelper.php b/app/Helpers/EmployeeHelper.php index e33e6dd..15a3f36 100644 --- a/app/Helpers/EmployeeHelper.php +++ b/app/Helpers/EmployeeHelper.php @@ -43,12 +43,16 @@ class EmployeeHelper if($is_addon_value == 1){ $is_addon_value = 0 ; }else{ $is_addon_value = 1 ; } - $employeeData = $this->employeeModel->where('emp_code',$data[0]->emp_code) - ->where('client_id',$data[0]->client_id) - ->where('client_branch_id',$data[0]->client_branch_id) - ->where('is_active', 1 ) - ->where('is_addon_value',$is_addon_value) - ->findAll(); + $employeeData = $this->employeeModel + ->join('employee_polices', 'employees.id = employee_polices.employee_id') + ->where('employees.emp_code',$data[0]->emp_code) + ->where('employees.client_id',$data[0]->client_id) + ->where('employees.client_branch_id',$data[0]->client_branch_id) + ->where('employees.is_active', 1 ) + ->where('employee_polices.client_policy_id', $client_policy_id) + ->where('employee_polices.is_active', 1) + ->where('is_addon_value',$is_addon_value) + ->findAll(); $array = $array[0]; diff --git a/app/Helpers/HttpRequestHelper.php b/app/Helpers/HttpRequestHelper.php index 3e072e8..53268b3 100755 --- a/app/Helpers/HttpRequestHelper.php +++ b/app/Helpers/HttpRequestHelper.php @@ -15,6 +15,7 @@ class HttpRequestHelper $data = [ 'ip' => $request->getIPAddress(), + 'real_ip' => getRealClientIP(), 'platform' => $platform, 'browser' => $browser, 'method' => strtoupper($request->getMethod()), diff --git a/app/Helpers/utility_helper.php b/app/Helpers/utility_helper.php index 71eeb49..bac046f 100755 --- a/app/Helpers/utility_helper.php +++ b/app/Helpers/utility_helper.php @@ -773,19 +773,110 @@ function getRealClientIP() return $request->getIPAddress(); } -function generateFingerprint() +function generateFingerprint(bool $exclude_ua = false): string { $request = service('request'); $ua = $request->getUserAgent()->getAgentString(); + // echo $ua; + // die; $ip = getRealClientIP(); - // echo $ip;die(); - // Use only subnet (first 3 blocks) to tolerate IP change - $ipParts = explode('.', $ip); - $ipSubnet = $ipParts[0] . '.' . $ipParts[1] . '.' . $ipParts[2]; - // $secret = env('app.sessionFingerprintSalt'); + // Normalize localhost + if ($ip === '127.0.0.1' || $ip === '::1') { + $ipGroup = 'localhost'; + } + // IPv4 handling + elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { + $parts = explode('.', $ip); + // Use /24 subnet (first 3 octets) + $ipGroup = $parts[0] . '.' . $parts[1] . '.' . $parts[2]; + } + // IPv6 handling + elseif (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) { + // Use first 4 blocks of IPv6 (rough /64 grouping) + $blocks = explode(':', $ip); + $ipGroup = implode(':', array_slice($blocks, 0, 4)); + } + // Fallback + else { + $ipGroup = 'unknown'; + } - // return hash('sha256', $ua . '|' . $ipSubnet . '|' . $secret); - return hash('sha256', $ua . '|' . $ipSubnet ); -} \ No newline at end of file + // return $ua . '_' . $ipGroup; + if($exclude_ua){ + return hash('sha256', $ipGroup); + } + return hash('sha256', $ua . '|' . $ipGroup); + +} + + +/** + * Extract identity from POST body or GET params. + * Looks for 'email' or 'mobile_number'. + */ + function resolveIdentity($request): ?string + { + // Try POST body first + $email = $request->getPost('email'); + // print_r($email);die; + $mobile = $request->getPost('mobile_number'); + + // Fallback to GET params + if (! $email && ! $mobile) { + $email = $request->getGet('email'); + $mobile = $request->getGet('mobile_number'); + } + // Fallback to JSON params + if (! $email && ! $mobile) { + $req_data = $request->getJSON(); + // print_r( $req_data); + + $mobile = $req_data->mobile_number ?? null; + // return trim($mobile_number); + + $email = $req_data->email ?? null; + + if (!$email) + { + $email = $req_data->email_id ?? null; + } + // return trim($email); + } + + if ($email) { + return strtolower(trim($email)); + } + + if ($mobile) { + return trim($mobile); + } + + return null; + } + + + function recordRateLimitFailure(string $context = 'authApi'): void + { + /** @var IncomingRequest $request */ + $request = \Config\Services::request(); + + $limiter = \Config\Services::limiter(); // or your custom limiter service + + $fingerprint = $request->getVar('rateLimitFingerprint') + ?? generateFingerprint(exclude_ua: true); + + + + $identity = $request->getVar('rateLimitIdentity') + ?? resolveIdentity($request); + + // Record IP-level failure + $limiter->recordIpFailure($fingerprint); + + // Record user-level failure + if (!empty($identity)) { + $limiter->recordUserFailure($identity, $context); + } + } \ No newline at end of file diff --git a/app/Libraries/RateLimiterService.php b/app/Libraries/RateLimiterService.php new file mode 100644 index 0000000..3bcb564 --- /dev/null +++ b/app/Libraries/RateLimiterService.php @@ -0,0 +1,386 @@ +config = config('RateLimiter'); + $this->cache = \Config\Services::cache(); + } + + // ========================================================================= + // PUBLIC — IP LEVEL + // ========================================================================= + + /** + * Check & throttle by fingerprint (IP+UA based). + * Returns null on pass, or an array ['level'=>..., 'message'=>...] on block. + */ + public function checkIp(string $fingerprint, string $routeType = 'jwtApi'): ?array + { + // echo $fingerprint;die; + // 1. Is the IP already blocked? + $blockInfo = $this->getIpBlock($fingerprint); + // print_rr($blockInfo);die(); + if ($blockInfo) { + // Count hit while blocked → maybe escalate + $this->recordIpBlockHit($fingerprint, $blockInfo['level']); + return $this->blockedResponse('ip', $blockInfo['level']); + } + + // 2. Throttle check + $cfg = $this->config->ipBlock; + $countKey = $this->config->cacheKeys['ip_count'] . $fingerprint; + $count = (int) ($this->cache->get($countKey) ?? 0); + + if ($count === 0) { + $this->cache->save($countKey, 1, $cfg['window']); + } else { + $this->cache->save($countKey, $count + 1, $cfg['window']); + } + + if (($count + 1) > $cfg['limit']) { + // Over limit → record violation + $violated = $this->incrementIpViolation($fingerprint); + if ($violated >= $cfg['violation_soft']) { + $this->blockIp($fingerprint, 'soft'); + return $this->blockedResponse('ip', 'soft'); + } + return [ + 'level' => 'throttle', + 'message' => 'Too many requests. Please slow down.', + 'status' => $this->config->statusCodes['throttle'], + ]; + } + + return null; + } + + /** + * Record a "bad outcome" for IP (e.g. controller calls this after failed auth). + * Same escalation path as throttle violations. + */ + public function recordIpFailure(string $fingerprint): ?array + { + $blockInfo = $this->getIpBlock($fingerprint); + if ($blockInfo) { + $this->recordIpBlockHit($fingerprint, $blockInfo['level']); + return $this->blockedResponse('ip', $blockInfo['level']); + } + + $violated = $this->incrementIpViolation($fingerprint); + $cfg = $this->config->ipBlock; + + if ($violated >= $cfg['violation_soft']) { + $this->blockIp($fingerprint, 'soft'); + return $this->blockedResponse('ip', 'soft'); + } + + return null; + } + + /** + * Manually block an IP at a given level. + */ + public function blockIp(string $fingerprint, string $level = 'soft'): void + { + $cfg = $this->config->ipBlock; + $blockKey = $this->config->cacheKeys['ip_block'] . $fingerprint; + + $duration = $this->blockDuration($cfg, $level); + + $data = [ + 'level' => $level, + 'blocked_at' => time(), + 'fingerprint'=> $fingerprint, + 'ip' => getRealClientIP(), + ]; + + // Duration 0 = store for 10 years (permanent until manual unblock) + $ttl = $duration > 0 ? $duration : (10 * 365 * 24 * 3600); + $this->cache->save($blockKey, $data, $ttl); + } + + /** + * Manually unblock an IP. Clears block, violations, and counters. + */ + public function unblockIp(string $fingerprint): void + { + $keys = $this->config->cacheKeys; + $this->cache->delete($keys['ip_block'] . $fingerprint); + $this->cache->delete($keys['ip_violations'] . $fingerprint); + $this->cache->delete($keys['ip_count'] . $fingerprint); + $this->cache->delete($keys['ip_block_hits'] . $fingerprint); + } + + /** + * Get current IP block info or null if not blocked. + */ + public function getIpBlock(string $fingerprint): ?array + { + $blockKey = $this->config->cacheKeys['ip_block'] . $fingerprint; + $data = $this->cache->get($blockKey); + return $data ?: null; + } + + // ========================================================================= + // PUBLIC — USER LEVEL + // ========================================================================= + + /** + * Check if a user (by email or mobile) is blocked. + * Returns null on pass, or block response array on block. + */ + public function checkUser(string $identity): ?array + { + $blockInfo = $this->getUserBlock($identity); + if ($blockInfo) { + $this->recordUserBlockHit($identity, $blockInfo['level']); + return $this->blockedResponse('user', $blockInfo['level']); + } + return null; + } + + /** + * Record a failed attempt for a user identity. + * Called from controller after() or manually after a failed verification. + * Handles escalation: free → soft → medium → hard + */ + public function recordUserFailure(string $identity, string $routeType = 'authApi'): ?array + { + $blockInfo = $this->getUserBlock($identity); + + if ($blockInfo) { + // Already blocked — count hit and maybe escalate + $this->recordUserBlockHit($identity, $blockInfo['level']); + return $this->blockedResponse('user', $blockInfo['level']); + } + + // Not blocked yet — increment violation count + $violated = $this->incrementUserViolation($identity, $routeType); + $cfg = $this->config->userBlock; + $routeCfg = $this->config->{$routeType}; + + if ($violated >= $routeCfg['violation_soft']) { + $this->blockUser($identity, 'soft'); + return $this->blockedResponse('user', 'soft'); + } + + return null; + } + + /** + * Manually block a user identity at a given level. + */ + public function blockUser(string $identity, string $level = 'soft'): void + { + $cfg = $this->config->userBlock; + $blockKey = $this->config->cacheKeys['user_block'] . $this->hashIdentity($identity); + + $duration = $this->blockDuration($cfg, $level); + $ttl = $duration > 0 ? $duration : (10 * 365 * 24 * 3600); + + $data = [ + 'level' => $level, + 'blocked_at' => time(), + 'identity' => $identity, + ]; + + $this->cache->save($blockKey, $data, $ttl); + } + + /** + * Manually unblock a user identity. Independent — does NOT touch IP block. + */ + public function unblockUser(string $identity): void + { + $keys = $this->config->cacheKeys; + $hashed = $this->hashIdentity($identity); + + $this->cache->delete($keys['user_block'] . $hashed); + $this->cache->delete($keys['user_violations'] . $hashed); + $this->cache->delete($keys['user_count'] . $hashed); + $this->cache->delete($keys['user_block_hits'] . $hashed); + } + + /** + * Get current user block info or null if not blocked. + */ + public function getUserBlock(string $identity): ?array + { + $blockKey = $this->config->cacheKeys['user_block'] . $this->hashIdentity($identity); + $data = $this->cache->get($blockKey); + return $data ?: null; + } + + // ========================================================================= + // USER THROTTLE (for JWT API routes — request count based) + // ========================================================================= + + /** + * Throttle check for a known user on JWT routes. + * Increments request counter; if over limit records violation. + */ + public function checkUserThrottle(string $identity, string $routeType = 'jwtApi'): ?array + { + $blockCheck = $this->checkUser($identity); + if ($blockCheck) { + return $blockCheck; + } + + $cfg = $this->config->{$routeType}; + $hashed = $this->hashIdentity($identity); + $countKey = $this->config->cacheKeys['user_count'] . $hashed; + $count = (int) ($this->cache->get($countKey) ?? 0); + + if ($count === 0) { + $this->cache->save($countKey, 1, $cfg['window']); + } else { + $this->cache->save($countKey, $count + 1, $cfg['window']); + } + + if (($count + 1) > $cfg['limit']) { + $violated = $this->incrementUserViolation($identity, $routeType); + if ($violated >= $cfg['violation_soft']) { + $this->blockUser($identity, 'soft'); + return $this->blockedResponse('user', 'soft'); + } + return [ + 'level' => 'throttle', + 'message' => 'Too many requests. Please slow down.', + 'status' => $this->config->statusCodes['throttle'], + ]; + } + + return null; + } + + // ========================================================================= + // PRIVATE HELPERS + // ========================================================================= + + /** + * Increment IP violation counter and return new count. + */ + protected function incrementIpViolation(string $fingerprint): int + { + $key = $this->config->cacheKeys['ip_violations'] . $fingerprint; + $count = (int) ($this->cache->get($key) ?? 0) + 1; + // Keep violation record for the block window duration + $this->cache->save($key, $count, $this->config->ipBlock['window'] * 10); + return $count; + } + + /** + * Record a hit while IP is already blocked; escalate if thresholds met. + */ + protected function recordIpBlockHit(string $fingerprint, string $currentLevel): void + { + $cfg = $this->config->ipBlock; + $hitKey = $this->config->cacheKeys['ip_block_hits'] . $fingerprint; + $hits = (int) ($this->cache->get($hitKey) ?? 0) + 1; + $this->cache->save($hitKey, $hits, 10 * 365 * 24 * 3600); + + if ($currentLevel === 'soft' && $hits >= $cfg['medium_trigger']) { + $this->cache->delete($hitKey); + $this->blockIp($fingerprint, 'medium'); + } elseif ($currentLevel === 'medium' && $hits >= $cfg['hard_trigger']) { + $this->cache->delete($hitKey); + $this->blockIp($fingerprint, 'hard'); + } + } + + /** + * Increment user violation counter and return new count. + */ + protected function incrementUserViolation(string $identity, string $routeType): int + { + $hashed = $this->hashIdentity($identity); + $key = $this->config->cacheKeys['user_violations'] . $hashed; + $count = (int) ($this->cache->get($key) ?? 0) + 1; + $window = $this->config->{$routeType}['window'] ?? 180; + $this->cache->save($key, $count, $window * 10); + return $count; + } + + /** + * Record a hit while user is already blocked; escalate if thresholds met. + */ + protected function recordUserBlockHit(string $identity, string $currentLevel): void + { + $cfg = $this->config->userBlock; + $hashed = $this->hashIdentity($identity); + $hitKey = $this->config->cacheKeys['user_block_hits'] . $hashed; + $hits = (int) ($this->cache->get($hitKey) ?? 0) + 1; + $this->cache->save($hitKey, $hits, 10 * 365 * 24 * 3600); + + if ($currentLevel === 'soft' && $hits >= $cfg['medium_trigger']) { + $this->cache->delete($hitKey); + $this->blockUser($identity, 'medium'); + } elseif ($currentLevel === 'medium' && $hits >= $cfg['hard_trigger']) { + $this->cache->delete($hitKey); + $this->blockUser($identity, 'hard'); + } + } + + /** + * Resolve block duration from config based on level. + */ + protected function blockDuration(array $cfg, string $level): int + { + return match ($level) { + 'soft' => $cfg['soft_duration'], + 'medium' => $cfg['medium_duration'], + 'hard' => $cfg['hard_duration'], + default => 0, + }; + } + + /** + * Build a standardised blocked response array. + */ + protected function blockedResponse(string $type, string $level): array + { + $messages = [ + 'soft' => 'Your access has been temporarily suspended. Please contact support.', + 'medium' => 'Your access has been restricted due to repeated violations.', + 'hard' => 'Your access has been permanently blocked. Please contact support.', + ]; + + return [ + 'level' => $level, + 'type' => $type, + 'message' => $messages[$level] ?? 'Access denied.', + 'status' => $this->config->statusCodes[$level], + ]; + } + + /** + * Hash user identity (email or mobile) for cache key safety. + */ + protected function hashIdentity(string $identity): string + { + // return strtolower(trim($identity)); + return hash('sha256', strtolower(trim($identity))); + } +} diff --git a/app/Views/UserList.php b/app/Views/UserList.php index be654b8..b526ca6 100755 --- a/app/Views/UserList.php +++ b/app/Views/UserList.php @@ -290,7 +290,7 @@ $(document).ready(function () { var student_id = $(this).attr('data-id'); $.get(''+student_id, function (data) { console.log(data); - toastr.success('User removed successfully', 'success'); + toastr.success('User removed successfully', 'Success'); window.location.reload() }) } diff --git a/app/Views/cd_master_list.php b/app/Views/cd_master_list.php index 92bde59..f8a3278 100755 --- a/app/Views/cd_master_list.php +++ b/app/Views/cd_master_list.php @@ -312,7 +312,7 @@ document.addEventListener("DOMContentLoaded", function () { has('success')) : ?> - toastr.success('= session()->getFlashdata('success') ?>', 'success'); + toastr.success('= session()->getFlashdata('success') ?>', 'Success'); var endDatePicker = flatpickr("#opening_date", { @@ -410,7 +410,7 @@ document.addEventListener("DOMContentLoaded", function () { console.log(res) if(res.status == true){ - toastr.warning(res.message, 'warning'); + toastr.warning(res.message, 'Warning'); $('#cd_ac_no').val(''); } }, @@ -446,10 +446,10 @@ document.addEventListener("DOMContentLoaded", function () { // console.log(res.status == true); if(res){ if (res.status == true) { - toastr.success('CD removed successfully.', 'success'); + toastr.success('CD removed successfully.', 'Success'); location.reload(); } else { - toastr.warning('Failed to remove CD.', 'warning'); + toastr.warning('Failed to remove CD.', 'Warning'); } } }, diff --git a/app/Views/client_branch.php b/app/Views/client_branch.php index 449d1e8..b8e9f29 100755 --- a/app/Views/client_branch.php +++ b/app/Views/client_branch.php @@ -609,7 +609,7 @@ $('body').on('click', '.btnBranchEdit', function() { setTimeout(function() { $('.loader').fadeOut(); $('.loader-mask').delay(350).fadeOut('slow'); - toastr.warning('Something Wrong!', 'warning'); + toastr.warning('Something Wrong!', 'Warning'); }, 1000); } }); @@ -811,10 +811,10 @@ function removeClientBranch(element) { // console.log(res.status == true); if (res) { if (res.status == true) { - toastr.success(res.message, 'success'); + toastr.success(res.message, 'Success'); location.reload(); } else { - toastr.warning(res.message, 'warning'); + toastr.warning(res.message, 'Warning'); } } }, @@ -824,7 +824,7 @@ function removeClientBranch(element) { setTimeout(function() { $('.loader').fadeOut(); $('.loader-mask').delay(350).fadeOut('slow'); - console.log('Something Wrong!', 'warning'); + console.log('Something Wrong!', 'Warning'); }, 1000); } }); @@ -938,7 +938,7 @@ function validateInput(input, table, field, submitBtnId){ checkDuplicateTableFieldValue(table, field, value, function(isDuplicate) { if (isDuplicate) { - toastr.warning(message, 'WARNING'); + toastr.warning(message, 'Warning'); // $(input).val('') $('#'+submitBtnId).prop('disabled', true); } else{ @@ -972,7 +972,7 @@ function validateDuplicateByClientBranch(input, field, submitButId) { if (isLocalDuplicate) { console.log(`r u n Local`); console.log(`duplicate found for ${field}`); - toastr.warning(message, 'WARNING'); + toastr.warning(message, 'Warning'); $('#' + submitButId).prop('disabled', true); return; } @@ -999,7 +999,7 @@ function validateDuplicateByClientBranch(input, field, submitButId) { if (response.isDuplicate) { console.log(`r u n Server`); console.log(`duplicate found for ${field}`); - toastr.warning(message, 'WARNING'); + toastr.warning(message, 'Warning'); $('#' + submitButId).prop('disabled', true); } else { console.log(`No duplicate for ${field}`); @@ -1044,13 +1044,13 @@ function checkAllFieldsValid(submitButId) { $('#' + submitButId).prop('disabled', true); // show correct message based on what’s duplicated if (emailDuplicates && mobileDuplicates) { - toastr.warning("Email and Mobile values are duplicate!", "WARNING"); + toastr.warning("Email and Mobile values are duplicate!", "Warning"); console.log('Both Email and Mobile duplicates'); } else if (emailDuplicates) { - toastr.warning("Email duplicate!", "WARNING"); + toastr.warning("Email duplicate!", "Warning"); console.log('Cross Check Email duplicates'); } else if (mobileDuplicates) { - toastr.warning("Mobile duplicate!", "WARNING"); + toastr.warning("Mobile duplicate!", "Warning"); console.log('Cross Check Mobile duplicates'); } console.log(`btn Dis - true`); @@ -1096,9 +1096,9 @@ function removeLevelContacts(id){ console.log('Data fetched successfully:', response); if (response.status == true) { - toastr.success(response.message, 'SUCCESS'); + toastr.success(response.message, 'Success'); } else { - toastr.warning(response.message, 'WARNING'); + toastr.warning(response.message, 'Warning'); } }, function(xhr, status, error) { diff --git a/app/Views/client_kyc.php b/app/Views/client_kyc.php index 99bab2b..2c96495 100755 --- a/app/Views/client_kyc.php +++ b/app/Views/client_kyc.php @@ -212,7 +212,7 @@ setTimeout(function() { $('.loader').fadeOut(); $('.loader-mask').delay(350).fadeOut('slow'); - toastr.warning('Something Wrong!', 'warning'); + toastr.warning('Something Wrong!', 'Warning'); }, 1000); } @@ -333,7 +333,7 @@ setTimeout(function() { $('.loader').fadeOut(); $('.loader-mask').delay(350).fadeOut('slow'); - toastr.warning('Something Wrong!', 'warning'); + toastr.warning('Something Wrong!', 'Warning'); }, 1000); } @@ -438,7 +438,7 @@ setTimeout(function() { $('.loader').fadeOut(); $('.loader-mask').delay(350).fadeOut('slow'); - toastr.warning('Something Wrong!', 'warning'); + toastr.warning('Something Wrong!', 'Warning'); }, 1000); } }); diff --git a/app/Views/client_list.php b/app/Views/client_list.php index 89ff403..a65ff46 100755 --- a/app/Views/client_list.php +++ b/app/Views/client_list.php @@ -402,7 +402,7 @@ // if(res){ // if (res.status == true) { - // toastr.success('Client removed successfully.', 'success'); + // toastr.success('Client removed successfully.', 'Success'); // location.reload(); // } else { // Swal.fire({ @@ -410,7 +410,7 @@ // text: res.message, // icon: "warning" // }); - // // toastr.warning(res.message, 'warning'); + // // toastr.warning(res.message, 'Warning'); // } // } // }, @@ -419,7 +419,7 @@ // console.error(status, error); // $('.loader').fadeOut(); // $('.loader-mask').delay(350).fadeOut('slow'); - // console.log('Something Wrong!', 'warning'); + // console.log('Something Wrong!', 'Warning'); // } // }); // } @@ -466,15 +466,15 @@ $('.loader-mask').delay(350).fadeOut('slow'); if (res.status == true) { - toastr.success(res.message, 'success'); + toastr.success(res.message, 'Success'); location.reload(); } else { Swal.fire({ - title: "warning!", + title: "Warning!", text: res.message, icon: "warning" }); - // toastr.warning(res.message, 'warning'); + // toastr.warning(res.message, 'Warning'); } }, error: function (xhr, status, error) { @@ -563,10 +563,10 @@ if(res.status == true){ let client_url = '= base_url('client/list/') ?>' + res.client_id + '?client_policy_id=' + res.client_policy_id+'#police-tab'; - toastr.success(res.message, 'SUCCESS') + toastr.success(res.message, 'Success') window.location.href = client_url }else{ - toastr.success(res.message, 'WARNING') + toastr.warning(res.message, 'Warning') } $('.close').click() diff --git a/app/Views/client_onboarding.php b/app/Views/client_onboarding.php index dc37b06..08e9359 100755 --- a/app/Views/client_onboarding.php +++ b/app/Views/client_onboarding.php @@ -200,7 +200,7 @@ body { if(check_client_id[0].value == '' || check_client_id[0].value == null || check_client_id[0].value == 0){ $('#btnBranchAdd').hide(); - toastr.warning('Please Add the Client!', 'warning',{timeOut: 2000}); + toastr.warning('Please Add the Client!', 'Warning',{timeOut: 2000}); }else{ if ($('#btnBranchBack')[0].style.display == 'none') { $('#btnBranchAdd').show(); @@ -215,7 +215,7 @@ body { if(check_client_id[0].value == '' || check_client_id[0].value == null || check_client_id[0].value == 0){ $('#relation_form').hide(); - toastr.warning('Please Add the Client!', 'warning',{timeOut: 2000}); + toastr.warning('Please Add the Client!', 'Warning',{timeOut: 2000}); }else{ $('#relation_form').show(); } @@ -228,7 +228,7 @@ body { if(check_client_id[0].value == '' || check_client_id[0].value == null || check_client_id[0].value == 0){ $('#BtnAdd').hide(); - toastr.warning('Please Add the Client!', 'warning',{timeOut: 2000}); + toastr.warning('Please Add the Client!', 'Warning',{timeOut: 2000}); }else{ if ($('#btnPolicyBack')[0].style.display == 'none') { $('#BtnAdd').show(); @@ -243,7 +243,7 @@ body { if(check_client_id[0].value == '' || check_client_id[0].value == null || check_client_id[0].value == 0){ $('#btnBranchAdd').hide(); - toastr.warning('Please Add the Client!', 'warning',{timeOut: 2000}); + toastr.warning('Please Add the Client!', 'Warning',{timeOut: 2000}); }else{ if ($('#btnBranchBack')[0].style.display == 'none') { $('#btnBranchAdd').show(); @@ -259,7 +259,7 @@ body { if(check_client_id[0].value == '' || check_client_id[0].value == null || check_client_id[0].value == 0){ $('#notification-tab').hide(); - toastr.warning('Please Add the Client!', 'warning',{timeOut: 2000}); + toastr.warning('Please Add the Client!', 'Warning',{timeOut: 2000}); }else{ if ($('#notification-tab')[0].style.display == 'none') { $('#notification-tab').show(); diff --git a/app/Views/client_others_tab.php b/app/Views/client_others_tab.php index e7f0979..193eb8b 100755 --- a/app/Views/client_others_tab.php +++ b/app/Views/client_others_tab.php @@ -59,9 +59,9 @@ $(document).ready(function() { $('.loader').fadeOut(); $('.loader-mask').delay(350).fadeOut('slow'); if (res.status == true) { - toastr.success(res.message, 'SUCCESS'); + toastr.success(res.message, 'Success'); } else { - toastr.warning(res.message, 'WARNING'); + toastr.warning(res.message, 'Warning'); } }, diff --git a/app/Views/client_policy.php b/app/Views/client_policy.php index 0da8700..ad919af 100755 --- a/app/Views/client_policy.php +++ b/app/Views/client_policy.php @@ -332,7 +332,7 @@ input:checked + .slider:before { -->