/** * This file is part of Oracle, licensed under the MIT License (MIT). * * Copyright (c) 2015 Helion3 http://helion3.com/ * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.helion3.oracle.bans; import java.net.InetAddress; import java.net.UnknownHostException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Optional; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.spongepowered.api.entity.living.player.Player; import org.spongepowered.api.profile.GameProfile; import org.spongepowered.api.service.ban.BanService; import org.spongepowered.api.text.Text; import org.spongepowered.api.util.ban.Ban; import org.spongepowered.api.util.ban.BanTypes; import org.spongepowered.api.util.ban.Ban.Builder; import org.spongepowered.api.util.ban.Ban.Ip; import org.spongepowered.api.util.ban.Ban.Profile; import com.helion3.oracle.Oracle; import com.helion3.oracle.players.PlayerIdentification; import com.helion3.oracle.players.PluginPlayer; import com.helion3.oracle.utils.JoinUtil; public class OracleBanService implements BanService { @SuppressWarnings({ "unchecked", "rawtypes" }) @Override public Collection<? extends Ban> getBans() { Collection<? extends Ban> bans = this.getProfileBans(); bans.addAll((Collection) this.getIpBans()); return bans; } @Override public Collection<Profile> getProfileBans() { Collection<Profile> collection = new ArrayList<Profile>(); Connection conn = null; PreparedStatement s = null; ResultSet rs = null; try { conn = Oracle.dbc(); s = conn.prepareStatement("SELECT reason, HEX(player_uuid) as uuid FROM oracle_bans b LEFT JOIN oracle_players p ON b.player_id = p.player_id WHERE ip_id IS NULL AND unbanned = 0 AND player_uuid != '\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0'"); s.executeQuery(); rs = s.getResultSet(); while(rs.next()) { // Note: we have to use the Future directly because this method expects a synchronous return Future<GameProfile> future = Oracle.getGame().getServer().getGameProfileManager().get(PlayerIdentification.uuidFromDbString(rs.getString("uuid"))); Builder builder = Ban.builder(); builder.reason(Text.of(rs.getString("reason"))); builder.type(BanTypes.PROFILE); builder.profile(future.get()); collection.add((Profile) builder.build()); } } catch (SQLException e) { e.printStackTrace(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally { if(rs != null) try { rs.close(); } catch (SQLException e) {} if(s != null) try { s.close(); } catch (SQLException e) {} if(conn != null) try { conn.close(); } catch (SQLException e) {} } return collection; } @Override public Collection<Ip> getIpBans() { Collection<Ip> collection = new ArrayList<Ip>(); Connection conn = null; PreparedStatement s = null; ResultSet rs = null; try { conn = Oracle.dbc(); s = conn.prepareStatement("SELECT reason, INET_NTOA(ip) as ip FROM oracle_bans b LEFT JOIN oracle_ips i ON b.ip_id = i.ip_id WHERE b.ip_id IS NOT NULL AND unbanned = 0"); s.executeQuery(); rs = s.getResultSet(); while(rs.next()) { Builder builder = Ban.builder(); builder.reason(Text.of(rs.getString("reason"))); builder.type(BanTypes.IP); builder.address(InetAddress.getByName(rs.getString("ip"))); collection.add((Ip) builder.build()); } } catch (SQLException e) { e.printStackTrace(); } catch (UnknownHostException e) { e.printStackTrace(); } finally { if(rs != null) try { rs.close(); } catch (SQLException e) {} if(s != null) try { s.close(); } catch (SQLException e) {} if(conn != null) try { conn.close(); } catch (SQLException e) {} } return collection; } @Override public Optional<Profile> getBanFor(GameProfile profile) { Connection conn = null; PreparedStatement s = null; ResultSet rs = null; Profile ban = null; try { PluginPlayer pluginPlayer = PlayerIdentification.getOraclePlayer(profile.getUniqueId()); if( pluginPlayer != null ){ conn = Oracle.dbc(); s = conn.prepareStatement ("SELECT * FROM oracle_bans WHERE player_id = ? AND unbanned = 0 LIMIT 1"); s.setInt(1, pluginPlayer.getId()); s.executeQuery(); rs = s.getResultSet(); if(rs.first()) { Builder builder = Ban.builder(); builder.reason(Text.of(rs.getString("reason"))); builder.type(BanTypes.PROFILE); builder.profile(profile); ban = (Ban.Profile) builder.build(); } } } catch (SQLException e) { e.printStackTrace(); } finally { if(rs != null) try { rs.close(); } catch (SQLException e) {} if(s != null) try { s.close(); } catch (SQLException e) {} if(conn != null) try { conn.close(); } catch (SQLException e) {} } return Optional.ofNullable(ban); } @Override public Optional<Ip> getBanFor(InetAddress address) { Connection conn = null; PreparedStatement s = null; ResultSet rs = null; Ip ban = null; try { int ipId = JoinUtil.lookupIp(address.getHostAddress()); conn = Oracle.dbc(); s = conn.prepareStatement ("SELECT * FROM oracle_bans WHERE ip_id = ? AND unbanned = 0 LIMIT 1"); s.setInt(1, ipId); s.executeQuery(); rs = s.getResultSet(); if(rs.first()) { Builder builder = Ban.builder(); builder.reason(Text.of(rs.getString("reason"))); builder.type(BanTypes.IP); builder.address(address); ban = (Ban.Ip) builder.build(); } } catch (SQLException e) { e.printStackTrace(); } finally { if(rs != null) try { rs.close(); } catch (SQLException e) {} if(s != null) try { s.close(); } catch (SQLException e) {} if(conn != null) try { conn.close(); } catch (SQLException e) {} } return Optional.ofNullable(ban); } @Override public boolean isBanned(GameProfile profile) { return getBanFor(profile).isPresent(); } @Override public boolean isBanned(InetAddress address) { return getBanFor(address).isPresent(); } @Override public boolean pardon(GameProfile profile) { Connection conn = null; PreparedStatement s = null; PreparedStatement s2 = null; try { conn = Oracle.dbc(); // Insert/Get Player ID PluginPlayer pluginPlayer = PlayerIdentification.getOraclePlayer(profile.getUniqueId()); // @todo no way to determine CommandSource // https://github.com/SpongePowered/SpongeCommon/issues/436 int staffId = 0; // Add unban record s = conn.prepareStatement("INSERT INTO oracle_unbans (player_id, staff_player_id, epoch) VALUES (?, ?, ?)"); s.setInt(1, pluginPlayer.getId()); s.setInt(2, staffId); s.setLong(3, System.currentTimeMillis() / 1000L); s.executeUpdate(); // Mark as unbanned s2 = conn.prepareStatement("UPDATE oracle_bans SET unbanned = 1 WHERE player_id = ?"); s2.setInt(1, pluginPlayer.getId()); s2.executeUpdate(); } catch (SQLException e){ e.printStackTrace(); } finally { if(s != null) try { s.close(); } catch (SQLException e) {} if(s2 != null) try { s2.close(); } catch (SQLException e) {} if(conn != null) try { conn.close(); } catch (SQLException e) {} } // @todo fix this return true; } @Override public boolean pardon(InetAddress address) { Connection conn = null; PreparedStatement s = null; PreparedStatement s2 = null; try { conn = Oracle.dbc(); // Insert/Get Player ID int ipId = JoinUtil.lookupIp(address.getHostAddress()); // @todo no way to determine CommandSource // https://github.com/SpongePowered/SpongeCommon/issues/436 int staffId = 0; // Add unban record s = conn.prepareStatement("INSERT INTO oracle_unbans (ip_id, staff_player_id, epoch) VALUES (?, ?, ?)"); s.setInt(1, ipId); s.setInt(2, staffId); s.setLong(3, System.currentTimeMillis() / 1000L); s.executeUpdate(); // Mark as unbanned s2 = conn.prepareStatement("UPDATE oracle_bans SET unbanned = 1 WHERE ip_id = ?"); s2.setInt(1, ipId); s2.executeUpdate(); } catch (SQLException e){ e.printStackTrace(); } finally { if(s != null) try { s.close(); } catch (SQLException e) {} if(s2 != null) try { s2.close(); } catch (SQLException e) {} if(conn != null) try { conn.close(); } catch (SQLException e) {} } // @todo fix this return true; } @Override public boolean removeBan(Ban ban) { if (ban.getType().equals(BanTypes.PROFILE)) { return this.pardon(((Ban.Profile) ban).getProfile()); } else if (ban.getType().equals(BanTypes.IP)) { return this.pardon(((Ban.Ip) ban).getAddress()); } throw new IllegalArgumentException(String.format("Ban %s had unrecognized BanType %s!", ban, ban.getType())); } @Override public Optional<? extends Ban> addBan(Ban ban) { Connection conn = null; PreparedStatement s = null; int staffId = 0; if (ban.getBanCommandSource().isPresent()) { if (ban.getBanCommandSource().get() instanceof Player) { PluginPlayer staffPluginPlayer = PlayerIdentification.getOraclePlayer(((Player)ban.getBanCommandSource().get()).getUniqueId()); staffId = staffPluginPlayer.getId(); } } try { conn = Oracle.dbc(); String reason = ""; if (ban.getReason().isPresent()) { reason = ban.getReason().get().toPlain().toString(); } if (ban.getType().equals(BanTypes.PROFILE)) { Ban.Profile banProfile = (Ban.Profile) ban; PluginPlayer pluginPlayer = PlayerIdentification.getOraclePlayer(banProfile.getProfile().getUniqueId()); if (pluginPlayer != null) { s = conn.prepareStatement("INSERT INTO oracle_bans (player_id, staff_player_id, reason, epoch) VALUES (?, ?, ?, ?)"); s.setInt(1, pluginPlayer.getId()); s.setInt(2, staffId); s.setString(3, reason); s.setLong(4, System.currentTimeMillis() / 1000L); s.executeUpdate(); } } else if (ban.getType().equals(BanTypes.IP)) { Ban.Ip banIp = (Ban.Ip) ban; // Insert/Get IP ID int ipId = JoinUtil.lookupIp(banIp.getAddress().getHostAddress()); conn = Oracle.dbc(); s = conn.prepareStatement("INSERT INTO oracle_bans (ip_id, staff_player_id, reason, epoch) VALUES (?, ?, ?, ?)"); s.setInt(1, ipId); s.setInt(2, staffId); s.setString(3, reason); s.setLong(4, System.currentTimeMillis() / 1000L); s.executeUpdate(); } } catch (SQLException e){ e.printStackTrace(); } finally { if(s != null) try { s.close(); } catch (SQLException e) {} if(conn != null) try { conn.close(); } catch (SQLException e) {} } return Optional.empty(); } @Override public boolean hasBan(Ban ban) { if (ban.getType().equals(BanTypes.PROFILE)) { return this.isBanned(((Ban.Profile) ban).getProfile()); } else if (ban.getType().equals(BanTypes.IP)) { return this.isBanned(((Ban.Ip) ban).getAddress()); } throw new IllegalArgumentException(String.format("Ban %s had unrecognized BanType %s!", ban, ban.getType())); } }