From 52ba80ab70d661bef39f37b780ff3c35a5ecdf73 Mon Sep 17 00:00:00 2001 From: Vlammar Date: Thu, 11 Nov 2021 21:41:37 +0100 Subject: [PATCH] Fixed an issue with image loading on paper and added allow list for image hosting sites --- .../fr/moribus/imageonmap/Permissions.java | 3 +- .../imageonmap/PluginConfiguration.java | 2 + .../imageonmap/commands/IoMCommand.java | 20 ++++++++ .../commands/maptool/NewCommand.java | 6 +++ .../commands/maptool/UpdateCommand.java | 8 +++- .../image/ImageRendererExecutor.java | 3 +- .../imageonmap/image/MapInitEvent.java | 48 ++++++++++++++++++- src/main/resources/config.yml | 3 ++ src/main/resources/plugin.yml | 10 ++-- 9 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/main/java/fr/moribus/imageonmap/Permissions.java b/src/main/java/fr/moribus/imageonmap/Permissions.java index ec1be2f..fa00415 100644 --- a/src/main/java/fr/moribus/imageonmap/Permissions.java +++ b/src/main/java/fr/moribus/imageonmap/Permissions.java @@ -60,7 +60,8 @@ public enum Permissions { BYPASS_SIZE("imageonmap.bypasssize"), BYPASS_IMAGE_LIMIT("imageonmap.bypassimagelimit"), BYPASS_MAP_LIMIT("imageonmap.bypassmaplimit"), - GIVE("imageonmap.give"); + GIVE("imageonmap.give"), + IGNOREALLOWLIST("imageonmap.ignoreallowlist_hostingsite"); private final String permission; private final String[] aliases; diff --git a/src/main/java/fr/moribus/imageonmap/PluginConfiguration.java b/src/main/java/fr/moribus/imageonmap/PluginConfiguration.java index 07646b1..3bf4b5c 100644 --- a/src/main/java/fr/moribus/imageonmap/PluginConfiguration.java +++ b/src/main/java/fr/moribus/imageonmap/PluginConfiguration.java @@ -59,4 +59,6 @@ public final class PluginConfiguration extends Configuration { public static ConfigurationItem LIMIT_SIZE_X = item("limit-map-size-x", 0); public static ConfigurationItem LIMIT_SIZE_Y = item("limit-map-size-y", 0); + public static ConfigurationItem ALLOWLIST_HOSTINGSITE = item("allowlist_hostingsite", ""); + } diff --git a/src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java b/src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java index 9623b98..9153450 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java +++ b/src/main/java/fr/moribus/imageonmap/commands/IoMCommand.java @@ -36,11 +36,14 @@ package fr.moribus.imageonmap.commands; +import fr.moribus.imageonmap.PluginConfiguration; import fr.moribus.imageonmap.map.ImageMap; import fr.moribus.imageonmap.map.MapManager; import fr.zcraft.quartzlib.components.commands.Command; import fr.zcraft.quartzlib.components.commands.CommandException; import fr.zcraft.quartzlib.components.i18n.I; +import fr.zcraft.quartzlib.tools.PluginLogger; +import java.net.URL; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -53,6 +56,23 @@ import org.bukkit.entity.Player; public abstract class IoMCommand extends Command { + protected boolean checkHostingSite(URL url) { + PluginLogger.info("allow list " + PluginConfiguration.ALLOWLIST_HOSTINGSITE.get()); + String urlsString = PluginConfiguration.ALLOWLIST_HOSTINGSITE.get(); + if (urlsString.trim().equals("")) { + return true; + } + String[] hosts = urlsString.trim().replaceAll("https://","").split(","); + for (String host : hosts) { + PluginLogger.info(host); + PluginLogger.info(url.getHost()); + if (url.getHost().equals(host.trim())) { + return true; + } + } + return false; + } + protected void retrieveUUID(String arg, Consumer consumer) { UUID uuid; OfflinePlayer offlinePlayer; diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java index 51dbfaa..687d1df 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java +++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/NewCommand.java @@ -107,6 +107,12 @@ public class NewCommand extends IoMCommand { } try { url = new URL(args[0]); + if (!Permissions.IGNOREALLOWLIST.grantedTo(player) && !checkHostingSite(url)) { + throwInvalidArgument(I.t("This hosting website is not trusted, if you think that this is an error " + + " contact your server administrator")); + return; + } + } catch (MalformedURLException ex) { throwInvalidArgument(I.t("Invalid URL.")); return; diff --git a/src/main/java/fr/moribus/imageonmap/commands/maptool/UpdateCommand.java b/src/main/java/fr/moribus/imageonmap/commands/maptool/UpdateCommand.java index dc3baa3..78144ee 100644 --- a/src/main/java/fr/moribus/imageonmap/commands/maptool/UpdateCommand.java +++ b/src/main/java/fr/moribus/imageonmap/commands/maptool/UpdateCommand.java @@ -168,6 +168,12 @@ public class UpdateCommand extends IoMCommand { URL url1; try { url1 = new URL(url); + if (!Permissions.IGNOREALLOWLIST.grantedTo(playerSender) && !checkHostingSite(url1)) { + throwInvalidArgument(I.t("This hosting website is not trusted, if you think that this is an error " + + " contact your server administrator")); + return; + } + //TODO replace by a check of the load status.(if not loaded load the mapmanager) MapManager.load(false);//we don't want to spam the console each time we reload the mapManager @@ -211,7 +217,7 @@ public class UpdateCommand extends IoMCommand { ActionBar.removeMessage(playerSender); } } - } catch (MalformedURLException ex) { + } catch (MalformedURLException | CommandException ex) { warning(sender, I.t("Invalid URL.")); } }); diff --git a/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java b/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java index e2f99b0..bc1edf5 100644 --- a/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java +++ b/src/main/java/fr/moribus/imageonmap/image/ImageRendererExecutor.java @@ -38,6 +38,7 @@ package fr.moribus.imageonmap.image; import fr.moribus.imageonmap.Permissions; import fr.moribus.imageonmap.PluginConfiguration; +import fr.moribus.imageonmap.commands.IoMCommand; import fr.moribus.imageonmap.map.ImageMap; import fr.moribus.imageonmap.map.MapManager; import fr.zcraft.quartzlib.components.i18n.I; @@ -98,6 +99,7 @@ public class ImageRendererExecutor extends Worker { public ImageMap run() throws Throwable { BufferedImage image = null; + //If the link is an imgur one if (url.toString().toLowerCase().startsWith("https://imgur.com/")) { @@ -162,7 +164,6 @@ public class ImageRendererExecutor extends Worker { submitQuery(new WorkerRunnable() { @Override public ImageMap run() throws Throwable { - final URLConnection connection = connecting(url); final InputStream stream = connection.getInputStream(); diff --git a/src/main/java/fr/moribus/imageonmap/image/MapInitEvent.java b/src/main/java/fr/moribus/imageonmap/image/MapInitEvent.java index ad3e9b2..69acacf 100644 --- a/src/main/java/fr/moribus/imageonmap/image/MapInitEvent.java +++ b/src/main/java/fr/moribus/imageonmap/image/MapInitEvent.java @@ -38,10 +38,16 @@ package fr.moribus.imageonmap.image; import fr.moribus.imageonmap.ImageOnMap; import fr.moribus.imageonmap.map.MapManager; +import fr.zcraft.quartzlib.components.events.FutureEventHandler; +import fr.zcraft.quartzlib.components.events.FutureEvents; +import fr.zcraft.quartzlib.components.events.WrappedEvent; import fr.zcraft.quartzlib.core.QuartzLib; +import fr.zcraft.quartzlib.tools.PluginLogger; +import fr.zcraft.quartzlib.tools.reflection.Reflection; import fr.zcraft.quartzlib.tools.runners.RunTask; import java.io.File; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.entity.Entity; @@ -53,13 +59,17 @@ import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityPickupItemEvent; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.player.PlayerItemHeldEvent; +import org.bukkit.event.world.ChunkEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.map.MapView; public class MapInitEvent implements Listener { + public static void init() { + QuartzLib.registerEvents(new MapInitEvent()); + FutureEvents.registerFutureEvents(new EntitiesLoadListener()); for (World world : Bukkit.getWorlds()) { for (ItemFrame frame : world.getEntitiesByClass(ItemFrame.class)) { @@ -98,7 +108,6 @@ public class MapInitEvent implements Listener { @EventHandler public void onChunkLoad(ChunkLoadEvent event) { - //Fix for paper RunTask.later(() -> { for (Entity entity : event.getChunk().getEntities()) { if (entity instanceof ItemFrame) { @@ -135,4 +144,41 @@ public class MapInitEvent implements Listener { } } + + protected static final class EntitiesLoadListener implements Listener { + @FutureEventHandler(event = "world.EntitiesLoadEvent") + public void onEntitiesLoad(WrappedEvent event) { + //New in 1.17 + //Used to make sure map are really loaded in 1.17 on Paper (else some won't render or update properly) + RunTask.later(() -> { + try { + Chunk chunk = (Chunk) Reflection.call(event.getEvent(), "getChunk"); + Entity[] entities = chunk.getEntities(); + //Not the most efficient method because we go through entity already loaded + + //The direct method using getEntities of + // https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/event/world/EntitiesLoadEvent.html + //Return an unmodifiable list of entities. + //Using this make the overall process a bit more efficient but way more complicated and very weak + // to change. + //TODO Investigate if there is a better way to do this. + //Early exit, most are empty entities array + if (entities.length == 0) { + return; + } + + for (Entity entity : entities) { + if (entity instanceof ItemFrame) { + initMap(((ItemFrame) entity).getItem()); + } + } + } catch (Exception e) { + PluginLogger.error(e.toString()); + return; + } + + }, 5L); + } + + } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index afed51b..635a75e 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -26,3 +26,6 @@ limit-map-size-y: 0 # Should the full image be saved when a map is rendered? save-full-image: false +# Give the name of trusted image hosting website +#Example allowlist_hostingsite: https://imgur.com/, https://i.imgur.com/, https://cdn.discordapp.com +allowlist_hostingsite: diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 9fc4b97..e00cc36 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -40,7 +40,7 @@ permissions: imageonmap.updateother: false imageonmap.bypassmaplimit: false imageonmap.bypassimagelimit: false - + imageonmap.ignoreallowlist_hostingsite: true imageonmap.userender: description: "Allows you to use /tomap and related commands (/maptool getremaining). Alias of imageonmap.new." default: true @@ -118,5 +118,9 @@ permissions: default: op imageonmap.bypassimagelimit: - description: "Allows you to bypass permission node check for the number of images in the playerMapStore(by default users have an unlimited amount of images)." - default: op \ No newline at end of file + description: "Allows you to bypass permission node check for the number of images in the playerMapStore (by default users have an unlimited amount of images)." + default: op + + imageonmap.ignoreallowlist_hostingsite: + description: "Allows you to ignore the restriction on the allow list for image hosting website." + default: true \ No newline at end of file