Add two-factor authentication (2FA) support

Introduces two-factor authentication (2FA) with TOTP, backup codes, and email codes. Adds controllers, services, views, and migration for 2FA setup, verification, and management. Updates user and settings models, email helper, and relevant controllers to support 2FA policy enforcement, configuration, and user flows. Enhances security by allowing admins to require or disable 2FA, and provides backup code generation and management for account recovery.
This commit is contained in:
Hosteroid
2025-10-16 17:25:06 +03:00
parent 1edde3645c
commit 6e8fef9b79
18 changed files with 2072 additions and 24 deletions

View File

@@ -26,6 +26,7 @@ class SettingsController extends Controller
$appSettings = $this->settingModel->getAppSettings();
$emailSettings = $this->settingModel->getEmailSettings();
$captchaSettings = $this->settingModel->getCaptchaSettings();
$twoFactorSettings = $this->settingModel->getTwoFactorSettings();
// Predefined notification day options
$notificationPresets = [
@@ -69,6 +70,7 @@ class SettingsController extends Controller
'appSettings' => $appSettings,
'emailSettings' => $emailSettings,
'captchaSettings' => $captchaSettings,
'twoFactorSettings' => $twoFactorSettings,
'notificationPresets' => $notificationPresets,
'checkIntervalPresets' => $checkIntervalPresets,
'title' => 'Settings'
@@ -435,5 +437,59 @@ class SettingsController extends Controller
$this->redirect('/settings#email');
}
public function updateTwoFactor()
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$this->redirect('/settings');
return;
}
// CSRF Protection
$this->verifyCsrf('/settings#security');
try {
$twoFactorPolicy = trim($_POST['two_factor_policy'] ?? 'optional');
$rateLimitMinutes = (int)($_POST['two_factor_rate_limit_minutes'] ?? 15);
$emailCodeExpiryMinutes = (int)($_POST['two_factor_email_code_expiry_minutes'] ?? 10);
// Validate policy
$validPolicies = ['disabled', 'optional', 'forced'];
if (!in_array($twoFactorPolicy, $validPolicies)) {
$_SESSION['error'] = 'Invalid 2FA policy selected';
$this->redirect('/settings#security');
return;
}
// Validate rate limit (1-60 minutes)
if ($rateLimitMinutes < 1 || $rateLimitMinutes > 60) {
$_SESSION['error'] = 'Rate limit must be between 1 and 60 minutes';
$this->redirect('/settings#security');
return;
}
// Validate email code expiry (1-30 minutes)
if ($emailCodeExpiryMinutes < 1 || $emailCodeExpiryMinutes > 30) {
$_SESSION['error'] = 'Email code expiry must be between 1 and 30 minutes';
$this->redirect('/settings#security');
return;
}
$twoFactorSettings = [
'two_factor_policy' => $twoFactorPolicy,
'two_factor_rate_limit_minutes' => $rateLimitMinutes,
'two_factor_email_code_expiry_minutes' => $emailCodeExpiryMinutes
];
$this->settingModel->updateTwoFactorSettings($twoFactorSettings);
$_SESSION['success'] = 'Two-Factor Authentication settings updated successfully';
$this->redirect('/settings#security');
} catch (\Exception $e) {
$_SESSION['error'] = 'Failed to update 2FA settings: ' . $e->getMessage();
$this->redirect('/settings#security');
}
}
}