diff --git a/src/main/java/dev/plex/HTTPDModule.java b/src/main/java/dev/plex/HTTPDModule.java index f837053..64ff11e 100644 --- a/src/main/java/dev/plex/HTTPDModule.java +++ b/src/main/java/dev/plex/HTTPDModule.java @@ -3,6 +3,8 @@ package dev.plex; import dev.plex.cache.FileCache; import dev.plex.config.ModuleConfig; import dev.plex.module.PlexModule; +import dev.plex.request.AbstractServlet; +import dev.plex.request.SchematicUploadServlet; import dev.plex.request.impl.AdminsEndpoint; import dev.plex.request.impl.IndefBansEndpoint; import dev.plex.request.impl.IndexEndpoint; @@ -11,7 +13,11 @@ import dev.plex.request.impl.PunishmentsEndpoint; import dev.plex.request.impl.SchematicDownloadEndpoint; import dev.plex.request.impl.SchematicUploadEndpoint; import dev.plex.util.PlexLog; + +import java.io.File; import java.util.concurrent.atomic.AtomicReference; + +import jakarta.servlet.MultipartConfigElement; import lombok.Getter; import net.milkbowl.vault.permission.Permission; import org.bukkit.Bukkit; @@ -24,6 +30,7 @@ import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; public class HTTPDModule extends PlexModule { @@ -38,6 +45,8 @@ public class HTTPDModule extends PlexModule public static final FileCache fileCache = new FileCache(); + public static final String template = AbstractServlet.readFileReal(HTTPDModule.class.getResourceAsStream("/httpd/template.html")); + @Override public void load() { @@ -75,6 +84,12 @@ public class HTTPDModule extends PlexModule new SchematicDownloadEndpoint(); new SchematicUploadEndpoint(); + ServletHolder uploadHolder = HTTPDModule.context.addServlet(SchematicUploadServlet.class, "/api/schematics/uploading"); + + File uploadLoc = new File(System.getProperty("java.io.tmpdir"), "schematic-temp-dir"); + if (!uploadLoc.exists()) uploadLoc.mkdirs(); + uploadHolder.getRegistration().setMultipartConfig(new MultipartConfigElement(uploadLoc.getAbsolutePath(), 1024 * 1024 * 5, 1024 * 1024 * 25, 1024 * 1024)); + server.setConnectors(new Connector[]{connector}); server.setHandler(context); @@ -114,4 +129,34 @@ public class HTTPDModule extends PlexModule permissions = rsp.getProvider(); return permissions != null; } + + public static File getWorldeditFolder() + { + if (Bukkit.getPluginManager().isPluginEnabled("WorldEdit")) + { + return new File(Bukkit.getPluginManager().getPlugin("WorldEdit").getDataFolder() + "/schematics/"); + } + else if (Bukkit.getPluginManager().isPluginEnabled("FastAsyncWorldEdit")) + { + return new File(Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit").getDataFolder() + "/schematics/"); + } + else + { + return null; + } + } + + private static boolean isFileSystemCaseSensitive = !new File( "a" ).equals( new File( "A" ) ); + + public static boolean fileNameEquals(String filename1, String filename2) + { + if (isFileSystemCaseSensitive) + { + return filename1.equals(filename2); + } + else + { + return filename1.equalsIgnoreCase(filename2); + } + } } diff --git a/src/main/java/dev/plex/cache/CacheItem.java b/src/main/java/dev/plex/cache/CacheItem.java index c847e94..6acba9a 100644 --- a/src/main/java/dev/plex/cache/CacheItem.java +++ b/src/main/java/dev/plex/cache/CacheItem.java @@ -13,7 +13,7 @@ public class CacheItem public CacheItem(File f) throws IOException { this.path = f.getPath(); - this.file = f.length() >= 1048576 ? null : Files.readAllBytes(f.toPath()); + this.file = Files.readAllBytes(f.toPath()); this.timestamp = System.currentTimeMillis(); } } diff --git a/src/main/java/dev/plex/cache/FileCache.java b/src/main/java/dev/plex/cache/FileCache.java index 2ff9e08..f0776ec 100644 --- a/src/main/java/dev/plex/cache/FileCache.java +++ b/src/main/java/dev/plex/cache/FileCache.java @@ -1,9 +1,12 @@ package dev.plex.cache; import com.google.common.collect.EvictingQueue; +import dev.plex.HTTPDModule; import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Queue; public class FileCache @@ -17,17 +20,17 @@ public class FileCache public byte[] getFile(String path) throws IOException { - CacheItem theItem = cache.stream().filter(cacheItem -> cacheItem.path.equals(path)).findFirst().orElse(null); + CacheItem theItem = cache.stream().filter(cacheItem -> HTTPDModule.fileNameEquals(cacheItem.path, path)).findFirst().orElse(null); if (theItem == null) { theItem = new CacheItem(new File(path)); - if (theItem.file != null) cache.add(theItem); + if (theItem.file.length < 1048576) cache.add(theItem); } if (System.currentTimeMillis() - theItem.timestamp > 3 * 60 * 1000) // 3 minutes { cache.remove(theItem); theItem = new CacheItem(new File(path)); - if (theItem.file != null) cache.add(theItem); + if (theItem.file.length < 1048576) cache.add(theItem); } return theItem.file; } diff --git a/src/main/java/dev/plex/request/AbstractServlet.java b/src/main/java/dev/plex/request/AbstractServlet.java index 8c8e201..c867855 100644 --- a/src/main/java/dev/plex/request/AbstractServlet.java +++ b/src/main/java/dev/plex/request/AbstractServlet.java @@ -15,6 +15,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.CharacterIterator; import java.text.StringCharacterIterator; +import java.util.Arrays; import java.util.List; import java.util.Objects; import lombok.Data; @@ -87,7 +88,25 @@ public class AbstractServlet extends HttpServlet }); } - public String readFile(InputStream filename) + public static String readFile(InputStream filename) + { + String base = HTTPDModule.template; + String page = readFileReal(filename); + String[] info = page.split("\n", 3); + System.out.println(Arrays.toString(info)); + base = base.replace("${TITLE}", info[0]); + base = base.replace("${ACTIVE_" + info[1] + "}", "active\" aria-current=\"page"); + base = base.replace("${ACTIVE_HOME}", ""); + base = base.replace("${ACTIVE_ADMINS}", ""); + base = base.replace("${ACTIVE_INDEFBANS}", ""); + base = base.replace("${ACTIVE_LIST}", ""); + base = base.replace("${ACTIVE_PUNISHMENTS}", ""); + base = base.replace("${ACTIVE_SCHEMATICS}", ""); + base = base.replace("${CONTENT}", info[2]); + return base; + } + + public static String readFileReal(InputStream filename) { StringBuilder contentBuilder = new StringBuilder(); try @@ -96,7 +115,7 @@ public class AbstractServlet extends HttpServlet String str; while ((str = in.readLine()) != null) { - contentBuilder.append(str); + contentBuilder.append(str).append("\n"); } in.close(); } diff --git a/src/main/java/dev/plex/request/SchematicUploadServlet.java b/src/main/java/dev/plex/request/SchematicUploadServlet.java new file mode 100644 index 0000000..6bda658 --- /dev/null +++ b/src/main/java/dev/plex/request/SchematicUploadServlet.java @@ -0,0 +1,70 @@ +package dev.plex.request; + +import dev.plex.HTTPDModule; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.Part; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.Arrays; +import java.util.regex.Pattern; + +public class SchematicUploadServlet extends HttpServlet +{ + private static final Pattern schemNameMatcher = Pattern.compile("^[a-z0-9'!,_ -]{1,30}\\.schem(atic)?$", Pattern.CASE_INSENSITIVE); + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + File worldeditFolder = HTTPDModule.getWorldeditFolder(); + if (worldeditFolder == null) + { + resp.getWriter().println(schematicUploadBadHTML("Worldedit is not installed!")); + return; + } + File[] schematics = worldeditFolder.listFiles(); + Part uploadPart = null; + try + { + uploadPart = req.getPart("file"); + } + catch (IllegalStateException e) + { + resp.getWriter().println(schematicUploadBadHTML("That schematic is too large!")); + return; + } + String filename = uploadPart.getSubmittedFileName().replaceAll("[^a-zA-Z0-9'!,_ .-]", "_"); + if (schemNameMatcher.matcher(filename).matches()) + { + boolean alreadyExists = schematics != null && Arrays.stream(schematics).anyMatch(file -> HTTPDModule.fileNameEquals(file.getName(), filename)); + if (alreadyExists) + { + resp.getWriter().println(schematicUploadBadHTML("A schematic with the name " + filename + " already exists!")); + return; + } + InputStream inputStream = uploadPart.getInputStream(); + Files.copy(inputStream, new File(worldeditFolder, filename).toPath(), StandardCopyOption.REPLACE_EXISTING); + inputStream.close(); + resp.getWriter().println(schematicUploadGoodHTML("Successfully uploaded " + filename + ".")); + } + } + + private String schematicUploadBadHTML(String message) + { + String file = AbstractServlet.readFile(this.getClass().getResourceAsStream("/httpd/schematic_upload_bad.html")); + file = file.replace("${MESSAGE}", message); + return file; + } + + private String schematicUploadGoodHTML(String message) + { + String file = AbstractServlet.readFile(this.getClass().getResourceAsStream("/httpd/schematic_upload_good.html")); + file = file.replace("${MESSAGE}", message); + return file; + } +} diff --git a/src/main/java/dev/plex/request/impl/SchematicDownloadEndpoint.java b/src/main/java/dev/plex/request/impl/SchematicDownloadEndpoint.java index b5d0d0b..71d1580 100644 --- a/src/main/java/dev/plex/request/impl/SchematicDownloadEndpoint.java +++ b/src/main/java/dev/plex/request/impl/SchematicDownloadEndpoint.java @@ -9,7 +9,6 @@ import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.util.Arrays; -import org.bukkit.Bukkit; public class SchematicDownloadEndpoint extends AbstractServlet { @@ -36,25 +35,9 @@ public class SchematicDownloadEndpoint extends AbstractServlet } } - private File getWorldeditFolder() - { - if (Bukkit.getPluginManager().isPluginEnabled("WorldEdit")) - { - return new File(Bukkit.getPluginManager().getPlugin("WorldEdit").getDataFolder() + "/schematics/"); - } - else if (Bukkit.getPluginManager().isPluginEnabled("FastAsyncWorldEdit")) - { - return new File(Bukkit.getPluginManager().getPlugin("FastAsyncWorldEdit").getDataFolder() + "/schematics/"); - } - else - { - return null; - } - } - private void schematicServe(String requestedSchematic, OutputStream outputStream) { - File worldeditFolder = getWorldeditFolder(); + File worldeditFolder = HTTPDModule.getWorldeditFolder(); if (worldeditFolder == null) { return; @@ -83,7 +66,7 @@ public class SchematicDownloadEndpoint extends AbstractServlet private String schematicHTML() { String file = readFile(this.getClass().getResourceAsStream("/httpd/schematic_download.html")); - File worldeditFolder = getWorldeditFolder(); + File worldeditFolder = HTTPDModule.getWorldeditFolder(); if (worldeditFolder == null) { return null; diff --git a/src/main/java/dev/plex/request/impl/SchematicUploadEndpoint.java b/src/main/java/dev/plex/request/impl/SchematicUploadEndpoint.java index 0ee23f2..37a5808 100644 --- a/src/main/java/dev/plex/request/impl/SchematicUploadEndpoint.java +++ b/src/main/java/dev/plex/request/impl/SchematicUploadEndpoint.java @@ -8,7 +8,7 @@ import jakarta.servlet.http.HttpServletResponse; public class SchematicUploadEndpoint extends AbstractServlet { @GetMapping(endpoint = "/api/schematics/upload/") - public String downloadSchematic(HttpServletRequest request, HttpServletResponse response) + public String uploadSchematic(HttpServletRequest request, HttpServletResponse response) { return readFile(this.getClass().getResourceAsStream("/httpd/schematic_upload.html")); } diff --git a/src/main/resources/httpd/admins.html b/src/main/resources/httpd/admins.html index 90e6133..3dc3bed 100644 --- a/src/main/resources/httpd/admins.html +++ b/src/main/resources/httpd/admins.html @@ -1,56 +1,4 @@ - - - - - - - Admins - Plex HTTPD - - - -
-

Plex HTTPD

- -
- - \ No newline at end of file +Admins +ADMINS +

Plex HTTPD

+ \ No newline at end of file diff --git a/src/main/resources/httpd/indefbans.html b/src/main/resources/httpd/indefbans.html index c09ed8e..efdc4e7 100644 --- a/src/main/resources/httpd/indefbans.html +++ b/src/main/resources/httpd/indefbans.html @@ -1,56 +1,4 @@ - - - - - - - Indefinite Bans - Plex HTTPD - - - -
-

Plex HTTPD

- -
- - \ No newline at end of file +Indefinite Bans +INDEFBANS +

Plex HTTPD

+ \ No newline at end of file diff --git a/src/main/resources/httpd/index.html b/src/main/resources/httpd/index.html index d1a8efd..705d2b2 100644 --- a/src/main/resources/httpd/index.html +++ b/src/main/resources/httpd/index.html @@ -1,57 +1,5 @@ - - - - - - - Home - Plex HTTPD - - - -
-

Welcome to the Plex HTTPD!

-

Use the sidebar to navigate the available pages.

-


There ${is_are} currently ${server_online_players} online out of ${server_total_players} total.

-
- - \ No newline at end of file +Home +HOME +

Welcome to the Plex HTTPD!

+

Use the sidebar to navigate the available pages.

+


There ${is_are} currently ${server_online_players} online out of ${server_total_players} total.

\ No newline at end of file diff --git a/src/main/resources/httpd/punishments.html b/src/main/resources/httpd/punishments.html index f64df4e..371b8d3 100644 --- a/src/main/resources/httpd/punishments.html +++ b/src/main/resources/httpd/punishments.html @@ -1,61 +1,11 @@ - - - - - - - Punishments - Plex HTTPD - - - -
-

Enter the UUID or username of the player you want to lookup

-
- - -
+Punishments +PUNISHMENTS +

Enter the UUID or username of the player you want to lookup

+
+ +
- - \ No newline at end of file + \ No newline at end of file diff --git a/src/main/resources/httpd/punishments_error.html b/src/main/resources/httpd/punishments_error.html index e1b22b1..1328f5e 100644 --- a/src/main/resources/httpd/punishments_error.html +++ b/src/main/resources/httpd/punishments_error.html @@ -1,56 +1,4 @@ - - - - - - - Punishments - Plex HTTPD - - - -
-

Plex HTTPD

- -
- - \ No newline at end of file +Punishments +PUNISHMENTS +

Plex HTTPD

+ \ No newline at end of file diff --git a/src/main/resources/httpd/punishments_good.html b/src/main/resources/httpd/punishments_good.html index 43ec513..b856d8e 100644 --- a/src/main/resources/httpd/punishments_good.html +++ b/src/main/resources/httpd/punishments_good.html @@ -1,55 +1,4 @@ - - - - - - - Punishments - Plex HTTPD - - - -
-

Plex HTTPD

- -
- - \ No newline at end of file +Punishments +PUNISHMENTS +

Plex HTTPD

+ \ No newline at end of file diff --git a/src/main/resources/httpd/schematic_download.html b/src/main/resources/httpd/schematic_download.html index 86995c6..5c42184 100644 --- a/src/main/resources/httpd/schematic_download.html +++ b/src/main/resources/httpd/schematic_download.html @@ -1,86 +1,34 @@ - - - - - - - Schematics - Plex HTTPD - - - -
-

Plex HTTPD

-
A list of schematics is below. You can click on the schematic name to download it.
-
- -
- - - - - - - - - ${schematics} - -
NameSize
- -
- - \ No newline at end of file + } + \ No newline at end of file diff --git a/src/main/resources/httpd/schematic_upload.html b/src/main/resources/httpd/schematic_upload.html index 74b8da8..17561cf 100644 --- a/src/main/resources/httpd/schematic_upload.html +++ b/src/main/resources/httpd/schematic_upload.html @@ -1,61 +1,10 @@ - - - - - - - Schematics - Plex HTTPD - - - -
-

Plex HTTPD

-
- -
- - -
-
-
- - \ No newline at end of file +Schematics +SCHEMATICS +

Plex HTTPD

+
+ +
+ + +
+
\ No newline at end of file diff --git a/src/main/resources/httpd/schematic_upload_bad.html b/src/main/resources/httpd/schematic_upload_bad.html new file mode 100644 index 0000000..a5c457a --- /dev/null +++ b/src/main/resources/httpd/schematic_upload_bad.html @@ -0,0 +1,4 @@ +Schematics +SCHEMATICS +

Plex HTTPD

+ \ No newline at end of file diff --git a/src/main/resources/httpd/schematic_upload_good.html b/src/main/resources/httpd/schematic_upload_good.html new file mode 100644 index 0000000..4bc6042 --- /dev/null +++ b/src/main/resources/httpd/schematic_upload_good.html @@ -0,0 +1,4 @@ +Schematics +SCHEMATICS +

Plex HTTPD

+ \ No newline at end of file diff --git a/src/main/resources/httpd/template.html b/src/main/resources/httpd/template.html new file mode 100644 index 0000000..8e2dbb2 --- /dev/null +++ b/src/main/resources/httpd/template.html @@ -0,0 +1,55 @@ + + + + + + + ${TITLE} - Plex HTTPD + + + +
+ ${CONTENT} +
+ + \ No newline at end of file