Add storage support for BungeeCord

This commit is contained in:
games647
2016-04-27 16:56:21 +02:00
parent 11cc4eabc0
commit 57a59045ce
7 changed files with 391 additions and 28 deletions

View File

@ -32,6 +32,8 @@ import org.bukkit.plugin.java.JavaPlugin;
* This plugin checks if a player has a paid account and if so tries to skip offline mode authentication.
*/
public class FastLoginBukkit extends JavaPlugin {
private static final int WORKER_THREADS = 5;
public static UUID parseId(String withoutDashes) {
return UUID.fromString(withoutDashes.substring(0, 8)
@ -44,7 +46,6 @@ public class FastLoginBukkit extends JavaPlugin {
//provide a immutable key pair to be thread safe | used for encrypting and decrypting traffic
private final KeyPair keyPair = EncryptionUtil.generateKeyPair();
private static final int WORKER_THREADS = 5;
private boolean bungeeCord;
private Storage storage;

View File

@ -37,7 +37,7 @@ public class ProtocolSupportListener implements Listener {
PlayerProfile playerProfile = plugin.getStorage().getProfile(username, true);
if (playerProfile != null) {
//user not exists in the db
if (playerProfile.getUserId() == -1) {
if (!playerProfile.isPremium() && playerProfile.getUserId() == -1) {
BukkitAuthPlugin authPlugin = plugin.getAuthPlugin();
if (plugin.getConfig().getBoolean("autoRegister") && !authPlugin.isRegistered(username)) {
UUID premiumUUID = plugin.getApiConnector().getPremiumUUID(username);

View File

@ -78,7 +78,7 @@ public class StartPacketListener extends PacketAdapter {
PlayerProfile playerProfile = plugin.getStorage().getProfile(username, true);
if (playerProfile != null) {
//user not exists in the db
if (playerProfile.getUserId() == -1) {
if (!playerProfile.isPremium() && playerProfile.getUserId() == -1) {
BukkitAuthPlugin authPlugin = plugin.getAuthPlugin();
if (plugin.getConfig().getBoolean("autoRegister") && !authPlugin.isRegistered(username)) {
UUID premiumUUID = plugin.getApiConnector().getPremiumUUID(username);

View File

@ -2,23 +2,70 @@ package com.github.games647.fastlogin.bungee;
import com.github.games647.fastlogin.bungee.hooks.BungeeAuthHook;
import com.github.games647.fastlogin.bungee.hooks.BungeeAuthPlugin;
import com.google.common.collect.Sets;
import java.util.Set;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.util.UUID;
import java.util.logging.Level;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration;
/**
* BungeeCord version of FastLogin. This plugin keeps track
* on online mode connections.
* BungeeCord version of FastLogin. This plugin keeps track on online mode connections.
*/
public class FastLoginBungee extends Plugin {
private final Set<String> enabledPremium = Sets.newConcurrentHashSet();
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));
}
private BungeeAuthPlugin bungeeAuthPlugin;
private Storage storage;
private Configuration configuration;
@Override
public void onEnable() {
File configFile = new File(getDataFolder(), "config.yml");
if (!configFile.exists()) {
try (InputStream in = getResourceAsStream("config.yml")) {
Files.copy(in, configFile.toPath());
} catch (IOException ioExc) {
getLogger().log(Level.SEVERE, "Error saving default config", ioExc);
}
}
try {
configuration = ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile);
String driver = configuration.getString("storage.driver");
String host = configuration.getString("storage.host", "");
int port = configuration.getInt("storage.port", 3306);
String database = configuration.getString("storage.database");
String username = configuration.getString("storage.username", "");
String password = configuration.getString("storage.password", "");
storage = new Storage(this, driver, host, port, database, username, password);
try {
storage.createTables();
} catch (Exception ex) {
getLogger().log(Level.SEVERE, "Failed to setup database. Disabling plugin...", ex);
return;
}
} catch (IOException ioExc) {
getLogger().log(Level.SEVERE, "Error loading config. Disabling plugin...", ioExc);
return;
}
//events
getProxy().getPluginManager().registerListener(this, new PlayerConnectionListener(this));
@ -28,13 +75,19 @@ public class FastLoginBungee extends Plugin {
registerHook();
}
/**
* A set of players who want to use fastlogin
*
* @return all player which want to be in onlinemode
*/
public Set<String> getEnabledPremium() {
return enabledPremium;
@Override
public void onDisable() {
if (storage != null) {
storage.close();
}
}
public Configuration getConfiguration() {
return configuration;
}
public Storage getStorage() {
return storage;
}
/**

View File

@ -6,10 +6,8 @@ import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import java.util.UUID;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.connection.Server;
@ -26,7 +24,7 @@ import net.md_5.bungee.event.EventHandler;
*/
public class PlayerConnectionListener implements Listener {
private final FastLoginBungee plugin;
protected final FastLoginBungee plugin;
public PlayerConnectionListener(FastLoginBungee plugin) {
this.plugin = plugin;
@ -41,8 +39,22 @@ public class PlayerConnectionListener implements Listener {
PendingConnection connection = preLoginEvent.getConnection();
String username = connection.getName();
//just enable it for activated users
if (plugin.getEnabledPremium().contains(username)) {
connection.setOnlineMode(true);
PlayerProfile playerProfile = plugin.getStorage().getProfile(username, true);
if (playerProfile != null) {
//user not exists in the db
if (!playerProfile.isPremium() && playerProfile.getUserId() == -1) {
// BungeeAuthPlugin authPlugin = plugin.getBungeeAuthPlugin();
// if (plugin.getConfiguration().getBoolean("autoRegister") && !authPlugin.isRegistered(username)) {
// UUID premiumUUID = plugin.getApiConnector().getPremiumUUID(username);
// if (premiumUUID != null) {
// plugin.getLogger().log(Level.FINER, "Player {0} uses a premium username", username);
// connection.setOnlineMode(true);
// }
// }
} else if (playerProfile.isPremium()) {
connection.setOnlineMode(true);
}
}
}
@ -70,9 +82,6 @@ public class PlayerConnectionListener implements Listener {
BungeeAuthPlugin authPlugin = plugin.getBungeeAuthPlugin();
if (authPlugin != null) {
authPlugin.forceLogin(player);
BaseComponent loginMessage = new TextComponent("Auto login");
loginMessage.setColor(ChatColor.DARK_GREEN);
player.sendMessage(loginMessage);
}
}
}
@ -94,11 +103,29 @@ public class PlayerConnectionListener implements Listener {
ByteArrayDataInput dataInput = ByteStreams.newDataInput(data);
String subchannel = dataInput.readUTF();
if ("ON".equals(subchannel)) {
ProxiedPlayer forPlayer = (ProxiedPlayer) pluginMessageEvent.getReceiver();
plugin.getEnabledPremium().add(forPlayer.getName());
final ProxiedPlayer forPlayer = (ProxiedPlayer) pluginMessageEvent.getReceiver();
ProxyServer.getInstance().getScheduler().runAsync(plugin, new Runnable() {
@Override
public void run() {
PlayerProfile playerProfile = plugin.getStorage().getProfile(forPlayer.getName(), true);
playerProfile.setPremium(true);
//todo: set uuid
plugin.getStorage().save(playerProfile);
}
});
} else if ("OFF".equals(subchannel)) {
ProxiedPlayer forPlayer = (ProxiedPlayer) pluginMessageEvent.getReceiver();
plugin.getEnabledPremium().remove(forPlayer.getName());
final ProxiedPlayer forPlayer = (ProxiedPlayer) pluginMessageEvent.getReceiver();
ProxyServer.getInstance().getScheduler().runAsync(plugin, new Runnable() {
@Override
public void run() {
PlayerProfile playerProfile = plugin.getStorage().getProfile(forPlayer.getName(), true);
playerProfile.setPremium(false);
playerProfile.setUuid(null);
//todo: set uuid
plugin.getStorage().save(playerProfile);
}
});
}
}
}

View File

@ -0,0 +1,78 @@
package com.github.games647.fastlogin.bungee;
import java.util.UUID;
public class PlayerProfile {
private final String playerName;
private long userId;
private UUID uuid;
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 String getPlayerName() {
return playerName;
}
public synchronized long getUserId() {
return userId;
}
protected synchronized void setUserId(long generatedId) {
this.userId = generatedId;
}
public synchronized UUID getUuid() {
return uuid;
}
public synchronized void setUuid(UUID uuid) {
this.uuid = uuid;
}
public synchronized boolean isPremium() {
return premium;
}
public synchronized void setPremium(boolean premium) {
this.premium = premium;
}
public synchronized String getLastIp() {
return lastIp;
}
public synchronized void setLastIp(String lastIp) {
this.lastIp = lastIp;
}
public long getLastLogin() {
return lastLogin;
}
public synchronized void setLastLogin(long lastLogin) {
this.lastLogin = lastLogin;
}
}

View File

@ -0,0 +1,204 @@
package com.github.games647.fastlogin.bungee;
import com.google.common.cache.CacheBuilder;
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.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 = CacheBuilder
.<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.");
}
}).asMap();
private final HikariDataSource dataSource;
private final FastLoginBungee plugin;
public Storage(FastLoginBungee 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), "
+ "`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);
String unparsedUUID = resultSet.getString(2);
UUID uuid;
if (unparsedUUID == null) {
uuid = null;
} else {
uuid = FastLoginBungee.parseId(unparsedUUID);
}
// 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;
} else {
PlayerProfile crackedProfile = new PlayerProfile(null, name, false, "");
profileCache.put(name, crackedProfile);
return crackedProfile;
}
} catch (SQLException sqlEx) {
plugin.getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx);
} finally {
closeQuietly(con);
}
}
return null;
}
// public PlayerProfile getProfile(UUID uuid, boolean fetch) {
//todo
// }
public boolean save(PlayerProfile playerProfile) {
Connection con = null;
try {
con = dataSource.getConnection();
UUID uuid = playerProfile.getUuid();
if (playerProfile.getUserId() == -1) {
PreparedStatement saveStatement = con.prepareStatement("INSERT INTO " + PREMIUM_TABLE
+ " (UUID, Name, Premium, LastIp) VALUES (?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
if (uuid == null) {
saveStatement.setString(1, null);
} else {
saveStatement.setString(1, uuid.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=CURRENT_TIMESTAMP WHERE UserID=?");
if (uuid == null) {
saveStatement.setString(1, null);
} else {
saveStatement.setString(1, uuid.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(5, 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);
}
}
}
}