From b2d7a03762cf77b87596cb9a0ad0161893af7770 Mon Sep 17 00:00:00 2001 From: stijnb1234 Date: Mon, 16 May 2022 22:12:20 +0200 Subject: [PATCH] Moved to Polymart check, updated deps --- pom.xml | 8 +- ...emepark-3.1.1.jar => ThemePark_v3.1.1.jar} | Bin 518043 -> 518242 bytes .../themeparkplus/ThemeParkPlus.java | 11 +- .../themeparkplus/managers/DBManager.java | 4 +- .../themeparkplus/sbutils/UpdateManager.java | 157 ++++----- .../themeparkplus/sbutils/Verify.java | 165 +++++++++ .../themeparkplus/util/License.java | 312 ------------------ 7 files changed, 236 insertions(+), 421 deletions(-) rename src/lib/{themepark-3.1.1.jar => ThemePark_v3.1.1.jar} (79%) create mode 100644 src/main/java/nl/sbdeveloper/themeparkplus/sbutils/Verify.java delete mode 100644 src/main/java/nl/sbdeveloper/themeparkplus/util/License.java diff --git a/pom.xml b/pom.xml index 3c8874c..4aa5dc3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ nl.SBDeveloper ThemeParkPlus - 3.0.0 + 3.1.0 jar ThemeParkPlus @@ -121,7 +121,7 @@ org.spigotmc spigot-api - 1.18.1-R0.1-SNAPSHOT + 1.18.2-R0.1-SNAPSHOT provided @@ -129,7 +129,7 @@ themepark 3.1.1 system - ${pom.basedir}/src/lib/themepark-3.1.1.jar + ${pom.basedir}/src/lib/ThemePark_v3.1.1.jar me.paradoxpixel @@ -147,7 +147,7 @@ de.tr7zw item-nbt-api - 2.8.0 + 2.9.2 com.github.MilkBowl diff --git a/src/lib/themepark-3.1.1.jar b/src/lib/ThemePark_v3.1.1.jar similarity index 79% rename from src/lib/themepark-3.1.1.jar rename to src/lib/ThemePark_v3.1.1.jar index 108c47569d31b94e6cfa1235df72bf061e54a09a..240a233036ce3ee2944e34316d5f5bc7cddbf875 100644 GIT binary patch delta 21944 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

&18A=YCZCKpJtx%o*LXq}&+~s8|EqZb delta 21241 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

