0

Added LoginSecurity module

This commit is contained in:
Pepich 2017-02-02 19:51:38 +01:00
parent ff52e3c27c
commit e4ed84c7ce
5 changed files with 511 additions and 1 deletions

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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);
}
}

View 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
}

View File

@ -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;
}
}