AuthorBuddy/Services/AuthService.cs
2026-05-21 11:04:42 +02:00

176 lines
5 KiB
C#

using AuthorBuddy.Web.Data;
using LiteDB;
namespace AuthorBuddy.Web.Services;
public class AuthService : IAuthService
{
private readonly ILiteDatabase _db;
private readonly ISettingsService _settingsService;
private UserEntity? _currentUser;
private string? _pending2FASecret;
private bool _requires2FA;
public AuthService(ILiteDatabase db, ISettingsService settingsService)
{
_db = db;
_settingsService = settingsService;
}
public bool IsLoggedIn => _currentUser != null;
public bool Is2FARequired => _requires2FA;
public async Task<bool> LoginAsync(string username, string password)
{
var col = _db.GetCollection<UserEntity>("users");
var user = col.FindOne(u => u.Name == username);
if (user == null || string.IsNullOrEmpty(user.PasswordHash))
return false;
if (!TotpHelper.VerifyPassword(password, user.PasswordHash))
return false;
if (user.TwoFactorEnabled)
{
_pending2FASecret = user.TwoFactorSecret;
_requires2FA = true;
return true;
}
await SetAuthenticatedUser(user);
return true;
}
public async Task LogoutAsync()
{
_currentUser = null;
_requires2FA = false;
_pending2FASecret = null;
await Task.CompletedTask;
}
public async Task AdminBypassLoginAsync(int userId)
{
var col = _db.GetCollection<UserEntity>("users");
var user = col.FindById(userId);
if (user != null)
await SetAuthenticatedUser(user);
}
public async Task<bool> RegisterAsync(string username, string password)
{
var col = _db.GetCollection<UserEntity>("users");
var existing = col.FindOne(u => u.Name == username);
if (existing != null) return false;
var user = new UserEntity
{
Name = username,
PasswordHash = TotpHelper.HashPassword(password),
IsCurrent = true,
TwoFactorEnabled = false,
TwoFactorSecret = string.Empty
};
col.Insert(user);
await SetAuthenticatedUser(user);
return true;
}
public Task<UserEntity?> GetCurrentUserAsync()
{
return Task.FromResult(_currentUser);
}
public async Task<bool> Verify2FAAsync(string code)
{
if (string.IsNullOrEmpty(_pending2FASecret)) return false;
if (!TotpHelper.VerifyCode(_pending2FASecret, code))
return false;
var col = _db.GetCollection<UserEntity>("users");
var user = col.FindOne(u => u.TwoFactorSecret == _pending2FASecret);
if (user == null) return false;
await SetAuthenticatedUser(user);
return true;
}
public Task<string> Generate2FASecretAsync()
{
return Task.FromResult(TotpHelper.GenerateSecret());
}
public string Get2FAProvisioningUri(string secret, string username)
{
return TotpHelper.GetProvisioningUri(secret, username);
}
public async Task<bool> Enable2FAAsync(string secret)
{
if (_currentUser == null) return false;
var col = _db.GetCollection<UserEntity>("users");
var user = col.FindById(_currentUser.Id);
if (user == null) return false;
user.TwoFactorSecret = secret;
user.TwoFactorEnabled = true;
col.Update(user);
_currentUser.TwoFactorSecret = secret;
_currentUser.TwoFactorEnabled = true;
return true;
}
public async Task<bool> Disable2FAAsync()
{
if (_currentUser == null) return false;
var col = _db.GetCollection<UserEntity>("users");
var user = col.FindById(_currentUser.Id);
if (user == null) return false;
user.TwoFactorSecret = string.Empty;
user.TwoFactorEnabled = false;
col.Update(user);
_currentUser.TwoFactorSecret = string.Empty;
_currentUser.TwoFactorEnabled = false;
return true;
}
public async Task<bool> Is2FAEnabledAsync()
{
if (_currentUser == null) return false;
var col = _db.GetCollection<UserEntity>("users");
var user = col.FindById(_currentUser.Id);
return user?.TwoFactorEnabled ?? false;
}
public async Task<string?> GetCurrent2FASecretAsync()
{
if (_currentUser == null) return null;
var col = _db.GetCollection<UserEntity>("users");
var user = col.FindById(_currentUser.Id);
return user?.TwoFactorSecret;
}
private async Task SetAuthenticatedUser(UserEntity user)
{
_currentUser = user;
_requires2FA = false;
_pending2FASecret = null;
_settingsService.CurrentProjectId = null;
_settingsService.CurrentFilePath = null;
var col = _db.GetCollection<UserEntity>("users");
var all = col.FindAll().ToList();
foreach (var u in all)
{
u.IsCurrent = u.Id == user.Id;
col.Update(u);
}
await _settingsService.InitializeAsync();
}
}