This commit is contained in:
UnlegitDqrk
2026-02-11 23:22:20 +01:00
parent 9483c36a66
commit 64ce55ea7b
39 changed files with 2033 additions and 3089 deletions

View File

@@ -0,0 +1,122 @@
package ins.frontend.utils;
import org.openautonomousconnection.webserver.utils.PasswordHasher;
import java.util.Objects;
/**
* Registration service for creating users with secure password hashing and basic validation.
*/
public final class RegistrationService {
private static final int USERNAME_MIN = 5;
private static final int USERNAME_MAX = 256;
private static final int PASSWORD_MIN = 6;
private static final int PASSWORD_MAX = 256;
private final UserDao userDao;
private final PasswordHasher hasher;
/**
* Creates a registration service.
*
* @param userDao user DAO
* @param hasher password hasher
*/
public RegistrationService(UserDao userDao, PasswordHasher hasher) {
this.userDao = Objects.requireNonNull(userDao, "userDao");
this.hasher = Objects.requireNonNull(hasher, "hasher");
}
private static String normalizeUsername(String u) {
if (u == null) return null;
String t = u.trim();
return t.isEmpty() ? null : t;
}
private static String validate(String username, String password) {
if (username == null) return "Missing username.";
if (password == null) return "Missing password.";
if (username.length() < USERNAME_MIN) return "Username too short (min " + USERNAME_MIN + ").";
if (username.length() > USERNAME_MAX) return "Username too long (max " + USERNAME_MAX + ").";
// Allow only a safe subset to avoid weird edge cases in UI and future.
for (int i = 0; i < username.length(); i++) {
char c = username.charAt(i);
boolean ok = (c >= 'a' && c <= 'z')
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')
|| c == '_' || c == '-' || c == '.';
if (!ok) return "Username contains invalid characters.";
}
if (password.length() < PASSWORD_MIN) return "Password too short (min " + PASSWORD_MIN + ").";
if (password.length() > PASSWORD_MAX) return "Password too long.";
return null;
}
/**
* Registers a new user.
*
* @param usernameRaw raw username (from form)
* @param passwordRaw raw password (from form)
* @return result containing either userId or an error message
*/
public Result register(String usernameRaw, String passwordRaw) {
String username = normalizeUsername(usernameRaw);
String password = (passwordRaw == null) ? "" : passwordRaw;
String validationError = validate(username, password);
if (validationError != null) {
return Result.error(validationError);
}
try {
// Choose: store username as-is OR store sha256(username).
// Your schema says: username(sha256 hex or plain) -> keep it plain for now.
String usernameStored = username;
if (userDao.findByUsername(usernameStored).isPresent()) {
return Result.error("Username already exists.");
}
String passwordEncoded = hasher.hash(password);
int userId = userDao.createUserWithNewUuid(usernameStored, passwordEncoded);
return Result.ok(userId);
} catch (Exception e) {
return Result.error("Registration failed: " + e.getMessage());
}
}
/**
* Registration result.
*
* @param ok whether succeeded
* @param userId created user id, or -1
* @param error error message, or null
*/
public record Result(boolean ok, int userId, String error) {
/**
* Creates a success result.
*
* @param userId user id
* @return result
*/
public static Result ok(int userId) {
return new Result(true, userId, null);
}
/**
* Creates an error result.
*
* @param error error message
* @return result
*/
public static Result error(String error) {
return new Result(false, -1, error);
}
}
}