logins work
This commit is contained in:
parent
aa3d381dd3
commit
d326767c7c
@ -3,12 +3,13 @@ package cc.pulseapp.api.common;
|
|||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import lombok.experimental.UtilityClass;
|
import lombok.experimental.UtilityClass;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Braydon
|
* @author Braydon
|
||||||
*/
|
*/
|
||||||
@UtilityClass
|
@UtilityClass
|
||||||
public final class IPUtils {
|
public final class RequestUtils {
|
||||||
private static final String[] IP_HEADERS = new String[] {
|
private static final String[] IP_HEADERS = new String[] {
|
||||||
"CF-Connecting-IP",
|
"CF-Connecting-IP",
|
||||||
"X-Forwarded-For"
|
"X-Forwarded-For"
|
||||||
@ -41,4 +42,15 @@ public final class IPUtils {
|
|||||||
}
|
}
|
||||||
return ip;
|
return ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user agent from the given request.
|
||||||
|
*
|
||||||
|
* @param request the request to get from
|
||||||
|
* @return the user agent
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static String getUserAgent(@NonNull HttpServletRequest request) {
|
||||||
|
return request.getHeader(HttpHeaders.USER_AGENT);
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,9 +1,11 @@
|
|||||||
package cc.pulseapp.api.controller.v1;
|
package cc.pulseapp.api.controller.v1;
|
||||||
|
|
||||||
import cc.pulseapp.api.exception.impl.BadRequestException;
|
import cc.pulseapp.api.exception.impl.BadRequestException;
|
||||||
import cc.pulseapp.api.model.user.AuthToken;
|
import cc.pulseapp.api.model.user.Session;
|
||||||
|
import cc.pulseapp.api.model.user.input.UserLoginInput;
|
||||||
import cc.pulseapp.api.model.user.input.UserRegistrationInput;
|
import cc.pulseapp.api.model.user.input.UserRegistrationInput;
|
||||||
import cc.pulseapp.api.service.AuthService;
|
import cc.pulseapp.api.service.AuthService;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
@ -32,8 +34,29 @@ public final class AuthController {
|
|||||||
this.authService = authService;
|
this.authService = authService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A POST endpoint to register a new user.
|
||||||
|
*
|
||||||
|
* @param request the http request
|
||||||
|
* @param input the registration input
|
||||||
|
* @return the session for the registered user
|
||||||
|
* @throws BadRequestException if the registration fails
|
||||||
|
*/
|
||||||
@PostMapping("/register") @ResponseBody @NonNull
|
@PostMapping("/register") @ResponseBody @NonNull
|
||||||
public ResponseEntity<AuthToken> register(UserRegistrationInput input) throws BadRequestException {
|
public ResponseEntity<Session> register(@NonNull HttpServletRequest request, UserRegistrationInput input) throws BadRequestException {
|
||||||
return ResponseEntity.ok(authService.registerUser(input));
|
return ResponseEntity.ok(authService.registerUser(request, input));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A POST endpoint to login a user.
|
||||||
|
*
|
||||||
|
* @param request the http request
|
||||||
|
* @param input the login input
|
||||||
|
* @return the session for the login user
|
||||||
|
* @throws BadRequestException if the login fails
|
||||||
|
*/
|
||||||
|
@PostMapping("/login") @ResponseBody @NonNull
|
||||||
|
public ResponseEntity<Session> login(@NonNull HttpServletRequest request, UserLoginInput input) throws BadRequestException {
|
||||||
|
return ResponseEntity.ok(authService.loginUser(request, input));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
package cc.pulseapp.api.log;
|
package cc.pulseapp.api.log;
|
||||||
|
|
||||||
import cc.pulseapp.api.common.IPUtils;
|
import cc.pulseapp.api.common.RequestUtils;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
@ -37,7 +37,7 @@ public class RequestLogger implements ResponseBodyAdvice<Object> {
|
|||||||
HttpServletResponse response = ((ServletServerHttpResponse) rawResponse).getServletResponse();
|
HttpServletResponse response = ((ServletServerHttpResponse) rawResponse).getServletResponse();
|
||||||
|
|
||||||
// Get the request ip ip
|
// Get the request ip ip
|
||||||
String ip = IPUtils.getRealIp(request);
|
String ip = RequestUtils.getRealIp(request);
|
||||||
|
|
||||||
log.info("%s | %s %s %s %s".formatted(
|
log.info("%s | %s %s %s %s".formatted(
|
||||||
ip, request.getMethod(), request.getRequestURI(), request.getProtocol(), response.getStatus()
|
ip, request.getMethod(), request.getRequestURI(), request.getProtocol(), response.getStatus()
|
||||||
|
@ -18,7 +18,7 @@ public final class Organization {
|
|||||||
/**
|
/**
|
||||||
* The snowflake id of this organization.
|
* The snowflake id of this organization.
|
||||||
*/
|
*/
|
||||||
@Id @EqualsAndHashCode.Include private final long id;
|
@Id @EqualsAndHashCode.Include private final long snowflake;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of this organization.
|
* The name of this organization.
|
||||||
|
@ -16,7 +16,7 @@ public final class StatusPage {
|
|||||||
/**
|
/**
|
||||||
* The snowflake id of this status page.
|
* The snowflake id of this status page.
|
||||||
*/
|
*/
|
||||||
@Id @EqualsAndHashCode.Include private final long id;
|
@Id @EqualsAndHashCode.Include private final long snowflake;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of this status page.
|
* The name of this status page.
|
||||||
|
@ -8,23 +8,21 @@ import org.springframework.data.annotation.Id;
|
|||||||
import org.springframework.data.redis.core.RedisHash;
|
import org.springframework.data.redis.core.RedisHash;
|
||||||
import org.springframework.data.redis.core.index.Indexed;
|
import org.springframework.data.redis.core.index.Indexed;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An authentication token for a {@link User}.
|
* A session for a {@link User}.
|
||||||
*
|
*
|
||||||
* @author Braydon
|
* @author Braydon
|
||||||
*/
|
*/
|
||||||
@AllArgsConstructor @Getter
|
@AllArgsConstructor @Getter
|
||||||
@RedisHash(value = "auth_token", timeToLive = 30 * 24 * 60 * 60) // Expire in 30 days (days, hours, mins, secs)
|
@RedisHash(value = "sessions", timeToLive = 30 * 24 * 60 * 60) // Expire in 30 days (days, hours, mins, secs)
|
||||||
public final class AuthToken {
|
public final class Session {
|
||||||
/**
|
/**
|
||||||
* The ID of this token.
|
* The snowflake of this session.
|
||||||
*/
|
*/
|
||||||
@Id @JsonIgnore @NonNull private final UUID id;
|
@Id @JsonIgnore private final long snowflake;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The snowflake of the user this token is for.
|
* The snowflake of the user this session is for.
|
||||||
*/
|
*/
|
||||||
@JsonIgnore private final long userSnowflake;
|
@JsonIgnore private final long userSnowflake;
|
||||||
|
|
||||||
@ -38,6 +36,16 @@ public final class AuthToken {
|
|||||||
*/
|
*/
|
||||||
@Indexed @NonNull private final String refreshToken;
|
@Indexed @NonNull private final String refreshToken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The IP address of the user that created this session.
|
||||||
|
*/
|
||||||
|
@NonNull @JsonIgnore private final String ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The user agent of the user that created this session.
|
||||||
|
*/
|
||||||
|
@NonNull @JsonIgnore private final String userAgent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The unix timestamp of when this token expires.
|
* The unix timestamp of when this token expires.
|
||||||
*/
|
*/
|
@ -10,14 +10,14 @@ import java.util.Date;
|
|||||||
/**
|
/**
|
||||||
* @author Braydon
|
* @author Braydon
|
||||||
*/
|
*/
|
||||||
@AllArgsConstructor @Getter
|
@AllArgsConstructor @Setter @Getter
|
||||||
@EqualsAndHashCode(onlyExplicitlyIncluded = true) @ToString
|
@EqualsAndHashCode(onlyExplicitlyIncluded = true) @ToString
|
||||||
@Document("users")
|
@Document("users")
|
||||||
public final class User {
|
public final class User {
|
||||||
/**
|
/**
|
||||||
* The snowflake id of this user.
|
* The snowflake id of this user.
|
||||||
*/
|
*/
|
||||||
@Id @EqualsAndHashCode.Include private final long id;
|
@Id @EqualsAndHashCode.Include private final long snowflake;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This user's email.
|
* This user's email.
|
||||||
@ -52,7 +52,7 @@ public final class User {
|
|||||||
/**
|
/**
|
||||||
* The date this user last logged in.
|
* The date this user last logged in.
|
||||||
*/
|
*/
|
||||||
@NonNull private final Date lastLogin;
|
@NonNull private Date lastLogin;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if this user has a given flag.
|
* Check if this user has a given flag.
|
||||||
|
@ -16,7 +16,7 @@ public final class UserDTO {
|
|||||||
/**
|
/**
|
||||||
* The snowflake id of this user.
|
* The snowflake id of this user.
|
||||||
*/
|
*/
|
||||||
@EqualsAndHashCode.Include private final long id;
|
@EqualsAndHashCode.Include private final long snowflake;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This user's email.
|
* This user's email.
|
||||||
@ -57,7 +57,7 @@ public final class UserDTO {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public static UserDTO asDTO(@NonNull User user, @NonNull Date creationTime) {
|
public static UserDTO asDTO(@NonNull User user, @NonNull Date creationTime) {
|
||||||
return new UserDTO(user.getId(), user.getEmail(), user.getUsername(), user.getTier(),
|
return new UserDTO(user.getSnowflake(), user.getEmail(), user.getUsername(), user.getTier(),
|
||||||
user.getLastLogin(), user.getFlags(), creationTime
|
user.getLastLogin(), user.getFlags(), creationTime
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package cc.pulseapp.api.model.user.input;
|
||||||
|
|
||||||
|
import cc.pulseapp.api.model.user.User;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input to login a {@link User}.
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
*/
|
||||||
|
@AllArgsConstructor @Getter @ToString
|
||||||
|
public final class UserLoginInput {
|
||||||
|
/**
|
||||||
|
* The email of the user to login with.
|
||||||
|
*/
|
||||||
|
private final String email;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The username of the user to login with.
|
||||||
|
*/
|
||||||
|
private final String username;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The password of the user to login with.
|
||||||
|
*/
|
||||||
|
private final String password;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The captcha response token to validate.
|
||||||
|
*/
|
||||||
|
private final String captchaResponse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if this input is valid.
|
||||||
|
*
|
||||||
|
* @return whether this input is valid
|
||||||
|
*/
|
||||||
|
public boolean isValid() {
|
||||||
|
return (email != null && (!email.isBlank()) || username != null && (!username.isBlank()))
|
||||||
|
&& password != null && (!password.isBlank())
|
||||||
|
&& captchaResponse != null && (!captchaResponse.isBlank());
|
||||||
|
}
|
||||||
|
}
|
@ -1,20 +0,0 @@
|
|||||||
package cc.pulseapp.api.repository;
|
|
||||||
|
|
||||||
import cc.pulseapp.api.model.user.AuthToken;
|
|
||||||
import lombok.NonNull;
|
|
||||||
import org.springframework.data.repository.CrudRepository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The repository for {@link AuthToken}'s.
|
|
||||||
*
|
|
||||||
* @author Braydon
|
|
||||||
*/
|
|
||||||
public interface AuthTokenRepository extends CrudRepository<AuthToken, String> {
|
|
||||||
/**
|
|
||||||
* Find an auth token by the access token.
|
|
||||||
*
|
|
||||||
* @param accessToken the access token to search by
|
|
||||||
* @return the auth token, null if none
|
|
||||||
*/
|
|
||||||
AuthToken findByAccessToken(@NonNull String accessToken);
|
|
||||||
}
|
|
@ -0,0 +1,20 @@
|
|||||||
|
package cc.pulseapp.api.repository;
|
||||||
|
|
||||||
|
import cc.pulseapp.api.model.user.Session;
|
||||||
|
import lombok.NonNull;
|
||||||
|
import org.springframework.data.repository.CrudRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The repository for {@link Session}'s.
|
||||||
|
*
|
||||||
|
* @author Braydon
|
||||||
|
*/
|
||||||
|
public interface SessionRepository extends CrudRepository<Session, String> {
|
||||||
|
/**
|
||||||
|
* Find a session by the access token.
|
||||||
|
*
|
||||||
|
* @param accessToken the access token to search by
|
||||||
|
* @return the session, null if none
|
||||||
|
*/
|
||||||
|
Session findByAccessToken(@NonNull String accessToken);
|
||||||
|
}
|
@ -17,4 +17,12 @@ public interface UserRepository extends MongoRepository<User, Long> {
|
|||||||
* @return the user with the email
|
* @return the user with the email
|
||||||
*/
|
*/
|
||||||
User findByEmailIgnoreCase(@NonNull String email);
|
User findByEmailIgnoreCase(@NonNull String email);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find a user by their username.
|
||||||
|
*
|
||||||
|
* @param username the username of the user
|
||||||
|
* @return the user with the username
|
||||||
|
*/
|
||||||
|
User findByUsernameIgnoreCase(@NonNull String username);
|
||||||
}
|
}
|
@ -2,23 +2,26 @@ package cc.pulseapp.api.service;
|
|||||||
|
|
||||||
import cc.pulseapp.api.common.EnvironmentUtils;
|
import cc.pulseapp.api.common.EnvironmentUtils;
|
||||||
import cc.pulseapp.api.common.HashUtils;
|
import cc.pulseapp.api.common.HashUtils;
|
||||||
|
import cc.pulseapp.api.common.RequestUtils;
|
||||||
import cc.pulseapp.api.common.StringUtils;
|
import cc.pulseapp.api.common.StringUtils;
|
||||||
import cc.pulseapp.api.exception.impl.BadRequestException;
|
import cc.pulseapp.api.exception.impl.BadRequestException;
|
||||||
import cc.pulseapp.api.model.IGenericResponse;
|
import cc.pulseapp.api.model.IGenericResponse;
|
||||||
import cc.pulseapp.api.model.user.AuthToken;
|
import cc.pulseapp.api.model.user.Session;
|
||||||
import cc.pulseapp.api.model.user.User;
|
import cc.pulseapp.api.model.user.User;
|
||||||
import cc.pulseapp.api.model.user.UserFlag;
|
import cc.pulseapp.api.model.user.UserFlag;
|
||||||
import cc.pulseapp.api.model.user.UserTier;
|
import cc.pulseapp.api.model.user.UserTier;
|
||||||
|
import cc.pulseapp.api.model.user.input.UserLoginInput;
|
||||||
import cc.pulseapp.api.model.user.input.UserRegistrationInput;
|
import cc.pulseapp.api.model.user.input.UserRegistrationInput;
|
||||||
import cc.pulseapp.api.repository.AuthTokenRepository;
|
import cc.pulseapp.api.repository.SessionRepository;
|
||||||
import cc.pulseapp.api.repository.UserRepository;
|
import cc.pulseapp.api.repository.UserRepository;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import lombok.NonNull;
|
import lombok.NonNull;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.util.Base64;
|
import java.util.Base64;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.UUID;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,26 +47,27 @@ public final class AuthService {
|
|||||||
/**
|
/**
|
||||||
* The auth token repository for generating and validating auth tokens.
|
* The auth token repository for generating and validating auth tokens.
|
||||||
*/
|
*/
|
||||||
@NonNull private final AuthTokenRepository authTokenRepository;
|
@NonNull private final SessionRepository sessionRepository;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public AuthService(@NonNull CaptchaService captchaService, @NonNull SnowflakeService snowflakeService,
|
public AuthService(@NonNull CaptchaService captchaService, @NonNull SnowflakeService snowflakeService,
|
||||||
@NonNull UserRepository userRepository, @NonNull AuthTokenRepository authTokenRepository) {
|
@NonNull UserRepository userRepository, @NonNull SessionRepository sessionRepository) {
|
||||||
this.captchaService = captchaService;
|
this.captchaService = captchaService;
|
||||||
this.snowflakeService = snowflakeService;
|
this.snowflakeService = snowflakeService;
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
this.authTokenRepository = authTokenRepository;
|
this.sessionRepository = sessionRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a new user.
|
* Register a new user.
|
||||||
*
|
*
|
||||||
|
* @param request the http request
|
||||||
* @param input the registration input
|
* @param input the registration input
|
||||||
* @return the registered user's auth token
|
* @return the registered user's auth token
|
||||||
* @throws BadRequestException if the input has an error
|
* @throws BadRequestException if the input has an error
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public AuthToken registerUser(UserRegistrationInput input) throws BadRequestException {
|
public Session registerUser(@NonNull HttpServletRequest request, UserRegistrationInput input) throws BadRequestException {
|
||||||
validateRegistrationInput(input); // Ensure the input is valid
|
validateRegistrationInput(input); // Ensure the input is valid
|
||||||
|
|
||||||
// Ensure the given email hasn't been used before
|
// Ensure the given email hasn't been used before
|
||||||
@ -74,30 +78,58 @@ public final class AuthService {
|
|||||||
// Create the user and return it
|
// Create the user and return it
|
||||||
byte[] salt = HashUtils.generateSalt();
|
byte[] salt = HashUtils.generateSalt();
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
return generateAuthToken(userRepository.save(new User(
|
return generateSession(request, userRepository.save(new User(
|
||||||
snowflakeService.generateSnowflake(), input.getEmail(), input.getUsername(),
|
snowflakeService.generateSnowflake(), input.getEmail(), input.getUsername(),
|
||||||
HashUtils.hash(salt, input.getPassword()), Base64.getEncoder().encodeToString(salt),
|
HashUtils.hash(salt, input.getPassword()), Base64.getEncoder().encodeToString(salt),
|
||||||
UserTier.FREE, 0, now
|
UserTier.FREE, 0, now
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Login a user.
|
||||||
|
*
|
||||||
|
* @param request the http request
|
||||||
|
* @param input the login input
|
||||||
|
* @return the logged in user's auth token
|
||||||
|
* @throws BadRequestException if the input has an error
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public Session loginUser(@NonNull HttpServletRequest request, UserLoginInput input) throws BadRequestException {
|
||||||
|
validateLoginInput(input); // Ensure the input is valid
|
||||||
|
|
||||||
|
// Lookup the user by the email or username and ensure the user exists
|
||||||
|
User user = input.getEmail() == null ? userRepository.findByUsernameIgnoreCase(Objects.requireNonNull(input.getUsername()))
|
||||||
|
: userRepository.findByEmailIgnoreCase(input.getEmail());
|
||||||
|
if (user == null) {
|
||||||
|
throw new BadRequestException(Error.USER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
// Ensure the password matches
|
||||||
|
if (!HashUtils.hash(Base64.getDecoder().decode(user.getPasswordSalt()), input.getPassword()).equals(user.getPassword())) {
|
||||||
|
throw new BadRequestException(Error.PASSWORDS_DO_NOT_MATCH);
|
||||||
|
}
|
||||||
|
user.setLastLogin(new Date());
|
||||||
|
return generateSession(request, userRepository.save(user));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an auth token for a user.
|
* Generate an auth token for a user.
|
||||||
*
|
*
|
||||||
|
* @param request the http request
|
||||||
* @param user the user to generate for
|
* @param user the user to generate for
|
||||||
* @return the generated auth token
|
* @return the generated auth token
|
||||||
* @throws BadRequestException if the user is disabled
|
* @throws BadRequestException if the user is disabled
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private AuthToken generateAuthToken(@NonNull User user) throws BadRequestException {
|
private Session generateSession(@NonNull HttpServletRequest request, @NonNull User user) throws BadRequestException {
|
||||||
// User's account has been disabled
|
// User's account has been disabled
|
||||||
if (user.hasFlag(UserFlag.DISABLED)) {
|
if (user.hasFlag(UserFlag.DISABLED)) {
|
||||||
throw new BadRequestException(Error.USER_DISABLED);
|
throw new BadRequestException(Error.USER_DISABLED);
|
||||||
}
|
}
|
||||||
return authTokenRepository.save(new AuthToken(
|
return sessionRepository.save(new Session(
|
||||||
UUID.randomUUID(), user.getId(),
|
snowflakeService.generateSnowflake(), user.getSnowflake(),
|
||||||
StringUtils.generateRandom(128, true, true, false),
|
StringUtils.generateRandom(128, true, true, false),
|
||||||
StringUtils.generateRandom(128, true, true, false),
|
StringUtils.generateRandom(128, true, true, false),
|
||||||
|
RequestUtils.getRealIp(request), RequestUtils.getUserAgent(request),
|
||||||
System.currentTimeMillis() + TimeUnit.DAYS.toMillis(30L)
|
System.currentTimeMillis() + TimeUnit.DAYS.toMillis(30L)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -136,10 +168,36 @@ public final class AuthService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate the given login input.
|
||||||
|
*
|
||||||
|
* @param input the login input
|
||||||
|
* @throws BadRequestException if the input has an error
|
||||||
|
*/
|
||||||
|
private void validateLoginInput(UserLoginInput input) throws BadRequestException {
|
||||||
|
// Ensure the input was provided
|
||||||
|
if (input == null || (!input.isValid())) {
|
||||||
|
throw new BadRequestException(Error.MALFORMED_INPUT);
|
||||||
|
}
|
||||||
|
// Ensure the email is valid
|
||||||
|
if (input.getEmail() != null && (!StringUtils.isValidEmail(input.getEmail()))) {
|
||||||
|
throw new BadRequestException(Error.EMAIL_INVALID);
|
||||||
|
}
|
||||||
|
// Ensure the username is valid
|
||||||
|
if (input.getUsername() != null && (!StringUtils.isValidUsername(input.getUsername()))) {
|
||||||
|
throw new BadRequestException(Error.USERNAME_INVALID);
|
||||||
|
}
|
||||||
|
// Finally validate the captcha
|
||||||
|
if (EnvironmentUtils.isProduction()) {
|
||||||
|
captchaService.validateCaptcha(input.getCaptchaResponse());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private enum Error implements IGenericResponse {
|
private enum Error implements IGenericResponse {
|
||||||
MALFORMED_INPUT,
|
MALFORMED_INPUT,
|
||||||
EMAIL_INVALID,
|
EMAIL_INVALID,
|
||||||
USERNAME_INVALID,
|
USERNAME_INVALID,
|
||||||
|
USER_NOT_FOUND,
|
||||||
PASSWORDS_DO_NOT_MATCH,
|
PASSWORDS_DO_NOT_MATCH,
|
||||||
EMAIL_ALREADY_USED,
|
EMAIL_ALREADY_USED,
|
||||||
USER_DISABLED
|
USER_DISABLED
|
||||||
|
Loading…
Reference in New Issue
Block a user