2025-04-07 13:21:35 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
/**
|
|
|
|
* User credentials management
|
|
|
|
*
|
|
|
|
* This page ("credentials") handles all credential-related actions including:
|
|
|
|
* - Two-factor authentication (2FA) setup, verification, and management
|
|
|
|
* - Password changes and resets
|
|
|
|
*
|
|
|
|
* Actions handled:
|
|
|
|
* - `setup`: Initial 2FA setup and verification
|
|
|
|
* - `verify`: Verify 2FA codes during login
|
|
|
|
* - `disable`: Disable 2FA
|
|
|
|
* - `password`: Change password
|
|
|
|
*/
|
|
|
|
|
2025-04-08 07:30:07 +00:00
|
|
|
// Initialize user object
|
|
|
|
$userObject = new User($dbWeb);
|
|
|
|
|
2025-04-14 07:39:58 +00:00
|
|
|
// Get action and item from request
|
2025-04-07 13:21:35 +00:00
|
|
|
$action = $_REQUEST['action'] ?? '';
|
|
|
|
$item = $_REQUEST['item'] ?? '';
|
|
|
|
|
|
|
|
// if a form is submitted
|
|
|
|
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
|
|
|
|
// Validate CSRF token
|
2025-04-08 07:30:07 +00:00
|
|
|
$security->verifyCsrfToken($_POST['csrf_token'] ?? '');
|
2025-04-07 13:21:35 +00:00
|
|
|
if (!$security->verifyCsrfToken($_POST['csrf_token'] ?? '')) {
|
|
|
|
Feedback::flash('ERROR', 'DEFAULT', 'Invalid security token. Please try again.');
|
|
|
|
header("Location: $app_root?page=credentials");
|
|
|
|
exit();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply rate limiting
|
|
|
|
require_once '../app/includes/rate_limit_middleware.php';
|
2025-04-14 07:39:58 +00:00
|
|
|
checkRateLimit($dbWeb, 'credentials', $userId);
|
2025-04-07 13:21:35 +00:00
|
|
|
|
|
|
|
switch ($item) {
|
|
|
|
case '2fa':
|
|
|
|
switch ($action) {
|
|
|
|
case 'setup':
|
|
|
|
// Validate the setup code
|
|
|
|
$code = $_POST['code'] ?? '';
|
|
|
|
$secret = $_POST['secret'] ?? '';
|
|
|
|
|
2025-04-14 07:39:58 +00:00
|
|
|
if ($userObject->enableTwoFactor($userId, $secret, $code)) {
|
2025-04-07 13:21:35 +00:00
|
|
|
Feedback::flash('NOTICE', 'DEFAULT', 'Two-factor authentication has been enabled successfully.');
|
|
|
|
header("Location: $app_root?page=credentials");
|
|
|
|
exit();
|
|
|
|
} else {
|
2025-04-08 07:30:07 +00:00
|
|
|
// Only show error if code was actually submitted
|
|
|
|
if ($code !== '') {
|
|
|
|
Feedback::flash('ERROR', 'DEFAULT', 'Invalid verification code. Please try again.');
|
|
|
|
}
|
|
|
|
header("Location: $app_root?page=credentials&action=setup");
|
2025-04-07 13:21:35 +00:00
|
|
|
exit();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'verify':
|
2025-04-08 07:30:07 +00:00
|
|
|
// This is a user-initiated verification
|
2025-04-07 13:21:35 +00:00
|
|
|
$code = $_POST['code'] ?? '';
|
2025-04-14 07:39:58 +00:00
|
|
|
if ($userObject->verifyTwoFactor($userId, $code)) {
|
2025-04-07 13:21:35 +00:00
|
|
|
$_SESSION['2fa_verified'] = true;
|
|
|
|
header("Location: $app_root?page=dashboard");
|
|
|
|
exit();
|
|
|
|
} else {
|
|
|
|
Feedback::flash('ERROR', 'DEFAULT', 'Invalid verification code. Please try again.');
|
|
|
|
header("Location: $app_root?page=credentials&action=verify");
|
|
|
|
exit();
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'disable':
|
2025-04-14 07:39:58 +00:00
|
|
|
if ($userObject->disableTwoFactor($userId)) {
|
2025-04-07 13:21:35 +00:00
|
|
|
Feedback::flash('NOTICE', 'DEFAULT', 'Two-factor authentication has been disabled.');
|
|
|
|
} else {
|
|
|
|
Feedback::flash('ERROR', 'DEFAULT', 'Failed to disable two-factor authentication.');
|
|
|
|
}
|
|
|
|
header("Location: $app_root?page=credentials");
|
|
|
|
exit();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'password':
|
|
|
|
require_once '../app/classes/validator.php';
|
|
|
|
|
|
|
|
$validator = new Validator($_POST);
|
|
|
|
$rules = [
|
|
|
|
'current_password' => [
|
2025-04-14 16:39:51 +00:00
|
|
|
'required' => true
|
2025-04-07 13:21:35 +00:00
|
|
|
],
|
|
|
|
'new_password' => [
|
|
|
|
'required' => true,
|
|
|
|
'min' => 8
|
|
|
|
],
|
|
|
|
'confirm_password' => [
|
|
|
|
'required' => true,
|
|
|
|
'matches' => 'new_password'
|
|
|
|
]
|
|
|
|
];
|
|
|
|
|
|
|
|
if (!$validator->validate($rules)) {
|
|
|
|
Feedback::flash('ERROR', 'DEFAULT', $validator->getFirstError());
|
|
|
|
header("Location: $app_root?page=credentials");
|
|
|
|
exit();
|
|
|
|
}
|
|
|
|
|
2025-04-14 07:39:58 +00:00
|
|
|
if ($userObject->changePassword($userId, $_POST['current_password'], $_POST['new_password'])) {
|
2025-04-07 13:21:35 +00:00
|
|
|
Feedback::flash('NOTICE', 'DEFAULT', 'Password has been changed successfully.');
|
|
|
|
} else {
|
|
|
|
Feedback::flash('ERROR', 'DEFAULT', 'Failed to change password. Please verify your current password.');
|
|
|
|
}
|
|
|
|
header("Location: $app_root?page=credentials");
|
|
|
|
exit();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// no form submitted, show the templates
|
|
|
|
} else {
|
|
|
|
// Get user timezone for templates
|
|
|
|
$userTimezone = !empty($userDetails[0]['timezone']) ? $userDetails[0]['timezone'] : 'UTC';
|
|
|
|
|
|
|
|
// Generate CSRF token if not exists
|
|
|
|
require_once '../app/helpers/security.php';
|
|
|
|
$security = SecurityHelper::getInstance();
|
|
|
|
$security->generateCsrfToken();
|
|
|
|
|
|
|
|
// Get 2FA status for the template
|
2025-04-14 07:39:58 +00:00
|
|
|
$has2fa = $userObject->isTwoFactorEnabled($userId);
|
2025-04-07 13:21:35 +00:00
|
|
|
|
|
|
|
switch ($action) {
|
2025-04-08 07:30:07 +00:00
|
|
|
case 'setup':
|
2025-04-07 13:21:35 +00:00
|
|
|
if (!$has2fa) {
|
2025-04-14 07:39:58 +00:00
|
|
|
$result = $userObject->enableTwoFactor($userId);
|
2025-04-08 07:30:07 +00:00
|
|
|
if ($result['success']) {
|
|
|
|
$setupData = $result['data'];
|
|
|
|
} else {
|
|
|
|
Feedback::flash('ERROR', 'DEFAULT', $result['message'] ?? 'Failed to generate 2FA setup data');
|
|
|
|
header("Location: $app_root?page=credentials");
|
|
|
|
exit();
|
|
|
|
}
|
2025-04-07 13:21:35 +00:00
|
|
|
}
|
|
|
|
// Get any new feedback messages
|
|
|
|
include '../app/helpers/feedback.php';
|
|
|
|
|
|
|
|
// Load the 2FA setup template
|
|
|
|
include '../app/templates/credentials-2fa-setup.php';
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'verify':
|
|
|
|
// Get any new feedback messages
|
|
|
|
include '../app/helpers/feedback.php';
|
|
|
|
|
|
|
|
// Load the 2FA verification template
|
|
|
|
include '../app/templates/credentials-2fa-verify.php';
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// Get any new feedback messages
|
|
|
|
include '../app/helpers/feedback.php';
|
|
|
|
|
|
|
|
// Load the combined management template
|
|
|
|
include '../app/templates/credentials-manage.php';
|
|
|
|
}
|
|
|
|
}
|