summaryrefslogtreecommitdiff
path: root/src/main/java/com/redstoner/modules/loginsecurity
diff options
context:
space:
mode:
authorDavid <david@panic.tk>2018-11-07 23:50:06 +0100
committerDavid <david@panic.tk>2018-11-07 23:50:06 +0100
commit604cf01967ede98bf5024e4926bb0777fc4e8eee (patch)
treee2fa63d7e683769ee3bf3eddc75280648e92eb04 /src/main/java/com/redstoner/modules/loginsecurity
parente86c52ef7c0e1e33c6af0e8674b038976bec11cc (diff)
Converted Modules to gradle
Diffstat (limited to 'src/main/java/com/redstoner/modules/loginsecurity')
-rw-r--r--src/main/java/com/redstoner/modules/loginsecurity/CancelledEventsHandler.java95
-rw-r--r--src/main/java/com/redstoner/modules/loginsecurity/CryptographyHandler.java53
-rw-r--r--src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.cmd49
-rw-r--r--src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.java263
-rw-r--r--src/main/java/com/redstoner/modules/loginsecurity/RepeatingLoginRunnable.java37
5 files changed, 497 insertions, 0 deletions
diff --git a/src/main/java/com/redstoner/modules/loginsecurity/CancelledEventsHandler.java b/src/main/java/com/redstoner/modules/loginsecurity/CancelledEventsHandler.java
new file mode 100644
index 0000000..e39d781
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/loginsecurity/CancelledEventsHandler.java
@@ -0,0 +1,95 @@
+package com.redstoner.modules.loginsecurity;
+
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+import org.bukkit.event.player.AsyncPlayerChatEvent;
+import org.bukkit.event.player.PlayerCommandPreprocessEvent;
+import org.bukkit.event.player.PlayerDropItemEvent;
+import org.bukkit.event.player.PlayerInteractEvent;
+import org.bukkit.event.player.PlayerItemHeldEvent;
+import org.bukkit.event.player.PlayerMoveEvent;
+import org.bukkit.event.player.PlayerPickupArrowEvent;
+import org.bukkit.event.player.PlayerPickupItemEvent;
+
+public class CancelledEventsHandler implements Listener {
+ private LoginSecurity mainClass;
+
+ public CancelledEventsHandler(LoginSecurity mainClass) {
+ this.mainClass = mainClass;
+ }
+
+ @EventHandler
+ public void onMove(PlayerMoveEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.getPlayer().teleport(LoginSecurity.loggingIn.get(e.getPlayer().getUniqueId()));
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onChat(AsyncPlayerChatEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.getPlayer().sendMessage(ChatColor.RED + "You must login before you can chat!");
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onCommand(PlayerCommandPreprocessEvent e) {
+ String command = e.getMessage();
+
+ if (!command.startsWith("/login") && isLoggingIn(e.getPlayer())) {
+ e.getPlayer().sendMessage(ChatColor.RED + "You must login before you can execute commands!");
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onItemHold(PlayerItemHeldEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onItemPickup(PlayerPickupItemEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onItemDrop(PlayerDropItemEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onInteract(PlayerInteractEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onArrowPickup(PlayerPickupArrowEvent e) {
+ if (isLoggingIn(e.getPlayer())) {
+ e.setCancelled(true);
+ }
+ }
+
+ @EventHandler(priority = EventPriority.HIGHEST)
+ public void onInvClick(InventoryClickEvent e) {
+ if (e.getWhoClicked() instanceof Player && isLoggingIn((Player) e.getWhoClicked())) {
+ e.setCancelled(true);
+ }
+ }
+
+ private boolean isLoggingIn(Player player) {
+ return mainClass.isLoggingIn(player);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/loginsecurity/CryptographyHandler.java b/src/main/java/com/redstoner/modules/loginsecurity/CryptographyHandler.java
new file mode 100644
index 0000000..48e81a9
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/loginsecurity/CryptographyHandler.java
@@ -0,0 +1,53 @@
+package com.redstoner.modules.loginsecurity;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.SecureRandom;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.util.Base64;
+
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
+public class CryptographyHandler {
+ public static String hash(String password, String salt) {
+ String algorithm = "PBKDF2WithHmacSHA256";
+ int derivedKeyLength = 256;
+ int iterations = 200000;
+ byte[] decodedSalt = Base64.getDecoder().decode(salt.getBytes());
+
+ KeySpec spec = new PBEKeySpec(password.toCharArray(), decodedSalt, iterations, derivedKeyLength);
+
+ byte[] hashed = null;
+
+ try {
+ SecretKeyFactory f = SecretKeyFactory.getInstance(algorithm);
+
+ hashed = f.generateSecret(spec).getEncoded();
+ } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+
+ return Base64.getEncoder().encodeToString(hashed).substring(0, 43);
+ }
+
+ public static boolean verify(String password, String salt, String hash) {
+ return hash(password, salt).equals(hash);
+ }
+
+ public static boolean verify(String password, String stored) {
+ String[] split = stored.split("\\$");
+
+ return verify(password, split[3], split[4]);
+ }
+
+ public static String generateSalt() throws NoSuchAlgorithmException, NoSuchProviderException {
+ SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
+
+ byte[] salt = new byte[16];
+ random.nextBytes(salt);
+
+ return Base64.getEncoder().encodeToString(salt).substring(0, 22);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.cmd b/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.cmd
new file mode 100644
index 0000000..952b3ed
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.cmd
@@ -0,0 +1,49 @@
+command register {
+ perm utils.loginsecurity;
+
+ [string:password] {
+ run register password;
+ help Protects your account with a password;
+ type player;
+ }
+}
+
+command login {
+ perm utils.loginsecurity;
+
+ [string:password] {
+ run login password;
+ help Logs you in;
+ type player;
+ }
+}
+
+command cgpass {
+ perm utils.loginsecurity;
+
+ [string:oldPassword] [string:newPassword] {
+ run cgpass oldPassword newPassword;
+ help Changes your password to the specified one;
+ type player;
+ }
+}
+
+command rmpass {
+ perm utils.loginsecurity;
+
+ [string:oldPassword] {
+ run rmpass oldPassword;
+ help Removes the password of your account;
+ type player;
+ }
+}
+
+command rmotherpass {
+ perm utils.loginsecurity.admin;
+
+ [string:playerName] {
+ run rmotherpass playerName;
+ help removes the password of another player;
+ perm utils.loginsecurity.admin;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.java b/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.java
new file mode 100644
index 0000000..7bcb89a
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/loginsecurity/LoginSecurity.java
@@ -0,0 +1,263 @@
+package com.redstoner.modules.loginsecurity;
+
+import java.io.Serializable;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.scheduler.BukkitScheduler;
+
+import com.nemez.cmdmgr.Command;
+import com.redstoner.annotations.AutoRegisterListener;
+import com.redstoner.annotations.Commands;
+import com.redstoner.annotations.Version;
+import com.redstoner.misc.CommandHolderType;
+import com.redstoner.misc.Main;
+import com.redstoner.misc.mysql.JSONManager;
+import com.redstoner.misc.mysql.MysqlHandler;
+import com.redstoner.misc.mysql.elements.ConstraintOperator;
+import com.redstoner.misc.mysql.elements.MysqlConstraint;
+import com.redstoner.misc.mysql.elements.MysqlDatabase;
+import com.redstoner.misc.mysql.elements.MysqlField;
+import com.redstoner.misc.mysql.elements.MysqlTable;
+import com.redstoner.misc.mysql.types.text.VarChar;
+import com.redstoner.modules.Module;
+
+@Commands(CommandHolderType.File)
+@AutoRegisterListener
+@Version(major = 4, minor = 1, revision = 0, compatible = 4)
+public class LoginSecurity implements Module, Listener
+{
+ protected static Map<UUID, Location> loggingIn;
+ private MysqlTable table;
+
+ @Override
+ public boolean onEnable()
+ {
+ Map<Serializable, Serializable> config = JSONManager.getConfiguration("loginsecurity.json");
+ if (config == null || !config.containsKey("database") || !config.containsKey("table"))
+ {
+ getLogger().message(Bukkit.getConsoleSender(), true,
+ "Could not load the LoginSecurity config file, disabling!");
+ return false;
+ }
+ try
+ {
+ MysqlDatabase database = MysqlHandler.INSTANCE.getDatabase((String) config.get("database"));
+ MysqlField uuid = new MysqlField("uuid", new VarChar(36), true);
+ MysqlField pass = new MysqlField("pass", new VarChar(88), true);
+ database.createTableIfNotExists((String) config.get("table"), uuid, pass);
+ table = database.getTable((String) config.get("table"));
+ }
+ catch (NullPointerException e)
+ {
+ getLogger().message(Bukkit.getConsoleSender(), true, "Could not use the LoginSecurity config, disabling!");
+ return false;
+ }
+ loggingIn = new HashMap<>();
+ Bukkit.getServer().getPluginManager().registerEvents(new CancelledEventsHandler(this), Main.plugin);
+ return true;
+ }
+
+ public static Map<UUID, Location> getLoggingIn()
+ {
+ return loggingIn;
+ }
+
+ @Command(hook = "register")
+ public void register(CommandSender sender, String password)
+ {
+ Player player = (Player) sender;
+ if (isRegistered(player))
+ {
+ player.sendMessage(ChatColor.GREEN + "You are already registered!");
+ return;
+ }
+ try
+ {
+ if (registerPlayer(player, password))
+ {
+ player.sendMessage(ChatColor.GREEN + "Succesfully registered!");
+ return;
+ }
+ }
+ catch (NoSuchAlgorithmException | NoSuchProviderException e)
+ {
+ e.printStackTrace();
+ }
+ player.sendMessage(ChatColor.RED + "Failed to register, please contact an admin!");
+ }
+
+ @Command(hook = "login")
+ public void login(CommandSender sender, String password)
+ {
+ Player player = (Player) sender;
+ if (!isRegistered(player))
+ {
+ player.sendMessage(ChatColor.RED + "You are not registered!");
+ return;
+ }
+ if (CryptographyHandler.verify(password, getHash(player)))
+ {
+ loggingIn.remove(player.getUniqueId());
+ }
+ else
+ {
+ player.sendMessage(ChatColor.RED + "Wrong password!");
+ }
+ }
+
+ @Command(hook = "cgpass")
+ public void cgpass(CommandSender sender, String oldPassword, String newPassword)
+ {
+ Player player = (Player) sender;
+ if (!isRegistered(player))
+ {
+ player.sendMessage(ChatColor.RED + "You are not registered!");
+ return;
+ }
+ if (!CryptographyHandler.verify(oldPassword, getHash(player)))
+ {
+ player.sendMessage(ChatColor.RED + "The old password you entered is wrong!");
+ return;
+ }
+ if (oldPassword.equals(newPassword))
+ {
+ player.sendMessage(ChatColor.RED + "You entered the same password!");
+ return;
+ }
+ if (table.delete(getUuidConstraint(player)))
+ {
+ try
+ {
+ registerPlayer(player, newPassword);
+ player.sendMessage(ChatColor.GREEN + "Succesfully changed password!");
+ }
+ catch (NoSuchAlgorithmException | NoSuchProviderException e)
+ {
+ e.printStackTrace();
+ player.sendMessage(ChatColor.RED + "Failed to set new password!");
+ }
+ }
+ else
+ {
+ player.sendMessage(ChatColor.RED + "Failed to remove old password from database!");
+ }
+ }
+
+ @Command(hook = "rmpass")
+ public void rmpass(CommandSender sender, String oldPassword)
+ {
+ Player player = (Player) sender;
+ if (!isRegistered(player))
+ {
+ player.sendMessage(ChatColor.RED + "You are not registered!");
+ return;
+ }
+ if (!CryptographyHandler.verify(oldPassword, getHash(player)))
+ {
+ player.sendMessage(ChatColor.RED + "The old password you entered is wrong!");
+ return;
+ }
+ if (table.delete(getUuidConstraint(player)))
+ {
+ player.sendMessage(ChatColor.GREEN + "Succesfully removed password!");
+ }
+ else
+ {
+ player.sendMessage(ChatColor.RED + "Failed to remove old password from database!");
+ }
+ }
+
+ @Command(hook = "rmotherpass")
+ public void rmotherpass(CommandSender sender, String playerName)
+ {
+ if (playerName.equals(""))
+ {
+ sender.sendMessage(ChatColor.RED + "That's not a valid player!");
+ return;
+ }
+ @SuppressWarnings("deprecation")
+ OfflinePlayer player = Bukkit.getOfflinePlayer(playerName);
+ if (!isRegistered(player))
+ {
+ sender.sendMessage(ChatColor.RED + "That player is not registered!");
+ return;
+ }
+ if (table.delete(getUuidConstraint(player)))
+ {
+ sender.sendMessage(ChatColor.GREEN + "Successfully removed " + playerName + "'s password!");
+ }
+ else
+ {
+ sender.sendMessage(ChatColor.RED + "Failed to remove " + playerName + "'s password!");
+ }
+ }
+
+ @EventHandler
+ public void onJoin(PlayerJoinEvent e)
+ {
+ Player player = e.getPlayer();
+ if (!isRegistered(player))
+ {
+ return;
+ }
+ getLogger().message(player, "You'll have to log in within 60s or you'll be kicked!");
+ loggingIn.put(player.getUniqueId(), player.getLocation());
+ BukkitScheduler scheduler = Bukkit.getScheduler();
+ RepeatingLoginRunnable repeatingRunnable = new RepeatingLoginRunnable(this, player);
+ repeatingRunnable.setId(scheduler.scheduleSyncRepeatingTask(Main.plugin, repeatingRunnable, 0L, 2L));
+ scheduler.scheduleSyncDelayedTask(Main.plugin, new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ if (isLoggingIn(player))
+ {
+ scheduler.cancelTask(repeatingRunnable.getId());
+ player.kickPlayer("You didn't login in time!");
+ }
+ }
+ }, 1200L);
+ }
+
+ public boolean isLoggingIn(Player player)
+ {
+ return loggingIn.containsKey(player.getUniqueId());
+ }
+
+ public MysqlConstraint getUuidConstraint(OfflinePlayer player)
+ {
+ return new MysqlConstraint("uuid", ConstraintOperator.EQUAL, player.getUniqueId().toString());
+ }
+
+ public boolean isRegistered(OfflinePlayer player)
+ {
+ return table.get("uuid", getUuidConstraint(player)).length > 0;
+ }
+
+ public String getHash(OfflinePlayer player)
+ {
+ return (String) table.get("pass", getUuidConstraint(player))[0];
+ }
+
+ public boolean registerPlayer(Player player, String password)
+ throws NoSuchAlgorithmException, NoSuchProviderException
+ {
+ String salt = CryptographyHandler.generateSalt();
+ String hash = CryptographyHandler.hash(password, salt);
+ String toInsert = "$pbkdf2-sha256$200000$" + salt + "$" + hash;
+ return table.insert(player.getUniqueId().toString(), toInsert);
+ }
+}
diff --git a/src/main/java/com/redstoner/modules/loginsecurity/RepeatingLoginRunnable.java b/src/main/java/com/redstoner/modules/loginsecurity/RepeatingLoginRunnable.java
new file mode 100644
index 0000000..4e8db6d
--- /dev/null
+++ b/src/main/java/com/redstoner/modules/loginsecurity/RepeatingLoginRunnable.java
@@ -0,0 +1,37 @@
+package com.redstoner.modules.loginsecurity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.entity.Player;
+
+public class RepeatingLoginRunnable implements Runnable {
+ private int id = -1;
+ private Player player;
+ private LoginSecurity mainClass;
+
+ public RepeatingLoginRunnable(LoginSecurity mainClass, Player player) {
+ this.player = player;
+ this.mainClass = mainClass;
+ }
+
+ @Override
+ public void run() {
+ if (!player.isOnline()) {
+ LoginSecurity.loggingIn.remove(player.getUniqueId());
+ Bukkit.getScheduler().cancelTask(id);
+ }
+
+ if (!mainClass.isLoggingIn(player)) {
+ player.sendMessage(ChatColor.GREEN + "Successfully logged in!");
+ Bukkit.getScheduler().cancelTask(id);
+ }
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+}