fix: add some error handling to captcha handling

This commit is contained in:
MiniDigger | Martin 2024-11-10 20:34:52 +01:00
parent aa68d62f95
commit a7fa398873
6 changed files with 18 additions and 12 deletions

View File

@ -48,22 +48,18 @@ public class AuthController extends HangarComponent {
private final VerificationService verificationService;
private final CredentialsService credentialsService;
private final UserService userService;
private final TurnstileService turnstileService;
public AuthController(final AuthService authService, final TokenService tokenService, final VerificationService verificationService, final CredentialsService credentialsService, final UserService userService, final TurnstileService turnstileService) {
public AuthController(final AuthService authService, final TokenService tokenService, final VerificationService verificationService, final CredentialsService credentialsService, final UserService userService) {
this.authService = authService;
this.tokenService = tokenService;
this.verificationService = verificationService;
this.credentialsService = credentialsService;
this.userService = userService;
this.turnstileService = turnstileService;
}
@Anyone
@PostMapping("/signup")
public ResponseEntity<?> signup(@RequestBody final SignupForm signupForm) {
this.turnstileService.validate(signupForm.captcha());
final UserTable userTable = this.authService.registerUser(signupForm);
if (userTable == null) {
return ResponseEntity.badRequest().build();

View File

@ -49,8 +49,9 @@ public class AuthService extends HangarComponent implements UserDetailsService {
private final TokenService tokenService;
private final UsersApiService usersApiService;
private final BucketService bucketService;
private final TurnstileService turnstileService;
public AuthService(final UserDAO userDAO, final UserCredentialDAO userCredentialDAO, final PasswordEncoder passwordEncoder, final ValidationService validationService, final VerificationService verificationService, final CredentialsService credentialsService, final HibpService hibpService, final MailService mailService, final TokenService tokenService, final UsersApiService usersApiService, final BucketService bucketService) {
public AuthService(final UserDAO userDAO, final UserCredentialDAO userCredentialDAO, final PasswordEncoder passwordEncoder, final ValidationService validationService, final VerificationService verificationService, final CredentialsService credentialsService, final HibpService hibpService, final MailService mailService, final TokenService tokenService, final UsersApiService usersApiService, final BucketService bucketService, final TurnstileService turnstileService) {
this.userDAO = userDAO;
this.userCredentialDAO = userCredentialDAO;
this.passwordEncoder = passwordEncoder;
@ -62,6 +63,7 @@ public class AuthService extends HangarComponent implements UserDetailsService {
this.tokenService = tokenService;
this.usersApiService = usersApiService;
this.bucketService = bucketService;
this.turnstileService = turnstileService;
}
@Transactional
@ -71,6 +73,8 @@ public class AuthService extends HangarComponent implements UserDetailsService {
}
this.validateNewUser(form.username(), form.email(), form.tos());
this.turnstileService.validate(form.captcha());
if (!this.config.isDisableRateLimiting()) {
Bucket bucket = this.bucketService.bucket("register-user", new RateLimit.Model(1, 1, 60 * 5, false, "register-user"));
if (bucket != null && !bucket.tryConsume(1)) {

View File

@ -1,9 +1,10 @@
package io.papermc.hangar.components.auth.service;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.papermc.hangar.HangarComponent;
import io.papermc.hangar.exceptions.HangarApiException;
import io.papermc.hangar.util.RequestUtil;
import java.util.Arrays;
import java.util.List;
import org.springframework.http.HttpEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
@ -34,10 +35,10 @@ public class TurnstileService extends HangarComponent {
var response = this.restTemplate.postForEntity(url, entity, TurnstileResponse.class);
if (response.getBody() != null && !response.getBody().success()) {
throw new HangarApiException("error.captcha", Arrays.toString(response.getBody().errorCodes()));
throw new HangarApiException("error.captcha", response.getBody().errorCodes());
}
}
}
record TurnstileResponse(boolean success, String[] errorCodes){}
record TurnstileResponse(boolean success, @JsonProperty("error-codes") List<String> errorCodes){}
}

View File

@ -1214,6 +1214,7 @@
"unknown": "An error occurred",
"aal1": "You need to verify your email first",
"aal2": "You need to setup 2fa first",
"privileged": "You need to be in a privileged session to do this"
"privileged": "You need to be in a privileged session to do this",
"captcha": "Error while verifying the security challenge: {0}. Please try again."
}
}

View File

@ -19,6 +19,7 @@ const notification = useNotificationStore();
const i18n = useI18n();
const form = reactive<SignupForm>({});
const loading = ref(false);
const turnstile = useTemplateRef("turnstile");
const errorMessage = ref<string | undefined>();
@ -31,6 +32,9 @@ async function submit() {
done.value = true;
} catch (e) {
notification.fromError(i18n, e);
if (e?.response?.data?.message === "error.captcha") {
turnstile.value?.reset();
}
}
loading.value = false;
}
@ -93,7 +97,7 @@ useSeo(computed(() => ({ title: "Sign up", route })));
<InputText v-model="form.username" label="Username" name="username" autocomplete="username" :rules="[required()]" />
<InputText v-model="form.email" type="email" label="E-Mail" name="email" autocomplete="email" :rules="[required(), email()]" />
<InputPassword v-model="form.password" label="Password" name="new-password" :rules="[required()]" />
<LazyNuxtTurnstile v-if="config.public.turnstile?.siteKey != '1x00000000000000000000AA'" v-model="form.captcha" />
<LazyNuxtTurnstile v-if="config.public.turnstile?.siteKey != '1x00000000000000000000AA'" ref="turnstile" v-model="form.captcha" />
<div v-if="errorMessage" class="c-red">{{ errorMessage }}</div>
<Button type="submit" :disabled="loading" @click.prevent="submit">Sign up</Button>
<div class="w-max">

View File

@ -37,7 +37,7 @@ export const useNotificationStore = defineStore("notification", () => {
message = i18n.t(error.response.data.detail);
}
if (error.response?.data?.message) {
message = i18n.t(error.response.data.message);
message = i18n.t(error.response.data.message, ...error.response.data.messageArgs);
}
await show({ message, color: "red", clearable, timeout, addedAt: Date.now() });
}