diff --git a/README.md b/OpSecurity V2/README.md similarity index 100% rename from README.md rename to OpSecurity V2/README.md diff --git a/pom.xml b/OpSecurity V2/pom.xml similarity index 100% rename from pom.xml rename to OpSecurity V2/pom.xml diff --git a/src/main/java/de/jatitv/opsecurity/Util.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/Util.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/Util.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/Util.java diff --git a/src/main/java/de/jatitv/opsecurity/cmdManagement/CmdExecuter.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/cmdManagement/CmdExecuter.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/cmdManagement/CmdExecuter.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/cmdManagement/CmdExecuter.java diff --git a/src/main/java/de/jatitv/opsecurity/cmdManagement/Commands.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/cmdManagement/Commands.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/cmdManagement/Commands.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/cmdManagement/Commands.java diff --git a/src/main/java/de/jatitv/opsecurity/config/config/ConfigConvert.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/config/ConfigConvert.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/config/config/ConfigConvert.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/config/ConfigConvert.java diff --git a/src/main/java/de/jatitv/opsecurity/config/config/CreateConfig.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/config/CreateConfig.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/config/config/CreateConfig.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/config/CreateConfig.java diff --git a/src/main/java/de/jatitv/opsecurity/config/config/SelectConfig.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/config/SelectConfig.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/config/config/SelectConfig.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/config/SelectConfig.java diff --git a/src/main/java/de/jatitv/opsecurity/config/languages/LanguagesCreate.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/languages/LanguagesCreate.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/config/languages/LanguagesCreate.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/languages/LanguagesCreate.java diff --git a/src/main/java/de/jatitv/opsecurity/config/languages/MSG.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/languages/MSG.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/config/languages/MSG.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/languages/MSG.java diff --git a/src/main/java/de/jatitv/opsecurity/config/languages/SelectMessages.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/languages/SelectMessages.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/config/languages/SelectMessages.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/config/languages/SelectMessages.java diff --git a/src/main/java/de/jatitv/opsecurity/listener/Check.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/Check.java similarity index 99% rename from src/main/java/de/jatitv/opsecurity/listener/Check.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/Check.java index 0c61a5a..5e680ba 100644 --- a/src/main/java/de/jatitv/opsecurity/listener/Check.java +++ b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/Check.java @@ -103,6 +103,7 @@ public class Check { } } } + if (SelectConfig.playerWhithPermissionKick && SelectConfig.permCommandEnable) { T2Ccmd.console(SelectConfig.kickCommand.replace("[player]", player.getName()).replace("[reason]", T2Creplace.replace(Util.getPrefix(), SelectMessages.Perm_kick))); T2Csend.console(T2Creplace.replace(Util.getPrefix(), SelectMessages.Perm_consoleKick.replace("[player]", @@ -120,6 +121,7 @@ public class Check { for (String cmd : SelectConfig.permCommand) { T2Ccmd.console(cmd.replace("[player]", player.getName()).replace("[perm]", s)); } + } return true; } diff --git a/src/main/java/de/jatitv/opsecurity/listener/Events.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/Events.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/listener/Events.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/Events.java diff --git a/src/main/java/de/jatitv/opsecurity/listener/LPCommand.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/LPCommand.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/listener/LPCommand.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/LPCommand.java diff --git a/src/main/java/de/jatitv/opsecurity/listener/OPCommand.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/OPCommand.java similarity index 99% rename from src/main/java/de/jatitv/opsecurity/listener/OPCommand.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/OPCommand.java index c61b31f..aad3047 100644 --- a/src/main/java/de/jatitv/opsecurity/listener/OPCommand.java +++ b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/OPCommand.java @@ -40,7 +40,6 @@ public class OPCommand implements Listener { @EventHandler public void onOpPlayer(PlayerCommandPreprocessEvent event) { - if (SelectConfig.opWhitelistEnable) { if ((event.getMessage().toLowerCase().startsWith("/op ") || event.getMessage().toLowerCase().startsWith("/minecraft:op "))) { switch (this.isNotOPWTL(event.getMessage())) { diff --git a/src/main/java/de/jatitv/opsecurity/listener/PlugManCommand.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/PlugManCommand.java similarity index 99% rename from src/main/java/de/jatitv/opsecurity/listener/PlugManCommand.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/PlugManCommand.java index b2d78e9..07b78e4 100644 --- a/src/main/java/de/jatitv/opsecurity/listener/PlugManCommand.java +++ b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/PlugManCommand.java @@ -12,7 +12,6 @@ import org.bukkit.event.server.ServerCommandEvent; public class PlugManCommand implements Listener { - @EventHandler public void onOPServer(ServerCommandEvent event) { if ((event.getCommand().toLowerCase().contains("plugman disable") && event.getCommand().toLowerCase().contains(Main.getPlugin().getDescription().getName().toLowerCase())) diff --git a/src/main/java/de/jatitv/opsecurity/listener/Timer.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/Timer.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/listener/Timer.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/listener/Timer.java diff --git a/src/main/java/de/jatitv/opsecurity/objects/PlayerObject.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/objects/PlayerObject.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/objects/PlayerObject.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/objects/PlayerObject.java diff --git a/src/main/java/de/jatitv/opsecurity/system/Load.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/system/Load.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/system/Load.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/system/Load.java diff --git a/src/main/java/de/jatitv/opsecurity/system/Main.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/system/Main.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/system/Main.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/system/Main.java diff --git a/src/main/java/de/jatitv/opsecurity/system/Metrics.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/system/Metrics.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/system/Metrics.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/system/Metrics.java diff --git a/src/main/java/de/jatitv/opsecurity/system/NameHistory.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/system/NameHistory.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/system/NameHistory.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/system/NameHistory.java diff --git a/src/main/java/de/jatitv/opsecurity/system/Permissions.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/system/Permissions.java similarity index 100% rename from src/main/java/de/jatitv/opsecurity/system/Permissions.java rename to OpSecurity V2/src/main/java/de/jatitv/opsecurity/system/Permissions.java diff --git a/OpSecurity V2/src/main/java/de/jatitv/opsecurity/util/Metrics.java b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/util/Metrics.java new file mode 100644 index 0000000..7564cb0 --- /dev/null +++ b/OpSecurity V2/src/main/java/de/jatitv/opsecurity/util/Metrics.java @@ -0,0 +1,846 @@ +// This claas was created by JaTiTV + +package de.jatitv.opsecurity.system; + +import de.jatitv.opsecurity.Util; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; + +public class Metrics { + + public static void Bstats() { + int pluginId = Util.getBstatsID(); // <-- Replace with the id of your plugin! + Metrics metrics = new Metrics(Main.getPlugin(), pluginId); + } + + private final Plugin plugin; + + private final MetricsBase metricsBase; + + /** + * Creates a new Metrics instance. + * + * @param plugin Your plugin instance. + * @param serviceId The id of the service. It can be found at What is my plugin id? + */ + public Metrics(JavaPlugin plugin, int serviceId) { + this.plugin = plugin; + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + if (!config.isSet("serverUuid")) { + config.addDefault("enabled", true); + config.addDefault("serverUuid", UUID.randomUUID().toString()); + config.addDefault("logFailedRequests", false); + config.addDefault("logSentData", false); + config.addDefault("logResponseStatusText", false); + // Inform the server owners about bStats + config + .options() + .header( + "bStats (https://bStats.org) collects some basic information for plugin authors, like how\n" + + "many people use their plugin and their total player count. It's recommended to keep bStats\n" + + "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n" + + "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n" + + "anonymous.") + .copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { + } + } + // Load the data + boolean enabled = config.getBoolean("enabled", true); + String serverUUID = config.getString("serverUuid"); + boolean logErrors = config.getBoolean("logFailedRequests", false); + boolean logSentData = config.getBoolean("logSentData", false); + boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false); + metricsBase = + new MetricsBase( + "bukkit", + serverUUID, + serviceId, + enabled, + this::appendPlatformData, + this::appendServiceData, + submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask), + plugin::isEnabled, + (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error), + (message) -> this.plugin.getLogger().log(Level.INFO, message), + logErrors, + logSentData, + logResponseStatusText); + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + metricsBase.addCustomChart(chart); + } + + private void appendPlatformData(JsonObjectBuilder builder) { + builder.appendField("playerAmount", getPlayerAmount()); + builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0); + builder.appendField("bukkitVersion", Bukkit.getVersion()); + builder.appendField("bukkitName", Bukkit.getName()); + builder.appendField("javaVersion", System.getProperty("java.version")); + builder.appendField("osName", System.getProperty("os.name")); + builder.appendField("osArch", System.getProperty("os.arch")); + builder.appendField("osVersion", System.getProperty("os.version")); + builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); + } + + private void appendServiceData(JsonObjectBuilder builder) { + builder.appendField("pluginVersion", plugin.getDescription().getVersion()); + } + + private int getPlayerAmount() { + try { + // Around MC 1.8 the return type was changed from an array to a collection, + // This fixes java.lang.NoSuchMethodError: + // org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + return onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + // Just use the new method if the reflection failed + return Bukkit.getOnlinePlayers().size(); + } + } + + public static class MetricsBase { + + /** The version of the Metrics class. */ + public static final String METRICS_VERSION = "2.2.1"; + + private static final ScheduledExecutorService scheduler = + Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics")); + + private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s"; + + private final String platform; + + private final String serverUuid; + + private final int serviceId; + + private final Consumer appendPlatformDataConsumer; + + private final Consumer appendServiceDataConsumer; + + private final Consumer submitTaskConsumer; + + private final Supplier checkServiceEnabledSupplier; + + private final BiConsumer errorLogger; + + private final Consumer infoLogger; + + private final boolean logErrors; + + private final boolean logSentData; + + private final boolean logResponseStatusText; + + private final Set customCharts = new HashSet<>(); + + private final boolean enabled; + + /** + * Creates a new MetricsBase class instance. + * + * @param platform The platform of the service. + * @param serviceId The id of the service. + * @param serverUuid The server uuid. + * @param enabled Whether or not data sending is enabled. + * @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all platform-specific data. + * @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all service-specific data. + * @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be + * used to delegate the data collection to a another thread to prevent errors caused by + * concurrency. Can be {@code null}. + * @param checkServiceEnabledSupplier A supplier to check if the service is still enabled. + * @param errorLogger A consumer that accepts log message and an error. + * @param infoLogger A consumer that accepts info log messages. + * @param logErrors Whether or not errors should be logged. + * @param logSentData Whether or not the sent data should be logged. + * @param logResponseStatusText Whether or not the response status text should be logged. + */ + public MetricsBase( + String platform, + String serverUuid, + int serviceId, + boolean enabled, + Consumer appendPlatformDataConsumer, + Consumer appendServiceDataConsumer, + Consumer submitTaskConsumer, + Supplier checkServiceEnabledSupplier, + BiConsumer errorLogger, + Consumer infoLogger, + boolean logErrors, + boolean logSentData, + boolean logResponseStatusText) { + this.platform = platform; + this.serverUuid = serverUuid; + this.serviceId = serviceId; + this.enabled = enabled; + this.appendPlatformDataConsumer = appendPlatformDataConsumer; + this.appendServiceDataConsumer = appendServiceDataConsumer; + this.submitTaskConsumer = submitTaskConsumer; + this.checkServiceEnabledSupplier = checkServiceEnabledSupplier; + this.errorLogger = errorLogger; + this.infoLogger = infoLogger; + this.logErrors = logErrors; + this.logSentData = logSentData; + this.logResponseStatusText = logResponseStatusText; + checkRelocation(); + if (enabled) { + startSubmitting(); + } + } + + public void addCustomChart(CustomChart chart) { + this.customCharts.add(chart); + } + + private void startSubmitting() { + final Runnable submitTask = + () -> { + if (!enabled || !checkServiceEnabledSupplier.get()) { + // Submitting data or service is disabled + scheduler.shutdown(); + return; + } + if (submitTaskConsumer != null) { + submitTaskConsumer.accept(this::submitData); + } else { + this.submitData(); + } + }; + // Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution + // of requests on the + // bStats backend. To circumvent this problem, we introduce some randomness into the initial + // and second delay. + // WARNING: You must not modify and part of this Metrics class, including the submit delay or + // frequency! + // WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it! + long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); + long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); + scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); + scheduler.scheduleAtFixedRate( + submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS); + } + + private void submitData() { + final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder(); + appendPlatformDataConsumer.accept(baseJsonBuilder); + final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder(); + appendServiceDataConsumer.accept(serviceJsonBuilder); + JsonObjectBuilder.JsonObject[] chartData = + customCharts.stream() + .map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors)) + .filter(Objects::nonNull) + .toArray(JsonObjectBuilder.JsonObject[]::new); + serviceJsonBuilder.appendField("id", serviceId); + serviceJsonBuilder.appendField("customCharts", chartData); + baseJsonBuilder.appendField("service", serviceJsonBuilder.build()); + baseJsonBuilder.appendField("serverUUID", serverUuid); + baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION); + JsonObjectBuilder.JsonObject data = baseJsonBuilder.build(); + scheduler.execute( + () -> { + try { + // Send the data + sendData(data); + } catch (Exception e) { + // Something went wrong! :( + if (logErrors) { + errorLogger.accept("Could not submit bStats metrics data", e); + } + } + }); + } + + private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { + if (logSentData) { + infoLogger.accept("Sent bStats metrics data: " + data.toString()); + } + String url = String.format(REPORT_URL, platform); + HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "Metrics-Service/1"); + connection.setDoOutput(true); + try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { + outputStream.write(compressedData); + } + StringBuilder builder = new StringBuilder(); + try (BufferedReader bufferedReader = + new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + if (logResponseStatusText) { + infoLogger.accept("Sent data to bStats and received response: " + builder); + } + } + + /** Checks that the class was properly relocated. */ + private void checkRelocation() { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null + || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little + // "trick" ... :D + final String defaultPackage = + new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'}); + final String examplePackage = + new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure no one just copy & pastes the example and uses the wrong package + // names + if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) + || MetricsBase.class.getPackage().getName().startsWith(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + /** + * Gzips the given string. + * + * @param str The string to gzip. + * @return The gzipped string. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + return outputStream.toByteArray(); + } + } + + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public abstract static class CustomChart { + + private final String chartId; + + protected CustomChart(String chartId) { + if (chartId == null) { + throw new IllegalArgumentException("chartId must not be null"); + } + this.chartId = chartId; + } + + public JsonObjectBuilder.JsonObject getRequestJsonObject( + BiConsumer errorLogger, boolean logErrors) { + JsonObjectBuilder builder = new JsonObjectBuilder(); + builder.appendField("chartId", chartId); + try { + JsonObjectBuilder.JsonObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + builder.appendField("data", data); + } catch (Throwable t) { + if (logErrors) { + errorLogger.accept("Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return builder.build(); + } + + protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; + } + + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + /** + * An extremely simple JSON builder. + * + *

While this class is neither feature-rich nor the most performant one, it's sufficient enough + * for its use-case. + */ + public static class JsonObjectBuilder { + + private StringBuilder builder = new StringBuilder(); + + private boolean hasAtLeastOneField = false; + + public JsonObjectBuilder() { + builder.append("{"); + } + + /** + * Appends a null field to the JSON. + * + * @param key The key of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendNull(String key) { + appendFieldUnescaped(key, "null"); + return this; + } + + /** + * Appends a string field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String value) { + if (value == null) { + throw new IllegalArgumentException("JSON value must not be null"); + } + appendFieldUnescaped(key, "\"" + escape(value) + "\""); + return this; + } + + /** + * Appends an integer field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int value) { + appendFieldUnescaped(key, String.valueOf(value)); + return this; + } + + /** + * Appends an object to the JSON. + * + * @param key The key of the field. + * @param object The object. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject object) { + if (object == null) { + throw new IllegalArgumentException("JSON object must not be null"); + } + appendFieldUnescaped(key, object.toString()); + return this; + } + + /** + * Appends a string array to the JSON. + * + * @param key The key of the field. + * @param values The string array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values) + .map(value -> "\"" + escape(value) + "\"") + .collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an integer array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an object array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends a field to the object. + * + * @param key The key of the field. + * @param escapedValue The escaped value of the field. + */ + private void appendFieldUnescaped(String key, String escapedValue) { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + if (key == null) { + throw new IllegalArgumentException("JSON key must not be null"); + } + if (hasAtLeastOneField) { + builder.append(","); + } + builder.append("\"").append(escape(key)).append("\":").append(escapedValue); + hasAtLeastOneField = true; + } + + /** + * Builds the JSON string and invalidates this builder. + * + * @return The built JSON string. + */ + public JsonObject build() { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + JsonObject object = new JsonObject(builder.append("}").toString()); + builder = null; + return object; + } + + /** + * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt. + * + *

This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'. + * Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n"). + * + * @param value The value to escape. + * @return The escaped value. + */ + private static String escape(String value) { + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (c == '"') { + builder.append("\\\""); + } else if (c == '\\') { + builder.append("\\\\"); + } else if (c <= '\u000F') { + builder.append("\\u000").append(Integer.toHexString(c)); + } else if (c <= '\u001F') { + builder.append("\\u00").append(Integer.toHexString(c)); + } else { + builder.append(c); + } + } + return builder.toString(); + } + + /** + * A super simple representation of a JSON object. + * + *

This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not + * allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String, + * JsonObject)}. + */ + public static class JsonObject { + + private final String value; + + private JsonObject(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/OpSecurity V2/src/main/resources/plugin.yml similarity index 100% rename from src/main/resources/plugin.yml rename to OpSecurity V2/src/main/resources/plugin.yml diff --git a/OpSecurity V3/.gitignore b/OpSecurity V3/.gitignore new file mode 100644 index 0000000..4788b4b --- /dev/null +++ b/OpSecurity V3/.gitignore @@ -0,0 +1,113 @@ +# User-specific stuff +.idea/ + +*.iml +*.ipr +*.iws + +# IntelliJ +out/ + +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +target/ + +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next + +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +.mvn/wrapper/maven-wrapper.jar +.flattened-pom.xml + +# Common working directory +run/ diff --git a/OpSecurity V3/pom.xml b/OpSecurity V3/pom.xml new file mode 100644 index 0000000..2772c25 --- /dev/null +++ b/OpSecurity V3/pom.xml @@ -0,0 +1,100 @@ + + + 4.0.0 + + net.t2code + T2C-OPSecurity + 3.0.2 + jar + + T2C-OPSecurity + + + 1.8 + UTF-8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + false + + + + + + + + src/main/resources + true + + + + + + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + sonatype + https://oss.sonatype.org/content/groups/public/ + + + + T2Code + https://repo.t2code.net/repository/T2Code/ + + + + + + + org.spigotmc + spigot-api + 1.19.2-R0.1-SNAPSHOT + provided + + + + net.t2code + T2CodeLib + 13.2 + + + + org.projectlombok + lombok + 1.18.24 + provided + + + org.projectlombok + lombok + 1.18.22 + compile + + + diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/Util.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/Util.java new file mode 100644 index 0000000..89aae40 --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/Util.java @@ -0,0 +1,28 @@ +package net.t2code.opsecurity; + +import lombok.Getter; + +public class Util { + + @Getter + private static String infoText = ""; + + @Getter + private static String requiredT2CodeLibVersion = "13.2"; + + @Getter + private static String prefix = "§8[§4T2C§8-§2OP§4Security§8]"; + + @Getter + private static Integer spigotID = 90739; + + @Getter + private static Integer bstatsID = 10858; + + @Getter + private static String spigot = "https://www.spigotmc.org/resources/" + getSpigotID(); + + @Getter + private static String discord = "http://dc.t2code.net"; + +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/check/OpCheck.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/check/OpCheck.java new file mode 100644 index 0000000..8487ce5 --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/check/OpCheck.java @@ -0,0 +1,97 @@ +package net.t2code.opsecurity.check; + +import net.t2code.opsecurity.config.config.Config; +import net.t2code.opsecurity.config.language.Language; +import net.t2code.opsecurity.config.opWhitelist.OPWhitelist; +import net.t2code.opsecurity.events.Events; +import net.t2code.opsecurity.objects.PlayerCash; +import net.t2code.opsecurity.objects.PlayerObject; +import net.t2code.opsecurity.system.BungeeSenderReceiver; +import net.t2code.opsecurity.system.Main; +import net.t2code.t2codelib.SPIGOT.api.commands.T2Ccmd; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Csend; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class OpCheck { + public static Boolean onCheck(Player player, Boolean join) { + if (!OPWhitelist.enable.valueBoolean) return false; + if (!player.isOp()) return false; + if (opWhitelist(player)) return false; + if (join) T2Csend.console(Language.opWhitelistNotifyOnJoin.value.replace("[player]", player.getName()).replace("[uuid]", String.valueOf(player.getUniqueId()))); + Bukkit.getScheduler().runTask(Main.getPlugin(), new Runnable() { + @Override + public void run() { + execute(player, join); + } + }); + return true; + } + + private static void execute(Player player, Boolean join) { + if (Config.notifyJoinWarning.valueBoolean && join) { + if (Config.notifyBungee.valueBoolean) { + BungeeSenderReceiver.sendToBungee(Language.opWhitelistNotifyOnJoin.value.replace("[player]", player.getName()).replace("[uuid]", String.valueOf(player.getUniqueId()))); + } else Events.notifyPlayer(Language.opWhitelistNotifyOnJoin.value.replace("[player]", player.getName()).replace("[uuid]", String.valueOf(player.getUniqueId()))); + } + + if (OPWhitelist.noOpPlayerSetGameModeEnable.valueBoolean) { + player.setGameMode(OPWhitelist.noOpPlayerSetGameModeValue.valueGameMode); + } + + if (OPWhitelist.noOpPlayerDeopEnable.valueBoolean) { + player.setOp(false); + if (OPWhitelist.noOpPlayerKickEnable.valueBoolean) { + if (!OPWhitelist.customCommandsEnable.valueBoolean) { + if (Config.kickCustomCommand.valueBoolean) { + T2Ccmd.console(Config.kickCommand.valueString.replace("[player]", player.getName()).replace("[reason]", + OPWhitelist.noOpPlayerKickEnable.valueBoolean && OPWhitelist.noOpPlayerDeopEnable.valueBoolean && OPWhitelist.noOpPlayerDeopPlayerSendMessage.valueBoolean + ? Language.opWhitelistKick.value + "

" + Language.opWhitelistDeop.value : Language.opWhitelistKick.value)); + } else player.kickPlayer(OPWhitelist.noOpPlayerDeopEnable.valueBoolean && OPWhitelist.noOpPlayerDeopPlayerSendMessage.valueBoolean + ? Language.opWhitelistKick.value + "\n \n" + Language.opWhitelistDeop.value : Language.opWhitelistKick.value); + } + T2Csend.console(Language.opWhitelistNotifyDeop.value.replace("[player]", player.getName().replace("[uuid]", String.valueOf(player.getUniqueId()))) + "
" + + Language.opWhitelistNotifyKick.value.replace("[player]", player.getName().replace("[uuid]", String.valueOf(player.getUniqueId()))).replace("[uuid]", String.valueOf(player.getUniqueId()))); + Events.notifyPlayer(Language.opWhitelistNotifyDeop.value.replace("[player]", player.getName()) + "
" + + Language.opWhitelistNotifyKick.value.replace("[player]", player.getName()).replace("[uuid]", String.valueOf(player.getUniqueId()))); + } else { + T2Csend.console(Language.opWhitelistNotifyDeop.value.replace("[player]", player.getName()).replace("[uuid]", String.valueOf(player.getUniqueId()))); + Events.notifyPlayer(Language.opWhitelistNotifyDeop.value.replace("[player]", player.getName()).replace("[uuid]", String.valueOf(player.getUniqueId()))); + + if (OPWhitelist.noOpPlayerDeopPlayerSendMessage.valueBoolean) { + Bukkit.getScheduler().runTaskLater(Main.getPlugin(), new Runnable() { + @Override + public void run() { + T2Csend.player(player, Language.opWhitelistDeop.value); + } + }, 5L); + } + } + } + if (OPWhitelist.noOpPlayerKickEnable.valueBoolean) { + if (!OPWhitelist.noOpPlayerDeopEnable.valueBoolean) { + if (!OPWhitelist.customCommandsEnable.valueBoolean) { + if (Config.kickCustomCommand.valueBoolean) { + T2Ccmd.console(Config.kickCommand.valueString.replace("[player]", player.getName()).replace("[reason]", Language.opWhitelistKick.value)); + } else player.kickPlayer(Language.opWhitelistKick.value); + } + T2Csend.console(Language.opWhitelistNotifyKick.value.replace("[player]", player.getName()).replace("[uuid]", String.valueOf(player.getUniqueId()))); + Events.notifyPlayer(Language.opWhitelistNotifyKick.value.replace("[player]", player.getName()).replace("[uuid]", String.valueOf(player.getUniqueId()))); + } + } + if (OPWhitelist.customCommandsEnable.valueBoolean) { + for (String cmd : OPWhitelist.customCommandsCommands.valueStringList) { + T2Ccmd.console(cmd.replace("[player]", player.getName())); + } + } + } + + public static Boolean opWhitelist(Player player) { + for (Map.Entry playerObject : PlayerCash.getOpHashMap().entrySet()) { + if (playerObject.getValue().playerName.equals(player.getName()) && playerObject.getValue().uuid.equals(player.getUniqueId().toString())) return true; + } + return false; + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/check/PermissionCheck.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/check/PermissionCheck.java new file mode 100644 index 0000000..08fa254 --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/check/PermissionCheck.java @@ -0,0 +1,63 @@ +package net.t2code.opsecurity.check; + +import net.t2code.opsecurity.config.config.Config; +import net.t2code.opsecurity.config.language.Language; +import net.t2code.opsecurity.config.permissionWhitelist.PermissionWhitelist; +import net.t2code.opsecurity.events.Events; +import net.t2code.opsecurity.objects.PlayerCash; +import net.t2code.opsecurity.objects.PlayerObject; +import net.t2code.opsecurity.system.BungeeSenderReceiver; +import net.t2code.opsecurity.system.Main; +import net.t2code.t2codelib.SPIGOT.api.commands.T2Ccmd; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Csend; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import java.util.Map; + +public class PermissionCheck { + public static Boolean onCheck(Player player, Boolean join) { + if (!PermissionWhitelist.enable.valueBoolean) return false; + for (String perm : PermissionWhitelist.permissions.valueStringList) { + if (!player.hasPermission(perm)) continue; + if (permWhitelist(player)) continue; + Bukkit.getScheduler().runTask(Main.getPlugin(), new Runnable() { + @Override + public void run() { + execute(player, join, perm); + } + }); + return true; + } + return false; + } + + private static void execute(Player player, Boolean join, String perm) { + if (join) T2Csend.console(Language.permissionWhitelistNotifyKick.value.replace("[player]", player.getName()).replace("[uuid]",String.valueOf(player.getUniqueId()))); + if (Config.notifyJoinWarning.valueBoolean && join) { + if (Config.notifyBungee.valueBoolean) { + BungeeSenderReceiver.sendToBungee(Language.permissionWhitelistNotifyOnJoin.value.replace("[player]", player.getName()).replace("[uuid]",String.valueOf(player.getUniqueId()))); + } else Events.notifyPlayer(Language.permissionWhitelistNotifyOnJoin.value.replace("[player]", player.getName()).replace("[uuid]",String.valueOf(player.getUniqueId()))); + } + + if (PermissionWhitelist.playerWithPermissionKick.valueBoolean) { + if (Config.kickCustomCommand.valueBoolean) { + T2Ccmd.console(Config.kickCommand.valueString.replace("[player]", player.getName()).replace("[reason]", Language.permissionWhitelistKick.value)); + } else player.kickPlayer(Language.permissionWhitelistKick.value); + T2Csend.console(Language.permissionWhitelistNotifyKick.value.replace("[player]", + player.getName()).replace("[perm]", perm).replace("[uuid]",String.valueOf(player.getUniqueId()))); + } + if (PermissionWhitelist.customCommandsCommands.valueBoolean) { + for (String cmd : PermissionWhitelist.customCommandsCommands.valueStringList) { + T2Ccmd.console(cmd.replace("[player]", player.getName()).replace("[perm]", perm)); + } + } + } + + private static Boolean permWhitelist(Player player) { + for (Map.Entry playerObject : PlayerCash.getPermissionHashMap().entrySet()) { + if (playerObject.getValue().playerName.equals(player.getName()) && playerObject.getValue().uuid.equals(player.getUniqueId().toString())) return true; + } + return false; + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/check/Timer.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/check/Timer.java new file mode 100644 index 0000000..9da4f6d --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/check/Timer.java @@ -0,0 +1,28 @@ +// This claas was created by JaTiTV + +package net.t2code.opsecurity.check; + +import net.t2code.opsecurity.config.config.Config; +import net.t2code.opsecurity.config.opWhitelist.OPWhitelist; +import net.t2code.opsecurity.config.permissionWhitelist.PermissionWhitelist; +import net.t2code.opsecurity.system.Main; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +public class Timer { + + public static void refreshTimer() { + if (!(OPWhitelist.enable.valueBoolean && PermissionWhitelist.enable.valueBoolean)) return; + if (!Config.checkTimerEnable.valueBoolean) return; + + Bukkit.getScheduler().scheduleAsyncRepeatingTask(Main.getPlugin(), new Runnable() { + @Override + public void run() { + for (Player player : Bukkit.getOnlinePlayers()) { + OpCheck.onCheck(player, false); + PermissionCheck.onCheck(player, false); + } + } + }, 0, 20L * Config.checkTimerRefreshInSec.valueInt); + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/command/CmdExecuter.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/command/CmdExecuter.java new file mode 100644 index 0000000..37fac7d --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/command/CmdExecuter.java @@ -0,0 +1,69 @@ +// This claas was created by JaTiTV + +package net.t2code.opsecurity.command; + +import net.t2code.opsecurity.Util; +import net.t2code.opsecurity.config.config.Config; +import net.t2code.opsecurity.objects.PlayerCash; +import net.t2code.opsecurity.objects.PlayerObject; +import net.t2code.opsecurity.system.Main; +import net.t2code.opsecurity.system.Permissions; +import net.t2code.t2codelib.SPIGOT.api.commands.T2Ctab; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Csend; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabCompleter; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class CmdExecuter implements CommandExecutor, TabCompleter { + + @Override + public boolean onCommand(CommandSender sender, Command command, String label, String[] args) { + if (args.length == 0) { + Commands.mainCommand(sender); + } else { + if (Config.onlyOPcanUseThePlugin.valueBoolean) { + if (!sender.isOp()) { + sender.sendMessage(Util.getPrefix() + "§cOnly OPs can use OPSecurity!"); + return false; + } + } + switch (args[0].toLowerCase()) { + case "reload": + case "rl": + Commands.reload(sender); + break; + case "info": + case "plugin": + case "pl": + case "version": + case "ver": + Commands.info(sender); + break; + case "help": + default: + Commands.help(sender); + break; + } + } + return false; + } + + private static HashMap arg1 = new HashMap() {{ + put("help", Permissions.help); + put("reload", Permissions.reload); + put("info", Permissions.info); + }}; + + @Override + public List onTabComplete(CommandSender sender, Command cmd, String s, String[] args) { + List list = new ArrayList<>(); + T2Ctab.tab(list,sender,0,args,arg1); + return list; + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/command/Commands.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/command/Commands.java new file mode 100644 index 0000000..94391dd --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/command/Commands.java @@ -0,0 +1,86 @@ +package net.t2code.opsecurity.command; + +import net.t2code.opsecurity.Util; +import net.t2code.opsecurity.check.OpCheck; +import net.t2code.opsecurity.config.FileSelect; +import net.t2code.opsecurity.config.config.Config; +import net.t2code.opsecurity.config.language.Language; +import net.t2code.opsecurity.enums.OpCommandRequest; +import net.t2code.opsecurity.objects.PlayerCash; +import net.t2code.opsecurity.system.Main; +import net.t2code.opsecurity.system.Permissions; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Csend; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Ctemplate; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +public class Commands { + + public static void help(CommandSender sender){ + if (!sender.hasPermission(Permissions.help)) { + T2Csend.sender(sender, Language.noPermissionForOpSec.value); + return; + } + //todo to language file + + sender.sendMessage(Util.getPrefix() + " §8----- §2OP§4Security §chelp §8-----"); + sender.sendMessage(Util.getPrefix()); + sender.sendMessage(Util.getPrefix() + " §8'§b/opsecurity reload§8' §eReload the Plugin."); + sender.sendMessage(Util.getPrefix() + " §8'§b/opsecurity help§8' §eOpens this help."); + sender.sendMessage(Util.getPrefix() + " §8'§b/opsecurity info§8' §eCall the info about §2OP§4Security§e."); + sender.sendMessage(Util.getPrefix()); + sender.sendMessage(Util.getPrefix() + " §8----------------------------"); + } + + public static void mainCommand(CommandSender sender) { + if (Config.onlyOPcanUseThePlugin.valueBoolean) { + if (!sender.isOp()) { + sender.sendMessage(Util.getPrefix() + "§cOnly OPs can use OPSecurity!"); + return; + } + } + if (sender.hasPermission(Permissions.help)) { + help(sender); + } else { + sender.sendMessage(Util.getPrefix() + " §cYou do not have permission for OPSecurity! §7<" + Permissions.help + ">"); + } + } + + public static void reload(CommandSender sender) { + if (!sender.hasPermission(Permissions.reload)) { + sender.sendMessage(Util.getPrefix() + "§cYou do not have permission for OPSecurity! §7<" + Permissions.reload + ">"); + return; + } + if (sender instanceof Player) { + Player player = (Player) sender; + if (Config.onlyOPcanUseThePlugin.valueBoolean) { + if (!OpCheck.opWhitelist(player)) { + sender.sendMessage(Util.getPrefix() + " §4You are not on the Whitelist!"); // todo + return; + } + } + T2Csend.player(player, Language.reloadStart.value); + } + if (sender instanceof Player) T2Csend.player((Player) sender, Language.reloadEnd.value); + Bukkit.getConsoleSender().sendMessage(Util.getPrefix() + "§8-------------------------------"); + Bukkit.getConsoleSender().sendMessage(Util.getPrefix() + " §6Plugin reload..."); + Bukkit.getConsoleSender().sendMessage(Util.getPrefix() + "§8-------------------------------"); + // Load.onLoad(Main.getPlugin(),Main.getAutor(),Main.getVersion()); + FileSelect.selectConfig(); + FileSelect.selectLanguage(); + FileSelect.selectOpWhitelist(); + FileSelect.selectPermissionWhitelist(); + Bukkit.getConsoleSender().sendMessage(Util.getPrefix() + "§8-------------------------------"); + Bukkit.getConsoleSender().sendMessage(Util.getPrefix() + " §2Plugin successfully reloaded."); + Bukkit.getConsoleSender().sendMessage(Util.getPrefix() + "§8-------------------------------"); + } + + public static void info(CommandSender sender) { + if (!sender.hasPermission(Permissions.info)) { + sender.sendMessage(Util.getPrefix() + "§cYou do not have permission for OPSecurity! §7<" + Permissions.info + ">"); + return; + } + T2Ctemplate.sendInfo(sender,Main.getPlugin(),Util.getSpigotID(),Util.getDiscord(),Util.getInfoText()); + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/FileSelect.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/FileSelect.java new file mode 100644 index 0000000..88bd2b6 --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/FileSelect.java @@ -0,0 +1,211 @@ +package net.t2code.opsecurity.config; + +import net.t2code.opsecurity.Util; +import net.t2code.opsecurity.config.config.Config; +import net.t2code.opsecurity.config.language.Language; +import net.t2code.opsecurity.config.opWhitelist.OPWhitelist; +import net.t2code.opsecurity.config.permissionWhitelist.PermissionWhitelist; +import net.t2code.opsecurity.objects.PlayerCash; +import net.t2code.opsecurity.objects.PlayerObject; +import net.t2code.opsecurity.system.Main; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Creplace; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Csend; +import net.t2code.t2codelib.SPIGOT.system.config.languages.SelectLibMsg; +import org.bukkit.GameMode; +import org.bukkit.Sound; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.util.*; + +public class FileSelect { + public static void selectConfig() { + File config = new File(Main.getPath(), "config.yml"); + YamlConfiguration yamlConfiguration = YamlConfiguration.loadConfiguration(config); + for (Config value : Config.values()) { + switch (value.cEnum) { + case STRING: + if (!yamlConfiguration.contains(value.path)) { + yamlConfiguration.set(value.path, value.valueString); + } + value.valueString = T2Creplace.replace(Util.getPrefix(), yamlConfiguration.getString(value.path)); + break; + case SOUND: + if (!yamlConfiguration.contains(value.path)) { + yamlConfiguration.set(value.path, value.sound.toString()); + } + try { + value.sound = Sound.valueOf(yamlConfiguration.getString(value.path)); + } catch (Exception ex) { + T2Csend.console("§4\n§4\n§4\n" + SelectLibMsg.soundNotFound.replace("[prefix]", Util.getPrefix()) + .replace("[sound]", "§8" + value.path + ": §6" + yamlConfiguration.getString(value.path)) + "§4\n§4\n§4\n"); + } + break; + case BOOLEAN: + if (!yamlConfiguration.contains(value.path)) { + yamlConfiguration.set(value.path, value.valueBoolean); + } + value.valueBoolean = yamlConfiguration.getBoolean(value.path); + break; + case INTEGER: + if (!yamlConfiguration.contains(value.path)) { + yamlConfiguration.set(value.path, value.valueInt); + } + + value.valueInt = yamlConfiguration.getInt(value.path); + break; + } + } + try { + yamlConfiguration.save(config); + } catch (IOException e) { + e.printStackTrace(); + } + } + + private static ArrayList defaultLanguages = new ArrayList<>(Arrays.asList("german", "english")); + + public static void selectLanguage() { + long long_ = System.currentTimeMillis(); + + for (String language : defaultLanguages) { + File config = new File(Main.getPath(), "languages/" + language + ".yml"); + YamlConfiguration yamlConfiguration = YamlConfiguration.loadConfiguration(config); + for (Language value : Language.values()) { + if (!yamlConfiguration.contains(value.path)) { + switch (language) { + case "german": + yamlConfiguration.set(value.path, value.german); + break; + case "english": + yamlConfiguration.set(value.path, value.english); + break; + } + } + } + T2Csend.debug(Main.getPlugin(), "save: " + language); + try { + yamlConfiguration.save(config); + } catch (IOException e) { + e.printStackTrace(); + } + } + + String selectMSG; + File config = new File(Main.getPath(), "languages/" + Config.language.valueString + ".yml"); + T2Csend.debug(Main.getPlugin(), config.getAbsolutePath()); + if (!config.isFile()) { + T2Csend.console(Util.getPrefix()); + T2Csend.console(Util.getPrefix() + " §4!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + T2Csend.console(Util.getPrefix() + " §4The selected §c" + Config.language.valueString + " §4language file was not found."); + T2Csend.console(Util.getPrefix() + " §6The default language §eEnglish §6is used!"); + T2Csend.console(Util.getPrefix() + " §4!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + T2Csend.console(Util.getPrefix()); + config = new File(Main.getPath(), "languages/" + "english.yml"); + selectMSG = "english"; + } else selectMSG = Config.language.valueString; + YamlConfiguration yamlConfiguration = YamlConfiguration.loadConfiguration(config); + + for (Language value : Language.values()) { + T2Csend.debug(Main.getPlugin(), "Select: File: " + config.getName() + " Path: " + value.path); + value.value = T2Creplace.replace(Util.getPrefix(), yamlConfiguration.getString(value.path)); + } + T2Csend.console(Util.getPrefix() + " §2Language successfully selected to: §6" + selectMSG + " §7- §e" + (System.currentTimeMillis() - long_) + "ms"); + } + + public static void selectOpWhitelist() { + PlayerCash.getOpHashMap().clear(); + File config = new File(Main.getPath(), "opWhitelist.yml"); + YamlConfiguration yamlConfiguration = YamlConfiguration.loadConfiguration(config); + for (OPWhitelist value : OPWhitelist.values()) { + switch (value.cEnum) { + case BOOLEAN: + if (!yamlConfiguration.contains(value.path)) { + yamlConfiguration.set(value.path, value.valueBoolean); + } + value.valueBoolean = yamlConfiguration.getBoolean(value.path); + break; + case STRINGLIST: + if (!yamlConfiguration.contains(value.path)) { + yamlConfiguration.set(value.path, value.valueBoolean); + } + value.valueStringList = T2Creplace.replace(Util.getPrefix(), yamlConfiguration.getStringList(value.path)); + break; + case PLAYERLIST: + if (!yamlConfiguration.contains(value.pathPlayerListPath)) { + yamlConfiguration.set(value.pathPlayerName.replace("KEY", "player1"), value.valuePlayerName); + yamlConfiguration.set(value.pathPlayerUuid.replace("KEY", "player1"), value.valuePlayerUuid); + yamlConfiguration.set(value.pathPlayerName.replace("KEY", "player2"), value.valuePlayerName); + yamlConfiguration.set(value.pathPlayerUuid.replace("KEY", "player2"), value.valuePlayerUuid); + } + for (String key : yamlConfiguration.getConfigurationSection(value.pathPlayerListPath).getKeys(false)) { + String name = yamlConfiguration.getString(value.pathPlayerName.replace("KEY", key)); + PlayerObject playerObject = new PlayerObject( + name, + yamlConfiguration.getString(value.pathPlayerUuid.replace("KEY", key).replace("-", ""))); + PlayerCash.getOpHashMap().put(name, playerObject); + } + break; + case GAMEMODE: + if (!yamlConfiguration.contains(value.path)) { + yamlConfiguration.set(value.path, value.valueGameMode.toString()); + } + try { + value.valueGameMode = GameMode.valueOf(yamlConfiguration.getString(value.path).toUpperCase()); + } catch (Exception ex) { + ex.printStackTrace(); + value.valueGameMode = GameMode.SURVIVAL; + } + break; + } + } + try { + yamlConfiguration.save(config); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void selectPermissionWhitelist() { + PlayerCash.getPermissionHashMap().clear(); + File config = new File(Main.getPath(), "permissionWhitelist.yml"); + YamlConfiguration yamlConfiguration = YamlConfiguration.loadConfiguration(config); + for (PermissionWhitelist value : PermissionWhitelist.values()) { + switch (value.cEnum) { + case BOOLEAN: + if (!yamlConfiguration.contains(value.path)) { + yamlConfiguration.set(value.path, value.valueBoolean); + } + value.valueBoolean = yamlConfiguration.getBoolean(value.path); + break; + case STRINGLIST: + if (!yamlConfiguration.contains(value.path)) { + yamlConfiguration.set(value.path, value.valueStringList); + } + value.valueStringList = T2Creplace.replace(Util.getPrefix(), yamlConfiguration.getStringList(value.path)); + break; + case PLAYERLIST: + if (!yamlConfiguration.contains(value.pathPlayerListPath)) { + yamlConfiguration.set(value.pathPlayerName.replace("KEY", "player1"), value.valuePlayerName); + yamlConfiguration.set(value.pathPlayerUuid.replace("KEY", "player1"), value.valuePlayerUuid); + yamlConfiguration.set(value.pathPlayerName.replace("KEY", "player2"), value.valuePlayerName); + yamlConfiguration.set(value.pathPlayerUuid.replace("KEY", "player2"), value.valuePlayerUuid); + } + for (String key : yamlConfiguration.getConfigurationSection(value.pathPlayerListPath).getKeys(false)) { + String name = yamlConfiguration.getString(value.pathPlayerName.replace("KEY", key)); + PlayerObject playerObject = new PlayerObject( + name, + yamlConfiguration.getString(value.pathPlayerUuid.replace("KEY", key).replace("-", ""))); + PlayerCash.getPermissionHashMap().put(name, playerObject); + } + break; + } + } + try { + yamlConfiguration.save(config); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/config/Config.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/config/Config.java new file mode 100644 index 0000000..7de3578 --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/config/Config.java @@ -0,0 +1,64 @@ +package net.t2code.opsecurity.config.config; + +import net.t2code.opsecurity.enums.ConfigParam; +import net.t2code.t2codelib.SPIGOT.api.minecraftVersion.T2CmcVersion; +import org.bukkit.Sound; + +public enum Config { + + language("plugin.language", "english", ConfigParam.STRING), + onlyOPcanUseThePlugin("plugin.onlyOPcanUseThePlugin", true, ConfigParam.BOOLEAN), + + checkOnJoin("check.onJoin", true, ConfigParam.BOOLEAN), + checkOnInteract("check.onInteract", true, ConfigParam.BOOLEAN), + checkOnCommand("check.onCommand", true, ConfigParam.BOOLEAN), + checkOnChat("check.onChat", true, ConfigParam.BOOLEAN), + checkTimerEnable("check.timer.enable", true, ConfigParam.BOOLEAN), + checkTimerRefreshInSec("check.timer.refreshInSec", 60, ConfigParam.INTEGER), + kickCustomCommand("kick.customCommand.Enable", false, ConfigParam.BOOLEAN), + kickCommand("kick.customCommand.command", "minecraft:kick [player] [reason]", ConfigParam.STRING), + notifyJoinWarning("notify.joinWarn.enable", true, ConfigParam.BOOLEAN), + notifyBungee("notify.allBungeePlayer.enable", false, ConfigParam.BOOLEAN), + notifySoundEnable("notify.soundEnable", true, ConfigParam.BOOLEAN), + notifySoundValue("notify.sound", sound(), ConfigParam.SOUND); + + public String path; + public String valueString; + public Integer valueInt; + public Boolean valueBoolean; + public Sound sound; + public ConfigParam cEnum; + + Config(String path, String value, ConfigParam cEnum) { + this.path = path; + this.valueString = value; + this.cEnum = cEnum; + } + + Config(String path, Sound value, ConfigParam cEnum) { + this.path = path; + this.sound = value; + this.cEnum = cEnum; + } + + Config(String path, Integer value, ConfigParam cEnum) { + this.path = path; + this.valueInt = value; + this.cEnum = cEnum; + } + + Config(String path, Boolean value, ConfigParam cEnum) { + this.path = path; + this.valueBoolean = value; + this.cEnum = cEnum; + } + + public static Sound sound() { + if (T2CmcVersion.isMc1_8()) { + return Sound.valueOf("NOTE_PIANO"); + } else if (T2CmcVersion.isMc1_9() || T2CmcVersion.isMc1_10() || T2CmcVersion.isMc1_11() || T2CmcVersion.isMc1_12()) { + return Sound.valueOf("BLOCK_NOTE_HARP"); + } else return Sound.valueOf("BLOCK_NOTE_BLOCK_HARP"); + } + +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/config/Converter.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/config/Converter.java new file mode 100644 index 0000000..a70060d --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/config/Converter.java @@ -0,0 +1,96 @@ +package net.t2code.opsecurity.config.config; + +import net.t2code.opsecurity.config.opWhitelist.OPWhitelist; +import net.t2code.opsecurity.config.permissionWhitelist.PermissionWhitelist; +import net.t2code.opsecurity.objects.PlayerObject; +import net.t2code.opsecurity.system.Main; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; + +public class Converter { + public static void convert() { + Path pathOld = Paths.get("plugins/OPSecurity/config.yml"); + Path pathNew = Paths.get(Main.getPath() + "/config.yml"); + if (Files.exists(pathNew) && !Files.isDirectory(pathNew)) { + return; + } + if (Files.exists(pathOld) && !Files.isDirectory(pathOld)) { + + File configOld = new File("plugins/OPSecurity/config.yml"); + YamlConfiguration yamlConfigurationOld = YamlConfiguration.loadConfiguration(configOld); + File opConfig = new File(Main.getPath(), "opWhitelist.yml"); + YamlConfiguration opYml = YamlConfiguration.loadConfiguration(opConfig); + File permConfig = new File(Main.getPath(), "permissionWhitelist.yml"); + YamlConfiguration permYml = YamlConfiguration.loadConfiguration(permConfig); + + Config.language.valueString = yamlConfigurationOld.getString("Plugin.language"); + Config.onlyOPcanUseThePlugin.valueBoolean = yamlConfigurationOld.getBoolean("Plugin.OnlyOPcanUseThePlugin"); + Config.checkOnJoin.valueBoolean = yamlConfigurationOld.getBoolean("Check.OnJoin"); + Config.checkOnInteract.valueBoolean = yamlConfigurationOld.getBoolean("Check.OnInteract"); + Config.checkOnCommand.valueBoolean = yamlConfigurationOld.getBoolean("Check.OnCommand"); + Config.checkOnChat.valueBoolean = yamlConfigurationOld.getBoolean("Check.OnChat"); + Config.checkTimerEnable.valueBoolean = yamlConfigurationOld.getBoolean("Check.Timer.Enable"); + Config.checkTimerRefreshInSec.valueInt = yamlConfigurationOld.getInt("Check.Timer.RefreshTime_inSec"); + + Config.kickCommand.valueString = yamlConfigurationOld.getString("Kick.Command"); + Config.notifyJoinWarning.valueBoolean = yamlConfigurationOld.getBoolean("Notify.JoinWarn.Enable"); + Config.notifySoundEnable.valueBoolean = yamlConfigurationOld.getBoolean("Notify.Sound.Enable"); + Config.notifySoundValue.valueString = yamlConfigurationOld.getString("Notify.Sound.Sound"); + + OPWhitelist.enable.valueBoolean = yamlConfigurationOld.getBoolean("OP_Whitelist.Enable"); + OPWhitelist.playerMustBeOnlineToOp.valueBoolean = yamlConfigurationOld.getBoolean("OP_Whitelist.PlayerMustBeOnlineToOp"); + + OPWhitelist.noOpPlayerDeopEnable.valueBoolean = yamlConfigurationOld.getBoolean("OP_Whitelist.noOpPlayerDeop.Enable"); + OPWhitelist.noOpPlayerDeopPlayerSendMessage.valueBoolean = yamlConfigurationOld.getBoolean("OP_Whitelist.noOpPlayerDeop.PlayerSendMessage"); + OPWhitelist.noOpPlayerKickEnable.valueBoolean = yamlConfigurationOld.getBoolean("OP_Whitelist.noOpPlayerKick.Enable"); + OPWhitelist.customCommandsEnable.valueBoolean = yamlConfigurationOld.getBoolean("OP_Whitelist.customCommands.Enable"); + OPWhitelist.customCommandsCommands.valueStringList = yamlConfigurationOld.getStringList("OP_Whitelist.customCommands.Commands"); + + ArrayList opWhitelist = new ArrayList<>(); + for (String key : yamlConfigurationOld.getConfigurationSection("OP_Whitelist.Whitelist").getKeys(false)) { + PlayerObject player = new PlayerObject(key, + yamlConfigurationOld.getString("OP_Whitelist.Whitelist." + key + ".UUID").replace("-", "")); + opWhitelist.add(player); + } + for (PlayerObject playerObject : opWhitelist) { + opYml.set("opWhitelist.whitelist.KEY.name".replace("KEY", playerObject.playerName), playerObject.playerName); + opYml.set("opWhitelist.whitelist.KEY.uuid".replace("KEY", playerObject.playerName), playerObject.uuid); + } + + PermissionWhitelist.enable.valueBoolean = yamlConfigurationOld.getBoolean("Permission_Whitelist.Enable"); + PermissionWhitelist.permissions.valueStringList = yamlConfigurationOld.getStringList("Permission_Whitelist.Permissions"); + + PermissionWhitelist.playerWithPermissionKick.valueBoolean = yamlConfigurationOld.getBoolean("Permission_Whitelist.PlayerWhithPermission_kick"); + PermissionWhitelist.customCommandsEnable.valueBoolean = yamlConfigurationOld.getBoolean("Permission_Whitelist.customCommands.Enable"); + PermissionWhitelist.customCommandsCommands.valueStringList = yamlConfigurationOld.getStringList("Permission_Whitelist.customCommands.Commands"); + + ArrayList permWhitelist = new ArrayList<>(); + for (String key : yamlConfigurationOld.getConfigurationSection("Permission_Whitelist.Whitelist").getKeys(false)) { + PlayerObject player = new PlayerObject(key, + yamlConfigurationOld.getString("Permission_Whitelist.Whitelist." + key + ".UUID").replace("-", "")); + permWhitelist.add(player); + } + for (PlayerObject playerObject : permWhitelist) { + permYml.set("permissionWhitelist.whitelist.KEY.name".replace("KEY", playerObject.playerName), playerObject.playerName); + permYml.set("permissionWhitelist.whitelist.KEY.uuid".replace("KEY", playerObject.playerName), playerObject.uuid); + } + + try { + opYml.save(opConfig); + } catch (IOException e) { + e.printStackTrace(); + } + try { + permYml.save(permConfig); + } catch (IOException e) { + e.printStackTrace(); + } + } + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/language/Language.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/language/Language.java new file mode 100644 index 0000000..edb7f7c --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/language/Language.java @@ -0,0 +1,80 @@ +package net.t2code.opsecurity.config.language; + +public enum Language { + soundNotFound("plugin.soundNotFound",null, + "[prefix] Der Sound [sound] wurde nicht gefunden! Bitte überprüfe die Einstellungen.", + "[prefix] The sound [sound] could not be found! Please check your settings."), + + noPermission("plugin.NoPermission",null, + "Keine Berechtigung!", + "No Permission!"), + + noPermissionForOpSec("plugin.NoPermission",null, + "[prefix] Du hast keine Berechtigung für OPSecurity!", + "[prefix] You do not have permission for OPSecurity!"), + + playerMustBeOnlineToOp("plugin.PlayerMustBeOnlineToOp",null, + "[prefix] Der Spieler muss online sein, um OP zu erhalten!", + "[prefix] Player must be online to get op!"), + + reloadStart("plugin.reload.start",null, + "[prefix] Plugin wird neu geladen...", + "[prefix] Plugin is reloaded..."), + + reloadEnd("plugin.reload.end",null, + "[prefix] Plugin wurde erfolgreich neu geladen.", + "[prefix] Plugin was successfully reloaded."), + + opWhitelistOpCommand("opWhitelist.opCommand",null, + "[prefix] Der angegebene Spieler befindet sich nicht auf der OP_Whitelist!", + "[prefix] The specified player is not on the OP_Whitelist!"), + + opWhitelistNotifyOnJoin("opWhitelist.notify.onJoin",null, + "[prefix] Spieler Name: [player]
UUID: [uuid]'>[player] ist dem Server beigetreten, befindet sich aber nicht auf der OP_Whitelist!
", + "[prefix] Player Name: [player]
UUID: [uuid]'>[player] is joined to the server but is not on the OP_Whitelist!
"), + + opWhitelistNotifyDeop("opWhitelist.notify.deop",null, + "[prefix] Spieler Name: [player]
UUID: [uuid]'>[player] wurde OP entfernt da er nicht auf der Spielerliste steht!
", + "[prefix] Player Name: [player]
UUID: [uuid]'>[player] was removed OP because he is not on the playerlist!
"), + + opWhitelistNotifyKick("opWhitelist.notify.kick",null, + "[prefix] Spieler Name: [player]
UUID: [uuid]'>[player] wurde gekickt, da er nicht auf der OP_Whitelist steht!
", + "[prefix] Player Name: [player]
UUID: [uuid]'>[player] was kicked because he is not on the OP_Whitelist!
"), + + opWhitelistDeop("opWhitelist.deop",null, + "&4Dir wurde OP entfernt da du dazu keine Permission besitzt.", + "&4You have been removed from OP because you do not have permission."), + + opWhitelistKick("opWhitelist.kick",null, + "&4Du hast OP, bist dazu aber nicht berechtigt. Deswegen wurdest du gekickt!", + "&4You have op but are not authorized to do so, that's why you were kicked!"), + + permissionWhitelistNotifyOnJoin("permissionWhitelist.notify.onJoin",null, + "[prefix] Player Name: [player]
UUID: [uuid]'>[player] hat die Permission [perm] und ist dazu nicht berechtigt! Name: [player]
UUID: [uuid]'>[player] ist nicht in der Spielerliste!
", + "[prefix] Player Name: [player]
UUID: [uuid]'>[player] has permission [perm] and is not authorized to do so! Name: [player]
UUID: [uuid]'>[player] is not on the Player list!
"), + + permissionWhitelistNotifyKick("permissionWhitelist.notify.kick",null, + "[prefix] Spieler Name: [player]
UUID: [uuid]'>[player] hat die Permission [perm] und ist dazu nicht berechtigt! Daher wurde er gekickt! Name: [player]
UUID: [uuid]'>[player] ist nicht in der Spielerliste!
", + "[prefix] Player Name: [player]
UUID: [uuid]'>[player] has permission [perm] and is not authorized to do so! Therefore he was kicked! Name: [player]
UUID: [uuid]'>[player] is not on the Player list!
"), + + permissionWhitelistKick("permissionWhitelist.kick",null, + "Du wurdest gekickt, da du Permissions besitzt, für die du keine Berechtigung besitzt!", + "You were kicked because you have permissions to which you do not have permission!"), + exactKickReason("console.exactKickReason", null, + "[prefix] Genauer Grund: [reason]", + "[prefix] Exact reason: [reason]"); + + + public String path; + public String value; + public String german; + public String english; + + Language(String path,String value, String german,String english) { + this.path = path; + this.value=value; + this.german = german; + this.english = english; + } + +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/opWhitelist/OPWhitelist.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/opWhitelist/OPWhitelist.java new file mode 100644 index 0000000..c55ec9d --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/opWhitelist/OPWhitelist.java @@ -0,0 +1,60 @@ +package net.t2code.opsecurity.config.opWhitelist; + +import net.t2code.opsecurity.enums.ConfigParam; +import org.bukkit.GameMode; + +import java.util.Arrays; +import java.util.List; + +public enum OPWhitelist { + enable("opWhitelist.enable", false, ConfigParam.BOOLEAN), + playerMustBeOnlineToOp("opWhitelist.playerMustBeOnlineToOp", true, ConfigParam.BOOLEAN), + noOpPlayerDeopEnable("opWhitelist.enable", true, ConfigParam.BOOLEAN), + noOpPlayerDeopPlayerSendMessage("opWhitelist.noOpPlayerDeop.playerSendMessage", true, ConfigParam.BOOLEAN), + noOpPlayerKickEnable("opWhitelist.noOpPlayerKick.enable", true, ConfigParam.BOOLEAN), + noOpPlayerSetGameModeEnable("opWhitelist.noOpPlayerSetGameMode.enable", true, ConfigParam.BOOLEAN), + noOpPlayerSetGameModeValue("opWhitelist.noOpPlayerSetGameMode.gameMode", GameMode.SURVIVAL, ConfigParam.GAMEMODE), + customCommandsEnable("opWhitelist.customCommands.enable", false, ConfigParam.BOOLEAN), + customCommandsCommands("opWhitelist.customCommands.commands", Arrays.asList("kick [player] &4You have op but are not authorized to do so, that's why you were kicked!") + , ConfigParam.STRINGLIST), + player("opWhitelist.whitelist","opWhitelist.whitelist.KEY.name", "opWhitelist.whitelist.KEY.uuid", "PlayerName", "00000000000000000000000000000000", ConfigParam.PLAYERLIST); + + public String path; + public String pathPlayerListPath; + public String pathPlayerName; + public String pathPlayerUuid; + public String valuePlayerName; + public String valuePlayerUuid; + public List valueStringList; + + public Boolean valueBoolean; + public GameMode valueGameMode; + public ConfigParam cEnum; + + OPWhitelist(String path, GameMode value, ConfigParam cEnum) { + this.path = path; + this.valueGameMode = value; + this.cEnum = cEnum; + } + + OPWhitelist(String listPath,String pathPlayerName, String pathUuid, String playerName, String uuid, ConfigParam cEnum) { + this.pathPlayerListPath = listPath; + this.pathPlayerName = pathPlayerName; + this.pathPlayerUuid = pathUuid; + this.valuePlayerName = playerName; + this.valuePlayerUuid = uuid; + this.cEnum = cEnum; + } + + OPWhitelist(String path, List value, ConfigParam cEnum) { + this.path = path; + this.valueStringList = value; + this.cEnum = cEnum; + } + + OPWhitelist(String path, Boolean value, ConfigParam cEnum) { + this.path = path; + this.valueBoolean = value; + this.cEnum = cEnum; + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/permissionWhitelist/PermissionWhitelist.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/permissionWhitelist/PermissionWhitelist.java new file mode 100644 index 0000000..692497f --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/config/permissionWhitelist/PermissionWhitelist.java @@ -0,0 +1,47 @@ +package net.t2code.opsecurity.config.permissionWhitelist; + +import net.t2code.opsecurity.enums.ConfigParam; + +import java.util.Arrays; +import java.util.List; + +public enum PermissionWhitelist { + enable("permissionWhitelist.enable", false, ConfigParam.BOOLEAN), + playerWithPermissionKick("permissionWhitelist.playerWithPermissionKick", true, ConfigParam.BOOLEAN), + permissions("permissionWhitelist.permissions", Arrays.asList("*", "t2c.opsecurity.admin"), ConfigParam.STRINGLIST), + customCommandsEnable("permissionWhitelist.customCommands.enable", false, ConfigParam.BOOLEAN), + customCommandsCommands("permissionWhitelist.customCommands.commands", Arrays.asList("lp user [player] permission unset *", "lp user [player] permission unset t2c.opsecurity.admin") + , ConfigParam.STRINGLIST), + player("permissionWhitelist.whitelist", "permissionWhitelist.whitelist.KEY.name", "permissionWhitelist.whitelist.KEY.uuid", "PlayerName", "00000000000000000000000000000000", ConfigParam.PLAYERLIST); + + public String path; + public String pathPlayerListPath; + public String pathPlayerName; + public String pathPlayerUuid; + public String valuePlayerName; + public String valuePlayerUuid; + public List valueStringList; + public Boolean valueBoolean; + public ConfigParam cEnum; + + PermissionWhitelist(String listPath, String pathPlayerName, String pathUuid, String playerName, String uuid, ConfigParam cEnum) { + this.pathPlayerListPath = listPath; + this.pathPlayerName = pathPlayerName; + this.pathPlayerUuid = pathUuid; + this.valuePlayerName = playerName; + this.valuePlayerUuid = uuid; + this.cEnum = cEnum; + } + + PermissionWhitelist(String path, List value, ConfigParam cEnum) { + this.path = path; + this.valueStringList = value; + this.cEnum = cEnum; + } + + PermissionWhitelist(String path, Boolean value, ConfigParam cEnum) { + this.path = path; + this.valueBoolean = value; + this.cEnum = cEnum; + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/enums/ConfigParam.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/enums/ConfigParam.java new file mode 100644 index 0000000..ddb2ac4 --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/enums/ConfigParam.java @@ -0,0 +1,11 @@ +package net.t2code.opsecurity.enums; + +public enum ConfigParam { + STRING, + INTEGER, + BOOLEAN, + STRINGLIST, + PLAYERLIST, + SOUND, + GAMEMODE +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/enums/OpCommandRequest.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/enums/OpCommandRequest.java new file mode 100644 index 0000000..fcbb7d5 --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/enums/OpCommandRequest.java @@ -0,0 +1,7 @@ +package net.t2code.opsecurity.enums; + +public enum OpCommandRequest { + ok, + mustOnline, + notWhitelisted +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/events/Events.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/events/Events.java new file mode 100644 index 0000000..40e3d8f --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/events/Events.java @@ -0,0 +1,79 @@ +package net.t2code.opsecurity.events; + +import net.t2code.opsecurity.Util; +import net.t2code.opsecurity.config.config.Config; +import net.t2code.opsecurity.check.OpCheck; +import net.t2code.opsecurity.check.PermissionCheck; +import net.t2code.opsecurity.system.Main; +import net.t2code.opsecurity.system.Permissions; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Csend; +import net.t2code.t2codelib.SPIGOT.api.update.T2CupdateAPI; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.*; + +public class Events implements Listener { + public static void notifyPlayer(String msg) { + if (!Config.notifyJoinWarning.valueBoolean) return; + for (Player notifyPlayer : Bukkit.getOnlinePlayers()) { + if (!notifyPlayer.hasPermission(Permissions.notify)) continue; + T2Csend.player(notifyPlayer, msg); + if (Config.notifySoundEnable.valueBoolean) notifyPlayer.playSound(notifyPlayer.getLocation(), Config.notifySoundValue.sound, 3, 1); + } + } + + @EventHandler + public void CommandSendEvent(PlayerCommandPreprocessEvent event) { + if (!Config.checkOnCommand.valueBoolean) return; + Player player = event.getPlayer(); + if (OpCheck.onCheck(player, false) || PermissionCheck.onCheck(player, false)) { + if (event.isCancelled()) return; + event.setCancelled(true); + } + } + + @EventHandler + public void PlayerChatEvent(PlayerChatEvent event) { + if (!Config.checkOnChat.valueBoolean) return; + Player player = event.getPlayer(); + if (OpCheck.onCheck(player, false) || PermissionCheck.onCheck(player, false)) { + if (event.isCancelled()) return; + event.setCancelled(true); + } + } + + @EventHandler + public void onInteract(PlayerInteractEvent event) { + if (!Config.checkOnInteract.valueBoolean) return; + Player player = event.getPlayer(); + Bukkit.getScheduler().runTaskLaterAsynchronously(Main.getPlugin(), new Runnable() { + @Override + public void run() { + if (OpCheck.onCheck(player, false) || PermissionCheck.onCheck(player, false)) { + event.setCancelled(true); + } + } + }, 1L); + } + + @EventHandler + public void onJoinCheck(PlayerJoinEvent event) { + if (!Config.checkOnJoin.valueBoolean) return; + Player player = event.getPlayer(); + Bukkit.getScheduler().runTaskLaterAsynchronously(Main.getPlugin(), new Runnable() { + @Override + public void run() { + OpCheck.onCheck(player, true); + PermissionCheck.onCheck(player, true); + } + }, 1L); + } + + @EventHandler + public void onJoinEvent(PlayerLoginEvent event) { + Player player = event.getPlayer(); + T2CupdateAPI.join(Main.getPlugin(), Util.getPrefix(), Permissions.updatemsg, player, Util.getSpigotID(), Util.getDiscord()); + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/events/OpCommand.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/events/OpCommand.java new file mode 100644 index 0000000..118e31d --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/events/OpCommand.java @@ -0,0 +1,84 @@ +package net.t2code.opsecurity.events; + +import net.t2code.opsecurity.check.OpCheck; +import net.t2code.opsecurity.config.language.Language; +import net.t2code.opsecurity.config.opWhitelist.OPWhitelist; +import net.t2code.opsecurity.enums.OpCommandRequest; +import net.t2code.opsecurity.objects.PlayerCash; +import net.t2code.opsecurity.objects.PlayerObject; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Csend; +import net.t2code.t2codelib.SPIGOT.api.player.T2CnameHistory; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.server.ServerCommandEvent; + +import java.io.IOException; +import java.util.Map; + +public class OpCommand implements Listener { + @EventHandler + public void onOPServer(ServerCommandEvent event) { + if (!OPWhitelist.enable.valueBoolean) return; + if ((event.getCommand().toLowerCase().startsWith("op ") || event.getCommand().toLowerCase().startsWith("minecraft:op "))) { + switch (isNotOPWTL(event.getCommand())) { + case mustOnline: + T2Csend.sender(event.getSender(), Language.playerMustBeOnlineToOp.value); + event.setCancelled(true); + break; + case notWhitelisted: + T2Csend.sender(event.getSender(), Language.opWhitelistOpCommand.value); + event.setCancelled(true); + break; + } + } + } + + @EventHandler + public void onOpPlayer(PlayerCommandPreprocessEvent event) { + if (!OPWhitelist.enable.valueBoolean) return; + if ((event.getMessage().toLowerCase().startsWith("/op ") || event.getMessage().toLowerCase().startsWith("/minecraft:op "))) { + switch (isNotOPWTL(event.getMessage())) { + case mustOnline: + T2Csend.player(event.getPlayer(), Language.playerMustBeOnlineToOp.value); + event.setCancelled(true); + break; + case notWhitelisted: + T2Csend.player(event.getPlayer(), Language.opWhitelistOpCommand.value); + event.setCancelled(true); + break; + } + } + } + + private OpCommandRequest isNotOPWTL(String command) { + if (command.charAt(0) == '/') command = command.replaceFirst("/", ""); + String arg = command.replace("op ", ""); + Player target = Bukkit.getPlayer(arg); + if (OPWhitelist.playerMustBeOnlineToOp.valueBoolean) { + if (target == null) return OpCommandRequest.mustOnline; + if (!opWhitelist(target.getName(), target.getUniqueId().toString())) return OpCommandRequest.notWhitelisted; + } + String targetUUID; + if (target != null) { + targetUUID = target.getUniqueId().toString(); + } else { + try { + targetUUID = T2CnameHistory.NameLookup.getPlayerUUID(arg); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + if (!opWhitelist(arg, targetUUID)) return OpCommandRequest.notWhitelisted; + return OpCommandRequest.ok; + } + + private static Boolean opWhitelist(String playerName, String playerUuid) { + for (Map.Entry playerObject : PlayerCash.getOpHashMap().entrySet()) { + if (playerObject.getValue().playerName.equals(playerName) && playerObject.getValue().uuid.equals(playerUuid)) return true; + } + return false; + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/events/PlugManCommand.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/events/PlugManCommand.java new file mode 100644 index 0000000..35acc1d --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/events/PlugManCommand.java @@ -0,0 +1,38 @@ +// This claas was created by JaTiTV + +package net.t2code.opsecurity.events; + +import net.t2code.opsecurity.Util; +import net.t2code.opsecurity.system.Main; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Csend; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.server.ServerCommandEvent; + +public class PlugManCommand implements Listener { + + @EventHandler + public void onOPServer(ServerCommandEvent event) { + if ((event.getCommand().toLowerCase().contains("plugman disable") && event.getCommand().toLowerCase().contains(Main.getPlugin().getDescription().getName().toLowerCase())) + || (event.getCommand().toLowerCase().contains("plugman reload") && event.getCommand().toLowerCase().contains(Main.getPlugin().getDescription().getName().toLowerCase())) + || (event.getCommand().toLowerCase().contains("plugman unload") && event.getCommand().toLowerCase().contains(Main.getPlugin().getDescription().getName().toLowerCase())) + || (event.getCommand().toLowerCase().contains("plugman restart") && event.getCommand().toLowerCase().contains(Main.getPlugin().getDescription().getName().toLowerCase())) + ) { + event.setCancelled(true); + T2Csend.console(Util.getPrefix() + " §4OPSecurity cannot be deactivated!"); + } + } + + @EventHandler + public void onOpPlayer(PlayerCommandPreprocessEvent event) { + if (event.getMessage().toLowerCase().startsWith("/plugman disable") && event.getMessage().toLowerCase().contains(Main.getPlugin().getDescription().getName().toLowerCase()) + || (event.getMessage().toLowerCase().startsWith("/plugman reload") && event.getMessage().toLowerCase().contains(Main.getPlugin().getDescription().getName().toLowerCase())) + || (event.getMessage().toLowerCase().startsWith("/plugman unload") && event.getMessage().toLowerCase().contains(Main.getPlugin().getDescription().getName().toLowerCase())) + || (event.getMessage().toLowerCase().startsWith("/plugman restart") && event.getMessage().toLowerCase().contains(Main.getPlugin().getDescription().getName().toLowerCase())) + ) { + event.setCancelled(true); + T2Csend.player(event.getPlayer(), Util.getPrefix() + " §4OPSecurity cannot be deactivated!"); + } + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/objects/PlayerCash.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/objects/PlayerCash.java new file mode 100644 index 0000000..05e5826 --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/objects/PlayerCash.java @@ -0,0 +1,12 @@ +package net.t2code.opsecurity.objects; + +import lombok.Getter; + +import java.util.HashMap; + +public class PlayerCash { + @Getter + private static HashMap opHashMap = new HashMap(); + @Getter + private static HashMap permissionHashMap = new HashMap(); +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/objects/PlayerObject.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/objects/PlayerObject.java new file mode 100644 index 0000000..03233d9 --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/objects/PlayerObject.java @@ -0,0 +1,11 @@ +package net.t2code.opsecurity.objects; + +public class PlayerObject { + public String playerName; + public String uuid; + + public PlayerObject(String playerName, String uuid) { + this.playerName = playerName; + this.uuid = uuid; + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/BungeeSenderReceiver.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/BungeeSenderReceiver.java new file mode 100644 index 0000000..ac27372 --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/BungeeSenderReceiver.java @@ -0,0 +1,41 @@ +package net.t2code.opsecurity.system; + +import net.t2code.opsecurity.events.Events; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Csend; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.messaging.PluginMessageListener; + +import java.io.*; + +public class BungeeSenderReceiver implements PluginMessageListener { + + public static void sendToBungee(String information) { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + DataOutputStream output = new DataOutputStream(stream); + try { + output.writeUTF(information.toString()); + } catch (IOException e) { + e.printStackTrace(); + } + for (Player player : Bukkit.getOnlinePlayers()) { + player.sendPluginMessage(Main.getPlugin(), "t2c:opsec", stream.toByteArray()); + return; + } + } + + @Override + public void onPluginMessageReceived(String channel, Player player, byte[] message) { + DataInputStream stream = new DataInputStream(new ByteArrayInputStream(message)); + T2Csend.debug(Main.getPlugin(), "stream: " + stream.toString()); + try { + String subChannel = stream.readUTF(); + String information = stream.readUTF(); + if (subChannel.equals("T2Cconsole")) { + Events.notifyPlayer(information); + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Load.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Load.java new file mode 100644 index 0000000..d93ccff --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Load.java @@ -0,0 +1,46 @@ +package net.t2code.opsecurity.system; + +import net.t2code.opsecurity.Util; +import net.t2code.opsecurity.command.CmdExecuter; +import net.t2code.opsecurity.config.FileSelect; +import net.t2code.opsecurity.config.config.Converter; +import net.t2code.opsecurity.events.Events; +import net.t2code.opsecurity.events.OpCommand; +import net.t2code.opsecurity.events.PlugManCommand; +import net.t2code.opsecurity.check.Timer; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Ctemplate; +import net.t2code.t2codelib.SPIGOT.api.register.T2Cregister; +import net.t2code.t2codelib.SPIGOT.api.update.T2CupdateAPI; + +import java.util.List; +import java.util.logging.Level; + +public class Load { + + public static void onLoad(Main plugin, List autor, String version) { + long long_ = T2Ctemplate.onLoadHeader(Util.getPrefix(), autor, version, Util.getSpigot(), Util.getDiscord()); + try { + Converter.convert(); + } catch (Exception ex) { + plugin.getLogger().log(Level.SEVERE, ex.getMessage()); + ex.printStackTrace(); + } + + FileSelect.selectConfig(); + FileSelect.selectLanguage(); + FileSelect.selectOpWhitelist(); + FileSelect.selectPermissionWhitelist(); + + plugin.getCommand("t2c-opsecurity").setExecutor(new CmdExecuter()); + + T2Cregister.listener(new OpCommand(), plugin); + T2Cregister.listener(new PlugManCommand(), plugin); + T2Cregister.listener(new Events(), plugin); + + Timer.refreshTimer(); + Permissions.register(); + T2CupdateAPI.onUpdateCheck(plugin, Util.getPrefix(), Util.getSpigotID(), Util.getDiscord()); + Metrics.Bstats(plugin, Util.getBstatsID()); + T2Ctemplate.onLoadFooter(Util.getPrefix(), long_); + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Main.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Main.java new file mode 100644 index 0000000..ea221aa --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Main.java @@ -0,0 +1,77 @@ +package net.t2code.opsecurity.system; + +import lombok.Getter; +import net.t2code.opsecurity.Util; +import net.t2code.t2codelib.SPIGOT.api.messages.T2Ctemplate; +import org.bukkit.Bukkit; +import org.bukkit.plugin.java.JavaPlugin; + +import java.io.File; +import java.util.List; +import java.util.logging.Level; + +public final class Main extends JavaPlugin { + + public static File getPath() { + return plugin.getDataFolder(); + } + + @Getter + private static Boolean t2codeLib = false; + @Getter + private static String version; + @Getter + private static List autor; + @Getter + private static Main plugin; + + @Override + public void onEnable() { + // Plugin startup logic + plugin = this; + autor = this.getDescription().getAuthors(); + version = this.getDescription().getVersion(); + if (pluginNotFound("T2CodeLib", 96388, Util.getRequiredT2CodeLibVersion())) return; + t2codeLib = true; + Load.onLoad(plugin,autor,version); + } + + @Override + public void onDisable() { + // Plugin shutdown logic + if (t2codeLib) T2Ctemplate.onDisable(Util.getPrefix(), autor, version, Util.getSpigot(), Util.getDiscord()); + } + + private static Boolean pluginNotFound(String pl, Integer spigotID, String ver) { + if (Bukkit.getPluginManager().getPlugin(pl) == null) { + plugin.getLogger().log(Level.SEVERE, "Plugin can not be loaded!"); + Bukkit.getConsoleSender().sendMessage(Util.getPrefix() + " §e" + pl + " §4could not be found. Please download it here: " + + "§6https://spigotmc.org/resources/" + pl + "." + spigotID + " §4to be able to use this plugin."); + Main.plugin.getPluginLoader().disablePlugin(Main.plugin); + return true; + } else { + String plVer = Bukkit.getPluginManager().getPlugin(pl).getDescription().getVersion(); + if (ver.contains("_")) { + if (!plVer.equals(ver)) { + plugin.getLogger().log(Level.SEVERE, "Plugin can not be loaded!"); + Bukkit.getConsoleSender().sendMessage(Util.getPrefix() + " §e" + pl + " §4is out of date! This plugin requires the version §2" + + ver + " §4of §6" + pl + " §4Please use this version! Please download it here or contact us in Discord: §6https://spigotmc.org/resources/" + + pl + "." + spigotID + " Or contact us in Discord: http://dc.t2code.net"); + Main.plugin.getPluginLoader().disablePlugin(Main.plugin); + return true; + } + return false; + } + String[] split = plVer.split("_"); + if (Double.parseDouble(split[0]) < Double.parseDouble(ver)) { + plugin.getLogger().log(Level.SEVERE, "Plugin can not be loaded!"); + Bukkit.getConsoleSender().sendMessage(Util.getPrefix() + " §e" + pl + " §4is out of date! This plugin requires at least version §2" + + ver + " §4of §6" + pl + " §4Please update it here: §6https://spigotmc.org/resources/" + pl + "." + spigotID + + " §4to use this version of " + plugin.getDescription().getName() + "."); + Main.plugin.getPluginLoader().disablePlugin(Main.plugin); + return true; + } + return false; + } + } +} diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Metrics.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Metrics.java new file mode 100644 index 0000000..df5384d --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Metrics.java @@ -0,0 +1,844 @@ +// This claas was created by JaTiTV + +package net.t2code.opsecurity.system; + +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.Method; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.logging.Level; +import java.util.stream.Collectors; +import java.util.zip.GZIPOutputStream; + +public class Metrics { + + public static void Bstats(JavaPlugin plugin, int pluginId) { + Metrics metrics = new Metrics(plugin, pluginId); + } + + private final Plugin plugin; + + private final MetricsBase metricsBase; + + /** + * Creates a new Metrics instance. + * + * @param plugin Your plugin instance. + * @param serviceId The id of the service. It can be found at What is my plugin id? + */ + public Metrics(JavaPlugin plugin, int serviceId) { + this.plugin = plugin; + // Get the config file + File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats"); + File configFile = new File(bStatsFolder, "config.yml"); + YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile); + if (!config.isSet("serverUuid")) { + config.addDefault("enabled", true); + config.addDefault("serverUuid", UUID.randomUUID().toString()); + config.addDefault("logFailedRequests", false); + config.addDefault("logSentData", false); + config.addDefault("logResponseStatusText", false); + // Inform the server owners about bStats + config + .options() + .header( + "bStats (https://bStats.org) collects some basic information for plugin authors, like how\n" + + "many people use their plugin and their total player count. It's recommended to keep bStats\n" + + "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n" + + "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n" + + "anonymous.") + .copyDefaults(true); + try { + config.save(configFile); + } catch (IOException ignored) { + } + } + // Load the data + boolean enabled = config.getBoolean("enabled", true); + String serverUUID = config.getString("serverUuid"); + boolean logErrors = config.getBoolean("logFailedRequests", false); + boolean logSentData = config.getBoolean("logSentData", false); + boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false); + metricsBase = + new MetricsBase( + "bukkit", + serverUUID, + serviceId, + enabled, + this::appendPlatformData, + this::appendServiceData, + submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask), + plugin::isEnabled, + (message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error), + (message) -> this.plugin.getLogger().log(Level.INFO, message), + logErrors, + logSentData, + logResponseStatusText); + } + + /** + * Adds a custom chart. + * + * @param chart The chart to add. + */ + public void addCustomChart(CustomChart chart) { + metricsBase.addCustomChart(chart); + } + + private void appendPlatformData(JsonObjectBuilder builder) { + builder.appendField("playerAmount", getPlayerAmount()); + builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0); + builder.appendField("bukkitVersion", Bukkit.getVersion()); + builder.appendField("bukkitName", Bukkit.getName()); + builder.appendField("javaVersion", System.getProperty("java.version")); + builder.appendField("osName", System.getProperty("os.name")); + builder.appendField("osArch", System.getProperty("os.arch")); + builder.appendField("osVersion", System.getProperty("os.version")); + builder.appendField("coreCount", Runtime.getRuntime().availableProcessors()); + } + + private void appendServiceData(JsonObjectBuilder builder) { + builder.appendField("pluginVersion", plugin.getDescription().getVersion()); + } + + private int getPlayerAmount() { + try { + // Around MC 1.8 the return type was changed from an array to a collection, + // This fixes java.lang.NoSuchMethodError: + // org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection; + Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers"); + return onlinePlayersMethod.getReturnType().equals(Collection.class) + ? ((Collection) onlinePlayersMethod.invoke(Bukkit.getServer())).size() + : ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length; + } catch (Exception e) { + // Just use the new method if the reflection failed + return Bukkit.getOnlinePlayers().size(); + } + } + + public static class MetricsBase { + + /** The version of the Metrics class. */ + public static final String METRICS_VERSION = "2.2.1"; + + private static final ScheduledExecutorService scheduler = + Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics")); + + private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s"; + + private final String platform; + + private final String serverUuid; + + private final int serviceId; + + private final Consumer appendPlatformDataConsumer; + + private final Consumer appendServiceDataConsumer; + + private final Consumer submitTaskConsumer; + + private final Supplier checkServiceEnabledSupplier; + + private final BiConsumer errorLogger; + + private final Consumer infoLogger; + + private final boolean logErrors; + + private final boolean logSentData; + + private final boolean logResponseStatusText; + + private final Set customCharts = new HashSet<>(); + + private final boolean enabled; + + /** + * Creates a new MetricsBase class instance. + * + * @param platform The platform of the service. + * @param serviceId The id of the service. + * @param serverUuid The server uuid. + * @param enabled Whether or not data sending is enabled. + * @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all platform-specific data. + * @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and + * appends all service-specific data. + * @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be + * used to delegate the data collection to a another thread to prevent errors caused by + * concurrency. Can be {@code null}. + * @param checkServiceEnabledSupplier A supplier to check if the service is still enabled. + * @param errorLogger A consumer that accepts log message and an error. + * @param infoLogger A consumer that accepts info log messages. + * @param logErrors Whether or not errors should be logged. + * @param logSentData Whether or not the sent data should be logged. + * @param logResponseStatusText Whether or not the response status text should be logged. + */ + public MetricsBase( + String platform, + String serverUuid, + int serviceId, + boolean enabled, + Consumer appendPlatformDataConsumer, + Consumer appendServiceDataConsumer, + Consumer submitTaskConsumer, + Supplier checkServiceEnabledSupplier, + BiConsumer errorLogger, + Consumer infoLogger, + boolean logErrors, + boolean logSentData, + boolean logResponseStatusText) { + this.platform = platform; + this.serverUuid = serverUuid; + this.serviceId = serviceId; + this.enabled = enabled; + this.appendPlatformDataConsumer = appendPlatformDataConsumer; + this.appendServiceDataConsumer = appendServiceDataConsumer; + this.submitTaskConsumer = submitTaskConsumer; + this.checkServiceEnabledSupplier = checkServiceEnabledSupplier; + this.errorLogger = errorLogger; + this.infoLogger = infoLogger; + this.logErrors = logErrors; + this.logSentData = logSentData; + this.logResponseStatusText = logResponseStatusText; + checkRelocation(); + if (enabled) { + startSubmitting(); + } + } + + public void addCustomChart(CustomChart chart) { + this.customCharts.add(chart); + } + + private void startSubmitting() { + final Runnable submitTask = + () -> { + if (!enabled || !checkServiceEnabledSupplier.get()) { + // Submitting data or service is disabled + scheduler.shutdown(); + return; + } + if (submitTaskConsumer != null) { + submitTaskConsumer.accept(this::submitData); + } else { + this.submitData(); + } + }; + // Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution + // of requests on the + // bStats backend. To circumvent this problem, we introduce some randomness into the initial + // and second delay. + // WARNING: You must not modify and part of this Metrics class, including the submit delay or + // frequency! + // WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it! + long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3)); + long secondDelay = (long) (1000 * 60 * (Math.random() * 30)); + scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS); + scheduler.scheduleAtFixedRate( + submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS); + } + + private void submitData() { + final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder(); + appendPlatformDataConsumer.accept(baseJsonBuilder); + final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder(); + appendServiceDataConsumer.accept(serviceJsonBuilder); + JsonObjectBuilder.JsonObject[] chartData = + customCharts.stream() + .map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors)) + .filter(Objects::nonNull) + .toArray(JsonObjectBuilder.JsonObject[]::new); + serviceJsonBuilder.appendField("id", serviceId); + serviceJsonBuilder.appendField("customCharts", chartData); + baseJsonBuilder.appendField("service", serviceJsonBuilder.build()); + baseJsonBuilder.appendField("serverUUID", serverUuid); + baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION); + JsonObjectBuilder.JsonObject data = baseJsonBuilder.build(); + scheduler.execute( + () -> { + try { + // Send the data + sendData(data); + } catch (Exception e) { + // Something went wrong! :( + if (logErrors) { + errorLogger.accept("Could not submit bStats metrics data", e); + } + } + }); + } + + private void sendData(JsonObjectBuilder.JsonObject data) throws Exception { + if (logSentData) { + infoLogger.accept("Sent bStats metrics data: " + data.toString()); + } + String url = String.format(REPORT_URL, platform); + HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection(); + // Compress the data to save bandwidth + byte[] compressedData = compress(data.toString()); + connection.setRequestMethod("POST"); + connection.addRequestProperty("Accept", "application/json"); + connection.addRequestProperty("Connection", "close"); + connection.addRequestProperty("Content-Encoding", "gzip"); + connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length)); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setRequestProperty("User-Agent", "Metrics-Service/1"); + connection.setDoOutput(true); + try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { + outputStream.write(compressedData); + } + StringBuilder builder = new StringBuilder(); + try (BufferedReader bufferedReader = + new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + String line; + while ((line = bufferedReader.readLine()) != null) { + builder.append(line); + } + } + if (logResponseStatusText) { + infoLogger.accept("Sent data to bStats and received response: " + builder); + } + } + + /** Checks that the class was properly relocated. */ + private void checkRelocation() { + // You can use the property to disable the check in your test environment + if (System.getProperty("bstats.relocatecheck") == null + || !System.getProperty("bstats.relocatecheck").equals("false")) { + // Maven's Relocate is clever and changes strings, too. So we have to use this little + // "trick" ... :D + final String defaultPackage = + new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'}); + final String examplePackage = + new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'}); + // We want to make sure no one just copy & pastes the example and uses the wrong package + // names + if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage) + || MetricsBase.class.getPackage().getName().startsWith(examplePackage)) { + throw new IllegalStateException("bStats Metrics class has not been relocated correctly!"); + } + } + } + + /** + * Gzips the given string. + * + * @param str The string to gzip. + * @return The gzipped string. + */ + private static byte[] compress(final String str) throws IOException { + if (str == null) { + return null; + } + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) { + gzip.write(str.getBytes(StandardCharsets.UTF_8)); + } + return outputStream.toByteArray(); + } + } + + public static class AdvancedBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().length == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class SimpleBarChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimpleBarChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + for (Map.Entry entry : map.entrySet()) { + valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()}); + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class MultiLineChart extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public MultiLineChart(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public static class AdvancedPie extends CustomChart { + + private final Callable> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public AdvancedPie(String chartId, Callable> callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean allSkipped = true; + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue() == 0) { + // Skip this invalid + continue; + } + allSkipped = false; + valuesBuilder.appendField(entry.getKey(), entry.getValue()); + } + if (allSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + public abstract static class CustomChart { + + private final String chartId; + + protected CustomChart(String chartId) { + if (chartId == null) { + throw new IllegalArgumentException("chartId must not be null"); + } + this.chartId = chartId; + } + + public JsonObjectBuilder.JsonObject getRequestJsonObject( + BiConsumer errorLogger, boolean logErrors) { + JsonObjectBuilder builder = new JsonObjectBuilder(); + builder.appendField("chartId", chartId); + try { + JsonObjectBuilder.JsonObject data = getChartData(); + if (data == null) { + // If the data is null we don't send the chart. + return null; + } + builder.appendField("data", data); + } catch (Throwable t) { + if (logErrors) { + errorLogger.accept("Failed to get data for custom chart with id " + chartId, t); + } + return null; + } + return builder.build(); + } + + protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception; + } + + public static class SingleLineChart extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SingleLineChart(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + int value = callable.call(); + if (value == 0) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class SimplePie extends CustomChart { + + private final Callable callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public SimplePie(String chartId, Callable callable) { + super(chartId); + this.callable = callable; + } + + @Override + protected JsonObjectBuilder.JsonObject getChartData() throws Exception { + String value = callable.call(); + if (value == null || value.isEmpty()) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("value", value).build(); + } + } + + public static class DrilldownPie extends CustomChart { + + private final Callable>> callable; + + /** + * Class constructor. + * + * @param chartId The id of the chart. + * @param callable The callable which is used to request the chart data. + */ + public DrilldownPie(String chartId, Callable>> callable) { + super(chartId); + this.callable = callable; + } + + @Override + public JsonObjectBuilder.JsonObject getChartData() throws Exception { + JsonObjectBuilder valuesBuilder = new JsonObjectBuilder(); + Map> map = callable.call(); + if (map == null || map.isEmpty()) { + // Null = skip the chart + return null; + } + boolean reallyAllSkipped = true; + for (Map.Entry> entryValues : map.entrySet()) { + JsonObjectBuilder valueBuilder = new JsonObjectBuilder(); + boolean allSkipped = true; + for (Map.Entry valueEntry : map.get(entryValues.getKey()).entrySet()) { + valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue()); + allSkipped = false; + } + if (!allSkipped) { + reallyAllSkipped = false; + valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build()); + } + } + if (reallyAllSkipped) { + // Null = skip the chart + return null; + } + return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build(); + } + } + + /** + * An extremely simple JSON builder. + * + *

While this class is neither feature-rich nor the most performant one, it's sufficient enough + * for its use-case. + */ + public static class JsonObjectBuilder { + + private StringBuilder builder = new StringBuilder(); + + private boolean hasAtLeastOneField = false; + + public JsonObjectBuilder() { + builder.append("{"); + } + + /** + * Appends a null field to the JSON. + * + * @param key The key of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendNull(String key) { + appendFieldUnescaped(key, "null"); + return this; + } + + /** + * Appends a string field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String value) { + if (value == null) { + throw new IllegalArgumentException("JSON value must not be null"); + } + appendFieldUnescaped(key, "\"" + escape(value) + "\""); + return this; + } + + /** + * Appends an integer field to the JSON. + * + * @param key The key of the field. + * @param value The value of the field. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int value) { + appendFieldUnescaped(key, String.valueOf(value)); + return this; + } + + /** + * Appends an object to the JSON. + * + * @param key The key of the field. + * @param object The object. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject object) { + if (object == null) { + throw new IllegalArgumentException("JSON object must not be null"); + } + appendFieldUnescaped(key, object.toString()); + return this; + } + + /** + * Appends a string array to the JSON. + * + * @param key The key of the field. + * @param values The string array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, String[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values) + .map(value -> "\"" + escape(value) + "\"") + .collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an integer array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, int[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends an object array to the JSON. + * + * @param key The key of the field. + * @param values The integer array. + * @return A reference to this object. + */ + public JsonObjectBuilder appendField(String key, JsonObject[] values) { + if (values == null) { + throw new IllegalArgumentException("JSON values must not be null"); + } + String escapedValues = + Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(",")); + appendFieldUnescaped(key, "[" + escapedValues + "]"); + return this; + } + + /** + * Appends a field to the object. + * + * @param key The key of the field. + * @param escapedValue The escaped value of the field. + */ + private void appendFieldUnescaped(String key, String escapedValue) { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + if (key == null) { + throw new IllegalArgumentException("JSON key must not be null"); + } + if (hasAtLeastOneField) { + builder.append(","); + } + builder.append("\"").append(escape(key)).append("\":").append(escapedValue); + hasAtLeastOneField = true; + } + + /** + * Builds the JSON string and invalidates this builder. + * + * @return The built JSON string. + */ + public JsonObject build() { + if (builder == null) { + throw new IllegalStateException("JSON has already been built"); + } + JsonObject object = new JsonObject(builder.append("}").toString()); + builder = null; + return object; + } + + /** + * Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt. + * + *

This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'. + * Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n"). + * + * @param value The value to escape. + * @return The escaped value. + */ + private static String escape(String value) { + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < value.length(); i++) { + char c = value.charAt(i); + if (c == '"') { + builder.append("\\\""); + } else if (c == '\\') { + builder.append("\\\\"); + } else if (c <= '\u000F') { + builder.append("\\u000").append(Integer.toHexString(c)); + } else if (c <= '\u001F') { + builder.append("\\u00").append(Integer.toHexString(c)); + } else { + builder.append(c); + } + } + return builder.toString(); + } + + /** + * A super simple representation of a JSON object. + * + *

This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not + * allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String, + * JsonObject)}. + */ + public static class JsonObject { + + private final String value; + + private JsonObject(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + } + } +} \ No newline at end of file diff --git a/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Permissions.java b/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Permissions.java new file mode 100644 index 0000000..ee9f5bd --- /dev/null +++ b/OpSecurity V3/src/main/java/net/t2code/opsecurity/system/Permissions.java @@ -0,0 +1,32 @@ +package net.t2code.opsecurity.system; + +import net.t2code.t2codelib.SPIGOT.api.register.T2Cregister; +import org.bukkit.permissions.PermissionDefault; + +public class Permissions { + public static final String key = "t2c.opsecurity."; + public static final String notify = key + "notify"; + public static final String updatemsg = key + "updatemsg"; + public static final String reload = key + "command.reload"; + public static final String info = key + "command.info"; + public static final String help = key + "command.help"; + + public static final String admin = key + "admin"; + public static final PermissionDefault op = PermissionDefault.OP; + public static final PermissionDefault notOp = PermissionDefault.NOT_OP; + + protected static void register() { + T2Cregister.permission(notify, op, Main.getPlugin()); + T2Cregister.permissionDescription(notify,"Players with this permission get the update message when joining if an update is available",Main.getPlugin()); + T2Cregister.permission(updatemsg, op, Main.getPlugin()); + T2Cregister.permission(reload, op, Main.getPlugin()); + T2Cregister.permission(info, op, Main.getPlugin()); + T2Cregister.permission(help, op, Main.getPlugin()); + + T2Cregister.permission(admin, op, notify, true, Main.getPlugin()); + T2Cregister.permission(admin, op, updatemsg, true, Main.getPlugin()); + T2Cregister.permission(admin, op, reload, true, Main.getPlugin()); + T2Cregister.permission(admin, op, info, true, Main.getPlugin()); + T2Cregister.permission(admin, op, help, true, Main.getPlugin()); + } +} diff --git a/OpSecurity V3/src/main/resources/plugin.yml b/OpSecurity V3/src/main/resources/plugin.yml new file mode 100644 index 0000000..936db6c --- /dev/null +++ b/OpSecurity V3/src/main/resources/plugin.yml @@ -0,0 +1,14 @@ +name: T2C-OPSecurity +provides: [OPSecurity] +version: '${project.version}' +main: net.t2code.opsecurity.system.Main +api-version: 1.13 +load: STARTUP +prefix: T2C-OPSecurity +authors: [ JaTiTV ] +softdepend: + - T2CodeLib + - OPSecurity +commands: + t2c-opsecurity: + aliases: [opsec, opsecurity] \ No newline at end of file