fix: Исправлены критические баги HIGH приоритета

- Исправлены утечки ResultSet в SQLiteDatabaseManager и PostgreSQLDatabaseManager
  Все ResultSet теперь закрываются в try-with-resources блоках
- Добавлена валидация входных данных reason в ReportCommand
  Проверка на пустую строку и максимальную длину 500 символов
- Исправлен integer overflow в PaginationUtil.calculateStartIndex
  Добавлена проверка на переполнение при умножении page * pageSize
- Добавлены null-проверки в ConfigManager.getMessage
  Защита от NPE при null элементах в массиве replacements
This commit is contained in:
loki 2026-04-09 00:34:12 +02:00
parent 4f1572c9df
commit bf65a1f9ae
5 changed files with 93 additions and 59 deletions

View file

@ -57,7 +57,18 @@ public class ReportCommand implements CommandExecutor, TabCompleter {
String targetName = args[0]; String targetName = args[0];
String reason = String.join(" ", Arrays.copyOfRange(args, 1, args.length)); String reason = String.join(" ", Arrays.copyOfRange(args, 1, args.length));
// Validate reason
if (reason.trim().isEmpty()) {
player.sendMessage(plugin.getConfigManager().getMessage("usage"));
return true;
}
if (reason.length() > 500) {
player.sendMessage("§cПричина слишком длинная! Максимум 500 символов.");
return true;
}
return handleReport(player, targetName, reason); return handleReport(player, targetName, reason);
} }

View file

