Files
Moonlight/Moonlight/App/Services/UserService.cs

181 lines
5.9 KiB
C#

using JWT.Algorithms;
using JWT.Builder;
using Moonlight.App.Database.Entities;
using Moonlight.App.Exceptions;
using Moonlight.App.Models.Misc;
using Moonlight.App.Repositories;
namespace Moonlight.App.Services;
public class UserService
{
private readonly UserRepository UserRepository;
private readonly TotpService TotpService;
private readonly ConfigService ConfigService;
private readonly string JwtSecret;
public UserService(
UserRepository userRepository,
TotpService totpService,
ConfigService configService)
{
UserRepository = userRepository;
TotpService = totpService;
ConfigService = configService;
JwtSecret = ConfigService
.GetSection("Moonlight")
.GetSection("Security")
.GetValue<string>("Token");
}
public async Task<string> Register(string email, string password, string firstname, string lastname)
{
var emailTaken = UserRepository.Get().FirstOrDefault(x => x.Email == email) != null;
if (emailTaken)
{
//AuditLogService.Log("register:fail", $"Invalid email: {email}");
throw new DisplayException("The email is already in use");
}
var user = UserRepository.Add(new()
{
Address = "",
Admin = false,
City = "",
Country = "",
Email = email,
Password = BCrypt.Net.BCrypt.HashPassword(password),
FirstName = firstname,
LastName = lastname,
State = "",
Status = UserStatus.Unverified,
CreatedAt = DateTime.Now,
DiscordDiscriminator = "",
DiscordId = -1,
DiscordUsername = "",
TotpEnabled = false,
TotpSecret = "",
UpdatedAt = DateTime.Now,
TokenValidTime = DateTime.Now.AddDays(-5)
});
//AuditLogService.Log("register:done", $"A new user has registered: Email: {email}");
//var mail = new WelcomeMail(user);
//await MailService.Send(mail, user);
return JwtBuilder.Create()
.WithAlgorithm(new HMACSHA256Algorithm())
.WithSecret(JwtSecret)
.AddClaim("exp", DateTimeOffset.UtcNow.AddDays(10).ToUnixTimeSeconds())
.AddClaim("iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds())
.AddClaim("userid", user.Id)
.Encode();
}
public Task<bool> CheckTotp(string email, string password)
{
var user = UserRepository.Get()
.FirstOrDefault(
x => x.Email.Equals(
email
)
);
if (user == null)
{
//AuditLogService.Log("login:fail", $"Invalid email: {email}. Password: {password}");
throw new DisplayException("Email and password combination not found");
}
if (BCrypt.Net.BCrypt.Verify(password, user.Password))
{
return Task.FromResult(user.TotpEnabled);
}
//AuditLogService.Log("login:fail", $"Invalid email: {email}. Password: {password}");
throw new DisplayException("Email and password combination not found");;
}
public async Task<string> Login(string email, string password, string totpCode = "")
{
var needTotp = await CheckTotp(email, password);
var user = UserRepository.Get()
.FirstOrDefault(
x => x.Email.Equals(
email
)
);
if (needTotp)
{
if (string.IsNullOrEmpty(totpCode))
throw new DisplayException("2FA code must be provided");
var totpCodeValid = await TotpService.Verify(user.TotpSecret, totpCode);
if (totpCodeValid)
{
//AuditLogService.Log("login:success", $"{user.Email} has successfully logged in");
return JwtBuilder.Create()
.WithAlgorithm(new HMACSHA256Algorithm())
.WithSecret(JwtSecret)
.AddClaim("exp", DateTimeOffset.UtcNow.AddDays(10).ToUnixTimeSeconds())
.AddClaim("iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds())
.AddClaim("userid", user.Id)
.Encode();
}
else
{
//AuditLogService.Log("login:fail", $"Invalid totp code: {totpCode}");
throw new DisplayException("2FA code invalid");
}
}
else
{
//AuditLogService.Log("login:success", $"{user.Email} has successfully logged in");
return JwtBuilder.Create()
.WithAlgorithm(new HMACSHA256Algorithm())
.WithSecret(JwtSecret)
.AddClaim("exp", DateTimeOffset.UtcNow.AddDays(10).ToUnixTimeSeconds())
.AddClaim("iat", DateTimeOffset.UtcNow.ToUnixTimeSeconds())
.AddClaim("userid", user.Id)
.Encode();
}
}
public async Task ChangePassword(User user, string password)
{
user.Password = BCrypt.Net.BCrypt.HashPassword(password);
user.TokenValidTime = DateTime.Now;
UserRepository.Update(user);
//var mail = new NewPasswordMail(user);
//await MailService.Send(mail, user);
//AuditLogService.Log("password:change", "The password has been set to a new one");
}
public Task<User> SftpLogin(int id, string password)
{
var user = UserRepository.Get().FirstOrDefault(x => x.Id == id);
if (user == null)
throw new Exception("Unknown user");
if (BCrypt.Net.BCrypt.Verify(password, user.Password))
{
//TODO: Maybe log
return Task.FromResult(user);
}
//TODO: Log
throw new Exception("Invalid userid or password");
}
}