mirror of
https://github.com/TheDeus-Group/TFM-4.3-Reloaded.git
synced 2024-06-10 10:44:56 +00:00
aca3398d21
Version 5.0 This TotalFreedomMod release implements many changes. Most notably, the internals have been completely revamped. TotalFreedomMod now relies on the Aero library for core mechanics such as command handling and services. Another important change is the UUID system. In TotalFreedomMod Electrum, it has been completely removed. The core reason for this is that the system as a whole was very bugged. Additionally, it did not solve the primary reason for its conception: preserving player data when the player changes their username. This is because TotalFreedomMod servers usually run in offline-mode. This meaning that some of the players joining do not have a registerd Mojang UUID whatsoever. All in all, the UUID system was buggy, and it did not fix the reason it was implemented, so it has been completely removed. The admin list and the ban list now use usernames and IPs again. Lastly, many smaller changes have been implemented. Due to the amount of changes, they have not been named individualy. Please refer to the issues below for more details. Fixes #342 Fixes #350 Fixes #380 Fixes #684 Fixes #704 Fixes #716 Fixes #735 Fixes #745 Fixes #784 Fixes #765 Fixes #791 Fixes #805 Fixes #826 Fixes #883 Fixes #1524 Fixes #1534 Fixes #1536 Fixes #1538 Fixes #1545 Fixes #1546 Fixes #1568 Fixes #1627 Resolves #403 Resolves #435 Resolves #597 Resolves #603 Resolves #628 Resolves #690 Resolves #708 Resolves #747 Resolves #748 Resolves #749 Resolves #764 Resolves #767 Resolves #782 Resolves #809 Resolves #803 Resolves #811 Resolves #813 Resolves #830 Resolves #848 Resolves #856 Resolves #876 Resolves #908 Resolves #992 Resolves #1018 Resolves #1432 Resolves #1446 Resolves #1494 Resolves #1501 Resolves #1526 Resolves #1540 Resolves #1550 Resolves #1560 Resolves #1561 Resolves #1578 Resolves #1613
313 lines
10 KiB
Java
313 lines
10 KiB
Java
package me.totalfreedom.totalfreedommod.httpd.module;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
import java.util.ArrayList;
|
|
import java.util.Collection;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.regex.Pattern;
|
|
import me.totalfreedom.totalfreedommod.TotalFreedomMod;
|
|
import me.totalfreedom.totalfreedommod.admin.Admin;
|
|
import me.totalfreedom.totalfreedommod.httpd.HTMLGenerationTools;
|
|
import me.totalfreedom.totalfreedommod.httpd.HTTPDPageBuilder;
|
|
import me.totalfreedom.totalfreedommod.httpd.HTTPDaemon;
|
|
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD;
|
|
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.Method;
|
|
import me.totalfreedom.totalfreedommod.httpd.NanoHTTPD.Response;
|
|
import me.totalfreedom.totalfreedommod.util.FLog;
|
|
import org.apache.commons.io.FileUtils;
|
|
import org.apache.commons.lang3.StringEscapeUtils;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
public class Module_schematic extends HTTPDModule
|
|
{
|
|
|
|
private static final File SCHEMATIC_FOLDER = new File("./plugins/WorldEdit/schematics/");
|
|
private static final String REQUEST_FORM_FILE_ELEMENT_NAME = "schematicFile";
|
|
private static final Pattern SCHEMATIC_FILENAME_LC = Pattern.compile("^[a-z0-9_'!,\\-]{1,30}\\.schematic$");
|
|
private static final String[] SCHEMATIC_FILTER = new String[]
|
|
{
|
|
"schematic"
|
|
};
|
|
private static final String UPLOAD_FORM = "<form method=\"post\" name=\"schematicForm\" id=\"schematicForm\" action=\"/schematic/upload/\" enctype=\"multipart/form-data\">\n"
|
|
+ "<p>Select a schematic file to upload. Filenames must be alphanumeric, between 1 and 30 characters long (inclusive), and have a .schematic extension.</p>\n"
|
|
+ "<input type=\"file\" id=\"schematicFile\" name=\"schematicFile\" />\n"
|
|
+ "<br />\n"
|
|
+ "<button type=\"submit\">Submit</button>\n"
|
|
+ "</form>";
|
|
|
|
public Module_schematic(TotalFreedomMod plugin, NanoHTTPD.HTTPSession session)
|
|
{
|
|
super(plugin, session);
|
|
}
|
|
|
|
@Override
|
|
public Response getResponse()
|
|
{
|
|
try
|
|
{
|
|
return new HTTPDPageBuilder(body(), title(), null, null).getResponse();
|
|
}
|
|
catch (ResponseOverrideException ex)
|
|
{
|
|
return ex.getResponse();
|
|
}
|
|
}
|
|
|
|
public String title()
|
|
{
|
|
return "TotalFreedomMod :: Schematic Manager";
|
|
}
|
|
|
|
public String body() throws ResponseOverrideException
|
|
{
|
|
if (!SCHEMATIC_FOLDER.exists())
|
|
{
|
|
return HTMLGenerationTools.paragraph("Can't find the WorldEdit schematic folder.");
|
|
}
|
|
|
|
final StringBuilder out = new StringBuilder();
|
|
|
|
final String[] args = StringUtils.split(uri, "/");
|
|
final ModuleMode mode = ModuleMode.getMode(getArg(args, 1));
|
|
|
|
switch (mode)
|
|
{
|
|
case LIST:
|
|
{
|
|
Collection<File> schematics = FileUtils.listFiles(SCHEMATIC_FOLDER, SCHEMATIC_FILTER, false);
|
|
|
|
final List<String> schematicsFormatted = new ArrayList<>();
|
|
for (File schematic : schematics)
|
|
{
|
|
String filename = StringEscapeUtils.escapeHtml4(schematic.getName());
|
|
|
|
if (SCHEMATIC_FILENAME_LC.matcher(filename.trim().toLowerCase()).find())
|
|
{
|
|
schematicsFormatted.add("<li><a href=\"/schematic/download?schematicName=" + filename + "\">" + filename + "</a></li>");
|
|
}
|
|
else
|
|
{
|
|
schematicsFormatted.add("<li>" + filename + " - (Illegal filename, can't download)</li>");
|
|
}
|
|
}
|
|
|
|
Collections.sort(schematicsFormatted, new Comparator<String>()
|
|
{
|
|
@Override
|
|
public int compare(String a, String b)
|
|
{
|
|
return a.toLowerCase().compareTo(b.toLowerCase());
|
|
}
|
|
});
|
|
|
|
out
|
|
.append(HTMLGenerationTools.heading("Schematics:", 1))
|
|
.append("<ul>")
|
|
.append(StringUtils.join(schematicsFormatted, "\r\n"))
|
|
.append("</ul>");
|
|
|
|
break;
|
|
}
|
|
case DOWNLOAD:
|
|
{
|
|
try
|
|
{
|
|
throw new ResponseOverrideException(downloadSchematic(params.get("schematicName")));
|
|
}
|
|
catch (SchematicTransferException ex)
|
|
{
|
|
out.append(HTMLGenerationTools.paragraph("Error downloading schematic: " + ex.getMessage()));
|
|
}
|
|
break;
|
|
}
|
|
case UPLOAD:
|
|
{
|
|
final String remoteAddress = socket.getInetAddress().getHostAddress();
|
|
if (!isAuthorized(remoteAddress))
|
|
{
|
|
out.append(HTMLGenerationTools.paragraph("Schematic upload access denied: Your IP, " + remoteAddress + ", is not registered to a superadmin on this server."));
|
|
}
|
|
else
|
|
{
|
|
if (method == Method.POST)
|
|
{
|
|
try
|
|
{
|
|
uploadSchematic();
|
|
out.append(HTMLGenerationTools.paragraph("Schematic uploaded successfully."));
|
|
}
|
|
catch (SchematicTransferException ex)
|
|
{
|
|
out.append(HTMLGenerationTools.paragraph("Error uploading schematic: " + ex.getMessage()));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
out.append(UPLOAD_FORM);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
out.append(HTMLGenerationTools.paragraph("Invalid request mode."));
|
|
break;
|
|
}
|
|
}
|
|
|
|
return out.toString();
|
|
}
|
|
|
|
private boolean uploadSchematic() throws SchematicTransferException
|
|
{
|
|
Map<String, String> files = getFiles();
|
|
|
|
final String tempFileName = files.get(REQUEST_FORM_FILE_ELEMENT_NAME);
|
|
if (tempFileName == null)
|
|
{
|
|
throw new SchematicTransferException("No file transmitted to server.");
|
|
}
|
|
|
|
final File tempFile = new File(tempFileName);
|
|
if (!tempFile.exists())
|
|
{
|
|
throw new SchematicTransferException();
|
|
}
|
|
|
|
String origFileName = params.get(REQUEST_FORM_FILE_ELEMENT_NAME);
|
|
if (origFileName == null || (origFileName = origFileName.trim()).isEmpty())
|
|
{
|
|
throw new SchematicTransferException("Can't resolve original file name.");
|
|
}
|
|
|
|
if (tempFile.length() > FileUtils.ONE_KB * 64L)
|
|
{
|
|
throw new SchematicTransferException("Schematic is too big (64kb max).");
|
|
}
|
|
|
|
if (!SCHEMATIC_FILENAME_LC.matcher(origFileName.toLowerCase()).find())
|
|
{
|
|
throw new SchematicTransferException("File name must be alphanumeric, between 1 and 30 characters long (inclusive), and have a \".schematic\" extension.");
|
|
}
|
|
|
|
final File targetFile = new File(SCHEMATIC_FOLDER.getPath(), origFileName);
|
|
if (targetFile.exists())
|
|
{
|
|
throw new SchematicTransferException("Schematic already exists on the server.");
|
|
}
|
|
|
|
try
|
|
{
|
|
FileUtils.copyFile(tempFile, targetFile);
|
|
}
|
|
catch (IOException ex)
|
|
{
|
|
FLog.severe(ex);
|
|
throw new SchematicTransferException();
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private Response downloadSchematic(String schematicName) throws SchematicTransferException
|
|
{
|
|
if (schematicName == null || !SCHEMATIC_FILENAME_LC.matcher((schematicName = schematicName.trim()).toLowerCase()).find())
|
|
{
|
|
throw new SchematicTransferException("Invalid schematic name requested: " + schematicName);
|
|
}
|
|
|
|
final File targetFile = new File(SCHEMATIC_FOLDER.getPath(), schematicName);
|
|
if (!targetFile.exists())
|
|
{
|
|
throw new SchematicTransferException("Schematic not found: " + schematicName);
|
|
}
|
|
|
|
Response response = HTTPDaemon.serveFileBasic(targetFile);
|
|
|
|
response.addHeader("Content-Disposition", "attachment; filename=" + targetFile.getName() + ";");
|
|
|
|
return response;
|
|
}
|
|
|
|
private boolean isAuthorized(String remoteAddress)
|
|
{
|
|
Admin entry = plugin.al.getEntryByIp(remoteAddress);
|
|
return entry != null && entry.isActive();
|
|
}
|
|
|
|
private static class SchematicTransferException extends Exception
|
|
{
|
|
|
|
public SchematicTransferException()
|
|
{
|
|
}
|
|
|
|
public SchematicTransferException(String string)
|
|
{
|
|
super(string);
|
|
}
|
|
}
|
|
|
|
private static class ResponseOverrideException extends Exception
|
|
{
|
|
|
|
private final Response response;
|
|
|
|
public ResponseOverrideException(Response response)
|
|
{
|
|
this.response = response;
|
|
}
|
|
|
|
public Response getResponse()
|
|
{
|
|
return response;
|
|
}
|
|
}
|
|
|
|
private static String getArg(String[] args, int index)
|
|
{
|
|
String out = (args.length == index + 1 ? args[index] : null);
|
|
return (out == null ? null : (out.trim().isEmpty() ? null : out.trim()));
|
|
}
|
|
|
|
private static enum ModuleMode
|
|
{
|
|
|
|
LIST("list"),
|
|
UPLOAD("upload"),
|
|
DOWNLOAD("download"),
|
|
INVALID(null);
|
|
//
|
|
private final String modeName;
|
|
|
|
private ModuleMode(String modeName)
|
|
{
|
|
this.modeName = modeName;
|
|
}
|
|
|
|
@Override
|
|
public String toString()
|
|
{
|
|
return this.modeName;
|
|
}
|
|
|
|
public static ModuleMode getMode(String needle)
|
|
{
|
|
for (ModuleMode mode : values())
|
|
{
|
|
final String haystack = mode.toString();
|
|
if (haystack != null && haystack.equalsIgnoreCase(needle))
|
|
{
|
|
return mode;
|
|
}
|
|
}
|
|
return INVALID;
|
|
}
|
|
}
|
|
|
|
}
|