-
-
Save xaoseric/3a04d2425d845f960f7d2f0b039ba194 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.devoteduhc.uhc.ubl; | |
import java.util.HashMap; | |
import java.util.Map; | |
import java.util.UUID; | |
public class BanEntry { | |
private Map<String, String> data = new HashMap<>(); | |
private String ign; | |
private UUID uuid; | |
/** | |
* Creates a new BanEntry from a list of pre-parsed field names, used to | |
* store record values by field name, and a raw CSV record | |
* | |
* @param fieldNames A pre-parsed array of field names | |
* @param rawCSV A raw CSV record | |
*/ | |
public BanEntry(UBL ubl, String[] fieldNames, String rawCSV) { | |
String[] parts = ubl.parseLine(rawCSV); | |
if (parts.length != fieldNames.length) { | |
throw new IllegalArgumentException("Expected " + fieldNames.length + " columns: " + rawCSV); | |
} | |
for (int i = 0; i < fieldNames.length; i++) { | |
data.put(fieldNames[i], parts[i]); | |
} | |
} | |
/** | |
* Set the value of the in-game name for this player | |
* | |
* @param ign The player's in-game name | |
*/ | |
public void setIgn(String ign) { | |
this.ign = ign; | |
} | |
/** | |
* Set the value of the universally unique identifier for this player | |
* | |
* @param uuid The player's UUID | |
*/ | |
public void setUUID(UUID uuid) { | |
this.uuid = uuid; | |
} | |
/** | |
* @return The player's in-game name | |
*/ | |
public String getIgn() { | |
return ign; | |
} | |
/** | |
* @return The player's universally unique identifier | |
*/ | |
public UUID getUUID() { | |
return uuid; | |
} | |
/** | |
* @param fieldName The field name to retrieve a value of | |
* @return The value of the given field | |
*/ | |
public String getData(String fieldName) { | |
return data.get(fieldName); | |
} | |
/** | |
* Sets the value of a given field | |
* | |
* @param fieldName The field name to set a value for | |
* @param value The value to set for this field | |
*/ | |
public void setData(String fieldName, String value) { | |
data.put(fieldName, value); | |
} | |
/** | |
* Get a map of all data in this ban entry. | |
* | |
* @return The data map. | |
*/ | |
public Map<String, String> getData() { | |
return data; | |
} | |
@Override | |
public boolean equals(Object obj) { | |
if (obj == this) { | |
return true; | |
} | |
if (obj instanceof BanEntry) { | |
BanEntry other = (BanEntry) obj; | |
if (other.uuid != null && uuid != null) { | |
return other.uuid.equals(uuid); | |
} | |
return other.ign.equalsIgnoreCase(ign); | |
} | |
return false; | |
} | |
@Override | |
public int hashCode() { | |
if (uuid != null) { | |
return uuid.hashCode(); | |
} else { | |
return ign.hashCode(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.devoteduhc.uhc.ubl; | |
import java.io.BufferedReader; | |
import java.io.BufferedWriter; | |
import java.io.File; | |
import java.io.FileReader; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.net.HttpURLConnection; | |
import java.net.MalformedURLException; | |
import java.net.URL; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.UUID; | |
import java.util.logging.Level; | |
import org.bukkit.Bukkit; | |
import org.bukkit.entity.Player; | |
import org.bukkit.scheduler.BukkitRunnable; | |
import org.bukkit.scheduler.BukkitTask; | |
import com.devoteduhc.uhc.UHCPlugin; | |
public class UBL implements Runnable { | |
private final UHCPlugin plugin; | |
private static final String BANLIST_URL = "https://docs.google.com/spreadsheet/ccc?key=0AjACyg1Jc3_GdEhqWU5PTEVHZDVLYWphd2JfaEZXd2c&output=csv"; | |
private static final int RETRIES = 3; | |
private static final int MAX_BANDWIDTH = 64; | |
private static final int BUFFER_SIZE = (MAX_BANDWIDTH * 1024) / 20; | |
private static final int TIMEOUT = 120; | |
private Map<UUID, BanEntry> banlist; | |
private BukkitTask autoChecker; | |
/** | |
* UBL class constructor. | |
* | |
* @param plugin The plugin. | |
*/ | |
public UBL(UHCPlugin plugin) { | |
this.plugin = plugin; | |
} | |
/** | |
* Get the ban entry for the given UUID. | |
* | |
* @param uuid The uuid to get for. | |
* @return The ban entry, null if none. | |
*/ | |
public BanEntry getBanEntry(UUID uuid) { | |
return banlist.get(uuid); | |
} | |
@Override | |
public void run() { | |
URL url; | |
String data; | |
BufferedReader in; | |
try { | |
url = new URL(BANLIST_URL); | |
HttpURLConnection con = (HttpURLConnection) url.openConnection(); | |
con.setInstanceFollowRedirects(false); | |
con.setConnectTimeout(TIMEOUT * 1000); | |
con.setReadTimeout(TIMEOUT * 1000); | |
con.addRequestProperty("Accept-Language", "en-US,en;q=0.8"); | |
con.addRequestProperty("User-Agent", "Mozilla"); | |
con.addRequestProperty("Referer", "google.com"); | |
boolean found = false; | |
int tries = 0; | |
StringBuilder cookies = new StringBuilder(); | |
while (!found) { | |
int status = con.getResponseCode(); | |
if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM || status == HttpURLConnection.HTTP_SEE_OTHER) { | |
String newUrl = con.getHeaderField("Location"); | |
String headerName; | |
for (int i = 1; (headerName = con.getHeaderFieldKey(i)) != null; i++) { | |
if (headerName.equals("Set-Cookie")) { | |
String newCookie = con.getHeaderField(i); | |
newCookie = newCookie.substring(0, newCookie.indexOf(";")); | |
String cookieName = newCookie.substring(0, newCookie.indexOf("=")); | |
String cookieValue = newCookie.substring(newCookie.indexOf("=") + 1, newCookie.length()); | |
if (cookies.length() != 0) { | |
cookies.append("; "); | |
} | |
cookies.append(cookieName).append("=").append(cookieValue); | |
} | |
} | |
con = (HttpURLConnection) new URL(newUrl).openConnection(); | |
con.setInstanceFollowRedirects(false); | |
con.setRequestProperty("Cookie", cookies.toString()); | |
con.setConnectTimeout(TIMEOUT * 1000); | |
con.setReadTimeout(TIMEOUT * 1000); | |
con.addRequestProperty("Accept-Language", "en-US,en;q=0.8"); | |
con.addRequestProperty("User-Agent", "Mozilla"); | |
con.addRequestProperty("Referer", "google.com"); | |
} | |
else if (status == HttpURLConnection.HTTP_OK) { | |
found = true; | |
} | |
else { | |
tries++; | |
if (tries >= RETRIES) { | |
throw new IOException("Failed to reach " + url.getHost() + " after " + RETRIES + " attempts"); | |
} | |
} | |
} | |
in = new BufferedReader(new InputStreamReader(con.getInputStream()), BUFFER_SIZE); | |
try { | |
data = downloadBanlist(in, BUFFER_SIZE, TIMEOUT * 20); | |
plugin.getLogger().info("UBL has been updated."); | |
for (Player online : Bukkit.getOnlinePlayers()) { | |
if (!isBanned(online.getUniqueId())) { | |
continue; | |
} | |
online.kickPlayer(getBanMessage(online.getUniqueId())); | |
} | |
} catch (IOException ex) { | |
plugin.getLogger().severe("Connection was interrupted while downloading banlist from " + BANLIST_URL); | |
data = loadFromBackup(); | |
for (Player online : Bukkit.getOnlinePlayers()) { | |
if (!isBanned(online.getUniqueId())) { | |
continue; | |
} | |
online.kickPlayer(getBanMessage(online.getUniqueId())); | |
} | |
} catch (InterruptedException ex) { | |
plugin.getLogger().log(Level.SEVERE, "Timed out while waiting for banlist server to send data", ex); | |
data = loadFromBackup(); | |
for (Player online : Bukkit.getOnlinePlayers()) { | |
if (!isBanned(online.getUniqueId())) { | |
continue; | |
} | |
online.kickPlayer(getBanMessage(online.getUniqueId())); | |
} | |
} | |
saveToBackup(data); | |
} catch (MalformedURLException ex) { | |
plugin.getLogger().severe("banlist-url in the config.yml is invalid or corrupt. This must be corrected and the config reloaded before the UBL can be updated"); | |
data = loadFromBackup(); | |
for (Player online : Bukkit.getOnlinePlayers()) { | |
if (!isBanned(online.getUniqueId())) { | |
continue; | |
} | |
online.kickPlayer(getBanMessage(online.getUniqueId())); | |
} | |
} catch (IOException ex) { | |
plugin.getLogger().warning("Banlist server " + BANLIST_URL + " is currently unreachable"); | |
data = loadFromBackup(); | |
for (Player online : Bukkit.getOnlinePlayers()) { | |
if (!isBanned(online.getUniqueId())) { | |
continue; | |
} | |
online.kickPlayer(getBanMessage(online.getUniqueId())); | |
} | |
} | |
parseData(data); | |
} | |
/** | |
* Reload configuration settings and update the banlist | |
*/ | |
public void reload() { | |
cancel(); | |
reloadConfigAsync(new BukkitRunnable() { | |
public void run() { | |
plugin.getLogger().info("Checking UBL for updates..."); | |
int autoCheckInterval = 60; | |
schedule(autoCheckInterval); | |
updateBanlist(); | |
} | |
}); | |
} | |
/** | |
* Load the configuration file asynchronously, and run a task when it is | |
* completed | |
* | |
* @param notifier The task to be run | |
*/ | |
public void reloadConfigAsync(BukkitRunnable notifier) { | |
new BukkitRunnable() { | |
private BukkitRunnable notifier; | |
public BukkitRunnable setNotifier(BukkitRunnable notifier) { | |
this.notifier = notifier; | |
return this; | |
} | |
@Override | |
public void run() { | |
notifier.runTask(plugin); | |
} | |
}.setNotifier(notifier).runTaskAsynchronously(plugin); | |
} | |
/** | |
* Attempt to update the banlist immediately | |
*/ | |
public void updateBanlist() { | |
download(); | |
} | |
/** | |
* Check if the given player is banned on the UBL and is not exempt on this | |
* server | |
* | |
* @param uuid The universally unique identifier of the player to check | |
* @return True, if the player is banned and not exempt, otherwise false | |
*/ | |
public boolean isBanned(UUID uuid) { | |
if (banlist != null) { | |
return banlist.containsKey(uuid); | |
} | |
return false; | |
} | |
/** | |
* @param uuid The universally unique identifier of the banned player | |
* @return A personalised ban message for this player | |
*/ | |
public String getBanMessage(UUID uuid) { | |
BanEntry banEntry = banlist.get(uuid); | |
if (banEntry == null) { | |
return "Not on the UBL"; | |
} | |
return "&8» &7You have been &4UBL'ed &7from &6/r/ultrahardcore &8«" + | |
"\n" + | |
"\n&cReason &8» &7" + banEntry.getData("Reason") + | |
"\n&cBan length &8» &7" + banEntry.getData("Length of Ban") + | |
"\n&cCase post &8» &7" + banEntry.getData("Case"); | |
} | |
/** | |
* Parse things. | |
* | |
* @param line The line to parse. | |
* @return The parsed line. | |
*/ | |
public String[] parseLine(String line) { | |
List<String> fields = new ArrayList<String>(); | |
StringBuilder sb = new StringBuilder(); | |
for (int i = 0; i < line.length(); i++) { | |
char c = line.charAt(i); | |
if (c == ',') { | |
fields.add(sb.toString()); | |
sb = new StringBuilder(); | |
} else if (c == '"') { | |
int ends = line.indexOf('"', i + 1); | |
if (ends == -1) { | |
throw new IllegalArgumentException("Expected double-quote to terminate (" + i + "): " + line); | |
} | |
sb.append(line.substring(i + 1, ends - 1)); | |
i = ends; | |
} else { | |
sb.append(c); | |
} | |
} | |
fields.add(sb.toString()); | |
return fields.toArray(new String[fields.size()]); | |
} | |
/** | |
* Update the entire ban-list using raw CSV lines, overwriting any previous | |
* settings | |
* | |
* @param bans The new ban-list | |
*/ | |
public void setBanList(String fieldNamesCSV, List<String> bans) { | |
String[] fieldNames = parseLine(fieldNamesCSV); | |
if (!Arrays.asList(fieldNames).contains("IGN") && !Arrays.asList(fieldNames).contains("UUID")) { | |
plugin.getLogger().warning("The ubl commitee fucked up the google doc, go spam to fix it :D"); | |
} | |
banlist = new HashMap<UUID, BanEntry>(); | |
for (String rawCSV : bans) { | |
BanEntry banEntry = new BanEntry(this, fieldNames, rawCSV); | |
String ign = banEntry.getData("IGN"); | |
if (ign != null) { | |
banEntry.setIgn(ign); | |
} | |
String uuidString = banEntry.getData("UUID").trim(); | |
if (uuidString == null) { | |
return; | |
} | |
if (uuidString.length() == 32) { | |
StringBuilder sb = new StringBuilder(); | |
sb.append(uuidString.substring(0, 8)).append('-'); | |
sb.append(uuidString.substring(8, 12)).append('-'); | |
sb.append(uuidString.substring(12, 16)).append('-'); | |
sb.append(uuidString.substring(16, 20)).append('-'); | |
sb.append(uuidString.substring(20, 32)); | |
uuidString = sb.toString(); | |
} | |
if (uuidString.length() == 36) { | |
UUID uuid = UUID.fromString(uuidString); | |
banlist.put(uuid, banEntry); | |
banEntry.setUUID(uuid); | |
} | |
} | |
} | |
/** | |
* Schedule regular updates | |
* | |
* @param interval How often to update in minutes | |
*/ | |
public void schedule(int interval) { | |
int ticks = interval * 1200; | |
cancel(); | |
autoChecker = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, ticks, ticks); | |
} | |
/** | |
* Schedule an immediate update | |
*/ | |
public void download() { | |
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, this); | |
} | |
/** | |
* Stop the regular updater | |
*/ | |
public void cancel() { | |
if (autoChecker != null) { | |
autoChecker.cancel(); | |
autoChecker = null; | |
} | |
} | |
/** | |
* Attempt to download the ban-list from the given stream within the specified time limit. | |
* | |
* @param in The input stream | |
* @param bufferSize The size of the data buffer in bytes | |
* @param timeout The time limit in server ticks | |
* @return The raw data | |
* @throws IOException The connection errored or was terminated | |
* @throws InterruptedException The time limit was exceeded | |
*/ | |
private String downloadBanlist(BufferedReader in, int bufferSize, int timeout) throws IOException, InterruptedException { | |
final Thread iothread = Thread.currentThread(); | |
BukkitTask timer = new BukkitRunnable() { | |
public void run() { | |
iothread.interrupt(); | |
} | |
}.runTaskLaterAsynchronously(plugin, timeout); | |
try { | |
char[] buffer = new char[bufferSize]; | |
StringBuilder builder = new StringBuilder(); | |
while (true) { | |
int bytesRead = in.read(buffer); | |
if (bytesRead == -1) { | |
return builder.toString(); | |
} | |
builder.append(buffer, 0, bytesRead); | |
Thread.sleep(50); | |
} | |
} finally { | |
timer.cancel(); | |
} | |
} | |
/** | |
* Parse some data. | |
* | |
* @param data The data parsing. | |
*/ | |
private void parseData(final String data) { | |
new BukkitRunnable() { | |
public void run() { | |
String[] lines = data.split("\\r?\\n"); | |
if (lines.length < 2) { | |
plugin.getLogger().warning("Banlist is empty!"); | |
return; | |
} | |
setBanList(lines[0], Arrays.asList(Arrays.copyOfRange(lines, 1, lines.length))); | |
} | |
}.runTask(plugin); | |
} | |
/** | |
* Load raw ban-list from the backup file, if it exists. | |
* | |
* If there are any problems, return an empty string | |
* | |
* @return The raw ban-list, or an empty string | |
*/ | |
public String loadFromBackup() { | |
File file = new File(plugin.getDataFolder(), "ubl.backup"); | |
if (!file.exists()) { | |
plugin.getLogger().severe("The backup file could not be located. You are running without UBL protection!"); | |
return ""; | |
} | |
try (BufferedReader in = new BufferedReader(new FileReader(file))) { | |
StringBuilder sb = new StringBuilder(); | |
char[] buffer = new char[8192]; | |
while (true) { | |
int bytesRead = in.read(buffer); | |
if (bytesRead == -1) { | |
break; | |
} | |
sb.append(buffer, 0, bytesRead); | |
} | |
plugin.getLogger().info("UBL loaded from local backup"); | |
return sb.toString(); | |
} catch (Exception ex) { | |
plugin.getLogger().log(Level.SEVERE, "Could not load UBL backup. You are running without UBL protection!", ex); | |
return ""; | |
} | |
} | |
/** | |
* Save the raw ban-list data to the backup file | |
* | |
* This should not be run on the main server thread | |
* | |
* @param data The raw ban-list data | |
*/ | |
public void saveToBackup(String data) { | |
File file = new File(plugin.getDataFolder(), "ubl.backup"); | |
try (BufferedWriter out = new BufferedWriter(new FileWriter(file))) { | |
out.write(data); | |
} catch (IOException ex) { | |
plugin.getLogger().log(Level.SEVERE, "Failed to save UBL backup", ex); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.devoteduhc.uhc.ubl; | |
import java.util.UUID; | |
import org.bukkit.Bukkit; | |
import org.bukkit.event.EventHandler; | |
import org.bukkit.event.EventPriority; | |
import org.bukkit.event.Listener; | |
import org.bukkit.event.player.AsyncPlayerPreLoginEvent; | |
import org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result; | |
public class UBLListener implements Listener { | |
private final UBL ubl; | |
public UBLListener(UBL ubl) { | |
this.ubl = ubl; | |
} | |
@EventHandler(priority = EventPriority.HIGHEST) | |
public void on(AsyncPlayerPreLoginEvent event) { | |
UUID uuid = event.getUniqueId(); | |
if (!ubl.isBanned(uuid)) { | |
return; | |
} | |
BanEntry entry = ubl.getBanEntry(uuid); | |
if (entry == null) { | |
return; // shouldn't happen but incase... | |
} | |
Bukkit.getLogger().info(event.getName() + " §7tried to join while being UBL'ed for: §c" + entry.getData("Reason")); | |
event.disallow(Result.KICK_BANNED, ubl.getBanMessage(uuid)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.devoteduhc.uhc.managers; | |
import com.devoteduhc.uhc.UHCPlugin; | |
import com.devoteduhc.uhc.ubl.UBL; | |
import com.devoteduhc.uhc.ubl.UBLListener; | |
import lombok.Getter; | |
import lombok.Setter; | |
import org.bukkit.event.HandlerList; | |
public class UBLManager { | |
private UHCPlugin plugin; | |
@Getter | |
@Setter | |
private UBL ubl; | |
@Getter | |
@Setter | |
private UBLListener ublListener; | |
public UBLManager(UHCPlugin plugin) { | |
this.plugin = plugin; | |
// register ubl and listener | |
ubl = new UBL(this.plugin); | |
ublListener = new UBLListener(ubl); | |
} | |
public void enable() { | |
// enable ubl | |
ubl.reload(); | |
// register ubl listener | |
plugin.getServer().getPluginManager().registerEvents(ublListener, plugin); | |
} | |
public void disable() { | |
// cancel ubl runnable | |
ubl.cancel(); | |
// unregister ubl listener | |
HandlerList.unregisterAll(ublListener); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.devoteduhc.uhc.ubl; | |
import java.io.BufferedReader; | |
import java.io.BufferedWriter; | |
import java.io.File; | |
import java.io.FileReader; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.io.InputStreamReader; | |
import java.net.HttpURLConnection; | |
import java.net.MalformedURLException; | |
import java.net.URL; | |
import java.util.ArrayList; | |
import java.util.Arrays; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.UUID; | |
import java.util.logging.Level; | |
import org.bukkit.Bukkit; | |
import org.bukkit.entity.Player; | |
import org.bukkit.scheduler.BukkitRunnable; | |
import org.bukkit.scheduler.BukkitTask; | |
import com.devoteduhc.uhc.UHCPlugin; | |
public class UBL implements Runnable { | |
private final UHCPlugin plugin; | |
private static final String BANLIST_URL = "https://docs.google.com/spreadsheet/ccc?key=0AjACyg1Jc3_GdEhqWU5PTEVHZDVLYWphd2JfaEZXd2c&output=csv"; | |
private static final int RETRIES = 3; | |
private static final int MAX_BANDWIDTH = 64; | |
private static final int BUFFER_SIZE = (MAX_BANDWIDTH * 1024) / 20; | |
private static final int TIMEOUT = 120; | |
private Map<UUID, BanEntry> banlist; | |
private BukkitTask autoChecker; | |
/** | |
* UBL class constructor. | |
* | |
* @param plugin The plugin. | |
*/ | |
public UBL(UHCPlugin plugin) { | |
this.plugin = plugin; | |
} | |
/** | |
* Get the ban entry for the given UUID. | |
* | |
* @param uuid The uuid to get for. | |
* @return The ban entry, null if none. | |
*/ | |
public BanEntry getBanEntry(UUID uuid) { | |
return banlist.get(uuid); | |
} | |
@Override | |
public void run() { | |
URL url; | |
String data; | |
BufferedReader in; | |
try { | |
url = new URL(BANLIST_URL); | |
HttpURLConnection con = (HttpURLConnection) url.openConnection(); | |
con.setInstanceFollowRedirects(false); | |
con.setConnectTimeout(TIMEOUT * 1000); | |
con.setReadTimeout(TIMEOUT * 1000); | |
con.addRequestProperty("Accept-Language", "en-US,en;q=0.8"); | |
con.addRequestProperty("User-Agent", "Mozilla"); | |
con.addRequestProperty("Referer", "google.com"); | |
boolean found = false; | |
int tries = 0; | |
StringBuilder cookies = new StringBuilder(); | |
while (!found) { | |
int status = con.getResponseCode(); | |
if (status == HttpURLConnection.HTTP_MOVED_TEMP || status == HttpURLConnection.HTTP_MOVED_PERM || status == HttpURLConnection.HTTP_SEE_OTHER) { | |
String newUrl = con.getHeaderField("Location"); | |
String headerName; | |
for (int i = 1; (headerName = con.getHeaderFieldKey(i)) != null; i++) { | |
if (headerName.equals("Set-Cookie")) { | |
String newCookie = con.getHeaderField(i); | |
newCookie = newCookie.substring(0, newCookie.indexOf(";")); | |
String cookieName = newCookie.substring(0, newCookie.indexOf("=")); | |
String cookieValue = newCookie.substring(newCookie.indexOf("=") + 1, newCookie.length()); | |
if (cookies.length() != 0) { | |
cookies.append("; "); | |
} | |
cookies.append(cookieName).append("=").append(cookieValue); | |
} | |
} | |
con = (HttpURLConnection) new URL(newUrl).openConnection(); | |
con.setInstanceFollowRedirects(false); | |
con.setRequestProperty("Cookie", cookies.toString()); | |
con.setConnectTimeout(TIMEOUT * 1000); | |
con.setReadTimeout(TIMEOUT * 1000); | |
con.addRequestProperty("Accept-Language", "en-US,en;q=0.8"); | |
con.addRequestProperty("User-Agent", "Mozilla"); | |
con.addRequestProperty("Referer", "google.com"); | |
} | |
else if (status == HttpURLConnection.HTTP_OK) { | |
found = true; | |
} | |
else { | |
tries++; | |
if (tries >= RETRIES) { | |
throw new IOException("Failed to reach " + url.getHost() + " after " + RETRIES + " attempts"); | |
} | |
} | |
} | |
in = new BufferedReader(new InputStreamReader(con.getInputStream()), BUFFER_SIZE); | |
try { | |
data = downloadBanlist(in, BUFFER_SIZE, TIMEOUT * 20); | |
plugin.getLogger().info("UBL has been updated."); | |
for (Player online : Bukkit.getOnlinePlayers()) { | |
if (!isBanned(online.getUniqueId())) { | |
continue; | |
} | |
online.kickPlayer(getBanMessage(online.getUniqueId())); | |
} | |
} catch (IOException ex) { | |
plugin.getLogger().severe("Connection was interrupted while downloading banlist from " + BANLIST_URL); | |
data = loadFromBackup(); | |
for (Player online : Bukkit.getOnlinePlayers()) { | |
if (!isBanned(online.getUniqueId())) { | |
continue; | |
} | |
online.kickPlayer(getBanMessage(online.getUniqueId())); | |
} | |
} catch (InterruptedException ex) { | |
plugin.getLogger().log(Level.SEVERE, "Timed out while waiting for banlist server to send data", ex); | |
data = loadFromBackup(); | |
for (Player online : Bukkit.getOnlinePlayers()) { | |
if (!isBanned(online.getUniqueId())) { | |
continue; | |
} | |
online.kickPlayer(getBanMessage(online.getUniqueId())); | |
} | |
} | |
saveToBackup(data); | |
} catch (MalformedURLException ex) { | |
plugin.getLogger().severe("banlist-url in the config.yml is invalid or corrupt. This must be corrected and the config reloaded before the UBL can be updated"); | |
data = loadFromBackup(); | |
for (Player online : Bukkit.getOnlinePlayers()) { | |
if (!isBanned(online.getUniqueId())) { | |
continue; | |
} | |
online.kickPlayer(getBanMessage(online.getUniqueId())); | |
} | |
} catch (IOException ex) { | |
plugin.getLogger().warning("Banlist server " + BANLIST_URL + " is currently unreachable"); | |
data = loadFromBackup(); | |
for (Player online : Bukkit.getOnlinePlayers()) { | |
if (!isBanned(online.getUniqueId())) { | |
continue; | |
} | |
online.kickPlayer(getBanMessage(online.getUniqueId())); | |
} | |
} | |
parseData(data); | |
} | |
/** | |
* Reload configuration settings and update the banlist | |
*/ | |
public void reload() { | |
cancel(); | |
reloadConfigAsync(new BukkitRunnable() { | |
public void run() { | |
plugin.getLogger().info("Checking UBL for updates..."); | |
int autoCheckInterval = 60; | |
schedule(autoCheckInterval); | |
updateBanlist(); | |
} | |
}); | |
} | |
/** | |
* Load the configuration file asynchronously, and run a task when it is | |
* completed | |
* | |
* @param notifier The task to be run | |
*/ | |
public void reloadConfigAsync(BukkitRunnable notifier) { | |
new BukkitRunnable() { | |
private BukkitRunnable notifier; | |
public BukkitRunnable setNotifier(BukkitRunnable notifier) { | |
this.notifier = notifier; | |
return this; | |
} | |
@Override | |
public void run() { | |
notifier.runTask(plugin); | |
} | |
}.setNotifier(notifier).runTaskAsynchronously(plugin); | |
} | |
/** | |
* Attempt to update the banlist immediately | |
*/ | |
public void updateBanlist() { | |
download(); | |
} | |
/** | |
* Check if the given player is banned on the UBL and is not exempt on this | |
* server | |
* | |
* @param uuid The universally unique identifier of the player to check | |
* @return True, if the player is banned and not exempt, otherwise false | |
*/ | |
public boolean isBanned(UUID uuid) { | |
if (banlist != null) { | |
return banlist.containsKey(uuid); | |
} | |
return false; | |
} | |
/** | |
* @param uuid The universally unique identifier of the banned player | |
* @return A personalised ban message for this player | |
*/ | |
public String getBanMessage(UUID uuid) { | |
BanEntry banEntry = banlist.get(uuid); | |
if (banEntry == null) { | |
return "Not on the UBL"; | |
} | |
return "&8» &7You have been &4UBL'ed &7from &6/r/ultrahardcore &8«" + | |
"\n" + | |
"\n&cReason &8» &7" + banEntry.getData("Reason") + | |
"\n&cBan length &8» &7" + banEntry.getData("Length of Ban") + | |
"\n&cCase post &8» &7" + banEntry.getData("Case"); | |
} | |
/** | |
* Parse things. | |
* | |
* @param line The line to parse. | |
* @return The parsed line. | |
*/ | |
public String[] parseLine(String line) { | |
List<String> fields = new ArrayList<String>(); | |
StringBuilder sb = new StringBuilder(); | |
for (int i = 0; i < line.length(); i++) { | |
char c = line.charAt(i); | |
if (c == ',') { | |
fields.add(sb.toString()); | |
sb = new StringBuilder(); | |
} else if (c == '"') { | |
int ends = line.indexOf('"', i + 1); | |
if (ends == -1) { | |
throw new IllegalArgumentException("Expected double-quote to terminate (" + i + "): " + line); | |
} | |
sb.append(line.substring(i + 1, ends - 1)); | |
i = ends; | |
} else { | |
sb.append(c); | |
} | |
} | |
fields.add(sb.toString()); | |
return fields.toArray(new String[fields.size()]); | |
} | |
/** | |
* Update the entire ban-list using raw CSV lines, overwriting any previous | |
* settings | |
* | |
* @param bans The new ban-list | |
*/ | |
public void setBanList(String fieldNamesCSV, List<String> bans) { | |
String[] fieldNames = parseLine(fieldNamesCSV); | |
if (!Arrays.asList(fieldNames).contains("IGN") && !Arrays.asList(fieldNames).contains("UUID")) { | |
plugin.getLogger().warning("The ubl commitee fucked up the google doc, go spam to fix it :D"); | |
} | |
banlist = new HashMap<UUID, BanEntry>(); | |
for (String rawCSV : bans) { | |
BanEntry banEntry = new BanEntry(this, fieldNames, rawCSV); | |
String ign = banEntry.getData("IGN"); | |
if (ign != null) { | |
banEntry.setIgn(ign); | |
} | |
String uuidString = banEntry.getData("UUID").trim(); | |
if (uuidString == null) { | |
return; | |
} | |
if (uuidString.length() == 32) { | |
StringBuilder sb = new StringBuilder(); | |
sb.append(uuidString.substring(0, 8)).append('-'); | |
sb.append(uuidString.substring(8, 12)).append('-'); | |
sb.append(uuidString.substring(12, 16)).append('-'); | |
sb.append(uuidString.substring(16, 20)).append('-'); | |
sb.append(uuidString.substring(20, 32)); | |
uuidString = sb.toString(); | |
} | |
if (uuidString.length() == 36) { | |
UUID uuid = UUID.fromString(uuidString); | |
banlist.put(uuid, banEntry); | |
banEntry.setUUID(uuid); | |
} | |
} | |
} | |
/** | |
* Schedule regular updates | |
* | |
* @param interval How often to update in minutes | |
*/ | |
public void schedule(int interval) { | |
int ticks = interval * 1200; | |
cancel(); | |
autoChecker = plugin.getServer().getScheduler().runTaskTimerAsynchronously(plugin, this, ticks, ticks); | |
} | |
/** | |
* Schedule an immediate update | |
*/ | |
public void download() { | |
plugin.getServer().getScheduler().runTaskAsynchronously(plugin, this); | |
} | |
/** | |
* Stop the regular updater | |
*/ | |
public void cancel() { | |
if (autoChecker != null) { | |
autoChecker.cancel(); | |
autoChecker = null; | |
} | |
} | |
/** | |
* Attempt to download the ban-list from the given stream within the specified time limit. | |
* | |
* @param in The input stream | |
* @param bufferSize The size of the data buffer in bytes | |
* @param timeout The time limit in server ticks | |
* @return The raw data | |
* @throws IOException The connection errored or was terminated | |
* @throws InterruptedException The time limit was exceeded | |
*/ | |
private String downloadBanlist(BufferedReader in, int bufferSize, int timeout) throws IOException, InterruptedException { | |
final Thread iothread = Thread.currentThread(); | |
BukkitTask timer = new BukkitRunnable() { | |
public void run() { | |
iothread.interrupt(); | |
} | |
}.runTaskLaterAsynchronously(plugin, timeout); | |
try { | |
char[] buffer = new char[bufferSize]; | |
StringBuilder builder = new StringBuilder(); | |
while (true) { | |
int bytesRead = in.read(buffer); | |
if (bytesRead == -1) { | |
return builder.toString(); | |
} | |
builder.append(buffer, 0, bytesRead); | |
Thread.sleep(50); | |
} | |
} finally { | |
timer.cancel(); | |
} | |
} | |
/** | |
* Parse some data. | |
* | |
* @param data The data parsing. | |
*/ | |
private void parseData(final String data) { | |
new BukkitRunnable() { | |
public void run() { | |
String[] lines = data.split("\\r?\\n"); | |
if (lines.length < 2) { | |
plugin.getLogger().warning("Banlist is empty!"); | |
return; | |
} | |
setBanList(lines[0], Arrays.asList(Arrays.copyOfRange(lines, 1, lines.length))); | |
} | |
}.runTask(plugin); | |
} | |
/** | |
* Load raw ban-list from the backup file, if it exists. | |
* | |
* If there are any problems, return an empty string | |
* | |
* @return The raw ban-list, or an empty string | |
*/ | |
public String loadFromBackup() { | |
File file = new File(plugin.getDataFolder(), "ubl.backup"); | |
if (!file.exists()) { | |
plugin.getLogger().severe("The backup file could not be located. You are running without UBL protection!"); | |
return ""; | |
} | |
try (BufferedReader in = new BufferedReader(new FileReader(file))) { | |
StringBuilder sb = new StringBuilder(); | |
char[] buffer = new char[8192]; | |
while (true) { | |
int bytesRead = in.read(buffer); | |
if (bytesRead == -1) { | |
break; | |
} | |
sb.append(buffer, 0, bytesRead); | |
} | |
plugin.getLogger().info("UBL loaded from local backup"); | |
return sb.toString(); | |
} catch (Exception ex) { | |
plugin.getLogger().log(Level.SEVERE, "Could not load UBL backup. You are running without UBL protection!", ex); | |
return ""; | |
} | |
} | |
/** | |
* Save the raw ban-list data to the backup file | |
* | |
* This should not be run on the main server thread | |
* | |
* @param data The raw ban-list data | |
*/ | |
public void saveToBackup(String data) { | |
File file = new File(plugin.getDataFolder(), "ubl.backup"); | |
try (BufferedWriter out = new BufferedWriter(new FileWriter(file))) { | |
out.write(data); | |
} catch (IOException ex) { | |
plugin.getLogger().log(Level.SEVERE, "Failed to save UBL backup", ex); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.devoteduhc.uhc.ubl; | |
import java.util.UUID; | |
import org.bukkit.Bukkit; | |
import org.bukkit.event.EventHandler; | |
import org.bukkit.event.EventPriority; | |
import org.bukkit.event.Listener; | |
import org.bukkit.event.player.AsyncPlayerPreLoginEvent; | |
import org.bukkit.event.player.AsyncPlayerPreLoginEvent.Result; | |
public class UBLListener implements Listener { | |
private final UBL ubl; | |
public UBLListener(UBL ubl) { | |
this.ubl = ubl; | |
} | |
@EventHandler(priority = EventPriority.HIGHEST) | |
public void on(AsyncPlayerPreLoginEvent event) { | |
UUID uuid = event.getUniqueId(); | |
if (!ubl.isBanned(uuid)) { | |
return; | |
} | |
BanEntry entry = ubl.getBanEntry(uuid); | |
if (entry == null) { | |
return; // shouldn't happen but incase... | |
} | |
Bukkit.getLogger().info(event.getName() + " §7tried to join while being UBL'ed for: §c" + entry.getData("Reason")); | |
event.disallow(Result.KICK_BANNED, ubl.getBanMessage(uuid)); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.devoteduhc.uhc.managers; | |
import com.devoteduhc.uhc.UHCPlugin; | |
import com.devoteduhc.uhc.ubl.UBL; | |
import com.devoteduhc.uhc.ubl.UBLListener; | |
import lombok.Getter; | |
import lombok.Setter; | |
import org.bukkit.event.HandlerList; | |
public class UBLManager { | |
private UHCPlugin plugin; | |
@Getter | |
@Setter | |
private UBL ubl; | |
@Getter | |
@Setter | |
private UBLListener ublListener; | |
public UBLManager(UHCPlugin plugin) { | |
this.plugin = plugin; | |
// register ubl and listener | |
ubl = new UBL(this.plugin); | |
ublListener = new UBLListener(ubl); | |
} | |
public void enable() { | |
// enable ubl | |
ubl.reload(); | |
// register ubl listener | |
plugin.getServer().getPluginManager().registerEvents(ublListener, plugin); | |
} | |
public void disable() { | |
// cancel ubl runnable | |
ubl.cancel(); | |
// unregister ubl listener | |
HandlerList.unregisterAll(ublListener); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment