diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/HastebinUtility.java b/worldedit-core/src/main/java/com/boydti/fawe/util/HastebinUtility.java deleted file mode 100644 index c844082bb..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/util/HastebinUtility.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.boydti.fawe.util; - -import com.boydti.fawe.Fawe; -import java.io.BufferedReader; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class HastebinUtility { - - public static final String BIN_URL = "https://hastebin.com/documents", USER_AGENT = "Mozilla/5.0"; - public static final Pattern PATTERN = Pattern.compile("\\{\"key\":\"([\\S\\s]*)\"\\}"); - - public static String upload(final String string) throws IOException { - final URL url = new URL(BIN_URL); - final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); - - connection.setRequestMethod("POST"); - connection.setRequestProperty("User-Agent", USER_AGENT); - connection.setDoOutput(true); - - try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) { - outputStream.write(string.getBytes()); - outputStream.flush(); - } - - StringBuilder response; - try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { - response = new StringBuilder(); - - String inputLine; - while ((inputLine = in.readLine()) != null) { - response.append(inputLine); - } - } - - Matcher matcher = PATTERN.matcher(response.toString()); - if (matcher.matches()) { - return "https://hastebin.com/" + matcher.group(1); - } else { - throw new RuntimeException("Couldn't read response!"); - } - } - - public static String upload(final File file) throws IOException { - final StringBuilder content = new StringBuilder(); - List lines = new ArrayList<>(); - try (BufferedReader reader = new BufferedReader(new FileReader(file))) { - String line; - int i = 0; - while ((line = reader.readLine()) != null) { - lines.add(line); - } - } - for (int i = Math.max(0, lines.size() - 1000); i < lines.size(); i++) { - content.append(lines.get(i)).append("\n"); - } - return upload(content.toString()); - } - - public static String debugPaste() throws IOException { - String settingsYML = HastebinUtility.upload(new File(Fawe.imp().getDirectory(), "config.yml")); - String messagesYML = HastebinUtility.upload(new File(Fawe.imp().getDirectory(), "message.yml")); - String commandsYML = HastebinUtility.upload(new File(Fawe.imp().getDirectory(), "commands.yml")); - String latestLOG; - try { - latestLOG = HastebinUtility.upload(new File(Fawe.imp().getDirectory(), "../../logs/latest.log")); - } catch (IOException ignored) { - latestLOG = "too big :("; - } - StringBuilder b = new StringBuilder(); - b.append( - "# Welcome to this paste\n# It is meant to provide us at IntellectualSites with better information about your " - + "problem\n\n# We will start with some informational files\n"); - b.append("links.config_yml: ").append(settingsYML).append('\n'); - b.append("links.messages_yml: ").append(messagesYML).append('\n'); - b.append("links.commands_yml: ").append(commandsYML).append('\n'); - b.append("links.latest_log: ").append(latestLOG).append('\n'); - b.append("\n# Server Information\n"); - b.append("server.platform: ").append(Fawe.imp().getPlatform()).append('\n'); - b.append(Fawe.imp().getDebugInfo()).append('\n'); - b.append("\n\n# YAY! Now, let's see what we can find in your JVM\n"); - Runtime runtime = Runtime.getRuntime(); - b.append("memory.free: ").append(runtime.freeMemory()).append('\n'); - b.append("memory.max: ").append(runtime.maxMemory()).append('\n'); - b.append("java.specification.version: '").append(System.getProperty("java.specification.version")).append("'\n"); - b.append("java.vendor: '").append(System.getProperty("java.vendor")).append("'\n"); - b.append("java.version: '").append(System.getProperty("java.version")).append("'\n"); - b.append("os.arch: '").append(System.getProperty("os.arch")).append("'\n"); - b.append("os.name: '").append(System.getProperty("os.name")).append("'\n"); - b.append("os.version: '").append(System.getProperty("os.version")).append("'\n\n"); - b.append("# Okay :D Great. You are now ready to create your bug report!"); - b.append("\n# You can do so at https://github.com/boy0001/FastAsyncWorldedit/issues"); - - String link = HastebinUtility.upload(b.toString()); - return link; - } - -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/util/IncendoPaster.java b/worldedit-core/src/main/java/com/boydti/fawe/util/IncendoPaster.java new file mode 100644 index 000000000..db8b2ab57 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/util/IncendoPaster.java @@ -0,0 +1,261 @@ +package com.boydti.fawe.util; + +import com.boydti.fawe.Fawe; +import com.google.common.base.Charsets; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import java.nio.file.Files; +import java.util.*; + +/** + * Single class paster for the Incendo paste service + * + * @author Sauilitired + */ +@SuppressWarnings({"unused", "WeakerAccess"}) +public final class IncendoPaster { + + /** + * Upload service URL + */ + public static final String UPLOAD_PATH = "https://incendo.org/paste/upload"; + /** + * Valid paste applications + */ + public static final Collection + VALID_APPLICATIONS = Arrays + .asList("plotsquared", "fastasyncworldedit", "incendopermissions", "kvantum"); + + private final Collection files = new ArrayList<>(); + private final String pasteApplication; + + /** + * Construct a new paster + * + * @param pasteApplication The application that is sending the paste + */ + public IncendoPaster(final String pasteApplication) { + if (pasteApplication == null || pasteApplication.isEmpty()) { + throw new IllegalArgumentException("paste application cannot be null, nor empty"); + } + if (!VALID_APPLICATIONS.contains(pasteApplication.toLowerCase(Locale.ENGLISH))) { + throw new IllegalArgumentException( + String.format("Unknown application name: %s", pasteApplication)); + } + this.pasteApplication = pasteApplication; + } + + /** + * Get an immutable collection containing all the files that have been added to this paster + * + * @return Unmodifiable collection + */ + public final Collection getFiles() { + return Collections.unmodifiableCollection(this.files); + } + + /** + * Add a file to the paster + * + * @param file File to paste + */ + public void addFile(final PasteFile file) { + if (file == null) { + throw new IllegalArgumentException("File cannot be null"); + } + // Check to see that no duplicate files are submitted + for (final PasteFile pasteFile : this.files) { + if (pasteFile.fileName.equalsIgnoreCase(file.getFileName())) { + throw new IllegalArgumentException(String.format("Found duplicate file with name %s", + file.getFileName())); + } + } + this.files.add(file); + } + + /** + * Create a JSON string from the submitted information + * + * @return compiled JSON string + */ + private String toJsonString() { + final StringBuilder builder = new StringBuilder("{\n"); + builder.append("\"paste_application\": \"").append(this.pasteApplication).append("\",\n\"files\": \""); + Iterator fileIterator = this.files.iterator(); + while (fileIterator.hasNext()) { + final PasteFile file = fileIterator.next(); + builder.append(file.getFileName()); + if (fileIterator.hasNext()) { + builder.append(","); + } + } + builder.append("\",\n"); + fileIterator = this.files.iterator(); + while (fileIterator.hasNext()) { + final PasteFile file = fileIterator.next(); + builder.append("\"file-").append(file.getFileName()).append("\": \"") + .append(file.getContent().replaceAll("\"", "\\\\\"")).append("\""); + if (fileIterator.hasNext()) { + builder.append(",\n"); + } + } + builder.append("\n}"); + return builder.toString(); + } + + /** + * Upload the paste and return the status message + * + * @return Status message + * @throws Throwable any and all exceptions + */ + public final String upload() throws Throwable { + final URL url = new URL(UPLOAD_PATH); + final URLConnection connection = url.openConnection(); + final HttpURLConnection httpURLConnection = (HttpURLConnection) connection; + httpURLConnection.setRequestMethod("POST"); + httpURLConnection.setDoOutput(true); + final byte[] content = toJsonString().getBytes(Charsets.UTF_8); + httpURLConnection.setFixedLengthStreamingMode(content.length); + httpURLConnection.setRequestProperty("Content-Type", "application/json"); + httpURLConnection.setRequestProperty("Accept", "*/*"); + httpURLConnection.connect(); + try (final OutputStream stream = httpURLConnection.getOutputStream()) { + stream.write(content); + } + if (!httpURLConnection.getResponseMessage().contains("OK")) { + throw new IllegalStateException(String.format("Server returned status: %d %s", + httpURLConnection.getResponseCode(), httpURLConnection.getResponseMessage())); + } + final StringBuilder input = new StringBuilder(); + try (final BufferedReader inputStream = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()))) { + String line; + while ((line = inputStream.readLine()) != null) { + input.append(line).append("\n"); + } + } + return input.toString(); + } + + /** + * Simple class that represents a paste file + */ + public static class PasteFile { + + private final String fileName; + private final String content; + + /** + * Construct a new paste file + * + * @param fileName File name, cannot be empty, nor null + * @param content File content, cannot be empty, nor null + */ + public PasteFile(final String fileName, final String content) { + if (fileName == null || fileName.isEmpty()) { + throw new IllegalArgumentException("file name cannot be null, nor empty"); + } + if (content == null || content.isEmpty()) { + throw new IllegalArgumentException("content cannot be null, nor empty"); + } + this.fileName = fileName; + this.content = content; + } + + /** + * Get the file name + * + * @return File name + */ + public String getFileName() { + return this.fileName; + } + + /** + * Get the file content as a single string + * + * @return File content + */ + public String getContent() { + return this.content; + } + } + + public static String debugPaste() throws IOException { + final IncendoPaster incendoPaster = new IncendoPaster("fastasyncworldedit"); + + StringBuilder b = new StringBuilder(); + b.append( + "# Welcome to this paste\n# It is meant to provide us at IntellectualSites with better information about your " + + "problem\n"); + b.append("\n# Server Information\n"); + b.append("server.platform: ").append(Fawe.imp().getPlatform()).append('\n'); + b.append(Fawe.imp().getDebugInfo()).append('\n'); + b.append("\n\n# YAY! Now, let's see what we can find in your JVM\n"); + Runtime runtime = Runtime.getRuntime(); + b.append("memory.free: ").append(runtime.freeMemory()).append('\n'); + b.append("memory.max: ").append(runtime.maxMemory()).append('\n'); + b.append("java.specification.version: '").append(System.getProperty("java.specification.version")).append("'\n"); + b.append("java.vendor: '").append(System.getProperty("java.vendor")).append("'\n"); + b.append("java.version: '").append(System.getProperty("java.version")).append("'\n"); + b.append("os.arch: '").append(System.getProperty("os.arch")).append("'\n"); + b.append("os.name: '").append(System.getProperty("os.name")).append("'\n"); + b.append("os.version: '").append(System.getProperty("os.version")).append("'\n\n"); + b.append("# Okay :D Great. You are now ready to create your bug report!"); + b.append("\n# You can do so at https://github.com/boy0001/FastAsyncWorldedit/issues"); + incendoPaster.addFile(new IncendoPaster.PasteFile("information", b.toString())); + + try { + final File logFile = new File(Fawe.imp().getDirectory(), "../../logs/latest.log"); + final String file; + if (Files.size(logFile.toPath()) > 14_000_000) { + file = "too big :("; + } else { + file = readFile(logFile); + } + incendoPaster.addFile(new IncendoPaster.PasteFile("latest.log", file)); + } catch (IOException ignored) { + } + + incendoPaster.addFile(new PasteFile("config.yml", readFile(new File(Fawe.imp().getDirectory(), "config.yml")))); + incendoPaster.addFile(new PasteFile("message.yml", readFile(new File(Fawe.imp().getDirectory(), "message.yml")))); + incendoPaster.addFile(new PasteFile("commands.yml", readFile(new File(Fawe.imp().getDirectory(), "commands.yml")))); + + final String rawResponse; + try { + rawResponse = incendoPaster.upload(); + } catch (Throwable throwable) { + throw new IOException(String.format("Failed to upload files: %s", throwable.getMessage()), throwable); + } + final JsonObject jsonObject = new JsonParser().parse(rawResponse).getAsJsonObject(); + + if (jsonObject.has("created")) { + final String pasteId = jsonObject.get("paste_id").getAsString(); + return String.format("https://incendo.org/paste/view/%s", pasteId); + } else { + throw new IOException(String.format("Failed to upload files: %s", + jsonObject.get("response").getAsString())); + } + } + + private static String readFile(final File file) throws IOException { + final StringBuilder content = new StringBuilder(); + final List lines = new ArrayList<>(); + try (final BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + lines.add(line); + } + } + for (int i = Math.max(0, lines.size() - 1000); i < lines.size(); i++) { + content.append(lines.get(i)).append("\n"); + } + return content.toString(); + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java index 8caa07c09..0de3b7a17 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/WorldEditCommands.java @@ -24,10 +24,7 @@ import com.boydti.fawe.FaweVersion; import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.Settings; import com.boydti.fawe.object.FawePlayer; -import com.boydti.fawe.util.HastebinUtility; -import com.boydti.fawe.util.StringMan; -import com.boydti.fawe.util.TaskManager; -import com.boydti.fawe.util.Updater; +import com.boydti.fawe.util.*; import com.sk89q.minecraft.util.commands.Command; import com.sk89q.minecraft.util.commands.CommandContext; import com.sk89q.minecraft.util.commands.CommandPermissions; @@ -189,7 +186,7 @@ public class WorldEditCommands { ) @CommandPermissions("worldedit.debugpaste") public void debugpaste(Actor actor) throws WorldEditException, IOException { - BBC.DOWNLOAD_LINK.send(actor, HastebinUtility.debugPaste()); + BBC.DOWNLOAD_LINK.send(actor, IncendoPaster.debugPaste()); } @Command(