From c50249edea65eddceb72aad6f4397051d53e8260 Mon Sep 17 00:00:00 2001 From: games647 Date: Thu, 7 Jul 2016 12:20:39 +0200 Subject: [PATCH] Switch to mcapi.ca and add configurable number of requests --- CHANGELOG.md | 1 + .../fastlogin/bukkit/FastLoginBukkit.java | 42 ++++++++++------- .../fastlogin/bukkit/MojangApiBukkit.java | 16 +++---- .../fastlogin/bungee/FastLoginBungee.java | 12 +++-- .../fastlogin/bungee/McAPIProfile.java | 15 ------ .../fastlogin/bungee/MojangApiBungee.java | 13 ++---- .../listener/PlayerConnectionListener.java | 1 - .../fastlogin/core/MojangApiConnector.java | 46 +++++++++++-------- core/src/main/resources/config.yml | 10 ++-- 9 files changed, 77 insertions(+), 79 deletions(-) delete mode 100644 bungee/src/main/java/com/github/games647/fastlogin/bungee/McAPIProfile.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 4fba66fd..c92c18d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ * Fixed skin applies if premium uuid is deactivated * Fix player entry is not saved if namechangecheck is enabled * Fix skin applies for third-party plugins +* Switch to mcapi.ca for uuid lookups ######1.6.2 diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java index 9808394c..b2f53235 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/FastLoginBukkit.java @@ -18,6 +18,7 @@ import com.google.common.cache.CacheLoader; import com.google.common.collect.Sets; import java.security.KeyPair; +import java.util.List; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentMap; @@ -45,19 +46,8 @@ public class FastLoginBukkit extends JavaPlugin { //this map is thread-safe for async access (Packet Listener) //SafeCacheBuilder is used in order to be version independent - private final ConcurrentMap session = CompatibleCacheBuilder - .newBuilder() - //2 minutes should be enough as a timeout for bad internet connection (Server, Client and Mojang) - .expireAfterWrite(1, TimeUnit.MINUTES) - //mapped by ip:port -> PlayerSession - .build(new CacheLoader() { - - @Override - public BukkitLoginSession load(String key) throws Exception { - //A key should be inserted manually on start packet - throw new UnsupportedOperationException("Not supported"); - } - }); + private final ConcurrentMap session = buildCache(1, -1); + //1 minutes should be enough as a timeout for bad internet connection (Server, Client and Mojang) private BukkitAuthPlugin authPlugin; private PasswordGenerator passwordGenerator = new DefaultPasswordGenerator(); @@ -67,9 +57,10 @@ public class FastLoginBukkit extends JavaPlugin { core.loadConfig(); core.loadMessages(); - core.setMojangApiConnector(new MojangApiBukkit(core - , getConfig().getStringList("ip-addresses") - , getConfig().getBoolean("lookup-third-party"))); + List ipAddresses = getConfig().getStringList("ip-addresses"); + int requestLimit = getConfig().getInt("mojang-request-limit"); + MojangApiBukkit mojangApi = new MojangApiBukkit(buildCache(10, -1), getLogger(), ipAddresses, requestLimit); + core.setMojangApiConnector(mojangApi); try { if (ClassUtil.isPresent("org.spigotmc.SpigotConfig")) { @@ -227,4 +218,23 @@ public class FastLoginBukkit extends JavaPlugin { this.serverStarted = true; } } + + private ConcurrentMap buildCache(int minutes, int maxSize) { + CompatibleCacheBuilder builder = CompatibleCacheBuilder.newBuilder(); + + if (minutes > 0) { + builder.expireAfterWrite(minutes, TimeUnit.MINUTES); + } + + if (maxSize > 0) { + builder.maximumSize(maxSize); + } + + return builder.build(new CacheLoader() { + @Override + public V load(K key) throws Exception { + throw new UnsupportedOperationException("Not supported yet."); + } + }); + } } diff --git a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java index 0de46498..cc641129 100644 --- a/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java +++ b/bukkit/src/main/java/com/github/games647/fastlogin/bukkit/MojangApiBukkit.java @@ -8,7 +8,9 @@ import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.util.List; import java.util.UUID; +import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; +import java.util.logging.Logger; import org.json.simple.JSONArray; import org.json.simple.JSONObject; @@ -19,8 +21,9 @@ public class MojangApiBukkit extends MojangApiConnector { //mojang api check to prove a player is logged in minecraft and made a join server request private static final String HAS_JOINED_URL = "https://sessionserver.mojang.com/session/minecraft/hasJoined?"; - public MojangApiBukkit(FastLoginCore plugin, List localAddresses, boolean apiLookup) { - super(plugin, localAddresses, apiLookup); + public MojangApiBukkit(ConcurrentMap requests, Logger logger, List localAddresses + , int rateLimit) { + super(requests, logger, localAddresses, rateLimit); } @Override @@ -57,7 +60,7 @@ public class MojangApiBukkit extends MojangApiConnector { } } catch (Exception ex) { //catch not only ioexceptions also parse and NPE on unexpected json format - plugin.getLogger().log(Level.WARNING, "Failed to verify session", ex); + logger.log(Level.WARNING, "Failed to verify session", ex); } //this connection doesn't need to be closed. So can make use of keep alive in java @@ -70,11 +73,4 @@ public class MojangApiBukkit extends MojangApiConnector { String uuid = (String) userData.get("id"); return FastLoginCore.parseId(uuid); } - - @Override - protected UUID getUUIDFromJsonAPI(String json) { - JSONObject userData = (JSONObject) JSONValue.parse(json); - String uuid = (String) userData.get("uuid"); - return FastLoginCore.parseId(uuid); - } } diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java index e76d8ee7..49114e20 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/FastLoginBungee.java @@ -5,15 +5,18 @@ import com.github.games647.fastlogin.bungee.hooks.BungeeAuthPlugin; import com.github.games647.fastlogin.bungee.listener.PlayerConnectionListener; import com.github.games647.fastlogin.bungee.listener.PluginMessageListener; import com.github.games647.fastlogin.core.FastLoginCore; +import com.google.common.cache.CacheBuilder; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import java.io.File; import java.io.IOException; +import java.util.List; import java.util.Random; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import java.util.logging.Level; import net.md_5.bungee.api.connection.PendingConnection; @@ -48,9 +51,12 @@ public class FastLoginBungee extends Plugin { File configFile = new File(getDataFolder(), "config.yml"); config = ConfigurationProvider.getProvider(YamlConfiguration.class).load(configFile); - loginCore.setMojangApiConnector(new MojangApiBungee(loginCore - , config.getStringList("ip-addresses") - , config.getBoolean("lookup-third-party"))); + List ipAddresses = getConfig().getStringList("ip-addresses"); + int requestLimit = getConfig().getInt("mojang-request-limit"); + ConcurrentMap requestCache = CacheBuilder.newBuilder() + .expireAfterWrite(10, TimeUnit.MINUTES).build().asMap(); + MojangApiBungee mojangApi = new MojangApiBungee(requestCache, getLogger(), ipAddresses, requestLimit); + loginCore.setMojangApiConnector(mojangApi); String driver = config.getString("driver"); String host = config.getString("host", ""); diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/McAPIProfile.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/McAPIProfile.java deleted file mode 100644 index c357aece..00000000 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/McAPIProfile.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.github.games647.fastlogin.bungee; - -public class McAPIProfile { - - private String uuid; - private String name; - - public String getUuid() { - return uuid; - } - - public String getName() { - return name; - } -} diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiBungee.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiBungee.java index 939b3370..6fa2e4c7 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiBungee.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/MojangApiBungee.java @@ -5,13 +5,16 @@ import com.github.games647.fastlogin.core.MojangApiConnector; import java.util.List; import java.util.UUID; +import java.util.concurrent.ConcurrentMap; +import java.util.logging.Logger; import net.md_5.bungee.BungeeCord; public class MojangApiBungee extends MojangApiConnector { - public MojangApiBungee(FastLoginCore plugin, List localAddresses, boolean apiLookup) { - super(plugin, localAddresses, apiLookup); + public MojangApiBungee(ConcurrentMap requests, Logger logger, List localAddresses + , int rateLimit) { + super(requests, logger, localAddresses, rateLimit); } @Override @@ -25,10 +28,4 @@ public class MojangApiBungee extends MojangApiConnector { //this is not needed in Bungee throw new UnsupportedOperationException("Not supported"); } - - @Override - protected UUID getUUIDFromJsonAPI(String json) { - McAPIProfile apiPlayer = BungeeCord.getInstance().gson.fromJson(json, McAPIProfile.class); - return FastLoginCore.parseId(apiPlayer.getUuid()); - } } diff --git a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java index dfe5c077..9635b1b6 100644 --- a/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java +++ b/bungee/src/main/java/com/github/games647/fastlogin/bungee/listener/PlayerConnectionListener.java @@ -55,7 +55,6 @@ public class PlayerConnectionListener implements Listener { //use the loginevent instead of the postlogin event in order to send the loginsuccess packet to the client //with the offline uuid this makes it possible to set the skin then - PendingConnection connection = loginEvent.getConnection(); String username = connection.getName(); if (connection.isOnlineMode()) { diff --git a/core/src/main/java/com/github/games647/fastlogin/core/MojangApiConnector.java b/core/src/main/java/com/github/games647/fastlogin/core/MojangApiConnector.java index ad749647..f0d51d37 100644 --- a/core/src/main/java/com/github/games647/fastlogin/core/MojangApiConnector.java +++ b/core/src/main/java/com/github/games647/fastlogin/core/MojangApiConnector.java @@ -11,7 +11,9 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; +import java.util.concurrent.ConcurrentMap; import java.util.logging.Level; +import java.util.logging.Logger; import java.util.regex.Pattern; import javax.net.ssl.HttpsURLConnection; @@ -22,7 +24,7 @@ public abstract class MojangApiConnector { private static final int TIMEOUT = 1 * 1_000; private static final String USER_AGENT = "Premium-Checker"; - private static final String MCAPI_UUID_URL = "https://us.mc-api.net/v3/uuid/"; + private static final String MCAPI_UUID_URL = "https://mcapi.ca/uuid/player/"; //only premium (paid account) users have a uuid from here private static final String UUID_LINK = "https://api.mojang.com/users/profiles/minecraft/"; @@ -34,15 +36,23 @@ public abstract class MojangApiConnector { //compile the pattern only on plugin enable -> and this have to be threadsafe private final Pattern playernameMatcher = Pattern.compile(VALID_PLAYERNAME); + private final ConcurrentMap requests; private final BalancedSSLFactory sslFactory; - private final boolean apiLookup; + private final int rateLimit; private long lastRateLimit; - protected final FastLoginCore plugin; + protected final Logger logger; - public MojangApiConnector(FastLoginCore plugin, List localAddresses, boolean apiLookup) { - this.plugin = plugin; - this.apiLookup = apiLookup; + public MojangApiConnector(ConcurrentMap requests, Logger logger, List localAddresses + , int rateLimit) { + this.logger = logger; + this.requests = requests; + + if (rateLimit > 600) { + this.rateLimit = 600; + } else { + this.rateLimit = rateLimit; + } if (localAddresses.isEmpty()) { this.sslFactory = null; @@ -52,13 +62,13 @@ public abstract class MojangApiConnector { try { InetAddress address = InetAddress.getByName(localAddress); if (!address.isAnyLocalAddress()) { - plugin.getLogger().log(Level.WARNING, "Submitted IP-Address is not local", address); + logger.log(Level.WARNING, "Submitted IP-Address is not local", address); continue; } addresses.add(address); } catch (UnknownHostException ex) { - plugin.getLogger().log(Level.SEVERE, "IP-Address is unknown to us", ex); + logger.log(Level.SEVERE, "IP-Address is unknown to us", ex); } } @@ -76,11 +86,13 @@ public abstract class MojangApiConnector { if (playernameMatcher.matcher(playerName).matches()) { //only make a API call if the name is valid existing mojang account - if (System.currentTimeMillis() - lastRateLimit < 1_000 * 60 * 10) { - plugin.getLogger().fine("STILL WAITING FOR RATE_LIMIT - TRYING Third-party API"); + if (requests.size() >= rateLimit || System.currentTimeMillis() - lastRateLimit < 1_000 * 60 * 10) { +// plugin.getLogger().fine("STILL WAITING FOR RATE_LIMIT - TRYING Third-party API"); return getUUIDFromAPI(playerName); } + requests.put(new Object(), new Object()); + try { HttpsURLConnection connection = getConnection(UUID_LINK + playerName); if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) { @@ -90,13 +102,13 @@ public abstract class MojangApiConnector { return getUUIDFromJson(line); } } else if (connection.getResponseCode() == RATE_LIMIT_CODE) { - plugin.getLogger().info("RATE_LIMIT REACHED - TRYING SECOND API"); + logger.info("RATE_LIMIT REACHED - TRYING THIRD-PARTY API"); lastRateLimit = System.currentTimeMillis(); return getUUIDFromAPI(playerName); } //204 - no content for not found } catch (Exception ex) { - plugin.getLogger().log(Level.SEVERE, "Failed to check if player has a paid account", ex); + logger.log(Level.SEVERE, "Failed to check if player has a paid account", ex); } //this connection doesn't need to be closed. So can make use of keep alive in java } @@ -105,10 +117,6 @@ public abstract class MojangApiConnector { } public UUID getUUIDFromAPI(String playerName) { - if (!playernameMatcher.matcher(playerName).matches()) { - return null; - } - try { HttpURLConnection httpConnection = (HttpURLConnection) new URL(MCAPI_UUID_URL + playerName).openConnection(); httpConnection.addRequestProperty("Content-Type", "application/json"); @@ -122,10 +130,10 @@ public abstract class MojangApiConnector { BufferedReader reader = new BufferedReader(new InputStreamReader(httpConnection.getInputStream())); String line = reader.readLine(); if (line != null && !line.equals("null")) { - return getUUIDFromJsonAPI(line); + return getUUIDFromJson(line); } } catch (IOException iOException) { - plugin.getLogger().log(Level.SEVERE, "Tried converting name->uuid from third-party api", iOException); + logger.log(Level.SEVERE, "Tried converting name->uuid from third-party api", iOException); } return null; @@ -135,8 +143,6 @@ public abstract class MojangApiConnector { protected abstract UUID getUUIDFromJson(String json); - protected abstract UUID getUUIDFromJsonAPI(String json); - protected HttpsURLConnection getConnection(String url) throws IOException { HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); connection.setConnectTimeout(TIMEOUT); diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 3f921b47..8935e395 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -122,14 +122,12 @@ premium-warning: true # - 192-168-0-2 ip-addresses: [] -# This option exists because of the reason as the previous one. Once FastLogin hits the rate-limit it will make requests -# to a third-party API. In this case: https://us.mc-api.net - Please support them if you can -# -# For the next ten minutes FastLogin will make requests to this website. Once the ten minutes are expired FastLogin -# will make requests to Mojang again, because the rate-limit expired. (in order to reduce the load to the third-party-api) +# How many requests should be established until the plugin uses the third-party API https://mcapi.ca/ +# Once this number is reached in a range of ten minutes it will start connecting to https://mcapi.ca/ for the next ten minutes +# This option exists in order to workaround the rate-limiting. Name -> UUID are fetched in the same way like heads # # If you want to join the discussion visit this: https://github.com/games647/FastLogin/issues/27#issuecomment-226954350 -lookup-third-party: true +mojang-request-limit: 600 # Database configuration # Recommened is the use of MariaDB (a better version of MySQL)