@ -63,8 +63,13 @@ public class ConfigManager {
public String getMessage(String key, String... replacements) { public String getMessage(String key, String... replacements) {
String message = getMessage(key); String message = getMessage(key);
if (replacements == null || replacements.length == 0) {
return message;
}
for (int i = 0; i < replacements.length - 1; i += 2) { for (int i = 0; i < replacements.length - 1; i += 2) {
message = message.replace(replacements[i], replacements[i + 1]); if (replacements[i] != null && replacements[i + 1] != null) {
message = message.replace(replacements[i], replacements[i + 1]);
}
} }
return message; return message;
} }

View file

@ -114,18 +114,19 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
public List<Report> getReportsForTarget(UUID targetUuid) { public List<Report> getReportsForTarget(UUID targetUuid) {
String sql = "SELECT * FROM reports WHERE target_uuid = ? ORDER BY created_at DESC"; String sql = "SELECT * FROM reports WHERE target_uuid = ? ORDER BY created_at DESC";
List<Report> reports = new ArrayList<>(); List<Report> reports = new ArrayList<>();
try (Connection conn = dataSource.getConnection(); try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) { PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, targetUuid.toString()); stmt.setString(1, targetUuid.toString());
ResultSet rs = stmt.executeQuery(); try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) { while (rs.next()) {
reports.add(mapReport(rs)); reports.add(mapReport(rs));
}
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to get reports for target", e); logger.log(Level.SEVERE, "Failed to get reports for target", e);
} }
return reports; return reports;
} }
@ -133,54 +134,56 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
public List<Report> getAllReports() { public List<Report> getAllReports() {
String sql = "SELECT * FROM reports ORDER BY created_at DESC"; String sql = "SELECT * FROM reports ORDER BY created_at DESC";
List<Report> reports = new ArrayList<>(); List<Report> reports = new ArrayList<>();
try (Connection conn = dataSource.getConnection(); try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) { PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery(); ResultSet rs = stmt.executeQuery()) {
while (rs.next()) { while (rs.next()) {
reports.add(mapReport(rs)); reports.add(mapReport(rs));
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to get all reports", e); logger.log(Level.SEVERE, "Failed to get all reports", e);
} }
return reports; return reports;
} }
@Override @Override
public int getReportCount(UUID targetUuid) { public int getReportCount(UUID targetUuid) {
String sql = "SELECT COUNT(*) FROM reports WHERE target_uuid = ?"; String sql = "SELECT COUNT(*) FROM reports WHERE target_uuid = ?";
try (Connection conn = dataSource.getConnection(); try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) { PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, targetUuid.toString()); stmt.setString(1, targetUuid.toString());
ResultSet rs = stmt.executeQuery(); try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) { if (rs.next()) {
return rs.getInt(1); return rs.getInt(1);
}
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to get report count", e); logger.log(Level.SEVERE, "Failed to get report count", e);
} }
return 0; return 0;
} }
@Override @Override
public boolean hasReported(UUID reporterUuid, UUID targetUuid) { public boolean hasReported(UUID reporterUuid, UUID targetUuid) {
String sql = "SELECT COUNT(*) FROM reports WHERE reporter_uuid = ? AND target_uuid = ?"; String sql = "SELECT COUNT(*) FROM reports WHERE reporter_uuid = ? AND target_uuid = ?";
try (Connection conn = dataSource.getConnection(); try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) { PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setString(1, reporterUuid.toString()); stmt.setString(1, reporterUuid.toString());
stmt.setString(2, targetUuid.toString()); stmt.setString(2, targetUuid.toString());
ResultSet rs = stmt.executeQuery(); try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) { if (rs.next()) {
return rs.getInt(1) > 0; return rs.getInt(1) > 0;
}
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to check if reported", e); logger.log(Level.SEVERE, "Failed to check if reported", e);
} }
return false; return false;
} }
@ -188,36 +191,37 @@ public class PostgreSQLDatabaseManager implements DatabaseManager {
public List<Report> getReportsPaginated(int page, int pageSize) { public List<Report> getReportsPaginated(int page, int pageSize) {
String sql = "SELECT * FROM reports ORDER BY created_at DESC LIMIT ? OFFSET ?"; String sql = "SELECT * FROM reports ORDER BY created_at DESC LIMIT ? OFFSET ?";
List<Report> reports = new ArrayList<>(); List<Report> reports = new ArrayList<>();
try (Connection conn = dataSource.getConnection(); try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) { PreparedStatement stmt = conn.prepareStatement(sql)) {
stmt.setInt(1, pageSize); stmt.setInt(1, pageSize);
stmt.setInt(2, page * pageSize); stmt.setInt(2, page * pageSize);
ResultSet rs = stmt.executeQuery(); try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) { while (rs.next()) {
reports.add(mapReport(rs)); reports.add(mapReport(rs));
}
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to get paginated reports", e); logger.log(Level.SEVERE, "Failed to get paginated reports", e);
} }
return reports; return reports;
} }
@Override @Override
public int getTotalReportCount() { public int getTotalReportCount() {
String sql = "SELECT COUNT(*) FROM reports"; String sql = "SELECT COUNT(*) FROM reports";
try (Connection conn = dataSource.getConnection(); try (Connection conn = dataSource.getConnection();
PreparedStatement stmt = conn.prepareStatement(sql)) { PreparedStatement stmt = conn.prepareStatement(sql);
ResultSet rs = stmt.executeQuery(); ResultSet rs = stmt.executeQuery()) {
if (rs.next()) { if (rs.next()) {
return rs.getInt(1); return rs.getInt(1);
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to get total report count", e); logger.log(Level.SEVERE, "Failed to get total report count", e);
} }
return 0; return 0;
} }

View file

@ -96,17 +96,18 @@ public class SQLiteDatabaseManager implements DatabaseManager {
public List<Report> getReportsForTarget(UUID targetUuid) { public List<Report> getReportsForTarget(UUID targetUuid) {
String sql = "SELECT * FROM reports WHERE target_uuid = ? ORDER BY created_at DESC"; String sql = "SELECT * FROM reports WHERE target_uuid = ? ORDER BY created_at DESC";
List<Report> reports = new ArrayList<>(); List<Report> reports = new ArrayList<>();
try (PreparedStatement stmt = connection.prepareStatement(sql)) { try (PreparedStatement stmt = connection.prepareStatement(sql);) {
stmt.setString(1, targetUuid.toString()); stmt.setString(1, targetUuid.toString());
ResultSet rs = stmt.executeQuery(); try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) { while (rs.next()) {
reports.add(mapReport(rs)); reports.add(mapReport(rs));
}
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to get reports for target", e); logger.log(Level.SEVERE, "Failed to get reports for target", e);
} }
return reports; return reports;
} }
@ -114,51 +115,53 @@ public class SQLiteDatabaseManager implements DatabaseManager {
public List<Report> getAllReports() { public List<Report> getAllReports() {
String sql = "SELECT * FROM reports ORDER BY created_at DESC"; String sql = "SELECT * FROM reports ORDER BY created_at DESC";
List<Report> reports = new ArrayList<>(); List<Report> reports = new ArrayList<>();
try (PreparedStatement stmt = connection.prepareStatement(sql)) { try (PreparedStatement stmt = connection.prepareStatement(sql);
ResultSet rs = stmt.executeQuery(); ResultSet rs = stmt.executeQuery()) {
while (rs.next()) { while (rs.next()) {
reports.add(mapReport(rs)); reports.add(mapReport(rs));
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to get all reports", e); logger.log(Level.SEVERE, "Failed to get all reports", e);
} }
return reports; return reports;
} }
@Override @Override
public int getReportCount(UUID targetUuid) { public int getReportCount(UUID targetUuid) {
String sql = "SELECT COUNT(*) FROM reports WHERE target_uuid = ?"; String sql = "SELECT COUNT(*) FROM reports WHERE target_uuid = ?";
try (PreparedStatement stmt = connection.prepareStatement(sql)) { try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, targetUuid.toString()); stmt.setString(1, targetUuid.toString());
ResultSet rs = stmt.executeQuery(); try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) { if (rs.next()) {
return rs.getInt(1); return rs.getInt(1);
}
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to get report count", e); logger.log(Level.SEVERE, "Failed to get report count", e);
} }
return 0; return 0;
} }
@Override @Override
public boolean hasReported(UUID reporterUuid, UUID targetUuid) { public boolean hasReported(UUID reporterUuid, UUID targetUuid) {
String sql = "SELECT COUNT(*) FROM reports WHERE reporter_uuid = ? AND target_uuid = ?"; String sql = "SELECT COUNT(*) FROM reports WHERE reporter_uuid = ? AND target_uuid = ?";
try (PreparedStatement stmt = connection.prepareStatement(sql)) { try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setString(1, reporterUuid.toString()); stmt.setString(1, reporterUuid.toString());
stmt.setString(2, targetUuid.toString()); stmt.setString(2, targetUuid.toString());
ResultSet rs = stmt.executeQuery(); try (ResultSet rs = stmt.executeQuery()) {
if (rs.next()) { if (rs.next()) {
return rs.getInt(1) > 0; return rs.getInt(1) > 0;
}
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to check if reported", e); logger.log(Level.SEVERE, "Failed to check if reported", e);
} }
return false; return false;
} }
@ -166,34 +169,35 @@ public class SQLiteDatabaseManager implements DatabaseManager {
public List<Report> getReportsPaginated(int page, int pageSize) { public List<Report> getReportsPaginated(int page, int pageSize) {
String sql = "SELECT * FROM reports ORDER BY created_at DESC LIMIT ? OFFSET ?"; String sql = "SELECT * FROM reports ORDER BY created_at DESC LIMIT ? OFFSET ?";
List<Report> reports = new ArrayList<>(); List<Report> reports = new ArrayList<>();
try (PreparedStatement stmt = connection.prepareStatement(sql)) { try (PreparedStatement stmt = connection.prepareStatement(sql)) {
stmt.setInt(1, pageSize); stmt.setInt(1, pageSize);
stmt.setInt(2, page * pageSize); stmt.setInt(2, page * pageSize);
ResultSet rs = stmt.executeQuery(); try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) { while (rs.next()) {
reports.add(mapReport(rs)); reports.add(mapReport(rs));
}
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to get paginated reports", e); logger.log(Level.SEVERE, "Failed to get paginated reports", e);
} }
return reports; return reports;
} }
@Override @Override
public int getTotalReportCount() { public int getTotalReportCount() {
String sql = "SELECT COUNT(*) FROM reports"; String sql = "SELECT COUNT(*) FROM reports";
try (PreparedStatement stmt = connection.prepareStatement(sql)) { try (PreparedStatement stmt = connection.prepareStatement(sql);
ResultSet rs = stmt.executeQuery(); ResultSet rs = stmt.executeQuery()) {
if (rs.next()) { if (rs.next()) {
return rs.getInt(1); return rs.getInt(1);
} }
} catch (SQLException e) { } catch (SQLException e) {
logger.log(Level.SEVERE, "Failed to get total report count", e); logger.log(Level.SEVERE, "Failed to get total report count", e);
} }
return 0; return 0;
} }

View file

@ -3,11 +3,21 @@ package dev.loki.lorep.util;
public class PaginationUtil { public class PaginationUtil {
public static int calculateTotalPages(int totalItems, int pageSize) { public static int calculateTotalPages(int totalItems, int pageSize) {
if (pageSize <= 0) {
throw new IllegalArgumentException("pageSize must be positive");
}
if (totalItems <= 0) return 1; if (totalItems <= 0) return 1;
return (int) Math.ceil((double) totalItems / pageSize); return (int) Math.ceil((double) totalItems / pageSize);
} }
public static int calculateStartIndex(int page, int pageSize) { public static int calculateStartIndex(int page, int pageSize) {
if (page < 0 || pageSize <= 0) {
return 0;
}
// Check for overflow
if (page > Integer.MAX_VALUE / pageSize) {
return Integer.MAX_VALUE;
}
return page * pageSize; return page * pageSize;
} }