Files
Moonlight/Moonlight/Core/Services/Users/UserAuthService.cs
2024-02-05 22:39:09 +01:00

134 lines
4.0 KiB
C#

using MoonCore.Abstractions;
using MoonCore.Attributes;
using MoonCore.Exceptions;
using MoonCore.Helpers;
using MoonCore.Services;
using Moonlight.Core.Configuration;
using Moonlight.Core.Database.Entities;
using Moonlight.Core.Event;
using Moonlight.Core.Extensions;
using Moonlight.Core.Models.Abstractions;
using Moonlight.Core.Models.Enums;
using Moonlight.Core.Models.Templates;
using Moonlight.Core.Services.Utils;
using OtpNet;
namespace Moonlight.Core.Services.Users;
[Scoped]
public class UserAuthService
{
private readonly Repository<User> UserRepository;
private readonly JwtService JwtService;
private readonly ConfigService<ConfigV1> ConfigService;
private readonly MailService MailService;
public UserAuthService(
Repository<User> userRepository,
JwtService jwtService,
ConfigService<ConfigV1> configService,
MailService mailService)
{
UserRepository = userRepository;
JwtService = jwtService;
ConfigService = configService;
MailService = mailService;
}
public async Task<User> Register(string username, string email, string password)
{
// Event though we have form validation i want to
// ensure that at least these basic formatting things are done
email = email.ToLower().Trim();
username = username.ToLower().Trim();
// Prevent duplication or username and/or email
if (UserRepository.Get().Any(x => x.Email == email))
throw new DisplayException("A user with that email does already exist");
if (UserRepository.Get().Any(x => x.Username == username))
throw new DisplayException("A user with that username does already exist");
var user = new User()
{
Username = username,
Email = email,
Password = HashHelper.HashToString(password)
};
var result = UserRepository.Add(user);
await Events.OnUserRegistered.InvokeAsync(result);
return result;
}
public async Task ChangePassword(User user, string newPassword)
{
user.Password = HashHelper.HashToString(newPassword);
user.TokenValidTimestamp = DateTime.UtcNow;
UserRepository.Update(user);
await Events.OnUserPasswordChanged.InvokeAsync(user);
}
public Task SeedTotp(User user)
{
var key = Base32Encoding.ToString(KeyGeneration.GenerateRandomKey(20));
user.TotpKey = key;
UserRepository.Update(user);
return Task.CompletedTask;
}
public async Task SetTotp(User user, bool state)
{
// Access to flags without identity service
var flags = new FlagStorage(user.Flags);
flags[UserFlag.TotpEnabled] = state;
user.Flags = flags.RawFlagString;
if (!state)
user.TotpKey = null;
UserRepository.Update(user);
await Events.OnUserTotpSet.InvokeAsync(user);
}
// Mails
public async Task SendVerification(User user)
{
var jwt = await JwtService.Create(data =>
{
data.Add("mailToVerify", user.Email);
}, "EmailVerification", TimeSpan.FromMinutes(10));
await MailService.Send(user, "Verify your account", "verifyMail", user, new MailVerify()
{
Url = ConfigService.Get().AppUrl + "/api/auth/verify?token=" + jwt
});
}
public async Task SendResetPassword(string email)
{
var user = UserRepository
.Get()
.FirstOrDefault(x => x.Email == email);
if (user == null)
throw new DisplayException("An account with that email was not found");
var jwt = await JwtService.Create(data =>
{
data.Add("accountToReset", user.Id.ToString());
}, "PasswordReset", TimeSpan.FromHours(1));
await MailService.Send(user, "Password reset for your account", "passwordReset", user, new ResetPassword()
{
Url = ConfigService.Get().AppUrl + "/api/auth/reset?token=" + jwt
});
}
}