diff options
-rw-r--r-- | build.gradle | 2 | ||||
-rw-r--r-- | src/main/java/net/elytrium/limboauth/LimboAuth.java | 42 | ||||
-rw-r--r-- | src/main/java/net/elytrium/limboauth/Settings.java | 31 |
3 files changed, 63 insertions, 12 deletions
diff --git a/build.gradle b/build.gradle index 1d31337..744d57c 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ plugins { } setGroup("net.elytrium") -setVersion("1.0.6") +setVersion("1.0.7-SNAPSHOT") java { setSourceCompatibility(JavaVersion.VERSION_11) diff --git a/src/main/java/net/elytrium/limboauth/LimboAuth.java b/src/main/java/net/elytrium/limboauth/LimboAuth.java index b52c32f..ed04f3a 100644 --- a/src/main/java/net/elytrium/limboauth/LimboAuth.java +++ b/src/main/java/net/elytrium/limboauth/LimboAuth.java @@ -17,6 +17,8 @@ package net.elytrium.limboauth; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; import com.google.inject.Inject; import com.j256.ormlite.dao.Dao; import com.j256.ormlite.dao.DaoManager; @@ -565,6 +567,19 @@ public class LimboAuth { } } + private boolean validateScheme(String json, List<String> scheme) { + if (!scheme.isEmpty()) { + JsonObject object = (JsonObject) JsonParser.parseString(json); + for (String field : scheme) { + if (!object.has(field)) { + return false; + } + } + } + + return true; + } + public boolean isPremiumExternal(String nickname) { String lowercaseNickname = nickname.toLowerCase(Locale.ROOT); if (this.premiumCache.containsKey(lowercaseNickname)) { @@ -572,26 +587,35 @@ public class LimboAuth { } try { - int statusCode = this.client.send( + HttpResponse<String> response = this.client.send( HttpRequest.newBuilder() .uri(URI.create(String.format(Settings.IMP.MAIN.ISPREMIUM_AUTH_URL, URLEncoder.encode(lowercaseNickname, StandardCharsets.UTF_8)))) .build(), HttpResponse.BodyHandlers.ofString() - ).statusCode(); + ); - boolean isPremium = statusCode == 200; + int statusCode = response.statusCode(); - // 429 Too Many Requests. - if (statusCode != 429) { - this.premiumCache.put(lowercaseNickname, new CachedPremiumUser(System.currentTimeMillis(), isPremium)); - } else { + if (statusCode == Settings.IMP.MAIN.STATUS_CODE_RATE_LIMIT) { return Settings.IMP.MAIN.ON_RATE_LIMIT_PREMIUM; } - return isPremium; + if (statusCode == Settings.IMP.MAIN.STATUS_CODE_USER_EXISTS + && this.validateScheme(response.body(), Settings.IMP.MAIN.USER_EXISTS_JSON_VALIDATOR_FIELDS)) { + this.premiumCache.put(lowercaseNickname, new CachedPremiumUser(System.currentTimeMillis(), true)); + return true; + } + + if (statusCode == Settings.IMP.MAIN.STATUS_CODE_USER_NOT_EXISTS + && this.validateScheme(response.body(), Settings.IMP.MAIN.USER_NOT_EXISTS_JSON_VALIDATOR_FIELDS)) { + this.premiumCache.put(lowercaseNickname, new CachedPremiumUser(System.currentTimeMillis(), false)); + return false; + } + + return Settings.IMP.MAIN.ON_SERVER_ERROR_PREMIUM; } catch (IOException | InterruptedException e) { LOGGER.error("Unable to authenticate with Mojang.", e); - return Settings.IMP.MAIN.ON_RATE_LIMIT_PREMIUM; + return Settings.IMP.MAIN.ON_SERVER_ERROR_PREMIUM; } } diff --git a/src/main/java/net/elytrium/limboauth/Settings.java b/src/main/java/net/elytrium/limboauth/Settings.java index 8a34d3b..99bb2f0 100644 --- a/src/main/java/net/elytrium/limboauth/Settings.java +++ b/src/main/java/net/elytrium/limboauth/Settings.java @@ -139,19 +139,46 @@ public class Settings extends YamlConfig { @Comment({ "Custom isPremium URL", "You can use Mojang one's API (set by default)", - "Or CloudFlare one's: https://api.ashcon.app/mojang/v1/user/%s", + "Or CloudFlare one's: https://api.ashcon.app/mojang/v2/user/%s", "Or use this code to make your own API: https://blog.cloudflare.com/minecraft-api-with-workers-coffeescript/", - "Or implement your own API, it should just respond with HTTP code 200 only if the player is premium" + "Or implement your own API, it should just respond with HTTP code 200 (see parameters below) only if the player is premium" }) public String ISPREMIUM_AUTH_URL = "https://api.mojang.com/users/profiles/minecraft/%s"; @Comment({ + "Status codes (see the comment above)", + "Responses with unlisted status codes will be identified as responses with a server error", + "Set 200 if you use using Mojang or CloudFlare API" + }) + public int STATUS_CODE_USER_EXISTS = 200; + @Comment("Set 204 if you use Mojang API, 404 if you use CloudFlare API") + public int STATUS_CODE_USER_NOT_EXISTS = 204; + @Comment("Set 429 if you use Mojang or CloudFlare API") + public int STATUS_CODE_RATE_LIMIT = 429; + + @Comment({ + "Sample Mojang API response: {\"name\":\"hevav\",\"id\":\"9c7024b2a48746b3b3934f397ae5d70f\"}", + "Sample CloudFlare API response: {\"uuid\":\"9c7024b2a48746b3b3934f397ae5d70f\",\"username\":\"hevav\", ...}", + "Responses with an invalid scheme will be identified as responses with a server error", + "Set this parameter to [], to disable JSON scheme validation" + }) + public List<String> USER_EXISTS_JSON_VALIDATOR_FIELDS = List.of("name", "id"); + public List<String> USER_NOT_EXISTS_JSON_VALIDATOR_FIELDS = List.of(); + + @Comment({ "If Mojang rate-limits your server, we cannot determine if the player is premium or not", "This option allows you to choose whether every player will be defined as premium or as cracked while Mojang is rate-limiting the server", "True - as premium; False - as cracked" }) public boolean ON_RATE_LIMIT_PREMIUM = true; + @Comment({ + "If Mojang API is down, we cannot determine if the player is premium or not", + "This option allows you to choose whether every player will be defined as premium or as cracked while Mojang API is unavailable", + "True - as premium; False - as cracked" + }) + public boolean ON_SERVER_ERROR_PREMIUM = true; + public List<String> REGISTER_COMMAND = List.of("/r", "/reg", "/register"); public List<String> LOGIN_COMMAND = List.of("/l", "/log", "/login"); public List<String> TOTP_COMMAND = List.of("/2fa", "/totp"); |