use backup codes when checking tfa pins
All checks were successful
Deploy API / deploy (ubuntu-latest, 2.44.0) (push) Successful in 54s

This commit is contained in:
Braydon 2024-09-19 23:50:30 -04:00
parent ce87e6e242
commit 48f8253612
2 changed files with 37 additions and 7 deletions

@ -128,10 +128,7 @@ public final class AuthService {
if (pin == null || (pin.isBlank())) { // No TFA pin received if (pin == null || (pin.isBlank())) { // No TFA pin received
throw new BadRequestException(Error.BORDER_CROSSING); throw new BadRequestException(Error.BORDER_CROSSING);
} }
// Incorrect TFA pin useTfaPin(user, pin); // Attempt to use the pin
if (pin.length() != 6 || (!tfaService.getPin(user.getTfa().getSecret()).equals(pin))) {
throw new BadRequestException(Error.TFA_PIN_INVALID);
}
} }
user.setLastLogin(new Date()); user.setLastLogin(new Date());
user = userRepository.save(user); user = userRepository.save(user);
@ -139,6 +136,39 @@ public final class AuthService {
UserDTO.asDTO(user, new Date(snowflakeService.extractCreationTime(user.getSnowflake())))); UserDTO.asDTO(user, new Date(snowflakeService.extractCreationTime(user.getSnowflake()))));
} }
/**
* Use a TFA pin for a user.
*
* @param user the user to use TFA for
* @param pin the pin to use
* @throws BadRequestException if using TFA fails
*/
public void useTfaPin(@NonNull User user, @NonNull String pin) throws BadRequestException {
if (pin.length() != 6) { // Ensure the pin is the correct length
throw new BadRequestException(Error.TFA_PIN_INVALID);
}
if (!user.hasFlag(UserFlag.TFA_ENABLED)) { // Ensure TFA is already on
throw new BadRequestException(Error.TFA_NOT_ENABLED);
}
String encryptedPin = HashUtils.hash(Base64.getDecoder().decode(user.getTfa().getBackupCodesSalt()), pin);
// Before checking the pin, check the user's backup codes
for (String backupCode : user.getTfa().getBackupCodes()) {
if (!encryptedPin.equals(backupCode)) {
continue;
}
// The code is a valid backup code, remove it from the user's list
user.getTfa().getBackupCodes().remove(backupCode);
userRepository.save(user);
return;
}
// Check if the TFA pin is valid
if (!tfaService.getPin(user.getTfa().getSecret()).equals(pin)) {
throw new BadRequestException(Error.TFA_PIN_INVALID);
}
}
/** /**
* Get the authenticated user. * Get the authenticated user.
* *
@ -262,6 +292,7 @@ public final class AuthService {
USER_NOT_FOUND, USER_NOT_FOUND,
PASSWORDS_DO_NOT_MATCH, PASSWORDS_DO_NOT_MATCH,
BORDER_CROSSING, BORDER_CROSSING,
TFA_NOT_ENABLED,
TFA_PIN_INVALID, TFA_PIN_INVALID,
EMAIL_ALREADY_USED, EMAIL_ALREADY_USED,
USER_DISABLED USER_DISABLED

@ -238,9 +238,8 @@ public final class UserService {
if (!user.hasFlag(UserFlag.TFA_ENABLED)) { // Ensure TFA is already on if (!user.hasFlag(UserFlag.TFA_ENABLED)) { // Ensure TFA is already on
throw new BadRequestException(Error.TFA_NOT_ENABLED); throw new BadRequestException(Error.TFA_NOT_ENABLED);
} }
if (!tfaService.getPin(user.getTfa().getSecret()).equals(input.getPin())) { // Ensure the pin is valid authService.useTfaPin(user, input.getPin()); // Ensure the pin is valid
throw new BadRequestException(Error.TFA_PIN_INVALID);
}
// Disable TFA for the user // Disable TFA for the user
user.setTfa(null); user.setTfa(null);
user.removeFlag(UserFlag.TFA_ENABLED); user.removeFlag(UserFlag.TFA_ENABLED);