From 3e844be65d568e15468440598e09321b5629dc01 Mon Sep 17 00:00:00 2001 From: games647 Date: Thu, 26 May 2016 11:03:56 +0200 Subject: [PATCH] Clean up project structure --- .gitignore | 3 +- bukkit/pom.xml | 9 +- .../games647/fastlogin/bukkit/BukkitCore.java | 57 +++++ .../fastlogin/bukkit/DelayedAuthHook.java | 70 ++++++ .../fastlogin/bukkit/FastLoginBukkit.java | 105 ++------- .../fastlogin/bukkit/ForceLoginTask.java | 4 +- .../fastlogin/bukkit/MojangApiBukkit.java | 73 ++++++ .../fastlogin/bukkit/MojangApiConnector.java | 124 ---------- .../fastlogin/bukkit/PlayerProfile.java | 78 ------- .../bukkit/commands/CrackedCommand.java | 10 +- .../bukkit/commands/PremiumCommand.java | 10 +- .../fastlogin/bukkit/hooks/AuthMeHook.java | 4 +- .../bukkit/listener/BukkitJoinListener.java | 1 - .../listener/ProtocolSupportListener.java | 6 +- .../EncryptionPacketListener.java | 5 +- .../{ => packet}/StartPacketListener.java | 8 +- bungee/pom.xml | 9 +- .../fastlogin/bungee/AsyncPremiumCheck.java | 52 +++++ .../games647/fastlogin/bungee/BungeeCore.java | 52 +++++ .../fastlogin/bungee/FastLoginBungee.java | 45 ++-- .../fastlogin/bungee/ForceLoginTask.java | 5 +- .../fastlogin/bungee/MojangApiBungee.java | 27 +++ .../games647/fastlogin/bungee/Storage.java | 211 ------------------ .../bungee/listener/AsyncStatusMessage.java | 72 ++++++ .../listener/PlayerConnectionListener.java | 47 +--- .../listener/PluginMessageListener.java | 65 +----- core/pom.xml | 32 +++ .../fastlogin/core/FastLoginCore.java | 59 +++++ .../fastlogin/core}/MojangApiConnector.java | 28 +-- .../fastlogin/core}/PlayerProfile.java | 4 +- .../games647/fastlogin/core}/Storage.java | 36 +-- .../src/main/resources/config.yml | 2 +- core/src/main/resources/messages.yml | 18 ++ pom.xml | 19 +- universal/pom.xml | 8 +- 35 files changed, 642 insertions(+), 716 deletions(-) create mode 100644 bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitCore.java create mode 100644 bukkit/src/main/java/com/github/games647/fastlogin/bukkit/DelayedAuthHook.java create mode 100644 bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java delete mode 100644 bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiConnector.java delete mode 100644 bukkit/src/main/java/com/github/games647/fastlogin/bukkit/PlayerProfile.java rename bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/{ => packet}/EncryptionPacketListener.java (98%) rename bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/{ => packet}/StartPacketListener.java (95%) create mode 100644 bungee/src/main/java/com/github/games647/fastlogin/bungee/AsyncPremiumCheck.java create mode 100644 bungee/src/main/java/com/github/games647/fastlogin/bungee/BungeeCore.java create mode 100644 bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiBungee.java delete mode 100644 bungee/src/main/java/com/github/games647/fastlogin/bungee/Storage.java create mode 100644 bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/AsyncStatusMessage.java create mode 100644 core/pom.xml create mode 100644 core/src/main/java/com/github/games647/fastlogin/core/FastLoginCore.java rename {bungee/src/main/java/com/github/games647/fastlogin/bungee => core/src/main/java/com/github/games647/fastlogin/core}/MojangApiConnector.java (74%) rename {bungee/src/main/java/com/github/games647/fastlogin/bungee => core/src/main/java/com/github/games647/fastlogin/core}/PlayerProfile.java (93%) rename {bukkit/src/main/java/com/github/games647/fastlogin/bukkit => core/src/main/java/com/github/games647/fastlogin/core}/Storage.java (83%) rename {bukkit => core}/src/main/resources/config.yml (97%) create mode 100644 core/src/main/resources/messages.yml diff --git a/.gitignore b/.gitignore index 6864fd06..be7173a9 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,5 @@ gradle-app.setting # Project module targets bukkit/target universal/target -bungee/target \ No newline at end of file +bungee/target +core/target \ No newline at end of file diff --git a/bukkit/pom.xml b/bukkit/pom.xml index fb77afb6..7e69439c 100644 --- a/bukkit/pom.xml +++ b/bukkit/pom.xml @@ -5,7 +5,7 @@ com.github.games647 fastlogin - 1.3.1 + 1.4 ../pom.xml @@ -53,6 +53,13 @@ + + com.github.games647 + fastlogin.core + ${project.version} + provided + + org.spigotmc diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitCore.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitCore.java new file mode 100644 index 00000000..318a68d2 --- /dev/null +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/BukkitCore.java @@ -0,0 +1,57 @@ +package com.github.games647.fastlogin.bukkit; + +import com.comphenix.protocol.utility.SafeCacheBuilder; +import com.github.games647.fastlogin.core.FastLoginCore; +import com.github.games647.fastlogin.core.PlayerProfile; +import com.google.common.cache.CacheLoader; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import java.io.File; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +public class BukkitCore extends FastLoginCore { + + private final FastLoginBukkit plugin; + + public BukkitCore(FastLoginBukkit plugin) { + this.plugin = plugin; + } + + @Override + public File getDataFolder() { + return plugin.getDataFolder(); + } + + @Override + public Logger getLogger() { + return plugin.getLogger(); + } + + @Override + public ConcurrentMap buildCache() { + return SafeCacheBuilder + .newBuilder() + .concurrencyLevel(20) + .expireAfterAccess(30, TimeUnit.MINUTES) + .build(new CacheLoader() { + @Override + public PlayerProfile load(String key) throws Exception { + //should be fetched manually + throw new UnsupportedOperationException("Not supported yet."); + } + }); + } + + @Override + public ThreadFactory getThreadFactory() { + String pluginName = plugin.getName(); + return new ThreadFactoryBuilder() + .setNameFormat(pluginName + " Database Pool Thread #%1$d") + //Hikari create daemons by default + .setDaemon(true) + .build(); + } +} diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/DelayedAuthHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/DelayedAuthHook.java new file mode 100644 index 00000000..e89fc6e3 --- /dev/null +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/DelayedAuthHook.java @@ -0,0 +1,70 @@ +package com.github.games647.fastlogin.bukkit; + +import com.github.games647.fastlogin.bukkit.hooks.AuthMeHook; +import com.github.games647.fastlogin.bukkit.hooks.BukkitAuthPlugin; +import com.github.games647.fastlogin.bukkit.hooks.CrazyLoginHook; +import com.github.games647.fastlogin.bukkit.hooks.LogItHook; +import com.github.games647.fastlogin.bukkit.hooks.LoginSecurityHook; +import com.github.games647.fastlogin.bukkit.hooks.UltraAuthHook; +import com.github.games647.fastlogin.bukkit.hooks.xAuthHook; +import com.google.common.collect.Lists; + +import java.util.List; +import java.util.logging.Level; + +import org.bukkit.Bukkit; + +public class DelayedAuthHook implements Runnable { + + private final FastLoginBukkit plugin; + + public DelayedAuthHook(FastLoginBukkit plugin) { + this.plugin = plugin; + } + + @Override + public void run() { + boolean hookFound = registerHooks(); + if (plugin.isBungeeCord()) { + plugin.getLogger().info("BungeeCord setting detected. No auth plugin is required"); + } else if (!hookFound) { + plugin.getLogger().warning("No auth plugin were found by this plugin " + + "(other plugins could hook into this after the intialization of this plugin)" + + "and bungeecord is deactivated. " + + "Either one or both of the checks have to pass in order to use this plugin"); + } + } + + private boolean registerHooks() { + BukkitAuthPlugin authPluginHook = null; + try { + List> supportedHooks = Lists.newArrayList(AuthMeHook.class + , CrazyLoginHook.class, LogItHook.class, LoginSecurityHook.class, UltraAuthHook.class + , xAuthHook.class); + for (Class clazz : supportedHooks) { + String pluginName = clazz.getSimpleName().replace("Hook", ""); + //uses only member classes which uses AuthPlugin interface (skip interfaces) + if (Bukkit.getServer().getPluginManager().getPlugin(pluginName) != null) { + //check only for enabled plugins. A single plugin could be disabled by plugin managers + authPluginHook = clazz.newInstance(); + plugin.getLogger().log(Level.INFO, "Hooking into auth plugin: {0}", pluginName); + break; + } + } + } catch (InstantiationException | IllegalAccessException ex) { + plugin.getLogger().log(Level.SEVERE, "Couldn't load the integration class", ex); + } + + if (authPluginHook == null) { + //run this check for exceptions (errors) and not found plugins + plugin.getLogger().warning("No support offline Auth plugin found. "); + return false; + } + + if (plugin.getAuthPlugin() != null) { + plugin.setAuthPluginHook(authPluginHook); + } + + return true; + } +} diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java index 82935595..1c9c383d 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java @@ -7,29 +7,19 @@ import com.comphenix.protocol.ProtocolManager; import com.comphenix.protocol.utility.SafeCacheBuilder; import com.github.games647.fastlogin.bukkit.commands.CrackedCommand; import com.github.games647.fastlogin.bukkit.commands.PremiumCommand; -import com.github.games647.fastlogin.bukkit.hooks.AuthMeHook; import com.github.games647.fastlogin.bukkit.hooks.BukkitAuthPlugin; -import com.github.games647.fastlogin.bukkit.hooks.CrazyLoginHook; -import com.github.games647.fastlogin.bukkit.hooks.LogItHook; -import com.github.games647.fastlogin.bukkit.hooks.LoginSecurityHook; -import com.github.games647.fastlogin.bukkit.hooks.UltraAuthHook; -import com.github.games647.fastlogin.bukkit.hooks.xAuthHook; import com.github.games647.fastlogin.bukkit.listener.BukkitJoinListener; import com.github.games647.fastlogin.bukkit.listener.BungeeCordListener; -import com.github.games647.fastlogin.bukkit.listener.EncryptionPacketListener; import com.github.games647.fastlogin.bukkit.listener.ProtocolSupportListener; -import com.github.games647.fastlogin.bukkit.listener.StartPacketListener; +import com.github.games647.fastlogin.bukkit.listener.packet.EncryptionPacketListener; +import com.github.games647.fastlogin.bukkit.listener.packet.StartPacketListener; +import com.github.games647.fastlogin.core.FastLoginCore; import com.google.common.cache.CacheLoader; -import com.google.common.collect.Lists; import java.security.KeyPair; -import java.sql.SQLException; -import java.util.List; -import java.util.UUID; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import java.util.logging.Logger; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -41,19 +31,11 @@ public class FastLoginBukkit extends JavaPlugin { private static final int WORKER_THREADS = 5; - public static UUID parseId(String withoutDashes) { - return UUID.fromString(withoutDashes.substring(0, 8) - + "-" + withoutDashes.substring(8, 12) - + "-" + withoutDashes.substring(12, 16) - + "-" + withoutDashes.substring(16, 20) - + "-" + withoutDashes.substring(20, 32)); - } - //provide a immutable key pair to be thread safe | used for encrypting and decrypting traffic private final KeyPair keyPair = EncryptionUtil.generateKeyPair(); - protected boolean bungeeCord; - private Storage storage; + private boolean bungeeCord; + private final FastLoginCore core = new BukkitCore(this); private boolean serverStarted; //this map is thread-safe for async access (Packet Listener) @@ -72,11 +54,12 @@ public class FastLoginBukkit extends JavaPlugin { }); private BukkitAuthPlugin authPlugin; - private final MojangApiConnector mojangApiConnector = new MojangApiConnector(this); private PasswordGenerator passwordGenerator = new DefaultPasswordGenerator(); @Override public void onEnable() { + core.setMojangApiConnector(new MojangApiBukkit(core)); + try { if (ClassUtil.isPresent("org.spigotmc.SpigotConfig")) { bungeeCord = Class.forName("org.spigotmc.SpigotConfig").getDeclaredField("bungee").getBoolean(null); @@ -111,11 +94,7 @@ public class FastLoginBukkit extends JavaPlugin { String username = getConfig().getString("username", ""); String password = getConfig().getString("password", ""); - this.storage = new Storage(this, driver, host, port, database, username, password); - try { - storage.createTables(); - } catch (SQLException sqlEx) { - getLogger().log(Level.SEVERE, "Failed to create database tables. Disabling plugin...", sqlEx); + if (!core.setupDatabase(driver, host, port, database, username, password)) { setEnabled(false); return; } @@ -137,20 +116,7 @@ public class FastLoginBukkit extends JavaPlugin { } //delay dependency setup because we load the plugin very early where plugins are initialized yet - getServer().getScheduler().runTask(this, new Runnable() { - @Override - public void run() { - boolean hookFound = registerHooks(); - if (bungeeCord) { - getLogger().info("BungeeCord setting detected. No auth plugin is required"); - } else if (!hookFound) { - getLogger().warning("No auth plugin were found by this plugin " - + "(other plugins could hook into this after the intialization of this plugin)" - + "and bungeecord is deactivated. " - + "Either one or both of the checks have to pass in order to use this plugin"); - } - } - }); + getServer().getScheduler().runTask(this, new DelayedAuthHook(this)); getServer().getPluginManager().registerEvents(new BukkitJoinListener(this), this); @@ -169,11 +135,15 @@ public class FastLoginBukkit extends JavaPlugin { player.removeMetadata(getName(), this); } - if (storage != null) { - storage.close(); + if (core != null) { + core.close(); } } + public FastLoginCore getCore() { + return core; + } + public String generateStringPassword(Player player) { return passwordGenerator.getRandomPassword(player); } @@ -201,10 +171,6 @@ public class FastLoginBukkit extends JavaPlugin { return keyPair; } - public Storage getStorage() { - return storage; - } - /** * Gets the auth plugin hook in order to interact with the plugins. This can be null if no supporting auth plugin * was found. @@ -216,7 +182,7 @@ public class FastLoginBukkit extends JavaPlugin { try { Thread.sleep(1000); } catch (InterruptedException ex) { - Logger.getLogger(FastLoginBukkit.class.getName()).log(Level.SEVERE, null, ex); + getLogger().log(Level.SEVERE, null, ex); } } @@ -227,45 +193,6 @@ public class FastLoginBukkit extends JavaPlugin { this.authPlugin = authPlugin; } - /** - * Gets the a connection in order to access important features from the Mojang API. - * - * @return the connector instance - */ - public MojangApiConnector getApiConnector() { - return mojangApiConnector; - } - - private boolean registerHooks() { - BukkitAuthPlugin authPluginHook = null; - try { - List> supportedHooks = Lists.newArrayList(AuthMeHook.class - , CrazyLoginHook.class, LogItHook.class, LoginSecurityHook.class, UltraAuthHook.class - , xAuthHook.class); - for (Class clazz : supportedHooks) { - String pluginName = clazz.getSimpleName().replace("Hook", ""); - //uses only member classes which uses AuthPlugin interface (skip interfaces) - if (getServer().getPluginManager().getPlugin(pluginName) != null) { - //check only for enabled plugins. A single plugin could be disabled by plugin managers - authPluginHook = clazz.newInstance(); - getLogger().log(Level.INFO, "Hooking into auth plugin: {0}", pluginName); - break; - } - } - } catch (InstantiationException | IllegalAccessException ex) { - getLogger().log(Level.SEVERE, "Couldn't load the integration class", ex); - } - - if (authPluginHook == null) { - //run this check for exceptions (errors) and not found plugins - getLogger().warning("No support offline Auth plugin found. "); - return false; - } - - authPlugin = authPluginHook; - return true; - } - public boolean isBungeeCord() { return bungeeCord; } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/ForceLoginTask.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/ForceLoginTask.java index f131aff0..d5c0b86a 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/ForceLoginTask.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/ForceLoginTask.java @@ -1,6 +1,8 @@ package com.github.games647.fastlogin.bukkit; import com.github.games647.fastlogin.bukkit.hooks.BukkitAuthPlugin; +import com.github.games647.fastlogin.core.PlayerProfile; +import com.github.games647.fastlogin.core.Storage; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; @@ -35,7 +37,7 @@ public class ForceLoginTask implements Runnable { BukkitAuthPlugin authPlugin = plugin.getAuthPlugin(); - Storage storage = plugin.getStorage(); + Storage storage = plugin.getCore().getStorage(); PlayerProfile playerProfile = null; if (storage != null) { playerProfile = storage.getProfile(player.getName(), false); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java new file mode 100644 index 00000000..c1e4873d --- /dev/null +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java @@ -0,0 +1,73 @@ +package com.github.games647.fastlogin.bukkit; + +import com.comphenix.protocol.wrappers.WrappedSignedProperty; +import com.github.games647.fastlogin.core.FastLoginCore; +import com.github.games647.fastlogin.core.MojangApiConnector; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.util.UUID; +import java.util.logging.Level; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.JSONValue; + +public class MojangApiBukkit extends MojangApiConnector { + + //mojang api check to prove a player is logged in minecraft and made a join server request + private static final String HAS_JOINED_URL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?"; + + public MojangApiBukkit(FastLoginCore plugin) { + super(plugin); + } + + @Override + public boolean hasJoinedServer(Object session, String serverId) { + if (!(session instanceof PlayerSession)) { + return false; + } + + PlayerSession playerSession = (PlayerSession) session; + try { + String url = HAS_JOINED_URL + "username=" + playerSession.getUsername() + "&serverId=" + serverId; + HttpURLConnection conn = getConnection(url); + + BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + String line = reader.readLine(); + if (line != null && !line.equals("null")) { + //validate parsing + //http://wiki.vg/Protocol_Encryption#Server + JSONObject userData = (JSONObject) JSONValue.parseWithException(line); + String uuid = (String) userData.get("id"); + playerSession.setUuid(FastLoginCore.parseId(uuid)); + + JSONArray properties = (JSONArray) userData.get("properties"); + JSONObject skinProperty = (JSONObject) properties.get(0); + + String propertyName = (String) skinProperty.get("name"); + if (propertyName.equals("textures")) { + String skinValue = (String) skinProperty.get("value"); + String signature = (String) skinProperty.get("signature"); + playerSession.setSkin(WrappedSignedProperty.fromValues(propertyName, skinValue, signature)); + } + + return true; + } + } catch (Exception ex) { + //catch not only ioexceptions also parse and NPE on unexpected json format + plugin.getLogger().log(Level.WARNING, "Failed to verify session", ex); + } + + //this connection doesn't need to be closed. So can make use of keep alive in java + return false; + } + + @Override + protected UUID getUUIDFromJson(String json) { + JSONObject userData = (JSONObject) JSONValue.parse(json); + String uuid = (String) userData.get("id"); + return FastLoginCore.parseId(uuid); + } +} diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiConnector.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiConnector.java deleted file mode 100644 index 8eb4c206..00000000 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiConnector.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.github.games647.fastlogin.bukkit; - -import com.comphenix.protocol.wrappers.WrappedSignedProperty; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.UUID; -import java.util.logging.Level; -import java.util.regex.Pattern; - -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.JSONValue; - -public class MojangApiConnector { - - //http connection, read timeout and user agent for a connection to mojang api servers - private static final int TIMEOUT = 1 * 1_000; - private static final String USER_AGENT = "Premium-Checker"; - - //mojang api check to prove a player is logged in minecraft and made a join server request - private static final String HAS_JOINED_URL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?"; - - //only premium (paid account) users have a uuid from here - private static final String UUID_LINK = "https://api.mojang.com/users/profiles/minecraft/"; - //this includes a-zA-Z1-9_ - private static final String VALID_PLAYERNAME = "^\\w{2,16}$"; - - //compile the pattern only on plugin enable -> and this have to be threadsafe - private final Pattern playernameMatcher = Pattern.compile(VALID_PLAYERNAME); - - private final FastLoginBukkit plugin; - - public MojangApiConnector(FastLoginBukkit plugin) { - this.plugin = plugin; - } - - /** - * - * @param playerName - * @return null on non-premium - */ - public UUID getPremiumUUID(String playerName) { - //check if it's a valid playername - if (playernameMatcher.matcher(playerName).matches()) { - //only make a API call if the name is valid existing mojang account - try { - HttpURLConnection connection = getConnection(UUID_LINK + playerName); - if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { - BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); - String line = reader.readLine(); - if (line != null && !line.equals("null")) { - JSONObject userData = (JSONObject) JSONValue.parseWithException(line); - String uuid = (String) userData.get("id"); - return parseId(uuid); - } - } - //204 - no content for not found - } catch (Exception ex) { - plugin.getLogger().log(Level.SEVERE, "Failed to check if player has a paid account", ex); - } - //this connection doesn't need to be closed. So can make use of keep alive in java - } - - return null; - } - - public boolean hasJoinedServer(PlayerSession session, String serverId) { - try { - String url = HAS_JOINED_URL + "username=" + session.getUsername() + "&serverId=" + serverId; - HttpURLConnection conn = getConnection(url); - - BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); - String line = reader.readLine(); - if (line != null && !line.equals("null")) { - //validate parsing - //http://wiki.vg/Protocol_Encryption#Server - JSONObject userData = (JSONObject) JSONValue.parseWithException(line); - String uuid = (String) userData.get("id"); - session.setUuid(parseId(uuid)); - - JSONArray properties = (JSONArray) userData.get("properties"); - JSONObject skinProperty = (JSONObject) properties.get(0); - - String propertyName = (String) skinProperty.get("name"); - if (propertyName.equals("textures")) { - String skinValue = (String) skinProperty.get("value"); - String signature = (String) skinProperty.get("signature"); - session.setSkin(WrappedSignedProperty.fromValues(propertyName, skinValue, signature)); - } - - return true; - } - } catch (Exception ex) { - //catch not only ioexceptions also parse and NPE on unexpected json format - plugin.getLogger().log(Level.WARNING, "Failed to verify session", ex); - } - - //this connection doesn't need to be closed. So can make use of keep alive in java - return false; - } - - private UUID parseId(String withoutDashes) { - return UUID.fromString(withoutDashes.substring(0, 8) - + "-" + withoutDashes.substring(8, 12) - + "-" + withoutDashes.substring(12, 16) - + "-" + withoutDashes.substring(16, 20) - + "-" + withoutDashes.substring(20, 32)); - } - - private HttpURLConnection getConnection(String url) throws IOException { - HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); - connection.setConnectTimeout(TIMEOUT); - connection.setReadTimeout(TIMEOUT); - //the new Mojang API just uses json as response - connection.setRequestProperty("Content-Type", "application/json"); - connection.setRequestProperty("User-Agent", USER_AGENT); - - return connection; - } -} diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/PlayerProfile.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/PlayerProfile.java deleted file mode 100644 index b7de0de2..00000000 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/PlayerProfile.java +++ /dev/null @@ -1,78 +0,0 @@ -package com.github.games647.fastlogin.bukkit; - -import java.util.UUID; - -public class PlayerProfile { - - private final String playerName; - - private long userId; - - private UUID uuid; - private boolean premium; - private String lastIp; - private long lastLogin; - - public PlayerProfile(long userId, UUID uuid, String playerName, boolean premium - , String lastIp, long lastLogin) { - this.userId = userId; - this.uuid = uuid; - this.playerName = playerName; - this.premium = premium; - this.lastIp = lastIp; - this.lastLogin = lastLogin; - } - - public PlayerProfile(UUID uuid, String playerName, boolean premium, String lastIp) { - this.userId = -1; - - this.uuid = uuid; - this.playerName = playerName; - this.premium = premium; - this.lastIp = lastIp; - } - - public String getPlayerName() { - return playerName; - } - - public synchronized long getUserId() { - return userId; - } - - protected synchronized void setUserId(long generatedId) { - this.userId = generatedId; - } - - public synchronized UUID getUuid() { - return uuid; - } - - public synchronized void setUuid(UUID uuid) { - this.uuid = uuid; - } - - public synchronized boolean isPremium() { - return premium; - } - - public synchronized void setPremium(boolean premium) { - this.premium = premium; - } - - public synchronized String getLastIp() { - return lastIp; - } - - public synchronized void setLastIp(String lastIp) { - this.lastIp = lastIp; - } - - public synchronized long getLastLogin() { - return lastLogin; - } - - public synchronized void setLastLogin(long lastLogin) { - this.lastLogin = lastLogin; - } -} diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/CrackedCommand.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/CrackedCommand.java index eb02804d..9f93c148 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/CrackedCommand.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/CrackedCommand.java @@ -1,7 +1,7 @@ package com.github.games647.fastlogin.bukkit.commands; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.PlayerProfile; +import com.github.games647.fastlogin.core.PlayerProfile; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; @@ -34,7 +34,7 @@ public class CrackedCommand implements CommandExecutor { sender.sendMessage(ChatColor.YELLOW + "Sending request..."); } else { //todo: load async if it's not in the cache anymore - final PlayerProfile profile = plugin.getStorage().getProfile(sender.getName(), true); + final PlayerProfile profile = plugin.getCore().getStorage().getProfile(sender.getName(), true); if (profile.isPremium()) { sender.sendMessage(ChatColor.DARK_GREEN + "Removed from the list of premium players"); profile.setPremium(false); @@ -42,7 +42,7 @@ public class CrackedCommand implements CommandExecutor { Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { - plugin.getStorage().save(profile); + plugin.getCore().getStorage().save(profile); } }); } else { @@ -62,7 +62,7 @@ public class CrackedCommand implements CommandExecutor { sender.sendMessage(ChatColor.YELLOW + "Sending request for player " + args[0] + "..."); } else { //todo: load async if it's not in the cache anymore - final PlayerProfile profile = plugin.getStorage().getProfile(args[0], true); + final PlayerProfile profile = plugin.getCore().getStorage().getProfile(args[0], true); if (profile == null) { sender.sendMessage(ChatColor.DARK_RED + "Player not in the database"); return true; @@ -75,7 +75,7 @@ public class CrackedCommand implements CommandExecutor { Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { - plugin.getStorage().save(profile); + plugin.getCore().getStorage().save(profile); } }); } else { diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/PremiumCommand.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/PremiumCommand.java index 8835747f..a25234a0 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/PremiumCommand.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/commands/PremiumCommand.java @@ -1,7 +1,7 @@ package com.github.games647.fastlogin.bukkit.commands; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.PlayerProfile; +import com.github.games647.fastlogin.core.PlayerProfile; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; @@ -39,7 +39,7 @@ public class PremiumCommand implements CommandExecutor { sender.sendMessage(ChatColor.YELLOW + "Sending request..."); } else { // //todo: load async if it's not in the cache anymore - final PlayerProfile profile = plugin.getStorage().getProfile(sender.getName(), true); + final PlayerProfile profile = plugin.getCore().getStorage().getProfile(sender.getName(), true); if (profile.isPremium()) { sender.sendMessage(ChatColor.DARK_RED + "You are already on the premium list"); } else { @@ -48,7 +48,7 @@ public class PremiumCommand implements CommandExecutor { Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { - plugin.getStorage().save(profile); + plugin.getCore().getStorage().save(profile); } }); @@ -68,7 +68,7 @@ public class PremiumCommand implements CommandExecutor { sender.sendMessage(ChatColor.YELLOW + "Sending request..."); } else { //todo: load async if it's not in the cache anymore - final PlayerProfile profile = plugin.getStorage().getProfile(args[0], true); + final PlayerProfile profile = plugin.getCore().getStorage().getProfile(args[0], true); if (profile == null) { sender.sendMessage(ChatColor.DARK_RED + "Player not in the database"); return true; @@ -82,7 +82,7 @@ public class PremiumCommand implements CommandExecutor { Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { - plugin.getStorage().save(profile); + plugin.getCore().getStorage().save(profile); } }); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/AuthMeHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/AuthMeHook.java index 5248007c..97aa8f05 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/AuthMeHook.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/AuthMeHook.java @@ -30,9 +30,7 @@ public class AuthMeHook implements BukkitAuthPlugin { } else { API.forceLogin(player); } - - //commented because the operation above is performed async -> race conditions -// return NewAPI.getInstance().isAuthenticated(player); + return true; } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BukkitJoinListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BukkitJoinListener.java index 8f2a8889..e83c7138 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BukkitJoinListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/BukkitJoinListener.java @@ -41,7 +41,6 @@ public class BukkitJoinListener implements Listener { public void onPlayerJoin(PlayerJoinEvent joinEvent) { Player player = joinEvent.getPlayer(); - //removing the session because we now use it PlayerSession session = plugin.getSessions().get(player.getAddress().toString()); if (session != null && plugin.getConfig().getBoolean("forwardSkin")) { WrappedGameProfile gameProfile = WrappedGameProfile.fromPlayer(player); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ProtocolSupportListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ProtocolSupportListener.java index 0519ed31..8a39fab1 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ProtocolSupportListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/ProtocolSupportListener.java @@ -1,9 +1,9 @@ package com.github.games647.fastlogin.bukkit.listener; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.PlayerProfile; import com.github.games647.fastlogin.bukkit.PlayerSession; import com.github.games647.fastlogin.bukkit.hooks.BukkitAuthPlugin; +import com.github.games647.fastlogin.core.PlayerProfile; import java.net.InetSocketAddress; import java.util.UUID; @@ -40,7 +40,7 @@ public class ProtocolSupportListener implements Listener { return; } - PlayerProfile playerProfile = plugin.getStorage().getProfile(username, true); + PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(username, true); if (playerProfile != null) { if (playerProfile.isPremium()) { if (playerProfile.getUserId() != -1) { @@ -50,7 +50,7 @@ public class ProtocolSupportListener implements Listener { //user not exists in the db try { if (plugin.getConfig().getBoolean("autoRegister") && !authPlugin.isRegistered(username)) { - UUID premiumUUID = plugin.getApiConnector().getPremiumUUID(username); + UUID premiumUUID = plugin.getCore().getMojangApiConnector().getPremiumUUID(username); if (premiumUUID != null) { plugin.getLogger().log(Level.FINER, "Player {0} uses a premium username", username); startPremiumSession(username, loginStartEvent, false); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/EncryptionPacketListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/EncryptionPacketListener.java similarity index 98% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/EncryptionPacketListener.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/EncryptionPacketListener.java index 7e9702d9..b1cabb94 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/EncryptionPacketListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/EncryptionPacketListener.java @@ -1,4 +1,4 @@ -package com.github.games647.fastlogin.bukkit.listener; +package com.github.games647.fastlogin.bukkit.listener.packet; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolManager; @@ -71,7 +71,6 @@ public class EncryptionPacketListener extends PacketAdapter { */ @Override public void onPacketReceiving(PacketEvent packetEvent) { - System.out.println("ENCRYPTION REQUEST"); Player player = packetEvent.getPlayer(); //the player name is unknown to ProtocolLib (so getName() doesn't work) - now uses ip:port as key @@ -102,7 +101,7 @@ public class EncryptionPacketListener extends PacketAdapter { String serverId = (new BigInteger(serverIdHash)).toString(16); String username = session.getUsername(); - if (plugin.getApiConnector().hasJoinedServer(session, serverId)) { + if (plugin.getCore().getMojangApiConnector().hasJoinedServer(session, serverId)) { plugin.getLogger().log(Level.FINE, "Player {0} has a verified premium account", username); session.setVerified(true); diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/StartPacketListener.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/StartPacketListener.java similarity index 95% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/StartPacketListener.java rename to bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/StartPacketListener.java index 65377a1c..03b8bb03 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/StartPacketListener.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/listener/packet/StartPacketListener.java @@ -1,4 +1,4 @@ -package com.github.games647.fastlogin.bukkit.listener; +package com.github.games647.fastlogin.bukkit.listener.packet; import com.comphenix.protocol.PacketType; import com.comphenix.protocol.ProtocolManager; @@ -6,7 +6,7 @@ import com.comphenix.protocol.events.PacketAdapter; import com.comphenix.protocol.events.PacketContainer; import com.comphenix.protocol.events.PacketEvent; import com.github.games647.fastlogin.bukkit.FastLoginBukkit; -import com.github.games647.fastlogin.bukkit.PlayerProfile; +import com.github.games647.fastlogin.core.PlayerProfile; import com.github.games647.fastlogin.bukkit.PlayerSession; import com.github.games647.fastlogin.bukkit.hooks.BukkitAuthPlugin; @@ -83,7 +83,7 @@ public class StartPacketListener extends PacketAdapter { return; } - PlayerProfile playerProfile = plugin.getStorage().getProfile(username, true); + PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(username, true); if (playerProfile != null) { if (playerProfile.isPremium()) { if (playerProfile.getUserId() != -1) { @@ -93,7 +93,7 @@ public class StartPacketListener extends PacketAdapter { //user not exists in the db try { if (plugin.getConfig().getBoolean("autoRegister") && !authPlugin.isRegistered(username)) { - UUID premiumUUID = plugin.getApiConnector().getPremiumUUID(username); + UUID premiumUUID = plugin.getCore().getMojangApiConnector().getPremiumUUID(username); if (premiumUUID != null) { plugin.getLogger().log(Level.FINER, "Player {0} uses a premium username", username); enablePremiumLogin(username, sessionKey, player, packetEvent, false); diff --git a/bungee/pom.xml b/bungee/pom.xml index 85af835b..026aa400 100644 --- a/bungee/pom.xml +++ b/bungee/pom.xml @@ -5,7 +5,7 @@ com.github.games647 fastlogin - 1.3.1 + 1.4 ../pom.xml @@ -37,6 +37,13 @@ + + ${project.groupId} + fastlogin.core + ${project.version} + provided + + net.md-5 bungeecord-proxy diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/AsyncPremiumCheck.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/AsyncPremiumCheck.java new file mode 100644 index 00000000..2bff5fa4 --- /dev/null +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/AsyncPremiumCheck.java @@ -0,0 +1,52 @@ +package com.github.games647.fastlogin.bungee; + +import com.github.games647.fastlogin.bungee.FastLoginBungee; +import com.github.games647.fastlogin.bungee.hooks.BungeeAuthPlugin; +import com.github.games647.fastlogin.core.PlayerProfile; +import java.util.UUID; +import java.util.logging.Level; +import net.md_5.bungee.api.connection.PendingConnection; +import net.md_5.bungee.api.event.PreLoginEvent; + +public class AsyncPremiumCheck implements Runnable { + + private final FastLoginBungee plugin; + private final PreLoginEvent preLoginEvent; + + public AsyncPremiumCheck(FastLoginBungee plugin, PreLoginEvent preLoginEvent) { + this.plugin = plugin; + this.preLoginEvent = preLoginEvent; + } + + @Override + public void run() { + PendingConnection connection = preLoginEvent.getConnection(); + String username = connection.getName(); + try { + PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(username, true); + if (playerProfile != null) { + if (playerProfile.isPremium()) { + if (playerProfile.getUserId() != -1) { + connection.setOnlineMode(true); + } + } else if (playerProfile.getUserId() == -1) { + //user not exists in the db + BungeeAuthPlugin authPlugin = plugin.getBungeeAuthPlugin(); + if (plugin.getConfiguration().getBoolean("autoRegister") + && (authPlugin == null || !authPlugin.isRegistered(username))) { + UUID premiumUUID = plugin.getCore().getMojangApiConnector().getPremiumUUID(username); + if (premiumUUID != null) { + plugin.getLogger().log(Level.FINER, "Player {0} uses a premium username", username); + connection.setOnlineMode(true); + plugin.getPendingAutoRegister().put(connection, new Object()); + } + } + } + } + } catch (Exception ex) { + plugin.getLogger().log(Level.SEVERE, "Failed to check premium state", ex); + } finally { + preLoginEvent.completeIntent(plugin); + } + } +} diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/BungeeCore.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/BungeeCore.java new file mode 100644 index 00000000..7e7719d3 --- /dev/null +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/BungeeCore.java @@ -0,0 +1,52 @@ +package com.github.games647.fastlogin.bungee; + +import com.github.games647.fastlogin.core.FastLoginCore; +import com.github.games647.fastlogin.core.PlayerProfile; +import com.google.common.cache.CacheBuilder; +import com.google.common.util.concurrent.ThreadFactoryBuilder; + +import java.io.File; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; + +import net.md_5.bungee.api.scheduler.GroupedThreadFactory; + +public class BungeeCore extends FastLoginCore { + + private final FastLoginBungee plugin; + + public BungeeCore(FastLoginBungee plugin) { + this.plugin = plugin; + } + + @Override + public File getDataFolder() { + return plugin.getDataFolder(); + } + + @Override + public Logger getLogger() { + return plugin.getLogger(); + } + + @Override + public ConcurrentMap buildCache() { + return CacheBuilder + .newBuilder() + .concurrencyLevel(20) + .expireAfterAccess(30, TimeUnit.MINUTES) + .build().asMap(); + } + + @Override + public ThreadFactory getThreadFactory() { + String pluginName = plugin.getDescription().getName(); + return new ThreadFactoryBuilder() + .setNameFormat(pluginName + " Database Pool Thread #%1$d") + //Hikari create daemons by default + .setDaemon(true) + .setThreadFactory(new GroupedThreadFactory(plugin, pluginName)).build(); + } +} diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java index 600b238e..4f8c0543 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java @@ -1,9 +1,10 @@ package com.github.games647.fastlogin.bungee; -import com.github.games647.fastlogin.bungee.listener.PlayerConnectionListener; import com.github.games647.fastlogin.bungee.hooks.BungeeAuthHook; import com.github.games647.fastlogin.bungee.hooks.BungeeAuthPlugin; +import com.github.games647.fastlogin.bungee.listener.PlayerConnectionListener; import com.github.games647.fastlogin.bungee.listener.PluginMessageListener; +import com.github.games647.fastlogin.core.FastLoginCore; import com.google.common.cache.CacheBuilder; import java.io.File; @@ -11,12 +12,10 @@ import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.util.Random; -import java.util.UUID; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.logging.Level; -import net.md_5.bungee.Util; import net.md_5.bungee.api.connection.PendingConnection; import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.config.Configuration; @@ -28,16 +27,11 @@ import net.md_5.bungee.config.YamlConfiguration; */ public class FastLoginBungee extends Plugin { - private static final char[] CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + private static final char[] PASSWORD_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" .toCharArray(); - public static UUID parseId(String withoutDashes) { - return Util.getUUID(withoutDashes); - } - + private final FastLoginCore loginCore = new BungeeCore(this); private BungeeAuthPlugin bungeeAuthPlugin; - private final MojangApiConnector mojangApiConnector = new MojangApiConnector(this); - private Storage storage; private Configuration configuration; private final Random random = new Random(); @@ -49,6 +43,8 @@ public class FastLoginBungee extends Plugin { @Override public void onEnable() { + loginCore.setMojangApiConnector(new MojangApiBungee(loginCore)); + if (!getDataFolder().exists()) { getDataFolder().mkdir(); } @@ -72,14 +68,9 @@ public class FastLoginBungee extends Plugin { String username = configuration.getString("username", ""); String password = configuration.getString("password", ""); - storage = new Storage(this, driver, host, port, database, username, password); - try { - storage.createTables(); - } catch (Exception ex) { - getLogger().log(Level.SEVERE, "Failed to setup database. Disabling plugin...", ex); + if (!loginCore.setupDatabase(driver, host, port, database, username, password)) { return; } - } catch (IOException ioExc) { getLogger().log(Level.SEVERE, "Error loading config. Disabling plugin...", ioExc); return; @@ -98,7 +89,7 @@ public class FastLoginBungee extends Plugin { public String generateStringPassword() { StringBuilder generatedPassword = new StringBuilder(8); for (int i = 1; i <= 8; i++) { - generatedPassword.append(CHARACTERS[random.nextInt(CHARACTERS.length - 1)]); + generatedPassword.append(PASSWORD_CHARACTERS[random.nextInt(PASSWORD_CHARACTERS.length - 1)]); } return generatedPassword.toString(); @@ -106,23 +97,21 @@ public class FastLoginBungee extends Plugin { @Override public void onDisable() { - if (storage != null) { - storage.close(); - } + loginCore.close(); + } + + public FastLoginCore getCore() { + return loginCore; + } + + public void setAuthPluginHook(BungeeAuthPlugin authPlugin) { + this.bungeeAuthPlugin = authPlugin; } public Configuration getConfiguration() { return configuration; } - public Storage getStorage() { - return storage; - } - - public MojangApiConnector getMojangApiConnector() { - return mojangApiConnector; - } - public ConcurrentMap getPendingAutoRegister() { return pendingAutoRegister; } diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/ForceLoginTask.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/ForceLoginTask.java index d66d21cf..2f619003 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/ForceLoginTask.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/ForceLoginTask.java @@ -1,5 +1,6 @@ package com.github.games647.fastlogin.bungee; +import com.github.games647.fastlogin.core.PlayerProfile; import com.github.games647.fastlogin.bungee.hooks.BungeeAuthPlugin; import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteStreams; @@ -23,7 +24,7 @@ public class ForceLoginTask implements Runnable { @Override public void run() { - PlayerProfile playerProfile = plugin.getStorage().getProfile(player.getName(), false); + PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(player.getName(), false); //force login only on success if (player.getPendingConnection().isOnlineMode()) { @@ -46,7 +47,7 @@ public class ForceLoginTask implements Runnable { //cracked player //update only on success to prevent corrupt data playerProfile.setPremium(false); - plugin.getStorage().save(playerProfile); + plugin.getCore().getStorage().save(playerProfile); } } diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiBungee.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiBungee.java new file mode 100644 index 00000000..39bdeb9c --- /dev/null +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiBungee.java @@ -0,0 +1,27 @@ +package com.github.games647.fastlogin.bungee; + +import com.github.games647.fastlogin.core.FastLoginCore; +import com.github.games647.fastlogin.core.MojangApiConnector; + +import java.util.UUID; + +import net.md_5.bungee.BungeeCord; + +public class MojangApiBungee extends MojangApiConnector { + + public MojangApiBungee(FastLoginCore plugin) { + super(plugin); + } + + @Override + protected UUID getUUIDFromJson(String json) { + MojangPlayer mojangPlayer = BungeeCord.getInstance().gson.fromJson(json, MojangPlayer.class); + return FastLoginCore.parseId(mojangPlayer.getId()); + } + + @Override + public boolean hasJoinedServer(Object session, String serverId) { + //this is not needed in Bungee + throw new UnsupportedOperationException("Not supported"); + } +} diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/Storage.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/Storage.java deleted file mode 100644 index 7e66700a..00000000 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/Storage.java +++ /dev/null @@ -1,211 +0,0 @@ -package com.github.games647.fastlogin.bungee; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.zaxxer.hikari.HikariConfig; -import com.zaxxer.hikari.HikariDataSource; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.UUID; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; -import java.util.logging.Level; -import net.md_5.bungee.api.scheduler.GroupedThreadFactory; - -public class Storage { - - private static final String PREMIUM_TABLE = "premium"; - - private final ConcurrentMap profileCache = CacheBuilder - .newBuilder() - .concurrencyLevel(20) - .expireAfterAccess(30, TimeUnit.MINUTES) - .build(new CacheLoader() { - @Override - public PlayerProfile load(String key) throws Exception { - //should be fetched manually - throw new UnsupportedOperationException("Not supported yet."); - } - }).asMap(); - - private final HikariDataSource dataSource; - private final FastLoginBungee plugin; - - public Storage(FastLoginBungee plugin, String driver, String host, int port, String databasePath - , String user, String pass) { - this.plugin = plugin; - - HikariConfig databaseConfig = new HikariConfig(); - databaseConfig.setUsername(user); - databaseConfig.setPassword(pass); - databaseConfig.setDriverClassName(driver); - String pluginName = plugin.getDescription().getName(); - - //set a custom thread factory to remove BungeeCord warning about different threads - databaseConfig.setThreadFactory(new ThreadFactoryBuilder() - .setNameFormat(pluginName + " Database Pool Thread #%1$d") - //Hikari create daemons by default - .setDaemon(true) - .setThreadFactory(new GroupedThreadFactory(plugin, pluginName)).build()); - - databasePath = databasePath.replace("{pluginDir}", plugin.getDataFolder().getAbsolutePath()); - - String jdbcUrl = "jdbc:"; - if (driver.contains("sqlite")) { - jdbcUrl += "sqlite" + "://" + databasePath; - databaseConfig.setConnectionTestQuery("SELECT 1"); - } else { - jdbcUrl += "mysql" + "://" + host + ':' + port + '/' + databasePath; - } - - databaseConfig.setJdbcUrl(jdbcUrl); - this.dataSource = new HikariDataSource(databaseConfig); - } - - public void createTables() throws SQLException { - Connection con = null; - try { - con = dataSource.getConnection(); - Statement statement = con.createStatement(); - String createDataStmt = "CREATE TABLE IF NOT EXISTS " + PREMIUM_TABLE + " (" - + "`UserID` INTEGER PRIMARY KEY AUTO_INCREMENT, " - + "`UUID` CHAR(36), " - + "`Name` VARCHAR(16) NOT NULL, " - + "`Premium` BOOLEAN NOT NULL, " - + "`LastIp` VARCHAR(255) NOT NULL, " - + "`LastLogin` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, " - + "UNIQUE (`UUID`), " - //the premium shouldn't steal the cracked account by changing the name - + "UNIQUE (`Name`) " - + ")"; - - if (dataSource.getJdbcUrl().contains("sqlite")) { - createDataStmt = createDataStmt.replace("AUTO_INCREMENT", "AUTOINCREMENT"); - } - - statement.executeUpdate(createDataStmt); - } finally { - closeQuietly(con); - } - } - - public PlayerProfile getProfile(String name, boolean fetch) { - if (profileCache.containsKey(name)) { - return profileCache.get(name); - } else if (fetch) { - Connection con = null; - try { - con = dataSource.getConnection(); - PreparedStatement loadStatement = con.prepareStatement("SELECT * FROM " + PREMIUM_TABLE - + " WHERE `Name`=? LIMIT 1"); - loadStatement.setString(1, name); - - ResultSet resultSet = loadStatement.executeQuery(); - if (resultSet.next()) { - long userId = resultSet.getInt(1); - - String unparsedUUID = resultSet.getString(2); - UUID uuid; - if (unparsedUUID == null) { - uuid = null; - } else { - uuid = FastLoginBungee.parseId(unparsedUUID); - } - -// String name = resultSet.getString(3); - boolean premium = resultSet.getBoolean(4); - String lastIp = resultSet.getString(5); - long lastLogin = resultSet.getTimestamp(6).getTime(); - PlayerProfile playerProfile = new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin); - profileCache.put(name, playerProfile); - return playerProfile; - } else { - PlayerProfile crackedProfile = new PlayerProfile(null, name, false, ""); - profileCache.put(name, crackedProfile); - return crackedProfile; - } - } catch (SQLException sqlEx) { - plugin.getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx); - } finally { - closeQuietly(con); - } - } - - return null; - } - - public boolean save(PlayerProfile playerProfile) { - Connection con = null; - try { - con = dataSource.getConnection(); - - UUID uuid = playerProfile.getUuid(); - - if (playerProfile.getUserId() == -1) { - PreparedStatement saveStatement = con.prepareStatement("INSERT INTO " + PREMIUM_TABLE - + " (UUID, Name, Premium, LastIp) VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); - - if (uuid == null) { - saveStatement.setString(1, null); - } else { - saveStatement.setString(1, uuid.toString().replace("-", "")); - } - - saveStatement.setString(2, playerProfile.getPlayerName()); - saveStatement.setBoolean(3, playerProfile.isPremium()); - saveStatement.setString(4, playerProfile.getLastIp()); - saveStatement.execute(); - - ResultSet generatedKeys = saveStatement.getGeneratedKeys(); - if (generatedKeys != null && generatedKeys.next()) { - playerProfile.setUserId(generatedKeys.getInt(1)); - } - } else { - PreparedStatement saveStatement = con.prepareStatement("UPDATE " + PREMIUM_TABLE - + " SET UUID=?, Name=?, Premium=?, LastIp=?, LastLogin=CURRENT_TIMESTAMP WHERE UserID=?"); - - if (uuid == null) { - saveStatement.setString(1, null); - } else { - saveStatement.setString(1, uuid.toString().replace("-", "")); - } - - saveStatement.setString(2, playerProfile.getPlayerName()); - saveStatement.setBoolean(3, playerProfile.isPremium()); - saveStatement.setString(4, playerProfile.getLastIp()); -// saveStatement.setTimestamp(5, new Timestamp(playerProfile.getLastLogin())); - - saveStatement.setLong(5, playerProfile.getUserId()); - saveStatement.execute(); - } - - return true; - } catch (SQLException ex) { - plugin.getLogger().log(Level.SEVERE, "Failed to save playerProfile", ex); - } finally { - closeQuietly(con); - } - - return false; - } - - public void close() { - dataSource.close(); - profileCache.clear(); - } - - private void closeQuietly(Connection con) { - if (con != null) { - try { - con.close(); - } catch (SQLException sqlEx) { - plugin.getLogger().log(Level.SEVERE, "Failed to close connection", sqlEx); - } - } - } -} diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/AsyncStatusMessage.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/AsyncStatusMessage.java new file mode 100644 index 00000000..6ee6726c --- /dev/null +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/AsyncStatusMessage.java @@ -0,0 +1,72 @@ +package com.github.games647.fastlogin.bungee.listener; + +import com.github.games647.fastlogin.bungee.FastLoginBungee; +import com.github.games647.fastlogin.core.PlayerProfile; + +import net.md_5.bungee.api.ChatColor; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.connection.ProxiedPlayer; + +public class AsyncStatusMessage implements Runnable { + + private final FastLoginBungee plugin; + private final ProxiedPlayer fromPlayer; + private final String targetPlayer; + private final boolean toPremium; + + public AsyncStatusMessage(FastLoginBungee plugin, ProxiedPlayer fromPlayer, String targetPlayer, boolean toPremium) { + this.plugin = plugin; + this.fromPlayer = fromPlayer; + this.targetPlayer = targetPlayer; + this.toPremium = toPremium; + } + + @Override + public void run() { + if (toPremium) { + activatePremium(); + } else { + turnOffPremium(); + } + } + + private void turnOffPremium() { + PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(targetPlayer, true); + if (!playerProfile.isPremium()) { + if (fromPlayer.isConnected()) { + TextComponent textComponent = new TextComponent("You are not in the premium list"); + textComponent.setColor(ChatColor.DARK_RED); + fromPlayer.sendMessage(textComponent); + } + + return; + } + + playerProfile.setPremium(false); + playerProfile.setUuid(null); + plugin.getCore().getStorage().save(playerProfile); + TextComponent textComponent = new TextComponent("Removed to the list of premium players"); + textComponent.setColor(ChatColor.DARK_GREEN); + fromPlayer.sendMessage(textComponent); + } + + private void activatePremium() { + PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(targetPlayer, true); + if (playerProfile.isPremium()) { + if (fromPlayer.isConnected()) { + TextComponent textComponent = new TextComponent("You are already on the premium list"); + textComponent.setColor(ChatColor.DARK_RED); + fromPlayer.sendMessage(textComponent); + } + + return; + } + + playerProfile.setPremium(true); + //todo: set uuid + plugin.getCore().getStorage().save(playerProfile); + TextComponent textComponent = new TextComponent("Added to the list of premium players"); + textComponent.setColor(ChatColor.DARK_GREEN); + fromPlayer.sendMessage(textComponent); + } +} diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java index 47bcd62b..3f0e9c0b 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java @@ -1,9 +1,9 @@ package com.github.games647.fastlogin.bungee.listener; +import com.github.games647.fastlogin.bungee.AsyncPremiumCheck; import com.github.games647.fastlogin.bungee.FastLoginBungee; import com.github.games647.fastlogin.bungee.ForceLoginTask; -import com.github.games647.fastlogin.bungee.PlayerProfile; -import com.github.games647.fastlogin.bungee.hooks.BungeeAuthPlugin; +import com.github.games647.fastlogin.core.PlayerProfile; import com.google.common.base.Charsets; import java.lang.reflect.Field; @@ -36,45 +36,13 @@ public class PlayerConnectionListener implements Listener { } @EventHandler - public void onPreLogin(final PreLoginEvent preLoginEvent) { + public void onPreLogin(PreLoginEvent preLoginEvent) { if (preLoginEvent.isCancelled()) { return; } preLoginEvent.registerIntent(plugin); - ProxyServer.getInstance().getScheduler().runAsync(plugin, new Runnable() { - @Override - public void run() { - PendingConnection connection = preLoginEvent.getConnection(); - String username = connection.getName(); - try { - PlayerProfile playerProfile = plugin.getStorage().getProfile(username, true); - if (playerProfile != null) { - if (playerProfile.isPremium()) { - if (playerProfile.getUserId() != -1) { - connection.setOnlineMode(true); - } - } else if (playerProfile.getUserId() == -1) { - //user not exists in the db - BungeeAuthPlugin authPlugin = plugin.getBungeeAuthPlugin(); - if (plugin.getConfiguration().getBoolean("autoRegister") - && (authPlugin == null || !authPlugin.isRegistered(username))) { - UUID premiumUUID = plugin.getMojangApiConnector().getPremiumUUID(username); - if (premiumUUID != null) { - plugin.getLogger().log(Level.FINER, "Player {0} uses a premium username", username); - connection.setOnlineMode(true); - plugin.getPendingAutoRegister().put(connection, new Object()); - } - } - } - } - } catch (Exception ex) { - plugin.getLogger().log(Level.SEVERE, "Failed to check premium state", ex); - } finally { - preLoginEvent.completeIntent(plugin); - } - } - }); + ProxyServer.getInstance().getScheduler().runAsync(plugin, new AsyncPremiumCheck(plugin, preLoginEvent)); } @EventHandler @@ -83,7 +51,7 @@ public class PlayerConnectionListener implements Listener { PendingConnection connection = player.getPendingConnection(); String username = connection.getName(); if (connection.isOnlineMode()) { - PlayerProfile playerProfile = plugin.getStorage().getProfile(player.getName(), false); + PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(player.getName(), false); playerProfile.setUuid(player.getUniqueId()); //bungeecord will do this automatically so override it on disabled option @@ -92,12 +60,11 @@ public class PlayerConnectionListener implements Listener { try { UUID offlineUUID = UUID.nameUUIDFromBytes(("OfflinePlayer:" + username).getBytes(Charsets.UTF_8)); + //bungeecord doesn't support overriding the premium uuid + //so we have to do it with reflection Field idField = initialHandler.getClass().getDeclaredField("uniqueId"); idField.setAccessible(true); idField.set(connection, offlineUUID); - - //bungeecord doesn't support overriding the premium uuid -// connection.setUniqueId(offlineUUID); } catch (NoSuchFieldException | IllegalAccessException ex) { plugin.getLogger().log(Level.SEVERE, "Failed to set offline uuid", ex); } diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java index 17e01906..e8989729 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java @@ -1,13 +1,11 @@ package com.github.games647.fastlogin.bungee.listener; import com.github.games647.fastlogin.bungee.FastLoginBungee; -import com.github.games647.fastlogin.bungee.PlayerProfile; +import com.github.games647.fastlogin.core.PlayerProfile; import com.google.common.io.ByteArrayDataInput; import com.google.common.io.ByteStreams; -import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ProxyServer; -import net.md_5.bungee.api.chat.TextComponent; import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.event.PluginMessageEvent; @@ -44,66 +42,25 @@ public class PluginMessageListener implements Listener { ByteArrayDataInput dataInput = ByteStreams.newDataInput(data); String subchannel = dataInput.readUTF(); - final ProxiedPlayer forPlayer = (ProxiedPlayer) pluginMessageEvent.getReceiver(); + ProxiedPlayer fromPlayer = (ProxiedPlayer) pluginMessageEvent.getReceiver(); if ("ON".equals(subchannel)) { - final String playerName = dataInput.readUTF(); + String playerName = dataInput.readUTF(); - ProxyServer.getInstance().getScheduler().runAsync(plugin, new Runnable() { - @Override - public void run() { - PlayerProfile playerProfile = plugin.getStorage().getProfile(playerName, true); - if (playerProfile.isPremium()) { - if (forPlayer.isConnected()) { - TextComponent textComponent = new TextComponent("You are already on the premium list"); - textComponent.setColor(ChatColor.DARK_RED); - forPlayer.sendMessage(textComponent); - } - - return; - } - - playerProfile.setPremium(true); - //todo: set uuid - plugin.getStorage().save(playerProfile); - TextComponent textComponent = new TextComponent("Added to the list of premium players"); - textComponent.setColor(ChatColor.DARK_GREEN); - forPlayer.sendMessage(textComponent); - } - }); + AsyncStatusMessage task = new AsyncStatusMessage(plugin, fromPlayer, playerName, true); + ProxyServer.getInstance().getScheduler().runAsync(plugin, task); } else if ("OFF".equals(subchannel)) { - final String playerName = dataInput.readUTF(); + String playerName = dataInput.readUTF(); - ProxyServer.getInstance().getScheduler().runAsync(plugin, new Runnable() { - @Override - public void run() { - PlayerProfile playerProfile = plugin.getStorage().getProfile(playerName, true); - if (!playerProfile.isPremium()) { - if (forPlayer.isConnected()) { - TextComponent textComponent = new TextComponent("You are not in the premium list"); - textComponent.setColor(ChatColor.DARK_RED); - forPlayer.sendMessage(textComponent); - } - - return; - } - - playerProfile.setPremium(false); - playerProfile.setUuid(null); - plugin.getStorage().save(playerProfile); - TextComponent textComponent = new TextComponent("Removed to the list of premium players"); - textComponent.setColor(ChatColor.DARK_GREEN); - forPlayer.sendMessage(textComponent); - } - }); + AsyncStatusMessage task = new AsyncStatusMessage(plugin, fromPlayer, playerName, false); + ProxyServer.getInstance().getScheduler().runAsync(plugin, task); } else if ("SUCCESS".equals(subchannel)) { - if (forPlayer.getPendingConnection().isOnlineMode()) { + if (fromPlayer.getPendingConnection().isOnlineMode()) { //bukkit module successfully received and force logged in the user //update only on success to prevent corrupt data - PlayerProfile playerProfile = plugin.getStorage().getProfile(forPlayer.getName(), false); + PlayerProfile playerProfile = plugin.getCore().getStorage().getProfile(fromPlayer.getName(), false); playerProfile.setPremium(true); //we override this in the loginevent -// playerProfile.setUuid(forPlayer.getUniqueId()); - plugin.getStorage().save(playerProfile); + plugin.getCore().getStorage().save(playerProfile); } } } diff --git a/core/pom.xml b/core/pom.xml new file mode 100644 index 00000000..0c6e7e84 --- /dev/null +++ b/core/pom.xml @@ -0,0 +1,32 @@ + + 4.0.0 + + + com.github.games647 + fastlogin + 1.4 + ../pom.xml + + + fastlogin.core + jar + + FastLoginCore + + + + + com.zaxxer + HikariCP + 2.4.6 + + + + + org.slf4j + slf4j-jdk14 + 1.7.21 + + + diff --git a/core/src/main/java/com/github/games647/fastlogin/core/FastLoginCore.java b/core/src/main/java/com/github/games647/fastlogin/core/FastLoginCore.java new file mode 100644 index 00000000..9b595139 --- /dev/null +++ b/core/src/main/java/com/github/games647/fastlogin/core/FastLoginCore.java @@ -0,0 +1,59 @@ +package com.github.games647.fastlogin.core; + +import java.io.File; +import java.util.UUID; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ThreadFactory; +import java.util.logging.Level; +import java.util.logging.Logger; + +public abstract class FastLoginCore { + + public static UUID parseId(String withoutDashes) { + return UUID.fromString(withoutDashes.substring(0, 8) + + "-" + withoutDashes.substring(8, 12) + + "-" + withoutDashes.substring(12, 16) + + "-" + withoutDashes.substring(16, 20) + + "-" + withoutDashes.substring(20, 32)); + } + + private MojangApiConnector mojangApiConnector; + private Storage storage; + + public void setMojangApiConnector(MojangApiConnector mojangApiConnector) { + this.mojangApiConnector = mojangApiConnector; + } + + public MojangApiConnector getMojangApiConnector() { + return mojangApiConnector; + } + + public Storage getStorage() { + return storage; + } + + public abstract File getDataFolder(); + + public abstract Logger getLogger(); + + public abstract ConcurrentMap buildCache(); + + public abstract ThreadFactory getThreadFactory(); + + public boolean setupDatabase(String driver, String host, int port, String database, String user, String password) { + storage = new Storage(this, driver, host, port, database, user, password); + try { + storage.createTables(); + return true; + } catch (Exception ex) { + getLogger().log(Level.SEVERE, "Failed to setup database. Disabling plugin...", ex); + return false; + } + } + + public void close() { + if (storage != null) { + storage.close(); + } + } +} diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiConnector.java b/core/src/main/java/com/github/games647/fastlogin/core/MojangApiConnector.java similarity index 74% rename from bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiConnector.java rename to core/src/main/java/com/github/games647/fastlogin/core/MojangApiConnector.java index 7d55b15b..7f84a9fc 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiConnector.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/MojangApiConnector.java @@ -1,6 +1,4 @@ -package com.github.games647.fastlogin.bungee; - -import com.google.gson.Gson; +package com.github.games647.fastlogin.core; import java.io.BufferedReader; import java.io.IOException; @@ -11,17 +9,12 @@ import java.util.UUID; import java.util.logging.Level; import java.util.regex.Pattern; -import net.md_5.bungee.BungeeCord; - -public class MojangApiConnector { +public abstract class MojangApiConnector { //http connection, read timeout and user agent for a connection to mojang api servers private static final int TIMEOUT = 1 * 1_000; private static final String USER_AGENT = "Premium-Checker"; - //mojang api check to prove a player is logged in minecraft and made a join server request - private static final String HAS_JOINED_URL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?"; - //only premium (paid account) users have a uuid from here private static final String UUID_LINK = "https://api.mojang.com/users/profiles/minecraft/"; //this includes a-zA-Z1-9_ @@ -30,11 +23,9 @@ public class MojangApiConnector { //compile the pattern only on plugin enable -> and this have to be threadsafe private final Pattern playernameMatcher = Pattern.compile(VALID_PLAYERNAME); - private final FastLoginBungee plugin; + protected final FastLoginCore plugin; - private final Gson gson = new Gson(); - - public MojangApiConnector(FastLoginBungee plugin) { + public MojangApiConnector(FastLoginCore plugin) { this.plugin = plugin; } @@ -53,8 +44,7 @@ public class MojangApiConnector { BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); String line = reader.readLine(); if (line != null && !line.equals("null")) { - MojangPlayer mojangPlayer = BungeeCord.getInstance().gson.fromJson(line, MojangPlayer.class); - return FastLoginBungee.parseId(mojangPlayer.getId()); + return getUUIDFromJson(line); } } //204 - no content for not found @@ -67,10 +57,14 @@ public class MojangApiConnector { return null; } - private HttpURLConnection getConnection(String url) throws IOException { + public abstract boolean hasJoinedServer(Object session, String serverId); + + protected abstract UUID getUUIDFromJson(String json); + + protected HttpURLConnection getConnection(String url) throws IOException { HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); connection.setConnectTimeout(TIMEOUT); - connection.setReadTimeout(TIMEOUT); + connection.setReadTimeout(2 * TIMEOUT); //the new Mojang API just uses json as response connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("User-Agent", USER_AGENT); diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/PlayerProfile.java b/core/src/main/java/com/github/games647/fastlogin/core/PlayerProfile.java similarity index 93% rename from bungee/src/main/java/com/github/games647/fastlogin/bungee/PlayerProfile.java rename to core/src/main/java/com/github/games647/fastlogin/core/PlayerProfile.java index af578218..1db2bcb6 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/PlayerProfile.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/PlayerProfile.java @@ -1,4 +1,4 @@ -package com.github.games647.fastlogin.bungee; +package com.github.games647.fastlogin.core; import java.util.UUID; @@ -40,7 +40,7 @@ public class PlayerProfile { return userId; } - protected synchronized void setUserId(long generatedId) { + public synchronized void setUserId(long generatedId) { this.userId = generatedId; } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/Storage.java b/core/src/main/java/com/github/games647/fastlogin/core/Storage.java similarity index 83% rename from bukkit/src/main/java/com/github/games647/fastlogin/bukkit/Storage.java rename to core/src/main/java/com/github/games647/fastlogin/core/Storage.java index d76e5cbf..b14d0c48 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/Storage.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/Storage.java @@ -1,7 +1,5 @@ -package com.github.games647.fastlogin.bukkit; +package com.github.games647.fastlogin.core; -import com.comphenix.protocol.utility.SafeCacheBuilder; -import com.google.common.cache.CacheLoader; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; @@ -12,38 +10,28 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.UUID; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.TimeUnit; import java.util.logging.Level; public class Storage { private static final String PREMIUM_TABLE = "premium"; - private final ConcurrentMap profileCache = SafeCacheBuilder - .newBuilder() - .concurrencyLevel(20) - .expireAfterAccess(30, TimeUnit.MINUTES) - .build(new CacheLoader() { - @Override - public PlayerProfile load(String key) throws Exception { - //should be fetched manually - throw new UnsupportedOperationException("Not supported yet."); - } - }); - + private final FastLoginCore core; + private final ConcurrentMap profileCache; private final HikariDataSource dataSource; - private final FastLoginBukkit plugin; - public Storage(FastLoginBukkit plugin, String driver, String host, int port, String databasePath + public Storage(FastLoginCore core, String driver, String host, int port, String databasePath , String user, String pass) { - this.plugin = plugin; + this.core = core; + this.profileCache = core.buildCache(); HikariConfig databaseConfig = new HikariConfig(); databaseConfig.setUsername(user); databaseConfig.setPassword(pass); databaseConfig.setDriverClassName(driver); + databaseConfig.setThreadFactory(core.getThreadFactory()); - databasePath = databasePath.replace("{pluginDir}", plugin.getDataFolder().getAbsolutePath()); + databasePath = databasePath.replace("{pluginDir}", core.getDataFolder().getAbsolutePath()); String jdbcUrl = "jdbc:"; if (driver.contains("sqlite")) { @@ -104,7 +92,7 @@ public class Storage { if (unparsedUUID == null) { uuid = null; } else { - uuid = FastLoginBukkit.parseId(unparsedUUID); + uuid = FastLoginCore.parseId(unparsedUUID); } // String name = resultSet.getString(3); @@ -120,7 +108,7 @@ public class Storage { return crackedProfile; } } catch (SQLException sqlEx) { - plugin.getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx); + core.getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx); } finally { closeQuietly(con); } @@ -176,7 +164,7 @@ public class Storage { return true; } catch (SQLException ex) { - plugin.getLogger().log(Level.SEVERE, "Failed to save playerProfile", ex); + core.getLogger().log(Level.SEVERE, "Failed to save playerProfile", ex); } finally { closeQuietly(con); } @@ -194,7 +182,7 @@ public class Storage { try { con.close(); } catch (SQLException sqlEx) { - plugin.getLogger().log(Level.SEVERE, "Failed to close connection", sqlEx); + core.getLogger().log(Level.SEVERE, "Failed to close connection", sqlEx); } } } diff --git a/bukkit/src/main/resources/config.yml b/core/src/main/resources/config.yml similarity index 97% rename from bukkit/src/main/resources/config.yml rename to core/src/main/resources/config.yml index 279df83b..38996455 100644 --- a/bukkit/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -3,7 +3,7 @@ # Source code: https://github.com/games647/FastLogin # # You can access the newest config here: -# https://github.com/games647/FastLogin/blob/master/bukkit/src/main/resources/config.yml +# https://github.com/games647/FastLogin/blob/master/core/src/main/resources/config.yml # Request a premium login without forcing the player to type a command # diff --git a/core/src/main/resources/messages.yml b/core/src/main/resources/messages.yml new file mode 100644 index 00000000..34662b1f --- /dev/null +++ b/core/src/main/resources/messages.yml @@ -0,0 +1,18 @@ +# FastLogin localization +# Project site: https://www.spigotmc.org/resources/fastlogin.14153 +# Source code: https://github.com/games647/FastLogin +# +# You can access the newest locale here: +# https://github.com/games647/FastLogin/blob/master/core/src/main/resources/messages.yml + +# ========= Shared (BungeeCord an Bukkit) ============ + + + +# ========= Bukkit only ================================ + + + +# ========= Bungee only ================================ + + diff --git a/pom.xml b/pom.xml index ae394f0f..0f9302de 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ pom FastLogin - 1.3.1 + 1.4 2015 https://www.spigotmc.org/resources/fastlogin.14153/ @@ -22,6 +22,7 @@ + core bukkit bungee universal @@ -83,20 +84,4 @@ - - - - - com.zaxxer - HikariCP - 2.4.6 - - - - - org.slf4j - slf4j-jdk14 - 1.7.21 - - diff --git a/universal/pom.xml b/universal/pom.xml index 1d962491..79c0552e 100644 --- a/universal/pom.xml +++ b/universal/pom.xml @@ -5,7 +5,7 @@ com.github.games647 fastlogin - 1.3.1 + 1.4 ../pom.xml @@ -47,6 +47,12 @@ + + ${project.groupId} + fastlogin.core + ${project.version} + + ${project.groupId} fastlogin.bukkit