diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java index b019f3d38..7952a0883 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/configuration/Settings.java @@ -647,16 +647,21 @@ public class Settings extends Config { } + @Comment({"Web/HTTP connection related settings"}) public static class WEB { - @Comment({ - "The web interface for clipboards", - " - All schematics are anonymous and private", - " - Downloads can be deleted by the user", - " - Supports clipboard uploads, downloads and saves", - }) + @Comment({"The web interface for clipboards", " - All schematics are anonymous and private", " - Downloads can be deleted by the user", " - Supports clipboard uploads, downloads and saves",}) public String URL = "https://schem.intellectualsites.com/fawe/"; + @Comment("The maximum amount of time in seconds the plugin can attempt to load images for.") + public int MAX_IMAGE_LOAD_TIME = 5; + + @Comment({ + "The maximum size (width x length) an image being loaded can be.", + " - 8294400 is 3840x2160" + }) + public int MAX_IMAGE_SIZE = 8294400; + } public static class EXTENT { diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java index 911576616..0875df13c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/MainUtil.java @@ -4,6 +4,7 @@ import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.history.changeset.FaweStreamChangeSet; +import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.internal.io.AbstractDelegateOutputStream; import com.fastasyncworldedit.core.internal.io.FaweInputStream; import com.fastasyncworldedit.core.internal.io.FaweOutputStream; @@ -532,6 +533,8 @@ public class MainUtil { public static BufferedImage toRGB(BufferedImage src) { if (src == null) { return src; + } else if ((long) src.getWidth() * src.getHeight() > Settings.settings().WEB.MAX_IMAGE_SIZE) { + throw new FaweException(Caption.of("fawe.web.image.load.size.too-large", Settings.settings().WEB.MAX_IMAGE_SIZE)); } BufferedImage img = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_INT_ARGB); Graphics2D g2d = img.createGraphics(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index f1fbf616d..dabc1dc92 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -21,7 +21,9 @@ package com.sk89q.worldedit.command; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.configuration.Caption; +import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.function.generator.CavesGen; +import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.util.MainUtil; import com.fastasyncworldedit.core.util.MaskTraverser; import com.fastasyncworldedit.core.util.MathMan; @@ -65,6 +67,11 @@ import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URL; import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import static com.google.common.base.Preconditions.checkNotNull; import static com.sk89q.worldedit.command.util.Logging.LogMode.ALL; @@ -587,12 +594,34 @@ public class GenerationCommands { if (!url.getHost().equalsIgnoreCase("i.imgur.com")) { throw new IOException("Only i.imgur.com links are allowed!"); } - BufferedImage image = MainUtil.readImage(url); if (dimensions != null) { - image = ImageUtil.getScaledInstance(image, dimensions.getBlockX(), dimensions.getBlockZ(), - RenderingHints.VALUE_INTERPOLATION_BILINEAR, false + checkCommandArgument( + (long) dimensions.getX() * dimensions.getZ() <= Settings.settings().WEB.MAX_IMAGE_SIZE, + Caption.of("fawe.error.image-dimensions", Settings.settings().WEB.MAX_IMAGE_SIZE) ); } + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future future = executor.submit(() -> { + BufferedImage image = MainUtil.readImage(url); + if (dimensions != null) { + image = ImageUtil.getScaledInstance(image, dimensions.getBlockX(), dimensions.getBlockZ(), + RenderingHints.VALUE_INTERPOLATION_BILINEAR, false + ); + } + return image; + }); + BufferedImage image; + try { + image = future.get(Settings.settings().WEB.MAX_IMAGE_LOAD_TIME, TimeUnit.SECONDS); + } catch (InterruptedException | TimeoutException ignored) { + actor.printError(Caption.of("fawe.web.image.load.timeout", Settings.settings().WEB.MAX_IMAGE_LOAD_TIME)); + return; + } catch (Throwable t) { + if (t.getCause() instanceof FaweException faweException) { + throw faweException; + } + throw new IOException(t.getCause()); + } BlockVector3 pos1 = session.getPlacementPosition(actor); BlockVector3 pos2 = pos1.add(image.getWidth() - 1, 0, image.getHeight() - 1); diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 5c180980e..083ea2406 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -17,6 +17,8 @@ "fawe.web.generating.link": "Uploading {0}, please wait...", "fawe.web.generating.link.failed": "Failed to generate download link!", "fawe.web.download.link": "{0}", + "fawe.web.image.load.timeout": "Image load attempt timed out, max time: {0}s. Please try a smaller-resolution image.", + "fawe.web.image.load.size.too-large": "Image dimensions too large! Max allowable size (width x height): {0} pixels.", "fawe.worldedit.general.texture.disabled": "Texturing reset", "fawe.worldedit.general.texture.set": "Set texturing to {1}", "fawe.worldedit.general.source.mask.disabled": "Global source mask disabled", @@ -104,6 +106,7 @@ "fawe.error.radius-too-small": "Radius must be >=0", "fawe.error.time-too-less": "Time must be >=0", "fawe.error.invalid-image": "Invalid image: {0}", + "fawe.error.image-dimensions": "Dimensions given for image too large, max allowable size (width x height): {0} pixels.", "fawe.error.file-not-found": "File not found: {0}", "fawe.error.file-is-invalid-directory": "File is a directory: {0}", "fawe.error.stacktrace": "===============---=============",