427 lines
12 KiB
Java
427 lines
12 KiB
Java
package com.cypherx.xauth;
|
|
|
|
import com.cypherx.xauth.commands.*;
|
|
import com.cypherx.xauth.database.*;
|
|
import com.cypherx.xauth.listeners.*;
|
|
|
|
import java.io.BufferedReader;
|
|
import java.io.File;
|
|
import java.io.FileReader;
|
|
import java.io.IOException;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.sql.Timestamp;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.UUID;
|
|
import java.util.concurrent.ConcurrentHashMap;
|
|
|
|
import org.bukkit.Location;
|
|
import org.bukkit.World;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.inventory.ItemStack;
|
|
import org.bukkit.inventory.PlayerInventory;
|
|
import org.bukkit.plugin.PluginDescriptionFile;
|
|
import org.bukkit.plugin.java.JavaPlugin;
|
|
|
|
public class xAuth extends JavaPlugin {
|
|
public static PluginDescriptionFile desc;
|
|
public static File dataFolder;
|
|
private ConcurrentHashMap<String, xAuthPlayer> playerCache = new ConcurrentHashMap<String, xAuthPlayer>();
|
|
private ConcurrentHashMap<UUID, TeleLocation> teleLocations = new ConcurrentHashMap<UUID, TeleLocation>();
|
|
private UUID globalUID = null;
|
|
|
|
public void onDisable() {
|
|
Player[] players = getServer().getOnlinePlayers();
|
|
if (players.length > 0) {
|
|
for (Player player : players) {
|
|
xAuthPlayer xPlayer = getPlayer(player.getName());
|
|
if (xPlayer.isGuest())
|
|
removeGuest(xPlayer);
|
|
}
|
|
}
|
|
|
|
Database.close();
|
|
xAuthSettings.saveChanges();
|
|
xAuthLog.info("v" + desc.getVersion() + " Disabled!");
|
|
}
|
|
|
|
public void onEnable() {
|
|
desc = getDescription();
|
|
dataFolder = getDataFolder();
|
|
|
|
if (!dataFolder.exists())
|
|
dataFolder.mkdirs();
|
|
|
|
xAuthSettings.setup(dataFolder);
|
|
xAuthMessages.setup(dataFolder);
|
|
|
|
if (xAuthSettings.autoDisable && getServer().getOnlineMode()) {
|
|
xAuthLog.warning("Disabling - Server is running in online-mode");
|
|
getServer().getPluginManager().disablePlugin(this);
|
|
return;
|
|
}
|
|
|
|
xAuthPermissions.setup(this);
|
|
xAuthHelp.setup(this);
|
|
|
|
Database.connect();
|
|
if (!Database.isConnected()) {
|
|
xAuthLog.severe("Disabling - No connection to database");
|
|
getServer().getPluginManager().disablePlugin(this);
|
|
return;
|
|
}
|
|
|
|
DbUpdate dbUpdate = new DbUpdate();
|
|
if (!dbUpdate.checkVersion()) {
|
|
xAuthLog.info("Updating database..");
|
|
dbUpdate.update();
|
|
}
|
|
|
|
DbUtil.deleteExpiredSessions();
|
|
loadTeleLocations();
|
|
|
|
File oldAuthFile = new File(dataFolder, "auths.txt");
|
|
if (oldAuthFile.exists())
|
|
importAccounts(oldAuthFile);
|
|
|
|
Database.printStats();
|
|
|
|
Player[] players = getServer().getOnlinePlayers();
|
|
if (players.length > 0) // /reload was used
|
|
handleReload(players);
|
|
|
|
(new xAuthPlayerListener(this)).registerEvents();
|
|
(new xAuthBlockListener(this)).registerEvents();
|
|
(new xAuthEntityListener(this)).registerEvents();
|
|
getCommand("register").setExecutor(new RegisterCommand(this));
|
|
getCommand("login").setExecutor(new LoginCommand(this));
|
|
getCommand("changepw").setExecutor(new ChangePasswordCommand(this));
|
|
getCommand("logout").setExecutor(new LogoutCommand(this));
|
|
getCommand("xauth").setExecutor(new xAuthCommand(this));
|
|
|
|
xAuthLog.info("v" + desc.getVersion() + " Enabled!");
|
|
}
|
|
|
|
private void importAccounts(File oldAuthFile) {
|
|
xAuthLog.info("Importing old auths.txt file to new format..");
|
|
List<Account> accounts = new ArrayList<Account>();
|
|
BufferedReader reader = null;
|
|
|
|
try {
|
|
reader = new BufferedReader(new FileReader(oldAuthFile));
|
|
String line;
|
|
Account account;
|
|
|
|
while ((line = reader.readLine()) != null) {
|
|
String[] split = line.split(":");
|
|
account = new Account(split[0], split[1], null);
|
|
accounts.add(account);
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
} finally {
|
|
try {
|
|
if (reader != null)
|
|
reader.close();
|
|
} catch (IOException e) {}
|
|
}
|
|
|
|
DbUtil.insertAccounts(accounts);
|
|
|
|
if (oldAuthFile.renameTo(new File(dataFolder, "auths.txt.old")))
|
|
xAuthLog.info("Import complete! auths.txt renamed to auths.txt.old");
|
|
else
|
|
xAuthLog.info("Import complete! Verify that all accounts were imported then remove/rename auths.txt");
|
|
}
|
|
|
|
public xAuthPlayer getPlayer(String playerName) {
|
|
String lowPlayerName = playerName.toLowerCase();
|
|
|
|
if (playerCache.containsKey(lowPlayerName))
|
|
return playerCache.get(lowPlayerName);
|
|
|
|
xAuthPlayer xPlayer = DbUtil.getPlayerFromDb(playerName);
|
|
if (xPlayer == null)
|
|
xPlayer = new xAuthPlayer(playerName);
|
|
|
|
playerCache.put(lowPlayerName, xPlayer);
|
|
return xPlayer;
|
|
}
|
|
|
|
public xAuthPlayer getPlayerJoin(String playerName) {
|
|
String lowPlayerName = playerName.toLowerCase();
|
|
|
|
if (playerCache.containsKey(lowPlayerName))
|
|
return DbUtil.reloadPlayer(playerCache.get(lowPlayerName));
|
|
|
|
xAuthPlayer xPlayer = DbUtil.getPlayerFromDb(playerName);
|
|
if (xPlayer == null)
|
|
xPlayer = new xAuthPlayer(playerName);
|
|
|
|
playerCache.put(lowPlayerName, xPlayer);
|
|
return xPlayer;
|
|
}
|
|
|
|
private void handleReload(Player[] players) {
|
|
for (Player player : players) {
|
|
xAuthPlayer xPlayer = getPlayerJoin(player.getName());
|
|
boolean isRegistered = xPlayer.isRegistered();
|
|
|
|
if (!xPlayer.isAuthenticated() && (isRegistered || (!isRegistered && xPlayer.mustRegister()))) {
|
|
createGuest(xPlayer);
|
|
xAuthMessages.send("miscReloaded", player);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void createGuest(xAuthPlayer xPlayer) {
|
|
final Player player = xPlayer.getPlayer();
|
|
|
|
// remove old session (if any)
|
|
if (xPlayer.hasSession())
|
|
DbUtil.deleteSession(xPlayer);
|
|
|
|
if (xAuthSettings.guestTimeout > 0 && xPlayer.isRegistered()) {
|
|
int taskId = getServer().getScheduler().scheduleAsyncDelayedTask(this, new Runnable() {
|
|
public void run() {
|
|
player.kickPlayer(xAuthMessages.get("miscKickTimeout", player, null));
|
|
}
|
|
}, xAuthSettings.guestTimeout * 20);
|
|
|
|
xPlayer.setTimeoutTaskId(taskId);
|
|
}
|
|
|
|
protect(xPlayer);
|
|
xPlayer.setLastNotifyTime(Util.getNow());
|
|
xPlayer.setGuest(true);
|
|
}
|
|
|
|
public void removeGuest(xAuthPlayer xPlayer) {
|
|
if (!xPlayer.isGuest())
|
|
return;
|
|
|
|
getServer().getScheduler().cancelTask(xPlayer.getTimeoutTaskId());
|
|
restore(xPlayer);
|
|
xPlayer.setGuest(false);
|
|
}
|
|
|
|
public void protect(xAuthPlayer xPlayer) {
|
|
Player player = xPlayer.getPlayer();
|
|
PlayerInventory playerInv = player.getInventory();
|
|
|
|
DbUtil.insertInventory(xPlayer);
|
|
playerInv.clear();
|
|
playerInv.setHelmet(null);
|
|
playerInv.setChestplate(null);
|
|
playerInv.setLeggings(null);
|
|
playerInv.setBoots(null);
|
|
player.saveData();
|
|
|
|
if (player.getHealth() > 0)
|
|
xPlayer.setLocation(player.getLocation());
|
|
|
|
if (xAuthSettings.protectLoc)
|
|
player.teleport(getLocationToTeleport(player.getWorld()));
|
|
}
|
|
|
|
public void restore(xAuthPlayer xPlayer) {
|
|
Player player = xPlayer.getPlayer();
|
|
PlayerInventory playerInv = player.getInventory();
|
|
|
|
ItemStack[] inv = DbUtil.getInventory(xPlayer);
|
|
ItemStack[] items = new ItemStack[inv.length - 4];
|
|
ItemStack[] armor = new ItemStack[4];
|
|
|
|
for (int i = 0; i < inv.length - 4; i++)
|
|
items[i] = inv[i];
|
|
|
|
//Backpack fix
|
|
if (playerInv.getSize() > items.length) {
|
|
ItemStack[] newItems = new ItemStack[playerInv.getSize()];
|
|
|
|
for(int i = 0; i < items.length; i++)
|
|
newItems[i] = items[i];
|
|
|
|
items = newItems;
|
|
}
|
|
//end Backpack fix
|
|
|
|
armor[0] = inv[inv.length - 4];
|
|
armor[1] = inv[inv.length - 3];
|
|
armor[2] = inv[inv.length - 2];
|
|
armor[3] = inv[inv.length - 1];
|
|
|
|
playerInv.setContents(items);
|
|
playerInv.setArmorContents(armor);
|
|
DbUtil.deleteInventory(xPlayer);
|
|
|
|
if (xPlayer.getLocation() != null)
|
|
xPlayer.getPlayer().teleport(xPlayer.getLocation());
|
|
player.saveData();
|
|
}
|
|
|
|
public void login(xAuthPlayer xPlayer) {
|
|
Account account = xPlayer.getAccount();
|
|
account.setLastLoginDate(Util.getNow());
|
|
account.setLastLoginHost(Util.getHostFromPlayer(xPlayer.getPlayer()));
|
|
DbUtil.saveAccount(account);
|
|
|
|
Session session = new Session(account.getId(), account.getLastLoginHost());
|
|
xPlayer.setSession(session);
|
|
DbUtil.insertSession(session);
|
|
|
|
removeGuest(xPlayer);
|
|
xPlayer.setStrikes(0);
|
|
}
|
|
|
|
public void changePassword(Account account, String newPass) {
|
|
account.setPassword(Util.encrypt(newPass));
|
|
DbUtil.saveAccount(account);
|
|
}
|
|
|
|
public boolean checkPassword(Account account, String checkPass) {
|
|
String realPass = account.getPassword();
|
|
|
|
// check for old encryption (md5 or whirlpool)
|
|
if (realPass.length() == 32 || realPass.length() == 128) {
|
|
String hash = (realPass.length() == 32 ? Util.md5(checkPass) : Util.whirlpool(checkPass));
|
|
if (realPass.equals(hash)) {
|
|
changePassword(account, checkPass); // change password to use new encryption
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
// xAuth 2 encryption
|
|
int saltPos = (checkPass.length() >= realPass.length() ? realPass.length() : checkPass.length());
|
|
|
|
// extract salt
|
|
String salt = realPass.substring(saltPos, saltPos + 12);
|
|
|
|
// encrypt salt + checkPass
|
|
Whirlpool w = new Whirlpool();
|
|
byte[] digest = new byte[Whirlpool.DIGESTBYTES];
|
|
w.NESSIEinit();
|
|
w.NESSIEadd(salt + checkPass);
|
|
w.NESSIEfinalize(digest);
|
|
String hash = Whirlpool.display(digest);
|
|
return (hash.substring(0, saltPos) + salt + hash.substring(saltPos)).equals(realPass);
|
|
}
|
|
|
|
private void loadTeleLocations() {
|
|
String sql = "SELECT * FROM `" + xAuthSettings.tblLocation + "`";
|
|
ResultSet rs = Database.queryRead(sql);
|
|
|
|
try {
|
|
while (rs.next()) {
|
|
TeleLocation teleLocation = new TeleLocation();
|
|
String uid = rs.getString("uid");
|
|
boolean update = false;
|
|
|
|
// Database version 0001 -> 0002 fix
|
|
if (Util.isUUID(uid))
|
|
teleLocation.setUID(UUID.fromString(uid));
|
|
else {
|
|
teleLocation.setUID(getServer().getWorld(uid).getUID());
|
|
update = true;
|
|
}
|
|
|
|
teleLocation.setX(rs.getDouble("x"));
|
|
teleLocation.setY(rs.getDouble("y"));
|
|
teleLocation.setZ(rs.getDouble("z"));
|
|
teleLocation.setYaw(rs.getFloat("yaw"));
|
|
teleLocation.setPitch(rs.getFloat("pitch"));
|
|
teleLocation.setGlobal(rs.getInt("global"));
|
|
teleLocations.put(teleLocation.getUID(), teleLocation);
|
|
|
|
if (teleLocation.getGlobal() == 1)
|
|
globalUID = teleLocation.getUID();
|
|
|
|
if (update) {
|
|
sql = "UPDATE `" + xAuthSettings.tblLocation + "` SET `uid` = ? WHERE `uid` = ?";
|
|
Database.queryWrite(sql, teleLocation.getUID().toString(), uid);
|
|
}
|
|
}
|
|
} catch (SQLException e) {
|
|
xAuthLog.severe("Could not load TeleLocations from database!", e);
|
|
} finally {
|
|
try {
|
|
rs.close();
|
|
} catch (SQLException e) {}
|
|
}
|
|
}
|
|
|
|
public TeleLocation getTeleLocation(UUID uid) {
|
|
if (uid == null)
|
|
return null;
|
|
|
|
return teleLocations.get(uid);
|
|
}
|
|
|
|
public void setTeleLocation(TeleLocation teleLocation) {
|
|
TeleLocation tOld = teleLocations.put(teleLocation.getUID(), teleLocation);
|
|
if (teleLocation.getGlobal() == 1)
|
|
globalUID = teleLocation.getUID();
|
|
|
|
if (tOld == null)
|
|
DbUtil.insertTeleLocation(teleLocation);
|
|
else
|
|
DbUtil.updateTeleLocation(teleLocation);
|
|
}
|
|
|
|
public void removeTeleLocation(TeleLocation teleLocation) {
|
|
teleLocations.remove(teleLocation.getUID());
|
|
if (teleLocation.getGlobal() == 1)
|
|
globalUID = null;
|
|
|
|
DbUtil.deleteTeleLocation(teleLocation);
|
|
}
|
|
|
|
public Location getLocationToTeleport(World world) {
|
|
TeleLocation teleLocation = getTeleLocation((globalUID == null ? world.getUID() : globalUID));
|
|
return (teleLocation == null ? world.getSpawnLocation() : teleLocation.getLocation());
|
|
}
|
|
|
|
public void strikeout(xAuthPlayer xPlayer) {
|
|
Player player = xPlayer.getPlayer();
|
|
|
|
if (xAuthSettings.strikeAction.equals("banip")) {
|
|
StrikeBan ban = new StrikeBan(Util.getHostFromPlayer(player));
|
|
DbUtil.insertStrikeBan(ban);
|
|
xAuthLog.info(ban.getHost() + " banned by strike system");
|
|
}
|
|
|
|
player.kickPlayer(xAuthMessages.get("miscKickStrike", player, null));
|
|
if (xAuthSettings.strikeAction.equals("kick"))
|
|
xAuthLog.info(player.getName() + " kicked by strike system");
|
|
|
|
xPlayer.setStrikes(0);
|
|
}
|
|
|
|
public boolean isBanned(String host) {
|
|
final StrikeBan ban = DbUtil.loadStrikeBan(host);
|
|
if (ban == null)
|
|
return false;
|
|
|
|
if (xAuthSettings.banLength == 0)
|
|
return true;
|
|
|
|
Timestamp unbanTime = new Timestamp(ban.getBanTime().getTime() + (xAuthSettings.banLength * 1000));
|
|
if (unbanTime.compareTo(Util.getNow()) > 0) // still banned
|
|
return true;
|
|
else // no longer banned, remove from database
|
|
DbUtil.deleteStrikeBan(ban);
|
|
|
|
return false;
|
|
}
|
|
|
|
public void reload() {
|
|
xAuthSettings.setup(dataFolder);
|
|
xAuthMessages.setup(dataFolder);
|
|
}
|
|
|
|
public UUID getGlobalUID() {
|
|
return globalUID;
|
|
}
|
|
} |