update login scurity
This commit is contained in:
@@ -5,7 +5,6 @@ namespace App\Controllers;
|
||||
use App\Models\LoginActivityModel;
|
||||
use App\Models\UserModel;
|
||||
use App\Models\UserRoleModel;
|
||||
use CodeIgniter\Controller;
|
||||
use CodeIgniter\Events\Events;
|
||||
use App\Models\IpAttemptModel;
|
||||
use App\Models\PasswordResetModel;
|
||||
@@ -19,7 +18,7 @@ require_once APPPATH . 'Helpers/pbkdf2_helper.php';
|
||||
require_once APPPATH . 'Helpers/jwt_helper.php';
|
||||
|
||||
|
||||
class AuthController extends Controller
|
||||
class AuthController extends BaseController
|
||||
{
|
||||
protected $configModel;
|
||||
protected $userModel;
|
||||
@@ -83,9 +82,23 @@ class AuthController extends Controller
|
||||
log_message('info', 'Processing login form submission.');
|
||||
$redirectTo = $this->sanitizeRedirectTarget((string) ($this->request->getPost('redirect_to') ?? $this->request->getGet('redirect_to') ?? ''));
|
||||
|
||||
$validator = \Config\Services::validation();
|
||||
$requestData = sanitize_request_value($this->request->getPost(['email', 'password']));
|
||||
$validator->setRules([
|
||||
'email' => 'required|valid_email|max_length[254]',
|
||||
'password' => 'required|max_length[255]',
|
||||
]);
|
||||
|
||||
if (! $validator->run($requestData)) {
|
||||
return redirect()
|
||||
->back()
|
||||
->with('error', 'Please enter a valid email and password.')
|
||||
->withInput();
|
||||
}
|
||||
|
||||
// Step 1: Get email, password, and IP from the request
|
||||
$email = $this->request->getPost('email');
|
||||
$password = $this->request->getPost('password');
|
||||
$email = strtolower((string) $requestData['email']);
|
||||
$password = (string) $requestData['password'];
|
||||
$ip = $this->request->getIPAddress();
|
||||
|
||||
log_message('info', 'Login attempt from IP: ' . $ip . ' for email: ' . $email);
|
||||
@@ -139,26 +152,29 @@ class AuthController extends Controller
|
||||
// JSON API: POST /api/login
|
||||
public function apiLogin()
|
||||
{
|
||||
$requestData = $this->request->getJSON(true);
|
||||
if (!$requestData) {
|
||||
// fallback to form vars
|
||||
$requestData = [
|
||||
'email' => $this->request->getPost('email'),
|
||||
'password' => $this->request->getPost('password'),
|
||||
];
|
||||
}
|
||||
$requestData = sanitize_request_value($this->request->getJSON(true) ?: [
|
||||
'email' => $this->request->getPost('email'),
|
||||
'password' => $this->request->getPost('password'),
|
||||
]);
|
||||
|
||||
$email = $requestData['email'] ?? '';
|
||||
$password = $requestData['password'] ?? '';
|
||||
$ip = $this->request->getIPAddress();
|
||||
$validation = \Config\Services::validation();
|
||||
$validation->setRules([
|
||||
'email' => 'required|valid_email|max_length[254]',
|
||||
'password' => 'required|max_length[255]',
|
||||
]);
|
||||
|
||||
if (!$email || !$password) {
|
||||
return $this->response->setStatusCode(400)->setJSON([
|
||||
if (! $validation->run($requestData)) {
|
||||
return $this->response->setStatusCode(422)->setJSON([
|
||||
'status' => false,
|
||||
'message' => 'Email and password are required.'
|
||||
'message' => 'Validation failed.',
|
||||
'errors' => $validation->getErrors(),
|
||||
]);
|
||||
}
|
||||
|
||||
$email = strtolower((string) ($requestData['email'] ?? ''));
|
||||
$password = (string) ($requestData['password'] ?? '');
|
||||
$ip = $this->request->getIPAddress();
|
||||
|
||||
if ($this->isIpBlocked($ip)) {
|
||||
return $this->response->setStatusCode(429)->setJSON([
|
||||
'status' => false,
|
||||
@@ -220,7 +236,15 @@ class AuthController extends Controller
|
||||
'exp' => $exp,
|
||||
];
|
||||
|
||||
$secret = env('JWT_SECRET', 'change-me-in-env');
|
||||
try {
|
||||
$secret = require_env('JWT_SECRET');
|
||||
} catch (\RuntimeException $e) {
|
||||
return $this->response->setStatusCode(500)->setJSON([
|
||||
'status' => false,
|
||||
'message' => 'JWT configuration is missing.',
|
||||
]);
|
||||
}
|
||||
|
||||
$token = jwt_encode($payload, $secret, 'HS256');
|
||||
|
||||
return $this->response->setJSON([
|
||||
@@ -240,18 +264,14 @@ class AuthController extends Controller
|
||||
*/
|
||||
public function apiRegister()
|
||||
{
|
||||
$requestData = $this->request->getJSON(true);
|
||||
if (!$requestData) {
|
||||
// fallback to form vars
|
||||
$requestData = $this->request->getPost();
|
||||
}
|
||||
$requestData = sanitize_request_value($this->request->getJSON(true) ?: $this->request->getPost());
|
||||
|
||||
// Basic validation
|
||||
$rules = [
|
||||
'firstname' => 'required|min_length[2]|max_length[30]',
|
||||
'lastname' => 'required|min_length[2]|max_length[30]',
|
||||
'email' => 'required|valid_email|is_unique[users.email]',
|
||||
'password' => 'required|min_length[8]',
|
||||
'firstname' => "required|regex_match[/^[\\p{L}\\s'\\-]+$/u]|min_length[2]|max_length[30]",
|
||||
'lastname' => "required|regex_match[/^[\\p{L}\\s'\\-]+$/u]|min_length[2]|max_length[30]",
|
||||
'email' => 'required|valid_email|max_length[254]|is_unique[users.email]',
|
||||
'password' => 'required|min_length[8]|max_length[255]',
|
||||
'cellphone' => 'required|min_length[10]|max_length[20]',
|
||||
];
|
||||
|
||||
@@ -332,7 +352,7 @@ class AuthController extends Controller
|
||||
'exp' => $exp,
|
||||
];
|
||||
|
||||
$secret = env('JWT_SECRET', 'change-me-in-env');
|
||||
$secret = require_env('JWT_SECRET');
|
||||
$token = jwt_encode($payload, $secret, 'HS256');
|
||||
|
||||
return $this->response->setStatusCode(201)->setJSON([
|
||||
|
||||
@@ -36,7 +36,7 @@ abstract class BaseController extends Controller
|
||||
*
|
||||
* @var list<string>
|
||||
*/
|
||||
protected $helpers = [];
|
||||
protected $helpers = ['security'];
|
||||
|
||||
/** @var ApiClient */
|
||||
protected ApiClient $api;
|
||||
@@ -73,6 +73,21 @@ abstract class BaseController extends Controller
|
||||
// Assuming the user role is stored in the session
|
||||
return session()->get('role');
|
||||
}
|
||||
|
||||
protected function validated(array $rules, ?array $data = null): array
|
||||
{
|
||||
$validation = service('validation');
|
||||
$payload = $data ?? ($this->request->getJSON(true) ?: $this->request->getPost());
|
||||
$payload = sanitize_request_value($payload);
|
||||
|
||||
$validation->setRules($rules);
|
||||
|
||||
if (! $validation->run($payload)) {
|
||||
throw new \InvalidArgumentException(json_encode($validation->getErrors(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?: 'Validation failed');
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -20,15 +20,22 @@ class ProofreadController extends ResourceController
|
||||
}
|
||||
|
||||
// Accept form-urlencoded payload to play nicely with CSRF protection
|
||||
$text = (string) ($this->request->getPost('text') ?? '');
|
||||
if ($text === '' || mb_strlen($text) > 20000) {
|
||||
$validation = service('validation');
|
||||
$payload = sanitize_request_value($this->request->getPost(['text']));
|
||||
$validation->setRules([
|
||||
'text' => 'required|min_length[1]|max_length[20000]',
|
||||
]);
|
||||
|
||||
if (! $validation->run($payload)) {
|
||||
return $this->respond([
|
||||
'ok' => false,
|
||||
'error' => 'Invalid text (empty or too long).',
|
||||
'error' => 'Invalid text payload.',
|
||||
'csrfHash' => csrf_hash(),
|
||||
], 422);
|
||||
}
|
||||
|
||||
$text = (string) $payload['text'];
|
||||
|
||||
$client = \Config\Services::curlrequest(['timeout' => 10]);
|
||||
|
||||
try {
|
||||
|
||||
@@ -24,10 +24,10 @@ class ContactController extends BaseController
|
||||
|
||||
// Define validation rules
|
||||
$validation->setRules([
|
||||
'name' => 'required|min_length[3]',
|
||||
'email' => 'required|valid_email',
|
||||
'subject' => 'required|min_length[3]',
|
||||
'message' => 'required|min_length[10]'
|
||||
'name' => "required|regex_match[/^[\\p{L}\\s'\\-]+$/u]|min_length[3]|max_length[100]",
|
||||
'email' => 'required|valid_email|max_length[254]',
|
||||
'subject' => 'required|min_length[3]|max_length[150]',
|
||||
'message' => 'required|min_length[10]|max_length[5000]'
|
||||
]);
|
||||
|
||||
if (!$validation->withRequest($this->request)->run()) {
|
||||
@@ -37,10 +37,10 @@ class ContactController extends BaseController
|
||||
}
|
||||
|
||||
// Process form data
|
||||
$name = $this->request->getPost('name');
|
||||
$email = strtolower($this->request->getPost('email'));
|
||||
$subject = $this->request->getPost('subject');
|
||||
$message = $this->request->getPost('message');
|
||||
$name = esc((string) $this->request->getPost('name'));
|
||||
$email = esc(strtolower((string) $this->request->getPost('email')));
|
||||
$subject = esc((string) $this->request->getPost('subject'));
|
||||
$message = nl2br(esc((string) $this->request->getPost('message')));
|
||||
|
||||
// Initialize the EmailController
|
||||
$emailController = new \App\Controllers\View\EmailController();
|
||||
@@ -63,4 +63,4 @@ class ContactController extends BaseController
|
||||
|
||||
return redirect()->to('/parent/contact');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -486,7 +486,7 @@ class EventController extends ResourceController
|
||||
|
||||
$chargesBuilder = $this->eventChargesModel
|
||||
->select('event_charges.*,
|
||||
users.firstname AS parent_firstname, users.lastname AS parent_lastname,
|
||||
users.firstname AS parent_firstname, users.lastname AS parent_lastname, users.cellphone AS parent_cellphone,
|
||||
students.firstname AS student_firstname, students.lastname AS student_lastname,
|
||||
events.event_name, events.description AS event_description, events.amount AS event_amount')
|
||||
->join('users', 'users.id = event_charges.parent_id', 'left')
|
||||
|
||||
Reference in New Issue
Block a user