diff --git a/CHANGELOG.md b/CHANGELOG.md index a0448da3..38a9c3fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,8 @@ ######1.3 -* Add support for AuthMe 3.X +* Added support for AuthMe 3.X * Fixed premium logins if the server is not fully started +* Added other command argument to /premium and /cracked ######1.2.1 diff --git a/README.md b/README.md index 76095035..f2cc4698 100644 --- a/README.md +++ b/README.md @@ -31,9 +31,10 @@ So they don't need to enter passwords. This is also called auto login (auto-logi ###Permissions: * fastlogin.bukkit.command.premium + * fastlogin.bukkit.command.cracked ###Requirements: -* Plugin: [ProtocolLib](http://www.spigotmc.org/resources/protocollib.1997/) +* Plugin: [ProtocolLib](http://www.spigotmc.org/resources/protocollib.1997/) or [ProtocolSupport](http://www.spigotmc.org/resources/protocolsupport.7201/) * Tested Bukkit/[Spigot](https://www.spigotmc.org) 1.9 (could also work with other versions) * Java 7+ * Run Spigot and/or BungeeCord/Waterfall in offline mode (see server.properties or config.yml) 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 062d77da..aa2f55f1 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 @@ -29,15 +29,12 @@ public class CrackedCommand implements CommandExecutor { return true; } - final Player player = (Player) sender; -// UUID uuid = player.getUniqueId(); - if (plugin.isBungeeCord()) { - notifiyBungeeCord((Player) sender); + notifiyBungeeCord(sender, sender.getName()); sender.sendMessage(ChatColor.YELLOW + "Sending request..."); } else { //todo: load async if it's not in the cache anymore - final PlayerProfile profile = plugin.getStorage().getProfile(player.getName(), true); + final PlayerProfile profile = plugin.getStorage().getProfile(sender.getName(), true); if (profile.isPremium()) { sender.sendMessage(ChatColor.DARK_GREEN + "Removed from the list of premium players"); profile.setPremium(false); @@ -55,27 +52,58 @@ public class CrackedCommand implements CommandExecutor { return true; } else { - sender.sendMessage(ChatColor.DARK_RED + "NOT IMPLEMENTED YET"); - //todo: -// String playerName = args[0]; -// boolean existed = plugin.getEnabledPremium().remove(playerName); -// if (existed) { -// sender.sendMessage(ChatColor.DARK_GREEN + "Removed from the list of premium players"); -// notifiyBungeeCord((Player) sender); -// } else { -// sender.sendMessage(ChatColor.DARK_RED + "User is not in the premium list"); -// } + if (!sender.hasPermission(command.getPermission() + ".other")) { + sender.sendMessage(ChatColor.DARK_RED + "Not enough permissions"); + return true; + } + + if (plugin.isBungeeCord()) { + notifiyBungeeCord(sender, args[0]); + 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); + if (profile == null) { + sender.sendMessage(ChatColor.DARK_RED + "Player not in the database"); + return true; + } + + if (profile.isPremium()) { + sender.sendMessage(ChatColor.DARK_GREEN + "Removed from the list of premium players"); + profile.setPremium(false); + profile.setUuid(null); + Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { + @Override + public void run() { + plugin.getStorage().save(profile); + } + }); + } else { + sender.sendMessage(ChatColor.DARK_RED + "Player is not in the premium list"); + } + } } return true; } - private void notifiyBungeeCord(Player target) { + private void notifiyBungeeCord(CommandSender sender, String target) { + if (sender instanceof Player) { + notifiyBungeeCord(sender, target); + } else { + //todo: add console support +// Player firstPlayer = Iterables.getFirst(Bukkit.getOnlinePlayers(), null); +// notifiyBungeeCord(firstPlayer, target); + } + } + + private void notifiyBungeeCord(Player sender, String target) { if (plugin.isBungeeCord()) { ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput(); dataOutput.writeUTF("OFF"); + dataOutput.writeUTF(target); - target.sendPluginMessage(plugin, plugin.getName(), dataOutput.toByteArray()); + plugin.getLogger().info("No player online to send a plugin message to the proxy"); } } } 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 45635811..395a7109 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 @@ -34,15 +34,12 @@ public class PremiumCommand implements CommandExecutor { return true; } - Player player = (Player) sender; -// UUID uuid = player.getUniqueId(); - if (plugin.isBungeeCord()) { - notifiyBungeeCord(player); + notifiyBungeeCord(sender, sender.getName()); sender.sendMessage(ChatColor.YELLOW + "Sending request..."); } else { // //todo: load async if it's not in the cache anymore - final PlayerProfile profile = plugin.getStorage().getProfile(player.getName(), true); + final PlayerProfile profile = plugin.getStorage().getProfile(sender.getName(), true); if (profile.isPremium()) { sender.sendMessage(ChatColor.DARK_RED + "You are already on the premium list"); } else { @@ -61,27 +58,59 @@ public class PremiumCommand implements CommandExecutor { return true; } else { - sender.sendMessage(ChatColor.DARK_RED + "NOT IMPLEMENTED YET"); - //todo: async load -// String playerName = args[0]; -// boolean didntexist = plugin.getEnabledPremium().add(playerName); -// if (!didntexist) { -// sender.sendMessage(ChatColor.DARK_RED + "You are already on the premium list"); -// } else { -// sender.sendMessage(ChatColor.DARK_GREEN + "Added to the list of premium players"); -// } -// notifiyBungeeCord(); + if (!sender.hasPermission(command.getPermission() + ".other")) { + sender.sendMessage(ChatColor.DARK_RED + "Not enough permissions"); + return true; + } + + if (plugin.isBungeeCord()) { + notifiyBungeeCord(sender, args[0]); + 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); + if (profile == null) { + sender.sendMessage(ChatColor.DARK_RED + "Player not in the database"); + return true; + } + + if (profile.isPremium()) { + sender.sendMessage(ChatColor.DARK_RED + "Player is already on the premium list"); + } else { + //todo: resolve uuid + profile.setPremium(true); + Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { + @Override + public void run() { + plugin.getStorage().save(profile); + } + }); + + sender.sendMessage(ChatColor.DARK_GREEN + "Added to the list of premium players"); + } + } } return true; } - private void notifiyBungeeCord(Player target) { + private void notifiyBungeeCord(CommandSender sender, String target) { + if (sender instanceof Player) { + notifiyBungeeCord(sender, target); + } else { + //todo: add console support +// Player firstPlayer = Iterables.getFirst(Bukkit.getOnlinePlayers(), null); +// notifiyBungeeCord(firstPlayer, target); + } + } + + private void notifiyBungeeCord(Player sender, String target) { if (plugin.isBungeeCord()) { ByteArrayDataOutput dataOutput = ByteStreams.newDataOutput(); dataOutput.writeUTF("ON"); + dataOutput.writeUTF(target); - target.sendPluginMessage(plugin, plugin.getName(), dataOutput.toByteArray()); + sender.sendPluginMessage(plugin, plugin.getName(), dataOutput.toByteArray()); } } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/LoginSecurityHook.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/LoginSecurityHook.java index fed0598e..e22e2ba3 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/LoginSecurityHook.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/hooks/LoginSecurityHook.java @@ -72,12 +72,12 @@ public class LoginSecurityHook implements BukkitAuthPlugin { @Override public boolean forceRegister(final Player player, final String password) { - final DataManager dataManager = securityPlugin.data; + DataManager dataManager = securityPlugin.data; UUID playerUUID = player.getUniqueId(); - final String uuidString = playerUUID.toString().replace("-", ""); - final InetAddress ipAddress = player.getAddress().getAddress(); - final String passwordHash = securityPlugin.hasher.hash(password); + String uuidString = playerUUID.toString().replace("-", ""); + InetAddress ipAddress = player.getAddress().getAddress(); + String passwordHash = securityPlugin.hasher.hash(password); //this executes a sql query without interacting with other parts so we can run it async. dataManager.register(uuidString, passwordHash, securityPlugin.hasher.getTypeId(), ipAddress.toString()); diff --git a/bukkit/src/main/resources/plugin.yml b/bukkit/src/main/resources/plugin.yml index 7fdc8c91..cbf0d57b 100644 --- a/bukkit/src/main/resources/plugin.yml +++ b/bukkit/src/main/resources/plugin.yml @@ -47,11 +47,11 @@ permissions: children: ${project.artifactId}.command.premium: true - ${project.artifactId}.command.unpremium: + ${project.artifactId}.command.cracked: description: 'Label themselves as cracked' default: true - ${project.artifactId}.command..unpremium.other: + ${project.artifactId}.command..cracked.other: description: 'Label others as cracked' children: - ${project.artifactId}.command.unpremium: true \ No newline at end of file + ${project.artifactId}.command.cracked: true \ No newline at end of file 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 3047ab75..600b238e 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,7 +1,9 @@ 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.PluginMessageListener; import com.google.common.cache.CacheBuilder; import java.io.File; @@ -85,6 +87,7 @@ public class FastLoginBungee extends Plugin { //events getProxy().getPluginManager().registerListener(this, new PlayerConnectionListener(this)); + getProxy().getPluginManager().registerListener(this, new PluginMessageListener(this)); //this is required to listen to messages from the server getProxy().registerChannel(getDescription().getName()); diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/hooks/BungeeAuthHook.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/hooks/BungeeAuthHook.java index e5d8fe57..033e83cc 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/hooks/BungeeAuthHook.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/hooks/BungeeAuthHook.java @@ -25,14 +25,14 @@ public class BungeeAuthHook implements BungeeAuthPlugin { private final Tables databaseConnection = new Tables(); @Override - public boolean forceLogin(final ProxiedPlayer player) { + public boolean forceLogin(ProxiedPlayer player) { //https://github.com/MatteCarra/BungeeAuth/blob/master/src/me/vik1395/BungeeAuth/Login.java#L92-95 Main.plonline.add(player.getName()); //renamed from ct to databaseConnection // databaseConnection.setStatus(player.getName(), "online"); - final Class[] parameterTypes = new Class[]{String.class, String.class}; - final Object[] arguments = new Object[]{player.getName(), "online"}; + Class[] parameterTypes = new Class[]{String.class, String.class}; + Object[] arguments = new Object[]{player.getName(), "online"}; try { callProtected("setStatus", parameterTypes, arguments); @@ -56,7 +56,7 @@ public class BungeeAuthHook implements BungeeAuthPlugin { } @Override - public boolean forceRegister(final ProxiedPlayer player, String password) { + public boolean forceRegister(ProxiedPlayer player, String password) { //https://github.com/MatteCarra/BungeeAuth/blob/master/src/me/vik1395/BungeeAuth/Register.java#L102 PasswordHandler ph = new PasswordHandler(); Random rand = new Random(); @@ -77,9 +77,9 @@ public class BungeeAuthHook implements BungeeAuthPlugin { //renamed t to databaseConnection // databaseConnection.newPlayerEntry(player.getName(), hash, pType, "", lastip, regdate, lastip, lastseen); - final Class[] parameterTypes = new Class[] {String.class, String.class, String.class, String.class + Class[] parameterTypes = new Class[] {String.class, String.class, String.class, String.class , String.class, String.class, String.class, String.class}; - final Object[] arguments = new Object[] {player.getName(), hash, pType, "", lastip, regdate, lastip, lastseen}; + Object[] arguments = new Object[] {player.getName(), hash, pType, "", lastip, regdate, lastip, lastseen}; try { callProtected("newPlayerEntry", parameterTypes, arguments); diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/PlayerConnectionListener.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java similarity index 54% rename from bungee/src/main/java/com/github/games647/fastlogin/bungee/PlayerConnectionListener.java rename to bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java index e85bfea7..a096df6f 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/PlayerConnectionListener.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java @@ -1,21 +1,18 @@ -package com.github.games647.fastlogin.bungee; +package com.github.games647.fastlogin.bungee.listener; +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.google.common.base.Charsets; -import com.google.common.io.ByteArrayDataInput; -import com.google.common.io.ByteStreams; import java.lang.reflect.Field; import java.util.UUID; import java.util.logging.Level; -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.PendingConnection; import net.md_5.bungee.api.connection.ProxiedPlayer; -import net.md_5.bungee.api.connection.Server; -import net.md_5.bungee.api.event.PluginMessageEvent; import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.event.PreLoginEvent; import net.md_5.bungee.api.event.ServerConnectedEvent; @@ -122,82 +119,4 @@ public class PlayerConnectionListener implements Listener { ForceLoginTask loginTask = new ForceLoginTask(plugin, player, serverConnectedEvent.getServer()); ProxyServer.getInstance().getScheduler().runAsync(plugin, loginTask); } - - @EventHandler - public void onPluginMessage(PluginMessageEvent pluginMessageEvent) { - String channel = pluginMessageEvent.getTag(); - if (pluginMessageEvent.isCancelled() || !plugin.getDescription().getName().equals(channel)) { - return; - } - - //the client shouldn't be able to read the messages in order to know something about server internal states - //moreover the client shouldn't be able fake a running premium check by sending the result message - pluginMessageEvent.setCancelled(true); - - //check if the message is sent from the server - if (Server.class.isAssignableFrom(pluginMessageEvent.getSender().getClass())) { - byte[] data = pluginMessageEvent.getData(); - ByteArrayDataInput dataInput = ByteStreams.newDataInput(data); - String subchannel = dataInput.readUTF(); - - final ProxiedPlayer forPlayer = (ProxiedPlayer) pluginMessageEvent.getReceiver(); - if ("ON".equals(subchannel)) { - ProxyServer.getInstance().getScheduler().runAsync(plugin, new Runnable() { - @Override - public void run() { - PlayerProfile playerProfile = plugin.getStorage().getProfile(forPlayer.getName(), 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); - } - }); - } else if ("OFF".equals(subchannel)) { - ProxyServer.getInstance().getScheduler().runAsync(plugin, new Runnable() { - @Override - public void run() { - PlayerProfile playerProfile = plugin.getStorage().getProfile(forPlayer.getName(), 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); - } - }); - } else if ("SUCCESS".equals(subchannel)) { - if (forPlayer.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.setPremium(true); - //we override this in the loginevent -// playerProfile.setUuid(forPlayer.getUniqueId()); - plugin.getStorage().save(playerProfile); - } - } - } - } } 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 new file mode 100644 index 00000000..17e01906 --- /dev/null +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PluginMessageListener.java @@ -0,0 +1,110 @@ +package com.github.games647.fastlogin.bungee.listener; + +import com.github.games647.fastlogin.bungee.FastLoginBungee; +import com.github.games647.fastlogin.bungee.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; +import net.md_5.bungee.api.plugin.Listener; +import net.md_5.bungee.event.EventHandler; + +public class PluginMessageListener implements Listener { + + protected final FastLoginBungee plugin; + + public PluginMessageListener(FastLoginBungee plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onPluginMessage(PluginMessageEvent pluginMessageEvent) { + String channel = pluginMessageEvent.getTag(); + if (pluginMessageEvent.isCancelled() || !plugin.getDescription().getName().equals(channel)) { + return; + } + + //the client shouldn't be able to read the messages in order to know something about server internal states + //moreover the client shouldn't be able fake a running premium check by sending the result message + pluginMessageEvent.setCancelled(true); + + //check if the message is sent from the server + if (Server.class.isAssignableFrom(pluginMessageEvent.getSender().getClass())) { + readMessage(pluginMessageEvent); + } + } + + private void readMessage(PluginMessageEvent pluginMessageEvent) { + byte[] data = pluginMessageEvent.getData(); + ByteArrayDataInput dataInput = ByteStreams.newDataInput(data); + String subchannel = dataInput.readUTF(); + + final ProxiedPlayer forPlayer = (ProxiedPlayer) pluginMessageEvent.getReceiver(); + if ("ON".equals(subchannel)) { + final 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); + } + }); + } else if ("OFF".equals(subchannel)) { + final 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); + } + }); + } else if ("SUCCESS".equals(subchannel)) { + if (forPlayer.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.setPremium(true); + //we override this in the loginevent +// playerProfile.setUuid(forPlayer.getUniqueId()); + plugin.getStorage().save(playerProfile); + } + } + } +}