diff --git a/backend/LexBoxApi/Controllers/LoginController.cs b/backend/LexBoxApi/Controllers/LoginController.cs index a9f3defbd..20241a5bd 100644 --- a/backend/LexBoxApi/Controllers/LoginController.cs +++ b/backend/LexBoxApi/Controllers/LoginController.cs @@ -1,5 +1,7 @@ using System.ComponentModel.DataAnnotations; using LexBoxApi.Auth; +using LexBoxApi.Models; +using LexBoxApi.Otel; using LexBoxApi.Services; using LexCore; using LexCore.Auth; @@ -7,6 +9,7 @@ using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.EntityFrameworkCore; namespace LexBoxApi.Controllers; @@ -20,18 +23,21 @@ public class LoginController : ControllerBase private readonly LoggedInContext _loggedInContext; private readonly EmailService _emailService; private readonly UserService _userService; + private readonly TurnstileService _turnstileService; public LoginController(LexAuthService lexAuthService, LexBoxDbContext lexBoxDbContext, LoggedInContext loggedInContext, EmailService emailService, - UserService userService) + UserService userService, + TurnstileService turnstileService) { _lexAuthService = lexAuthService; _lexBoxDbContext = lexBoxDbContext; _loggedInContext = loggedInContext; _emailService = emailService; _userService = userService; + _turnstileService = turnstileService; } [HttpGet("loginRedirect")] @@ -101,9 +107,21 @@ public async Task Logout() [HttpPost("forgotPassword")] [AllowAnonymous] - public async Task ForgotPassword(string email) + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesErrorResponseType(typeof(Dictionary))] + [ProducesDefaultResponseType] + public async Task ForgotPassword(ForgotPasswordInput input) { - await _lexAuthService.ForgotPassword(email); + using var registerActivity = LexBoxActivitySource.Get().StartActivity("ForgotPassword"); + var validToken = await _turnstileService.IsTokenValid(input.TurnstileToken, input.Email); + registerActivity?.AddTag("app.turnstile_token_valid", validToken); + if (!validToken) + { + ModelState.AddModelError(r => r.TurnstileToken, "token invalid"); + return ValidationProblem(ModelState); + } + + await _lexAuthService.ForgotPassword(input.Email); return Ok(); } diff --git a/backend/LexBoxApi/Models/ForgotPasswordInput.cs b/backend/LexBoxApi/Models/ForgotPasswordInput.cs new file mode 100644 index 000000000..2da950b6c --- /dev/null +++ b/backend/LexBoxApi/Models/ForgotPasswordInput.cs @@ -0,0 +1,7 @@ +using System.ComponentModel.DataAnnotations; + +namespace LexBoxApi.Models; + +public record ForgotPasswordInput( + [EmailAddress] string Email, + string TurnstileToken); diff --git a/frontend/src/lib/i18n/locales/en.json b/frontend/src/lib/i18n/locales/en.json index 5f2928d91..745aa59e2 100644 --- a/frontend/src/lib/i18n/locales/en.json +++ b/frontend/src/lib/i18n/locales/en.json @@ -244,7 +244,6 @@ the [Linguistics Institute at Payap University](https://li.payap.ac.th/) in Chia "label_name": "Name", "label_password": "Password", "name_missing": "Name missing", - "turnstile_error": "Captcha Error, try again" }, "reset_password": { "title": "Reset Password", @@ -326,5 +325,8 @@ the [Linguistics Institute at Payap University](https://li.payap.ac.th/) in Chia }, "notifications": { "update_detected": "A new version of the application was detected. You may need to reload the page.", + }, + "turnstile": { + "invalid": "Captcha Error, try again", } } diff --git a/frontend/src/routes/(unauthenticated)/forgotPassword/+page.svelte b/frontend/src/routes/(unauthenticated)/forgotPassword/+page.svelte index bcee7eb79..e9b42bf7b 100644 --- a/frontend/src/routes/(unauthenticated)/forgotPassword/+page.svelte +++ b/frontend/src/routes/(unauthenticated)/forgotPassword/+page.svelte @@ -1,19 +1,45 @@