Ban ip, macs & hwid in PG
Finally rid of all db code in Client
This commit is contained in:
@@ -52,14 +52,10 @@ import scripting.quest.QuestActionManager;
|
|||||||
import scripting.quest.QuestScriptManager;
|
import scripting.quest.QuestScriptManager;
|
||||||
import server.TimerManager;
|
import server.TimerManager;
|
||||||
import server.life.Monster;
|
import server.life.Monster;
|
||||||
import tools.DatabaseConnection;
|
|
||||||
import tools.PacketCreator;
|
import tools.PacketCreator;
|
||||||
|
|
||||||
import javax.script.ScriptEngine;
|
import javax.script.ScriptEngine;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.PreparedStatement;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
@@ -69,8 +65,6 @@ import java.util.Calendar;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@@ -321,61 +315,6 @@ public class Client extends ChannelInboundHandlerAdapter {
|
|||||||
return inServerTransition;
|
return inServerTransition;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Recode to close statements...
|
|
||||||
// Only used from ban command.
|
|
||||||
private void loadMacsIfNescessary() throws SQLException {
|
|
||||||
if (macs.isEmpty()) {
|
|
||||||
try (Connection con = DatabaseConnection.getConnection();
|
|
||||||
PreparedStatement ps = con.prepareStatement("SELECT macs FROM accounts WHERE id = ?")) {
|
|
||||||
ps.setInt(1, accId);
|
|
||||||
try (ResultSet rs = ps.executeQuery()) {
|
|
||||||
if (rs.next()) {
|
|
||||||
for (String mac : rs.getString("macs").split(", ")) {
|
|
||||||
if (!mac.equals("")) {
|
|
||||||
macs.add(mac);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void banMacs() {
|
|
||||||
try {
|
|
||||||
loadMacsIfNescessary();
|
|
||||||
|
|
||||||
List<String> filtered = new LinkedList<>();
|
|
||||||
try (Connection con = DatabaseConnection.getConnection()) {
|
|
||||||
try (PreparedStatement ps = con.prepareStatement("SELECT filter FROM macfilters");
|
|
||||||
ResultSet rs = ps.executeQuery()) {
|
|
||||||
while (rs.next()) {
|
|
||||||
filtered.add(rs.getString("filter"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try (PreparedStatement ps = con.prepareStatement("INSERT INTO macbans (mac, aid) VALUES (?, ?)")) {
|
|
||||||
for (String mac : macs) {
|
|
||||||
boolean matched = false;
|
|
||||||
for (String filter : filtered) {
|
|
||||||
if (mac.matches(filter)) {
|
|
||||||
matched = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!matched) {
|
|
||||||
ps.setString(1, mac);
|
|
||||||
ps.setString(2, String.valueOf(getAccID()));
|
|
||||||
ps.executeUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPin(String pin) {
|
public void setPin(String pin) {
|
||||||
this.pin = pin;
|
this.pin = pin;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package database.account;
|
|||||||
|
|
||||||
import client.LoginState;
|
import client.LoginState;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
|
import net.server.coordinator.session.Hwid;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
@@ -14,7 +15,8 @@ import java.util.Objects;
|
|||||||
@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, byte chrSlots, LoginState loginState, LocalDateTime lastLogin,
|
String pin, String pic, byte chrSlots, LoginState loginState, LocalDateTime lastLogin,
|
||||||
boolean banned, Instant bannedUntil, Byte banReason, String banDescription) {
|
boolean banned, Instant bannedUntil, Byte banReason, String banDescription, String ip,
|
||||||
|
String macs, Hwid hwid) {
|
||||||
public Account {
|
public Account {
|
||||||
Objects.requireNonNull(name);
|
Objects.requireNonNull(name);
|
||||||
Objects.requireNonNull(password);
|
Objects.requireNonNull(password);
|
||||||
|
|||||||
@@ -11,6 +11,10 @@ import java.util.Optional;
|
|||||||
* @author Ponk
|
* @author Ponk
|
||||||
*/
|
*/
|
||||||
public class AccountRepository {
|
public class AccountRepository {
|
||||||
|
private static final String SELECT_ACCOUNT_COLS = "a.id, a.name, password, pin, pic, birthdate, a.gender, " +
|
||||||
|
"tos_accepted, chr_slots, login_state, last_login, banned, banned_until, ban_reason, ban_description, " +
|
||||||
|
"ip, macs, hwid";
|
||||||
|
|
||||||
private final PgDatabaseConnection connection;
|
private final PgDatabaseConnection connection;
|
||||||
|
|
||||||
public AccountRepository(PgDatabaseConnection connection) {
|
public AccountRepository(PgDatabaseConnection connection) {
|
||||||
@@ -19,10 +23,9 @@ public class AccountRepository {
|
|||||||
|
|
||||||
public Optional<Account> findByNameIgnoreCase(String name) {
|
public Optional<Account> findByNameIgnoreCase(String name) {
|
||||||
String sql = """
|
String sql = """
|
||||||
SELECT id, name, password, pin, pic, birthdate, gender, tos_accepted, chr_slots, login_state,
|
SELECT %s
|
||||||
last_login, banned, banned_until, ban_reason, ban_description
|
FROM account AS a
|
||||||
FROM account
|
WHERE lower(name) = lower(:name)""".formatted(SELECT_ACCOUNT_COLS);
|
||||||
WHERE lower(name) = lower(:name)""";
|
|
||||||
try (Handle handle = connection.getHandle()) {
|
try (Handle handle = connection.getHandle()) {
|
||||||
return handle.createQuery(sql)
|
return handle.createQuery(sql)
|
||||||
.bind("name", name)
|
.bind("name", name)
|
||||||
@@ -33,10 +36,9 @@ public class AccountRepository {
|
|||||||
|
|
||||||
public Optional<Account> findById(int accountId) {
|
public Optional<Account> findById(int accountId) {
|
||||||
String sql = """
|
String sql = """
|
||||||
SELECT id, name, password, pin, pic, birthdate, gender, tos_accepted, chr_slots, login_state,
|
SELECT %s
|
||||||
last_login, banned, banned_until, ban_reason, ban_description
|
FROM account AS a
|
||||||
FROM account
|
WHERE id = :id""".formatted(SELECT_ACCOUNT_COLS);
|
||||||
WHERE id = :id""";
|
|
||||||
try (Handle handle = connection.getHandle()) {
|
try (Handle handle = connection.getHandle()) {
|
||||||
return handle.createQuery(sql)
|
return handle.createQuery(sql)
|
||||||
.bind("id", accountId)
|
.bind("id", accountId)
|
||||||
@@ -45,16 +47,16 @@ public class AccountRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Integer> findIdByChrNameIgnoreCase(String name) {
|
public Optional<Account> findByChrNameIgnoreCase(String name) {
|
||||||
String sql = """
|
String sql = """
|
||||||
SELECT id
|
SELECT %s
|
||||||
FROM account AS a
|
FROM account AS a
|
||||||
INNER JOIN chr AS c ON a.id = c.account
|
INNER JOIN chr AS c ON a.id = c.account
|
||||||
WHERE lower(c.name) = lower(:name)""";
|
WHERE lower(c.name) = lower(:name)""".formatted(SELECT_ACCOUNT_COLS);
|
||||||
try (Handle handle = connection.getHandle()) {
|
try (Handle handle = connection.getHandle()) {
|
||||||
return handle.createQuery(sql)
|
return handle.createQuery(sql)
|
||||||
.bind("name", name)
|
.bind("name", name)
|
||||||
.mapTo(Integer.class)
|
.mapTo(Account.class)
|
||||||
.findOne();
|
.findOne();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,14 +160,14 @@ public class AccountRepository {
|
|||||||
public boolean setBanned(int accountId, Instant bannedUntil, byte banReason, String description) {
|
public boolean setBanned(int accountId, Instant bannedUntil, byte banReason, String description) {
|
||||||
String sql = """
|
String sql = """
|
||||||
UPDATE account
|
UPDATE account
|
||||||
SET banned = true, banned_until = :bannedUntil, ban_reason = :banReason, description = :description
|
SET banned = true, banned_until = :bannedUntil, ban_reason = :banReason, ban_description = :banDescription
|
||||||
WHERE id = :id""";
|
WHERE id = :id""";
|
||||||
try (Handle handle = connection.getHandle()) {
|
try (Handle handle = connection.getHandle()) {
|
||||||
return handle.createUpdate(sql)
|
return handle.createUpdate(sql)
|
||||||
.bind("id", accountId)
|
.bind("id", accountId)
|
||||||
.bind("bannedUntil", bannedUntil)
|
.bind("bannedUntil", bannedUntil)
|
||||||
.bind("banReason", banReason)
|
.bind("banReason", banReason)
|
||||||
.bind("description", description)
|
.bind("banDescription", description)
|
||||||
.execute() > 0;
|
.execute() > 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package database.account;
|
|||||||
|
|
||||||
import client.LoginState;
|
import client.LoginState;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.server.coordinator.session.Hwid;
|
||||||
import org.jdbi.v3.core.mapper.RowMapper;
|
import org.jdbi.v3.core.mapper.RowMapper;
|
||||||
import org.jdbi.v3.core.statement.StatementContext;
|
import org.jdbi.v3.core.statement.StatementContext;
|
||||||
|
|
||||||
@@ -40,6 +41,11 @@ public class AccountRowMapper implements RowMapper<Account> {
|
|||||||
.orElse(null))
|
.orElse(null))
|
||||||
.banReason(rs.getByte("ban_reason"))
|
.banReason(rs.getByte("ban_reason"))
|
||||||
.banDescription(rs.getString("ban_description"))
|
.banDescription(rs.getString("ban_description"))
|
||||||
|
.ip(rs.getString("ip"))
|
||||||
|
.macs(rs.getString("macs"))
|
||||||
|
.hwid(Optional.ofNullable(rs.getString("hwid"))
|
||||||
|
.map(Hwid::new)
|
||||||
|
.orElse(null))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
package database.ban;
|
package database.ban;
|
||||||
|
|
||||||
import database.PgDatabaseConnection;
|
import database.PgDatabaseConnection;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jdbi.v3.core.Handle;
|
import org.jdbi.v3.core.Handle;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
public class HwidBanRepository {
|
public class HwidBanRepository {
|
||||||
private final PgDatabaseConnection connection;
|
private final PgDatabaseConnection connection;
|
||||||
|
|
||||||
@@ -22,4 +24,19 @@ public class HwidBanRepository {
|
|||||||
.list();
|
.list();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean saveHwidBan(String hwid, int accountId) {
|
||||||
|
String sql = """
|
||||||
|
INSERT INTO hwid_ban (hwid, account_id)
|
||||||
|
VALUES (:hwid, :accountId)""";
|
||||||
|
try (Handle handle = connection.getHandle()) {
|
||||||
|
return handle.createUpdate(sql)
|
||||||
|
.bind("hwid", hwid)
|
||||||
|
.bind("accountId", accountId)
|
||||||
|
.execute() > 0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to save hwid ban. The hwid is already banned? accountId: {}, hwid: {}", accountId, hwid, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,4 +46,11 @@ public class HwidBanManager {
|
|||||||
public synchronized boolean isBanned(Hwid hwid) {
|
public synchronized boolean isBanned(Hwid hwid) {
|
||||||
return bannedHwids.contains(hwid);
|
return bannedHwids.contains(hwid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void banHwid(Hwid hwid, int accountId) {
|
||||||
|
if (hwid == null) {
|
||||||
|
throw new IllegalArgumentException("hwid cannot be null");
|
||||||
|
}
|
||||||
|
hwidBanRepository.saveHwidBan(hwid.hwid(), accountId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ public class AccountService {
|
|||||||
return accountRepository.findById(accountId);
|
return accountRepository.findById(accountId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Optional<Integer> getAccountIdByChrName(String chrName) {
|
public Optional<Account> getAccountIdByChrName(String chrName) {
|
||||||
return accountRepository.findIdByChrNameIgnoreCase(chrName);
|
return accountRepository.findByChrNameIgnoreCase(chrName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean acceptTos(int accountId) {
|
public boolean acceptTos(int accountId) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import client.Character;
|
|||||||
import client.Client;
|
import client.Client;
|
||||||
import client.autoban.AutobanFactory;
|
import client.autoban.AutobanFactory;
|
||||||
import config.YamlConfig;
|
import config.YamlConfig;
|
||||||
|
import database.account.Account;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.packet.Packet;
|
import net.packet.Packet;
|
||||||
import net.server.Server;
|
import net.server.Server;
|
||||||
@@ -16,6 +17,8 @@ import tools.PacketCreator;
|
|||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@@ -86,8 +89,6 @@ public class BanService {
|
|||||||
ban(c, victimName, duration, reason, description);
|
ban(c, victimName, duration, reason, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: also ban ip and macs. Table "ipbans" and "macbans" (while taking "macfilters" into consideration).
|
|
||||||
// That's how it was done previously, anyway.
|
|
||||||
private void ban(Client c, String victimName, Duration duration, byte reason, String description) {
|
private void ban(Client c, String victimName, Duration duration, byte reason, String description) {
|
||||||
Character victim = c.getChannelServer().getPlayerStorage().getCharacterByName(victimName);
|
Character victim = c.getChannelServer().getPlayerStorage().getCharacterByName(victimName);
|
||||||
|
|
||||||
@@ -107,12 +108,16 @@ public class BanService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean banOfflineChr(String victimName, Duration duration, byte reason, String description) {
|
private boolean banOfflineChr(String victimName, Duration duration, byte reason, String description) {
|
||||||
Optional<Integer> foundAccountId = accountService.getAccountIdByChrName(victimName);
|
Optional<Account> foundAccount = accountService.getAccountIdByChrName(victimName);
|
||||||
if (foundAccountId.isEmpty()) {
|
if (foundAccount.isEmpty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveBan(foundAccountId.get(), duration, reason, description);
|
Account account = foundAccount.get();
|
||||||
|
saveBan(account.id(), duration, reason, description);
|
||||||
|
banIp(account.ip(), account.id());
|
||||||
|
banMacs(account.macs(), account.id());
|
||||||
|
banHwid(account.hwid(), account.id());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,8 +127,13 @@ public class BanService {
|
|||||||
String ip = victim.getClient().getRemoteAddress();
|
String ip = victim.getClient().getRemoteAddress();
|
||||||
String enrichedDescription = "[%s] %s (IP: %s)".formatted(description, readableName, ip);
|
String enrichedDescription = "[%s] %s (IP: %s)".formatted(description, readableName, ip);
|
||||||
saveBan(victim.getAccountID(), duration, reason, enrichedDescription);
|
saveBan(victim.getAccountID(), duration, reason, enrichedDescription);
|
||||||
|
banIp(ip, victim.getAccountID());
|
||||||
|
Account victimAccount = victim.getClient().getAccount();
|
||||||
|
banMacs(victimAccount.macs(), victim.getAccountID());
|
||||||
|
banHwid(victimAccount.hwid(), victim.getAccountID());
|
||||||
|
|
||||||
victim.sendPacket(PacketCreator.sendPolice("You have been banned by %s.".formatted(c.getPlayer().getName())));
|
victim.sendPacket(PacketCreator.sendPolice("You have been banned by %s.".formatted(c.getPlayer().getName())));
|
||||||
TimerManager.getInstance().schedule(() -> transitionService.disconnect(c, false),
|
TimerManager.getInstance().schedule(() -> transitionService.disconnect(victim.getClient(), true),
|
||||||
TimeUnit.SECONDS.toMillis(5));
|
TimeUnit.SECONDS.toMillis(5));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -138,6 +148,31 @@ public class BanService {
|
|||||||
accountService.ban(accountId, bannedUntil, reason, description);
|
accountService.ban(accountId, bannedUntil, reason, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void banIp(String ip, int accountId) {
|
||||||
|
if (ip == null || ip.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipBanManager.banIp(ip, accountId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void banMacs(String macs, int accountId) {
|
||||||
|
if (macs == null || macs.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String> macsToBan = Arrays.asList(macs.split(", "));
|
||||||
|
macsToBan.forEach(mac -> macBanManager.banMac(mac, accountId));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void banHwid(Hwid hwid, int accountId) {
|
||||||
|
if (hwid == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hwidBanManager.banHwid(hwid, accountId);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isBanned(Client c) {
|
public boolean isBanned(Client c) {
|
||||||
return isIpBanned(c) || isHwidBanned(c) || isMacBanned(c);
|
return isIpBanned(c) || isHwidBanned(c) || isMacBanned(c);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ public class TransitionService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SessionCoordinator.getInstance().closeSession(c, false);
|
SessionCoordinator.getInstance().closeSession(c, shutdown);
|
||||||
|
|
||||||
|
|
||||||
if (!c.isInTransition() && c.isLoggedIn()) {
|
if (!c.isInTransition() && c.isLoggedIn()) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ CREATE TABLE hwid_ban
|
|||||||
created_at timestamp DEFAULT now() NOT NULL,
|
created_at timestamp DEFAULT now() NOT NULL,
|
||||||
PRIMARY KEY (hwid)
|
PRIMARY KEY (hwid)
|
||||||
);
|
);
|
||||||
GRANT SELECT ON TABLE hwid_ban TO ${server-username};
|
GRANT SELECT, INSERT ON TABLE hwid_ban TO ${server-username};
|
||||||
|
|
||||||
CREATE TABLE mac_ban
|
CREATE TABLE mac_ban
|
||||||
(
|
(
|
||||||
|
|||||||
Reference in New Issue
Block a user