forked from TuxCoding/FastLogin
Added database setup
This commit is contained in:
@@ -18,7 +18,9 @@ import com.google.common.reflect.ClassPath;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.KeyPair;
|
import java.security.KeyPair;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@@ -33,6 +35,14 @@ import org.bukkit.plugin.java.JavaPlugin;
|
|||||||
*/
|
*/
|
||||||
public class FastLoginBukkit extends JavaPlugin {
|
public class FastLoginBukkit extends JavaPlugin {
|
||||||
|
|
||||||
|
public static UUID parseId(String withoutDashes) {
|
||||||
|
return UUID.fromString(withoutDashes.substring(0, 8)
|
||||||
|
+ "-" + withoutDashes.substring(8, 12)
|
||||||
|
+ "-" + withoutDashes.substring(12, 16)
|
||||||
|
+ "-" + withoutDashes.substring(16, 20)
|
||||||
|
+ "-" + withoutDashes.substring(20, 32));
|
||||||
|
}
|
||||||
|
|
||||||
//provide a immutable key pair to be thread safe | used for encrypting and decrypting traffic
|
//provide a immutable key pair to be thread safe | used for encrypting and decrypting traffic
|
||||||
private final KeyPair keyPair = EncryptionUtil.generateKeyPair();
|
private final KeyPair keyPair = EncryptionUtil.generateKeyPair();
|
||||||
|
|
||||||
@@ -40,6 +50,7 @@ public class FastLoginBukkit extends JavaPlugin {
|
|||||||
private final Set<String> enabledPremium = Sets.newConcurrentHashSet();
|
private final Set<String> enabledPremium = Sets.newConcurrentHashSet();
|
||||||
|
|
||||||
private boolean bungeeCord;
|
private boolean bungeeCord;
|
||||||
|
private Storage storage;
|
||||||
|
|
||||||
//this map is thread-safe for async access (Packet Listener)
|
//this map is thread-safe for async access (Packet Listener)
|
||||||
//SafeCacheBuilder is used in order to be version independent
|
//SafeCacheBuilder is used in order to be version independent
|
||||||
@@ -63,7 +74,6 @@ public class FastLoginBukkit extends JavaPlugin {
|
|||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
saveDefaultConfig();
|
saveDefaultConfig();
|
||||||
|
|
||||||
bungeeCord = Bukkit.spigot().getConfig().getBoolean("settings.bungeecord");
|
|
||||||
if (getServer().getOnlineMode()) {
|
if (getServer().getOnlineMode()) {
|
||||||
//we need to require offline to prevent a session request for a offline player
|
//we need to require offline to prevent a session request for a offline player
|
||||||
getLogger().severe("Server have to be in offline mode");
|
getLogger().severe("Server have to be in offline mode");
|
||||||
@@ -71,18 +81,50 @@ public class FastLoginBukkit extends JavaPlugin {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerHooks();
|
bungeeCord = Bukkit.spigot().getConfig().getBoolean("settings.bungeecord");
|
||||||
|
boolean hookFound = registerHooks();
|
||||||
|
if (bungeeCord) {
|
||||||
|
getLogger().info("BungeeCord setting detected. No auth plugin is required");
|
||||||
|
} else if (!hookFound) {
|
||||||
|
getLogger().info("No auth plugin were found and bungeecord is deactivated. "
|
||||||
|
+ "Either one or both of the checks have to pass in order to use this plugin");
|
||||||
|
setEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//register listeners on success
|
if (bungeeCord) {
|
||||||
if (getServer().getPluginManager().isPluginEnabled("ProtocolSupport")) {
|
//check for incoming messages from the bungeecord version of this plugin
|
||||||
getServer().getPluginManager().registerEvents(new ProtocolSupportListener(this), this);
|
getServer().getMessenger().registerIncomingPluginChannel(this, getName(), new BungeeCordListener(this));
|
||||||
|
getServer().getMessenger().registerOutgoingPluginChannel(this, getName());
|
||||||
|
//register listeners on success
|
||||||
} else {
|
} else {
|
||||||
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
String driver = getConfig().getString("driver");
|
||||||
|
String host = getConfig().getString("host", "");
|
||||||
|
int port = getConfig().getInt("port", 3306);
|
||||||
|
String database = getConfig().getString("database");
|
||||||
|
|
||||||
//we are performing HTTP request on these so run it async (seperate from the Netty IO threads)
|
String username = getConfig().getString("username", "");
|
||||||
AsynchronousManager asynchronousManager = protocolManager.getAsynchronousManager();
|
String password = getConfig().getString("password", "");
|
||||||
asynchronousManager.registerAsyncHandler(new StartPacketListener(this, protocolManager)).start();
|
|
||||||
asynchronousManager.registerAsyncHandler(new EncryptionPacketListener(this, protocolManager)).start();
|
this.storage = new Storage(this, driver, host, port, database, username, password);
|
||||||
|
try {
|
||||||
|
storage.createTables();
|
||||||
|
} catch (SQLException sqlEx) {
|
||||||
|
getLogger().log(Level.SEVERE, "Failed to create database tables. Disabling plugin...", sqlEx);
|
||||||
|
setEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getServer().getPluginManager().isPluginEnabled("ProtocolSupport")) {
|
||||||
|
getServer().getPluginManager().registerEvents(new ProtocolSupportListener(this), this);
|
||||||
|
} else {
|
||||||
|
ProtocolManager protocolManager = ProtocolLibrary.getProtocolManager();
|
||||||
|
|
||||||
|
//we are performing HTTP request on these so run it async (seperate from the Netty IO threads)
|
||||||
|
AsynchronousManager asynchronousManager = protocolManager.getAsynchronousManager();
|
||||||
|
asynchronousManager.registerAsyncHandler(new StartPacketListener(this, protocolManager)).start();
|
||||||
|
asynchronousManager.registerAsyncHandler(new EncryptionPacketListener(this, protocolManager)).start();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getServer().getPluginManager().registerEvents(new BukkitJoinListener(this), this);
|
getServer().getPluginManager().registerEvents(new BukkitJoinListener(this), this);
|
||||||
@@ -90,24 +132,21 @@ public class FastLoginBukkit extends JavaPlugin {
|
|||||||
//register commands using a unique name
|
//register commands using a unique name
|
||||||
getCommand("premium").setExecutor(new PremiumCommand(this));
|
getCommand("premium").setExecutor(new PremiumCommand(this));
|
||||||
getCommand("cracked").setExecutor(new CrackedCommand(this));
|
getCommand("cracked").setExecutor(new CrackedCommand(this));
|
||||||
|
|
||||||
if (bungeeCord) {
|
|
||||||
//check for incoming messages from the bungeecord version of this plugin
|
|
||||||
getServer().getMessenger().registerIncomingPluginChannel(this, getName(), new BungeeCordListener(this));
|
|
||||||
getServer().getMessenger().registerOutgoingPluginChannel(this, getName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
//clean up
|
//clean up
|
||||||
session.clear();
|
session.clear();
|
||||||
enabledPremium.clear();
|
|
||||||
|
|
||||||
//remove old blacklists
|
//remove old blacklists
|
||||||
for (Player player : getServer().getOnlinePlayers()) {
|
for (Player player : getServer().getOnlinePlayers()) {
|
||||||
player.removeMetadata(getName(), this);
|
player.removeMetadata(getName(), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (storage != null) {
|
||||||
|
storage.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String generateStringPassword() {
|
public String generateStringPassword() {
|
||||||
@@ -143,8 +182,8 @@ public class FastLoginBukkit extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the auth plugin hook in order to interact with the plugins.
|
* Gets the auth plugin hook in order to interact with the plugins. This can be null if no supporting auth plugin
|
||||||
* This can be null if no supporting auth plugin was found.
|
* was found.
|
||||||
*
|
*
|
||||||
* @return interface to any supported auth plugin
|
* @return interface to any supported auth plugin
|
||||||
*/
|
*/
|
||||||
@@ -153,8 +192,7 @@ public class FastLoginBukkit extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the a connection in order to access important
|
* Gets the a connection in order to access important features from the Mojang API.
|
||||||
* features from the Mojang API.
|
|
||||||
*
|
*
|
||||||
* @return the connector instance
|
* @return the connector instance
|
||||||
*/
|
*/
|
||||||
|
@@ -0,0 +1,74 @@
|
|||||||
|
package com.github.games647.fastlogin.bukkit;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class PlayerProfile {
|
||||||
|
|
||||||
|
private final UUID uuid;
|
||||||
|
private final String playerName;
|
||||||
|
|
||||||
|
private long userId;
|
||||||
|
|
||||||
|
private boolean premium;
|
||||||
|
private String lastIp;
|
||||||
|
private long lastLogin;
|
||||||
|
|
||||||
|
public PlayerProfile(long userId, UUID uuid, String playerName, boolean premium
|
||||||
|
, String lastIp, long lastLogin) {
|
||||||
|
this.userId = userId;
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.playerName = playerName;
|
||||||
|
this.premium = premium;
|
||||||
|
this.lastIp = lastIp;
|
||||||
|
this.lastLogin = lastLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerProfile(UUID uuid, String playerName, boolean premium, String lastIp) {
|
||||||
|
this.userId = -1;
|
||||||
|
|
||||||
|
this.uuid = uuid;
|
||||||
|
this.playerName = playerName;
|
||||||
|
this.premium = premium;
|
||||||
|
this.lastIp = lastIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized long getUserId() {
|
||||||
|
return userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized void setUserId(long generatedId) {
|
||||||
|
this.userId = generatedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UUID getUuid() {
|
||||||
|
return uuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPlayerName() {
|
||||||
|
return playerName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPremium() {
|
||||||
|
return premium;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPremium(boolean premium) {
|
||||||
|
this.premium = premium;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastIp() {
|
||||||
|
return lastIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastIp(String lastIp) {
|
||||||
|
this.lastIp = lastIp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastLogin() {
|
||||||
|
return lastLogin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLastLogin(long lastLogin) {
|
||||||
|
this.lastLogin = lastLogin;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,178 @@
|
|||||||
|
package com.github.games647.fastlogin.bukkit;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.utility.SafeCacheBuilder;
|
||||||
|
import com.google.common.cache.CacheLoader;
|
||||||
|
import com.zaxxer.hikari.HikariConfig;
|
||||||
|
import com.zaxxer.hikari.HikariDataSource;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
public class Storage {
|
||||||
|
|
||||||
|
private static final String PREMIUM_TABLE = "premium";
|
||||||
|
|
||||||
|
private final ConcurrentMap<String, PlayerProfile> profileCache = SafeCacheBuilder
|
||||||
|
.<String, PlayerProfile>newBuilder()
|
||||||
|
.concurrencyLevel(20)
|
||||||
|
.expireAfterAccess(30, TimeUnit.MINUTES)
|
||||||
|
.build(new CacheLoader<String, PlayerProfile>() {
|
||||||
|
@Override
|
||||||
|
public PlayerProfile load(String key) throws Exception {
|
||||||
|
//should be fetched manually
|
||||||
|
throw new UnsupportedOperationException("Not supported yet.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
private final HikariDataSource dataSource;
|
||||||
|
private final FastLoginBukkit plugin;
|
||||||
|
|
||||||
|
public Storage(FastLoginBukkit plugin, String driver, String host, int port, String databasePath
|
||||||
|
, String user, String pass) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
|
||||||
|
HikariConfig databaseConfig = new HikariConfig();
|
||||||
|
databaseConfig.setUsername(user);
|
||||||
|
databaseConfig.setPassword(pass);
|
||||||
|
databaseConfig.setDriverClassName(driver);
|
||||||
|
|
||||||
|
databasePath = databasePath.replace("{pluginDir}", plugin.getDataFolder().getAbsolutePath());
|
||||||
|
|
||||||
|
String jdbcUrl = "jdbc:";
|
||||||
|
if (driver.contains("sqlite")) {
|
||||||
|
jdbcUrl += "sqlite" + "://" + databasePath;
|
||||||
|
databaseConfig.setConnectionTestQuery("SELECT 1");
|
||||||
|
} else {
|
||||||
|
jdbcUrl += "mysql" + "://" + host + ':' + port + '/' + databasePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
databaseConfig.setJdbcUrl(jdbcUrl);
|
||||||
|
this.dataSource = new HikariDataSource(databaseConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createTables() throws SQLException {
|
||||||
|
Connection con = null;
|
||||||
|
try {
|
||||||
|
con = dataSource.getConnection();
|
||||||
|
Statement statement = con.createStatement();
|
||||||
|
String createDataStmt = "CREATE TABLE IF NOT EXISTS " + PREMIUM_TABLE + " ("
|
||||||
|
+ "`UserID` INTEGER PRIMARY KEY AUTO_INCREMENT, "
|
||||||
|
+ "`UUID` CHAR(36) NOT NULL, "
|
||||||
|
+ "`Name` VARCHAR(16) NOT NULL, "
|
||||||
|
+ "`Premium` BOOLEAN NOT NULL, "
|
||||||
|
+ "`LastIp` VARCHAR(255) NOT NULL, "
|
||||||
|
+ "`LastLogin` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, "
|
||||||
|
+ "UNIQUE (`UUID`), "
|
||||||
|
//the premium shouldn't steal the cracked account by changing the name
|
||||||
|
+ "UNIQUE (`Name`) "
|
||||||
|
+ ")";
|
||||||
|
|
||||||
|
if (dataSource.getJdbcUrl().contains("sqlite")) {
|
||||||
|
createDataStmt = createDataStmt.replace("AUTO_INCREMENT", "AUTOINCREMENT");
|
||||||
|
}
|
||||||
|
|
||||||
|
statement.executeUpdate(createDataStmt);
|
||||||
|
} finally {
|
||||||
|
closeQuietly(con);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerProfile getProfile(String name, boolean fetch) {
|
||||||
|
if (profileCache.containsKey(name)) {
|
||||||
|
return profileCache.get(name);
|
||||||
|
} else if (fetch) {
|
||||||
|
Connection con = null;
|
||||||
|
try {
|
||||||
|
con = dataSource.getConnection();
|
||||||
|
PreparedStatement loadStatement = con.prepareStatement("SELECT * FROM " + PREMIUM_TABLE
|
||||||
|
+ " WHERE `Name`=? LIMIT 1");
|
||||||
|
loadStatement.setString(1, name);
|
||||||
|
|
||||||
|
ResultSet resultSet = loadStatement.executeQuery();
|
||||||
|
if (resultSet.next()) {
|
||||||
|
long userId = resultSet.getInt(1);
|
||||||
|
UUID uuid = FastLoginBukkit.parseId(resultSet.getString(2));
|
||||||
|
// String name = resultSet.getString(3);
|
||||||
|
boolean premium = resultSet.getBoolean(4);
|
||||||
|
String lastIp = resultSet.getString(5);
|
||||||
|
long lastLogin = resultSet.getTimestamp(6).getTime();
|
||||||
|
PlayerProfile playerProfile = new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin);
|
||||||
|
profileCache.put(name, playerProfile);
|
||||||
|
return playerProfile;
|
||||||
|
}
|
||||||
|
} catch (SQLException sqlEx) {
|
||||||
|
plugin.getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx);
|
||||||
|
} finally {
|
||||||
|
closeQuietly(con);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean save(PlayerProfile playerProfile) {
|
||||||
|
Connection con = null;
|
||||||
|
try {
|
||||||
|
con = dataSource.getConnection();
|
||||||
|
|
||||||
|
if (playerProfile.getUserId() == -1) {
|
||||||
|
PreparedStatement saveStatement = con.prepareStatement("INSERT INTO " + PREMIUM_TABLE
|
||||||
|
+ " (UUID, Name, Premium, LastIp) VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
|
||||||
|
|
||||||
|
saveStatement.setString(1, playerProfile.getUuid().toString().replace("-", ""));
|
||||||
|
saveStatement.setString(2, playerProfile.getPlayerName());
|
||||||
|
saveStatement.setBoolean(3, playerProfile.isPremium());
|
||||||
|
saveStatement.setString(4, playerProfile.getLastIp());
|
||||||
|
saveStatement.execute();
|
||||||
|
|
||||||
|
ResultSet generatedKeys = saveStatement.getGeneratedKeys();
|
||||||
|
if (generatedKeys != null && generatedKeys.next()) {
|
||||||
|
playerProfile.setUserId(generatedKeys.getInt(1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PreparedStatement saveStatement = con.prepareStatement("UPDATE " + PREMIUM_TABLE
|
||||||
|
+ " SET UUID=?, Name=?, Premium=?, LastIp=?, LastLogin=? WHERE UserID=?");
|
||||||
|
|
||||||
|
saveStatement.setString(1, playerProfile.getUuid().toString().replace("-", ""));
|
||||||
|
saveStatement.setString(2, playerProfile.getPlayerName());
|
||||||
|
saveStatement.setBoolean(3, playerProfile.isPremium());
|
||||||
|
saveStatement.setString(4, playerProfile.getLastIp());
|
||||||
|
saveStatement.setTimestamp(5, new Timestamp(playerProfile.getLastLogin()));
|
||||||
|
|
||||||
|
saveStatement.setLong(6, playerProfile.getUserId());
|
||||||
|
saveStatement.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
plugin.getLogger().log(Level.SEVERE, "Failed to save playerProfile", ex);
|
||||||
|
} finally {
|
||||||
|
closeQuietly(con);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() {
|
||||||
|
dataSource.close();
|
||||||
|
profileCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeQuietly(Connection con) {
|
||||||
|
if (con != null) {
|
||||||
|
try {
|
||||||
|
con.close();
|
||||||
|
} catch (SQLException sqlEx) {
|
||||||
|
plugin.getLogger().log(Level.SEVERE, "Failed to close connection", sqlEx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -53,12 +53,16 @@ forwardSkin: true
|
|||||||
|
|
||||||
# Database configuration
|
# Database configuration
|
||||||
# Recommened is the use of MariaDB (a better version of MySQL)
|
# Recommened is the use of MariaDB (a better version of MySQL)
|
||||||
driver: mysql
|
|
||||||
host: localhost
|
# Single file SQLite database
|
||||||
port: 3306
|
driver: org.sqlite.JDBC
|
||||||
database: FastLogin
|
# File location
|
||||||
username: myUser
|
database: '{pluginDir}/FastLogin.db'
|
||||||
password: myPassword
|
|
||||||
# If you use an existing database which will be used by other programs too
|
# MySQL and SQLite
|
||||||
# you define here a prefix, to prevent conflicts.
|
#driver: com.mysql.jdbc.Driver
|
||||||
tablePrefix: ''
|
#host: localhost
|
||||||
|
#port: 3306
|
||||||
|
#database: FastLogin
|
||||||
|
#username: myUser
|
||||||
|
#password: myPassword
|
@@ -30,6 +30,7 @@
|
|||||||
<includes>
|
<includes>
|
||||||
<include>${project.groupId}:*</include>
|
<include>${project.groupId}:*</include>
|
||||||
<include>com.zaxxer:HikariCP</include>
|
<include>com.zaxxer:HikariCP</include>
|
||||||
|
<include>org.slf4j:*</include>
|
||||||
</includes>
|
</includes>
|
||||||
</artifactSet>
|
</artifactSet>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
Reference in New Issue
Block a user