UWHvln7!UG#EAVb(OR~K+DN7y8eqY4qkEctk$ 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�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 diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java b/src/main/java/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java index 290cc81..0fe3a3a 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java +++ b/src/main/java/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java @@ -5,9 +5,9 @@ import nl.sbdeveloper.themeparkplus.commands.TPPCMD; import nl.sbdeveloper.themeparkplus.listeners.*; import nl.sbdeveloper.themeparkplus.managers.DBManager; import nl.sbdeveloper.themeparkplus.sbutils.UpdateManager; +import nl.sbdeveloper.themeparkplus.sbutils.Verify; import nl.sbdeveloper.themeparkplus.sbutils.YamlFile; import nl.sbdeveloper.themeparkplus.util.Inventory; -import nl.sbdeveloper.themeparkplus.util.License; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; @@ -80,7 +80,12 @@ public final class ThemeParkPlus extends JavaPlugin { return; } - new License(this, "TP", license); + getLogger().info("This copy is bought by %%__USERNAME__%% (%%__USER__%%)."); + getLogger().info("Validating your purchase..."); + Verify v = new Verify(this); + if (v.isValidated()) { + getLogger().info("Your purchase is valid. Thanks for your purchase!"); + } if (Bukkit.getPluginManager().getPlugin("WorldEdit") == null) { Bukkit.getLogger().severe("[ThemeParkPlus] Missing WorldEdit! Please install it first."); @@ -153,7 +158,7 @@ public final class ThemeParkPlus extends JavaPlugin { new Metrics(this, 5023); if (getSConfig().getFile().getBoolean("UpdateChecker.Enabled")) { - UpdateManager updateManager = new UpdateManager(this, 7, license); + UpdateManager updateManager = new UpdateManager(this, UpdateManager.CheckType.POLYMART_PAID); updateManager.handleResponse((versionResponse, version) -> { switch (versionResponse) { diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/managers/DBManager.java b/src/main/java/nl/sbdeveloper/themeparkplus/managers/DBManager.java index 17ba9c6..9b945a8 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/managers/DBManager.java +++ b/src/main/java/nl/sbdeveloper/themeparkplus/managers/DBManager.java @@ -8,7 +8,7 @@ import nl.sbdeveloper.themeparkplus.api.objects.MalfunctionReport; import nl.sbdeveloper.themeparkplus.api.objects.WaitingRow; import nl.sbdeveloper.themeparkplus.sbutils.LocationSerializer; import nl.sbdeveloper.themeparkplus.sbutils.SQLiteDB; -import nl.sbdeveloper.themeparkplus.util.License; +import nl.sbdeveloper.themeparkplus.sbutils.Verify; import nl.sbdeveloper.themeparkplus.util.LocationGsonAdapter; import org.bukkit.Location; @@ -95,7 +95,7 @@ public class DBManager { } public void save() { - if (License.isValid() == null || !License.isValid()) return; + if (Verify.isValid() == null || !Verify.isValid()) return; for (Map.Entry entry : PlusAPI.getGates().entrySet()) { Gson gson = getGson(); diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/sbutils/UpdateManager.java b/src/main/java/nl/sbdeveloper/themeparkplus/sbutils/UpdateManager.java index f3fcf99..2c6f20a 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/sbutils/UpdateManager.java +++ b/src/main/java/nl/sbdeveloper/themeparkplus/sbutils/UpdateManager.java @@ -1,8 +1,13 @@ +/* + * This file is part of TPRidecountAddon. + * Copyright (c) 2018-2022. SBDevelopment - All Rights Reserved + * Unauthorized copying of this file, via any medium is strictly prohibited + * Proprietary and confidential + * Written by Stijn Bannink , April 2022 + */ + package nl.sbdeveloper.themeparkplus.sbutils; -import com.google.gson.JsonArray; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; @@ -10,66 +15,62 @@ import org.bukkit.plugin.java.JavaPlugin; import javax.net.ssl.HttpsURLConnection; import java.io.*; import java.lang.reflect.Method; -import java.net.HttpURLConnection; import java.net.URL; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; -import java.nio.charset.StandardCharsets; import java.util.function.BiConsumer; /** - * Update class for SBDevelopment + * Update checker class + * * @author Stijn [SBDeveloper] * @since 05-03-2020 - * @version 2.0 [26-12-2020] - This class supports the v2 Update API - * - *

© Stijn Bannink [stijnbannink23@gmail.com] - All rights reserved.

