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 server.TimerManager;
|
||||
import server.life.Monster;
|
||||
import tools.DatabaseConnection;
|
||||
import tools.PacketCreator;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
@@ -69,8 +65,6 @@ import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
@@ -321,61 +315,6 @@ public class Client extends ChannelInboundHandlerAdapter {
|
||||
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) {
|
||||
this.pin = pin;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package database.account;
|
||||
|
||||
import client.LoginState;
|
||||
import lombok.Builder;
|
||||
import net.server.coordinator.session.Hwid;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
@@ -14,7 +15,8 @@ import java.util.Objects;
|
||||
@Builder
|
||||
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,
|
||||
boolean banned, Instant bannedUntil, Byte banReason, String banDescription) {
|
||||
boolean banned, Instant bannedUntil, Byte banReason, String banDescription, String ip,
|
||||
String macs, Hwid hwid) {
|
||||
public Account {
|
||||
Objects.requireNonNull(name);
|
||||
Objects.requireNonNull(password);
|
||||
|
||||
@@ -11,6 +11,10 @@ import java.util.Optional;
|
||||
* @author Ponk
|
||||
*/
|
||||
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;
|
||||
|
||||
public AccountRepository(PgDatabaseConnection connection) {
|
||||
@@ -19,10 +23,9 @@ public class AccountRepository {
|
||||
|
||||
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, banned_until, ban_reason, ban_description
|
||||
FROM account
|
||||
WHERE lower(name) = lower(:name)""";
|
||||
SELECT %s
|
||||
FROM account AS a
|
||||
WHERE lower(name) = lower(:name)""".formatted(SELECT_ACCOUNT_COLS);
|
||||
try (Handle handle = connection.getHandle()) {
|
||||
return handle.createQuery(sql)
|
||||
.bind("name", name)
|
||||
@@ -33,10 +36,9 @@ public class AccountRepository {
|
||||
|
||||
public Optional<Account> findById(int accountId) {
|
||||
String sql = """
|
||||
SELECT id, name, password, pin, pic, birthdate, gender, tos_accepted, chr_slots, login_state,
|
||||
last_login, banned, banned_until, ban_reason, ban_description
|
||||
FROM account
|
||||
WHERE id = :id""";
|
||||
SELECT %s
|
||||
FROM account AS a
|
||||
WHERE id = :id""".formatted(SELECT_ACCOUNT_COLS);
|
||||
try (Handle handle = connection.getHandle()) {
|
||||
return handle.createQuery(sql)
|
||||
.bind("id", accountId)
|
||||
@@ -45,16 +47,16 @@ public class AccountRepository {
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Integer> findIdByChrNameIgnoreCase(String name) {
|
||||
public Optional<Account> findByChrNameIgnoreCase(String name) {
|
||||
String sql = """
|
||||
SELECT id
|
||||
SELECT %s
|
||||
FROM account AS a
|
||||
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()) {
|
||||
return handle.createQuery(sql)
|
||||
.bind("name", name)
|
||||
.mapTo(Integer.class)
|
||||
.mapTo(Account.class)
|
||||
.findOne();
|
||||
}
|
||||
}
|
||||
@@ -158,14 +160,14 @@ public class AccountRepository {
|
||||
public boolean setBanned(int accountId, Instant bannedUntil, byte banReason, String description) {
|
||||
String sql = """
|
||||
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""";
|
||||
try (Handle handle = connection.getHandle()) {
|
||||
return handle.createUpdate(sql)
|
||||
.bind("id", accountId)
|
||||
.bind("bannedUntil", bannedUntil)
|
||||
.bind("banReason", banReason)
|
||||
.bind("description", description)
|
||||
.bind("banDescription", description)
|
||||
.execute() > 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package database.account;
|
||||
|
||||
import client.LoginState;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.server.coordinator.session.Hwid;
|
||||
import org.jdbi.v3.core.mapper.RowMapper;
|
||||
import org.jdbi.v3.core.statement.StatementContext;
|
||||
|
||||
@@ -40,6 +41,11 @@ public class AccountRowMapper implements RowMapper<Account> {
|
||||
.orElse(null))
|
||||
.banReason(rs.getByte("ban_reason"))
|
||||
.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();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
package database.ban;
|
||||
|
||||
import database.PgDatabaseConnection;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.jdbi.v3.core.Handle;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
public class HwidBanRepository {
|
||||
private final PgDatabaseConnection connection;
|
||||
|
||||
@@ -22,4 +24,19 @@ public class HwidBanRepository {
|
||||
.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) {
|
||||
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);
|
||||
}
|
||||
|
||||
public Optional<Integer> getAccountIdByChrName(String chrName) {
|
||||
return accountRepository.findIdByChrNameIgnoreCase(chrName);
|
||||
public Optional<Account> getAccountIdByChrName(String chrName) {
|
||||
return accountRepository.findByChrNameIgnoreCase(chrName);
|
||||
}
|
||||
|
||||
public boolean acceptTos(int accountId) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import client.Character;
|
||||
import client.Client;
|
||||
import client.autoban.AutobanFactory;
|
||||
import config.YamlConfig;
|
||||
import database.account.Account;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import net.packet.Packet;
|
||||
import net.server.Server;
|
||||
@@ -16,6 +17,8 @@ import tools.PacketCreator;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -86,8 +89,6 @@ public class BanService {
|
||||
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) {
|
||||
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) {
|
||||
Optional<Integer> foundAccountId = accountService.getAccountIdByChrName(victimName);
|
||||
if (foundAccountId.isEmpty()) {
|
||||
Optional<Account> foundAccount = accountService.getAccountIdByChrName(victimName);
|
||||
if (foundAccount.isEmpty()) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -122,8 +127,13 @@ public class BanService {
|
||||
String ip = victim.getClient().getRemoteAddress();
|
||||
String enrichedDescription = "[%s] %s (IP: %s)".formatted(description, readableName, ip);
|
||||
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())));
|
||||
TimerManager.getInstance().schedule(() -> transitionService.disconnect(c, false),
|
||||
TimerManager.getInstance().schedule(() -> transitionService.disconnect(victim.getClient(), true),
|
||||
TimeUnit.SECONDS.toMillis(5));
|
||||
return true;
|
||||
}
|
||||
@@ -138,6 +148,31 @@ public class BanService {
|
||||
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) {
|
||||
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()) {
|
||||
|
||||
@@ -14,7 +14,7 @@ CREATE TABLE hwid_ban
|
||||
created_at timestamp DEFAULT now() NOT NULL,
|
||||
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
|
||||
(
|
||||
|
||||
Reference in New Issue
Block a user