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

@@ -256,5 +256,33 @@ class Setting extends Model
return $result;
}
/**
* Get 2FA settings
*/
public function getTwoFactorSettings(): array
{
return [
'policy' => $this->getValue('two_factor_policy', 'optional'),
'rate_limit_minutes' => (int)$this->getValue('two_factor_rate_limit_minutes', 15),
'email_code_expiry_minutes' => (int)$this->getValue('two_factor_email_code_expiry_minutes', 10)
];
}
/**
* Update 2FA settings
*/
public function updateTwoFactorSettings(array $settings): bool
{
$result = true;
foreach ($settings as $key => $value) {
if (!$this->setValue($key, $value)) {
$result = false;
}
}
return $result;
}
}

View File

@@ -182,7 +182,7 @@ class User extends Model
public function findByVerificationToken(string $token): ?array
{
$stmt = $this->db->prepare(
"SELECT * FROM users WHERE email_verification_token = ? AND email_verified = 0"
"SELECT * FROM users WHERE email_verification_token = ? AND (email_verified IS NULL OR email_verified = 0)"
);
$stmt->execute([$token]);
$result = $stmt->fetch();
@@ -254,5 +254,35 @@ class User extends Model
$stmt = $this->db->prepare("DELETE FROM remember_tokens WHERE token = ?");
return $stmt->execute([$token]);
}
/**
* Get user's 2FA status
*/
public function getTwoFactorStatus(int $userId): array
{
$user = $this->find($userId);
if (!$user) {
return ['enabled' => false, 'can_enable' => false, 'required' => false];
}
$twoFactorService = new \App\Services\TwoFactorService();
return [
'enabled' => (bool)$user['two_factor_enabled'],
'can_enable' => $twoFactorService->canEnableTwoFactor($userId),
'required' => $twoFactorService->isTwoFactorRequired($userId),
'setup_at' => $user['two_factor_setup_at'],
'backup_codes_count' => $user['two_factor_backup_codes'] ? count(json_decode($user['two_factor_backup_codes'], true)) : 0
];
}
/**
* Check if user has verified email (required for 2FA)
*/
public function hasVerifiedEmail(int $userId): bool
{
$user = $this->find($userId);
return $user && $user['email_verified'];
}
}