+ * @version 2.2 [17-04-2022] - Added Polymart support */ public class UpdateManager { - private static final String SPIGOT_API = "https://api.spigotmc.org/legacy/update.php?resource=%d"; - private static final String SPIGOT_DOWNLOAD = "http://api.spiget.org/v2/resources/%s/download"; + private static final String SPIGOT_DOWNLOAD = "https://api.spiget.org/v2/resources/%s/download"; - private static final String SBDPLUGINS_API = "https://updates.sbdplugins.nl/api/v2/plugins/%d"; - private static final String SBDPLUGINS_DOWNLOAD = "https://updates.sbdplugins.nl/api/v2/download/%d"; + private static final String POLYMART_API = "https://api.polymart.org/v1/getResourceInfoSimple/?resource_id=%d&key=version"; + private static final String POLYMART_DOWNLOAD = "https://api.polymart.org/v1/requestUpdateURL/?inject_version=%d&resource_id=%d&user_id=%d&nonce=%d&download_agent=%d&download_time=%d&download_token=%s"; private final Plugin plugin; private final Version currentVersion; - private final int resourceID; private final CheckType type; - private final String license; + + //Spigot & Polymart + private final int resourceID; + + //Polymart only + private int injector_version; + private int user_id; + private int nonce; + private int download_agent; + private int download_time; + private String download_token; private BiConsumer versionResponse; private BiConsumer downloadResponse; /** - * Construct a new UpdateManager for Spigot + * Construct a new UpdateManager * - * @param plugin The javaplugin (Main class) - * @param resourceID The resourceID on spigot/sbdplugins + * @param plugin The plugin instance */ - public UpdateManager(Plugin plugin, int resourceID) { + public UpdateManager(Plugin plugin, CheckType type) { this.plugin = plugin; this.currentVersion = new Version(plugin.getDescription().getVersion()); - this.resourceID = resourceID; - this.type = CheckType.SPIGOT; - this.license = null; - } - - /** - * Construct a new UpdateManager for SBDPlugins - * - * @param plugin The javaplugin (Main class) - * @param resourceID The resourceID on spigot/sbdplugins - * @param license The license for the download - */ - public UpdateManager(Plugin plugin, int resourceID, String license) { - this.plugin = plugin; - this.currentVersion = new Version(plugin.getDescription().getVersion()); - this.resourceID = resourceID; - this.type = CheckType.SBDPLUGINS; - this.license = license; + this.type = type; + this.resourceID = Integer.parseInt("%%__RESOURCE__%%"); + if (type == CheckType.POLYMART_PAID) { + this.injector_version = Integer.parseInt("%%__INJECT_VER__%%"); + this.user_id = Integer.parseInt("%%__USER__%%"); + this.nonce = Integer.parseInt("%%__NONCE__%%"); + this.download_agent = Integer.parseInt("%%__AGENT__%%"); + this.download_time = Integer.parseInt("%%__TIMESTAMP__%%"); + this.download_token = "%%__VERIFY_TOKEN__%%"; + } } /** @@ -93,25 +94,16 @@ public class UpdateManager { public void check() { Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> { try { - BufferedReader in = null; - if (type == CheckType.SPIGOT) { - HttpsURLConnection con = (HttpsURLConnection) new URL(String.format(SPIGOT_API, this.resourceID)).openConnection(); - con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", "Mozilla/5.0"); - - in = new BufferedReader(new InputStreamReader(con.getInputStream())); - } else if (type == CheckType.SBDPLUGINS) { - HttpsURLConnection con = (HttpsURLConnection) new URL(String.format(SBDPLUGINS_API, this.resourceID)).openConnection(); - con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", "Mozilla/5.0"); - - in = new BufferedReader(new InputStreamReader(con.getInputStream())); + HttpsURLConnection con; + if (type == CheckType.POLYMART_PAID) { + con = (HttpsURLConnection) new URL(String.format(POLYMART_API, this.resourceID)).openConnection(); + } else { + con = (HttpsURLConnection) new URL(String.format(SPIGOT_API, this.resourceID)).openConnection(); } + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "SBDChecker/2.1"); - if (in == null) return; - - String version; - + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); String inputLine; StringBuilder response = new StringBuilder(); while ((inputLine = in.readLine()) != null) { @@ -119,21 +111,7 @@ public class UpdateManager { } in.close(); - JsonParser parser = new JsonParser(); - - if (type == CheckType.SPIGOT) { - JsonArray array = parser.parse(response.toString()).getAsJsonArray(); - - version = array.get(0).getAsJsonObject().get("name").getAsString(); - } else { - JsonObject object = parser.parse(response.toString()).getAsJsonObject(); - - version = object.get("version").getAsString(); - } - - if (version == null) return; - - Version onlineVersion = new Version(version); + Version onlineVersion = new Version(response.toString()); VersionResponse verRes = this.currentVersion.check(onlineVersion); @@ -166,37 +144,16 @@ public class UpdateManager { ReadableByteChannel channel; try { //https://stackoverflow.com/questions/921262/how-to-download-and-save-a-file-from-internet-using-java - int response; - InputStream stream; - if (type == CheckType.SBDPLUGINS) { - HttpURLConnection connection = (HttpURLConnection) new URL(String.format(SBDPLUGINS_DOWNLOAD, this.resourceID)).openConnection(); - - String urlParameters = "license=" + license + "&port=" + Bukkit.getPort(); - byte[] postData = urlParameters.getBytes(StandardCharsets.UTF_8); - int postDataLength = postData.length; - - connection.setRequestMethod("GET"); - connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); - connection.setRequestProperty("charset", "utf-8"); - connection.setRequestProperty("Content-Length", Integer.toString(postDataLength)); - connection.setRequestProperty("User-Agent", "Mozilla/5.0"); - connection.setDoOutput(true); - - DataOutputStream wr = new DataOutputStream(connection.getOutputStream()); - wr.write(postData); - wr.close(); - - response = connection.getResponseCode(); - stream = connection.getInputStream(); + HttpsURLConnection connection; + if (type == CheckType.POLYMART_PAID) { + connection = (HttpsURLConnection) new URL(String.format(POLYMART_DOWNLOAD, this.injector_version, this.resourceID, this.user_id, this.nonce, this.download_agent, this.download_time, this.download_token)).openConnection(); } else { - HttpsURLConnection connection = (HttpsURLConnection) new URL(String.format(SPIGOT_DOWNLOAD, this.resourceID)).openConnection(); - connection.setRequestProperty("User-Agent", "Mozilla/5.0"); - - response = connection.getResponseCode(); - stream = connection.getInputStream(); + connection = (HttpsURLConnection) new URL(String.format(SPIGOT_DOWNLOAD, this.resourceID)).openConnection(); } + connection.setRequestProperty("User-Agent", "Mozilla/5.0"); - if (response != 200) { + InputStream stream = connection.getInputStream(); + if (connection.getResponseCode() != 200) { BufferedReader in = new BufferedReader(new InputStreamReader(stream)); String inputLine; @@ -206,7 +163,7 @@ public class UpdateManager { } in.close(); - throw new RuntimeException("Download returned status #" + response, new Throwable(responsestr.toString())); + throw new RuntimeException("Download returned status #" + connection.getResponseCode(), new Throwable(responsestr.toString())); } channel = Channels.newChannel(stream); @@ -259,8 +216,8 @@ public class UpdateManager { } } - private enum CheckType { - SPIGOT, SBDPLUGINS + public enum CheckType { + SPIGOT, POLYMART_PAID } public enum VersionResponse { diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/sbutils/Verify.java b/src/main/java/nl/sbdeveloper/themeparkplus/sbutils/Verify.java new file mode 100644 index 0000000..4f58f52 --- /dev/null +++ b/src/main/java/nl/sbdeveloper/themeparkplus/sbutils/Verify.java @@ -0,0 +1,165 @@ +/* + * This file is part of ActionFoto. + * Copyright (c) 2018-2022. SBDevelopment - All Rights Reserved + * Unauthorized copying of this file, via any medium is strictly prohibited + * Proprietary and confidential + * Written by Stijn Bannink , April 2022 + */ + +package nl.sbdeveloper.themeparkplus.sbutils; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; + +/** + * Purchase verification class + * + * @author Stijn [SBDeveloper] + * @version 2.0 [17-04-2022] - Updated to Polymart + * @since 23-12-2019 + */ +public class Verify implements Listener { + private static final String endpointURL = "https://api.polymart.org/v1/verifyPurchase/?inject_version=%d&resource_id=%d&user_id=%d&nonce=%d&download_agent=%d&download_time=%d&download_token=%s"; + + private final JavaPlugin plugin; // The plugin instance + + private final int resourceID; + private final int injector_version; + private final int user_id; + private final int nonce; + private final int download_agent; + private final int download_time; + private final String download_token; + + private String invalidReason = null; // The reason the license is invalid, if null it's not invalid! + private static Boolean valid = null; // If true, it's valid, if false, it's not valid, if null it's not checked! + + /** + * Construct a new license + * + * @param plugin The plugin + */ + public Verify(JavaPlugin plugin) { + this.plugin = plugin; + + this.resourceID = Integer.parseInt("%%__RESOURCE__%%"); + this.injector_version = Integer.parseInt("%%__INJECT_VER__%%"); + this.user_id = Integer.parseInt("%%__USER__%%"); + this.nonce = Integer.parseInt("%%__NONCE__%%"); + this.download_agent = Integer.parseInt("%%__AGENT__%%"); + this.download_time = Integer.parseInt("%%__TIMESTAMP__%%"); + this.download_token = "%%__VERIFY_TOKEN__%%"; + + Bukkit.getPluginManager().registerEvents(this, plugin); + + validate(); + } + + @EventHandler + public void onJoin(PlayerJoinEvent e) { + if (this.invalidReason == null) return; + + Player p = e.getPlayer(); + if (p.isOp() || p.hasPermission("sbd.licensemessages")) { + Bukkit.getScheduler().runTaskLater(this.plugin, () -> p.sendMessage(ChatColor.GOLD + "[" + ChatColor.RED + this.plugin.getName() + ChatColor.GOLD + "] " + ChatColor.RED + "The license is incorrect! Reason: " + ChatColor.GOLD + this.invalidReason), 5 * 20L /* 5 sec */); + } + } + + /** + * Validate the purchase + */ + private void validate() { + try { + URL url = new URL(String.format(endpointURL, this.injector_version, this.resourceID, this.user_id, this.nonce, this.download_agent, this.download_time, this.download_token)); + HttpURLConnection con = (HttpURLConnection) url.openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "SBDVerify/2.0"); + con.setConnectTimeout(5000); //Timeout after 5 sec. + con.setReadTimeout(5000); //Timeout after 5 sec. + int code = con.getResponseCode(); + if (code != 200) { + disable("Could not send the validating request."); + return; + } + BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream())); + String inputLine; + StringBuilder response = new StringBuilder(); + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + + JsonObject json = new JsonParser().parse(response.toString()).getAsJsonObject(); + if (json == null) { + disable("Could not send the validating request."); + return; + } + + if (!json.has("response")) { + disable("An invalid response was returned by the validating request."); + return; + } + + JsonObject resp = json.get("response").getAsJsonObject(); + if (!resp.has("success")) { + disable("An invalid response was returned by the validating request."); + return; + } + + if (!resp.get("success").getAsBoolean()) { + disable("The purchase of this plugin could not be verified."); + } + } catch (IOException e) { + disable("Could not send the validating request."); + } + } + + /** + * Disable the plugin (private) + * + * @param reason The disabling reason + */ + private void disable(String reason) { + this.invalidReason = reason; + + Bukkit.getScheduler().runTask(this.plugin, () -> { + valid = false; + + plugin.getLogger().severe("Stopping plugin because licensing system check failed."); + plugin.getLogger().severe("Reason: " + reason); + plugin.getLogger().severe("Contact the developer if you believe something is wrong on their side."); + Bukkit.getPluginManager().disablePlugin(this.plugin); + }); + } + + /** + * Check if the license is valid + * + * @return true = VALID, false = INVALID, null = UNCHECKED + */ + public Boolean isValidated() { + return this.invalidReason == null; + } + + /** + * Check if the license is valid + * + * @return true = VALID, false = INVALID, null = UNCHECKED + */ + public static Boolean isValid() { + return valid; + } +} \ No newline at end of file diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/util/License.java b/src/main/java/nl/sbdeveloper/themeparkplus/util/License.java deleted file mode 100644 index fc01aae..0000000 --- a/src/main/java/nl/sbdeveloper/themeparkplus/util/License.java +++ /dev/null @@ -1,312 +0,0 @@ -package nl.sbdeveloper.themeparkplus.util; - -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerJoinEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.nio.charset.StandardCharsets; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; - -/** - * License class for SBDevelopment - * - * v1.6 - Changed on 06-08-2020 - * - * @author Stijn [SBDeveloper] - * @since 23-12-2019 - */ -public class License implements Listener { - /* - This file is part of ThemeParkRidecountAddon. - Copyright (c) 2018-2020 SBDevelopment - All Rights Reserved - Unauthorized copying of this file, via any medium is strictly prohibited - Proprietary and confidential - Written by Stijn Bannink , January 2020 - */ - - private final JavaPlugin plugin; // The plugin instance - private final String license; // The license code - private final String prefix; // The correct prefix for this plugin - private String invalidReason; // The reason the license is invalid, if null it's not invalid! - private static Boolean valid; // If true, it's valid, if false, it's not valid, if null it's not checked! - - /** - * Construct a new license - * @param plugin The Main class [Javaplugin] - * @param prefix The prefix, like TPP or AF - * @param license The license from the config - */ - public License(JavaPlugin plugin, String prefix, String license) { - this.prefix = prefix; - this.plugin = plugin; - this.license = license; - - Bukkit.getPluginManager().registerEvents(this, plugin); - - validateLicense(); - } - - @EventHandler - public void onJoin(PlayerJoinEvent e) { - if (this.invalidReason == null) return; - - Player p = e.getPlayer(); - if (p.isOp() || p.hasPermission("sbd.licensemessages")) { - Bukkit.getScheduler().runTaskLater(this.plugin, () -> p.sendMessage(ChatColor.GOLD + "[" + ChatColor.RED + this.plugin.getName() + ChatColor.GOLD + "] " + ChatColor.RED + "The license is incorrect! Reason: " + ChatColor.GOLD + this.invalidReason), 3 * 20L /* 3 sec */); - } - } - - /** - * Check a license - * - */ - private void validateLicense() { - //STEP 1: Check prefix - if (!this.license.split("-")[0].contains(this.prefix)) { - disable("You used the wrong license for this product."); - return; - } - - //STEP 2: Send license request - String url = "https://sbdplugins.nl/wp-json/lmfwc/v2/licenses/" + this.license; - JsonObject response; - try { - response = sendGETRequestJSON(url); - } catch (IOException e) { - disable("Something went wrong while sending the request."); - return; - } - - if (response == null) { - disable("Something went wrong while sending the request. Did you even fill out a license?"); - return; - } - - JsonObject dataObject = response.get("data").getAsJsonObject(); - - //STEP 3: Check status - switch(dataObject.get("status").getAsString()) { - case "2": - //Delivered -> Try to activate (double check timesActivated) - break; - case "3": - //Activated! - break; - default: - disable("Your license has a wrong status."); - return; - } - - //STEP 4: Check times activated, and if not activated, activate. - if (dataObject.get("timesActivated").isJsonNull() || dataObject.get("timesActivated").getAsString().equalsIgnoreCase("0")) { - activate(); - return; - } - - //STEP 5: Check expire date - if (dataObject.get("expiresAt").isJsonNull()) { - disable("Your license has no expire date."); - return; - } - - SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - Date date; - try { - date = format.parse(dataObject.get("expiresAt").getAsString()); - } catch (ParseException e) { - e.printStackTrace(); - disable("Your license has a wrong expire date."); - return; - } - - if (date == null) { - disable("Your license has a wrong expire date."); - return; - } - - if (!(date.after(new Date()))) { - disable("Your license has expired."); - return; - } - - //STEP 6: Check IP and port. - if (!dataObject.get("ipcheck").getAsBoolean()) { - disable("Your license has been used with another IP. Update it in our Discord."); - return; - } - - if (dataObject.get("port").isJsonNull()) { - disable("Your license has no port."); - return; - } - - String por = dataObject.get("port").getAsString(); - if (!checkPortValue(Bukkit.getServer().getPort(), por)) { - disable("Your license has been used with another Port. Update it in our Discord."); - return; - } - - valid = true; - } - - /** - * Activate the license - * - */ - private void activate() { - //STEP 1: Send license activate request - String url = "https://sbdplugins.nl/wp-json/lmfwc/v2/licenses/activate/" + this.license + "?port=" + Bukkit.getServer().getPort(); - @Nullable JsonObject response; - try { - response = sendGETRequestJSON(url); - } catch (IOException e) { - disable("Something went wrong while sending the request."); - return; - } - - if (response == null) { - disable("Something went wrong while sending the request. Did you even fill out a license?"); - return; - } - - JsonObject dataObject = response.get("data").getAsJsonObject(); - - //STEP 2: Check status - switch(dataObject.get("status").getAsString()) { - case "2": - //Delivered -> STILL NOT ACTIVATED?! -> Double check - break; - case "3": - //Activated! - break; - default: - disable("Your license has a wrong status."); - return; - } - - //STEP 3: Check times activated, and if still not activated, disable. - if (dataObject.get("timesActivated").isJsonNull() || dataObject.get("timesActivated").getAsString().equalsIgnoreCase("0")) { - disable("Couldn't activate the license."); - } - } - - /** - * Disable the plugin (private) - * - * @param reason The disabling reason - */ - private void disable(String reason) { - this.invalidReason = reason; - - Bukkit.getScheduler().runTask(this.plugin, () -> { - valid = false; - - Bukkit.getLogger().severe("[" + this.plugin.getName() + "] Stopping plugin because licensing system check failed."); - Bukkit.getLogger().severe("[" + this.plugin.getName() + "] Reason: " + reason); - Bukkit.getLogger().severe("[" + this.plugin.getName() + "] Contact the developer if you believe something is wrong on their side."); - Bukkit.getPluginManager().disablePlugin(this.plugin); - }); - } - - /** - * Send an GET request with JSONObject response - * - * @param uri The URL - * - * @return The JSONObject - * @throws IOException URL errors - */ - private JsonObject sendGETRequestJSON(String uri) throws IOException { - URL url = new URL(uri); - HttpURLConnection con = (HttpURLConnection) url.openConnection(); - con.setRequestMethod("GET"); - con.setRequestProperty("User-Agent", "Mozilla/5.0"); - String authStringEnc = "Y2tfMGEzNWEzMWE2NzExNmM3NDg2MGEwYTJhNjUxNGVjZjM4NTBmM2JmMDpjc185NmYxZGNlYjI4MWRkZDExOTBjMzQ3ZjJjYzMwMGNjZTIzYWNhODI1"; - con.setRequestProperty("Authorization", "Basic " + authStringEnc); - int code = con.getResponseCode(); - if (code == 404) { - return null; - } - - BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream(), StandardCharsets.UTF_8)); - String inputLine; - boolean firstLine = true; - StringBuilder response = new StringBuilder(); - while ((inputLine = in.readLine()) != null) { - if (firstLine) { inputLine = removeUTF8BOM(inputLine); firstLine = false; } - response.append(inputLine); - } - in.close(); - - JsonParser parser = new JsonParser(); - return parser.parse(response.toString()).getAsJsonObject(); - } - - private boolean checkPortValue(int input, String dataValue) { - //STEP 1: Check wildcard - if (dataValue.equals("*")) return true; - - //STEP 2: Check if equals - try { - int dataVal = Integer.parseInt(dataValue); - - return input == dataVal; - } catch (NumberFormatException ignored) {} - - //STEP 3: Check if range - if (dataValue.contains("-")) { - String[] dataSplit = dataValue.split("-"); - - //STEP 3.1: Check if min or max is wildcard - if (dataSplit[0].equals("*") && !dataSplit[1].equals("*")) { - int max = Integer.parseInt(dataSplit[1]); - return input <= max; - } else if (dataSplit[1].equals("*") && !dataSplit[0].equals("*")) { - int min = Integer.parseInt(dataSplit[0]); - return min <= input; - } else { - try { - int min = Integer.parseInt(dataSplit[0]); - int max = Integer.parseInt(dataSplit[1]); - - return (min <= input) && (input <= max); - } catch (NumberFormatException ex) { - return false; - } - } - } - - //Else, invalid value - return false; - } - - private String removeUTF8BOM(String s) { - String UTF8_BOM = "\uFEFF"; - if (s.startsWith(UTF8_BOM)) { - s = s.substring(1); - } - return s; - } - - /** - * Check if the license is valid - * - * @return true -> VALID, false -> INVALID, null -> UNCHECKED - */ - public static Boolean isValid() { - return valid; - } -} \ No newline at end of file