GWM : VAPT Scan Vulnerabilities

This commit is contained in:
Gowtham M 2026-01-08 16:58:50 +05:30
parent dabe60b498
commit 4d15ddb92a
5 changed files with 285 additions and 77 deletions

View File

@ -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");

View File

@ -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);
}
}

View File

@ -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)

View File

@ -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'];
}
}

View File

@ -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];
}
}