Added LoginSecurity module
This commit is contained in:
parent
ff52e3c27c
commit
e4ed84c7ce
@ -12,6 +12,7 @@ import com.redstoner.modules.check.Check;
|
||||
import com.redstoner.modules.damnspam.DamnSpam;
|
||||
import com.redstoner.modules.imout.Imout;
|
||||
import com.redstoner.modules.lagchunks.LagChunks;
|
||||
import com.redstoner.modules.loginsecurity.LoginSecurity;
|
||||
import com.redstoner.modules.scriptutils.Scriptutils;
|
||||
import com.redstoner.modules.skullclick.SkullClick;
|
||||
import com.redstoner.modules.warn.Warn;
|
||||
@ -47,7 +48,7 @@ public class Main extends JavaPlugin
|
||||
// TODO: ModuleLoader.addModule(Imbusy.class);
|
||||
ModuleLoader.addModule(Imout.class);
|
||||
ModuleLoader.addModule(LagChunks.class);
|
||||
// TODO: ModuleLoader.addModule(Loginsecurity.class);
|
||||
ModuleLoader.addModule(LoginSecurity.class);
|
||||
// TODO: ModuleLoader.addModule(Mentio.class);
|
||||
// TODO: ModuleLoader.addModule(Misc.class);
|
||||
ModuleLoader.addModule(Motd.class);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
324
src/com/redstoner/modules/loginsecurity/LoginSecurity.java
Normal file
324
src/com/redstoner/modules/loginsecurity/LoginSecurity.java
Normal file
@ -0,0 +1,324 @@
|
||||
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.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;
|
||||
|
||||
public class LoginSecurity implements Module, Listener
|
||||
{
|
||||
private boolean enabled = false;
|
||||
protected static Map<UUID, Location> loggingIn;
|
||||
private MysqlTable table;
|
||||
|
||||
@Override
|
||||
public void onEnable()
|
||||
{
|
||||
Map<Serializable, Serializable> config = JSONManager.getConfiguration("LoginSecurity.json");
|
||||
if (config == null || !config.containsKey("database") || !config.containsKey("table"))
|
||||
{
|
||||
Bukkit.getConsoleSender()
|
||||
.sendMessage(ChatColor.RED + "Could not load the LoginSecurity config file, disabling!");
|
||||
enabled = 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)
|
||||
{
|
||||
Bukkit.getConsoleSender().sendMessage(ChatColor.RED + "Could not use the LoginSecurity config, disabling!");
|
||||
enabled = false;
|
||||
}
|
||||
loggingIn = new HashMap<>();
|
||||
Bukkit.getServer().getPluginManager().registerEvents(new CancelledEventsHandler(this), Main.plugin);
|
||||
enabled = 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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enabled()
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable()
|
||||
{
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
// @noformat
|
||||
@Override
|
||||
public String getCommandString()
|
||||
{
|
||||
return "command register {\n" +
|
||||
" perm utils.loginsecurity;\n" +
|
||||
" \n" +
|
||||
" [string:password] {\n" +
|
||||
" run register password;\n" +
|
||||
" help Protects your account with a password;\n" +
|
||||
" type player;\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"command login {\n" +
|
||||
" perm utils.loginsecurity;\n" +
|
||||
" \n" +
|
||||
" [string:password] {\n" +
|
||||
" run login password;\n" +
|
||||
" help Logs you in;\n" +
|
||||
" type player;\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"command cgpass {\n" +
|
||||
" perm utils.loginsecurity;\n" +
|
||||
" \n" +
|
||||
" [string:oldPassword] [string:newPassword] {\n" +
|
||||
" run cgpass oldPassword newPassword;\n" +
|
||||
" help Changes your password to the specified one;\n" +
|
||||
" type player;\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"command rmpass {\n" +
|
||||
" perm utils.loginsecurity;\n" +
|
||||
" \n" +
|
||||
" [string:oldPassword] {\n" +
|
||||
" run rmpass oldPassword;\n" +
|
||||
" help Removes the password of your account;\n" +
|
||||
" type player;\n" +
|
||||
" }\n" +
|
||||
"}\n" +
|
||||
"\n" +
|
||||
"command rmotherpass {\n" +
|
||||
" perm utils.loginsecurity.admin;\n" +
|
||||
" \n" +
|
||||
" [string:playerName] {\n" +
|
||||
" run rmotherpass playerName;\n" +
|
||||
" help removes the password of another player;\n" +
|
||||
" perm utils.loginsecurity.admin;\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
}
|
||||
// @format
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user