aboutsummaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs8
-rw-r--r--server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs8
-rw-r--r--server/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs8
-rw-r--r--server/src/Program.cs2
-rw-r--r--server/src/Services/ForgotPasswordService.cs115
-rw-r--r--server/src/Services/PasswordResetService.cs115
-rw-r--r--server/src/Services/UserService.cs10
7 files changed, 133 insertions, 133 deletions
diff --git a/server/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs b/server/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs
index 1c2a51b..8fbc9a0 100644
--- a/server/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs
+++ b/server/src/Endpoints/Internal/PasswordResetRequests/CreateResetRequestRoute.cs
@@ -4,13 +4,13 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests;
public class CreateResetRequestRoute : RouteBaseAsync.WithRequest<string>.WithActionResult
{
private readonly ILogger<CreateResetRequestRoute> _logger;
- private readonly ForgotPasswordService _forgotPasswordService;
+ private readonly PasswordResetService _passwordResetService;
private readonly AppDbContext _context;
/// <inheritdoc />
- public CreateResetRequestRoute(ILogger<CreateResetRequestRoute> logger, ForgotPasswordService forgotPasswordService, AppDbContext context) {
+ public CreateResetRequestRoute(ILogger<CreateResetRequestRoute> logger, PasswordResetService passwordResetService, AppDbContext context) {
_logger = logger;
- _forgotPasswordService = forgotPasswordService;
+ _passwordResetService = passwordResetService;
_context = context;
}
@@ -45,7 +45,7 @@ public class CreateResetRequestRoute : RouteBaseAsync.WithRequest<string>.WithAc
try {
var user = _context.Users.SingleOrDefault(c => c.Username.Equals(username));
if (user != default) {
- await _forgotPasswordService.AddRequestAsync(user, tz, cancellationToken);
+ await _passwordResetService.AddRequestAsync(user, tz, cancellationToken);
return Ok();
}
diff --git a/server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs b/server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs
index e33a4fb..96f344a 100644
--- a/server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs
+++ b/server/src/Endpoints/Internal/PasswordResetRequests/FulfillResetRequestRoute.cs
@@ -4,11 +4,11 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests;
/// <inheritdoc />
public class FulfillResetRequestRoute : RouteBaseAsync.WithRequest<FulfillResetRequestPayload>.WithActionResult
{
- private readonly ForgotPasswordService _forgotPasswordService;
+ private readonly PasswordResetService _passwordResetService;
/// <inheritdoc />
- public FulfillResetRequestRoute(ForgotPasswordService forgotPasswordService) {
- _forgotPasswordService = forgotPasswordService;
+ public FulfillResetRequestRoute(PasswordResetService passwordResetService) {
+ _passwordResetService = passwordResetService;
}
/// <summary>
@@ -21,7 +21,7 @@ public class FulfillResetRequestRoute : RouteBaseAsync.WithRequest<FulfillResetR
[HttpPost("~/_/forgot-password-requests/fulfill")]
public override async Task<ActionResult> HandleAsync(FulfillResetRequestPayload request, CancellationToken cancellationToken = default) {
try {
- var fulfilled = await _forgotPasswordService.FullFillRequestAsync(request.Id, request.NewPassword, cancellationToken);
+ var fulfilled = await _passwordResetService.FullFillRequestAsync(request.Id, request.NewPassword, cancellationToken);
return Ok(fulfilled);
} catch (Exception e) {
if (e is ForgotPasswordRequestNotFoundException or UserNotFoundException) {
diff --git a/server/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs b/server/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs
index 9984094..c4dcd22 100644
--- a/server/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs
+++ b/server/src/Endpoints/Internal/PasswordResetRequests/IsResetRequestValidRoute.cs
@@ -3,11 +3,11 @@ namespace IOL.GreatOffice.Api.Endpoints.Internal.PasswordResetRequests;
/// <inheritdoc />
public class IsResetRequestValidRoute : RouteBaseAsync.WithRequest<Guid>.WithActionResult
{
- private readonly ForgotPasswordService _forgotPasswordService;
+ private readonly PasswordResetService _passwordResetService;
/// <inheritdoc />
- public IsResetRequestValidRoute(ForgotPasswordService forgotPasswordService) {
- _forgotPasswordService = forgotPasswordService;
+ public IsResetRequestValidRoute(PasswordResetService passwordResetService) {
+ _passwordResetService = passwordResetService;
}
/// <summary>
@@ -19,7 +19,7 @@ public class IsResetRequestValidRoute : RouteBaseAsync.WithRequest<Guid>.WithAct
[AllowAnonymous]
[HttpGet("~/_/forgot-password-requests/is-valid")]
public override async Task<ActionResult> HandleAsync(Guid id, CancellationToken cancellationToken = default) {
- var request = await _forgotPasswordService.GetRequestAsync(id, cancellationToken);
+ var request = await _passwordResetService.GetRequestAsync(id, cancellationToken);
if (request == default) {
return NotFound();
}
diff --git a/server/src/Program.cs b/server/src/Program.cs
index 40ef1b0..3d84bf9 100644
--- a/server/src/Program.cs
+++ b/server/src/Program.cs
@@ -54,7 +54,7 @@ public static class Program
builder.Services.AddHttpClient();
builder.Services.AddMemoryCache();
builder.Services.AddScoped<MailService>();
- builder.Services.AddScoped<ForgotPasswordService>();
+ builder.Services.AddScoped<PasswordResetService>();
builder.Services.AddScoped<UserService>();
builder.Services.AddTransient<VaultService>();
var vaultService = builder.Services.BuildServiceProvider().GetRequiredService<VaultService>();
diff --git a/server/src/Services/ForgotPasswordService.cs b/server/src/Services/ForgotPasswordService.cs
deleted file mode 100644
index b7e99ad..0000000
--- a/server/src/Services/ForgotPasswordService.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-namespace IOL.GreatOffice.Api.Services;
-
-public class ForgotPasswordService
-{
- private readonly AppDbContext _context;
- private readonly MailService _mailService;
- private readonly AppConfiguration _configuration;
- private readonly ILogger<ForgotPasswordService> _logger;
-
-
- public ForgotPasswordService(
- AppDbContext context,
- VaultService vaultService,
- ILogger<ForgotPasswordService> logger,
- MailService mailService
- ) {
- _context = context;
- _configuration = vaultService.GetCurrentAppConfiguration();
- _logger = logger;
- _mailService = mailService;
- }
-
- public async Task<ForgotPasswordRequest> GetRequestAsync(Guid id, CancellationToken cancellationToken = default) {
- var request = await _context.ForgotPasswordRequests
- .Include(c => c.User)
- .SingleOrDefaultAsync(c => c.Id == id, cancellationToken);
- if (request == default) {
- return default;
- }
-
- _logger.LogInformation($"Found forgot password request for user: {request.User.Username}, expires at {request.ExpirationDate} (in {request.ExpirationDate.Subtract(AppDateTime.UtcNow).Minutes} minutes).");
- return request;
- }
-
- public async Task<bool> FullFillRequestAsync(Guid id, string newPassword, CancellationToken cancellationToken = default) {
- var request = await GetRequestAsync(id, cancellationToken);
- if (request == default) {
- throw new ForgotPasswordRequestNotFoundException("Request with id: " + id + " was not found");
- }
-
- var user = _context.Users.SingleOrDefault(c => c.Id == request.User.Id);
- if (user == default) {
- throw new UserNotFoundException("User with id: " + request.User.Id + " was not found");
- }
-
- user.HashAndSetPassword(newPassword);
- _context.Users.Update(user);
- await _context.SaveChangesAsync(cancellationToken);
- _logger.LogInformation($"Fullfilled forgot password request for user: {request.User.Username}");
- await DeleteRequestsForUserAsync(user.Id, cancellationToken);
- return true;
- }
-
-
- public async Task AddRequestAsync(User user, TimeZoneInfo requestTz, CancellationToken cancellationToken = default) {
- await DeleteRequestsForUserAsync(user.Id, cancellationToken);
- var request = new ForgotPasswordRequest(user);
- _context.ForgotPasswordRequests.Add(request);
- await _context.SaveChangesAsync(cancellationToken);
- var portalUrl = _configuration.PORTAL_URL;
- var emailFromAddress = _configuration.EMAIL_FROM_ADDRESS;
- var emailFromDisplayName = _configuration.EMAIL_FROM_DISPLAY_NAME;
- var zonedExpirationDate = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(request.ExpirationDate, requestTz.Id);
- var message = new MailMessage {
- From = new MailAddress(emailFromAddress, emailFromDisplayName),
- To = {
- new MailAddress(user.Username)
- },
- Subject = "Time Tracker - Forgot password request",
- Body = @$"
-Hi {user.Username}
-
-Go to the following link to set a new password.
-
-{portalUrl}/#/reset-password?id={request.Id}
-
-The link expires at {zonedExpirationDate:yyyy-MM-dd hh:mm}.
-If you did not request a password reset, no action is required.
-"
- };
-
-#pragma warning disable 4014
- Task.Run(() => {
-#pragma warning restore 4014
- _mailService.SendMail(message);
- _logger.LogInformation($"Added forgot password request for user: {request.User.Username}, expires in {request.ExpirationDate.Subtract(AppDateTime.UtcNow)}.");
- },
- cancellationToken);
- }
-
- public async Task DeleteRequestsForUserAsync(Guid userId, CancellationToken cancellationToken = default) {
- var requestsToRemove = _context.ForgotPasswordRequests.Where(c => c.UserId == userId).ToList();
- if (!requestsToRemove.Any()) return;
- _context.ForgotPasswordRequests.RemoveRange(requestsToRemove);
- await _context.SaveChangesAsync(cancellationToken);
- _logger.LogInformation($"Deleted {requestsToRemove.Count} forgot password requests for user: {userId}.");
- }
-
-
- public async Task DeleteStaleRequestsAsync(CancellationToken cancellationToken = default) {
- var deleteCount = 0;
- foreach (var request in _context.ForgotPasswordRequests) {
- if (!request.IsExpired) {
- continue;
- }
-
- _context.ForgotPasswordRequests.Remove(request);
- deleteCount++;
- _logger.LogInformation($"Marking forgot password request with id: {request.Id} for deletion, expiration date was {request.ExpirationDate}.");
- }
-
- await _context.SaveChangesAsync(cancellationToken);
- _logger.LogInformation($"Deleted {deleteCount} stale forgot password requests.");
- }
-}
diff --git a/server/src/Services/PasswordResetService.cs b/server/src/Services/PasswordResetService.cs
new file mode 100644
index 0000000..1b4f147
--- /dev/null
+++ b/server/src/Services/PasswordResetService.cs
@@ -0,0 +1,115 @@
+namespace IOL.GreatOffice.Api.Services;
+
+public class PasswordResetService
+{
+ private readonly AppDbContext _context;
+ private readonly MailService _mailService;
+ private readonly AppConfiguration _configuration;
+ private readonly ILogger<PasswordResetService> _logger;
+
+
+ public PasswordResetService(
+ AppDbContext context,
+ VaultService vaultService,
+ ILogger<PasswordResetService> logger,
+ MailService mailService
+ ) {
+ _context = context;
+ _configuration = vaultService.GetCurrentAppConfiguration();
+ _logger = logger;
+ _mailService = mailService;
+ }
+
+ public async Task<ForgotPasswordRequest> GetRequestAsync(Guid id, CancellationToken cancellationToken = default) {
+ var request = await _context.ForgotPasswordRequests
+ .Include(c => c.User)
+ .SingleOrDefaultAsync(c => c.Id == id, cancellationToken);
+ if (request == default) {
+ return default;
+ }
+
+ _logger.LogInformation($"Found password reset request for user: {request.User.Username}, expires at {request.ExpirationDate} (in {request.ExpirationDate.Subtract(AppDateTime.UtcNow).Minutes} minutes).");
+ return request;
+ }
+
+ public async Task<bool> FullFillRequestAsync(Guid id, string newPassword, CancellationToken cancellationToken = default) {
+ var request = await GetRequestAsync(id, cancellationToken);
+ if (request == default) {
+ throw new ForgotPasswordRequestNotFoundException("Request with id: " + id + " was not found");
+ }
+
+ var user = _context.Users.SingleOrDefault(c => c.Id == request.User.Id);
+ if (user == default) {
+ throw new UserNotFoundException("User with id: " + request.User.Id + " was not found");
+ }
+
+ user.HashAndSetPassword(newPassword);
+ _context.Users.Update(user);
+ await _context.SaveChangesAsync(cancellationToken);
+ _logger.LogInformation($"Fullfilled password reset request for user: {request.User.Username}");
+ await DeleteRequestsForUserAsync(user.Id, cancellationToken);
+ return true;
+ }
+
+
+ public async Task AddRequestAsync(User user, TimeZoneInfo requestTz, CancellationToken cancellationToken = default) {
+ await DeleteRequestsForUserAsync(user.Id, cancellationToken);
+ var request = new ForgotPasswordRequest(user);
+ _context.ForgotPasswordRequests.Add(request);
+ await _context.SaveChangesAsync(cancellationToken);
+ var portalUrl = _configuration.PORTAL_URL;
+ var emailFromAddress = _configuration.EMAIL_FROM_ADDRESS;
+ var emailFromDisplayName = _configuration.EMAIL_FROM_DISPLAY_NAME;
+ var zonedExpirationDate = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(request.ExpirationDate, requestTz.Id);
+ var message = new MailMessage {
+ From = new MailAddress(emailFromAddress, emailFromDisplayName),
+ To = {
+ new MailAddress(user.Username)
+ },
+ Subject = "Reset password - Greatoffice",
+ Body = @$"
+Hi {user.Username}
+
+Go to the following link to set a new password.
+
+{portalUrl}/reset-password/{request.Id}
+
+The link expires at {zonedExpirationDate:yyyy-MM-dd hh:mm}.
+If you did not request a password reset, no action is required.
+"
+ };
+
+#pragma warning disable 4014
+ Task.Run(() => {
+#pragma warning restore 4014
+ _mailService.SendMail(message);
+ _logger.LogInformation($"Added password reset request for user: {request.User.Username}, expires in {request.ExpirationDate.Subtract(AppDateTime.UtcNow)}.");
+ },
+ cancellationToken);
+ }
+
+ public async Task DeleteRequestsForUserAsync(Guid userId, CancellationToken cancellationToken = default) {
+ var requestsToRemove = _context.ForgotPasswordRequests.Where(c => c.UserId == userId).ToList();
+ if (!requestsToRemove.Any()) return;
+ _context.ForgotPasswordRequests.RemoveRange(requestsToRemove);
+ await _context.SaveChangesAsync(cancellationToken);
+ _logger.LogInformation($"Deleted {requestsToRemove.Count} password reset requests for user: {userId}.");
+ }
+
+
+ public async Task DeleteStaleRequestsAsync(CancellationToken cancellationToken = default) {
+ var deleteCount = 0;
+ foreach (var request in _context.ForgotPasswordRequests.Where(c => c.IsExpired)) {
+ if (!request.IsExpired) {
+ continue;
+ }
+
+ _context.ForgotPasswordRequests.Remove(request);
+ deleteCount++;
+ _logger.LogInformation($"Marking password reset request with id: {request.Id} for deletion, expiration date was {request.ExpirationDate}.");
+ }
+
+ await _context.SaveChangesAsync(cancellationToken);
+ _logger.LogInformation($"Deleted {deleteCount} stale password reset requests.");
+ }
+} \ No newline at end of file
diff --git a/server/src/Services/UserService.cs b/server/src/Services/UserService.cs
index 9b531de..6db663a 100644
--- a/server/src/Services/UserService.cs
+++ b/server/src/Services/UserService.cs
@@ -2,14 +2,14 @@ namespace IOL.GreatOffice.Api.Services;
public class UserService
{
- private readonly ForgotPasswordService _forgotPasswordService;
+ private readonly PasswordResetService _passwordResetService;
/// <summary>
/// Provides methods to perform common operations on user data.
/// </summary>
- /// <param name="forgotPasswordService"></param>
- public UserService(ForgotPasswordService forgotPasswordService) {
- _forgotPasswordService = forgotPasswordService;
+ /// <param name="passwordResetService"></param>
+ public UserService(PasswordResetService passwordResetService) {
+ _passwordResetService = passwordResetService;
}
/// <summary>
@@ -37,7 +37,7 @@ public class UserService
}
await httpContext.SignInAsync(principal, authenticationProperties);
- await _forgotPasswordService.DeleteRequestsForUserAsync(user.Id);
+ await _passwordResetService.DeleteRequestsForUserAsync(user.Id);
}
/// <summary>