Rework login, get account from PG
This commit is contained in:
@@ -22,6 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||||||
package client;
|
package client;
|
||||||
|
|
||||||
import config.YamlConfig;
|
import config.YamlConfig;
|
||||||
|
import database.account.Account;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||||
import io.netty.handler.timeout.IdleStateEvent;
|
import io.netty.handler.timeout.IdleStateEvent;
|
||||||
@@ -63,6 +64,7 @@ import java.sql.PreparedStatement;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -72,6 +74,7 @@ import java.util.Iterator;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.locks.Lock;
|
import java.util.concurrent.locks.Lock;
|
||||||
@@ -84,6 +87,8 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
private static final int MAX_FAILED_LOGIN_ATTEMPTS = 5;
|
private static final int MAX_FAILED_LOGIN_ATTEMPTS = 5;
|
||||||
private static final int MAX_CHR_SLOTS = 15;
|
private static final int MAX_CHR_SLOTS = 15;
|
||||||
|
|
||||||
|
public static final byte NO_GENDER = 10;
|
||||||
|
|
||||||
public static final int LOGIN_NOTLOGGEDIN = 0;
|
public static final int LOGIN_NOTLOGGEDIN = 0;
|
||||||
public static final int LOGIN_SERVER_TRANSITION = 1;
|
public static final int LOGIN_SERVER_TRANSITION = 1;
|
||||||
public static final int LOGIN_LOGGEDIN = 2;
|
public static final int LOGIN_LOGGEDIN = 2;
|
||||||
@@ -97,12 +102,13 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
private volatile boolean inTransition;
|
private volatile boolean inTransition;
|
||||||
|
|
||||||
private io.netty.channel.Channel ioChannel;
|
private io.netty.channel.Channel ioChannel;
|
||||||
|
private Account account;
|
||||||
private Character player;
|
private Character player;
|
||||||
private int channel = 1;
|
private int channel = 1;
|
||||||
private int accId = -4;
|
private int accId = -4;
|
||||||
private boolean loggedIn = false;
|
private boolean loggedIn = false;
|
||||||
private boolean serverTransition = false;
|
private boolean serverTransition = false;
|
||||||
private Calendar birthday = null;
|
private Calendar birthday = null; // TODO: convert to LocalDate
|
||||||
private String accountName = null;
|
private String accountName = null;
|
||||||
private int world;
|
private int world;
|
||||||
private volatile long lastPong;
|
private volatile long lastPong;
|
||||||
@@ -281,6 +287,25 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
return getChannelServer().getEventSM().getEventManager(event);
|
return getChannelServer().getEventSM().getEventManager(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Account getAccount() {
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccount(Account account) {
|
||||||
|
Objects.requireNonNull(account);
|
||||||
|
this.account = account;
|
||||||
|
this.accId = account.id();
|
||||||
|
this.accountName = account.name();
|
||||||
|
this.characterSlots = account.chrSlots();
|
||||||
|
this.pin = account.pin();
|
||||||
|
this.pic = account.pic();
|
||||||
|
this.gender = Objects.requireNonNullElse(account.gender(), NO_GENDER);
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
LocalDate birthdate = account.birthdate();
|
||||||
|
calendar.set(birthdate.getYear(), birthdate.getMonthValue() - 1, birthdate.getDayOfMonth());
|
||||||
|
this.birthday = calendar;
|
||||||
|
}
|
||||||
|
|
||||||
public Character getPlayer() {
|
public Character getPlayer() {
|
||||||
return player;
|
return player;
|
||||||
}
|
}
|
||||||
@@ -301,6 +326,8 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
return serverTransition;
|
return serverTransition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: load ipbans on server start and query it on demand. This query should not be run on every login!
|
||||||
|
@Deprecated
|
||||||
public boolean hasBannedIP() {
|
public boolean hasBannedIP() {
|
||||||
boolean ret = false;
|
boolean ret = false;
|
||||||
try (Connection con = DatabaseConnection.getConnection();
|
try (Connection con = DatabaseConnection.getConnection();
|
||||||
@@ -342,6 +369,8 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: load macbans on server start and query it on demand. This query should not be run on every login!
|
||||||
|
@Deprecated
|
||||||
public boolean hasBannedMac() {
|
public boolean hasBannedMac() {
|
||||||
if (macs.isEmpty()) {
|
if (macs.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
@@ -377,6 +406,7 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Recode to close statements...
|
// TODO: Recode to close statements...
|
||||||
|
// Only used from ban command.
|
||||||
private void loadMacsIfNescessary() throws SQLException {
|
private void loadMacsIfNescessary() throws SQLException {
|
||||||
if (macs.isEmpty()) {
|
if (macs.isEmpty()) {
|
||||||
try (Connection con = DatabaseConnection.getConnection();
|
try (Connection con = DatabaseConnection.getConnection();
|
||||||
@@ -493,15 +523,21 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int login(String login, String pwd, Hwid hwid) {
|
public boolean tryLogin() {
|
||||||
int loginok = 5;
|
|
||||||
|
|
||||||
if (++loginattempt >= MAX_FAILED_LOGIN_ATTEMPTS) {
|
if (++loginattempt >= MAX_FAILED_LOGIN_ATTEMPTS) {
|
||||||
loggedIn = false;
|
loggedIn = false;
|
||||||
SessionCoordinator.getInstance().closeSession(this, false);
|
SessionCoordinator.getInstance().closeSession(this, false);
|
||||||
return 6; // thanks Survival_Project for finding out an issue with AUTOMATIC_REGISTER here
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: load account outside in LoginPasswordHandler (from service).
|
||||||
|
//
|
||||||
|
public int login(String login, String pwd, Hwid hwid) {
|
||||||
|
int loginok = 5;
|
||||||
|
|
||||||
try (Connection con = DatabaseConnection.getConnection();
|
try (Connection con = DatabaseConnection.getConnection();
|
||||||
PreparedStatement ps = con.prepareStatement("SELECT id, password, gender, banned, pin, pic, characterslots, tos FROM accounts WHERE name = ?")) {
|
PreparedStatement ps = con.prepareStatement("SELECT id, password, gender, banned, pin, pic, characterslots, tos FROM accounts WHERE name = ?")) {
|
||||||
ps.setString(1, login);
|
ps.setString(1, login);
|
||||||
@@ -576,6 +612,8 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: check tempban directly on loaded account
|
||||||
|
@Deprecated
|
||||||
public Calendar getTempBanCalendarFromDB() {
|
public Calendar getTempBanCalendarFromDB() {
|
||||||
final Calendar lTempban = Calendar.getInstance();
|
final Calendar lTempban = Calendar.getInstance();
|
||||||
|
|
||||||
@@ -675,6 +713,7 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: move to LoginPasswordHandler
|
||||||
public int getLoginState() { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN
|
public int getLoginState() { // 0 = LOGIN_NOTLOGGEDIN, 1= LOGIN_SERVER_TRANSITION, 2 = LOGIN_LOGGEDIN
|
||||||
try (Connection con = DatabaseConnection.getConnection()) {
|
try (Connection con = DatabaseConnection.getConnection()) {
|
||||||
int state;
|
int state;
|
||||||
@@ -952,6 +991,7 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
public void setGender(byte m) {
|
public void setGender(byte m) {
|
||||||
this.gender = m;
|
this.gender = m;
|
||||||
|
|
||||||
|
// TODO: move to AccountService
|
||||||
try (Connection con = DatabaseConnection.getConnection();
|
try (Connection con = DatabaseConnection.getConnection();
|
||||||
PreparedStatement ps = con.prepareStatement("UPDATE accounts SET gender = ? WHERE id = ?")) {
|
PreparedStatement ps = con.prepareStatement("UPDATE accounts SET gender = ? WHERE id = ?")) {
|
||||||
ps.setByte(1, gender);
|
ps.setByte(1, gender);
|
||||||
|
|||||||
@@ -4,11 +4,18 @@ import lombok.Builder;
|
|||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ponk
|
* @author Ponk
|
||||||
*/
|
*/
|
||||||
@Builder
|
@Builder
|
||||||
public record Account(int id, String name, String password, boolean acceptedTos, byte gender, LocalDate birthdate,
|
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) {
|
String pin, String pic, byte chrSlots, byte loginState, LocalDateTime lastLogin, boolean banned,
|
||||||
|
LocalDateTime tempBanTimestamp) {
|
||||||
|
public Account {
|
||||||
|
Objects.requireNonNull(name);
|
||||||
|
Objects.requireNonNull(password);
|
||||||
|
Objects.requireNonNull(birthdate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,24 @@ public class AccountRepository {
|
|||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Optional<Account> findByNameIgnoreCase(String name) {
|
||||||
|
String sql = """
|
||||||
|
SELECT id, name, password, pin, pic, birthdate, gender, tos_accepted, chr_slots, login_state,
|
||||||
|
last_login, banned, temp_ban_timestamp
|
||||||
|
FROM account
|
||||||
|
WHERE lower(name) = lower(:name)""";
|
||||||
|
try (Handle handle = connection.getHandle()) {
|
||||||
|
return handle.createQuery(sql)
|
||||||
|
.bind("name", name)
|
||||||
|
.mapTo(Account.class)
|
||||||
|
.findOne();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<Account> findById(int accountId) {
|
public Optional<Account> findById(int accountId) {
|
||||||
String sql = """
|
String sql = """
|
||||||
SELECT id, name, password, pin, pic, logged_in, last_login, birthdate, banned, gender, tos_accepted
|
SELECT id, name, password, pin, pic, birthdate, gender, tos_accepted, chr_slots, login_state,
|
||||||
|
last_login, banned, temp_ban_timestamp
|
||||||
FROM account
|
FROM account
|
||||||
WHERE id = :id""";
|
WHERE id = :id""";
|
||||||
try (Handle handle = connection.getHandle()) {
|
try (Handle handle = connection.getHandle()) {
|
||||||
@@ -30,13 +45,15 @@ public class AccountRepository {
|
|||||||
|
|
||||||
public Integer insert(Account account) {
|
public Integer insert(Account account) {
|
||||||
String sql = """
|
String sql = """
|
||||||
INSERT INTO account (name, password, birthdate)
|
INSERT INTO account (name, password, birthdate, chr_slots, login_state)
|
||||||
VALUES (:name, :password, :birthdate)""";
|
VALUES (:name, :password, :birthdate, :chrSlots, :loginState)""";
|
||||||
try (Handle handle = connection.getHandle()) {
|
try (Handle handle = connection.getHandle()) {
|
||||||
return handle.createUpdate(sql)
|
return handle.createUpdate(sql)
|
||||||
.bind("name", account.name())
|
.bind("name", account.name())
|
||||||
.bind("password", account.password())
|
.bind("password", account.password())
|
||||||
.bind("birthdate", account.birthdate())
|
.bind("birthdate", account.birthdate())
|
||||||
|
.bind("chrSlots", account.chrSlots())
|
||||||
|
.bind("loginState", account.loginState())
|
||||||
.executeAndReturnGeneratedKeys("id")
|
.executeAndReturnGeneratedKeys("id")
|
||||||
.mapTo(Integer.class)
|
.mapTo(Integer.class)
|
||||||
.one();
|
.one();
|
||||||
|
|||||||
@@ -21,14 +21,20 @@ public class AccountRowMapper implements RowMapper<Account> {
|
|||||||
.password(rs.getString("password"))
|
.password(rs.getString("password"))
|
||||||
.pin(rs.getString("pin"))
|
.pin(rs.getString("pin"))
|
||||||
.pic(rs.getString("pic"))
|
.pic(rs.getString("pic"))
|
||||||
.loggedIn(rs.getInt("logged_in"))
|
.birthdate(rs.getDate("birthdate").toLocalDate())
|
||||||
|
.gender(Optional.ofNullable(rs.getObject("gender", Short.class))
|
||||||
|
.map(Short::byteValue)
|
||||||
|
.orElse(null))
|
||||||
|
.acceptedTos(rs.getBoolean("tos_accepted"))
|
||||||
|
.chrSlots(rs.getByte("chr_slots"))
|
||||||
|
.loginState(rs.getByte("login_state"))
|
||||||
.lastLogin(Optional.ofNullable(rs.getTimestamp("last_login"))
|
.lastLogin(Optional.ofNullable(rs.getTimestamp("last_login"))
|
||||||
.map(Timestamp::toLocalDateTime)
|
.map(Timestamp::toLocalDateTime)
|
||||||
.orElse(null))
|
.orElse(null))
|
||||||
.birthdate(rs.getDate("birthdate").toLocalDate())
|
|
||||||
.banned(rs.getBoolean("banned"))
|
.banned(rs.getBoolean("banned"))
|
||||||
.gender(rs.getByte("gender"))
|
.tempBanTimestamp(Optional.ofNullable(rs.getTimestamp("temp_ban_timestamp"))
|
||||||
.acceptedTos(rs.getBoolean("tos_accepted"))
|
.map(Timestamp::toLocalDateTime)
|
||||||
|
.orElse(null))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,10 +26,12 @@ import client.Client;
|
|||||||
import client.DefaultDates;
|
import client.DefaultDates;
|
||||||
import config.YamlConfig;
|
import config.YamlConfig;
|
||||||
import constants.game.GameConstants;
|
import constants.game.GameConstants;
|
||||||
|
import database.account.Account;
|
||||||
import net.PacketHandler;
|
import net.PacketHandler;
|
||||||
import net.packet.InPacket;
|
import net.packet.InPacket;
|
||||||
import net.server.Server;
|
import net.server.Server;
|
||||||
import net.server.coordinator.session.Hwid;
|
import net.server.coordinator.session.Hwid;
|
||||||
|
import net.server.coordinator.session.SessionCoordinator;
|
||||||
import net.server.world.World;
|
import net.server.world.World;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -46,6 +48,7 @@ import java.sql.PreparedStatement;
|
|||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
public final class LoginPasswordHandler implements PacketHandler {
|
public final class LoginPasswordHandler implements PacketHandler {
|
||||||
private static final Logger log = LoggerFactory.getLogger(LoginPasswordHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(LoginPasswordHandler.class);
|
||||||
@@ -64,7 +67,7 @@ public final class LoginPasswordHandler implements PacketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void handlePacket(InPacket p, Client c) {
|
public void handlePacket(InPacket p, Client c) {
|
||||||
String remoteHost = c.getRemoteAddress();
|
String remoteHost = c.getRemoteAddress();
|
||||||
if (remoteHost.contentEquals("null")) {
|
if (remoteHost.contentEquals("null")) {
|
||||||
c.sendPacket(PacketCreator.getLoginFailed(14)); // thanks Alchemist for noting remoteHost could be null
|
c.sendPacket(PacketCreator.getLoginFailed(14)); // thanks Alchemist for noting remoteHost could be null
|
||||||
@@ -73,51 +76,94 @@ public final class LoginPasswordHandler implements PacketHandler {
|
|||||||
|
|
||||||
String login = p.readString();
|
String login = p.readString();
|
||||||
String pwd = p.readString();
|
String pwd = p.readString();
|
||||||
c.setAccountName(login);
|
|
||||||
|
|
||||||
p.skip(6); // localhost masked the initial part with zeroes...
|
p.skip(6); // localhost masked the initial part with zeroes...
|
||||||
byte[] hwidNibbles = p.readBytes(4);
|
byte[] hwidNibbles = p.readBytes(4);
|
||||||
Hwid hwid = new Hwid(HexTool.toCompactHexString(hwidNibbles));
|
c.setHwid(new Hwid(HexTool.toCompactHexString(hwidNibbles)));
|
||||||
int loginok = c.login(login, pwd, hwid);
|
|
||||||
|
|
||||||
|
if (!c.tryLogin()) {
|
||||||
if (YamlConfig.config.server.AUTOMATIC_REGISTER && loginok == 5) {
|
return;
|
||||||
try {
|
}
|
||||||
int accountId = createAccountPostgres(login, pwd);
|
Optional<Account> foundAccount = accountService.getAccount(login);
|
||||||
createAccountMysql(accountId, login, pwd);
|
if (foundAccount.isEmpty()) {
|
||||||
c.setAccID(accountId);
|
if (YamlConfig.config.server.AUTOMATIC_REGISTER) {
|
||||||
} finally {
|
Account newAccount = createAccount(login, pwd);
|
||||||
loginok = c.login(login, pwd, hwid);
|
foundAccount = Optional.of(newAccount);
|
||||||
|
} else {
|
||||||
|
c.sendPacket(PacketCreator.getLoginFailed(5));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c.hasBannedIP() || c.hasBannedMac()) {
|
Account account = foundAccount.get();
|
||||||
|
if (account.banned()) {
|
||||||
|
c.sendPacket(PacketCreator.getLoginFailed(3));
|
||||||
|
// TODO: send ban reason instead of login failed, something like this:
|
||||||
|
// c.sendPacket(PacketCreator.getPermBan(c.getGReason()));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!correctPassword(pwd, account)) {
|
||||||
|
c.sendPacket(PacketCreator.getLoginFailed(4));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
c.setAccount(account);
|
||||||
|
|
||||||
|
if (c.getLoginState() > Client.LOGIN_NOTLOGGEDIN) {
|
||||||
|
c.sendPacket(PacketCreator.getLoginFailed(7));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!account.acceptedTos()) {
|
||||||
|
c.sendPacket(PacketCreator.getLoginFailed(23));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean banCheckDisabled = false;
|
||||||
|
if (!banCheckDisabled && (c.hasBannedIP() || c.hasBannedMac())) {
|
||||||
c.sendPacket(PacketCreator.getLoginFailed(3));
|
c.sendPacket(PacketCreator.getLoginFailed(3));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Calendar tempban = c.getTempBanCalendarFromDB();
|
|
||||||
if (tempban != null) {
|
/* TODO: check temp ban from account, something like this:
|
||||||
|
LocalDateTime tempBan = account.tempBanTimestamp();
|
||||||
|
if (tempBan != null && tempBan.isAfter(LocalDateTime.now())) {
|
||||||
|
Duration remainingTempBan = Duration.between(LocalDateTime.now(), tempBan);
|
||||||
|
c.sendPacket(PacketCreator.getTempBan());
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
boolean tempBanDisabled = false;
|
||||||
|
Calendar tempban = null;
|
||||||
|
if (!tempBanDisabled && (tempban = c.getTempBanCalendarFromDB()) != null) {
|
||||||
if (tempban.getTimeInMillis() > Calendar.getInstance().getTimeInMillis()) {
|
if (tempban.getTimeInMillis() > Calendar.getInstance().getTimeInMillis()) {
|
||||||
c.sendPacket(PacketCreator.getTempBan(tempban.getTimeInMillis(), c.getGReason()));
|
c.sendPacket(PacketCreator.getTempBan(tempban.getTimeInMillis(), c.getGReason()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (loginok == 3) {
|
|
||||||
c.sendPacket(PacketCreator.getPermBan(c.getGReason()));//crashes but idc :D
|
Integer failureCode = checkMultiClient(c);
|
||||||
return;
|
if (failureCode != null) {
|
||||||
} else if (loginok != 0) {
|
c.sendPacket(PacketCreator.getLoginFailed(failureCode));
|
||||||
c.sendPacket(PacketCreator.getLoginFailed(loginok));
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (c.finishLogin()) {
|
|
||||||
checkChar(c);
|
if (!c.finishLogin()) {
|
||||||
login(c);
|
|
||||||
} else {
|
|
||||||
c.sendPacket(PacketCreator.getLoginFailed(7));
|
c.sendPacket(PacketCreator.getLoginFailed(7));
|
||||||
}
|
}
|
||||||
|
checkChar(c);
|
||||||
|
|
||||||
|
c.sendPacket(PacketCreator.getAuthSuccess(c));
|
||||||
|
Server.getInstance().registerLoginState(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int createAccountPostgres(String name, String password) {
|
private Account createAccount(String name, String password) {
|
||||||
|
Account account = createAccountPostgres(name, password);
|
||||||
|
createAccountMysql(account.id(), name, password);
|
||||||
|
return account;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Account createAccountPostgres(String name, String password) {
|
||||||
return accountService.createNew(name, password);
|
return accountService.createNew(name, password);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,7 +172,7 @@ public final class LoginPasswordHandler implements PacketHandler {
|
|||||||
PreparedStatement ps = con.prepareStatement("INSERT INTO accounts (id, name, password, birthday, tempban) VALUES (?, ?, ?, ?, ?);")) {
|
PreparedStatement ps = con.prepareStatement("INSERT INTO accounts (id, name, password, birthday, tempban) VALUES (?, ?, ?, ?, ?);")) {
|
||||||
ps.setInt(1, id);
|
ps.setInt(1, id);
|
||||||
ps.setString(2, name);
|
ps.setString(2, name);
|
||||||
ps.setString(3, BCrypt.hashpw(password, BCrypt.gensalt(12)));
|
ps.setString(3, BCrypt.hashpw(password, BCrypt.gensalt()));
|
||||||
ps.setDate(4, Date.valueOf(DefaultDates.getBirthday()));
|
ps.setDate(4, Date.valueOf(DefaultDates.getBirthday()));
|
||||||
ps.setTimestamp(5, Timestamp.valueOf(DefaultDates.getTempban()));
|
ps.setTimestamp(5, Timestamp.valueOf(DefaultDates.getTempban()));
|
||||||
ps.executeUpdate();
|
ps.executeUpdate();
|
||||||
@@ -135,6 +181,24 @@ public final class LoginPasswordHandler implements PacketHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean correctPassword(String input, Account account) {
|
||||||
|
return BCrypt.checkpw(input, account.password());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer checkMultiClient(Client c) {
|
||||||
|
SessionCoordinator.AntiMulticlientResult res = SessionCoordinator.getInstance()
|
||||||
|
.attemptLoginSession(c, c.getHwid(), c.getAccID(), false);
|
||||||
|
|
||||||
|
return switch (res) {
|
||||||
|
case SUCCESS -> null;
|
||||||
|
case REMOTE_LOGGEDIN -> 17;
|
||||||
|
case REMOTE_REACHED_LIMIT -> 13;
|
||||||
|
case REMOTE_PROCESSING -> 10;
|
||||||
|
case MANY_ACCOUNT_ATTEMPTS -> 16;
|
||||||
|
default -> 8;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private void checkChar(Client c) { // issue with multiple chars from same account login found by shavit, resinate
|
private void checkChar(Client c) { // issue with multiple chars from same account login found by shavit, resinate
|
||||||
if (!YamlConfig.config.server.USE_CHARACTER_ACCOUNT_CHECK) {
|
if (!YamlConfig.config.server.USE_CHARACTER_ACCOUNT_CHECK) {
|
||||||
return;
|
return;
|
||||||
@@ -151,9 +215,4 @@ public final class LoginPasswordHandler implements PacketHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void login(Client c) {
|
|
||||||
c.sendPacket(PacketCreator.getAuthSuccess(c));//why the fk did I do c.getAccountName()?
|
|
||||||
Server.getInstance().registerLoginState(c);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import tools.PacketCreator;
|
|||||||
public class SetGenderHandler extends AbstractPacketHandler {
|
public class SetGenderHandler extends AbstractPacketHandler {
|
||||||
@Override
|
@Override
|
||||||
public void handlePacket(InPacket p, Client c) {
|
public void handlePacket(InPacket p, Client c) {
|
||||||
if (c.getGender() == 10) { //Packet shouldn't come if Gender isn't 10.
|
if (c.getGender() == Client.NO_GENDER) { //Packet shouldn't come if Gender isn't 10.
|
||||||
byte confirmed = p.readByte();
|
byte confirmed = p.readByte();
|
||||||
if (confirmed == 0x01) {
|
if (confirmed == 0x01) {
|
||||||
c.setGender(p.readByte());
|
c.setGender(p.readByte());
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ import java.util.Optional;
|
|||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class AccountService {
|
public class AccountService {
|
||||||
private static final int PASSWORD_HASH_SALT_LOG_ROUNDS = 12;
|
|
||||||
private static final LocalDate GMS_RELEASE = LocalDate.of(2005, 5, 11);
|
private static final LocalDate GMS_RELEASE = LocalDate.of(2005, 5, 11);
|
||||||
|
private static final byte INITIAL_CHR_SLOTS = 3;
|
||||||
|
|
||||||
private final AccountRepository accountRepository;
|
private final AccountRepository accountRepository;
|
||||||
|
|
||||||
@@ -28,27 +28,34 @@ public class AccountService {
|
|||||||
this.accountRepository = accountRepository;
|
this.accountRepository = accountRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int createNew(String name, String password) {
|
public Account createNew(String name, String password) {
|
||||||
Account newAccount = Account.builder()
|
Account newAccount = Account.builder()
|
||||||
.name(name)
|
.name(name)
|
||||||
.password(hashPassword(password))
|
.password(hashPassword(password))
|
||||||
.birthdate(GMS_RELEASE)
|
.birthdate(GMS_RELEASE)
|
||||||
|
.chrSlots(INITIAL_CHR_SLOTS)
|
||||||
|
.loginState((byte) Client.LOGIN_NOTLOGGEDIN)
|
||||||
|
.gender(null)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
Integer accountId;
|
Integer accountId;
|
||||||
try {
|
try {
|
||||||
accountId = accountRepository.insert(newAccount);
|
accountId = accountRepository.insert(newAccount);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("Failed to create new account", e);
|
log.error("Failed to insert new account", e);
|
||||||
throw new RuntimeException("Failed to create new account");
|
throw new RuntimeException("Failed to insert new account");
|
||||||
}
|
}
|
||||||
|
|
||||||
return Optional.ofNullable(accountId)
|
return getAccount(accountId)
|
||||||
.orElseThrow(() -> new RuntimeException("Failed to create new account - missing id"));
|
.orElseThrow(() -> new RuntimeException("Failed to get account after insert, id: " + accountId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private String hashPassword(String password) {
|
private String hashPassword(String password) {
|
||||||
return BCrypt.hashpw(password, BCrypt.gensalt(PASSWORD_HASH_SALT_LOG_ROUNDS));
|
return BCrypt.hashpw(password, BCrypt.gensalt());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Optional<Account> getAccount(String name) {
|
||||||
|
return accountRepository.findByNameIgnoreCase(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Account> getAccount(int accountId) {
|
public Optional<Account> getAccount(int accountId) {
|
||||||
|
|||||||
@@ -5,23 +5,23 @@ CREATE TABLE account
|
|||||||
password varchar(200) NOT NULL,
|
password varchar(200) NOT NULL,
|
||||||
pin varchar(4),
|
pin varchar(4),
|
||||||
pic varchar(26),
|
pic varchar(26),
|
||||||
logged_in smallint DEFAULT 0 NOT NULL,
|
|
||||||
created_at timestamp DEFAULT now() NOT NULL,
|
created_at timestamp DEFAULT now() NOT NULL,
|
||||||
last_login timestamp,
|
|
||||||
birthdate date NOT NULL,
|
birthdate date NOT NULL,
|
||||||
banned boolean DEFAULT false NOT NULL,
|
tos_accepted boolean DEFAULT false NOT NULL,
|
||||||
banreason text,
|
gender smallint,
|
||||||
macs text,
|
chr_slots smallint NOT NULL,
|
||||||
nx_credit integer DEFAULT 0 NOT NULL,
|
nx_credit integer DEFAULT 0 NOT NULL,
|
||||||
maple_point integer DEFAULT 0 NOT NULL,
|
maple_point integer DEFAULT 0 NOT NULL,
|
||||||
nx_prepaid integer DEFAULT 0 NOT NULL,
|
nx_prepaid integer DEFAULT 0 NOT NULL,
|
||||||
chr_slots smallint DEFAULT 3 NOT NULL,
|
login_state smallint NOT NULL,
|
||||||
gender smallint DEFAULT 10 NOT NULL,
|
last_login timestamp,
|
||||||
|
banned boolean DEFAULT false NOT NULL,
|
||||||
|
banreason text,
|
||||||
temp_ban_timestamp timestamp,
|
temp_ban_timestamp timestamp,
|
||||||
greason smallint,
|
greason smallint,
|
||||||
tos_accepted boolean DEFAULT false NOT NULL,
|
|
||||||
ip text,
|
ip text,
|
||||||
hwid text,
|
hwid text,
|
||||||
|
macs text,
|
||||||
PRIMARY KEY (id),
|
PRIMARY KEY (id),
|
||||||
UNIQUE (name)
|
UNIQUE (name)
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user