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