Use Gson's TypeAdapter for more type safety

This commit is contained in:
games647
2017-09-23 13:56:28 +02:00
parent 66b808c999
commit e6c23a4bb5
14 changed files with 69 additions and 39 deletions

View File

@ -1,5 +1,9 @@
### 1.11 ### 1.11
* Add support for IPv6 proxies
* Shared configuration implementation for easier maintained code
* Use Gson for json parsing, because it's supported on all platforms and removes code duplicates
* Clean up project code
* Drop support for deprecated AuthMe API * Drop support for deprecated AuthMe API
* Remove legacy database migration code * 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

View File

@ -1,6 +1,5 @@
package com.github.games647.fastlogin.bukkit; package com.github.games647.fastlogin.bukkit;
import com.github.games647.fastlogin.core.CommonUtil;
import com.github.games647.fastlogin.core.mojang.MojangApiConnector; import com.github.games647.fastlogin.core.mojang.MojangApiConnector;
import com.github.games647.fastlogin.core.mojang.SkinProperties; import com.github.games647.fastlogin.core.mojang.SkinProperties;
import com.github.games647.fastlogin.core.mojang.VerificationReply; import com.github.games647.fastlogin.core.mojang.VerificationReply;
@ -44,9 +43,7 @@ public class MojangApiBukkit extends MojangApiConnector {
//validate parsing //validate parsing
//http://wiki.vg/Protocol_Encryption#Server //http://wiki.vg/Protocol_Encryption#Server
VerificationReply verification = gson.fromJson(reader, VerificationReply.class); VerificationReply verification = gson.fromJson(reader, VerificationReply.class);
playerSession.setUuid(verification.getId());
String uuid = verification.getId();
playerSession.setUuid(CommonUtil.parseId(uuid));
SkinProperties[] properties = verification.getProperties(); SkinProperties[] properties = verification.getProperties();
if (properties != null && properties.length > 0) { if (properties != null && properties.length > 0) {

View File

@ -77,7 +77,7 @@ public class ProtocolLibListener extends PacketAdapter {
PacketContainer packet = packetEvent.getPacket(); PacketContainer packet = packetEvent.getPacket();
String username = packet.getGameProfiles().read(0).getName(); String username = packet.getGameProfiles().read(0).getName();
plugin.getLogger().log(Level.FINER, "Player {0} with {1} connecting", new Object[]{sessionKey, username}); plugin.getLogger().log(Level.FINER, "GameProfile {0} with {1} connecting", new Object[]{sessionKey, username});
packetEvent.getAsyncMarker().incrementProcessingDelay(); packetEvent.getAsyncMarker().incrementProcessingDelay();
Runnable nameCheckTask = new NameCheckTask(plugin, packetEvent, random, player, username); Runnable nameCheckTask = new NameCheckTask(plugin, packetEvent, random, player, username);

View File

@ -52,7 +52,7 @@ public class VerifyResponseTask implements Runnable {
BukkitLoginSession session = plugin.getLoginSessions().get(player.getAddress().toString()); BukkitLoginSession session = plugin.getLoginSessions().get(player.getAddress().toString());
if (session == null) { if (session == null) {
disconnect(plugin.getCore().getMessage("invalid-request"), true disconnect(plugin.getCore().getMessage("invalid-request"), true
, "Player {0} tried to send encryption response at invalid state", player.getAddress()); , "GameProfile {0} tried to send encryption response at invalid state", player.getAddress());
} else { } else {
verifyResponse(session); verifyResponse(session);
} }
@ -97,7 +97,7 @@ public class VerifyResponseTask implements Runnable {
String username = session.getUsername(); String username = session.getUsername();
if (plugin.getCore().getApiConnector().hasJoinedServer(session, serverId, player.getAddress())) { if (plugin.getCore().getApiConnector().hasJoinedServer(session, serverId, player.getAddress())) {
plugin.getLogger().log(Level.INFO, "Player {0} has a verified premium account", username); plugin.getLogger().log(Level.INFO, "GameProfile {0} has a verified premium account", username);
session.setVerified(true); session.setVerified(true);
setPremiumUUID(session.getUuid()); setPremiumUUID(session.getUuid());
@ -105,7 +105,7 @@ public class VerifyResponseTask implements Runnable {
} else { } else {
//user tried to fake a authentication //user tried to fake a authentication
disconnect(plugin.getCore().getMessage("invalid-session"), true disconnect(plugin.getCore().getMessage("invalid-session"), true
, "Player {0} ({1}) tried to log in with an invalid session ServerId: {2}" , "GameProfile {0} ({1}) tried to log in with an invalid session ServerId: {2}"
, session.getUsername(), player.getAddress(), serverId); , session.getUsername(), player.getAddress(), serverId);
} }
} }
@ -132,7 +132,7 @@ public class VerifyResponseTask implements Runnable {
if (!Arrays.equals(requestVerify, EncryptionUtil.decrypt(cipher, privateKey, responseVerify))) { if (!Arrays.equals(requestVerify, EncryptionUtil.decrypt(cipher, privateKey, responseVerify))) {
//check if the verify token are equal to the server sent one //check if the verify token are equal to the server sent one
disconnect(plugin.getCore().getMessage("invalid-verify-token"), true disconnect(plugin.getCore().getMessage("invalid-verify-token"), true
, "Player {0} ({1}) tried to login with an invalid verify token. Server: {2} Client: {3}" , "GameProfile {0} ({1}) tried to login with an invalid verify token. Server: {2} Client: {3}"
, session.getUsername(), packetEvent.getPlayer().getAddress(), requestVerify, responseVerify); , session.getUsername(), packetEvent.getPlayer().getAddress(), requestVerify, responseVerify);
return false; return false;
} }

View File

@ -3,7 +3,7 @@ package com.github.games647.fastlogin.core.hooks;
/** /**
* Represents a supporting authentication plugin in BungeeCord and Bukkit/Spigot/... servers * Represents a supporting authentication plugin in BungeeCord and Bukkit/Spigot/... servers
* *
* @param <P> either org.bukkit.entity.Player for Bukkit or net.md_5.bungee.api.connection.ProxiedPlayer for BungeeCord * @param <P> either org.bukkit.entity.GameProfile for Bukkit or net.md_5.bungee.api.connection.ProxiedPlayer for BungeeCord
*/ */
public interface AuthPlugin<P> { public interface AuthPlugin<P> {

View File

@ -1,11 +1,13 @@
package com.github.games647.fastlogin.core.mojang; package com.github.games647.fastlogin.core.mojang;
public class Player { import java.util.UUID;
private String id; public class GameProfile {
private UUID id;
private String name; private String name;
public String getId() { public UUID getId() {
return id; return id;
} }

View File

@ -8,6 +8,7 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.net.HostAndPort; import com.google.common.net.HostAndPort;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.IOException; import java.io.IOException;
@ -53,7 +54,7 @@ public class MojangApiConnector {
private final int rateLimit; private final int rateLimit;
private long lastRateLimit; private long lastRateLimit;
protected final Gson gson = new Gson(); protected final Gson gson = new GsonBuilder().registerTypeAdapter(UUID.class, new UUIDTypeAdapter()).create();
protected final Logger logger; protected final Logger logger;
public MojangApiConnector(Logger logger, Collection<String> localAddresses, int rateLimit public MojangApiConnector(Logger logger, Collection<String> localAddresses, int rateLimit
@ -122,15 +123,14 @@ public class MojangApiConnector {
private UUID getUUIDFromJson(String json) { private UUID getUUIDFromJson(String json) {
boolean isArray = json.startsWith("["); boolean isArray = json.startsWith("[");
Player mojangPlayer; GameProfile mojangPlayer;
if (isArray) { if (isArray) {
mojangPlayer = gson.fromJson(json, Player[].class)[0]; mojangPlayer = gson.fromJson(json, GameProfile[].class)[0];
} else { } else {
mojangPlayer = gson.fromJson(json, Player.class); mojangPlayer = gson.fromJson(json, GameProfile.class);
} }
String id = mojangPlayer.getId(); return mojangPlayer.getId();
return CommonUtil.parseId(id);
} }
protected HttpsURLConnection getConnection(String url, Proxy proxy) throws IOException { protected HttpsURLConnection getConnection(String url, Proxy proxy) throws IOException {
@ -141,11 +141,9 @@ public class MojangApiConnector {
connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("User-Agent", USER_AGENT); connection.setRequestProperty("User-Agent", USER_AGENT);
//this connection doesn't need to be closed. So can make use of keep alive in java connection.setSSLSocketFactory(sslFactory);
if (sslFactory != null) {
connection.setSSLSocketFactory(sslFactory);
}
//this connection doesn't need to be closed. So can make use of keep alive in java
return connection; return connection;
} }

View File

@ -2,12 +2,11 @@ package com.github.games647.fastlogin.core.mojang;
public class SkinProperties { public class SkinProperties {
private String name;
private String value; private String value;
private String signature; private String signature;
public String getName() { public String getName() {
return name; return "textures";
} }
public String getValue() { public String getValue() {

View File

@ -0,0 +1,28 @@
package com.github.games647.fastlogin.core.mojang;
import com.github.games647.fastlogin.core.CommonUtil;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.util.UUID;
public class UUIDTypeAdapter extends TypeAdapter<UUID> {
public void write(JsonWriter out, UUID value) throws IOException {
out.value(fromUUID(value));
}
public UUID read(JsonReader in) throws IOException {
return fromString(in.nextString());
}
public static String fromUUID(UUID value) {
return value.toString().replace("-", "");
}
public static UUID fromString(String input) {
return CommonUtil.parseId(input);
}
}

View File

@ -1,12 +1,14 @@
package com.github.games647.fastlogin.core.mojang; package com.github.games647.fastlogin.core.mojang;
import java.util.UUID;
public class VerificationReply { public class VerificationReply {
private String id; private UUID id;
private String name; private String name;
private SkinProperties[] properties; private SkinProperties[] properties;
public String getId() { public UUID getId() {
return id; return id;
} }

View File

@ -31,7 +31,7 @@ import net.md_5.bungee.config.ConfigurationProvider;
import net.md_5.bungee.config.YamlConfiguration; import net.md_5.bungee.config.YamlConfiguration;
/** /**
* @param <P> Player class * @param <P> GameProfile class
* @param <C> CommandSender * @param <C> CommandSender
* @param <T> Plugin class * @param <T> Plugin class
*/ */

View File

@ -65,7 +65,7 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
} }
private boolean checkPremiumName(S source, String username, PlayerProfile profile) throws Exception { private boolean checkPremiumName(S source, String username, PlayerProfile profile) throws Exception {
core.getPlugin().getLogger().log(Level.FINER, "Player {0} uses a premium username", username); core.getPlugin().getLogger().log(Level.FINER, "GameProfile {0} uses a premium username", username);
if (core.getConfig().get("autoRegister", false) && (authHook == null || !authHook.isRegistered(username))) { if (core.getConfig().get("autoRegister", false) && (authHook == null || !authHook.isRegistered(username))) {
requestPremiumLogin(source, profile, username, false); requestPremiumLogin(source, profile, username, false);
return true; return true;
@ -80,7 +80,7 @@ public abstract class JoinManagement<P extends C, C, S extends LoginSource> {
PlayerProfile profile = core.getStorage().loadProfile(premiumUUID); PlayerProfile profile = core.getStorage().loadProfile(premiumUUID);
if (profile != null) { if (profile != null) {
//uuid exists in the database //uuid exists in the database
core.getPlugin().getLogger().log(Level.FINER, "Player {0} changed it's username", premiumUUID); core.getPlugin().getLogger().log(Level.FINER, "GameProfile {0} changed it's username", premiumUUID);
//update the username to the new one in the database //update the username to the new one in the database
profile.setPlayerName(username); profile.setPlayerName(username);

View File

@ -62,7 +62,7 @@ premiumUuid: false
# #### Case 1 # #### Case 1
# nameChangeCheck = false ----- autoRegister = false # nameChangeCheck = false ----- autoRegister = false
# #
# Player logins as cracked until the player invoked the command /premium. Then we could override the existing database # GameProfile logins as cracked until the player invoked the command /premium. Then we could override the existing database
# record. # record.
# #
# #### Case 2 # #### Case 2

View File

@ -24,25 +24,25 @@
# Switch mode is activated and a new (non-whitelist) cracked player tries to join # Switch mode is activated and a new (non-whitelist) cracked player tries to join
switch-kick-message: '&4Only paid minecraft whitelisted accounts are allowed to join this server' switch-kick-message: '&4Only paid minecraft whitelisted accounts are allowed to join this server'
# Player activated premium login in order to skip offline authentication # GameProfile activated premium login in order to skip offline authentication
add-premium: '&2Added to the list of premium players' add-premium: '&2Added to the list of premium players'
# Player activated premium login in order to skip offline authentication # GameProfile activated premium login in order to skip offline authentication
add-premium-other: '&2Player has been added to the premium list' add-premium-other: '&2Player has been added to the premium list'
# Player is already set be a paid account # GameProfile is already set be a paid account
already-exists: '&4You are already on the premium list' already-exists: '&4You are already on the premium list'
# Player is already set be a paid account # GameProfile is already set be a paid account
already-exists-other: '&4Player is already on the premium list' already-exists-other: '&4Player is already on the premium list'
# Player was changed to be cracked # GameProfile was changed to be cracked
remove-premium: '&2Removed from the list of premium players' remove-premium: '&2Removed from the list of premium players'
# Player is already set to be cracked # GameProfile is already set to be cracked
not-premium: '&4You are not in the premium list' not-premium: '&4You are not in the premium list'
# Player is already set to be cracked # GameProfile is already set to be cracked
not-premium-other: '&4Player is not in the premium list' not-premium-other: '&4Player is not in the premium list'
# Admin wanted to change the premium of a user that isn't known to the plugin # Admin wanted to change the premium of a user that isn't known to the plugin
@ -58,7 +58,7 @@ auto-login: '&2Auto logged in'
auto-register: '&2Auto registered with password: %password auto-register: '&2Auto registered with password: %password
You may want change it?' You may want change it?'
# Player is not able to toggle the premium state of other players # GameProfile is not able to toggle the premium state of other players
no-permission: '&4Not enough permissions' no-permission: '&4Not enough permissions'
# Although the console can toggle the premium state, it's not possible for the console itself. # Although the console can toggle the premium state, it's not possible for the console itself.