diff --git a/pom.xml b/pom.xml index f9def84..0f4f46a 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,11 @@ 2.9.2 provided + + mysql + mysql-connector-java + 8.0.13 + @@ -90,6 +95,8 @@ com.beust:jcommander com.github.jai-imageio:jai-imageio-core commons-codec:commons-codec + mysql:mysql-connector-java + com.google.protobuf:protobuf-java ${project.name} diff --git a/src/main/java/eu/oskar3123/spigot2fa/Main.java b/src/main/java/eu/oskar3123/spigot2fa/Main.java index 11721e6..8e21ad4 100644 --- a/src/main/java/eu/oskar3123/spigot2fa/Main.java +++ b/src/main/java/eu/oskar3123/spigot2fa/Main.java @@ -1,28 +1,39 @@ package eu.oskar3123.spigot2fa; import eu.oskar3123.spigot2fa.command.TFACommand; -import eu.oskar3123.spigot2fa.config.Config; -import eu.oskar3123.spigot2fa.config.ConfigHandler; +import eu.oskar3123.spigot2fa.config.PlayersConfiguration; +import eu.oskar3123.spigot2fa.config.SQLPlayersConfiguration; +import eu.oskar3123.spigot2fa.config.YAMLPlayersConfiguration; +import eu.oskar3123.spigot2fa.config.yaml.Config; +import eu.oskar3123.spigot2fa.config.yaml.ConfigHandler; import eu.oskar3123.spigot2fa.handler.TFAHandler; import eu.oskar3123.spigot2fa.listener.AuthListener; import eu.oskar3123.spigot2fa.listener.MapListener; +import org.bukkit.configuration.Configuration; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.java.JavaPlugin; +import java.sql.SQLException; + public class Main extends JavaPlugin { public TFAHandler tfaHandler; public ConfigHandler configHandler; public Config config; - public Config players; + public PlayersConfiguration players; @Override public void onEnable() { this.configHandler = new ConfigHandler(this); this.config = this.configHandler.addConfig(new Config("config")); - this.players = this.configHandler.addConfig(new Config("players")); + if (!initPlayersConfig()) + { + getLogger().severe("Failed to init players backend, disabling plugin"); + getServer().getPluginManager().disablePlugin(this); + return; + } this.tfaHandler = new TFAHandler(this); registerCommands(); registerListeners(); @@ -31,7 +42,51 @@ public class Main extends JavaPlugin @Override public void onDisable() { - this.tfaHandler.abortAll(); + if (this.tfaHandler != null) + { + this.tfaHandler.abortAll(); + } + } + + private boolean initPlayersConfig() + { + Configuration c = this.configHandler.getConfig(this.config); + String mode = c.getString("backend"); + if (mode.equalsIgnoreCase("yml") || mode.equalsIgnoreCase("yaml")) + { + players = new YAMLPlayersConfiguration(this.configHandler, "players"); + return true; + } + else if (mode.equalsIgnoreCase("mysql")) + { + String hostname = c.getString("mysql.hostname"); + String port = c.getString("mysql.port"); + String database = c.getString("mysql.database"); + String username = c.getString("mysql.username"); + String password = c.getString("mysql.password"); + String tablePrefix = c.getString("mysql.tableprefix"); + try + { + players = new SQLPlayersConfiguration(hostname, port, database, username, password, tablePrefix); + return true; + } + catch (ClassNotFoundException e) + { + e.printStackTrace(); + getLogger().severe("JDBC driver for mysql not found"); + return false; + } + catch (SQLException e) + { + e.printStackTrace(); + getLogger().severe("Failed to connect to database, check your settings"); + return false; + } + } + else + { + return false; + } } private void registerCommands() diff --git a/src/main/java/eu/oskar3123/spigot2fa/config/PlayersConfiguration.java b/src/main/java/eu/oskar3123/spigot2fa/config/PlayersConfiguration.java new file mode 100644 index 0000000..4554ad9 --- /dev/null +++ b/src/main/java/eu/oskar3123/spigot2fa/config/PlayersConfiguration.java @@ -0,0 +1,52 @@ +package eu.oskar3123.spigot2fa.config; + +import java.util.UUID; + +public interface PlayersConfiguration +{ + + class PlayersData + { + + private UUID uuid; + private String secret; + private String lastIp; + private long lastLogin; + + public PlayersData(UUID uuid, String secret, String lastIp, long lastLogin) + { + this.uuid = uuid; + this.secret = secret; + this.lastIp = lastIp; + this.lastLogin = lastLogin; + } + + public UUID getUUID() + { + return uuid; + } + + public String getSecret() + { + return secret; + } + + public String getLastIP() + { + return lastIp; + } + + public long getLastLogin() + { + return lastLogin; + } + + } + + boolean hasData(UUID uuid); + + PlayersData getData(UUID uuid); + + boolean setData(UUID uuid, PlayersData data); + +} diff --git a/src/main/java/eu/oskar3123/spigot2fa/config/SQLPlayersConfiguration.java b/src/main/java/eu/oskar3123/spigot2fa/config/SQLPlayersConfiguration.java new file mode 100644 index 0000000..b5a3ac8 --- /dev/null +++ b/src/main/java/eu/oskar3123/spigot2fa/config/SQLPlayersConfiguration.java @@ -0,0 +1,164 @@ +package eu.oskar3123.spigot2fa.config; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.UUID; + +public class SQLPlayersConfiguration implements PlayersConfiguration +{ + + private String hostname; + private String port; + private String database; + private String username; + private String password; + private String tableName; + private Connection connection; + + public SQLPlayersConfiguration(String hostname, String port, String database, String username, String password, String tablePrefix) throws ClassNotFoundException, SQLException + { + this.hostname = hostname; + this.port = port; + this.database = database; + this.username = username; + this.password = password; + Class.forName("com.mysql.jdbc.Driver"); + this.tableName = tablePrefix + "playerdata"; + if (!connect(10)) + { + throw new SQLException("Failed to connect"); + } + init(); + } + + private boolean connect(int retries) + { + retries--; + try + { + if (connection != null && connection.isValid(1)) + { + return true; + } + connection = DriverManager.getConnection(String.format("jdbc:mysql://%s:%s/%s", this.hostname, this.port, this.database), this.username, this.password); + return true; + } + catch (SQLException e) + { + if (retries > 0) + { + return connect(retries); + } + return false; + } + } + + private void init() throws SQLException + { + String createSql = "CREATE TABLE IF NOT EXISTS `" + this.tableName + "` ( \n" + + " `uuid` VARCHAR(36) NOT NULL , \n" + + " `secret` VARCHAR(32) NOT NULL , \n" + + " `lastip` VARCHAR(15) NOT NULL , \n" + + " `lastlogin` BIGINT NOT NULL , \n" + + " PRIMARY KEY (`uuid`)\n" + + ") ENGINE = InnoDB;"; + connection.createStatement().executeUpdate(createSql); + } + + @Override + public boolean hasData(UUID uuid) + { + try + { + if (!connect(10)) + { + return false; + } + String querySql = "SELECT COUNT(`uuid`) FROM `" + this.tableName + "` WHERE `uuid`='" + uuid.toString() + "';"; + ResultSet result = connection.createStatement().executeQuery(querySql); + if (result.next()) + { + return result.getLong(1) > 0; + + } + return false; + } + catch (SQLException e) + { + return false; + } + } + + @Override + public PlayersData getData(UUID uuid) + { + try + { + if (!connect(10)) + { + return null; + } + String querySql = "SELECT `secret`, `lastip`, `lastlogin` FROM `" + this.tableName + "` WHERE `uuid`='" + uuid.toString() + "';"; + ResultSet result = connection.createStatement().executeQuery(querySql); + if (!result.next()) + { + return null; + } + String secret = result.getString("secret"); + String lastIp = result.getString("lastip"); + long lastLogin = result.getLong("lastlogin"); + return new PlayersData(uuid, secret, lastIp, lastLogin); + } + catch (SQLException e) + { + return null; + } + } + + @Override + public boolean setData(UUID uuid, PlayersData data) + { + try + { + if (!connect(10)) + { + return false; + } + if (data == null) + { + String deleteSql = "DELETE FROM `" + this.tableName + "` WHERE `uuid`='" + uuid.toString() + "';"; + System.out.println(deleteSql); + connection.isValid(1); + connection.createStatement().executeUpdate(deleteSql); + return true; + } + if (hasData(uuid)) + { + String updateSql = "UPDATE `" + this.tableName + "` SET `secret`='" + + data.getSecret() + "', `lastip`='" + + data.getLastIP() + "', `lastlogin`=" + + data.getLastLogin() + " WHERE `uuid`='" + + data.getUUID().toString() + "';"; + System.out.println(updateSql); + connection.createStatement().executeUpdate(updateSql); + return true; + } + String insertSql = "INSERT INTO `" + this.tableName + "` (`uuid`, `secret`, `lastip`, `lastlogin`) VALUES (" + + "'" + uuid.toString() + "', " + + "'" + data.getSecret() + "', " + + "'" + data.getLastIP() + "', " + + data.getLastLogin() + ");"; + System.out.println(insertSql); + connection.createStatement().executeUpdate(insertSql); + return true; + } + catch (SQLException e) + { + System.out.println("setData failed"); + return false; + } + } + +} diff --git a/src/main/java/eu/oskar3123/spigot2fa/config/YAMLPlayersConfiguration.java b/src/main/java/eu/oskar3123/spigot2fa/config/YAMLPlayersConfiguration.java new file mode 100644 index 0000000..b2a048b --- /dev/null +++ b/src/main/java/eu/oskar3123/spigot2fa/config/YAMLPlayersConfiguration.java @@ -0,0 +1,52 @@ +package eu.oskar3123.spigot2fa.config; + +import eu.oskar3123.spigot2fa.config.yaml.Config; +import eu.oskar3123.spigot2fa.config.yaml.ConfigHandler; +import org.bukkit.configuration.Configuration; + +import java.util.UUID; + +public class YAMLPlayersConfiguration implements PlayersConfiguration +{ + + private ConfigHandler configHandler; + private Config config; + + public YAMLPlayersConfiguration(ConfigHandler configHandler, String name) + { + this.configHandler = configHandler; + this.configHandler.addConfig(this.config = new Config(name)); + } + + @Override + public boolean hasData(UUID uuid) + { + return this.configHandler.getConfig(this.config).isSet(uuid.toString()); + } + + @Override + public PlayersData getData(UUID uuid) + { + if (!hasData(uuid)) + { + return null; + } + Configuration c = this.configHandler.getConfig(this.config); + String secret = c.getString(uuid.toString() + ".secret"); + String lastIp = c.getString(uuid.toString() + ".lastip"); + long lastLogin = c.getLong(uuid.toString() + ".lastlogin"); + return new PlayersData(uuid, secret, lastIp, lastLogin); + } + + @Override + public boolean setData(UUID uuid, PlayersData data) + { + Configuration c = this.configHandler.getConfig(this.config); + c.set(uuid.toString() + ".secret", data.getSecret()); + c.set(uuid.toString() + ".lastip", data.getLastIP()); + c.set(uuid.toString() + ".lastlogin", data.getLastLogin()); + this.configHandler.saveConfig(this.config, true); + return true; + } + +} diff --git a/src/main/java/eu/oskar3123/spigot2fa/config/Config.java b/src/main/java/eu/oskar3123/spigot2fa/config/yaml/Config.java similarity index 84% rename from src/main/java/eu/oskar3123/spigot2fa/config/Config.java rename to src/main/java/eu/oskar3123/spigot2fa/config/yaml/Config.java index 63d55a3..5319189 100644 --- a/src/main/java/eu/oskar3123/spigot2fa/config/Config.java +++ b/src/main/java/eu/oskar3123/spigot2fa/config/yaml/Config.java @@ -1,4 +1,4 @@ -package eu.oskar3123.spigot2fa.config; +package eu.oskar3123.spigot2fa.config.yaml; import org.bukkit.configuration.file.FileConfiguration; diff --git a/src/main/java/eu/oskar3123/spigot2fa/config/ConfigHandler.java b/src/main/java/eu/oskar3123/spigot2fa/config/yaml/ConfigHandler.java similarity index 98% rename from src/main/java/eu/oskar3123/spigot2fa/config/ConfigHandler.java rename to src/main/java/eu/oskar3123/spigot2fa/config/yaml/ConfigHandler.java index 52b4f7f..38fd5d4 100644 --- a/src/main/java/eu/oskar3123/spigot2fa/config/ConfigHandler.java +++ b/src/main/java/eu/oskar3123/spigot2fa/config/yaml/ConfigHandler.java @@ -1,4 +1,4 @@ -package eu.oskar3123.spigot2fa.config; +package eu.oskar3123.spigot2fa.config.yaml; import com.google.common.base.Charsets; import org.bukkit.Bukkit; diff --git a/src/main/java/eu/oskar3123/spigot2fa/handler/TFAHandler.java b/src/main/java/eu/oskar3123/spigot2fa/handler/TFAHandler.java index 39a0914..a2aae72 100644 --- a/src/main/java/eu/oskar3123/spigot2fa/handler/TFAHandler.java +++ b/src/main/java/eu/oskar3123/spigot2fa/handler/TFAHandler.java @@ -1,12 +1,12 @@ package eu.oskar3123.spigot2fa.handler; import eu.oskar3123.spigot2fa.Main; +import eu.oskar3123.spigot2fa.config.PlayersConfiguration; import eu.oskar3123.spigot2fa.map.QRMapRenderer; import eu.oskar3123.spigot2fa.tfa.TFA; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.configuration.Configuration; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.MapMeta; @@ -52,9 +52,13 @@ public class TFAHandler } long now = new Date().getTime(); long sessionTimeInMs = plugin.configHandler.getConfig(plugin.config).getLong("2fa.sessiontime") * 60000L; - Configuration players = plugin.configHandler.getConfig(plugin.players); - long last = players.getLong(uuid.toString() + ".lastlogin"); - String lastIp = players.getString(uuid.toString() + ".lastip"); + PlayersConfiguration.PlayersData playersData = plugin.players.getData(uuid); + if (playersData == null) + { + return true; + } + long last = playersData.getLastLogin(); + String lastIp = playersData.getLastIP(); return last >= now - sessionTimeInMs && ip.equalsIgnoreCase(lastIp); } @@ -75,10 +79,12 @@ public class TFAHandler { now = time; } - Configuration players = plugin.configHandler.getConfig(plugin.players); - players.set(uuid.toString() + ".lastlogin", now); - players.set(uuid.toString() + ".lastip", ip); - plugin.configHandler.saveConfig(plugin.players, true); + PlayersConfiguration.PlayersData playersData = plugin.players.getData(uuid); + PlayersConfiguration.PlayersData newData = new PlayersConfiguration.PlayersData(uuid, playersData.getSecret(), ip, now); + if (!plugin.players.setData(uuid, newData)) + { + plugin.getLogger().severe("Failed to set data"); + } } public String formatSecret(String secret) @@ -88,21 +94,26 @@ public class TFAHandler public void remove2FA(UUID uuid) { - plugin.configHandler.getConfig(plugin.players).set(uuid.toString(), null); - plugin.configHandler.saveConfig(plugin.players, true); + if (!plugin.players.setData(uuid, null)) + { + plugin.getLogger().severe("Failed to set data"); + } } public boolean hasEnabled2FA(UUID uuid) { - return plugin.configHandler.getConfig(plugin.players).isString(uuid.toString() + ".secret"); + return plugin.players.hasData(uuid); } public void creatingSuccess(Player player) { String secret = remove(player.getUniqueId()); player.getInventory().setItemInMainHand(new ItemStack(Material.AIR)); - plugin.configHandler.getConfig(plugin.players).set(player.getUniqueId().toString() + ".secret", secret); - plugin.configHandler.saveConfig(plugin.players, true); + PlayersConfiguration.PlayersData playersData = new PlayersConfiguration.PlayersData(player.getUniqueId(), secret, player.getAddress().getAddress().getHostAddress(), 0); + if (!plugin.players.setData(player.getUniqueId(), playersData)) + { + plugin.getLogger().severe("Failed to set data"); + } } public void creatingFailed(Player player) @@ -187,8 +198,12 @@ public class TFAHandler { return isInProcess.get(uuid); } - Configuration players = plugin.configHandler.getConfig(plugin.players); - return players.getString(uuid.toString() + ".secret"); + PlayersConfiguration.PlayersData playersData = plugin.players.getData(uuid); + if (playersData == null) + { + return null; + } + return playersData.getSecret(); } public void stopCreating(Player player) diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index fa3136c..98a5e57 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,3 +1,12 @@ +mysql: + hostname: '' + port: '' + database: '' + username: '' + password: '' + tableprefix: '2fa_' +# yml or mysql +backend: 'yml' 2fa: issuer: 'Mineworlds' account: '{NAME}'