Clean up using IDE inspections

This commit is contained in:
games647
2017-09-21 15:00:39 +02:00
parent 5bf9b05d30
commit 109508dae6
21 changed files with 164 additions and 313 deletions

25
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,25 @@
#### Make sure you are running the latest build of the plugin and checked for duplicate issues!
### What behaviour is observed:
What happened?
### What behaviour is expected:
What did you expect?
### Steps/models to reproduce:
The actions that cause the issue
### Plugin list:
This can be found by running `/pl`
### Environment description
Standalone server/Bungeecord network, SQLite/MySql, ...
### Plugin version:
This can be found by running `/version plugin-name`
### Error Log:
[Hastebin](https://hastebin.com/) / [Gist](https://gist.github.com/) link of the error or stacktrace (if any)
### Configuration:
[Hastebin](https://hastebin.com/) / [Gist](https://gist.github.com/) link of your config.yml file (remember to delete any sensitive data)

19
.gitignore vendored
View File

@ -3,22 +3,21 @@
/.project /.project
/.settings /.settings
# netbeans # NetBeans
/nbproject */nbproject
nb-configuration.xml nb-configuration.xml
/bukkit/nbproject/
# maven # maven
/target */target
# vim # vim
.*.sw[a-p] .*.sw[a-p]
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml # virtual machine crash logs, see https://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid* hs_err_pid*
# various other potential build files # various other potential build files
/build */build/
/bin /bin
/dist /dist
/manifest.mf /manifest.mf
@ -27,7 +26,7 @@ hs_err_pid*
# Mac filesystem dust # Mac filesystem dust
.DS_Store .DS_Store
# intellij # IntelliJ
*.iml *.iml
*.ipr *.ipr
*.iws *.iws
@ -41,9 +40,3 @@ gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) # Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar !gradle-wrapper.jar
# Project module targets
bukkit/target
universal/target
bungee/target
core/target

View File

@ -1,4 +1,4 @@
# Use https://travis-ci.org/ for automatic tests # Use https://travis-ci.org/ for automatic testing
# speed up testing https://blog.travis-ci.com/2014-12-17-faster-builds-with-container-based-infrastructure/ # speed up testing https://blog.travis-ci.com/2014-12-17-faster-builds-with-container-based-infrastructure/
sudo: false sudo: false
@ -8,5 +8,4 @@ language: java
script: mvn compile test script: mvn compile test
# We run on 8
jdk: [oraclejdk8] jdk: [oraclejdk8]

View File

@ -1,5 +1,7 @@
### 1.11 ### 1.11
* Drop support for deprecated AuthMe API
* Remove legacy database migration code
* Drop support for RoyalAuth, because it doesn't seem to be supported anymore * Drop support for RoyalAuth, because it doesn't seem to be supported anymore
* Clean up client-server encryption -> use only one cipher per connection, simplify code * Clean up client-server encryption -> use only one cipher per connection, simplify code

102
README.md
View File

@ -28,7 +28,6 @@ So they don't need to enter passwords. This is also called auto login (auto-logi
### Commands: ### Commands:
* /premium [player] Label the invoker or the argument as paid account * /premium [player] Label the invoker or the argument as paid account
* /cracked [player] Label the invoker or the argument as cracked account * /cracked [player] Label the invoker or the argument as cracked account
* /importdb <autoIn/bpa/eldzi> <mysql/sqlite> [host:port] [database] [username] [password] - Imports the database from another plugin
### Permissions: ### Permissions:
* fastlogin.bukkit.command.premium * fastlogin.bukkit.command.premium
@ -39,7 +38,7 @@ So they don't need to enter passwords. This is also called auto login (auto-logi
### Requirements: ### Requirements:
* Plugin: [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/) or [ProtocolSupport](https://www.spigotmc.org/resources/protocolsupport.7201/) * Plugin: [ProtocolLib](https://www.spigotmc.org/resources/protocollib.1997/) or [ProtocolSupport](https://www.spigotmc.org/resources/protocolsupport.7201/)
* Tested Bukkit/[Spigot](https://www.spigotmc.org) 1.9 (could also work with other versions) * Tested [Spigot](https://www.spigotmc.org) 1.8+ (could also work with other versions)
* Java 8+ * Java 8+
* Run Spigot and/or BungeeCord/Waterfall in offline mode (see server.properties or config.yml) * Run Spigot and/or BungeeCord/Waterfall in offline mode (see server.properties or config.yml)
* An auth plugin. Supported plugins * An auth plugin. Supported plugins
@ -58,10 +57,6 @@ So they don't need to enter passwords. This is also called auto login (auto-logi
* [BungeeAuth](https://www.spigotmc.org/resources/bungeeauth.493/) * [BungeeAuth](https://www.spigotmc.org/resources/bungeeauth.493/)
### Downloads
https://www.spigotmc.org/resources/fastlogin.14153/history
*** ***
### How to install ### How to install
@ -84,98 +79,3 @@ Put your stats id from the BungeeCord config into this file
7. Set your proxy (BungeeCord) in offline mode by setting the value onlinemode in your config.yml to false 7. Set your proxy (BungeeCord) in offline mode by setting the value onlinemode in your config.yml to false
8. You should *always* firewall your spigot server that it's only accessible through BungeeCord https://www.spigotmc.org/wiki/bungeecord-installation/#post-installation 8. You should *always* firewall your spigot server that it's only accessible through BungeeCord https://www.spigotmc.org/wiki/bungeecord-installation/#post-installation
9. (BungeeCord doesn't support SQLite per default, so you should change the configuration to MySQL or MariaDB) 9. (BungeeCord doesn't support SQLite per default, so you should change the configuration to MySQL or MariaDB)
***
### FAQ
#### Index
1. [How does Minecraft logins work?](#how-does-minecraft-logins-work)
2. [How does this plugin work?](#how-does-this-plugin-work)
3. [Why does the plugin require offline mode?](#why-does-the-plugin-require-offline-mode)
4. [Can cracked player join with premium usernames?](#can-cracked-player-join-with-premium-usernames)
5. [Why do players have to invoke a command?](#why-do-players-have-to-invoke-a-command)
6. [What happens if a paid account joins with a used username?](#what-happens-if-a-paid-account-joins-with-a-used-username)
7. [Does the plugin have BungeeCord support?](#does-the-plugin-have-bungeecord-support)
8. [Could premium players have a premium UUID and Skin?](#could-premium-players-have-a-premium-uuid-and-skin)
9. [Is this plugin compatible with Cauldron?](#is-this-plugin-compatible-with-cauldron)
#### How does minecraft logins work?
###### Online Mode
1. Client -> Server: I want to login, here is my username
2. Server -> Client: Okay. I'm in online mode so here is my public key for encryption and my server id
3. Client -> Mojang: I'm player "xyz". I want to join a server with that server id
4. Mojang -> Client: Session data checked. You can continue
5. Client -> Server: I received a successful response from Mojang. Here our shared secret key
6. Server -> Mojang: Does the player "xyz" with this shared secret key has a valid account to join me?
7. Mojang -> Server: Yes, the player has the following additionally properties (UUID, Skin)
8. Client and Server: encrypt all following communication packet
9. Server -> Client: Everything checked you can play now
###### Offline Mode
In offline mode step 2-7 is skipped. So a login request is directly followed by 8.
###### More details
http://wiki.vg/Protocol#Login
#### How does this plugin work?
By using ProtocolLib, this plugin works as a proxy between the client and server. This plugin will fake that the server
runs in online mode. It does everything an online mode server would do. This will be for example, generating keys or
checking for valid sessions. Because everything is the same compared to an offline mode login after an encrypted
connection, we will intercept only **login** packets of **premium** players.
1. Player is connecting to the server.
2. Plugin checks if the username we received activated the fast login method (i.e. using command)
3. Run a check if the username is currently used by a paid account.
(We don't know yet if the client connecting is premium)
4. Request an Mojang Session Server authentication
5. On response check if all data is correct
6. Encrypt the connection
7. On success intercept all related login packets and fake a new login packet as a normal offline login
#### Why does the plugin require offline mode?
1. As you can see in the question "how does minecraft login works", offline mode is equivalent to online mode except of
the encryption and session checks on login. So we can intercept and cancel the first packets for premium players and
enable an encrypted connection. Then we send a new fake packet in order to pretend that this a new login request from
a offline mode player. The server will handle the rest.
2. Some plugins check if the server is in online mode. If so, they could process the real offline (cracked) accounts
incorrectly. For example, a plugin tries to fetch the UUID from Mojang, but the name of the player is not associated to
a paid account.
3. Servers, who allow cracked players and just speed up logins for premium players, are **already** in offline mode.
#### Can cracked player join with premium usernames?
Yes, indeed. Therefore the command for toggling the fast login method exists.
#### Why do players have to invoke a command?
1. It's a secure way to make sure a person with a paid account cannot steal the account
of a cracked player that has the same username. The player have to proof first that it's his own account.
2. We only receive the username from the player on login. We could check if that username is associated
to a paid account but if we request a online mode login from a cracked player (who uses a username from
a paid account), the player will disconnect with the reason "bad login" or "Invalid session". There is no way to change
that message on the server side (without client modifications), because it's a connection between the Client and the
session-server.
3. If a premium player would skip registration too, a player of a cracked account could later still register the
account and would claim and steal the account from the premium player. Because commands cannot be invoked unless the
player has a account or is logged in, protects this method also premium players
### What happens if a paid account joins with a used username?
The player on the server have to activate the feature of this plugin by command. If a person buys the username
of his own account, it's still secured. A normal offline mode login makes sure he's the owner of the server account
and Mojang account. Then the command can be executed. So someone different cannot steal the account of cracked player
by buying the username.
#### Does the plugin have BungeeCord support?
Yes it has. See the how to install above.
#### Could premium players have a premium UUID and Skin?
Since 0.7 both features are implemented. You can check the config.yml in order to activate it.
#### Is this plugin compatible with Cauldron?
It's not tested yet, but all needed methods also exists in Cauldron so it could work together.
***
### Useful Links:
* [Login Protocol](http://wiki.vg/Protocol#Login)
* [Protocol Encryption](http://wiki.vg/Protocol_Encryption)

View File

@ -65,7 +65,7 @@
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.12-R0.1-SNAPSHOT</version> <version>1.12.2-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>

View File

@ -126,7 +126,7 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
public void sendBungeeActivateMessage(CommandSender sender, String target, boolean activate) { public void sendBungeeActivateMessage(CommandSender sender, String target, boolean activate) {
if (sender instanceof Player) { if (sender instanceof Player) {
notifyBungeeCord((Player) sender, target, activate, sender instanceof Player); notifyBungeeCord((Player) sender, target, activate, true);
} else { } else {
Player firstPlayer = Iterables.getFirst(getServer().getOnlinePlayers(), null); Player firstPlayer = Iterables.getFirst(getServer().getOnlinePlayers(), null);
if (firstPlayer == null) { if (firstPlayer == null) {
@ -134,7 +134,7 @@ public class FastLoginBukkit extends JavaPlugin implements PlatformPlugin<Comman
return; return;
} }
notifyBungeeCord(firstPlayer, target, activate, sender instanceof Player); notifyBungeeCord(firstPlayer, target, activate, false);
} }
} }

View File

@ -9,7 +9,7 @@ import java.io.InputStreamReader;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.List; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -24,41 +24,44 @@ public class MojangApiBukkit extends MojangApiConnector {
private static final String HAS_JOINED_URL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?" + private static final String HAS_JOINED_URL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?" +
"username=%s&serverId=%s"; "username=%s&serverId=%s";
public MojangApiBukkit(Logger logger, List<String> localAddresses, int rateLimit, Map<String, Integer> proxies) { public MojangApiBukkit(Logger logger, Collection<String> localAddresses, int rateLimit
, Map<String, Integer> proxies) {
super(logger, localAddresses, rateLimit, proxies); super(logger, localAddresses, rateLimit, proxies);
} }
@Override @Override
public boolean hasJoinedServer(LoginSession session, String serverId, InetSocketAddress ip) { public boolean hasJoinedServer(LoginSession session, String serverId, InetSocketAddress ip) {
BukkitLoginSession playerSession = (BukkitLoginSession) session; BukkitLoginSession playerSession = (BukkitLoginSession) session;
String url = String.format(HAS_JOINED_URL, playerSession.getUsername(), serverId);
try { try {
String url = String.format(HAS_JOINED_URL, playerSession.getUsername(), serverId);
if (ip != null) { if (ip != null) {
url += "&ip=" + URLEncoder.encode(ip.getAddress().getHostAddress(), "UTF-8"); url += "&ip=" + URLEncoder.encode(ip.getAddress().getHostAddress(), "UTF-8");
} }
HttpURLConnection conn = getConnection(url); HttpURLConnection conn = getConnection(url);
BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
String line = reader.readLine(); String line = reader.readLine();
if (line != null && !"null".equals(line)) { if (line != null && !"null".equals(line)) {
//validate parsing //validate parsing
//http://wiki.vg/Protocol_Encryption#Server //http://wiki.vg/Protocol_Encryption#Server
JSONObject userData = (JSONObject) JSONValue.parseWithException(line); JSONObject userData = (JSONObject) JSONValue.parseWithException(line);
String uuid = (String) userData.get("id"); String uuid = (String) userData.get("id");
playerSession.setUuid(FastLoginCore.parseId(uuid)); playerSession.setUuid(FastLoginCore.parseId(uuid));
JSONArray properties = (JSONArray) userData.get("properties"); JSONArray properties = (JSONArray) userData.get("properties");
JSONObject skinProperty = (JSONObject) properties.get(0); JSONObject skinProperty = (JSONObject) properties.get(0);
String propertyName = (String) skinProperty.get("name"); String propertyName = (String) skinProperty.get("name");
if ("textures".equals(propertyName)) { if ("textures".equals(propertyName)) {
String skinValue = (String) skinProperty.get("value"); String skinValue = (String) skinProperty.get("value");
String signature = (String) skinProperty.get("signature"); String signature = (String) skinProperty.get("signature");
playerSession.setSkin(skinValue, signature); playerSession.setSkin(skinValue, signature);
}
return true;
} }
return true;
} }
} catch (Exception ex) { } catch (Exception ex) {
//catch not only io-exceptions also parse and NPE on unexpected json format //catch not only io-exceptions also parse and NPE on unexpected json format

View File

@ -34,7 +34,7 @@ public class PremiumPlaceholder extends PlaceholderHook {
return null; return null;
} }
public static boolean register(FastLoginBukkit plugin) { public static void register(FastLoginBukkit plugin) {
return PlaceholderAPI.registerPlaceholderHook(plugin, new PremiumPlaceholder(plugin)); PlaceholderAPI.registerPlaceholderHook(plugin, new PremiumPlaceholder(plugin));
} }
} }

View File

@ -20,11 +20,9 @@ public class LogItHook implements AuthPlugin<Player> {
@Override @Override
public boolean forceLogin(Player player) { public boolean forceLogin(Player player) {
SessionManager sessionManager = LogItCore.getInstance().getSessionManager(); SessionManager sessionManager = LogItCore.getInstance().getSessionManager();
if (sessionManager.isSessionAlive(player)) { return sessionManager.isSessionAlive(player)
return true; || sessionManager.startSession(player) == CancelledState.NOT_CANCELLED;
}
return sessionManager.startSession(player) == CancelledState.NOT_CANCELLED;
} }
@Override @Override

View File

@ -24,11 +24,8 @@ public class LoginSecurityHook implements AuthPlugin<Player> {
@Override @Override
public boolean forceLogin(Player player) { public boolean forceLogin(Player player) {
PlayerSession session = LoginSecurity.getSessionManager().getPlayerSession(player); PlayerSession session = LoginSecurity.getSessionManager().getPlayerSession(player);
if (session.isAuthorized()) { return session.isAuthorized() || session.performAction(new LoginAction(AuthService.PLUGIN, plugin)).isSuccess();
return true;
}
return session.performAction(new LoginAction(AuthService.PLUGIN, plugin)).isSuccess();
} }
@Override @Override

View File

@ -52,11 +52,7 @@ public class UltraAuthHook implements AuthPlugin<Player> {
@Override @Override
public boolean forceRegister(Player player, String password) { public boolean forceRegister(Player player, String password) {
UltraAuthAPI.setPlayerPasswordOnline(player, password); UltraAuthAPI.setPlayerPasswordOnline(player, password);
if (PlayerManager.getInstance().checkPlayerPassword(player, password)) { //the register method silents any exception so check if our entry was saved
//the register method silents any exception so check if our entry was saved return PlayerManager.getInstance().checkPlayerPassword(player, password) && forceLogin(player);
return forceLogin(player);
}
return false;
} }
} }

View File

@ -63,15 +63,11 @@ public class xAuthHook implements AuthPlugin<Player> {
//not thread-safe //not thread-safe
Future<Boolean> future = Bukkit.getScheduler().callSyncMethod(xAuthPlugin, () -> { Future<Boolean> future = Bukkit.getScheduler().callSyncMethod(xAuthPlugin, () -> {
xAuthPlayer xAuthPlayer = xAuthPlugin.getPlayerManager().getPlayer(player); xAuthPlayer xAuthPlayer = xAuthPlugin.getPlayerManager().getPlayer(player);
if (xAuthPlayer != null) { //this should run async because the plugin executes a sql query, but the method
//this should run async because the plugin executes a sql query, but the method //accesses non thread-safe collections :(
//accesses non thread-safe collections :( return xAuthPlayer != null
&& xAuthPlugin.getAuthClass(xAuthPlayer).adminRegister(player.getName(), password, null);
return xAuthPlugin.getAuthClass(xAuthPlayer)
.adminRegister(player.getName(), password, null);
}
return false;
}); });
try { try {

View File

@ -1,7 +1,7 @@
package com.github.games647.fastlogin.bungee; package com.github.games647.fastlogin.bungee;
import com.github.games647.fastlogin.bungee.hooks.BungeeAuthHook; import com.github.games647.fastlogin.bungee.hooks.BungeeAuthHook;
import com.github.games647.fastlogin.bungee.listener.PlayerConnectionListener; import com.github.games647.fastlogin.bungee.listener.ConnectionListener;
import com.github.games647.fastlogin.bungee.listener.PluginMessageListener; import com.github.games647.fastlogin.bungee.listener.PluginMessageListener;
import com.github.games647.fastlogin.core.shared.FastLoginCore; import com.github.games647.fastlogin.core.shared.FastLoginCore;
import com.github.games647.fastlogin.core.shared.MojangApiConnector; import com.github.games647.fastlogin.core.shared.MojangApiConnector;
@ -46,7 +46,7 @@ public class FastLoginBungee extends Plugin implements PlatformPlugin<CommandSen
} }
//events //events
getProxy().getPluginManager().registerListener(this, new PlayerConnectionListener(this)); getProxy().getPluginManager().registerListener(this, new ConnectionListener(this));
getProxy().getPluginManager().registerListener(this, new PluginMessageListener(this)); getProxy().getPluginManager().registerListener(this, new PluginMessageListener(this));
//this is required to listen to messages from the server //this is required to listen to messages from the server

View File

@ -4,7 +4,7 @@ import com.github.games647.fastlogin.core.shared.LoginSession;
import com.github.games647.fastlogin.core.shared.MojangApiConnector; import com.github.games647.fastlogin.core.shared.MojangApiConnector;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.util.List; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -12,7 +12,8 @@ import net.md_5.bungee.BungeeCord;
public class MojangApiBungee extends MojangApiConnector { public class MojangApiBungee extends MojangApiConnector {
public MojangApiBungee(Logger logger, List<String> localAddresses, int rateLimit, Map<String, Integer> proxies) { public MojangApiBungee(Logger logger, Collection<String> localAddresses, int rateLimit
, Map<String, Integer> proxies) {
super(logger, localAddresses, rateLimit, proxies); super(logger, localAddresses, rateLimit, proxies);
} }

View File

@ -21,11 +21,8 @@ public class BungeeAuthHook implements AuthPlugin<ProxiedPlayer> {
@Override @Override
public boolean forceLogin(ProxiedPlayer player) { public boolean forceLogin(ProxiedPlayer player) {
String playerName = player.getName(); String playerName = player.getName();
if (Main.plonline.contains(playerName)) { return Main.plonline.contains(playerName) || requestHandler.forceLogin(playerName);
return true;
}
return requestHandler.forceLogin(playerName);
} }
@Override @Override

View File

@ -31,11 +31,11 @@ import net.md_5.bungee.event.EventPriority;
* plugin message to the Bukkit version of this plugin in * plugin message to the Bukkit version of this plugin in
* order to clear that the connection is online mode. * order to clear that the connection is online mode.
*/ */
public class PlayerConnectionListener implements Listener { public class ConnectionListener implements Listener {
private final FastLoginBungee plugin; private final FastLoginBungee plugin;
public PlayerConnectionListener(FastLoginBungee plugin) { public ConnectionListener(FastLoginBungee plugin) {
this.plugin = plugin; this.plugin = plugin;
} }

View File

@ -54,11 +54,8 @@ public class ForceLoginTask extends ForceLoginManagement<ProxiedPlayer, CommandS
@Override @Override
public boolean forceRegister(ProxiedPlayer player) { public boolean forceRegister(ProxiedPlayer player) {
if (session.isAlreadyLogged()) { return session.isAlreadyLogged() || super.forceRegister(player);
return true;
}
return super.forceRegister(player);
} }
@Override @Override

View File

@ -62,12 +62,8 @@ public class AuthStorage {
} }
public void createTables() throws SQLException { public void createTables() throws SQLException {
Connection con = null; try (Connection con = dataSource.getConnection();
Statement createStmt = null; Statement createStmt = con.createStatement()) {
try {
con = dataSource.getConnection();
createStmt = con.createStatement();
String createDataStmt = "CREATE TABLE IF NOT EXISTS " + PREMIUM_TABLE + " (" String createDataStmt = "CREATE TABLE IF NOT EXISTS " + PREMIUM_TABLE + " ("
+ "UserID INTEGER PRIMARY KEY AUTO_INCREMENT, " + "UserID INTEGER PRIMARY KEY AUTO_INCREMENT, "
+ "UUID CHAR(36), " + "UUID CHAR(36), "
@ -84,132 +80,106 @@ public class AuthStorage {
} }
createStmt.executeUpdate(createDataStmt); createStmt.executeUpdate(createDataStmt);
} finally {
closeQuietly(con);
closeQuietly(createStmt);
} }
} }
public PlayerProfile loadProfile(String name) { public PlayerProfile loadProfile(String name) {
Connection con = null; try (Connection con = dataSource.getConnection();
PreparedStatement loadStmt = null; PreparedStatement loadStmt = con.prepareStatement("SELECT * FROM "
ResultSet resultSet = null; + PREMIUM_TABLE + " WHERE Name=? LIMIT 1")) {
try {
con = dataSource.getConnection();
loadStmt = con.prepareStatement("SELECT * FROM " + PREMIUM_TABLE + " WHERE Name=? LIMIT 1");
loadStmt.setString(1, name); loadStmt.setString(1, name);
resultSet = loadStmt.executeQuery(); try (ResultSet resultSet = loadStmt.executeQuery()) {
if (resultSet.next()) { if (resultSet.next()) {
long userId = resultSet.getInt(1); long userId = resultSet.getInt(1);
UUID uuid = FastLoginCore.parseId(resultSet.getString(2)); UUID uuid = FastLoginCore.parseId(resultSet.getString(2));
boolean premium = resultSet.getBoolean(4); boolean premium = resultSet.getBoolean(4);
String lastIp = resultSet.getString(5); String lastIp = resultSet.getString(5);
long lastLogin = resultSet.getTimestamp(6).getTime(); long lastLogin = resultSet.getTimestamp(6).getTime();
return new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin); return new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin);
} else { } else {
return new PlayerProfile(null, name, false, ""); return new PlayerProfile(null, name, false, "");
}
} }
} catch (SQLException sqlEx) { } catch (SQLException sqlEx) {
core.getPlugin().getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx); core.getPlugin().getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx);
} finally {
closeQuietly(con);
closeQuietly(loadStmt);
closeQuietly(resultSet);
} }
return null; return null;
} }
public PlayerProfile loadProfile(UUID uuid) { public PlayerProfile loadProfile(UUID uuid) {
Connection con = null; try (Connection con = dataSource.getConnection();
PreparedStatement loadStmt = null; PreparedStatement loadStmt = con.prepareStatement("SELECT * FROM "
ResultSet resultSet = null; + PREMIUM_TABLE + " WHERE UUID=? LIMIT 1")) {
try {
con = dataSource.getConnection();
loadStmt = con.prepareStatement("SELECT * FROM " + PREMIUM_TABLE + " WHERE UUID=? LIMIT 1");
loadStmt.setString(1, uuid.toString().replace("-", "")); loadStmt.setString(1, uuid.toString().replace("-", ""));
resultSet = loadStmt.executeQuery(); try (ResultSet resultSet = loadStmt.executeQuery()) {
if (resultSet.next()) { if (resultSet.next()) {
long userId = resultSet.getInt(1); long userId = resultSet.getInt(1);
String name = resultSet.getString(3); String name = resultSet.getString(3);
boolean premium = resultSet.getBoolean(4); boolean premium = resultSet.getBoolean(4);
String lastIp = resultSet.getString(5); String lastIp = resultSet.getString(5);
long lastLogin = resultSet.getTimestamp(6).getTime(); long lastLogin = resultSet.getTimestamp(6).getTime();
return new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin); return new PlayerProfile(userId, uuid, name, premium, lastIp, lastLogin);
}
} }
} catch (SQLException sqlEx) { } catch (SQLException sqlEx) {
core.getPlugin().getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx); core.getPlugin().getLogger().log(Level.SEVERE, "Failed to query profile", sqlEx);
} finally {
closeQuietly(con);
closeQuietly(loadStmt);
closeQuietly(resultSet);
} }
return null; return null;
} }
public boolean save(PlayerProfile playerProfile) { public boolean save(PlayerProfile playerProfile) {
Connection con = null; try (Connection con = dataSource.getConnection()) {
PreparedStatement updateStmt = null;
PreparedStatement saveStmt = null;
ResultSet generatedKeys = null;
try {
con = dataSource.getConnection();
UUID uuid = playerProfile.getUuid(); UUID uuid = playerProfile.getUuid();
if (playerProfile.getUserId() == -1) { if (playerProfile.getUserId() == -1) {
saveStmt = con.prepareStatement("INSERT INTO " + PREMIUM_TABLE try (PreparedStatement saveStmt = con.prepareStatement("INSERT INTO " + PREMIUM_TABLE
+ " (UUID, Name, Premium, LastIp) VALUES (?, ?, ?, ?) ", Statement.RETURN_GENERATED_KEYS); + " (UUID, Name, Premium, LastIp) VALUES (?, ?, ?, ?) ", Statement.RETURN_GENERATED_KEYS)) {
if (uuid == null) {
saveStmt.setString(1, null);
} else {
saveStmt.setString(1, uuid.toString().replace("-", ""));
}
if (uuid == null) { saveStmt.setString(2, playerProfile.getPlayerName());
saveStmt.setString(1, null); saveStmt.setBoolean(3, playerProfile.isPremium());
} else { saveStmt.setString(4, playerProfile.getLastIp());
saveStmt.setString(1, uuid.toString().replace("-", ""));
}
saveStmt.setString(2, playerProfile.getPlayerName()); saveStmt.execute();
saveStmt.setBoolean(3, playerProfile.isPremium());
saveStmt.setString(4, playerProfile.getLastIp());
saveStmt.execute(); try (ResultSet generatedKeys = saveStmt.getGeneratedKeys()) {
if (generatedKeys != null && generatedKeys.next()) {
generatedKeys = saveStmt.getGeneratedKeys(); playerProfile.setUserId(generatedKeys.getInt(1));
if (generatedKeys != null && generatedKeys.next()) { }
playerProfile.setUserId(generatedKeys.getInt(1)); }
} }
} else { } else {
saveStmt = con.prepareStatement("UPDATE " + PREMIUM_TABLE try (PreparedStatement saveStmt = con.prepareStatement("UPDATE " + PREMIUM_TABLE
+ " SET UUID=?, Name=?, Premium=?, LastIp=?, LastLogin=CURRENT_TIMESTAMP WHERE UserID=?"); + " SET UUID=?, Name=?, Premium=?, LastIp=?, LastLogin=CURRENT_TIMESTAMP WHERE UserID=?")) {
if (uuid == null) {
saveStmt.setString(1, null);
} else {
saveStmt.setString(1, uuid.toString().replace("-", ""));
}
if (uuid == null) { saveStmt.setString(2, playerProfile.getPlayerName());
saveStmt.setString(1, null); saveStmt.setBoolean(3, playerProfile.isPremium());
} else { saveStmt.setString(4, playerProfile.getLastIp());
saveStmt.setString(1, uuid.toString().replace("-", ""));
saveStmt.setLong(5, playerProfile.getUserId());
saveStmt.execute();
} }
saveStmt.setString(2, playerProfile.getPlayerName());
saveStmt.setBoolean(3, playerProfile.isPremium());
saveStmt.setString(4, playerProfile.getLastIp());
saveStmt.setLong(5, playerProfile.getUserId());
saveStmt.execute();
} }
return true; return true;
} catch (SQLException ex) { } catch (SQLException ex) {
core.getPlugin().getLogger().log(Level.SEVERE, "Failed to save playerProfile", ex); core.getPlugin().getLogger().log(Level.SEVERE, "Failed to save playerProfile", ex);
} finally {
closeQuietly(con);
closeQuietly(updateStmt);
closeQuietly(saveStmt);
closeQuietly(generatedKeys);
} }
return false; return false;
@ -218,14 +188,4 @@ public class AuthStorage {
public void close() { public void close() {
dataSource.close(); dataSource.close();
} }
private void closeQuietly(AutoCloseable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (Exception closeEx) {
core.getPlugin().getLogger().log(Level.SEVERE, "Failed to close connection", closeEx);
}
}
}
} }

View File

@ -83,41 +83,18 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
saveDefaultFile("messages.yml"); saveDefaultFile("messages.yml");
saveDefaultFile("config.yml"); saveDefaultFile("config.yml");
BufferedReader reader = null;
try { try {
reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("config.yml"))); sharedConfig = new SharedConfig(loadFile("config.yml"));
sharedConfig = new SharedConfig(plugin.loadYamlFile(reader)); Map<String, Object> messages = loadFile("messages.yml");
reader.close();
reader = Files.newBufferedReader(plugin.getDataFolder().toPath().resolve("config.yml")); for (Entry<String, Object> entry : messages.entrySet()) {
sharedConfig.getConfigValues().putAll(plugin.loadYamlFile(reader));
reader.close();
reader = new BufferedReader(new InputStreamReader(getClass().getClassLoader().getResourceAsStream("messages.yml")));
reader = Files.newBufferedReader(plugin.getDataFolder().toPath().resolve("messages.yml"));
Map<String, Object> messageConfig = plugin.loadYamlFile(reader);
reader.close();
reader = Files.newBufferedReader(plugin.getDataFolder().toPath().resolve("messages.yml"));
messageConfig.putAll(plugin.loadYamlFile(reader));
for (Entry<String, Object> entry : messageConfig.entrySet()) {
String message = plugin.translateColorCodes('&', (String) entry.getValue()); String message = plugin.translateColorCodes('&', (String) entry.getValue());
if (!message.isEmpty()) { if (!message.isEmpty()) {
localeMessages.put(entry.getKey(), message); localeMessages.put(entry.getKey(), message);
} }
} }
reader.close();
} catch (IOException ioEx) { } catch (IOException ioEx) {
plugin.getLogger().log(Level.INFO, "Failed to load yaml files", ioEx); plugin.getLogger().log(Level.INFO, "Failed to load yaml files", ioEx);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
plugin.getLogger().log(Level.SEVERE, null, ex);
}
}
} }
List<String> ipAddresses = sharedConfig.get("ip-addresses"); List<String> ipAddresses = sharedConfig.get("ip-addresses");
@ -130,6 +107,22 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
this.apiConnector = plugin.makeApiConnector(plugin.getLogger(), ipAddresses, requestLimit, proxies); this.apiConnector = plugin.makeApiConnector(plugin.getLogger(), ipAddresses, requestLimit, proxies);
} }
private Map<String, Object> loadFile(String fileName) throws IOException {
Map<String, Object> values;
try (InputStream defaultStream = getClass().getClassLoader().getResourceAsStream(fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(defaultStream))) {
values = plugin.loadYamlFile(reader);
}
Path file = plugin.getDataFolder().toPath().resolve(fileName);
try (BufferedReader reader = Files.newBufferedReader(file)) {
values.putAll(plugin.loadYamlFile(reader));
}
return values;
}
public MojangApiConnector getApiConnector() { public MojangApiConnector getApiConnector() {
return apiConnector; return apiConnector;
} }
@ -213,17 +206,10 @@ public class FastLoginCore<P extends C, C, T extends PlatformPlugin<C>> {
Path configFile = dataFolder.resolve(fileName); Path configFile = dataFolder.resolve(fileName);
if (Files.notExists(configFile)) { if (Files.notExists(configFile)) {
InputStream in = getClass().getClassLoader().getResourceAsStream(fileName); try (InputStream in = getClass().getClassLoader().getResourceAsStream(fileName)) {
try {
Files.copy(in, configFile); Files.copy(in, configFile);
} catch (IOException ioExc) { } catch (IOException ioExc) {
plugin.getLogger().log(Level.SEVERE, "Error saving default " + fileName, ioExc); plugin.getLogger().log(Level.SEVERE, "Error saving default " + fileName, ioExc);
} finally {
try {
in.close();
} catch (IOException ex) {
plugin.getLogger().log(Level.SEVERE, null, ex);
}
} }
} }
} }

View File

@ -92,10 +92,11 @@ public abstract class MojangApiConnector {
} }
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
String line = reader.readLine(); String line = reader.readLine();
if (!"null".equals(line)) { if (!"null".equals(line)) {
return FastLoginCore.parseId(getUUIDFromJson(line)); return FastLoginCore.parseId(getUUIDFromJson(line));
}
} }
} else if (connection.getResponseCode() == RATE_LIMIT_CODE) { } else if (connection.getResponseCode() == RATE_LIMIT_CODE) {
logger.info("RATE_LIMIT REACHED"); logger.info("RATE_LIMIT REACHED");