forked from TuxCoding/FastLogin
Add storage support for BungeeCord
This commit is contained in:
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user