Finished
This commit is contained in:
154
frontend/utils/UserDao.java
Normal file
154
frontend/utils/UserDao.java
Normal file
@@ -0,0 +1,154 @@
|
||||
package ins.frontend.utils;
|
||||
|
||||
import org.openautonomousconnection.webserver.utils.Sha256;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* DAO for users table:
|
||||
* users(id, uid(uuid string), username(sha256 hex or plain), password(pbkdf2...))
|
||||
*/
|
||||
public final class UserDao {
|
||||
|
||||
private final DataSourceProvider dataSource;
|
||||
|
||||
/**
|
||||
* Creates a UserDao.
|
||||
*
|
||||
* @param dataSource connection provider
|
||||
*/
|
||||
public UserDao(DataSourceProvider dataSource) {
|
||||
this.dataSource = Objects.requireNonNull(dataSource, "dataSource");
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a user by username.
|
||||
*
|
||||
* @param uid exact uid match
|
||||
* @return optional row
|
||||
* @throws SQLException on SQL errors
|
||||
*/
|
||||
public Optional<UserRow> findByUid(UUID uid) throws SQLException {
|
||||
if (uid == null) return Optional.empty();
|
||||
|
||||
String sql = "SELECT id, uid, username, password FROM users WHERE uid = ? LIMIT 1";
|
||||
|
||||
try (Connection c = dataSource.getConnection();
|
||||
PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
|
||||
ps.setString(1, uid.toString());
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (!rs.next()) return Optional.empty();
|
||||
return Optional.of(new UserRow(
|
||||
rs.getInt("id"),
|
||||
rs.getString("uid"),
|
||||
rs.getString("username"),
|
||||
rs.getString("password")
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new user.
|
||||
*
|
||||
* @param uid uuid string (36 chars)
|
||||
* @param username username string (your choice: raw or sha256 hex)
|
||||
* @param passwordEncoded encoded password
|
||||
* @return generated users.id
|
||||
* @throws SQLException on SQL errors
|
||||
*/
|
||||
public int createUser(String uid, String username, String passwordEncoded) throws SQLException {
|
||||
if (uid == null || uid.isBlank()) throw new IllegalArgumentException("uid must not be blank");
|
||||
if (username == null || username.isBlank()) throw new IllegalArgumentException("username must not be blank");
|
||||
if (passwordEncoded == null || passwordEncoded.isBlank())
|
||||
throw new IllegalArgumentException("passwordEncoded must not be blank");
|
||||
|
||||
String sql = "INSERT INTO users (uid, username, password) VALUES (?, ?, ?)";
|
||||
|
||||
try (Connection c = dataSource.getConnection();
|
||||
PreparedStatement ps = c.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS)) {
|
||||
|
||||
ps.setString(1, uid);
|
||||
ps.setString(2, Sha256.hex(username));
|
||||
ps.setString(3, passwordEncoded);
|
||||
ps.executeUpdate();
|
||||
|
||||
try (ResultSet rs = ps.getGeneratedKeys()) {
|
||||
if (rs.next()) return rs.getInt(1);
|
||||
}
|
||||
}
|
||||
|
||||
throw new SQLException("No generated key returned for users.id");
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience: creates a user with a new random UUID.
|
||||
*
|
||||
* @param username username
|
||||
* @param passwordEncoded encoded password
|
||||
* @return generated users.id
|
||||
* @throws SQLException on SQL errors
|
||||
*/
|
||||
public int createUserWithNewUuid(String username, String passwordEncoded) throws SQLException {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
while (findByUid(uuid).isPresent()) uuid = UUID.randomUUID();
|
||||
return createUser(uuid.toString(), username, passwordEncoded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a user by username.
|
||||
*
|
||||
* @param username exact username match
|
||||
* @return optional row
|
||||
* @throws SQLException on SQL errors
|
||||
*/
|
||||
public Optional<UserRow> findByUsername(String username) throws SQLException {
|
||||
if (username == null || username.isBlank()) return Optional.empty();
|
||||
username = Sha256.hex(username);
|
||||
|
||||
String sql = "SELECT id, uid, username, password FROM users WHERE username = ? LIMIT 1";
|
||||
|
||||
try (Connection c = dataSource.getConnection();
|
||||
PreparedStatement ps = c.prepareStatement(sql)) {
|
||||
|
||||
ps.setString(1, username);
|
||||
|
||||
try (ResultSet rs = ps.executeQuery()) {
|
||||
if (!rs.next()) return Optional.empty();
|
||||
return Optional.of(new UserRow(
|
||||
rs.getInt("id"),
|
||||
rs.getString("uid"),
|
||||
rs.getString("username"),
|
||||
rs.getString("password")
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connection provider abstraction.
|
||||
*/
|
||||
public interface DataSourceProvider {
|
||||
/**
|
||||
* @return open SQL connection
|
||||
* @throws SQLException on errors
|
||||
*/
|
||||
Connection getConnection() throws SQLException;
|
||||
}
|
||||
|
||||
/**
|
||||
* User row.
|
||||
*
|
||||
* @param id users.id
|
||||
* @param uid users.uid (uuid)
|
||||
* @param username users.username
|
||||
* @param passwordEncoded users.password
|
||||
*/
|
||||
public record UserRow(int id, String uid, String username, String passwordEncoded) {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user