/* * CommandBook * Copyright (C) 2011 sk89q <http://www.sk89q.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.sk89q.commandbook.bans; import com.sk89q.commandbook.CommandBook; import com.sk89q.commandbook.InfoComponent; import com.sk89q.commandbook.util.ChatUtil; import com.sk89q.commandbook.util.InputUtil; import com.sk89q.minecraft.util.commands.*; import com.zachsthings.libcomponents.ComponentInformation; import com.zachsthings.libcomponents.bukkit.BasePlugin; import com.zachsthings.libcomponents.bukkit.BukkitComponent; import com.zachsthings.libcomponents.config.ConfigurationBase; import com.zachsthings.libcomponents.config.Setting; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerLoginEvent; import java.net.InetAddress; import java.util.UUID; @ComponentInformation(friendlyName = "Bans", desc = "A system for kicks and bans.") public class BansComponent extends BukkitComponent implements Listener { private BanDatabase bans; private LocalConfiguration config; @Override public void enable() { config = configure(new LocalConfiguration()); // Setup the ban database bans = new CSVBanDatabase(CommandBook.inst().getDataFolder()); bans.load(); CommandBook.registerEvents(this); registerCommands(Commands.class); } @Override public void reload() { super.reload(); getBanDatabase().load(); configure(config); } @Override public void disable() { bans.unload(); } private static class LocalConfiguration extends ConfigurationBase { @Setting("message") public String banMessage = "You have been banned"; @Setting("broadcast-bans") public boolean broadcastBans; @Setting("broadcast-kicks") public boolean broadcastKicks; } /** * Get the ban database. * * @return */ public BanDatabase getBanDatabase() { return bans; } /** * Called on player login. * * @param event Relevant event details */ @EventHandler(priority = EventPriority.NORMAL) public void playerLogin(PlayerLoginEvent event) { Player player = event.getPlayer(); Ban ban = null; if (getBanDatabase().isBanned(player.getUniqueId())) { ban = getBanDatabase().getBanned(player.getUniqueId()); } else if (getBanDatabase().isBanned(event.getAddress())) { ban = getBanDatabase().getBanned(event.getAddress().getHostAddress()); } if (ban != null) { String reason = ban.getReason(); boolean hasReason = reason != null; String how = "You are " + (ban.getAddress() != null ? "IP " : "") + "banned" + (hasReason ? " for:" : "."); String end = "Expires: " + (ban.getEnd() == 0L ? ChatColor.DARK_RED + "Never" : ChatUtil.getFriendlyTime(ban.getEnd())); event.disallow(PlayerLoginEvent.Result.KICK_BANNED, how + (hasReason ? "\n" + reason : "") + "\n" + end); } } @EventHandler public void playerWhois(InfoComponent.PlayerWhoisEvent event) { if (CommandBook.inst().hasPermission(event.getSource(), "commandbook.bans.isbanned")) { event.addWhoisInformation(null, "Player " + (getBanDatabase().isBanned(event.getPlayer().getUniqueId()) ? "is" : "is not") + " banned."); } } public class Commands { @Command(aliases = {"kick"}, usage = "<target> [reason...]", desc = "Kick a user", flags = "os", min = 1, max = -1) @CommandPermissions({"commandbook.kick"}) public void kick(CommandContext args, CommandSender sender) throws CommandException { Iterable<Player> targets = InputUtil.PlayerParser.matchPlayers(sender, args.getString(0)); String message = args.argsLength() >= 2 ? args.getJoinedStrings(1) : "Kicked!"; String broadcastPlayers = ""; for (Player player : targets) { if (CommandBook.inst().hasPermission(player, "commandbook.kick.exempt") && !(args.hasFlag('o') && CommandBook.inst().hasPermission(sender, "commandbook.kick.exempt.override"))) { sender.sendMessage(ChatColor.RED + "Player " + player.getName() + ChatColor.RED + " is exempt from being kicked!"); continue; } player.kickPlayer(message); broadcastPlayers += ChatUtil.toColoredName(player, ChatColor.YELLOW) + " "; getBanDatabase().logKick(player, sender, message); } if (broadcastPlayers.length() > 0) { sender.sendMessage(ChatColor.YELLOW + "Player(s) kicked."); //Broadcast the Message if (config.broadcastKicks && !args.hasFlag('s')) { BasePlugin.server().broadcastMessage(ChatColor.YELLOW + ChatUtil.toColoredName(sender, ChatColor.YELLOW) + " has kicked " + broadcastPlayers + " - " + message); } } } @Command(aliases = {"ban"}, usage = "[-t end ] <target> [reason...]", desc = "Ban a user (and their address with the -i flag)", flags = "iset:o", min = 1, max = -1) @CommandPermissions({"commandbook.bans.ban"}) public void ban(CommandContext args, CommandSender sender) throws CommandException { UUID banID; String playerName = args.getString(0); InetAddress banAddress = null; long endDate = args.hasFlag('t') ? InputUtil.TimeParser.matchFutureDate(args.getFlag('t')) : 0L; String message = args.argsLength() >= 2 ? args.getJoinedStrings(1) : null; boolean kicked = false; final boolean hasExemptOverride = args.hasFlag('o') && CommandBook.inst().hasPermission(sender, "commandbook.bans.exempt.override"); Player player; // Exact mode matches names exactly try { if (args.hasFlag('e')) { player = InputUtil.PlayerParser.matchPlayerExactly(sender, playerName); } else { player = InputUtil.PlayerParser.matchSinglePlayer(sender, playerName); } } catch (CommandException ex) { player = null; } // Grab their UUID if (player == null) { banID = CommandBook.server().getOfflinePlayer(playerName).getUniqueId(); if (args.hasFlag('i')) { throw new CommandException("This player must be online to ban their IP address as well."); } } else { banID = player.getUniqueId(); if (CommandBook.inst().hasPermission(player, "commandbook.bans.exempt") && !hasExemptOverride) { throw new CommandException("This player is exempt from being banned! " + "(use -o flag to override if you have commandbook.bans.exempt.override)"); } kicked = true; // Need to kick & log if (args.hasFlag('i')) { CommandBook.inst().checkPermission(sender, "commandbook.bans.ban.ip"); banAddress = player.getAddress().getAddress(); for (Player aPlayer : CommandBook.server().getOnlinePlayers()) { if (aPlayer.getAddress().getAddress().equals(banAddress)) { player.kickPlayer(message == null ? "Banned!" : message); getBanDatabase().logKick(player, sender, message); } } } else { player.kickPlayer(message == null ? "Banned!" : message); getBanDatabase().logKick(player, sender, message); } } sender.sendMessage(ChatColor.YELLOW + playerName + " banned" + (!kicked ? "" : " and kicked") + '.'); // Broadcast the Message if (config.broadcastBans && !args.hasFlag('s')) { CommandBook.server().broadcastMessage(ChatColor.YELLOW + ChatUtil.toColoredName(sender, ChatColor.YELLOW) + " has banned " + playerName + (message == null ? "" : " - " + message)); } getBanDatabase().ban(banID, playerName, banAddress != null ? banAddress.getHostAddress() : null, sender, message, endDate); if (!getBanDatabase().save()) { sender.sendMessage(ChatColor.RED + "Bans database failed to save. See console."); } } @Command(aliases = {"banip", "ipban"}, usage = "<target> [reason...]", desc = "Ban an IP address", flags = "st:", min = 1, max = -1) @CommandPermissions({"commandbook.bans.ban.ip"}) public void banIP(CommandContext args, CommandSender sender) throws CommandException { String message = args.argsLength() >= 2 ? args.getJoinedStrings(1) : null; long endDate = args.hasFlag('t') ? InputUtil.TimeParser.matchFutureDate(args.getFlag('t')) : 0L; String addr = args.getString(0) .replace("\r", "") .replace("\n", "") .replace("\0", "") .replace("\b", ""); // Need to kick + log for (Player player : CommandBook.server().getOnlinePlayers()) { if (player.getAddress().getAddress().getHostAddress().equals(addr)) { player.kickPlayer(message == null ? "Banned!" : message); getBanDatabase().logKick(player, sender, message); } } getBanDatabase().ban(null, null, addr, sender, message, endDate); sender.sendMessage(ChatColor.YELLOW + addr + " banned."); if (!getBanDatabase().save()) { sender.sendMessage(ChatColor.RED + "Bans database failed to save. See console."); } } @Command(aliases = {"unban"}, usage = "<target>", desc = "Unban a user", min = 1, max = -1) @CommandPermissions({"commandbook.bans.unban"}) public void unban(CommandContext args, CommandSender sender) throws CommandException { String message = args.argsLength() >= 2 ? args.getJoinedStrings(1) : "Unbanned!"; String banName = args.getString(0) .replace("\r", "") .replace("\n", "") .replace("\0", "") .replace("\b", ""); UUID ID = CommandBook.server().getOfflinePlayer(banName).getUniqueId(); if (getBanDatabase().unban(ID, null, sender, message) || getBanDatabase().unbanName(banName, sender, message)) { sender.sendMessage(ChatColor.YELLOW + banName + " unbanned."); if (!getBanDatabase().save()) { sender.sendMessage(ChatColor.RED + "Bans database failed to save. See console."); } } else { sender.sendMessage(ChatColor.RED + banName + " was not banned."); } } @Command(aliases = {"unbanip", "unipban"}, usage = "<target> [reason...]", desc = "Unban an IP address", min = 1, max = -1) @CommandPermissions({"commandbook.bans.unban.ip"}) public void unbanIP(CommandContext args, CommandSender sender) throws CommandException { String addr = args.getString(0) .replace("\r", "") .replace("\n", "") .replace("\0", "") .replace("\b", ""); String message = args.argsLength() >= 2 ? args.getJoinedStrings(1) : "Unbanned!"; if (getBanDatabase().unban(null, addr, sender, message)) { sender.sendMessage(ChatColor.YELLOW + addr + " unbanned."); if (!getBanDatabase().save()) { sender.sendMessage(ChatColor.RED + "Bans database failed to save. See console."); } } else { sender.sendMessage(ChatColor.RED + addr + " was not banned."); } } @Command(aliases = {"baninfo", "isbanned"}, usage = "<target>", desc = "Check if a user is banned", min = 1, max = 1) @CommandPermissions({"commandbook.bans.isbanned", "commandbook.bans.baninfo"}) public void banInfo(CommandContext args, CommandSender sender) throws CommandException { String banName = args.getString(0) .replace("\r", "") .replace("\n", "") .replace("\0", "") .replace("\b", ""); UUID ID = CommandBook.server().getOfflinePlayer(banName).getUniqueId(); Ban ban = getBanDatabase().getBanned(ID); if (ban == null) { sender.sendMessage(ChatColor.YELLOW + banName + " is " + ChatColor.RED + "not " + ChatColor.YELLOW + "banned."); } else { String add = ban.getAddress() == null ? "" : " (Address: " + ban.getAddress() + ")"; sender.sendMessage(ChatColor.YELLOW + banName + add + ChatColor.RED + " is" + ChatColor.YELLOW + " banned."); if (!CommandBook.inst().hasPermission(sender, "commandbook.bans.baninfo")) return; sender.sendMessage(ChatColor.YELLOW + "Duration: " + (ban.getEnd() == 0L ? "Indefinite" : "Until " + ChatUtil.getFriendlyTime(ban.getEnd()))); if (ban.getReason() != null) { sender.sendMessage(ChatColor.YELLOW + "Reason: " + ban.getReason()); } } } @Command(aliases = {"bans"}, desc = "Ban management") @NestedCommand({ManagementCommands.class}) public void bans() throws CommandException { } } public class ManagementCommands { @Command(aliases = {"load", "reload", "read"}, usage = "", desc = "Reload bans from disk", min = 0, max = 0) @CommandPermissions({"commandbook.bans.load"}) public void loadBans(CommandContext args, CommandSender sender) throws CommandException { if (getBanDatabase().load()) { sender.sendMessage(ChatColor.YELLOW + "Bans database reloaded."); } else { throw new CommandException("Bans database failed to load entirely. See server console."); } } @Command(aliases = {"save", "write"}, usage = "", desc = "Save bans to disk", min = 0, max = 0) @CommandPermissions({"commandbook.bans.save"}) public void saveBans(CommandContext args, CommandSender sender) throws CommandException { if (getBanDatabase().save()) { sender.sendMessage(ChatColor.YELLOW + "Bans database saved."); } else { throw new CommandException("Bans database failed to save entirely. See server console."); } } } }