Skip to content

Commit

Permalink
Add turnstile to forgot-password page
Browse files Browse the repository at this point in the history
  • Loading branch information
myieye committed Oct 16, 2023
1 parent cdec1d5 commit 12b436d
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 11 deletions.
24 changes: 21 additions & 3 deletions backend/LexBoxApi/Controllers/LoginController.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using System.ComponentModel.DataAnnotations;
using LexBoxApi.Auth;
using LexBoxApi.Models;
using LexBoxApi.Otel;
using LexBoxApi.Services;
using LexCore;
using LexCore.Auth;
using LexData;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.EntityFrameworkCore;

namespace LexBoxApi.Controllers;
Expand All @@ -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")]
Expand Down Expand Up @@ -101,9 +107,21 @@ public async Task<ActionResult> Logout()

[HttpPost("forgotPassword")]
[AllowAnonymous]
public async Task<ActionResult> ForgotPassword(string email)
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesErrorResponseType(typeof(Dictionary<string, string[]>))]
[ProducesDefaultResponseType]
public async Task<ActionResult> 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<ForgotPasswordInput>(r => r.TurnstileToken, "token invalid");
return ValidationProblem(ModelState);
}

await _lexAuthService.ForgotPassword(input.Email);
return Ok();
}

Expand Down
7 changes: 7 additions & 0 deletions backend/LexBoxApi/Models/ForgotPasswordInput.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using System.ComponentModel.DataAnnotations;

namespace LexBoxApi.Models;

public record ForgotPasswordInput(
[EmailAddress] string Email,
string TurnstileToken);
4 changes: 3 additions & 1 deletion frontend/src/lib/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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",
}
}
40 changes: 34 additions & 6 deletions frontend/src/routes/(unauthenticated)/forgotPassword/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,19 +1,45 @@
<script lang="ts">
import { goto } from '$app/navigation';
import { Form, Input, lexSuperForm } from '$lib/forms';
import { ProtectedForm, Input, lexSuperForm, FormError } from '$lib/forms';
import { SubmitButton } from '$lib/forms';
import t from '$lib/i18n';
import Page from '$lib/layout/Page.svelte';
import { toSearchParams } from '$lib/util/query-params';
import { z } from 'zod';
type ForgotPasswordResponseErrors = {
errors: {
/* eslint-disable @typescript-eslint/naming-convention */
TurnstileToken?: unknown,
/* eslint-enable @typescript-eslint/naming-convention */
}
}
const formSchema = z.object({
email: z.string().email($t('register.email')),
});
let { form, errors, enhance, submitting } = lexSuperForm(formSchema, async () => {
await fetch(`api/login/forgotPassword?${toSearchParams($form)}`, {
let turnstileToken = '';
let { form, errors, enhance, submitting, message } = lexSuperForm(formSchema, async () => {
const response = await fetch(`api/login/forgotPassword`, {
method: 'POST',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
...$form,
turnstileToken,
}),
});
if (!response.ok) {
const { errors } = await response.json() as ForgotPasswordResponseErrors;
const turnstileError = !!errors.TurnstileToken;
if (!turnstileError) throw new Error('Unknown error', { cause: errors });
$message = $t('turnstile.invalid');
return;
}
await goto('/forgotPassword/emailSent');
}, {
taintedMessage: null,
Expand All @@ -24,7 +50,8 @@
<svelte:fragment slot="header">
{$t('forgot_password.title')}
</svelte:fragment>
<Form {enhance}>

<ProtectedForm {enhance} bind:turnstileToken>
<Input
id="email"
label={$t('register.label_email')}
Expand All @@ -33,6 +60,7 @@
bind:value={$form.email}
error={$errors.email}
/>
<FormError error={$message} />
<SubmitButton loading={$submitting}>{$t('forgot_password.send_email')}</SubmitButton>
</Form>
</ProtectedForm>
</Page>
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
const { user, error } = await register($form.password, $form.name, $form.email, turnstileToken);
if (error) {
if (error.turnstile) {
$message = $t('register.turnstile_error');
$message = $t('turnstile.invalid');
}
if (error.accountExists) {
$errors.email = [$t('register.account_exists')];
Expand Down

0 comments on commit 12b436d

Please sign in to comment.