diff --git a/src/main/java/client/Client.java b/src/main/java/client/Client.java index 361b7724f1..d557c0a5aa 100644 --- a/src/main/java/client/Client.java +++ b/src/main/java/client/Client.java @@ -54,14 +54,10 @@ import server.TimerManager; import server.life.Monster; import tools.BCrypt; import tools.DatabaseConnection; -import tools.HexTool; import tools.PacketCreator; import javax.script.ScriptEngine; import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -894,35 +890,6 @@ public class Client extends ChannelInboundHandlerAdapter { return QuestScriptManager.getInstance().getQM(this); } - public boolean acceptToS() { - if (accountName == null) { - return true; - } - - boolean disconnect = false; - try (Connection con = DatabaseConnection.getConnection()) { - try (PreparedStatement ps = con.prepareStatement("SELECT `tos` FROM accounts WHERE id = ?")) { - ps.setInt(1, accId); - - try (ResultSet rs = ps.executeQuery()) { - if (rs.next()) { - if (rs.getByte("tos") == 1) { - disconnect = true; - } - } - } - } - - try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET tos = 1 WHERE id = ?")) { - ps.setInt(1, accId); - ps.executeUpdate(); - } - } catch (SQLException e) { - e.printStackTrace(); - } - return disconnect; - } - public void lockClient() { lock.lock(); } @@ -945,16 +912,6 @@ public class Client extends ChannelInboundHandlerAdapter { actionsSemaphore.release(); } - private static boolean checkHash(String hash, String type, String password) { - try { - MessageDigest digester = MessageDigest.getInstance(type); - digester.update(password.getBytes(StandardCharsets.UTF_8), 0, password.length()); - return HexTool.toHexString(digester.digest()).replace(" ", "").toLowerCase().equals(hash); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Encoding the string failed", e); - } - } - public short getAvailableCharacterSlots() { return (short) Math.max(0, characterSlots - Server.getInstance().getAccountCharacterCount(accId)); } diff --git a/src/main/java/database/JdbiConfig.java b/src/main/java/database/JdbiConfig.java index 3f4c6875ab..e3a109ad5f 100644 --- a/src/main/java/database/JdbiConfig.java +++ b/src/main/java/database/JdbiConfig.java @@ -1,5 +1,6 @@ package database; +import database.account.AccountRowMapper; import database.drop.GlobalMonsterDropRowMapper; import database.drop.MonsterDropRowMapper; import database.maker.MakerIngredientRowMapper; @@ -26,6 +27,7 @@ public final class JdbiConfig { private static List> rowMappers() { return List.of( + new AccountRowMapper(), new NoteRowMapper(), new MakerReagentRowMapper(), new MakerRecipeRowMapper(), diff --git a/src/main/java/database/account/Account.java b/src/main/java/database/account/Account.java index 1984811012..3051d2d796 100644 --- a/src/main/java/database/account/Account.java +++ b/src/main/java/database/account/Account.java @@ -3,8 +3,12 @@ package database.account; import lombok.Builder; import java.time.LocalDate; +import java.time.LocalDateTime; +/** + * @author Ponk + */ @Builder -public record Account(String name, String password, boolean acceptedTos, LocalDate birthdate, String pin, String pic, - int loggedIn) { +public record Account(int id, String name, String password, boolean acceptedTos, byte gender, LocalDate birthdate, + String pin, String pic, int chrSlots, int loggedIn, LocalDateTime lastLogin, boolean banned) { } diff --git a/src/main/java/database/account/AccountRepository.java b/src/main/java/database/account/AccountRepository.java index 608fba9f44..d651bf8321 100644 --- a/src/main/java/database/account/AccountRepository.java +++ b/src/main/java/database/account/AccountRepository.java @@ -3,6 +3,11 @@ package database.account; import database.PgDatabaseConnection; import org.jdbi.v3.core.Handle; +import java.util.Optional; + +/** + * @author Ponk + */ public class AccountRepository { private final PgDatabaseConnection connection; @@ -10,8 +15,17 @@ public class AccountRepository { this.connection = connection; } - public Account getByName(String name) { - return null; // TODO + public Optional findById(int accountId) { + String sql = """ + SELECT id, name, password, pin, pic, logged_in, last_login, birthdate, banned, gender, tos_accepted + FROM account + WHERE id = :id"""; + try (Handle handle = connection.getHandle()) { + return handle.createQuery(sql) + .bind("id", accountId) + .mapTo(Account.class) + .findOne(); + } } public Integer insert(Account account) { @@ -28,4 +42,17 @@ public class AccountRepository { .one(); } } + + public void setTos(int accountId, boolean acceptedTos) { + String sql = """ + UPDATE account + SET tos_accepted = :acceptedTos + WHERE id = :id"""; + try (Handle handle = connection.getHandle()) { + handle.createUpdate(sql) + .bind("id", accountId) + .bind("acceptedTos", acceptedTos) + .execute(); + } + } } diff --git a/src/main/java/database/account/AccountRowMapper.java b/src/main/java/database/account/AccountRowMapper.java new file mode 100644 index 0000000000..101fb7b9b6 --- /dev/null +++ b/src/main/java/database/account/AccountRowMapper.java @@ -0,0 +1,34 @@ +package database.account; + +import org.jdbi.v3.core.mapper.RowMapper; +import org.jdbi.v3.core.statement.StatementContext; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Optional; + +/** + * @author Ponk + */ +public class AccountRowMapper implements RowMapper { + + @Override + public Account map(ResultSet rs, StatementContext ctx) throws SQLException { + return Account.builder() + .id(rs.getInt("id")) + .name(rs.getString("name")) + .password(rs.getString("password")) + .pin(rs.getString("pin")) + .pic(rs.getString("pic")) + .loggedIn(rs.getInt("logged_in")) + .lastLogin(Optional.ofNullable(rs.getTimestamp("last_login")) + .map(Timestamp::toLocalDateTime) + .orElse(null)) + .birthdate(rs.getDate("birthdate").toLocalDate()) + .banned(rs.getBoolean("banned")) + .gender(rs.getByte("gender")) + .acceptedTos(rs.getBoolean("tos_accepted")) + .build(); + } +} diff --git a/src/main/java/net/PacketProcessor.java b/src/main/java/net/PacketProcessor.java index 0d16bb3a58..fe7120aaf6 100644 --- a/src/main/java/net/PacketProcessor.java +++ b/src/main/java/net/PacketProcessor.java @@ -276,7 +276,7 @@ public final class PacketProcessor { } private void registerLoginHandlers() { - registerHandler(RecvOpcode.ACCEPT_TOS, new AcceptToSHandler()); + registerHandler(RecvOpcode.ACCEPT_TOS, new AcceptToSHandler(channelDeps.accountService())); registerHandler(RecvOpcode.AFTER_LOGIN, new AfterLoginHandler()); registerHandler(RecvOpcode.SERVERLIST_REREQUEST, new ServerlistRequestHandler()); registerHandler(RecvOpcode.CHARLIST_REQUEST, new CharlistRequestHandler()); diff --git a/src/main/java/net/server/handlers/login/AcceptToSHandler.java b/src/main/java/net/server/handlers/login/AcceptToSHandler.java index 8964fe5fd0..7722500aa8 100644 --- a/src/main/java/net/server/handlers/login/AcceptToSHandler.java +++ b/src/main/java/net/server/handlers/login/AcceptToSHandler.java @@ -4,12 +4,19 @@ import client.Client; import net.AbstractPacketHandler; import net.netty.GameViolationException; import net.packet.InPacket; +import service.AccountService; import tools.PacketCreator; /** * @author kevintjuh93 + * @author Ponk */ public final class AcceptToSHandler extends AbstractPacketHandler { + private final AccountService accountService; + + public AcceptToSHandler(final AccountService accountService) { + this.accountService = accountService; + } @Override public boolean validateState(Client c) { @@ -18,7 +25,7 @@ public final class AcceptToSHandler extends AbstractPacketHandler { @Override public void handlePacket(InPacket p, Client c) { - if (p.available() == 0 || p.readByte() != 1 || c.acceptToS()) { + if (p.available() == 0 || p.readByte() != 1 || !accountService.acceptTos(c.getAccID())) { throw new GameViolationException("ToS not accepted"); } diff --git a/src/main/java/service/AccountService.java b/src/main/java/service/AccountService.java index e7db415663..0b50f92108 100644 --- a/src/main/java/service/AccountService.java +++ b/src/main/java/service/AccountService.java @@ -4,10 +4,18 @@ import database.account.Account; import database.account.AccountRepository; import lombok.extern.slf4j.Slf4j; import tools.BCrypt; +import tools.DatabaseConnection; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import java.time.LocalDate; import java.util.Optional; +/** + * @author Ponk + */ @Slf4j public class AccountService { private static final int PASSWORD_HASH_SALT_LOG_ROUNDS = 12; @@ -41,4 +49,52 @@ public class AccountService { private String hashPassword(String password) { return BCrypt.hashpw(password, BCrypt.gensalt(PASSWORD_HASH_SALT_LOG_ROUNDS)); } + + public Optional getAccount(int accountId) { + return accountRepository.findById(accountId); + } + + public boolean acceptTos(int accountId) { + acceptTosMysql(accountId); + acceptTosPostgres(accountId); + return true; + } + + private boolean acceptTosMysql(int accountId) { + try (Connection con = DatabaseConnection.getConnection()) { + try (PreparedStatement ps = con.prepareStatement("SELECT `tos` FROM accounts WHERE id = ?")) { + ps.setInt(1, accountId); + + try (ResultSet rs = ps.executeQuery()) { + if (rs.next()) { + if (rs.getByte("tos") == 1) { + return false; + } + } + } + } + + try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET tos = 1 WHERE id = ?")) { + ps.setInt(1, accountId); + ps.executeUpdate(); + } + } catch (SQLException e) { + e.printStackTrace(); + } + return true; + } + + private boolean acceptTosPostgres(int accountId) { + Optional account = getAccount(accountId); + if (account.isEmpty()) { + return false; + } + + if (account.get().acceptedTos()) { + return false; + } + + accountRepository.setTos(accountId, true); + return true; + } }