verifyCsrfToken($_POST['csrf_token'] ?? ''); 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'; checkRateLimit($dbWeb, 'credentials', $user_id); switch ($item) { case '2fa': switch ($action) { case 'setup': // Validate the setup code $code = $_POST['code'] ?? ''; $secret = $_POST['secret'] ?? ''; if ($userObject->enableTwoFactor($user_id, $secret, $code)) { Feedback::flash('NOTICE', 'DEFAULT', 'Two-factor authentication has been enabled successfully.'); header("Location: $app_root?page=credentials"); exit(); } else { // 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"); exit(); } break; case 'verify': // This is a user-initiated verification $code = $_POST['code'] ?? ''; if ($userObject->verifyTwoFactor($user_id, $code)) { $_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': if ($userObject->disableTwoFactor($user_id)) { 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' => [ 'required' => true, 'min' => 8 ], '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(); } if ($userObject->changePassword($user_id, $_POST['current_password'], $_POST['new_password'])) { 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 $has2fa = $userObject->isTwoFactorEnabled($user_id); switch ($action) { case 'setup': if (!$has2fa) { $result = $userObject->enableTwoFactor($user_id); 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(); } } // 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'; } }