├── .gitignore ├── src └── main │ ├── resources │ ├── sql │ │ ├── playerdata │ │ │ ├── updates │ │ │ │ ├── h2 │ │ │ │ │ ├── 001_add_potion_effects.sql │ │ │ │ │ ├── 002_null_items_armor.sql │ │ │ │ │ └── 003_add_fire_air_ticks.sql │ │ │ │ └── mysql │ │ │ │ │ ├── 001_add_potion_effects.sql │ │ │ │ │ ├── 002_null_items_armor.sql │ │ │ │ │ └── 003_add_fire_air_ticks.sql │ │ │ └── table.sql │ │ ├── lockout │ │ │ ├── updates │ │ │ │ ├── mysql │ │ │ │ │ └── 001_add_lockout_id.sql │ │ │ │ └── h2 │ │ │ │ │ └── 001_add_lockout_id.sql │ │ │ └── table.sql │ │ ├── session │ │ │ └── table.sql │ │ ├── location │ │ │ └── table.sql │ │ └── account │ │ │ └── table.sql │ ├── config.yml │ ├── plugin.yml │ └── messages.yml │ └── java │ └── com │ ├── cypherx │ └── xauth │ │ ├── database │ │ ├── TableUpdateException.java │ │ ├── Table.java │ │ ├── ConnectionPool.java │ │ ├── DatabaseController.java │ │ └── DatabaseUpdater.java │ │ ├── updater │ │ ├── UpdatePriority.java │ │ └── Updater.java │ │ ├── strike │ │ ├── StrikeRecord.java │ │ └── StrikeManager.java │ │ ├── password │ │ ├── PasswordType.java │ │ ├── PasswordHandler.java │ │ └── Whirlpool.java │ │ ├── xAuthLog.java │ │ ├── xAuthScheduler.java │ │ ├── PlayerData.java │ │ ├── listeners │ │ ├── xAuthBlockListener.java │ │ ├── xAuthEntityListener.java │ │ └── xAuthPlayerListener.java │ │ ├── commands │ │ ├── LogoutCommand.java │ │ ├── ChangePwdCommand.java │ │ ├── RegisterCommand.java │ │ ├── LoginCommand.java │ │ └── xAuthCommand.java │ │ ├── Utils.java │ │ ├── xAuthPlayer.java │ │ ├── plugins │ │ └── xPermissions.java │ │ ├── MessageHandler.java │ │ ├── auth │ │ ├── Auth.java │ │ ├── AuthURL.java │ │ └── AuthSQL.java │ │ ├── LocationManager.java │ │ ├── xAuth.java │ │ ├── PlayerDataHandler.java │ │ └── PlayerManager.java │ └── martiansoftware │ └── jsap │ └── CommandLineTokenizer.java └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | /.settings 2 | /lib 3 | /release 4 | /bin 5 | /target 6 | /.classpath 7 | /.project -------------------------------------------------------------------------------- /src/main/resources/sql/playerdata/updates/h2/001_add_potion_effects.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `{TABLE}` ADD COLUMN `potioneffects` TEXT NULL; -------------------------------------------------------------------------------- /src/main/resources/sql/playerdata/updates/mysql/001_add_potion_effects.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `{TABLE}` ADD COLUMN `potioneffects` TEXT NULL; -------------------------------------------------------------------------------- /src/main/resources/sql/playerdata/updates/mysql/002_null_items_armor.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `{TABLE}` MODIFY `items` TEXT NULL; 2 | ALTER TABLE `{TABLE}` MODIFY `armor` TEXT NULL; -------------------------------------------------------------------------------- /src/main/resources/sql/playerdata/updates/h2/002_null_items_armor.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `{TABLE}` ALTER COLUMN `items` SET NULL; 2 | ALTER TABLE `{TABLE}` ALTER COLUMN `armor` SET NULL; -------------------------------------------------------------------------------- /src/main/resources/sql/lockout/updates/mysql/001_add_lockout_id.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `{TABLE}` ADD COLUMN `id` INT UNSIGNED NOT NULL AUTO_INCREMENT FIRST, DROP PRIMARY KEY, ADD PRIMARY KEY (`id`); -------------------------------------------------------------------------------- /src/main/resources/sql/lockout/table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `{TABLE}` ( 2 | `ipaddress` VARCHAR(45) NOT NULL, 3 | `playername` VARCHAR(255) NOT NULL, 4 | `time` DATETIME NOT NULL, 5 | PRIMARY KEY (`ipaddress`) 6 | ); -------------------------------------------------------------------------------- /src/main/resources/sql/playerdata/updates/h2/003_add_fire_air_ticks.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `{TABLE}` ADD COLUMN `fireticks` SMALLINT NOT NULL DEFAULT 0; 2 | ALTER TABLE `{TABLE}` ADD COLUMN `remainingair` SMALLINT NOT NULL DEFAULT 300; -------------------------------------------------------------------------------- /src/main/resources/sql/playerdata/updates/mysql/003_add_fire_air_ticks.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `{TABLE}` ADD COLUMN `fireticks` SMALLINT NOT NULL DEFAULT 0; 2 | ALTER TABLE `{TABLE}` ADD COLUMN `remainingair` SMALLINT NOT NULL DEFAULT 300; -------------------------------------------------------------------------------- /src/main/resources/sql/playerdata/table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `{TABLE}` ( 2 | `playername` VARCHAR(255) NOT NULL, 3 | `items` TEXT NOT NULL, 4 | `armor` TEXT NOT NULL, 5 | `location` TEXT NULL, 6 | PRIMARY KEY (`playername`) 7 | ); -------------------------------------------------------------------------------- /src/main/resources/sql/lockout/updates/h2/001_add_lockout_id.sql: -------------------------------------------------------------------------------- 1 | ALTER TABLE `{TABLE}` ADD COLUMN `id` INT UNSIGNED NOT NULL AUTO_INCREMENT BEFORE `ipaddress`; 2 | ALTER TABLE `{TABLE}` DROP PRIMARY KEY; 3 | ALTER TABLE `{TABLE}` ADD PRIMARY KEY (`id`); -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/database/TableUpdateException.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.database; 2 | 3 | @SuppressWarnings("serial") 4 | public class TableUpdateException extends Exception { 5 | public TableUpdateException(String message) { 6 | super(message); 7 | } 8 | } -------------------------------------------------------------------------------- /src/main/resources/sql/session/table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `{TABLE}` ( 2 | `accountid` INT UNSIGNED NOT NULL, 3 | `ipaddress` CHAR(45) NOT NULL, 4 | `logintime` DATETIME NOT NULL, 5 | PRIMARY KEY(`accountid`), 6 | FOREIGN KEY (`accountid`) REFERENCES `{TABLE_ACCOUNT}`(`id`) ON DELETE CASCADE 7 | ); -------------------------------------------------------------------------------- /src/main/resources/sql/location/table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `{TABLE}` ( 2 | `uid` VARCHAR(36) NOT NULL, 3 | `x` DOUBLE NOT NULL, 4 | `y` DOUBLE NOT NULL, 5 | `z` DOUBLE NOT NULL, 6 | `yaw` FLOAT NOT NULL, 7 | `pitch` FLOAT NOT NULL, 8 | `global` TINYINT(1) NOT NULL DEFAULT 0, 9 | PRIMARY KEY(`uid`) 10 | ); -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/database/Table.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.database; 2 | 3 | public enum Table { 4 | ACCOUNT ("accounts"), 5 | LOCATION ("locations"), 6 | LOCKOUT ("lockouts"), 7 | PLAYERDATA ("playerdata"), 8 | SESSION ("sessions"); 9 | 10 | private String name; 11 | 12 | Table(String name) { 13 | this.name = name; 14 | } 15 | 16 | public String getName() { return name; } 17 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/updater/UpdatePriority.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.updater; 2 | 3 | public enum UpdatePriority { 4 | LOW(1), 5 | MEDIUM(2), 6 | HIGH(3); 7 | 8 | int level; 9 | 10 | UpdatePriority(int level) { 11 | this.level = level; 12 | } 13 | 14 | public static UpdatePriority getPriority(int level) { 15 | for (UpdatePriority p : values()) 16 | if (p.level == level) 17 | return p; 18 | 19 | return null; 20 | } 21 | } -------------------------------------------------------------------------------- /src/main/resources/sql/account/table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `{TABLE}` ( 2 | `id` INT UNSIGNED NOT NULL AUTO_INCREMENT, 3 | `playername` VARCHAR(255) NOT NULL, 4 | `password` VARCHAR(255) NOT NULL, 5 | `pwtype` TINYINT(2) UNSIGNED NOT NULL DEFAULT 0, 6 | `email` VARCHAR(100) NULL, 7 | `registerdate` DATETIME NULL, 8 | `registerip` CHAR(45) NULL, 9 | `lastlogindate` DATETIME NULL, 10 | `lastloginip` CHAR(45) NULL, 11 | `active` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, 12 | PRIMARY KEY (`id`) 13 | ); -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/strike/StrikeRecord.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.strike; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class StrikeRecord { 7 | private Map strikes = new HashMap(); 8 | 9 | public StrikeRecord() { 10 | // Empty constructor is empty 11 | } 12 | 13 | // Returns new strike amount 14 | public int addStrike(String playerName) { 15 | Integer count = strikes.get(playerName); 16 | if (count == null) 17 | count = 0; 18 | 19 | strikes.put(playerName, ++count); 20 | return count; 21 | } 22 | 23 | public void clearStrikes(String playerName) { 24 | strikes.remove(playerName); 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/password/PasswordType.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.password; 2 | 3 | public enum PasswordType { 4 | DEFAULT(0), 5 | WHIRLPOOL(1), 6 | MD5(2, "MD5"), 7 | SHA1(3, "SHA1"), 8 | SHA256(4, "SHA-256"), 9 | AUTHME_SHA256(5); 10 | 11 | private int type; 12 | private String algorithm; 13 | 14 | PasswordType(int type) { 15 | this(type, null); 16 | } 17 | 18 | PasswordType(int type, String algorithm) { 19 | this.type = type; 20 | this.algorithm = algorithm; 21 | } 22 | 23 | public int getType() { return type; } 24 | public String getAlgorithm() { return algorithm; } 25 | 26 | public static PasswordType getType(int type) { 27 | for (PasswordType t : values()) 28 | if (t.type == type) 29 | return t; 30 | 31 | return null; 32 | } 33 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/xAuthLog.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth; 2 | 3 | import java.util.logging.Level; 4 | import java.util.logging.Logger; 5 | 6 | import org.bukkit.Bukkit; 7 | 8 | public class xAuthLog { 9 | private static final Logger logger = Bukkit.getLogger(); 10 | 11 | public static void info(String msg) { 12 | logger.log(Level.INFO, "[xAuth] " + msg); 13 | } 14 | 15 | public static void warning(String msg) { 16 | logger.log(Level.WARNING, "[xAuth] " + msg); 17 | } 18 | 19 | public static void severe(String msg) { 20 | logger.log(Level.SEVERE, "[xAuth] " + msg); 21 | } 22 | 23 | public static void info(String msg, Throwable e) { 24 | logger.log(Level.INFO, "[xAuth] " + msg, e); 25 | } 26 | 27 | public static void warning(String msg, Throwable e) { 28 | logger.log(Level.WARNING, "[xAuth] " + msg, e); 29 | } 30 | 31 | public static void severe(String msg, Throwable e) { 32 | logger.log(Level.SEVERE, "[xAuth] " + msg, e); 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/xAuthScheduler.java: -------------------------------------------------------------------------------- 1 | /*package com.cypherx.xauth; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.entity.Player; 5 | 6 | public class xAuthScheduler { 7 | private final xAuth plugin; 8 | 9 | public xAuthScheduler(final xAuth plugin) { 10 | this.plugin = plugin; 11 | } 12 | 13 | // TODO change to Sync? 14 | public void sendDelayedMessage(final Player player, final String node, int delay) { 15 | Bukkit.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() { 16 | public void run() { 17 | if (player.isOnline()) 18 | plugin.getMsgHndlr().sendMessage(node, player); 19 | } 20 | }, delay); 21 | } 22 | 23 | // TODO change to Sync? 24 | public int scheduleTimeoutTask(final Player player, final int timeout) { 25 | return Bukkit.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() { 26 | public void run() { 27 | if (player.isOnline()) 28 | player.kickPlayer(plugin.getMsgHndlr().get("misc.timeout")); 29 | } 30 | }, plugin.getConfig().getInt("guest.timeout") * 20); 31 | } 32 | }*/ -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/PlayerData.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth; 2 | 3 | import java.util.Collection; 4 | 5 | import org.bukkit.Location; 6 | import org.bukkit.inventory.ItemStack; 7 | import org.bukkit.potion.PotionEffect; 8 | 9 | public class PlayerData { 10 | private ItemStack[] items = null; 11 | private ItemStack[] armor = null; 12 | private Location location = null; 13 | private Collection potEffects; 14 | private int fireTicks; 15 | private int remainingAir; 16 | 17 | public PlayerData(ItemStack[] items, ItemStack[] armor, Location location, Collection potEffects, int fireTicks, int remainingAir) { 18 | this.items = items; 19 | this.armor = armor; 20 | this.location = location; 21 | this.potEffects = potEffects; 22 | this.fireTicks = fireTicks; 23 | this.remainingAir = remainingAir; 24 | } 25 | 26 | public ItemStack[] getItems() { return items; } 27 | public ItemStack[] getArmor () { return armor; } 28 | public Location getLocation() { return location; } 29 | public Collection getPotionEffects() { return potEffects; } 30 | public int getFireTicks() { return fireTicks; } 31 | public int getRemainingAir() { return remainingAir; } 32 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/listeners/xAuthBlockListener.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.listeners; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.event.EventHandler; 5 | import org.bukkit.event.EventPriority; 6 | import org.bukkit.event.Listener; 7 | import org.bukkit.event.block.BlockBreakEvent; 8 | import org.bukkit.event.block.BlockPlaceEvent; 9 | 10 | import com.cypherx.xauth.PlayerManager; 11 | import com.cypherx.xauth.xAuth; 12 | import com.cypherx.xauth.xAuthPlayer; 13 | 14 | public class xAuthBlockListener implements Listener { 15 | private final PlayerManager plyrMngr; 16 | 17 | public xAuthBlockListener(final xAuth plugin) { 18 | this.plyrMngr = plugin.getPlyrMngr(); 19 | Bukkit.getServer().getPluginManager().registerEvents(this, plugin); 20 | } 21 | 22 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 23 | public void onBlockBreak(BlockBreakEvent event) { 24 | xAuthPlayer xp = plyrMngr.getPlayer(event.getPlayer()); 25 | if (plyrMngr.isRestricted(xp, event)) { 26 | plyrMngr.sendNotice(xp); 27 | event.setCancelled(true); 28 | } 29 | } 30 | 31 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 32 | public void onBlockPlace(BlockPlaceEvent event) { 33 | xAuthPlayer xp = plyrMngr.getPlayer(event.getPlayer()); 34 | if (plyrMngr.isRestricted(xp, event)) { 35 | plyrMngr.sendNotice(xp); 36 | event.setCancelled(true); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/commands/LogoutCommand.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.commands; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandExecutor; 5 | import org.bukkit.command.CommandSender; 6 | import org.bukkit.entity.Player; 7 | 8 | import com.cypherx.xauth.xAuth; 9 | import com.cypherx.xauth.xAuthPlayer; 10 | import com.cypherx.xauth.xAuthPlayer.Status; 11 | import com.martiansoftware.jsap.CommandLineTokenizer; 12 | 13 | public class LogoutCommand implements CommandExecutor { 14 | private final xAuth plugin; 15 | 16 | public LogoutCommand(final xAuth plugin) { 17 | this.plugin = plugin; 18 | } 19 | 20 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { 21 | args = CommandLineTokenizer.tokenize(args); 22 | 23 | if (sender instanceof Player) { 24 | xAuthPlayer p = plugin.getPlyrMngr().getPlayer((Player) sender); 25 | String response = null; 26 | 27 | if (p.isAuthenticated()) { 28 | boolean success = plugin.getPlyrMngr().deleteSession(p.getAccountId()); 29 | if (success) { 30 | plugin.getPlyrMngr().protect(p); 31 | p.setStatus(Status.Registered); 32 | plugin.getAuthClass(p).offline(p.getPlayerName()); 33 | response = "logout.success"; 34 | } else 35 | response = "logout.error.general"; 36 | } else 37 | response = "logout.error.logged"; 38 | 39 | plugin.getMsgHndlr().sendMessage(response, p.getPlayer()); 40 | return true; 41 | } 42 | 43 | return false; 44 | } 45 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/commands/ChangePwdCommand.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.commands; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandExecutor; 5 | import org.bukkit.command.CommandSender; 6 | import org.bukkit.entity.Player; 7 | 8 | import com.cypherx.xauth.xAuth; 9 | import com.cypherx.xauth.xAuthLog; 10 | import com.cypherx.xauth.xAuthPlayer; 11 | import com.cypherx.xauth.auth.Auth; 12 | import com.martiansoftware.jsap.CommandLineTokenizer; 13 | 14 | public class ChangePwdCommand implements CommandExecutor { 15 | private final xAuth plugin; 16 | 17 | public ChangePwdCommand(final xAuth plugin) { 18 | this.plugin = plugin; 19 | } 20 | 21 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { 22 | args = CommandLineTokenizer.tokenize(args); 23 | 24 | if (sender instanceof Player) { 25 | xAuthPlayer p = plugin.getPlyrMngr().getPlayer((Player) sender); 26 | 27 | if (args.length < 2) { 28 | plugin.getMsgHndlr().sendMessage("changepw.usage", p.getPlayer()); 29 | return true; 30 | } 31 | 32 | String oldPassword = args[0]; 33 | String newPassword = args[1]; 34 | 35 | Auth a = plugin.getAuthClass(p); 36 | boolean success = a.changePassword(p.getPlayerName(), oldPassword, newPassword); 37 | 38 | String response = a.getResponse(); 39 | if (response != null) 40 | plugin.getMsgHndlr().sendMessage(response, p.getPlayer()); 41 | 42 | if (success) 43 | xAuthLog.info(p.getPlayerName() + " has changed their password"); 44 | 45 | return true; 46 | } 47 | 48 | return false; 49 | } 50 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/commands/RegisterCommand.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.commands; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandExecutor; 5 | import org.bukkit.command.CommandSender; 6 | import org.bukkit.entity.Player; 7 | 8 | import com.cypherx.xauth.xAuth; 9 | import com.cypherx.xauth.xAuthLog; 10 | import com.cypherx.xauth.xAuthPlayer; 11 | import com.cypherx.xauth.auth.Auth; 12 | import com.martiansoftware.jsap.CommandLineTokenizer; 13 | 14 | public class RegisterCommand implements CommandExecutor { 15 | private final xAuth plugin; 16 | 17 | public RegisterCommand(final xAuth plugin) { 18 | this.plugin = plugin; 19 | } 20 | 21 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { 22 | args = CommandLineTokenizer.tokenize(args); 23 | 24 | if (sender instanceof Player) { 25 | xAuthPlayer p = plugin.getPlyrMngr().getPlayer((Player) sender); 26 | 27 | if ((plugin.getConfig().getBoolean("registration.require-email") && args.length < 2) || args.length < 1) { 28 | plugin.getMsgHndlr().sendMessage("register.usage", p.getPlayer()); 29 | return true; 30 | } 31 | 32 | String playerName = p.getPlayerName(); 33 | String password = args[0]; 34 | String email = args.length > 1 ? args[1] : null; 35 | 36 | Auth a = plugin.getAuthClass(p); 37 | boolean success = a.register(playerName, password, email); 38 | 39 | String response = a.getResponse(); 40 | if (response != null) 41 | plugin.getMsgHndlr().sendMessage(response, p.getPlayer()); 42 | 43 | if (success) { 44 | if (!plugin.getConfig().getBoolean("registration.require-login")) 45 | plugin.getPlyrMngr().doLogin(p); 46 | 47 | xAuthLog.info(playerName + " has registered"); 48 | } 49 | 50 | return true; 51 | } 52 | 53 | return false; 54 | } 55 | } -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | main: 2 | auto-disable: true 3 | check-for-updates: true 4 | download-library: true 5 | reload-on-join: false 6 | 7 | mysql: 8 | enabled: false 9 | host: localhost 10 | port: 3306 11 | user: user 12 | password: password 13 | database: xauth 14 | tables: 15 | account: accounts 16 | location: locations 17 | lockout: lockouts 18 | playerdata: playerdata 19 | session: sessions 20 | 21 | authurl: 22 | enabled: false 23 | url: http://google.com 24 | registration: false 25 | status: false 26 | groups: false 27 | broadcast-login: false 28 | 29 | single-session: 30 | reverse: true 31 | guests: 32 | reverse: false 33 | immunity-length: 5 34 | 35 | registration: 36 | enabled: true 37 | forced: true 38 | require-email: false 39 | validate-email: false 40 | account-limit: 0 41 | activation: false 42 | require-login: true 43 | 44 | password: 45 | min-length: 6 46 | allow-change: true 47 | complexity: 48 | lowercase: false 49 | uppercase: false 50 | number: false 51 | symbol: false 52 | 53 | guest: 54 | timeout: 300 55 | notify-cooldown: 5 56 | hide-inventory: true 57 | protect-location: true 58 | allowed-commands: 59 | - register 60 | - login 61 | - l 62 | restrict: 63 | player: 64 | chat: true 65 | interact: true 66 | move: true 67 | pickup: true 68 | block: 69 | place: true 70 | break: true 71 | entity: 72 | damage: true 73 | target: true 74 | 75 | session: 76 | length: 3600 77 | verifyip: true 78 | godmode-length: 5 79 | 80 | strikes: 81 | amount: 5 82 | lockout-length: 3600 83 | 84 | account: 85 | track-last-login: false 86 | 87 | filter: 88 | min-length: 2 89 | allowed: '' 90 | disallowed: '' 91 | blank-name: true -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/commands/LoginCommand.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.commands; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandExecutor; 5 | import org.bukkit.command.CommandSender; 6 | import org.bukkit.entity.Player; 7 | 8 | import com.cypherx.xauth.xAuth; 9 | import com.cypherx.xauth.xAuthLog; 10 | import com.cypherx.xauth.xAuthPlayer; 11 | import com.cypherx.xauth.auth.Auth; 12 | import com.martiansoftware.jsap.CommandLineTokenizer; 13 | 14 | public class LoginCommand implements CommandExecutor { 15 | private final xAuth plugin; 16 | 17 | public LoginCommand(final xAuth plugin) { 18 | this.plugin = plugin; 19 | } 20 | 21 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { 22 | args = CommandLineTokenizer.tokenize(args); 23 | 24 | if (sender instanceof Player) { 25 | xAuthPlayer p = plugin.getPlyrMngr().getPlayer((Player) sender); 26 | 27 | if (args.length < 1) { 28 | plugin.getMsgHndlr().sendMessage("login.usage", p.getPlayer()); 29 | return true; 30 | } 31 | 32 | String playerName = p.getPlayerName(); 33 | String password = args[0]; 34 | 35 | Auth a = plugin.getAuthClass(p); 36 | boolean passChecks = a.login(playerName, password); 37 | String response = a.getResponse(); 38 | 39 | if (passChecks) { 40 | boolean success = plugin.getPlyrMngr().doLogin(p); 41 | if (success) { 42 | if (plugin.isAuthURL() && plugin.getConfig().getBoolean("authurl.broadcast-login") && response != null && response != "") 43 | plugin.getServer().broadcastMessage(response); 44 | response = "login.success"; 45 | a.online(p.getPlayerName()); 46 | xAuthLog.info(playerName + " has logged in"); 47 | } else 48 | response = "login.error.general"; 49 | } 50 | 51 | if (response != null) 52 | plugin.getMsgHndlr().sendMessage(response, p.getPlayer()); 53 | 54 | return true; 55 | } 56 | 57 | return false; 58 | } 59 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/database/ConnectionPool.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.database; 2 | 3 | import java.sql.Connection; 4 | import java.sql.DriverManager; 5 | import java.sql.SQLException; 6 | import java.util.Vector; 7 | import java.util.concurrent.locks.Lock; 8 | import java.util.concurrent.locks.ReentrantLock; 9 | 10 | public class ConnectionPool { 11 | private static final int maxConnections = 10; 12 | 13 | private String url, user, password; 14 | private Vector idleConnections = new Vector(); 15 | private Vector busyConnections = new Vector(); 16 | private Lock lock = new ReentrantLock(); 17 | 18 | public ConnectionPool(String driver, String url, String user, String password) throws ClassNotFoundException { 19 | Class.forName(driver); 20 | this.url = url; 21 | this.user = user; 22 | this.password = password; 23 | } 24 | 25 | public Connection leaseConn() throws SQLException { 26 | lock.lock(); 27 | try { 28 | if (!idleConnections.isEmpty()) { 29 | Connection conn = idleConnections.firstElement(); 30 | idleConnections.removeElementAt(0); 31 | if (conn.isValid(1)) { 32 | busyConnections.add(conn); 33 | return conn; 34 | } else { 35 | conn.close(); 36 | return leaseConn(); 37 | } 38 | } 39 | 40 | if (idleConnections.size() + busyConnections.size() >= maxConnections) 41 | throw new SQLException("Connection pool is full"); 42 | 43 | Connection conn = DriverManager.getConnection(url, user, password); 44 | if (conn.isValid(1)) { 45 | busyConnections.add(conn); 46 | return conn; 47 | } else { 48 | conn.close(); 49 | throw new SQLException("Failed to validate new connection"); 50 | } 51 | } finally { 52 | lock.unlock(); 53 | } 54 | } 55 | 56 | public synchronized void returnConn(Connection conn) { 57 | lock.lock(); 58 | busyConnections.remove(conn); 59 | idleConnections.add(conn); 60 | lock.unlock(); 61 | } 62 | 63 | public synchronized void close() throws SQLException { 64 | lock.lock(); 65 | for (Connection conn : idleConnections) 66 | conn.close(); 67 | 68 | for (Connection conn : busyConnections) 69 | conn.close(); 70 | 71 | busyConnections.clear(); 72 | idleConnections.clear(); 73 | lock.unlock(); 74 | } 75 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/updater/Updater.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.updater; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.IOException; 5 | import java.io.InputStreamReader; 6 | import java.net.URL; 7 | 8 | import com.cypherx.xauth.xAuthLog; 9 | 10 | public class Updater { 11 | private static final String VERSION_FILE = "http://love-despite.com/cypher/bukkit/xAuth/version.txt"; 12 | 13 | private final String currVer; 14 | private String latestVer; 15 | private UpdatePriority priority; 16 | 17 | public Updater(String currVer) { 18 | this.currVer = currVer; 19 | loadLatestVersion(); 20 | } 21 | 22 | private void loadLatestVersion() { 23 | BufferedReader reader = null; 24 | 25 | try { 26 | URL url = new URL(VERSION_FILE); 27 | reader = new BufferedReader(new InputStreamReader(url.openStream())); 28 | String str = reader.readLine(); 29 | String[] split = str.split("\\|"); 30 | latestVer = split[0]; 31 | priority = UpdatePriority.getPriority(Integer.parseInt(split[1])); 32 | } catch (IOException e) { 33 | xAuthLog.warning("Could not check for newer version!"); 34 | latestVer = null; 35 | } finally { 36 | try { 37 | if (reader != null) 38 | reader.close(); 39 | } catch (IOException e) {} 40 | } 41 | } 42 | 43 | public boolean isUpdateAvailable() { 44 | if (latestVer == null) 45 | return false; 46 | 47 | return compareVer(latestVer, currVer) > 0; 48 | } 49 | 50 | private int compareVer(String str1, String str2) { 51 | String[] vals1 = str1.split("\\."); 52 | String[] vals2 = str2.split("\\."); 53 | int i = 0; 54 | 55 | while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) 56 | i++; 57 | 58 | if (i < vals1.length && i < vals2.length) { 59 | int diff = new Integer(vals1[i]).compareTo(new Integer(vals2[i])); 60 | return diff < 0 ? -1 : diff == 0 ? 0 : 1; 61 | } 62 | 63 | return vals1.length < vals2.length ? -1 : vals1.length == vals2.length ? 0 : 1; 64 | } 65 | 66 | public void printMessage() { 67 | xAuthLog.warning("-------- xAuth Updater --------"); 68 | xAuthLog.warning("This server appears to be running an older version"); 69 | xAuthLog.warning(String.format("of xAuth. Version %s is now available.", latestVer)); 70 | xAuthLog.warning(""); 71 | xAuthLog.warning(String.format("Priority: %s", priority)); 72 | xAuthLog.warning("Details: http://bit.ly/I5nFne"); 73 | xAuthLog.warning("Download: http://bit.ly/IbRYP2"); 74 | xAuthLog.warning("-------------------------------"); 75 | } 76 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/Utils.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth; 2 | 3 | import java.io.BufferedInputStream; 4 | import java.io.BufferedReader; 5 | import java.io.File; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.InputStream; 9 | import java.io.InputStreamReader; 10 | import java.io.Reader; 11 | import java.io.StringWriter; 12 | import java.io.Writer; 13 | import java.net.URL; 14 | import java.util.regex.Matcher; 15 | import java.util.regex.Pattern; 16 | 17 | public class Utils { 18 | public static String streamToString(InputStream in) { 19 | if (in != null) { 20 | Writer writer = new StringWriter(); 21 | 22 | char[] buffer = new char[1024]; 23 | try { 24 | Reader reader = new BufferedReader(new InputStreamReader(in, "UTF-8")); 25 | int n; 26 | while ((n = reader.read(buffer)) != -1) 27 | writer.write(buffer, 0, n); 28 | } catch (IOException e) { 29 | e.printStackTrace(); 30 | } finally { 31 | try { 32 | in.close(); 33 | } catch (IOException e) {} 34 | } 35 | return writer.toString(); 36 | } else 37 | return ""; 38 | } 39 | 40 | public static void downloadFile(File file, String location) { 41 | BufferedInputStream input = null; 42 | FileOutputStream output = null; 43 | 44 | try { 45 | URL url = new URL(location); 46 | input = new BufferedInputStream(url.openStream()); 47 | output = new FileOutputStream(file); 48 | 49 | byte data[] = new byte[1024]; 50 | int count; 51 | 52 | while ((count = input.read(data)) != -1) 53 | output.write(data, 0, count); 54 | } catch (IOException e) { 55 | xAuthLog.severe("Failed to download file: " + file.getName(), e); 56 | } finally { 57 | try { 58 | if (input != null) 59 | input.close(); 60 | } catch (IOException e) {} 61 | 62 | try { 63 | if (output != null) 64 | output.close(); 65 | } catch (IOException e) {} 66 | } 67 | } 68 | 69 | public static boolean isIPAddress(String ipAddress) { 70 | if (ipAddress == null) 71 | return false; 72 | 73 | Pattern pattern = Pattern.compile( 74 | "\\b" + 75 | "((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\." + 76 | "((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\." + 77 | "((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])\\." + 78 | "((?!\\d\\d\\d)\\d+|1\\d\\d|2[0-4]\\d|25[0-5])" + 79 | "\\b"); 80 | Matcher matcher = pattern.matcher(ipAddress); 81 | return matcher.matches(); 82 | } 83 | 84 | public static boolean isWhitespace(String str) { 85 | if (str == null) 86 | return false; 87 | 88 | for (int i = 0; i < str.length(); i++) 89 | if (!Character.isWhitespace(str.charAt(i))) 90 | return false; 91 | 92 | return true; 93 | } 94 | } -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: xAuth 2 | version: 2.0.9 3 | description: Offline-mode Authentication 4 | author: CypherX 5 | website: https://github.com/CypherX/xAuth 6 | 7 | main: com.cypherx.xauth.xAuth 8 | 9 | commands: 10 | register: 11 | description: Register your player with the supplied password. 12 | usage: / [email] 13 | login: 14 | description: Authenticate yourself as the owner of this player. 15 | aliases: [l] 16 | usage: / 17 | logout: 18 | description: Manually end your login session. 19 | usage: / 20 | changepw: 21 | description: Change your password. 22 | aliases: [changepassword, changepass, cpw] 23 | usage: / 24 | xauth: 25 | description: Access all xAuth admin commands. 26 | aliases: [x] 27 | usage: | 28 | / register [email] 29 | / changepw 30 | / logout 31 | / unregister 32 | / location set|remove [global] 33 | / reload 34 | / activate 35 | / config 36 | 37 | permissions: 38 | xauth.register: 39 | description: Allows players/groups to register when new registrations are disabled. 40 | default: false 41 | xauth.admin.*: 42 | description: Grants access to all xAuth admin commands 43 | children: 44 | xauth.admin.register: true 45 | xauth.admin.changepw: true 46 | xauth.admin.logout: true 47 | xauth.admin.unregister: true 48 | xauth.admin.location: true 49 | xauth.admin.reload: true 50 | xauth.admin.activate: true 51 | xauth.admin.config: true 52 | xauth.admin.register: 53 | description: Allows you to register other players 54 | default: op 55 | xauth.admin.changepw: 56 | description: Allows changing of other players passwords 57 | default: op 58 | xauth.admin.logout: 59 | description: Allows you to end a players session 60 | default: op 61 | xauth.admin.unregister: 62 | description: Remove a players registration 63 | default: op 64 | xauth.admin.location: 65 | description: Set/remove the current world or global teleport location 66 | default: op 67 | xauth.admin.reload: 68 | description: Allows you to reload the xAuth configuration and player cache. 69 | default: op 70 | xauth.admin.activate: 71 | description: Allows you to activate a player's account. 72 | default: op 73 | xauth.admin.config: 74 | description: Allows you to modify the configuration via a command. 75 | default: op 76 | xauth.bypass.acclimit: 77 | description: Allows you to bypass the account limit and register an unlimited amount of accounts. -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/xAuthPlayer.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth; 2 | 3 | import java.sql.Timestamp; 4 | 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.entity.Player; 7 | 8 | public class xAuthPlayer { 9 | private String playerName; 10 | private int accountId = 0; 11 | private Status status = Status.Guest; 12 | private PlayerData playerData; 13 | private Timestamp lastNotifyTime; 14 | private Timestamp loginTime; 15 | private boolean creativeMode; 16 | private int timeoutTaskId = -1; 17 | private boolean isProtected = false; 18 | private Timestamp connectTime; 19 | 20 | public xAuthPlayer(final String playerName) { 21 | this.playerName = playerName; 22 | } 23 | 24 | public xAuthPlayer(final String playerName, final int accountId) { 25 | this.playerName = playerName; 26 | this.accountId = accountId; 27 | status = Status.Registered; 28 | } 29 | 30 | public String getPlayerName() { return playerName; } 31 | public Player getPlayer() { return Bukkit.getServer().getPlayerExact(playerName); } 32 | public int getAccountId() { return accountId; } 33 | public void setAccountId(int accountId) { this.accountId = accountId; } 34 | public Status getStatus() { return status; } 35 | public void setStatus(Status status) { this.status = status; } 36 | public PlayerData getPlayerData() { return playerData; } 37 | public void setPlayerData(PlayerData playerData) { this.playerData = playerData; } 38 | public Timestamp getLastNotifyTime() { return lastNotifyTime; } 39 | public void setLastNotifyTime(Timestamp lastNotifyTime) { this.lastNotifyTime = lastNotifyTime; } 40 | public Timestamp getLoginTime() { return loginTime; } 41 | public void setLoginTime(Timestamp loginTime) { this.loginTime = loginTime; } 42 | public boolean isCreativeMode() { return creativeMode; } 43 | public void setCreative(boolean creativeMode) { this.creativeMode = creativeMode; } 44 | public int getTimeoutTaskId() { return timeoutTaskId; } 45 | public void setTimeoutTaskId(int timeoutTaskId) { this.timeoutTaskId = timeoutTaskId; } 46 | public boolean isProtected() { return isProtected; } 47 | public void setProtected(boolean isProtected) { this.isProtected = isProtected; } 48 | public Timestamp getConnectTime() { return connectTime; } 49 | public void setConnectTime(Timestamp connectTime) { this.connectTime = connectTime; } 50 | 51 | public boolean isGuest() { return status == Status.Guest; } 52 | public boolean isRegistered() { return status != Status.Guest; } 53 | public boolean isAuthenticated() { return status == Status.Authenticated; } 54 | 55 | public String getIPAddress() { 56 | Player player = getPlayer(); 57 | if (player == null) 58 | return null; 59 | 60 | try { 61 | return player.getAddress().getAddress().getHostAddress(); 62 | } catch (NullPointerException e) { 63 | return null; 64 | } 65 | } 66 | 67 | public enum Status { 68 | Guest, // not registered 69 | Registered, // registered but not logged in 70 | Authenticated // logged in 71 | } 72 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | com.cypherx 4 | xAuth 5 | 2.0.9 6 | xAuth 7 | 8 | 9 | UTF-8 10 | 11 | 12 | 13 | 14 | bukkit-repo 15 | http://repo.bukkit.org/content/groups/public 16 | 17 | 25 | 26 | 27 | 28 | 29 | org.bukkit 30 | bukkit 31 | 1.2.5-R1.2 32 | 33 | 43 | 44 | 45 | 46 | 47 | 48 | . 49 | ${basedir}/src/main/resources/ 50 | true 51 | 52 | config.yml 53 | messages.yml 54 | plugin.yml 55 | 56 | 57 | 58 | sql 59 | ${basedir}/src/main/resources/sql/ 60 | true 61 | 62 | **/*.sql 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.apache.maven.plugins 70 | maven-compiler-plugin 71 | 2.3.2 72 | 73 | true 74 | 75 | 76 | 77 | org.apache.maven.plugins 78 | maven-jar-plugin 79 | 2.4 80 | 81 | 82 | 83 | ../lib/h2-1.3.164.jar 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/strike/StrikeManager.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.strike; 2 | 3 | import java.sql.ResultSet; 4 | import java.sql.Timestamp; 5 | import java.sql.Connection; 6 | import java.sql.PreparedStatement; 7 | import java.sql.SQLException; 8 | import java.util.HashMap; 9 | import java.util.Map; 10 | 11 | import org.bukkit.entity.Player; 12 | 13 | import com.cypherx.xauth.xAuth; 14 | import com.cypherx.xauth.xAuthLog; 15 | import com.cypherx.xauth.database.Table; 16 | 17 | public class StrikeManager { 18 | private final xAuth plugin; 19 | private Map strikeRecords = new HashMap(); 20 | 21 | public StrikeManager(final xAuth plugin) { 22 | this.plugin = plugin; 23 | } 24 | 25 | public StrikeRecord getRecord(String ipAddress) { 26 | if (strikeRecords.containsKey(ipAddress)) 27 | return strikeRecords.get(ipAddress); 28 | 29 | StrikeRecord record = new StrikeRecord(); 30 | strikeRecords.put(ipAddress, record); 31 | return record; 32 | } 33 | 34 | public void strikeout(Player player) { 35 | player.kickPlayer(plugin.getMsgHndlr().get("misc.strikeout")); 36 | xAuthLog.info(player.getName() + " kicked for passing the incorrect password threshold"); 37 | 38 | if (plugin.getConfig().getInt("strikes.lockout-length") > 0) { 39 | String ipAddress = player.getAddress().getAddress().getHostAddress(); 40 | String playerName = player.getName(); 41 | 42 | Connection conn = plugin.getDbCtrl().getConnection(); 43 | PreparedStatement ps = null; 44 | 45 | try { 46 | String sql = String.format("INSERT INTO `%s` (`ipaddress`, `playername`, `time`) VALUES (?, ?, ?)", 47 | plugin.getDbCtrl().getTable(Table.LOCKOUT)); 48 | ps = conn.prepareStatement(sql); 49 | ps.setString(1, ipAddress); 50 | ps.setString(2, playerName); 51 | ps.setTimestamp(3, new Timestamp(System.currentTimeMillis())); 52 | ps.executeUpdate(); 53 | } catch (SQLException e) { 54 | xAuthLog.severe(String.format("Failed to insert lockout record for player: %s (%s)", playerName, ipAddress), e); 55 | } finally { 56 | plugin.getDbCtrl().close(conn, ps); 57 | } 58 | } 59 | } 60 | 61 | public boolean isLockedOut(String ipAddress, String playerName) { 62 | if (plugin.getConfig().getInt("strikes.lockout-length") < 1) 63 | return false; 64 | 65 | Connection conn = plugin.getDbCtrl().getConnection(); 66 | PreparedStatement ps = null; 67 | ResultSet rs = null; 68 | 69 | try { 70 | String sql = String.format("SELECT `time` FROM `%s` WHERE `ipaddress` = ? AND `playername` = ?", 71 | plugin.getDbCtrl().getTable(Table.LOCKOUT)); 72 | ps = conn.prepareStatement(sql); 73 | ps.setString(1, ipAddress); 74 | ps.setString(2, playerName); 75 | rs = ps.executeQuery(); 76 | if (!rs.next()) 77 | return false; 78 | 79 | Timestamp lockoutTime = rs.getTimestamp("time"); 80 | Timestamp expireTime = new Timestamp(lockoutTime.getTime() + (plugin.getConfig().getInt("strikes.lockout-length") * 1000)); 81 | return expireTime.compareTo(new Timestamp(System.currentTimeMillis())) > 0; 82 | } catch (SQLException e) { 83 | xAuthLog.severe(String.format("Failed to load lockout time for player: %s (%s)", playerName, ipAddress), e); 84 | return false; 85 | } finally { 86 | plugin.getDbCtrl().close(conn, ps, rs); 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/plugins/xPermissions.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.plugins; 2 | 3 | //import org.bukkit.Bukkit; 4 | import org.bukkit.command.CommandSender; 5 | import org.bukkit.command.ConsoleCommandSender; 6 | import org.bukkit.command.RemoteConsoleCommandSender; 7 | import org.bukkit.entity.Player; 8 | //import org.bukkit.plugin.Plugin; 9 | //import org.bukkit.plugin.PluginDescriptionFile; 10 | 11 | //import ru.tehkode.permissions.bukkit.PermissionsEx; 12 | 13 | //import com.cypherx.xauth.xAuthLog; 14 | 15 | //import de.bananaco.bpermissions.api.ApiLayer; 16 | //import de.bananaco.bpermissions.api.util.CalculableType; 17 | 18 | public class xPermissions { 19 | //private static PermissionsType type = null; 20 | //private static Plugin permissionsPlugin; 21 | 22 | /*public static void init() { 23 | Plugin permissionsEx = Bukkit.getServer().getPluginManager().getPlugin("PermissionsEx"); 24 | Plugin bPermissions = Bukkit.getServer().getPluginManager().getPlugin("bPermissions"); 25 | 26 | if (permissionsEx != null) { 27 | type = PermissionsType.PermissionsEx; 28 | permissionsPlugin = permissionsEx; 29 | } else if (bPermissions != null) { 30 | type = PermissionsType.bPermissions; 31 | permissionsPlugin = bPermissions; 32 | } else 33 | type = PermissionsType.BukkitPerms; 34 | 35 | if (permissionsPlugin != null) { 36 | PluginDescriptionFile desc = permissionsPlugin.getDescription(); 37 | xAuthLog.info("Permissions support enabled: " + desc.getName() + " v" + desc.getVersion()); 38 | } else 39 | xAuthLog.info("Bukkit Permissions enabled (no plugin detected)"); 40 | }*/ 41 | 42 | public static boolean has(CommandSender sender, String permission) { 43 | if (sender instanceof Player) 44 | return has((Player)sender, permission); 45 | else if (sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) 46 | return true; 47 | else 48 | return false; 49 | } 50 | 51 | public static boolean has(Player player, String permission) { 52 | /*switch (type) { 53 | case PermissionsEx: 54 | return PermissionsEx.getPermissionManager().has(player, permission); 55 | case bPermissions: 56 | return ApiLayer.hasPermission(player.getWorld().getName(), CalculableType.USER, player.getName(), permission); 57 | case BukkitPerms: 58 | return player.hasPermission(permission); 59 | default: 60 | return player.isOp(); 61 | }*/ 62 | return player.hasPermission(permission); 63 | } 64 | 65 | /*public static void addGroup(Player player, String group) { 66 | switch (type) { 67 | case PermissionsEx: 68 | PermissionsEx.getUser(player).addGroup(group); 69 | break; 70 | case bPermissions: 71 | ApiLayer.addGroup(player.getWorld().getName(), CalculableType.USER, player.getName(), group); 72 | break; 73 | case BukkitPerms: 74 | xAuthLog.warning("Bukkit Permissions does not support modifying groups"); 75 | break; 76 | } 77 | } 78 | 79 | public static void removeGroup(Player player, String group) { 80 | switch (type) { 81 | case PermissionsEx: 82 | PermissionsEx.getUser(player).removeGroup(group); 83 | break; 84 | case bPermissions: 85 | ApiLayer.removeGroup(player.getWorld().getName(), CalculableType.USER, player.getName(), group); 86 | break; 87 | case BukkitPerms: 88 | xAuthLog.warning("Bukkit Permissions does not support modifying groups"); 89 | break; 90 | } 91 | }*/ 92 | 93 | /*private enum PermissionsType { 94 | PermissionsEx, 95 | bPermissions, 96 | BukkitPerms 97 | }*/ 98 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/MessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.configuration.file.FileConfiguration; 9 | import org.bukkit.configuration.file.YamlConfiguration; 10 | 11 | public class MessageHandler { 12 | private final xAuth plugin; 13 | private final String fileName = "messages.yml"; 14 | private final File configFile; 15 | private FileConfiguration config = null; 16 | 17 | public MessageHandler(final xAuth plugin) { 18 | this.plugin = plugin; 19 | this.configFile = new File(plugin.getDataFolder(), fileName); 20 | } 21 | 22 | public FileConfiguration getConfig() { 23 | if (config == null) 24 | reloadConfig(); 25 | 26 | return config; 27 | } 28 | 29 | public void reloadConfig() { 30 | config = YamlConfiguration.loadConfiguration(configFile); 31 | 32 | InputStream defConfigStream = plugin.getResource(fileName); 33 | if (defConfigStream != null) { 34 | YamlConfiguration defConfig = YamlConfiguration.loadConfiguration(defConfigStream); 35 | config.setDefaults(defConfig); 36 | } 37 | } 38 | 39 | public void saveConfig() { 40 | try { 41 | getConfig().save(configFile); 42 | } catch (IOException e) { 43 | xAuthLog.severe("Could not save message configuration to " + configFile, e); 44 | } 45 | } 46 | 47 | public void sendMessage(String node, CommandSender sender) { 48 | sendMessage(node, sender, null); 49 | } 50 | 51 | public void sendMessage(String node, CommandSender sender, String targetName) { 52 | if (sender != null) { 53 | String message = get(node, sender.getName(), targetName); 54 | 55 | for (String line : message.split("\n")) 56 | sender.sendMessage(line); 57 | } 58 | } 59 | 60 | public String get(String node) { 61 | return get(node, null, null); 62 | } 63 | 64 | private String get(String node, String playerName, String targetName) { 65 | return replace(config.getString(node, node), playerName, targetName); 66 | } 67 | 68 | private String replace(String message, String playerName, String targetName) { 69 | // colors 70 | message = message.replace("{BLACK}", "&0"); 71 | message = message.replace("{DARKBLUE}", "&1"); 72 | message = message.replace("{DARKGREEN}", "&2"); 73 | message = message.replace("{DARKTEAL}", "&3"); 74 | message = message.replace("{DARKRED}", "&4"); 75 | message = message.replace("{PURPLE}", "&5"); 76 | message = message.replace("{GOLD}", "&6"); 77 | message = message.replace("{GRAY}", "&7"); 78 | message = message.replace("{DARKGRAY}", "&8"); 79 | message = message.replace("{BLUE}", "&9"); 80 | message = message.replace("{BRIGHTGREEN}", "&a"); 81 | message = message.replace("{TEAL}", "&b"); 82 | message = message.replace("{RED}", "&c"); 83 | message = message.replace("{PINK}", "&d"); 84 | message = message.replace("{YELLOW}", "&e"); 85 | message = message.replace("{WHITE}", "&f"); 86 | message = message.replace("&", "\u00a7"); 87 | 88 | // player 89 | if (playerName != null) 90 | message = message.replace("{PLAYER}", playerName); 91 | 92 | // target 93 | if (targetName != null) 94 | message = message.replace("{TARGET}", targetName); 95 | 96 | // TODO other replacement vars 97 | message = message.replace("{PWMINLENGTH}", String.valueOf(plugin.getConfig().getInt("password.min-length"))); 98 | 99 | // newline 100 | message = message.replace("{NEWLINE}", "\n"); 101 | return message; 102 | } 103 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/listeners/xAuthEntityListener.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.listeners; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.entity.Entity; 5 | import org.bukkit.entity.LivingEntity; 6 | import org.bukkit.entity.Player; 7 | import org.bukkit.event.EventHandler; 8 | import org.bukkit.event.EventPriority; 9 | import org.bukkit.event.Listener; 10 | import org.bukkit.event.entity.EntityDamageByEntityEvent; 11 | import org.bukkit.event.entity.EntityDamageEvent; 12 | import org.bukkit.event.entity.EntityRegainHealthEvent; 13 | import org.bukkit.event.entity.EntityTargetEvent; 14 | import org.bukkit.event.entity.FoodLevelChangeEvent; 15 | import org.bukkit.event.entity.PotionSplashEvent; 16 | 17 | import com.cypherx.xauth.PlayerManager; 18 | import com.cypherx.xauth.xAuth; 19 | import com.cypherx.xauth.xAuthPlayer; 20 | 21 | public class xAuthEntityListener implements Listener { 22 | private final PlayerManager plyrMngr; 23 | 24 | public xAuthEntityListener(final xAuth plugin) { 25 | this.plyrMngr = plugin.getPlyrMngr(); 26 | Bukkit.getServer().getPluginManager().registerEvents(this, plugin); 27 | } 28 | 29 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 30 | public void onEntityDamage(EntityDamageEvent event) { 31 | Entity entity = event.getEntity(); 32 | if (entity instanceof Player && ((Player)entity).isOnline()) { // player taking damage 33 | xAuthPlayer xp = plyrMngr.getPlayer(((Player)entity).getName()); 34 | if (plyrMngr.isRestricted(xp, event) || plyrMngr.hasGodmode(xp, event.getCause())) 35 | event.setCancelled(true); 36 | } 37 | 38 | if (event instanceof EntityDamageByEntityEvent) { // player dealing damage to other entity 39 | EntityDamageByEntityEvent edbeEvent = (EntityDamageByEntityEvent) event; 40 | Entity damager = edbeEvent.getDamager(); 41 | if (damager instanceof Player) { 42 | xAuthPlayer player = plyrMngr.getPlayer(((Player)damager).getName()); 43 | if (plyrMngr.isRestricted(player, edbeEvent)) { 44 | plyrMngr.sendNotice(player); 45 | event.setCancelled(true); 46 | } 47 | } 48 | } 49 | } 50 | 51 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 52 | public void onEntityTarget(EntityTargetEvent event) { 53 | Entity target = event.getTarget(); 54 | if (target instanceof Player) { 55 | xAuthPlayer xp = plyrMngr.getPlayer(((Player) target).getName()); 56 | if (plyrMngr.isRestricted(xp, event)) 57 | event.setCancelled(true); 58 | } 59 | } 60 | 61 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 62 | public void onFoodLevelChange(FoodLevelChangeEvent event) { 63 | Entity entity = event.getEntity(); 64 | if (entity instanceof Player) { 65 | xAuthPlayer xp = plyrMngr.getPlayer(((Player) entity).getName()); 66 | if (plyrMngr.isRestricted(xp, event)) 67 | event.setCancelled(true); 68 | } 69 | } 70 | 71 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 72 | public void onPotionSplash(PotionSplashEvent event) { 73 | for (LivingEntity entity : event.getAffectedEntities()) { 74 | if (entity instanceof Player) { 75 | xAuthPlayer xp = plyrMngr.getPlayer(((Player) entity).getName()); 76 | if (plyrMngr.isRestricted(xp, event)) 77 | event.setIntensity(entity, 0); 78 | } 79 | } 80 | } 81 | 82 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 83 | public void onEntityRegainHealth(EntityRegainHealthEvent event) { 84 | Entity entity = event.getEntity(); 85 | if (entity instanceof Player) { 86 | xAuthPlayer xp = plyrMngr.getPlayer(((Player) entity).getName()); 87 | if (plyrMngr.isRestricted(xp, event)) 88 | event.setCancelled(true); 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/auth/Auth.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2011 moparisthebest 3 | *

4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | *

9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | *

14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | *

17 | * Official forums are http://www.moparscape.org/smf/ 18 | * Email me at admin@moparisthebest.com , I read it but don't usually respond. 19 | */ 20 | 21 | package com.cypherx.xauth.auth; 22 | 23 | import com.cypherx.xauth.xAuth; 24 | 25 | public abstract class Auth { 26 | protected xAuth plugin; 27 | protected String response = null; 28 | protected String group = null; 29 | 30 | /** 31 | * Returns human-readable response suitable for printing to users, or null if nothing should be printed. 32 | * @return String 33 | */ 34 | public String getResponse() { return response; } 35 | 36 | /** 37 | * Returns permissions group user should be a member of, or null if no group should be added. 38 | * @return String 39 | */ 40 | public String getGroup() { return group; } 41 | 42 | /** 43 | * Attempts to authenticate a user with a given password. Sets response and group appropriately. 44 | * Also sets status to online if supported, so no need to call online() if this is successful. 45 | * @param user Username 46 | * @param pass Password 47 | * @return success 48 | */ 49 | public abstract boolean login(String user, String pass); 50 | 51 | /** 52 | * Attempts to register a username with the given password and email. Sets response appropriately. 53 | * @param user Username 54 | * @param pass Password 55 | * @param email Valid email address, can be null. 56 | * @return success 57 | */ 58 | public abstract boolean register(String user, String pass, String email); 59 | 60 | /** 61 | * Attempts to register an account for the user specified. 62 | * This is reserved for the /xauth register command and skips most checks. 63 | * @param user 64 | * @param pass 65 | * @param email 66 | * @return success 67 | */ 68 | public abstract boolean adminRegister(String user, String pass, String email); 69 | 70 | /** 71 | * Attempts to change a user's password. 72 | * @param user Username 73 | * @param oldPass Old password 74 | * @param newPass New password 75 | * @return success 76 | */ 77 | public abstract boolean changePassword(String user, String oldPass, String newPass); 78 | 79 | /** 80 | * Attempts to change the specified user's password. 81 | * This is reserved for the /xauth changepw command skips most checks. 82 | * @param user 83 | * @param newPass 84 | * @return success 85 | */ 86 | public abstract boolean adminChangePassword(String user, String newPass); 87 | 88 | /** 89 | * Sets status of user to online if supported. This is for use when a user doesn't need to supply 90 | * a password due to a session that has not yet timed out. Sets response appropriately. 91 | * @param user Username 92 | * @return success May be safely ignored 93 | */ 94 | public abstract boolean online(String user); 95 | 96 | /** 97 | * Sets status of user to offline if supported, to be called when a user logs out or is disconnected. 98 | * No response is set and none need be displayed. 99 | * @param user Username 100 | * @return success May be safely ignored 101 | */ 102 | public abstract boolean offline(String user); 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/password/PasswordHandler.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.password; 2 | 3 | import java.math.BigInteger; 4 | import java.security.MessageDigest; 5 | import java.security.NoSuchAlgorithmException; 6 | import java.sql.Connection; 7 | import java.sql.PreparedStatement; 8 | import java.sql.ResultSet; 9 | import java.sql.SQLException; 10 | import java.util.UUID; 11 | 12 | import com.cypherx.xauth.xAuth; 13 | import com.cypherx.xauth.xAuthLog; 14 | import com.cypherx.xauth.database.Table; 15 | 16 | public class PasswordHandler { 17 | private final xAuth plugin; 18 | 19 | public PasswordHandler(final xAuth plugin) { 20 | this.plugin = plugin; 21 | } 22 | 23 | public boolean checkPassword(int accountId, String checkPass) { 24 | String realPass = ""; 25 | PasswordType type = PasswordType.DEFAULT; 26 | 27 | Connection conn = plugin.getDbCtrl().getConnection(); 28 | PreparedStatement ps = null; 29 | ResultSet rs = null; 30 | 31 | try { 32 | String sql = String.format("SELECT `password`, `pwtype` FROM `%s` WHERE `id` = ?", 33 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); 34 | ps = conn.prepareStatement(sql); 35 | ps.setInt(1, accountId); 36 | rs = ps.executeQuery(); 37 | if (!rs.next()) 38 | return false; 39 | 40 | realPass = rs.getString("password"); 41 | type = PasswordType.getType(rs.getInt("pwtype")); 42 | } catch (SQLException e) { 43 | xAuthLog.severe("Failed to retrieve password hash for account: " + accountId, e); 44 | return false; 45 | } finally { 46 | plugin.getDbCtrl().close(conn, ps, rs); 47 | } 48 | 49 | String checkPassHash = ""; 50 | if (type == PasswordType.DEFAULT) { 51 | int saltPos = (checkPass.length() >= realPass.length() ? realPass.length() - 1 : checkPass.length()); 52 | String salt = realPass.substring(saltPos, saltPos + 12); 53 | String hash = whirlpool(salt + checkPass); 54 | checkPassHash = hash.substring(0, saltPos) + salt + hash.substring(saltPos); 55 | } else if (type == PasswordType.WHIRLPOOL) { 56 | checkPassHash = whirlpool(checkPass); 57 | } else if (type == PasswordType.AUTHME_SHA256) { 58 | String salt = realPass.split("\\$")[2]; 59 | checkPassHash = "$SHA$" + salt + "$" + hash(hash(checkPass, "SHA-256") + salt, "SHA-256"); 60 | } else 61 | checkPassHash = hash(checkPass, type.getAlgorithm()); 62 | 63 | if (checkPassHash.equals(realPass)) { 64 | // update hash in database to use xAuth's hashing method 65 | String newHash = hash(checkPass); 66 | conn = plugin.getDbCtrl().getConnection(); 67 | 68 | try { 69 | String sql = String.format("UPDATE `%s` SET `password` = ?, `pwtype` = ? WHERE `id` = ?", 70 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); 71 | ps = conn.prepareStatement(sql); 72 | ps.setString(1, newHash); 73 | ps.setInt(2, 0); 74 | ps.setInt(3, accountId); 75 | ps.executeUpdate(); 76 | } catch (SQLException e) { 77 | xAuthLog.severe("Failed to update password hash for account: " + accountId, e); 78 | } finally { 79 | plugin.getDbCtrl().close(conn, ps); 80 | } 81 | 82 | return true; 83 | } else 84 | return false; 85 | } 86 | 87 | // xAuth's custom hashing technique 88 | public String hash(String toHash) { 89 | String salt = whirlpool(UUID.randomUUID().toString()).substring(0, 12); 90 | String hash = whirlpool(salt + toHash); 91 | int saltPos = (toHash.length() >= hash.length() ? hash.length() - 1 : toHash.length()); 92 | return hash.substring(0, saltPos) + salt + hash.substring(saltPos); 93 | } 94 | 95 | private String hash(String toHash, String algorithm) { 96 | try { 97 | MessageDigest md = MessageDigest.getInstance(algorithm); 98 | md.update(toHash.getBytes()); 99 | byte[] digest = md.digest(); 100 | return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest)); 101 | } catch (NoSuchAlgorithmException e) { 102 | e.printStackTrace(); 103 | return null; 104 | } 105 | } 106 | 107 | private String whirlpool(String toHash) { 108 | Whirlpool w = new Whirlpool(); 109 | byte[] digest = new byte[Whirlpool.DIGESTBYTES]; 110 | w.NESSIEinit(); 111 | w.NESSIEadd(toHash); 112 | w.NESSIEfinalize(digest); 113 | return Whirlpool.display(digest); 114 | } 115 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/LocationManager.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | import java.util.UUID; 10 | 11 | import org.bukkit.Bukkit; 12 | import org.bukkit.Location; 13 | import org.bukkit.World; 14 | 15 | import com.cypherx.xauth.database.Table; 16 | 17 | public class LocationManager { 18 | private final xAuth plugin; 19 | private Map locations = new HashMap(); 20 | private UUID globalUID = null; 21 | 22 | public LocationManager(final xAuth plugin) { 23 | this.plugin = plugin; 24 | loadLocations(); 25 | } 26 | 27 | public void loadLocations() { 28 | Connection conn = plugin.getDbCtrl().getConnection(); 29 | PreparedStatement ps = null; 30 | ResultSet rs = null; 31 | 32 | try { 33 | String sql = String.format("SELECT * FROM `%s`", 34 | plugin.getDbCtrl().getTable(Table.LOCATION)); 35 | ps = conn.prepareStatement(sql); 36 | rs = ps.executeQuery(); 37 | 38 | while (rs.next()) { 39 | UUID uid = UUID.fromString(rs.getString("uid")); 40 | double x = rs.getDouble("x"); 41 | double y = rs.getDouble("y"); 42 | double z = rs.getDouble("z"); 43 | float yaw = rs.getFloat("yaw"); 44 | float pitch = rs.getFloat("pitch"); 45 | int global = rs.getInt("global"); 46 | locations.put(uid, new Location(Bukkit.getServer().getWorld(uid), x, y, z, yaw, pitch)); 47 | 48 | if (global == 1) 49 | globalUID = uid; 50 | } 51 | } catch (SQLException e) { 52 | xAuthLog.severe("Failed to load teleport locations!", e); 53 | } finally { 54 | plugin.getDbCtrl().close(conn, ps, rs); 55 | } 56 | } 57 | 58 | public Location getLocation(World world) { 59 | UUID uid = globalUID == null ? world.getUID() : globalUID; 60 | Location loc = locations.get(uid); 61 | return loc == null ? world.getSpawnLocation() : loc; 62 | } 63 | 64 | public boolean setLocation(Location loc, boolean global) { 65 | UUID uid = loc.getWorld().getUID(); 66 | Connection conn = plugin.getDbCtrl().getConnection(); 67 | PreparedStatement ps = null; 68 | 69 | try { 70 | String sql; 71 | if (plugin.getDbCtrl().isMySQL()) 72 | sql = String.format("INSERT INTO `%s` VALUES (?, ?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE `uid` = VALUES(`uid`), `x` = VALUES(`x`), `y` = VALUES(`y`), `z` = VALUES(`z`), `yaw` = VALUES(`yaw`), `pitch` = VALUES(`pitch`), `global` = VALUES(`global`)", 73 | plugin.getDbCtrl().getTable(Table.LOCATION)); 74 | else 75 | sql = String.format("MERGE INTO `%s` VALUES (?, ?, ?, ?, ?, ?, ?)", 76 | plugin.getDbCtrl().getTable(Table.LOCATION)); 77 | 78 | ps = conn.prepareStatement(sql); 79 | ps.setString(1, uid.toString()); 80 | ps.setDouble(2, loc.getX()); 81 | ps.setDouble(3, loc.getY()); 82 | ps.setDouble(4, loc.getZ()); 83 | ps.setFloat(5, loc.getYaw()); 84 | ps.setFloat(6, loc.getPitch()); 85 | ps.setInt(7, global ? 1 : 0); 86 | ps.executeUpdate(); 87 | 88 | locations.put(uid, loc); 89 | if (global) 90 | globalUID = uid; 91 | else if (!global && globalUID != null && globalUID == uid) 92 | globalUID = null; 93 | 94 | return true; 95 | } catch (SQLException e) { 96 | xAuthLog.severe("Failed to set location!", e); 97 | return false; 98 | } finally { 99 | plugin.getDbCtrl().close(conn, ps); 100 | } 101 | } 102 | 103 | public boolean removeLocation(World world) { 104 | UUID uid = world.getUID(); 105 | Connection conn = plugin.getDbCtrl().getConnection(); 106 | PreparedStatement ps = null; 107 | 108 | try { 109 | String sql = String.format("DELETE FROM `%s` WHERE `uid` = ?", 110 | plugin.getDbCtrl().getTable(Table.LOCATION)); 111 | ps = conn.prepareStatement(sql); 112 | ps.setString(1, uid.toString()); 113 | ps.executeUpdate(); 114 | 115 | locations.remove(uid); 116 | if (uid == globalUID) 117 | globalUID = null; 118 | 119 | return true; 120 | } catch (SQLException e) { 121 | xAuthLog.severe("Failed to remove location!", e); 122 | return false; 123 | } finally { 124 | plugin.getDbCtrl().close(conn, ps); 125 | } 126 | } 127 | 128 | public boolean isLocationSet(World world) { 129 | return locations.containsKey(world.getUID()); 130 | } 131 | 132 | public UUID getGlobalUID() { return globalUID; } 133 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/database/DatabaseController.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.database; 2 | 3 | import java.io.File; 4 | import java.sql.Connection; 5 | import java.sql.PreparedStatement; 6 | import java.sql.ResultSet; 7 | import java.sql.SQLException; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import org.bukkit.configuration.ConfigurationSection; 12 | 13 | import com.cypherx.xauth.xAuth; 14 | import com.cypherx.xauth.xAuthLog; 15 | 16 | public class DatabaseController { 17 | private final xAuth plugin; 18 | private ConnectionPool connPool; 19 | private List activeTables = new ArrayList
(); 20 | private DBMS dbms = DBMS.H2; 21 | 22 | public DatabaseController(final xAuth plugin) { 23 | this.plugin = plugin; 24 | dbInit(); 25 | } 26 | 27 | private void dbInit() { 28 | // Initialize connection pool 29 | String driver, url, user, pass; 30 | 31 | if (plugin.getConfig().getBoolean("mysql.enabled")) { // MySQL 32 | dbms = DBMS.MySQL; 33 | ConfigurationSection cs = plugin.getConfig().getConfigurationSection("mysql"); 34 | String host = cs.getString("host"); 35 | int port = cs.getInt("port"); 36 | String db = cs.getString("database"); 37 | 38 | driver = "com.mysql.jdbc.Driver"; 39 | url = "jdbc:mysql://" + host + ":" + port + "/" + db + "?zeroDateTimeBehavior=convertToNull"; 40 | user = cs.getString("user"); 41 | pass = cs.getString("password"); 42 | } else { // H2 43 | driver = "org.h2.Driver"; 44 | url = "jdbc:h2:" + plugin.getDataFolder() + File.separator + "xAuth;MODE=MySQL;IGNORECASE=TRUE"; 45 | user = "sa"; 46 | pass = ""; 47 | } 48 | 49 | try { 50 | connPool = new ConnectionPool(driver, url, user, pass); 51 | } catch (ClassNotFoundException e) { 52 | xAuthLog.severe("Failed to create instance of " + getDBMS() + " JDBC Driver!", e); 53 | } 54 | 55 | // Register tables 56 | activeTables.add(Table.ACCOUNT); 57 | activeTables.add(Table.PLAYERDATA); 58 | 59 | // Activate session table only if session length is higher than zero 60 | if (plugin.getConfig().getInt("session.length") > 0) 61 | activeTables.add(Table.SESSION); 62 | 63 | // Activate location table only if location protection is enabled 64 | if (plugin.getConfig().getBoolean("guest.protect-location")) 65 | activeTables.add(Table.LOCATION); 66 | 67 | // Activate lockout table only if lockouts are enabled 68 | if (plugin.getConfig().getInt("strikes.lockout-length") > 0) 69 | activeTables.add(Table.LOCKOUT); 70 | } 71 | 72 | public boolean isConnectable() { 73 | Connection conn = null; 74 | 75 | try { 76 | conn = getConnection(); 77 | return conn != null && !conn.isClosed(); 78 | } catch (SQLException e) { 79 | return false; 80 | } finally { 81 | close(conn); 82 | } 83 | } 84 | 85 | public Connection getConnection() { 86 | try { 87 | return connPool.leaseConn(); 88 | } catch (Exception e) { 89 | xAuthLog.severe("Failed to borrow " + getDBMS() + " connection from pool!", e); 90 | return null; 91 | } 92 | } 93 | 94 | public void close(Connection conn, PreparedStatement ps) { 95 | close(conn, ps, null); 96 | } 97 | 98 | public void close(Connection conn, PreparedStatement ps, ResultSet rs) { 99 | close(rs); 100 | close(ps); 101 | close(conn); 102 | } 103 | 104 | public void close(Connection conn) { 105 | if (conn != null) { 106 | try { 107 | conn.setAutoCommit(true); 108 | connPool.returnConn(conn); 109 | } 110 | catch (Exception e) { 111 | xAuthLog.warning("Failed to return connection to pool!", e); 112 | } 113 | } 114 | } 115 | 116 | public void close(PreparedStatement ps) { 117 | if (ps != null) { 118 | try { 119 | ps.close(); 120 | } catch (SQLException e) { 121 | xAuthLog.warning("Failed to close PreparedStatement object!", e); 122 | } 123 | } 124 | } 125 | 126 | private void close(ResultSet rs) { 127 | if (rs != null) { 128 | try { 129 | rs.close(); 130 | } catch (SQLException e) { 131 | xAuthLog.warning("Failed to close ResultSet object!", e); 132 | } 133 | } 134 | } 135 | 136 | public void close() { 137 | try { 138 | connPool.close(); 139 | } catch (Exception e) { 140 | xAuthLog.severe("Failed to close " + getDBMS() + " connection pool!", e); 141 | } 142 | } 143 | 144 | public void runUpdater() { 145 | DatabaseUpdater dbUpdater = new DatabaseUpdater(plugin, this); 146 | dbUpdater.runUpdate(); 147 | } 148 | 149 | public boolean isTableActive(Table tbl) { 150 | return activeTables.contains(tbl); 151 | } 152 | 153 | public String getTable(Table tbl) { 154 | if (dbms == DBMS.H2) 155 | return tbl.getName(); 156 | 157 | return plugin.getConfig().getString("mysql.tables." + tbl.toString().toLowerCase()); 158 | } 159 | 160 | public List
getActiveTables() { return activeTables; } 161 | public String getDBMS() { return dbms.toString(); } 162 | public boolean isMySQL() { return dbms == DBMS.MySQL; } 163 | private enum DBMS { H2, MySQL } 164 | } -------------------------------------------------------------------------------- /src/main/java/com/martiansoftware/jsap/CommandLineTokenizer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2002-2004, Martian Software, Inc. 3 | * This file is made available under the LGPL as described in the accompanying 4 | * LICENSE.TXT file. 5 | */ 6 | 7 | /* 8 | * Slightly modified by CypherX to clean up warnings. 9 | */ 10 | 11 | package com.martiansoftware.jsap; 12 | 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | 16 | /** 17 | *

A utility class to parse a command line contained in a single String into 18 | * an array of argument tokens, much as the JVM (or more accurately, your 19 | * operating system) does before calling your programs' public static 20 | * void main(String[] args) 21 | * methods.

22 | * 23 | *

This class has been developed to parse the command line in the same way 24 | * that MS Windows 2000 does. Arguments containing spaces should be enclosed 25 | * in quotes. Quotes that should be in the argument string should be escaped 26 | * with a preceding backslash ('\') character. Backslash characters that 27 | * should be in the argument string should also be escaped with a preceding 28 | * backslash character.

29 | * 30 | * Whenever JSAP.parse(String) is called, the specified String is 31 | * tokenized by this class, then forwarded to JSAP.parse(String[]) 32 | * for further processing. 33 | * 34 | * @author Marty Lamb 35 | * @see com.martiansoftware.jsap.JSAP#parse(String) 36 | * @see com.martiansoftware.jsap.JSAP#parse(String[]) 37 | */ 38 | public class CommandLineTokenizer { 39 | 40 | /** 41 | * Hide the constructor. 42 | */ 43 | private CommandLineTokenizer() { 44 | } 45 | 46 | /** 47 | * Goofy internal utility to avoid duplicated code. If the specified 48 | * StringBuffer is not empty, its contents are appended to the resulting 49 | * array (temporarily stored in the specified ArrayList). The StringBuffer 50 | * is then emptied in order to begin storing the next argument. 51 | * @param resultBuffer the List temporarily storing the resulting 52 | * argument array. 53 | * @param buf the StringBuffer storing the current argument. 54 | */ 55 | private static void appendToBuffer(List resultBuffer, StringBuffer buf) { 56 | if (buf.length() > 0) { 57 | resultBuffer.add(buf.toString()); 58 | buf.setLength(0); 59 | } 60 | } 61 | 62 | // Added by CypherX for ease of use. 63 | public static String[] tokenize(String[] args) { 64 | if (args == null || args.length == 0) 65 | return tokenize(""); 66 | 67 | StringBuilder sb = new StringBuilder(args[0]); 68 | for (int i = 1; i < args.length; i++) 69 | sb.append(" ").append(args[i]); 70 | 71 | return tokenize(sb.toString()); 72 | } 73 | 74 | /** 75 | * Parses the specified command line into an array of individual arguments. 76 | * Arguments containing spaces should be enclosed in quotes. 77 | * Quotes that should be in the argument string should be escaped with a 78 | * preceding backslash ('\') character. Backslash characters that should 79 | * be in the argument string should also be escaped with a preceding 80 | * backslash character. 81 | * @param commandLine the command line to parse 82 | * @return an argument array representing the specified command line. 83 | */ 84 | public static String[] tokenize(String commandLine) { 85 | List resultBuffer = new ArrayList(); 86 | 87 | if (commandLine != null) { 88 | int z = commandLine.length(); 89 | boolean insideQuotes = false; 90 | StringBuffer buf = new StringBuffer(); 91 | 92 | for (int i = 0; i < z; ++i) { 93 | char c = commandLine.charAt(i); 94 | if (c == '"') { 95 | appendToBuffer(resultBuffer, buf); 96 | insideQuotes = !insideQuotes; 97 | } else if (c == '\\') { 98 | if ((z > i + 1) 99 | && ((commandLine.charAt(i + 1) == '"') 100 | || (commandLine.charAt(i + 1) == '\\'))) { 101 | buf.append(commandLine.charAt(i + 1)); 102 | ++i; 103 | } else { 104 | buf.append("\\"); 105 | } 106 | } else { 107 | if (insideQuotes) { 108 | buf.append(c); 109 | } else { 110 | if (Character.isWhitespace(c)) { 111 | appendToBuffer(resultBuffer, buf); 112 | } else { 113 | buf.append(c); 114 | } 115 | } 116 | } 117 | } 118 | appendToBuffer(resultBuffer, buf); 119 | 120 | } 121 | 122 | String[] result = new String[resultBuffer.size()]; 123 | return ((String[]) resultBuffer.toArray(result)); 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/main/resources/messages.yml: -------------------------------------------------------------------------------- 1 | join: 2 | register: '{RED}You are not registered.{NEWLINE}{RED}Please register using /register .' 3 | login: '{RED}Please log in using /login .' 4 | resume: '{BRIGHTGREEN}Welcome back, your login session has been resumed.' 5 | error: 6 | lockout: 'You are temporarily locked out for exceeding the incorrect password threshold.' 7 | name: 'Your name contains one or more illegal characters.' 8 | online: 'You are already online!' 9 | 10 | register: 11 | usage: '{RED}Correct Usage: /register [email]' 12 | success: '{BRIGHTGREEN}You have successfully registered!{NEWLINE}{BRIGHTGREEN}You may now log in using /login ' 13 | error: 14 | disabled: '{RED}Registrations are currently disabled!' 15 | registered: '{RED}You are already registered!' 16 | limit: '{RED}You may not register any more accounts!' 17 | password: '{RED}Your password must be at least {PWMINLENGTH} characters long!' 18 | email: '{RED}Please use a valid email address when registering!' 19 | general: '{RED}Something went wrong while creating your account!' 20 | 21 | login: 22 | usage: '{RED}Correct Usage: /login ' 23 | success: '{BRIGHTGREEN}You are now logged in!' 24 | error: 25 | registered: '{RED}You are not registered!' 26 | authenticated: '{RED}You are already logged in!' 27 | password: '{RED}Incorrect password!' 28 | active: '{RED}Your account is not activated!' 29 | general: '{RED}Something went wrong while logging you in!' 30 | 31 | logout: 32 | success: '{BRIGHTGREEN}You have been logged out!' 33 | error: 34 | logged: '{RED}You are not logged in!' 35 | general: '{RED}Something went wrong while logging you out!' 36 | 37 | changepw: 38 | usage: '{RED}Correct Usage: /changepw ' 39 | success: '{BRIGHTGREEN}Password changed!' 40 | error: 41 | disabled: '{RED}Password changes are currently disabled.' 42 | logged: '{RED}You are not logged in!' 43 | incorrect: '{RED}Incorrect old password!' 44 | invalid: '{RED}Your new password does not meet complexity requirements!' 45 | general: '{RED}Something went wrong while changing your password!' 46 | 47 | authurl: 48 | registration: '{RED}AuthURL registration is disabled.' 49 | changepw: '{RED}AuthURL does not support password changes.' 50 | 51 | misc: 52 | illegal: '{GRAY}You must be logged in to do that!' 53 | timeout: 'You have taken too long to log in!' 54 | strikeout: 'You have entered too many invalid passwords!' 55 | reloaded: '{RED}Server reloaded, you must log in.' 56 | 57 | admin: 58 | permission: 'You do not have permission to use this command!' 59 | register: 60 | usage: '{RED}Correct Usage: /xauth register [email]' 61 | success: '{BRIGHTGREEN}Account successfully created for: {WHITE}{TARGET}' 62 | error: 63 | registered: '{RED}This player is already registered!' 64 | general: '{RED}Something went wrong while creating an account for {TARGET}' 65 | changepw: 66 | usage: '{RED}Correct Usage: /xauth changepw ' 67 | success: '{TARGET}''s {BRIGHTGREEN}password has been changed!' 68 | error: 69 | registered: '{RED}This player is not registered!' 70 | general: '{RED}Something went wrong while changing {TARGET}''s password!' 71 | logout: 72 | usage: '{RED}Correct Usage: /xauth logout ' 73 | error: 74 | logged: '{TARGET} {RED}is not logged in!' 75 | general: '{RED}Something went wrong while logging this player out!' 76 | success: 77 | player: '{TARGET} {BRIGHTGREEN}has been logged out!' 78 | target: '{BRIGHTGREEN}You have been logged out by an Administrator!' 79 | unregister: 80 | usage: '{RED}Correct Usage: /xauth unregister ' 81 | error: 82 | registered: '{RED}This player is not registered!' 83 | general: '{RED}Something went wrong while unregistering this player!' 84 | success: 85 | player: '{TARGET} {BRIGHTGREEN}has been unregistered!' 86 | target: '{RED}You have been unregistered and logged out!' 87 | location: 88 | usage: '{RED}Correct Usage: /xauth location set|remove [global]' 89 | set: 90 | error: 91 | global: '{RED}Global teleport location is set to this world.{NEWLINE}{RED}Please remove it first.' 92 | general: '{RED}Something went wrong while setting this location!' 93 | success: 94 | regular: '{BRIGHTGREEN}Teleport location for this world set to your location!' 95 | global: '{BRIGHTGREEN}Global teleport location set to your location!' 96 | remove: 97 | error: 98 | noglobal: '{RED}A global teleport location is not set!' 99 | notset: '{RED}This world does not have a teleport location!' 100 | global: '{RED}Global teleport location is set to this world.{NEWLINE}{RED}Please use /xauth location remove global' 101 | general: '{RED}Something went wrong while removing this location!' 102 | success: 103 | regular: '{BRIGHTGREEN}Teleport location for this world has been removed!' 104 | global: '{BRIGHTGREEN}Global teleport location has been removed!' 105 | reload: '{BRIGHTGREEN}xAuth reloaded.' 106 | activate: 107 | usage: '{RED}Correct Usage: /xauth activate ' 108 | error: 109 | registered: '{RED}This player is not registered!' 110 | active: '{RED}This player is already active!' 111 | general: '{RED}Something went wrong while activating this player!' 112 | success: '{BRIGHTGREEN}{TARGET} has been activated!' 113 | config: 114 | usage: '{RED}Correct Usage: /xauth config ' 115 | error: 116 | exist: '{RED}This configuration node does not exist!' 117 | int: '{RED}This configuration node requires an integer value!' 118 | invalid: '{RED}This setting cannot be altered using this command!' 119 | success: '{BRIGHTGREEN}Configuration updated!' -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/xAuth.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth; 2 | 3 | import java.io.File; 4 | import java.util.Calendar; 5 | import java.util.GregorianCalendar; 6 | import java.util.TimeZone; 7 | 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.plugin.java.JavaPlugin; 10 | 11 | import com.cypherx.xauth.auth.*; 12 | import com.cypherx.xauth.commands.*; 13 | import com.cypherx.xauth.database.DatabaseController; 14 | import com.cypherx.xauth.listeners.*; 15 | import com.cypherx.xauth.password.PasswordHandler; 16 | //import com.cypherx.xauth.plugins.xPermissions; 17 | import com.cypherx.xauth.strike.StrikeManager; 18 | import com.cypherx.xauth.updater.Updater; 19 | 20 | public class xAuth extends JavaPlugin { 21 | private DatabaseController dbCtrl; 22 | private MessageHandler msgCtrl; 23 | private PlayerManager plyrMngr; 24 | private PlayerDataHandler plyrDtHndlr; 25 | private PasswordHandler pwdHndlr; 26 | private LocationManager locMngr; 27 | private StrikeManager strkMngr; 28 | private String h2Version = "1.3.164"; 29 | 30 | public void onDisable() { 31 | if (dbCtrl != null) { 32 | for (Player p : getServer().getOnlinePlayers()) { 33 | xAuthPlayer xp = plyrMngr.getPlayer(p); 34 | if (xp.isProtected()) 35 | plyrMngr.unprotect(xp); 36 | } 37 | 38 | dbCtrl.close(); 39 | } 40 | } 41 | 42 | public void onEnable() { 43 | // Create any required directories 44 | getDataFolder().mkdirs(); 45 | 46 | // Create/load configuration and customizable messages 47 | loadConfiguration(); 48 | 49 | // Disable plugin if auto-disable is set to true and server is running in online-mode 50 | if (getConfig().getBoolean("main.auto-disable") && getServer().getOnlineMode()) { 51 | xAuthLog.info("Auto-disabling, server is running in online-mode"); 52 | getServer().getPluginManager().disablePlugin(this); 53 | return; 54 | } 55 | 56 | if (getConfig().getBoolean("main.check-for-updates")) { 57 | Updater updater = new Updater(getDescription().getVersion()); 58 | if (updater.isUpdateAvailable()) 59 | updater.printMessage(); 60 | } 61 | 62 | File h2File = new File("lib", "h2-" + h2Version + ".jar"); 63 | if (!h2File.exists() && getConfig().getBoolean("main.download-library") && !getConfig().getBoolean("mysql.enabled")) { 64 | xAuthLog.info("-------------------------------"); 65 | xAuthLog.info("Downloading required H2 library.."); 66 | downloadLib(h2File); 67 | xAuthLog.info("Download complete."); 68 | xAuthLog.info(""); 69 | xAuthLog.info("Reload the server to enable xAuth."); 70 | xAuthLog.info("-------------------------------"); 71 | 72 | getServer().getPluginManager().disablePlugin(this); 73 | return; 74 | } 75 | 76 | // Initialize permissions support 77 | //xPermissions.init(); 78 | 79 | // Initialize database controller 80 | dbCtrl = new DatabaseController(this); 81 | 82 | // Test connection to database 83 | if (!dbCtrl.isConnectable()) { 84 | xAuthLog.severe("Failed to establish " + dbCtrl.getDBMS() + " database connection!"); 85 | 86 | // disable (for now, may change in the future) 87 | getServer().getPluginManager().disablePlugin(this); 88 | return; 89 | } 90 | 91 | xAuthLog.info("Successfully established connection to " + dbCtrl.getDBMS() + " database"); 92 | dbCtrl.runUpdater(); 93 | 94 | // Initialize ALL THE CLASSES 95 | plyrMngr = new PlayerManager(this); 96 | plyrDtHndlr = new PlayerDataHandler(this); 97 | pwdHndlr = new PasswordHandler(this); 98 | locMngr = new LocationManager(this); 99 | strkMngr = new StrikeManager(this); 100 | 101 | Player[] players = getServer().getOnlinePlayers(); 102 | if (players.length > 0) 103 | plyrMngr.handleReload(players); 104 | 105 | // Initialize listeners 106 | new xAuthPlayerListener(this); 107 | new xAuthBlockListener(this); 108 | new xAuthEntityListener(this); 109 | 110 | // Register commands 111 | getCommand("register").setExecutor(new RegisterCommand(this)); 112 | getCommand("login").setExecutor(new LoginCommand(this)); 113 | getCommand("logout").setExecutor(new LogoutCommand(this)); 114 | getCommand("changepw").setExecutor(new ChangePwdCommand(this)); 115 | getCommand("xauth").setExecutor(new xAuthCommand(this)); 116 | 117 | xAuthLog.info(String.format("v%s Enabled!", getDescription().getVersion())); 118 | lol(); 119 | } 120 | 121 | private void loadConfiguration() { 122 | // configuration 123 | getConfig().options().copyDefaults(true); 124 | saveConfig(); 125 | 126 | // messages 127 | msgCtrl = new MessageHandler(this); 128 | msgCtrl.getConfig().options().copyDefaults(true); 129 | msgCtrl.saveConfig(); 130 | msgCtrl.reloadConfig(); 131 | } 132 | 133 | private void downloadLib(File h2File) { 134 | File dir = new File("lib"); 135 | if (!dir.exists()) 136 | dir.mkdir(); 137 | 138 | Utils.downloadFile(h2File, "http://love-despite.com/cypher/bukkit/lib/" + h2File.getName()); 139 | } 140 | 141 | public File getJar() { return getFile(); } 142 | public DatabaseController getDbCtrl() { return dbCtrl; } 143 | public MessageHandler getMsgHndlr() { return msgCtrl; } 144 | public PlayerManager getPlyrMngr() { return plyrMngr; } 145 | public PlayerDataHandler getPlyrDtHndlr() { return plyrDtHndlr; } 146 | public PasswordHandler getPwdHndlr() { return pwdHndlr; } 147 | public LocationManager getLocMngr() { return locMngr; } 148 | public StrikeManager getStrkMngr() { return strkMngr; } 149 | 150 | public Auth getAuthClass(xAuthPlayer p){ 151 | if (isAuthURL()) 152 | return new AuthURL(this, p.getIPAddress()); 153 | else 154 | return new AuthSQL(this, p); 155 | } 156 | 157 | public boolean isAuthURL(){ 158 | return this.getConfig().getBoolean("authurl.enabled"); 159 | } 160 | 161 | public void reload() { 162 | loadConfiguration(); 163 | //plyrMngr.reload(); 164 | } 165 | 166 | private void lol() { 167 | Calendar cal = new GregorianCalendar(TimeZone.getDefault()); 168 | int month = cal.get(Calendar.MONTH); 169 | int day = cal.get(Calendar.DAY_OF_MONTH); 170 | 171 | if (month == 3 && day == 1) { 172 | xAuthLog.warning("Your trial version of xAuth expires today!"); 173 | xAuthLog.warning("Purchase the full version on Steam for $19.99."); 174 | } else if (month == 3 && day == 2) 175 | xAuthLog.info("April Fools!! xAuth will always be free!"); 176 | } 177 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/auth/AuthURL.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2011 moparisthebest 3 | *

4 | * This program is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | *

9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | *

14 | * You should have received a copy of the GNU General Public License 15 | * along with this program. If not, see . 16 | *

17 | * Official forums are http://www.moparscape.org/smf/ 18 | * Email me at admin@moparisthebest.com , I read it but don't usually respond. 19 | */ 20 | 21 | package com.cypherx.xauth.auth; 22 | 23 | import java.io.BufferedReader; 24 | import java.io.DataOutputStream; 25 | import java.io.InputStreamReader; 26 | import java.net.HttpURLConnection; 27 | import java.net.URL; 28 | import java.net.URLEncoder; 29 | 30 | import com.cypherx.xauth.xAuth; 31 | import com.cypherx.xauth.xAuthLog; 32 | 33 | 34 | /** 35 | * This class is made to interact with authURL scripts on servers. It is backwards compatible with the original 36 | * version that just supported login authentication, but now has more features. 37 | *

38 | * A new instance of this class is meant to be created for each transaction. 39 | *

40 | * If you wish to implement this functionality into your program in addition to other methods, 41 | * I encourage you to implement the included 'Auth' interface and then use a single helper method to return an 42 | * appropriate instance of Auth for you to use. 43 | * author: moparisthebest 44 | */ 45 | public class AuthURL extends Auth { 46 | 47 | // increment this any time something is changed that requires a change in the protocol script-side 48 | private static final int version = 1; 49 | 50 | private String ipAddress = null; 51 | 52 | public AuthURL(final xAuth plugin) { 53 | this(plugin, null); 54 | } 55 | 56 | public AuthURL(final xAuth plugin, final String ipAddress) { 57 | this.plugin = plugin; 58 | this.ipAddress = ipAddress; 59 | } 60 | 61 | /** 62 | * Attempts to authenticate a user with a given password. Sets response and group appropriately. 63 | * Also sets status to online if supported, so no need to call online() if this is successful. 64 | * 65 | * @param user Username 66 | * @param pass Password 67 | * @return success 68 | */ 69 | public boolean login(String user, String pass) { 70 | return checkAuthURL("login", "user", user, "pass", pass); 71 | } 72 | 73 | /** 74 | * Attempts to register a username with the given password and email. Sets response appropriately. 75 | * 76 | * @param user Username 77 | * @param pass Password 78 | * @param email Valid email address, can be null. 79 | * @return success 80 | */ 81 | public boolean register(String user, String pass, String email) { 82 | if (!plugin.getConfig().getBoolean("authurl.registration")) { 83 | response = "authurl.registration"; 84 | return false; 85 | } 86 | return checkAuthURL("register", "user", user, "pass", pass, "email", email); 87 | } 88 | 89 | public boolean adminRegister(String user, String pass, String email) { 90 | return false; 91 | } 92 | 93 | public boolean changePassword(String user, String oldPass, String newPass) { 94 | response = "authurl.changepw"; 95 | return false; 96 | } 97 | 98 | public boolean adminChangePassword(String user, String newPass) { 99 | response = "authurl.changepw"; 100 | return false; 101 | } 102 | 103 | /** 104 | * Sets status of user to online if supported. This is for use when a user doesn't need to supply 105 | * a password due to a session that has not yet timed out. Sets response appropriately. 106 | * 107 | * @param user Username 108 | * @return success May be safely ignored 109 | */ 110 | public boolean online(String user) { 111 | if (!plugin.getConfig().getBoolean("authurl.status")) { 112 | //response = "AuthURL online is disabled."; 113 | return false; 114 | } 115 | return checkAuthURL("online", "user", user); 116 | } 117 | 118 | /** 119 | * Sets status of user to offline if supported, to be called when a user logs out or is disconnected. 120 | * No response is set and none need be displayed. 121 | * 122 | * @param user Username 123 | * @return success May be safely ignored 124 | */ 125 | public boolean offline(String user) { 126 | if (!plugin.getConfig().getBoolean("authurl.status")) { 127 | //response = "AuthURL offline is disabled."; 128 | return false; 129 | } 130 | return checkAuthURL("offline", "user", user); 131 | } 132 | 133 | private void writeParam(DataOutputStream out, String name, String value) throws Exception { 134 | if (value == null) 135 | return; 136 | String param = "&" + name + "=" + URLEncoder.encode(value, "UTF-8"); 137 | out.writeBytes(param); 138 | } 139 | 140 | private boolean checkAuthURL(String action, String... params) { 141 | // if there isn't at least one parameter OR 142 | // if params length is not an even number 143 | if (params.length < 2 || ((params.length % 2) != 0)) 144 | return false; 145 | try { 146 | //HttpURLConnection.setFollowRedirects(false); 147 | HttpURLConnection uc = (HttpURLConnection) new URL(plugin.getConfig().getString("authurl.url")).openConnection(); 148 | 149 | uc.setRequestMethod("POST"); 150 | uc.setDoInput(true); 151 | uc.setDoOutput(true); 152 | uc.setUseCaches(false); 153 | uc.setAllowUserInteraction(false); 154 | uc.setInstanceFollowRedirects(false); 155 | uc.setRequestProperty("User-Agent", "Mozilla/5.0 authURL/" + version); 156 | uc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 157 | DataOutputStream out = new DataOutputStream(uc.getOutputStream()); 158 | // first lets write the authurl_version we are working with 159 | out.writeBytes("authurl_version=" + version); 160 | // now write the IP if it is set 161 | writeParam(out, "ip", this.ipAddress); 162 | writeParam(out, "action", action); 163 | for (int x = 0; x < params.length; ++x) 164 | writeParam(out, params[x], params[++x]); 165 | out.flush(); 166 | out.close(); 167 | 168 | BufferedReader in = new BufferedReader(new InputStreamReader(uc.getInputStream())); 169 | String line = in.readLine(); 170 | boolean success = line != null && line.equals("YES"); 171 | response = in.readLine(); 172 | if (plugin.getConfig().getBoolean("authurl.groups")) 173 | group = in.readLine(); 174 | in.close(); 175 | return success; 176 | } catch (Exception e) { 177 | //response = e.getMessage(); 178 | xAuthLog.severe("Failed to process AuthURL script during action: " + action, e); 179 | return false; 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/database/DatabaseUpdater.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.database; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileOutputStream; 6 | import java.io.IOException; 7 | import java.sql.Connection; 8 | import java.sql.PreparedStatement; 9 | import java.sql.SQLException; 10 | import java.util.ArrayList; 11 | import java.util.Enumeration; 12 | import java.util.List; 13 | import java.util.Properties; 14 | import java.util.jar.JarEntry; 15 | import java.util.jar.JarFile; 16 | 17 | import com.cypherx.xauth.Utils; 18 | import com.cypherx.xauth.xAuth; 19 | import com.cypherx.xauth.xAuthLog; 20 | 21 | public class DatabaseUpdater { 22 | private final xAuth plugin; 23 | private final DatabaseController dbCon; 24 | private File dbVersionFile; 25 | private final Properties dbVersionProp = new Properties(); 26 | 27 | public DatabaseUpdater(final xAuth plugin, final DatabaseController dbCon) { 28 | this.plugin = plugin; 29 | this.dbCon = dbCon; 30 | 31 | loadVersionFile(); 32 | } 33 | 34 | private void loadVersionFile() { 35 | // Load table version file 36 | dbVersionFile = new File(plugin.getDataFolder(), "DBVERSION"); 37 | try { 38 | if (!dbVersionFile.exists()) 39 | dbVersionFile.createNewFile(); 40 | 41 | dbVersionProp.load(new FileInputStream(dbVersionFile)); 42 | } catch (IOException e) { 43 | xAuthLog.severe("Failed to load database version file!"); 44 | } 45 | } 46 | 47 | private void updateVersionFile(String tblId, int version) { 48 | dbVersionProp.setProperty(tblId, String.valueOf(version)); 49 | try { 50 | dbVersionProp.store(new FileOutputStream(dbVersionFile), null); 51 | } catch (IOException e) { 52 | xAuthLog.severe("Failed to update database table version file!", e); 53 | } 54 | } 55 | 56 | public void runUpdate() { 57 | for (Table tbl : dbCon.getActiveTables()) { 58 | String tblId = tbl.toString().toLowerCase(); 59 | String tblName = dbCon.getTable(tbl); 60 | List updateFiles = loadUpdateFiles(tblId); 61 | 62 | // -1 = not created, 0 = default table, 1+ = updated 63 | int currentVersion = Integer.parseInt(dbVersionProp.getProperty(tblId, "-1")); 64 | 65 | // Create table if it does not exist 66 | if (currentVersion == -1) { 67 | Connection conn = dbCon.getConnection(); 68 | 69 | try { 70 | String createSql = loadSQL("sql/" + tblId + "/table.sql", tblName); 71 | executeQuery(createSql, conn); 72 | xAuthLog.info("Table created: " + tblName); 73 | currentVersion = 0; 74 | } catch (TableUpdateException e) { 75 | xAuthLog.severe("Failed to create table: " + tblName, e); 76 | } finally { 77 | dbCon.close(conn); 78 | } 79 | } 80 | 81 | // 0 = No updates exist, 1+ = updates exist 82 | int updateVersion = getLatestUpdateVersion(updateFiles); 83 | 84 | // Time to update~ 85 | if (updateVersion > currentVersion && currentVersion > -1) { 86 | Connection conn = dbCon.getConnection(); 87 | 88 | try { 89 | // Let's not commit changes as they get executed (in case of error) 90 | conn.setAutoCommit(false); 91 | 92 | // Loop through all update files.. 93 | for (String updateFile : updateFiles) { 94 | if (getUpdateVersion(updateFile) <= currentVersion) 95 | continue; 96 | 97 | // Load queries from update files and split into lines (one query per line) 98 | String[] updateSql = loadSQL(updateFile, tblName).split(System.getProperty("line.separator")); 99 | 100 | // ANOTHER LOOP (Loop through each query) 101 | for (String sql : updateSql) 102 | executeQuery(sql, conn); 103 | 104 | // Let's commit those changes now that no errors have occurred 105 | conn.commit(); 106 | currentVersion++; 107 | } 108 | 109 | xAuthLog.info(String.format("Table [%s] updated to revision [%s]", tblName, formatVersion(currentVersion))); 110 | } catch (TableUpdateException e) { 111 | xAuthLog.severe(String.format("Something went wrong while updating table [%s] to revision [%s]", tblName, formatVersion(currentVersion + 1)), e); 112 | 113 | try { 114 | // oh noes, an error has occurred! quick, rollback any changes from this update 115 | conn.rollback(); 116 | } catch (SQLException ex) {} 117 | } catch (SQLException e) { 118 | e.printStackTrace(); 119 | } finally { 120 | dbCon.close(conn); 121 | } 122 | } 123 | 124 | // Save updated version to file 125 | updateVersionFile(tblId, currentVersion); 126 | } 127 | } 128 | 129 | private List loadUpdateFiles(String tblId) { 130 | List updateFiles = new ArrayList(); 131 | String updatePath = "sql/" + tblId + "/updates/" + dbCon.getDBMS().toLowerCase(); 132 | 133 | try { 134 | JarFile jar = new JarFile(plugin.getJar()); 135 | Enumeration entries = jar.entries(); 136 | 137 | //Loop through contents of jar to get update file names and latest version 138 | while(entries.hasMoreElements()) { 139 | String name = entries.nextElement().getName(); 140 | if (name.startsWith(updatePath) && name.endsWith(".sql")) 141 | updateFiles.add(name); 142 | } 143 | } catch (IOException e) { 144 | xAuthLog.severe("Failed to load update files for table: " + tblId, e); 145 | } 146 | 147 | return updateFiles; 148 | } 149 | 150 | private int getUpdateVersion(String filePath) { 151 | String fileName = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.lastIndexOf(".")); 152 | return Integer.parseInt(fileName.split("_")[0]); 153 | } 154 | 155 | private int getLatestUpdateVersion(List updateFiles) { 156 | if (updateFiles.size() < 1) 157 | return 0; 158 | 159 | String filePath = updateFiles.get(updateFiles.size() - 1); 160 | return getUpdateVersion(filePath); 161 | } 162 | 163 | private String loadSQL(String path, String tblName) { 164 | String sql = Utils.streamToString(plugin.getResource(path)); 165 | sql = sql.replace("{TABLE}", tblName); 166 | sql = sql.replace("{TABLE_ACCOUNT}", 167 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); // foreign key in session table 168 | return sql; 169 | } 170 | 171 | private void executeQuery(String query, Connection conn) throws TableUpdateException { 172 | if (query.length() > 0) { 173 | PreparedStatement ps = null; 174 | 175 | try { 176 | ps = conn.prepareStatement(query); 177 | ps.executeUpdate(); 178 | } catch (SQLException e) { 179 | throw new TableUpdateException(e.getMessage()); 180 | } finally { 181 | dbCon.close(ps); 182 | } 183 | } 184 | } 185 | 186 | // hurrr aesthetics 187 | private String formatVersion(int currentVersion) { 188 | String strCurVer = String.valueOf(currentVersion); 189 | if (strCurVer.length() == 1) 190 | return "00" + strCurVer; 191 | else if (strCurVer.length() == 2) 192 | return "0" + strCurVer; 193 | 194 | return strCurVer; 195 | } 196 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/auth/AuthSQL.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.auth; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.regex.Matcher; 8 | import java.util.regex.Pattern; 9 | 10 | import com.avaje.ebean.validation.factory.EmailValidatorFactory; 11 | import com.cypherx.xauth.xAuth; 12 | import com.cypherx.xauth.xAuthLog; 13 | import com.cypherx.xauth.xAuthPlayer; 14 | import com.cypherx.xauth.database.Table; 15 | import com.cypherx.xauth.plugins.xPermissions; 16 | import com.cypherx.xauth.xAuthPlayer.Status; 17 | 18 | public class AuthSQL extends Auth { 19 | private final xAuthPlayer player; 20 | 21 | public AuthSQL(final xAuth plugin, final xAuthPlayer player) { 22 | this.plugin = plugin; 23 | this.player = player; 24 | } 25 | 26 | public boolean login(String user, String pass) { 27 | if (!player.isRegistered()) { 28 | response = "login.error.registered"; 29 | return false; 30 | } else if (player.isAuthenticated()) { 31 | response = "login.error.authenticated"; 32 | return false; 33 | } else if (!plugin.getPwdHndlr().checkPassword(player.getAccountId(), pass)) { 34 | int strikes = plugin.getStrkMngr().getRecord(player.getIPAddress()).addStrike(player.getPlayerName()); 35 | if (strikes >= plugin.getConfig().getInt("strikes.amount")) 36 | plugin.getStrkMngr().strikeout(player.getPlayer()); 37 | 38 | response = "login.error.password"; 39 | return false; 40 | } else if (!plugin.getPlyrMngr().isActive(player.getAccountId())) { 41 | response = "login.error.active"; 42 | return false; 43 | } 44 | 45 | return true; 46 | } 47 | 48 | public boolean register(String user, String pass, String email) { 49 | if (!plugin.getConfig().getBoolean("registration.enabled")) { 50 | response = "register.error.disabled"; 51 | return false; 52 | } else if (player.isRegistered()) { 53 | response = "register.error.registered"; 54 | return false; 55 | } else if (!isWithinAccLimit(player.getIPAddress())) { 56 | response = "register.error.limit"; 57 | return false; 58 | } else if (!isValidPass(pass)) { 59 | response = "register.error.password"; 60 | return false; 61 | } else if (!isValidEmail(email)) { 62 | response = "register.error.email"; 63 | return false; 64 | } 65 | 66 | return execRegQuery(user, pass, email, false); 67 | } 68 | 69 | public boolean adminRegister(String user, String pass, String email) { 70 | if (player.isRegistered()) { 71 | response = "admin.register.error.registered"; 72 | return false; 73 | } 74 | 75 | return execRegQuery(user, pass, email, true); 76 | } 77 | 78 | private boolean execRegQuery(String user, String pass, String email, boolean admin) { 79 | try { 80 | int accId = plugin.getPlyrMngr().createAccount(user, pass, email, player.getIPAddress()); 81 | if (accId > 0) { 82 | player.setAccountId(accId); 83 | player.setStatus(Status.Registered); 84 | response = admin ? "admin.register.success" : "register.success"; 85 | return true; 86 | } else 87 | throw new SQLException(); 88 | } catch (SQLException e) { 89 | xAuthLog.severe("Something went wrong while creating account for player: " + user, e); 90 | response = admin ? "admin.register.error.general" : "register.error.general"; 91 | return false; 92 | } 93 | } 94 | 95 | public boolean changePassword(String user, String oldPass, String newPass) { 96 | if (!plugin.getConfig().getBoolean("password.allow-change")) { 97 | response = "changepw.error.disabled"; 98 | return false; 99 | } else if (!player.isAuthenticated()) { 100 | response = "changepw.error.logged"; 101 | return false; 102 | } else if (!plugin.getPwdHndlr().checkPassword(player.getAccountId(), oldPass)) { 103 | response = "changepw.error.incorrect"; 104 | return false; 105 | } else if (!isValidPass(newPass)) { 106 | response = "changepw.error.invalid"; 107 | return false; 108 | } 109 | 110 | return execCpwQuery(user, newPass, false); 111 | } 112 | 113 | public boolean adminChangePassword(String user, String newPass) { 114 | if (!player.isRegistered()) { 115 | response = "admin.changepw.registered"; 116 | return false; 117 | } 118 | 119 | return execCpwQuery(user, newPass, true); 120 | } 121 | 122 | public boolean execCpwQuery(String user, String newPass, boolean admin) { 123 | Connection conn = plugin.getDbCtrl().getConnection(); 124 | PreparedStatement ps = null; 125 | 126 | try { 127 | String sql = String.format("UPDATE `%s` SET `password` = ? WHERE `id` = ?", 128 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); 129 | ps = conn.prepareStatement(sql); 130 | ps.setString(1, plugin.getPwdHndlr().hash(newPass)); 131 | ps.setInt(2, player.getAccountId()); 132 | ps.executeUpdate(); 133 | response = admin ? "admin.changepw.success" : "changepw.success"; 134 | return true; 135 | } catch (SQLException e) { 136 | xAuthLog.severe("Failed to change password for player: " + user, e); 137 | response = admin ? "admin.changepw.error.general" : "changepw.error.general"; 138 | return false; 139 | } finally { 140 | plugin.getDbCtrl().close(conn, ps); 141 | } 142 | } 143 | 144 | public boolean online(String user) { 145 | // nothing for AuthSQL 146 | return true; 147 | } 148 | 149 | public boolean offline(String user) { 150 | // nothing for AuthSQL 151 | return true; 152 | } 153 | 154 | private boolean isWithinAccLimit(String ipaddress) { 155 | int limit = plugin.getConfig().getInt("registration.account-limit"); 156 | if (limit < 1 || xPermissions.has(player.getPlayer(), "xauth.bypass.acclimit")) 157 | return true; 158 | 159 | int count = 0; 160 | Connection conn = plugin.getDbCtrl().getConnection(); 161 | PreparedStatement ps = null; 162 | ResultSet rs = null; 163 | 164 | try { 165 | String sql = String.format("SELECT COUNT(`id`) FROM `%s` WHERE `registerip` = ?", 166 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); 167 | ps = conn.prepareStatement(sql); 168 | ps.setString(1, ipaddress); 169 | rs = ps.executeQuery(); 170 | if (rs.next()) 171 | count = rs.getInt(1); 172 | } catch (SQLException e) { 173 | xAuthLog.severe("Could not check account count for ip: " + ipaddress, e); 174 | } finally { 175 | plugin.getDbCtrl().close(conn, ps, rs); 176 | } 177 | 178 | return limit > count; 179 | } 180 | 181 | private boolean isValidPass(String pass) { 182 | String pattern = "("; 183 | 184 | if (plugin.getConfig().getBoolean("password.complexity.lowercase")) 185 | pattern += "(?=.*[a-z])"; 186 | 187 | if (plugin.getConfig().getBoolean("password.complexity.uppercase")) 188 | pattern += "(?=.*[A-Z])"; 189 | 190 | if (plugin.getConfig().getBoolean("password.complexity.number")) 191 | pattern += "(?=.*\\d)"; 192 | 193 | if (plugin.getConfig().getBoolean("password.complexity.symbol")) 194 | pattern += "(?=.*\\W)"; 195 | 196 | pattern += ".{" + plugin.getConfig().getInt("password.min-length") + ",})"; 197 | Pattern p = Pattern.compile(pattern); 198 | Matcher matcher = p.matcher(pass); 199 | return matcher.matches(); 200 | } 201 | 202 | private boolean isValidEmail(String email) { 203 | if (!plugin.getConfig().getBoolean("registration.validate-email")) 204 | return true; 205 | 206 | return EmailValidatorFactory.EMAIL.isValid(email); 207 | } 208 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/listeners/xAuthPlayerListener.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.listeners; 2 | 3 | import java.sql.Timestamp; 4 | 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.Location; 7 | import org.bukkit.Material; 8 | import org.bukkit.World; 9 | import org.bukkit.entity.HumanEntity; 10 | import org.bukkit.entity.Player; 11 | import org.bukkit.event.EventHandler; 12 | import org.bukkit.event.EventPriority; 13 | import org.bukkit.event.Listener; 14 | import org.bukkit.event.block.Action; 15 | import org.bukkit.event.inventory.InventoryClickEvent; 16 | import org.bukkit.event.player.PlayerChatEvent; 17 | import org.bukkit.event.player.PlayerCommandPreprocessEvent; 18 | import org.bukkit.event.player.PlayerDropItemEvent; 19 | import org.bukkit.event.player.PlayerInteractEvent; 20 | import org.bukkit.event.player.PlayerJoinEvent; 21 | import org.bukkit.event.player.PlayerLoginEvent; 22 | import org.bukkit.event.player.PlayerLoginEvent.Result; 23 | import org.bukkit.event.player.PlayerMoveEvent; 24 | import org.bukkit.event.player.PlayerPickupItemEvent; 25 | import org.bukkit.event.player.PlayerQuitEvent; 26 | 27 | import com.cypherx.xauth.PlayerManager; 28 | import com.cypherx.xauth.Utils; 29 | import com.cypherx.xauth.xAuth; 30 | import com.cypherx.xauth.xAuthPlayer; 31 | import com.cypherx.xauth.xAuthPlayer.Status; 32 | 33 | public class xAuthPlayerListener implements Listener { 34 | private final xAuth plugin; 35 | private final PlayerManager plyrMngr; 36 | 37 | public xAuthPlayerListener(final xAuth plugin) { 38 | this.plugin = plugin; 39 | this.plyrMngr = plugin.getPlyrMngr(); 40 | Bukkit.getServer().getPluginManager().registerEvents(this, plugin); 41 | } 42 | 43 | @EventHandler(priority = EventPriority.LOWEST) 44 | public void onPlayerLogin(final PlayerLoginEvent event) { 45 | if (!event.getResult().equals(Result.ALLOWED)) 46 | return; 47 | 48 | Player p = event.getPlayer(); 49 | if (p.isOnline()) { 50 | xAuthPlayer xp = plyrMngr.getPlayer(p); 51 | boolean reverse = plugin.getConfig().getBoolean("single-session.reverse"); 52 | 53 | if (reverse && !xp.isAuthenticated()) { 54 | if (!plugin.getConfig().getBoolean("single-session.guests.reverse")) { 55 | Timestamp expireTime = new Timestamp(xp.getConnectTime().getTime() + 56 | (plugin.getConfig().getInt("single-session.guests.immunity-length") * 1000)); 57 | reverse = !(expireTime.compareTo(new Timestamp(System.currentTimeMillis())) < 0); 58 | } 59 | } 60 | 61 | if (reverse) 62 | event.disallow(Result.KICK_OTHER, plugin.getMsgHndlr().get("join.error.online")); 63 | } 64 | 65 | String ipAddress = event.getAddress().getHostAddress(); 66 | if (Utils.isIPAddress(ipAddress)) 67 | if (plugin.getStrkMngr().isLockedOut(ipAddress, p.getName())) 68 | event.disallow(Result.KICK_OTHER, plugin.getMsgHndlr().get("join.error.lockout")); 69 | 70 | if (!isValidName(p.getName())) 71 | event.disallow(Result.KICK_OTHER, plugin.getMsgHndlr().get("join.error.name")); 72 | } 73 | 74 | @EventHandler(priority = EventPriority.MONITOR) 75 | public void onPlayerJoin(final PlayerJoinEvent event) { 76 | Player p = event.getPlayer(); 77 | if (p == null || !p.isOnline()) 78 | return; 79 | 80 | xAuthPlayer xp = plyrMngr.getPlayer(p, plugin.getConfig().getBoolean("main.reload-on-join")); 81 | xp.setConnectTime(new Timestamp(System.currentTimeMillis())); 82 | 83 | String node = ""; 84 | boolean protect = false; 85 | 86 | if (xp.isRegistered() || plugin.isAuthURL()) { 87 | if (plyrMngr.checkSession(xp)) { 88 | xp.setStatus(Status.Authenticated); 89 | plugin.getAuthClass(xp).online(p.getName()); 90 | node = "join.resume"; 91 | } else { 92 | xp.setStatus(Status.Registered); 93 | node = "join.login"; 94 | protect = true; 95 | //plyrMngr.protect(xp); 96 | } 97 | } else if (plyrMngr.mustRegister(p)) { 98 | xp.setStatus(Status.Guest); 99 | node = "join.register"; 100 | protect = true; 101 | //plyrMngr.protect(xp); 102 | } 103 | 104 | if (protect) { 105 | xp.setProtected(true); 106 | scheduleDelayedProtect(xp); 107 | } 108 | 109 | if (!node.isEmpty()) 110 | sendDelayedMessage(p, node, 1); 111 | } 112 | 113 | @EventHandler(priority = EventPriority.MONITOR) 114 | public void onPlayerQuit(final PlayerQuitEvent event) { 115 | xAuthPlayer p = plyrMngr.getPlayer(event.getPlayer()); 116 | if (p.isProtected()) 117 | plyrMngr.unprotect(p); 118 | 119 | plugin.getAuthClass(p).offline(event.getPlayer().getName()); 120 | } 121 | 122 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 123 | public void onPlayerChat(PlayerChatEvent event) { 124 | xAuthPlayer p = plyrMngr.getPlayer(event.getPlayer()); 125 | if (plyrMngr.isRestricted(p, event)) { 126 | plyrMngr.sendNotice(p); 127 | event.setCancelled(true); 128 | } 129 | } 130 | 131 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 132 | public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { 133 | xAuthPlayer p = plyrMngr.getPlayer(event.getPlayer().getName()); 134 | if (plyrMngr.isRestricted(p, event)) { 135 | String command = event.getMessage().split(" ")[0].replaceFirst("/", ""); 136 | 137 | // Idea was to auto-detect command aliases so they didn't have to be added to the allow list. 138 | // Currently doesn't work as it allows native Minecraft commands to slip through 139 | /*PluginCommand pCommand = plugin.getServer().getPluginCommand(command); 140 | if (pCommand == null) 141 | return; 142 | 143 | if (!plugin.getConfig().getStringList("guest.allowed-commands").contains(pCommand.getName())) { 144 | plyrMngr.sendNotice(p); 145 | event.setMessage("/"); 146 | event.setCancelled(true); 147 | }*/ 148 | 149 | if (!plugin.getConfig().getStringList("guest.allowed-commands").contains(command)) { 150 | plyrMngr.sendNotice(p); 151 | event.setMessage("/"); 152 | event.setCancelled(true); 153 | } 154 | } 155 | } 156 | 157 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 158 | public void onPlayerDropItem(final PlayerDropItemEvent event) { 159 | if (!plugin.getConfig().getBoolean("guest.hide-inventory")) { 160 | xAuthPlayer p = plyrMngr.getPlayer(event.getPlayer()); 161 | if (plyrMngr.isRestricted(p, event)) { 162 | plyrMngr.sendNotice(p); 163 | event.setCancelled(true); 164 | } 165 | } 166 | } 167 | 168 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 169 | public void onPlayerInteract(PlayerInteractEvent event) { 170 | xAuthPlayer p = plyrMngr.getPlayer(event.getPlayer().getName()); 171 | if (plyrMngr.isRestricted(p, event)) { 172 | Action action = event.getAction(); 173 | Material type = event.getClickedBlock().getType(); 174 | 175 | // TODO add missing blocks 176 | if (action == Action.LEFT_CLICK_BLOCK) { 177 | if (type == Material.NOTE_BLOCK 178 | || type == Material.WOODEN_DOOR 179 | || type == Material.LEVER 180 | || type == Material.IRON_DOOR 181 | || type == Material.STONE_BUTTON 182 | || type == Material.TRAP_DOOR) { 183 | plyrMngr.sendNotice(p); 184 | event.setCancelled(true); 185 | } 186 | } else if (action == Action.RIGHT_CLICK_BLOCK) { 187 | if (type == Material.DISPENSER 188 | || type == Material.NOTE_BLOCK 189 | || type == Material.BED 190 | || type == Material.CHEST 191 | || type == Material.WORKBENCH 192 | || type == Material.FURNACE 193 | || type == Material.SIGN 194 | || type == Material.WOODEN_DOOR 195 | || type == Material.LEVER 196 | || type == Material.IRON_DOOR 197 | || type == Material.STONE_BUTTON 198 | || type == Material.JUKEBOX 199 | || type == Material.TRAP_DOOR 200 | || type == Material.ENCHANTMENT_TABLE) { 201 | plyrMngr.sendNotice(p); 202 | event.setCancelled(true); 203 | } 204 | } else if (action == Action.PHYSICAL) { 205 | if (type == Material.SOIL || type == Material.STONE_PLATE || type == Material.WOOD_PLATE) 206 | event.setCancelled(true); 207 | } 208 | } 209 | } 210 | 211 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 212 | public void onPlayerMove(PlayerMoveEvent event) { 213 | xAuthPlayer p = plyrMngr.getPlayer(event.getPlayer()); 214 | if (plyrMngr.isRestricted(p, event)) { 215 | World w = p.getPlayer().getWorld(); 216 | Location loc = plugin.getConfig().getBoolean("guest.protect-location") ? 217 | plugin.getLocMngr().getLocation(w) : p.getPlayerData().getLocation(); 218 | 219 | Location testLoc = new Location(loc.getWorld(), loc.getX(), loc.getY(), loc.getZ()); 220 | while ((w.getBlockAt(testLoc).isEmpty() || w.getBlockAt(testLoc).isLiquid()) && testLoc.getY() >= 0) 221 | testLoc.setY((int)testLoc.getY() - 1); 222 | 223 | if (testLoc.getY() > 0) 224 | loc.setY(testLoc.getY() + 1); 225 | 226 | event.setTo(loc); 227 | plyrMngr.sendNotice(p); 228 | } 229 | } 230 | 231 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 232 | public void onPlayerPickupItem(PlayerPickupItemEvent event) { 233 | xAuthPlayer p = plyrMngr.getPlayer(event.getPlayer()); 234 | if (plyrMngr.isRestricted(p, event)) 235 | event.setCancelled(true); 236 | } 237 | 238 | @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true) 239 | public void onInventoryClick(final InventoryClickEvent event) { 240 | if (!plugin.getConfig().getBoolean("guest.hide-inventory")) { 241 | HumanEntity entity = event.getWhoClicked(); 242 | if (entity instanceof Player) { 243 | xAuthPlayer p = plyrMngr.getPlayer(((Player) entity).getName()); 244 | if (plyrMngr.isRestricted(p, event)) { 245 | plyrMngr.sendNotice(p); 246 | event.setCancelled(true); 247 | } 248 | } 249 | } 250 | } 251 | 252 | private boolean isValidName(String pName) { 253 | if (pName.length() < plugin.getConfig().getInt("filter.min-length")) 254 | return false; 255 | 256 | String allowed = plugin.getConfig().getString("filter.allowed"); 257 | if (allowed.length() > 0) { 258 | for (int i = 0; i < pName.length(); i++) { 259 | if (allowed.indexOf(pName.charAt(i)) == -1) 260 | return false; 261 | } 262 | } 263 | 264 | String disallowed = plugin.getConfig().getString("filter.disallowed"); 265 | if (disallowed.length() > 0) { 266 | for (int i = 0; i < pName.length(); i++) { 267 | if (disallowed.indexOf(pName.charAt(i)) >= 0) 268 | return false; 269 | } 270 | } 271 | 272 | if (plugin.getConfig().getBoolean("filter.blank-name") && Utils.isWhitespace(pName)) 273 | return false; 274 | 275 | return true; 276 | } 277 | 278 | private void scheduleDelayedProtect(final xAuthPlayer xp) { 279 | Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { 280 | public void run() { 281 | plyrMngr.protect(xp); 282 | } 283 | }, 1); 284 | } 285 | 286 | private void sendDelayedMessage(final Player player, final String node, int delay) { 287 | Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { 288 | public void run() { 289 | if (player.isOnline()) 290 | plugin.getMsgHndlr().sendMessage(node, player); 291 | } 292 | }, delay); 293 | } 294 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/PlayerDataHandler.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.ArrayList; 8 | import java.util.Collection; 9 | import java.util.Map; 10 | 11 | import org.bukkit.Bukkit; 12 | import org.bukkit.Location; 13 | import org.bukkit.enchantments.Enchantment; 14 | import org.bukkit.enchantments.EnchantmentWrapper; 15 | import org.bukkit.entity.Player; 16 | import org.bukkit.inventory.ItemStack; 17 | import org.bukkit.inventory.PlayerInventory; 18 | import org.bukkit.potion.PotionEffect; 19 | import org.bukkit.potion.PotionEffectType; 20 | 21 | import com.cypherx.xauth.database.Table; 22 | 23 | public class PlayerDataHandler { 24 | private final xAuth plugin; 25 | 26 | public PlayerDataHandler(final xAuth plugin) { 27 | this.plugin = plugin; 28 | } 29 | 30 | public void storeData(xAuthPlayer xp, Player p) { 31 | PlayerInventory pInv = p.getInventory(); 32 | ItemStack[] items = pInv.getContents(); 33 | ItemStack[] armor = pInv.getArmorContents(); 34 | Location loc = p.isDead() ? null : p.getLocation(); 35 | Collection potEffects = p.getActivePotionEffects(); 36 | int fireTicks = p.isDead() ? 0 : p.getFireTicks(); 37 | int remainingAir = p.getRemainingAir(); 38 | 39 | String strItems = null; 40 | String strArmor = null; 41 | String strLoc = null; 42 | String strPotFx = buildPotFxString(potEffects); 43 | xp.setPlayerData(new PlayerData(items, armor, loc, potEffects, fireTicks, remainingAir)); 44 | 45 | boolean hideInv = plugin.getConfig().getBoolean("guest.hide-inventory"); 46 | boolean hideLoc = plugin.getConfig().getBoolean("guest.protect-location"); 47 | 48 | if (hideInv) { 49 | strItems = buildItemString(items); 50 | strArmor = buildItemString(armor); 51 | 52 | pInv.clear(); 53 | pInv.setHelmet(null); 54 | pInv.setChestplate(null); 55 | pInv.setLeggings(null); 56 | pInv.setBoots(null); 57 | } 58 | 59 | if (hideLoc && !p.isDead()) { 60 | strLoc = loc.getWorld().getName() + ":" + loc.getX() + ":" + loc.getY() + ":" + loc.getZ() + ":" + loc.getYaw() + ":" + loc.getPitch(); 61 | p.teleport(plugin.getLocMngr().getLocation(p.getWorld())); 62 | } 63 | 64 | for (PotionEffect effect : p.getActivePotionEffects()) 65 | p.addPotionEffect(new PotionEffect(effect.getType(), 0, 0), true); 66 | 67 | p.setFireTicks(0); 68 | p.setRemainingAir(300); 69 | 70 | // only store player data if there's something to insert 71 | if (strItems != null || strArmor != null || strLoc != null || strPotFx != null) { 72 | Connection conn = plugin.getDbCtrl().getConnection(); 73 | PreparedStatement ps = null; 74 | 75 | try { 76 | String sql; 77 | if (plugin.getDbCtrl().isMySQL()) 78 | sql = String.format("INSERT IGNORE INTO `%s` VALUES (?, ?, ?, ?, ?, ?, ?)", 79 | plugin.getDbCtrl().getTable(Table.PLAYERDATA)); 80 | else 81 | sql = String.format("INSERT INTO `%s` SELECT ?, ?, ?, ?, ?, ?, ? FROM DUAL WHERE NOT EXISTS (SELECT * FROM `%s` WHERE `playername` = ?)", 82 | plugin.getDbCtrl().getTable(Table.PLAYERDATA), plugin.getDbCtrl().getTable(Table.PLAYERDATA)); 83 | 84 | ps = conn.prepareStatement(sql); 85 | ps.setString(1, p.getName()); 86 | ps.setString(2, strItems); 87 | ps.setString(3, strArmor); 88 | ps.setString(4, strLoc); 89 | ps.setString(5, strPotFx); 90 | ps.setInt(6, fireTicks); 91 | ps.setInt(7, remainingAir); 92 | if (!plugin.getDbCtrl().isMySQL()) 93 | ps.setString(8, p.getName()); 94 | ps.executeUpdate(); 95 | } catch (SQLException e) { 96 | xAuthLog.severe("Failed to insert player data into database!", e); 97 | } finally { 98 | plugin.getDbCtrl().close(conn, ps); 99 | } 100 | } 101 | } 102 | 103 | private String buildItemString(ItemStack[] items) { 104 | StringBuilder sbItems = new StringBuilder(); 105 | StringBuilder sbAmount = new StringBuilder(); 106 | StringBuilder sbDurability = new StringBuilder(); 107 | StringBuilder sbEnchants = new StringBuilder(); 108 | 109 | for (ItemStack item : items) { 110 | int itemId = 0; 111 | int amount = 0; 112 | short durability = 0; 113 | Map enchants = null; 114 | 115 | if (item != null) { 116 | itemId = item.getTypeId(); 117 | amount = item.getAmount(); 118 | durability = item.getDurability(); 119 | enchants = item.getEnchantments(); 120 | 121 | if (!enchants.keySet().isEmpty()) { 122 | for (Enchantment enchant : enchants.keySet()) { 123 | int id = enchant.getId(); 124 | int level = enchants.get(enchant); 125 | sbEnchants.append(id + ":" + level + "-"); 126 | } 127 | 128 | sbEnchants.deleteCharAt(sbEnchants.lastIndexOf("-")); 129 | } 130 | } 131 | 132 | sbItems.append(itemId).append(","); 133 | sbAmount.append(amount).append(","); 134 | sbDurability.append(durability).append(","); 135 | sbEnchants.append(","); 136 | } 137 | 138 | sbItems.deleteCharAt(sbItems.lastIndexOf(",")); 139 | sbAmount.deleteCharAt(sbAmount.lastIndexOf(",")); 140 | sbDurability.deleteCharAt(sbDurability.lastIndexOf(",")); 141 | sbEnchants.deleteCharAt(sbEnchants.lastIndexOf(",")); 142 | return sbItems.append(";").append(sbAmount).append(";").append(sbDurability).append(";").append(sbEnchants).toString(); 143 | } 144 | 145 | private String buildPotFxString(Collection effects) { 146 | if (effects.size() < 1) 147 | return null; 148 | 149 | StringBuilder sbType = new StringBuilder(); 150 | StringBuilder sbDur = new StringBuilder(); 151 | StringBuilder sbAmp = new StringBuilder(); 152 | 153 | for (PotionEffect effect : effects) { 154 | sbType.append(effect.getType().getId()).append(","); 155 | sbDur.append(effect.getDuration()).append(","); 156 | sbAmp.append(effect.getAmplifier()).append(","); 157 | } 158 | 159 | sbType.deleteCharAt(sbType.lastIndexOf(",")); 160 | sbDur.deleteCharAt(sbDur.lastIndexOf(",")); 161 | sbAmp.deleteCharAt(sbAmp.lastIndexOf(",")); 162 | return sbType.append(";").append(sbDur).append(";").append(sbAmp).toString(); 163 | } 164 | 165 | private ItemStack[] buildItemStack(String str) { 166 | ItemStack[] items = null; 167 | String[] itemSplit = str.split(";"); 168 | String[] itemid = itemSplit[0].split(","); 169 | String[] amount = itemSplit[1].split(","); 170 | String[] durability = itemSplit[2].split(","); 171 | String[] enchants = itemSplit[3].split(",", -1); 172 | items = new ItemStack[itemid.length]; 173 | 174 | for (int i = 0; i < items.length; i++) { 175 | items[i] = new ItemStack(Integer.parseInt(itemid[i]), Integer.parseInt(amount[i]), Short.parseShort(durability[i])); 176 | 177 | if (!enchants[i].isEmpty()) { 178 | String[] itemEnchants = enchants[i].split("-"); 179 | for (String enchant : itemEnchants) { 180 | String[] enchantSplit = enchant.split(":"); 181 | int id = Integer.parseInt(enchantSplit[0]); 182 | int level = Integer.parseInt(enchantSplit[1]); 183 | Enchantment e = new EnchantmentWrapper(id); 184 | items[i].addUnsafeEnchantment(e, level); 185 | } 186 | } 187 | } 188 | 189 | return items; 190 | } 191 | 192 | private Collection buildPotFx(String str) { 193 | String[] effectSplit = str.split(";"); 194 | String[] type = effectSplit[0].split(","); 195 | String[] duration = effectSplit[1].split(","); 196 | String[] amplifier = effectSplit[2].split(","); 197 | Collection effects = new ArrayList(); 198 | 199 | for (int i = 0; i < type.length; i++) { 200 | PotionEffectType potFxType = PotionEffectType.getById(Integer.parseInt(type[i])); 201 | int potFxDur = Integer.parseInt(duration[i]); 202 | int potFxAmp = Integer.parseInt(amplifier[i]); 203 | effects.add(new PotionEffect(potFxType, potFxDur, potFxAmp)); 204 | } 205 | 206 | return effects; 207 | } 208 | 209 | public void restoreData(xAuthPlayer xp, Player p) { 210 | ItemStack[] items = null; 211 | ItemStack[] armor = null; 212 | Location loc = null; 213 | Collection potFx = null; 214 | int fireTicks = 0; 215 | int remainingAir = 300; 216 | 217 | // Use cached copy of player data, if it exists 218 | PlayerData playerData = xp.getPlayerData(); 219 | if (playerData != null) { 220 | items = playerData.getItems(); 221 | armor = playerData.getArmor(); 222 | loc = playerData.getLocation(); 223 | potFx = playerData.getPotionEffects(); 224 | fireTicks = playerData.getFireTicks(); 225 | remainingAir = playerData.getRemainingAir(); 226 | } else { 227 | Connection conn = plugin.getDbCtrl().getConnection(); 228 | PreparedStatement ps = null; 229 | ResultSet rs = null; 230 | 231 | try { 232 | String sql = String.format("SELECT `items`, `armor`, `location`, `potioneffects`, `fireticks`, `remainingair` FROM `%s` WHERE `playername` = ?", 233 | plugin.getDbCtrl().getTable(Table.PLAYERDATA)); 234 | ps = conn.prepareStatement(sql); 235 | ps.setString(1, p.getName()); 236 | rs = ps.executeQuery(); 237 | 238 | if (rs.next()) { 239 | items = buildItemStack(rs.getString("items")); 240 | armor = buildItemStack(rs.getString("armor")); 241 | 242 | String rsLoc = rs.getString("location"); 243 | if (rsLoc != null) { 244 | String[] locSplit = rsLoc.split(":"); 245 | loc = new Location(Bukkit.getWorld(locSplit[0]), Double.parseDouble(locSplit[1]), Double.parseDouble(locSplit[2]), 246 | Double.parseDouble(locSplit[3]), Float.parseFloat(locSplit[4]), Float.parseFloat(locSplit[5])); 247 | } 248 | 249 | String rsPotFx = rs.getString("potioneffects"); 250 | if (rsPotFx != null) 251 | potFx = buildPotFx(rsPotFx); 252 | 253 | fireTicks = rs.getInt("fireticks"); 254 | remainingAir = rs.getInt("remainingair"); 255 | } 256 | } catch (SQLException e) { 257 | xAuthLog.severe("Failed to load playerdata from database for player: " + p.getName(), e); 258 | } finally { 259 | plugin.getDbCtrl().close(conn, ps, rs); 260 | } 261 | } 262 | 263 | PlayerInventory pInv = p.getInventory(); 264 | boolean hideInv = plugin.getConfig().getBoolean("guest.hide-inventory"); 265 | boolean hideLoc = plugin.getConfig().getBoolean("guest.protect-location"); 266 | 267 | if (hideInv && items != null) { 268 | // Fix for inventory extension plugins 269 | if (pInv.getSize() > items.length) { 270 | ItemStack[] newItems = new ItemStack[pInv.getSize()]; 271 | for(int i = 0; i < items.length; i++) 272 | newItems[i] = items[i]; 273 | 274 | items = newItems; 275 | } 276 | //End Fix for inventory extension plugins 277 | 278 | pInv.setContents(items); 279 | } 280 | 281 | if (hideInv && armor != null) 282 | pInv.setArmorContents(armor); 283 | 284 | if (hideLoc && loc != null && p.getHealth() > 0) 285 | p.teleport(loc); 286 | 287 | if (potFx != null) 288 | p.addPotionEffects(potFx); 289 | 290 | p.setFireTicks(fireTicks); 291 | p.setRemainingAir(remainingAir); 292 | xp.setPlayerData(null); 293 | 294 | Connection conn = plugin.getDbCtrl().getConnection(); 295 | PreparedStatement ps = null; 296 | try { 297 | String sql = String.format("DELETE FROM `%s` WHERE `playername` = ?", 298 | plugin.getDbCtrl().getTable(Table.PLAYERDATA)); 299 | ps = conn.prepareStatement(sql); 300 | ps.setString(1, p.getName()); 301 | ps.executeUpdate(); 302 | } catch (SQLException e) { 303 | xAuthLog.severe("Could not delete playerdata record from database for player: " + p.getName(), e); 304 | } finally { 305 | plugin.getDbCtrl().close(conn, ps); 306 | } 307 | } 308 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/commands/xAuthCommand.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.commands; 2 | 3 | import org.bukkit.command.Command; 4 | import org.bukkit.command.CommandExecutor; 5 | import org.bukkit.command.CommandSender; 6 | import org.bukkit.command.ConsoleCommandSender; 7 | import org.bukkit.command.RemoteConsoleCommandSender; 8 | import org.bukkit.entity.Player; 9 | 10 | import com.cypherx.xauth.xAuth; 11 | import com.cypherx.xauth.xAuthLog; 12 | import com.cypherx.xauth.xAuthPlayer; 13 | import com.cypherx.xauth.auth.Auth; 14 | import com.cypherx.xauth.plugins.xPermissions; 15 | import com.cypherx.xauth.xAuthPlayer.Status; 16 | import com.martiansoftware.jsap.CommandLineTokenizer; 17 | 18 | public class xAuthCommand implements CommandExecutor { 19 | private final xAuth plugin; 20 | 21 | public xAuthCommand(xAuth plugin) { 22 | this.plugin = plugin; 23 | } 24 | 25 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { 26 | if (sender instanceof Player || sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) { 27 | if (args.length < 1) 28 | return false; 29 | 30 | args = CommandLineTokenizer.tokenize(args); 31 | String subCommand = args[0]; 32 | if (subCommand.equals("register")) 33 | return registerCommand(sender, args); 34 | else if (subCommand.equals("changepw") || subCommand.equals("cpw") || subCommand.equals("changepassword") || subCommand.equals("changepass")) 35 | return changePwCommand(sender, args); 36 | else if (subCommand.equals("logout")) 37 | return logoutCommand(sender, args); 38 | else if (subCommand.equals("unregister") || subCommand.equals("unreg")) 39 | return unregisterCommand(sender, args); 40 | else if (subCommand.equals("location") || subCommand.equals("loc")) 41 | return locationCommand(sender, args); 42 | else if (subCommand.equals("reload")) 43 | return reloadCommand(sender, args); 44 | else if (subCommand.equals("activate")) 45 | return activateCommand(sender, args); 46 | else if (subCommand.equals("config") || subCommand.equals("conf")) 47 | return configCommand(sender, args); 48 | 49 | return true; 50 | } 51 | 52 | return false; 53 | } 54 | 55 | private boolean registerCommand(CommandSender sender, String[] args) { 56 | if (!xPermissions.has(sender, "xauth.admin.register")) { 57 | plugin.getMsgHndlr().sendMessage("admin.permission", sender); 58 | return true; 59 | } else if (args.length < 3) { 60 | plugin.getMsgHndlr().sendMessage("admin.register.usage", sender); 61 | return true; 62 | } 63 | 64 | String targetName = args[1]; 65 | String password = args[2]; 66 | String email = args.length > 3 ? args[3] : null; 67 | xAuthPlayer xp = plugin.getPlyrMngr().getPlayer(targetName); 68 | 69 | Auth a = plugin.getAuthClass(xp); 70 | boolean success = a.adminRegister(targetName, password, email); 71 | 72 | String response = a.getResponse(); 73 | if (response != null) 74 | plugin.getMsgHndlr().sendMessage(response, sender, targetName); 75 | 76 | if (success) 77 | xAuthLog.info(sender.getName() + " has registered an account for " + targetName); 78 | 79 | return true; 80 | } 81 | 82 | private boolean changePwCommand(CommandSender sender, String[] args) { 83 | if (!xPermissions.has(sender, "xauth.admin.changepw")) { 84 | plugin.getMsgHndlr().sendMessage("admin.permission", sender); 85 | return true; 86 | } else if (args.length < 3) { 87 | plugin.getMsgHndlr().sendMessage("admin.changepw.usage", sender); 88 | return true; 89 | } 90 | 91 | String targetName = args[1]; 92 | String newPassword = args[2]; 93 | xAuthPlayer xp = plugin.getPlyrMngr().getPlayer(targetName); 94 | 95 | Auth a = plugin.getAuthClass(xp); 96 | boolean success = a.adminChangePassword(targetName, newPassword); 97 | 98 | String response = a.getResponse(); 99 | if (response != null) 100 | plugin.getMsgHndlr().sendMessage(response, sender, targetName); 101 | 102 | if (success) 103 | xAuthLog.info(sender.getName() + " changed " + targetName + "'s password"); 104 | 105 | return true; 106 | } 107 | 108 | private boolean logoutCommand(CommandSender sender, String[] args) { 109 | if (!xPermissions.has(sender, "xauth.admin.logout")) { 110 | plugin.getMsgHndlr().sendMessage("admin.permission", sender); 111 | return true; 112 | } else if (args.length < 2) { 113 | plugin.getMsgHndlr().sendMessage("admin.logout.usage", sender); 114 | return true; 115 | } 116 | 117 | String targetName = args[1]; 118 | xAuthPlayer xp = plugin.getPlyrMngr().getPlayer(targetName); 119 | 120 | if (!xp.isAuthenticated()) { 121 | plugin.getMsgHndlr().sendMessage("admin.logout.error.logged", sender, targetName); 122 | return true; 123 | } 124 | 125 | boolean success = plugin.getPlyrMngr().deleteSession(xp.getAccountId()); 126 | if (success) { 127 | xp.setStatus(Status.Registered); 128 | plugin.getAuthClass(xp).offline(xp.getPlayerName()); 129 | plugin.getMsgHndlr().sendMessage("admin.logout.success.player", sender, targetName); 130 | 131 | Player target = xp.getPlayer(); 132 | if (target != null) { 133 | plugin.getPlyrMngr().protect(xp); 134 | plugin.getMsgHndlr().sendMessage("admin.logout.success.target", target); 135 | } 136 | } else 137 | plugin.getMsgHndlr().sendMessage("admin.logout.error.general", sender); 138 | 139 | return true; 140 | } 141 | 142 | private boolean unregisterCommand(CommandSender sender, String[] args) { 143 | if (!xPermissions.has(sender, "xauth.admin.unregister")) { 144 | plugin.getMsgHndlr().sendMessage("admin.permission", sender); 145 | return true; 146 | } else if (args.length < 2) { 147 | plugin.getMsgHndlr().sendMessage("admin.unregister.usage", sender); 148 | return true; 149 | } 150 | 151 | String targetName = args[1]; 152 | xAuthPlayer xp = plugin.getPlyrMngr().getPlayer(targetName); 153 | 154 | if (!xp.isRegistered()) { 155 | plugin.getMsgHndlr().sendMessage("admin.unregister.error.registered", sender, targetName); 156 | return true; 157 | } 158 | 159 | boolean success = plugin.getPlyrMngr().deleteAccount(xp.getAccountId()); 160 | if (success) { 161 | xp.setStatus(Status.Guest); 162 | plugin.getAuthClass(xp).offline(xp.getPlayerName()); 163 | plugin.getMsgHndlr().sendMessage("admin.unregister.success.player", sender, targetName); 164 | 165 | Player target = xp.getPlayer(); 166 | if (target != null) { 167 | plugin.getPlyrMngr().protect(xp); 168 | plugin.getMsgHndlr().sendMessage("admin.unregister.success.target", target); 169 | } 170 | } else 171 | plugin.getMsgHndlr().sendMessage("admin.unregister.error.general", sender); 172 | 173 | return true; 174 | } 175 | 176 | private boolean locationCommand(CommandSender sender, String[] args) { 177 | if (sender instanceof ConsoleCommandSender) { 178 | xAuthLog.info("This command cannot be executed from the console!"); 179 | return true; 180 | } 181 | 182 | Player player = (Player) sender; 183 | if (!xPermissions.has(player, "xauth.admin.location")) { 184 | plugin.getMsgHndlr().sendMessage("admin.permission", player); 185 | return true; 186 | } else if (args.length < 2 || !(args[1].equals("set") || args[1].equals("remove"))) { 187 | plugin.getMsgHndlr().sendMessage("admin.location.usage", player); 188 | return true; 189 | } 190 | 191 | String action = args[1]; 192 | boolean global = args.length > 2 && args[2].equals("global") ? true : false; 193 | String response; 194 | 195 | if (action.equals("set")) { 196 | if (!global && player.getWorld().getUID().equals(plugin.getLocMngr().getGlobalUID())) { 197 | plugin.getMsgHndlr().sendMessage("admin.location.set.error.global", player); 198 | return true; 199 | } 200 | 201 | boolean success = plugin.getLocMngr().setLocation(player.getLocation(), global); 202 | if (success) 203 | response = "admin.location.set.success." + (global ? "global" : "regular"); 204 | else 205 | response = "admin.location.set.error.general"; 206 | } else { 207 | if (global) { 208 | if (plugin.getLocMngr().getGlobalUID() == null) { 209 | plugin.getMsgHndlr().sendMessage("admin.location.remove.error.noglobal", player); 210 | return true; 211 | } 212 | } else { 213 | if (!plugin.getLocMngr().isLocationSet(player.getWorld())) { 214 | plugin.getMsgHndlr().sendMessage("admin.location.remove.error.notset", player); 215 | return true; 216 | } else if (player.getWorld().getUID().equals(plugin.getLocMngr().getGlobalUID())) { 217 | plugin.getMsgHndlr().sendMessage("admin.location.remove.error.global", player); 218 | return true; 219 | } 220 | } 221 | 222 | boolean success = plugin.getLocMngr().removeLocation(player.getWorld()); 223 | if (success) 224 | response = "admin.location.remove.success." + (global ? "global" : "regular"); 225 | else 226 | response = "admin.location.remove.error.general"; 227 | } 228 | 229 | plugin.getMsgHndlr().sendMessage(response, player); 230 | return true; 231 | } 232 | 233 | private boolean reloadCommand(CommandSender sender, String[] args) { 234 | if (!xPermissions.has(sender, "xauth.admin.reload")) { 235 | plugin.getMsgHndlr().sendMessage("admin.permission", sender); 236 | return true; 237 | } 238 | 239 | plugin.reload(); 240 | plugin.getMsgHndlr().sendMessage("admin.reload", sender); 241 | return true; 242 | } 243 | 244 | private boolean activateCommand(CommandSender sender, String[] args) { 245 | if (!xPermissions.has(sender, "xauth.admin.activate")) { 246 | plugin.getMsgHndlr().sendMessage("admin.permission", sender); 247 | return true; 248 | } else if (args.length < 2) { 249 | plugin.getMsgHndlr().sendMessage("admin.activate.usage", sender); 250 | return true; 251 | } 252 | 253 | String targetName = args[1]; 254 | xAuthPlayer xp = plugin.getPlyrMngr().getPlayer(targetName); 255 | 256 | if (!xp.isRegistered()) { 257 | plugin.getMsgHndlr().sendMessage("admin.activate.error.registered", sender); 258 | return true; 259 | } else if (plugin.getPlyrMngr().isActive(xp.getAccountId())) { 260 | plugin.getMsgHndlr().sendMessage("admin.activate.error.active", sender); 261 | return true; 262 | } 263 | 264 | boolean success = plugin.getPlyrMngr().activateAcc(xp.getAccountId()); 265 | plugin.getMsgHndlr().sendMessage(success ? "admin.activate.success" : "admin.activate.error.general", sender, targetName); 266 | 267 | return true; 268 | } 269 | 270 | private boolean configCommand(CommandSender sender, String[] args) { 271 | if (!xPermissions.has(sender, "xauth.admin.config")) { 272 | plugin.getMsgHndlr().sendMessage("admin.permission", sender); 273 | return true; 274 | } else if (args.length < 3) { 275 | plugin.getMsgHndlr().sendMessage("admin.config.usage", sender); 276 | return true; 277 | } 278 | 279 | String node = args[1]; 280 | Object defVal = plugin.getConfig().getDefaults().get(node); 281 | 282 | if (defVal == null) { 283 | plugin.getMsgHndlr().sendMessage("admin.config.error.exist", sender); 284 | return true; 285 | } 286 | 287 | String value = args[2]; 288 | 289 | try { 290 | if (defVal instanceof String) 291 | plugin.getConfig().set(node, value); 292 | else if (defVal instanceof Integer) 293 | plugin.getConfig().set(node, Integer.parseInt(value)); 294 | else if (defVal instanceof Boolean) 295 | plugin.getConfig().set(node, Boolean.parseBoolean(value)); 296 | else 297 | throw new IllegalArgumentException(); 298 | } catch (NumberFormatException e) { 299 | plugin.getMsgHndlr().sendMessage("admin.config.error.int", sender); 300 | return true; 301 | } catch (IllegalArgumentException e) { 302 | plugin.getMsgHndlr().sendMessage("admin.config.error.invalid", sender); 303 | return true; 304 | } 305 | 306 | plugin.saveConfig(); 307 | plugin.getMsgHndlr().sendMessage("admin.config.success", sender); 308 | return true; 309 | } 310 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/PlayerManager.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.sql.Statement; 8 | import java.sql.Timestamp; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | import java.util.concurrent.ConcurrentMap; 11 | 12 | import org.bukkit.Bukkit; 13 | import org.bukkit.GameMode; 14 | import org.bukkit.entity.Player; 15 | import org.bukkit.event.Event; 16 | import org.bukkit.event.entity.EntityDamageEvent.DamageCause; 17 | 18 | import com.cypherx.xauth.database.Table; 19 | import com.cypherx.xauth.plugins.xPermissions; 20 | import com.cypherx.xauth.xAuthPlayer.Status; 21 | 22 | public class PlayerManager { 23 | private final xAuth plugin; 24 | private final ConcurrentMap players = new ConcurrentHashMap(); 25 | 26 | public PlayerManager(final xAuth plugin) { 27 | this.plugin = plugin; 28 | } 29 | 30 | public xAuthPlayer getPlayer(Player player) { 31 | return getPlayer(player, false); 32 | } 33 | 34 | public xAuthPlayer getPlayer(Player player, boolean reload) { 35 | return getPlayer(player.getName(), reload); 36 | } 37 | 38 | public xAuthPlayer getPlayer(String playerName) { 39 | return getPlayer(playerName, false); 40 | } 41 | 42 | private xAuthPlayer getPlayer(String playerName, boolean reload) { 43 | String lowPlayerName = playerName.toLowerCase(); 44 | 45 | if (players.containsKey(lowPlayerName) && !reload) 46 | return players.get(lowPlayerName); 47 | 48 | xAuthPlayer player = loadPlayer(playerName); 49 | 50 | if (player == null) 51 | player = new xAuthPlayer(playerName); 52 | 53 | players.put(lowPlayerName, player); 54 | return player; 55 | } 56 | 57 | private xAuthPlayer loadPlayer(String playerName) { 58 | Connection conn = plugin.getDbCtrl().getConnection(); 59 | PreparedStatement ps = null; 60 | ResultSet rs = null; 61 | 62 | try { 63 | String sql = String.format("SELECT `id` FROM `%s` WHERE `playername` = ?", 64 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); 65 | ps = conn.prepareStatement(sql); 66 | ps.setString(1, playerName); 67 | rs = ps.executeQuery(); 68 | if (!rs.next()) 69 | return null; 70 | 71 | return new xAuthPlayer(playerName, rs.getInt("id")); 72 | } catch (SQLException e) { 73 | xAuthLog.severe(String.format("Failed to load player: %s", playerName), e); 74 | return null; 75 | } finally { 76 | plugin.getDbCtrl().close(conn, ps, rs); 77 | } 78 | } 79 | 80 | public void handleReload(Player[] players) { 81 | for (Player p : players) { 82 | xAuthPlayer xp = getPlayer(p.getName()); 83 | boolean mustLogin = false; 84 | 85 | if (xp.isRegistered()) { 86 | if (!checkSession(xp)) { 87 | mustLogin = true; 88 | plugin.getAuthClass(xp).offline(p.getName()); 89 | } else { 90 | xp.setStatus(Status.Authenticated); 91 | plugin.getAuthClass(xp).online(p.getName()); 92 | } 93 | } 94 | else if (mustRegister(p)) { 95 | mustLogin = true; 96 | plugin.getAuthClass(xp).offline(p.getName()); 97 | } 98 | 99 | if (mustLogin) { 100 | protect(xp); 101 | plugin.getMsgHndlr().sendMessage("misc.reloaded", p); 102 | } 103 | } 104 | } 105 | 106 | public boolean mustRegister(Player player) { 107 | if (plugin.getConfig().getBoolean("authurl.enabled")) 108 | return plugin.getConfig().getBoolean("authurl.registration"); 109 | 110 | return plugin.getConfig().getBoolean("registration.forced") || xPermissions.has(player, "xauth.register"); 111 | } 112 | 113 | public boolean checkSession(xAuthPlayer player) { 114 | if (!plugin.getDbCtrl().isTableActive(Table.SESSION)) 115 | return false; 116 | 117 | Connection conn = plugin.getDbCtrl().getConnection(); 118 | PreparedStatement ps = null; 119 | ResultSet rs= null; 120 | 121 | try { 122 | String sql = String.format("SELECT `ipaddress`, `logintime` FROM `%s` WHERE `accountid` = ?", 123 | plugin.getDbCtrl().getTable(Table.SESSION)); 124 | ps = conn.prepareStatement(sql); 125 | ps.setInt(1, player.getAccountId()); 126 | rs = ps.executeQuery(); 127 | if (!rs.next()) 128 | return false; 129 | 130 | String ipAddress = rs.getString("ipaddress"); 131 | Timestamp loginTime = rs.getTimestamp("logintime"); 132 | 133 | boolean valid = isSessionValid(player, ipAddress, loginTime); 134 | if (valid) 135 | return true; 136 | 137 | deleteSession(player.getAccountId()); 138 | return false; 139 | } catch (SQLException e) { 140 | xAuthLog.severe(String.format("Failed to load session for account: %d", player.getAccountId()), e); 141 | return false; 142 | } finally { 143 | plugin.getDbCtrl().close(conn, ps, rs); 144 | } 145 | } 146 | 147 | private boolean isSessionValid(xAuthPlayer xp, String ipAddress, Timestamp loginTime) { 148 | if (plugin.getConfig().getBoolean("session.verifyip") && !ipAddress.equals(xp.getIPAddress())) 149 | return false; 150 | 151 | Timestamp expireTime = new Timestamp(loginTime.getTime() + (plugin.getConfig().getInt("session.length") * 1000)); 152 | return expireTime.compareTo(new Timestamp(System.currentTimeMillis())) > 0; 153 | } 154 | 155 | public void protect(xAuthPlayer xp) { 156 | Player p = xp.getPlayer(); 157 | if (p == null) 158 | return; 159 | 160 | plugin.getPlyrDtHndlr().storeData(xp, p); 161 | 162 | xp.setCreative(p.getGameMode().equals(GameMode.CREATIVE)); 163 | if (xp.isCreativeMode()) 164 | p.setGameMode(GameMode.SURVIVAL); 165 | 166 | xp.setLastNotifyTime(new Timestamp(System.currentTimeMillis())); 167 | 168 | int timeout = plugin.getConfig().getInt("guest.timeout"); 169 | if (timeout > 0 && xp.isRegistered()) 170 | xp.setTimeoutTaskId(scheduleTimeoutTask(p, timeout)); 171 | 172 | xp.setProtected(true); 173 | } 174 | 175 | private int scheduleTimeoutTask(final Player player, final int timeout) { 176 | return Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() { 177 | public void run() { 178 | if (player.isOnline()) 179 | player.kickPlayer(plugin.getMsgHndlr().get("misc.timeout")); 180 | } 181 | }, plugin.getConfig().getInt("guest.timeout") * 20); 182 | } 183 | 184 | public void unprotect(xAuthPlayer xp) { 185 | Player p = xp.getPlayer(); 186 | plugin.getPlyrDtHndlr().restoreData(xp, p); 187 | 188 | if (xp.isCreativeMode()) 189 | p.setGameMode(GameMode.CREATIVE); 190 | 191 | int timeoutTaskId = xp.getTimeoutTaskId(); 192 | if (timeoutTaskId > -1) { 193 | Bukkit.getScheduler().cancelTask(timeoutTaskId); 194 | xp.setTimeoutTaskId(-1); 195 | } 196 | 197 | xp.setProtected(false); 198 | } 199 | 200 | public boolean isRestricted(xAuthPlayer player, Event event) { 201 | if (!player.isProtected()) 202 | return false; 203 | 204 | boolean restrict = true; 205 | String[] split = event.getEventName().split("\\."); 206 | String eventName = split[split.length - 1]; 207 | split = eventName.split("(?=\\p{Upper})"); 208 | 209 | // first element (0) will always be empty for whatever reason 210 | String type = split[1].toLowerCase(); //player, block, entity 211 | String action = split[2].toLowerCase(); // move, place, target, etc. 212 | String restrictNode = String.format("restrict.%s.%s", type, action); 213 | String allowNode = String.format("allow.%s.%s", type, action); 214 | 215 | if (plugin.getConfig().contains("guest." + restrictNode)) { 216 | if (!plugin.getConfig().getBoolean("guest." + restrictNode)) 217 | restrict = false; 218 | 219 | if (xPermissions.has(player.getPlayer(), "xauth." + restrictNode)) 220 | restrict = true; 221 | else if (xPermissions.has(player.getPlayer(), "xauth." + allowNode)) 222 | restrict = false; 223 | } 224 | 225 | return restrict; 226 | } 227 | 228 | public void sendNotice(xAuthPlayer player) { 229 | if (canNotify(player)) { 230 | plugin.getMsgHndlr().sendMessage("misc.illegal", player.getPlayer()); 231 | player.setLastNotifyTime(new Timestamp(System.currentTimeMillis())); 232 | } 233 | } 234 | 235 | private boolean canNotify(xAuthPlayer player) { 236 | Timestamp lastNotifyTime = player.getLastNotifyTime(); 237 | if (lastNotifyTime == null) 238 | return true; 239 | 240 | Timestamp nextNotifyTime = new Timestamp(lastNotifyTime.getTime() + (plugin.getConfig().getInt("guest.notify-cooldown") * 1000)); 241 | return nextNotifyTime.compareTo(new Timestamp(System.currentTimeMillis())) < 0; 242 | } 243 | 244 | public boolean hasGodmode(xAuthPlayer player, DamageCause cause) { 245 | int godmodeLength = plugin.getConfig().getInt("session.godmode-length"); 246 | Timestamp loginTime = player.getLoginTime(); 247 | if (godmodeLength < 1 || loginTime == null || cause == DamageCause.FIRE_TICK || cause == DamageCause.DROWNING) 248 | return false; 249 | 250 | Timestamp expireTime = new Timestamp(loginTime.getTime() + (godmodeLength * 1000)); 251 | return expireTime.compareTo(new Timestamp(System.currentTimeMillis())) > 0; 252 | } 253 | 254 | public boolean isActive(int id) { 255 | if (!plugin.getConfig().getBoolean("registration.activation")) 256 | return true; 257 | 258 | Connection conn = plugin.getDbCtrl().getConnection(); 259 | PreparedStatement ps = null; 260 | ResultSet rs = null; 261 | 262 | try { 263 | String sql = String.format("SELECT `active` FROM `%s` WHERE `id` = ?", 264 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); 265 | ps = conn.prepareStatement(sql); 266 | ps.setInt(1, id); 267 | rs = ps.executeQuery(); 268 | if (!rs.next()) 269 | return false; 270 | 271 | return rs.getBoolean("active"); 272 | } catch (SQLException e) { 273 | xAuthLog.severe("Failed to check active status of account: " + id, e); 274 | return false; 275 | } finally { 276 | plugin.getDbCtrl().close(conn, ps, rs); 277 | } 278 | } 279 | 280 | public boolean activateAcc(int id) { 281 | Connection conn = plugin.getDbCtrl().getConnection(); 282 | PreparedStatement ps = null; 283 | 284 | try { 285 | String sql = String.format("UPDATE `%s` SET `active` = 1 WHERE `id` = ?", 286 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); 287 | ps = conn.prepareStatement(sql); 288 | ps.setInt(1, id); 289 | ps.executeUpdate(); 290 | return true; 291 | } catch (SQLException e) { 292 | xAuthLog.severe("Failed to activate account: " + id, e); 293 | return false; 294 | } finally { 295 | plugin.getDbCtrl().close(conn, ps); 296 | } 297 | } 298 | 299 | public boolean doLogin(xAuthPlayer xp) { 300 | int accountId = xp.getAccountId(); 301 | String ipAddress = xp.getIPAddress(); 302 | Timestamp currentTime = new Timestamp(System.currentTimeMillis()); 303 | 304 | try { 305 | // create account if one does not exist (for AuthURL only) 306 | if (plugin.getConfig().getBoolean("authurl.enabled") && accountId < 1) { 307 | accountId = createAccount(xp.getPlayerName(), "authURL", null, ipAddress); 308 | xp.setAccountId(accountId); 309 | xp.setStatus(Status.Registered); 310 | } 311 | 312 | if (plugin.getConfig().getBoolean("account.track-last-login")) 313 | updateLastLogin(accountId, ipAddress, currentTime); 314 | 315 | // insert session if session.length > 0 316 | if (plugin.getDbCtrl().isTableActive(Table.SESSION)) 317 | createSession(accountId, ipAddress); 318 | 319 | // clear strikes 320 | plugin.getStrkMngr().getRecord(ipAddress).clearStrikes(xp.getPlayerName()); 321 | 322 | unprotect(xp); 323 | xp.setLoginTime(currentTime); 324 | xp.setStatus(Status.Authenticated); 325 | return true; 326 | } catch (SQLException e) { 327 | xAuthLog.severe("Something went wrong while logging in player: " + xp.getPlayerName(), e); 328 | return false; 329 | } 330 | } 331 | 332 | public int createAccount(String user, String pass, String email, String ipaddress) throws SQLException { 333 | Connection conn = plugin.getDbCtrl().getConnection(); 334 | PreparedStatement ps = null; 335 | ResultSet rs = null; 336 | 337 | try { 338 | String sql = String.format("INSERT INTO `%s` (`playername`, `password`, `email`, `registerdate`, `registerip`) VALUES (?, ?, ?, ?, ?)", 339 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); 340 | ps = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); 341 | ps.setString(1, user); 342 | ps.setString(2, plugin.getPwdHndlr().hash(pass)); 343 | ps.setString(3, email); 344 | ps.setTimestamp(4, new Timestamp(System.currentTimeMillis())); 345 | ps.setString(5, ipaddress); 346 | ps.executeUpdate(); 347 | rs = ps.getGeneratedKeys(); 348 | return rs.next() ? rs.getInt(1) : -1; 349 | } finally { 350 | plugin.getDbCtrl().close(conn, ps, rs); 351 | } 352 | } 353 | 354 | public boolean updateLastLogin(int accountId, String ipAddress, Timestamp currentTime) throws SQLException { 355 | Connection conn = plugin.getDbCtrl().getConnection(); 356 | PreparedStatement ps = null; 357 | 358 | try { 359 | String sql = String.format("UPDATE `%s` SET `lastlogindate` = ?, `lastloginip` = ? WHERE `id` = ?", 360 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); 361 | ps = conn.prepareStatement(sql); 362 | ps.setTimestamp(1, currentTime); 363 | ps.setString(2, ipAddress); 364 | ps.setInt(3, accountId); 365 | ps.executeUpdate(); 366 | return true; 367 | } finally { 368 | plugin.getDbCtrl().close(conn, ps); 369 | } 370 | } 371 | 372 | public boolean deleteAccount(int accountId) { 373 | Connection conn = plugin.getDbCtrl().getConnection(); 374 | PreparedStatement ps = null; 375 | 376 | try { 377 | String sql = String.format("DELETE FROM `%s` WHERE `id` = ?", 378 | plugin.getDbCtrl().getTable(Table.ACCOUNT)); 379 | ps = conn.prepareStatement(sql); 380 | ps.setInt(1, accountId); 381 | ps.executeUpdate(); 382 | return true; 383 | } catch (SQLException e) { 384 | xAuthLog.severe("Something went wrong while deleting account: " + accountId, e); 385 | return false; 386 | } finally { 387 | plugin.getDbCtrl().close(conn, ps); 388 | } 389 | } 390 | 391 | public boolean createSession(int accountId, String ipAddress) throws SQLException { 392 | Connection conn = plugin.getDbCtrl().getConnection(); 393 | PreparedStatement ps = null; 394 | 395 | try { 396 | String sql = String.format("INSERT INTO `%s` VALUES (?, ?, ?)", 397 | plugin.getDbCtrl().getTable(Table.SESSION)); 398 | ps = conn.prepareStatement(sql); 399 | ps.setInt(1, accountId); 400 | ps.setString(2, ipAddress); 401 | ps.setTimestamp(3, new Timestamp(System.currentTimeMillis())); 402 | ps.executeUpdate(); 403 | return true; 404 | } finally { 405 | plugin.getDbCtrl().close(conn, ps); 406 | } 407 | } 408 | 409 | public boolean deleteSession(int accountId) { 410 | if (!plugin.getDbCtrl().isTableActive(Table.SESSION)) 411 | return true; 412 | 413 | Connection conn = plugin.getDbCtrl().getConnection(); 414 | PreparedStatement ps = null; 415 | 416 | try { 417 | String sql = String.format("DELETE FROM `%s` WHERE `accountid` = ?", 418 | plugin.getDbCtrl().getTable(Table.SESSION)); 419 | ps = conn.prepareStatement(sql); 420 | ps.setInt(1, accountId); 421 | ps.executeUpdate(); 422 | return true; 423 | } catch (SQLException e) { 424 | xAuthLog.severe("Something went wrong while deleting session for account: " + accountId, e); 425 | return false; 426 | } finally { 427 | plugin.getDbCtrl().close(conn, ps); 428 | } 429 | } 430 | 431 | public void reload() { 432 | players.clear(); 433 | } 434 | } -------------------------------------------------------------------------------- /src/main/java/com/cypherx/xauth/password/Whirlpool.java: -------------------------------------------------------------------------------- 1 | package com.cypherx.xauth.password; 2 | 3 | /** 4 | * The Whirlpool hashing function. 5 | * 6 | *

7 | * References 8 | * 9 | *

10 | * The Whirlpool algorithm was developed by 11 | * Paulo S. L. M. Barreto and 12 | * Vincent Rijmen. 13 | * 14 | * See 15 | * P.S.L.M. Barreto, V. Rijmen, 16 | * ``The Whirlpool hashing function,'' 17 | * First NESSIE workshop, 2000 (tweaked version, 2003), 18 | * 19 | * 20 | * @author Paulo S.L.M. Barreto 21 | * @author Vincent Rijmen. 22 | * 23 | * @version 3.0 (2003.03.12) 24 | * 25 | * ============================================================================= 26 | * 27 | * Differences from version 2.1: 28 | * 29 | * - Suboptimal diffusion matrix replaced by cir(1, 1, 4, 1, 8, 5, 2, 9). 30 | * 31 | * ============================================================================= 32 | * 33 | * Differences from version 2.0: 34 | * 35 | * - Generation of ISO/IEC 10118-3 test vectors. 36 | * - Bug fix: nonzero carry was ignored when tallying the data length 37 | * (this bug apparently only manifested itself when feeding data 38 | * in pieces rather than in a single chunk at once). 39 | * 40 | * Differences from version 1.0: 41 | * 42 | * - Original S-box replaced by the tweaked, hardware-efficient version. 43 | * 44 | * ============================================================================= 45 | * 46 | * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS 47 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 48 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 49 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE 50 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 51 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 52 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 53 | * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 54 | * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 55 | * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 56 | * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 57 | * 58 | */ 59 | 60 | import java.util.Arrays; 61 | 62 | class Whirlpool { 63 | 64 | /** 65 | * The message digest size (in bits) 66 | */ 67 | public static final int DIGESTBITS = 512; 68 | 69 | /** 70 | * The message digest size (in bytes) 71 | */ 72 | public static final int DIGESTBYTES = DIGESTBITS >>> 3; 73 | 74 | /** 75 | * The number of rounds of the internal dedicated block cipher. 76 | */ 77 | protected static final int R = 10; 78 | 79 | /** 80 | * The substitution box. 81 | */ 82 | private static final String sbox = 83 | "\u1823\uc6E8\u87B8\u014F\u36A6\ud2F5\u796F\u9152" + 84 | "\u60Bc\u9B8E\uA30c\u7B35\u1dE0\ud7c2\u2E4B\uFE57" + 85 | "\u1577\u37E5\u9FF0\u4AdA\u58c9\u290A\uB1A0\u6B85" + 86 | "\uBd5d\u10F4\ucB3E\u0567\uE427\u418B\uA77d\u95d8" + 87 | "\uFBEE\u7c66\udd17\u479E\ucA2d\uBF07\uAd5A\u8333" + 88 | "\u6302\uAA71\uc819\u49d9\uF2E3\u5B88\u9A26\u32B0" + 89 | "\uE90F\ud580\uBEcd\u3448\uFF7A\u905F\u2068\u1AAE" + 90 | "\uB454\u9322\u64F1\u7312\u4008\uc3Ec\udBA1\u8d3d" + 91 | "\u9700\ucF2B\u7682\ud61B\uB5AF\u6A50\u45F3\u30EF" + 92 | "\u3F55\uA2EA\u65BA\u2Fc0\udE1c\uFd4d\u9275\u068A" + 93 | "\uB2E6\u0E1F\u62d4\uA896\uF9c5\u2559\u8472\u394c" + 94 | "\u5E78\u388c\ud1A5\uE261\uB321\u9c1E\u43c7\uFc04" + 95 | "\u5199\u6d0d\uFAdF\u7E24\u3BAB\ucE11\u8F4E\uB7EB" + 96 | "\u3c81\u94F7\uB913\u2cd3\uE76E\uc403\u5644\u7FA9" + 97 | "\u2ABB\uc153\udc0B\u9d6c\u3174\uF646\uAc89\u14E1" + 98 | "\u163A\u6909\u70B6\ud0Ed\ucc42\u98A4\u285c\uF886"; 99 | 100 | private static long[][] C = new long[8][256]; 101 | private static long[] rc = new long[R + 1]; 102 | 103 | static { 104 | for (int x = 0; x < 256; x++) { 105 | char c = sbox.charAt(x/2); 106 | long v1 = ((x & 1) == 0) ? c >>> 8 : c & 0xff; 107 | long v2 = v1 << 1; 108 | if (v2 >= 0x100L) { 109 | v2 ^= 0x11dL; 110 | } 111 | long v4 = v2 << 1; 112 | if (v4 >= 0x100L) { 113 | v4 ^= 0x11dL; 114 | } 115 | long v5 = v4 ^ v1; 116 | long v8 = v4 << 1; 117 | if (v8 >= 0x100L) { 118 | v8 ^= 0x11dL; 119 | } 120 | long v9 = v8 ^ v1; 121 | /* 122 | * build the circulant table C[0][x] = S[x].[1, 1, 4, 1, 8, 5, 2, 9]: 123 | */ 124 | C[0][x] = 125 | (v1 << 56) | (v1 << 48) | (v4 << 40) | (v1 << 32) | 126 | (v8 << 24) | (v5 << 16) | (v2 << 8) | (v9 ); 127 | /* 128 | * build the remaining circulant tables C[t][x] = C[0][x] rotr t 129 | */ 130 | for (int t = 1; t < 8; t++) { 131 | C[t][x] = (C[t - 1][x] >>> 8) | ((C[t - 1][x] << 56)); 132 | } 133 | } 134 | 135 | /* 136 | * build the round constants: 137 | */ 138 | rc[0] = 0L; /* not used (assigment kept only to properly initialize all variables) */ 139 | for (int r = 1; r <= R; r++) { 140 | int i = 8*(r - 1); 141 | rc[r] = 142 | (C[0][i ] & 0xff00000000000000L) ^ 143 | (C[1][i + 1] & 0x00ff000000000000L) ^ 144 | (C[2][i + 2] & 0x0000ff0000000000L) ^ 145 | (C[3][i + 3] & 0x000000ff00000000L) ^ 146 | (C[4][i + 4] & 0x00000000ff000000L) ^ 147 | (C[5][i + 5] & 0x0000000000ff0000L) ^ 148 | (C[6][i + 6] & 0x000000000000ff00L) ^ 149 | (C[7][i + 7] & 0x00000000000000ffL); 150 | } 151 | } 152 | 153 | /** 154 | * Global number of hashed bits (256-bit counter). 155 | */ 156 | protected byte[] bitLength = new byte[32]; 157 | 158 | /** 159 | * Buffer of data to hash. 160 | */ 161 | protected byte[] buffer = new byte[64]; 162 | 163 | /** 164 | * Current number of bits on the buffer. 165 | */ 166 | protected int bufferBits = 0; 167 | 168 | /** 169 | * Current (possibly incomplete) byte slot on the buffer. 170 | */ 171 | protected int bufferPos = 0; 172 | 173 | /** 174 | * The hashing state. 175 | */ 176 | protected long[] hash = new long[8]; 177 | protected long[] K = new long[8]; // the round key 178 | protected long[] L = new long[8]; 179 | protected long[] block = new long[8]; // mu(buffer) 180 | protected long[] state = new long[8]; // the cipher state 181 | 182 | public Whirlpool() { 183 | } 184 | 185 | /** 186 | * The core Whirlpool transform. 187 | */ 188 | protected void processBuffer() { 189 | /* 190 | * map the buffer to a block: 191 | */ 192 | for (int i = 0, j = 0; i < 8; i++, j += 8) { 193 | block[i] = 194 | (((long)buffer[j ] ) << 56) ^ 195 | (((long)buffer[j + 1] & 0xffL) << 48) ^ 196 | (((long)buffer[j + 2] & 0xffL) << 40) ^ 197 | (((long)buffer[j + 3] & 0xffL) << 32) ^ 198 | (((long)buffer[j + 4] & 0xffL) << 24) ^ 199 | (((long)buffer[j + 5] & 0xffL) << 16) ^ 200 | (((long)buffer[j + 6] & 0xffL) << 8) ^ 201 | (((long)buffer[j + 7] & 0xffL) ); 202 | } 203 | /* 204 | * compute and apply K^0 to the cipher state: 205 | */ 206 | for (int i = 0; i < 8; i++) { 207 | state[i] = block[i] ^ (K[i] = hash[i]); 208 | } 209 | /* 210 | * iterate over all rounds: 211 | */ 212 | for (int r = 1; r <= R; r++) { 213 | /* 214 | * compute K^r from K^{r-1}: 215 | */ 216 | for (int i = 0; i < 8; i++) { 217 | L[i] = 0L; 218 | for (int t = 0, s = 56; t < 8; t++, s -= 8) { 219 | L[i] ^= C[t][(int)(K[(i - t) & 7] >>> s) & 0xff]; 220 | } 221 | } 222 | for (int i = 0; i < 8; i++) { 223 | K[i] = L[i]; 224 | } 225 | K[0] ^= rc[r]; 226 | /* 227 | * apply the r-th round transformation: 228 | */ 229 | for (int i = 0; i < 8; i++) { 230 | L[i] = K[i]; 231 | for (int t = 0, s = 56; t < 8; t++, s -= 8) { 232 | L[i] ^= C[t][(int)(state[(i - t) & 7] >>> s) & 0xff]; 233 | } 234 | } 235 | for (int i = 0; i < 8; i++) { 236 | state[i] = L[i]; 237 | } 238 | } 239 | /* 240 | * apply the Miyaguchi-Preneel compression function: 241 | */ 242 | for (int i = 0; i < 8; i++) { 243 | hash[i] ^= state[i] ^ block[i]; 244 | } 245 | } 246 | 247 | /** 248 | * Initialize the hashing state. 249 | */ 250 | public void NESSIEinit() { 251 | Arrays.fill(bitLength, (byte)0); 252 | bufferBits = bufferPos = 0; 253 | buffer[0] = 0; // it's only necessary to cleanup buffer[bufferPos]. 254 | Arrays.fill(hash, 0L); // initial value 255 | } 256 | 257 | /** 258 | * Delivers input data to the hashing algorithm. 259 | * 260 | * @param source plaintext data to hash. 261 | * @param sourceBits how many bits of plaintext to process. 262 | * 263 | * This method maintains the invariant: bufferBits < 512 264 | */ 265 | public void NESSIEadd(byte[] source, long sourceBits) { 266 | /* 267 | sourcePos 268 | | 269 | +-------+-------+------- 270 | ||||||||||||||||||||| source 271 | +-------+-------+------- 272 | +-------+-------+-------+-------+-------+------- 273 | |||||||||||||||||||||| buffer 274 | +-------+-------+-------+-------+-------+------- 275 | | 276 | bufferPos 277 | */ 278 | int sourcePos = 0; // index of leftmost source byte containing data (1 to 8 bits). 279 | int sourceGap = (8 - ((int)sourceBits & 7)) & 7; // space on source[sourcePos]. 280 | int bufferRem = bufferBits & 7; // occupied bits on buffer[bufferPos]. 281 | int b; 282 | // tally the length of the added data: 283 | long value = sourceBits; 284 | for (int i = 31, carry = 0; i >= 0; i--) { 285 | carry += (bitLength[i] & 0xff) + ((int)value & 0xff); 286 | bitLength[i] = (byte)carry; 287 | carry >>>= 8; 288 | value >>>= 8; 289 | } 290 | // process data in chunks of 8 bits: 291 | while (sourceBits > 8) { // at least source[sourcePos] and source[sourcePos+1] contain data. 292 | // take a byte from the source: 293 | b = ((source[sourcePos] << sourceGap) & 0xff) | 294 | ((source[sourcePos + 1] & 0xff) >>> (8 - sourceGap)); 295 | if (b < 0 || b >= 256) { 296 | throw new RuntimeException("LOGIC ERROR"); 297 | } 298 | // process this byte: 299 | buffer[bufferPos++] |= b >>> bufferRem; 300 | bufferBits += 8 - bufferRem; // bufferBits = 8*bufferPos; 301 | if (bufferBits == 512) { 302 | // process data block: 303 | processBuffer(); 304 | // reset buffer: 305 | bufferBits = bufferPos = 0; 306 | } 307 | buffer[bufferPos] = (byte)((b << (8 - bufferRem)) & 0xff); 308 | bufferBits += bufferRem; 309 | // proceed to remaining data: 310 | sourceBits -= 8; 311 | sourcePos++; 312 | } 313 | // now 0 <= sourceBits <= 8; 314 | // furthermore, all data (if any is left) is in source[sourcePos]. 315 | if (sourceBits > 0) { 316 | b = (source[sourcePos] << sourceGap) & 0xff; // bits are left-justified on b. 317 | // process the remaining bits: 318 | buffer[bufferPos] |= b >>> bufferRem; 319 | } else { 320 | b = 0; 321 | } 322 | if (bufferRem + sourceBits < 8) { 323 | // all remaining data fits on buffer[bufferPos], and there still remains some space. 324 | bufferBits += sourceBits; 325 | } else { 326 | // buffer[bufferPos] is full: 327 | bufferPos++; 328 | bufferBits += 8 - bufferRem; // bufferBits = 8*bufferPos; 329 | sourceBits -= 8 - bufferRem; 330 | // now 0 <= sourceBits < 8; furthermore, all data is in source[sourcePos]. 331 | if (bufferBits == 512) { 332 | // process data block: 333 | processBuffer(); 334 | // reset buffer: 335 | bufferBits = bufferPos = 0; 336 | } 337 | buffer[bufferPos] = (byte)((b << (8 - bufferRem)) & 0xff); 338 | bufferBits += (int)sourceBits; 339 | } 340 | } 341 | 342 | /** 343 | * Get the hash value from the hashing state. 344 | * 345 | * This method uses the invariant: bufferBits < 512 346 | */ 347 | public void NESSIEfinalize(byte[] digest) { 348 | // append a '1'-bit: 349 | buffer[bufferPos] |= 0x80 >>> (bufferBits & 7); 350 | bufferPos++; // all remaining bits on the current byte are set to zero. 351 | // pad with zero bits to complete 512N + 256 bits: 352 | if (bufferPos > 32) { 353 | while (bufferPos < 64) { 354 | buffer[bufferPos++] = 0; 355 | } 356 | // process data block: 357 | processBuffer(); 358 | // reset buffer: 359 | bufferPos = 0; 360 | } 361 | while (bufferPos < 32) { 362 | buffer[bufferPos++] = 0; 363 | } 364 | // append bit length of hashed data: 365 | System.arraycopy(bitLength, 0, buffer, 32, 32); 366 | // process data block: 367 | processBuffer(); 368 | // return the completed message digest: 369 | for (int i = 0, j = 0; i < 8; i++, j += 8) { 370 | long h = hash[i]; 371 | digest[j ] = (byte)(h >>> 56); 372 | digest[j + 1] = (byte)(h >>> 48); 373 | digest[j + 2] = (byte)(h >>> 40); 374 | digest[j + 3] = (byte)(h >>> 32); 375 | digest[j + 4] = (byte)(h >>> 24); 376 | digest[j + 5] = (byte)(h >>> 16); 377 | digest[j + 6] = (byte)(h >>> 8); 378 | digest[j + 7] = (byte)(h ); 379 | } 380 | } 381 | 382 | /** 383 | * Delivers string input data to the hashing algorithm. 384 | * 385 | * @param source plaintext data to hash (ASCII text string). 386 | * 387 | * This method maintains the invariant: bufferBits < 512 388 | */ 389 | public void NESSIEadd(String source) { 390 | if (source.length() > 0) { 391 | byte[] data = new byte[source.length()]; 392 | for (int i = 0; i < source.length(); i++) { 393 | data[i] = (byte)source.charAt(i); 394 | } 395 | NESSIEadd(data, 8*data.length); 396 | } 397 | } 398 | 399 | public static String display(byte[] array) { 400 | char[] val = new char[2*array.length]; 401 | //String hex = "0123456789ABCDEF"; 402 | String hex = "0123456789abcdef"; 403 | for (int i = 0; i < array.length; i++) { 404 | int b = array[i] & 0xff; 405 | val[2*i] = hex.charAt(b >>> 4); 406 | val[2*i + 1] = hex.charAt(b & 15); 407 | } 408 | return String.valueOf(val); 409 | } 410 | } 411 | --------------------------------------------------------------------------------